diff --git a/sys/dev/hfa/fore_aali.h b/sys/dev/hfa/fore_aali.h index ccf39221428..3e00a941072 100644 --- a/sys/dev/hfa/fore_aali.h +++ b/sys/dev/hfa/fore_aali.h @@ -331,6 +331,8 @@ typedef volatile unsigned long Cmd_code; #define CMD_SET_OC3_REG 0x07 /* Set SUNI OC3 registers */ #define CMD_GET_OC3_REG 0x08 /* Get SUNI OC3 registers */ #define CMD_GET_PROM 0x09 /* Get PROM data */ +#define CMD_ZERO_STATS4 0x09 /* FT 4 Zero stats (unimpl) */ +#define CMD_GET_PROM4 0x0a /* FT 4 Get PROM data */ #define CMD_INTR_REQ 0x80 /* Request host interrupt */ #endif /* _KERNEL */ diff --git a/sys/dev/hfa/fore_command.c b/sys/dev/hfa/fore_command.c index e73091f87d1..d4442a9139d 100644 --- a/sys/dev/hfa/fore_command.c +++ b/sys/dev/hfa/fore_command.c @@ -235,8 +235,9 @@ fore_cmd_drain(fup) /* * Process each completed entry + * ForeThought 4 may set QSTAT_ERROR without QSTAT_COMPLETED. */ - while (*fup->fu_cmd_head->hcq_status & QSTAT_COMPLETED) { + while (*fup->fu_cmd_head->hcq_status & (QSTAT_COMPLETED | QSTAT_ERROR)) { hcp = fup->fu_cmd_head; @@ -333,6 +334,14 @@ fore_cmd_drain(fup) break; case CMD_GET_PROM: + if (fup->fu_ft4) + goto unknown; + goto prom; + + case CMD_GET_PROM4: + if (!fup->fu_ft4) + goto unknown; + prom: if (*hcp->hcq_status & QSTAT_ERROR) { /* * Couldn't get PROM data @@ -371,6 +380,7 @@ fore_cmd_drain(fup) break; default: + unknown: log(LOG_ERR, "fore_cmd_drain: unknown command %ld\n", hcp->hcq_code); } diff --git a/sys/dev/hfa/fore_init.c b/sys/dev/hfa/fore_init.c index 216ed32a82e..2957b7c3503 100644 --- a/sys/dev/hfa/fore_init.c +++ b/sys/dev/hfa/fore_init.c @@ -95,6 +95,8 @@ fore_initialize(fup) Init_parms *inp; caddr_t errmsg; u_long vers; + u_int c, wait; +#define MAX_WAIT 100 /* * Must wait until firmware has been downloaded and is running @@ -149,6 +151,11 @@ fore_initialize(fup) sizeof(fup->fu_config.ac_firm_vers), "%ld.%ld.%ld", (vers >> 16) & 0xff, (vers >> 8) & 0xff, vers & 0xff); + if (((vers >> 16) & 0xff) == 4) + fup->fu_ft4 = 1; + else + fup->fu_ft4 = 0; + #ifdef notdef /* * Turn on CP debugging @@ -193,7 +200,41 @@ fore_initialize(fup) * the CP to interrupt to signal completion */ inp->init_status = CP_WRITE(QSTAT_PENDING); - inp->init_cmd = CP_WRITE(CMD_INIT | CMD_INTR_REQ); + + if (!fup->fu_ft4) { + inp->init_cmd = CP_WRITE(CMD_INIT | CMD_INTR_REQ); + return; + } + inp->init_cmd = CP_WRITE(CMD_INIT); + + /* + * With the ForeThought 4.X image it appears that we need to + * busy wait on the initializisation command to complete. + * Otherwise the command queue address (the first word + * of the queue structure) will be mangled. + */ + c = 0; + for (wait = 0; wait < MAX_WAIT; wait++) { + c = CP_READ(inp->init_status); + if (c & QSTAT_COMPLETED) + break; + DELAY(1000); + } + if (c & QSTAT_ERROR) { + log(LOG_ERR, "fore initialization failed: intf=%s%d, " + "hbeat=0x%lx\n", fup->fu_pif.pif_name, + fup->fu_pif.pif_unit, (u_long)CP_READ(aap->aali_heartbeat)); + fore_interface_free(fup); + return; + } + if (!(c & QSTAT_COMPLETED)) { + log(LOG_ERR, "fore initialization timed out: intf=%s%d, " + "hbeat=0x%lx\n", fup->fu_pif.pif_name, fup->fu_pif.pif_unit, + (u_long)CP_READ(aap->aali_heartbeat)); + fore_interface_free(fup); + return; + } + fore_initialize_complete(fup); return; failed: @@ -277,6 +318,9 @@ fore_initialize_complete(fup) * This will be called after CP initialization has completed. * There is (currently) no retry if this fails. * + * It took me some time to find out that FT3 and FT4 use different + * operation codes for GET_PROM. + * * Called at interrupt level. * * Arguments: @@ -302,7 +346,10 @@ fore_get_prom(fup) /* * Queue entry available, so set our view of things up */ - hcp->hcq_code = CMD_GET_PROM; + if (fup->fu_ft4) + hcp->hcq_code = CMD_GET_PROM4; + else + hcp->hcq_code = CMD_GET_PROM; hcp->hcq_arg = NULL; fup->fu_cmd_tail = hcp->hcq_next; @@ -319,7 +366,7 @@ fore_get_prom(fup) return; } cqp->cmdq_prom.prom_buffer = (CP_dma) CP_WRITE(fup->fu_promd); - cqp->cmdq_prom.prom_cmd = CP_WRITE(CMD_GET_PROM | CMD_INTR_REQ); + cqp->cmdq_prom.prom_cmd = CP_WRITE(hcp->hcq_code | CMD_INTR_REQ); } else { /* diff --git a/sys/dev/hfa/fore_intr.c b/sys/dev/hfa/fore_intr.c index 2193a5161b6..319c66548a3 100644 --- a/sys/dev/hfa/fore_intr.c +++ b/sys/dev/hfa/fore_intr.c @@ -171,6 +171,10 @@ fore_intr(arg) */ if ((fup->fu_flags & CUF_INITED) == 0) { + if (fup->fu_ft4) + /* may not happen */ + goto done; + /* * We're just initializing device now, so see if * the initialization command has completed diff --git a/sys/dev/hfa/fore_var.h b/sys/dev/hfa/fore_var.h index 6f7dd4c59f5..ba26928cef3 100644 --- a/sys/dev/hfa/fore_var.h +++ b/sys/dev/hfa/fore_var.h @@ -226,6 +226,7 @@ struct fore_unit { Fore_prom *fu_prom; /* Device PROM buffer */ Fore_prom *fu_promd; /* Device PROM buffer (DMA) */ struct callout_handle fu_thandle; /* Timer handle */ + int fu_ft4; /* Running ForeThought 4 firmware */ }; typedef struct fore_unit Fore_unit;