Commit cda26511 authored by Robert Sprowson's avatar Robert Sprowson

Fix for stall clear stalling when called from umass

Since SCSISoftUSB relies on devices stalling (rather than doing a test unit ready), stalls occur when a card reader with no card present is queried.
The port of umass ends up trying to add something to the control transfer queue, but enters with interrupts disabled, so the clear endpoint stall just times out having not done anything (other callers have interrupts enabled so do clear the stall).
Apply change of policy that NetBSD made in revision 1.28.2.19 where the clear endpoint stall is cleared asynchronously rather than being left around until the next transfer is queued.
Since we don't have threads on RISC OS, and callbacks wouldn't happen either, we schedule a one shot RTSupport to trigger the clear at CBAI level.
Apply change from NetBSD 1.28.2.37 to remove the old clear code too.

Version 0.11. Tagged as 'XHCIDriver-0_11'
parent 50d41438
/* (0.10)
/* (0.11)
*
* This file is automatically maintained by srccommit, do not edit manually.
* Last processed by srccommit version: 1.1.
*
*/
#define Module_MajorVersion_CMHG 0.10
#define Module_MajorVersion_CMHG 0.11
#define Module_MinorVersion_CMHG
#define Module_Date_CMHG 06 Dec 2015
#define Module_Date_CMHG 25 Mar 2016
#define Module_MajorVersion "0.10"
#define Module_Version 10
#define Module_MajorVersion "0.11"
#define Module_Version 11
#define Module_MinorVersion ""
#define Module_Date "06 Dec 2015"
#define Module_Date "25 Mar 2016"
#define Module_ApplicationDate "06-Dec-15"
#define Module_ApplicationDate "25-Mar-16"
#define Module_ComponentName "XHCIDriver"
#define Module_ComponentPath "mixed/RiscOS/Sources/HWSupport/USB/Controllers/XHCIDriver"
#define Module_FullVersion "0.10"
#define Module_HelpVersion "0.10 (06 Dec 2015)"
#define Module_LibraryVersionInfo "0:10"
#define Module_FullVersion "0.11"
#define Module_HelpVersion "0.11 (25 Mar 2016)"
#define Module_LibraryVersionInfo "0:11"
......@@ -32,6 +32,7 @@
#include "Global/OSRSI6.h"
#include "Global/HALEntries.h"
#include "Interface/USBDriver.h"
#include "Interface/RTSupport.h"
#include "AsmUtils/clz.h"
#include "AsmUtils/callbacks.h"
......@@ -259,10 +260,38 @@ static _kernel_oserror *glue_abort_pipe_callback(_kernel_swi_regs *r, void *pw,
void glue_abort_pipe(void (*fn)(void *), void *xfer)
{
//TODO! Could rationalise this to use RTSupport too?
abort_pipe_fn = fn;
callx_add_callback(glue_abort_pipe_callback, xfer);
}
void glue_clear_endpoint_stall(struct usb_task *task, void (*fun)(void *), void *arg)
{
extern void *g_pw;
static const int pollword = 1;
/* Schedule the task at callback after interrupt level */
task->fun = fun;
task->arg = arg;
_swix(RT_Register, _INR(0,7)|_OUT(0),
0, /* Flags */
glue_rt_entry, *((uint32_t **)g_pw)+1, task, &pollword, NULL, NULL,
"XHCIClearStall:50",
(int *)&task->next /* Repurpose TAILQ for keeping a handle */);
}
int glue_rt_handler(void *arg)
{
const struct usb_task *task = arg;
task->fun(task->arg);
/* Task returned, kill it */
_swix(RT_Deregister, _INR(0,1), 0, *(int *)&task->next);
return 0;
}
/*
* Semaphores
*/
......
......@@ -132,6 +132,9 @@ fail:
struct xhci_pipe {
struct usbd_pipe xp_pipe;
#ifdef BRANCH_NHUSB
struct usb_task xp_async_task;
#endif
};
#define XHCI_INTR_ENDPT 1
......@@ -1332,6 +1335,62 @@ xhci_open(usbd_pipe_handle pipe)
return USBD_NORMAL_COMPLETION;
}
#ifdef BRANCH_NHUSB
/*
* Recover STALLed endpoint.
* xHCI 1.1 sect 4.10.2.1
* Issue RESET_EP to recover halt condition and SET_TR_DEQUEUE to remove
* all transfers on transfer ring.
* These are done in thread context asynchronously.
*/
static void
xhci_clear_endpoint_stall_async_task(void *cookie)
{
struct usbd_xfer * const xfer = (void *)cookie;
struct xhci_softc * const sc = xfer->pipe->device->bus->hci_private;
struct xhci_slot * const xs = xfer->pipe->device->hci_private;
const u_int dci = xhci_ep_get_dci(xfer->pipe->endpoint->edesc);
struct xhci_ring * const tr = &xs->xs_ep[dci].xe_tr;
XHCIHIST_FUNC(); XHCIHIST_CALLED();
DPRINTFN(4, "xfer %p slot %u dci %u", xfer, xs->xs_idx, dci, 0);
xhci_reset_endpoint(xfer->pipe);
xhci_set_dequeue(xfer->pipe);
mutex_enter(&sc->sc_lock);
tr->is_halted = false;
usb_transfer_complete(xfer);
mutex_exit(&sc->sc_lock);
DPRINTFN(4, "ends", 0, 0, 0, 0);
}
static usbd_status
xhci_clear_endpoint_stall_async(struct usbd_xfer *xfer)
{
struct xhci_softc * const sc = xfer->pipe->device->bus->hci_private;
struct xhci_pipe * const xp = (struct xhci_pipe *)xfer->pipe;
XHCIHIST_FUNC(); XHCIHIST_CALLED();
DPRINTFN(4, "xfer %p", xfer, 0, 0, 0);
if (sc->sc_dying) {
return USBD_IOERROR;
}
#ifdef RISCOS
glue_clear_endpoint_stall(&xp->xp_async_task, xhci_clear_endpoint_stall_async_task, xfer);
#else
usb_init_task(&xp->xp_async_task,
xhci_clear_endpoint_stall_async_task, xfer, USB_TASKQ_MPSAFE);
usb_add_task(xfer->pipe->dev, &xp->xp_async_task, USB_TASKQ_HC);
DPRINTFN(4, "ends", 0, 0, 0, 0);
#endif
return USBD_NORMAL_COMPLETION;
}
#endif
static void
xhci_rhpsc(struct xhci_softc * const sc, u_int port)
{
......@@ -1469,6 +1528,24 @@ xhci_handle_event(struct xhci_softc * const sc,
xr->is_halted = true;
DPRINTFN(1, "ev: xfer done: err %u slot %u dci %u",
XHCI_TRB_2_ERROR_GET(trb_2), slot, dci, 0);
#ifdef BRANCH_NHUSB
/*
* Stalled endpoints can be recoverd by issuing
* command TRB TYPE_RESET_EP on xHCI instead of
* issuing request CLEAR_FEATURE UF_ENDPOINT_HALT
* on the endpoint. However, this function may be
* called from softint context (e.g. from umass),
* in that case driver gets KASSERT in cv_timedwait
* in xhci_do_command.
* To avoid this, this runs reset_endpoint and
* usb_transfer_complete in usb task thread
* asynchronously (and then umass issues clear
* UF_ENDPOINT_HALT).
*/
xfer->status=err;
xhci_clear_endpoint_stall_async(xfer);
return;
#endif
} else {
err = USBD_IOERROR;
}
......@@ -3101,12 +3178,14 @@ xhci_device_ctrl_start(usbd_xfer_handle xfer)
req->bmRequestType | (req->bRequest << 8), UGETW(req->wValue),
UGETW(req->wIndex), UGETW(req->wLength));
#ifndef BRANCH_NHUSB /* event handler does this */
/* XXX */
if (tr->is_halted) {
xhci_reset_endpoint(xfer->pipe);
tr->is_halted = false;
xhci_set_dequeue(xfer->pipe);
}
#endif
/* we rely on the bottom bits for extra info */
KASSERT(((uintptr_t)xfer & 0x3) == 0x0);
......
......@@ -77,7 +77,10 @@ void cv_init(kcondvar_t *, const char *);
void cv_signal(kcondvar_t *);
int cv_timedwait(kcondvar_t *, kmutex_t *, int);
/* Timeout abort pipe */
/* Abort pipe and clear stall tasks */
void glue_clear_endpoint_stall(struct usb_task *, void (*fn)(void *), void *xfer);
int glue_rt_entry(void *);
int glue_rt_handler(void *);
void glue_abort_pipe(void (*fn)(void *), void *xfer);
/* Little helpers */
......
......@@ -21,8 +21,33 @@
AREA |C$$code|, CODE, READONLY
EXPORT veneer_init
EXPORT glue_rt_entry
IMPORT glue_rt_handler
IMPORT memcpy
; int glue_rt_entry(void *);
;
; Veneer to get back the C module environment from an RTSupport thread
; and return back to RTSupport when done. Named as entry/handler in
; the same way CMHG does.
glue_rt_entry
; copy relocation offsets (library/client) to base of SVC stack
LDMIA a1, {a1,a2}
MSR CPSR_c, #SVC32_mode
MOV sl, sp, LSR #20
MOV sl, sl, LSL #20
STMIA sl, {a1,a2}
; jump into C in SVC mode, IRQs enabled
; SL at relocation offsets, FP=0, R0=arg
ADD sl, sl, #540
MOV a1, ip
BL glue_rt_handler
; back to RTSupport in SYS mode, R0=flags
MSR CPSR_c, #SYS32_mode
MOV pc, lr
; int *veneer_init(void);
;
; Copies a little veneer to the RMA, much like the ones CMHG produces
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment