From: Pawel Laszczak <pawell@cadence.com>
To: unlisted-recipients:; (no To-header on input)
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
<linux-usb@vger.kernel.org>, Felipe Balbi <balbi@kernel.org>,
<linux-kernel@vger.kernel.org>, <ltyrala@cadence.com>,
<adouglas@cadence.com>, <pawell@cadence.com>
Subject: [PATCH 10/31] usb: usbssp: added usbssp_trb_in_td function.
Date: Thu, 19 Jul 2018 18:57:43 +0100 [thread overview]
Message-ID: <1532023084-28083-11-git-send-email-pawell@cadence.com> (raw)
In-Reply-To: <1532023084-28083-1-git-send-email-pawell@cadence.com>
Patch adds usbssp_trb_in_td function. This function checks if given
TRB object belongs to TD.
Patch also add procedure for testing this function and some testing
cases.
Signed-off-by: Pawel Laszczak <pawell@cadence.com>
---
drivers/usb/usbssp/gadget-mem.c | 168 +++++++++++++++++++++++++++++++
drivers/usb/usbssp/gadget-ring.c | 76 ++++++++++++++
drivers/usb/usbssp/gadget.h | 5 +
3 files changed, 249 insertions(+)
diff --git a/drivers/usb/usbssp/gadget-mem.c b/drivers/usb/usbssp/gadget-mem.c
index ecb6e1bbd212..fef83b6b6cf0 100644
--- a/drivers/usb/usbssp/gadget-mem.c
+++ b/drivers/usb/usbssp/gadget-mem.c
@@ -765,6 +765,170 @@ void usbssp_mem_cleanup(struct usbssp_udc *usbssp_data)
usbssp_data->page_shift = 0;
}
+static int usbssp_test_trb_in_td(struct usbssp_udc *usbssp_data,
+ struct usbssp_segment *input_seg,
+ union usbssp_trb *start_trb,
+ union usbssp_trb *end_trb,
+ dma_addr_t input_dma,
+ struct usbssp_segment *result_seg,
+ char *test_name, int test_number)
+{
+ unsigned long long start_dma;
+ unsigned long long end_dma;
+ struct usbssp_segment *seg;
+
+ start_dma = usbssp_trb_virt_to_dma(input_seg, start_trb);
+ end_dma = usbssp_trb_virt_to_dma(input_seg, end_trb);
+
+ seg = usbssp_trb_in_td(usbssp_data, input_seg, start_trb,
+ end_trb, input_dma, false);
+
+ if (seg != result_seg) {
+ dev_warn(usbssp_data->dev, "WARN: %s TRB math test %d failed!\n",
+ test_name, test_number);
+ dev_warn(usbssp_data->dev, "Tested TRB math w/ seg %p and "
+ "input DMA 0x%llx\n",
+ input_seg,
+ (unsigned long long) input_dma);
+ dev_warn(usbssp_data->dev, "starting TRB %p (0x%llx DMA), "
+ "ending TRB %p (0x%llx DMA)\n",
+ start_trb, start_dma,
+ end_trb, end_dma);
+ dev_warn(usbssp_data->dev, "Expected seg %p, got seg %p\n",
+ result_seg, seg);
+
+ usbssp_trb_in_td(usbssp_data, input_seg, start_trb,
+ end_trb, input_dma, true);
+ return -1;
+ }
+ return 0;
+}
+
+/* TRB math checks for usbssp_trb_in_td(), using the command and event rings. */
+static int usbssp_check_trb_in_td_math(struct usbssp_udc *usbssp_data)
+{
+ struct {
+ dma_addr_t input_dma;
+ struct usbssp_segment *result_seg;
+ } simple_test_vector[] = {
+ /* A zeroed DMA field should fail */
+ { 0, NULL },
+ /* One TRB before the ring start should fail */
+ { usbssp_data->event_ring->first_seg->dma - 16, NULL },
+ /* One byte before the ring start should fail */
+ { usbssp_data->event_ring->first_seg->dma - 1, NULL },
+ /* Starting TRB should succeed */
+ { usbssp_data->event_ring->first_seg->dma,
+ usbssp_data->event_ring->first_seg },
+ /* Ending TRB should succeed */
+ { usbssp_data->event_ring->first_seg->dma +
+ (TRBS_PER_SEGMENT - 1)*16,
+ usbssp_data->event_ring->first_seg },
+ /* One byte after the ring end should fail */
+ { usbssp_data->event_ring->first_seg->dma +
+ (TRBS_PER_SEGMENT - 1)*16 + 1, NULL },
+ /* One TRB after the ring end should fail */
+ { usbssp_data->event_ring->first_seg->dma +
+ (TRBS_PER_SEGMENT)*16, NULL },
+ /* An address of all ones should fail */
+ { (dma_addr_t) (~0), NULL },
+ };
+ struct {
+ struct usbssp_segment *input_seg;
+ union usbssp_trb *start_trb;
+ union usbssp_trb *end_trb;
+ dma_addr_t input_dma;
+ struct usbssp_segment *result_seg;
+ } complex_test_vector[] = {
+ /* Test feeding a valid DMA address from a different ring */
+ { .input_seg = usbssp_data->event_ring->first_seg,
+ .start_trb = usbssp_data->event_ring->first_seg->trbs,
+ .end_trb = &usbssp_data->event_ring->first_seg->trbs[TRBS_PER_SEGMENT - 1],
+ .input_dma = usbssp_data->cmd_ring->first_seg->dma,
+ .result_seg = NULL,
+ },
+ /* Test feeding a valid end TRB from a different ring */
+ { .input_seg = usbssp_data->event_ring->first_seg,
+ .start_trb = usbssp_data->event_ring->first_seg->trbs,
+ .end_trb = &usbssp_data->cmd_ring->first_seg->trbs[TRBS_PER_SEGMENT - 1],
+ .input_dma = usbssp_data->cmd_ring->first_seg->dma,
+ .result_seg = NULL,
+ },
+ /* Test feeding a valid start and end TRB from a different ring */
+ { .input_seg = usbssp_data->event_ring->first_seg,
+ .start_trb = usbssp_data->cmd_ring->first_seg->trbs,
+ .end_trb = &usbssp_data->cmd_ring->first_seg->trbs[TRBS_PER_SEGMENT - 1],
+ .input_dma = usbssp_data->cmd_ring->first_seg->dma,
+ .result_seg = NULL,
+ },
+ /* TRB in this ring, but after this TD */
+ { .input_seg = usbssp_data->event_ring->first_seg,
+ .start_trb = &usbssp_data->event_ring->first_seg->trbs[0],
+ .end_trb = &usbssp_data->event_ring->first_seg->trbs[3],
+ .input_dma = usbssp_data->event_ring->first_seg->dma + 4*16,
+ .result_seg = NULL,
+ },
+ /* TRB in this ring, but before this TD */
+ { .input_seg = usbssp_data->event_ring->first_seg,
+ .start_trb = &usbssp_data->event_ring->first_seg->trbs[3],
+ .end_trb = &usbssp_data->event_ring->first_seg->trbs[6],
+ .input_dma = usbssp_data->event_ring->first_seg->dma + 2*16,
+ .result_seg = NULL,
+ },
+ /* TRB in this ring, but after this wrapped TD */
+ { .input_seg = usbssp_data->event_ring->first_seg,
+ .start_trb = &usbssp_data->event_ring->first_seg->trbs[TRBS_PER_SEGMENT - 3],
+ .end_trb = &usbssp_data->event_ring->first_seg->trbs[1],
+ .input_dma = usbssp_data->event_ring->first_seg->dma + 2*16,
+ .result_seg = NULL,
+ },
+ /* TRB in this ring, but before this wrapped TD */
+ { .input_seg = usbssp_data->event_ring->first_seg,
+ .start_trb = &usbssp_data->event_ring->first_seg->trbs[TRBS_PER_SEGMENT - 3],
+ .end_trb = &usbssp_data->event_ring->first_seg->trbs[1],
+ .input_dma = usbssp_data->event_ring->first_seg->dma + (TRBS_PER_SEGMENT - 4)*16,
+ .result_seg = NULL,
+ },
+ /* TRB not in this ring, and we have a wrapped TD */
+ { .input_seg = usbssp_data->event_ring->first_seg,
+ .start_trb = &usbssp_data->event_ring->first_seg->trbs[TRBS_PER_SEGMENT - 3],
+ .end_trb = &usbssp_data->event_ring->first_seg->trbs[1],
+ .input_dma = usbssp_data->cmd_ring->first_seg->dma + 2*16,
+ .result_seg = NULL,
+ },
+ };
+
+ unsigned int num_tests;
+ int i, ret;
+
+ num_tests = ARRAY_SIZE(simple_test_vector);
+ for (i = 0; i < num_tests; i++) {
+ ret = usbssp_test_trb_in_td(usbssp_data,
+ usbssp_data->event_ring->first_seg,
+ usbssp_data->event_ring->first_seg->trbs,
+ &usbssp_data->event_ring->first_seg->trbs[TRBS_PER_SEGMENT - 1],
+ simple_test_vector[i].input_dma,
+ simple_test_vector[i].result_seg,
+ "Simple", i);
+ if (ret < 0)
+ return ret;
+ }
+
+ num_tests = ARRAY_SIZE(complex_test_vector);
+ for (i = 0; i < num_tests; i++) {
+ ret = usbssp_test_trb_in_td(usbssp_data,
+ complex_test_vector[i].input_seg,
+ complex_test_vector[i].start_trb,
+ complex_test_vector[i].end_trb,
+ complex_test_vector[i].input_dma,
+ complex_test_vector[i].result_seg,
+ "Complex", i);
+ if (ret < 0)
+ return ret;
+ }
+ dev_dbg(usbssp_data->dev, "TRB math tests passed.\n");
+ return 0;
+}
static void usbssp_set_event_deq(struct usbssp_udc *usbssp_data)
{
@@ -1187,6 +1351,10 @@ int usbssp_mem_init(struct usbssp_udc *usbssp_data, gfp_t flags)
if (!usbssp_data->event_ring)
goto fail;
+ /*invoke check procedure for usbssp_trb_in_td function*/
+ if (usbssp_check_trb_in_td_math(usbssp_data) < 0)
+ goto fail;
+
ret = usbssp_alloc_erst(usbssp_data, usbssp_data->event_ring,
&usbssp_data->erst, flags);
if (ret)
diff --git a/drivers/usb/usbssp/gadget-ring.c b/drivers/usb/usbssp/gadget-ring.c
index 7c4b6b7b7b0a..3075909c2e31 100644
--- a/drivers/usb/usbssp/gadget-ring.c
+++ b/drivers/usb/usbssp/gadget-ring.c
@@ -73,3 +73,79 @@ void usbssp_cleanup_command_queue(struct usbssp_udc *usbssp_data)
list_for_each_entry_safe(cur_cmd, tmp_cmd, &usbssp_data->cmd_list, cmd_list)
usbssp_complete_del_and_free_cmd(cur_cmd, COMP_COMMAND_ABORTED);
}
+
+/*
+ * This TD is defined by the TRBs starting at start_trb in start_seg and ending
+ * at end_trb, which may be in another segment. If the suspect DMA address is a
+ * TRB in this TD, this function returns that TRB's segment. Otherwise it
+ * returns 0.
+ */
+struct usbssp_segment *usbssp_trb_in_td(struct usbssp_udc *usbssp_data,
+ struct usbssp_segment *start_seg,
+ union usbssp_trb *start_trb,
+ union usbssp_trb *end_trb,
+ dma_addr_t suspect_dma,
+ bool debug)
+{
+ dma_addr_t start_dma;
+ dma_addr_t end_seg_dma;
+ dma_addr_t end_trb_dma;
+ struct usbssp_segment *cur_seg;
+
+ start_dma = usbssp_trb_virt_to_dma(start_seg, start_trb);
+ cur_seg = start_seg;
+
+ do {
+ if (start_dma == 0)
+ return NULL;
+ /* We may get an event for a Link TRB in the middle of a TD */
+ end_seg_dma = usbssp_trb_virt_to_dma(cur_seg,
+ &cur_seg->trbs[TRBS_PER_SEGMENT - 1]);
+ /* If the end TRB isn't in this segment, this is set to 0 */
+ end_trb_dma = usbssp_trb_virt_to_dma(cur_seg, end_trb);
+
+ if (debug)
+ dev_warn(usbssp_data->dev,
+ "Looking for event-dma %016llx trb-start"
+ "%016llx trb-end %016llx seg-start %016llx"
+ " seg-end %016llx\n",
+ (unsigned long long)suspect_dma,
+ (unsigned long long)start_dma,
+ (unsigned long long)end_trb_dma,
+ (unsigned long long)cur_seg->dma,
+ (unsigned long long)end_seg_dma);
+
+ if (end_trb_dma > 0) {
+ /*
+ * The end TRB is in this segment, so suspect should
+ * be here
+ */
+ if (start_dma <= end_trb_dma) {
+ if (suspect_dma >= start_dma &&
+ suspect_dma <= end_trb_dma)
+ return cur_seg;
+ } else {
+ /*
+ * Case for one segment with a
+ * TD wrapped around to the top
+ */
+ if ((suspect_dma >= start_dma &&
+ suspect_dma <= end_seg_dma) ||
+ (suspect_dma >= cur_seg->dma &&
+ suspect_dma <= end_trb_dma))
+ return cur_seg;
+ }
+ return NULL;
+ } else {
+ /* Might still be somewhere in this segment */
+ if (suspect_dma >= start_dma &&
+ suspect_dma <= end_seg_dma)
+ return cur_seg;
+ }
+
+ cur_seg = cur_seg->next;
+ start_dma = usbssp_trb_virt_to_dma(cur_seg, &cur_seg->trbs[0]);
+ } while (cur_seg != start_seg);
+
+ return NULL;
+}
diff --git a/drivers/usb/usbssp/gadget.h b/drivers/usb/usbssp/gadget.h
index 9dba86a0274a..927c34579899 100644
--- a/drivers/usb/usbssp/gadget.h
+++ b/drivers/usb/usbssp/gadget.h
@@ -1711,6 +1711,11 @@ irqreturn_t usbssp_irq(int irq, void *priv);
/* USBSSP ring, segment, TRB, and TD functions */
dma_addr_t usbssp_trb_virt_to_dma(struct usbssp_segment *seg,
union usbssp_trb *trb);
+struct usbssp_segment *usbssp_trb_in_td(struct usbssp_udc *usbssp_data,
+ struct usbssp_segment *start_seg,
+ union usbssp_trb *start_trb,
+ union usbssp_trb *end_trb,
+ dma_addr_t suspect_dma, bool debug);
void usbssp_handle_command_timeout(struct work_struct *work);
void usbssp_cleanup_command_queue(struct usbssp_udc *usbssp_data);
--
2.17.1
next prev parent reply other threads:[~2018-07-19 18:02 UTC|newest]
Thread overview: 56+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-07-19 17:57 [PATCH 00/31] Introduced new Cadence USBSSP DRD Driver Pawel Laszczak
2018-07-19 17:57 ` [PATCH 01/31] usb: usbssp: Defined register maps and other useful structures Pawel Laszczak
2018-07-19 17:57 ` [PATCH 02/31] usb: usbssp: Added some decoding functions Pawel Laszczak
2018-09-10 18:18 ` Greg Kroah-Hartman
2018-09-11 5:48 ` Felipe Balbi
2018-09-11 8:12 ` Greg Kroah-Hartman
2018-09-11 9:01 ` Pawel Laszczak
2018-07-19 17:57 ` [PATCH 03/31] usb: usbssp: Add trace events used in driver Pawel Laszczak
2018-07-19 17:57 ` [PATCH 04/31] usb: usbssp: Added USBSSP platform driver Pawel Laszczak
2018-08-01 12:24 ` Roger Quadros
2018-08-02 6:25 ` Pawel Laszczak
2018-08-02 13:28 ` Roger Quadros
2018-07-19 17:57 ` [PATCH 05/31] usb: usbssp: Added first part of initialization sequence Pawel Laszczak
2018-08-03 10:17 ` Roger Quadros
2018-08-06 8:57 ` Pawel Laszczak
2018-08-06 10:33 ` Roger Quadros
2018-08-06 12:03 ` Pawel Laszczak
2018-07-19 17:57 ` [PATCH 06/31] usb: usbssp: added template functions used by upper layer Pawel Laszczak
2018-08-03 10:42 ` Roger Quadros
2018-08-04 6:37 ` Pawel Laszczak
2018-08-06 8:57 ` Roger Quadros
2018-08-06 11:40 ` Pawel Laszczak
2018-07-19 17:57 ` [PATCH 07/31] usb: usbssp: Initialization - added usbssp_mem_init Pawel Laszczak
2018-07-19 17:57 ` [PATCH 08/31] usb: usbssp: Added ring and segment handling functions Pawel Laszczak
2018-07-19 17:57 ` [PATCH 09/31] usb: usbssp: add implementation of usbssp_mem_cleanup Pawel Laszczak
2018-07-19 17:57 ` Pawel Laszczak [this message]
2018-07-19 17:57 ` [PATCH 11/31] usb: usbssp: added function for stopping driver Pawel Laszczak
2018-07-19 17:57 ` [PATCH 12/31] usb: usbssp: added functions for queuing commands Pawel Laszczak
2018-07-19 17:57 ` [PATCH 13/31] usb: usbssp: addec procedure for handlin Port Status Change events Pawel Laszczak
2018-07-19 17:57 ` [PATCH 14/31] usb: usbssp: added procedure handling command completion events Pawel Laszczak
2018-07-19 17:57 ` [PATCH 15/31] usb: usbssp: added device controller error, transfer and SETUP completion event Pawel Laszczak
2018-07-19 17:57 ` [PATCH 16/31] usb: usbssp: added connect/disconnect procedures Pawel Laszczak
2018-07-19 17:57 ` [PATCH 17/31] usb: usbssp: added implementation of usbssp_halt_endpoint function Pawel Laszczak
2018-07-19 17:57 ` [PATCH 18/31] usb: usbssp: added handling of Port Reset event Pawel Laszczak
2018-07-19 17:57 ` [PATCH 19/31] usb: usbssp: added support for USB enumeration process Pawel Laszczak
2018-07-19 17:57 ` [PATCH 20/31] usb: usbssp: added queuing procedure for control transfer Pawel Laszczak
2018-07-19 17:57 ` [PATCH 21/31] usb: usbssp: added queuing procedure for BULK and INT transfer Pawel Laszczak
2018-07-19 17:57 ` [PATCH 22/31] usb: usbssp: added procedure removing request from transfer ring Pawel Laszczak
2018-07-19 17:57 ` [PATCH 23/31] usb: usbssp: added implementation of transfer events Pawel Laszczak
2018-07-19 17:57 ` [PATCH 24/31] usb: usbssp: added detecting command timeout Pawel Laszczak
2018-07-19 17:57 ` [PATCH 25/31] usb: usbssp: added implementation of usbssp interface Pawel Laszczak
2018-07-19 17:57 ` [PATCH 26/31] usb: usbssp: added endpoint configuration functionality Pawel Laszczak
2018-07-19 17:58 ` [PATCH 27/31] usb: usbssp: implements usbssp_gadget_ep_enable function Pawel Laszczak
2018-07-19 17:58 ` [PATCH 28/31] usb: usbssp: implemented usbssp_gadget_ep_disable function Pawel Laszczak
2018-07-19 17:58 ` [PATCH 29/31] usb: usbssp: added support for LPM Pawel Laszczak
2018-07-19 17:58 ` [PATCH 30/31] usb: usbssp: added support for TEST_MODE Pawel Laszczak
2018-07-19 17:58 ` [PATCH 31/31] usb: usbssp: add pci to platform driver wrapper Pawel Laszczak
2018-08-01 11:27 ` [PATCH 00/31] Introduced new Cadence USBSSP DRD Driver Roger Quadros
2018-08-02 4:26 ` Pawel Laszczak
2018-08-02 13:24 ` Roger Quadros
2018-09-10 18:21 ` Greg Kroah-Hartman
2018-08-17 21:05 ` Bin Liu
2018-08-21 14:50 ` Pawel Laszczak
2018-09-10 18:20 ` Greg Kroah-Hartman
2018-09-10 18:16 ` Greg Kroah-Hartman
-- strict thread matches above, loose matches on Subject: below --
2018-07-12 5:46 Pawel Laszczak
2018-07-12 5:47 ` [PATCH 10/31] usb: usbssp: added usbssp_trb_in_td function Pawel Laszczak
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1532023084-28083-11-git-send-email-pawell@cadence.com \
--to=pawell@cadence.com \
--cc=adouglas@cadence.com \
--cc=balbi@kernel.org \
--cc=gregkh@linuxfoundation.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-usb@vger.kernel.org \
--cc=ltyrala@cadence.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).