4 * Copyright (C) 2021 Avery Design Systems, Inc.
6 * This work is licensed under the terms of the GNU GPL, version 2 or later.
7 * See the COPYING file in the top-level directory.
10 #include "qemu/osdep.h"
11 #include "hw/pci/pci.h"
12 #include "hw/cxl/cxl.h"
13 #include "qapi/error.h"
14 #include "qemu/error-report.h"
16 static void cdat_len_check(CDATSubHeader
*hdr
, Error
**errp
)
19 assert(hdr
->reserved
== 0);
23 assert(hdr
->length
== sizeof(CDATDsmas
));
25 case CDAT_TYPE_DSLBIS
:
26 assert(hdr
->length
== sizeof(CDATDslbis
));
28 case CDAT_TYPE_DSMSCIS
:
29 assert(hdr
->length
== sizeof(CDATDsmscis
));
32 assert(hdr
->length
== sizeof(CDATDsis
));
34 case CDAT_TYPE_DSEMTS
:
35 assert(hdr
->length
== sizeof(CDATDsemts
));
37 case CDAT_TYPE_SSLBIS
:
38 assert(hdr
->length
>= sizeof(CDATSslbisHeader
));
39 assert((hdr
->length
- sizeof(CDATSslbisHeader
)) %
40 sizeof(CDATSslbe
) == 0);
43 error_setg(errp
, "Type %d is reserved", hdr
->type
);
47 static void ct3_build_cdat(CDATObject
*cdat
, Error
**errp
)
49 g_autofree CDATTableHeader
*cdat_header
= NULL
;
50 g_autofree CDATEntry
*cdat_st
= NULL
;
54 /* Use default table if fopen == NULL */
55 assert(cdat
->build_cdat_table
);
57 cdat_header
= g_malloc0(sizeof(*cdat_header
));
59 error_setg(errp
, "Failed to allocate CDAT header");
63 cdat
->built_buf_len
= cdat
->build_cdat_table(&cdat
->built_buf
, cdat
->private);
65 if (!cdat
->built_buf_len
) {
66 /* Build later as not all data available yet */
67 cdat
->to_update
= true;
70 cdat
->to_update
= false;
72 cdat_st
= g_malloc0(sizeof(*cdat_st
) * (cdat
->built_buf_len
+ 1));
74 error_setg(errp
, "Failed to allocate CDAT entry array");
78 /* Entry 0 for CDAT header, starts with Entry 1 */
79 for (ent
= 1; ent
< cdat
->built_buf_len
+ 1; ent
++) {
80 CDATSubHeader
*hdr
= cdat
->built_buf
[ent
- 1];
81 uint8_t *buf
= (uint8_t *)cdat
->built_buf
[ent
- 1];
83 cdat_st
[ent
].base
= hdr
;
84 cdat_st
[ent
].length
= hdr
->length
;
86 cdat_header
->length
+= hdr
->length
;
87 for (i
= 0; i
< hdr
->length
; i
++) {
93 cdat_header
->revision
= CXL_CDAT_REV
;
94 /* For now, no runtime updates */
95 cdat_header
->sequence
= 0;
96 cdat_header
->length
+= sizeof(CDATTableHeader
);
97 sum
+= cdat_header
->revision
+ cdat_header
->sequence
+
99 /* Sum of all bytes including checksum must be 0 */
100 cdat_header
->checksum
= ~sum
+ 1;
102 cdat_st
[0].base
= g_steal_pointer(&cdat_header
);
103 cdat_st
[0].length
= sizeof(*cdat_header
);
104 cdat
->entry_len
= 1 + cdat
->built_buf_len
;
105 cdat
->entry
= g_steal_pointer(&cdat_st
);
108 static void ct3_load_cdat(CDATObject
*cdat
, Error
**errp
)
110 g_autofree CDATEntry
*cdat_st
= NULL
;
113 int i
= 0, ent
= 1, file_size
= 0;
117 /* Read CDAT file and create its cache */
118 fp
= fopen(cdat
->filename
, "r");
120 error_setg(errp
, "CDAT: Unable to open file");
124 fseek(fp
, 0, SEEK_END
);
125 file_size
= ftell(fp
);
126 fseek(fp
, 0, SEEK_SET
);
127 cdat
->buf
= g_malloc0(file_size
);
129 if (fread(cdat
->buf
, file_size
, 1, fp
) == 0) {
130 error_setg(errp
, "CDAT: File read failed");
136 if (file_size
< sizeof(CDATTableHeader
)) {
137 error_setg(errp
, "CDAT: File too short");
140 i
= sizeof(CDATTableHeader
);
142 while (i
< file_size
) {
143 hdr
= (CDATSubHeader
*)(cdat
->buf
+ i
);
144 cdat_len_check(hdr
, errp
);
148 if (i
!= file_size
) {
149 error_setg(errp
, "CDAT: File length mismatch");
153 cdat_st
= g_malloc0(sizeof(*cdat_st
) * num_ent
);
155 error_setg(errp
, "CDAT: Failed to allocate entry array");
159 /* Set CDAT header, Entry = 0 */
160 cdat_st
[0].base
= cdat
->buf
;
161 cdat_st
[0].length
= sizeof(CDATTableHeader
);
164 while (i
< cdat_st
[0].length
) {
165 sum
+= cdat
->buf
[i
++];
168 /* Read CDAT structures */
169 while (i
< file_size
) {
170 hdr
= (CDATSubHeader
*)(cdat
->buf
+ i
);
171 cdat_len_check(hdr
, errp
);
173 cdat_st
[ent
].base
= hdr
;
174 cdat_st
[ent
].length
= hdr
->length
;
176 while (cdat
->buf
+ i
<
177 (uint8_t *)cdat_st
[ent
].base
+ cdat_st
[ent
].length
) {
178 assert(i
< file_size
);
179 sum
+= cdat
->buf
[i
++];
186 warn_report("CDAT: Found checksum mismatch in %s", cdat
->filename
);
188 cdat
->entry_len
= num_ent
;
189 cdat
->entry
= g_steal_pointer(&cdat_st
);
192 void cxl_doe_cdat_init(CXLComponentState
*cxl_cstate
, Error
**errp
)
194 CDATObject
*cdat
= &cxl_cstate
->cdat
;
196 if (cdat
->filename
) {
197 ct3_load_cdat(cdat
, errp
);
199 ct3_build_cdat(cdat
, errp
);
203 void cxl_doe_cdat_update(CXLComponentState
*cxl_cstate
, Error
**errp
)
205 CDATObject
*cdat
= &cxl_cstate
->cdat
;
207 if (cdat
->to_update
) {
208 ct3_build_cdat(cdat
, errp
);
212 void cxl_doe_cdat_release(CXLComponentState
*cxl_cstate
)
214 CDATObject
*cdat
= &cxl_cstate
->cdat
;
217 if (cdat
->built_buf
) {
218 cdat
->free_cdat_table(cdat
->built_buf
, cdat
->built_buf_len
,