Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F162636262
D55986.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
11 KB
Referenced Files
None
Subscribers
None
D55986.diff
View Options
diff --git a/sys/conf/files b/sys/conf/files
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -3285,10 +3285,11 @@
# 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
--- /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 <sys/param.h>
+#include <sys/systm.h>
+#include <sys/buf.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/proc.h>
+#include <sys/smp.h>
+
+#include <vm/vm.h>
+
+#include <contrib/dev/acpica/include/acpi.h>
+
+#include <dev/acpica/acpivar.h>
+
+#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
--- a/sys/dev/ufshci/ufshci_ctrlr.c
+++ b/sys/dev/ufshci/ufshci_ctrlr.c
@@ -21,6 +21,50 @@
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_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 @@
return (error);
}
-static int
+int
ufshci_ctrlr_enable(struct ufshci_controller *ctrlr)
{
uint32_t ie, hcs;
@@ -302,15 +352,18 @@
/* 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
--- a/sys/dev/ufshci/ufshci_private.h
+++ b/sys/dev/ufshci/ufshci_private.h
@@ -315,10 +315,15 @@
#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 @@
/* 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_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
--- 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 @@
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
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Thu, Jul 16, 7:14 AM (17 h, 1 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
35128885
Default Alt Text
D55986.diff (11 KB)
Attached To
Mode
D55986: ufshci: Support ACPI
Attached
Detach File
Event Timeline
Log In to Comment