[PATCH 1/2] hw/ufs: Separate the controller core from the PCI frontend
Jeuk Kim <[email protected]>
| Newsgroups | gmane.comp.emulators.qemu.block,gmane.comp.emulators.qemu |
|---|---|
| Message-ID | <6f0a70394e7fcad24daf1b1cffd3b23494893b29.1786096976.git.jeuk20.kim@samsung.com> |
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 <[email protected]> --- 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 <[email protected]> + * + * 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