diff options
-rw-r--r-- | drivers/scsi/Kconfig | 15 | ||||
-rw-r--r-- | drivers/scsi/esas2r/esas2r_ioctl.c | 16 | ||||
-rw-r--r-- | drivers/scsi/imm.c | 70 | ||||
-rw-r--r-- | drivers/scsi/imm.h | 4 | ||||
-rw-r--r-- | drivers/scsi/libsas/sas_discover.c | 2 | ||||
-rw-r--r-- | drivers/scsi/libsas/sas_init.c | 4 | ||||
-rw-r--r-- | drivers/scsi/libsas/sas_internal.h | 12 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_os.c | 5 | ||||
-rw-r--r-- | drivers/ufs/core/ufshcd.c | 7 | ||||
-rw-r--r-- | drivers/ufs/host/ufs-mediatek.c | 2 | ||||
-rw-r--r-- | drivers/ufs/host/ufs-qcom.c | 215 | ||||
-rw-r--r-- | drivers/ufs/host/ufs-qcom.h | 20 | ||||
-rw-r--r-- | drivers/ufs/host/ufshcd-pltfrm.c | 15 | ||||
-rw-r--r-- | drivers/ufs/host/ufshcd-pltfrm.h | 2 | ||||
-rw-r--r-- | include/scsi/libsas.h | 17 | ||||
-rw-r--r-- | include/trace/events/ufs.h | 15 |
16 files changed, 270 insertions, 151 deletions
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index 695a57d894cd..addac7fbe37b 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -834,21 +834,6 @@ config SCSI_IMM To compile this driver as a module, choose M here: the module will be called imm. -config SCSI_IZIP_EPP16 - bool "ppa/imm option - Use slow (but safe) EPP-16" - depends on SCSI_IMM - help - EPP (Enhanced Parallel Port) is a standard for parallel ports which - allows them to act as expansion buses that can handle up to 64 - peripheral devices. - - Some parallel port chipsets are slower than their motherboard, and - so we have to control the state of the chipset's FIFO queue every - now and then to avoid data loss. This will be done if you say Y - here. - - Generally, saying Y is the safe option and slows things down a bit. - config SCSI_IZIP_SLOW_CTR bool "ppa/imm option - Assume slow parport control register" depends on SCSI_PPA || SCSI_IMM diff --git a/drivers/scsi/esas2r/esas2r_ioctl.c b/drivers/scsi/esas2r/esas2r_ioctl.c index 055d2e87a2c8..3f7c1d131ec3 100644 --- a/drivers/scsi/esas2r/esas2r_ioctl.c +++ b/drivers/scsi/esas2r/esas2r_ioctl.c @@ -41,6 +41,8 @@ * USA. */ +#include <linux/bitfield.h> + #include "esas2r.h" /* @@ -792,16 +794,10 @@ static int hba_ioctl_callback(struct esas2r_adapter *a, pcie_capability_read_dword(a->pcid, PCI_EXP_LNKCAP, &caps); - gai->pci.link_speed_curr = - (u8)(stat & PCI_EXP_LNKSTA_CLS); - gai->pci.link_speed_max = - (u8)(caps & PCI_EXP_LNKCAP_SLS); - gai->pci.link_width_curr = - (u8)((stat & PCI_EXP_LNKSTA_NLW) - >> PCI_EXP_LNKSTA_NLW_SHIFT); - gai->pci.link_width_max = - (u8)((caps & PCI_EXP_LNKCAP_MLW) - >> 4); + gai->pci.link_speed_curr = FIELD_GET(PCI_EXP_LNKSTA_CLS, stat); + gai->pci.link_speed_max = FIELD_GET(PCI_EXP_LNKCAP_SLS, caps); + gai->pci.link_width_curr = FIELD_GET(PCI_EXP_LNKSTA_NLW, stat); + gai->pci.link_width_max = FIELD_GET(PCI_EXP_LNKCAP_MLW, caps); } gai->pci.msi_vector_cnt = 1; diff --git a/drivers/scsi/imm.c b/drivers/scsi/imm.c index 07db98161a03..180a5ddedb2c 100644 --- a/drivers/scsi/imm.c +++ b/drivers/scsi/imm.c @@ -51,10 +51,15 @@ typedef struct { } imm_struct; static void imm_reset_pulse(unsigned int base); -static int device_check(imm_struct *dev); +static int device_check(imm_struct *dev, bool autodetect); #include "imm.h" +static unsigned int mode = IMM_AUTODETECT; +module_param(mode, uint, 0644); +MODULE_PARM_DESC(mode, "Transfer mode (0 = Autodetect, 1 = SPP 4-bit, " + "2 = SPP 8-bit, 3 = EPP 8-bit, 4 = EPP 16-bit, 5 = EPP 32-bit"); + static inline imm_struct *imm_dev(struct Scsi_Host *host) { return *(imm_struct **)&host->hostdata; @@ -366,13 +371,10 @@ static int imm_out(imm_struct *dev, char *buffer, int len) case IMM_EPP_8: epp_reset(ppb); w_ctr(ppb, 0x4); -#ifdef CONFIG_SCSI_IZIP_EPP16 - if (!(((long) buffer | len) & 0x01)) - outsw(ppb + 4, buffer, len >> 1); -#else - if (!(((long) buffer | len) & 0x03)) + if (dev->mode == IMM_EPP_32 && !(((long) buffer | len) & 0x03)) outsl(ppb + 4, buffer, len >> 2); -#endif + else if (dev->mode == IMM_EPP_16 && !(((long) buffer | len) & 0x01)) + outsw(ppb + 4, buffer, len >> 1); else outsb(ppb + 4, buffer, len); w_ctr(ppb, 0xc); @@ -426,13 +428,10 @@ static int imm_in(imm_struct *dev, char *buffer, int len) case IMM_EPP_8: epp_reset(ppb); w_ctr(ppb, 0x24); -#ifdef CONFIG_SCSI_IZIP_EPP16 - if (!(((long) buffer | len) & 0x01)) - insw(ppb + 4, buffer, len >> 1); -#else - if (!(((long) buffer | len) & 0x03)) - insl(ppb + 4, buffer, len >> 2); -#endif + if (dev->mode == IMM_EPP_32 && !(((long) buffer | len) & 0x03)) + insw(ppb + 4, buffer, len >> 2); + else if (dev->mode == IMM_EPP_16 && !(((long) buffer | len) & 0x01)) + insl(ppb + 4, buffer, len >> 1); else insb(ppb + 4, buffer, len); w_ctr(ppb, 0x2c); @@ -589,13 +588,28 @@ static int imm_select(imm_struct *dev, int target) static int imm_init(imm_struct *dev) { + bool autodetect = dev->mode == IMM_AUTODETECT; + + if (autodetect) { + int modes = dev->dev->port->modes; + + /* Mode detection works up the chain of speed + * This avoids a nasty if-then-else-if-... tree + */ + dev->mode = IMM_NIBBLE; + + if (modes & PARPORT_MODE_TRISTATE) + dev->mode = IMM_PS2; + } + if (imm_connect(dev, 0) != 1) return -EIO; imm_reset_pulse(dev->base); mdelay(1); /* Delay to allow devices to settle */ imm_disconnect(dev); mdelay(1); /* Another delay to allow devices to settle */ - return device_check(dev); + + return device_check(dev, autodetect); } static inline int imm_send_command(struct scsi_cmnd *cmd) @@ -1000,7 +1014,7 @@ static int imm_reset(struct scsi_cmnd *cmd) return SUCCESS; } -static int device_check(imm_struct *dev) +static int device_check(imm_struct *dev, bool autodetect) { /* This routine looks for a device and then attempts to use EPP to send a command. If all goes as planned then EPP is available. */ @@ -1012,8 +1026,8 @@ static int device_check(imm_struct *dev) old_mode = dev->mode; for (loop = 0; loop < 8; loop++) { /* Attempt to use EPP for Test Unit Ready */ - if ((ppb & 0x0007) == 0x0000) - dev->mode = IMM_EPP_32; + if (autodetect && (ppb & 0x0007) == 0x0000) + dev->mode = IMM_EPP_8; second_pass: imm_connect(dev, CONNECT_EPP_MAYBE); @@ -1038,7 +1052,7 @@ static int device_check(imm_struct *dev) udelay(1000); imm_disconnect(dev); udelay(1000); - if (dev->mode == IMM_EPP_32) { + if (dev->mode != old_mode) { dev->mode = old_mode; goto second_pass; } @@ -1063,7 +1077,7 @@ static int device_check(imm_struct *dev) udelay(1000); imm_disconnect(dev); udelay(1000); - if (dev->mode == IMM_EPP_32) { + if (dev->mode != old_mode) { dev->mode = old_mode; goto second_pass; } @@ -1150,7 +1164,6 @@ static int __imm_attach(struct parport *pb) DECLARE_WAIT_QUEUE_HEAD_ONSTACK(waiting); DEFINE_WAIT(wait); int ports; - int modes, ppb; int err = -ENOMEM; struct pardev_cb imm_cb; @@ -1162,7 +1175,7 @@ static int __imm_attach(struct parport *pb) dev->base = -1; - dev->mode = IMM_AUTODETECT; + dev->mode = mode < IMM_UNKNOWN ? mode : IMM_AUTODETECT; INIT_LIST_HEAD(&dev->list); temp = find_parent(); @@ -1197,18 +1210,9 @@ static int __imm_attach(struct parport *pb) } dev->waiting = NULL; finish_wait(&waiting, &wait); - ppb = dev->base = dev->dev->port->base; + dev->base = dev->dev->port->base; dev->base_hi = dev->dev->port->base_hi; - w_ctr(ppb, 0x0c); - modes = dev->dev->port->modes; - - /* Mode detection works up the chain of speed - * This avoids a nasty if-then-else-if-... tree - */ - dev->mode = IMM_NIBBLE; - - if (modes & PARPORT_MODE_TRISTATE) - dev->mode = IMM_PS2; + w_ctr(dev->base, 0x0c); /* Done configuration */ diff --git a/drivers/scsi/imm.h b/drivers/scsi/imm.h index 411cf94af5b0..398fa5b15181 100644 --- a/drivers/scsi/imm.h +++ b/drivers/scsi/imm.h @@ -100,11 +100,7 @@ static char *IMM_MODE_STRING[] = [IMM_PS2] = "PS/2", [IMM_EPP_8] = "EPP 8 bit", [IMM_EPP_16] = "EPP 16 bit", -#ifdef CONFIG_SCSI_IZIP_EPP16 - [IMM_EPP_32] = "EPP 16 bit", -#else [IMM_EPP_32] = "EPP 32 bit", -#endif [IMM_UNKNOWN] = "Unknown", }; diff --git a/drivers/scsi/libsas/sas_discover.c b/drivers/scsi/libsas/sas_discover.c index ff7b63b10aeb..8fb7c41c0962 100644 --- a/drivers/scsi/libsas/sas_discover.c +++ b/drivers/scsi/libsas/sas_discover.c @@ -275,7 +275,7 @@ static void sas_resume_devices(struct work_struct *work) * * See comment in sas_discover_sata(). */ -int sas_discover_end_dev(struct domain_device *dev) +static int sas_discover_end_dev(struct domain_device *dev) { return sas_notify_lldd_dev_found(dev); } diff --git a/drivers/scsi/libsas/sas_init.c b/drivers/scsi/libsas/sas_init.c index 8586dc79f2a0..9c8cc723170d 100644 --- a/drivers/scsi/libsas/sas_init.c +++ b/drivers/scsi/libsas/sas_init.c @@ -315,8 +315,8 @@ int sas_phy_reset(struct sas_phy *phy, int hard_reset) } EXPORT_SYMBOL_GPL(sas_phy_reset); -int sas_set_phy_speed(struct sas_phy *phy, - struct sas_phy_linkrates *rates) +static int sas_set_phy_speed(struct sas_phy *phy, + struct sas_phy_linkrates *rates) { int ret; diff --git a/drivers/scsi/libsas/sas_internal.h b/drivers/scsi/libsas/sas_internal.h index a6dc7dc07fce..3804aef165ad 100644 --- a/drivers/scsi/libsas/sas_internal.h +++ b/drivers/scsi/libsas/sas_internal.h @@ -39,6 +39,18 @@ struct sas_phy_data { struct sas_work enable_work; }; +void sas_hash_addr(u8 *hashed, const u8 *sas_addr); + +int sas_discover_root_expander(struct domain_device *dev); + +int sas_ex_revalidate_domain(struct domain_device *dev); +void sas_unregister_domain_devices(struct asd_sas_port *port, int gone); +void sas_init_disc(struct sas_discovery *disc, struct asd_sas_port *port); +void sas_discover_event(struct asd_sas_port *port, enum discover_event ev); + +void sas_init_dev(struct domain_device *dev); +void sas_unregister_dev(struct asd_sas_port *port, struct domain_device *dev); + void sas_scsi_recover_host(struct Scsi_Host *shost); int sas_register_phys(struct sas_ha_struct *sas_ha); diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 50db08265c51..7e103d711825 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -5,6 +5,7 @@ */ #include "qla_def.h" +#include <linux/bitfield.h> #include <linux/moduleparam.h> #include <linux/vmalloc.h> #include <linux/delay.h> @@ -633,8 +634,8 @@ qla24xx_pci_info_str(struct scsi_qla_host *vha, char *str, size_t str_len) const char *speed_str; pcie_capability_read_dword(ha->pdev, PCI_EXP_LNKCAP, &lstat); - lspeed = lstat & PCI_EXP_LNKCAP_SLS; - lwidth = (lstat & PCI_EXP_LNKCAP_MLW) >> 4; + lspeed = FIELD_GET(PCI_EXP_LNKCAP_SLS, lstat); + lwidth = FIELD_GET(PCI_EXP_LNKCAP_MLW, lstat); switch (lspeed) { case 1: diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index c2df07545f96..5f874c685f8d 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -447,8 +447,8 @@ static void ufshcd_add_command_trace(struct ufs_hba *hba, unsigned int tag, } else { doorbell = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL); } - trace_ufshcd_command(dev_name(hba->dev), str_t, tag, - doorbell, hwq_id, transfer_len, intr, lba, opcode, group_id); + trace_ufshcd_command(cmd->device, str_t, tag, doorbell, hwq_id, + transfer_len, intr, lba, opcode, group_id); } static void ufshcd_print_clk_freqs(struct ufs_hba *hba) @@ -8723,7 +8723,8 @@ static int ufshcd_probe_hba(struct ufs_hba *hba, bool init_dev_params) if (ret) goto out; - if (hba->quirks & UFSHCD_QUIRK_REINIT_AFTER_MAX_GEAR_SWITCH) { + if (!hba->pm_op_in_progress && + (hba->quirks & UFSHCD_QUIRK_REINIT_AFTER_MAX_GEAR_SWITCH)) { /* Reset the device and controller before doing reinit */ ufshcd_device_reset(hba); ufshcd_hba_stop(hba); diff --git a/drivers/ufs/host/ufs-mediatek.c b/drivers/ufs/host/ufs-mediatek.c index 2383ecd88f1c..941f58744d08 100644 --- a/drivers/ufs/host/ufs-mediatek.c +++ b/drivers/ufs/host/ufs-mediatek.c @@ -806,7 +806,7 @@ static int ufs_mtk_vreg_fix_vcc(struct ufs_hba *hba) return 0; } - err = ufshcd_populate_vreg(dev, vcc_name, &info->vcc); + err = ufshcd_populate_vreg(dev, vcc_name, &info->vcc, false); if (err) return err; diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c index d1149b1c3ed5..a6078d5939ed 100644 --- a/drivers/ufs/host/ufs-qcom.c +++ b/drivers/ufs/host/ufs-qcom.c @@ -93,8 +93,7 @@ static const struct __ufs_qcom_bw_table { static struct ufs_qcom_host *ufs_qcom_hosts[MAX_UFS_QCOM_HOSTS]; static void ufs_qcom_get_default_testbus_cfg(struct ufs_qcom_host *host); -static int ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div(struct ufs_hba *hba, - u32 clk_cycles); +static int ufs_qcom_set_core_clk_ctrl(struct ufs_hba *hba, bool is_scale_up); static struct ufs_qcom_host *rcdev_to_ufs_host(struct reset_controller_dev *rcd) { @@ -460,7 +459,7 @@ static int ufs_qcom_power_up_sequence(struct ufs_hba *hba) return ret; } - phy_set_mode_ext(phy, PHY_MODE_UFS_HS_B, host->hs_gear); + phy_set_mode_ext(phy, PHY_MODE_UFS_HS_B, host->phy_gear); /* power on phy - start serdes and phy's power and clocks */ ret = phy_power_on(phy); @@ -528,11 +527,20 @@ static int ufs_qcom_hce_enable_notify(struct ufs_hba *hba, return err; } -/* +/** + * ufs_qcom_cfg_timers - Configure ufs qcom cfg timers + * + * @hba: host controller instance + * @gear: Current operating gear + * @hs: current power mode + * @rate: current operating rate (A or B) + * @update_link_startup_timer: indicate if link_start ongoing + * @is_pre_scale_up: flag to check if pre scale up condition. * Return: zero for success and non-zero in case of a failure. */ static int ufs_qcom_cfg_timers(struct ufs_hba *hba, u32 gear, - u32 hs, u32 rate, bool update_link_startup_timer) + u32 hs, u32 rate, bool update_link_startup_timer, + bool is_pre_scale_up) { struct ufs_qcom_host *host = ufshcd_get_variant(hba); struct ufs_clk_info *clki; @@ -563,11 +571,14 @@ static int ufs_qcom_cfg_timers(struct ufs_hba *hba, u32 gear, /* * The Qunipro controller does not use following registers: * SYS1CLK_1US_REG, TX_SYMBOL_CLK_1US_REG, CLK_NS_REG & - * UFS_REG_PA_LINK_STARTUP_TIMER - * But UTP controller uses SYS1CLK_1US_REG register for Interrupt + * UFS_REG_PA_LINK_STARTUP_TIMER. + * However UTP controller uses SYS1CLK_1US_REG register for Interrupt * Aggregation logic. - */ - if (ufs_qcom_cap_qunipro(host) && !ufshcd_is_intr_aggr_allowed(hba)) + * It is mandatory to write SYS1CLK_1US_REG register on UFS host + * controller V4.0.0 onwards. + */ + if (host->hw_ver.major < 4 && ufs_qcom_cap_qunipro(host) && + !ufshcd_is_intr_aggr_allowed(hba)) return 0; if (gear == 0) { @@ -576,8 +587,14 @@ static int ufs_qcom_cfg_timers(struct ufs_hba *hba, u32 gear, } list_for_each_entry(clki, &hba->clk_list_head, list) { - if (!strcmp(clki->name, "core_clk")) - core_clk_rate = clk_get_rate(clki->clk); + if (!strcmp(clki->name, "core_clk")) { + if (is_pre_scale_up) + core_clk_rate = clki->max_freq; + else + core_clk_rate = clk_get_rate(clki->clk); + break; + } + } /* If frequency is smaller than 1MHz, set to 1MHz */ @@ -679,20 +696,17 @@ static int ufs_qcom_link_startup_notify(struct ufs_hba *hba, switch (status) { case PRE_CHANGE: if (ufs_qcom_cfg_timers(hba, UFS_PWM_G1, SLOWAUTO_MODE, - 0, true)) { + 0, true, false)) { dev_err(hba->dev, "%s: ufs_qcom_cfg_timers() failed\n", __func__); return -EINVAL; } - if (ufs_qcom_cap_qunipro(host)) - /* - * set unipro core clock cycles to 150 & clear clock - * divider - */ - err = ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div(hba, - 150); - + if (ufs_qcom_cap_qunipro(host)) { + err = ufs_qcom_set_core_clk_ctrl(hba, true); + if (err) + dev_err(hba->dev, "cfg core clk ctrl failed\n"); + } /* * Some UFS devices (and may be host) have issues if LCC is * enabled. So we are setting PA_Local_TX_LCC_Enable to 0 @@ -909,8 +923,13 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba, return ret; } - /* Use the agreed gear */ - host->hs_gear = dev_req_params->gear_tx; + /* + * Update phy_gear only when the gears are scaled to a higher value. This is + * because, the PHY gear settings are backwards compatible and we only need to + * change the PHY gear settings while scaling to higher gears. + */ + if (dev_req_params->gear_tx > host->phy_gear) + host->phy_gear = dev_req_params->gear_tx; /* enable the device ref clock before changing to HS mode */ if (!ufshcd_is_hs_mode(&hba->pwr_info) && @@ -926,7 +945,7 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba, case POST_CHANGE: if (ufs_qcom_cfg_timers(hba, dev_req_params->gear_rx, dev_req_params->pwr_rx, - dev_req_params->hs_rate, false)) { + dev_req_params->hs_rate, false, false)) { dev_err(hba->dev, "%s: ufs_qcom_cfg_timers() failed\n", __func__); /* @@ -1277,7 +1296,7 @@ static int ufs_qcom_init(struct ufs_hba *hba) * Power up the PHY using the minimum supported gear (UFS_HS_G2). * Switching to max gear will be performed during reinit if supported. */ - host->hs_gear = UFS_HS_G2; + host->phy_gear = UFS_HS_G2; return 0; @@ -1296,14 +1315,96 @@ static void ufs_qcom_exit(struct ufs_hba *hba) phy_exit(host->generic_phy); } -static int ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div(struct ufs_hba *hba, - u32 clk_cycles) +/** + * ufs_qcom_set_clk_40ns_cycles - Configure 40ns clk cycles + * + * @hba: host controller instance + * @cycles_in_1us: No of cycles in 1us to be configured + * + * Returns error if dme get/set configuration for 40ns fails + * and returns zero on success. + */ +static int ufs_qcom_set_clk_40ns_cycles(struct ufs_hba *hba, + u32 cycles_in_1us) { + struct ufs_qcom_host *host = ufshcd_get_variant(hba); + u32 cycles_in_40ns; + u32 reg; int err; - u32 core_clk_ctrl_reg; - if (clk_cycles > DME_VS_CORE_CLK_CTRL_MAX_CORE_CLK_1US_CYCLES_MASK) + /* + * UFS host controller V4.0.0 onwards needs to program + * PA_VS_CORE_CLK_40NS_CYCLES attribute per programmed + * frequency of unipro core clk of UFS host controller. + */ + if (host->hw_ver.major < 4) + return 0; + + /* + * Generic formulae for cycles_in_40ns = (freq_unipro/25) is not + * applicable for all frequencies. For ex: ceil(37.5 MHz/25) will + * be 2 and ceil(403 MHZ/25) will be 17 whereas Hardware + * specification expect to be 16. Hence use exact hardware spec + * mandated value for cycles_in_40ns instead of calculating using + * generic formulae. + */ + switch (cycles_in_1us) { + case UNIPRO_CORE_CLK_FREQ_403_MHZ: + cycles_in_40ns = 16; + break; + case UNIPRO_CORE_CLK_FREQ_300_MHZ: + cycles_in_40ns = 12; + break; + case UNIPRO_CORE_CLK_FREQ_201_5_MHZ: + cycles_in_40ns = 8; + break; + case UNIPRO_CORE_CLK_FREQ_150_MHZ: + cycles_in_40ns = 6; + break; + case UNIPRO_CORE_CLK_FREQ_100_MHZ: + cycles_in_40ns = 4; + break; + case UNIPRO_CORE_CLK_FREQ_75_MHZ: + cycles_in_40ns = 3; + break; + case UNIPRO_CORE_CLK_FREQ_37_5_MHZ: + cycles_in_40ns = 2; + break; + default: + dev_err(hba->dev, "UNIPRO clk freq %u MHz not supported\n", + cycles_in_1us); return -EINVAL; + } + + err = ufshcd_dme_get(hba, UIC_ARG_MIB(PA_VS_CORE_CLK_40NS_CYCLES), ®); + if (err) + return err; + + reg &= ~PA_VS_CORE_CLK_40NS_CYCLES_MASK; + reg |= cycles_in_40ns; + + return ufshcd_dme_set(hba, UIC_ARG_MIB(PA_VS_CORE_CLK_40NS_CYCLES), reg); +} + +static int ufs_qcom_set_core_clk_ctrl(struct ufs_hba *hba, bool is_scale_up) +{ + struct ufs_qcom_host *host = ufshcd_get_variant(hba); + struct list_head *head = &hba->clk_list_head; + struct ufs_clk_info *clki; + u32 cycles_in_1us; + u32 core_clk_ctrl_reg; + int err; + + list_for_each_entry(clki, head, list) { + if (!IS_ERR_OR_NULL(clki->clk) && + !strcmp(clki->name, "core_clk_unipro")) { + if (is_scale_up) + cycles_in_1us = ceil(clki->max_freq, (1000 * 1000)); + else + cycles_in_1us = ceil(clk_get_rate(clki->clk), (1000 * 1000)); + break; + } + } err = ufshcd_dme_get(hba, UIC_ARG_MIB(DME_VS_CORE_CLK_CTRL), @@ -1311,32 +1412,58 @@ static int ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div(struct ufs_hba *hba, if (err) return err; - core_clk_ctrl_reg &= ~DME_VS_CORE_CLK_CTRL_MAX_CORE_CLK_1US_CYCLES_MASK; - core_clk_ctrl_reg |= clk_cycles; + /* Bit mask is different for UFS host controller V4.0.0 onwards */ + if (host->hw_ver.major >= 4) { + if (!FIELD_FIT(CLK_1US_CYCLES_MASK_V4, cycles_in_1us)) + return -ERANGE; + core_clk_ctrl_reg &= ~CLK_1US_CYCLES_MASK_V4; + core_clk_ctrl_reg |= FIELD_PREP(CLK_1US_CYCLES_MASK_V4, cycles_in_1us); + } else { + if (!FIELD_FIT(CLK_1US_CYCLES_MASK, cycles_in_1us)) + return -ERANGE; + core_clk_ctrl_reg &= ~CLK_1US_CYCLES_MASK; + core_clk_ctrl_reg |= FIELD_PREP(CLK_1US_CYCLES_MASK, cycles_in_1us); + } /* Clear CORE_CLK_DIV_EN */ core_clk_ctrl_reg &= ~DME_VS_CORE_CLK_CTRL_CORE_CLK_DIV_EN_BIT; - return ufshcd_dme_set(hba, + err = ufshcd_dme_set(hba, UIC_ARG_MIB(DME_VS_CORE_CLK_CTRL), core_clk_ctrl_reg); -} + if (err) + return err; -static int ufs_qcom_clk_scale_up_pre_change(struct ufs_hba *hba) -{ - /* nothing to do as of now */ - return 0; + /* Configure unipro core clk 40ns attribute */ + return ufs_qcom_set_clk_40ns_cycles(hba, cycles_in_1us); } -static int ufs_qcom_clk_scale_up_post_change(struct ufs_hba *hba) +static int ufs_qcom_clk_scale_up_pre_change(struct ufs_hba *hba) { struct ufs_qcom_host *host = ufshcd_get_variant(hba); + struct ufs_pa_layer_attr *attr = &host->dev_req_params; + int ret; if (!ufs_qcom_cap_qunipro(host)) return 0; - /* set unipro core clock cycles to 150 and clear clock divider */ - return ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div(hba, 150); + if (attr) { + ret = ufs_qcom_cfg_timers(hba, attr->gear_rx, + attr->pwr_rx, attr->hs_rate, + false, true); + if (ret) { + dev_err(hba->dev, "%s ufs cfg timer failed\n", + __func__); + return ret; + } + } + /* set unipro core clock attributes and clear clock divider */ + return ufs_qcom_set_core_clk_ctrl(hba, true); +} + +static int ufs_qcom_clk_scale_up_post_change(struct ufs_hba *hba) +{ + return 0; } static int ufs_qcom_clk_scale_down_pre_change(struct ufs_hba *hba) @@ -1371,15 +1498,14 @@ static int ufs_qcom_clk_scale_down_post_change(struct ufs_hba *hba) if (!ufs_qcom_cap_qunipro(host)) return 0; - /* set unipro core clock cycles to 75 and clear clock divider */ - return ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div(hba, 75); + /* set unipro core clock attributes and clear clock divider */ + return ufs_qcom_set_core_clk_ctrl(hba, false); } static int ufs_qcom_clk_scale_notify(struct ufs_hba *hba, bool scale_up, enum ufs_notify_change_status status) { struct ufs_qcom_host *host = ufshcd_get_variant(hba); - struct ufs_pa_layer_attr *dev_req_params = &host->dev_req_params; int err = 0; /* check the host controller state before sending hibern8 cmd */ @@ -1409,11 +1535,6 @@ static int ufs_qcom_clk_scale_notify(struct ufs_hba *hba, return err; } - ufs_qcom_cfg_timers(hba, - dev_req_params->gear_rx, - dev_req_params->pwr_rx, - dev_req_params->hs_rate, - false); ufs_qcom_icc_update_bw(host); ufshcd_uic_hibern8_exit(hba); } diff --git a/drivers/ufs/host/ufs-qcom.h b/drivers/ufs/host/ufs-qcom.h index d6f8e74bd538..9950a0089475 100644 --- a/drivers/ufs/host/ufs-qcom.h +++ b/drivers/ufs/host/ufs-qcom.h @@ -129,8 +129,21 @@ enum { #define PA_VS_CONFIG_REG1 0x9000 #define DME_VS_CORE_CLK_CTRL 0xD002 /* bit and mask definitions for DME_VS_CORE_CLK_CTRL attribute */ -#define DME_VS_CORE_CLK_CTRL_CORE_CLK_DIV_EN_BIT BIT(8) -#define DME_VS_CORE_CLK_CTRL_MAX_CORE_CLK_1US_CYCLES_MASK 0xFF +#define CLK_1US_CYCLES_MASK_V4 GENMASK(27, 16) +#define CLK_1US_CYCLES_MASK GENMASK(7, 0) +#define DME_VS_CORE_CLK_CTRL_CORE_CLK_DIV_EN_BIT BIT(8) +#define PA_VS_CORE_CLK_40NS_CYCLES 0x9007 +#define PA_VS_CORE_CLK_40NS_CYCLES_MASK GENMASK(6, 0) + + +/* QCOM UFS host controller core clk frequencies */ +#define UNIPRO_CORE_CLK_FREQ_37_5_MHZ 38 +#define UNIPRO_CORE_CLK_FREQ_75_MHZ 75 +#define UNIPRO_CORE_CLK_FREQ_100_MHZ 100 +#define UNIPRO_CORE_CLK_FREQ_150_MHZ 150 +#define UNIPRO_CORE_CLK_FREQ_300_MHZ 300 +#define UNIPRO_CORE_CLK_FREQ_201_5_MHZ 202 +#define UNIPRO_CORE_CLK_FREQ_403_MHZ 403 static inline void ufs_qcom_get_controller_revision(struct ufs_hba *hba, @@ -227,7 +240,7 @@ struct ufs_qcom_host { struct gpio_desc *device_reset; - u32 hs_gear; + u32 phy_gear; bool esi_enabled; }; @@ -244,6 +257,7 @@ ufs_qcom_get_debug_reg_offset(struct ufs_qcom_host *host, u32 reg) #define ufs_qcom_is_link_off(hba) ufshcd_is_link_off(hba) #define ufs_qcom_is_link_active(hba) ufshcd_is_link_active(hba) #define ufs_qcom_is_link_hibern8(hba) ufshcd_is_link_hibern8(hba) +#define ceil(freq, div) ((freq) % (div) == 0 ? ((freq)/(div)) : ((freq)/(div) + 1)) int ufs_qcom_testbus_config(struct ufs_qcom_host *host); diff --git a/drivers/ufs/host/ufshcd-pltfrm.c b/drivers/ufs/host/ufshcd-pltfrm.c index 797a4dfe45d9..61cf8b957da4 100644 --- a/drivers/ufs/host/ufshcd-pltfrm.c +++ b/drivers/ufs/host/ufshcd-pltfrm.c @@ -121,7 +121,7 @@ static bool phandle_exists(const struct device_node *np, #define MAX_PROP_SIZE 32 int ufshcd_populate_vreg(struct device *dev, const char *name, - struct ufs_vreg **out_vreg) + struct ufs_vreg **out_vreg, bool skip_current) { char prop_name[MAX_PROP_SIZE]; struct ufs_vreg *vreg = NULL; @@ -147,6 +147,11 @@ int ufshcd_populate_vreg(struct device *dev, const char *name, if (!vreg->name) return -ENOMEM; + if (skip_current) { + vreg->max_uA = 0; + goto out; + } + snprintf(prop_name, MAX_PROP_SIZE, "%s-max-microamp", name); if (of_property_read_u32(np, prop_name, &vreg->max_uA)) { dev_info(dev, "%s: unable to find %s\n", __func__, prop_name); @@ -175,19 +180,19 @@ static int ufshcd_parse_regulator_info(struct ufs_hba *hba) struct device *dev = hba->dev; struct ufs_vreg_info *info = &hba->vreg_info; - err = ufshcd_populate_vreg(dev, "vdd-hba", &info->vdd_hba); + err = ufshcd_populate_vreg(dev, "vdd-hba", &info->vdd_hba, true); if (err) goto out; - err = ufshcd_populate_vreg(dev, "vcc", &info->vcc); + err = ufshcd_populate_vreg(dev, "vcc", &info->vcc, false); if (err) goto out; - err = ufshcd_populate_vreg(dev, "vccq", &info->vccq); + err = ufshcd_populate_vreg(dev, "vccq", &info->vccq, false); if (err) goto out; - err = ufshcd_populate_vreg(dev, "vccq2", &info->vccq2); + err = ufshcd_populate_vreg(dev, "vccq2", &info->vccq2, false); out: return err; } diff --git a/drivers/ufs/host/ufshcd-pltfrm.h b/drivers/ufs/host/ufshcd-pltfrm.h index 2df108f4ac13..a86a3ada4bef 100644 --- a/drivers/ufs/host/ufshcd-pltfrm.h +++ b/drivers/ufs/host/ufshcd-pltfrm.h @@ -32,6 +32,6 @@ void ufshcd_init_pwr_dev_param(struct ufs_dev_params *dev_param); int ufshcd_pltfrm_init(struct platform_device *pdev, const struct ufs_hba_variant_ops *vops); int ufshcd_populate_vreg(struct device *dev, const char *name, - struct ufs_vreg **out_vreg); + struct ufs_vreg **out_vreg, bool skip_current); #endif /* UFSHCD_PLTFRM_H_ */ diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h index 8a43534eea5c..f5257103fdb6 100644 --- a/include/scsi/libsas.h +++ b/include/scsi/libsas.h @@ -404,8 +404,6 @@ cmd_to_domain_dev(struct scsi_cmnd *cmd) return sdev_to_domain_dev(cmd->device); } -void sas_hash_addr(u8 *hashed, const u8 *sas_addr); - /* Before calling a notify event, LLDD should use this function * when the link is severed (possibly from its tasklet). * The idea is that the Class only reads those, while the LLDD, @@ -681,7 +679,6 @@ extern void sas_resume_ha(struct sas_ha_struct *sas_ha); extern void sas_resume_ha_no_sync(struct sas_ha_struct *sas_ha); extern void sas_suspend_ha(struct sas_ha_struct *sas_ha); -int sas_set_phy_speed(struct sas_phy *phy, struct sas_phy_linkrates *rates); int sas_phy_reset(struct sas_phy *phy, int hard_reset); int sas_phy_enable(struct sas_phy *phy, int enable); extern int sas_queuecommand(struct Scsi_Host *, struct scsi_cmnd *); @@ -699,20 +696,6 @@ extern struct scsi_transport_template * sas_domain_attach_transport(struct sas_domain_function_template *); extern struct device_attribute dev_attr_phy_event_threshold; -int sas_discover_root_expander(struct domain_device *); - -int sas_ex_revalidate_domain(struct domain_device *); - -void sas_unregister_domain_devices(struct asd_sas_port *port, int gone); -void sas_init_disc(struct sas_discovery *disc, struct asd_sas_port *); -void sas_discover_event(struct asd_sas_port *, enum discover_event ev); - -int sas_discover_end_dev(struct domain_device *); - -void sas_unregister_dev(struct asd_sas_port *port, struct domain_device *); - -void sas_init_dev(struct domain_device *); - void sas_task_abort(struct sas_task *); int sas_eh_abort_handler(struct scsi_cmnd *cmd); int sas_eh_device_reset_handler(struct scsi_cmnd *cmd); diff --git a/include/trace/events/ufs.h b/include/trace/events/ufs.h index 992517ac3292..b930669bd1f0 100644 --- a/include/trace/events/ufs.h +++ b/include/trace/events/ufs.h @@ -267,15 +267,15 @@ DEFINE_EVENT(ufshcd_template, ufshcd_wl_runtime_resume, TP_ARGS(dev_name, err, usecs, dev_state, link_state)); TRACE_EVENT(ufshcd_command, - TP_PROTO(const char *dev_name, enum ufs_trace_str_t str_t, + TP_PROTO(struct scsi_device *sdev, enum ufs_trace_str_t str_t, unsigned int tag, u32 doorbell, u32 hwq_id, int transfer_len, u32 intr, u64 lba, u8 opcode, u8 group_id), - TP_ARGS(dev_name, str_t, tag, doorbell, hwq_id, transfer_len, - intr, lba, opcode, group_id), + TP_ARGS(sdev, str_t, tag, doorbell, hwq_id, transfer_len, intr, lba, + opcode, group_id), TP_STRUCT__entry( - __string(dev_name, dev_name) + __field(struct scsi_device *, sdev) __field(enum ufs_trace_str_t, str_t) __field(unsigned int, tag) __field(u32, doorbell) @@ -288,7 +288,7 @@ TRACE_EVENT(ufshcd_command, ), TP_fast_assign( - __assign_str(dev_name, dev_name); + __entry->sdev = sdev; __entry->str_t = str_t; __entry->tag = tag; __entry->doorbell = doorbell; @@ -302,8 +302,9 @@ TRACE_EVENT(ufshcd_command, TP_printk( "%s: %s: tag: %u, DB: 0x%x, size: %d, IS: %u, LBA: %llu, opcode: 0x%x (%s), group_id: 0x%x, hwq_id: %d", - show_ufs_cmd_trace_str(__entry->str_t), __get_str(dev_name), - __entry->tag, __entry->doorbell, __entry->transfer_len, __entry->intr, + show_ufs_cmd_trace_str(__entry->str_t), + dev_name(&__entry->sdev->sdev_dev), __entry->tag, + __entry->doorbell, __entry->transfer_len, __entry->intr, __entry->lba, (u32)__entry->opcode, str_opcode(__entry->opcode), (u32)__entry->group_id, __entry->hwq_id ) |