summaryrefslogtreecommitdiff
path: root/firmware/src/os
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2014-11-11 22:31:27 +0100
committerHarald Welte <laforge@gnumonks.org>2014-11-11 22:31:27 +0100
commit5a40e2fed18ed75c7b8d62f52cf4a7c660a8e026 (patch)
treebce986dd5ab366dd141456f842c887868b73db7a /firmware/src/os
parent3c85f8de8d394eaea5ed7f6e2675201d079e227b (diff)
parentb6caca4b64a73d8d3ab4ce6b51cea71b8f1a54b0 (diff)
Merge branch 'minxu-fixes'
Diffstat (limited to 'firmware/src/os')
-rw-r--r--firmware/src/os/dbgu.c309
-rw-r--r--firmware/src/os/dbgu.h7
-rw-r--r--firmware/src/os/main.c1
-rw-r--r--firmware/src/os/pcd_enumerate.c75
-rw-r--r--firmware/src/os/req_ctx.c164
-rw-r--r--firmware/src/os/req_ctx.h46
-rw-r--r--firmware/src/os/system_irq.c18
-rw-r--r--firmware/src/os/usbcmd_generic.c2
-rw-r--r--firmware/src/os/wdt.c4
9 files changed, 414 insertions, 212 deletions
diff --git a/firmware/src/os/dbgu.c b/firmware/src/os/dbgu.c
index 113208e..72eaa88 100644
--- a/firmware/src/os/dbgu.c
+++ b/firmware/src/os/dbgu.c
@@ -45,18 +45,17 @@
#include <asm/system.h>
#include <compile.h>
-//#define DEBUG_UNBUFFERED
+/* In case we find that while (); is non interruptible, we may need to
+ * uncommend this line: */
+// #define ALLOW_INTERRUPT_LOOP asm("nop;nop;nop;nop;nop;nop;nop;nop;")
+
+#define ALLOW_INTERRUPT_LOOP
+
+/* DEBUG_BUFFER_SIZE MUST BE A POWER OF 2 */
+#define DEBUG_BUFFER_SIZE (1 << 10)
+#define DEBUG_BUFFER_MASK (DEBUG_BUFFER_SIZE - 1)
-#define USART_SYS_LEVEL 4
/*---------------------------- Global Variable ------------------------------*/
-//*--------------------------1--------------------------------------------------
-//* \fn AT91F_DBGU_Printk
-//* \brief This function is used to send a string through the DBGU channel
-//*----------------------------------------------------------------------------
-void AT91F_DBGU_Ready(void)
-{
- while (!(AT91C_BASE_DBGU->DBGU_CSR & AT91C_US_TXEMPTY)) ;
-}
//*----------------------------------------------------------------------------
//* Function Name : Send_reset
@@ -69,7 +68,7 @@ static void Send_reset(void)
// Acknoledge the interrupt
// Mark the End of Interrupt on the AIC
AT91C_BASE_AIC->AIC_EOICR = 0;
- AT91F_DBGU_Ready();
+ while (!(AT91C_BASE_DBGU->DBGU_CSR & AT91C_US_TXEMPTY)) ;
// Jump in reset
pfct();
}
@@ -92,26 +91,26 @@ static void DBGU_irq_handler(u_int32_t sr)
break;
case '1': //* info
udp_pullup_off();
- AT91F_DBGU_Printk("Set Pull up\n\r");
+ AT91F_DBGU_Frame("Set Pull up\n\r");
// Reset Application
Send_reset();
break;
case '2':
- AT91F_DBGU_Printk("Toggling LED 1\n\r");
+ AT91F_DBGU_Frame("Toggling LED 1\n\r");
led_toggle(1);
break;
case '3':
- AT91F_DBGU_Printk("Toggling LED 2\n\r");
+ AT91F_DBGU_Frame("Toggling LED 2\n\r");
led_toggle(2);
break;
case '9':
- AT91F_DBGU_Printk("Resetting SAM7\n\r");
+ AT91F_DBGU_Frame("Resetting SAM7\n\r");
AT91F_RSTSoftReset(AT91C_BASE_RSTC, AT91C_RSTC_PROCRST|
AT91C_RSTC_PERRST|AT91C_RSTC_EXTRST);
break;
default:
if (_main_dbgu(value) < 0)
- AT91F_DBGU_Printk("\n\r");
+ AT91F_DBGU_Frame("\n\r");
break;
} // end switch
}
@@ -148,17 +147,17 @@ void AT91F_DBGU_Init(void)
//* open interrupt
sysirq_register(AT91SAM7_SYSIRQ_DBGU, &DBGU_irq_handler);
- AT91F_DBGU_Printk("\n\r");
- AT91F_DBGU_Printk("(C) 2006-2011 by Harald Welte <hwelte@hmw-consulting.de>\n\r"
+ debugp("\n\r");
+ debugp("(C) 2006-2011 by Harald Welte <hwelte@hmw-consulting.de>\n\r"
"This software is FREE SOFTWARE licensed under GNU GPL\n\r");
- AT91F_DBGU_Printk("Version " COMPILE_SVNREV
+ debugp("Version " COMPILE_SVNREV
" compiled " COMPILE_DATE
" by " COMPILE_BY "\n\r\n\r");
- AT91F_DBGU_Printk("\n\rDEBUG Interface:\n\r"
+ debugp("\n\rDEBUG Interface:\n\r"
"0) Set Pull-up 1) Clear Pull-up 2) Toggle LED1 3) "
"Toggle LED2\r\n9) Reset\n\r");
- debugp("RSTC_SR=0x%08x\n", rst_status);
+ debugp("RSTC_SR=0x%08x\n\r", rst_status);
}
/*
@@ -173,31 +172,36 @@ void AT91F_DBGU_Fini(void)
}
//*----------------------------------------------------------------------------
-//* \fn AT91F_DBGU_Printk
-//* \brief This function is used to send a string through the DBGU channel (Very low level debugging)
-//*----------------------------------------------------------------------------
-void AT91F_DBGU_Printk(char *buffer)
-{
- while (*buffer != '\0') {
- while (!AT91F_US_TxReady((AT91PS_USART) AT91C_BASE_DBGU)) ;
- AT91F_US_PutChar((AT91PS_USART) AT91C_BASE_DBGU, *buffer++);
- }
-}
-
-//*----------------------------------------------------------------------------
//* \fn AT91F_DBGU_Frame
-//* \brief This function is used to send a string through the DBGU channel
+//* \brief This function is used to send a string through the DBGU channel (Very low level debugging)
//*----------------------------------------------------------------------------
void AT91F_DBGU_Frame(char *buffer)
{
- unsigned char len;
-
- for (len = 0; buffer[len] != '\0'; len++) {
+ unsigned long intcFlags;
+ unsigned int len = 0;
+ while (buffer[len++]) ALLOW_INTERRUPT_LOOP;
+ len--;
+ local_irq_save(intcFlags);
+ AT91C_BASE_DBGU->DBGU_PTCR = 1 << 9; // Disable transfer
+ if (AT91C_BASE_DBGU->DBGU_TNCR) {
+ AT91C_BASE_DBGU->DBGU_PTCR = 1 << 8; // Resume transfer
+ local_irq_restore(intcFlags);
+ while ((AT91C_BASE_DBGU->DBGU_CSR & AT91C_US_TXBUFE) == 0) ALLOW_INTERRUPT_LOOP;
+ local_irq_save(intcFlags);
+ AT91C_BASE_DBGU->DBGU_PTCR = 1 << 9; // Disable transfer
+ AT91C_BASE_DBGU->DBGU_TPR = (unsigned)buffer;
+ AT91C_BASE_DBGU->DBGU_TCR = len;
+ } else if (AT91C_BASE_DBGU->DBGU_TCR) {
+ AT91C_BASE_DBGU->DBGU_TNPR = (unsigned)buffer;
+ AT91C_BASE_DBGU->DBGU_TNCR = len;
+ } else {
+ AT91C_BASE_DBGU->DBGU_TPR = (unsigned)buffer;
+ AT91C_BASE_DBGU->DBGU_TCR = len;
}
-
- AT91F_US_SendFrame((AT91PS_USART) AT91C_BASE_DBGU,
- (unsigned char *)buffer, len, 0, 0);
-
+ AT91C_BASE_DBGU->DBGU_PTCR = 1 << 8; // Resume transfer
+ local_irq_restore(intcFlags);
+ /* Return ONLY after we complete Transfer */
+ while ((AT91C_BASE_DBGU->DBGU_CSR & AT91C_US_TXBUFE) == 0) ALLOW_INTERRUPT_LOOP;
}
//*----------------------------------------------------------------------------
@@ -239,105 +243,180 @@ hexdump(const void *data, unsigned int len)
}
struct dbgu {
- char buf[4096];
- char *next_inbyte;
- char *next_outbyte;
+ char buf[DEBUG_BUFFER_SIZE];
+ /* Since debugp appears to require to be re-entrant, we need a
+ * bit more state variables
+ * in_head Position where incoming *append* characters have
+ * finished copy to buffer
+ * in_tail Position where NEW incoming *append* characters
+ * should COPY to
+ * out_head Position where the LAST *possibly incomplete*
+ * dbgu_rb_flush started from
+ * out_tail Position where the NEXT dbug_rb_flush should
+ * start from
+ * The position in the RING should be in this order:
+ * --> out_tail --> in_head --> in_tail --> out_head -->
+ */
+ volatile unsigned int in_head, in_tail, out_head, out_tail;
+
+ /* flush_stack is to indicate rb_flush is being executed, NOT to
+ * execute again */
+ volatile unsigned int flush_stack;
+
+ /* append_stack is to indicate the re-entrack stack order of the
+ * current dbgu_append call */
+ volatile unsigned int append_stack;
};
+
static struct dbgu dbgu;
void dbgu_rb_init(void)
{
- memset(dbgu.buf, 0, sizeof(dbgu.buf));
- dbgu.next_inbyte = &dbgu.buf[0];
- dbgu.next_outbyte = &dbgu.buf[0];
-}
-
-/* pull one char out of debug ring buffer */
-static int dbgu_rb_pull(char *ret)
-{
- unsigned long flags;
-
- local_irq_save(flags);
-
- if (dbgu.next_outbyte == dbgu.next_inbyte) {
- local_irq_restore(flags);
- return -1;
- }
-
- *ret = *dbgu.next_outbyte;
-
- dbgu.next_outbyte++;
- if (dbgu.next_outbyte == &dbgu.buf[0]+sizeof(dbgu.buf)) {
- //AT91F_DBGU_Printk("WRAP DURING PULL\r\n");
- dbgu.next_outbyte = &dbgu.buf[0];
- } else if (dbgu.next_outbyte > &dbgu.buf[0]+sizeof(dbgu.buf)) {
- //AT91F_DBGU_Printk("OUTBYTE > END_OF_BUF!!\r\n");
- dbgu.next_outbyte -= sizeof(dbgu.buf);
- }
-
- local_irq_restore(flags);
-
- return 0;
-}
-
-static void __rb_flush(void)
-{
- char ch;
- while (dbgu_rb_pull(&ch) >= 0) {
- while (!AT91F_US_TxReady((AT91PS_USART) AT91C_BASE_DBGU)) ;
- AT91F_US_PutChar((AT91PS_USART) AT91C_BASE_DBGU, ch);
- }
+ dbgu.in_head = dbgu.in_tail = dbgu.out_head = dbgu.out_tail = 0;
+ dbgu.flush_stack = dbgu.append_stack = 0;
}
/* flush pending data from debug ring buffer to serial port */
-void dbgu_rb_flush(void)
-{
- __rb_flush();
-}
-static void __dbgu_rb_append(char *data, int len)
+static void dbgu_rb_flush(void)
{
- char *pos = dbgu.next_inbyte;
-
- dbgu.next_inbyte += len;
- if (dbgu.next_inbyte >= &dbgu.buf[0]+sizeof(dbgu.buf)) {
- AT91F_DBGU_Printk("WRAP DURING APPEND\r\n");
- dbgu.next_inbyte -= sizeof(dbgu.buf);
+ unsigned long intcFlags;
+ unsigned int flush_stack, start, len;
+ if (dbgu.in_head == dbgu.out_tail)
+ return;
+
+ /* Transmit can ONLY be disabled when Interrupt is disabled. We
+ * don't want to be interrupted while Transmit is disabled. */
+ local_irq_save(intcFlags);
+ flush_stack = dbgu.flush_stack;
+ dbgu.flush_stack = 1;
+ if (flush_stack) {
+ local_irq_restore(intcFlags);
+ return;
}
-
- memcpy(pos, data, len);
+ AT91C_BASE_DBGU->DBGU_PTCR = 1 << 9; // Disable transfer
+ start = (unsigned)dbgu.buf + dbgu.out_tail;
+ len = (dbgu.in_head - dbgu.out_tail) & DEBUG_BUFFER_MASK;
+ if (dbgu.in_head > dbgu.out_tail || dbgu.in_head == 0) { // Just 1 fragmentf
+ if (AT91C_BASE_DBGU->DBGU_TNCR) {
+ if (AT91C_BASE_DBGU->DBGU_TNPR + AT91C_BASE_DBGU->DBGU_TNCR == start) {
+ AT91C_BASE_DBGU->DBGU_TNCR += len;
+ } else {
+ AT91C_BASE_DBGU->DBGU_PTCR = 1 << 8; // Resume transfer
+ local_irq_restore(intcFlags);
+ while ((AT91C_BASE_DBGU->DBGU_CSR & AT91C_US_TXBUFE) == 0) ALLOW_INTERRUPT_LOOP;
+ dbgu.out_head = dbgu.out_tail; // in case we are interrupted, they may need more space
+ /* Since the ONLY place where Transmit is started is dbgu_rb_flush and AT91F_DBGU_Frame and:
+ * 1) AT91F_DBGU_Frame always leave the dbgu in a TX completed state
+ * 2) dbgu_rb is non-reentrant by safeguard at the beginning of this routing
+ * We can assume that after this INTERRUPTIBLE while loop, there are NO data to be transmitted
+ */
+ local_irq_save(intcFlags);
+ AT91C_BASE_DBGU->DBGU_PTCR = 1 << 9; // Disable transfer
+ AT91C_BASE_DBGU->DBGU_TPR = start;
+ AT91C_BASE_DBGU->DBGU_TCR = len;
+ }
+ } else if (AT91C_BASE_DBGU->DBGU_TCR) {
+ if (AT91C_BASE_DBGU->DBGU_TPR + AT91C_BASE_DBGU->DBGU_TCR == start) {
+ dbgu.out_head = AT91C_BASE_DBGU->DBGU_TPR - (unsigned)dbgu.buf;
+ AT91C_BASE_DBGU->DBGU_TCR += len;
+ } else {
+ AT91C_BASE_DBGU->DBGU_TNPR = start;
+ AT91C_BASE_DBGU->DBGU_TNCR = len;
+ }
+ } else {
+ AT91C_BASE_DBGU->DBGU_TPR = start;
+ AT91C_BASE_DBGU->DBGU_TCR = len;
+ dbgu.out_head = dbgu.out_tail;
+ }
+ } else { // 2 fragments
+ if ((AT91C_BASE_DBGU->DBGU_CSR & AT91C_US_TXBUFE) == 0) {
+ AT91C_BASE_DBGU->DBGU_PTCR = 1 << 8; // Resume transfer
+ local_irq_restore(intcFlags);
+ while ((AT91C_BASE_DBGU->DBGU_CSR & AT91C_US_TXBUFE) == 0) ALLOW_INTERRUPT_LOOP;
+ dbgu.out_head = dbgu.out_tail; // in case we are interrupted, they may need more space
+ local_irq_save(intcFlags);
+ AT91C_BASE_DBGU->DBGU_PTCR = 1 << 9; // Disable transfer
+ }
+ AT91C_BASE_DBGU->DBGU_TPR = start;
+ AT91C_BASE_DBGU->DBGU_TCR = DEBUG_BUFFER_SIZE - dbgu.out_tail;
+ AT91C_BASE_DBGU->DBGU_TNPR = (unsigned)dbgu.buf;
+ AT91C_BASE_DBGU->DBGU_TNCR = dbgu.in_head;
+ dbgu.out_head = dbgu.out_tail;
+ }
+ AT91C_BASE_DBGU->DBGU_PTCR = 1 << 8; // Resume transfer
+ dbgu.out_tail = dbgu.in_head;
+ dbgu.flush_stack = 0;
+ local_irq_restore(intcFlags);
}
void dbgu_rb_append(char *data, int len)
{
- unsigned long flags;
- int bytes_left;
- char *data_cur;
+ /* Rules:
+ * 1) ONLY the LOWEST order of dbgu_rb_append CAN update in_head;
+ * 2) WHEN updateing in_head, always set it to the current in_tail (since all higher order dbgu_rb_append have completed
+ * 3) ONLY the LOWEST order of dbgu_rb_append MAY call dbgu_rb_flush
+ */
+ unsigned long intcFlags;
+ unsigned int append_stack, avail, local_head;
+ if (len <= 0)
+ return;
- local_irq_save(flags);
-
- bytes_left = &dbgu.buf[0]+sizeof(dbgu.buf)-dbgu.next_inbyte;
- data_cur = data;
-
- if (len > bytes_left) {
- AT91F_DBGU_Printk("LEN > BYTES_LEFT\r\n");
- __rb_flush();
- __dbgu_rb_append(data_cur, bytes_left);
- len -= bytes_left;
- data_cur += bytes_left;
+ local_irq_save(intcFlags);
+ append_stack = dbgu.append_stack++;
+ if (AT91C_BASE_DBGU->DBGU_CSR & AT91C_US_TXBUFE)
+ dbgu.out_head = dbgu.out_tail;
+ avail = (dbgu.out_head - 1 - dbgu.in_tail) & DEBUG_BUFFER_MASK;
+ local_head = (unsigned)len;
+ if (local_head > avail) {
+ local_irq_restore(intcFlags);
+ while ((AT91C_BASE_DBGU->DBGU_CSR & AT91C_US_TXBUFE) == 0);
+ local_irq_save(intcFlags);
+ while ((AT91C_BASE_DBGU->DBGU_CSR & AT91C_US_TXBUFE) == 0);
+ dbgu.out_head = dbgu.out_tail;
+ avail = (dbgu.out_head - 1 - dbgu.in_tail) & DEBUG_BUFFER_MASK;
+ if (local_head > avail) {
+ local_head -= avail;
+ AT91C_BASE_DBGU->DBGU_TPR = (unsigned)data;
+ AT91C_BASE_DBGU->DBGU_TCR = local_head;
+ data += local_head;
+ len = avail;
+ }
}
- __dbgu_rb_append(data_cur, len);
-
- local_irq_restore(flags);
+ local_head = dbgu.in_tail;
+ dbgu.in_tail += len;
+ dbgu.in_tail &= DEBUG_BUFFER_MASK;
+ local_irq_restore(intcFlags);
+ if (dbgu.out_head <= local_head) {
+ // We may have to wrap around: out_head won't change because NO call to flush will be made YET
+ avail = DEBUG_BUFFER_SIZE - local_head;
+ if (avail >= (unsigned)len) {
+ memcpy(dbgu.buf + local_head, data, (size_t)len);
+ } else {
+ memcpy(dbgu.buf + local_head, data, (size_t)avail);
+ memcpy(dbgu.buf, data + avail, (size_t)(len - avail));
+ }
+ } else {
+ memcpy(dbgu.buf + local_head, data, len);
+ }
+ local_irq_save(intcFlags);
+ dbgu.append_stack--;
+ if (!append_stack)
+ dbgu.in_head = dbgu.in_tail;
+ local_irq_restore(intcFlags);
+ if (!append_stack)
+ dbgu_rb_flush();
}
static char dbg_buf[256];
+static int line_num = 0;
void debugp(const char *format, ...)
{
va_list ap;
va_start(ap, format);
- vsnprintf(dbg_buf, sizeof(dbg_buf)-1, format, ap);
+ sprintf(dbg_buf, "[%06X] ", line_num++);
+ vsnprintf(dbg_buf + 9, sizeof(dbg_buf)-10, format, ap);
va_end(ap);
dbg_buf[sizeof(dbg_buf)-1] = '\0';
diff --git a/firmware/src/os/dbgu.h b/firmware/src/os/dbgu.h
index c36ac8c..2a5b59d 100644
--- a/firmware/src/os/dbgu.h
+++ b/firmware/src/os/dbgu.h
@@ -17,17 +17,14 @@
#define AT91C_DBGU_BAUD 115200
-//#define DEBUGP(x) AT91F_DBGU_Printk(x)
-
//* ----------------------- External Function Prototype -----------------------
extern const char *hexdump(const void *data, unsigned int len);
void AT91F_DBGU_Init(void);
void AT91F_DBGU_Fini(void);
-void AT91F_DBGU_Printk( char *buffer);
-void AT91F_DBGU_Frame( char *buffer);
+void AT91F_DBGU_Frame(char *buffer);
+#define AT91F_DBGU_Printk(x) AT91F_DBGU_Frame(x)
int AT91F_DBGU_Get( char *val);
-void dbgu_rb_flush(void);
#ifndef __WinARM__
void AT91F_DBGU_scanf(char * type,unsigned int * val);
#endif
diff --git a/firmware/src/os/main.c b/firmware/src/os/main.c
index 968f6ad..363befc 100644
--- a/firmware/src/os/main.c
+++ b/firmware/src/os/main.c
@@ -77,7 +77,6 @@ int main(void)
while (1) {
/* Call application specific main idle function */
_main_func();
- dbgu_rb_flush();
/* restart watchdog timer */
wdt_restart();
diff --git a/firmware/src/os/pcd_enumerate.c b/firmware/src/os/pcd_enumerate.c
index 3a7397f..403cef9 100644
--- a/firmware/src/os/pcd_enumerate.c
+++ b/firmware/src/os/pcd_enumerate.c
@@ -99,8 +99,10 @@ struct epstate {
};
static const struct epstate epstate[] = {
- [0] = { .state_busy = RCTX_STATE_INVALID },
- [1] = { .state_busy = RCTX_STATE_INVALID },
+ [0] = { .state_busy = RCTX_STATE_UDP_EP0_BUSY,
+ .state_pending = RCTX_STATE_UDP_EP0_PENDING },
+ [1] = { .state_busy = RCTX_STATE_UDP_EP1_BUSY,
+ .state_pending = RCTX_STATE_UDP_EP1_PENDING },
[2] = { .state_busy = RCTX_STATE_UDP_EP2_BUSY,
.state_pending = RCTX_STATE_UDP_EP2_PENDING },
[3] = { .state_busy = RCTX_STATE_UDP_EP3_BUSY,
@@ -112,8 +114,6 @@ static void reset_ep(unsigned int ep)
AT91PS_UDP pUDP = upcd.pUdp;
struct req_ctx *rctx;
- //pUDP->UDP_CSR[ep] = AT91C_UDP_EPEDS;
-
atomic_set(&upcd.ep[ep].pkts_in_transit, 0);
/* free all currently transmitting contexts */
@@ -125,6 +125,7 @@ static void reset_ep(unsigned int ep)
pUDP->UDP_RSTEP |= (1 << ep);
pUDP->UDP_RSTEP &= ~(1 << ep);
+ pUDP->UDP_CSR[ep] = AT91C_UDP_EPEDS;
upcd.ep[ep].incomplete.rctx = NULL;
}
@@ -137,7 +138,7 @@ void udp_unthrottle(void)
pUDP->UDP_IER = AT91C_UDP_EPINT1;
}
-static int __udp_refill_ep(int ep)
+int udp_refill_ep(int ep)
{
u_int16_t i;
AT91PS_UDP pUDP = upcd.pUdp;
@@ -152,9 +153,11 @@ static int __udp_refill_ep(int ep)
/* If there are already two packets in transit, the DPR of
* the SAM7 UDC doesn't have space for more data */
- if (atomic_read(&upcd.ep[ep].pkts_in_transit) == 2) {
+ if (atomic_read(&upcd.ep[ep].pkts_in_transit) == 2)
return -EBUSY;
- }
+
+ /* disable endpoint interrup */
+ pUDP->UDP_IDR |= 1 << ep;
/* If we have an incompletely-transmitted req_ctx (>EP size),
* we need to transmit the rest and finish the transaction */
@@ -165,8 +168,23 @@ static int __udp_refill_ep(int ep)
/* get pending rctx and start transmitting from zero */
rctx = req_ctx_find_get(0, epstate[ep].state_pending,
epstate[ep].state_busy);
- if (!rctx)
+ if (!rctx) {
+ /* re-enable endpoint interrupt */
+ pUDP->UDP_IER |= 1 << ep;
return 0;
+ }
+ if (rctx->tot_len == 0) {
+ /* re-enable endpoint interrupt */
+ pUDP->UDP_IER |= 1 << ep;
+ req_ctx_put(rctx);
+ return 0;
+ }
+ DEBUGPCR("USBT(D=%08X, L=%04u, P=$02u) H4/T4: %02X %02X %02X %02X / %02X %02X %02X %02X",
+ rctx->data, rctx->tot_len, req_ctx_count(epstate[ep].state_pending),
+ rctx->data[4], rctx->data[5], rctx->data[6], rctx->data[7],
+ rctx->data[rctx->tot_len - 4], rctx->data[rctx->tot_len - 3],
+ rctx->data[rctx->tot_len - 2], rctx->data[rctx->tot_len - 1]);
+
start = 0;
upcd.ep[ep].incomplete.bytes_sent = 0;
@@ -178,8 +196,6 @@ static int __udp_refill_ep(int ep)
end = start + AT91C_EP_IN_SIZE;
/* fill FIFO/DPR */
- DEBUGII("RCTX_tx(ep=%u,ctx=%u):%u ", ep, req_ctx_num(rctx),
- end - start);
for (i = start; i < end; i++)
pUDP->UDP_FDR[ep] = rctx->data[i];
@@ -188,15 +204,13 @@ static int __udp_refill_ep(int ep)
pUDP->UDP_CSR[ep] |= AT91C_UDP_TXPKTRDY;
}
- if ((end - start < AT91C_EP_OUT_SIZE) ||
- (((end - start) == 0) && end && (rctx->tot_len % AT91C_EP_OUT_SIZE) == 0)) {
+ if (end == rctx->tot_len) {
/* CASE 1: return context to pool, if
* - packet transfer < AT91C_EP_OUT_SIZE
* - after ZLP of transfer == AT91C_EP_OUT_SIZE
* - after ZLP of transfer % AT91C_EP_OUT_SIZE == 0
* - after last packet of transfer % AT91C_EP_OUT_SIZE != 0
*/
- DEBUGII("RCTX(ep=%u,ctx=%u)_tx_done ", ep, req_ctx_num(rctx));
upcd.ep[ep].incomplete.rctx = NULL;
req_ctx_put(rctx);
} else {
@@ -204,25 +218,15 @@ static int __udp_refill_ep(int ep)
* - after data of transfer == AT91C_EP_OUT_SIZE
* - after data of transfer > AT91C_EP_OUT_SIZE
* - after last packet of transfer % AT91C_EP_OUT_SIZE == 0
- */
+ */
upcd.ep[ep].incomplete.rctx = rctx;
upcd.ep[ep].incomplete.bytes_sent += end - start;
- DEBUGII("RCTX(ep=%u)_tx_cont ", ep);
}
- return 1;
-}
+ /* re-enable endpoint interrupt */
+ pUDP->UDP_IER |= 1 << ep;
-int udp_refill_ep(int ep)
-{
- unsigned long flags;
- int ret;
-
- local_irq_save(flags);
- ret = __udp_refill_ep(ep);
- local_irq_restore(flags);
-
- return ret;
+ return 1;
}
static void udp_irq(void)
@@ -238,19 +242,18 @@ static void udp_irq(void)
DEBUGI("ENDBUSRES ");
pUDP->UDP_ICR = AT91C_UDP_ENDBUSRES;
pUDP->UDP_IER = AT91C_UDP_EPINT0;
- /* reset all endpoints */
- pUDP->UDP_RSTEP = (unsigned int)-1;
- pUDP->UDP_RSTEP = 0;
+ reset_ep(0);
+ reset_ep(1);
+ reset_ep(2);
+ reset_ep(3);
+
/* Enable the function */
pUDP->UDP_FADDR = AT91C_UDP_FEN;
+
/* Configure endpoint 0 */
pUDP->UDP_CSR[0] = (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_CTRL);
upcd.cur_config = 0;
upcd.state = USB_STATE_DEFAULT;
-
- reset_ep(1);
- reset_ep(2);
- reset_ep(3);
#ifdef CONFIG_DFU
if (*dfu->dfu_state == DFU_STATE_appDETACH) {
@@ -359,7 +362,7 @@ cont_ep2:
if (atomic_dec_return(&upcd.ep[2].pkts_in_transit) == 1)
pUDP->UDP_CSR[2] |= AT91C_UDP_TXPKTRDY;
- __udp_refill_ep(2);
+ udp_refill_ep(2);
}
}
if (isr & AT91C_UDP_EPINT3) {
@@ -374,7 +377,7 @@ cont_ep2:
if (atomic_dec_return(&upcd.ep[3].pkts_in_transit) == 1)
pUDP->UDP_CSR[3] |= AT91C_UDP_TXPKTRDY;
- __udp_refill_ep(3);
+ udp_refill_ep(3);
}
}
if (isr & AT91C_UDP_RXSUSP) {
diff --git a/firmware/src/os/req_ctx.c b/firmware/src/os/req_ctx.c
index cc8d57b..722c099 100644
--- a/firmware/src/os/req_ctx.c
+++ b/firmware/src/os/req_ctx.c
@@ -29,11 +29,11 @@
/* FIXME: locking, FIFO order processing */
#if defined(__AT91SAM7S64__) || defined(RUN_FROM_RAM)
-#define NUM_RCTX_SMALL 16
-#define NUM_RCTX_LARGE 1
+#define NUM_RCTX_SMALL 0
+#define NUM_RCTX_LARGE 8
#else
-#define NUM_RCTX_SMALL 8
-#define NUM_RCTX_LARGE 4
+#define NUM_RCTX_SMALL 0
+#define NUM_RCTX_LARGE 20
#endif
#define NUM_REQ_CTX (NUM_RCTX_SMALL+NUM_RCTX_LARGE)
@@ -43,63 +43,173 @@ static u_int8_t rctx_data_large[NUM_RCTX_LARGE][RCTX_SIZE_LARGE];
static struct req_ctx req_ctx[NUM_REQ_CTX];
+/* queue of RCTX indexed by their current state */
+static struct req_ctx *req_ctx_queues[RCTX_STATE_COUNT], *req_ctx_tails[RCTX_STATE_COUNT];
+static unsigned req_counts[RCTX_STATE_COUNT];
+
struct req_ctx __ramfunc *req_ctx_find_get(int large,
unsigned long old_state,
unsigned long new_state)
{
+ struct req_ctx *toReturn;
unsigned long flags;
- u_int8_t i;
-
- if (large)
- i = NUM_RCTX_SMALL;
- else
- i = 0;
- for (; i < NUM_REQ_CTX; i++) {
- local_irq_save(flags);
- if (req_ctx[i].state == old_state) {
- req_ctx[i].state = new_state;
- local_irq_restore(flags);
- return &req_ctx[i];
- }
- local_irq_restore(flags);
+ if (old_state >= RCTX_STATE_COUNT || new_state >= RCTX_STATE_COUNT) {
+ DEBUGPCR("Invalid parameters for req_ctx_find_get");
+ return NULL;
}
-
- return NULL;
+ local_irq_save(flags);
+ toReturn = req_ctx_queues[old_state];
+ if (toReturn) {
+ if ((req_ctx_queues[old_state] = toReturn->next))
+ toReturn->next->prev = NULL;
+ else
+ req_ctx_tails[old_state] = NULL;
+ req_counts[old_state]--;
+ if ((toReturn->prev = req_ctx_tails[new_state]))
+ toReturn->prev->next = toReturn;
+ else
+ req_ctx_queues[new_state] = toReturn;
+ req_ctx_tails[new_state] = toReturn;
+ toReturn->state = new_state;
+ toReturn->next = NULL;
+ req_counts[new_state]++;
+ }
+ local_irq_restore(flags);
+ return toReturn;
}
u_int8_t req_ctx_num(struct req_ctx *ctx)
{
- return ((char *)ctx - (char *)&req_ctx[0])/sizeof(*ctx);
+ return ctx - req_ctx;
}
void req_ctx_set_state(struct req_ctx *ctx, unsigned long new_state)
{
unsigned long flags;
+ unsigned old_state;
- /* FIXME: do we need this kind of locking, we're UP! */
+ if (new_state >= RCTX_STATE_COUNT) {
+ DEBUGPCR("Invalid new_state for req_ctx_set_state");
+ return;
+ }
local_irq_save(flags);
+ old_state = ctx->state;
+ if (ctx->prev)
+ ctx->prev->next = ctx->next;
+ else
+ req_ctx_queues[old_state] = ctx->next;
+ if (ctx->next)
+ ctx->next->prev = ctx->prev;
+ else
+ req_ctx_tails[old_state] = ctx->prev;
+ req_counts[old_state]--;
+ if ((ctx->prev = req_ctx_tails[new_state]))
+ ctx->prev->next = ctx;
+ else
+ req_ctx_queues[new_state] = ctx;
+ req_ctx_tails[new_state] = ctx;
ctx->state = new_state;
+ ctx->next = NULL;
+ req_counts[new_state]++;
local_irq_restore(flags);
}
+#ifdef DEBUG_REQCTX
+void req_print(int state) {
+ int count = 0;
+ struct req_ctx *ctx, *last = NULL;
+ DEBUGP("State [%02i] start <==> ", state);
+ ctx = req_ctx_queues[state];
+ while (ctx) {
+ if (last != ctx->prev)
+ DEBUGP("*INV_PREV* ");
+ DEBUGP("%08X => ", ctx);
+ last = ctx;
+ ctx = ctx->next;
+ count++;
+ if (count > NUM_REQ_CTX) {
+ DEBUGP("*WILD POINTER* => ");
+ break;
+ }
+ }
+ DEBUGPCR("NULL");
+ if (!req_ctx_queues[state] && req_ctx_tails[state]) {
+ DEBUGPCR("NULL head, NON-NULL tail");
+ }
+ if (last != req_ctx_tails[state]) {
+ DEBUGPCR("Tail does not match last element");
+ }
+}
+#endif
+
void req_ctx_put(struct req_ctx *ctx)
{
- req_ctx_set_state(ctx, RCTX_STATE_FREE);
+ unsigned long intcFlags;
+ unsigned old_state;
+
+ local_irq_save(intcFlags);
+ old_state = ctx->state;
+ if (ctx->prev)
+ ctx->prev->next = ctx->next;
+ else
+ req_ctx_queues[old_state] = ctx->next;
+ if (ctx->next)
+ ctx->next->prev = ctx->prev;
+ else
+ req_ctx_tails[old_state] = ctx->prev;
+ req_counts[old_state]--;
+ if ((ctx->prev = req_ctx_tails[RCTX_STATE_FREE]))
+ ctx->prev->next = ctx;
+ else
+ req_ctx_queues[RCTX_STATE_FREE] = ctx;
+ req_ctx_tails[RCTX_STATE_FREE] = ctx;
+ ctx->state = RCTX_STATE_FREE;
+ ctx->next = NULL;
+ req_counts[RCTX_STATE_FREE]++;
+ local_irq_restore(intcFlags);
+}
+
+unsigned int req_ctx_count(unsigned long state)
+{
+ if (state >= RCTX_STATE_COUNT)
+ return 0;
+ return req_counts[state];
}
void req_ctx_init(void)
{
int i;
-
for (i = 0; i < NUM_RCTX_SMALL; i++) {
+ req_ctx[i].prev = req_ctx + i - 1;
+ req_ctx[i].next = req_ctx + i + 1;
req_ctx[i].size = RCTX_SIZE_SMALL;
+ req_ctx[i].tot_len = 0;
req_ctx[i].data = rctx_data[i];
req_ctx[i].state = RCTX_STATE_FREE;
+ DEBUGPCR("SMALL req_ctx[%02i] initialized at %08X, Data: %08X => %08X",
+ i, req_ctx + i, req_ctx[i].data, req_ctx[i].data + RCTX_SIZE_SMALL);
+ }
+
+ for (; i < NUM_REQ_CTX; i++) {
+ req_ctx[i].prev = req_ctx + i - 1;
+ req_ctx[i].next = req_ctx + i + 1;
+ req_ctx[i].size = RCTX_SIZE_LARGE;
+ req_ctx[i].tot_len = 0;
+ req_ctx[i].data = rctx_data_large[i];
+ req_ctx[i].state = RCTX_STATE_FREE;
+ DEBUGPCR("LARGE req_ctx[%02i] initialized at %08X, Data: %08X => %08X",
+ i, req_ctx + i, req_ctx[i].data, req_ctx[i].data + RCTX_SIZE_LARGE);
}
+ req_ctx[0].prev = NULL;
+ req_ctx[NUM_REQ_CTX - 1].next = NULL;
+
+ req_ctx_queues[RCTX_STATE_FREE] = req_ctx;
+ req_ctx_tails[RCTX_STATE_FREE] = req_ctx + NUM_REQ_CTX - 1;
+ req_counts[RCTX_STATE_FREE] = NUM_REQ_CTX;
- for (i = 0; i < NUM_RCTX_LARGE; i++) {
- req_ctx[NUM_RCTX_SMALL+i].size = RCTX_SIZE_LARGE;
- req_ctx[NUM_RCTX_SMALL+i].data = rctx_data_large[i];
+ for (i = RCTX_STATE_FREE + 1; i < RCTX_STATE_COUNT; i++) {
+ req_ctx_queues[i] = req_ctx_tails[i] = NULL;
+ req_counts[i] = 0;
}
}
diff --git a/firmware/src/os/req_ctx.h b/firmware/src/os/req_ctx.h
index 94b5c5a..92c21a7 100644
--- a/firmware/src/os/req_ctx.h
+++ b/firmware/src/os/req_ctx.h
@@ -1,11 +1,10 @@
#ifndef _REQ_CTX_H
#define _REQ_CTX_H
-#define RCTX_SIZE_LARGE 2048
-#define RCTX_SIZE_SMALL 128
+#define RCTX_SIZE_LARGE 960
+#define RCTX_SIZE_SMALL 320
#define MAX_HDRSIZE sizeof(struct openpcd_hdr)
-#define MAX_REQSIZE (64-MAX_HDRSIZE)
#define req_buf_payload(x) (x->data[x->hdr_len])
#define req_buf_hdr(x) (x->data[0])
@@ -15,35 +14,38 @@
struct req_ctx {
volatile u_int32_t state;
+ volatile struct req_ctx *prev, *next;
u_int16_t size;
u_int16_t tot_len;
u_int8_t *data;
};
-#define RCTX_STATE_FREE 0xfe
-#define RCTX_STATE_UDP_RCV_BUSY 0x01
-#define RCTX_STATE_UDP_RCV_DONE 0x02
-#define RCTX_STATE_MAIN_PROCESSING 0x03
-#define RCTX_STATE_RC632IRQ_BUSY 0x04
-
-#define RCTX_STATE_UDP_EP2_PENDING 0x10
-#define RCTX_STATE_UDP_EP2_BUSY 0x11
-
-#define RCTX_STATE_UDP_EP3_PENDING 0x12
-#define RCTX_STATE_UDP_EP3_BUSY 0x13
-
-#define RCTX_STATE_SSC_RX_BUSY 0x20
-
-#define RCTX_STATE_LIBRFID_BUSY 0x30
-
-#define RCTX_STATE_PIOIRQ_BUSY 0x80
-
-#define RCTX_STATE_INVALID 0xff
+#define RCTX_STATE_FREE 0
+#define RCTX_STATE_UDP_RCV_BUSY 1
+#define RCTX_STATE_UDP_RCV_DONE 2
+#define RCTX_STATE_MAIN_PROCESSING 3
+#define RCTX_STATE_RC632IRQ_BUSY 4
+#define RCTX_STATE_UDP_EP2_PENDING 5
+#define RCTX_STATE_UDP_EP2_BUSY 6
+#define RCTX_STATE_UDP_EP3_PENDING 7
+#define RCTX_STATE_UDP_EP3_BUSY 8
+#define RCTX_STATE_SSC_RX_BUSY 9
+#define RCTX_STATE_LIBRFID_BUSY 10
+#define RCTX_STATE_PIOIRQ_BUSY 11
+#define RCTX_STATE_INVALID 12
+// Nominally UNUSED states
+#define RCTX_STATE_UDP_EP0_PENDING 13
+#define RCTX_STATE_UDP_EP0_BUSY 14
+#define RCTX_STATE_UDP_EP1_PENDING 15
+#define RCTX_STATE_UDP_EP1_BUSY 16
+// Count of the number of STATES
+#define RCTX_STATE_COUNT 17
extern struct req_ctx __ramfunc *req_ctx_find_get(int large, unsigned long old_state, unsigned long new_state);
extern struct req_ctx *req_ctx_find_busy(void);
extern void req_ctx_set_state(struct req_ctx *ctx, unsigned long new_state);
extern void req_ctx_put(struct req_ctx *ctx);
extern u_int8_t req_ctx_num(struct req_ctx *ctx);
+unsigned int req_ctx_count(unsigned long state);
#endif /* _REQ_CTX_H */
diff --git a/firmware/src/os/system_irq.c b/firmware/src/os/system_irq.c
index dc787eb..4c1da31 100644
--- a/firmware/src/os/system_irq.c
+++ b/firmware/src/os/system_irq.c
@@ -25,15 +25,15 @@
#include <os/system_irq.h>
#include <os/dbgu.h>
+#include <string.h>
#include "../openpcd.h"
static sysirq_hdlr *sysirq_hdlrs[AT91SAM7_SYSIRQ_COUNT];
-static void sys_irq(void)
+void sys_irq(u_int32_t previous_pc)
{
u_int32_t sr;
- DEBUGP("sys_irq ");
/* Somehow Atmel decided to do really stupid interrupt sharing
* for commonly-used interrupts such as the timer irq */
@@ -139,6 +139,10 @@ static void sys_irq(void)
if (*AT91C_WDTC_WDMR & AT91C_WDTC_WDFIEN) {
sr = *AT91C_WDTC_WDSR;
if (sr) {
+ char dbg_buf[100];
+ sprintf(dbg_buf, "sys_irq [Old PC = %08X]\n\r", previous_pc);
+ AT91F_DBGU_Frame(dbg_buf);
+
DEBUGP("WDT(");
if (sysirq_hdlrs[AT91SAM7_SYSIRQ_WDT]) {
DEBUGP("handler ");
@@ -154,6 +158,14 @@ static void sys_irq(void)
DEBUGPCR("END");
}
+static void sysirq_entry(void)
+{
+ /* DON'T MODIFY THIS SECTION AND Cstartup.S/IRQ_Handler_Entry */
+ register unsigned *previous_pc asm("r0");
+ asm("ADD R1, SP, #16; LDR R0, [R1]");
+ sys_irq(previous_pc);
+}
+
void sysirq_register(enum sysirqs irq, sysirq_hdlr *hdlr)
{
if (irq >= AT91SAM7_SYSIRQ_COUNT)
@@ -167,6 +179,6 @@ void sysirq_init(void)
AT91F_AIC_ConfigureIt(AT91C_BASE_AIC, AT91C_ID_SYS,
OPENPCD_IRQ_PRIO_SYS,
AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL,
- &sys_irq);
+ &sysirq_entry);
AT91F_AIC_EnableIt(AT91C_BASE_AIC, AT91C_ID_SYS);
}
diff --git a/firmware/src/os/usbcmd_generic.c b/firmware/src/os/usbcmd_generic.c
index 77b992f..aff13eb 100644
--- a/firmware/src/os/usbcmd_generic.c
+++ b/firmware/src/os/usbcmd_generic.c
@@ -132,7 +132,7 @@ static int gen_usb_rx(struct req_ctx *rctx)
void usbcmd_gen_init(void)
{
- DEBUGP("Inititalizing usbcmd_gen_init\n");
+ DEBUGP("Inititalizing usbcmd_gen_init\n\r");
/* setup FLASH write support for environment storage */
flash_init();
diff --git a/firmware/src/os/wdt.c b/firmware/src/os/wdt.c
index 99d86a1..d5c19a3 100644
--- a/firmware/src/os/wdt.c
+++ b/firmware/src/os/wdt.c
@@ -33,9 +33,9 @@
static void wdt_irq(u_int32_t sr)
{
if (sr & 1)
- DEBUGPCRF("================> WATCHDOG EXPIRED !!!!!");
+ AT91F_DBGU_Frame("================> WATCHDOG EXPIRED !!!!!\n\r");
if (sr & 2)
- DEBUGPCRF("================> WATCHDOG ERROR !!!!!");
+ AT91F_DBGU_Frame("================> WATCHDOG ERROR !!!!!\n\r");
}
void wdt_restart(void)
personal git repositories of Harald Welte. Your mileage may vary