From 2e5da889d44a3a9629f895de3488306e7f5ddf16 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 4 Jan 2012 01:32:34 -0800 Subject: [SCSI] isci: cleanup oem parameter and recipe handling Before updating the code to support the latest platform updates and silicon revision cleanup some of the long deref chains. Signed-off-by: Dan Williams Signed-off-by: James Bottomley --- drivers/scsi/isci/phy.c | 81 ++++++++++++++++++++++++------------------------- 1 file changed, 39 insertions(+), 42 deletions(-) (limited to 'drivers/scsi/isci/phy.c') diff --git a/drivers/scsi/isci/phy.c b/drivers/scsi/isci/phy.c index 35f50c2183e1..0ae0990b39dd 100644 --- a/drivers/scsi/isci/phy.c +++ b/drivers/scsi/isci/phy.c @@ -91,22 +91,23 @@ sci_phy_transport_layer_initialization(struct isci_phy *iphy, static enum sci_status sci_phy_link_layer_initialization(struct isci_phy *iphy, - struct scu_link_layer_registers __iomem *reg) + struct scu_link_layer_registers __iomem *llr) { struct isci_host *ihost = iphy->owning_port->owning_controller; + struct sci_phy_user_params *phy_user; + struct sci_phy_oem_params *phy_oem; int phy_idx = iphy->phy_index; - struct sci_phy_user_params *phy_user = &ihost->user_parameters.phys[phy_idx]; - struct sci_phy_oem_params *phy_oem = - &ihost->oem_parameters.phys[phy_idx]; - u32 phy_configuration; struct sci_phy_cap phy_cap; + u32 phy_configuration; u32 parity_check = 0; u32 parity_count = 0; u32 llctl, link_rate; u32 clksm_value = 0; u32 sp_timeouts = 0; - iphy->link_layer_registers = reg; + phy_user = &ihost->user_parameters.phys[phy_idx]; + phy_oem = &ihost->oem_parameters.phys[phy_idx]; + iphy->link_layer_registers = llr; /* Set our IDENTIFY frame data */ #define SCI_END_DEVICE 0x01 @@ -116,32 +117,26 @@ sci_phy_link_layer_initialization(struct isci_phy *iphy, SCU_SAS_TIID_GEN_BIT(STP_INITIATOR) | SCU_SAS_TIID_GEN_BIT(DA_SATA_HOST) | SCU_SAS_TIID_GEN_VAL(DEVICE_TYPE, SCI_END_DEVICE), - &iphy->link_layer_registers->transmit_identification); + &llr->transmit_identification); /* Write the device SAS Address */ - writel(0xFEDCBA98, - &iphy->link_layer_registers->sas_device_name_high); - writel(phy_idx, &iphy->link_layer_registers->sas_device_name_low); + writel(0xFEDCBA98, &llr->sas_device_name_high); + writel(phy_idx, &llr->sas_device_name_low); /* Write the source SAS Address */ - writel(phy_oem->sas_address.high, - &iphy->link_layer_registers->source_sas_address_high); - writel(phy_oem->sas_address.low, - &iphy->link_layer_registers->source_sas_address_low); + writel(phy_oem->sas_address.high, &llr->source_sas_address_high); + writel(phy_oem->sas_address.low, &llr->source_sas_address_low); /* Clear and Set the PHY Identifier */ - writel(0, &iphy->link_layer_registers->identify_frame_phy_id); - writel(SCU_SAS_TIPID_GEN_VALUE(ID, phy_idx), - &iphy->link_layer_registers->identify_frame_phy_id); + writel(0, &llr->identify_frame_phy_id); + writel(SCU_SAS_TIPID_GEN_VALUE(ID, phy_idx), &llr->identify_frame_phy_id); /* Change the initial state of the phy configuration register */ - phy_configuration = - readl(&iphy->link_layer_registers->phy_configuration); + phy_configuration = readl(&llr->phy_configuration); /* Hold OOB state machine in reset */ phy_configuration |= SCU_SAS_PCFG_GEN_BIT(OOB_RESET); - writel(phy_configuration, - &iphy->link_layer_registers->phy_configuration); + writel(phy_configuration, &llr->phy_configuration); /* Configure the SNW capabilities */ phy_cap.all = 0; @@ -155,9 +150,9 @@ sci_phy_link_layer_initialization(struct isci_phy *iphy, phy_cap.gen1_ssc = 1; } - /* - * The SAS specification indicates that the phy_capabilities that - * are transmitted shall have an even parity. Calculate the parity. */ + /* The SAS specification indicates that the phy_capabilities that + * are transmitted shall have an even parity. Calculate the parity. + */ parity_check = phy_cap.all; while (parity_check != 0) { if (parity_check & 0x1) @@ -165,20 +160,20 @@ sci_phy_link_layer_initialization(struct isci_phy *iphy, parity_check >>= 1; } - /* - * If parity indicates there are an odd number of bits set, then - * set the parity bit to 1 in the phy capabilities. */ + /* If parity indicates there are an odd number of bits set, then + * set the parity bit to 1 in the phy capabilities. + */ if ((parity_count % 2) != 0) phy_cap.parity = 1; - writel(phy_cap.all, &iphy->link_layer_registers->phy_capabilities); + writel(phy_cap.all, &llr->phy_capabilities); /* Set the enable spinup period but disable the ability to send * notify enable spinup */ writel(SCU_ENSPINUP_GEN_VAL(COUNT, phy_user->notify_enable_spin_up_insertion_frequency), - &iphy->link_layer_registers->notify_enable_spinup_control); + &llr->notify_enable_spinup_control); /* Write the ALIGN Insertion Ferequency for connected phy and * inpendent of connected state @@ -189,11 +184,10 @@ sci_phy_link_layer_initialization(struct isci_phy *iphy, clksm_value |= SCU_ALIGN_INSERTION_FREQUENCY_GEN_VAL(GENERAL, phy_user->align_insertion_frequency); - writel(clksm_value, &iphy->link_layer_registers->clock_skew_management); + writel(clksm_value, &llr->clock_skew_management); /* @todo Provide a way to write this register correctly */ - writel(0x02108421, - &iphy->link_layer_registers->afe_lookup_table_control); + writel(0x02108421, &llr->afe_lookup_table_control); llctl = SCU_SAS_LLCTL_GEN_VAL(NO_OUTBOUND_TASK_TIMEOUT, (u8)ihost->user_parameters.no_outbound_task_timeout); @@ -210,9 +204,9 @@ sci_phy_link_layer_initialization(struct isci_phy *iphy, break; } llctl |= SCU_SAS_LLCTL_GEN_VAL(MAX_LINK_RATE, link_rate); - writel(llctl, &iphy->link_layer_registers->link_layer_control); + writel(llctl, &llr->link_layer_control); - sp_timeouts = readl(&iphy->link_layer_registers->sas_phy_timeouts); + sp_timeouts = readl(&llr->sas_phy_timeouts); /* Clear the default 0x36 (54us) RATE_CHANGE timeout value. */ sp_timeouts &= ~SCU_SAS_PHYTOV_GEN_VAL(RATE_CHANGE, 0xFF); @@ -222,20 +216,23 @@ sci_phy_link_layer_initialization(struct isci_phy *iphy, */ sp_timeouts |= SCU_SAS_PHYTOV_GEN_VAL(RATE_CHANGE, 0x3B); - writel(sp_timeouts, &iphy->link_layer_registers->sas_phy_timeouts); + writel(sp_timeouts, &llr->sas_phy_timeouts); if (is_a2(ihost->pdev)) { - /* Program the max ARB time for the PHY to 700us so we inter-operate with - * the PMC expander which shuts down PHYs if the expander PHY generates too - * many breaks. This time value will guarantee that the initiator PHY will - * generate the break. + /* Program the max ARB time for the PHY to 700us so we + * inter-operate with the PMC expander which shuts down + * PHYs if the expander PHY generates too many breaks. + * This time value will guarantee that the initiator PHY + * will generate the break. */ writel(SCIC_SDS_PHY_MAX_ARBITRATION_WAIT_TIME, - &iphy->link_layer_registers->maximum_arbitration_wait_timer_timeout); + &llr->maximum_arbitration_wait_timer_timeout); } - /* Disable link layer hang detection, rely on the OS timeout for I/O timeouts. */ - writel(0, &iphy->link_layer_registers->link_layer_hang_detection_timeout); + /* Disable link layer hang detection, rely on the OS timeout for + * I/O timeouts. + */ + writel(0, &llr->link_layer_hang_detection_timeout); /* We can exit the initial state to the stopped state */ sci_change_state(&iphy->sm, SCI_PHY_STOPPED); -- cgit v1.2.3 From afd13a1f2b05157c7621d87dfe89ea6ea9061bd8 Mon Sep 17 00:00:00 2001 From: Jeff Skirvin Date: Wed, 4 Jan 2012 01:32:39 -0800 Subject: [SCSI] isci: update afe (analog-front-end) recipe for C1 C1 silicon requires updates to the phy tuning recipe and also support for user provided cable selects (per-phy) for short, medium, and long cables. Default to 'short' awaiting support for selecting the cable via oem parameters. Reviewed-by: Jiangbi Liu Signed-off-by: Marcin Tomczak Signed-off-by: Jeff Skirvin Signed-off-by: Dan Williams Signed-off-by: James Bottomley --- drivers/scsi/isci/host.c | 111 +++++++++++++++++++++++++++++++++-------- drivers/scsi/isci/host.h | 9 +++- drivers/scsi/isci/phy.c | 7 ++- drivers/scsi/isci/probe_roms.c | 2 +- 4 files changed, 103 insertions(+), 26 deletions(-) (limited to 'drivers/scsi/isci/phy.c') diff --git a/drivers/scsi/isci/host.c b/drivers/scsi/isci/host.c index 8e7de192cf6d..383bb6913087 100644 --- a/drivers/scsi/isci/host.c +++ b/drivers/scsi/isci/host.c @@ -1908,12 +1908,23 @@ void sci_controller_power_control_queue_remove(struct isci_host *ihost, ihost->power_control.requesters[iphy->phy_index] = NULL; } +static int is_long_cable(int phy, unsigned char selection_byte) +{ + return 0; +} + +static int is_medium_cable(int phy, unsigned char selection_byte) +{ + return 0; +} + #define AFE_REGISTER_WRITE_DELAY 10 static void sci_controller_afe_initialization(struct isci_host *ihost) { struct scu_afe_registers __iomem *afe = &ihost->scu_registers->afe; const struct sci_oem_params *oem = &ihost->oem_parameters; + unsigned char cable_selection_mask = 0; struct pci_dev *pdev = ihost->pdev; u32 afe_status; u32 phy_id; @@ -1922,11 +1933,11 @@ static void sci_controller_afe_initialization(struct isci_host *ihost) writel(0x0081000f, &afe->afe_dfx_master_control0); udelay(AFE_REGISTER_WRITE_DELAY); - if (is_b0(pdev)) { + if (is_b0(pdev) || is_c0(pdev) || is_c1(pdev)) { /* PM Rx Equalization Save, PM SPhy Rx Acknowledgement * Timer, PM Stagger Timer */ - writel(0x0007BFFF, &afe->afe_pmsn_master_control2); + writel(0x0007FFFF, &afe->afe_pmsn_master_control2); udelay(AFE_REGISTER_WRITE_DELAY); } @@ -1935,14 +1946,23 @@ static void sci_controller_afe_initialization(struct isci_host *ihost) writel(0x00005A00, &afe->afe_bias_control); else if (is_b0(pdev) || is_c0(pdev)) writel(0x00005F00, &afe->afe_bias_control); + else if (is_c1(pdev)) + writel(0x00005500, &afe->afe_bias_control); udelay(AFE_REGISTER_WRITE_DELAY); /* Enable PLL */ - if (is_b0(pdev) || is_c0(pdev)) - writel(0x80040A08, &afe->afe_pll_control0); - else + if (is_a2(pdev)) writel(0x80040908, &afe->afe_pll_control0); + else if (is_b0(pdev) || is_c0(pdev)) + writel(0x80040A08, &afe->afe_pll_control0); + else if (is_c1(pdev)) { + writel(0x80000B08, &afe->afe_pll_control0); + udelay(AFE_REGISTER_WRITE_DELAY); + writel(0x00000B08, &afe->afe_pll_control0); + udelay(AFE_REGISTER_WRITE_DELAY); + writel(0x80000B08, &afe->afe_pll_control0); + } udelay(AFE_REGISTER_WRITE_DELAY); @@ -1963,46 +1983,68 @@ static void sci_controller_afe_initialization(struct isci_host *ihost) for (phy_id = 0; phy_id < SCI_MAX_PHYS; phy_id++) { struct scu_afe_transceiver *xcvr = &afe->scu_afe_xcvr[phy_id]; const struct sci_phy_oem_params *oem_phy = &oem->phys[phy_id]; + int cable_length_long = + is_long_cable(phy_id, cable_selection_mask); + int cable_length_medium = + is_medium_cable(phy_id, cable_selection_mask); + + if (is_a2(pdev)) { + /* All defaults, except the Receive Word + * Alignament/Comma Detect Enable....(0xe800) + */ + writel(0x00004512, &xcvr->afe_xcvr_control0); + udelay(AFE_REGISTER_WRITE_DELAY); - if (is_b0(pdev)) { - /* Configure transmitter SSC parameters */ + writel(0x0050100F, &xcvr->afe_xcvr_control1); + udelay(AFE_REGISTER_WRITE_DELAY); + } else if (is_b0(pdev)) { + /* Configure transmitter SSC parameters */ writel(0x00030000, &xcvr->afe_tx_ssc_control); udelay(AFE_REGISTER_WRITE_DELAY); } else if (is_c0(pdev)) { - /* Configure transmitter SSC parameters */ - writel(0x0003000, &xcvr->afe_tx_ssc_control); + /* Configure transmitter SSC parameters */ + writel(0x00010202, &xcvr->afe_tx_ssc_control); udelay(AFE_REGISTER_WRITE_DELAY); /* All defaults, except the Receive Word * Alignament/Comma Detect Enable....(0xe800) */ - writel(0x00004500, &xcvr->afe_xcvr_control0); + writel(0x00014500, &xcvr->afe_xcvr_control0); udelay(AFE_REGISTER_WRITE_DELAY); - } else { + } else if (is_c1(pdev)) { + /* Configure transmitter SSC parameters */ + writel(0x00010202, &xcvr->afe_tx_ssc_control); + udelay(AFE_REGISTER_WRITE_DELAY); + /* All defaults, except the Receive Word * Alignament/Comma Detect Enable....(0xe800) */ - writel(0x00004512, &xcvr->afe_xcvr_control0); - udelay(AFE_REGISTER_WRITE_DELAY); - - writel(0x0050100F, &xcvr->afe_xcvr_control1); + writel(0x0001C500, &xcvr->afe_xcvr_control0); udelay(AFE_REGISTER_WRITE_DELAY); } - /* Power up TX and RX out from power down (PWRDNTX and PWRDNRX) - * & increase TX int & ext bias 20%....(0xe85c) + /* Power up TX and RX out from power down (PWRDNTX and + * PWRDNRX) & increase TX int & ext bias 20%....(0xe85c) */ if (is_a2(pdev)) writel(0x000003F0, &xcvr->afe_channel_control); else if (is_b0(pdev)) { - /* Power down TX and RX (PWRDNTX and PWRDNRX) */ writel(0x000003D7, &xcvr->afe_channel_control); udelay(AFE_REGISTER_WRITE_DELAY); + writel(0x000003D4, &xcvr->afe_channel_control); - } else { + } else if (is_c0(pdev)) { writel(0x000001E7, &xcvr->afe_channel_control); udelay(AFE_REGISTER_WRITE_DELAY); + writel(0x000001E4, &xcvr->afe_channel_control); + } else if (is_c1(pdev)) { + writel(cable_length_long ? 0x000002F7 : 0x000001F7, + &xcvr->afe_channel_control); + udelay(AFE_REGISTER_WRITE_DELAY); + + writel(cable_length_long ? 0x000002F4 : 0x000001F4, + &xcvr->afe_channel_control); } udelay(AFE_REGISTER_WRITE_DELAY); @@ -2012,7 +2054,16 @@ static void sci_controller_afe_initialization(struct isci_host *ihost) udelay(AFE_REGISTER_WRITE_DELAY); } - writel(0x00004100, &xcvr->afe_xcvr_control0); + if (is_a2(pdev) || is_b0(pdev)) + /* RDPI=0x0(RX Power On), RXOOBDETPDNC=0x0, + * TPD=0x0(TX Power On), RDD=0x0(RX Detect + * Enabled) ....(0xe800) + */ + writel(0x00004100, &xcvr->afe_xcvr_control0); + else if (is_c0(pdev)) + writel(0x00014100, &xcvr->afe_xcvr_control0); + else if (is_c1(pdev)) + writel(0x0001C100, &xcvr->afe_xcvr_control0); udelay(AFE_REGISTER_WRITE_DELAY); /* Leave DFE/FFE on */ @@ -2023,13 +2074,29 @@ static void sci_controller_afe_initialization(struct isci_host *ihost) udelay(AFE_REGISTER_WRITE_DELAY); /* Enable TX equalization (0xe824) */ writel(0x00040000, &xcvr->afe_tx_control); - } else { - writel(0x0140DF0F, &xcvr->afe_rx_ssc_control1); + } else if (is_c0(pdev)) { + writel(0x01400C0F, &xcvr->afe_rx_ssc_control1); udelay(AFE_REGISTER_WRITE_DELAY); writel(0x3F6F103F, &xcvr->afe_rx_ssc_control0); udelay(AFE_REGISTER_WRITE_DELAY); + /* Enable TX equalization (0xe824) */ + writel(0x00040000, &xcvr->afe_tx_control); + } else if (is_c1(pdev)) { + writel(cable_length_long ? 0x01500C0C : + cable_length_medium ? 0x01400C0D : 0x02400C0D, + &xcvr->afe_xcvr_control1); + udelay(AFE_REGISTER_WRITE_DELAY); + + writel(0x000003E0, &xcvr->afe_dfx_rx_control1); + udelay(AFE_REGISTER_WRITE_DELAY); + + writel(cable_length_long ? 0x33091C1F : + cable_length_medium ? 0x3315181F : 0x2B17161F, + &xcvr->afe_rx_ssc_control0); + udelay(AFE_REGISTER_WRITE_DELAY); + /* Enable TX equalization (0xe824) */ writel(0x00040000, &xcvr->afe_tx_control); } diff --git a/drivers/scsi/isci/host.h b/drivers/scsi/isci/host.h index 646051afd3cb..4573075a6b97 100644 --- a/drivers/scsi/isci/host.h +++ b/drivers/scsi/isci/host.h @@ -435,7 +435,14 @@ static inline bool is_b0(struct pci_dev *pdev) static inline bool is_c0(struct pci_dev *pdev) { - if (pdev->revision >= 5) + if (pdev->revision == 5) + return true; + return false; +} + +static inline bool is_c1(struct pci_dev *pdev) +{ + if (pdev->revision >= 6) return true; return false; } diff --git a/drivers/scsi/isci/phy.c b/drivers/scsi/isci/phy.c index 0ae0990b39dd..c650d3003c22 100644 --- a/drivers/scsi/isci/phy.c +++ b/drivers/scsi/isci/phy.c @@ -186,8 +186,11 @@ sci_phy_link_layer_initialization(struct isci_phy *iphy, writel(clksm_value, &llr->clock_skew_management); - /* @todo Provide a way to write this register correctly */ - writel(0x02108421, &llr->afe_lookup_table_control); + if (is_c0(ihost->pdev) || is_c1(ihost->pdev)) { + writel(0x04210400, &llr->afe_lookup_table_control); + writel(0x020A7C05, &llr->sas_primitive_timeout); + } else + writel(0x02108421, &llr->afe_lookup_table_control); llctl = SCU_SAS_LLCTL_GEN_VAL(NO_OUTBOUND_TASK_TIMEOUT, (u8)ihost->user_parameters.no_outbound_task_timeout); diff --git a/drivers/scsi/isci/probe_roms.c b/drivers/scsi/isci/probe_roms.c index b5f4341de243..9b8117b9d756 100644 --- a/drivers/scsi/isci/probe_roms.c +++ b/drivers/scsi/isci/probe_roms.c @@ -147,7 +147,7 @@ struct isci_orom *isci_request_firmware(struct pci_dev *pdev, const struct firmw memcpy(orom, fw->data, fw->size); - if (is_c0(pdev)) + if (is_c0(pdev) || is_c1(pdev)) goto out; /* -- cgit v1.2.3 From 594e566ae5985e0cc3185ac21509a86e90aad577 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Wed, 4 Jan 2012 01:32:44 -0800 Subject: [SCSI] isci: oem parameter format v1.1 (ssc select) v1.1 allows finer grained tuning of the SSC (spread-spectrum-clocking) settings for SAS and SATA. See notes in probe_roms.h Signed-off-by: Dave Jiang Signed-off-by: Dan Williams Signed-off-by: James Bottomley --- drivers/scsi/isci/host.c | 47 +++++++++++++++++++++++++++++++++++-- drivers/scsi/isci/init.c | 3 ++- drivers/scsi/isci/phy.c | 51 +++++++++++++++++++++++++++++++++++++++- drivers/scsi/isci/probe_roms.h | 53 ++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 148 insertions(+), 6 deletions(-) (limited to 'drivers/scsi/isci/phy.c') diff --git a/drivers/scsi/isci/host.c b/drivers/scsi/isci/host.c index 383bb6913087..ed1441c89577 100644 --- a/drivers/scsi/isci/host.c +++ b/drivers/scsi/isci/host.c @@ -1759,7 +1759,7 @@ static enum sci_status sci_controller_construct(struct isci_host *ihost, return sci_controller_reset(ihost); } -int sci_oem_parameters_validate(struct sci_oem_params *oem) +int sci_oem_parameters_validate(struct sci_oem_params *oem, u8 version) { int i; @@ -1791,18 +1791,61 @@ int sci_oem_parameters_validate(struct sci_oem_params *oem) oem->controller.max_concurr_spin_up < 1) return -EINVAL; + if (oem->controller.do_enable_ssc) { + if (version < ISCI_ROM_VER_1_1 && oem->controller.do_enable_ssc != 1) + return -EINVAL; + + if (version >= ISCI_ROM_VER_1_1) { + u8 test = oem->controller.ssc_sata_tx_spread_level; + + switch (test) { + case 0: + case 2: + case 3: + case 6: + case 7: + break; + default: + return -EINVAL; + } + + test = oem->controller.ssc_sas_tx_spread_level; + if (oem->controller.ssc_sas_tx_type == 0) { + switch (test) { + case 0: + case 2: + case 3: + break; + default: + return -EINVAL; + } + } else if (oem->controller.ssc_sas_tx_type == 1) { + switch (test) { + case 0: + case 3: + case 6: + break; + default: + return -EINVAL; + } + } + } + } + return 0; } static enum sci_status sci_oem_parameters_set(struct isci_host *ihost) { u32 state = ihost->sm.current_state_id; + struct isci_pci_info *pci_info = to_pci_info(ihost->pdev); if (state == SCIC_RESET || state == SCIC_INITIALIZING || state == SCIC_INITIALIZED) { - if (sci_oem_parameters_validate(&ihost->oem_parameters)) + if (sci_oem_parameters_validate(&ihost->oem_parameters, + pci_info->orom->hdr.version)) return SCI_FAILURE_INVALID_PARAMETER_VALUE; return SCI_SUCCESS; diff --git a/drivers/scsi/isci/init.c b/drivers/scsi/isci/init.c index a97edabcb85a..8a34fd92e42e 100644 --- a/drivers/scsi/isci/init.c +++ b/drivers/scsi/isci/init.c @@ -466,7 +466,8 @@ static int __devinit isci_pci_probe(struct pci_dev *pdev, const struct pci_devic orom = isci_request_oprom(pdev); for (i = 0; orom && i < ARRAY_SIZE(orom->ctrl); i++) { - if (sci_oem_parameters_validate(&orom->ctrl[i])) { + if (sci_oem_parameters_validate(&orom->ctrl[i], + orom->hdr.version)) { dev_warn(&pdev->dev, "[%d]: invalid oem parameters detected, falling back to firmware\n", i); devm_kfree(&pdev->dev, orom); diff --git a/drivers/scsi/isci/phy.c b/drivers/scsi/isci/phy.c index c650d3003c22..61000cde84c7 100644 --- a/drivers/scsi/isci/phy.c +++ b/drivers/scsi/isci/phy.c @@ -144,10 +144,59 @@ sci_phy_link_layer_initialization(struct isci_phy *iphy, phy_cap.gen3_no_ssc = 1; phy_cap.gen2_no_ssc = 1; phy_cap.gen1_no_ssc = 1; - if (ihost->oem_parameters.controller.do_enable_ssc == true) { + if (ihost->oem_parameters.controller.do_enable_ssc) { + struct scu_afe_registers __iomem *afe = &ihost->scu_registers->afe; + struct scu_afe_transceiver *xcvr = &afe->scu_afe_xcvr[phy_idx]; + struct isci_pci_info *pci_info = to_pci_info(ihost->pdev); + bool en_sas = false; + bool en_sata = false; + u32 sas_type = 0; + u32 sata_spread = 0x2; + u32 sas_spread = 0x2; + phy_cap.gen3_ssc = 1; phy_cap.gen2_ssc = 1; phy_cap.gen1_ssc = 1; + + if (pci_info->orom->hdr.version < ISCI_ROM_VER_1_1) + en_sas = en_sata = true; + else { + sata_spread = ihost->oem_parameters.controller.ssc_sata_tx_spread_level; + sas_spread = ihost->oem_parameters.controller.ssc_sas_tx_spread_level; + + if (sata_spread) + en_sata = true; + + if (sas_spread) { + en_sas = true; + sas_type = ihost->oem_parameters.controller.ssc_sas_tx_type; + } + + } + + if (en_sas) { + u32 reg; + + reg = readl(&xcvr->afe_xcvr_control0); + reg |= (0x00100000 | (sas_type << 19)); + writel(reg, &xcvr->afe_xcvr_control0); + + reg = readl(&xcvr->afe_tx_ssc_control); + reg |= sas_spread << 8; + writel(reg, &xcvr->afe_tx_ssc_control); + } + + if (en_sata) { + u32 reg; + + reg = readl(&xcvr->afe_tx_ssc_control); + reg |= sata_spread; + writel(reg, &xcvr->afe_tx_ssc_control); + + reg = readl(&llr->stp_control); + reg |= 1 << 12; + writel(reg, &llr->stp_control); + } } /* The SAS specification indicates that the phy_capabilities that diff --git a/drivers/scsi/isci/probe_roms.h b/drivers/scsi/isci/probe_roms.h index 2c75248ca326..42dd05414f3b 100644 --- a/drivers/scsi/isci/probe_roms.h +++ b/drivers/scsi/isci/probe_roms.h @@ -152,7 +152,7 @@ struct sci_user_parameters { #define MAX_CONCURRENT_DEVICE_SPIN_UP_COUNT 4 struct sci_oem_params; -int sci_oem_parameters_validate(struct sci_oem_params *oem); +int sci_oem_parameters_validate(struct sci_oem_params *oem, u8 version); struct isci_orom; struct isci_orom *isci_request_oprom(struct pci_dev *pdev); @@ -191,6 +191,10 @@ struct isci_oem_hdr { 0x1a, 0x04, 0xc6) #define ISCI_EFI_VAR_NAME "RstScuO" +#define ISCI_ROM_VER_1_0 0x10 +#define ISCI_ROM_VER_1_1 0x11 +#define ISCI_ROM_VER_LATEST ISCI_ROM_VER_1_1 + /* 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. @@ -220,7 +224,52 @@ struct sci_oem_params { struct { uint8_t mode_type; uint8_t max_concurr_spin_up; - uint8_t do_enable_ssc; + /* + * This bitfield indicates the OEM's desired default Tx + * Spread Spectrum Clocking (SSC) settings for SATA and SAS. + * NOTE: Default SSC Modulation Frequency is 31.5KHz. + */ + union { + struct { + /* + * NOTE: Max spread for SATA is +0 / -5000 PPM. + * Down-spreading SSC (only method allowed for SATA): + * SATA SSC Tx Disabled = 0x0 + * SATA SSC Tx at +0 / -1419 PPM Spread = 0x2 + * SATA SSC Tx at +0 / -2129 PPM Spread = 0x3 + * SATA SSC Tx at +0 / -4257 PPM Spread = 0x6 + * SATA SSC Tx at +0 / -4967 PPM Spread = 0x7 + */ + uint8_t ssc_sata_tx_spread_level:4; + /* + * SAS SSC Tx Disabled = 0x0 + * + * NOTE: Max spread for SAS down-spreading +0 / + * -2300 PPM + * Down-spreading SSC: + * SAS SSC Tx at +0 / -1419 PPM Spread = 0x2 + * SAS SSC Tx at +0 / -2129 PPM Spread = 0x3 + * + * NOTE: Max spread for SAS center-spreading +2300 / + * -2300 PPM + * Center-spreading SSC: + * SAS SSC Tx at +1064 / -1064 PPM Spread = 0x3 + * SAS SSC Tx at +2129 / -2129 PPM Spread = 0x6 + */ + uint8_t ssc_sas_tx_spread_level:3; + /* + * NOTE: Refer to the SSC section of the SAS 2.x + * Specification for proper setting of this field. + * For standard SAS Initiator SAS PHY operation it + * should be 0 for Down-spreading. + * SAS SSC Tx spread type: + * Down-spreading SSC = 0 + * Center-spreading SSC = 1 + */ + uint8_t ssc_sas_tx_type:1; + }; + uint8_t do_enable_ssc; + }; uint8_t reserved; } controller; -- cgit v1.2.3 From 0953dbea1d9a84c8443b5f5bb45229a6c9d7f9f3 Mon Sep 17 00:00:00 2001 From: Marcin Tomczak Date: Wed, 4 Jan 2012 01:33:36 -0800 Subject: [SCSI] isci: fix start OOB Split scu_link_layer_start_oob function to reset and enable and add flush after all steps. Signed-off-by: Marcin Tomczak Signed-off-by: Dan Williams Signed-off-by: James Bottomley --- drivers/scsi/isci/phy.c | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) (limited to 'drivers/scsi/isci/phy.c') diff --git a/drivers/scsi/isci/phy.c b/drivers/scsi/isci/phy.c index 61000cde84c7..fe18acfd6eb3 100644 --- a/drivers/scsi/isci/phy.c +++ b/drivers/scsi/isci/phy.c @@ -1098,24 +1098,25 @@ static void scu_link_layer_stop_protocol_engine( writel(enable_spinup_value, &iphy->link_layer_registers->notify_enable_spinup_control); } -/** - * - * - * This method will start the OOB/SN state machine for this struct isci_phy object. - */ -static void scu_link_layer_start_oob( - struct isci_phy *iphy) +static void scu_link_layer_start_oob(struct isci_phy *iphy) { - u32 scu_sas_pcfg_value; - - scu_sas_pcfg_value = - readl(&iphy->link_layer_registers->phy_configuration); - scu_sas_pcfg_value |= SCU_SAS_PCFG_GEN_BIT(OOB_ENABLE); - scu_sas_pcfg_value &= - ~(SCU_SAS_PCFG_GEN_BIT(OOB_RESET) | - SCU_SAS_PCFG_GEN_BIT(HARD_RESET)); - writel(scu_sas_pcfg_value, - &iphy->link_layer_registers->phy_configuration); + struct scu_link_layer_registers __iomem *ll = iphy->link_layer_registers; + u32 val; + + /** Reset OOB sequence - start */ + val = readl(&ll->phy_configuration); + val &= ~(SCU_SAS_PCFG_GEN_BIT(OOB_RESET) | + SCU_SAS_PCFG_GEN_BIT(HARD_RESET)); + writel(val, &ll->phy_configuration); + readl(&ll->phy_configuration); /* flush */ + /** Reset OOB sequence - end */ + + /** Start OOB sequence - start */ + val = readl(&ll->phy_configuration); + val |= SCU_SAS_PCFG_GEN_BIT(OOB_ENABLE); + writel(val, &ll->phy_configuration); + readl(&ll->phy_configuration); /* flush */ + /** Start OOB sequence - end */ } /** -- cgit v1.2.3