summaryrefslogtreecommitdiffstats
path: root/sys/dev/aac/aac.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/aac/aac.c')
-rw-r--r--sys/dev/aac/aac.c89
1 files changed, 50 insertions, 39 deletions
diff --git a/sys/dev/aac/aac.c b/sys/dev/aac/aac.c
index 42587dd..046fa19 100644
--- a/sys/dev/aac/aac.c
+++ b/sys/dev/aac/aac.c
@@ -624,45 +624,43 @@ aac_intr(void *arg)
{
struct aac_softc *sc;
u_int16_t reason;
+ u_int32_t *resp_queue;
debug_called(2);
sc = (struct aac_softc *)arg;
- reason = AAC_GET_ISTATUS(sc);
+ /*
+ * Optimize the common case of adapter response interrupts.
+ * We must read from the card prior to processing the responses
+ * to ensure the clear is flushed prior to accessing the queues.
+ * Reading the queues from local memory might save us a PCI read.
+ */
+ resp_queue = sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE];
+ if (resp_queue[AAC_PRODUCER_INDEX] != resp_queue[AAC_CONSUMER_INDEX])
+ reason = AAC_DB_RESPONSE_READY;
+ else
+ reason = AAC_GET_ISTATUS(sc);
+ AAC_CLEAR_ISTATUS(sc, reason);
+ (void)AAC_GET_ISTATUS(sc);
+
+ /* It's not ok to return here because of races with the previous step */
+ if (reason & AAC_DB_RESPONSE_READY)
+ aac_host_response(sc);
/* controller wants to talk to the log */
- if (reason & AAC_DB_PRINTF) {
- AAC_CLEAR_ISTATUS(sc, AAC_DB_PRINTF);
+ if (reason & AAC_DB_PRINTF)
aac_print_printf(sc);
- }
/* controller has a message for us? */
if (reason & AAC_DB_COMMAND_READY) {
- AAC_CLEAR_ISTATUS(sc, AAC_DB_COMMAND_READY);
/* XXX What happens if the thread is already awake? */
if (sc->aifflags & AAC_AIFFLAGS_RUNNING) {
sc->aifflags |= AAC_AIFFLAGS_PENDING;
wakeup(sc->aifthread);
}
}
-
- /* controller has a response for us? */
- if (reason & AAC_DB_RESPONSE_READY) {
- AAC_CLEAR_ISTATUS(sc, AAC_DB_RESPONSE_READY);
- aac_host_response(sc);
- }
-
- /*
- * spurious interrupts that we don't use - reset the mask and clear the
- * interrupts
- */
- if (reason & (AAC_DB_COMMAND_NOT_FULL | AAC_DB_RESPONSE_NOT_FULL)) {
- AAC_UNMASK_INTERRUPTS(sc);
- AAC_CLEAR_ISTATUS(sc, AAC_DB_COMMAND_NOT_FULL |
- AAC_DB_RESPONSE_NOT_FULL);
- }
-};
+}
/*
* Command Processing
@@ -729,7 +727,6 @@ aac_start(struct aac_command *cm)
/* save a pointer to the command for speedy reverse-lookup */
cm->cm_fib->Header.SenderData = (u_int32_t)cm; /* XXX 64-bit physical
* address issue */
-
/* put the FIB on the outbound queue */
error = aac_enqueue_fib(sc, cm->cm_queue, cm);
return(error);
@@ -928,11 +925,14 @@ aac_bio_command(struct aac_softc *sc, struct aac_command **cmp)
/* build the FIB */
fib = cm->cm_fib;
fib->Header.XferState =
- AAC_FIBSTATE_HOSTOWNED |
- AAC_FIBSTATE_INITIALISED |
- AAC_FIBSTATE_FROMHOST |
- AAC_FIBSTATE_REXPECTED |
- AAC_FIBSTATE_NORM;
+ AAC_FIBSTATE_HOSTOWNED |
+ AAC_FIBSTATE_INITIALISED |
+ AAC_FIBSTATE_EMPTY |
+ AAC_FIBSTATE_FROMHOST |
+ AAC_FIBSTATE_REXPECTED |
+ AAC_FIBSTATE_NORM |
+ AAC_FIBSTATE_ASYNC |
+ AAC_FIBSTATE_FAST_RESPONSE;
fib->Header.Command = ContainerCommand;
fib->Header.Size = sizeof(struct aac_fib_header);
@@ -1081,7 +1081,8 @@ aac_release_command(struct aac_command *cm)
* initialised here for debugging purposes only.
*/
cm->cm_fib->Header.SenderFibAddress = (u_int32_t)cm->cm_fib;
- cm->cm_fib->Header.ReceiverFibAddress = cm->cm_fibphys;
+ cm->cm_fib->Header.ReceiverFibAddress = (u_int32_t)cm->cm_fibphys;
+ cm->cm_fib->Header.SenderData = 0;
aac_enqueue_free(cm);
}
@@ -1121,7 +1122,7 @@ aac_alloc_commands(struct aac_softc *sc)
bus_dmamap_load(sc->aac_fib_dmat, sc->aac_fibmap, sc->aac_fibs,
AAC_FIB_COUNT * sizeof(struct aac_fib),
aac_map_command_helper, sc, 0);
-
+ bzero(sc->aac_fibs, AAC_FIB_COUNT * sizeof(struct aac_fib));
/* initialise constant fields in the command structure */
for (i = 0; i < AAC_FIB_COUNT; i++) {
cm = &sc->aac_command[i];
@@ -1206,12 +1207,12 @@ aac_map_command(struct aac_command *cm)
cm->cm_data, cm->cm_datalen,
aac_map_command_sg, cm, 0);
- if (cm->cm_flags & AAC_CMD_DATAIN)
- bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
- BUS_DMASYNC_PREREAD);
- if (cm->cm_flags & AAC_CMD_DATAOUT)
- bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
- BUS_DMASYNC_PREWRITE);
+ if (cm->cm_flags & AAC_CMD_DATAIN)
+ bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
+ BUS_DMASYNC_PREREAD);
+ if (cm->cm_flags & AAC_CMD_DATAOUT)
+ bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap,
+ BUS_DMASYNC_PREWRITE);
}
cm->cm_flags |= AAC_CMD_MAPPED;
}
@@ -1362,10 +1363,11 @@ aac_init(struct aac_softc *sc)
*/
ip = &sc->aac_common->ac_init;
ip->InitStructRevision = AAC_INIT_STRUCT_REVISION;
+ ip->MiniPortRevision = AAC_INIT_STRUCT_MINIPORT_REVISION;
ip->AdapterFibsPhysicalAddress = sc->aac_common_busaddr +
offsetof(struct aac_common, ac_fibs);
- ip->AdapterFibsVirtualAddress = &sc->aac_common->ac_fibs[0];
+ ip->AdapterFibsVirtualAddress = (u_int32_t)&sc->aac_common->ac_fibs[0];
ip->AdapterFibsSize = AAC_ADAPTER_FIBS * sizeof(struct aac_fib);
ip->AdapterFibAlign = sizeof(struct aac_fib);
@@ -1373,7 +1375,8 @@ aac_init(struct aac_softc *sc)
offsetof(struct aac_common, ac_printf);
ip->PrintfBufferSize = AAC_PRINTF_BUFSIZE;
- ip->HostPhysMemPages = 0; /* not used? */
+ /* The adapter assumes that pages are 4K in size */
+ ip->HostPhysMemPages = ctob(physmem) / AAC_PAGE_SIZE;
ip->HostElapsedSeconds = time_second; /* reset later if invalid */
/*
@@ -1398,7 +1401,6 @@ aac_init(struct aac_softc *sc)
ip->CommHeaderAddress = sc->aac_common_busaddr +
((u_int32_t)sc->aac_queues -
(u_int32_t)sc->aac_common);
- bzero(sc->aac_queues, sizeof(struct aac_queue_table));
sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] =
AAC_HOST_NORM_CMD_ENTRIES;
@@ -1704,6 +1706,15 @@ aac_dequeue_fib(struct aac_softc *sc, int queue, u_int32_t *fib_size,
*fib_addr = (struct aac_fib *)(sc->aac_qentries[queue] +
ci)->aq_fib_addr;
+ /*
+ * Is this a fast response? If it is, update the fib fields in
+ * local memory so the whole fib doesn't have to be DMA'd back up.
+ */
+ if (*(uintptr_t *)fib_addr & 0x01) {
+ *(uintptr_t *)fib_addr &= ~0x01;
+ (*fib_addr)->Header.XferState |= AAC_FIBSTATE_DONEADAP;
+ *((u_int32_t*)((*fib_addr)->data)) = AAC_ERROR_NORMAL;
+ }
/* update consumer index */
sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX] = ci + 1;
OpenPOWER on IntegriCloud