xref: /openbmc/libcper/sections/cper-section-pcie.c (revision cc36701137e8ad0e7a537c624cd486fb72fb66de)
1  /**
2   * Describes functions for converting PCIe CPER sections from binary and JSON format
3   * into an intermediate format.
4   *
5   * Author: Lawrence.Tang@arm.com
6   **/
7  #include <stdio.h>
8  #include <string.h>
9  #include <json.h>
10  #include <libcper/base64.h>
11  #include <libcper/Cper.h>
12  #include <libcper/cper-utils.h>
13  #include <libcper/sections/cper-section-pcie.h>
14  
15  struct aer_info_registers {
16  	UINT32 pcie_capability_header;
17  	UINT32 uncorrectable_error_status;
18  	UINT32 uncorrectable_error_mask;
19  	UINT32 uncorrectable_error_severity;
20  	UINT32 correctable_error_status;
21  	UINT32 correctable_error_mask;
22  	UINT32 aer_capabilites_control;
23  	UINT32 tlp_header_log[4];
24  };
25  
26  //Converts a single PCIe CPER section into JSON IR.
cper_section_pcie_to_ir(void * section)27  json_object *cper_section_pcie_to_ir(void *section)
28  {
29  	EFI_PCIE_ERROR_DATA *pcie_error = (EFI_PCIE_ERROR_DATA *)section;
30  	json_object *section_ir = json_object_new_object();
31  
32  	//Validation bits.
33  	json_object *validation = bitfield_to_ir(
34  		pcie_error->ValidFields, 8, PCIE_ERROR_VALID_BITFIELD_NAMES);
35  	json_object_object_add(section_ir, "validationBits", validation);
36  
37  	//Port type.
38  	json_object *port_type = integer_to_readable_pair(
39  		pcie_error->PortType, 9, PCIE_ERROR_PORT_TYPES_KEYS,
40  		PCIE_ERROR_PORT_TYPES_VALUES, "Unknown");
41  	json_object_object_add(section_ir, "portType", port_type);
42  
43  	//Version, provided each half in BCD.
44  	json_object *version = json_object_new_object();
45  	json_object_object_add(
46  		version, "minor",
47  		json_object_new_int(bcd_to_int(pcie_error->Version & 0xFF)));
48  	json_object_object_add(
49  		version, "major",
50  		json_object_new_int(bcd_to_int(pcie_error->Version >> 8)));
51  	json_object_object_add(section_ir, "version", version);
52  
53  	//Command & status.
54  	json_object *command_status = json_object_new_object();
55  	json_object_object_add(
56  		command_status, "commandRegister",
57  		json_object_new_uint64(pcie_error->CommandStatus & 0xFFFF));
58  	json_object_object_add(
59  		command_status, "statusRegister",
60  		json_object_new_uint64(pcie_error->CommandStatus >> 16));
61  	json_object_object_add(section_ir, "commandStatus", command_status);
62  
63  	//PCIe Device ID.
64  	json_object *device_id = json_object_new_object();
65  	UINT64 class_id = (pcie_error->DevBridge.ClassCode[0] << 16) +
66  			  (pcie_error->DevBridge.ClassCode[1] << 8) +
67  			  pcie_error->DevBridge.ClassCode[2];
68  	json_object_object_add(
69  		device_id, "vendorID",
70  		json_object_new_uint64(pcie_error->DevBridge.VendorId));
71  	json_object_object_add(
72  		device_id, "deviceID",
73  		json_object_new_uint64(pcie_error->DevBridge.DeviceId));
74  
75  	char hexstring_buf[EFI_UINT64_HEX_STRING_LEN];
76  	snprintf(hexstring_buf, EFI_UINT64_HEX_STRING_LEN, "0x%0X",
77  		 pcie_error->DevBridge.DeviceId);
78  	json_object_object_add(device_id, "deviceIDHex",
79  			       json_object_new_string(hexstring_buf));
80  
81  	json_object_object_add(device_id, "classCode",
82  			       json_object_new_uint64(class_id));
83  	json_object_object_add(
84  		device_id, "functionNumber",
85  		json_object_new_uint64(pcie_error->DevBridge.Function));
86  	json_object_object_add(
87  		device_id, "deviceNumber",
88  		json_object_new_uint64(pcie_error->DevBridge.Device));
89  	json_object_object_add(
90  		device_id, "segmentNumber",
91  		json_object_new_uint64(pcie_error->DevBridge.Segment));
92  	json_object_object_add(
93  		device_id, "primaryOrDeviceBusNumber",
94  		json_object_new_uint64(
95  			pcie_error->DevBridge.PrimaryOrDeviceBus));
96  	json_object_object_add(
97  		device_id, "secondaryBusNumber",
98  		json_object_new_uint64(pcie_error->DevBridge.SecondaryBus));
99  	json_object_object_add(
100  		device_id, "slotNumber",
101  		json_object_new_uint64(pcie_error->DevBridge.Slot.Number));
102  	json_object_object_add(section_ir, "deviceID", device_id);
103  
104  	//Device serial number.
105  	json_object_object_add(section_ir, "deviceSerialNumber",
106  			       json_object_new_uint64(pcie_error->SerialNo));
107  
108  	//Bridge control status.
109  	json_object *bridge_control_status = json_object_new_object();
110  	json_object_object_add(
111  		bridge_control_status, "secondaryStatusRegister",
112  		json_object_new_uint64(pcie_error->BridgeControlStatus &
113  				       0xFFFF));
114  	json_object_object_add(
115  		bridge_control_status, "controlRegister",
116  		json_object_new_uint64(pcie_error->BridgeControlStatus >> 16));
117  	json_object_object_add(section_ir, "bridgeControlStatus",
118  			       bridge_control_status);
119  
120  	//Capability structure.
121  	//The PCIe capability structure provided here could either be PCIe 1.1 Capability Structure
122  	//(36-byte, padded to 60 bytes) or PCIe 2.0 Capability Structure (60-byte). There does not seem
123  	//to be a way to differentiate these, so this is left as a b64 dump.
124  	int32_t encoded_len = 0;
125  
126  	char *encoded = base64_encode((UINT8 *)pcie_error->Capability.PcieCap,
127  				      60, &encoded_len);
128  	if (encoded == NULL) {
129  		printf("Failed to allocate encode output buffer. \n");
130  	} else {
131  		json_object *capability = json_object_new_object();
132  		json_object_object_add(capability, "data",
133  				       json_object_new_string_len(encoded,
134  								  encoded_len));
135  		free(encoded);
136  
137  		json_object_object_add(section_ir, "capabilityStructure",
138  				       capability);
139  	}
140  
141  	//AER information.
142  	json_object *aer_capability_ir = json_object_new_object();
143  	encoded_len = 0;
144  
145  	encoded = base64_encode((UINT8 *)pcie_error->AerInfo.PcieAer, 96,
146  				&encoded_len);
147  	if (encoded == NULL) {
148  		printf("Failed to allocate encode output buffer. \n");
149  	} else {
150  		json_object_object_add(aer_capability_ir, "data",
151  				       json_object_new_string_len(encoded,
152  								  encoded_len));
153  		free(encoded);
154  	}
155  
156  	struct aer_info_registers *aer_decode;
157  	aer_decode = (struct aer_info_registers *)&pcie_error->AerInfo.PcieAer;
158  	json_object_object_add(
159  		aer_capability_ir, "capability_header",
160  		json_object_new_uint64(aer_decode->pcie_capability_header));
161  	json_object_object_add(
162  		aer_capability_ir, "uncorrectable_error_status",
163  		json_object_new_uint64(aer_decode->uncorrectable_error_status));
164  
165  	snprintf(hexstring_buf, EFI_UINT64_HEX_STRING_LEN, "0x%08" PRIX32,
166  		 aer_decode->uncorrectable_error_status);
167  	json_object_object_add(aer_capability_ir,
168  			       "uncorrectable_error_status_hex",
169  			       json_object_new_string(hexstring_buf));
170  
171  	json_object_object_add(
172  		aer_capability_ir, "uncorrectable_error_mask",
173  		json_object_new_uint64(aer_decode->uncorrectable_error_mask));
174  	json_object_object_add(
175  		aer_capability_ir, "uncorrectable_error_severity",
176  		json_object_new_uint64(
177  			aer_decode->uncorrectable_error_severity));
178  	json_object_object_add(
179  		aer_capability_ir, "correctable_error_status",
180  		json_object_new_uint64(aer_decode->correctable_error_status));
181  
182  	snprintf(hexstring_buf, EFI_UINT64_HEX_STRING_LEN, "0x%08" PRIX32,
183  		 aer_decode->correctable_error_status);
184  	json_object_object_add(aer_capability_ir,
185  			       "correctable_error_status_hex",
186  			       json_object_new_string(hexstring_buf));
187  
188  	json_object_object_add(
189  		aer_capability_ir, "correctable_error_mask",
190  		json_object_new_uint64(aer_decode->correctable_error_mask));
191  	json_object_object_add(
192  		aer_capability_ir, "capabilites_control",
193  		json_object_new_uint64(aer_decode->aer_capabilites_control));
194  	json_object_object_add(
195  		aer_capability_ir, "tlp_header_0",
196  		json_object_new_uint64(aer_decode->tlp_header_log[0]));
197  	json_object_object_add(
198  		aer_capability_ir, "tlp_header_1",
199  		json_object_new_uint64(aer_decode->tlp_header_log[1]));
200  	json_object_object_add(
201  		aer_capability_ir, "tlp_header_2",
202  		json_object_new_uint64(aer_decode->tlp_header_log[2]));
203  	json_object_object_add(
204  		aer_capability_ir, "tlp_header_3",
205  		json_object_new_uint64(aer_decode->tlp_header_log[3]));
206  	json_object_object_add(section_ir, "aerInfo", aer_capability_ir);
207  
208  	return section_ir;
209  }
210  
211  //Converts a single CPER-JSON PCIe section into CPER binary, outputting to the given stream.
ir_section_pcie_to_cper(json_object * section,FILE * out)212  void ir_section_pcie_to_cper(json_object *section, FILE *out)
213  {
214  	EFI_PCIE_ERROR_DATA *section_cper =
215  		(EFI_PCIE_ERROR_DATA *)calloc(1, sizeof(EFI_PCIE_ERROR_DATA));
216  
217  	//Validation bits.
218  	section_cper->ValidFields = ir_to_bitfield(
219  		json_object_object_get(section, "validationBits"), 8,
220  		PCIE_ERROR_VALID_BITFIELD_NAMES);
221  
222  	//Version.
223  	json_object *version = json_object_object_get(section, "version");
224  	UINT32 minor = int_to_bcd(
225  		json_object_get_int(json_object_object_get(version, "minor")));
226  	UINT32 major = int_to_bcd(
227  		json_object_get_int(json_object_object_get(version, "major")));
228  	section_cper->Version = minor + (major << 8);
229  
230  	//Command/status registers.
231  	json_object *command_status =
232  		json_object_object_get(section, "commandStatus");
233  	UINT32 command = (UINT16)json_object_get_uint64(
234  		json_object_object_get(command_status, "commandRegister"));
235  	UINT32 status = (UINT16)json_object_get_uint64(
236  		json_object_object_get(command_status, "statusRegister"));
237  	section_cper->CommandStatus = command + (status << 16);
238  
239  	//Device ID.
240  	json_object *device_id = json_object_object_get(section, "deviceID");
241  	UINT64 class_id = json_object_get_uint64(
242  		json_object_object_get(device_id, "classCode"));
243  	section_cper->DevBridge.VendorId = (UINT16)json_object_get_uint64(
244  		json_object_object_get(device_id, "vendorID"));
245  	section_cper->DevBridge.DeviceId = (UINT16)json_object_get_uint64(
246  		json_object_object_get(device_id, "deviceID"));
247  	section_cper->DevBridge.ClassCode[0] = class_id >> 16;
248  	section_cper->DevBridge.ClassCode[1] = (class_id >> 8) & 0xFF;
249  	section_cper->DevBridge.ClassCode[2] = class_id & 0xFF;
250  	section_cper->DevBridge.Function = (UINT8)json_object_get_uint64(
251  		json_object_object_get(device_id, "functionNumber"));
252  	section_cper->DevBridge.Device = (UINT8)json_object_get_uint64(
253  		json_object_object_get(device_id, "deviceNumber"));
254  	section_cper->DevBridge.Segment = (UINT16)json_object_get_uint64(
255  		json_object_object_get(device_id, "segmentNumber"));
256  	section_cper->DevBridge.PrimaryOrDeviceBus =
257  		(UINT8)json_object_get_uint64(json_object_object_get(
258  			device_id, "primaryOrDeviceBusNumber"));
259  	section_cper->DevBridge.SecondaryBus = (UINT8)json_object_get_uint64(
260  		json_object_object_get(device_id, "secondaryBusNumber"));
261  	section_cper->DevBridge.Slot.Number = (UINT16)json_object_get_uint64(
262  		json_object_object_get(device_id, "slotNumber"));
263  
264  	//Bridge/control status.
265  	json_object *bridge_control =
266  		json_object_object_get(section, "bridgeControlStatus");
267  	UINT32 bridge_status = (UINT16)json_object_get_uint64(
268  		json_object_object_get(bridge_control,
269  				       "secondaryStatusRegister"));
270  	UINT32 control_status = (UINT16)json_object_get_uint64(
271  		json_object_object_get(bridge_control, "controlRegister"));
272  	section_cper->BridgeControlStatus =
273  		bridge_status + (control_status << 16);
274  
275  	//Capability structure.
276  	json_object *capability =
277  		json_object_object_get(section, "capabilityStructure");
278  	json_object *encoded = json_object_object_get(capability, "data");
279  
280  	int32_t decoded_len = 0;
281  
282  	UINT8 *decoded = base64_decode(json_object_get_string(encoded),
283  				       json_object_get_string_len(encoded),
284  				       &decoded_len);
285  	if (decoded == NULL) {
286  		printf("Failed to allocate decode output buffer. \n");
287  	} else {
288  		memcpy(section_cper->Capability.PcieCap, decoded, decoded_len);
289  		free(decoded);
290  	}
291  
292  	//AER capability structure.
293  	json_object *aer_info = json_object_object_get(section, "aerInfo");
294  	encoded = json_object_object_get(aer_info, "data");
295  	decoded_len = 0;
296  
297  	decoded = base64_decode(json_object_get_string(encoded),
298  				json_object_get_string_len(encoded),
299  				&decoded_len);
300  
301  	if (decoded == NULL) {
302  		printf("Failed to allocate decode output buffer. \n");
303  	} else {
304  		memcpy(section_cper->AerInfo.PcieAer, decoded, decoded_len);
305  		free(decoded);
306  	}
307  
308  	//Miscellaneous value fields.
309  	section_cper->PortType = (UINT32)readable_pair_to_integer(
310  		json_object_object_get(section, "portType"));
311  	section_cper->SerialNo = json_object_get_uint64(
312  		json_object_object_get(section, "deviceSerialNumber"));
313  
314  	//Write out to stream, free resources.
315  	fwrite(section_cper, sizeof(EFI_PCIE_ERROR_DATA), 1, out);
316  	fflush(out);
317  	free(section_cper);
318  }
319