From nobody Wed Mar 25 04:46:56 2026 X-Original-To: dev-commits-src-main@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 4fgZBS5BxTz6WhxM for ; Wed, 25 Mar 2026 04:46:56 +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 "R12" (not verified)) by mx1.freebsd.org (Postfix) with ESMTPS id 4fgZBS32ZMz3mGS for ; Wed, 25 Mar 2026 04:46:56 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1774414016; 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=qUzQ0IPbVbhT9oVOS/OCeDBNszyOYmsZMmatc46FhZI=; b=h2QpYeSLmcHxyNvEYPfW4CxQ3OL2E2e9bHybEtBICmMn8ah4U6bAgQUrGYe6UqaLIRc+x6 wmjQDYUkQZyRh4grmIOz1ER6mbRiOmVMkk094W0RyqcfXGDbw6mL08cqmcOaRZCauglMHp 63A+4e2tS013aHf6rq1SshJ29ZtE+h/jMdK3eCFMuwK2LXREGbUXurrjQ3WwouHl2t0jav E2d94RU4FRFr8TUNYEb/V/2eJ9xYWM2oSi7GGfdcCxmTzMEohOhyGBJLlU86Mp7fT3ZAyP yLBmMLRQFAB2Z7uR736d90xTU2bYM2IeLCv2055dI84RkZhIaizlHUXxaei/Ig== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1774414016; a=rsa-sha256; cv=none; b=mWITNx2Wp65Yv5K4PRDOQdKs1HWF3ZN1YBNFKxwm7H+/3QJh8GQS5pZ4EFqp4P8H3p+DGW U8e/6sl4/N1aNOeJwVk36knRAUXF4TriU4BcyAEXOCKR8grpE8d3EaJRWHGIHkwkie4idV EUpZ6IGBIbMWlFNUiAHz/M7Ag8pPX6FCRsBg5M5nUS5X9qMWQ5CWo+uuVEsLw4IitzgIKl /cqL4If8mQ+rIBN09wzcr3QPLTLbnZXCn9mmpEZhyiAp9qAD3EPwPWye4ol4kqy0QxeWa5 UXhHjuCxdu/zuYyHV0Y9Wz/7GrctD43a9rBjXLER3up4jCqoBiFHTa3xT1K7qw== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1774414016; 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=qUzQ0IPbVbhT9oVOS/OCeDBNszyOYmsZMmatc46FhZI=; b=bwTI9bJi7IdRZRPdzG7lRcWe4eHrzh3ID200m3/4DHpnA/oZIkPCnydnNV2Yzt4+NHTv86 cVFeVr0FpNSP/6O2+wr3VAZdYIsJxn+mJFWW+D4U2NMouOmBh03K55gMxfe4KAdNfgp4UP Fw/zJLb6u2YKx301nfemsqEyLYk+l7O+lnItPp9C3EiWXNvbKoIHyadeWYJXLGEA38CnwG W5Yrsyh1d3m/t3HzrQAHQ/bZmn2RVq/iAPK39SxH0M6nDCtoyUbALovbpm+8yiQ305eh2q pp3i5IKDWnzqFkJuXWMOFfihuWfPmzciZUj6szJRqGvI0q8iCybjCcpF5nX8hA== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4fgZBS2MwWzqgd for ; Wed, 25 Mar 2026 04:46:56 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 382cc by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Wed, 25 Mar 2026 04:46:56 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Jaeyoon Choi Subject: git: e2083e8d3a01 - main - ufshci: Support ACPI List-Id: Commit messages for the main branch of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-main@freebsd.org Sender: owner-dev-commits-src-main@FreeBSD.org 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/main X-Git-Reftype: branch X-Git-Commit: e2083e8d3a01cac739b38521abc72620d3810aba Auto-Submitted: auto-generated Date: Wed, 25 Mar 2026 04:46:56 +0000 Message-Id: <69c368c0.382cc.15737923@gitrepo.freebsd.org> The branch main has been updated by jaeyoon: URL: https://cgit.FreeBSD.org/src/commit/?id=e2083e8d3a01cac739b38521abc72620d3810aba commit e2083e8d3a01cac739b38521abc72620d3810aba Author: Jaeyoon Choi AuthorDate: 2026-03-24 05:16:26 +0000 Commit: Jaeyoon Choi CommitDate: 2026-03-24 16:45:34 +0000 ufshci: Support ACPI Supports UFS host controller attachment via ACPI. Tested on the Samsung Galaxy Book 4 Edge using Qualcomm Snapdragon X Elite. Additionally, a quirk related to power mode change has been added. For reference, it doesn't reach maximum speed yet. I plan to improve it later. Sponsored by: Samsung Electronics Reviewed by: imp (mentor) Differential Revision: https://reviews.freebsd.org/D55986 --- sys/conf/files | 3 +- sys/dev/ufshci/ufshci_acpi.c | 248 ++++++++++++++++++++++++++++++++++++++++ sys/dev/ufshci/ufshci_ctrlr.c | 71 ++++++++++-- sys/dev/ufshci/ufshci_private.h | 12 +- sys/modules/ufshci/Makefile | 3 + 5 files changed, 324 insertions(+), 13 deletions(-) diff --git a/sys/conf/files b/sys/conf/files index 5fc84f911e19..269f9387ec08 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -3285,10 +3285,11 @@ dev/uart/uart_tty.c optional uart # Universal Flash Storage Host Controller Interface drivers # dev/ufshci/ufshci.c optional ufshci +dev/ufshci/ufshci_acpi.c optional ufshci acpi dev/ufshci/ufshci_ctrlr.c optional ufshci dev/ufshci/ufshci_ctrlr_cmd.c optional ufshci dev/ufshci/ufshci_dev.c optional ufshci -dev/ufshci/ufshci_pci.c optional ufshci +dev/ufshci/ufshci_pci.c optional ufshci pci dev/ufshci/ufshci_req_queue.c optional ufshci dev/ufshci/ufshci_req_sdb.c optional ufshci dev/ufshci/ufshci_sim.c optional ufshci diff --git a/sys/dev/ufshci/ufshci_acpi.c b/sys/dev/ufshci/ufshci_acpi.c new file mode 100644 index 000000000000..94da0d3cb411 --- /dev/null +++ b/sys/dev/ufshci/ufshci_acpi.c @@ -0,0 +1,248 @@ +/*- + * Copyright (c) 2026, Samsung Electronics Co., Ltd. + * Written by Jaeyoon Choi + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include + +#include "ufshci_private.h" + +static int ufshci_acpi_probe(device_t); +static int ufshci_acpi_attach(device_t); +static int ufshci_acpi_detach(device_t); +static int ufshci_acpi_suspend(device_t); +static int ufshci_acpi_resume(device_t); + +static device_method_t ufshci_acpi_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, ufshci_acpi_probe), + DEVMETHOD(device_attach, ufshci_acpi_attach), + DEVMETHOD(device_detach, ufshci_acpi_detach), + DEVMETHOD(device_suspend, ufshci_acpi_suspend), + DEVMETHOD(device_resume, ufshci_acpi_resume), { 0, 0 } +}; + +static driver_t ufshci_acpi_driver = { + "ufshci", + ufshci_acpi_methods, + sizeof(struct ufshci_controller), +}; + +DRIVER_MODULE(ufshci, acpi, ufshci_acpi_driver, 0, 0); +MODULE_DEPEND(ufshci, acpi, 1, 1, 1); + +static struct ufshci_acpi_device { + const char *hid; + const char *desc; + uint32_t ref_clk; + uint32_t quirks; +} ufshci_acpi_devices[] = { + { "QCOM24A5", "Qualcomm Snapdragon X Elite UFS Host Controller", + UFSHCI_REF_CLK_19_2MHz, + UFSHCI_QUIRK_REINIT_AFTER_MAX_GEAR_SWITCH | + UFSHCI_QUIRK_BROKEN_LSDBS_MCQS_CAP }, + { 0x00000000, NULL, 0, 0 } +}; + +static char *ufshci_acpi_ids[] = { "QCOM24A5", NULL }; + +static const struct ufshci_acpi_device * +ufshci_acpi_find_device(device_t dev) +{ + char *hid; + int i; + int rv; + + rv = ACPI_ID_PROBE(device_get_parent(dev), dev, ufshci_acpi_ids, &hid); + if (rv > 0) + return (NULL); + + for (i = 0; ufshci_acpi_devices[i].hid != NULL; i++) { + if (strcmp(ufshci_acpi_devices[i].hid, hid) != 0) + continue; + return (&ufshci_acpi_devices[i]); + } + + return (NULL); +} + +static int +ufshci_acpi_probe(device_t dev) +{ + struct ufshci_controller *ctrlr = device_get_softc(dev); + const struct ufshci_acpi_device *acpi_dev; + + acpi_dev = ufshci_acpi_find_device(dev); + if (acpi_dev == NULL) + return (ENXIO); + + if (acpi_dev->hid) { + ctrlr->quirks = acpi_dev->quirks; + ctrlr->ref_clk = acpi_dev->ref_clk; + } + + if (acpi_dev->desc) { + device_set_desc(dev, acpi_dev->desc); + return (BUS_PROBE_DEFAULT); + } + + return (ENXIO); +} + +static int +ufshci_acpi_allocate_memory(struct ufshci_controller *ctrlr) +{ + ctrlr->resource_id = 0; + ctrlr->resource = bus_alloc_resource_any(ctrlr->dev, SYS_RES_MEMORY, + &ctrlr->resource_id, RF_ACTIVE); + + if (ctrlr->resource == NULL) { + ufshci_printf(ctrlr, "unable to allocate acpi resource\n"); + return (ENOMEM); + } + + ctrlr->bus_tag = rman_get_bustag(ctrlr->resource); + ctrlr->bus_handle = rman_get_bushandle(ctrlr->resource); + ctrlr->regs = (struct ufshci_registers *)ctrlr->bus_handle; + + return (0); +} + +static int +ufshci_acpi_setup_shared(struct ufshci_controller *ctrlr) +{ + int error; + + ctrlr->num_io_queues = 1; + ctrlr->rid = 0; + ctrlr->res = bus_alloc_resource_any(ctrlr->dev, SYS_RES_IRQ, + &ctrlr->rid, RF_SHAREABLE | RF_ACTIVE); + if (ctrlr->res == NULL) { + ufshci_printf(ctrlr, "unable to allocate shared interrupt\n"); + return (ENOMEM); + } + + error = bus_setup_intr(ctrlr->dev, ctrlr->res, + INTR_TYPE_MISC | INTR_MPSAFE, NULL, ufshci_ctrlr_shared_handler, + ctrlr, &ctrlr->tag); + if (error) { + ufshci_printf(ctrlr, "unable to setup shared interrupt\n"); + return (error); + } + + return (0); +} + +static int +ufshci_acpi_setup_interrupts(struct ufshci_controller *ctrlr) +{ + int num_io_queues, per_cpu_io_queues, min_cpus_per_ioq; + + /* + * TODO: Need to implement MCQ(Multi Circular Queue) + * Example: num_io_queues = mp_ncpus; + */ + num_io_queues = 1; + TUNABLE_INT_FETCH("hw.ufshci.num_io_queues", &num_io_queues); + if (num_io_queues < 1 || num_io_queues > mp_ncpus) + num_io_queues = mp_ncpus; + + per_cpu_io_queues = 1; + TUNABLE_INT_FETCH("hw.ufshci.per_cpu_io_queues", &per_cpu_io_queues); + if (per_cpu_io_queues == 0) + num_io_queues = 1; + + min_cpus_per_ioq = smp_threads_per_core; + TUNABLE_INT_FETCH("hw.ufshci.min_cpus_per_ioq", &min_cpus_per_ioq); + if (min_cpus_per_ioq > 1) { + num_io_queues = min(num_io_queues, + max(1, mp_ncpus / min_cpus_per_ioq)); + } + + if (num_io_queues > vm_ndomains) + num_io_queues -= num_io_queues % vm_ndomains; + + ctrlr->num_io_queues = num_io_queues; + return (ufshci_acpi_setup_shared(ctrlr)); +} + +static int +ufshci_acpi_attach(device_t dev) +{ + struct ufshci_controller *ctrlr = device_get_softc(dev); + int status; + + ctrlr->dev = dev; + status = ufshci_acpi_allocate_memory(ctrlr); + if (status != 0) + goto bad; + + status = ufshci_acpi_setup_interrupts(ctrlr); + if (status != 0) + goto bad; + + return (ufshci_attach(dev)); +bad: + if (ctrlr->resource != NULL) { + bus_release_resource(dev, SYS_RES_MEMORY, ctrlr->resource_id, + ctrlr->resource); + } + + if (ctrlr->tag) + bus_teardown_intr(dev, ctrlr->res, ctrlr->tag); + + if (ctrlr->res) + bus_release_resource(dev, SYS_RES_IRQ, rman_get_rid(ctrlr->res), + ctrlr->res); + + return (status); +} + +static int +ufshci_acpi_detach(device_t dev) +{ + return (ufshci_detach(dev)); +} + +static int +ufshci_acpi_suspend(device_t dev) +{ + struct ufshci_controller *ctrlr = device_get_softc(dev); + int error; + + error = bus_generic_suspend(dev); + if (error) + return (error); + + /* Currently, PCI-based ufshci only supports POWER_STYPE_STANDBY */ + error = ufshci_ctrlr_suspend(ctrlr, POWER_STYPE_STANDBY); + return (error); +} + +static int +ufshci_acpi_resume(device_t dev) +{ + struct ufshci_controller *ctrlr = device_get_softc(dev); + int error; + + error = ufshci_ctrlr_resume(ctrlr, POWER_STYPE_AWAKE); + if (error) + return (error); + + error = bus_generic_resume(dev); + return (error); +} diff --git a/sys/dev/ufshci/ufshci_ctrlr.c b/sys/dev/ufshci/ufshci_ctrlr.c index f011d03189e0..244aa723d02a 100644 --- a/sys/dev/ufshci/ufshci_ctrlr.c +++ b/sys/dev/ufshci/ufshci_ctrlr.c @@ -21,6 +21,50 @@ ufshci_ctrlr_fail(struct ufshci_controller *ctrlr) ufshci_req_queue_fail(ctrlr, &ctrlr->transfer_req_queue); } +/* Some controllers require a reinit after switching to the max gear. */ +static int +ufshci_ctrlr_reinit_after_max_gear_switch(struct ufshci_controller *ctrlr) +{ + int error; + + /* Reset device */ + ufshci_utmr_req_queue_disable(ctrlr); + ufshci_utr_req_queue_disable(ctrlr); + + error = ufshci_ctrlr_disable(ctrlr); + if (error != 0) + return (error); + + error = ufshci_ctrlr_enable(ctrlr); + if (error != 0) + return (error); + + error = ufshci_utmr_req_queue_enable(ctrlr); + if (error != 0) + return (error); + + error = ufshci_utr_req_queue_enable(ctrlr); + if (error != 0) + return (error); + + error = ufshci_ctrlr_send_nop(ctrlr); + if (error != 0) + return (error); + + /* Reinit the target device. */ + error = ufshci_dev_init(ctrlr); + if (error != 0) + return (error); + + /* Initialize Reference Clock */ + error = ufshci_dev_init_reference_clock(ctrlr); + if (error != 0) + return (error); + + /* Initialize unipro */ + return (ufshci_dev_init_unipro(ctrlr)); +} + static void ufshci_ctrlr_start(struct ufshci_controller *ctrlr, bool resetting) { @@ -77,6 +121,12 @@ ufshci_ctrlr_start(struct ufshci_controller *ctrlr, bool resetting) ufshci_dev_init_uic_link_state(ctrlr); + if ((ctrlr->quirks & UFSHCI_QUIRK_REINIT_AFTER_MAX_GEAR_SWITCH) && + ufshci_ctrlr_reinit_after_max_gear_switch(ctrlr) != 0) { + ufshci_ctrlr_fail(ctrlr); + return; + } + /* Read Controller Descriptor (Device, Geometry) */ if (ufshci_dev_get_descriptor(ctrlr) != 0) { ufshci_ctrlr_fail(ctrlr); @@ -199,7 +249,7 @@ ufshci_ctrlr_disable(struct ufshci_controller *ctrlr) return (error); } -static int +int ufshci_ctrlr_enable(struct ufshci_controller *ctrlr) { uint32_t ie, hcs; @@ -302,15 +352,18 @@ ufshci_ctrlr_construct(struct ufshci_controller *ctrlr, device_t dev) /* Read Device Capabilities */ ctrlr->cap = cap = ufshci_mmio_read_4(ctrlr, cap); - ctrlr->is_single_db_supported = UFSHCIV(UFSHCI_CAP_REG_LSDBS, cap); - /* - * TODO: This driver does not yet support multi-queue. - * Check the UFSHCI_CAP_REG_MCQS bit in the future to determine if - * multi-queue support is available. - */ - ctrlr->is_mcq_supported = false; - if (!(ctrlr->is_single_db_supported == 0 || ctrlr->is_mcq_supported)) + if (ctrlr->quirks & UFSHCI_QUIRK_BROKEN_LSDBS_MCQS_CAP) { + ctrlr->is_single_db_supported = true; + ctrlr->is_mcq_supported = true; + } else { + ctrlr->is_single_db_supported = (UFSHCIV(UFSHCI_CAP_REG_LSDBS, + cap) == 0); + ctrlr->is_mcq_supported = (UFSHCIV(UFSHCI_CAP_REG_MCQS, cap) == + 1); + } + if (!(ctrlr->is_single_db_supported || ctrlr->is_mcq_supported)) return (ENXIO); + /* * The maximum transfer size supported by UFSHCI spec is 65535 * 256 KiB * However, we limit the maximum transfer size to 1MiB(256 * 4KiB) for diff --git a/sys/dev/ufshci/ufshci_private.h b/sys/dev/ufshci/ufshci_private.h index b25df45d6b75..067b51a419e8 100644 --- a/sys/dev/ufshci/ufshci_private.h +++ b/sys/dev/ufshci/ufshci_private.h @@ -315,10 +315,15 @@ struct ufshci_controller { #define UFSHCI_QUIRK_NOT_SUPPORT_ABORT_TASK \ 16 /* QEMU does not support Task Management Request */ #define UFSHCI_QUIRK_SKIP_WELL_KNOWN_LUNS \ - 32 /* QEMU does not support Well known logical units*/ + 32 /* QEMU does not support Well known logical units */ #define UFSHCI_QUIRK_BROKEN_AUTO_HIBERNATE \ 64 /* Some controllers have the Auto hibernate feature enabled but it \ does not work. */ +#define UFSHCI_QUIRK_REINIT_AFTER_MAX_GEAR_SWITCH \ + 128 /* Some controllers need to reinit the device after gear switch. \ + */ +#define UFSHCI_QUIRK_BROKEN_LSDBS_MCQS_CAP \ + 256 /* Some controllers have their LSDB and MCQS fields reset to 0. */ uint32_t ref_clk; @@ -391,8 +396,8 @@ struct ufshci_controller { /* UFS Transport Protocol Layer (UTP) */ struct ufshci_req_queue task_mgmt_req_queue; struct ufshci_req_queue transfer_req_queue; - bool is_single_db_supported; /* 0 = supported */ - bool is_mcq_supported; /* 1 = supported */ + bool is_single_db_supported; + bool is_mcq_supported; /* UFS Interconnect Layer (UIC) */ struct mtx uic_cmd_lock; @@ -443,6 +448,7 @@ int ufshci_ctrlr_suspend(struct ufshci_controller *ctrlr, int ufshci_ctrlr_resume(struct ufshci_controller *ctrlr, enum power_stype stype); int ufshci_ctrlr_disable(struct ufshci_controller *ctrlr); +int ufshci_ctrlr_enable(struct ufshci_controller *ctrlr); /* 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); diff --git a/sys/modules/ufshci/Makefile b/sys/modules/ufshci/Makefile index ab5f3eaf88d0..aa0419d3a6d6 100644 --- a/sys/modules/ufshci/Makefile +++ b/sys/modules/ufshci/Makefile @@ -3,6 +3,7 @@ KMOD = ufshci SRCS = ufshci.c \ + ufshci_acpi.c \ ufshci_pci.c \ ufshci_ctrlr.c \ ufshci_dev.c \ @@ -12,8 +13,10 @@ SRCS = ufshci.c \ ufshci_req_sdb.c \ ufshci_sim.c \ ufshci_sysctl.c \ + acpi_if.h \ bus_if.h \ device_if.h \ + opt_acpi.h \ opt_cam.h \ pci_if.h