1*aba578bdSHuai-Cheng Kuo /* 2*aba578bdSHuai-Cheng Kuo * CXL CDAT Structure 3*aba578bdSHuai-Cheng Kuo * 4*aba578bdSHuai-Cheng Kuo * Copyright (C) 2021 Avery Design Systems, Inc. 5*aba578bdSHuai-Cheng Kuo * 6*aba578bdSHuai-Cheng Kuo * This work is licensed under the terms of the GNU GPL, version 2 or later. 7*aba578bdSHuai-Cheng Kuo * See the COPYING file in the top-level directory. 8*aba578bdSHuai-Cheng Kuo */ 9*aba578bdSHuai-Cheng Kuo 10*aba578bdSHuai-Cheng Kuo #include "qemu/osdep.h" 11*aba578bdSHuai-Cheng Kuo #include "hw/pci/pci.h" 12*aba578bdSHuai-Cheng Kuo #include "hw/cxl/cxl.h" 13*aba578bdSHuai-Cheng Kuo #include "qapi/error.h" 14*aba578bdSHuai-Cheng Kuo #include "qemu/error-report.h" 15*aba578bdSHuai-Cheng Kuo 16*aba578bdSHuai-Cheng Kuo static void cdat_len_check(CDATSubHeader *hdr, Error **errp) 17*aba578bdSHuai-Cheng Kuo { 18*aba578bdSHuai-Cheng Kuo assert(hdr->length); 19*aba578bdSHuai-Cheng Kuo assert(hdr->reserved == 0); 20*aba578bdSHuai-Cheng Kuo 21*aba578bdSHuai-Cheng Kuo switch (hdr->type) { 22*aba578bdSHuai-Cheng Kuo case CDAT_TYPE_DSMAS: 23*aba578bdSHuai-Cheng Kuo assert(hdr->length == sizeof(CDATDsmas)); 24*aba578bdSHuai-Cheng Kuo break; 25*aba578bdSHuai-Cheng Kuo case CDAT_TYPE_DSLBIS: 26*aba578bdSHuai-Cheng Kuo assert(hdr->length == sizeof(CDATDslbis)); 27*aba578bdSHuai-Cheng Kuo break; 28*aba578bdSHuai-Cheng Kuo case CDAT_TYPE_DSMSCIS: 29*aba578bdSHuai-Cheng Kuo assert(hdr->length == sizeof(CDATDsmscis)); 30*aba578bdSHuai-Cheng Kuo break; 31*aba578bdSHuai-Cheng Kuo case CDAT_TYPE_DSIS: 32*aba578bdSHuai-Cheng Kuo assert(hdr->length == sizeof(CDATDsis)); 33*aba578bdSHuai-Cheng Kuo break; 34*aba578bdSHuai-Cheng Kuo case CDAT_TYPE_DSEMTS: 35*aba578bdSHuai-Cheng Kuo assert(hdr->length == sizeof(CDATDsemts)); 36*aba578bdSHuai-Cheng Kuo break; 37*aba578bdSHuai-Cheng Kuo case CDAT_TYPE_SSLBIS: 38*aba578bdSHuai-Cheng Kuo assert(hdr->length >= sizeof(CDATSslbisHeader)); 39*aba578bdSHuai-Cheng Kuo assert((hdr->length - sizeof(CDATSslbisHeader)) % 40*aba578bdSHuai-Cheng Kuo sizeof(CDATSslbe) == 0); 41*aba578bdSHuai-Cheng Kuo break; 42*aba578bdSHuai-Cheng Kuo default: 43*aba578bdSHuai-Cheng Kuo error_setg(errp, "Type %d is reserved", hdr->type); 44*aba578bdSHuai-Cheng Kuo } 45*aba578bdSHuai-Cheng Kuo } 46*aba578bdSHuai-Cheng Kuo 47*aba578bdSHuai-Cheng Kuo static void ct3_build_cdat(CDATObject *cdat, Error **errp) 48*aba578bdSHuai-Cheng Kuo { 49*aba578bdSHuai-Cheng Kuo g_autofree CDATTableHeader *cdat_header = NULL; 50*aba578bdSHuai-Cheng Kuo g_autofree CDATEntry *cdat_st = NULL; 51*aba578bdSHuai-Cheng Kuo uint8_t sum = 0; 52*aba578bdSHuai-Cheng Kuo int ent, i; 53*aba578bdSHuai-Cheng Kuo 54*aba578bdSHuai-Cheng Kuo /* Use default table if fopen == NULL */ 55*aba578bdSHuai-Cheng Kuo assert(cdat->build_cdat_table); 56*aba578bdSHuai-Cheng Kuo 57*aba578bdSHuai-Cheng Kuo cdat_header = g_malloc0(sizeof(*cdat_header)); 58*aba578bdSHuai-Cheng Kuo if (!cdat_header) { 59*aba578bdSHuai-Cheng Kuo error_setg(errp, "Failed to allocate CDAT header"); 60*aba578bdSHuai-Cheng Kuo return; 61*aba578bdSHuai-Cheng Kuo } 62*aba578bdSHuai-Cheng Kuo 63*aba578bdSHuai-Cheng Kuo cdat->built_buf_len = cdat->build_cdat_table(&cdat->built_buf, cdat->private); 64*aba578bdSHuai-Cheng Kuo 65*aba578bdSHuai-Cheng Kuo if (!cdat->built_buf_len) { 66*aba578bdSHuai-Cheng Kuo /* Build later as not all data available yet */ 67*aba578bdSHuai-Cheng Kuo cdat->to_update = true; 68*aba578bdSHuai-Cheng Kuo return; 69*aba578bdSHuai-Cheng Kuo } 70*aba578bdSHuai-Cheng Kuo cdat->to_update = false; 71*aba578bdSHuai-Cheng Kuo 72*aba578bdSHuai-Cheng Kuo cdat_st = g_malloc0(sizeof(*cdat_st) * (cdat->built_buf_len + 1)); 73*aba578bdSHuai-Cheng Kuo if (!cdat_st) { 74*aba578bdSHuai-Cheng Kuo error_setg(errp, "Failed to allocate CDAT entry array"); 75*aba578bdSHuai-Cheng Kuo return; 76*aba578bdSHuai-Cheng Kuo } 77*aba578bdSHuai-Cheng Kuo 78*aba578bdSHuai-Cheng Kuo /* Entry 0 for CDAT header, starts with Entry 1 */ 79*aba578bdSHuai-Cheng Kuo for (ent = 1; ent < cdat->built_buf_len + 1; ent++) { 80*aba578bdSHuai-Cheng Kuo CDATSubHeader *hdr = cdat->built_buf[ent - 1]; 81*aba578bdSHuai-Cheng Kuo uint8_t *buf = (uint8_t *)cdat->built_buf[ent - 1]; 82*aba578bdSHuai-Cheng Kuo 83*aba578bdSHuai-Cheng Kuo cdat_st[ent].base = hdr; 84*aba578bdSHuai-Cheng Kuo cdat_st[ent].length = hdr->length; 85*aba578bdSHuai-Cheng Kuo 86*aba578bdSHuai-Cheng Kuo cdat_header->length += hdr->length; 87*aba578bdSHuai-Cheng Kuo for (i = 0; i < hdr->length; i++) { 88*aba578bdSHuai-Cheng Kuo sum += buf[i]; 89*aba578bdSHuai-Cheng Kuo } 90*aba578bdSHuai-Cheng Kuo } 91*aba578bdSHuai-Cheng Kuo 92*aba578bdSHuai-Cheng Kuo /* CDAT header */ 93*aba578bdSHuai-Cheng Kuo cdat_header->revision = CXL_CDAT_REV; 94*aba578bdSHuai-Cheng Kuo /* For now, no runtime updates */ 95*aba578bdSHuai-Cheng Kuo cdat_header->sequence = 0; 96*aba578bdSHuai-Cheng Kuo cdat_header->length += sizeof(CDATTableHeader); 97*aba578bdSHuai-Cheng Kuo sum += cdat_header->revision + cdat_header->sequence + 98*aba578bdSHuai-Cheng Kuo cdat_header->length; 99*aba578bdSHuai-Cheng Kuo /* Sum of all bytes including checksum must be 0 */ 100*aba578bdSHuai-Cheng Kuo cdat_header->checksum = ~sum + 1; 101*aba578bdSHuai-Cheng Kuo 102*aba578bdSHuai-Cheng Kuo cdat_st[0].base = g_steal_pointer(&cdat_header); 103*aba578bdSHuai-Cheng Kuo cdat_st[0].length = sizeof(*cdat_header); 104*aba578bdSHuai-Cheng Kuo cdat->entry_len = 1 + cdat->built_buf_len; 105*aba578bdSHuai-Cheng Kuo cdat->entry = g_steal_pointer(&cdat_st); 106*aba578bdSHuai-Cheng Kuo } 107*aba578bdSHuai-Cheng Kuo 108*aba578bdSHuai-Cheng Kuo static void ct3_load_cdat(CDATObject *cdat, Error **errp) 109*aba578bdSHuai-Cheng Kuo { 110*aba578bdSHuai-Cheng Kuo g_autofree CDATEntry *cdat_st = NULL; 111*aba578bdSHuai-Cheng Kuo uint8_t sum = 0; 112*aba578bdSHuai-Cheng Kuo int num_ent; 113*aba578bdSHuai-Cheng Kuo int i = 0, ent = 1, file_size = 0; 114*aba578bdSHuai-Cheng Kuo CDATSubHeader *hdr; 115*aba578bdSHuai-Cheng Kuo FILE *fp = NULL; 116*aba578bdSHuai-Cheng Kuo 117*aba578bdSHuai-Cheng Kuo /* Read CDAT file and create its cache */ 118*aba578bdSHuai-Cheng Kuo fp = fopen(cdat->filename, "r"); 119*aba578bdSHuai-Cheng Kuo if (!fp) { 120*aba578bdSHuai-Cheng Kuo error_setg(errp, "CDAT: Unable to open file"); 121*aba578bdSHuai-Cheng Kuo return; 122*aba578bdSHuai-Cheng Kuo } 123*aba578bdSHuai-Cheng Kuo 124*aba578bdSHuai-Cheng Kuo fseek(fp, 0, SEEK_END); 125*aba578bdSHuai-Cheng Kuo file_size = ftell(fp); 126*aba578bdSHuai-Cheng Kuo fseek(fp, 0, SEEK_SET); 127*aba578bdSHuai-Cheng Kuo cdat->buf = g_malloc0(file_size); 128*aba578bdSHuai-Cheng Kuo 129*aba578bdSHuai-Cheng Kuo if (fread(cdat->buf, file_size, 1, fp) == 0) { 130*aba578bdSHuai-Cheng Kuo error_setg(errp, "CDAT: File read failed"); 131*aba578bdSHuai-Cheng Kuo return; 132*aba578bdSHuai-Cheng Kuo } 133*aba578bdSHuai-Cheng Kuo 134*aba578bdSHuai-Cheng Kuo fclose(fp); 135*aba578bdSHuai-Cheng Kuo 136*aba578bdSHuai-Cheng Kuo if (file_size < sizeof(CDATTableHeader)) { 137*aba578bdSHuai-Cheng Kuo error_setg(errp, "CDAT: File too short"); 138*aba578bdSHuai-Cheng Kuo return; 139*aba578bdSHuai-Cheng Kuo } 140*aba578bdSHuai-Cheng Kuo i = sizeof(CDATTableHeader); 141*aba578bdSHuai-Cheng Kuo num_ent = 1; 142*aba578bdSHuai-Cheng Kuo while (i < file_size) { 143*aba578bdSHuai-Cheng Kuo hdr = (CDATSubHeader *)(cdat->buf + i); 144*aba578bdSHuai-Cheng Kuo cdat_len_check(hdr, errp); 145*aba578bdSHuai-Cheng Kuo i += hdr->length; 146*aba578bdSHuai-Cheng Kuo num_ent++; 147*aba578bdSHuai-Cheng Kuo } 148*aba578bdSHuai-Cheng Kuo if (i != file_size) { 149*aba578bdSHuai-Cheng Kuo error_setg(errp, "CDAT: File length missmatch"); 150*aba578bdSHuai-Cheng Kuo return; 151*aba578bdSHuai-Cheng Kuo } 152*aba578bdSHuai-Cheng Kuo 153*aba578bdSHuai-Cheng Kuo cdat_st = g_malloc0(sizeof(*cdat_st) * num_ent); 154*aba578bdSHuai-Cheng Kuo if (!cdat_st) { 155*aba578bdSHuai-Cheng Kuo error_setg(errp, "CDAT: Failed to allocate entry array"); 156*aba578bdSHuai-Cheng Kuo return; 157*aba578bdSHuai-Cheng Kuo } 158*aba578bdSHuai-Cheng Kuo 159*aba578bdSHuai-Cheng Kuo /* Set CDAT header, Entry = 0 */ 160*aba578bdSHuai-Cheng Kuo cdat_st[0].base = cdat->buf; 161*aba578bdSHuai-Cheng Kuo cdat_st[0].length = sizeof(CDATTableHeader); 162*aba578bdSHuai-Cheng Kuo i = 0; 163*aba578bdSHuai-Cheng Kuo 164*aba578bdSHuai-Cheng Kuo while (i < cdat_st[0].length) { 165*aba578bdSHuai-Cheng Kuo sum += cdat->buf[i++]; 166*aba578bdSHuai-Cheng Kuo } 167*aba578bdSHuai-Cheng Kuo 168*aba578bdSHuai-Cheng Kuo /* Read CDAT structures */ 169*aba578bdSHuai-Cheng Kuo while (i < file_size) { 170*aba578bdSHuai-Cheng Kuo hdr = (CDATSubHeader *)(cdat->buf + i); 171*aba578bdSHuai-Cheng Kuo cdat_len_check(hdr, errp); 172*aba578bdSHuai-Cheng Kuo 173*aba578bdSHuai-Cheng Kuo cdat_st[ent].base = hdr; 174*aba578bdSHuai-Cheng Kuo cdat_st[ent].length = hdr->length; 175*aba578bdSHuai-Cheng Kuo 176*aba578bdSHuai-Cheng Kuo while (cdat->buf + i < 177*aba578bdSHuai-Cheng Kuo (uint8_t *)cdat_st[ent].base + cdat_st[ent].length) { 178*aba578bdSHuai-Cheng Kuo assert(i < file_size); 179*aba578bdSHuai-Cheng Kuo sum += cdat->buf[i++]; 180*aba578bdSHuai-Cheng Kuo } 181*aba578bdSHuai-Cheng Kuo 182*aba578bdSHuai-Cheng Kuo ent++; 183*aba578bdSHuai-Cheng Kuo } 184*aba578bdSHuai-Cheng Kuo 185*aba578bdSHuai-Cheng Kuo if (sum != 0) { 186*aba578bdSHuai-Cheng Kuo warn_report("CDAT: Found checksum mismatch in %s", cdat->filename); 187*aba578bdSHuai-Cheng Kuo } 188*aba578bdSHuai-Cheng Kuo cdat->entry_len = num_ent; 189*aba578bdSHuai-Cheng Kuo cdat->entry = g_steal_pointer(&cdat_st); 190*aba578bdSHuai-Cheng Kuo } 191*aba578bdSHuai-Cheng Kuo 192*aba578bdSHuai-Cheng Kuo void cxl_doe_cdat_init(CXLComponentState *cxl_cstate, Error **errp) 193*aba578bdSHuai-Cheng Kuo { 194*aba578bdSHuai-Cheng Kuo CDATObject *cdat = &cxl_cstate->cdat; 195*aba578bdSHuai-Cheng Kuo 196*aba578bdSHuai-Cheng Kuo if (cdat->filename) { 197*aba578bdSHuai-Cheng Kuo ct3_load_cdat(cdat, errp); 198*aba578bdSHuai-Cheng Kuo } else { 199*aba578bdSHuai-Cheng Kuo ct3_build_cdat(cdat, errp); 200*aba578bdSHuai-Cheng Kuo } 201*aba578bdSHuai-Cheng Kuo } 202*aba578bdSHuai-Cheng Kuo 203*aba578bdSHuai-Cheng Kuo void cxl_doe_cdat_update(CXLComponentState *cxl_cstate, Error **errp) 204*aba578bdSHuai-Cheng Kuo { 205*aba578bdSHuai-Cheng Kuo CDATObject *cdat = &cxl_cstate->cdat; 206*aba578bdSHuai-Cheng Kuo 207*aba578bdSHuai-Cheng Kuo if (cdat->to_update) { 208*aba578bdSHuai-Cheng Kuo ct3_build_cdat(cdat, errp); 209*aba578bdSHuai-Cheng Kuo } 210*aba578bdSHuai-Cheng Kuo } 211*aba578bdSHuai-Cheng Kuo 212*aba578bdSHuai-Cheng Kuo void cxl_doe_cdat_release(CXLComponentState *cxl_cstate) 213*aba578bdSHuai-Cheng Kuo { 214*aba578bdSHuai-Cheng Kuo CDATObject *cdat = &cxl_cstate->cdat; 215*aba578bdSHuai-Cheng Kuo 216*aba578bdSHuai-Cheng Kuo free(cdat->entry); 217*aba578bdSHuai-Cheng Kuo if (cdat->built_buf) { 218*aba578bdSHuai-Cheng Kuo cdat->free_cdat_table(cdat->built_buf, cdat->built_buf_len, 219*aba578bdSHuai-Cheng Kuo cdat->private); 220*aba578bdSHuai-Cheng Kuo } 221*aba578bdSHuai-Cheng Kuo if (cdat->buf) { 222*aba578bdSHuai-Cheng Kuo free(cdat->buf); 223*aba578bdSHuai-Cheng Kuo } 224*aba578bdSHuai-Cheng Kuo } 225