|
@@ -1949,6 +1949,24 @@ static void dwc2_hc_chhltd_intr(struct dwc2_hsotg *hsotg,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * Check if the given qtd is still the top of the list (and thus valid).
|
|
|
+ *
|
|
|
+ * If dwc2_hcd_qtd_unlink_and_free() has been called since we grabbed
|
|
|
+ * the qtd from the top of the list, this will return false (otherwise true).
|
|
|
+ */
|
|
|
+static bool dwc2_check_qtd_still_ok(struct dwc2_qtd *qtd, struct dwc2_qh *qh)
|
|
|
+{
|
|
|
+ struct dwc2_qtd *cur_head;
|
|
|
+
|
|
|
+ if (qh == NULL)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ cur_head = list_first_entry(&qh->qtd_list, struct dwc2_qtd,
|
|
|
+ qtd_list_entry);
|
|
|
+ return (cur_head == qtd);
|
|
|
+}
|
|
|
+
|
|
|
/* Handles interrupt for a specific Host Channel */
|
|
|
static void dwc2_hc_n_intr(struct dwc2_hsotg *hsotg, int chnum)
|
|
|
{
|
|
@@ -2031,27 +2049,59 @@ static void dwc2_hc_n_intr(struct dwc2_hsotg *hsotg, int chnum)
|
|
|
*/
|
|
|
hcint &= ~HCINTMSK_NYET;
|
|
|
}
|
|
|
- if (hcint & HCINTMSK_CHHLTD)
|
|
|
+
|
|
|
+ if (hcint & HCINTMSK_CHHLTD) {
|
|
|
dwc2_hc_chhltd_intr(hsotg, chan, chnum, qtd);
|
|
|
- if (hcint & HCINTMSK_AHBERR)
|
|
|
+ if (!dwc2_check_qtd_still_ok(qtd, chan->qh))
|
|
|
+ goto exit;
|
|
|
+ }
|
|
|
+ if (hcint & HCINTMSK_AHBERR) {
|
|
|
dwc2_hc_ahberr_intr(hsotg, chan, chnum, qtd);
|
|
|
- if (hcint & HCINTMSK_STALL)
|
|
|
+ if (!dwc2_check_qtd_still_ok(qtd, chan->qh))
|
|
|
+ goto exit;
|
|
|
+ }
|
|
|
+ if (hcint & HCINTMSK_STALL) {
|
|
|
dwc2_hc_stall_intr(hsotg, chan, chnum, qtd);
|
|
|
- if (hcint & HCINTMSK_NAK)
|
|
|
+ if (!dwc2_check_qtd_still_ok(qtd, chan->qh))
|
|
|
+ goto exit;
|
|
|
+ }
|
|
|
+ if (hcint & HCINTMSK_NAK) {
|
|
|
dwc2_hc_nak_intr(hsotg, chan, chnum, qtd);
|
|
|
- if (hcint & HCINTMSK_ACK)
|
|
|
+ if (!dwc2_check_qtd_still_ok(qtd, chan->qh))
|
|
|
+ goto exit;
|
|
|
+ }
|
|
|
+ if (hcint & HCINTMSK_ACK) {
|
|
|
dwc2_hc_ack_intr(hsotg, chan, chnum, qtd);
|
|
|
- if (hcint & HCINTMSK_NYET)
|
|
|
+ if (!dwc2_check_qtd_still_ok(qtd, chan->qh))
|
|
|
+ goto exit;
|
|
|
+ }
|
|
|
+ if (hcint & HCINTMSK_NYET) {
|
|
|
dwc2_hc_nyet_intr(hsotg, chan, chnum, qtd);
|
|
|
- if (hcint & HCINTMSK_XACTERR)
|
|
|
+ if (!dwc2_check_qtd_still_ok(qtd, chan->qh))
|
|
|
+ goto exit;
|
|
|
+ }
|
|
|
+ if (hcint & HCINTMSK_XACTERR) {
|
|
|
dwc2_hc_xacterr_intr(hsotg, chan, chnum, qtd);
|
|
|
- if (hcint & HCINTMSK_BBLERR)
|
|
|
+ if (!dwc2_check_qtd_still_ok(qtd, chan->qh))
|
|
|
+ goto exit;
|
|
|
+ }
|
|
|
+ if (hcint & HCINTMSK_BBLERR) {
|
|
|
dwc2_hc_babble_intr(hsotg, chan, chnum, qtd);
|
|
|
- if (hcint & HCINTMSK_FRMOVRUN)
|
|
|
+ if (!dwc2_check_qtd_still_ok(qtd, chan->qh))
|
|
|
+ goto exit;
|
|
|
+ }
|
|
|
+ if (hcint & HCINTMSK_FRMOVRUN) {
|
|
|
dwc2_hc_frmovrun_intr(hsotg, chan, chnum, qtd);
|
|
|
- if (hcint & HCINTMSK_DATATGLERR)
|
|
|
+ if (!dwc2_check_qtd_still_ok(qtd, chan->qh))
|
|
|
+ goto exit;
|
|
|
+ }
|
|
|
+ if (hcint & HCINTMSK_DATATGLERR) {
|
|
|
dwc2_hc_datatglerr_intr(hsotg, chan, chnum, qtd);
|
|
|
+ if (!dwc2_check_qtd_still_ok(qtd, chan->qh))
|
|
|
+ goto exit;
|
|
|
+ }
|
|
|
|
|
|
+exit:
|
|
|
chan->hcint = 0;
|
|
|
}
|
|
|
|