From 621ed49d3a2ea3c45be1cf774bef48439bd566f3 Mon Sep 17 00:00:00 2001 From: Ran Wang Date: Wed, 18 Nov 2020 15:49:02 +0800 Subject: [PATCH 1/3] usb: xhci: fix lack of short packet event trb handling For bulk IN transfer, the codes will set ISP flag to request event TRB being generated by xHC for the case of short packet. So when encountering buffer-cross-64K-boundary (which we will divide payload and enqueuqe more than 1 transfer TRB), and the first TRB ends up with a short packet condition it will trigger an short packet code transfer event per that flag and cause more than 1 event TRB generated for this transfer. However, current codes will only handle the first transfer event TRB then mark current transfer completed, causing next transfer failure due to event TRB mis-match. Such issue has been observed on some Layerscape platforms (LS1028A, LS1088A, etc) with USB ethernet device. This patch adds a loop to make sure the event TRB for last transfer TRB has been handled in time. Signed-off-by: Ran Wang Reviewed-by: Bin Meng --- drivers/usb/host/xhci-ring.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 13065d7ca99..d708fc928b2 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -580,10 +580,13 @@ int xhci_bulk_tx(struct usb_device *udev, unsigned long pipe, int ret; u32 trb_fields[4]; u64 val_64 = virt_to_phys(buffer); + void *last_transfer_trb_addr; + int available_length; debug("dev=%p, pipe=%lx, buffer=%p, length=%d\n", udev, pipe, buffer, length); + available_length = length; ep_index = usb_pipe_ep_index(pipe); virt_dev = ctrl->devs[slot_id]; @@ -697,7 +700,7 @@ int xhci_bulk_tx(struct usb_device *udev, unsigned long pipe, trb_fields[2] = length_field; trb_fields[3] = field | TRB_TYPE(TRB_NORMAL); - queue_trb(ctrl, ring, (num_trbs > 1), trb_fields); + last_transfer_trb_addr = queue_trb(ctrl, ring, (num_trbs > 1), trb_fields); --num_trbs; @@ -710,6 +713,7 @@ int xhci_bulk_tx(struct usb_device *udev, unsigned long pipe, giveback_first_trb(udev, ep_index, start_cycle, start_trb); +again: event = xhci_wait_for_event(ctrl, TRB_TRANSFER); if (!event) { debug("XHCI bulk transfer timed out, aborting...\n"); @@ -718,12 +722,20 @@ int xhci_bulk_tx(struct usb_device *udev, unsigned long pipe, udev->act_len = 0; return -ETIMEDOUT; } - field = le32_to_cpu(event->trans_event.flags); + if ((uintptr_t)(le64_to_cpu(event->trans_event.buffer)) + != (uintptr_t)last_transfer_trb_addr) { + available_length -= + (int)EVENT_TRB_LEN(le32_to_cpu(event->trans_event.transfer_len)); + xhci_acknowledge_event(ctrl); + goto again; + } + + field = le32_to_cpu(event->trans_event.flags); BUG_ON(TRB_TO_SLOT_ID(field) != slot_id); BUG_ON(TRB_TO_EP_INDEX(field) != ep_index); - record_transfer_result(udev, event, length); + record_transfer_result(udev, event, available_length); xhci_acknowledge_event(ctrl); xhci_inval_cache((uintptr_t)buffer, length); From 17d5a461a0da967c511032a160278b0e1d9fd349 Mon Sep 17 00:00:00 2001 From: Hayes Wang Date: Wed, 16 Dec 2020 17:03:22 +0800 Subject: [PATCH 2/3] eth/r8152: free previous memory if r8152_eth_probe fail The r8152_eth_probe() may allocate a memory for ss->dev_priv. It has to be freed if r8152_eth_probe() fails finally. Signed-off-by: Hayes Wang --- drivers/usb/eth/r8152.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/usb/eth/r8152.c b/drivers/usb/eth/r8152.c index 215bcbbef80..82a05a9c351 100644 --- a/drivers/usb/eth/r8152.c +++ b/drivers/usb/eth/r8152.c @@ -1647,7 +1647,7 @@ int r8152_eth_probe(struct usb_device *dev, unsigned int ifnum, if (usb_set_interface(dev, iface_desc->bInterfaceNumber, 0) || !ss->ep_in || !ss->ep_out || !ss->ep_int) { debug("Problems with device\n"); - return 0; + goto error; } dev->privptr = (void *)ss; @@ -1659,7 +1659,7 @@ int r8152_eth_probe(struct usb_device *dev, unsigned int ifnum, r8152b_get_version(tp); if (rtl_ops_init(tp)) - return 0; + goto error; tp->rtl_ops.init(tp); tp->rtl_ops.up(tp); @@ -1669,6 +1669,11 @@ int r8152_eth_probe(struct usb_device *dev, unsigned int ifnum, DUPLEX_FULL); return 1; + +error: + cfree(ss->dev_priv); + ss->dev_priv = 0; + return 0; } int r8152_eth_get_info(struct usb_device *dev, struct ueth_data *ss, From 72294407726e9652f4ab44add3dbd118797683d1 Mon Sep 17 00:00:00 2001 From: Hayes Wang Date: Wed, 16 Dec 2020 17:03:23 +0800 Subject: [PATCH 3/3] eth/r8152: fix the aggregation issue Remove the redundant setting for USB_RX_EARLY_SIZE. Besides, for RTL8153B, it is necessary to notify the hardware of the changes of the aggregation settings. Signed-off-by: Hayes Wang --- drivers/usb/eth/r8152.c | 17 +++++++++++++++-- drivers/usb/eth/r8152.h | 5 +++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/drivers/usb/eth/r8152.c b/drivers/usb/eth/r8152.c index 82a05a9c351..5f309192b42 100644 --- a/drivers/usb/eth/r8152.c +++ b/drivers/usb/eth/r8152.c @@ -447,6 +447,12 @@ static void rtl8152_set_rx_mode(struct r8152 *tp) ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data); } +static inline void r8153b_rx_agg_chg_indicate(struct r8152 *tp) +{ + ocp_write_byte(tp, MCU_TYPE_USB, USB_UPT_RXDMA_OWN, + OWN_UPDATE | OWN_CLEAR); +} + static int rtl_enable(struct r8152 *tp) { u32 ocp_data; @@ -457,6 +463,15 @@ static int rtl_enable(struct r8152 *tp) ocp_data |= PLA_CR_RE | PLA_CR_TE; ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CR, ocp_data); + switch (tp->version) { + case RTL_VER_08: + case RTL_VER_09: + r8153b_rx_agg_chg_indicate(tp); + break; + default: + break; + } + rxdy_gated_en(tp, false); rtl8152_set_rx_mode(tp); @@ -525,8 +540,6 @@ static void r8153_set_rx_early_size(struct r8152 *tp) debug("** %s Invalid Device\n", __func__); break; } - - ocp_write_word(tp, MCU_TYPE_USB, USB_RX_EARLY_SIZE, ocp_data); } static int rtl8153_enable(struct r8152 *tp) diff --git a/drivers/usb/eth/r8152.h b/drivers/usb/eth/r8152.h index fa57e42502a..45172c055f4 100644 --- a/drivers/usb/eth/r8152.h +++ b/drivers/usb/eth/r8152.h @@ -92,6 +92,7 @@ #define USB_PM_CTRL_STATUS 0xd432 /* RTL8153A */ #define USB_RX_EXTRA_AGGR_TMR 0xd432 /* RTL8153B */ #define USB_TX_DMA 0xd434 +#define USB_UPT_RXDMA_OWN 0xd437 #define USB_TOLERANCE 0xd490 #define USB_LPM_CTRL 0xd41a #define USB_BMU_RESET 0xd4b0 @@ -346,6 +347,10 @@ #define BMU_RESET_EP_IN 0x01 #define BMU_RESET_EP_OUT 0x02 +/* USB_UPT_RXDMA_OWN */ +#define OWN_UPDATE BIT(0) +#define OWN_CLEAR BIT(1) + /* USB_UPS_CTRL */ #define POWER_CUT 0x0100