From nobody Tue Oct 06 07:50:48 2026 X-Original-To: dev-commits-src-branches@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4hzT2c338Xz6cVsB for ; Tue, 06 Oct 2026 07:50:48 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "YR2" (not verified)) by mx1.freebsd.org (Postfix) with ESMTPS id 4hzT2c1S0pz4G1S for ; Tue, 06 Oct 2026 07:50:48 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1791273048; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=L2cLFl1/wfZDaRCNpm/tZ+MIncnxtewHm35oI2/K41k=; b=Z2h05I6ykPDp9e5QxZftBgi4DrlEM94ey2K0ExcD/zY/8vDC1RWZOreYi9l9GrPA+mmdK5 13Ta12ytcWuvrKhP67RzLids6OglFBMxuIKPCZoVnTqFPFkWVqmoiYutEyFv473TYQVg6y MrxvKGELK3x8lty+uzo0phmp+Ev0SjKH2vTlh76GzUVBmfRNgOlBoKzelccki2S0uAZqwa Ds+N/+7wBuufAjmLyWK8R82EYrWw21V4vr3sxYngNgNl6VoFQ34GuecaMY1vEvI2d/sWKi UqS26nB7CN77FiqMPkcKagv5+ySz1qb6fL7gsoJi3UNivVVITBuRTxBtCQKZtw== ARC-Seal: i=1; a=rsa-sha256; d=freebsd.org; s=dkim; cv=none; t=1791273048; b=vrTuNdHqRaWuUvOtq0PylWdTk/+nkL/tSExuUkVeR99tEuKUYMNZWI/hmXY4b4fzFIdCQc E5UYrqszjb5fWlWdNoFbXi0u/maOnlLeKRRN3DyNWkeYimxHMhF3MilTVCKF+/3n2Zbp9q 65tRl+aladnE/I4GSHhl7bEbU4+nzbdkHMgX9ydoafcyHgGPuqU7vibFAP4hzF6bvVsroc egvp+eF7yd2Y4FfK+TS59nrkJieI0eTs69tqeYgvkKW4k2k2z4mou2ODgEpCxc0hbtT1+s vp46UX8GNbhwcvdP2jSvQ6rtH8ZKQppRSvYa+1iev43UmAE4JEwbZXv9YGVEYg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1791273048; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=L2cLFl1/wfZDaRCNpm/tZ+MIncnxtewHm35oI2/K41k=; b=Wze0HtqchYOb+axTmMtgAhGb5uIY53vV6z7UCLqFjR+e1jmrg+37i7B6VRXA2aOSSMefc8 E1DHgyyQVvFYg241ULDnUzjJVcSv3vW+yuRa/bEoggfpyVCKZTkcNdbYFqKLUF4jamUU7y my072GOHsy8hi+mdSnPcuQ/8GMupbWOKvG7DgphzvIKddZzAPl3bJVxPgX8J24s/VIpxQ8 /a7m2wyMoIjguA4vwK569jfobHENA/7dxgmuAzo8AEs7pIK/JxO/fqthOEKhLZYNGIK3aJ vbTeIqzqBiiPO1f5Artio6COQnYK85NiyOXoUPgo5xTqZZ1YuhiwBqRe5Z+vzw== ARC-Authentication-Results: i=1; mx1.freebsd.org; none Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4hzT2c0GR0zwyt for ; Tue, 06 Oct 2026 07:50:48 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 18721 by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Tue, 06 Oct 2026 07:50:48 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: Jaeyoon Choi Subject: git: 1b063270950c - stable/15 - ufshci: Support suspend/resume List-Id: Commits to the stable branches of the FreeBSD src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-branches List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-branches@freebsd.org Sender: owner-dev-commits-src-branches@FreeBSD.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: jaeyoon X-Git-Repository: src X-Git-Refname: refs/heads/stable/15 X-Git-Reftype: branch X-Git-Commit: 1b063270950c4b444f156d54619c6740271f96ef Auto-Submitted: auto-generated Date: Tue, 06 Oct 2026 07:50:48 +0000 Message-Id: <6ac4a858.18721.dbf2b12@gitrepo.freebsd.org> The branch stable/15 has been updated by jaeyoon: URL: https://cgit.FreeBSD.org/src/commit/?id=1b063270950c4b444f156d54619c6740271f96ef commit 1b063270950c4b444f156d54619c6740271f96ef Author: Jaeyoon Choi AuthorDate: 2025-12-03 04:05:36 +0000 Commit: Jaeyoon Choi CommitDate: 2026-10-06 06:27:48 +0000 ufshci: Support suspend/resume Handle system power events and issue START STOP UNIT (SSU) to the UFS Device WLUN (0x50). Reviewed by: imp (mentor) Sponsored by: Samsung Electronics Differential Revision: https://reviews.freebsd.org/D54002 (cherry picked from commit 3a99f31fdb6c66434f77d83ca5166aae4ad2d22c) --- sys/dev/ufshci/ufshci_ctrlr.c | 50 +++++++++++++++++++++++++++++++++++++++ sys/dev/ufshci/ufshci_dev.c | 19 +++++++++++++++ sys/dev/ufshci/ufshci_pci.c | 22 ++++++++++++++++- sys/dev/ufshci/ufshci_private.h | 35 ++++++++++++++++++++++++++- sys/dev/ufshci/ufshci_req_queue.c | 3 ++- sys/dev/ufshci/ufshci_sim.c | 7 +++++- sys/dev/ufshci/ufshci_sysctl.c | 3 +++ 7 files changed, 135 insertions(+), 4 deletions(-) diff --git a/sys/dev/ufshci/ufshci_ctrlr.c b/sys/dev/ufshci/ufshci_ctrlr.c index 7c225423c266..6bdee85142a0 100644 --- a/sys/dev/ufshci/ufshci_ctrlr.c +++ b/sys/dev/ufshci/ufshci_ctrlr.c @@ -610,3 +610,53 @@ ufshci_reg_dump(struct ufshci_controller *ctrlr) ufshci_printf(ctrlr, "========================================\n"); } + +int +ufshci_ctrlr_suspend(struct ufshci_controller *ctrlr, enum power_stype stype) +{ + int error; + + if (!ctrlr->ufs_dev.power_mode_supported) + return (0); + + /* TODO: Need to flush the request queue */ + + if (ctrlr->ufs_device_wlun_periph) { + ctrlr->ufs_dev.power_mode = power_map[stype].dev_pwr; + error = ufshci_sim_send_ssu(ctrlr, /*start*/ false, + power_map[stype].ssu_pc, /*immed*/ false); + if (error) { + ufshci_printf(ctrlr, + "Failed to send SSU in suspend handler\n"); + return (error); + } + } + + /* TODO: Change the link state to Hibernate if necessary. */ + + return (0); +} + +int +ufshci_ctrlr_resume(struct ufshci_controller *ctrlr, enum power_stype stype) +{ + int error; + + if (!ctrlr->ufs_dev.power_mode_supported) + return (0); + + /* TODO: Change the link state to Active if necessary. */ + + if (ctrlr->ufs_device_wlun_periph) { + ctrlr->ufs_dev.power_mode = power_map[stype].dev_pwr; + error = ufshci_sim_send_ssu(ctrlr, /*start*/ false, + power_map[stype].ssu_pc, /*immed*/ false); + if (error) { + ufshci_printf(ctrlr, + "Failed to send SSU in resume handler\n"); + return (error); + } + } + + return (0); +} diff --git a/sys/dev/ufshci/ufshci_dev.c b/sys/dev/ufshci/ufshci_dev.c index 9696e8ea8091..136823523fd3 100644 --- a/sys/dev/ufshci/ufshci_dev.c +++ b/sys/dev/ufshci/ufshci_dev.c @@ -469,6 +469,8 @@ ufshci_dev_init_ufs_power_mode(struct ufshci_controller *ctrlr) } ctrlr->ufs_dev.power_mode_supported = true; + ctrlr->ufs_dev.power_mode = UFSHCI_DEV_PWR_ACTIVE; + return (0); } @@ -786,3 +788,20 @@ out: ufshci_dev_disable_write_booster(ctrlr); return (error); } + +int +ufshci_dev_get_current_power_mode(struct ufshci_controller *ctrlr, + uint8_t *power_mode) +{ + uint64_t value; + int err; + + err = ufshci_dev_read_attribute(ctrlr, UFSHCI_ATTR_B_CURRENT_POWER_MODE, + /*index*/ 0, /*selector*/ 0, &value); + if (err) + return (err); + + *power_mode = (uint8_t)value; + + return (0); +} diff --git a/sys/dev/ufshci/ufshci_pci.c b/sys/dev/ufshci/ufshci_pci.c index 756ac6540632..d4ba05e1a37d 100644 --- a/sys/dev/ufshci/ufshci_pci.c +++ b/sys/dev/ufshci/ufshci_pci.c @@ -23,6 +23,8 @@ static int ufshci_pci_probe(device_t); static int ufshci_pci_attach(device_t); static int ufshci_pci_detach(device_t); +static int ufshci_pci_suspend(device_t); +static int ufshci_pci_resume(device_t); static int ufshci_pci_setup_interrupts(struct ufshci_controller *ctrlr); @@ -31,7 +33,8 @@ static device_method_t ufshci_pci_methods[] = { DEVMETHOD(device_probe, ufshci_pci_probe), DEVMETHOD(device_attach, ufshci_pci_attach), DEVMETHOD(device_detach, ufshci_pci_detach), - /* TODO: Implement Suspend, Resume */ + DEVMETHOD(device_suspend, ufshci_pci_suspend), + DEVMETHOD(device_resume, ufshci_pci_resume), DEVMETHOD_END }; @@ -261,3 +264,20 @@ msi: intx: return (ufshci_pci_setup_shared(ctrlr, ctrlr->msi_count > 0 ? 1 : 0)); } + +static int +ufshci_pci_suspend(device_t dev) +{ + struct ufshci_controller *ctrlr = device_get_softc(dev); + + /* Currently, PCI-based ufshci only supports POWER_STYPE_STANDBY */ + return (ufshci_ctrlr_suspend(ctrlr, POWER_STYPE_STANDBY)); +} + +static int +ufshci_pci_resume(device_t dev) +{ + struct ufshci_controller *ctrlr = device_get_softc(dev); + + return (ufshci_ctrlr_resume(ctrlr, POWER_STYPE_AWAKE)); +} diff --git a/sys/dev/ufshci/ufshci_private.h b/sys/dev/ufshci/ufshci_private.h index 5ded8777753d..07e29e8ea73e 100644 --- a/sys/dev/ufshci/ufshci_private.h +++ b/sys/dev/ufshci/ufshci_private.h @@ -26,12 +26,14 @@ #include #include #include +#include #include #include #include #include +#include #include "ufshci.h" @@ -247,6 +249,30 @@ struct ufshci_req_queue { bus_dmamap_t ucdmem_map; }; +enum ufshci_dev_pwr { + UFSHCI_DEV_PWR_ACTIVE = 0, + UFSHCI_DEV_PWR_SLEEP, + UFSHCI_DEV_PWR_POWERDOWN, + UFSHCI_DEV_PWR_DEEPSLEEP, + UFSHCI_DEV_PWR_COUNT, +}; + +struct ufshci_power_entry { + enum ufshci_dev_pwr dev_pwr; + uint8_t ssu_pc; /* SSU Power Condition */ +}; + +/* SSU Power Condition 0x40 is defined in the UFS specification */ +static const struct ufshci_power_entry power_map[POWER_STYPE_COUNT] = { + [POWER_STYPE_AWAKE] = { UFSHCI_DEV_PWR_ACTIVE, SSS_PC_ACTIVE }, + [POWER_STYPE_STANDBY] = { UFSHCI_DEV_PWR_SLEEP, SSS_PC_IDLE }, + [POWER_STYPE_SUSPEND_TO_MEM] = { UFSHCI_DEV_PWR_POWERDOWN, + SSS_PC_STANDBY }, + [POWER_STYPE_SUSPEND_TO_IDLE] = { UFSHCI_DEV_PWR_SLEEP, SSS_PC_IDLE }, + [POWER_STYPE_HIBERNATE] = { UFSHCI_DEV_PWR_DEEPSLEEP, 0x40 }, + [POWER_STYPE_POWEROFF] = { UFSHCI_DEV_PWR_POWERDOWN, SSS_PC_STANDBY }, +}; + struct ufshci_device { uint32_t max_lun_count; @@ -266,6 +292,7 @@ struct ufshci_device { /* Power mode */ bool power_mode_supported; + enum ufshci_dev_pwr power_mode; }; /* @@ -400,12 +427,16 @@ void ufshci_sim_detach(struct ufshci_controller *ctrlr); struct cam_periph *ufshci_sim_find_periph(struct ufshci_controller *ctrlr, uint8_t wlun); int ufshci_sim_send_ssu(struct ufshci_controller *ctrlr, bool start, - int pwr_cond, bool immed); + uint8_t pwr_cond, bool immed); /* Controller */ int ufshci_ctrlr_construct(struct ufshci_controller *ctrlr, device_t dev); void ufshci_ctrlr_destruct(struct ufshci_controller *ctrlr, device_t dev); void ufshci_ctrlr_reset(struct ufshci_controller *ctrlr); +int ufshci_ctrlr_suspend(struct ufshci_controller *ctrlr, + enum power_stype stype); +int ufshci_ctrlr_resume(struct ufshci_controller *ctrlr, + enum power_stype stype); /* ctrlr defined as void * to allow use with config_intrhook. */ void ufshci_ctrlr_start_config_hook(void *arg); void ufshci_ctrlr_poll(struct ufshci_controller *ctrlr); @@ -429,6 +460,8 @@ int ufshci_dev_init_uic_power_mode(struct ufshci_controller *ctrlr); int ufshci_dev_init_ufs_power_mode(struct ufshci_controller *ctrlr); int ufshci_dev_get_descriptor(struct ufshci_controller *ctrlr); int ufshci_dev_config_write_booster(struct ufshci_controller *ctrlr); +int ufshci_dev_get_current_power_mode(struct ufshci_controller *ctrlr, + uint8_t *power_mode); /* Controller Command */ void ufshci_ctrlr_cmd_send_task_mgmt_request(struct ufshci_controller *ctrlr, diff --git a/sys/dev/ufshci/ufshci_req_queue.c b/sys/dev/ufshci/ufshci_req_queue.c index 7aa164d00bec..df7e4b159278 100644 --- a/sys/dev/ufshci/ufshci_req_queue.c +++ b/sys/dev/ufshci/ufshci_req_queue.c @@ -147,7 +147,8 @@ ufshci_req_queue_response_is_error(struct ufshci_req_queue *req_queue, /* Check response UPIU header */ if (response->header.response != UFSHCI_RESPONSE_CODE_TARGET_SUCCESS) { ufshci_printf(req_queue->ctrlr, - "Invalid response code = 0x%x\n", + "Function(0x%x) Invalid response code = 0x%x\n", + response->header.ext_iid_or_function, response->header.response); is_error = true; } diff --git a/sys/dev/ufshci/ufshci_sim.c b/sys/dev/ufshci/ufshci_sim.c index 0cd691de47e2..1589e7475ad4 100644 --- a/sys/dev/ufshci/ufshci_sim.c +++ b/sys/dev/ufshci/ufshci_sim.c @@ -46,6 +46,11 @@ ufshci_sim_scsiio_done(void *ccb_arg, const struct ufshci_completion *cpl, ccb->ccb_h.status &= ~CAM_SIM_QUEUED; if (error) { + printf("ufshci: SCSI command completion error, Status(0x%x)" + " Key(0x%x), ASC(0x%x), ASCQ(0x%x)\n", + cpl->response_upiu.cmd_response_upiu.header + .ext_iid_or_status, + sense_data[2], sense_data[12], sense_data[13]); ccb->ccb_h.status = CAM_REQ_CMP_ERR; xpt_done(ccb); } else { @@ -455,7 +460,7 @@ ufshci_sim_find_periph(struct ufshci_controller *ctrlr, uint8_t wlun) /* This function is called during suspend/resume. */ int ufshci_sim_send_ssu(struct ufshci_controller *ctrlr, bool start, - int power_condition, bool immed) + uint8_t power_condition, bool immed) { struct cam_periph *periph = ctrlr->ufs_device_wlun_periph; union ccb *ccb; diff --git a/sys/dev/ufshci/ufshci_sysctl.c b/sys/dev/ufshci/ufshci_sysctl.c index 3ec4ea935464..30b0ccaeed13 100644 --- a/sys/dev/ufshci/ufshci_sysctl.c +++ b/sys/dev/ufshci/ufshci_sysctl.c @@ -201,6 +201,9 @@ ufshci_sysctl_initialize_ctrlr(struct ufshci_controller *ctrlr) CTLFLAG_RD, &dev->power_mode_supported, 0, "Device power mode support"); + SYSCTL_ADD_UINT(ctrlr_ctx, ctrlr_list, OID_AUTO, "power_mode", + CTLFLAG_RD, &dev->power_mode, 0, "Current device power mode"); + SYSCTL_ADD_PROC(ctrlr_ctx, ctrlr_list, OID_AUTO, "timeout_period", CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_MPSAFE, &ctrlr->timeout_period, 0, ufshci_sysctl_timeout_period, "IU",