qemu

Форк
0
/
cxl.c 
326 строк · 10.8 Кб
1
/*
2
 * CXL ACPI Implementation
3
 *
4
 * Copyright(C) 2020 Intel Corporation.
5
 *
6
 * This library is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU Lesser General Public
8
 * License as published by the Free Software Foundation; either
9
 * version 2 of the License, or (at your option) any later version.
10
 *
11
 * This library is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
 * Lesser General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU Lesser General Public
17
 * License along with this library; if not, see <http://www.gnu.org/licenses/>
18
 */
19

20
#include "qemu/osdep.h"
21
#include "hw/sysbus.h"
22
#include "hw/pci/pci_bridge.h"
23
#include "hw/pci/pci_host.h"
24
#include "hw/cxl/cxl.h"
25
#include "hw/mem/memory-device.h"
26
#include "hw/acpi/acpi.h"
27
#include "hw/acpi/aml-build.h"
28
#include "hw/acpi/bios-linker-loader.h"
29
#include "hw/acpi/cxl.h"
30
#include "qapi/error.h"
31
#include "qemu/uuid.h"
32

33
void build_cxl_dsm_method(Aml *dev)
34
{
35
    Aml *method, *ifctx, *ifctx2;
36

37
    method = aml_method("_DSM", 4, AML_SERIALIZED);
38
    {
39
        Aml *function, *uuid;
40

41
        uuid = aml_arg(0);
42
        function = aml_arg(2);
43
        /* CXL spec v3.0 9.17.3.1 _DSM Function for Retrieving QTG ID */
44
        ifctx = aml_if(aml_equal(
45
            uuid, aml_touuid("F365F9A6-A7DE-4071-A66A-B40C0B4F8E52")));
46

47
        /* Function 0, standard DSM query function */
48
        ifctx2 = aml_if(aml_equal(function, aml_int(0)));
49
        {
50
            uint8_t byte_list[1] = { 0x01 }; /* function 1 only */
51

52
            aml_append(ifctx2,
53
                       aml_return(aml_buffer(sizeof(byte_list), byte_list)));
54
        }
55
        aml_append(ifctx, ifctx2);
56

57
        /*
58
         * Function 1
59
         * Creating a package with static values. The max supported QTG ID will
60
         * be 1 and recommended QTG IDs are 0 and then 1.
61
         * The values here are statically created to simplify emulation. Values
62
         * from a real BIOS would be determined by the performance of all the
63
         * present CXL memory and then assigned.
64
         */
65
        ifctx2 = aml_if(aml_equal(function, aml_int(1)));
66
        {
67
            Aml *pak, *pak1;
68

69
            /*
70
             * Return: A package containing two elements - a WORD that returns
71
             * the maximum throttling group that the platform supports, and a
72
             * package containing the QTG ID(s) that the platform recommends.
73
             * Package {
74
             *     Max Supported QTG ID
75
             *     Package {QTG Recommendations}
76
             * }
77
             *
78
             * While the SPEC specified WORD that hints at the value being
79
             * 16bit, the ACPI dump of BIOS DSDT table showed that the values
80
             * are integers with no specific size specification. aml_int() will
81
             * be used for the values.
82
             */
83
            pak1 = aml_package(2);
84
            /* Set QTG ID of 0 */
85
            aml_append(pak1, aml_int(0));
86
            /* Set QTG ID of 1 */
87
            aml_append(pak1, aml_int(1));
88

89
            pak = aml_package(2);
90
            /* Set Max QTG 1 */
91
            aml_append(pak, aml_int(1));
92
            aml_append(pak, pak1);
93

94
            aml_append(ifctx2, aml_return(pak));
95
        }
96
        aml_append(ifctx, ifctx2);
97
    }
98
    aml_append(method, ifctx);
99
    aml_append(dev, method);
100
}
101

102
static void cedt_build_chbs(GArray *table_data, PXBCXLDev *cxl)
103
{
104
    PXBDev *pxb = PXB_DEV(cxl);
105
    SysBusDevice *sbd = SYS_BUS_DEVICE(cxl->cxl_host_bridge);
106
    struct MemoryRegion *mr = sbd->mmio[0].memory;
107

108
    /* Type */
109
    build_append_int_noprefix(table_data, 0, 1);
110

111
    /* Reserved */
112
    build_append_int_noprefix(table_data, 0, 1);
113

114
    /* Record Length */
115
    build_append_int_noprefix(table_data, 32, 2);
116

117
    /* UID - currently equal to bus number */
118
    build_append_int_noprefix(table_data, pxb->bus_nr, 4);
119

120
    /* Version */
121
    build_append_int_noprefix(table_data, 1, 4);
122

123
    /* Reserved */
124
    build_append_int_noprefix(table_data, 0, 4);
125

126
    /* Base - subregion within a container that is in PA space */
127
    build_append_int_noprefix(table_data, mr->container->addr + mr->addr, 8);
128

129
    /* Length */
130
    build_append_int_noprefix(table_data, memory_region_size(mr), 8);
131
}
132

133
/*
134
 * CFMWS entries in CXL 2.0 ECN: CEDT CFMWS & QTG _DSM.
135
 * Interleave ways encoding in CXL 2.0 ECN: 3, 6, 12 and 16-way memory
136
 * interleaving.
137
 */
138
static void cedt_build_cfmws(GArray *table_data, CXLState *cxls)
139
{
140
    GList *it;
141

142
    for (it = cxls->fixed_windows; it; it = it->next) {
143
        CXLFixedWindow *fw = it->data;
144
        int i;
145

146
        /* Type */
147
        build_append_int_noprefix(table_data, 1, 1);
148

149
        /* Reserved */
150
        build_append_int_noprefix(table_data, 0, 1);
151

152
        /* Record Length */
153
        build_append_int_noprefix(table_data, 36 + 4 * fw->num_targets, 2);
154

155
        /* Reserved */
156
        build_append_int_noprefix(table_data, 0, 4);
157

158
        /* Base HPA */
159
        build_append_int_noprefix(table_data, fw->mr.addr, 8);
160

161
        /* Window Size */
162
        build_append_int_noprefix(table_data, fw->size, 8);
163

164
        /* Host Bridge Interleave Ways */
165
        build_append_int_noprefix(table_data, fw->enc_int_ways, 1);
166

167
        /* Host Bridge Interleave Arithmetic */
168
        build_append_int_noprefix(table_data, 0, 1);
169

170
        /* Reserved */
171
        build_append_int_noprefix(table_data, 0, 2);
172

173
        /* Host Bridge Interleave Granularity */
174
        build_append_int_noprefix(table_data, fw->enc_int_gran, 4);
175

176
        /* Window Restrictions */
177
        build_append_int_noprefix(table_data, 0x0f, 2); /* No restrictions */
178

179
        /* QTG ID */
180
        build_append_int_noprefix(table_data, 0, 2);
181

182
        /* Host Bridge List (list of UIDs - currently bus_nr) */
183
        for (i = 0; i < fw->num_targets; i++) {
184
            g_assert(fw->target_hbs[i]);
185
            build_append_int_noprefix(table_data, PXB_DEV(fw->target_hbs[i])->bus_nr, 4);
186
        }
187
    }
188
}
189

190
static int cxl_foreach_pxb_hb(Object *obj, void *opaque)
191
{
192
    Aml *cedt = opaque;
193

194
    if (object_dynamic_cast(obj, TYPE_PXB_CXL_DEV)) {
195
        cedt_build_chbs(cedt->buf, PXB_CXL_DEV(obj));
196
    }
197

198
    return 0;
199
}
200

201
void cxl_build_cedt(GArray *table_offsets, GArray *table_data,
202
                    BIOSLinker *linker, const char *oem_id,
203
                    const char *oem_table_id, CXLState *cxl_state)
204
{
205
    Aml *cedt;
206
    AcpiTable table = { .sig = "CEDT", .rev = 1, .oem_id = oem_id,
207
                        .oem_table_id = oem_table_id };
208

209
    acpi_add_table(table_offsets, table_data);
210
    acpi_table_begin(&table, table_data);
211
    cedt = init_aml_allocator();
212

213
    /* reserve space for CEDT header */
214

215
    object_child_foreach_recursive(object_get_root(), cxl_foreach_pxb_hb, cedt);
216
    cedt_build_cfmws(cedt->buf, cxl_state);
217

218
    /* copy AML table into ACPI tables blob and patch header there */
219
    g_array_append_vals(table_data, cedt->buf->data, cedt->buf->len);
220
    free_aml_allocator();
221

222
    acpi_table_end(linker, &table);
223
}
224

225
static Aml *__build_cxl_osc_method(void)
226
{
227
    Aml *method, *if_uuid, *else_uuid, *if_arg1_not_1, *if_cxl, *if_caps_masked;
228
    Aml *a_ctrl = aml_local(0);
229
    Aml *a_cdw1 = aml_name("CDW1");
230

231
    method = aml_method("_OSC", 4, AML_NOTSERIALIZED);
232
    /* CDW1 is used for the return value so is present whether or not a match occurs */
233
    aml_append(method, aml_create_dword_field(aml_arg(3), aml_int(0), "CDW1"));
234

235
    /*
236
     * Generate shared section between:
237
     * CXL 2.0 - 9.14.2.1.4 and
238
     * PCI Firmware Specification 3.0
239
     * 4.5.1. _OSC Interface for PCI Host Bridge Devices
240
     * The _OSC interface for a PCI/PCI-X/PCI Express hierarchy is
241
     * identified by the Universal Unique IDentifier (UUID)
242
     * 33DB4D5B-1FF7-401C-9657-7441C03DD766
243
     * The _OSC interface for a CXL Host bridge is
244
     * identified by the UUID 68F2D50B-C469-4D8A-BD3D-941A103FD3FC
245
     * A CXL Host bridge is compatible with a PCI host bridge so
246
     * for the shared section match both.
247
     */
248
    if_uuid = aml_if(
249
        aml_lor(aml_equal(aml_arg(0),
250
                          aml_touuid("33DB4D5B-1FF7-401C-9657-7441C03DD766")),
251
                aml_equal(aml_arg(0),
252
                          aml_touuid("68F2D50B-C469-4D8A-BD3D-941A103FD3FC"))));
253
    aml_append(if_uuid, aml_create_dword_field(aml_arg(3), aml_int(4), "CDW2"));
254
    aml_append(if_uuid, aml_create_dword_field(aml_arg(3), aml_int(8), "CDW3"));
255

256
    aml_append(if_uuid, aml_store(aml_name("CDW3"), a_ctrl));
257

258
    /*
259
     *
260
     * Allows OS control for all 5 features:
261
     * PCIeHotplug SHPCHotplug PME AER PCIeCapability
262
     */
263
    aml_append(if_uuid, aml_and(a_ctrl, aml_int(0x1F), a_ctrl));
264

265
    /*
266
     * Check _OSC revision.
267
     * PCI Firmware specification 3.3 and CXL 2.0 both use revision 1
268
     * Unknown Revision is CDW1 - BIT (3)
269
     */
270
    if_arg1_not_1 = aml_if(aml_lnot(aml_equal(aml_arg(1), aml_int(0x1))));
271
    aml_append(if_arg1_not_1, aml_or(a_cdw1, aml_int(0x08), a_cdw1));
272
    aml_append(if_uuid, if_arg1_not_1);
273

274
    if_caps_masked = aml_if(aml_lnot(aml_equal(aml_name("CDW3"), a_ctrl)));
275

276
    /* Capability bits were masked */
277
    aml_append(if_caps_masked, aml_or(a_cdw1, aml_int(0x10), a_cdw1));
278
    aml_append(if_uuid, if_caps_masked);
279

280
    aml_append(if_uuid, aml_store(aml_name("CDW2"), aml_name("SUPP")));
281
    aml_append(if_uuid, aml_store(aml_name("CDW3"), aml_name("CTRL")));
282

283
    /* Update DWORD3 (the return value) */
284
    aml_append(if_uuid, aml_store(a_ctrl, aml_name("CDW3")));
285

286
    /* CXL only section as per CXL 2.0 - 9.14.2.1.4 */
287
    if_cxl = aml_if(aml_equal(
288
        aml_arg(0), aml_touuid("68F2D50B-C469-4D8A-BD3D-941A103FD3FC")));
289
    /* CXL support field */
290
    aml_append(if_cxl, aml_create_dword_field(aml_arg(3), aml_int(12), "CDW4"));
291
    /* CXL capabilities */
292
    aml_append(if_cxl, aml_create_dword_field(aml_arg(3), aml_int(16), "CDW5"));
293
    aml_append(if_cxl, aml_store(aml_name("CDW4"), aml_name("SUPC")));
294
    aml_append(if_cxl, aml_store(aml_name("CDW5"), aml_name("CTRC")));
295

296
    /* CXL 2.0 Port/Device Register access */
297
    aml_append(if_cxl,
298
               aml_or(aml_name("CDW5"), aml_int(0x1), aml_name("CDW5")));
299
    aml_append(if_uuid, if_cxl);
300

301
    aml_append(if_uuid, aml_return(aml_arg(3)));
302
    aml_append(method, if_uuid);
303

304
    /*
305
     * If no UUID matched, return Unrecognized UUID via Arg3 DWord 1
306
     * ACPI 6.4 - 6.2.11
307
     * Unrecognised UUID - BIT(2)
308
     */
309
    else_uuid = aml_else();
310

311
    aml_append(else_uuid,
312
               aml_or(aml_name("CDW1"), aml_int(0x4), aml_name("CDW1")));
313
    aml_append(else_uuid, aml_return(aml_arg(3)));
314
    aml_append(method, else_uuid);
315

316
    return method;
317
}
318

319
void build_cxl_osc_method(Aml *dev)
320
{
321
    aml_append(dev, aml_name_decl("SUPP", aml_int(0)));
322
    aml_append(dev, aml_name_decl("CTRL", aml_int(0)));
323
    aml_append(dev, aml_name_decl("SUPC", aml_int(0)));
324
    aml_append(dev, aml_name_decl("CTRC", aml_int(0)));
325
    aml_append(dev, __build_cxl_osc_method());
326
}
327

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.