All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/2] hw/ufs: Add a generic SysBus frontend
@ 2026-08-07 10:36 Jeuk Kim
  2026-08-07 10:36 ` [PATCH 1/2] hw/ufs: Separate the controller core from the PCI frontend Jeuk Kim
  2026-08-07 10:36 ` [PATCH 2/2] hw/ufs: Add a generic SysBus frontend Jeuk Kim
  0 siblings, 2 replies; 3+ messages in thread
From: Jeuk Kim @ 2026-08-07 10:36 UTC (permalink / raw)
  To: qemu-devel
  Cc: jeuk20.kim, pbonzini, qemu-block, j-young.choi, mikail.sadic,
	hyenc.jeong

The UFS controller implementation is currently tied to its PCI QOM
device. This series separates the controller core from the PCI frontend
and adds a reusable SysBus frontend, following the AHCI model.

The existing "ufs" PCI device and its properties remain unchanged.
Platform-specific controllers can derive from TYPE_SYSBUS_UFS and keep
only their hardware-specific behavior.

Jeuk Kim (2):
  hw/ufs: Separate the controller core from the PCI frontend
  hw/ufs: Add a generic SysBus frontend

 hw/ufs/Kconfig      |   9 ++++
 hw/ufs/lu.c         |   2 +-
 hw/ufs/meson.build  |   4 +-
 hw/ufs/trace-events |   4 +-
 hw/ufs/ufs-pci.c    | 112 ++++++++++++++++++++++++++++++++++++++++++++
 hw/ufs/ufs-sysbus.c |  81 ++++++++++++++++++++++++++++++++
 hw/ufs/ufs-sysbus.h |  22 +++++++++
 hw/ufs/ufs.c        | 108 +++++++++---------------------------------
 hw/ufs/ufs.h        |  14 ++++--
 9 files changed, 262 insertions(+), 94 deletions(-)
 create mode 100644 hw/ufs/ufs-pci.c
 create mode 100644 hw/ufs/ufs-sysbus.c
 create mode 100644 hw/ufs/ufs-sysbus.h

-- 
2.43.0


^ permalink raw reply	[flat|nested] 3+ messages in thread

* [PATCH 1/2] hw/ufs: Separate the controller core from the PCI frontend
  2026-08-07 10:36 [PATCH 0/2] hw/ufs: Add a generic SysBus frontend Jeuk Kim
@ 2026-08-07 10:36 ` Jeuk Kim
  2026-08-07 10:36 ` [PATCH 2/2] hw/ufs: Add a generic SysBus frontend Jeuk Kim
  1 sibling, 0 replies; 3+ messages in thread
From: Jeuk Kim @ 2026-08-07 10:36 UTC (permalink / raw)
  To: qemu-devel
  Cc: jeuk20.kim, pbonzini, qemu-block, j-young.choi, mikail.sadic,
	hyenc.jeong

UfsHc is currently also the PCI device instance, tying common code to
PCI-specific DMA and IRQ interfaces and preventing reuse by non-PCI
frontends.

Make UfsHc transport-independent and embed it in UfsPciState. Move the
PCI-specific handling to ufs-pci.c, pass the owning DeviceState and DMA
AddressSpace to the core, and record the core explicitly in UfsBus.

Split the common implementation into CONFIG_UFS, selected by
CONFIG_UFS_PCI. The user-visible "ufs" device and its properties remain
unchanged. No functional change is intended.

Signed-off-by: Jeuk Kim <jeuk20.kim@samsung.com>
---
 hw/ufs/Kconfig      |   5 ++
 hw/ufs/lu.c         |   2 +-
 hw/ufs/meson.build  |   3 +-
 hw/ufs/trace-events |   4 +-
 hw/ufs/ufs-pci.c    | 112 ++++++++++++++++++++++++++++++++++++++++++++
 hw/ufs/ufs.c        | 108 +++++++++---------------------------------
 hw/ufs/ufs.h        |  14 ++++--
 7 files changed, 154 insertions(+), 94 deletions(-)
 create mode 100644 hw/ufs/ufs-pci.c

diff --git a/hw/ufs/Kconfig b/hw/ufs/Kconfig
index b7b3392e85..47e28a30ea 100644
--- a/hw/ufs/Kconfig
+++ b/hw/ufs/Kconfig
@@ -1,4 +1,9 @@
+config UFS
+    bool
+    select SCSI
+
 config UFS_PCI
     bool
     default y if PCI_DEVICES
     depends on PCI
+    select UFS
diff --git a/hw/ufs/lu.c b/hw/ufs/lu.c
index 13f4a90145..eeca865eb5 100644
--- a/hw/ufs/lu.c
+++ b/hw/ufs/lu.c
@@ -497,7 +497,7 @@ static void ufs_lu_realize(DeviceState *dev, Error **errp)
 {
     UfsLu *lu = DO_UPCAST(UfsLu, qdev, dev);
     BusState *s = qdev_get_parent_bus(dev);
-    UfsHc *u = UFS(s->parent);
+    UfsHc *u = UFS_BUS(s)->hc;
     BlockBackend *blk = lu->conf.blk;
 
     if (!ufs_lu_check_constraints(lu, errp)) {
diff --git a/hw/ufs/meson.build b/hw/ufs/meson.build
index 6e68328b93..880fc52c05 100644
--- a/hw/ufs/meson.build
+++ b/hw/ufs/meson.build
@@ -1 +1,2 @@
-system_ss.add(when: 'CONFIG_UFS_PCI', if_true: files('ufs.c', 'lu.c'))
+system_ss.add(when: 'CONFIG_UFS', if_true: files('ufs.c', 'lu.c'))
+system_ss.add(when: 'CONFIG_UFS_PCI', if_true: files('ufs-pci.c'))
diff --git a/hw/ufs/trace-events b/hw/ufs/trace-events
index 662d9afee3..0cd3ba9b02 100644
--- a/hw/ufs/trace-events
+++ b/hw/ufs/trace-events
@@ -1,6 +1,6 @@
 # ufs.c
-ufs_irq_raise(void) "INTx"
-ufs_irq_lower(void) "INTx"
+ufs_irq_raise(void) "IRQ"
+ufs_irq_lower(void) "IRQ"
 ufs_mmio_read(uint64_t addr, uint64_t data, unsigned size) "addr 0x%"PRIx64" data 0x%"PRIx64" size %d"
 ufs_mmio_write(uint64_t addr, uint64_t data, unsigned size) "addr 0x%"PRIx64" data 0x%"PRIx64" size %d"
 ufs_process_db(uint32_t slot) "UTRLDBR slot %"PRIu32""
diff --git a/hw/ufs/ufs-pci.c b/hw/ufs/ufs-pci.c
new file mode 100644
index 0000000000..10e4f06c72
--- /dev/null
+++ b/hw/ufs/ufs-pci.c
@@ -0,0 +1,112 @@
+/*
+ * QEMU Universal Flash Storage (UFS) PCI Controller
+ *
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Written by Jeuk Kim <jeuk20.kim@samsung.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+/**
+ * Usage
+ * -----
+ *
+ * Add options:
+ *      -drive file=<file>,if=none,id=<drive_id>
+ *      -device ufs,serial=<serial>,id=<bus_name>, \
+ *              nutrs=<N[optional]>,nutmrs=<N[optional]>
+ *      -device ufs-lu,drive=<drive_id>,bus=<bus_name>
+ */
+
+#include "qemu/osdep.h"
+#include "hw/core/irq.h"
+#include "hw/core/qdev-properties.h"
+#include "hw/pci/pci.h"
+#include "hw/pci/pci_device.h"
+#include "migration/vmstate.h"
+#include "ufs.h"
+
+#define TYPE_UFS_PCI "ufs"
+OBJECT_DECLARE_SIMPLE_TYPE(UfsPciState, UFS_PCI)
+
+struct UfsPciState {
+    PCIDevice parent_obj;
+    UfsHc ufs;
+};
+
+static void ufs_pci_realize(PCIDevice *pci_dev, Error **errp)
+{
+    UfsPciState *s = UFS_PCI(pci_dev);
+    UfsHc *u = &s->ufs;
+    uint8_t *pci_conf = pci_dev->config;
+
+    pci_conf[PCI_INTERRUPT_PIN] = 1;
+    pci_config_set_prog_interface(pci_conf, 0x1);
+    u->irq = pci_allocate_irq(pci_dev);
+    if (!ufs_realize(u, DEVICE(pci_dev), pci_get_address_space(pci_dev),
+                     errp)) {
+        qemu_free_irq(u->irq);
+        u->irq = NULL;
+        return;
+    }
+
+    pci_register_bar(pci_dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &u->iomem);
+}
+
+static void ufs_pci_exit(PCIDevice *pci_dev)
+{
+    UfsPciState *s = UFS_PCI(pci_dev);
+
+    ufs_unrealize(&s->ufs);
+    qemu_free_irq(s->ufs.irq);
+}
+
+static const Property ufs_pci_props[] = {
+    DEFINE_PROP_STRING("serial", UfsPciState, ufs.params.serial),
+    DEFINE_PROP_UINT8("nutrs", UfsPciState, ufs.params.nutrs, 32),
+    DEFINE_PROP_UINT8("nutmrs", UfsPciState, ufs.params.nutmrs, 8),
+    DEFINE_PROP_BOOL("mcq", UfsPciState, ufs.params.mcq, false),
+    DEFINE_PROP_UINT8("mcq-maxq", UfsPciState, ufs.params.mcq_maxq, 2),
+    DEFINE_PROP_UINT32("wb-max-size", UfsPciState,
+                       ufs.params.wb_max_size, 0x400),
+    DEFINE_PROP_UINT32("wb-min-size", UfsPciState,
+                       ufs.params.wb_min_size, 0x100),
+};
+
+static const VMStateDescription ufs_pci_vmstate = {
+    .name = "ufs",
+    .unmigratable = 1,
+};
+
+static void ufs_pci_class_init(ObjectClass *oc, const void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(oc);
+    PCIDeviceClass *pc = PCI_DEVICE_CLASS(oc);
+
+    pc->realize = ufs_pci_realize;
+    pc->exit = ufs_pci_exit;
+    pc->vendor_id = PCI_VENDOR_ID_REDHAT;
+    pc->device_id = PCI_DEVICE_ID_REDHAT_UFS;
+    pc->class_id = PCI_CLASS_STORAGE_UFS;
+
+    set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
+    dc->desc = "Universal Flash Storage";
+    device_class_set_props(dc, ufs_pci_props);
+    dc->vmsd = &ufs_pci_vmstate;
+}
+
+static const TypeInfo ufs_pci_info = {
+    .name = TYPE_UFS_PCI,
+    .parent = TYPE_PCI_DEVICE,
+    .class_init = ufs_pci_class_init,
+    .instance_size = sizeof(UfsPciState),
+    .interfaces = (const InterfaceInfo[]){ { INTERFACE_PCIE_DEVICE }, {} },
+};
+
+static void ufs_pci_register_types(void)
+{
+    type_register_static(&ufs_pci_info);
+}
+
+type_init(ufs_pci_register_types)
diff --git a/hw/ufs/ufs.c b/hw/ufs/ufs.c
index 464fd465b3..36c674af32 100644
--- a/hw/ufs/ufs.c
+++ b/hw/ufs/ufs.c
@@ -11,19 +11,10 @@
 /**
  * Reference Specs: https://www.jedec.org/, 4.1
  *
- * Usage
- * -----
- *
- * Add options:
- *      -drive file=<file>,if=none,id=<drive_id>
- *      -device ufs,serial=<serial>,id=<bus_name>, \
- *              nutrs=<N[optional]>,nutmrs=<N[optional]>
- *      -device ufs-lu,drive=<drive_id>,bus=<bus_name>
  */
 
 #include "qemu/osdep.h"
 #include "qapi/error.h"
-#include "migration/vmstate.h"
 #include "scsi/constants.h"
 #include "hw/core/irq.h"
 #include "trace.h"
@@ -102,7 +93,8 @@ static MemTxResult ufs_addr_read(UfsHc *u, hwaddr addr, void *buf, int size)
         return MEMTX_DECODE_ERROR;
     }
 
-    return pci_dma_read(PCI_DEVICE(u), addr, buf, size);
+    return dma_memory_read(u->dma_as, addr, buf, size,
+                           MEMTXATTRS_UNSPECIFIED);
 }
 
 static MemTxResult ufs_addr_write(UfsHc *u, hwaddr addr, const void *buf,
@@ -117,7 +109,8 @@ static MemTxResult ufs_addr_write(UfsHc *u, hwaddr addr, const void *buf,
         return MEMTX_DECODE_ERROR;
     }
 
-    return pci_dma_write(PCI_DEVICE(u), addr, buf, size);
+    return dma_memory_write(u->dma_as, addr, buf, size,
+                            MEMTXATTRS_UNSPECIFIED);
 }
 
 static inline hwaddr ufs_get_utrd_addr(UfsHc *u, uint32_t slot)
@@ -222,7 +215,7 @@ static MemTxResult ufs_dma_read_prdt(UfsRequest *req)
     }
 
     req->sg = g_malloc0(sizeof(QEMUSGList));
-    pci_dma_sglist_init(req->sg, PCI_DEVICE(u), prdt_len);
+    qemu_sglist_init(req->sg, u->dev, prdt_len, u->dma_as);
     req->data_len = 0;
 
     for (uint16_t i = 0; i < prdt_len; ++i) {
@@ -317,14 +310,12 @@ static MemTxResult ufs_dma_write_upiu(UfsRequest *req)
 
 static void ufs_irq_check(UfsHc *u)
 {
-    PCIDevice *pci = PCI_DEVICE(u);
-
     if ((u->reg.is & UFS_INTR_MASK) & u->reg.ie) {
         trace_ufs_irq_raise();
-        pci_irq_assert(pci);
+        qemu_irq_raise(u->irq);
     } else {
         trace_ufs_irq_lower();
-        pci_irq_deassert(pci);
+        qemu_irq_lower(u->irq);
     }
 }
 
@@ -596,7 +587,7 @@ static bool ufs_mcq_create_sq(UfsHc *u, uint8_t qid, uint32_t attr)
     sq->size = qsize;
 
     sq->bh = qemu_bh_new_guarded(ufs_mcq_process_sq, sq,
-                                 &DEVICE(u)->mem_reentrancy_guard);
+                                 &u->dev->mem_reentrancy_guard);
     sq->req = g_new0(UfsRequest, sq->size);
     QTAILQ_INIT(&sq->req_list);
     for (int i = 0; i < sq->size; i++) {
@@ -690,7 +681,7 @@ static bool ufs_mcq_create_cq(UfsHc *u, uint8_t qid, uint32_t attr)
     cq->size = qsize;
 
     cq->bh = qemu_bh_new_guarded(ufs_mcq_process_cq, cq,
-                                 &DEVICE(u)->mem_reentrancy_guard);
+                                 &u->dev->mem_reentrancy_guard);
     QTAILQ_INIT(&cq->req_list);
 
     u->cq[qid] = cq;
@@ -2488,19 +2479,6 @@ static bool ufs_check_constraints(UfsHc *u, Error **errp)
     return true;
 }
 
-static void ufs_init_pci(UfsHc *u, PCIDevice *pci_dev)
-{
-    uint8_t *pci_conf = pci_dev->config;
-
-    pci_conf[PCI_INTERRUPT_PIN] = 1;
-    pci_config_set_prog_interface(pci_conf, 0x1);
-
-    memory_region_init_io(&u->iomem, OBJECT(u), &ufs_mmio_ops, u, "ufs",
-                          u->reg_size);
-    pci_register_bar(pci_dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &u->iomem);
-    u->irq = pci_allocate_irq(pci_dev);
-}
-
 static void ufs_init_state(UfsHc *u)
 {
     u->req_list = g_new0(UfsRequest, u->params.nutrs);
@@ -2513,9 +2491,9 @@ static void ufs_init_state(UfsHc *u)
     }
 
     u->doorbell_bh = qemu_bh_new_guarded(ufs_process_req, u,
-                                         &DEVICE(u)->mem_reentrancy_guard);
+                                         &u->dev->mem_reentrancy_guard);
     u->complete_bh = qemu_bh_new_guarded(ufs_sendback_req, u,
-                                         &DEVICE(u)->mem_reentrancy_guard);
+                                         &u->dev->mem_reentrancy_guard);
 
     if (u->params.mcq) {
         memset(u->sq, 0, sizeof(u->sq));
@@ -2689,35 +2667,36 @@ static void ufs_init_hc(UfsHc *u)
     timer_mod(&u->idle_timer, now + UFS_IDLE_TIMER_TICK);
 }
 
-static void ufs_realize(PCIDevice *pci_dev, Error **errp)
+bool ufs_realize(UfsHc *u, DeviceState *dev, AddressSpace *dma_as,
+                 Error **errp)
 {
-    UfsHc *u = UFS(pci_dev);
+    u->dev = dev;
+    u->dma_as = dma_as;
 
     if (!ufs_check_constraints(u, errp)) {
-        return;
+        return false;
     }
 
-    qbus_init(&u->bus, sizeof(UfsBus), TYPE_UFS_BUS, &pci_dev->qdev,
-              u->parent_obj.qdev.id);
+    qbus_init(&u->bus, sizeof(UfsBus), TYPE_UFS_BUS, dev, dev->id);
+    u->bus.hc = u;
 
     ufs_init_state(u);
     ufs_init_hc(u);
-    ufs_init_pci(u, pci_dev);
+    memory_region_init_io(&u->iomem, OBJECT(dev), &ufs_mmio_ops, u, "ufs",
+                          u->reg_size);
 
     ufs_init_wlu(&u->report_wlu, UFS_UPIU_REPORT_LUNS_WLUN);
     ufs_init_wlu(&u->dev_wlu, UFS_UPIU_UFS_DEVICE_WLUN);
     ufs_init_wlu(&u->boot_wlu, UFS_UPIU_BOOT_WLUN);
     ufs_init_wlu(&u->rpmb_wlu, UFS_UPIU_RPMB_WLUN);
+
+    return true;
 }
 
-static void ufs_exit(PCIDevice *pci_dev)
+void ufs_unrealize(UfsHc *u)
 {
-    UfsHc *u = UFS(pci_dev);
-
     timer_del(&u->idle_timer);
 
-    qemu_free_irq(u->irq);
-
     qemu_bh_delete(u->doorbell_bh);
     qemu_bh_delete(u->complete_bh);
 
@@ -2740,38 +2719,6 @@ static void ufs_exit(PCIDevice *pci_dev)
     }
 }
 
-static const Property ufs_props[] = {
-    DEFINE_PROP_STRING("serial", UfsHc, params.serial),
-    DEFINE_PROP_UINT8("nutrs", UfsHc, params.nutrs, 32),
-    DEFINE_PROP_UINT8("nutmrs", UfsHc, params.nutmrs, 8),
-    DEFINE_PROP_BOOL("mcq", UfsHc, params.mcq, false),
-    DEFINE_PROP_UINT8("mcq-maxq", UfsHc, params.mcq_maxq, 2),
-    DEFINE_PROP_UINT32("wb-max-size", UfsHc, params.wb_max_size, 0x400),
-    DEFINE_PROP_UINT32("wb-min-size", UfsHc, params.wb_min_size, 0x100),
-};
-
-static const VMStateDescription ufs_vmstate = {
-    .name = "ufs",
-    .unmigratable = 1,
-};
-
-static void ufs_class_init(ObjectClass *oc, const void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(oc);
-    PCIDeviceClass *pc = PCI_DEVICE_CLASS(oc);
-
-    pc->realize = ufs_realize;
-    pc->exit = ufs_exit;
-    pc->vendor_id = PCI_VENDOR_ID_REDHAT;
-    pc->device_id = PCI_DEVICE_ID_REDHAT_UFS;
-    pc->class_id = PCI_CLASS_STORAGE_UFS;
-
-    set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
-    dc->desc = "Universal Flash Storage";
-    device_class_set_props(dc, ufs_props);
-    dc->vmsd = &ufs_vmstate;
-}
-
 static bool ufs_bus_check_address(BusState *qbus, DeviceState *qdev,
                                   Error **errp)
 {
@@ -2798,14 +2745,6 @@ static void ufs_bus_class_init(ObjectClass *class, const void *data)
     bc->check_address = ufs_bus_check_address;
 }
 
-static const TypeInfo ufs_info = {
-    .name = TYPE_UFS,
-    .parent = TYPE_PCI_DEVICE,
-    .class_init = ufs_class_init,
-    .instance_size = sizeof(UfsHc),
-    .interfaces = (const InterfaceInfo[]){ { INTERFACE_PCIE_DEVICE }, {} },
-};
-
 static const TypeInfo ufs_bus_info = {
     .name = TYPE_UFS_BUS,
     .parent = TYPE_BUS,
@@ -2816,7 +2755,6 @@ static const TypeInfo ufs_bus_info = {
 
 static void ufs_register_types(void)
 {
-    type_register_static(&ufs_info);
     type_register_static(&ufs_bus_info);
 }
 
diff --git a/hw/ufs/ufs.h b/hw/ufs/ufs.h
index feb47f460d..aa8361d93d 100644
--- a/hw/ufs/ufs.h
+++ b/hw/ufs/ufs.h
@@ -11,9 +11,11 @@
 #ifndef HW_UFS_UFS_H
 #define HW_UFS_UFS_H
 
-#include "hw/pci/pci_device.h"
+#include "hw/core/qdev.h"
 #include "hw/scsi/scsi.h"
 #include "block/ufs.h"
+#include "scsi/constants.h"
+#include "system/dma.h"
 
 #define UFS_MAX_LUS 32
 #define UFS_MAX_MCQ_QNUM 32
@@ -27,6 +29,7 @@ typedef struct UfsBusClass {
 
 typedef struct UfsBus {
     BusState parent_bus;
+    struct UfsHc *hc;
 } UfsBus;
 
 #define TYPE_UFS_BUS "ufs-bus"
@@ -141,7 +144,8 @@ typedef struct UfsWb {
 } UfsWb;
 
 typedef struct UfsHc {
-    PCIDevice parent_obj;
+    DeviceState *dev;
+    AddressSpace *dma_as;
     UfsBus bus;
     MemoryRegion iomem;
     UfsReg reg;
@@ -268,9 +272,6 @@ static inline bool ufs_is_write_req(UfsRequest *req)
     return (cmd == WRITE_6) || (cmd == WRITE_10) || (cmd == WRITE_16);
 }
 
-#define TYPE_UFS "ufs"
-#define UFS(obj) OBJECT_CHECK(UfsHc, (obj), TYPE_UFS)
-
 #define TYPE_UFS_LU "ufs-lu"
 #define UFSLU(obj) OBJECT_CHECK(UfsLu, (obj), TYPE_UFS_LU)
 
@@ -302,4 +303,7 @@ void ufs_build_query_response(UfsRequest *req);
 void ufs_complete_req(UfsRequest *req, UfsReqResult req_result);
 void ufs_wb_update_avail_buffer(UfsHc *u);
 void ufs_init_wlu(UfsLu *wlu, uint8_t wlun);
+bool ufs_realize(UfsHc *u, DeviceState *dev, AddressSpace *dma_as,
+                 Error **errp);
+void ufs_unrealize(UfsHc *u);
 #endif /* HW_UFS_UFS_H */
-- 
2.43.0



^ permalink raw reply related	[flat|nested] 3+ messages in thread

* [PATCH 2/2] hw/ufs: Add a generic SysBus frontend
  2026-08-07 10:36 [PATCH 0/2] hw/ufs: Add a generic SysBus frontend Jeuk Kim
  2026-08-07 10:36 ` [PATCH 1/2] hw/ufs: Separate the controller core from the PCI frontend Jeuk Kim
@ 2026-08-07 10:36 ` Jeuk Kim
  1 sibling, 0 replies; 3+ messages in thread
From: Jeuk Kim @ 2026-08-07 10:36 UTC (permalink / raw)
  To: qemu-devel
  Cc: jeuk20.kim, pbonzini, qemu-block, j-young.choi, mikail.sadic,
	hyenc.jeong

Add TYPE_SYSBUS_UFS as a reusable frontend for the
transport-independent UFS controller core.

Use the system memory address space for DMA, expose the controller MMIO
region and IRQ through SysBus, and provide the same properties and
migration policy as the PCI frontend. Platform-specific controllers can
derive from this type and keep only their hardware-specific behavior.

Signed-off-by: Jeuk Kim <jeuk20.kim@samsung.com>
---
 hw/ufs/Kconfig      |  4 +++
 hw/ufs/meson.build  |  1 +
 hw/ufs/ufs-sysbus.c | 81 +++++++++++++++++++++++++++++++++++++++++++++
 hw/ufs/ufs-sysbus.h | 22 ++++++++++++
 4 files changed, 108 insertions(+)
 create mode 100644 hw/ufs/ufs-sysbus.c
 create mode 100644 hw/ufs/ufs-sysbus.h

diff --git a/hw/ufs/Kconfig b/hw/ufs/Kconfig
index 47e28a30ea..0e40f08a41 100644
--- a/hw/ufs/Kconfig
+++ b/hw/ufs/Kconfig
@@ -7,3 +7,7 @@ config UFS_PCI
     default y if PCI_DEVICES
     depends on PCI
     select UFS
+
+config UFS_SYSBUS
+    bool
+    select UFS
diff --git a/hw/ufs/meson.build b/hw/ufs/meson.build
index 880fc52c05..a84627b96a 100644
--- a/hw/ufs/meson.build
+++ b/hw/ufs/meson.build
@@ -1,2 +1,3 @@
 system_ss.add(when: 'CONFIG_UFS', if_true: files('ufs.c', 'lu.c'))
 system_ss.add(when: 'CONFIG_UFS_PCI', if_true: files('ufs-pci.c'))
+system_ss.add(when: 'CONFIG_UFS_SYSBUS', if_true: files('ufs-sysbus.c'))
diff --git a/hw/ufs/ufs-sysbus.c b/hw/ufs/ufs-sysbus.c
new file mode 100644
index 0000000000..e811d967e2
--- /dev/null
+++ b/hw/ufs/ufs-sysbus.c
@@ -0,0 +1,81 @@
+/*
+ * QEMU Universal Flash Storage (UFS) sysbus controller
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "hw/core/qdev-properties.h"
+#include "ufs-sysbus.h"
+#include "migration/vmstate.h"
+#include "system/address-spaces.h"
+
+static void ufs_sysbus_realize(DeviceState *dev, Error **errp)
+{
+    SysbusUfsState *s = SYSBUS_UFS(dev);
+
+    if (!ufs_realize(&s->ufs, dev, &address_space_memory, errp)) {
+        return;
+    }
+
+    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->ufs.iomem);
+}
+
+static void ufs_sysbus_unrealize(DeviceState *dev)
+{
+    SysbusUfsState *s = SYSBUS_UFS(dev);
+
+    ufs_unrealize(&s->ufs);
+}
+
+static void ufs_sysbus_init(Object *obj)
+{
+    SysbusUfsState *s = SYSBUS_UFS(obj);
+
+    sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->ufs.irq);
+}
+
+static const Property ufs_sysbus_props[] = {
+    DEFINE_PROP_STRING("serial", SysbusUfsState, ufs.params.serial),
+    DEFINE_PROP_UINT8("nutrs", SysbusUfsState, ufs.params.nutrs, 32),
+    DEFINE_PROP_UINT8("nutmrs", SysbusUfsState, ufs.params.nutmrs, 8),
+    DEFINE_PROP_BOOL("mcq", SysbusUfsState, ufs.params.mcq, false),
+    DEFINE_PROP_UINT8("mcq-maxq", SysbusUfsState,
+                      ufs.params.mcq_maxq, 2),
+    DEFINE_PROP_UINT32("wb-max-size", SysbusUfsState,
+                       ufs.params.wb_max_size, 0x400),
+    DEFINE_PROP_UINT32("wb-min-size", SysbusUfsState,
+                       ufs.params.wb_min_size, 0x100),
+};
+
+static const VMStateDescription ufs_sysbus_vmstate = {
+    .name = TYPE_SYSBUS_UFS,
+    .unmigratable = 1,
+};
+
+static void ufs_sysbus_class_init(ObjectClass *oc, const void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(oc);
+
+    dc->realize = ufs_sysbus_realize;
+    dc->unrealize = ufs_sysbus_unrealize;
+    dc->vmsd = &ufs_sysbus_vmstate;
+    dc->desc = "Universal Flash Storage";
+    device_class_set_props(dc, ufs_sysbus_props);
+    set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
+}
+
+static const TypeInfo ufs_sysbus_info = {
+    .name = TYPE_SYSBUS_UFS,
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(SysbusUfsState),
+    .instance_init = ufs_sysbus_init,
+    .class_init = ufs_sysbus_class_init,
+};
+
+static void ufs_sysbus_register_types(void)
+{
+    type_register_static(&ufs_sysbus_info);
+}
+
+type_init(ufs_sysbus_register_types)
diff --git a/hw/ufs/ufs-sysbus.h b/hw/ufs/ufs-sysbus.h
new file mode 100644
index 0000000000..71b6787d3a
--- /dev/null
+++ b/hw/ufs/ufs-sysbus.h
@@ -0,0 +1,22 @@
+/*
+ * QEMU Universal Flash Storage (UFS) sysbus controller
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef HW_UFS_UFS_SYSBUS_H
+#define HW_UFS_UFS_SYSBUS_H
+
+#include "hw/core/sysbus.h"
+#include "ufs.h"
+
+#define TYPE_SYSBUS_UFS "sysbus-ufs"
+OBJECT_DECLARE_SIMPLE_TYPE(SysbusUfsState, SYSBUS_UFS)
+
+struct SysbusUfsState {
+    SysBusDevice parent_obj;
+
+    UfsHc ufs;
+};
+
+#endif /* HW_UFS_UFS_SYSBUS_H */
-- 
2.43.0



^ permalink raw reply related	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2026-08-07 10:39 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-07 10:36 [PATCH 0/2] hw/ufs: Add a generic SysBus frontend Jeuk Kim
2026-08-07 10:36 ` [PATCH 1/2] hw/ufs: Separate the controller core from the PCI frontend Jeuk Kim
2026-08-07 10:36 ` [PATCH 2/2] hw/ufs: Add a generic SysBus frontend Jeuk Kim

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.