Loading drivers/scsi/ufs/ufs-qcom.c +144 −1 Original line number Diff line number Diff line Loading @@ -65,6 +65,7 @@ static int ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div(struct ufs_hba *hba, u32 clk_1us_cycles, u32 clk_40ns_cycles); static void ufs_qcom_pm_qos_suspend(struct ufs_qcom_host *host); static int ufs_qcom_init_sysfs(struct ufs_hba *hba); static void ufs_qcom_dump_regs(struct ufs_hba *hba, int offset, int len, char *prefix) Loading Loading @@ -1545,8 +1546,11 @@ static int ufs_qcom_setup_clocks(struct ufs_hba *hba, bool on, if (on && (status == POST_CHANGE)) { if (!host->is_phy_pwr_on) { phy_power_on(host->generic_phy); err = phy_power_on(host->generic_phy); host->is_phy_pwr_on = true; if (!err) atomic_set(&host->clks_on, on); } /* enable the device ref clock for HS mode*/ if (ufshcd_is_hs_mode(&hba->pwr_info)) Loading Loading @@ -2253,6 +2257,8 @@ static int ufs_qcom_init(struct ufs_hba *hba) err = 0; } ufs_qcom_init_sysfs(hba); ufs_qcom_save_host_ptr(hba); goto out; Loading Loading @@ -2429,6 +2435,8 @@ static int ufs_qcom_clk_scale_notify(struct ufs_hba *hba, break; } if (!err) atomic_set(&host->scale_up, scale_up); return err; } Loading Loading @@ -2704,6 +2712,8 @@ static void ufs_qcom_dump_dbg_regs(struct ufs_hba *hba, bool no_sleep) struct ufs_qcom_host *host = ufshcd_get_variant(hba); struct phy *phy = host->generic_phy; host->err_occurred = true; ufs_qcom_dump_regs(hba, REG_UFS_SYS1CLK_1US, 16, "HCI Vendor Specific Registers "); ufs_qcom_print_hw_debug_reg_all(hba, NULL, ufs_qcom_dump_regs_wrapper); Loading Loading @@ -2768,6 +2778,139 @@ static struct ufs_hba_variant ufs_hba_qcom_variant = { .pm_qos_vops = &ufs_hba_pm_qos_variant_ops, }; /** * QCOM specific sysfs group and nodes */ static ssize_t err_state_show(struct device *dev, struct device_attribute *attr, char *buf) { struct ufs_hba *hba = dev_get_drvdata(dev); struct ufs_qcom_host *host = ufshcd_get_variant(hba); return scnprintf(buf, PAGE_SIZE, "%d\n", !!host->err_occurred); } static DEVICE_ATTR_RO(err_state); static ssize_t power_mode_show(struct device *dev, struct device_attribute *attr, char *buf) { struct ufs_hba *hba = dev_get_drvdata(dev); static const char * const names[] = { "INVALID MODE", "FAST MODE", "SLOW MODE", "INVALID MODE", "FASTAUTO MODE", "SLOWAUTO MODE", "INVALID MODE", }; /* Print current power info */ return scnprintf(buf, PAGE_SIZE, "[Rx,Tx]: Gear[%d,%d], Lane[%d,%d], PWR[%s,%s], Rate-%c\n", hba->pwr_info.gear_rx, hba->pwr_info.gear_tx, hba->pwr_info.lane_rx, hba->pwr_info.lane_tx, names[hba->pwr_info.pwr_rx], names[hba->pwr_info.pwr_tx], hba->pwr_info.hs_rate == PA_HS_MODE_B ? 'B' : 'A'); } static DEVICE_ATTR_RO(power_mode); static ssize_t bus_speed_mode_show(struct device *dev, struct device_attribute *attr, char *buf) { struct ufs_hba *hba = dev_get_drvdata(dev); struct ufs_qcom_host *host = ufshcd_get_variant(hba); return scnprintf(buf, PAGE_SIZE, "%d\n", !!atomic_read(&host->scale_up)); } static DEVICE_ATTR_RO(bus_speed_mode); static ssize_t clk_status_show(struct device *dev, struct device_attribute *attr, char *buf) { struct ufs_hba *hba = dev_get_drvdata(dev); struct ufs_qcom_host *host = ufshcd_get_variant(hba); return scnprintf(buf, PAGE_SIZE, "%d\n", !!atomic_read(&host->clks_on)); } static DEVICE_ATTR_RO(clk_status); static unsigned int ufs_qcom_gec(struct ufs_hba *hba, struct ufs_uic_err_reg_hist *err_hist, char *err_name) { unsigned long flags; int i, cnt_err = 0; spin_lock_irqsave(hba->host->host_lock, flags); for (i = 0; i < UIC_ERR_REG_HIST_LENGTH; i++) { int p = (i + err_hist->pos) % UIC_ERR_REG_HIST_LENGTH; if (err_hist->tstamp[p] == 0) continue; dev_err(hba->dev, "%s[%d] = 0x%x at %lld us\n", err_name, p, err_hist->reg[p], ktime_to_us(err_hist->tstamp[p])); ++cnt_err; } spin_unlock_irqrestore(hba->host->host_lock, flags); return cnt_err; } static ssize_t err_count_show(struct device *dev, struct device_attribute *attr, char *buf) { struct ufs_hba *hba = dev_get_drvdata(dev); return scnprintf(buf, PAGE_SIZE, "%s: %d\n%s: %d\n%s: %d\n", "pa_err_cnt_total", ufs_qcom_gec(hba, &hba->ufs_stats.pa_err, "pa_err_cnt_total"), "dl_err_cnt_total", ufs_qcom_gec(hba, &hba->ufs_stats.dl_err, "dl_err_cnt_total"), "dme_err_cnt", ufs_qcom_gec(hba, &hba->ufs_stats.dme_err, "dme_err_cnt")); } static DEVICE_ATTR_RO(err_count); static struct attribute *ufs_qcom_sysfs_attrs[] = { &dev_attr_err_state.attr, &dev_attr_power_mode.attr, &dev_attr_bus_speed_mode.attr, &dev_attr_clk_status.attr, &dev_attr_err_count.attr, NULL }; static const struct attribute_group ufs_qcom_sysfs_group = { .name = "qcom", .attrs = ufs_qcom_sysfs_attrs, }; static int ufs_qcom_init_sysfs(struct ufs_hba *hba) { int ret; ret = sysfs_create_group(&hba->dev->kobj, &ufs_qcom_sysfs_group); if (ret) dev_err(hba->dev, "%s: Failed to create qcom sysfs group (err = %d)\n", __func__, ret); return ret; } /** * ufs_qcom_probe - probe routine of the driver * @pdev: pointer to Platform device handle Loading drivers/scsi/ufs/ufs-qcom.h +5 −1 Original line number Diff line number Diff line /* SPDX-License-Identifier: GPL-2.0 */ /* Copyright (c) 2013-2019, The Linux Foundation. All rights reserved. /* Copyright (c) 2013-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -365,6 +365,10 @@ struct ufs_qcom_host { struct ufs_vreg *vccq_parent; bool work_pending; bool is_phy_pwr_on; bool err_occurred; /* FlashPVL entries */ atomic_t scale_up; atomic_t clks_on; }; static inline u32 Loading Loading
drivers/scsi/ufs/ufs-qcom.c +144 −1 Original line number Diff line number Diff line Loading @@ -65,6 +65,7 @@ static int ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div(struct ufs_hba *hba, u32 clk_1us_cycles, u32 clk_40ns_cycles); static void ufs_qcom_pm_qos_suspend(struct ufs_qcom_host *host); static int ufs_qcom_init_sysfs(struct ufs_hba *hba); static void ufs_qcom_dump_regs(struct ufs_hba *hba, int offset, int len, char *prefix) Loading Loading @@ -1545,8 +1546,11 @@ static int ufs_qcom_setup_clocks(struct ufs_hba *hba, bool on, if (on && (status == POST_CHANGE)) { if (!host->is_phy_pwr_on) { phy_power_on(host->generic_phy); err = phy_power_on(host->generic_phy); host->is_phy_pwr_on = true; if (!err) atomic_set(&host->clks_on, on); } /* enable the device ref clock for HS mode*/ if (ufshcd_is_hs_mode(&hba->pwr_info)) Loading Loading @@ -2253,6 +2257,8 @@ static int ufs_qcom_init(struct ufs_hba *hba) err = 0; } ufs_qcom_init_sysfs(hba); ufs_qcom_save_host_ptr(hba); goto out; Loading Loading @@ -2429,6 +2435,8 @@ static int ufs_qcom_clk_scale_notify(struct ufs_hba *hba, break; } if (!err) atomic_set(&host->scale_up, scale_up); return err; } Loading Loading @@ -2704,6 +2712,8 @@ static void ufs_qcom_dump_dbg_regs(struct ufs_hba *hba, bool no_sleep) struct ufs_qcom_host *host = ufshcd_get_variant(hba); struct phy *phy = host->generic_phy; host->err_occurred = true; ufs_qcom_dump_regs(hba, REG_UFS_SYS1CLK_1US, 16, "HCI Vendor Specific Registers "); ufs_qcom_print_hw_debug_reg_all(hba, NULL, ufs_qcom_dump_regs_wrapper); Loading Loading @@ -2768,6 +2778,139 @@ static struct ufs_hba_variant ufs_hba_qcom_variant = { .pm_qos_vops = &ufs_hba_pm_qos_variant_ops, }; /** * QCOM specific sysfs group and nodes */ static ssize_t err_state_show(struct device *dev, struct device_attribute *attr, char *buf) { struct ufs_hba *hba = dev_get_drvdata(dev); struct ufs_qcom_host *host = ufshcd_get_variant(hba); return scnprintf(buf, PAGE_SIZE, "%d\n", !!host->err_occurred); } static DEVICE_ATTR_RO(err_state); static ssize_t power_mode_show(struct device *dev, struct device_attribute *attr, char *buf) { struct ufs_hba *hba = dev_get_drvdata(dev); static const char * const names[] = { "INVALID MODE", "FAST MODE", "SLOW MODE", "INVALID MODE", "FASTAUTO MODE", "SLOWAUTO MODE", "INVALID MODE", }; /* Print current power info */ return scnprintf(buf, PAGE_SIZE, "[Rx,Tx]: Gear[%d,%d], Lane[%d,%d], PWR[%s,%s], Rate-%c\n", hba->pwr_info.gear_rx, hba->pwr_info.gear_tx, hba->pwr_info.lane_rx, hba->pwr_info.lane_tx, names[hba->pwr_info.pwr_rx], names[hba->pwr_info.pwr_tx], hba->pwr_info.hs_rate == PA_HS_MODE_B ? 'B' : 'A'); } static DEVICE_ATTR_RO(power_mode); static ssize_t bus_speed_mode_show(struct device *dev, struct device_attribute *attr, char *buf) { struct ufs_hba *hba = dev_get_drvdata(dev); struct ufs_qcom_host *host = ufshcd_get_variant(hba); return scnprintf(buf, PAGE_SIZE, "%d\n", !!atomic_read(&host->scale_up)); } static DEVICE_ATTR_RO(bus_speed_mode); static ssize_t clk_status_show(struct device *dev, struct device_attribute *attr, char *buf) { struct ufs_hba *hba = dev_get_drvdata(dev); struct ufs_qcom_host *host = ufshcd_get_variant(hba); return scnprintf(buf, PAGE_SIZE, "%d\n", !!atomic_read(&host->clks_on)); } static DEVICE_ATTR_RO(clk_status); static unsigned int ufs_qcom_gec(struct ufs_hba *hba, struct ufs_uic_err_reg_hist *err_hist, char *err_name) { unsigned long flags; int i, cnt_err = 0; spin_lock_irqsave(hba->host->host_lock, flags); for (i = 0; i < UIC_ERR_REG_HIST_LENGTH; i++) { int p = (i + err_hist->pos) % UIC_ERR_REG_HIST_LENGTH; if (err_hist->tstamp[p] == 0) continue; dev_err(hba->dev, "%s[%d] = 0x%x at %lld us\n", err_name, p, err_hist->reg[p], ktime_to_us(err_hist->tstamp[p])); ++cnt_err; } spin_unlock_irqrestore(hba->host->host_lock, flags); return cnt_err; } static ssize_t err_count_show(struct device *dev, struct device_attribute *attr, char *buf) { struct ufs_hba *hba = dev_get_drvdata(dev); return scnprintf(buf, PAGE_SIZE, "%s: %d\n%s: %d\n%s: %d\n", "pa_err_cnt_total", ufs_qcom_gec(hba, &hba->ufs_stats.pa_err, "pa_err_cnt_total"), "dl_err_cnt_total", ufs_qcom_gec(hba, &hba->ufs_stats.dl_err, "dl_err_cnt_total"), "dme_err_cnt", ufs_qcom_gec(hba, &hba->ufs_stats.dme_err, "dme_err_cnt")); } static DEVICE_ATTR_RO(err_count); static struct attribute *ufs_qcom_sysfs_attrs[] = { &dev_attr_err_state.attr, &dev_attr_power_mode.attr, &dev_attr_bus_speed_mode.attr, &dev_attr_clk_status.attr, &dev_attr_err_count.attr, NULL }; static const struct attribute_group ufs_qcom_sysfs_group = { .name = "qcom", .attrs = ufs_qcom_sysfs_attrs, }; static int ufs_qcom_init_sysfs(struct ufs_hba *hba) { int ret; ret = sysfs_create_group(&hba->dev->kobj, &ufs_qcom_sysfs_group); if (ret) dev_err(hba->dev, "%s: Failed to create qcom sysfs group (err = %d)\n", __func__, ret); return ret; } /** * ufs_qcom_probe - probe routine of the driver * @pdev: pointer to Platform device handle Loading
drivers/scsi/ufs/ufs-qcom.h +5 −1 Original line number Diff line number Diff line /* SPDX-License-Identifier: GPL-2.0 */ /* Copyright (c) 2013-2019, The Linux Foundation. All rights reserved. /* Copyright (c) 2013-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -365,6 +365,10 @@ struct ufs_qcom_host { struct ufs_vreg *vccq_parent; bool work_pending; bool is_phy_pwr_on; bool err_occurred; /* FlashPVL entries */ atomic_t scale_up; atomic_t clks_on; }; static inline u32 Loading