diff options
Diffstat (limited to 'sys/dev/twa/tw_osl_freebsd.c')
-rw-r--r-- | sys/dev/twa/tw_osl_freebsd.c | 179 |
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) { |