1 /*-
2 * Copyright (c) 2025, Samsung Electronics Co., Ltd.
3 * Written by Jaeyoon Choi
4 *
5 * SPDX-License-Identifier: BSD-2-Clause
6 */
7
8 #include <sys/param.h>
9 #include <sys/bus.h>
10 #include <sys/conf.h>
11
12 #include "ufshci_private.h"
13 #include "ufshci_reg.h"
14
15 static int
ufshci_dev_send_query(struct ufshci_controller * ctrlr,struct ufshci_query_param param,struct ufshci_completion_poll_status * status,const char * fail_msg)16 ufshci_dev_send_query(struct ufshci_controller *ctrlr,
17 struct ufshci_query_param param,
18 struct ufshci_completion_poll_status *status, const char *fail_msg)
19 {
20 int error;
21
22 status->done = 0;
23 error = ufshci_ctrlr_cmd_send_query_request(ctrlr,
24 ufshci_completion_poll_cb, status, param);
25 if (error)
26 return (error);
27
28 ufshci_completion_poll(status);
29 if (status->error) {
30 ufshci_printf(ctrlr, "%s failed!\n", fail_msg);
31 return (ENXIO);
32 }
33
34 return (0);
35 }
36
37 static int
ufshci_dev_read_descriptor(struct ufshci_controller * ctrlr,enum ufshci_descriptor_type desc_type,uint8_t index,uint8_t selector,void * desc,size_t desc_size)38 ufshci_dev_read_descriptor(struct ufshci_controller *ctrlr,
39 enum ufshci_descriptor_type desc_type, uint8_t index, uint8_t selector,
40 void *desc, size_t desc_size)
41 {
42 struct ufshci_completion_poll_status status;
43 struct ufshci_query_param param;
44 int error;
45
46 param.function = UFSHCI_QUERY_FUNC_STANDARD_READ_REQUEST;
47 param.opcode = UFSHCI_QUERY_OPCODE_READ_DESCRIPTOR;
48 param.type = desc_type;
49 param.index = index;
50 param.selector = selector;
51 param.value = 0;
52 param.desc_size = desc_size;
53
54 error = ufshci_dev_send_query(ctrlr, param, &status, __func__);
55 if (error)
56 return (error);
57
58 memcpy(desc, status.cpl.response_upiu.query_response_upiu.command_data,
59 desc_size);
60
61 return (0);
62 }
63
64 static int
ufshci_dev_read_device_descriptor(struct ufshci_controller * ctrlr,struct ufshci_device_descriptor * desc)65 ufshci_dev_read_device_descriptor(struct ufshci_controller *ctrlr,
66 struct ufshci_device_descriptor *desc)
67 {
68 return (ufshci_dev_read_descriptor(ctrlr, UFSHCI_DESC_TYPE_DEVICE, 0, 0,
69 desc, sizeof(struct ufshci_device_descriptor)));
70 }
71
72 static int
ufshci_dev_read_geometry_descriptor(struct ufshci_controller * ctrlr,struct ufshci_geometry_descriptor * desc)73 ufshci_dev_read_geometry_descriptor(struct ufshci_controller *ctrlr,
74 struct ufshci_geometry_descriptor *desc)
75 {
76 return (ufshci_dev_read_descriptor(ctrlr, UFSHCI_DESC_TYPE_GEOMETRY, 0,
77 0, desc, sizeof(struct ufshci_geometry_descriptor)));
78 }
79
80 static int
ufshci_dev_read_unit_descriptor(struct ufshci_controller * ctrlr,uint8_t lun,struct ufshci_unit_descriptor * desc)81 ufshci_dev_read_unit_descriptor(struct ufshci_controller *ctrlr, uint8_t lun,
82 struct ufshci_unit_descriptor *desc)
83 {
84 return (ufshci_dev_read_descriptor(ctrlr, UFSHCI_DESC_TYPE_UNIT, lun, 0,
85 desc, sizeof(struct ufshci_unit_descriptor)));
86 }
87
88 static int
ufshci_dev_read_flag(struct ufshci_controller * ctrlr,enum ufshci_flags flag_type,uint8_t * flag)89 ufshci_dev_read_flag(struct ufshci_controller *ctrlr,
90 enum ufshci_flags flag_type, uint8_t *flag)
91 {
92 struct ufshci_completion_poll_status status;
93 struct ufshci_query_param param;
94 int error;
95
96 param.function = UFSHCI_QUERY_FUNC_STANDARD_READ_REQUEST;
97 param.opcode = UFSHCI_QUERY_OPCODE_READ_FLAG;
98 param.type = flag_type;
99 param.index = 0;
100 param.selector = 0;
101 param.value = 0;
102 param.desc_size = 0;
103
104 error = ufshci_dev_send_query(ctrlr, param, &status, __func__);
105 if (error)
106 return (error);
107
108 *flag = status.cpl.response_upiu.query_response_upiu.flag_value;
109
110 return (0);
111 }
112
113 static int
ufshci_dev_set_flag(struct ufshci_controller * ctrlr,enum ufshci_flags flag_type)114 ufshci_dev_set_flag(struct ufshci_controller *ctrlr,
115 enum ufshci_flags flag_type)
116 {
117 struct ufshci_completion_poll_status status;
118 struct ufshci_query_param param;
119
120 param.function = UFSHCI_QUERY_FUNC_STANDARD_WRITE_REQUEST;
121 param.opcode = UFSHCI_QUERY_OPCODE_SET_FLAG;
122 param.type = flag_type;
123 param.index = 0;
124 param.selector = 0;
125 param.value = 0;
126 param.desc_size = 0;
127
128 return (ufshci_dev_send_query(ctrlr, param, &status, __func__));
129 }
130
131 static int
ufshci_dev_clear_flag(struct ufshci_controller * ctrlr,enum ufshci_flags flag_type)132 ufshci_dev_clear_flag(struct ufshci_controller *ctrlr,
133 enum ufshci_flags flag_type)
134 {
135 struct ufshci_completion_poll_status status;
136 struct ufshci_query_param param;
137
138 param.function = UFSHCI_QUERY_FUNC_STANDARD_WRITE_REQUEST;
139 param.opcode = UFSHCI_QUERY_OPCODE_CLEAR_FLAG;
140 param.type = flag_type;
141 param.index = 0;
142 param.selector = 0;
143 param.value = 0;
144 param.desc_size = 0;
145
146 return (ufshci_dev_send_query(ctrlr, param, &status, __func__));
147 }
148
149 static int
ufshci_dev_read_attribute(struct ufshci_controller * ctrlr,enum ufshci_attributes attr_type,uint8_t index,uint8_t selector,uint64_t * value)150 ufshci_dev_read_attribute(struct ufshci_controller *ctrlr,
151 enum ufshci_attributes attr_type, uint8_t index, uint8_t selector,
152 uint64_t *value)
153 {
154 struct ufshci_completion_poll_status status;
155 struct ufshci_query_param param;
156 int error;
157
158 param.function = UFSHCI_QUERY_FUNC_STANDARD_READ_REQUEST;
159 param.opcode = UFSHCI_QUERY_OPCODE_READ_ATTRIBUTE;
160 param.type = attr_type;
161 param.index = index;
162 param.selector = selector;
163 param.value = 0;
164 param.desc_size = 0;
165
166 error = ufshci_dev_send_query(ctrlr, param, &status, __func__);
167 if (error)
168 return (error);
169
170 *value = be64toh(status.cpl.response_upiu.query_response_upiu.value_64);
171
172 return (0);
173 }
174
175 static int
ufshci_dev_write_attribute(struct ufshci_controller * ctrlr,enum ufshci_attributes attr_type,uint8_t index,uint8_t selector,uint64_t value)176 ufshci_dev_write_attribute(struct ufshci_controller *ctrlr,
177 enum ufshci_attributes attr_type, uint8_t index, uint8_t selector,
178 uint64_t value)
179 {
180 struct ufshci_completion_poll_status status;
181 struct ufshci_query_param param;
182
183 param.function = UFSHCI_QUERY_FUNC_STANDARD_WRITE_REQUEST;
184 param.opcode = UFSHCI_QUERY_OPCODE_WRITE_ATTRIBUTE;
185 param.type = attr_type;
186 param.index = index;
187 param.selector = selector;
188 param.value = value;
189 param.desc_size = 0;
190
191 return (ufshci_dev_send_query(ctrlr, param, &status, __func__));
192 }
193
194 int
ufshci_dev_init(struct ufshci_controller * ctrlr)195 ufshci_dev_init(struct ufshci_controller *ctrlr)
196 {
197 int timeout = ticks + MSEC_2_TICKS(ctrlr->device_init_timeout_in_ms);
198 sbintime_t delta_t = SBT_1US;
199 uint8_t flag;
200 int error;
201 const uint8_t device_init_completed = 0;
202
203 error = ufshci_dev_set_flag(ctrlr, UFSHCI_FLAG_F_DEVICE_INIT);
204 if (error)
205 return (error);
206
207 /* Wait for the UFSHCI_FLAG_F_DEVICE_INIT flag to change */
208 while (1) {
209 error = ufshci_dev_read_flag(ctrlr, UFSHCI_FLAG_F_DEVICE_INIT,
210 &flag);
211 if (error)
212 return (error);
213 if (flag == device_init_completed)
214 break;
215 if (timeout - ticks < 0) {
216 ufshci_printf(ctrlr,
217 "device init did not become %d "
218 "within %d ms\n",
219 device_init_completed,
220 ctrlr->device_init_timeout_in_ms);
221 return (ENXIO);
222 }
223
224 pause_sbt("ufshciinit", delta_t, 0, C_PREL(1));
225 delta_t = min(SBT_1MS, delta_t * 3 / 2);
226 }
227
228 return (0);
229 }
230
231 int
ufshci_dev_reset(struct ufshci_controller * ctrlr)232 ufshci_dev_reset(struct ufshci_controller *ctrlr)
233 {
234 if (ufshci_uic_send_dme_endpoint_reset(ctrlr))
235 return (ENXIO);
236
237 return (ufshci_dev_init(ctrlr));
238 }
239
240 int
ufshci_dev_init_reference_clock(struct ufshci_controller * ctrlr)241 ufshci_dev_init_reference_clock(struct ufshci_controller *ctrlr)
242 {
243 int error;
244 uint8_t index, selector;
245 uint64_t value;
246
247 index = 0; /* bRefClkFreq is device type attribute */
248 selector = 0; /* bRefClkFreq is device type attribute */
249
250 /*
251 * bRefClkFreq is a persistent attribute. Skip the write when
252 * the device already holds the wanted value.
253 */
254 error = ufshci_dev_read_attribute(ctrlr, UFSHCI_ATTR_B_REF_CLK_FREQ,
255 index, selector, &value);
256 if (error != 0) {
257 ufshci_printf(ctrlr, "bRefClkFreq read failed, writing %u\n",
258 ctrlr->ref_clk);
259 } else if ((uint32_t)value == ctrlr->ref_clk) {
260 return (0);
261 } else {
262 ufshci_printf(ctrlr, "changing bRefClkFreq from %u to %u\n",
263 (uint32_t)value, ctrlr->ref_clk);
264 }
265
266 error = ufshci_dev_write_attribute(ctrlr, UFSHCI_ATTR_B_REF_CLK_FREQ,
267 index, selector, ctrlr->ref_clk);
268 if (error)
269 return (error);
270
271 return (0);
272 }
273
274 int
ufshci_dev_init_unipro(struct ufshci_controller * ctrlr)275 ufshci_dev_init_unipro(struct ufshci_controller *ctrlr)
276 {
277 uint32_t pa_granularity, peer_pa_granularity;
278 uint32_t t_activate, pear_t_activate;
279
280 if (ctrlr->quirks & UFSHCI_QUIRK_LONG_PEER_PA_TACTIVATE) {
281 /*
282 * PA_Granularity: Granularity for PA_TActivate and
283 * PA_Hibern8Time
284 * - 1=1us, 2=4us, 3=8us, 4=16us, 5=32us, 6=100us
285 */
286 if (ufshci_uic_send_dme_get(ctrlr, PA_Granularity,
287 &pa_granularity))
288 return (ENXIO);
289 if (ufshci_uic_send_dme_peer_get(ctrlr, PA_Granularity,
290 &peer_pa_granularity))
291 return (ENXIO);
292
293 /*
294 * PA_TActivate: Time to wait before activating a burst in order
295 * to wake-up peer M-RX UniPro automatically sets timing
296 * information such as PA_TActivate through the
297 * PACP_CAP_EXT1_ind command during Link Startup operation.
298 */
299 if (ufshci_uic_send_dme_get(ctrlr, PA_TActivate, &t_activate))
300 return (ENXIO);
301 if (ufshci_uic_send_dme_peer_get(ctrlr, PA_TActivate,
302 &pear_t_activate))
303 return (ENXIO);
304
305 /*
306 * Intel Lake-field UFSHCI has a quirk. We need to add 200us to
307 * the PEER's PA_TActivate.
308 */
309 if (pa_granularity == peer_pa_granularity) {
310 pear_t_activate = t_activate + 2;
311 if (ufshci_uic_send_dme_peer_set(ctrlr, PA_TActivate,
312 pear_t_activate))
313 return (ENXIO);
314 }
315 }
316
317 return (0);
318 }
319
320 int
ufshci_dev_init_uic_power_mode(struct ufshci_controller * ctrlr)321 ufshci_dev_init_uic_power_mode(struct ufshci_controller *ctrlr)
322 {
323 /*
324 * TX/RX PWRMode:
325 * - TX[3:0], RX[7:4]
326 * - Fast Mode = 1, Slow Mode = 2, FastAuto Mode = 4, SlowAuto Mode = 5
327 */
328 const uint32_t fast_mode = 1;
329 const uint32_t rx_bit_shift = 4;
330 uint32_t peer_granularity;
331
332 /* Update lanes with available TX/RX lanes */
333 if (ufshci_uic_send_dme_get(ctrlr, PA_AvailTxDataLanes,
334 &ctrlr->max_tx_lanes))
335 return (ENXIO);
336 if (ufshci_uic_send_dme_get(ctrlr, PA_AvailRxDataLanes,
337 &ctrlr->max_rx_lanes))
338 return (ENXIO);
339
340 /* Get max HS-GEAR value */
341 if (ufshci_uic_send_dme_get(ctrlr, PA_MaxRxHSGear,
342 &ctrlr->max_rx_hs_gear))
343 return (ENXIO);
344
345 /* Set the data lane to max */
346 ctrlr->tx_lanes = ctrlr->max_tx_lanes;
347 ctrlr->rx_lanes = ctrlr->max_rx_lanes;
348 if (ufshci_uic_send_dme_set(ctrlr, PA_ActiveTxDataLanes,
349 ctrlr->tx_lanes))
350 return (ENXIO);
351 if (ufshci_uic_send_dme_set(ctrlr, PA_ActiveRxDataLanes,
352 ctrlr->rx_lanes))
353 return (ENXIO);
354
355 if (ctrlr->quirks & UFSHCI_QUIRK_CHANGE_LANE_AND_GEAR_SEPARATELY) {
356 /* Before changing gears, first change the number of lanes. */
357 if (ufshci_uic_send_dme_get(ctrlr, PA_PWRMode,
358 &ctrlr->tx_rx_power_mode))
359 return (ENXIO);
360 if (ufshci_uic_send_dme_set(ctrlr, PA_PWRMode,
361 ctrlr->tx_rx_power_mode))
362 return (ENXIO);
363
364 /* Wait for power mode changed. */
365 if (ufshci_uic_power_mode_ready(ctrlr)) {
366 ufshci_reg_dump(ctrlr);
367 return (ENXIO);
368 }
369 }
370
371 /* Set HS-GEAR to max gear */
372 ctrlr->hs_gear = ctrlr->max_rx_hs_gear;
373 if (ufshci_uic_send_dme_set(ctrlr, PA_TxGear, ctrlr->hs_gear))
374 return (ENXIO);
375 if (ufshci_uic_send_dme_set(ctrlr, PA_RxGear, ctrlr->hs_gear))
376 return (ENXIO);
377
378 /*
379 * Set termination
380 * - HS-MODE = ON / LS-MODE = OFF
381 */
382 if (ufshci_uic_send_dme_set(ctrlr, PA_TxTermination, true))
383 return (ENXIO);
384 if (ufshci_uic_send_dme_set(ctrlr, PA_RxTermination, true))
385 return (ENXIO);
386
387 /* Set HSSeries */
388 if (ufshci_uic_send_dme_set(ctrlr, PA_HSSeries, ctrlr->hs_series))
389 return (ENXIO);
390
391 /* HS-G4 and above need initial adaptation. */
392 if (ctrlr->hs_gear >= 4 &&
393 ufshci_uic_send_dme_set(ctrlr, PA_TxHsAdaptType, PA_INITIAL_ADAPT))
394 return (ENXIO);
395
396 /* Set Timeout values */
397 if (ufshci_uic_send_dme_set(ctrlr, PA_PWRModeUserData0,
398 DL_FC0ProtectionTimeOutVal_Default))
399 return (ENXIO);
400 if (ufshci_uic_send_dme_set(ctrlr, PA_PWRModeUserData1,
401 DL_TC0ReplayTimeOutVal_Default))
402 return (ENXIO);
403 if (ufshci_uic_send_dme_set(ctrlr, PA_PWRModeUserData2,
404 DL_AFC0ReqTimeOutVal_Default))
405 return (ENXIO);
406 if (ufshci_uic_send_dme_set(ctrlr, PA_PWRModeUserData3,
407 DL_FC0ProtectionTimeOutVal_Default))
408 return (ENXIO);
409 if (ufshci_uic_send_dme_set(ctrlr, PA_PWRModeUserData4,
410 DL_TC0ReplayTimeOutVal_Default))
411 return (ENXIO);
412 if (ufshci_uic_send_dme_set(ctrlr, PA_PWRModeUserData5,
413 DL_AFC0ReqTimeOutVal_Default))
414 return (ENXIO);
415
416 if (ufshci_uic_send_dme_set(ctrlr, DME_LocalFC0ProtectionTimeOutVal,
417 DL_FC0ProtectionTimeOutVal_Default))
418 return (ENXIO);
419 if (ufshci_uic_send_dme_set(ctrlr, DME_LocalTC0ReplayTimeOutVal,
420 DL_TC0ReplayTimeOutVal_Default))
421 return (ENXIO);
422 if (ufshci_uic_send_dme_set(ctrlr, DME_LocalAFC0ReqTimeOutVal,
423 DL_AFC0ReqTimeOutVal_Default))
424 return (ENXIO);
425
426 /* Set TX/RX PWRMode */
427 ctrlr->tx_rx_power_mode = (fast_mode << rx_bit_shift) | fast_mode;
428 if (ufshci_uic_send_dme_set(ctrlr, PA_PWRMode, ctrlr->tx_rx_power_mode))
429 return (ENXIO);
430
431 /* Wait for power mode changed. */
432 if (ufshci_uic_power_mode_ready(ctrlr)) {
433 ufshci_reg_dump(ctrlr);
434 return (ENXIO);
435 }
436
437 if (ctrlr->quirks & UFSHCI_QUIRK_WAIT_AFTER_POWER_MODE_CHANGE) {
438 /*
439 * Intel Lake-field UFSHCI has a quirk.
440 * We need to wait 1250us and clear dme error.
441 */
442 pause_sbt("ufshci", ustosbt(1250), 0, C_PREL(1));
443
444 /* Test with dme_peer_get to make sure there are no errors. */
445 if (ufshci_uic_send_dme_peer_get(ctrlr, PA_Granularity,
446 &peer_granularity))
447 return (ENXIO);
448 }
449
450 return (0);
451 }
452
453 void
ufshci_dev_enable_auto_hibernate(struct ufshci_controller * ctrlr)454 ufshci_dev_enable_auto_hibernate(struct ufshci_controller *ctrlr)
455 {
456 if (!ctrlr->ufs_dev.auto_hibernation_supported)
457 return;
458
459 ufshci_mmio_write_4(ctrlr, ahit, ctrlr->ufs_dev.ahit);
460 }
461
462 void
ufshci_dev_init_auto_hibernate(struct ufshci_controller * ctrlr)463 ufshci_dev_init_auto_hibernate(struct ufshci_controller *ctrlr)
464 {
465 ctrlr->ufs_dev.auto_hibernation_supported =
466 UFSHCIV(UFSHCI_CAP_REG_AUTOH8, ctrlr->cap) &&
467 !(ctrlr->quirks & UFSHCI_QUIRK_BROKEN_AUTO_HIBERNATE);
468
469 if (!ctrlr->ufs_dev.auto_hibernation_supported)
470 return;
471
472 /* The default value for auto hibernation is 150 ms */
473 ctrlr->ufs_dev.ahit = 0;
474 ctrlr->ufs_dev.ahit |= UFSHCIF(UFSHCI_AHIT_REG_AH8ITV, 150);
475 ctrlr->ufs_dev.ahit |= UFSHCIF(UFSHCI_AHIT_REG_TS, 3);
476
477 ufshci_dev_enable_auto_hibernate(ctrlr);
478 }
479
480 void
ufshci_dev_init_uic_link_state(struct ufshci_controller * ctrlr)481 ufshci_dev_init_uic_link_state(struct ufshci_controller *ctrlr)
482 {
483 ctrlr->ufs_dev.link_state = UFSHCI_UIC_LINK_STATE_ACTIVE;
484 }
485
486 int
ufshci_dev_init_ufs_power_mode(struct ufshci_controller * ctrlr)487 ufshci_dev_init_ufs_power_mode(struct ufshci_controller *ctrlr)
488 {
489 ctrlr->ufs_dev.power_mode_supported = false;
490
491 if (ctrlr->quirks & UFSHCI_QUIRK_SKIP_WELL_KNOWN_LUNS)
492 return (0);
493
494 if (ctrlr->ufs_device_wlun_periph == NULL) {
495 /* The returned reference is kept by the cached pointer. */
496 ctrlr->ufs_device_wlun_periph = ufshci_sim_find_periph(ctrlr,
497 UFSHCI_WLUN_UFS_DEVICE);
498 if (ctrlr->ufs_device_wlun_periph == NULL) {
499 ufshci_printf(ctrlr,
500 "Well-known LUN `UFS Device (0x50)` not found\n");
501 return (0);
502 }
503 }
504
505 ctrlr->ufs_dev.power_mode_supported = true;
506 ctrlr->ufs_dev.power_mode = UFSHCI_DEV_PWR_ACTIVE;
507
508 return (0);
509 }
510
511 int
ufshci_dev_get_descriptor(struct ufshci_controller * ctrlr)512 ufshci_dev_get_descriptor(struct ufshci_controller *ctrlr)
513 {
514 struct ufshci_device *device = &ctrlr->ufs_dev;
515 /*
516 * The kDeviceDensityUnit is defined in the spec as 512.
517 * qTotalRawDeviceCapacity use big-endian byte ordering.
518 */
519 const uint32_t device_density_unit = 512;
520 uint32_t ver;
521 int error;
522
523 error = ufshci_dev_read_device_descriptor(ctrlr, &device->dev_desc);
524 if (error)
525 return (error);
526
527 ver = be16toh(device->dev_desc.wSpecVersion);
528 ufshci_printf(ctrlr, "UFS device spec version %u.%u.%u\n",
529 UFSHCIV(UFSHCI_VER_REG_MJR, ver), UFSHCIV(UFSHCI_VER_REG_MNR, ver),
530 UFSHCIV(UFSHCI_VER_REG_VS, ver));
531 ufshci_printf(ctrlr, "%u enabled LUNs found\n",
532 device->dev_desc.bNumberLU);
533
534 error = ufshci_dev_read_geometry_descriptor(ctrlr, &device->geo_desc);
535 if (error)
536 return (error);
537
538 if (device->geo_desc.bMaxNumberLU == 0) {
539 device->max_lun_count = 8;
540 } else if (device->geo_desc.bMaxNumberLU == 1) {
541 device->max_lun_count = 32;
542 } else {
543 ufshci_printf(ctrlr,
544 "Invalid Geometry Descriptor bMaxNumberLU value=%d\n",
545 device->geo_desc.bMaxNumberLU);
546 return (ENXIO);
547 }
548 ctrlr->max_lun_count = device->max_lun_count;
549
550 ufshci_printf(ctrlr, "UFS device total size is %lu bytes\n",
551 be64toh(device->geo_desc.qTotalRawDeviceCapacity) *
552 device_density_unit);
553
554 return (0);
555 }
556
557 static int
ufshci_dev_enable_write_booster(struct ufshci_controller * ctrlr)558 ufshci_dev_enable_write_booster(struct ufshci_controller *ctrlr)
559 {
560 struct ufshci_device *dev = &ctrlr->ufs_dev;
561 int error;
562
563 /* Enable WriteBooster */
564 error = ufshci_dev_set_flag(ctrlr, UFSHCI_FLAG_F_WRITE_BOOSTER_EN);
565 if (error) {
566 ufshci_printf(ctrlr, "Failed to enable WriteBooster\n");
567 return (error);
568 }
569 dev->is_wb_enabled = true;
570
571 /* Enable WriteBooster buffer flush during hibernate */
572 error = ufshci_dev_set_flag(ctrlr,
573 UFSHCI_FLAG_F_WB_BUFFER_FLUSH_DURING_HIBERNATE);
574 if (error) {
575 ufshci_printf(ctrlr,
576 "Failed to enable WriteBooster buffer flush during hibernate\n");
577 return (error);
578 }
579
580 /* Enable WriteBooster buffer flush */
581 error = ufshci_dev_set_flag(ctrlr, UFSHCI_FLAG_F_WB_BUFFER_FLUSH_EN);
582 if (error) {
583 ufshci_printf(ctrlr,
584 "Failed to enable WriteBooster buffer flush\n");
585 return (error);
586 }
587 dev->is_wb_flush_enabled = true;
588
589 return (0);
590 }
591
592 static int
ufshci_dev_disable_write_booster(struct ufshci_controller * ctrlr)593 ufshci_dev_disable_write_booster(struct ufshci_controller *ctrlr)
594 {
595 struct ufshci_device *dev = &ctrlr->ufs_dev;
596 int error;
597
598 /* Disable WriteBooster buffer flush */
599 error = ufshci_dev_clear_flag(ctrlr, UFSHCI_FLAG_F_WB_BUFFER_FLUSH_EN);
600 if (error) {
601 ufshci_printf(ctrlr,
602 "Failed to disable WriteBooster buffer flush\n");
603 return (error);
604 }
605 dev->is_wb_flush_enabled = false;
606
607 /* Disable WriteBooster buffer flush during hibernate */
608 error = ufshci_dev_clear_flag(ctrlr,
609 UFSHCI_FLAG_F_WB_BUFFER_FLUSH_DURING_HIBERNATE);
610 if (error) {
611 ufshci_printf(ctrlr,
612 "Failed to disable WriteBooster buffer flush during hibernate\n");
613 return (error);
614 }
615
616 /* Disable WriteBooster */
617 error = ufshci_dev_clear_flag(ctrlr, UFSHCI_FLAG_F_WRITE_BOOSTER_EN);
618 if (error) {
619 ufshci_printf(ctrlr, "Failed to disable WriteBooster\n");
620 return (error);
621 }
622 dev->is_wb_enabled = false;
623
624 return (0);
625 }
626
627 static int
ufshci_dev_is_write_booster_buffer_life_time_left(struct ufshci_controller * ctrlr,bool * is_life_time_left)628 ufshci_dev_is_write_booster_buffer_life_time_left(
629 struct ufshci_controller *ctrlr, bool *is_life_time_left)
630 {
631 struct ufshci_device *dev = &ctrlr->ufs_dev;
632 uint8_t buffer_lun;
633 uint64_t life_time;
634 uint32_t error;
635
636 if (dev->wb_buffer_type == UFSHCI_DESC_WB_BUF_TYPE_LU_DEDICATED)
637 buffer_lun = dev->wb_dedicated_lu;
638 else
639 buffer_lun = 0;
640
641 error = ufshci_dev_read_attribute(ctrlr,
642 UFSHCI_ATTR_B_WB_BUFFER_LIFE_TIME_EST, buffer_lun, 0, &life_time);
643 if (error)
644 return (error);
645
646 *is_life_time_left = (life_time != UFSHCI_ATTR_WB_LIFE_EXCEEDED);
647
648 return (0);
649 }
650
651 /*
652 * This function is not yet in use. It will be used when suspend/resume is
653 * implemented.
654 */
655 static __unused int
ufshci_dev_need_write_booster_buffer_flush(struct ufshci_controller * ctrlr,bool * need_flush)656 ufshci_dev_need_write_booster_buffer_flush(struct ufshci_controller *ctrlr,
657 bool *need_flush)
658 {
659 struct ufshci_device *dev = &ctrlr->ufs_dev;
660 bool is_life_time_left = false;
661 uint64_t available_buffer_size, current_buffer_size;
662 uint8_t buffer_lun;
663 uint32_t error;
664
665 *need_flush = false;
666
667 if (!dev->is_wb_enabled)
668 return (0);
669
670 error = ufshci_dev_is_write_booster_buffer_life_time_left(ctrlr,
671 &is_life_time_left);
672 if (error)
673 return (error);
674
675 if (!is_life_time_left)
676 return (ufshci_dev_disable_write_booster(ctrlr));
677
678 if (dev->wb_buffer_type == UFSHCI_DESC_WB_BUF_TYPE_LU_DEDICATED)
679 buffer_lun = dev->wb_dedicated_lu;
680 else
681 buffer_lun = 0;
682
683 error = ufshci_dev_read_attribute(ctrlr,
684 UFSHCI_ATTR_B_AVAILABLE_WB_BUFFER_SIZE, buffer_lun, 0,
685 &available_buffer_size);
686 if (error)
687 return (error);
688
689 switch (dev->wb_user_space_config_option) {
690 case UFSHCI_DESC_WB_BUF_USER_SPACE_REDUCTION:
691 *need_flush = (available_buffer_size <=
692 UFSHCI_ATTR_WB_AVAILABLE_10);
693 break;
694 case UFSHCI_DESC_WB_BUF_PRESERVE_USER_SPACE:
695 /*
696 * In PRESERVE USER SPACE mode, flush should be performed when
697 * the current buffer is greater than 0 and the available buffer
698 * below write_booster_flush_threshold is left.
699 */
700 error = ufshci_dev_read_attribute(ctrlr,
701 UFSHCI_ATTR_D_CURRENT_WB_BUFFER_SIZE, buffer_lun, 0,
702 ¤t_buffer_size);
703 if (error)
704 return (error);
705
706 if (current_buffer_size == 0)
707 return (0);
708
709 *need_flush = (available_buffer_size <
710 dev->write_booster_flush_threshold);
711 break;
712 default:
713 ufshci_printf(ctrlr,
714 "Invalid bWriteBoosterBufferPreserveUserSpaceEn value");
715 return (EINVAL);
716 }
717
718 /*
719 * TODO: Need to handle WRITEBOOSTER_FLUSH_NEEDED exception case from
720 * wExceptionEventStatus attribute.
721 */
722
723 return (0);
724 }
725
726 int
ufshci_dev_config_write_booster(struct ufshci_controller * ctrlr)727 ufshci_dev_config_write_booster(struct ufshci_controller *ctrlr)
728 {
729 struct ufshci_device *dev = &ctrlr->ufs_dev;
730 uint32_t extended_ufs_feature_support;
731 uint32_t alloc_units = 0;
732 struct ufshci_unit_descriptor unit_desc;
733 uint8_t lun;
734 bool is_life_time_left;
735 uint32_t mega_byte = 1024 * 1024;
736 uint32_t error = 0;
737
738 extended_ufs_feature_support = be32toh(
739 dev->dev_desc.dExtendedUfsFeaturesSupport);
740 if (!(extended_ufs_feature_support &
741 UFSHCI_DESC_EXT_UFS_FEATURE_WRITE_BOOSTER)) {
742 /* This device does not support Write Booster */
743 return (0);
744 }
745
746 if (ufshci_dev_enable_write_booster(ctrlr))
747 return (0);
748
749 /* Get WriteBooster buffer parameters */
750 dev->wb_buffer_type = dev->dev_desc.bWriteBoosterBufferType;
751 dev->wb_user_space_config_option =
752 dev->dev_desc.bWriteBoosterBufferPreserveUserSpaceEn;
753
754 /*
755 * Find the size of the write buffer.
756 * With LU-dedicated (00h), the WriteBooster buffer is assigned
757 * exclusively to one chosen LU (not one-per-LU), whereas Shared (01h)
758 * uses a single device-wide buffer shared by multiple LUs.
759 */
760 if (dev->wb_buffer_type == UFSHCI_DESC_WB_BUF_TYPE_SINGLE_SHARED) {
761 alloc_units = be32toh(
762 dev->dev_desc.dNumSharedWriteBoosterBufferAllocUnits);
763 ufshci_printf(ctrlr,
764 "WriteBooster buffer type = Shared, alloc_units=%d\n",
765 alloc_units);
766 } else if (dev->wb_buffer_type ==
767 UFSHCI_DESC_WB_BUF_TYPE_LU_DEDICATED) {
768 ufshci_printf(ctrlr, "WriteBooster buffer type = Dedicated\n");
769 for (lun = 0; lun < ctrlr->max_lun_count; lun++) {
770 /* Find a dedicated buffer using a unit descriptor */
771 if (ufshci_dev_read_unit_descriptor(ctrlr, lun,
772 &unit_desc))
773 continue;
774
775 alloc_units = be32toh(
776 unit_desc.dLUNumWriteBoosterBufferAllocUnits);
777 if (alloc_units) {
778 dev->wb_dedicated_lu = lun;
779 break;
780 }
781 }
782 } else {
783 ufshci_printf(ctrlr,
784 "Not supported WriteBooster buffer type: 0x%x\n",
785 dev->wb_buffer_type);
786 goto out;
787 }
788
789 if (alloc_units == 0) {
790 ufshci_printf(ctrlr, "The WriteBooster buffer size is zero\n");
791 goto out;
792 }
793
794 dev->wb_buffer_size_mb = alloc_units *
795 dev->geo_desc.bAllocationUnitSize *
796 (be32toh(dev->geo_desc.dSegmentSize)) /
797 (mega_byte / UFSHCI_SECTOR_SIZE);
798
799 /* Set to flush when 40% of the available buffer size remains */
800 dev->write_booster_flush_threshold = UFSHCI_ATTR_WB_AVAILABLE_40;
801
802 /*
803 * Check if WriteBooster Buffer lifetime is left.
804 * WriteBooster Buffer lifetime — percent of life used based on P/E
805 * cycles. If "preserve user space" is enabled, writes to normal user
806 * space also consume WB life since the area is shared.
807 */
808 error = ufshci_dev_is_write_booster_buffer_life_time_left(ctrlr,
809 &is_life_time_left);
810 if (error)
811 goto out;
812
813 if (!is_life_time_left) {
814 ufshci_printf(ctrlr,
815 "There is no WriteBooster buffer life time left.\n");
816 goto out;
817 }
818
819 ufshci_printf(ctrlr, "WriteBooster Enabled\n");
820 return (0);
821 out:
822 ufshci_dev_disable_write_booster(ctrlr);
823 return (error);
824 }
825
826 int
ufshci_dev_get_current_power_mode(struct ufshci_controller * ctrlr,uint8_t * power_mode)827 ufshci_dev_get_current_power_mode(struct ufshci_controller *ctrlr,
828 uint8_t *power_mode)
829 {
830 uint64_t value;
831 int err;
832
833 err = ufshci_dev_read_attribute(ctrlr, UFSHCI_ATTR_B_CURRENT_POWER_MODE,
834 /*index*/ 0, /*selector*/ 0, &value);
835 if (err)
836 return (err);
837
838 *power_mode = (uint8_t)value;
839
840 return (0);
841 }
842
843 static int
ufshci_dev_hibernate_enter(struct ufshci_controller * ctrlr)844 ufshci_dev_hibernate_enter(struct ufshci_controller *ctrlr)
845 {
846 int error;
847
848 error = ufshci_uic_send_dme_hibernate_enter(ctrlr);
849 if (error)
850 return (error);
851
852 return (ufshci_uic_hibernation_ready(ctrlr));
853 }
854
855 static int
ufshci_dev_hibernate_exit(struct ufshci_controller * ctrlr)856 ufshci_dev_hibernate_exit(struct ufshci_controller *ctrlr)
857 {
858 int error;
859
860 error = ufshci_uic_send_dme_hibernate_exit(ctrlr);
861 if (error)
862 return (error);
863
864 return (ufshci_uic_hibernation_ready(ctrlr));
865 }
866
867 int
ufshci_dev_link_state_transition(struct ufshci_controller * ctrlr,enum ufshci_uic_link_state target_state)868 ufshci_dev_link_state_transition(struct ufshci_controller *ctrlr,
869 enum ufshci_uic_link_state target_state)
870 {
871 struct ufshci_device *dev = &ctrlr->ufs_dev;
872 int error = 0;
873
874 if (dev->link_state == target_state)
875 return (0);
876
877 switch (target_state) {
878 case UFSHCI_UIC_LINK_STATE_OFF:
879 error = ufshci_dev_hibernate_enter(ctrlr);
880 if (error)
881 break;
882 error = ufshci_ctrlr_disable(ctrlr);
883 break;
884 case UFSHCI_UIC_LINK_STATE_ACTIVE:
885 if (dev->link_state == UFSHCI_UIC_LINK_STATE_HIBERNATE)
886 error = ufshci_dev_hibernate_exit(ctrlr);
887 else
888 error = EINVAL;
889 break;
890 case UFSHCI_UIC_LINK_STATE_HIBERNATE:
891 if (dev->link_state == UFSHCI_UIC_LINK_STATE_ACTIVE)
892 error = ufshci_dev_hibernate_enter(ctrlr);
893 else
894 error = EINVAL;
895 break;
896 case UFSHCI_UIC_LINK_STATE_BROKEN:
897 break;
898 default:
899 error = EINVAL;
900 break;
901 }
902
903 if (error)
904 return (error);
905
906 dev->link_state = target_state;
907
908 return (0);
909 }
910