libsys: add standard condition spinning primitives

This commit is contained in:
David van Moolenbroek 2010-07-12 23:14:40 +00:00
parent 78a0260993
commit 1ecdac623a
12 changed files with 197 additions and 113 deletions

View File

@ -44,7 +44,7 @@ struct command {
}; };
/* Timeouts and max retries. */ /* Timeouts and max retries. */
PRIVATE int timeout_ticks = DEF_TIMEOUT_TICKS; PRIVATE int timeout_usecs = DEF_TIMEOUT_USECS;
PRIVATE int max_errors = MAX_ERRORS; PRIVATE int max_errors = MAX_ERRORS;
PRIVATE long w_standard_timeouts = 0; PRIVATE long w_standard_timeouts = 0;
PRIVATE long w_pci_debug = 0; PRIVATE long w_pci_debug = 0;
@ -941,12 +941,12 @@ PRIVATE int w_io_test(void)
save_dev = w_device; save_dev = w_device;
/* Reduce timeout values for this test transaction. */ /* Reduce timeout values for this test transaction. */
save_timeout = timeout_ticks; save_timeout = timeout_usecs;
save_errors = max_errors; save_errors = max_errors;
save_wakeup = wakeup_ticks; save_wakeup = wakeup_ticks;
if (!w_standard_timeouts) { if (!w_standard_timeouts) {
timeout_ticks = system_hz * 4; timeout_usecs = 4000000;
wakeup_ticks = system_hz * 6; wakeup_ticks = system_hz * 6;
max_errors = 3; max_errors = 3;
} }
@ -964,7 +964,7 @@ PRIVATE int w_io_test(void)
panic("Couldn't switch back devices"); panic("Couldn't switch back devices");
/* Restore parameters. */ /* Restore parameters. */
timeout_ticks = save_timeout; timeout_usecs = save_timeout;
max_errors = save_errors; max_errors = save_errors;
wakeup_ticks = save_wakeup; wakeup_ticks = save_wakeup;
w_testing = 0; w_testing = 0;
@ -1920,24 +1920,19 @@ int mask; /* status mask */
int value; /* required status */ int value; /* required status */
{ {
/* Wait until controller is in the required state. Return zero on timeout. /* Wait until controller is in the required state. Return zero on timeout.
* An alarm that set a timeout flag is used. TIMEOUT is in micros, we need
* ticks. Disabling the alarm is not needed, because a static flag is used
* and a leftover timeout cannot do any harm.
*/ */
unsigned long w_status; unsigned long w_status;
clock_t t0, t1; spin_t spin;
int s; int s;
getuptime(&t0); SPIN_FOR(&spin, timeout_usecs) {
do {
if ((s=sys_inb(w_wn->base_cmd + REG_STATUS, &w_status)) != OK) if ((s=sys_inb(w_wn->base_cmd + REG_STATUS, &w_status)) != OK)
panic("Couldn't read register: %d", s); panic("Couldn't read register: %d", s);
w_wn->w_status= w_status; w_wn->w_status= w_status;
if ((w_wn->w_status & mask) == value) { if ((w_wn->w_status & mask) == value) {
return 1; return 1;
} }
} while ((s=getuptime(&t1)) == OK && (t1-t0) < timeout_ticks ); }
if (OK != s) printf("AT_WINI: warning, get_uptime failed: %d\n",s);
w_need_reset(); /* controller gone deaf */ w_need_reset(); /* controller gone deaf */
return(0); return(0);
@ -1951,23 +1946,18 @@ int mask; /* status mask */
int value; /* required status */ int value; /* required status */
{ {
/* Wait until controller is in the required state. Return zero on timeout. /* Wait until controller is in the required state. Return zero on timeout.
* An alarm that set a timeout flag is used. TIMEOUT is in micros, we need
* ticks. Disabling the alarm is not needed, because a static flag is used
* and a leftover timeout cannot do any harm.
*/ */
unsigned long w_status; unsigned long w_status;
clock_t t0, t1; spin_t spin;
int s; int s;
getuptime(&t0); SPIN_FOR(&spin, timeout_usecs) {
do {
if ((s=sys_inb(w_wn->base_dma + DMA_STATUS, &w_status)) != OK) if ((s=sys_inb(w_wn->base_dma + DMA_STATUS, &w_status)) != OK)
panic("Couldn't read register: %d", s); panic("Couldn't read register: %d", s);
if ((w_status & mask) == value) { if ((w_status & mask) == value) {
return 1; return 1;
} }
} while ((s=getuptime(&t1)) == OK && (t1-t0) < timeout_ticks ); }
if (OK != s) printf("AT_WINI: warning, get_uptime failed: %d\n",s);
return(0); return(0);
} }
@ -2320,7 +2310,7 @@ message *m;
if (timeout == 0) { if (timeout == 0) {
/* Restore defaults. */ /* Restore defaults. */
timeout_ticks = DEF_TIMEOUT_TICKS; timeout_usecs = DEF_TIMEOUT_USECS;
max_errors = MAX_ERRORS; max_errors = MAX_ERRORS;
wakeup_ticks = WAKEUP_TICKS; wakeup_ticks = WAKEUP_TICKS;
w_silent = 0; w_silent = 0;
@ -2337,8 +2327,10 @@ message *m;
max_errors = 3; max_errors = 3;
w_silent = 1; w_silent = 1;
if (timeout_ticks > timeout) timeout = timeout * 1000000 / sys_hz();
timeout_ticks = timeout;
if (timeout_usecs > timeout)
timeout_usecs = timeout;
} }
r= sys_safecopyto(m->IO_ENDPT, r= sys_safecopyto(m->IO_ENDPT,

View File

@ -200,7 +200,7 @@
#define NR_SUBDEVS (MAX_DRIVES * SUB_PER_DRIVE) #define NR_SUBDEVS (MAX_DRIVES * SUB_PER_DRIVE)
#define DELAY_USECS 1000 /* controller timeout in microseconds */ #define DELAY_USECS 1000 /* controller timeout in microseconds */
#define DELAY_TICKS 1 /* controller timeout in ticks */ #define DELAY_TICKS 1 /* controller timeout in ticks */
#define DEF_TIMEOUT_TICKS 300 /* controller timeout in ticks */ #define DEF_TIMEOUT_USECS 5000000L /* controller timeout in microseconds */
#define RECOVERY_USECS 500000 /* controller recovery time in microseconds */ #define RECOVERY_USECS 500000 /* controller recovery time in microseconds */
#define RECOVERY_TICKS 30 /* controller recovery time in ticks */ #define RECOVERY_TICKS 30 /* controller recovery time in ticks */
#define INITIALIZED 0x01 /* drive is initialized */ #define INITIALIZED 0x01 /* drive is initialized */

View File

@ -130,8 +130,7 @@
#define NR_DRIVES 2 /* maximum number of drives */ #define NR_DRIVES 2 /* maximum number of drives */
#define DIVISOR 128 /* used for sector size encoding */ #define DIVISOR 128 /* used for sector size encoding */
#define SECTOR_SIZE_CODE 2 /* code to say "512" to the controller */ #define SECTOR_SIZE_CODE 2 /* code to say "512" to the controller */
#define TIMEOUT_MICROS 500000L /* microseconds waiting for FDC */ #define TIMEOUT_MICROS 5000000L /* microseconds waiting for FDC */
#define TIMEOUT_TICKS 30 /* ticks waiting for FDC */
#define NT 7 /* number of diskette/drive combinations */ #define NT 7 /* number of diskette/drive combinations */
#define UNCALIBRATED 0 /* drive needs to be calibrated at next use */ #define UNCALIBRATED 0 /* drive needs to be calibrated at next use */
#define CALIBRATED 1 /* no calibration needed */ #define CALIBRATED 1 /* no calibration needed */
@ -950,15 +949,14 @@ PRIVATE int fdc_results(void)
int s, result_nr; int s, result_nr;
unsigned long status; unsigned long status;
clock_t t0,t1; spin_t spin;
/* Extract bytes from FDC until it says it has no more. The loop is /* Extract bytes from FDC until it says it has no more. The loop is
* really an outer loop on result_nr and an inner loop on status. * really an outer loop on result_nr and an inner loop on status.
* A timeout flag alarm is set. * A timeout flag alarm is set.
*/ */
result_nr = 0; result_nr = 0;
getuptime(&t0); SPIN_FOR(&spin, TIMEOUT_MICROS) {
do {
/* Reading one byte is almost a mirror of fdc_out() - the DIRECTION /* Reading one byte is almost a mirror of fdc_out() - the DIRECTION
* bit must be set instead of clear, but the CTL_BUSY bit destroys * bit must be set instead of clear, but the CTL_BUSY bit destroys
* the perfection of the mirror. * the perfection of the mirror.
@ -981,8 +979,7 @@ PRIVATE int fdc_results(void)
return(OK); /* only good exit */ return(OK); /* only good exit */
} }
} while ( (s=getuptime(&t1))==OK && (t1-t0) < TIMEOUT_TICKS ); }
if (OK!=s) printf("FLOPPY: warning, getuptime failed: %d\n", s);
need_reset = TRUE; /* controller chip must be reset */ need_reset = TRUE; /* controller chip must be reset */
if ((s=sys_irqenable(&irq_hook_id)) != OK) if ((s=sys_irqenable(&irq_hook_id)) != OK)
@ -1026,27 +1023,26 @@ PRIVATE void fdc_out(
* can only write to it when it is listening, and it decides when to listen. * can only write to it when it is listening, and it decides when to listen.
* If the controller refuses to listen, the FDC chip is given a hard reset. * If the controller refuses to listen, the FDC chip is given a hard reset.
*/ */
clock_t t0, t1; spin_t spin;
int s; int s;
unsigned long status; unsigned long status;
if (need_reset) return; /* if controller is not listening, return */ if (need_reset) return; /* if controller is not listening, return */
/* It may take several tries to get the FDC to accept a command. */ /* It may take several tries to get the FDC to accept a command. */
getuptime(&t0); SPIN_FOR(&spin, TIMEOUT_MICROS) {
do {
if ( (s=getuptime(&t1))==OK && (t1-t0) > TIMEOUT_TICKS ) {
if (OK!=s) printf("FLOPPY: warning, getuptime failed: %d\n", s);
need_reset = TRUE; /* hit it over the head */
return;
}
if ((s=sys_inb(FDC_STATUS, &status)) != OK) if ((s=sys_inb(FDC_STATUS, &status)) != OK)
panic("Sys_inb in fdc_out() failed: %d", s); panic("Sys_inb in fdc_out() failed: %d", s);
}
while ((status & (MASTER | DIRECTION)) != (MASTER | 0));
if ((status & (MASTER | DIRECTION)) == (MASTER | 0)) {
if ((s=sys_outb(FDC_DATA, val)) != OK) if ((s=sys_outb(FDC_DATA, val)) != OK)
panic("Sys_outb in fdc_out() failed: %d", s); panic("Sys_outb in fdc_out() failed: %d", s);
return;
}
}
need_reset = TRUE; /* hit it over the head */
} }
/*===========================================================================* /*===========================================================================*

View File

@ -946,7 +946,6 @@ static void fxp_confaddr(fxp_t *fp)
{ {
static char eakey[]= FXP_ENVVAR "#_EA"; static char eakey[]= FXP_ENVVAR "#_EA";
static char eafmt[]= "x:x:x:x:x:x"; static char eafmt[]= "x:x:x:x:x:x";
clock_t t0,t1;
int i, r; int i, r;
u32_t bus_addr; u32_t bus_addr;
long v; long v;
@ -987,12 +986,8 @@ static void fxp_confaddr(fxp_t *fp)
fxp_cu_ptr_cmd(fp, SC_CU_START, bus_addr, TRUE /* check idle */); fxp_cu_ptr_cmd(fp, SC_CU_START, bus_addr, TRUE /* check idle */);
getuptime(&t0);
do {
/* Wait for CU command to complete */ /* Wait for CU command to complete */
if (tmpbufp->ias.ias_status & CBL_F_C) SPIN_UNTIL(tmpbufp->ias.ias_status & CBL_F_C, 1000);
break;
} while (getuptime(&t1)==OK && (t1-t0) < micros_to_ticks(1000));
if (!(tmpbufp->ias.ias_status & CBL_F_C)) if (!(tmpbufp->ias.ias_status & CBL_F_C))
panic("fxp_confaddr: CU command failed to complete"); panic("fxp_confaddr: CU command failed to complete");
@ -1356,7 +1351,6 @@ fxp_t *fp;
{ {
int r; int r;
u32_t bus_addr; u32_t bus_addr;
clock_t t0,t1;
/* Configure device */ /* Configure device */
tmpbufp->cc.cc_status= 0; tmpbufp->cc.cc_status= 0;
@ -1372,12 +1366,8 @@ fxp_t *fp;
fxp_cu_ptr_cmd(fp, SC_CU_START, bus_addr, TRUE /* check idle */); fxp_cu_ptr_cmd(fp, SC_CU_START, bus_addr, TRUE /* check idle */);
getuptime(&t0);
do {
/* Wait for CU command to complete */ /* Wait for CU command to complete */
if (tmpbufp->cc.cc_status & CBL_F_C) SPIN_UNTIL(tmpbufp->cc.cc_status & CBL_F_C, 100000);
break;
} while (getuptime(&t1)==OK && (t1-t0) < micros_to_ticks(100000));
if (!(tmpbufp->cc.cc_status & CBL_F_C)) if (!(tmpbufp->cc.cc_status & CBL_F_C))
panic("fxp_do_conf: CU command failed to complete"); panic("fxp_do_conf: CU command failed to complete");
@ -1395,7 +1385,7 @@ int cmd;
phys_bytes bus_addr; phys_bytes bus_addr;
int check_idle; int check_idle;
{ {
clock_t t0,t1; spin_t spin;
port_t port; port_t port;
u8_t scb_cmd; u8_t scb_cmd;
@ -1412,15 +1402,15 @@ int check_idle;
fxp_outb(port, SCB_CMD, cmd); fxp_outb(port, SCB_CMD, cmd);
/* What is a reasonable time-out? There is nothing in the /* What is a reasonable time-out? There is nothing in the
* documentation. 1 ms should be enough. * documentation. 1 ms should be enough. We use 100 ms.
*/ */
getuptime(&t0); spin_init(&spin, 100000);
do { do {
/* Wait for CU command to be accepted */ /* Wait for CU command to be accepted */
scb_cmd= fxp_inb(port, SCB_CMD); scb_cmd= fxp_inb(port, SCB_CMD);
if ((scb_cmd & SC_CUC_MASK) == SC_CU_NOP) if ((scb_cmd & SC_CUC_MASK) == SC_CU_NOP)
break; break;
} while (getuptime(&t1)==OK && (t1-t0) < micros_to_ticks(100000)); } while (spin_check(&spin));
if ((scb_cmd & SC_CUC_MASK) != SC_CU_NOP) if ((scb_cmd & SC_CUC_MASK) != SC_CU_NOP)
panic("fxp_cu_ptr_cmd: CU does not accept command"); panic("fxp_cu_ptr_cmd: CU does not accept command");
@ -1435,7 +1425,7 @@ int cmd;
phys_bytes bus_addr; phys_bytes bus_addr;
int check_idle; int check_idle;
{ {
clock_t t0,t1; spin_t spin;
port_t port; port_t port;
u8_t scb_cmd; u8_t scb_cmd;
@ -1451,13 +1441,13 @@ int check_idle;
fxp_outl(port, SCB_POINTER, bus_addr); fxp_outl(port, SCB_POINTER, bus_addr);
fxp_outb(port, SCB_CMD, cmd); fxp_outb(port, SCB_CMD, cmd);
getuptime(&t0); spin_init(&spin, 1000);
do { do {
/* Wait for RU command to be accepted */ /* Wait for RU command to be accepted */
scb_cmd= fxp_inb(port, SCB_CMD); scb_cmd= fxp_inb(port, SCB_CMD);
if ((scb_cmd & SC_RUC_MASK) == SC_RU_NOP) if ((scb_cmd & SC_RUC_MASK) == SC_RU_NOP)
break; break;
} while (getuptime(&t1)==OK && (t1-t0) < micros_to_ticks(1000)); } while (spin_check(&spin));
if ((scb_cmd & SC_RUC_MASK) != SC_RU_NOP) if ((scb_cmd & SC_RUC_MASK) != SC_RU_NOP)
panic("fxp_ru_ptr_cmd: RU does not accept command"); panic("fxp_ru_ptr_cmd: RU does not accept command");
@ -1501,7 +1491,6 @@ fxp_t *fp;
*===========================================================================*/ *===========================================================================*/
static void fxp_getstat_s(message *mp) static void fxp_getstat_s(message *mp)
{ {
clock_t t0,t1;
int r; int r;
fxp_t *fp; fxp_t *fp;
u32_t *p; u32_t *p;
@ -1520,12 +1509,8 @@ static void fxp_getstat_s(message *mp)
*/ */
fxp_cu_ptr_cmd(fp, SC_CU_DUMP_SC, 0, FALSE /* do not check idle */); fxp_cu_ptr_cmd(fp, SC_CU_DUMP_SC, 0, FALSE /* do not check idle */);
getuptime(&t0);
do {
/* Wait for CU command to complete */ /* Wait for CU command to complete */
if (*p != 0) SPIN_UNTIL(*p != 0, 1000);
break;
} while (getuptime(&t1)==OK && (t1-t0) < micros_to_ticks(1000));
if (*p == 0) if (*p == 0)
panic("fxp_getstat: CU command failed to complete"); panic("fxp_getstat: CU command failed to complete");
@ -2220,7 +2205,7 @@ PRIVATE u16_t mii_read(fp, reg)
fxp_t *fp; fxp_t *fp;
int reg; int reg;
{ {
clock_t t0,t1; spin_t spin;
port_t port; port_t port;
u32_t v; u32_t v;
@ -2234,12 +2219,12 @@ int reg;
fxp_outl(port, CSR_MDI_CTL, CM_READ | (1 << CM_PHYADDR_SHIFT) | fxp_outl(port, CSR_MDI_CTL, CM_READ | (1 << CM_PHYADDR_SHIFT) |
(reg << CM_REG_SHIFT)); (reg << CM_REG_SHIFT));
getuptime(&t0); spin_init(&spin, 100000);
do { do {
v= fxp_inl(port, CSR_MDI_CTL); v= fxp_inl(port, CSR_MDI_CTL);
if (v & CM_READY) if (v & CM_READY)
break; break;
} while (getuptime(&t1)==OK && (t1-t0) < micros_to_ticks(100000)); } while (spin_check(&spin));
if (!(v & CM_READY)) if (!(v & CM_READY))
panic("mii_read: MDI not ready after command"); panic("mii_read: MDI not ready after command");

View File

@ -689,18 +689,13 @@ re_t *rep;
u32_t t; u32_t t;
phys_bytes bus_buf; phys_bytes bus_buf;
int i; int i;
clock_t t0,t1;
port= rep->re_base_port; port= rep->re_base_port;
#if 0 #if 0
/* Reset the PHY */ /* Reset the PHY */
rl_outb(port, RL_BMCR, MII_CTRL_RST); rl_outb(port, RL_BMCR, MII_CTRL_RST);
getuptime(&t0); SPIN_UNTIL(!(rl_inb(port, RL_BMCR) & MII_CTRL_RST), 1000000);
do {
if (!(rl_inb(port, RL_BMCR) & MII_CTRL_RST))
break;
} while (getuptime(&t1)==OK && (t1-t0) < system_hz);
if (rl_inb(port, RL_BMCR) & MII_CTRL_RST) if (rl_inb(port, RL_BMCR) & MII_CTRL_RST)
panic("reset PHY failed to complete"); panic("reset PHY failed to complete");
#endif #endif
@ -711,11 +706,7 @@ re_t *rep;
port, rl_inb(port, RL_CR)); port, rl_inb(port, RL_CR));
#endif #endif
rl_outb(port, RL_CR, RL_CR_RST); rl_outb(port, RL_CR, RL_CR_RST);
getuptime(&t0); SPIN_UNTIL(!(rl_inb(port, RL_CR) & RL_CR_RST), 1000000);
do {
if (!(rl_inb(port, RL_CR) & RL_CR_RST))
break;
} while (getuptime(&t1)==OK && (t1-t0) < system_hz);
#if VERBOSE #if VERBOSE
printf("rl_reset_hw: (after reset) port = 0x%x, RL_CR = 0x%x\n", printf("rl_reset_hw: (after reset) port = 0x%x, RL_CR = 0x%x\n",
port, rl_inb(port, RL_CR)); port, rl_inb(port, RL_CR));
@ -1572,7 +1563,6 @@ static void rl_clear_rx(re_t *rep)
{ {
port_t port; port_t port;
u8_t cr; u8_t cr;
clock_t t0,t1;
rep->re_clear_rx= FALSE; rep->re_clear_rx= FALSE;
port= rep->re_base_port; port= rep->re_base_port;
@ -1581,11 +1571,7 @@ static void rl_clear_rx(re_t *rep)
cr= rl_inb(port, RL_CR); cr= rl_inb(port, RL_CR);
cr &= ~RL_CR_RE; cr &= ~RL_CR_RE;
rl_outb(port, RL_CR, cr); rl_outb(port, RL_CR, cr);
getuptime(&t0); SPIN_UNTIL(!(rl_inb(port, RL_CR) & RL_CR_RE), 1000000);
do {
if (!(rl_inb(port, RL_CR) & RL_CR_RE))
break;
} while (getuptime(&t1)==OK && (t1-t0) < system_hz);
if (rl_inb(port, RL_CR) & RL_CR_RE) if (rl_inb(port, RL_CR) & RL_CR_RE)
panic("cannot disable receiver"); panic("cannot disable receiver");
@ -1819,7 +1805,6 @@ static int rl_handler(re_t *rep)
#if 0 #if 0
u8_t cr; u8_t cr;
#endif #endif
clock_t t0,t1;
int_event_check = FALSE; /* disable check by default */ int_event_check = FALSE; /* disable check by default */
port= rep->re_base_port; port= rep->re_base_port;
@ -1912,11 +1897,7 @@ static int rl_handler(re_t *rep)
cr= rl_inb(port, RL_CR); cr= rl_inb(port, RL_CR);
cr &= ~RL_CR_TE; cr &= ~RL_CR_TE;
rl_outb(port, RL_CR, cr); rl_outb(port, RL_CR, cr);
getuptime(&t0); SPIN_UNTIL(!(rl_inb(port, RL_CR) & RL_CR_TE), 1000000);
do {
if (!(rl_inb(port, RL_CR) & RL_CR_TE))
break;
} while (getuptime(&t1)==OK && (t1-t0) < system_hz);
if (rl_inb(port, RL_CR) & RL_CR_TE) { if (rl_inb(port, RL_CR) & RL_CR_TE) {
panic("cannot disable transmitter"); panic("cannot disable transmitter");
} }
@ -2289,7 +2270,6 @@ int a;
u16_t w; u16_t w;
{ {
int b, i, cmd; int b, i, cmd;
clock_t t0, t1;
outb_reg3(dep, 1, 0x80 | 0x8); /* Set CS */ outb_reg3(dep, 1, 0x80 | 0x8); /* Set CS */
@ -2316,11 +2296,7 @@ u16_t w;
outb_reg3(dep, 1, 0x80); /* Drop CS */ outb_reg3(dep, 1, 0x80); /* Drop CS */
/* micro_delay(1); */ /* Is this required? */ /* micro_delay(1); */ /* Is this required? */
outb_reg3(dep, 1, 0x80 | 0x8); /* Set CS */ outb_reg3(dep, 1, 0x80 | 0x8); /* Set CS */
getuptime(&t0); SPIN_UNTIL(inb_reg3(dep, 1) & 1, 10000);
do {
if (inb_reg3(dep, 1) & 1)
break;
} while (getuptime(&t1) == OK && (t1 == t0));
if (!(inb_reg3(dep, 1) & 1)) if (!(inb_reg3(dep, 1) & 1))
panic("device remains busy"); panic("device remains busy");
} }

View File

@ -1015,11 +1015,7 @@ re_t *rep;
printf("rl_reset_hw: (before reset) port = 0x%x, RL_CR = 0x%x\n", printf("rl_reset_hw: (before reset) port = 0x%x, RL_CR = 0x%x\n",
port, rl_inb(port, RL_CR)); port, rl_inb(port, RL_CR));
rl_outb(port, RL_CR, RL_CR_RST); rl_outb(port, RL_CR, RL_CR_RST);
getuptime(&t0); SPIN_UNTIL(!(rl_inb(port, RL_CR) & RL_CR_RST), 1000000);
do {
if (!(rl_inb(port, RL_CR) & RL_CR_RST))
break;
} while (getuptime(&t1) == OK && (t1 - t0) < system_hz);
printf("rl_reset_hw: (after reset) port = 0x%x, RL_CR = 0x%x\n", printf("rl_reset_hw: (after reset) port = 0x%x, RL_CR = 0x%x\n",
port, rl_inb(port, RL_CR)); port, rl_inb(port, RL_CR));
if (rl_inb(port, RL_CR) & RL_CR_RST) if (rl_inb(port, RL_CR) & RL_CR_RST)

View File

@ -316,7 +316,7 @@ PRIVATE void do_int(struct port *pp)
{ {
int r, devind, vcc_5v, vcc_3v, vcc_Xv, vcc_Yv, int r, devind, vcc_5v, vcc_3v, vcc_Xv, vcc_Yv,
socket_5v, socket_3v, socket_Xv, socket_Yv; socket_5v, socket_3v, socket_Xv, socket_Yv;
clock_t t0, t1; spin_t spin;
u32_t csr_event, csr_present, csr_control; u32_t csr_event, csr_present, csr_control;
u8_t v8; u8_t v8;
u16_t v16; u16_t v16;
@ -453,12 +453,12 @@ PRIVATE void do_int(struct port *pp)
printf("TI_CARD_CTRL: 0x%02x\n", v8); printf("TI_CARD_CTRL: 0x%02x\n", v8);
} }
getuptime(&t0); spin_init(&spin, 100000);
do { do {
csr_present= pp->csr_ptr->csr_present; csr_present= pp->csr_ptr->csr_present;
if (csr_present & CP_PWRCYCLE) if (csr_present & CP_PWRCYCLE)
break; break;
} while (getuptime(&t1)==OK && (t1-t0) < micros_to_ticks(100000)); } while (spin_check(&spin));
if (!(csr_present & CP_PWRCYCLE)) if (!(csr_present & CP_PWRCYCLE))
{ {

View File

@ -22,7 +22,7 @@ INCS+= minix/a.out.h minix/bitmap.h minix/callnr.h minix/cdrom.h \
minix/netdriver.h minix/partition.h minix/paths.h \ minix/netdriver.h minix/partition.h minix/paths.h \
minix/portio.h minix/profile.h minix/queryparam.h \ minix/portio.h minix/profile.h minix/queryparam.h \
minix/rs.h minix/safecopies.h minix/sched.h minix/sef.h minix/sound.h \ minix/rs.h minix/safecopies.h minix/sched.h minix/sef.h minix/sound.h \
minix/sys_config.h minix/sysinfo.h minix/syslib.h \ minix/spin.h minix/sys_config.h minix/sysinfo.h minix/syslib.h \
minix/sysutil.h minix/timers.h minix/tty.h minix/type.h minix/types.h \ minix/sysutil.h minix/timers.h minix/tty.h minix/type.h minix/types.h \
minix/u64.h minix/vfsif.h minix/vm.h \ minix/u64.h minix/vfsif.h minix/vm.h \
minix/compiler.h minix/compiler-ack.h minix/sha2.h minix/compiler.h minix/compiler-ack.h minix/sha2.h

View File

@ -22,6 +22,7 @@
#include <minix/syslib.h> #include <minix/syslib.h>
#include <minix/sysutil.h> #include <minix/sysutil.h>
#include <minix/timers.h> #include <minix/timers.h>
#include <minix/spin.h>
#include <minix/bitmap.h> #include <minix/bitmap.h>
#include <machine/interrupt.h> /* IRQ vectors and miscellaneous ports */ #include <machine/interrupt.h> /* IRQ vectors and miscellaneous ports */

38
include/minix/spin.h Normal file
View File

@ -0,0 +1,38 @@
/* Prototypes for condition spinning helper functions (part of libsys). */
#ifndef _MINIX_SPIN_H
#define _MINIX_SPIN_H
/* Opaque spin state structure. */
typedef struct {
int s_state;
u32_t s_usecs;
u64_t s_base_tsc;
clock_t s_base_uptime;
int s_timeout;
} spin_t;
/* Functions. */
_PROTOTYPE( void spin_init, (spin_t *s, u32_t usecs) );
_PROTOTYPE( int spin_check, (spin_t *s) );
/* Macros. */
/* Execute a loop for at least 'u' microseconds, using spin object 's'.
* The body of the loop is guaranteed to be executed at least once.
*/
#define SPIN_FOR(s,u) \
for (spin_init((s), (u)); spin_check((s)); )
/* Return whether spin object 's' timed out after a loop. */
#define SPIN_TIMEOUT(s) ((s)->s_timeout)
/* Spin until the given condition becomes true, or 'u' microseconds expired.
* The condition is guaranteed to be checked at least once.
*/
#define SPIN_UNTIL(c,u) do { \
spin_t s; \
SPIN_FOR(&s,(u)) \
if (c) break; \
} while (0)
#endif /* _MINIX_SPIN_H */

View File

@ -121,7 +121,8 @@ SRCS= \
profile_extern.c \ profile_extern.c \
profile.c \ profile.c \
vprintf.c \ vprintf.c \
timers.c timers.c \
spin.c
CPPFLAGS.sched_start.c+= -I${MINIXSRCDIR} CPPFLAGS.sched_start.c+= -I${MINIXSRCDIR}

99
lib/libsys/spin.c Normal file
View File

@ -0,0 +1,99 @@
/* Helper functions that allow driver writers to easily busy-wait (spin) for a
* condition to become satisfied within a certain maximum time span.
*/
/* This implementation first spins without making any system calls for a
* while, and then starts using system calls (specifically, the system call to
* obtain the current time) while spinning. The reason for this is that in
* many cases, the condition to be checked will become satisfied rather
* quickly, and we want to avoid getting descheduled in that case. However,
* after a while, running out of scheduling quantum will cause our priority to
* be lowered, and we can avoid this by voluntarily giving up the CPU, by
* making a system call.
*/
#include "sysutil.h"
#include <minix/spin.h>
/* Number of microseconds to keep spinning initially, without performing a
* system call. We pick a value somewhat smaller than a typical clock tick.
* Note that for the above reasons, we want to avoid using sys_hz() here.
*/
#define TSC_SPIN 1000 /* in microseconds */
/* Internal spin states. */
enum {
STATE_INIT, /* simply check the condition (once) */
STATE_BASE_TS, /* get the initial TSC value (once) */
STATE_TS, /* use the TSC to spin (up to TSC_SPIN us) */
STATE_UPTIME /* use the clock to spin */
};
PUBLIC void spin_init(spin_t *s, u32_t usecs)
{
/* Initialize the given spin state structure, set to spin at most the
* given number of microseconds.
*/
s->s_state = STATE_INIT;
s->s_usecs = usecs;
s->s_timeout = FALSE;
}
PUBLIC int spin_check(spin_t *s)
{
/* Check whether a timeout has taken place. Return TRUE if the caller
* should continue spinning, and FALSE if a timeout has occurred. The
* implementation assumes that it is okay to spin a little bit too long
* (up to a full clock tick extra).
*/
u64_t cur_tsc, tsc_delta;
clock_t now, micro_delta;
switch (s->s_state) {
case STATE_INIT:
s->s_state = STATE_BASE_TS;
break;
case STATE_BASE_TS:
s->s_state = STATE_TS;
read_tsc_64(&s->s_base_tsc);
break;
case STATE_TS:
read_tsc_64(&cur_tsc);
tsc_delta = sub64(cur_tsc, s->s_base_tsc);
micro_delta = tsc_64_to_micros(tsc_delta);
if (micro_delta >= s->s_usecs) {
s->s_timeout = TRUE;
return FALSE;
}
if (micro_delta >= TSC_SPIN) {
s->s_usecs -= micro_delta;
getuptime(&s->s_base_uptime);
s->s_state = STATE_UPTIME;
}
break;
case STATE_UPTIME:
getuptime(&now);
/* We assume that sys_hz() caches its return value. */
micro_delta = ((now - s->s_base_uptime) * 1000 / sys_hz()) *
1000;
if (micro_delta >= s->s_usecs) {
s->s_timeout = TRUE;
return FALSE;
}
break;
default:
panic("spin_check: invalid state %d", s->s_state);
}
return TRUE;
}