diff options
author | Joel Stanley <joel@jms.id.au> | 2020-08-31 03:46:52 +0300 |
---|---|---|
committer | Joel Stanley <joel@jms.id.au> | 2020-08-31 03:46:57 +0300 |
commit | 0dd0c8c492fa70707ca4f0d36dcb2e3c64105b16 (patch) | |
tree | a420abd8f26264544246602c60d161a7cc4de390 /drivers/scsi | |
parent | 31d8605658d37d9197a989838508481d5dc1d8bc (diff) | |
parent | 9ece50d8a470ca7235ffd6ac0f9c5f0f201fe2c8 (diff) | |
download | linux-dev-5.8.tar.xz |
Merge tag 'v5.8.5' into dev-5.8dev-5.8
This is the 5.8.5 stable release
Signed-off-by: Joel Stanley <joel@jms.id.au>
Diffstat (limited to 'drivers/scsi')
-rw-r--r-- | drivers/scsi/arm/cumana_2.c | 2 | ||||
-rw-r--r-- | drivers/scsi/arm/eesox.c | 2 | ||||
-rw-r--r-- | drivers/scsi/arm/powertec.c | 2 | ||||
-rw-r--r-- | drivers/scsi/libfc/fc_disc.c | 12 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_nvmet.c | 2 | ||||
-rw-r--r-- | drivers/scsi/megaraid/megaraid_sas_base.c | 9 | ||||
-rw-r--r-- | drivers/scsi/mesh.c | 8 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_iocb.c | 4 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_os.c | 4 | ||||
-rw-r--r-- | drivers/scsi/scsi_debug.c | 6 | ||||
-rw-r--r-- | drivers/scsi/scsi_lib.c | 4 | ||||
-rw-r--r-- | drivers/scsi/ufs/ti-j721e-ufs.c | 1 | ||||
-rw-r--r-- | drivers/scsi/ufs/ufs_quirks.h | 1 | ||||
-rw-r--r-- | drivers/scsi/ufs/ufshcd-pci.c | 16 | ||||
-rw-r--r-- | drivers/scsi/ufs/ufshcd.c | 192 | ||||
-rw-r--r-- | drivers/scsi/ufs/ufshcd.h | 40 |
16 files changed, 244 insertions, 61 deletions
diff --git a/drivers/scsi/arm/cumana_2.c b/drivers/scsi/arm/cumana_2.c index 65691c21f133..29294f0ef8a9 100644 --- a/drivers/scsi/arm/cumana_2.c +++ b/drivers/scsi/arm/cumana_2.c @@ -450,7 +450,7 @@ static int cumanascsi2_probe(struct expansion_card *ec, if (info->info.scsi.dma != NO_DMA) free_dma(info->info.scsi.dma); - free_irq(ec->irq, host); + free_irq(ec->irq, info); out_release: fas216_release(host); diff --git a/drivers/scsi/arm/eesox.c b/drivers/scsi/arm/eesox.c index 6e204a2e0c8d..591ae2a6dd74 100644 --- a/drivers/scsi/arm/eesox.c +++ b/drivers/scsi/arm/eesox.c @@ -571,7 +571,7 @@ static int eesoxscsi_probe(struct expansion_card *ec, const struct ecard_id *id) if (info->info.scsi.dma != NO_DMA) free_dma(info->info.scsi.dma); - free_irq(ec->irq, host); + free_irq(ec->irq, info); out_remove: fas216_remove(host); diff --git a/drivers/scsi/arm/powertec.c b/drivers/scsi/arm/powertec.c index 772a13e5fd91..d99ef014528e 100644 --- a/drivers/scsi/arm/powertec.c +++ b/drivers/scsi/arm/powertec.c @@ -378,7 +378,7 @@ static int powertecscsi_probe(struct expansion_card *ec, if (info->info.scsi.dma != NO_DMA) free_dma(info->info.scsi.dma); - free_irq(ec->irq, host); + free_irq(ec->irq, info); out_release: fas216_release(host); diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c index 2b865c6423e2..e00dc4693fcb 100644 --- a/drivers/scsi/libfc/fc_disc.c +++ b/drivers/scsi/libfc/fc_disc.c @@ -581,8 +581,12 @@ static void fc_disc_gpn_id_resp(struct fc_seq *sp, struct fc_frame *fp, if (PTR_ERR(fp) == -FC_EX_CLOSED) goto out; - if (IS_ERR(fp)) - goto redisc; + if (IS_ERR(fp)) { + mutex_lock(&disc->disc_mutex); + fc_disc_restart(disc); + mutex_unlock(&disc->disc_mutex); + goto out; + } cp = fc_frame_payload_get(fp, sizeof(*cp)); if (!cp) @@ -609,7 +613,7 @@ static void fc_disc_gpn_id_resp(struct fc_seq *sp, struct fc_frame *fp, new_rdata->disc_id = disc->disc_id; fc_rport_login(new_rdata); } - goto out; + goto free_fp; } rdata->disc_id = disc->disc_id; mutex_unlock(&rdata->rp_mutex); @@ -626,6 +630,8 @@ redisc: fc_disc_restart(disc); mutex_unlock(&disc->disc_mutex); } +free_fp: + fc_frame_free(fp); out: kref_put(&rdata->kref, fc_rport_destroy); if (!IS_ERR(fp)) diff --git a/drivers/scsi/lpfc/lpfc_nvmet.c b/drivers/scsi/lpfc/lpfc_nvmet.c index 88760416a8cb..fcd9d4c2f1ee 100644 --- a/drivers/scsi/lpfc/lpfc_nvmet.c +++ b/drivers/scsi/lpfc/lpfc_nvmet.c @@ -2112,7 +2112,7 @@ lpfc_nvmet_destroy_targetport(struct lpfc_hba *phba) } tgtp->tport_unreg_cmp = &tport_unreg_cmp; nvmet_fc_unregister_targetport(phba->targetport); - if (!wait_for_completion_timeout(tgtp->tport_unreg_cmp, + if (!wait_for_completion_timeout(&tport_unreg_cmp, msecs_to_jiffies(LPFC_NVMET_WAIT_TMO))) lpfc_printf_log(phba, KERN_ERR, LOG_NVME, "6179 Unreg targetport x%px timeout " diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index 00668335c2af..924ea9f4cdd0 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -5602,9 +5602,13 @@ megasas_setup_irqs_msix(struct megasas_instance *instance, u8 is_probe) &instance->irq_context[i])) { dev_err(&instance->pdev->dev, "Failed to register IRQ for vector %d.\n", i); - for (j = 0; j < i; j++) + for (j = 0; j < i; j++) { + if (j < instance->low_latency_index_start) + irq_set_affinity_hint( + pci_irq_vector(pdev, j), NULL); free_irq(pci_irq_vector(pdev, j), &instance->irq_context[j]); + } /* Retry irq register for IO_APIC*/ instance->msix_vectors = 0; instance->msix_load_balance = false; @@ -5642,6 +5646,9 @@ megasas_destroy_irqs(struct megasas_instance *instance) { if (instance->msix_vectors) for (i = 0; i < instance->msix_vectors; i++) { + if (i < instance->low_latency_index_start) + irq_set_affinity_hint( + pci_irq_vector(instance->pdev, i), NULL); free_irq(pci_irq_vector(instance->pdev, i), &instance->irq_context[i]); } diff --git a/drivers/scsi/mesh.c b/drivers/scsi/mesh.c index f9f8f4921654..fd1d03064079 100644 --- a/drivers/scsi/mesh.c +++ b/drivers/scsi/mesh.c @@ -1045,6 +1045,8 @@ static void handle_error(struct mesh_state *ms) while ((in_8(&mr->bus_status1) & BS1_RST) != 0) udelay(1); printk("done\n"); + if (ms->dma_started) + halt_dma(ms); handle_reset(ms); /* request_q is empty, no point in mesh_start() */ return; @@ -1357,7 +1359,8 @@ static void halt_dma(struct mesh_state *ms) ms->conn_tgt, ms->data_ptr, scsi_bufflen(cmd), ms->tgts[ms->conn_tgt].data_goes_out); } - scsi_dma_unmap(cmd); + if (cmd) + scsi_dma_unmap(cmd); ms->dma_started = 0; } @@ -1712,6 +1715,9 @@ static int mesh_host_reset(struct scsi_cmnd *cmd) spin_lock_irqsave(ms->host->host_lock, flags); + if (ms->dma_started) + halt_dma(ms); + /* Reset the controller & dbdma channel */ out_le32(&md->control, (RUN|PAUSE|FLUSH|WAKE) << 16); /* stop dma */ out_8(&mr->exception, 0xff); /* clear all exception bits */ diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c index 8865c35d3421..7c2ad8c18398 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c @@ -2305,8 +2305,8 @@ __qla2x00_alloc_iocbs(struct qla_qpair *qpair, srb_t *sp) pkt = req->ring_ptr; memset(pkt, 0, REQUEST_ENTRY_SIZE); if (IS_QLAFX00(ha)) { - wrt_reg_byte((void __iomem *)&pkt->entry_count, req_cnt); - wrt_reg_word((void __iomem *)&pkt->handle, handle); + wrt_reg_byte((u8 __force __iomem *)&pkt->entry_count, req_cnt); + wrt_reg_dword((__le32 __force __iomem *)&pkt->handle, handle); } else { pkt->entry_count = req_cnt; pkt->handle = handle; diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index e92fad99338c..5c7c22d0fab4 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -2829,10 +2829,6 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) /* This may fail but that's ok */ pci_enable_pcie_error_reporting(pdev); - /* Turn off T10-DIF when FC-NVMe is enabled */ - if (ql2xnvmeenable) - ql2xenabledif = 0; - ha = kzalloc(sizeof(struct qla_hw_data), GFP_KERNEL); if (!ha) { ql_log_pci(ql_log_fatal, pdev, 0x0009, diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 843cccb38cb7..b0d93bf79978 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -6610,6 +6610,12 @@ static int __init scsi_debug_init(void) pr_err("submit_queues must be 1 or more\n"); return -EINVAL; } + + if ((sdebug_max_queue > SDEBUG_CANQUEUE) || (sdebug_max_queue < 1)) { + pr_err("max_queue must be in range [1, %d]\n", SDEBUG_CANQUEUE); + return -EINVAL; + } + sdebug_q_arr = kcalloc(submit_queues, sizeof(struct sdebug_queue), GFP_KERNEL); if (sdebug_q_arr == NULL) diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 06056e9ec333..ae620dada8ce 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -2841,8 +2841,10 @@ scsi_host_block(struct Scsi_Host *shost) mutex_lock(&sdev->state_mutex); ret = scsi_internal_device_block_nowait(sdev); mutex_unlock(&sdev->state_mutex); - if (ret) + if (ret) { + scsi_device_put(sdev); break; + } } /* diff --git a/drivers/scsi/ufs/ti-j721e-ufs.c b/drivers/scsi/ufs/ti-j721e-ufs.c index 46bb905b4d6a..eafe0db98d54 100644 --- a/drivers/scsi/ufs/ti-j721e-ufs.c +++ b/drivers/scsi/ufs/ti-j721e-ufs.c @@ -38,6 +38,7 @@ static int ti_j721e_ufs_probe(struct platform_device *pdev) /* Select MPHY refclk frequency */ clk = devm_clk_get(dev, NULL); if (IS_ERR(clk)) { + ret = PTR_ERR(clk); dev_err(dev, "Cannot claim MPHY clock.\n"); goto clk_err; } diff --git a/drivers/scsi/ufs/ufs_quirks.h b/drivers/scsi/ufs/ufs_quirks.h index e3175a63c676..e80d5f26a442 100644 --- a/drivers/scsi/ufs/ufs_quirks.h +++ b/drivers/scsi/ufs/ufs_quirks.h @@ -12,6 +12,7 @@ #define UFS_ANY_VENDOR 0xFFFF #define UFS_ANY_MODEL "ANY_MODEL" +#define UFS_VENDOR_MICRON 0x12C #define UFS_VENDOR_TOSHIBA 0x198 #define UFS_VENDOR_SAMSUNG 0x1CE #define UFS_VENDOR_SKHYNIX 0x1AD diff --git a/drivers/scsi/ufs/ufshcd-pci.c b/drivers/scsi/ufs/ufshcd-pci.c index 8f78a8151499..b220666774ce 100644 --- a/drivers/scsi/ufs/ufshcd-pci.c +++ b/drivers/scsi/ufs/ufshcd-pci.c @@ -67,11 +67,23 @@ static int ufs_intel_link_startup_notify(struct ufs_hba *hba, return err; } +static int ufs_intel_ehl_init(struct ufs_hba *hba) +{ + hba->quirks |= UFSHCD_QUIRK_BROKEN_AUTO_HIBERN8; + return 0; +} + static struct ufs_hba_variant_ops ufs_intel_cnl_hba_vops = { .name = "intel-pci", .link_startup_notify = ufs_intel_link_startup_notify, }; +static struct ufs_hba_variant_ops ufs_intel_ehl_hba_vops = { + .name = "intel-pci", + .init = ufs_intel_ehl_init, + .link_startup_notify = ufs_intel_link_startup_notify, +}; + #ifdef CONFIG_PM_SLEEP /** * ufshcd_pci_suspend - suspend power management function @@ -200,8 +212,8 @@ static const struct dev_pm_ops ufshcd_pci_pm_ops = { static const struct pci_device_id ufshcd_pci_tbl[] = { { PCI_VENDOR_ID_SAMSUNG, 0xC00C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, { PCI_VDEVICE(INTEL, 0x9DFA), (kernel_ulong_t)&ufs_intel_cnl_hba_vops }, - { PCI_VDEVICE(INTEL, 0x4B41), (kernel_ulong_t)&ufs_intel_cnl_hba_vops }, - { PCI_VDEVICE(INTEL, 0x4B43), (kernel_ulong_t)&ufs_intel_cnl_hba_vops }, + { PCI_VDEVICE(INTEL, 0x4B41), (kernel_ulong_t)&ufs_intel_ehl_hba_vops }, + { PCI_VDEVICE(INTEL, 0x4B43), (kernel_ulong_t)&ufs_intel_ehl_hba_vops }, { } /* terminate list */ }; diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index ad4fc829cbb2..136b863bc1d4 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -216,6 +216,8 @@ ufs_get_desired_pm_lvl_for_dev_link_state(enum ufs_dev_pwr_mode dev_state, static struct ufs_dev_fix ufs_fixups[] = { /* UFS cards deviations table */ + UFS_FIX(UFS_VENDOR_MICRON, UFS_ANY_MODEL, + UFS_DEVICE_QUIRK_DELAY_BEFORE_LPM), UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL, UFS_DEVICE_QUIRK_DELAY_BEFORE_LPM), UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL, @@ -672,7 +674,11 @@ static inline int ufshcd_get_tr_ocs(struct ufshcd_lrb *lrbp) */ static inline void ufshcd_utrl_clear(struct ufs_hba *hba, u32 pos) { - ufshcd_writel(hba, ~(1 << pos), REG_UTP_TRANSFER_REQ_LIST_CLEAR); + if (hba->quirks & UFSHCI_QUIRK_BROKEN_REQ_LIST_CLR) + ufshcd_writel(hba, (1 << pos), REG_UTP_TRANSFER_REQ_LIST_CLEAR); + else + ufshcd_writel(hba, ~(1 << pos), + REG_UTP_TRANSFER_REQ_LIST_CLEAR); } /** @@ -682,7 +688,10 @@ static inline void ufshcd_utrl_clear(struct ufs_hba *hba, u32 pos) */ static inline void ufshcd_utmrl_clear(struct ufs_hba *hba, u32 pos) { - ufshcd_writel(hba, ~(1 << pos), REG_UTP_TASK_REQ_LIST_CLEAR); + if (hba->quirks & UFSHCI_QUIRK_BROKEN_REQ_LIST_CLR) + ufshcd_writel(hba, (1 << pos), REG_UTP_TASK_REQ_LIST_CLEAR); + else + ufshcd_writel(hba, ~(1 << pos), REG_UTP_TASK_REQ_LIST_CLEAR); } /** @@ -1314,6 +1323,7 @@ static int ufshcd_devfreq_get_dev_status(struct device *dev, unsigned long flags; struct list_head *clk_list = &hba->clk_list_head; struct ufs_clk_info *clki; + ktime_t curr_t; if (!ufshcd_is_clkscaling_supported(hba)) return -EINVAL; @@ -1321,6 +1331,7 @@ static int ufshcd_devfreq_get_dev_status(struct device *dev, memset(stat, 0, sizeof(*stat)); spin_lock_irqsave(hba->host->host_lock, flags); + curr_t = ktime_get(); if (!scaling->window_start_t) goto start_window; @@ -1332,18 +1343,17 @@ static int ufshcd_devfreq_get_dev_status(struct device *dev, */ stat->current_frequency = clki->curr_freq; if (scaling->is_busy_started) - scaling->tot_busy_t += ktime_to_us(ktime_sub(ktime_get(), - scaling->busy_start_t)); + scaling->tot_busy_t += ktime_us_delta(curr_t, + scaling->busy_start_t); - stat->total_time = jiffies_to_usecs((long)jiffies - - (long)scaling->window_start_t); + stat->total_time = ktime_us_delta(curr_t, scaling->window_start_t); stat->busy_time = scaling->tot_busy_t; start_window: - scaling->window_start_t = jiffies; + scaling->window_start_t = curr_t; scaling->tot_busy_t = 0; if (hba->outstanding_reqs) { - scaling->busy_start_t = ktime_get(); + scaling->busy_start_t = curr_t; scaling->is_busy_started = true; } else { scaling->busy_start_t = 0; @@ -1877,6 +1887,7 @@ static void ufshcd_exit_clk_gating(struct ufs_hba *hba) static void ufshcd_clk_scaling_start_busy(struct ufs_hba *hba) { bool queue_resume_work = false; + ktime_t curr_t = ktime_get(); if (!ufshcd_is_clkscaling_supported(hba)) return; @@ -1892,13 +1903,13 @@ static void ufshcd_clk_scaling_start_busy(struct ufs_hba *hba) &hba->clk_scaling.resume_work); if (!hba->clk_scaling.window_start_t) { - hba->clk_scaling.window_start_t = jiffies; + hba->clk_scaling.window_start_t = curr_t; hba->clk_scaling.tot_busy_t = 0; hba->clk_scaling.is_busy_started = false; } if (!hba->clk_scaling.is_busy_started) { - hba->clk_scaling.busy_start_t = ktime_get(); + hba->clk_scaling.busy_start_t = curr_t; hba->clk_scaling.is_busy_started = true; } } @@ -1925,8 +1936,11 @@ static void ufshcd_clk_scaling_update_busy(struct ufs_hba *hba) static inline void ufshcd_send_command(struct ufs_hba *hba, unsigned int task_tag) { - hba->lrb[task_tag].issue_time_stamp = ktime_get(); - hba->lrb[task_tag].compl_time_stamp = ktime_set(0, 0); + struct ufshcd_lrb *lrbp = &hba->lrb[task_tag]; + + lrbp->issue_time_stamp = ktime_get(); + lrbp->compl_time_stamp = ktime_set(0, 0); + ufshcd_vops_setup_xfer_req(hba, task_tag, (lrbp->cmd ? true : false)); ufshcd_add_command_trace(hba, task_tag, "send"); ufshcd_clk_scaling_start_busy(hba); __set_bit(task_tag, &hba->outstanding_reqs); @@ -2161,8 +2175,14 @@ static int ufshcd_map_sg(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) return sg_segments; if (sg_segments) { - lrbp->utr_descriptor_ptr->prd_table_length = - cpu_to_le16((u16)sg_segments); + + if (hba->quirks & UFSHCD_QUIRK_PRDT_BYTE_GRAN) + lrbp->utr_descriptor_ptr->prd_table_length = + cpu_to_le16((sg_segments * + sizeof(struct ufshcd_sg_entry))); + else + lrbp->utr_descriptor_ptr->prd_table_length = + cpu_to_le16((u16) (sg_segments)); prd_table = (struct ufshcd_sg_entry *)lrbp->ucd_prdt_ptr; @@ -2536,7 +2556,6 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) /* issue command to the controller */ spin_lock_irqsave(hba->host->host_lock, flags); - ufshcd_vops_setup_xfer_req(hba, tag, true); ufshcd_send_command(hba, tag); out_unlock: spin_unlock_irqrestore(hba->host->host_lock, flags); @@ -2723,7 +2742,6 @@ static int ufshcd_exec_dev_cmd(struct ufs_hba *hba, /* Make sure descriptors are ready before ringing the doorbell */ wmb(); spin_lock_irqsave(hba->host->host_lock, flags); - ufshcd_vops_setup_xfer_req(hba, tag, false); ufshcd_send_command(hba, tag); spin_unlock_irqrestore(hba->host->host_lock, flags); @@ -3511,11 +3529,21 @@ static void ufshcd_host_memory_configure(struct ufs_hba *hba) cpu_to_le32(upper_32_bits(cmd_desc_element_addr)); /* Response upiu and prdt offset should be in double words */ - utrdlp[i].response_upiu_offset = - cpu_to_le16(response_offset >> 2); - utrdlp[i].prd_table_offset = cpu_to_le16(prdt_offset >> 2); - utrdlp[i].response_upiu_length = - cpu_to_le16(ALIGNED_UPIU_SIZE >> 2); + if (hba->quirks & UFSHCD_QUIRK_PRDT_BYTE_GRAN) { + utrdlp[i].response_upiu_offset = + cpu_to_le16(response_offset); + utrdlp[i].prd_table_offset = + cpu_to_le16(prdt_offset); + utrdlp[i].response_upiu_length = + cpu_to_le16(ALIGNED_UPIU_SIZE); + } else { + utrdlp[i].response_upiu_offset = + cpu_to_le16(response_offset >> 2); + utrdlp[i].prd_table_offset = + cpu_to_le16(prdt_offset >> 2); + utrdlp[i].response_upiu_length = + cpu_to_le16(ALIGNED_UPIU_SIZE >> 2); + } ufshcd_init_lrb(hba, &hba->lrb[i], i); } @@ -3545,6 +3573,52 @@ static int ufshcd_dme_link_startup(struct ufs_hba *hba) "dme-link-startup: error code %d\n", ret); return ret; } +/** + * ufshcd_dme_reset - UIC command for DME_RESET + * @hba: per adapter instance + * + * DME_RESET command is issued in order to reset UniPro stack. + * This function now deals with cold reset. + * + * Returns 0 on success, non-zero value on failure + */ +static int ufshcd_dme_reset(struct ufs_hba *hba) +{ + struct uic_command uic_cmd = {0}; + int ret; + + uic_cmd.command = UIC_CMD_DME_RESET; + + ret = ufshcd_send_uic_cmd(hba, &uic_cmd); + if (ret) + dev_err(hba->dev, + "dme-reset: error code %d\n", ret); + + return ret; +} + +/** + * ufshcd_dme_enable - UIC command for DME_ENABLE + * @hba: per adapter instance + * + * DME_ENABLE command is issued in order to enable UniPro stack. + * + * Returns 0 on success, non-zero value on failure + */ +static int ufshcd_dme_enable(struct ufs_hba *hba) +{ + struct uic_command uic_cmd = {0}; + int ret; + + uic_cmd.command = UIC_CMD_DME_ENABLE; + + ret = ufshcd_send_uic_cmd(hba, &uic_cmd); + if (ret) + dev_err(hba->dev, + "dme-reset: error code %d\n", ret); + + return ret; +} static inline void ufshcd_add_delay_before_dme_cmd(struct ufs_hba *hba) { @@ -4269,7 +4343,7 @@ static inline void ufshcd_hba_stop(struct ufs_hba *hba) } /** - * ufshcd_hba_enable - initialize the controller + * ufshcd_hba_execute_hce - initialize the controller * @hba: per adapter instance * * The controller resets itself and controller firmware initialization @@ -4278,7 +4352,7 @@ static inline void ufshcd_hba_stop(struct ufs_hba *hba) * * Returns 0 on success, non-zero value on failure */ -int ufshcd_hba_enable(struct ufs_hba *hba) +static int ufshcd_hba_execute_hce(struct ufs_hba *hba) { int retry; @@ -4326,6 +4400,32 @@ int ufshcd_hba_enable(struct ufs_hba *hba) return 0; } + +int ufshcd_hba_enable(struct ufs_hba *hba) +{ + int ret; + + if (hba->quirks & UFSHCI_QUIRK_BROKEN_HCE) { + ufshcd_set_link_off(hba); + ufshcd_vops_hce_enable_notify(hba, PRE_CHANGE); + + /* enable UIC related interrupts */ + ufshcd_enable_intr(hba, UFSHCD_UIC_MASK); + ret = ufshcd_dme_reset(hba); + if (!ret) { + ret = ufshcd_dme_enable(hba); + if (!ret) + ufshcd_vops_hce_enable_notify(hba, POST_CHANGE); + if (ret) + dev_err(hba->dev, + "Host controller enable failed with non-hce\n"); + } + } else { + ret = ufshcd_hba_execute_hce(hba); + } + + return ret; +} EXPORT_SYMBOL_GPL(ufshcd_hba_enable); static int ufshcd_disable_tx_lcc(struct ufs_hba *hba, bool peer) @@ -4724,6 +4824,12 @@ ufshcd_transfer_rsp_status(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) /* overall command status of utrd */ ocs = ufshcd_get_tr_ocs(lrbp); + if (hba->quirks & UFSHCD_QUIRK_BROKEN_OCS_FATAL_ERROR) { + if (be32_to_cpu(lrbp->ucd_rsp_ptr->header.dword_1) & + MASK_RSP_UPIU_RESULT) + ocs = OCS_SUCCESS; + } + switch (ocs) { case OCS_SUCCESS: result = ufshcd_get_req_rsp(lrbp->ucd_rsp_ptr); @@ -4902,7 +5008,8 @@ static irqreturn_t ufshcd_transfer_req_compl(struct ufs_hba *hba) * false interrupt if device completes another request after resetting * aggregation and before reading the DB. */ - if (ufshcd_is_intr_aggr_allowed(hba)) + if (ufshcd_is_intr_aggr_allowed(hba) && + !(hba->quirks & UFSHCI_QUIRK_SKIP_RESET_INTR_AGGR)) ufshcd_reset_intr_aggr(hba); tr_doorbell = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL); @@ -5906,7 +6013,7 @@ static irqreturn_t ufshcd_intr(int irq, void *__hba) intr_status = ufshcd_readl(hba, REG_INTERRUPT_STATUS); } while (intr_status && --retries); - if (retval == IRQ_NONE) { + if (enabled_intr_status && retval == IRQ_NONE) { dev_err(hba->dev, "%s: Unhandled interrupt 0x%08x\n", __func__, intr_status); ufshcd_dump_regs(hba, 0, UFSHCI_REG_SPACE_SIZE, "host_regs: "); @@ -6815,20 +6922,30 @@ out: static void ufshcd_wb_probe(struct ufs_hba *hba, u8 *desc_buf) { + struct ufs_dev_info *dev_info = &hba->dev_info; u8 lun; u32 d_lu_wb_buf_alloc; if (!ufshcd_is_wb_allowed(hba)) return; + /* + * Probe WB only for UFS-2.2 and UFS-3.1 (and later) devices or + * UFS devices with quirk UFS_DEVICE_QUIRK_SUPPORT_EXTENDED_FEATURES + * enabled + */ + if (!(dev_info->wspecversion >= 0x310 || + dev_info->wspecversion == 0x220 || + (hba->dev_quirks & UFS_DEVICE_QUIRK_SUPPORT_EXTENDED_FEATURES))) + goto wb_disabled; if (hba->desc_size.dev_desc < DEVICE_DESC_PARAM_EXT_UFS_FEATURE_SUP + 4) goto wb_disabled; - hba->dev_info.d_ext_ufs_feature_sup = + dev_info->d_ext_ufs_feature_sup = get_unaligned_be32(desc_buf + DEVICE_DESC_PARAM_EXT_UFS_FEATURE_SUP); - if (!(hba->dev_info.d_ext_ufs_feature_sup & UFS_DEV_WRITE_BOOSTER_SUP)) + if (!(dev_info->d_ext_ufs_feature_sup & UFS_DEV_WRITE_BOOSTER_SUP)) goto wb_disabled; /* @@ -6837,17 +6954,17 @@ static void ufshcd_wb_probe(struct ufs_hba *hba, u8 *desc_buf) * a max of 1 lun would have wb buffer configured. * Now only shared buffer mode is supported. */ - hba->dev_info.b_wb_buffer_type = + dev_info->b_wb_buffer_type = desc_buf[DEVICE_DESC_PARAM_WB_TYPE]; - hba->dev_info.b_presrv_uspc_en = + dev_info->b_presrv_uspc_en = desc_buf[DEVICE_DESC_PARAM_WB_PRESRV_USRSPC_EN]; - if (hba->dev_info.b_wb_buffer_type == WB_BUF_MODE_SHARED) { - hba->dev_info.d_wb_alloc_units = + if (dev_info->b_wb_buffer_type == WB_BUF_MODE_SHARED) { + dev_info->d_wb_alloc_units = get_unaligned_be32(desc_buf + DEVICE_DESC_PARAM_WB_SHARED_ALLOC_UNITS); - if (!hba->dev_info.d_wb_alloc_units) + if (!dev_info->d_wb_alloc_units) goto wb_disabled; } else { for (lun = 0; lun < UFS_UPIU_MAX_WB_LUN_ID; lun++) { @@ -6858,7 +6975,7 @@ static void ufshcd_wb_probe(struct ufs_hba *hba, u8 *desc_buf) (u8 *)&d_lu_wb_buf_alloc, sizeof(d_lu_wb_buf_alloc)); if (d_lu_wb_buf_alloc) { - hba->dev_info.wb_dedicated_lu = lun; + dev_info->wb_dedicated_lu = lun; break; } } @@ -6947,14 +7064,7 @@ static int ufs_get_device_desc(struct ufs_hba *hba) ufs_fixup_device_setup(hba); - /* - * Probe WB only for UFS-3.1 devices or UFS devices with quirk - * UFS_DEVICE_QUIRK_SUPPORT_EXTENDED_FEATURES enabled - */ - if (dev_info->wspecversion >= 0x310 || - dev_info->wspecversion == 0x220 || - (hba->dev_quirks & UFS_DEVICE_QUIRK_SUPPORT_EXTENDED_FEATURES)) - ufshcd_wb_probe(hba, desc_buf); + ufshcd_wb_probe(hba, desc_buf); /* * ufshcd_read_string_desc returns size of the string diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index bf97d616e597..4bf98c229537 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -411,7 +411,7 @@ struct ufs_saved_pwr_info { struct ufs_clk_scaling { int active_reqs; unsigned long tot_busy_t; - unsigned long window_start_t; + ktime_t window_start_t; ktime_t busy_start_t; struct device_attribute enable_attr; struct ufs_saved_pwr_info saved_pwr_info; @@ -520,6 +520,41 @@ enum ufshcd_quirks { * ops (get_ufs_hci_version) to get the correct version. */ UFSHCD_QUIRK_BROKEN_UFS_HCI_VERSION = 1 << 5, + + /* + * Clear handling for transfer/task request list is just opposite. + */ + UFSHCI_QUIRK_BROKEN_REQ_LIST_CLR = 1 << 6, + + /* + * This quirk needs to be enabled if host controller doesn't allow + * that the interrupt aggregation timer and counter are reset by s/w. + */ + UFSHCI_QUIRK_SKIP_RESET_INTR_AGGR = 1 << 7, + + /* + * This quirks needs to be enabled if host controller cannot be + * enabled via HCE register. + */ + UFSHCI_QUIRK_BROKEN_HCE = 1 << 8, + + /* + * This quirk needs to be enabled if the host controller regards + * resolution of the values of PRDTO and PRDTL in UTRD as byte. + */ + UFSHCD_QUIRK_PRDT_BYTE_GRAN = 1 << 9, + + /* + * This quirk needs to be enabled if the host controller reports + * OCS FATAL ERROR with device error through sense data + */ + UFSHCD_QUIRK_BROKEN_OCS_FATAL_ERROR = 1 << 10, + + /* + * This quirk needs to be enabled if the host controller has + * auto-hibernate capability but it doesn't work. + */ + UFSHCD_QUIRK_BROKEN_AUTO_HIBERN8 = 1 << 11, }; enum ufshcd_caps { @@ -786,7 +821,8 @@ return true; static inline bool ufshcd_is_auto_hibern8_supported(struct ufs_hba *hba) { - return (hba->capabilities & MASK_AUTO_HIBERN8_SUPPORT); + return (hba->capabilities & MASK_AUTO_HIBERN8_SUPPORT) && + !(hba->quirks & UFSHCD_QUIRK_BROKEN_AUTO_HIBERN8); } static inline bool ufshcd_is_auto_hibern8_enabled(struct ufs_hba *hba) |