]> Git Repo - qemu.git/blob - hw/cxl/cxl-mailbox-utils.c
hw/cxl/device: Implement basic mailbox (8.2.8.4)
[qemu.git] / hw / cxl / cxl-mailbox-utils.c
1 /*
2  * CXL Utility library for mailbox interface
3  *
4  * Copyright(C) 2020 Intel Corporation.
5  *
6  * This work is licensed under the terms of the GNU GPL, version 2. See the
7  * COPYING file in the top-level directory.
8  */
9
10 #include "qemu/osdep.h"
11 #include "hw/cxl/cxl.h"
12 #include "hw/pci/pci.h"
13 #include "qemu/log.h"
14 #include "qemu/uuid.h"
15
16 /*
17  * How to add a new command, example. The command set FOO, with cmd BAR.
18  *  1. Add the command set and cmd to the enum.
19  *     FOO    = 0x7f,
20  *          #define BAR 0
21  *  2. Implement the handler
22  *    static ret_code cmd_foo_bar(struct cxl_cmd *cmd,
23  *                                  CXLDeviceState *cxl_dstate, uint16_t *len)
24  *  3. Add the command to the cxl_cmd_set[][]
25  *    [FOO][BAR] = { "FOO_BAR", cmd_foo_bar, x, y },
26  *  4. Implement your handler
27  *     define_mailbox_handler(FOO_BAR) { ... return CXL_MBOX_SUCCESS; }
28  *
29  *
30  *  Writing the handler:
31  *    The handler will provide the &struct cxl_cmd, the &CXLDeviceState, and the
32  *    in/out length of the payload. The handler is responsible for consuming the
33  *    payload from cmd->payload and operating upon it as necessary. It must then
34  *    fill the output data into cmd->payload (overwriting what was there),
35  *    setting the length, and returning a valid return code.
36  *
37  *  XXX: The handler need not worry about endianess. The payload is read out of
38  *  a register interface that already deals with it.
39  */
40
41 /* 8.2.8.4.5.1 Command Return Codes */
42 typedef enum {
43     CXL_MBOX_SUCCESS = 0x0,
44     CXL_MBOX_BG_STARTED = 0x1,
45     CXL_MBOX_INVALID_INPUT = 0x2,
46     CXL_MBOX_UNSUPPORTED = 0x3,
47     CXL_MBOX_INTERNAL_ERROR = 0x4,
48     CXL_MBOX_RETRY_REQUIRED = 0x5,
49     CXL_MBOX_BUSY = 0x6,
50     CXL_MBOX_MEDIA_DISABLED = 0x7,
51     CXL_MBOX_FW_XFER_IN_PROGRESS = 0x8,
52     CXL_MBOX_FW_XFER_OUT_OF_ORDER = 0x9,
53     CXL_MBOX_FW_AUTH_FAILED = 0xa,
54     CXL_MBOX_FW_INVALID_SLOT = 0xb,
55     CXL_MBOX_FW_ROLLEDBACK = 0xc,
56     CXL_MBOX_FW_REST_REQD = 0xd,
57     CXL_MBOX_INVALID_HANDLE = 0xe,
58     CXL_MBOX_INVALID_PA = 0xf,
59     CXL_MBOX_INJECT_POISON_LIMIT = 0x10,
60     CXL_MBOX_PERMANENT_MEDIA_FAILURE = 0x11,
61     CXL_MBOX_ABORTED = 0x12,
62     CXL_MBOX_INVALID_SECURITY_STATE = 0x13,
63     CXL_MBOX_INCORRECT_PASSPHRASE = 0x14,
64     CXL_MBOX_UNSUPPORTED_MAILBOX = 0x15,
65     CXL_MBOX_INVALID_PAYLOAD_LENGTH = 0x16,
66     CXL_MBOX_MAX = 0x17
67 } ret_code;
68
69 struct cxl_cmd;
70 typedef ret_code (*opcode_handler)(struct cxl_cmd *cmd,
71                                    CXLDeviceState *cxl_dstate, uint16_t *len);
72 struct cxl_cmd {
73     const char *name;
74     opcode_handler handler;
75     ssize_t in;
76     uint16_t effect; /* Reported in CEL */
77     uint8_t *payload;
78 };
79
80 #define DEFINE_MAILBOX_HANDLER_ZEROED(name, size)                         \
81     uint16_t __zero##name = size;                                         \
82     static ret_code cmd_##name(struct cxl_cmd *cmd,                       \
83                                CXLDeviceState *cxl_dstate, uint16_t *len) \
84     {                                                                     \
85         *len = __zero##name;                                              \
86         memset(cmd->payload, 0, *len);                                    \
87         return CXL_MBOX_SUCCESS;                                          \
88     }
89 #define DEFINE_MAILBOX_HANDLER_NOP(name)                                  \
90     static ret_code cmd_##name(struct cxl_cmd *cmd,                       \
91                                CXLDeviceState *cxl_dstate, uint16_t *len) \
92     {                                                                     \
93         return CXL_MBOX_SUCCESS;                                          \
94     }
95
96 static QemuUUID cel_uuid;
97
98 static struct cxl_cmd cxl_cmd_set[256][256] = {};
99
100 void cxl_process_mailbox(CXLDeviceState *cxl_dstate)
101 {
102     uint16_t ret = CXL_MBOX_SUCCESS;
103     struct cxl_cmd *cxl_cmd;
104     uint64_t status_reg;
105     opcode_handler h;
106     uint64_t command_reg = cxl_dstate->mbox_reg_state64[R_CXL_DEV_MAILBOX_CMD];
107
108     uint8_t set = FIELD_EX64(command_reg, CXL_DEV_MAILBOX_CMD, COMMAND_SET);
109     uint8_t cmd = FIELD_EX64(command_reg, CXL_DEV_MAILBOX_CMD, COMMAND);
110     uint16_t len = FIELD_EX64(command_reg, CXL_DEV_MAILBOX_CMD, LENGTH);
111     cxl_cmd = &cxl_cmd_set[set][cmd];
112     h = cxl_cmd->handler;
113     if (h) {
114         if (len == cxl_cmd->in) {
115             cxl_cmd->payload = cxl_dstate->mbox_reg_state +
116                 A_CXL_DEV_CMD_PAYLOAD;
117             ret = (*h)(cxl_cmd, cxl_dstate, &len);
118             assert(len <= cxl_dstate->payload_size);
119         } else {
120             ret = CXL_MBOX_INVALID_PAYLOAD_LENGTH;
121         }
122     } else {
123         qemu_log_mask(LOG_UNIMP, "Command %04xh not implemented\n",
124                       set << 8 | cmd);
125         ret = CXL_MBOX_UNSUPPORTED;
126     }
127
128     /* Set the return code */
129     status_reg = FIELD_DP64(0, CXL_DEV_MAILBOX_STS, ERRNO, ret);
130
131     /* Set the return length */
132     command_reg = FIELD_DP64(command_reg, CXL_DEV_MAILBOX_CMD, COMMAND_SET, 0);
133     command_reg = FIELD_DP64(command_reg, CXL_DEV_MAILBOX_CMD, COMMAND, 0);
134     command_reg = FIELD_DP64(command_reg, CXL_DEV_MAILBOX_CMD, LENGTH, len);
135
136     cxl_dstate->mbox_reg_state64[R_CXL_DEV_MAILBOX_CMD] = command_reg;
137     cxl_dstate->mbox_reg_state64[R_CXL_DEV_MAILBOX_STS] = status_reg;
138
139     /* Tell the host we're done */
140     ARRAY_FIELD_DP32(cxl_dstate->mbox_reg_state32, CXL_DEV_MAILBOX_CTRL,
141                      DOORBELL, 0);
142 }
143
144 int cxl_initialize_mailbox(CXLDeviceState *cxl_dstate)
145 {
146     /* CXL 2.0: Table 169 Get Supported Logs Log Entry */
147     const char *cel_uuidstr = "0da9c0b5-bf41-4b78-8f79-96b1623b3f17";
148
149     for (int set = 0; set < 256; set++) {
150         for (int cmd = 0; cmd < 256; cmd++) {
151             if (cxl_cmd_set[set][cmd].handler) {
152                 struct cxl_cmd *c = &cxl_cmd_set[set][cmd];
153                 struct cel_log *log =
154                     &cxl_dstate->cel_log[cxl_dstate->cel_size];
155
156                 log->opcode = (set << 8) | cmd;
157                 log->effect = c->effect;
158                 cxl_dstate->cel_size++;
159             }
160         }
161     }
162
163     return qemu_uuid_parse(cel_uuidstr, &cel_uuid);
164 }
This page took 0.036132 seconds and 4 git commands to generate.