From patchwork Thu Aug 13 03:24:59 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?b?Q2h1bmZlbmcgWXVuICjkupHmmKXls7Ap?= X-Patchwork-Id: 1343987 X-Patchwork-Delegate: marek.vasut@gmail.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=2a01:238:438b:c500:173d:9f52:ddab:ee01; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=mediatek.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=mediatek.com header.i=@mediatek.com header.a=rsa-sha256 header.s=dk header.b=uFNlXDZ8; dkim-atps=neutral Received: from phobos.denx.de (phobos.denx.de [IPv6:2a01:238:438b:c500:173d:9f52:ddab:ee01]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4BRsTK2TMDz9sTM for ; Thu, 13 Aug 2020 13:27:48 +1000 (AEST) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 43B318220B; Thu, 13 Aug 2020 05:26:48 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=mediatek.com Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (1024-bit key; unprotected) header.d=mediatek.com header.i=@mediatek.com header.b="uFNlXDZ8"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id DC0F482194; Thu, 13 Aug 2020 05:26:37 +0200 (CEST) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=0.5 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,MIME_BASE64_TEXT,RDNS_NONE,SPF_HELO_NONE, UNPARSEABLE_RELAY,URIBL_BLOCKED autolearn=no autolearn_force=no version=3.4.2 Received: from mailgw01.mediatek.com (unknown [210.61.82.183]) by phobos.denx.de (Postfix) with ESMTP id 1BC9881B5E for ; Thu, 13 Aug 2020 05:26:31 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=mediatek.com Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=chunfeng.yun@mediatek.com X-UUID: e2f5518ea410482bbbfb05fbbca7d1ac-20200813 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Transfer-Encoding:Content-Type:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; bh=JUkrDHyFNUdiAGJGKPyDy9L22bN0TJPMSW6kZGK0x+w=; b=uFNlXDZ8oJSxnwc/lq0olOM8wfZEbiHKxTBxHTSuz3aCuXrpMlyktOejTdPk9nk80LPlXS+gYpa+IHguA8sSDfjllmQldur4HLdX6zUqLXv3PC4hwXaR2Jsis6eH1Pa+RHMml00+I1I0uc//7jCMaZGApatG3lEsBF7fFMbyLoQ=; X-UUID: e2f5518ea410482bbbfb05fbbca7d1ac-20200813 Received: from mtkcas08.mediatek.inc [(172.21.101.126)] by mailgw01.mediatek.com (envelope-from ) (Cellopoint E-mail Firewall v4.1.10 Build 0809 with TLS) with ESMTP id 230488103; Thu, 13 Aug 2020 11:26:24 +0800 Received: from MTKCAS06.mediatek.inc (172.21.101.30) by mtkmbs08n2.mediatek.inc (172.21.101.56) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Thu, 13 Aug 2020 11:26:22 +0800 Received: from localhost.localdomain (10.17.3.153) by MTKCAS06.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Thu, 13 Aug 2020 11:26:22 +0800 From: Chunfeng Yun To: Marek Vasut , Bin Meng , Frank Wunderlich CC: Ryder Lee , Weijie Gao , GSS_MTK_Uboot_upstream , , Chunfeng Yun Subject: [PATCH 02/11] usb: xhci: create one unified function to calculate TRB TD remainder. Date: Thu, 13 Aug 2020 11:24:59 +0800 Message-ID: <1597289108-22936-2-git-send-email-chunfeng.yun@mediatek.com> X-Mailer: git-send-email 1.8.1.1.dirty In-Reply-To: <1597289108-22936-1-git-send-email-chunfeng.yun@mediatek.com> References: <1597289108-22936-1-git-send-email-chunfeng.yun@mediatek.com> MIME-Version: 1.0 X-TM-SNTS-SMTP: 6E73C33340C2D95F1FDE46A254AF82F0825834E730771DFA120EA67D731D57ED2000:8 X-MTK: N X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.34 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.102.3 at phobos.denx.de X-Virus-Status: Clean xhci versions 1.0 and later report the untransferred data remaining in a TD a bit differently than older hosts. We used to have separate functions for these, and needed to check host version before calling the right function. Now Mediatek host has an additional quirk on how it uses the TD Size field for remaining data. To prevent yet another function for calculating remainder we instead want to make one quirk friendly unified function. Porting from the Linux: c840d6ce772d("xhci: create one unified function to calculate TRB TD remainder.") 124c39371114("xhci: use boolean to indicate last trb in td remainder calculation") Signed-off-by: Chunfeng Yun --- drivers/usb/host/xhci-ring.c | 105 +++++++++++++++++++++---------------------- include/usb/xhci.h | 2 + 2 files changed, 52 insertions(+), 55 deletions(-) diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 79bfc34..0f86b01 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -298,55 +298,52 @@ void xhci_queue_command(struct xhci_ctrl *ctrl, u8 *ptr, u32 slot_id, xhci_writel(&ctrl->dba->doorbell[0], DB_VALUE_HOST); } -/** - * The TD size is the number of bytes remaining in the TD (including this TRB), - * right shifted by 10. - * It must fit in bits 21:17, so it can't be bigger than 31. +/* + * For xHCI 1.0 host controllers, TD size is the number of max packet sized + * packets remaining in the TD (*not* including this TRB). * - * @param remainder remaining packets to be sent - * @return remainder if remainder is less than max else max - */ -static u32 xhci_td_remainder(unsigned int remainder) -{ - u32 max = (1 << (21 - 17 + 1)) - 1; - - if ((remainder >> 10) >= max) - return max << 17; - else - return (remainder >> 10) << 17; -} - -/** - * Finds out the remanining packets to be sent + * Total TD packet count = total_packet_count = + * DIV_ROUND_UP(TD size in bytes / wMaxPacketSize) + * + * Packets transferred up to and including this TRB = packets_transferred = + * rounddown(total bytes transferred including this TRB / wMaxPacketSize) + * + * TD size = total_packet_count - packets_transferred * - * @param running_total total size sent so far + * For xHCI 0.96 and older, TD size field should be the remaining bytes + * including this TRB, right shifted by 10 + * + * For all hosts it must fit in bits 21:17, so it can't be bigger than 31. + * This is taken care of in the TRB_TD_SIZE() macro + * + * The last TRB in a TD must have the TD size set to zero. + * + * @param ctrl host controller data structure + * @param transferred total size sent so far * @param trb_buff_len length of the TRB Buffer - * @param total_packet_count total packet count - * @param maxpacketsize max packet size of current pipe - * @param num_trbs_left number of TRBs left to be processed - * @return 0 if running_total or trb_buff_len is 0, else remainder + * @param td_total_len total packet count + * @param maxp max packet size of current pipe + * @param more_trbs_coming indicate last trb in TD + * @return remainder */ -static u32 xhci_v1_0_td_remainder(int running_total, - int trb_buff_len, - unsigned int total_packet_count, - int maxpacketsize, - unsigned int num_trbs_left) +static u32 xhci_td_remainder(struct xhci_ctrl *ctrl, int transferred, + int trb_buff_len, unsigned int td_total_len, + int maxp, bool more_trbs_coming) { - int packets_transferred; + u32 total_packet_count; + + if (ctrl->hci_version < 0x100) + return ((td_total_len - transferred) >> 10); /* One TRB with a zero-length data packet. */ - if (num_trbs_left == 0 || (running_total == 0 && trb_buff_len == 0)) + if (!more_trbs_coming || (transferred == 0 && trb_buff_len == 0) || + trb_buff_len == td_total_len) return 0; - /* - * All the TRB queueing functions don't count the current TRB in - * running_total. - */ - packets_transferred = (running_total + trb_buff_len) / maxpacketsize; + total_packet_count = DIV_ROUND_UP(td_total_len, maxp); - if ((total_packet_count - packets_transferred) > 31) - return 31 << 17; - return (total_packet_count - packets_transferred) << 17; + /* Queueing functions don't count the current TRB into transferred */ + return (total_packet_count - ((transferred + trb_buff_len) / maxp)); } /** @@ -572,7 +569,7 @@ int xhci_bulk_tx(struct usb_device *udev, unsigned long pipe, union xhci_trb *event; int running_total, trb_buff_len; - unsigned int total_packet_count; + bool more_trbs_coming = true; int maxpacketsize; u64 addr; int ret; @@ -636,8 +633,6 @@ int xhci_bulk_tx(struct usb_device *udev, unsigned long pipe, running_total = 0; maxpacketsize = usb_maxpacket(udev, pipe); - total_packet_count = DIV_ROUND_UP(length, maxpacketsize); - /* How much data is in the first TRB? */ /* * How much data is (potentially) left before the 64KB boundary? @@ -672,27 +667,24 @@ int xhci_bulk_tx(struct usb_device *udev, unsigned long pipe, * Chain all the TRBs together; clear the chain bit in the last * TRB to indicate it's the last TRB in the chain. */ - if (num_trbs > 1) + if (num_trbs > 1) { field |= TRB_CHAIN; - else + } else { field |= TRB_IOC; + more_trbs_coming = false; + } /* Only set interrupt on short packet for IN endpoints */ if (usb_pipein(pipe)) field |= TRB_ISP; /* Set the TRB length, TD size, and interrupter fields. */ - if (ctrl->hci_version < 0x100) - remainder = xhci_td_remainder(length - running_total); - else - remainder = xhci_v1_0_td_remainder(running_total, - trb_buff_len, - total_packet_count, - maxpacketsize, - num_trbs - 1); + remainder = xhci_td_remainder(ctrl, running_total, trb_buff_len, + length, maxpacketsize, + more_trbs_coming); length_field = ((trb_buff_len & TRB_LEN_MASK) | - remainder | + TRB_TD_SIZE(remainder) | ((0 & TRB_INTR_TARGET_MASK) << TRB_INTR_TARGET_SHIFT)); @@ -764,6 +756,7 @@ int xhci_ctrl_tx(struct usb_device *udev, unsigned long pipe, struct xhci_virt_device *virt_dev = ctrl->devs[slot_id]; struct xhci_ring *ep_ring; union xhci_trb *event; + u32 remainder; debug("req=%u (%#x), type=%u (%#x), value=%u (%#x), index=%u\n", req->request, req->request, @@ -866,12 +859,14 @@ int xhci_ctrl_tx(struct usb_device *udev, unsigned long pipe, else field = (TRB_DATA << TRB_TYPE_SHIFT); - length_field = (length & TRB_LEN_MASK) | xhci_td_remainder(length) | + remainder = xhci_td_remainder(ctrl, 0, length, length, + usb_maxpacket(udev, pipe), 1); + length_field = (length & TRB_LEN_MASK) | TRB_TD_SIZE(remainder) | ((0 & TRB_INTR_TARGET_MASK) << TRB_INTR_TARGET_SHIFT); debug("length_field = %d, length = %d," "xhci_td_remainder(length) = %d , TRB_INTR_TARGET(0) = %d\n", length_field, (length & TRB_LEN_MASK), - xhci_td_remainder(length), 0); + TRB_TD_SIZE(remainder), 0); if (length > 0) { if (req->requesttype & USB_DIR_IN) diff --git a/include/usb/xhci.h b/include/usb/xhci.h index a3e5914..15926eb 100644 --- a/include/usb/xhci.h +++ b/include/usb/xhci.h @@ -850,6 +850,8 @@ struct xhci_event_cmd { /* transfer_len bitmasks - bits 0:16 */ #define TRB_LEN(p) ((p) & 0x1ffff) #define TRB_LEN_MASK (0x1ffff) +/* TD Size, packets remaining in this TD, bits 21:17 (5 bits, so max 31) */ +#define TRB_TD_SIZE(p) (min((p), (u32)31) << 17) /* Interrupter Target - which MSI-X vector to target the completion event at */ #define TRB_INTR_TARGET_SHIFT (22) #define TRB_INTR_TARGET_MASK (0x3ff)