summaryrefslogtreecommitdiffstats
path: root/sys/dev/hfa
diff options
context:
space:
mode:
authorharti <harti@FreeBSD.org>2003-07-31 14:20:07 +0000
committerharti <harti@FreeBSD.org>2003-07-31 14:20:07 +0000
commit4bd81e8df02c228993397aaab260c6c41c49f324 (patch)
tree5ac17744fbfaed400fa40b954c5004756b89b4eb /sys/dev/hfa
parentf606719cc510c63902ecf1fc001d0da6fba90120 (diff)
downloadFreeBSD-src-4bd81e8df02c228993397aaab260c6c41c49f324.zip
FreeBSD-src-4bd81e8df02c228993397aaab260c6c41c49f324.tar.gz
Make the driver to work with firmware version 4.1.12 (other 4.X.Y should
also do it). Three problems have been encountered: 1. The initialisation command does not work in interrupt mode. Whether this is a firmware bug or a feature is not clear. The original Fore drivers execute the initialize command always in polling mode, so it appears that this behaviour is expected. When we detect a 4.X.Y firmware do busy wait on the command status. 2. The command code of the GET_PROM command has changed. This is an unofficial command anyway. What was GET_PROM in 3.X.Y is CLEAR_STATS in 4.X.Y (although unimplemented in the firmware). We need to use the correct code depending on the firmware. 3. The 4.X.Y firmware can set the error flag in the command status without also setting the completion flag (as the documenation says). Check both variants. An additional field in the per-card structure fu_ft4 is TRUE when we have detected a 4.X.Y firmware. Otherwise it is false. The behaviour of the driver when using a 3.X.Y firmware should be identical to the previous behaviour. This change will enable traffic shaping of (at least one) CBR channels.
Diffstat (limited to 'sys/dev/hfa')
-rw-r--r--sys/dev/hfa/fore_aali.h2
-rw-r--r--sys/dev/hfa/fore_command.c12
-rw-r--r--sys/dev/hfa/fore_init.c53
-rw-r--r--sys/dev/hfa/fore_intr.c4
-rw-r--r--sys/dev/hfa/fore_var.h1
5 files changed, 68 insertions, 4 deletions
diff --git a/sys/dev/hfa/fore_aali.h b/sys/dev/hfa/fore_aali.h
index ccf3922..3e00a94 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 e73091f..d4442a9 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 216ed32a..2957b7c 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 2193a51..319c665 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 6f7dd4c..ba26928 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;
OpenPOWER on IntegriCloud