xref: /openbmc/qemu/hw/s390x/s390-virtio-ccw.c (revision bfb27e60)
1 /*
2  * virtio ccw machine
3  *
4  * Copyright 2012 IBM Corp.
5  * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com>
6  *
7  * This work is licensed under the terms of the GNU GPL, version 2 or (at
8  * your option) any later version. See the COPYING file in the top-level
9  * directory.
10  */
11 
12 #include "hw/boards.h"
13 #include "exec/address-spaces.h"
14 #include "s390-virtio.h"
15 #include "hw/s390x/sclp.h"
16 #include "hw/s390x/s390_flic.h"
17 #include "ioinst.h"
18 #include "css.h"
19 #include "virtio-ccw.h"
20 #include "qemu/config-file.h"
21 
22 #define TYPE_S390_CCW_MACHINE               "s390-ccw-machine"
23 
24 void io_subsystem_reset(void)
25 {
26     DeviceState *css, *sclp, *flic;
27 
28     css = DEVICE(object_resolve_path_type("", "virtual-css-bridge", NULL));
29     if (css) {
30         qdev_reset_all(css);
31     }
32     sclp = DEVICE(object_resolve_path_type("",
33                   "s390-sclp-event-facility", NULL));
34     if (sclp) {
35         qdev_reset_all(sclp);
36     }
37     flic = DEVICE(object_resolve_path_type("", "s390-flic", NULL));
38     if (flic) {
39         qdev_reset_all(flic);
40     }
41 }
42 
43 static int virtio_ccw_hcall_notify(const uint64_t *args)
44 {
45     uint64_t subch_id = args[0];
46     uint64_t queue = args[1];
47     SubchDev *sch;
48     int cssid, ssid, schid, m;
49 
50     if (ioinst_disassemble_sch_ident(subch_id, &m, &cssid, &ssid, &schid)) {
51         return -EINVAL;
52     }
53     sch = css_find_subch(m, cssid, ssid, schid);
54     if (!sch || !css_subch_visible(sch)) {
55         return -EINVAL;
56     }
57     if (queue >= VIRTIO_PCI_QUEUE_MAX) {
58         return -EINVAL;
59     }
60     virtio_queue_notify(virtio_ccw_get_vdev(sch), queue);
61     return 0;
62 
63 }
64 
65 static int virtio_ccw_hcall_early_printk(const uint64_t *args)
66 {
67     uint64_t mem = args[0];
68 
69     if (mem < ram_size) {
70         /* Early printk */
71         return 0;
72     }
73     return -EINVAL;
74 }
75 
76 static void virtio_ccw_register_hcalls(void)
77 {
78     s390_register_virtio_hypercall(KVM_S390_VIRTIO_CCW_NOTIFY,
79                                    virtio_ccw_hcall_notify);
80     /* Tolerate early printk. */
81     s390_register_virtio_hypercall(KVM_S390_VIRTIO_NOTIFY,
82                                    virtio_ccw_hcall_early_printk);
83 }
84 
85 static void ccw_init(MachineState *machine)
86 {
87     ram_addr_t my_ram_size = machine->ram_size;
88     MemoryRegion *sysmem = get_system_memory();
89     MemoryRegion *ram = g_new(MemoryRegion, 1);
90     sclpMemoryHotplugDev *mhd = init_sclp_memory_hotplug_dev();
91     uint8_t *storage_keys;
92     int ret;
93     VirtualCssBus *css_bus;
94     QemuOpts *opts = qemu_opts_find(qemu_find_opts("memory"), NULL);
95     ram_addr_t pad_size = 0;
96     ram_addr_t maxmem = qemu_opt_get_size(opts, "maxmem", my_ram_size);
97     ram_addr_t standby_mem_size = maxmem - my_ram_size;
98 
99     /* The storage increment size is a multiple of 1M and is a power of 2.
100      * The number of storage increments must be MAX_STORAGE_INCREMENTS or fewer.
101      * The variable 'mhd->increment_size' is an exponent of 2 that can be
102      * used to calculate the size (in bytes) of an increment. */
103     mhd->increment_size = 20;
104     while ((my_ram_size >> mhd->increment_size) > MAX_STORAGE_INCREMENTS) {
105         mhd->increment_size++;
106     }
107     while ((standby_mem_size >> mhd->increment_size) > MAX_STORAGE_INCREMENTS) {
108         mhd->increment_size++;
109     }
110 
111     /* The core and standby memory areas need to be aligned with
112      * the increment size.  In effect, this can cause the
113      * user-specified memory size to be rounded down to align
114      * with the nearest increment boundary. */
115     standby_mem_size = standby_mem_size >> mhd->increment_size
116                                         << mhd->increment_size;
117     my_ram_size = my_ram_size >> mhd->increment_size
118                               << mhd->increment_size;
119 
120     /* let's propagate the changed ram size into the global variable. */
121     ram_size = my_ram_size;
122 
123     /* get a BUS */
124     css_bus = virtual_css_bus_init();
125     s390_sclp_init();
126     s390_init_ipl_dev(machine->kernel_filename, machine->kernel_cmdline,
127                       machine->initrd_filename, "s390-ccw.img");
128     s390_flic_init();
129 
130     /* register hypercalls */
131     virtio_ccw_register_hcalls();
132 
133     /* allocate RAM for core */
134     memory_region_init_ram(ram, NULL, "s390.ram", my_ram_size);
135     vmstate_register_ram_global(ram);
136     memory_region_add_subregion(sysmem, 0, ram);
137 
138     /* If the size of ram is not on a MEM_SECTION_SIZE boundary,
139        calculate the pad size necessary to force this boundary. */
140     if (standby_mem_size) {
141         if (my_ram_size % MEM_SECTION_SIZE) {
142             pad_size = MEM_SECTION_SIZE - my_ram_size % MEM_SECTION_SIZE;
143         }
144         my_ram_size += standby_mem_size + pad_size;
145         mhd->pad_size = pad_size;
146         mhd->standby_mem_size = standby_mem_size;
147     }
148 
149     /* allocate storage keys */
150     storage_keys = g_malloc0(my_ram_size / TARGET_PAGE_SIZE);
151 
152     /* init CPUs */
153     s390_init_cpus(machine->cpu_model, storage_keys);
154 
155     if (kvm_enabled()) {
156         kvm_s390_enable_css_support(s390_cpu_addr2state(0));
157     }
158     /*
159      * Create virtual css and set it as default so that non mcss-e
160      * enabled guests only see virtio devices.
161      */
162     ret = css_create_css_image(VIRTUAL_CSSID, true);
163     assert(ret == 0);
164 
165     /* Create VirtIO network adapters */
166     s390_create_virtio_net(BUS(css_bus), "virtio-net-ccw");
167 }
168 
169 static void ccw_machine_class_init(ObjectClass *oc, void *data)
170 {
171     MachineClass *mc = MACHINE_CLASS(oc);
172     NMIClass *nc = NMI_CLASS(oc);
173 
174     mc->name = "s390-ccw-virtio";
175     mc->alias = "s390-ccw";
176     mc->desc = "VirtIO-ccw based S390 machine";
177     mc->init = ccw_init;
178     mc->block_default_type = IF_VIRTIO;
179     mc->no_cdrom = 1;
180     mc->no_floppy = 1;
181     mc->no_serial = 1;
182     mc->no_parallel = 1;
183     mc->no_sdcard = 1;
184     mc->use_sclp = 1,
185     mc->max_cpus = 255;
186     nc->nmi_monitor_handler = s390_nmi;
187 }
188 
189 static const TypeInfo ccw_machine_info = {
190     .name          = TYPE_S390_CCW_MACHINE,
191     .parent        = TYPE_MACHINE,
192     .class_init    = ccw_machine_class_init,
193     .interfaces = (InterfaceInfo[]) {
194         { TYPE_NMI },
195         { }
196     },
197 };
198 
199 static void ccw_machine_register_types(void)
200 {
201     type_register_static(&ccw_machine_info);
202 }
203 
204 type_init(ccw_machine_register_types)
205