summaryrefslogtreecommitdiffstats
path: root/sys/dev/twa/tw_osl_freebsd.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/twa/tw_osl_freebsd.c')
-rw-r--r--sys/dev/twa/tw_osl_freebsd.c179
1 files changed, 142 insertions, 37 deletions
diff --git a/sys/dev/twa/tw_osl_freebsd.c b/sys/dev/twa/tw_osl_freebsd.c
index 09bb55e..5cb25bd 100644
--- a/sys/dev/twa/tw_osl_freebsd.c
+++ b/sys/dev/twa/tw_osl_freebsd.c
@@ -175,6 +175,9 @@ static TW_INT32 twa_detach(device_t dev);
static TW_INT32 twa_shutdown(device_t dev);
static TW_VOID twa_busdma_lock(TW_VOID *lock_arg, bus_dma_lock_op_t op);
static TW_VOID twa_pci_intr(TW_VOID *arg);
+static TW_VOID twa_watchdog(TW_VOID *arg);
+int twa_setup_intr(struct twa_softc *sc);
+int twa_teardown_intr(struct twa_softc *sc);
static TW_INT32 tw_osli_alloc_mem(struct twa_softc *sc);
static TW_VOID tw_osli_free_resources(struct twa_softc *sc);
@@ -238,6 +241,32 @@ twa_probe(device_t dev)
return(ENXIO);
}
+int twa_setup_intr(struct twa_softc *sc)
+{
+ int error = 0;
+
+ if (!(sc->intr_handle) && (sc->irq_res)) {
+ error = bus_setup_intr(sc->bus_dev, sc->irq_res,
+ INTR_TYPE_CAM | INTR_MPSAFE,
+ NULL, twa_pci_intr,
+ sc, &sc->intr_handle);
+ }
+ return( error );
+}
+
+
+int twa_teardown_intr(struct twa_softc *sc)
+{
+ int error = 0;
+
+ if ((sc->intr_handle) && (sc->irq_res)) {
+ error = bus_teardown_intr(sc->bus_dev,
+ sc->irq_res, sc->intr_handle);
+ sc->intr_handle = NULL;
+ }
+ return( error );
+}
+
/*
@@ -354,10 +383,7 @@ twa_attach(device_t dev)
tw_osli_free_resources(sc);
return(ENXIO);
}
- if ((error = bus_setup_intr(sc->bus_dev, sc->irq_res,
- INTR_TYPE_CAM | INTR_MPSAFE,
- NULL, twa_pci_intr,
- sc, &sc->intr_handle))) {
+ if ((error = twa_setup_intr(sc))) {
tw_osli_printf(sc, "error = %d",
TW_CL_SEVERITY_ERROR_STRING,
TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
@@ -412,10 +438,77 @@ twa_attach(device_t dev)
return(error);
}
+ sc->watchdog_index = 0;
+ callout_init(&(sc->watchdog_callout[0]), CALLOUT_MPSAFE);
+ callout_init(&(sc->watchdog_callout[1]), CALLOUT_MPSAFE);
+ callout_reset(&(sc->watchdog_callout[0]), 5*hz, twa_watchdog, &sc->ctlr_handle);
+
return(0);
}
+static TW_VOID
+twa_watchdog(TW_VOID *arg)
+{
+ struct tw_cl_ctlr_handle *ctlr_handle =
+ (struct tw_cl_ctlr_handle *)arg;
+ struct twa_softc *sc = ctlr_handle->osl_ctlr_ctxt;
+ int i;
+ int i_need_a_reset = 0;
+ int driver_is_active = 0;
+ int my_watchdog_was_pending = 1234;
+ TW_UINT64 current_time;
+ struct tw_osli_req_context *my_req;
+
+
+//==============================================================================
+ current_time = (TW_UINT64) (tw_osl_get_local_time());
+
+ for (i = 0; i < TW_OSLI_MAX_NUM_REQUESTS; i++) {
+ my_req = &(sc->req_ctx_buf[i]);
+
+ if ((my_req->state == TW_OSLI_REQ_STATE_BUSY) &&
+ (my_req->deadline) &&
+ (my_req->deadline < current_time)) {
+ tw_cl_set_reset_needed(ctlr_handle);
+#ifdef TW_OSL_DEBUG
+ device_printf((sc)->bus_dev, "Request %d timed out! d = %p, c = %p\n", i, (void*)my_req->deadline, (void*)current_time);
+#else /* TW_OSL_DEBUG */
+ device_printf((sc)->bus_dev, "Request %d timed out!\n", i);
+#endif /* TW_OSL_DEBUG */
+ break;
+ }
+ }
+//==============================================================================
+
+ i_need_a_reset = tw_cl_is_reset_needed(ctlr_handle);
+
+ i = (int) ((sc->watchdog_index++) & 1);
+
+ driver_is_active = tw_cl_is_active(ctlr_handle);
+
+ if (i_need_a_reset) {
+#ifdef TW_OSL_DEBUG
+ device_printf((sc)->bus_dev, "Watchdog rescheduled in 70 seconds\n");
+#endif /* TW_OSL_DEBUG */
+ my_watchdog_was_pending =
+ callout_reset(&(sc->watchdog_callout[i]), 70*hz, twa_watchdog, &sc->ctlr_handle);
+ tw_cl_reset_ctlr(ctlr_handle);
+#ifdef TW_OSL_DEBUG
+ device_printf((sc)->bus_dev, "Watchdog reset completed!\n");
+#endif /* TW_OSL_DEBUG */
+ } else if (driver_is_active) {
+ my_watchdog_was_pending =
+ callout_reset(&(sc->watchdog_callout[i]), 5*hz, twa_watchdog, &sc->ctlr_handle);
+ }
+#ifdef TW_OSL_DEBUG
+ if (i_need_a_reset || my_watchdog_was_pending)
+ device_printf((sc)->bus_dev, "i_need_a_reset = %d, "
+ "driver_is_active = %d, my_watchdog_was_pending = %d\n",
+ i_need_a_reset, driver_is_active, my_watchdog_was_pending);
+#endif /* TW_OSL_DEBUG */
+}
+
/*
* Function name: tw_osli_alloc_mem
@@ -715,9 +808,7 @@ tw_osli_free_resources(struct twa_softc *sc)
/* Disconnect the interrupt handler. */
- if (sc->intr_handle)
- if ((error = bus_teardown_intr(sc->bus_dev,
- sc->irq_res, sc->intr_handle)))
+ if ((error = twa_teardown_intr(sc)))
tw_osli_dbg_dprintf(1, sc,
"teardown_intr returned %d", error);
@@ -809,6 +900,9 @@ twa_shutdown(device_t dev)
tw_osli_dbg_dprintf(3, sc, "entered");
+ /* Disconnect interrupts. */
+ error = twa_teardown_intr(sc);
+
/* Disconnect from the controller. */
if ((error = tw_cl_shutdown_ctlr(&(sc->ctlr_handle), 0))) {
tw_osli_printf(sc, "error = %d",
@@ -997,33 +1091,35 @@ tw_osli_fw_passthru(struct twa_softc *sc, TW_INT8 *buf)
error = 0; /* False error */
break;
}
- tw_osli_printf(sc, "request = %p",
- TW_CL_SEVERITY_ERROR_STRING,
- TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
- 0x2018,
- "Passthru request timed out!",
- req);
- /*
- * Should I check here if the timeout happened
- * because of yet another reset, and not do a
- * second reset?
- */
- tw_cl_reset_ctlr(&sc->ctlr_handle);
+ if (!(tw_cl_is_reset_needed(&(req->ctlr->ctlr_handle)))) {
+#ifdef TW_OSL_DEBUG
+ tw_osli_printf(sc, "request = %p",
+ TW_CL_SEVERITY_ERROR_STRING,
+ TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
+ 0x2018,
+ "Passthru request timed out!",
+ req);
+#else /* TW_OSL_DEBUG */
+ device_printf((sc)->bus_dev, "Passthru request timed out!\n");
+#endif /* TW_OSL_DEBUG */
+ tw_cl_reset_ctlr(&(req->ctlr->ctlr_handle));
+ }
+
+ error = 0;
+ end_time = tw_osl_get_local_time() + timeout;
+ continue;
/*
* Don't touch req after a reset. It (and any
- * associated data) will already have been
+ * associated data) will be
* unmapped by the callback.
*/
- user_buf->driver_pkt.os_status = error;
- error = ETIMEDOUT;
- goto fw_passthru_err;
}
/*
* Either the request got completed, or we were woken up by a
* signal. Calculate the new timeout, in case it was the latter.
*/
timeout = (end_time - tw_osl_get_local_time());
- }
+ } /* End of while loop */
/* If there was a payload, copy it back. */
if ((!error) && (req->length))
@@ -1037,19 +1133,9 @@ tw_osli_fw_passthru(struct twa_softc *sc, TW_INT8 *buf)
error);
fw_passthru_err:
- /*
- * Print the failure message. For some reason, on certain OS versions,
- * printing this error message during reset hangs the display (although
- * the rest of the system is running fine. So, don't print it if the
- * failure was due to a reset.
- */
- if ((error) && (error != TW_CL_ERR_REQ_BUS_RESET))
- tw_osli_printf(sc, "error = %d",
- TW_CL_SEVERITY_ERROR_STRING,
- TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
- 0x201A,
- "Firmware passthru failed!",
- error);
+
+ if (req_pkt->status == TW_CL_ERR_REQ_BUS_RESET)
+ error = EBUSY;
user_buf->driver_pkt.os_status = error;
/* Free resources. */
@@ -1073,6 +1159,8 @@ TW_VOID
tw_osl_complete_passthru(struct tw_cl_req_handle *req_handle)
{
struct tw_osli_req_context *req = req_handle->osl_req_ctxt;
+ struct tw_cl_req_packet *req_pkt =
+ (struct tw_cl_req_packet *)(&req->req_pkt);
struct twa_softc *sc = req->ctlr;
tw_osli_dbg_dprintf(5, sc, "entered");
@@ -1120,6 +1208,9 @@ tw_osl_complete_passthru(struct tw_cl_req_handle *req_handle)
if (req->flags & TW_OSLI_REQ_FLAGS_MAPPED)
return;
+ if (req_pkt->status == TW_CL_ERR_REQ_BUS_RESET)
+ return;
+
tw_osli_printf(sc, "request = %p",
TW_CL_SEVERITY_ERROR_STRING,
TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
@@ -1166,6 +1257,7 @@ tw_osli_get_request(struct twa_softc *sc)
req->req_handle.is_io = 0;
req->data = NULL;
req->length = 0;
+ req->deadline = 0;
req->real_data = NULL;
req->real_length = 0;
req->state = TW_OSLI_REQ_STATE_INIT;/* req being initialized */
@@ -1207,6 +1299,11 @@ twa_map_load_data_callback(TW_VOID *arg, bus_dma_segment_t *segs,
tw_osli_dbg_dprintf(10, sc, "entered");
+ if (error == EINVAL) {
+ req->error_code = error;
+ return;
+ }
+
/* Mark the request as currently being processed. */
req->state = TW_OSLI_REQ_STATE_BUSY;
/* Move the request into the busy queue. */
@@ -1400,6 +1497,14 @@ tw_osli_map_request(struct tw_osli_req_context *req)
mtx_unlock_spin(sc->io_lock);
error = 0;
} else {
+ tw_osli_printf(sc, "error = %d",
+ TW_CL_SEVERITY_ERROR_STRING,
+ TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
+ 0x9999,
+ "Failed to map DMA memory "
+ "for I/O request",
+ error);
+ req->flags |= TW_OSLI_REQ_FLAGS_FAILED;
/* Free alignment buffer if it was used. */
if (req->flags &
TW_OSLI_REQ_FLAGS_DATA_COPY_NEEDED) {
OpenPOWER on IntegriCloud