diff options
author | Henryk Dembkowski <Henryk.Dembkowski@intel.com> | 2011-02-24 00:55:11 (GMT) |
---|---|---|
committer | Dan Williams <dan.j.williams@intel.com> | 2011-07-03 10:55:30 (GMT) |
commit | 07373a5caa29e4159ef1ea5e72985ddaf013519a (patch) | |
tree | 0ea13c0ede1012dec6e6d491ed181418e62453ee /drivers/scsi/isci | |
parent | 8db37aabaceb3dcd18754c1e782d4474e4052c81 (diff) | |
download | linux-fsl-qoriq-07373a5caa29e4159ef1ea5e72985ddaf013519a.tar.xz |
isci: add support for 2 more oem parmeters
1/ add OEM paramater support for mode_type (MPC vs APC)
2/ add OEM parameter support for max_number_concurrent_device_spin_up
3/ cleanup scic_sds_controller_start_next_phy
todo: hook up the amp control afe parameters into the afe init code
Signed-off-by: Henryk Dembkowski <henryk.dembkowski@intel.com>
Signed-off-by: Jacek Danecki <Jacek.Danecki@intel.com>
[cleaned up scic_sds_controller_start_next_phy]
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Diffstat (limited to 'drivers/scsi/isci')
-rw-r--r-- | drivers/scsi/isci/core/scic_config_parameters.h | 3 | ||||
-rw-r--r-- | drivers/scsi/isci/core/scic_sds_controller.c | 271 | ||||
-rw-r--r-- | drivers/scsi/isci/core/scic_sds_controller.h | 30 | ||||
-rw-r--r-- | drivers/scsi/isci/core/scic_sds_port_configuration_agent.c | 2 | ||||
-rw-r--r-- | drivers/scsi/isci/firmware/create_fw.h | 7 | ||||
-rw-r--r-- | drivers/scsi/isci/probe_roms.h | 14 |
6 files changed, 174 insertions, 153 deletions
diff --git a/drivers/scsi/isci/core/scic_config_parameters.h b/drivers/scsi/isci/core/scic_config_parameters.h index 5e1345d..f64f24f 100644 --- a/drivers/scsi/isci/core/scic_config_parameters.h +++ b/drivers/scsi/isci/core/scic_config_parameters.h @@ -224,6 +224,8 @@ union scic_user_parameters { */ #define SCIC_SDS_PARM_PHY_MASK_MAX 0xF +#define MAX_CONCURRENT_DEVICE_SPIN_UP_COUNT 4 + /** * This structure/union specifies the various different OEM parameter sets * available. Each type is specific to a hardware controller version. @@ -237,7 +239,6 @@ union scic_oem_parameters { * 1. */ struct scic_sds_oem_params sds1; - }; /** diff --git a/drivers/scsi/isci/core/scic_sds_controller.c b/drivers/scsi/isci/core/scic_sds_controller.c index e7f3711..12b2ad5 100644 --- a/drivers/scsi/isci/core/scic_sds_controller.c +++ b/drivers/scsi/isci/core/scic_sds_controller.c @@ -293,6 +293,7 @@ void scic_sds_controller_initialize_power_control( ); this_controller->power_control.phys_waiting = 0; + this_controller->power_control.phys_granted_power = 0; } /* --------------------------------------------------------------------------- */ @@ -770,31 +771,6 @@ void scic_sds_controller_timeout_handler( __func__); } -/** - * scic_sds_controller_get_port_configuration_mode - * @this_controller: This is the controller to use to determine if we are using - * manual or automatic port configuration. - * - * SCIC_PORT_CONFIGURATION_MODE - */ -enum SCIC_PORT_CONFIGURATION_MODE scic_sds_controller_get_port_configuration_mode( - struct scic_sds_controller *this_controller) -{ - u32 index; - enum SCIC_PORT_CONFIGURATION_MODE mode; - - mode = SCIC_PORT_AUTOMATIC_CONFIGURATION_MODE; - - for (index = 0; index < SCI_MAX_PORTS; index++) { - if (this_controller->oem_parameters.sds1.ports[index].phy_mask != 0) { - mode = SCIC_PORT_MANUAL_CONFIGURATION_MODE; - break; - } - } - - return mode; -} - enum sci_status scic_sds_controller_stop_ports(struct scic_sds_controller *scic) { u32 index; @@ -859,7 +835,7 @@ void scic_sds_controller_phy_timer_stop( /** * This method is called internally by the controller object to start the next - * phy on the controller. If all the phys have been starte, then this + * phy on the controller. If all the phys have been started, then this * method will attempt to transition the controller to the READY state and * inform the user (scic_cb_controller_start_complete()). * @this_controller: This parameter specifies the controller object for which @@ -867,101 +843,88 @@ void scic_sds_controller_phy_timer_stop( * * enum sci_status */ -enum sci_status scic_sds_controller_start_next_phy( - struct scic_sds_controller *this_controller) +enum sci_status scic_sds_controller_start_next_phy(struct scic_sds_controller *scic) { + struct scic_sds_oem_params *oem = &scic->oem_parameters.sds1; + struct scic_sds_phy *sci_phy; enum sci_status status; status = SCI_SUCCESS; - if (this_controller->phy_startup_timer_pending == false) { - if (this_controller->next_phy_to_start == SCI_MAX_PHYS) { - bool is_controller_start_complete = true; - struct scic_sds_phy *the_phy; - u8 index; + if (scic->phy_startup_timer_pending) + return status; - for (index = 0; index < SCI_MAX_PHYS; index++) { - the_phy = &this_controller->phy_table[index]; - - if (scic_sds_phy_get_port(the_phy) != NULL) { - /** - * The controller start operation is complete if and only - * if: - * - all links have been given an opportunity to start - * - have no indication of a connected device - * - have an indication of a connected device and it has - * finished the link training process. - */ - if ( - ( - (the_phy->is_in_link_training == false) - && (the_phy->parent.state_machine.current_state_id - == SCI_BASE_PHY_STATE_INITIAL) - ) - || ( - (the_phy->is_in_link_training == false) - && (the_phy->parent.state_machine.current_state_id - == SCI_BASE_PHY_STATE_STOPPED) - ) - || ( - (the_phy->is_in_link_training == true) - && (the_phy->parent.state_machine.current_state_id - == SCI_BASE_PHY_STATE_STARTING) - ) - ) { - is_controller_start_complete = false; - break; - } - } - } + if (scic->next_phy_to_start >= SCI_MAX_PHYS) { + bool is_controller_start_complete = true; + u32 state; + u8 index; - /* - * The controller has successfully finished the start process. - * Inform the SCI Core user and transition to the READY state. */ - if (is_controller_start_complete == true) { - scic_sds_controller_transition_to_ready( - this_controller, SCI_SUCCESS - ); - scic_sds_controller_phy_timer_stop(this_controller); + for (index = 0; index < SCI_MAX_PHYS; index++) { + sci_phy = &scic->phy_table[index]; + state = sci_phy->parent.state_machine.current_state_id; + + if (!scic_sds_phy_get_port(sci_phy)) + continue; + + /* The controller start operation is complete iff: + * - all links have been given an opportunity to start + * - have no indication of a connected device + * - have an indication of a connected device and it has + * finished the link training process. + */ + if ((sci_phy->is_in_link_training == false && + state == SCI_BASE_PHY_STATE_INITIAL) || + (sci_phy->is_in_link_training == false && + state == SCI_BASE_PHY_STATE_STOPPED) || + (sci_phy->is_in_link_training == true && + state == SCI_BASE_PHY_STATE_STARTING)) { + is_controller_start_complete = false; + break; } - } else { - struct scic_sds_phy *the_phy; - - the_phy = &this_controller->phy_table[this_controller->next_phy_to_start]; + } - if ( - scic_sds_controller_get_port_configuration_mode(this_controller) - == SCIC_PORT_MANUAL_CONFIGURATION_MODE - ) { - if (scic_sds_phy_get_port(the_phy) == NULL) { - this_controller->next_phy_to_start++; - - /* - * Caution recursion ahead be forwarned - * - * The PHY was never added to a PORT in MPC mode so start the next phy in sequence - * This phy will never go link up and will not draw power the OEM parameters either - * configured the phy incorrectly for the PORT or it was never assigned to a PORT */ - return scic_sds_controller_start_next_phy(this_controller); - } + /* + * The controller has successfully finished the start process. + * Inform the SCI Core user and transition to the READY state. */ + if (is_controller_start_complete == true) { + scic_sds_controller_transition_to_ready(scic, SCI_SUCCESS); + scic_sds_controller_phy_timer_stop(scic); + } + } else { + sci_phy = &scic->phy_table[scic->next_phy_to_start]; + + if (oem->controller.mode_type == SCIC_PORT_MANUAL_CONFIGURATION_MODE) { + if (scic_sds_phy_get_port(sci_phy) == NULL) { + scic->next_phy_to_start++; + + /* Caution recursion ahead be forwarned + * + * The PHY was never added to a PORT in MPC mode + * so start the next phy in sequence This phy + * will never go link up and will not draw power + * the OEM parameters either configured the phy + * incorrectly for the PORT or it was never + * assigned to a PORT + */ + return scic_sds_controller_start_next_phy(scic); } + } - status = scic_sds_phy_start(the_phy); + status = scic_sds_phy_start(sci_phy); - if (status == SCI_SUCCESS) { - scic_sds_controller_phy_timer_start(this_controller); - } else { - dev_warn(scic_to_dev(this_controller), - "%s: Controller stop operation failed " - "to stop phy %d because of status " - "%d.\n", - __func__, - this_controller->phy_table[this_controller->next_phy_to_start].phy_index, - status); - } - - this_controller->next_phy_to_start++; + if (status == SCI_SUCCESS) { + scic_sds_controller_phy_timer_start(scic); + } else { + dev_warn(scic_to_dev(scic), + "%s: Controller stop operation failed " + "to stop phy %d because of status " + "%d.\n", + __func__, + scic->phy_table[scic->next_phy_to_start].phy_index, + status); } + + scic->next_phy_to_start++; } return status; @@ -1059,6 +1022,31 @@ static void scic_sds_controller_power_control_timer_start( } /** + * This method stops the power control timer for this controller object. + * + * @param scic + */ +void scic_sds_controller_power_control_timer_stop(struct scic_sds_controller *scic) +{ + if (scic->power_control.timer_started) { + isci_event_timer_stop(scic, scic->power_control.timer); + scic->power_control.timer_started = false; + } +} + +/** + * This method stops and starts the power control timer for this controller object. + * + * @param scic + */ +void scic_sds_controller_power_control_timer_restart( + struct scic_sds_controller *scic) +{ + scic_sds_controller_power_control_timer_stop(scic); + scic_sds_controller_power_control_timer_start(scic); +} + +/** * * * @@ -1070,6 +1058,8 @@ static void scic_sds_controller_power_control_timer_handler( this_controller = (struct scic_sds_controller *)controller; + this_controller->power_control.phys_granted_power = 0; + if (this_controller->power_control.phys_waiting == 0) { this_controller->power_control.timer_started = false; } else { @@ -1081,19 +1071,24 @@ static void scic_sds_controller_power_control_timer_handler( && (this_controller->power_control.phys_waiting != 0); i++) { if (this_controller->power_control.requesters[i] != NULL) { - the_phy = this_controller->power_control.requesters[i]; - this_controller->power_control.requesters[i] = NULL; - this_controller->power_control.phys_waiting--; - break; + if (this_controller->power_control.phys_granted_power < + this_controller->oem_parameters.sds1.controller.max_concurrent_dev_spin_up) { + the_phy = this_controller->power_control.requesters[i]; + this_controller->power_control.requesters[i] = NULL; + this_controller->power_control.phys_waiting--; + this_controller->power_control.phys_granted_power++; + scic_sds_phy_consume_power_handler(the_phy); + } else { + break; + } } } /* * It doesn't matter if the power list is empty, we need to start the - * timer in case another phy becomes ready. */ + * timer in case another phy becomes ready. + */ scic_sds_controller_power_control_timer_start(this_controller); - - scic_sds_phy_consume_power_handler(the_phy); } } @@ -1109,15 +1104,20 @@ void scic_sds_controller_power_control_queue_insert( { BUG_ON(the_phy == NULL); - if ( - (this_controller->power_control.timer_started) - && (this_controller->power_control.requesters[the_phy->phy_index] == NULL) - ) { + if (this_controller->power_control.phys_granted_power < + this_controller->oem_parameters.sds1.controller.max_concurrent_dev_spin_up) { + this_controller->power_control.phys_granted_power++; + scic_sds_phy_consume_power_handler(the_phy); + + /* + * stop and start the power_control timer. When the timer fires, the + * no_of_phys_granted_power will be set to 0 + */ + scic_sds_controller_power_control_timer_restart(this_controller); + } else { + /* Add the phy in the waiting list */ this_controller->power_control.requesters[the_phy->phy_index] = the_phy; this_controller->power_control.phys_waiting++; - } else { - scic_sds_controller_power_control_timer_start(this_controller); - scic_sds_phy_consume_power_handler(the_phy); } } @@ -2021,7 +2021,7 @@ void scic_sds_controller_release_frame( * This method sets user parameters and OEM parameters to default values. * Users can override these values utilizing the scic_user_parameters_set() * and scic_oem_parameters_set() methods. - * @controller: This parameter specifies the controller for which to set the + * @scic: This parameter specifies the controller for which to set the * configuration parameters to their default values. * */ @@ -2029,6 +2029,12 @@ static void scic_sds_controller_set_default_config_parameters(struct scic_sds_co { u16 index; + /* Default to APC mode. */ + scic->oem_parameters.sds1.controller.mode_type = SCIC_PORT_AUTOMATIC_CONFIGURATION_MODE; + + /* Default to APC mode. */ + scic->oem_parameters.sds1.controller.max_concurrent_dev_spin_up = 1; + /* Default to no SSC operation. */ scic->oem_parameters.sds1.controller.do_enable_ssc = false; @@ -2607,6 +2613,7 @@ enum sci_status scic_oem_parameters_set( == SCI_BASE_CONTROLLER_STATE_INITIALIZED) ) { u16 index; + u8 combined_phy_mask = 0; /* * Validate the oem parameters. If they are not legal, then @@ -2626,6 +2633,24 @@ enum sci_status scic_oem_parameters_set( } } + if (scic_parms->sds1.controller.mode_type == SCIC_PORT_AUTOMATIC_CONFIGURATION_MODE) { + for (index = 0; index < SCI_MAX_PHYS; index++) { + if (scic_parms->sds1.ports[index].phy_mask != 0) + return SCI_FAILURE_INVALID_PARAMETER_VALUE; + } + } else if (scic_parms->sds1.controller.mode_type == SCIC_PORT_MANUAL_CONFIGURATION_MODE) { + for (index = 0; index < SCI_MAX_PHYS; index++) + combined_phy_mask |= scic_parms->sds1.ports[index].phy_mask; + + if (combined_phy_mask == 0) + return SCI_FAILURE_INVALID_PARAMETER_VALUE; + } else { + return SCI_FAILURE_INVALID_PARAMETER_VALUE; + } + + if (scic_parms->sds1.controller.max_concurrent_dev_spin_up > MAX_CONCURRENT_DEVICE_SPIN_UP_COUNT) + return SCI_FAILURE_INVALID_PARAMETER_VALUE; + memcpy(&scic->oem_parameters, scic_parms, sizeof(*scic_parms)); return SCI_SUCCESS; } diff --git a/drivers/scsi/isci/core/scic_sds_controller.h b/drivers/scsi/isci/core/scic_sds_controller.h index 9b8e55d..6386a64 100644 --- a/drivers/scsi/isci/core/scic_sds_controller.h +++ b/drivers/scsi/isci/core/scic_sds_controller.h @@ -122,23 +122,6 @@ enum SCIC_SDS_CONTROLLER_MEMORY_DESCRIPTORS { /** - * - * - * Allowed PORT configuration modes APC Automatic PORT configuration mode is - * defined by the OEM configuration parameters providing no PHY_MASK parameters - * for any PORT. i.e. There are no phys assigned to any of the ports at start. - * MPC Manual PORT configuration mode is defined by the OEM configuration - * parameters providing a PHY_MASK value for any PORT. It is assumed that any - * PORT with no PHY_MASK is an invalid port and not all PHYs must be assigned. - * A PORT_PHY mask that assigns just a single PHY to a port and no other PHYs - * being assigned is sufficient to declare manual PORT configuration. - */ -enum SCIC_PORT_CONFIGURATION_MODE { - SCIC_PORT_MANUAL_CONFIGURATION_MODE, - SCIC_PORT_AUTOMATIC_CONFIGURATION_MODE -}; - -/** * struct scic_power_control - * * This structure defines the fields for managing power control for direct @@ -164,6 +147,11 @@ struct scic_power_control { u8 phys_waiting; /** + * This field is used to keep track of how many phys have been granted to consume power + */ + u8 phys_granted_power; + + /** * This field is an array of phys that we are waiting on. The phys are direct * mapped into requesters via struct scic_sds_phy.phy_index */ @@ -560,14 +548,6 @@ u32 scic_sds_controller_get_object_size(void); /* --------------------------------------------------------------------------- */ - -/* --------------------------------------------------------------------------- */ - -enum SCIC_PORT_CONFIGURATION_MODE scic_sds_controller_get_port_configuration_mode( - struct scic_sds_controller *this_controller); - -/* --------------------------------------------------------------------------- */ - void scic_sds_controller_post_request( struct scic_sds_controller *this_controller, u32 request); diff --git a/drivers/scsi/isci/core/scic_sds_port_configuration_agent.c b/drivers/scsi/isci/core/scic_sds_port_configuration_agent.c index e26a4e6..7c95210 100644 --- a/drivers/scsi/isci/core/scic_sds_port_configuration_agent.c +++ b/drivers/scsi/isci/core/scic_sds_port_configuration_agent.c @@ -822,7 +822,7 @@ enum sci_status scic_sds_port_configuration_agent_initialize( enum sci_status status = SCI_SUCCESS; enum SCIC_PORT_CONFIGURATION_MODE mode; - mode = scic_sds_controller_get_port_configuration_mode(controller); + mode = controller->oem_parameters.sds1.controller.mode_type; if (mode == SCIC_PORT_MANUAL_CONFIGURATION_MODE) { status = scic_sds_mpc_agent_validate_phy_configuration(controller, port_agent); diff --git a/drivers/scsi/isci/firmware/create_fw.h b/drivers/scsi/isci/firmware/create_fw.h index bedbe4f..788a8de 100644 --- a/drivers/scsi/isci/firmware/create_fw.h +++ b/drivers/scsi/isci/firmware/create_fw.h @@ -1,5 +1,6 @@ #ifndef _CREATE_FW_H_ #define _CREATE_FW_H_ +#include "../probe_roms.h" /* we are configuring for 2 SCUs */ @@ -24,16 +25,16 @@ static const int num_elements = 2; * if there is a port/phy on which you do not wish to override the default * values, use the value assigned to UNINIT_PARAM (255). */ +/* discovery mode type (port auto config mode by default ) */ #ifdef MPC +static const int mode_type = SCIC_PORT_MANUAL_CONFIGURATION_MODE; static const __u8 phy_mask[2][4] = { {1, 2, 4, 8}, {1, 2, 4, 8} }; #else /* APC (default) */ +static const int mode_type = SCIC_PORT_AUTOMATIC_CONFIGURATION_MODE; static const __u8 phy_mask[2][4]; #endif -/* discovery mode type (port auto config mode by default ) */ -static const int mode_type; - /* Maximum number of concurrent device spin up */ static const int max_num_concurrent_dev_spin_up = 1; diff --git a/drivers/scsi/isci/probe_roms.h b/drivers/scsi/isci/probe_roms.h index 96d8b92..69526ff 100644 --- a/drivers/scsi/isci/probe_roms.h +++ b/drivers/scsi/isci/probe_roms.h @@ -86,6 +86,20 @@ struct isci_orom *isci_get_efi_var(struct pci_dev *pdev); #define ISCI_EFI_ATTRIBUTES 0 #define ISCI_EFI_VAR_NAME "isci_oemb" +/* Allowed PORT configuration modes APC Automatic PORT configuration mode is + * defined by the OEM configuration parameters providing no PHY_MASK parameters + * for any PORT. i.e. There are no phys assigned to any of the ports at start. + * MPC Manual PORT configuration mode is defined by the OEM configuration + * parameters providing a PHY_MASK value for any PORT. It is assumed that any + * PORT with no PHY_MASK is an invalid port and not all PHYs must be assigned. + * A PORT_PHY mask that assigns just a single PHY to a port and no other PHYs + * being assigned is sufficient to declare manual PORT configuration. + */ +enum SCIC_PORT_CONFIGURATION_MODE { + SCIC_PORT_MANUAL_CONFIGURATION_MODE = 0, + SCIC_PORT_AUTOMATIC_CONFIGURATION_MODE = 1 +}; + struct sci_bios_oem_param_block_hdr { uint8_t signature[ISCI_ROM_SIG_SIZE]; uint16_t total_block_length; |