qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

cxl-device-utils.c (8449B)


      1 /*
      2  * CXL Utility library for devices
      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 "qemu/log.h"
     12 #include "hw/cxl/cxl.h"
     13 
     14 /*
     15  * Device registers have no restrictions per the spec, and so fall back to the
     16  * default memory mapped register rules in 8.2:
     17  *   Software shall use CXL.io Memory Read and Write to access memory mapped
     18  *   register defined in this section. Unless otherwise specified, software
     19  *   shall restrict the accesses width based on the following:
     20  *   • A 32 bit register shall be accessed as a 1 Byte, 2 Bytes or 4 Bytes
     21  *     quantity.
     22  *   • A 64 bit register shall be accessed as a 1 Byte, 2 Bytes, 4 Bytes or 8
     23  *     Bytes
     24  *   • The address shall be a multiple of the access width, e.g. when
     25  *     accessing a register as a 4 Byte quantity, the address shall be
     26  *     multiple of 4.
     27  *   • The accesses shall map to contiguous bytes.If these rules are not
     28  *     followed, the behavior is undefined
     29  */
     30 
     31 static uint64_t caps_reg_read(void *opaque, hwaddr offset, unsigned size)
     32 {
     33     CXLDeviceState *cxl_dstate = opaque;
     34 
     35     if (size == 4) {
     36         return cxl_dstate->caps_reg_state32[offset / sizeof(*cxl_dstate->caps_reg_state32)];
     37     } else {
     38         return cxl_dstate->caps_reg_state64[offset / sizeof(*cxl_dstate->caps_reg_state64)];
     39     }
     40 }
     41 
     42 static uint64_t dev_reg_read(void *opaque, hwaddr offset, unsigned size)
     43 {
     44     return 0;
     45 }
     46 
     47 static uint64_t mailbox_reg_read(void *opaque, hwaddr offset, unsigned size)
     48 {
     49     CXLDeviceState *cxl_dstate = opaque;
     50 
     51     switch (size) {
     52     case 1:
     53         return cxl_dstate->mbox_reg_state[offset];
     54     case 2:
     55         return cxl_dstate->mbox_reg_state16[offset / size];
     56     case 4:
     57         return cxl_dstate->mbox_reg_state32[offset / size];
     58     case 8:
     59         return cxl_dstate->mbox_reg_state64[offset / size];
     60     default:
     61         g_assert_not_reached();
     62     }
     63 }
     64 
     65 static void mailbox_mem_writel(uint32_t *reg_state, hwaddr offset,
     66                                uint64_t value)
     67 {
     68     switch (offset) {
     69     case A_CXL_DEV_MAILBOX_CTRL:
     70         /* fallthrough */
     71     case A_CXL_DEV_MAILBOX_CAP:
     72         /* RO register */
     73         break;
     74     default:
     75         qemu_log_mask(LOG_UNIMP,
     76                       "%s Unexpected 32-bit access to 0x%" PRIx64 " (WI)\n",
     77                       __func__, offset);
     78         return;
     79     }
     80 
     81     reg_state[offset / sizeof(*reg_state)] = value;
     82 }
     83 
     84 static void mailbox_mem_writeq(uint64_t *reg_state, hwaddr offset,
     85                                uint64_t value)
     86 {
     87     switch (offset) {
     88     case A_CXL_DEV_MAILBOX_CMD:
     89         break;
     90     case A_CXL_DEV_BG_CMD_STS:
     91         /* BG not supported */
     92         /* fallthrough */
     93     case A_CXL_DEV_MAILBOX_STS:
     94         /* Read only register, will get updated by the state machine */
     95         return;
     96     default:
     97         qemu_log_mask(LOG_UNIMP,
     98                       "%s Unexpected 64-bit access to 0x%" PRIx64 " (WI)\n",
     99                       __func__, offset);
    100         return;
    101     }
    102 
    103 
    104     reg_state[offset / sizeof(*reg_state)] = value;
    105 }
    106 
    107 static void mailbox_reg_write(void *opaque, hwaddr offset, uint64_t value,
    108                               unsigned size)
    109 {
    110     CXLDeviceState *cxl_dstate = opaque;
    111 
    112     if (offset >= A_CXL_DEV_CMD_PAYLOAD) {
    113         memcpy(cxl_dstate->mbox_reg_state + offset, &value, size);
    114         return;
    115     }
    116 
    117     switch (size) {
    118     case 4:
    119         mailbox_mem_writel(cxl_dstate->mbox_reg_state32, offset, value);
    120         break;
    121     case 8:
    122         mailbox_mem_writeq(cxl_dstate->mbox_reg_state64, offset, value);
    123         break;
    124     default:
    125         g_assert_not_reached();
    126     }
    127 
    128     if (ARRAY_FIELD_EX32(cxl_dstate->mbox_reg_state32, CXL_DEV_MAILBOX_CTRL,
    129                          DOORBELL)) {
    130         cxl_process_mailbox(cxl_dstate);
    131     }
    132 }
    133 
    134 static uint64_t mdev_reg_read(void *opaque, hwaddr offset, unsigned size)
    135 {
    136     uint64_t retval = 0;
    137 
    138     retval = FIELD_DP64(retval, CXL_MEM_DEV_STS, MEDIA_STATUS, 1);
    139     retval = FIELD_DP64(retval, CXL_MEM_DEV_STS, MBOX_READY, 1);
    140 
    141     return retval;
    142 }
    143 
    144 static void ro_reg_write(void *opaque, hwaddr offset, uint64_t value,
    145                            unsigned size)
    146 {
    147     /* Many register sets are read only */
    148 }
    149 
    150 static const MemoryRegionOps mdev_ops = {
    151     .read = mdev_reg_read,
    152     .write = ro_reg_write,
    153     .endianness = DEVICE_LITTLE_ENDIAN,
    154     .valid = {
    155         .min_access_size = 1,
    156         .max_access_size = 8,
    157         .unaligned = false,
    158     },
    159     .impl = {
    160         .min_access_size = 8,
    161         .max_access_size = 8,
    162     },
    163 };
    164 
    165 static const MemoryRegionOps mailbox_ops = {
    166     .read = mailbox_reg_read,
    167     .write = mailbox_reg_write,
    168     .endianness = DEVICE_LITTLE_ENDIAN,
    169     .valid = {
    170         .min_access_size = 1,
    171         .max_access_size = 8,
    172         .unaligned = false,
    173     },
    174     .impl = {
    175         .min_access_size = 1,
    176         .max_access_size = 8,
    177     },
    178 };
    179 
    180 static const MemoryRegionOps dev_ops = {
    181     .read = dev_reg_read,
    182     .write = ro_reg_write,
    183     .endianness = DEVICE_LITTLE_ENDIAN,
    184     .valid = {
    185         .min_access_size = 1,
    186         .max_access_size = 8,
    187         .unaligned = false,
    188     },
    189     .impl = {
    190         .min_access_size = 1,
    191         .max_access_size = 8,
    192     },
    193 };
    194 
    195 static const MemoryRegionOps caps_ops = {
    196     .read = caps_reg_read,
    197     .write = ro_reg_write,
    198     .endianness = DEVICE_LITTLE_ENDIAN,
    199     .valid = {
    200         .min_access_size = 1,
    201         .max_access_size = 8,
    202         .unaligned = false,
    203     },
    204     .impl = {
    205         .min_access_size = 4,
    206         .max_access_size = 8,
    207     },
    208 };
    209 
    210 void cxl_device_register_block_init(Object *obj, CXLDeviceState *cxl_dstate)
    211 {
    212     /* This will be a BAR, so needs to be rounded up to pow2 for PCI spec */
    213     memory_region_init(&cxl_dstate->device_registers, obj, "device-registers",
    214                        pow2ceil(CXL_MMIO_SIZE));
    215 
    216     memory_region_init_io(&cxl_dstate->caps, obj, &caps_ops, cxl_dstate,
    217                           "cap-array", CXL_CAPS_SIZE);
    218     memory_region_init_io(&cxl_dstate->device, obj, &dev_ops, cxl_dstate,
    219                           "device-status", CXL_DEVICE_STATUS_REGISTERS_LENGTH);
    220     memory_region_init_io(&cxl_dstate->mailbox, obj, &mailbox_ops, cxl_dstate,
    221                           "mailbox", CXL_MAILBOX_REGISTERS_LENGTH);
    222     memory_region_init_io(&cxl_dstate->memory_device, obj, &mdev_ops,
    223                           cxl_dstate, "memory device caps",
    224                           CXL_MEMORY_DEVICE_REGISTERS_LENGTH);
    225 
    226     memory_region_add_subregion(&cxl_dstate->device_registers, 0,
    227                                 &cxl_dstate->caps);
    228     memory_region_add_subregion(&cxl_dstate->device_registers,
    229                                 CXL_DEVICE_STATUS_REGISTERS_OFFSET,
    230                                 &cxl_dstate->device);
    231     memory_region_add_subregion(&cxl_dstate->device_registers,
    232                                 CXL_MAILBOX_REGISTERS_OFFSET,
    233                                 &cxl_dstate->mailbox);
    234     memory_region_add_subregion(&cxl_dstate->device_registers,
    235                                 CXL_MEMORY_DEVICE_REGISTERS_OFFSET,
    236                                 &cxl_dstate->memory_device);
    237 }
    238 
    239 static void device_reg_init_common(CXLDeviceState *cxl_dstate) { }
    240 
    241 static void mailbox_reg_init_common(CXLDeviceState *cxl_dstate)
    242 {
    243     /* 2048 payload size, with no interrupt or background support */
    244     ARRAY_FIELD_DP32(cxl_dstate->mbox_reg_state32, CXL_DEV_MAILBOX_CAP,
    245                      PAYLOAD_SIZE, CXL_MAILBOX_PAYLOAD_SHIFT);
    246     cxl_dstate->payload_size = CXL_MAILBOX_MAX_PAYLOAD_SIZE;
    247 }
    248 
    249 static void memdev_reg_init_common(CXLDeviceState *cxl_dstate) { }
    250 
    251 void cxl_device_register_init_common(CXLDeviceState *cxl_dstate)
    252 {
    253     uint64_t *cap_hdrs = cxl_dstate->caps_reg_state64;
    254     const int cap_count = 3;
    255 
    256     /* CXL Device Capabilities Array Register */
    257     ARRAY_FIELD_DP64(cap_hdrs, CXL_DEV_CAP_ARRAY, CAP_ID, 0);
    258     ARRAY_FIELD_DP64(cap_hdrs, CXL_DEV_CAP_ARRAY, CAP_VERSION, 1);
    259     ARRAY_FIELD_DP64(cap_hdrs, CXL_DEV_CAP_ARRAY, CAP_COUNT, cap_count);
    260 
    261     cxl_device_cap_init(cxl_dstate, DEVICE_STATUS, 1);
    262     device_reg_init_common(cxl_dstate);
    263 
    264     cxl_device_cap_init(cxl_dstate, MAILBOX, 2);
    265     mailbox_reg_init_common(cxl_dstate);
    266 
    267     cxl_device_cap_init(cxl_dstate, MEMORY_DEVICE, 0x4000);
    268     memdev_reg_init_common(cxl_dstate);
    269 
    270     assert(cxl_initialize_mailbox(cxl_dstate) == 0);
    271 }