Skip to content

Commit 3a4bf06

Browse files
Yaniv GardiChristoph Hellwig
authored andcommitted
ufs: Active Power Mode - configuring bActiveICCLevel
The maximum power consumption in active is determined by bActiveICCLevel. The configuration is done by reading max current supported by the regulators connected to VCC, VCCQ and VCCQ2 rails on the boards, and reading the current consumption levels from the device for each rails (vcc/vccq/vccq2) using power descriptor. We configure the bActiveICCLevel attribute, with the max value that correspond to the minimum-of(VCC-current-level,VCCQ-current-level, VCCQ2-current-level). In order to minimize resume latency, pre-fetch icc levels and reference clock during initialization and avoid reading them each link startup during resume. Signed-off-by: Raviv Shvili <[email protected]> Signed-off-by: Yaniv Gardi <[email protected]> Signed-off-by: Dolev Raviv <[email protected]> Signed-off-by: Christoph Hellwig <[email protected]>
1 parent 1d337ec commit 3a4bf06

File tree

3 files changed

+165
-0
lines changed

3 files changed

+165
-0
lines changed

drivers/scsi/ufs/ufs.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ enum flag_idn {
115115

116116
/* Attribute idn for Query requests */
117117
enum attr_idn {
118+
QUERY_ATTR_IDN_ACTIVE_ICC_LVL = 0x03,
118119
QUERY_ATTR_IDN_BKOPS_STATUS = 0x05,
119120
QUERY_ATTR_IDN_EE_CONTROL = 0x0D,
120121
QUERY_ATTR_IDN_EE_STATUS = 0x0E,
@@ -174,6 +175,31 @@ enum unit_desc_param {
174175
UNIT_DESC_PARAM_LARGE_UNIT_SIZE_M1 = 0x22,
175176
};
176177

178+
/* bActiveICCLevel parameter current units */
179+
enum {
180+
UFSHCD_NANO_AMP = 0,
181+
UFSHCD_MICRO_AMP = 1,
182+
UFSHCD_MILI_AMP = 2,
183+
UFSHCD_AMP = 3,
184+
};
185+
186+
#define POWER_DESC_MAX_SIZE 0x62
187+
#define POWER_DESC_MAX_ACTV_ICC_LVLS 16
188+
189+
/* Attribute bActiveICCLevel parameter bit masks definitions */
190+
#define ATTR_ICC_LVL_UNIT_OFFSET 14
191+
#define ATTR_ICC_LVL_UNIT_MASK (0x3 << ATTR_ICC_LVL_UNIT_OFFSET)
192+
#define ATTR_ICC_LVL_VALUE_MASK 0x3FF
193+
194+
/* Power descriptor parameters offsets in bytes */
195+
enum power_desc_param_offset {
196+
PWR_DESC_LEN = 0x0,
197+
PWR_DESC_TYPE = 0x1,
198+
PWR_DESC_ACTIVE_LVLS_VCC_0 = 0x2,
199+
PWR_DESC_ACTIVE_LVLS_VCCQ_0 = 0x22,
200+
PWR_DESC_ACTIVE_LVLS_VCCQ2_0 = 0x42,
201+
};
202+
177203
/* Exception event mask values */
178204
enum {
179205
MASK_EE_STATUS = 0xFFFF,

drivers/scsi/ufs/ufshcd.c

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3264,6 +3264,125 @@ static int ufshcd_eh_host_reset_handler(struct scsi_cmnd *cmd)
32643264
return err;
32653265
}
32663266

3267+
/**
3268+
* ufshcd_get_max_icc_level - calculate the ICC level
3269+
* @sup_curr_uA: max. current supported by the regulator
3270+
* @start_scan: row at the desc table to start scan from
3271+
* @buff: power descriptor buffer
3272+
*
3273+
* Returns calculated max ICC level for specific regulator
3274+
*/
3275+
static u32 ufshcd_get_max_icc_level(int sup_curr_uA, u32 start_scan, char *buff)
3276+
{
3277+
int i;
3278+
int curr_uA;
3279+
u16 data;
3280+
u16 unit;
3281+
3282+
for (i = start_scan; i >= 0; i--) {
3283+
data = be16_to_cpu(*((u16 *)(buff + 2*i)));
3284+
unit = (data & ATTR_ICC_LVL_UNIT_MASK) >>
3285+
ATTR_ICC_LVL_UNIT_OFFSET;
3286+
curr_uA = data & ATTR_ICC_LVL_VALUE_MASK;
3287+
switch (unit) {
3288+
case UFSHCD_NANO_AMP:
3289+
curr_uA = curr_uA / 1000;
3290+
break;
3291+
case UFSHCD_MILI_AMP:
3292+
curr_uA = curr_uA * 1000;
3293+
break;
3294+
case UFSHCD_AMP:
3295+
curr_uA = curr_uA * 1000 * 1000;
3296+
break;
3297+
case UFSHCD_MICRO_AMP:
3298+
default:
3299+
break;
3300+
}
3301+
if (sup_curr_uA >= curr_uA)
3302+
break;
3303+
}
3304+
if (i < 0) {
3305+
i = 0;
3306+
pr_err("%s: Couldn't find valid icc_level = %d", __func__, i);
3307+
}
3308+
3309+
return (u32)i;
3310+
}
3311+
3312+
/**
3313+
* ufshcd_calc_icc_level - calculate the max ICC level
3314+
* In case regulators are not initialized we'll return 0
3315+
* @hba: per-adapter instance
3316+
* @desc_buf: power descriptor buffer to extract ICC levels from.
3317+
* @len: length of desc_buff
3318+
*
3319+
* Returns calculated ICC level
3320+
*/
3321+
static u32 ufshcd_find_max_sup_active_icc_level(struct ufs_hba *hba,
3322+
u8 *desc_buf, int len)
3323+
{
3324+
u32 icc_level = 0;
3325+
3326+
if (!hba->vreg_info.vcc || !hba->vreg_info.vccq ||
3327+
!hba->vreg_info.vccq2) {
3328+
dev_err(hba->dev,
3329+
"%s: Regulator capability was not set, actvIccLevel=%d",
3330+
__func__, icc_level);
3331+
goto out;
3332+
}
3333+
3334+
if (hba->vreg_info.vcc)
3335+
icc_level = ufshcd_get_max_icc_level(
3336+
hba->vreg_info.vcc->max_uA,
3337+
POWER_DESC_MAX_ACTV_ICC_LVLS - 1,
3338+
&desc_buf[PWR_DESC_ACTIVE_LVLS_VCC_0]);
3339+
3340+
if (hba->vreg_info.vccq)
3341+
icc_level = ufshcd_get_max_icc_level(
3342+
hba->vreg_info.vccq->max_uA,
3343+
icc_level,
3344+
&desc_buf[PWR_DESC_ACTIVE_LVLS_VCCQ_0]);
3345+
3346+
if (hba->vreg_info.vccq2)
3347+
icc_level = ufshcd_get_max_icc_level(
3348+
hba->vreg_info.vccq2->max_uA,
3349+
icc_level,
3350+
&desc_buf[PWR_DESC_ACTIVE_LVLS_VCCQ2_0]);
3351+
out:
3352+
return icc_level;
3353+
}
3354+
3355+
static void ufshcd_init_icc_levels(struct ufs_hba *hba)
3356+
{
3357+
int ret;
3358+
int buff_len = QUERY_DESC_POWER_MAX_SIZE;
3359+
u8 desc_buf[QUERY_DESC_POWER_MAX_SIZE];
3360+
3361+
ret = ufshcd_read_power_desc(hba, desc_buf, buff_len);
3362+
if (ret) {
3363+
dev_err(hba->dev,
3364+
"%s: Failed reading power descriptor.len = %d ret = %d",
3365+
__func__, buff_len, ret);
3366+
return;
3367+
}
3368+
3369+
hba->init_prefetch_data.icc_level =
3370+
ufshcd_find_max_sup_active_icc_level(hba,
3371+
desc_buf, buff_len);
3372+
dev_dbg(hba->dev, "%s: setting icc_level 0x%x",
3373+
__func__, hba->init_prefetch_data.icc_level);
3374+
3375+
ret = ufshcd_query_attr(hba, UPIU_QUERY_OPCODE_WRITE_ATTR,
3376+
QUERY_ATTR_IDN_ACTIVE_ICC_LVL, 0, 0,
3377+
&hba->init_prefetch_data.icc_level);
3378+
3379+
if (ret)
3380+
dev_err(hba->dev,
3381+
"%s: Failed configuring bActiveICCLevel = %d ret = %d",
3382+
__func__, hba->init_prefetch_data.icc_level , ret);
3383+
3384+
}
3385+
32673386
/**
32683387
* ufshcd_probe_hba - probe hba to detect device and initialize
32693388
* @hba: per-adapter instance
@@ -3293,9 +3412,16 @@ static int ufshcd_probe_hba(struct ufs_hba *hba)
32933412

32943413
/* If we are in error handling context no need to scan the host */
32953414
if (!ufshcd_eh_in_progress(hba)) {
3415+
if (!hba->is_init_prefetch)
3416+
ufshcd_init_icc_levels(hba);
3417+
32963418
scsi_scan_host(hba->host);
32973419
pm_runtime_put_sync(hba->dev);
32983420
}
3421+
3422+
if (!hba->is_init_prefetch)
3423+
hba->is_init_prefetch = true;
3424+
32993425
out:
33003426
/*
33013427
* If we failed to initialize the device or the device is not

drivers/scsi/ufs/ufshcd.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,15 @@ struct ufs_hba_variant_ops {
195195
int (*link_startup_notify)(struct ufs_hba *, bool);
196196
};
197197

198+
/**
199+
* struct ufs_init_prefetch - contains data that is pre-fetched once during
200+
* initialization
201+
* @icc_level: icc level which was read during initialization
202+
*/
203+
struct ufs_init_prefetch {
204+
u32 icc_level;
205+
};
206+
198207
/**
199208
* struct ufs_hba - per adapter private structure
200209
* @mmio_base: UFSHCI base register address
@@ -229,6 +238,8 @@ struct ufs_hba_variant_ops {
229238
* @intr_mask: Interrupt Mask Bits
230239
* @ee_ctrl_mask: Exception event control mask
231240
* @is_powered: flag to check if HBA is powered
241+
* @is_init_prefetch: flag to check if data was pre-fetched in initialization
242+
* @init_prefetch_data: data pre-fetched during initialization
232243
* @eh_work: Worker to handle UFS errors that require s/w attention
233244
* @eeh_work: Worker to handle exception events
234245
* @errors: HBA errors
@@ -285,6 +296,8 @@ struct ufs_hba {
285296
u32 intr_mask;
286297
u16 ee_ctrl_mask;
287298
bool is_powered;
299+
bool is_init_prefetch;
300+
struct ufs_init_prefetch init_prefetch_data;
288301

289302
/* Work Queues */
290303
struct work_struct eh_work;

0 commit comments

Comments
 (0)