Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/ufshci/ufshci_ctrlr.c
| /*- | /*- | ||||
| * Copyright (c) 2025, Samsung Electronics Co., Ltd. | * Copyright (c) 2025, Samsung Electronics Co., Ltd. | ||||
| * Written by Jaeyoon Choi | * Written by Jaeyoon Choi | ||||
| * | * | ||||
| * SPDX-License-Identifier: BSD-2-Clause | * SPDX-License-Identifier: BSD-2-Clause | ||||
| */ | */ | ||||
| #include <sys/param.h> | #include <sys/param.h> | ||||
| #include <sys/bus.h> | #include <sys/bus.h> | ||||
| #include <sys/conf.h> | #include <sys/conf.h> | ||||
| #include "ufshci_private.h" | #include "ufshci_private.h" | ||||
| #include "ufshci_reg.h" | #include "ufshci_reg.h" | ||||
| static void | |||||
| ufshci_ctrlr_fail(struct ufshci_controller *ctrlr) | |||||
jaeyoon: This function was moved here from line 299. | |||||
| { | |||||
| ctrlr->is_failed = true; | |||||
| ufshci_req_queue_fail(ctrlr, | |||||
| ctrlr->task_mgmt_req_queue.qops.get_hw_queue( | |||||
| &ctrlr->task_mgmt_req_queue)); | |||||
| ufshci_req_queue_fail(ctrlr, | |||||
| ctrlr->transfer_req_queue.qops.get_hw_queue( | |||||
| &ctrlr->transfer_req_queue)); | |||||
| } | |||||
| static void | |||||
| ufshci_ctrlr_start(struct ufshci_controller *ctrlr, bool resetting) | |||||
Done Inline ActionsThis function was moved here from line 312 and resetting was added. jaeyoon: This function was moved here from line 312 and `resetting` was added. | |||||
| { | |||||
| TSENTER(); | |||||
| /* | |||||
Done Inline Actionsso for these special cases, it might be good to document what's special about resetting imp: so for these special cases, it might be good to document what's special about resetting
| |||||
| * If `resetting` is true, we are on the reset path. | |||||
| * Re-enable request queues here because ufshci_ctrlr_reset_task() | |||||
| * disables them during reset. | |||||
| */ | |||||
| if (resetting) { | |||||
| if (ufshci_utmr_req_queue_enable(ctrlr) != 0) { | |||||
| ufshci_ctrlr_fail(ctrlr); | |||||
| return; | |||||
| } | |||||
| if (ufshci_utr_req_queue_enable(ctrlr) != 0) { | |||||
| ufshci_ctrlr_fail(ctrlr); | |||||
| return; | |||||
| } | |||||
| } | |||||
| if (ufshci_ctrlr_send_nop(ctrlr) != 0) { | |||||
| ufshci_ctrlr_fail(ctrlr); | |||||
| return; | |||||
| } | |||||
| /* Initialize UFS target drvice */ | |||||
| if (ufshci_dev_init(ctrlr) != 0) { | |||||
| ufshci_ctrlr_fail(ctrlr); | |||||
| return; | |||||
| } | |||||
| /* Initialize Reference Clock */ | |||||
| if (ufshci_dev_init_reference_clock(ctrlr) != 0) { | |||||
| ufshci_ctrlr_fail(ctrlr); | |||||
| return; | |||||
| } | |||||
| /* Initialize unipro */ | |||||
| if (ufshci_dev_init_unipro(ctrlr) != 0) { | |||||
| ufshci_ctrlr_fail(ctrlr); | |||||
| return; | |||||
| } | |||||
| /* | |||||
| * Initialize UIC Power Mode | |||||
| * QEMU UFS devices do not support unipro and power mode. | |||||
| */ | |||||
| if (!(ctrlr->quirks & UFSHCI_QUIRK_IGNORE_UIC_POWER_MODE) && | |||||
| ufshci_dev_init_uic_power_mode(ctrlr) != 0) { | |||||
| ufshci_ctrlr_fail(ctrlr); | |||||
| return; | |||||
| } | |||||
| /* Initialize UFS Power Mode */ | |||||
| if (ufshci_dev_init_ufs_power_mode(ctrlr) != 0) { | |||||
| ufshci_ctrlr_fail(ctrlr); | |||||
| return; | |||||
| } | |||||
| /* Read Controller Descriptor (Device, Geometry) */ | |||||
| if (ufshci_dev_get_descriptor(ctrlr) != 0) { | |||||
| ufshci_ctrlr_fail(ctrlr); | |||||
| return; | |||||
| } | |||||
| if (ufshci_dev_config_write_booster(ctrlr)) { | |||||
| ufshci_ctrlr_fail(ctrlr); | |||||
| return; | |||||
| } | |||||
| /* TODO: Configure Write Protect */ | |||||
| /* TODO: Configure Background Operations */ | |||||
| /* | |||||
| * If the reset is due to a timeout, it is already attached to the SIM | |||||
| * and does not need to be attached again. | |||||
| */ | |||||
| if (!resetting && ufshci_sim_attach(ctrlr) != 0) { | |||||
| ufshci_ctrlr_fail(ctrlr); | |||||
| return; | |||||
| } | |||||
| TSEXIT(); | |||||
| } | |||||
| static int | static int | ||||
| ufshci_ctrlr_enable_host_ctrlr(struct ufshci_controller *ctrlr) | ufshci_ctrlr_disable_host_ctrlr(struct ufshci_controller *ctrlr) | ||||
| { | { | ||||
| int timeout = ticks + MSEC_2_TICKS(ctrlr->device_init_timeout_in_ms); | int timeout = ticks + MSEC_2_TICKS(ctrlr->device_init_timeout_in_ms); | ||||
| sbintime_t delta_t = SBT_1US; | sbintime_t delta_t = SBT_1US; | ||||
| uint32_t hce; | uint32_t hce; | ||||
| hce = ufshci_mmio_read_4(ctrlr, hce); | hce = ufshci_mmio_read_4(ctrlr, hce); | ||||
| /* If UFS host controller is already enabled, disable it. */ | /* If UFS host controller is already enabled, disable it. */ | ||||
| if (UFSHCIV(UFSHCI_HCE_REG_HCE, hce)) { | if (UFSHCIV(UFSHCI_HCE_REG_HCE, hce)) { | ||||
| hce &= ~UFSHCIM(UFSHCI_HCE_REG_HCE); | hce &= ~UFSHCIM(UFSHCI_HCE_REG_HCE); | ||||
| ufshci_mmio_write_4(ctrlr, hce, hce); | ufshci_mmio_write_4(ctrlr, hce, hce); | ||||
| } | } | ||||
| /* Wait for the HCE flag to change */ | |||||
| while (1) { | |||||
| hce = ufshci_mmio_read_4(ctrlr, hce); | |||||
| if (!UFSHCIV(UFSHCI_HCE_REG_HCE, hce)) | |||||
| break; | |||||
| if (timeout - ticks < 0) { | |||||
| ufshci_printf(ctrlr, | |||||
| "host controller failed to disable " | |||||
| "within %d ms\n", | |||||
| ctrlr->device_init_timeout_in_ms); | |||||
| return (ENXIO); | |||||
| } | |||||
| pause_sbt("ufshci_disable_hce", delta_t, 0, C_PREL(1)); | |||||
| delta_t = min(SBT_1MS, delta_t * 3 / 2); | |||||
| } | |||||
| return (0); | |||||
| } | |||||
| static int | |||||
| ufshci_ctrlr_enable_host_ctrlr(struct ufshci_controller *ctrlr) | |||||
| { | |||||
| int timeout = ticks + MSEC_2_TICKS(ctrlr->device_init_timeout_in_ms); | |||||
| sbintime_t delta_t = SBT_1US; | |||||
| uint32_t hce; | |||||
| hce = ufshci_mmio_read_4(ctrlr, hce); | |||||
| /* Enable UFS host controller */ | /* Enable UFS host controller */ | ||||
| hce |= UFSHCIM(UFSHCI_HCE_REG_HCE); | hce |= UFSHCIM(UFSHCI_HCE_REG_HCE); | ||||
| ufshci_mmio_write_4(ctrlr, hce, hce); | ufshci_mmio_write_4(ctrlr, hce, hce); | ||||
| /* | /* | ||||
| * During the controller initialization, the value of the HCE bit is | * During the controller initialization, the value of the HCE bit is | ||||
| * unstable, so we need to read the HCE value after some time after | * unstable, so we need to read the HCE value after some time after | ||||
| * initialization is complete. | * initialization is complete. | ||||
| */ | */ | ||||
| pause_sbt("ufshci_hce", ustosbt(100), 0, C_PREL(1)); | pause_sbt("ufshci_enable_hce", ustosbt(100), 0, C_PREL(1)); | ||||
| /* Wait for the HCE flag to change */ | /* Wait for the HCE flag to change */ | ||||
| while (1) { | while (1) { | ||||
| hce = ufshci_mmio_read_4(ctrlr, hce); | hce = ufshci_mmio_read_4(ctrlr, hce); | ||||
| if (UFSHCIV(UFSHCI_HCE_REG_HCE, hce)) | if (UFSHCIV(UFSHCI_HCE_REG_HCE, hce)) | ||||
| break; | break; | ||||
| if (timeout - ticks < 0) { | if (timeout - ticks < 0) { | ||||
| ufshci_printf(ctrlr, | ufshci_printf(ctrlr, | ||||
| "host controller failed to enable " | "host controller failed to enable " | ||||
| "within %d ms\n", | "within %d ms\n", | ||||
| ctrlr->device_init_timeout_in_ms); | ctrlr->device_init_timeout_in_ms); | ||||
| return (ENXIO); | return (ENXIO); | ||||
| } | } | ||||
| pause_sbt("ufshci_hce", delta_t, 0, C_PREL(1)); | pause_sbt("ufshci_enable_hce", delta_t, 0, C_PREL(1)); | ||||
| delta_t = min(SBT_1MS, delta_t * 3 / 2); | delta_t = min(SBT_1MS, delta_t * 3 / 2); | ||||
| } | } | ||||
| return (0); | return (0); | ||||
| } | } | ||||
| static int | |||||
| ufshci_ctrlr_disable(struct ufshci_controller *ctrlr) | |||||
| { | |||||
| int error; | |||||
| /* Disable all interrupts */ | |||||
| ufshci_mmio_write_4(ctrlr, ie, 0); | |||||
| error = ufshci_ctrlr_disable_host_ctrlr(ctrlr); | |||||
| return (error); | |||||
| } | |||||
| static int | |||||
| ufshci_ctrlr_enable(struct ufshci_controller *ctrlr) | |||||
Done Inline ActionsThis function is an extracted part of the ufshci_ctrlr_construct() function. (lines 120, 137) jaeyoon: This function is an extracted part of the ufshci_ctrlr_construct() function. (lines 120, 137) | |||||
| { | |||||
| uint32_t ie, hcs; | |||||
| int error; | |||||
| error = ufshci_ctrlr_enable_host_ctrlr(ctrlr); | |||||
| if (error) | |||||
| return (error); | |||||
| /* Send DME_LINKSTARTUP command to start the link startup procedure */ | |||||
| error = ufshci_uic_send_dme_link_startup(ctrlr); | |||||
| if (error) | |||||
| return (error); | |||||
| /* | |||||
| * The device_present(UFSHCI_HCS_REG_DP) bit becomes true if the host | |||||
| * controller has successfully received a Link Startup UIC command | |||||
| * response and the UFS device has found a physical link to the | |||||
| * controller. | |||||
| */ | |||||
| hcs = ufshci_mmio_read_4(ctrlr, hcs); | |||||
| if (!UFSHCIV(UFSHCI_HCS_REG_DP, hcs)) { | |||||
| ufshci_printf(ctrlr, "UFS device not found\n"); | |||||
| return (ENXIO); | |||||
| } | |||||
| /* Enable additional interrupts by programming the IE register. */ | |||||
| ie = ufshci_mmio_read_4(ctrlr, ie); | |||||
| ie |= UFSHCIM(UFSHCI_IE_REG_UTRCE); /* UTR Completion */ | |||||
| ie |= UFSHCIM(UFSHCI_IE_REG_UEE); /* UIC Error */ | |||||
| ie |= UFSHCIM(UFSHCI_IE_REG_UTMRCE); /* UTMR Completion */ | |||||
| ie |= UFSHCIM(UFSHCI_IE_REG_DFEE); /* Device Fatal Error */ | |||||
| ie |= UFSHCIM(UFSHCI_IE_REG_UTPEE); /* UTP Error */ | |||||
| ie |= UFSHCIM(UFSHCI_IE_REG_HCFEE); /* Host Ctrlr Fatal Error */ | |||||
| ie |= UFSHCIM(UFSHCI_IE_REG_SBFEE); /* System Bus Fatal Error */ | |||||
| ie |= UFSHCIM(UFSHCI_IE_REG_CEFEE); /* Crypto Engine Fatal Error */ | |||||
| ufshci_mmio_write_4(ctrlr, ie, ie); | |||||
| /* TODO: Initialize interrupt Aggregation Control Register (UTRIACR) */ | |||||
| return (0); | |||||
| } | |||||
| static int | |||||
| ufshci_ctrlr_hw_reset(struct ufshci_controller *ctrlr) | |||||
| { | |||||
| int error; | |||||
| error = ufshci_ctrlr_disable(ctrlr); | |||||
| if (error) | |||||
| return (error); | |||||
| error = ufshci_ctrlr_enable(ctrlr); | |||||
| return (error); | |||||
| } | |||||
| static void | |||||
| ufshci_ctrlr_reset_task(void *arg, int pending) | |||||
| { | |||||
| struct ufshci_controller *ctrlr = arg; | |||||
| int error; | |||||
| /* Release resources */ | |||||
| ufshci_utmr_req_queue_disable(ctrlr); | |||||
| ufshci_utr_req_queue_disable(ctrlr); | |||||
| error = ufshci_ctrlr_hw_reset(ctrlr); | |||||
| if (error) | |||||
| return (ufshci_ctrlr_fail(ctrlr)); | |||||
| ufshci_ctrlr_start(ctrlr, true); | |||||
| } | |||||
| int | int | ||||
| ufshci_ctrlr_construct(struct ufshci_controller *ctrlr, device_t dev) | ufshci_ctrlr_construct(struct ufshci_controller *ctrlr, device_t dev) | ||||
| { | { | ||||
| uint32_t ver, cap, hcs, ie, ahit; | uint32_t ver, cap, ahit; | ||||
| uint32_t timeout_period, retry_count; | uint32_t timeout_period, retry_count; | ||||
| int error; | int error; | ||||
| ctrlr->device_init_timeout_in_ms = UFSHCI_DEVICE_INIT_TIMEOUT_MS; | ctrlr->device_init_timeout_in_ms = UFSHCI_DEVICE_INIT_TIMEOUT_MS; | ||||
| ctrlr->uic_cmd_timeout_in_ms = UFSHCI_UIC_CMD_TIMEOUT_MS; | ctrlr->uic_cmd_timeout_in_ms = UFSHCI_UIC_CMD_TIMEOUT_MS; | ||||
| ctrlr->dev = dev; | ctrlr->dev = dev; | ||||
| ctrlr->sc_unit = device_get_unit(dev); | ctrlr->sc_unit = device_get_unit(dev); | ||||
| Show All 36 Lines | ufshci_ctrlr_construct(struct ufshci_controller *ctrlr, device_t dev) | ||||
| timeout_period = min(timeout_period, UFSHCI_MAX_TIMEOUT_PERIOD); | timeout_period = min(timeout_period, UFSHCI_MAX_TIMEOUT_PERIOD); | ||||
| timeout_period = max(timeout_period, UFSHCI_MIN_TIMEOUT_PERIOD); | timeout_period = max(timeout_period, UFSHCI_MIN_TIMEOUT_PERIOD); | ||||
| ctrlr->timeout_period = timeout_period; | ctrlr->timeout_period = timeout_period; | ||||
| retry_count = UFSHCI_DEFAULT_RETRY_COUNT; | retry_count = UFSHCI_DEFAULT_RETRY_COUNT; | ||||
| TUNABLE_INT_FETCH("hw.ufshci.retry_count", &retry_count); | TUNABLE_INT_FETCH("hw.ufshci.retry_count", &retry_count); | ||||
| ctrlr->retry_count = retry_count; | ctrlr->retry_count = retry_count; | ||||
| /* Disable all interrupts */ | ctrlr->enable_aborts = 1; | ||||
| ufshci_mmio_write_4(ctrlr, ie, 0); | if (ctrlr->quirks & UFSHCI_QUIRK_NOT_SUPPORT_ABORT_TASK) | ||||
| ctrlr->enable_aborts = 0; | |||||
| else | |||||
| TUNABLE_INT_FETCH("hw.ufshci.enable_aborts", | |||||
| &ctrlr->enable_aborts); | |||||
| /* Enable Host Controller */ | /* Reset the UFSHCI controller */ | ||||
| error = ufshci_ctrlr_enable_host_ctrlr(ctrlr); | error = ufshci_ctrlr_hw_reset(ctrlr); | ||||
| if (error) | if (error) | ||||
| return (error); | return (error); | ||||
| /* Send DME_LINKSTARTUP command to start the link startup procedure */ | |||||
| error = ufshci_uic_send_dme_link_startup(ctrlr); | |||||
| if (error) | |||||
| return (error); | |||||
| /* Read the UECPA register to clear */ | /* Read the UECPA register to clear */ | ||||
| ufshci_mmio_read_4(ctrlr, uecpa); | ufshci_mmio_read_4(ctrlr, uecpa); | ||||
| /* Diable Auto-hibernate */ | /* Diable Auto-hibernate */ | ||||
| ahit = 0; | ahit = 0; | ||||
| ufshci_mmio_write_4(ctrlr, ahit, ahit); | ufshci_mmio_write_4(ctrlr, ahit, ahit); | ||||
| /* | |||||
| * The device_present(UFSHCI_HCS_REG_DP) bit becomes true if the host | |||||
| * controller has successfully received a Link Startup UIC command | |||||
| * response and the UFS device has found a physical link to the | |||||
| * controller. | |||||
| */ | |||||
| hcs = ufshci_mmio_read_4(ctrlr, hcs); | |||||
| if (!UFSHCIV(UFSHCI_HCS_REG_DP, hcs)) { | |||||
| ufshci_printf(ctrlr, "UFS device not found\n"); | |||||
| return (ENXIO); | |||||
| } | |||||
| /* Allocate and initialize UTP Task Management Request List. */ | /* Allocate and initialize UTP Task Management Request List. */ | ||||
| error = ufshci_utmr_req_queue_construct(ctrlr); | error = ufshci_utmr_req_queue_construct(ctrlr); | ||||
| if (error) | if (error) | ||||
| return (error); | return (error); | ||||
| /* Allocate and initialize UTP Transfer Request List or SQ/CQ. */ | /* Allocate and initialize UTP Transfer Request List or SQ/CQ. */ | ||||
| error = ufshci_utr_req_queue_construct(ctrlr); | error = ufshci_utr_req_queue_construct(ctrlr); | ||||
| if (error) | if (error) | ||||
| return (error); | return (error); | ||||
| /* Enable additional interrupts by programming the IE register. */ | |||||
| ie = ufshci_mmio_read_4(ctrlr, ie); | |||||
| ie |= UFSHCIM(UFSHCI_IE_REG_UTRCE); /* UTR Completion */ | |||||
| ie |= UFSHCIM(UFSHCI_IE_REG_UEE); /* UIC Error */ | |||||
| ie |= UFSHCIM(UFSHCI_IE_REG_UTMRCE); /* UTMR Completion */ | |||||
| ie |= UFSHCIM(UFSHCI_IE_REG_DFEE); /* Device Fatal Error */ | |||||
| ie |= UFSHCIM(UFSHCI_IE_REG_UTPEE); /* UTP Error */ | |||||
| ie |= UFSHCIM(UFSHCI_IE_REG_HCFEE); /* Host Ctrlr Fatal Error */ | |||||
| ie |= UFSHCIM(UFSHCI_IE_REG_SBFEE); /* System Bus Fatal Error */ | |||||
| ie |= UFSHCIM(UFSHCI_IE_REG_CEFEE); /* Crypto Engine Fatal Error */ | |||||
| ufshci_mmio_write_4(ctrlr, ie, ie); | |||||
| /* TODO: Initialize interrupt Aggregation Control Register (UTRIACR) */ | |||||
| /* TODO: Separate IO and Admin slot */ | /* TODO: Separate IO and Admin slot */ | ||||
| /* | /* | ||||
| * max_hw_pend_io is the number of slots in the transfer_req_queue. | * max_hw_pend_io is the number of slots in the transfer_req_queue. | ||||
| * Reduce num_entries by one to reserve an admin slot. | * Reduce num_entries by one to reserve an admin slot. | ||||
| */ | */ | ||||
| ctrlr->max_hw_pend_io = ctrlr->transfer_req_queue.num_entries - 1; | ctrlr->max_hw_pend_io = ctrlr->transfer_req_queue.num_entries - 1; | ||||
| /* Create a thread for the taskqueue. */ | |||||
| ctrlr->taskqueue = taskqueue_create("ufshci_taskq", M_WAITOK, | |||||
| taskqueue_thread_enqueue, &ctrlr->taskqueue); | |||||
| taskqueue_start_threads(&ctrlr->taskqueue, 1, PI_DISK, "ufshci taskq"); | |||||
| TASK_INIT(&ctrlr->reset_task, 0, ufshci_ctrlr_reset_task, ctrlr); | |||||
| return (0); | return (0); | ||||
| } | } | ||||
| void | void | ||||
| ufshci_ctrlr_destruct(struct ufshci_controller *ctrlr, device_t dev) | ufshci_ctrlr_destruct(struct ufshci_controller *ctrlr, device_t dev) | ||||
| { | { | ||||
| if (ctrlr->resource == NULL) | if (ctrlr->resource == NULL) | ||||
| goto nores; | goto nores; | ||||
| Show All 15 Lines | ufshci_ctrlr_destruct(struct ufshci_controller *ctrlr, device_t dev) | ||||
| ufshci_sim_detach(ctrlr); | ufshci_sim_detach(ctrlr); | ||||
| mtx_unlock(&ctrlr->sc_mtx); | mtx_unlock(&ctrlr->sc_mtx); | ||||
| bus_release_resource(dev, SYS_RES_MEMORY, ctrlr->resource_id, | bus_release_resource(dev, SYS_RES_MEMORY, ctrlr->resource_id, | ||||
| ctrlr->resource); | ctrlr->resource); | ||||
| nores: | nores: | ||||
| KASSERT(!mtx_owned(&ctrlr->uic_cmd_lock), | |||||
| ("destroying uic_cmd_lock while still owned")); | |||||
| mtx_destroy(&ctrlr->uic_cmd_lock); | mtx_destroy(&ctrlr->uic_cmd_lock); | ||||
| KASSERT(!mtx_owned(&ctrlr->sc_mtx), | |||||
| ("destroying sc_mtx while still owned")); | |||||
| mtx_destroy(&ctrlr->sc_mtx); | mtx_destroy(&ctrlr->sc_mtx); | ||||
| return; | return; | ||||
| } | } | ||||
| int | void | ||||
| ufshci_ctrlr_reset(struct ufshci_controller *ctrlr) | ufshci_ctrlr_reset(struct ufshci_controller *ctrlr) | ||||
| { | { | ||||
| uint32_t ie; | taskqueue_enqueue(ctrlr->taskqueue, &ctrlr->reset_task); | ||||
| int error; | |||||
| /* Backup and disable all interrupts */ | |||||
| ie = ufshci_mmio_read_4(ctrlr, ie); | |||||
| ufshci_mmio_write_4(ctrlr, ie, 0); | |||||
| /* Release resources */ | |||||
| ufshci_utmr_req_queue_destroy(ctrlr); | |||||
| ufshci_utr_req_queue_destroy(ctrlr); | |||||
| /* Reset Host Controller */ | |||||
| error = ufshci_ctrlr_enable_host_ctrlr(ctrlr); | |||||
| if (error) | |||||
| return (error); | |||||
| /* Send DME_LINKSTARTUP command to start the link startup procedure */ | |||||
| error = ufshci_uic_send_dme_link_startup(ctrlr); | |||||
| if (error) | |||||
| return (error); | |||||
| /* Enable interrupts */ | |||||
| ufshci_mmio_write_4(ctrlr, ie, ie); | |||||
| /* Allocate and initialize UTP Task Management Request List. */ | |||||
| error = ufshci_utmr_req_queue_construct(ctrlr); | |||||
| if (error) | |||||
| return (error); | |||||
| /* Allocate and initialize UTP Transfer Request List or SQ/CQ. */ | |||||
| error = ufshci_utr_req_queue_construct(ctrlr); | |||||
| if (error) | |||||
| return (error); | |||||
| return (0); | |||||
| } | } | ||||
| int | int | ||||
| ufshci_ctrlr_submit_task_mgmt_request(struct ufshci_controller *ctrlr, | ufshci_ctrlr_submit_task_mgmt_request(struct ufshci_controller *ctrlr, | ||||
| struct ufshci_request *req) | struct ufshci_request *req) | ||||
| { | { | ||||
| return ( | return ( | ||||
| ufshci_req_queue_submit_request(&ctrlr->task_mgmt_req_queue, req, | ufshci_req_queue_submit_request(&ctrlr->task_mgmt_req_queue, req, | ||||
| Show All 27 Lines | ufshci_ctrlr_send_nop(struct ufshci_controller *ctrlr) | ||||
| if (status.error) { | if (status.error) { | ||||
| ufshci_printf(ctrlr, "ufshci_ctrlr_send_nop failed!\n"); | ufshci_printf(ctrlr, "ufshci_ctrlr_send_nop failed!\n"); | ||||
| return (ENXIO); | return (ENXIO); | ||||
| } | } | ||||
| return (0); | return (0); | ||||
| } | } | ||||
| static void | |||||
| ufshci_ctrlr_fail(struct ufshci_controller *ctrlr, bool admin_also) | |||||
| { | |||||
| printf("ufshci(4): ufshci_ctrlr_fail\n"); | |||||
| ctrlr->is_failed = true; | |||||
| /* TODO: task_mgmt_req_queue should be handled as fail */ | |||||
| ufshci_req_queue_fail(ctrlr, | |||||
| &ctrlr->transfer_req_queue.hwq[UFSHCI_SDB_Q]); | |||||
| } | |||||
| static void | |||||
| ufshci_ctrlr_start(struct ufshci_controller *ctrlr) | |||||
| { | |||||
| TSENTER(); | |||||
| if (ufshci_ctrlr_send_nop(ctrlr) != 0) { | |||||
| ufshci_ctrlr_fail(ctrlr, false); | |||||
| return; | |||||
| } | |||||
| /* Initialize UFS target drvice */ | |||||
| if (ufshci_dev_init(ctrlr) != 0) { | |||||
| ufshci_ctrlr_fail(ctrlr, false); | |||||
| return; | |||||
| } | |||||
| /* Initialize Reference Clock */ | |||||
| if (ufshci_dev_init_reference_clock(ctrlr) != 0) { | |||||
| ufshci_ctrlr_fail(ctrlr, false); | |||||
| return; | |||||
| } | |||||
| /* Initialize unipro */ | |||||
| if (ufshci_dev_init_unipro(ctrlr) != 0) { | |||||
| ufshci_ctrlr_fail(ctrlr, false); | |||||
| return; | |||||
| } | |||||
| /* | |||||
| * Initialize UIC Power Mode | |||||
| * QEMU UFS devices do not support unipro and power mode. | |||||
| */ | |||||
| if (!(ctrlr->quirks & UFSHCI_QUIRK_IGNORE_UIC_POWER_MODE) && | |||||
| ufshci_dev_init_uic_power_mode(ctrlr) != 0) { | |||||
| ufshci_ctrlr_fail(ctrlr, false); | |||||
| return; | |||||
| } | |||||
| /* Initialize UFS Power Mode */ | |||||
| if (ufshci_dev_init_ufs_power_mode(ctrlr) != 0) { | |||||
| ufshci_ctrlr_fail(ctrlr, false); | |||||
| return; | |||||
| } | |||||
| /* Read Controller Descriptor (Device, Geometry) */ | |||||
| if (ufshci_dev_get_descriptor(ctrlr) != 0) { | |||||
| ufshci_ctrlr_fail(ctrlr, false); | |||||
| return; | |||||
| } | |||||
| if (ufshci_dev_config_write_booster(ctrlr)) { | |||||
| ufshci_ctrlr_fail(ctrlr, false); | |||||
| return; | |||||
| } | |||||
| /* TODO: Configure Background Operations */ | |||||
| if (ufshci_sim_attach(ctrlr) != 0) { | |||||
| ufshci_ctrlr_fail(ctrlr, false); | |||||
| return; | |||||
| } | |||||
| TSEXIT(); | |||||
| } | |||||
| void | void | ||||
| ufshci_ctrlr_start_config_hook(void *arg) | ufshci_ctrlr_start_config_hook(void *arg) | ||||
| { | { | ||||
| struct ufshci_controller *ctrlr = arg; | struct ufshci_controller *ctrlr = arg; | ||||
| TSENTER(); | TSENTER(); | ||||
| if (ufshci_utmr_req_queue_enable(ctrlr) == 0 && | if (ufshci_utmr_req_queue_enable(ctrlr) == 0 && | ||||
| ufshci_utr_req_queue_enable(ctrlr) == 0) | ufshci_utr_req_queue_enable(ctrlr) == 0) | ||||
| ufshci_ctrlr_start(ctrlr); | ufshci_ctrlr_start(ctrlr, false); | ||||
| else | else | ||||
| ufshci_ctrlr_fail(ctrlr, false); | ufshci_ctrlr_fail(ctrlr); | ||||
| ufshci_sysctl_initialize_ctrlr(ctrlr); | ufshci_sysctl_initialize_ctrlr(ctrlr); | ||||
| config_intrhook_disestablish(&ctrlr->config_hook); | config_intrhook_disestablish(&ctrlr->config_hook); | ||||
| TSEXIT(); | TSEXIT(); | ||||
| } | } | ||||
| /* | /* | ||||
| ▲ Show 20 Lines • Show All 128 Lines • Show Last 20 Lines | |||||
This function was moved here from line 299.