xref: /openbmc/libcper/sections/cper-section-pci-bus.c (revision ad6c880fc739b6ca750c3ab594e270efd972c2ac)
1 /**
2  * Describes functions for converting PCI/PCI-X bus 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/Cper.h>
11 #include <libcper/cper-utils.h>
12 #include <libcper/sections/cper-section-pci-bus.h>
13 #include <libcper/log.h>
14 #include <string.h>
15 
16 //Converts a single PCI/PCI-X bus CPER section into JSON IR.
cper_section_pci_bus_to_ir(const UINT8 * section,UINT32 size,char ** desc_string)17 json_object *cper_section_pci_bus_to_ir(const UINT8 *section, UINT32 size,
18 					char **desc_string)
19 {
20 	int outstr_len = 0;
21 	*desc_string = malloc(SECTION_DESC_STRING_SIZE);
22 	outstr_len = snprintf(*desc_string, SECTION_DESC_STRING_SIZE,
23 			      "A PCI/PCI-X Bus Error occurred");
24 	if (outstr_len < 0) {
25 		cper_print_log(
26 			"Error: Could not write to PCI/PCI-X Bus description string\n");
27 	} else if (outstr_len > SECTION_DESC_STRING_SIZE) {
28 		cper_print_log(
29 			"Error: PCI/PCI-X Bus description string truncated\n");
30 	}
31 
32 	if (size < sizeof(EFI_PCI_PCIX_BUS_ERROR_DATA)) {
33 		return NULL;
34 	}
35 
36 	EFI_PCI_PCIX_BUS_ERROR_DATA *bus_error =
37 		(EFI_PCI_PCIX_BUS_ERROR_DATA *)section;
38 	json_object *section_ir = json_object_new_object();
39 
40 	//Validation bits.
41 	ValidationTypes ui64Type = { UINT_64T,
42 				     .value.ui64 = bus_error->ValidFields };
43 
44 	//Error status.
45 	if (isvalid_prop_to_ir(&ui64Type, 0)) {
46 		json_object *error_status = cper_generic_error_status_to_ir(
47 			&bus_error->ErrorStatus);
48 		json_object_object_add(section_ir, "errorStatus", error_status);
49 	}
50 
51 	//PCI bus error type.
52 	if (isvalid_prop_to_ir(&ui64Type, 1)) {
53 		json_object *error_type = integer_to_readable_pair(
54 			bus_error->Type, 8, PCI_BUS_ERROR_TYPES_KEYS,
55 			PCI_BUS_ERROR_TYPES_VALUES, "Unknown (Reserved)");
56 		json_object_object_add(section_ir, "errorType", error_type);
57 	}
58 
59 	//Bus ID.
60 	if (isvalid_prop_to_ir(&ui64Type, 2)) {
61 		json_object *bus_id = json_object_new_object();
62 		json_object_object_add(bus_id, "busNumber",
63 				       json_object_new_int(bus_error->BusId &
64 							   0xFF));
65 		json_object_object_add(bus_id, "segmentNumber",
66 				       json_object_new_int(bus_error->BusId >>
67 							   8));
68 		json_object_object_add(section_ir, "busID", bus_id);
69 	}
70 
71 	//Miscellaneous numeric fields.
72 	//Byte 7, bit 0.
73 	UINT8 command_type = (bus_error->BusCommand >> 56) & 0x1;
74 	if (isvalid_prop_to_ir(&ui64Type, 3)) {
75 		json_object_object_add(
76 			section_ir, "busAddress",
77 			json_object_new_uint64(bus_error->BusAddress));
78 	}
79 	if (isvalid_prop_to_ir(&ui64Type, 4)) {
80 		json_object_object_add(
81 			section_ir, "busData",
82 			json_object_new_uint64(bus_error->BusData));
83 	}
84 	if (isvalid_prop_to_ir(&ui64Type, 5)) {
85 		json_object_object_add(
86 			section_ir, "busCommandType",
87 			json_object_new_string(command_type == 0 ? "PCI" :
88 								   "PCI-X"));
89 	}
90 	char hexstring_buf[EFI_UINT64_HEX_STRING_LEN];
91 
92 	if (isvalid_prop_to_ir(&ui64Type, 6)) {
93 		json_object_object_add(
94 			section_ir, "busRequestorID",
95 			json_object_new_uint64(bus_error->RequestorId));
96 
97 		snprintf(hexstring_buf, EFI_UINT64_HEX_STRING_LEN, "0x%016llX",
98 			 bus_error->RequestorId);
99 		json_object_object_add(section_ir, "busRequestorIDHex",
100 				       json_object_new_string(hexstring_buf));
101 	}
102 
103 	if (isvalid_prop_to_ir(&ui64Type, 7)) {
104 		json_object_object_add(
105 			section_ir, "busCompleterID",
106 			json_object_new_uint64(bus_error->ResponderId));
107 		snprintf(hexstring_buf, EFI_UINT64_HEX_STRING_LEN, "0x%016llX",
108 			 bus_error->ResponderId);
109 		json_object_object_add(section_ir, "busCompleterIDHex",
110 				       json_object_new_string(hexstring_buf));
111 	}
112 
113 	if (isvalid_prop_to_ir(&ui64Type, 8)) {
114 		json_object_object_add(
115 			section_ir, "targetID",
116 			json_object_new_uint64(bus_error->TargetId));
117 	}
118 
119 	return section_ir;
120 }
121 
122 //Converts a single provided PCI/PCI-X bus CPER-JSON section into CPER binary, outputting to the
123 //provided stream.
ir_section_pci_bus_to_cper(json_object * section,FILE * out)124 void ir_section_pci_bus_to_cper(json_object *section, FILE *out)
125 {
126 	EFI_PCI_PCIX_BUS_ERROR_DATA *section_cper =
127 		(EFI_PCI_PCIX_BUS_ERROR_DATA *)calloc(
128 			1, sizeof(EFI_PCI_PCIX_BUS_ERROR_DATA));
129 
130 	//Validation bits.
131 	ValidationTypes ui64Type = { UINT_64T, .value.ui64 = 0 };
132 	struct json_object *obj = NULL;
133 
134 	//Error status.
135 	if (json_object_object_get_ex(section, "errorStatus", &obj)) {
136 		ir_generic_error_status_to_cper(obj,
137 						&section_cper->ErrorStatus);
138 		add_to_valid_bitfield(&ui64Type, 0);
139 	}
140 
141 	//Bus ID.
142 	if (json_object_object_get_ex(section, "busID", &obj)) {
143 		json_object *bus_id = json_object_object_get(section, "busID");
144 		UINT16 bus_number = (UINT8)json_object_get_int(
145 			json_object_object_get(bus_id, "busNumber"));
146 		UINT16 segment_number = (UINT8)json_object_get_int(
147 			json_object_object_get(bus_id, "segmentNumber"));
148 		section_cper->BusId = bus_number + (segment_number << 8);
149 		add_to_valid_bitfield(&ui64Type, 2);
150 	}
151 
152 	//Remaining fields.
153 	UINT64 pcix_command = (UINT64)0x1 << 56;
154 
155 	if (json_object_object_get_ex(section, "errorType", &obj)) {
156 		section_cper->Type = (UINT16)readable_pair_to_integer(obj);
157 		add_to_valid_bitfield(&ui64Type, 1);
158 	}
159 	if (json_object_object_get_ex(section, "busAddress", &obj)) {
160 		section_cper->BusAddress = json_object_get_uint64(
161 			json_object_object_get(section, "busAddress"));
162 		add_to_valid_bitfield(&ui64Type, 3);
163 	}
164 	if (json_object_object_get_ex(section, "busData", &obj)) {
165 		section_cper->BusData = json_object_get_uint64(obj);
166 		add_to_valid_bitfield(&ui64Type, 4);
167 	}
168 	if (json_object_object_get_ex(section, "busCommandType", &obj)) {
169 		const char *bus_command = json_object_get_string(obj);
170 		section_cper->BusCommand =
171 			strcmp(bus_command, "PCI") == 0 ? 0 : pcix_command;
172 		add_to_valid_bitfield(&ui64Type, 5);
173 	}
174 	if (json_object_object_get_ex(section, "busRequestorID", &obj)) {
175 		section_cper->RequestorId = json_object_get_uint64(obj);
176 		add_to_valid_bitfield(&ui64Type, 6);
177 	}
178 	if (json_object_object_get_ex(section, "busCompleterID", &obj)) {
179 		section_cper->ResponderId = json_object_get_uint64(obj);
180 		add_to_valid_bitfield(&ui64Type, 7);
181 	}
182 	if (json_object_object_get_ex(section, "targetID", &obj)) {
183 		section_cper->TargetId = json_object_get_uint64(obj);
184 		add_to_valid_bitfield(&ui64Type, 8);
185 	}
186 	section_cper->ValidFields = ui64Type.value.ui64;
187 
188 	//Write to stream, free resources.
189 	fwrite(section_cper, sizeof(EFI_PCI_PCIX_BUS_ERROR_DATA), 1, out);
190 	fflush(out);
191 	free(section_cper);
192 }
193