40
#define UFS_TOO_HIGH_TEMP_BOUNDARY 160
41
#define UFS_TOO_LOW_TEMP_BOUNDARY 60
42
43
+#define UFS_HID_DEFRAG_BATCH_DIV 10 /* ~10% of remaining per tick */
44
+#define UFS_HID_PROGRESS_COMPLETE 100
45
+
46
static void ufs_exec_req(UfsRequest *req);
47
static void ufs_clear_req(UfsRequest *req);
48
1291
[UFS_QUERY_ATTR_IDN_REFRESH_UNIT] = UFS_QUERY_ATTR_READ,
1292
[UFS_QUERY_ATTR_IDN_TIMESTAMP] = UFS_QUERY_ATTR_WRITE,
1293
[UFS_QUERY_ATTR_IDN_DEVICE_LEVEL_EXCEPTION_ID] = UFS_QUERY_ATTR_READ,
1291
- /* host initiated defragmentation is not supported */
1292
- [UFS_QUERY_ATTR_IDN_DEFRAG_OP] = UFS_QUERY_ATTR_READ,
1294
+ [UFS_QUERY_ATTR_IDN_DEFRAG_OP] = UFS_QUERY_ATTR_READ | UFS_QUERY_ATTR_WRITE,
1295
[UFS_QUERY_ATTR_IDN_HID_AVAIL_SIZE] = UFS_QUERY_ATTR_READ,
1294
- [UFS_QUERY_ATTR_IDN_HID_SIZE] = UFS_QUERY_ATTR_READ,
1296
+ [UFS_QUERY_ATTR_IDN_HID_SIZE] = UFS_QUERY_ATTR_READ | UFS_QUERY_ATTR_WRITE,
1297
[UFS_QUERY_ATTR_IDN_HID_PROG_RATIO] = UFS_QUERY_ATTR_READ,
1298
[UFS_QUERY_ATTR_IDN_HID_STATE] = UFS_QUERY_ATTR_READ,
1299
[UFS_QUERY_ATTR_IDN_WB_BUFF_RESIZE_HINT] = UFS_QUERY_ATTR_READ,
1373
return value;
1374
}
1375
1376
+static void ufs_hid_reset(UfsHc *u)
1377
+{
1378
+ u->attributes.defrag_op = UFS_HID_OP_DISABLE;
1379
+ u->attributes.hid_state = UFS_HID_STATE_IDLE;
1380
+ u->attributes.hid_prog_ratio = 0;
1381
+ u->attributes.hid_avail_size = cpu_to_be32(0xFFFFFFFF);
1382
+ u->hid_defrag_total = 0;
1383
+ u->hid_defrag_remaining = 0;
1384
+}
1385
+
1386
+static uint32_t ufs_hid_read_progress_ratio(UfsHc *u)
1387
+{
1388
+ uint32_t value = u->attributes.hid_prog_ratio;
1389
+
1390
+ if (value == UFS_HID_PROGRESS_COMPLETE) {
1391
+ ufs_hid_reset(u);
1392
+ }
1393
+
1394
+ return value;
1395
+}
1396
+
1397
static uint32_t ufs_read_attr_value(UfsHc *u, uint8_t idn)
1398
{
1399
+ uint8_t state;
1400
+
1401
switch (idn) {
1402
case UFS_QUERY_ATTR_IDN_BOOT_LU_EN:
1403
return u->attributes.boot_lun_en;
1476
case UFS_QUERY_ATTR_IDN_HID_SIZE:
1477
return be32_to_cpu(u->attributes.hid_size);
1478
case UFS_QUERY_ATTR_IDN_HID_PROG_RATIO:
1454
- return u->attributes.hid_prog_ratio;
1479
+ return ufs_hid_read_progress_ratio(u);
1480
case UFS_QUERY_ATTR_IDN_HID_STATE:
1456
- return u->attributes.hid_state;
1481
+ state = u->attributes.hid_state;
1482
+
1483
+ if (state == UFS_HID_STATE_DEFRAG_COMPLETED ||
1484
+ state == UFS_HID_STATE_DEFRAG_NOT_REQUIRED) {
1485
+ ufs_hid_reset(u);
1486
+ }
1487
+
1488
+ return state;
1489
case UFS_QUERY_ATTR_IDN_WB_BUFF_RESIZE_HINT:
1490
return u->attributes.wb_buffer_resize_hint;
1491
case UFS_QUERY_ATTR_IDN_WB_BUFF_RESIZE_STATUS:
1636
return true;
1637
}
1638
1639
+static QueryRespCode ufs_hid_write_defrag_operation(UfsHc *u, uint32_t value)
1640
+{
1641
+ switch (value) {
1642
+ case UFS_HID_OP_DISABLE:
1643
+ ufs_hid_reset(u);
1644
+ break;
1645
+ case UFS_HID_OP_ANALYSIS:
1646
+ case UFS_HID_OP_DEFRAG:
1647
+ u->attributes.defrag_op = value;
1648
+ u->attributes.hid_state = UFS_HID_STATE_ANALYSIS_IN_PROGRESS;
1649
+ u->attributes.hid_prog_ratio = 0;
1650
+ break;
1651
+ default:
1652
+ return UFS_QUERY_RESULT_INVALID_VALUE;
1653
+ }
1654
+
1655
+ trace_ufs_hid_defrag_operation(value, u->attributes.hid_state);
1656
+ return UFS_QUERY_RESULT_SUCCESS;
1657
+}
1658
+
1659
static QueryRespCode ufs_write_attr_value(UfsHc *u, uint8_t idn, uint32_t value)
1660
{
1661
switch (idn) {
1720
return UFS_QUERY_RESULT_INVALID_VALUE;
1721
}
1722
break;
1723
+ case UFS_QUERY_ATTR_IDN_DEFRAG_OP:
1724
+ return ufs_hid_write_defrag_operation(u, value);
1725
+ case UFS_QUERY_ATTR_IDN_HID_SIZE:
1726
+ u->attributes.hid_size = cpu_to_be32(value);
1727
+ break;
1728
default:
1729
g_assert_not_reached();
1730
return 0;
2268
u->attributes.wb_buffer_resize_status = UFS_WB_RESIZE_COMPLETED;
2269
}
2270
2271
+static void ufs_hid_process(UfsHc *u)
2272
+{
2273
+ uint32_t requested, batch, done;
2274
+
2275
+ switch (u->attributes.hid_state) {
2276
+ case UFS_HID_STATE_ANALYSIS_IN_PROGRESS:
2277
+ u->attributes.hid_avail_size = cpu_to_be32(u->hid_fragment_count);
2278
+ if (u->hid_fragment_count > 0) {
2279
+ u->attributes.hid_state = UFS_HID_STATE_DEFRAG_REQUIRED;
2280
+ } else {
2281
+ u->attributes.hid_state = UFS_HID_STATE_DEFRAG_NOT_REQUIRED;
2282
+ }
2283
+
2284
+ if (u->attributes.defrag_op == UFS_HID_OP_ANALYSIS ||
2285
+ u->attributes.hid_state == UFS_HID_STATE_DEFRAG_NOT_REQUIRED) {
2286
+ u->attributes.defrag_op = UFS_HID_OP_DISABLE;
2287
+ }
2288
+
2289
+ trace_ufs_hid_defrag_operation(u->attributes.defrag_op,
2290
+ u->attributes.hid_state);
2291
+ break;
2292
+
2293
+ case UFS_HID_STATE_DEFRAG_REQUIRED:
2294
+ if (u->attributes.defrag_op != UFS_HID_OP_DEFRAG) {
2295
+ break;
2296
+ }
2297
+
2298
+ requested = MIN(be32_to_cpu(u->attributes.hid_size),
2299
+ be32_to_cpu(u->attributes.hid_avail_size));
2300
+ if (!requested) {
2301
+ u->attributes.hid_state = UFS_HID_STATE_DEFRAG_COMPLETED;
2302
+ u->attributes.defrag_op = UFS_HID_OP_DISABLE;
2303
+ u->attributes.hid_prog_ratio = UFS_HID_PROGRESS_COMPLETE;
2304
+
2305
+ trace_ufs_hid_defrag_operation(u->attributes.defrag_op,
2306
+ u->attributes.hid_state);
2307
+ break;
2308
+ }
2309
+
2310
+ u->attributes.hid_state = UFS_HID_STATE_DEFRAG_IN_PROGRESS;
2311
+ u->hid_defrag_total = requested;
2312
+ u->hid_defrag_remaining = requested;
2313
+ u->attributes.hid_prog_ratio = 0;
2314
+ break;
2315
+
2316
+ case UFS_HID_STATE_DEFRAG_IN_PROGRESS:
2317
+ if (u->hid_defrag_remaining > 0) {
2318
+ batch = u->hid_defrag_remaining / UFS_HID_DEFRAG_BATCH_DIV;
2319
+ if (batch == 0) {
2320
+ batch = 1;
2321
+ }
2322
+
2323
+ u->hid_defrag_remaining -= batch;
2324
+ u->hid_fragment_count -= batch;
2325
+
2326
+ done = u->hid_defrag_total - u->hid_defrag_remaining;
2327
+ u->attributes.hid_prog_ratio =
2328
+ ((uint64_t)done * UFS_HID_PROGRESS_COMPLETE) /
2329
+ u->hid_defrag_total;
2330
+
2331
+ trace_ufs_hid_defrag_progress(u->hid_defrag_remaining,
2332
+ u->attributes.hid_prog_ratio);
2333
+ }
2334
+
2335
+ if (!u->hid_defrag_remaining) {
2336
+ u->attributes.hid_state = UFS_HID_STATE_DEFRAG_COMPLETED;
2337
+ u->attributes.defrag_op = UFS_HID_OP_DISABLE;
2338
+ u->attributes.hid_prog_ratio = UFS_HID_PROGRESS_COMPLETE;
2339
+
2340
+ trace_ufs_hid_defrag_operation(u->attributes.defrag_op,
2341
+ u->attributes.hid_state);
2342
+ }
2343
+
2344
+ break;
2345
+
2346
+ default:
2347
+ break;
2348
+ }
2349
+}
2350
+
2351
static void ufs_process_idle(UfsHc *u)
2352
{
2353
ufs_wb_process_flush(u);
2354
ufs_wb_process_resize(u);
2355
ufs_wb_sync_buffer_size(u);
2356
+ ufs_hid_process(u);
2357
}
2358
2359
static inline bool ufs_check_idle(UfsHc *u)
2522
uint32_t mcqconfig = 0;
2523
uint32_t mcqcap = 0;
2524
uint32_t ext_wb_sup = WB_RESIZE | WB_FIFO | WB_PINNED;
2387
- uint32_t ext_ufs_feat_sup =
2388
- UFS_DEV_WB_SUPPORT | UFS_DEV_HIGH_TEMP_NOTIF | UFS_DEV_LOW_TEMP_NOTIF;
2525
+ uint32_t ext_ufs_feat_sup = UFS_DEV_WB_SUPPORT | UFS_DEV_HIGH_TEMP_NOTIF |
2526
+ UFS_DEV_LOW_TEMP_NOTIF | UFS_DEV_HID_SUPPORT;
2527
int64_t now = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL_RT);
2528
2529
u->reg_size = pow2ceil(ufs_reg_size(u));
2625
u->attributes.max_num_of_rtt = 0x02;
2626
u->attributes.device_too_high_temp_boundary = UFS_TOO_HIGH_TEMP_BOUNDARY;
2627
u->attributes.device_too_low_temp_boundary = UFS_TOO_LOW_TEMP_BOUNDARY;
2628
+ u->attributes.hid_avail_size = cpu_to_be32(0xFFFFFFFF);
2629
+ u->attributes.hid_size = cpu_to_be32(0xFFFFFFFF);
2630
2631
memset(&u->flags, 0, sizeof(u->flags));
2632
u->flags.permanently_disable_fw_update = 1;