master
c 112 lines 3.06 KB
Raw
1 /*
2 * QEMU Universal Flash Storage (UFS) PCI Controller
3 *
4 * Copyright (c) 2023 Samsung Electronics Co., Ltd. All rights reserved.
5 *
6 * Written by Jeuk Kim <jeuk20.kim@samsung.com>
7 *
8 * SPDX-License-Identifier: GPL-2.0-or-later
9 */
10
11 /**
12 * Usage
13 * -----
14 *
15 * Add options:
16 * -drive file=<file>,if=none,id=<drive_id>
17 * -device ufs,serial=<serial>,id=<bus_name>, \
18 * nutrs=<N[optional]>,nutmrs=<N[optional]>
19 * -device ufs-lu,drive=<drive_id>,bus=<bus_name>
20 */
21
22 #include "qemu/osdep.h"
23 #include "hw/core/irq.h"
24 #include "hw/core/qdev-properties.h"
25 #include "hw/pci/pci.h"
26 #include "hw/pci/pci_device.h"
27 #include "migration/vmstate.h"
28 #include "ufs.h"
29
30 #define TYPE_UFS_PCI "ufs"
31 OBJECT_DECLARE_SIMPLE_TYPE(UfsPciState, UFS_PCI)
32
33 struct UfsPciState {
34 PCIDevice parent_obj;
35 UfsHc ufs;
36 };
37
38 static void ufs_pci_realize(PCIDevice *pci_dev, Error **errp)
39 {
40 UfsPciState *s = UFS_PCI(pci_dev);
41 UfsHc *u = &s->ufs;
42 uint8_t *pci_conf = pci_dev->config;
43
44 pci_conf[PCI_INTERRUPT_PIN] = 1;
45 pci_config_set_prog_interface(pci_conf, 0x1);
46 u->irq = pci_allocate_irq(pci_dev);
47 if (!ufs_realize(u, DEVICE(pci_dev), pci_get_address_space(pci_dev),
48 errp)) {
49 qemu_free_irq(u->irq);
50 u->irq = NULL;
51 return;
52 }
53
54 pci_register_bar(pci_dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &u->iomem);
55 }
56
57 static void ufs_pci_exit(PCIDevice *pci_dev)
58 {
59 UfsPciState *s = UFS_PCI(pci_dev);
60
61 ufs_unrealize(&s->ufs);
62 qemu_free_irq(s->ufs.irq);
63 }
64
65 static const Property ufs_pci_props[] = {
66 DEFINE_PROP_STRING("serial", UfsPciState, ufs.params.serial),
67 DEFINE_PROP_UINT8("nutrs", UfsPciState, ufs.params.nutrs, 32),
68 DEFINE_PROP_UINT8("nutmrs", UfsPciState, ufs.params.nutmrs, 8),
69 DEFINE_PROP_BOOL("mcq", UfsPciState, ufs.params.mcq, false),
70 DEFINE_PROP_UINT8("mcq-maxq", UfsPciState, ufs.params.mcq_maxq, 2),
71 DEFINE_PROP_UINT32("wb-max-size", UfsPciState, ufs.params.wb_max_size,
72 0x400),
73 DEFINE_PROP_UINT32("wb-min-size", UfsPciState, ufs.params.wb_min_size,
74 0x100),
75 };
76
77 static const VMStateDescription ufs_pci_vmstate = {
78 .name = "ufs",
79 .unmigratable = 1,
80 };
81
82 static void ufs_pci_class_init(ObjectClass *oc, const void *data)
83 {
84 DeviceClass *dc = DEVICE_CLASS(oc);
85 PCIDeviceClass *pc = PCI_DEVICE_CLASS(oc);
86
87 pc->realize = ufs_pci_realize;
88 pc->exit = ufs_pci_exit;
89 pc->vendor_id = PCI_VENDOR_ID_REDHAT;
90 pc->device_id = PCI_DEVICE_ID_REDHAT_UFS;
91 pc->class_id = PCI_CLASS_STORAGE_UFS;
92
93 set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
94 dc->desc = "Universal Flash Storage";
95 device_class_set_props(dc, ufs_pci_props);
96 dc->vmsd = &ufs_pci_vmstate;
97 }
98
99 static const TypeInfo ufs_pci_info = {
100 .name = TYPE_UFS_PCI,
101 .parent = TYPE_PCI_DEVICE,
102 .class_init = ufs_pci_class_init,
103 .instance_size = sizeof(UfsPciState),
104 .interfaces = (const InterfaceInfo[]){ { INTERFACE_PCIE_DEVICE }, {} },
105 };
106
107 static void ufs_pci_register_types(void)
108 {
109 type_register_static(&ufs_pci_info);
110 }
111
112 type_init(ufs_pci_register_types)