GitLab has been upgraded to 13.3.6. If you encounter any issues mail code@riscosopen.org

Commit 5ae117ef authored by Jeffrey Lee's avatar Jeffrey Lee

Add memory barriers to register reads/writes. Reduce frequency of memory allocations.

Detail:
  s/regaccess - New file containing assembler register access routines, with memory barriers to protect against the BCM2835 AXI bus returning device loads out-of-order
  Makefile, dwc/dwc_common_port/h/dwc_os - Updated to use register access functions instead of inline code
  c/dwc_common_riscos - Added a simple bucket-and-chain data structure to dwc_alloc/dwc_free, to collect free memory blocks and allow them to be reused later, to reduce the load on the heap manager.
Admin:
  Tested in BCM2835 ROM


Version 0.03. Tagged as 'DWCDriver-0_03'
parent fb5f8bf6
......@@ -18,7 +18,7 @@
COMPONENT = DWCDriver
RES_OBJ = msgs
OBJS = cmodule call_veneer triggercbs dwc_common_riscos dwc_otg_riscos softc_root softc_device port
OBJS = cmodule call_veneer triggercbs dwc_common_riscos dwc_otg_riscos softc_root softc_device port regaccess
OBJS_HAL = o_hal.musb o_hal.musb_peri o_hal.musb_root o_hal.musb_usb o_hal.musb_util o_hal.tps o_hal.musb_hal
LIBS = ${CALLXLIB} ${ASMUTILS} ${TBOXLIBS}
CMHGFILE = modhead
......
/* (0.02)
/* (0.03)
*
* This file is automatically maintained by srccommit, do not edit manually.
* Last processed by srccommit version: 1.1.
*
*/
#define Module_MajorVersion_CMHG 0.02
#define Module_MajorVersion_CMHG 0.03
#define Module_MinorVersion_CMHG
#define Module_Date_CMHG 07 Jun 2012
#define Module_Date_CMHG 15 Jun 2012
#define Module_MajorVersion "0.02"
#define Module_Version 2
#define Module_MajorVersion "0.03"
#define Module_Version 3
#define Module_MinorVersion ""
#define Module_Date "07 Jun 2012"
#define Module_Date "15 Jun 2012"
#define Module_ApplicationDate "07-Jun-12"
#define Module_ApplicationDate "15-Jun-12"
#define Module_ComponentName "DWCDriver"
#define Module_ComponentPath "mixed/RiscOS/Sources/HWSupport/USB/Controllers/DWCDriver"
#define Module_FullVersion "0.02"
#define Module_HelpVersion "0.02 (07 Jun 2012)"
#define Module_LibraryVersionInfo "0:2"
#define Module_FullVersion "0.03"
#define Module_HelpVersion "0.03 (15 Jun 2012)"
#define Module_LibraryVersionInfo "0:3"
......@@ -114,12 +114,55 @@ void __DWC_DMA_FREE(uint32_t size, void *virt_addr, dwc_dma_t dma_addr)
_swix(PCI_RAMFree,_IN(0),virt_addr);
}
/* The DWC driver can make memory allocations on quite a regular basis, and
doesn't always seem to cope very well if the allocations fail.
To reduce the load on the heap manager we'll use a simple bucket and chain
system to collect together all the 'free' memory blocks, so that they can
be quickly and easily reused for future transfers. This somewhat mimics
the way the BSD code recycles their xfer structs */
#define MAX_BUCKET_SIZE 1024 /* Maximum block size that will be placed into a bucket */
#define BUCKET_GRANULARITY 32 /* Size that OS_Module rounds RMA allocations to */
struct mem_chain {
union {
struct mem_chain *next; /* Free blocks point at the next block in the chain */
struct mem_chain **bucket; /* Allocated blocks point at the bucket they belong in */
} u;
};
static struct mem_chain *mem_buckets[MAX_BUCKET_SIZE/BUCKET_GRANULARITY];
void *__DWC_ALLOC(uint32_t size)
{
void *p = malloc(size);
if(p)
memset(p,0,size);
return p;
/* Round allocation size to bucket size
We need 8 bytes of overhead: 4 for the 'bucket' ptr in allocated blocks, and 4 bytes for the size field the heap manager's size field
If we were feeling naughty we could peek at the heap manager's size field to work out which bucket an allocated block belongs in, but for now let's do it by the book */
size += (BUCKET_GRANULARITY-1)+8;
size &= ~(BUCKET_GRANULARITY-1);
struct mem_chain **bucket = NULL;
struct mem_chain *block;
if(size < MAX_BUCKET_SIZE)
bucket = &mem_buckets[size/BUCKET_GRANULARITY];
int irqs = ensure_irqs_off();
if(!bucket || !*bucket)
{
restore_irqs(irqs);
block = malloc(size-4); /* Subtract 4 bytes for heap block header */
if(!block)
return NULL;
}
else
{
block = *bucket;
*bucket = block->u.next;
restore_irqs(irqs);
}
block->u.bucket = bucket;
memset(block+1,0,size-8); /* Subtract 8 bytes for heap block header and our header */
return block+1;
}
void *__DWC_ALLOC_ATOMIC(uint32_t size)
......@@ -130,7 +173,20 @@ void *__DWC_ALLOC_ATOMIC(uint32_t size)
void __DWC_FREE(void *addr)
{
free(addr);
if(!addr)
return;
struct mem_chain *block = ((struct mem_chain *) addr)-1;
struct mem_chain **bucket = block->u.bucket;
if(!bucket)
{
free(block);
return;
}
/* Add this block back onto the chain */
int irqs = ensure_irqs_off();
block->u.next = *bucket;
*bucket = block;
restore_irqs(irqs);
}
char *DWC_STRDUP(char const *str)
......@@ -821,6 +877,19 @@ void dwc_common_riscos_shutdown(void)
tasklets.stop = 1;
tasklets.pollword = 1;
_swix(RT_Yield,_IN(1),&tasklets.stopped);
/* Free all memory blocks */
for(int i=0;i<MAX_BUCKET_SIZE/BUCKET_GRANULARITY;i++)
{
struct mem_chain *block = mem_buckets[i];
while(block)
{
struct mem_chain *next = block->u.next;
free(block);
block = next;
}
}
memset(mem_buckets,0,sizeof(mem_buckets)); /* Just in case */
}
dwc_common_init = NO;
}
......@@ -339,6 +339,8 @@ extern uint16_t DWC_BE16_TO_CPU(void *p);
* The reg value is a pointer to the register calculated from the void *base
* variable passed into the driver when it is started. */
#if 0
/** Reads the content of a 32-bit register. */
static inline uint32_t DWC_READ_REG32(uint32_t volatile *reg) { return *reg; }
#define dwc_read_reg32 DWC_READ_REG32
......@@ -358,6 +360,29 @@ static inline void DWC_WRITE_REG64(uint64_t volatile *reg, uint64_t value) { *re
static inline void DWC_MODIFY_REG32(uint32_t volatile *reg, uint32_t clear_mask, uint32_t set_mask) { *reg = ((*reg) & ~clear_mask) | set_mask; }
#define dwc_modify_reg32 DWC_MODIFY_REG32
#else
/** Reads the content of a 32-bit register. */
extern uint32_t DWC_READ_REG32(uint32_t volatile *reg);
#define dwc_read_reg32 DWC_READ_REG32
/** Reads the content of a 64-bit register. */
extern uint64_t DWC_READ_REG64(uint64_t volatile *reg);
#define dwc_read_reg64 DWC_READ_REG64
/** Writes to a 32-bit register. */
extern void DWC_WRITE_REG32(uint32_t volatile *reg, uint32_t value);
#define dwc_write_reg32 DWC_WRITE_REG32
/** Writes to a 64-bit register. */
extern void DWC_WRITE_REG64(uint64_t volatile *reg, uint64_t value);
#define dwc_write_reg64 DWC_WRITE_REG64
/**
* Modify bit values in a register. Using the
* algorithm: (reg_contents & ~clear_mask) | set_mask.
*/
extern void DWC_MODIFY_REG32(uint32_t volatile *reg, uint32_t clear_mask, uint32_t set_mask);
#define dwc_modify_reg32 DWC_MODIFY_REG32
#endif
/** @cond */
/** @name Some convenience MACROS used internally. Define DEBUG_REGS to log the
......
;
; Copyright (c) 2012, RISC OS Open Ltd
; All rights reserved.
;
; Redistribution and use in source and binary forms, with or without
; modification, are permitted provided that the following conditions are met:
; * Redistributions of source code must retain the above copyright
; notice, this list of conditions and the following disclaimer.
; * Redistributions in binary form must reproduce the above copyright
; notice, this list of conditions and the following disclaimer in the
; documentation and/or other materials provided with the distribution.
; * Neither the name of RISC OS Open Ltd nor the names of its contributors
; may be used to endorse or promote products derived from this software
; without specific prior written permission.
;
; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
; IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
; ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
; LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
; CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
; SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
; CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
; ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
; POSSIBILITY OF SUCH DAMAGE.
;
GET Hdr:ListOpts
GET Hdr:CPU.Arch
AREA |C$$code|, CODE, READONLY
EXPORT DWC_READ_REG32
EXPORT DWC_READ_REG64
EXPORT DWC_WRITE_REG32
EXPORT DWC_WRITE_REG64
EXPORT DWC_MODIFY_REG32
MACRO
myDSB
[ NoARMv6
! 1, "Don't know what to do on pre-ARMv6!"
|
[ NoARMv7
; pre-ARMv7, use legacy MCR op
MCR p15,0,a1,c7,c10,4
|
; ARMv7+, use DSB instruction
DSB
]
]
MEND
; uint32_t DWC_READ_REG32(uint32_t volatile *reg)
DWC_READ_REG32
LDR a1, [a1]
myDSB
MOV pc, lr
; uint64_t DWC_READ_REG64(uint64_t volatile *reg)
DWC_READ_REG64
LDMIA a1, {a1-a2}
myDSB
MOV pc, lr
; void DWC_WRITE_REG32(uint32_t volatile *reg, uint32_t value)
DWC_WRITE_REG32
myDSB
STR a2, [a1]
MOV pc, lr
; void DWC_WRITE_REG64(uint64_t volatile *reg, uint64_t value)
DWC_WRITE_REG64
myDSB
STMIA a1, {a2-a3}
MOV pc, lr
; void DWC_MODIFY_REG32(uint32_t volatile *reg, uint32_t clear_mask, uint32_t set_mask)
DWC_MODIFY_REG32
LDR a4, [a1]
myDSB
BIC a4, a4, a2
ORR a4, a4, a3
STR a4, [a1]
MOV pc, lr
END
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