Commit 5204687d authored by Jeffrey Lee's avatar Jeffrey Lee

Update SCSISoftUSB to use RTSupport where possible, for much better USB performance

Detail:
  On initialisation SCSISoftUSB now checks if a suitable version of the RTSupport module is loaded (0.05 or above), and if so, will use RTSupport in preference to TickerV to schedule USB transfers. When combined with tweaked DeviceFS buffer thresholds and some extra code to listen out for buffer filling/emptying upcalls, this allows for significant performance improvements for USB 2.0 devices.
  If at any point RTSupport becomes unavailable or the RT_Register SWI fails (or if a suitable version of RTSupport is not present) the code will (potentially temporarily) fall back to using TickerV to ensure the filesystem remains functional.
Admin:
  Tested on RISC OS 5.15 rev C2 beagleboard & RISC OS 5.12 Iyonix with & without RTSupport 0.05.


Version 0.11. Tagged as 'SCSISoftUSB-0_11'
parent 6b282157
/* (0.10)
/* (0.11)
*
* This file is automatically maintained by srccommit, do not edit manually.
* Last processed by srccommit version: 1.2.
* 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 20 Sep 2005
#define Module_Date_CMHG 22 Oct 2009
#define Module_MajorVersion "0.10"
#define Module_Version 10
#define Module_MajorVersion "0.11"
#define Module_Version 11
#define Module_MinorVersion ""
#define Module_Date "20 Sep 2005"
#define Module_Date "22 Oct 2009"
#define Module_ApplicationDate "20-Sep-05"
#define Module_ApplicationDate "22-Oct-09"
#define Module_ComponentName "SCSISoftUSB"
#define Module_ComponentPath "RiscOS/Sources/HWSupport/SCSI/SCSISoftUSB"
#define Module_ComponentPath "mixed/RiscOS/Sources/HWSupport/SCSI/SCSISoftUSB"
#define Module_FullVersion "0.10"
#define Module_HelpVersion "0.10 (20 Sep 2005)"
#define Module_LibraryVersionInfo "0:10"
#define Module_FullVersion "0.11"
#define Module_HelpVersion "0.11 (22 Oct 2009)"
#define Module_LibraryVersionInfo "0:11"
......@@ -57,6 +57,11 @@ MessagesFD global_MessageFD; /* message file descriptor */
my_usb_device_t *global_DeviceList = NULL; /* list of usb device info */
my_usb_device_t *global_TickerList = NULL; /* list of devices using TickerV */
bool global_UseRTSupport = false; /* Use RTSupport instead of TickerV? */
int global_RTSupportPollword = 0; /* RTSupport pollword */
_kernel_stack_chunk *global_RTSupportStack = 0; /* RTSupport stack chunk */
int global_RTSupportHandle = 0; /* RTSupport handle */
callback_type global_CallbackType = callback_NONE; /* Type of our registered callback, if any */
/*****************************************************************************
* Function prototypes - Private to this file
......
......@@ -39,6 +39,7 @@
#include "Global/RISCOS.h"
#include "Interface/DeviceFS.h"
#include "Interface/SCSIErr.h"
#include "Interface/RTSupport.h"
#include "dev/usb/usb.h"
#include "dev/usb/usbdi.h"
......@@ -55,6 +56,12 @@
* MACROS
*****************************************************************************/
/* Some primitive debugging code to spit out characters via HAL_DebugTX */
#if 0
#define DEBUGCHAR(X) _swix(OS_Hardware,_IN(0)|_INR(8,9),X,0,86)
#else
#define DEBUGCHAR(X)
#endif
/*****************************************************************************
* New type definitions
......@@ -80,6 +87,7 @@ static void *static_BufManWS;
static void Callback(struct umass_softc *softc, void *void_device, int not_transferred, int status);
static void GetOnTickerV(my_usb_device_t *device);
static void GetOffTickerV(my_usb_device_t *device);
static void ProdRTSupport(void);
/*****************************************************************************
......@@ -421,6 +429,11 @@ _kernel_oserror *glue_DoCommand(my_usb_device_t *device, uint32_t lun, uint32_t
/* Do some background transfers */
GetOnTickerV(device);
device->ticker_semaphore = false;
if(global_CallbackType == callback_RTSupport)
{
/* Wake up the RTSupport callback. Even if GetOnTickerV() just registered the callback with RTSupport, this code is still required because the ticker semaphore would have prevented any processing from occuring */
ProdRTSupport();
}
}
if (!irqs_were_off) _kernel_irqs_off();
return NULL;
......@@ -457,9 +470,7 @@ void glue_Tick(my_usb_device_t *device)
DEBUGf("Initial state, status = %x %x ", softc->transfer_state, device->status);
/* Assume interrupts are disabled on entry - */
/* this will be true for TickerV, for any events (we're most likely to use Event_OutputEmpty) */
/* and (as a special case for upcalls) for UpCall_DeviceThresAbove/Below */
/* There may be reentrancy problems with the events and upcalls - defer implementation until this is investigated */
/* this will be true for TickerV and the RTSupport wrapper */
_kernel_oserror *e;
size_t buffer_used;
......@@ -649,10 +660,13 @@ void glue_Tick(my_usb_device_t *device)
device->ticker_semaphore = false;
if (softc->transfer_state == TSTATE_IDLE)
{
DEBUGCHAR('I');
device->command_active = false;
GetOffTickerV(device);
DEBUGCHAR('J');
if (softc->transfer_priv != NULL)
{
DEBUGCHAR('K');
DEBUGf("Calling SCSIdriver from Tick, addr=%x err=%x r0=%x r4=%x r5=%x r12=%x\n", (int)device->callback, (int)device->callback_error, device->callback_status_byte, device->callback_not_transferred, (int)device->callback_pw, (int)device->callback_wp);
asm_DoTransferCompleteCallback(device->callback_error,
device->callback_status_byte,
......@@ -660,6 +674,7 @@ void glue_Tick(my_usb_device_t *device)
device->callback_not_transferred,
device->callback_pw,
device->callback_wp);
DEBUGCHAR('L');
}
}
}
......@@ -701,6 +716,55 @@ void glue_ReopenStream(uint32_t file_handle)
}
}
/*****************************************************************************
* glue_BufferThresholdCheck
*
* Decide whether we should wake up glue_Tick
*
* Assumptions
* NONE
*
* Inputs
* buffer: Buffer handle that's sent a filling/emptying upcall
* filling: True if it's a filling upcall, false if emptying
*
* Outputs
* NONE
*
* Returns
* NOTHING
*****************************************************************************/
void glue_BufferThresholdCheck(uint32_t buffer,bool filling)
{
/* Scan the ticker list and see if we are actively processing this buffer */
bool irqs_were_off = _kernel_irqs_disabled();
if (!irqs_were_off) _kernel_irqs_off();
DEBUGf("glue_BufferThresholdCheck: buffer %08x filling %d\n",buffer,filling);
my_usb_device_t *device = global_TickerList;
while(device)
{
if((device->current_pipe) && (device->current_pipe->buffer_handle == buffer))
{
/* Ignore write pipes that are filling, and read pipes that are emptying */
if(device->current_pipe->write != filling)
{
DEBUGf("Match found: Waking glue_Tick!\n");
// Set RTSupport pollword and exit
global_RTSupportPollword = 1;
}
else
{
DEBUGf("Ignoring upcall; upcall was generated by our own activity\n");
}
break;
}
device = device->next_ticker;
}
if (!irqs_were_off) _kernel_irqs_on();
}
/*****************************************************************************
* Callback
*
......@@ -768,6 +832,62 @@ static void Callback(struct umass_softc *softc, void *void_device, int not_trans
return;
}
/*****************************************************************************
* RTSupportWrapper
*
* Wrapper function that sits between the RTSupport module and
* module_TickerVHandler
*
* Assumptions
* NONE
*
* Inputs
* r0: R0 value from RTSupport. Unused.
*
* Outputs
* NONE
*
* Returns
* Time of next execution. May not return at all if the RTSupport callback is
* no longer needed.
*****************************************************************************/
static __value_in_regs rtsupport_routine_result RTSupportWrapper(void *r0)
{
unsigned int time;
_kernel_oserror *e;
IGNORE(r0);
DEBUGCHAR('>');
/* Make sure IRQs are off. RTSupport will restore the correct state when/if we exit. */
_kernel_irqs_off();
if(global_CallbackType == callback_NONE)
{
/* We haven't returned from RT_Register yet. Avoid lots of nasty issues by just clearing the pollword and exiting. */
DEBUGCHAR('~');
global_RTSupportPollword = 0;
goto exit;
}
DEBUGCHAR('0'+global_RTSupportPollword);
_swix(OS_Hardware,_INR(8,9)|_OUT(0),0,21,&time);
DEBUGf("RTSupportWrapper: pollword %d offset %d\n",global_RTSupportPollword,130000-time);
/* Run TickerVHandler to perform the bulk of our work. */
module_TickerVHandler(0,0);
DEBUGCHAR('<');
/* If RTSupport is active (which it should be!) and we have nothing in the ticker list, deregister ourselves */
if((global_CallbackType == callback_RTSupport) && !global_TickerList)
{
DEBUGCHAR('-');
global_CallbackType = callback_NONE; /* Pre-update since the below call should not return */
e = _swix(RT_Deregister, _INR(0,1),
0,
global_RTSupportHandle);
DEBUGCHAR('#');
}
/* Else get time of next execution */
exit:
_swix(OS_ReadMonotonicTime,_OUT(0),&time);
return (rtsupport_routine_result) { 1<<2, NULL, time+1 };
}
/*****************************************************************************
* GetOnTickerV
*
......@@ -793,12 +913,44 @@ static void GetOnTickerV(my_usb_device_t *device)
if (!irqs_were_off) _kernel_irqs_off();
device->next_ticker = global_TickerList;
global_TickerList = device;
if (device->next_ticker == NULL)
if ((device->next_ticker == NULL) && (global_CallbackType == callback_NONE))
{
_swix(OS_Claim, _INR(0,2),
TickerV,
module_tickerv_handler,
global_PrivateWord);
/* If we're using RTSupport, attempt to register with it
If we fail to register with it (e.g. memory can't be moved when outside the wimp), fallback to TickerV */
if(global_UseRTSupport)
{
DEBUGCHAR('+');
_kernel_oserror *e = _swix(RT_Register,_INR(0,7)|_OUT(0),
0,
RTSupportWrapper,
0,
global_PrivateWord,
&global_RTSupportPollword,
((int)global_RTSupportStack)+560,
((int)global_RTSupportStack)+RTSTACK_SIZE,
"SCSISoftUSB:48",
&global_RTSupportHandle);
if(!e)
{
global_CallbackType = callback_RTSupport;
DEBUGCHAR('+');
}
else
{
DEBUGCHAR('!');
DEBUGf("Error registering with RTSupport: %08x %s\n",e->errnum,e->errmess);
/* Fall through to TickerV callback */
}
}
if(global_CallbackType == callback_NONE)
{
DEBUGCHAR('T');
_swix(OS_Claim, _INR(0,2),
TickerV,
module_tickerv_handler,
global_PrivateWord);
global_CallbackType = callback_TickerV;
}
DEBUGf("\n hello tickerV ");
}
if (!irqs_were_off) _kernel_irqs_on();
......@@ -832,16 +984,22 @@ static void GetOffTickerV(my_usb_device_t *device)
while (ptr != NULL)
{
if (ptr == device)
{
{
if (prev == NULL)
{
if ((global_TickerList = ptr->next_ticker) == NULL)
{
DEBUGf("\n byebye tickerV ");
_swix(OS_Release, _INR(0,2),
TickerV,
module_tickerv_handler,
global_PrivateWord);
if(global_CallbackType == callback_TickerV)
{
DEBUGCHAR('t');
_swix(OS_Release, _INR(0,2),
TickerV,
module_tickerv_handler,
global_PrivateWord);
global_CallbackType = callback_NONE;
}
// Can't deregister with RTSupport here - we may be inside the callback function, in which case RTSupport will kill us before we're able to send the completion callback to the SCSI driver
}
}
else
......@@ -859,6 +1017,59 @@ static void GetOffTickerV(my_usb_device_t *device)
if (!irqs_were_off) _kernel_irqs_on();
}
/*****************************************************************************
* ProdRTSupport
*
* Prods the RTSupport callback - either entering the callback immediately if
* we're in a foreground process, or setting the pollword if we're in an IRQ
* handler (which will cause the routine to be entered after the IRQ), or
* setting the pollword if we're already in the callback (which will cause it
* to be re-entered on exit)
*
* Assumptions
* NONE
*
* Inputs
* NONE
*
* Outputs
* NONE
*
* Returns
* NOTHING
*****************************************************************************/
static void ProdRTSupport(void)
{
global_RTSupportPollword = 1;
DEBUGCHAR('P');
if(global_CallbackType != callback_RTSupport)
return;
int context=0;
_kernel_oserror *e = _swix(RT_ReadInfo,_IN(0)|_OUT(0),0,&context);
if(e)
{
DEBUGCHAR('@');
DEBUGf("RT_ReadInfo: Error %08x %s\n",e->errnum,e->errmess);
return;
}
if(context == 0)
{
bool irqs_were_off = _kernel_irqs_disabled();
if (!irqs_were_off) _kernel_irqs_off();
DEBUGf("ProdRTSupport: Waking callback immediately\n");
context = 1; /* Pollword of 1 to make sure we eventually return here! */
DEBUGCHAR('A');
_swix(RT_Yield,_IN(1),&context);
DEBUGCHAR('B');
if (!irqs_were_off) _kernel_irqs_on();
}
else
{
DEBUGCHAR('C');
DEBUGf("ProdRTSupport: Already in callback or IRQ\n");
}
}
/*****************************************************************************
* usbd_do_request
*
......@@ -958,12 +1169,15 @@ usbd_status usbd_open_pipe(usbd_interface_handle iface, u_int8_t address, u_int8
DeviceCall_ExternalBase + 3, /* return handles */
device->devicefs_name,
device->pipe[flags].handle,
&device->pipe[flags].buffer);
&device->pipe[flags].buffer_handle);
if (!e) e = _swix(Buffer_InternalInfo, _IN(0)|_OUTR(0,2),
device->pipe[flags].buffer,
device->pipe[flags].buffer_handle,
&device->pipe[flags].buffer,
&static_BufManRout,
&static_BufManWS);
/* Set threshold so that we get told when the buffer becomes empty/non-empty */
if (!e) e = _swix(Buffer_Threshold,_INR(0,1),device->pipe[flags].buffer_handle,BUFFER_SIZE-1);
if (e)
{
usbd_close_pipe((usbd_pipe_handle)(device->pipe + flags));
......@@ -1066,6 +1280,13 @@ usbd_status umass_setup_transfer(struct umass_softc *sc, usbd_pipe_handle pipeh,
device->orig_transferlength = buflen+device->current_fill;
device->curr_transferlength = buflen;
device->background_transfer_active = true;
if(pipe->write)
{
/* Prod the RTSupport callback so it wakes up and performs the write immediately */
ProdRTSupport();
}
return USBD_NORMAL_COMPLETION;
}
......
......@@ -44,6 +44,7 @@
#include "Global/Services.h"
#include "Global/RISCOS.h"
#include "Interface/SCSIErr.h"
#include "Interface/RTSupport.h"
#include "DebugLib/DebugLib.h"
#include "USB/USBDevFS.h"
......@@ -136,8 +137,8 @@ _kernel_oserror *module_Init(const char *cmd_tail, int podule_base, void *pw)
// debug_set_area_level_prefix(true);
// debug_set_area_pad_limit(0);
debug_set_unbuffered_files (TRUE);
debug_set_stamp_debug (TRUE);
debug_set_device( DEBUGIT_OUTPUT);
// debug_set_stamp_debug (TRUE);
debug_set_device( DADEBUG_OUTPUT);
// debug_set_device( PRINTF_OUTPUT);
// debug_set_raw_device( DEBUGIT_OUTPUT);
// debug_set_trace_device(DEBUGIT_OUTPUT);
......@@ -189,6 +190,49 @@ _kernel_oserror *module_Init(const char *cmd_tail, int podule_base, void *pw)
if (!e)
{
CallbackSet = true;
/* Detection of RTSupport module
We require at least version 0.05, because previous versions had some rather nasty bugs that are too much hassle to work around for the benefit of the two people who have old versions of RTSupport on their machine and are unable to upgrade to newer versions */
char **mod_code;
if(!_swix(OS_Module,_INR(0,1) | _OUT(3),18,"RTSupport",&mod_code))
{
/* Find and decode version number, similar to RMEnsure.
We really need a SWI for this! */
char *help_str = mod_code[5]+(uint32_t)mod_code;
while(*help_str && !isdigit(*help_str))
help_str++;
int version=0;
while(isdigit(*help_str))
{
version = (version<<4) | (*help_str-'0');
help_str++;
}
int zeros=4;
if(*help_str == '.')
{
help_str++;
while(isdigit(*help_str) && zeros)
{
version = (version<<4) | (*help_str-'0');
help_str++;
zeros--;
}
}
version = version<<(zeros*4);
if(version >= 0x0500)
{
global_RTSupportStack = calloc(1, RTSTACK_SIZE);
if(global_RTSupportStack)
{
global_UseRTSupport = true;
global_RTSupportStack->sc_mark = 0xF60690FF;
global_RTSupportStack->sc_size = RTSTACK_SIZE;
memcpy(global_RTSupportStack+1,_kernel_current_stack_chunk()+1,28);
}
}
}
if(!global_UseRTSupport)
global_RTSupportPollword = 1; /* Force pollword nonzero so we avoid pointless calls to glue_BufferThreshouldCheck */
}
if (e && CallbackSet) _swix(OS_RemoveCallBack, _INR(0,1),
......@@ -275,10 +319,17 @@ _kernel_oserror *module_Final(int fatal, int podule, void *pw)
module_callback_from_init,
global_PrivateWord);
global_TickerList=NULL;
_swix(OS_Release, _INR(0,2),
TickerV,
module_tickerv_handler,
global_PrivateWord);
if(global_CallbackType == callback_TickerV)
_swix(OS_Release, _INR(0,2),
TickerV,
module_tickerv_handler,
global_PrivateWord);
else if(global_CallbackType == callback_RTSupport)
_swix(RT_Deregister, _INR(0,1),
0,
global_RTSupportHandle);
if(global_RTSupportStack)
free(global_RTSupportStack);
_swix(OS_Release, _INR(0,2),
UpCallV,
module_upcallv_handler,
......@@ -915,7 +966,7 @@ _kernel_oserror *module_SCSIHandler(_kernel_swi_regs *r, void *pw)
/*****************************************************************************
* module_TickerVHandler
*
* TickerV handler and callback processor
* TickerV/RTSupport handler and callback processor
*
* Assumptions
* NONE
......@@ -935,9 +986,12 @@ _kernel_oserror *module_TickerVHandler(_kernel_swi_regs *r, void *pw)
IGNORE(r);
IGNORE(pw);
static bool semaphore = false;
if (semaphore) return NULL;
if (semaphore)
return NULL;
semaphore = true;
my_usb_device_t *device = global_TickerList;
if(global_CallbackType == callback_RTSupport) /* If we're using TickerV, the RTSupport pollword is kept at 1 so we skip calling glue_BufferThresholdCheck */
global_RTSupportPollword = 0;
while (device != NULL)
{
my_usb_device_t *next = device->next_ticker; /* read now in case it delinks itself */
......@@ -968,6 +1022,7 @@ _kernel_oserror *module_TickerVHandler(_kernel_swi_regs *r, void *pw)
_kernel_oserror *module_UpCallVHandler(_kernel_swi_regs *r, void *pw)
{
IGNORE(pw);
if (((r->r[0] == 8) || (r->r[0] == 9) /* Buffer filling/emptying */ ) && global_TickerList && !global_RTSupportPollword) glue_BufferThresholdCheck(r->r[1],r->r[0]==8);
if (r->r[0] == 11 /* stream closed */) glue_ReopenStream(r->r[3]);
return NULL;
}
......
......@@ -72,6 +72,7 @@
}
#endif
#define RTSTACK_SIZE 2048
/*****************************************************************************
* New type definitions
......@@ -87,6 +88,7 @@ typedef struct
{
uint32_t handle; /* FileSwitch handle */
uint32_t buffer; /* BufferManager internal buffer ID */
uint32_t buffer_handle; /* Buffer handle, as used by the upcalls */
uint32_t devicedriverstreamhandle;
bool write; /* direction */
struct my_usb_device *device; /* for getting back to device handle */
......@@ -149,6 +151,12 @@ typedef struct my_usb_device
}
my_usb_device_t;
typedef struct
{
uint32_t flags;
uint32_t *pollword;
uint32_t timeout;
} rtsupport_routine_result;
/*****************************************************************************
* Constants
......@@ -160,6 +168,13 @@ enum
data_WRITE = 2 << 24 /* by the BSD code (except for the shift). */
};
typedef enum
{
callback_NONE,
callback_TickerV,
callback_RTSupport
} callback_type;
/*****************************************************************************
* Global variables
......@@ -167,7 +182,12 @@ enum
extern void *global_PrivateWord; /* so we don't have to worry about passing pw around */
extern MessagesFD global_MessageFD; /* message file descriptor */
extern my_usb_device_t *global_DeviceList; /* list of usb device info */
extern my_usb_device_t *global_TickerList; /* list of devices using TickerV */
extern my_usb_device_t *global_TickerList; /* list of devices using TickerV/RTSupport */
extern bool global_UseRTSupport; /* Use RTSupport module for scheduling, not TickerV */
extern int global_RTSupportPollword; /* RTSupport pollword */
extern _kernel_stack_chunk *global_RTSupportStack; /* RTSupport stack chunk */
extern int global_RTSupportHandle; /* RTSupport handle */
extern callback_type global_CallbackType; /* Type of our registered callback, if any */
#ifdef UMASS_DEBUG
extern char *states[];
#endif
......
......@@ -189,6 +189,26 @@ extern void glue_Tick(my_usb_device_t *device);
*****************************************************************************/
extern void glue_ReopenStream(uint32_t file_handle);
/*****************************************************************************
* glue_BufferThresholdCheck
*
* Decide whether we should wake up glue_Tick
*
* Assumptions
* NONE
*
* Inputs
* buffer: Buffer handle that's sent a filling/emptying upcall
* filling: True if it's a filling upcall, false if emptying
*
* Outputs
* NONE
*
* Returns
* NOTHING
*****************************************************************************/
extern void glue_BufferThresholdCheck(uint32_t buffer,bool filling);
#endif /* end of sentry #ifdef */
/*****************************************************************************
......
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