|
@@ -1564,340 +1564,6 @@ static void scic_sds_controller_process_completions(
|
|
|
|
|
|
}
|
|
|
|
|
|
-/**
|
|
|
- * This method is a private routine for processing the completion queue entries.
|
|
|
- * @this_controller:
|
|
|
- *
|
|
|
- */
|
|
|
-static void scic_sds_controller_transitioned_process_completions(
|
|
|
- struct scic_sds_controller *this_controller)
|
|
|
-{
|
|
|
- u32 completion_count = 0;
|
|
|
- u32 completion_entry;
|
|
|
- u32 get_index;
|
|
|
- u32 get_cycle;
|
|
|
- u32 event_index;
|
|
|
- u32 event_cycle;
|
|
|
-
|
|
|
- dev_dbg(scic_to_dev(this_controller),
|
|
|
- "%s: completion queue begining get:0x%08x\n",
|
|
|
- __func__,
|
|
|
- this_controller->completion_queue_get);
|
|
|
-
|
|
|
- /* Get the component parts of the completion queue */
|
|
|
- get_index = NORMALIZE_GET_POINTER(this_controller->completion_queue_get);
|
|
|
- get_cycle = SMU_CQGR_CYCLE_BIT & this_controller->completion_queue_get;
|
|
|
-
|
|
|
- event_index = NORMALIZE_EVENT_POINTER(this_controller->completion_queue_get);
|
|
|
- event_cycle = SMU_CQGR_EVENT_CYCLE_BIT & this_controller->completion_queue_get;
|
|
|
-
|
|
|
- while (
|
|
|
- NORMALIZE_GET_POINTER_CYCLE_BIT(get_cycle)
|
|
|
- == COMPLETION_QUEUE_CYCLE_BIT(
|
|
|
- this_controller->completion_queue[get_index])
|
|
|
- ) {
|
|
|
- completion_count++;
|
|
|
-
|
|
|
- completion_entry = this_controller->completion_queue[get_index];
|
|
|
- INCREMENT_COMPLETION_QUEUE_GET(this_controller, get_index, get_cycle);
|
|
|
-
|
|
|
- dev_dbg(scic_to_dev(this_controller),
|
|
|
- "%s: completion queue entry:0x%08x\n",
|
|
|
- __func__,
|
|
|
- completion_entry);
|
|
|
-
|
|
|
- switch (SCU_GET_COMPLETION_TYPE(completion_entry)) {
|
|
|
- case SCU_COMPLETION_TYPE_TASK:
|
|
|
- scic_sds_controller_task_completion(this_controller, completion_entry);
|
|
|
- break;
|
|
|
-
|
|
|
- case SCU_COMPLETION_TYPE_NOTIFY:
|
|
|
- case SCU_COMPLETION_TYPE_EVENT:
|
|
|
- /*
|
|
|
- * Presently we do the same thing with a notify event that we
|
|
|
- * do with the other event codes. */
|
|
|
- INCREMENT_EVENT_QUEUE_GET(this_controller, event_index, event_cycle);
|
|
|
- /* Fall-through */
|
|
|
-
|
|
|
- case SCU_COMPLETION_TYPE_SDMA:
|
|
|
- case SCU_COMPLETION_TYPE_UFI:
|
|
|
- default:
|
|
|
- dev_warn(scic_to_dev(this_controller),
|
|
|
- "%s: SCIC Controller ignoring completion type "
|
|
|
- "%x\n",
|
|
|
- __func__,
|
|
|
- completion_entry);
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /* Update the get register if we completed one or more entries */
|
|
|
- if (completion_count > 0) {
|
|
|
- this_controller->completion_queue_get =
|
|
|
- SMU_CQGR_GEN_BIT(ENABLE)
|
|
|
- | SMU_CQGR_GEN_BIT(EVENT_ENABLE)
|
|
|
- | event_cycle | SMU_CQGR_GEN_VAL(EVENT_POINTER, event_index)
|
|
|
- | get_cycle | SMU_CQGR_GEN_VAL(POINTER, get_index);
|
|
|
-
|
|
|
- SMU_CQGR_WRITE(this_controller, this_controller->completion_queue_get);
|
|
|
- }
|
|
|
-
|
|
|
- dev_dbg(scic_to_dev(this_controller),
|
|
|
- "%s: completion queue ending get:0x%08x\n",
|
|
|
- __func__,
|
|
|
- this_controller->completion_queue_get);
|
|
|
-}
|
|
|
-
|
|
|
-/*
|
|
|
- * ****************************************************************************-
|
|
|
- * * SCIC SDS Controller Interrupt and Completion functions
|
|
|
- * ****************************************************************************- */
|
|
|
-
|
|
|
-/**
|
|
|
- * This method provides standard (common) processing of interrupts for polling
|
|
|
- * and legacy based interrupts.
|
|
|
- * @controller:
|
|
|
- * @interrupt_status:
|
|
|
- *
|
|
|
- * This method returns a boolean (bool) indication as to whether an completions
|
|
|
- * are pending to be processed. true if an interrupt is to be processed false
|
|
|
- * if no interrupt was pending
|
|
|
- */
|
|
|
-static bool scic_sds_controller_standard_interrupt_handler(
|
|
|
- struct scic_sds_controller *this_controller,
|
|
|
- u32 interrupt_status)
|
|
|
-{
|
|
|
- bool is_completion_needed = false;
|
|
|
-
|
|
|
- if ((interrupt_status & SMU_ISR_QUEUE_ERROR) ||
|
|
|
- ((interrupt_status & SMU_ISR_QUEUE_SUSPEND) &&
|
|
|
- (!scic_sds_controller_completion_queue_has_entries(
|
|
|
- this_controller)))) {
|
|
|
- /*
|
|
|
- * We have a fatal error on the read of the completion queue bar
|
|
|
- * OR
|
|
|
- * We have a fatal error there is nothing in the completion queue
|
|
|
- * but we have a report from the hardware that the queue is full
|
|
|
- * / @todo how do we request the a controller reset */
|
|
|
- is_completion_needed = true;
|
|
|
- this_controller->encountered_fatal_error = true;
|
|
|
- }
|
|
|
-
|
|
|
- if (scic_sds_controller_completion_queue_has_entries(this_controller)) {
|
|
|
- is_completion_needed = true;
|
|
|
- }
|
|
|
-
|
|
|
- return is_completion_needed;
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * This is the method provided to handle polling for interrupts for the
|
|
|
- * controller object.
|
|
|
- *
|
|
|
- * bool true if an interrupt is to be processed false if no interrupt was
|
|
|
- * pending
|
|
|
- */
|
|
|
-static bool scic_sds_controller_polling_interrupt_handler(
|
|
|
- struct scic_sds_controller *scic)
|
|
|
-{
|
|
|
- u32 interrupt_status;
|
|
|
-
|
|
|
- /*
|
|
|
- * In INTERRUPT_POLLING_MODE we exit the interrupt handler if the
|
|
|
- * hardware indicates nothing is pending. Since we are not being
|
|
|
- * called from a real interrupt, we don't want to confuse the hardware
|
|
|
- * by servicing the completion queue before the hardware indicates it
|
|
|
- * is ready. We'll simply wait for another polling interval and check
|
|
|
- * again.
|
|
|
- */
|
|
|
- interrupt_status = SMU_ISR_READ(scic);
|
|
|
- if ((interrupt_status &
|
|
|
- (SMU_ISR_COMPLETION |
|
|
|
- SMU_ISR_QUEUE_ERROR |
|
|
|
- SMU_ISR_QUEUE_SUSPEND)) == 0) {
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
- return scic_sds_controller_standard_interrupt_handler(
|
|
|
- scic, interrupt_status);
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * This is the method provided to handle completions when interrupt polling is
|
|
|
- * in use.
|
|
|
- */
|
|
|
-static void scic_sds_controller_polling_completion_handler(
|
|
|
- struct scic_sds_controller *scic)
|
|
|
-{
|
|
|
- if (scic->encountered_fatal_error == true) {
|
|
|
- dev_err(scic_to_dev(scic),
|
|
|
- "%s: SCIC Controller has encountered a fatal error.\n",
|
|
|
- __func__);
|
|
|
-
|
|
|
- sci_base_state_machine_change_state(
|
|
|
- scic_sds_controller_get_base_state_machine(scic),
|
|
|
- SCI_BASE_CONTROLLER_STATE_FAILED);
|
|
|
- } else if (scic_sds_controller_completion_queue_has_entries(scic)) {
|
|
|
- if (scic->restrict_completions == false)
|
|
|
- scic_sds_controller_process_completions(scic);
|
|
|
- else
|
|
|
- scic_sds_controller_transitioned_process_completions(
|
|
|
- scic);
|
|
|
- }
|
|
|
-
|
|
|
- /*
|
|
|
- * The interrupt handler does not adjust the CQ's
|
|
|
- * get pointer. So, SCU's INTx pin stays asserted during the
|
|
|
- * interrupt handler even though it tries to clear the interrupt
|
|
|
- * source. Therefore, the completion handler must ensure that the
|
|
|
- * interrupt source is cleared. Otherwise, we get a spurious
|
|
|
- * interrupt for which the interrupt handler will not issue a
|
|
|
- * corresponding completion event. Also, we unmask interrupts.
|
|
|
- */
|
|
|
- SMU_ISR_WRITE(
|
|
|
- scic,
|
|
|
- (u32)(SMU_ISR_COMPLETION | SMU_ISR_QUEUE_ERROR | SMU_ISR_QUEUE_SUSPEND)
|
|
|
- );
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * This is the method provided to handle legacy interrupts for the controller
|
|
|
- * object.
|
|
|
- *
|
|
|
- * bool true if an interrupt is processed false if no interrupt was processed
|
|
|
- */
|
|
|
-static bool scic_sds_controller_legacy_interrupt_handler(
|
|
|
- struct scic_sds_controller *scic)
|
|
|
-{
|
|
|
- u32 interrupt_status;
|
|
|
- bool is_completion_needed;
|
|
|
-
|
|
|
- interrupt_status = SMU_ISR_READ(scic);
|
|
|
- is_completion_needed = scic_sds_controller_standard_interrupt_handler(
|
|
|
- scic, interrupt_status);
|
|
|
-
|
|
|
- return is_completion_needed;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-/**
|
|
|
- * This is the method provided to handle legacy completions it is expected that
|
|
|
- * the SCI User will call this completion handler anytime the interrupt
|
|
|
- * handler reports that it has handled an interrupt.
|
|
|
- */
|
|
|
-static void scic_sds_controller_legacy_completion_handler(
|
|
|
- struct scic_sds_controller *scic)
|
|
|
-{
|
|
|
- scic_sds_controller_polling_completion_handler(scic);
|
|
|
- SMU_IMR_WRITE(scic, 0x00000000);
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * This is the method provided to handle an MSIX interrupt message when there
|
|
|
- * is just a single MSIX message being provided by the hardware. This mode
|
|
|
- * of operation is single vector mode.
|
|
|
- *
|
|
|
- * bool true if an interrupt is processed false if no interrupt was processed
|
|
|
- */
|
|
|
-static bool scic_sds_controller_single_vector_interrupt_handler(
|
|
|
- struct scic_sds_controller *scic)
|
|
|
-{
|
|
|
- u32 interrupt_status;
|
|
|
-
|
|
|
- /*
|
|
|
- * Mask the interrupts
|
|
|
- * There is a race in the hardware that could cause us not to be notified
|
|
|
- * of an interrupt completion if we do not take this step. We will unmask
|
|
|
- * the interrupts in the completion routine. */
|
|
|
- SMU_IMR_WRITE(scic, 0xFFFFFFFF);
|
|
|
-
|
|
|
- interrupt_status = SMU_ISR_READ(scic);
|
|
|
- interrupt_status &= (SMU_ISR_QUEUE_ERROR | SMU_ISR_QUEUE_SUSPEND);
|
|
|
-
|
|
|
- if ((interrupt_status == 0) &&
|
|
|
- scic_sds_controller_completion_queue_has_entries(scic)) {
|
|
|
- /*
|
|
|
- * There is at least one completion queue entry to process so we can
|
|
|
- * return a success and ignore for now the case of an error interrupt */
|
|
|
- SMU_ISR_WRITE(scic, SMU_ISR_COMPLETION);
|
|
|
- return true;
|
|
|
- }
|
|
|
-
|
|
|
- if (interrupt_status != 0) {
|
|
|
- /*
|
|
|
- * There is an error interrupt pending so let it through and handle
|
|
|
- * in the callback */
|
|
|
- return true;
|
|
|
- }
|
|
|
-
|
|
|
- /*
|
|
|
- * Clear any offending interrupts since we could not find any to handle
|
|
|
- * and unmask them all */
|
|
|
- SMU_ISR_WRITE(scic, 0x00000000);
|
|
|
- SMU_IMR_WRITE(scic, 0x00000000);
|
|
|
-
|
|
|
- return false;
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * This is the method provided to handle completions for a single MSIX message.
|
|
|
- */
|
|
|
-static void scic_sds_controller_single_vector_completion_handler(
|
|
|
- struct scic_sds_controller *scic)
|
|
|
-{
|
|
|
- u32 interrupt_status;
|
|
|
-
|
|
|
- interrupt_status = SMU_ISR_READ(scic);
|
|
|
- interrupt_status &= (SMU_ISR_QUEUE_ERROR | SMU_ISR_QUEUE_SUSPEND);
|
|
|
-
|
|
|
- if (interrupt_status & SMU_ISR_QUEUE_ERROR) {
|
|
|
- dev_err(scic_to_dev(scic),
|
|
|
- "%s: SCIC Controller has encountered a fatal error.\n",
|
|
|
- __func__);
|
|
|
-
|
|
|
- /*
|
|
|
- * We have a fatal condition and must reset the controller
|
|
|
- * Leave the interrupt mask in place and get the controller reset */
|
|
|
- sci_base_state_machine_change_state(
|
|
|
- scic_sds_controller_get_base_state_machine(scic),
|
|
|
- SCI_BASE_CONTROLLER_STATE_FAILED);
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- if ((interrupt_status & SMU_ISR_QUEUE_SUSPEND) &&
|
|
|
- !scic_sds_controller_completion_queue_has_entries(scic)) {
|
|
|
- dev_err(scic_to_dev(scic),
|
|
|
- "%s: SCIC Controller has encountered a fatal error.\n",
|
|
|
- __func__);
|
|
|
-
|
|
|
- /*
|
|
|
- * We have a fatal condtion and must reset the controller
|
|
|
- * Leave the interrupt mask in place and get the controller reset */
|
|
|
- sci_base_state_machine_change_state(
|
|
|
- scic_sds_controller_get_base_state_machine(scic),
|
|
|
- SCI_BASE_CONTROLLER_STATE_FAILED);
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- if (scic_sds_controller_completion_queue_has_entries(scic)) {
|
|
|
- scic_sds_controller_process_completions(scic);
|
|
|
-
|
|
|
- /*
|
|
|
- * We dont care which interrupt got us to processing the completion queu
|
|
|
- * so clear them both. */
|
|
|
- SMU_ISR_WRITE(
|
|
|
- scic,
|
|
|
- (SMU_ISR_COMPLETION | SMU_ISR_QUEUE_SUSPEND));
|
|
|
- }
|
|
|
-
|
|
|
- SMU_IMR_WRITE(scic, 0x00000000);
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * This is the method provided to handle a MSIX message for a normal completion.
|
|
|
- *
|
|
|
- * bool true if an interrupt is processed false if no interrupt was processed
|
|
|
- */
|
|
|
bool scic_sds_controller_isr(struct scic_sds_controller *scic)
|
|
|
{
|
|
|
if (scic_sds_controller_completion_queue_has_entries(scic)) {
|
|
@@ -1920,10 +1586,6 @@ bool scic_sds_controller_isr(struct scic_sds_controller *scic)
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
-/**
|
|
|
- * This is the method provided to handle the completions for a normal MSIX
|
|
|
- * message.
|
|
|
- */
|
|
|
void scic_sds_controller_completion_handler(struct scic_sds_controller *scic)
|
|
|
{
|
|
|
/* Empty out the completion queue */
|
|
@@ -1994,14 +1656,6 @@ void scic_sds_controller_error_handler(struct scic_sds_controller *scic)
|
|
|
}
|
|
|
|
|
|
|
|
|
-/*
|
|
|
- * ****************************************************************************-
|
|
|
- * * SCIC SDS Controller External Methods
|
|
|
- * ****************************************************************************- */
|
|
|
-
|
|
|
-/**
|
|
|
- * This method returns the sizeof the SCIC SDS Controller Object
|
|
|
- */
|
|
|
u32 scic_sds_controller_get_object_size(void)
|
|
|
{
|
|
|
return sizeof(struct scic_sds_controller);
|
|
@@ -2535,72 +2189,6 @@ enum sci_status scic_controller_reset(
|
|
|
return status;
|
|
|
}
|
|
|
|
|
|
-/* --------------------------------------------------------------------------- */
|
|
|
-
|
|
|
-enum sci_status scic_controller_get_handler_methods(
|
|
|
- enum scic_interrupt_type interrupt_type,
|
|
|
- u16 message_count,
|
|
|
- struct scic_controller_handler_methods *handler_methods)
|
|
|
-{
|
|
|
- enum sci_status status = SCI_FAILURE_UNSUPPORTED_MESSAGE_COUNT;
|
|
|
-
|
|
|
- switch (interrupt_type) {
|
|
|
- case SCIC_LEGACY_LINE_INTERRUPT_TYPE:
|
|
|
- if (message_count == 0) {
|
|
|
- handler_methods[0].interrupt_handler
|
|
|
- = scic_sds_controller_legacy_interrupt_handler;
|
|
|
- handler_methods[0].completion_handler
|
|
|
- = scic_sds_controller_legacy_completion_handler;
|
|
|
-
|
|
|
- status = SCI_SUCCESS;
|
|
|
- }
|
|
|
- break;
|
|
|
-
|
|
|
- case SCIC_MSIX_INTERRUPT_TYPE:
|
|
|
- if (message_count == 1) {
|
|
|
- handler_methods[0].interrupt_handler
|
|
|
- = scic_sds_controller_single_vector_interrupt_handler;
|
|
|
- handler_methods[0].completion_handler
|
|
|
- = scic_sds_controller_single_vector_completion_handler;
|
|
|
-
|
|
|
- status = SCI_SUCCESS;
|
|
|
- } else if (message_count == 2) {
|
|
|
- handler_methods[0].interrupt_handler
|
|
|
- = scic_sds_controller_isr;
|
|
|
- handler_methods[0].completion_handler
|
|
|
- = scic_sds_controller_completion_handler;
|
|
|
-
|
|
|
- handler_methods[1].interrupt_handler
|
|
|
- = scic_sds_controller_error_isr;
|
|
|
- handler_methods[1].completion_handler
|
|
|
- = scic_sds_controller_error_handler;
|
|
|
-
|
|
|
- status = SCI_SUCCESS;
|
|
|
- }
|
|
|
- break;
|
|
|
-
|
|
|
- case SCIC_NO_INTERRUPTS:
|
|
|
- if (message_count == 0) {
|
|
|
-
|
|
|
- handler_methods[0].interrupt_handler
|
|
|
- = scic_sds_controller_polling_interrupt_handler;
|
|
|
- handler_methods[0].completion_handler
|
|
|
- = scic_sds_controller_polling_completion_handler;
|
|
|
-
|
|
|
- status = SCI_SUCCESS;
|
|
|
- }
|
|
|
- break;
|
|
|
-
|
|
|
- default:
|
|
|
- status = SCI_FAILURE_INVALID_PARAMETER_VALUE;
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- return status;
|
|
|
-}
|
|
|
-
|
|
|
-/* --------------------------------------------------------------------------- */
|
|
|
-
|
|
|
enum sci_io_status scic_controller_start_io(
|
|
|
struct scic_sds_controller *scic,
|
|
|
struct scic_sds_remote_device *remote_device,
|