blob: 0d6a47aec1ec9f6cee8c2afa1dba1dfeec4265ab [file] [log] [blame]
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001/*
2// Copyright (c) 2019 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
16#include <errno.h>
17#include <fcntl.h>
18#include <peci.h>
Anna Platash03d7dae2021-02-05 13:52:05 +010019#include <stdlib.h>
Jason M. Bills7ef5a552020-04-06 14:58:44 -070020#include <string.h>
21#include <sys/ioctl.h>
22#include <syslog.h>
23#include <time.h>
24#include <unistd.h>
Jason M. Billsa2ceec22020-05-05 13:16:00 -070025#pragma GCC diagnostic push
26#pragma GCC diagnostic ignored "-Wcpp"
27#pragma GCC diagnostic ignored "-Wvariadic-macros"
28#include <linux/peci-ioctl.h>
29#pragma GCC diagnostic pop
Jason M. Bills7ef5a552020-04-06 14:58:44 -070030
31EPECIStatus peci_GetDIB_seq(uint8_t target, uint64_t* dib, int peci_fd);
32
Anna Platash03d7dae2021-02-05 13:52:05 +010033char* peci_device_list[2];
34#define DEV_NAME_SIZE 64
35/*-------------------------------------------------------------------------
36 * This funcion sets the name of the PECI device file to use.
37 * If the PECI device name is null try "/dev/peci-default",
38 * if "/dev/peci-default" does not exist, fall back to "/dev/peci-0"
39 *------------------------------------------------------------------------*/
40void peci_SetDevName(char* peci_dev)
41{
Nirav Shahfd5dfd52022-03-09 12:29:41 -080042 static char peci_name_new[DEV_NAME_SIZE] = {0};
Anna Platash03d7dae2021-02-05 13:52:05 +010043
44 if (peci_dev)
45 {
46 strncpy(peci_name_new, peci_dev, sizeof(peci_name_new));
47 peci_name_new[DEV_NAME_SIZE - 1] = '\0';
48 peci_device_list[0] = peci_name_new;
49 peci_device_list[1] = NULL;
50 syslog(LOG_INFO, "PECI set dev name to %s\n", peci_device_list[0]);
51 }
52 else
53 {
54 peci_device_list[0] = "/dev/peci-default";
55 peci_device_list[1] = "/dev/peci-0";
56 syslog(LOG_INFO, "PECI set dev names to %s, %s\n", peci_device_list[0],
57 peci_device_list[1]);
58 }
59}
60
61/*-------------------------------------------------------------------------
62 * This function initializes PECI device name when a shared library
63 * is loaded, typically during program startup.
64 *------------------------------------------------------------------------*/
65static void init() __attribute__((constructor));
66static void init()
67{
68 // By default PECI_DEV is not defined in the environment,
69 // so this will call peci_SetDevName(NULL) and initialize
70 // PECI device name to defaults.
71 peci_SetDevName(getenv("PECI_DEV"));
72}
73
Jason M. Bills7ef5a552020-04-06 14:58:44 -070074/*-------------------------------------------------------------------------
75 * This function unlocks the peci interface
76 *------------------------------------------------------------------------*/
77void peci_Unlock(int peci_fd)
78{
79 if (close(peci_fd) != 0)
80 {
81 syslog(LOG_ERR, "PECI device failed to unlock.\n");
82 }
83}
84
Jason M. Bills7ef5a552020-04-06 14:58:44 -070085/*-------------------------------------------------------------------------
86 * This function attempts to lock the peci interface with the specified
87 * timeout and returns a file descriptor if successful.
88 *------------------------------------------------------------------------*/
89EPECIStatus peci_Lock(int* peci_fd, int timeout_ms)
90{
Nirav Shahfd5dfd52022-03-09 12:29:41 -080091 struct timespec sRequest = {0};
Jason M. Bills7ef5a552020-04-06 14:58:44 -070092 sRequest.tv_sec = 0;
93 sRequest.tv_nsec = PECI_TIMEOUT_RESOLUTION_MS * 1000 * 1000;
94 int timeout_count = 0;
Anna Platash03d7dae2021-02-05 13:52:05 +010095 char* peci_device = peci_device_list[0];
Jason M. Bills7ef5a552020-04-06 14:58:44 -070096
97 if (NULL == peci_fd)
98 {
99 return PECI_CC_INVALID_REQ;
100 }
101
102 // Open the PECI driver with the specified timeout
Anna Platash03d7dae2021-02-05 13:52:05 +0100103 *peci_fd = open(peci_device, O_RDWR | O_CLOEXEC);
104 if (*peci_fd == -1 && errno == ENOENT && peci_device_list[1])
105 {
106 peci_device = peci_device_list[1];
107 *peci_fd = open(peci_device, O_RDWR | O_CLOEXEC);
108 }
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700109 switch (timeout_ms)
110 {
111 case PECI_NO_WAIT:
112 break;
113 case PECI_WAIT_FOREVER:
114 while (-1 == *peci_fd)
115 {
116 nanosleep(&sRequest, NULL);
Anna Platash03d7dae2021-02-05 13:52:05 +0100117 *peci_fd = open(peci_device, O_RDWR | O_CLOEXEC);
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700118 }
119 default:
120 while (-1 == *peci_fd && timeout_count < timeout_ms)
121 {
122 nanosleep(&sRequest, NULL);
123 timeout_count += PECI_TIMEOUT_RESOLUTION_MS;
Anna Platash03d7dae2021-02-05 13:52:05 +0100124 *peci_fd = open(peci_device, O_RDWR | O_CLOEXEC);
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700125 }
126 }
127 if (-1 == *peci_fd)
128 {
129 syslog(LOG_ERR, " >>> PECI Device Busy <<< \n");
130 return PECI_CC_DRIVER_ERR;
131 }
132 return PECI_CC_SUCCESS;
133}
134
135/*-------------------------------------------------------------------------
136 * This function closes the peci interface
137 *------------------------------------------------------------------------*/
138static void peci_Close(int peci_fd)
139{
140 peci_Unlock(peci_fd);
141}
142
143/*-------------------------------------------------------------------------
144 * This function opens the peci interface and returns a file descriptor
145 *------------------------------------------------------------------------*/
146static EPECIStatus peci_Open(int* peci_fd)
147{
148 if (NULL == peci_fd)
149 {
150 return PECI_CC_INVALID_REQ;
151 }
152
153 // Lock the PECI driver with a default timeout
154 return peci_Lock(peci_fd, PECI_TIMEOUT_MS);
155}
156
157/*-------------------------------------------------------------------------
158 * This function issues peci commands to peci driver
159 *------------------------------------------------------------------------*/
160static EPECIStatus HW_peci_issue_cmd(unsigned int cmd, char* cmdPtr,
161 int peci_fd)
162{
163 if (cmdPtr == NULL)
164 {
165 return PECI_CC_INVALID_REQ;
166 }
167
168 if (ioctl(peci_fd, cmd, cmdPtr) != 0)
169 {
170 if (errno == ETIMEDOUT)
171 {
172 return PECI_CC_TIMEOUT;
173 }
174 return PECI_CC_DRIVER_ERR;
175 }
176
177 return PECI_CC_SUCCESS;
178}
179
180/*-------------------------------------------------------------------------
181 * Find the specified PCI bus number value
182 *------------------------------------------------------------------------*/
183EPECIStatus FindBusNumber(uint8_t u8Bus, uint8_t u8Cpu, uint8_t* pu8BusValue)
184{
185 uint8_t u8CpuBus0[] = {
186 PECI_PCI_BUS0_CPU0,
187 PECI_PCI_BUS0_CPU1,
188 };
189 uint8_t u8Bus0 = 0;
190 uint8_t u8Offset = 0;
Jason M. Billsbc641112020-08-19 16:31:53 -0700191 EPECIStatus ret = PECI_CC_SUCCESS;
Nirav Shahfd5dfd52022-03-09 12:29:41 -0800192 uint8_t u8Reg[4] = {0};
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700193 uint8_t cc = 0;
194
195 // First check for valid inputs
196 // Check cpu and bus numbers, only support buses [5:0]
197 if ((u8Bus > 5) || (u8Cpu >= (sizeof(u8CpuBus0) / sizeof(uint8_t))) ||
198 (pu8BusValue == NULL))
199 {
200 return PECI_CC_INVALID_REQ;
201 }
202
203 // Get the Bus 0 value for the requested CPU
204 u8Bus0 = u8CpuBus0[u8Cpu];
205
206 // Next check that the bus numbers are valid
207 // CPUBUSNO_VALID register - Above registers valid? - B(0) D5 F0 offset
208 // D4h
209 ret = peci_RdPCIConfig(u8Cpu, u8Bus0, PECI_PCI_CPUBUSNO_DEV,
210 PECI_PCI_CPUBUSNO_FUNC, PECI_PCI_CPUBUSNO_VALID,
211 u8Reg, &cc);
212 if (ret != PECI_CC_SUCCESS)
213 {
214 return ret;
215 }
216 // BIOS will set bit 31 of CPUBUSNO_VALID when the bus numbers are valid
217 if ((u8Reg[3] & 0x80) == 0)
218 {
219 return PECI_CC_HW_ERR;
220 }
221
222 // Bus numbers are valid so read the correct offset for the requested
223 // bus CPUBUSNO register - CPU Internal Bus Numbers [3:0] - B(0) D5 F0
224 // offset CCh CPUBUSNO_1 register - CPU Internal Bus Numbers [5:4] -
225 // B(0) D5 F0 offset D0h
226 u8Offset = u8Bus <= 3 ? PECI_PCI_CPUBUSNO : PECI_PCI_CPUBUSNO_1;
227 ret = peci_RdPCIConfig(u8Cpu, u8Bus0, PECI_PCI_CPUBUSNO_DEV,
228 PECI_PCI_CPUBUSNO_FUNC, u8Offset, u8Reg, &cc);
229 if (ret != PECI_CC_SUCCESS)
230 {
231 return ret;
232 }
233
234 // Now return the bus value for the requested bus
235 *pu8BusValue = u8Reg[u8Bus % 4];
236
237 // Unused bus numbers are set to zero which is only valid for bus 0
238 // so, return an error for any other bus set to zero
239 if (*pu8BusValue == 0 && u8Bus != 0)
240 {
241 return PECI_CC_CPU_NOT_PRESENT;
242 }
243
244 return PECI_CC_SUCCESS;
245}
246
247/*-------------------------------------------------------------------------
248 * This function checks the CPU PECI interface
249 *------------------------------------------------------------------------*/
250EPECIStatus peci_Ping(uint8_t target)
251{
252 int peci_fd = -1;
Jason M. Billsbc641112020-08-19 16:31:53 -0700253 EPECIStatus ret = PECI_CC_SUCCESS;
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700254
Jason M. Bills6ca31642020-08-06 10:26:19 -0700255 // The target address must be in the valid range
256 if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR)
257 {
258 return PECI_CC_INVALID_REQ;
259 }
260
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700261 if (peci_Open(&peci_fd) != PECI_CC_SUCCESS)
262 {
263 return PECI_CC_DRIVER_ERR;
264 }
265 ret = peci_Ping_seq(target, peci_fd);
266
267 peci_Close(peci_fd);
268 return ret;
269}
270
271/*-------------------------------------------------------------------------
272 * This function allows sequential Ping with the provided
273 * peci file descriptor.
274 *------------------------------------------------------------------------*/
275EPECIStatus peci_Ping_seq(uint8_t target, int peci_fd)
276{
Jason M. Billsbc641112020-08-19 16:31:53 -0700277 EPECIStatus ret = PECI_CC_SUCCESS;
Nirav Shahfd5dfd52022-03-09 12:29:41 -0800278 struct peci_ping_msg cmd = {0};
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700279
Jason M. Bills6ca31642020-08-06 10:26:19 -0700280 // The target address must be in the valid range
281 if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR)
282 {
283 return PECI_CC_INVALID_REQ;
284 }
285
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700286 cmd.addr = target;
287 ret = HW_peci_issue_cmd(PECI_IOC_PING, (char*)&cmd, peci_fd);
288
289 return ret;
290}
291
292/*-------------------------------------------------------------------------
293 * This function gets PECI device information
294 *------------------------------------------------------------------------*/
295EPECIStatus peci_GetDIB(uint8_t target, uint64_t* dib)
296{
297 int peci_fd = -1;
Jason M. Billsbc641112020-08-19 16:31:53 -0700298 EPECIStatus ret = PECI_CC_SUCCESS;
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700299
300 if (dib == NULL)
301 {
302 return PECI_CC_INVALID_REQ;
303 }
304
Jason M. Bills6ca31642020-08-06 10:26:19 -0700305 // The target address must be in the valid range
306 if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR)
307 {
308 return PECI_CC_INVALID_REQ;
309 }
310
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700311 if (peci_Open(&peci_fd) != PECI_CC_SUCCESS)
312 {
313 return PECI_CC_DRIVER_ERR;
314 }
315 ret = peci_GetDIB_seq(target, dib, peci_fd);
316
317 peci_Close(peci_fd);
318 return ret;
319}
320
321/*-------------------------------------------------------------------------
322 * This function allows sequential GetDIB with the provided
323 * peci file descriptor.
324 *------------------------------------------------------------------------*/
325EPECIStatus peci_GetDIB_seq(uint8_t target, uint64_t* dib, int peci_fd)
326{
Nirav Shahfd5dfd52022-03-09 12:29:41 -0800327 struct peci_get_dib_msg cmd = {0};
Jason M. Billsbc641112020-08-19 16:31:53 -0700328 EPECIStatus ret = PECI_CC_SUCCESS;
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700329 cmd.addr = target;
330
331 if (dib == NULL)
332 {
333 return PECI_CC_INVALID_REQ;
334 }
335
Jason M. Bills6ca31642020-08-06 10:26:19 -0700336 // The target address must be in the valid range
337 if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR)
338 {
339 return PECI_CC_INVALID_REQ;
340 }
341
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700342 ret = HW_peci_issue_cmd(PECI_IOC_GET_DIB, (char*)&cmd, peci_fd);
343
344 if (ret == PECI_CC_SUCCESS)
345 {
346 *dib = cmd.dib;
347 }
348
349 return ret;
350}
351
352/*-------------------------------------------------------------------------
353 * This function get PECI Thermal temperature
354 * Expressed in signed fixed point value of 1/64 degrees celsius
355 *------------------------------------------------------------------------*/
356EPECIStatus peci_GetTemp(uint8_t target, int16_t* temperature)
357{
358 int peci_fd = -1;
Nirav Shahfd5dfd52022-03-09 12:29:41 -0800359 struct peci_get_temp_msg cmd = {0};
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700360
361 if (temperature == NULL)
362 {
363 return PECI_CC_INVALID_REQ;
364 }
365
Jason M. Bills6ca31642020-08-06 10:26:19 -0700366 // The target address must be in the valid range
367 if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR)
368 {
369 return PECI_CC_INVALID_REQ;
370 }
371
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700372 if (peci_Open(&peci_fd) != PECI_CC_SUCCESS)
373 {
374 return PECI_CC_DRIVER_ERR;
375 }
376
377 cmd.addr = target;
378
379 EPECIStatus ret =
380 HW_peci_issue_cmd(PECI_IOC_GET_TEMP, (char*)&cmd, peci_fd);
381
382 if (ret == PECI_CC_SUCCESS)
383 {
384 *temperature = cmd.temp_raw;
385 }
386
387 peci_Close(peci_fd);
388
389 return ret;
390}
391
392/*-------------------------------------------------------------------------
393 * This function provides read access to the package configuration
394 * space within the processor.
395 *------------------------------------------------------------------------*/
396EPECIStatus peci_RdPkgConfig(uint8_t target, uint8_t u8Index, uint16_t u16Value,
397 uint8_t u8ReadLen, uint8_t* pPkgConfig,
398 uint8_t* cc)
399{
Jason M. Bills8bb8f372022-03-01 16:04:44 -0800400 // Default to domain ID 0
401 return peci_RdPkgConfig_dom(target, 0, u8Index, u16Value, u8ReadLen,
402 pPkgConfig, cc);
403}
404
405/*-------------------------------------------------------------------------
406 * This function provides read access to the package configuration
407 * space within the processor in the specified domain.
408 *------------------------------------------------------------------------*/
409EPECIStatus peci_RdPkgConfig_dom(uint8_t target, uint8_t domainId,
410 uint8_t u8Index, uint16_t u16Value,
411 uint8_t u8ReadLen, uint8_t* pPkgConfig,
412 uint8_t* cc)
413{
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700414 int peci_fd = -1;
Jason M. Billsbc641112020-08-19 16:31:53 -0700415 EPECIStatus ret = PECI_CC_SUCCESS;
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700416
417 if (pPkgConfig == NULL || cc == NULL)
418 {
419 return PECI_CC_INVALID_REQ;
420 }
421
Jason M. Bills6ca31642020-08-06 10:26:19 -0700422 // The target address must be in the valid range
423 if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR)
424 {
425 return PECI_CC_INVALID_REQ;
426 }
427
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700428 if (peci_Open(&peci_fd) != PECI_CC_SUCCESS)
429 {
430 return PECI_CC_DRIVER_ERR;
431 }
Jason M. Bills8bb8f372022-03-01 16:04:44 -0800432 ret = peci_RdPkgConfig_seq_dom(target, domainId, u8Index, u16Value,
433 u8ReadLen, pPkgConfig, peci_fd, cc);
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700434
435 peci_Close(peci_fd);
436 return ret;
437}
438
439/*-------------------------------------------------------------------------
440 * This function allows sequential RdPkgConfig with the provided
441 * peci file descriptor.
442 *------------------------------------------------------------------------*/
443EPECIStatus peci_RdPkgConfig_seq(uint8_t target, uint8_t u8Index,
444 uint16_t u16Value, uint8_t u8ReadLen,
445 uint8_t* pPkgConfig, int peci_fd, uint8_t* cc)
446{
Jason M. Bills8bb8f372022-03-01 16:04:44 -0800447 // Default to domain ID 0
448 return peci_RdPkgConfig_seq_dom(target, 0, u8Index, u16Value, u8ReadLen,
449 pPkgConfig, peci_fd, cc);
450}
451
452/*-------------------------------------------------------------------------
453 * This function allows sequential RdPkgConfig with the provided
454 * peci file descriptor in the specified domain.
455 *------------------------------------------------------------------------*/
456EPECIStatus peci_RdPkgConfig_seq_dom(uint8_t target, uint8_t domainId,
457 uint8_t u8Index, uint16_t u16Value,
458 uint8_t u8ReadLen, uint8_t* pPkgConfig,
459 int peci_fd, uint8_t* cc)
460{
Nirav Shahfd5dfd52022-03-09 12:29:41 -0800461 struct peci_rd_pkg_cfg_msg cmd = {0};
Jason M. Billsbc641112020-08-19 16:31:53 -0700462 EPECIStatus ret = PECI_CC_SUCCESS;
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700463
464 if (pPkgConfig == NULL || cc == NULL)
465 {
466 return PECI_CC_INVALID_REQ;
467 }
468
Jason M. Bills6ca31642020-08-06 10:26:19 -0700469 // The target address must be in the valid range
470 if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR)
471 {
472 return PECI_CC_INVALID_REQ;
473 }
474
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700475 // Per the PECI spec, the write length must be a byte, word, or dword
476 if (u8ReadLen != 1 && u8ReadLen != 2 && u8ReadLen != 4)
477 {
478 return PECI_CC_INVALID_REQ;
479 }
480
481 // The PECI buffer must be large enough to hold the requested data
482 if (sizeof(cmd.pkg_config) < u8ReadLen)
483 {
484 return PECI_CC_INVALID_REQ;
485 }
486
487 cmd.addr = target;
488 cmd.index = u8Index; // RdPkgConfig index
489 cmd.param = u16Value; // Config parameter value
490 cmd.rx_len = u8ReadLen;
Jason M. Bills8bb8f372022-03-01 16:04:44 -0800491 cmd.domain_id = domainId;
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700492
493 ret = HW_peci_issue_cmd(PECI_IOC_RD_PKG_CFG, (char*)&cmd, peci_fd);
494 *cc = cmd.cc;
495 if (ret == PECI_CC_SUCCESS)
496 {
497 memcpy(pPkgConfig, cmd.pkg_config, u8ReadLen);
498 }
499
500 return ret;
501}
502
503/*-------------------------------------------------------------------------
504 * This function provides write access to the package configuration
505 * space within the processor
506 *------------------------------------------------------------------------*/
507EPECIStatus peci_WrPkgConfig(uint8_t target, uint8_t u8Index, uint16_t u16Param,
508 uint32_t u32Value, uint8_t u8WriteLen, uint8_t* cc)
509{
Jason M. Bills8bb8f372022-03-01 16:04:44 -0800510 // Default to domain ID 0
511 return peci_WrPkgConfig_dom(target, 0, u8Index, u16Param, u32Value,
512 u8WriteLen, cc);
513}
514
515/*-------------------------------------------------------------------------
516 * This function provides write access to the package configuration
517 * space within the processor in the specified domain
518 *------------------------------------------------------------------------*/
519EPECIStatus peci_WrPkgConfig_dom(uint8_t target, uint8_t domainId,
520 uint8_t u8Index, uint16_t u16Param,
521 uint32_t u32Value, uint8_t u8WriteLen,
522 uint8_t* cc)
523{
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700524 int peci_fd = -1;
Jason M. Billsbc641112020-08-19 16:31:53 -0700525 EPECIStatus ret = PECI_CC_SUCCESS;
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700526
527 if (cc == NULL)
528 {
529 return PECI_CC_INVALID_REQ;
530 }
531
Jason M. Bills6ca31642020-08-06 10:26:19 -0700532 // The target address must be in the valid range
533 if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR)
534 {
535 return PECI_CC_INVALID_REQ;
536 }
537
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700538 if (peci_Open(&peci_fd) != PECI_CC_SUCCESS)
539 {
540 return PECI_CC_DRIVER_ERR;
541 }
Jason M. Bills8bb8f372022-03-01 16:04:44 -0800542 ret = peci_WrPkgConfig_seq_dom(target, domainId, u8Index, u16Param,
543 u32Value, u8WriteLen, peci_fd, cc);
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700544
545 peci_Close(peci_fd);
546 return ret;
547}
548
549/*-------------------------------------------------------------------------
550 * This function allows sequential WrPkgConfig with the provided
551 * peci file descriptor.
552 *------------------------------------------------------------------------*/
553EPECIStatus peci_WrPkgConfig_seq(uint8_t target, uint8_t u8Index,
554 uint16_t u16Param, uint32_t u32Value,
555 uint8_t u8WriteLen, int peci_fd, uint8_t* cc)
556{
Jason M. Bills8bb8f372022-03-01 16:04:44 -0800557 // Default to domain ID 0
558 return peci_WrPkgConfig_seq_dom(target, 0, u8Index, u16Param, u32Value,
559 u8WriteLen, peci_fd, cc);
560}
561
562/*-------------------------------------------------------------------------
563 * This function allows sequential WrPkgConfig with the provided
564 * peci file descriptor in the specified domain.
565 *------------------------------------------------------------------------*/
566EPECIStatus peci_WrPkgConfig_seq_dom(uint8_t target, uint8_t domainId,
567 uint8_t u8Index, uint16_t u16Param,
568 uint32_t u32Value, uint8_t u8WriteLen,
569 int peci_fd, uint8_t* cc)
570{
Nirav Shahfd5dfd52022-03-09 12:29:41 -0800571 struct peci_wr_pkg_cfg_msg cmd = {0};
Jason M. Billsbc641112020-08-19 16:31:53 -0700572 EPECIStatus ret = PECI_CC_SUCCESS;
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700573
574 if (cc == NULL)
575 {
576 return PECI_CC_INVALID_REQ;
577 }
578
Jason M. Bills6ca31642020-08-06 10:26:19 -0700579 // The target address must be in the valid range
580 if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR)
581 {
582 return PECI_CC_INVALID_REQ;
583 }
584
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700585 // Per the PECI spec, the write length must be a byte, word, or dword
586 if ((u8WriteLen != 1) && (u8WriteLen != 2) && (u8WriteLen != 4))
587 {
588 return PECI_CC_INVALID_REQ;
589 }
590
591 cmd.addr = target;
592 cmd.index = u8Index; // RdPkgConfig index
593 cmd.param = u16Param; // parameter value
594 cmd.tx_len = u8WriteLen;
595 cmd.value = u32Value;
Jason M. Bills8bb8f372022-03-01 16:04:44 -0800596 cmd.domain_id = domainId;
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700597
598 ret = HW_peci_issue_cmd(PECI_IOC_WR_PKG_CFG, (char*)&cmd, peci_fd);
599 *cc = cmd.cc;
600
601 return ret;
602}
603
604/*-------------------------------------------------------------------------
605 * This function provides read access to Model Specific Registers
606 * defined in the processor doc.
607 *------------------------------------------------------------------------*/
608EPECIStatus peci_RdIAMSR(uint8_t target, uint8_t threadID, uint16_t MSRAddress,
609 uint64_t* u64MsrVal, uint8_t* cc)
610{
Jason M. Bills8bb8f372022-03-01 16:04:44 -0800611 // Default to domain ID 0
612 return peci_RdIAMSR_dom(target, 0, threadID, MSRAddress, u64MsrVal, cc);
613}
614
615/*-------------------------------------------------------------------------
616 * This function provides read access to Model Specific Registers
617 * defined in the processor doc in the specified domain.
618 *------------------------------------------------------------------------*/
619EPECIStatus peci_RdIAMSR_dom(uint8_t target, uint8_t domainId, uint8_t threadID,
620 uint16_t MSRAddress, uint64_t* u64MsrVal,
621 uint8_t* cc)
622{
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700623 int peci_fd = -1;
Nirav Shahfd5dfd52022-03-09 12:29:41 -0800624 struct peci_rd_ia_msr_msg cmd = {0};
Jason M. Billsbc641112020-08-19 16:31:53 -0700625 EPECIStatus ret = PECI_CC_SUCCESS;
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700626
627 if (u64MsrVal == NULL || cc == NULL)
628 {
629 return PECI_CC_INVALID_REQ;
630 }
631
Jason M. Bills6ca31642020-08-06 10:26:19 -0700632 // The target address must be in the valid range
633 if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR)
634 {
635 return PECI_CC_INVALID_REQ;
636 }
637
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700638 if (peci_Open(&peci_fd) != PECI_CC_SUCCESS)
639 {
640 return PECI_CC_DRIVER_ERR;
641 }
642
643 cmd.addr = target;
644 cmd.thread_id = threadID; // request byte for thread ID
645 cmd.address = MSRAddress; // MSR Address
Jason M. Bills8bb8f372022-03-01 16:04:44 -0800646 cmd.domain_id = domainId;
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700647
648 ret = HW_peci_issue_cmd(PECI_IOC_RD_IA_MSR, (char*)&cmd, peci_fd);
649 *cc = cmd.cc;
650 if (ret == PECI_CC_SUCCESS)
651 {
652 *u64MsrVal = cmd.value;
653 }
654
655 peci_Close(peci_fd);
656 return ret;
657}
658
659/*-------------------------------------------------------------------------
660 * This function provides read access to the PCI configuration space at
661 * the requested PCI configuration address.
662 *------------------------------------------------------------------------*/
663EPECIStatus peci_RdPCIConfig(uint8_t target, uint8_t u8Bus, uint8_t u8Device,
664 uint8_t u8Fcn, uint16_t u16Reg, uint8_t* pPCIData,
665 uint8_t* cc)
666{
Jason M. Bills8bb8f372022-03-01 16:04:44 -0800667 // Default to domain ID 0
668 return peci_RdPCIConfig_dom(target, 0, u8Bus, u8Device, u8Fcn, u16Reg,
669 pPCIData, cc);
670}
671
672/*-------------------------------------------------------------------------
673 * This function provides read access to the PCI configuration space at
674 * the requested PCI configuration address in the specified domain.
675 *------------------------------------------------------------------------*/
676EPECIStatus peci_RdPCIConfig_dom(uint8_t target, uint8_t domainId,
677 uint8_t u8Bus, uint8_t u8Device, uint8_t u8Fcn,
678 uint16_t u16Reg, uint8_t* pPCIData,
679 uint8_t* cc)
680{
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700681 int peci_fd = -1;
Jason M. Billsbc641112020-08-19 16:31:53 -0700682 EPECIStatus ret = PECI_CC_SUCCESS;
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700683
684 if (pPCIData == NULL || cc == NULL)
685 {
686 return PECI_CC_INVALID_REQ;
687 }
688
Jason M. Bills6ca31642020-08-06 10:26:19 -0700689 // The target address must be in the valid range
690 if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR)
691 {
692 return PECI_CC_INVALID_REQ;
693 }
694
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700695 if (peci_Open(&peci_fd) != PECI_CC_SUCCESS)
696 {
697 return PECI_CC_DRIVER_ERR;
698 }
Jason M. Bills8bb8f372022-03-01 16:04:44 -0800699 ret = peci_RdPCIConfig_seq_dom(target, domainId, u8Bus, u8Device, u8Fcn,
700 u16Reg, pPCIData, peci_fd, cc);
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700701
702 peci_Close(peci_fd);
703 return ret;
704}
705
706/*-------------------------------------------------------------------------
707 * This function allows sequential RdPCIConfig with the provided
708 * peci file descriptor.
709 *------------------------------------------------------------------------*/
710EPECIStatus peci_RdPCIConfig_seq(uint8_t target, uint8_t u8Bus,
711 uint8_t u8Device, uint8_t u8Fcn,
712 uint16_t u16Reg, uint8_t* pPCIData,
713 int peci_fd, uint8_t* cc)
714{
Jason M. Bills8bb8f372022-03-01 16:04:44 -0800715 // Default to domain ID 0
716 return peci_RdPCIConfig_seq_dom(target, 0, u8Bus, u8Device, u8Fcn, u16Reg,
717 pPCIData, peci_fd, cc);
718}
719
720/*-------------------------------------------------------------------------
721 * This function allows sequential RdPCIConfig with the provided
722 * peci file descriptor in the specified domain.
723 *------------------------------------------------------------------------*/
724EPECIStatus peci_RdPCIConfig_seq_dom(uint8_t target, uint8_t domainId,
725 uint8_t u8Bus, uint8_t u8Device,
726 uint8_t u8Fcn, uint16_t u16Reg,
727 uint8_t* pPCIData, int peci_fd,
728 uint8_t* cc)
729{
Nirav Shahfd5dfd52022-03-09 12:29:41 -0800730 struct peci_rd_pci_cfg_msg cmd = {0};
Jason M. Billsbc641112020-08-19 16:31:53 -0700731 EPECIStatus ret = PECI_CC_SUCCESS;
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700732
733 if (pPCIData == NULL || cc == NULL)
734 {
735 return PECI_CC_INVALID_REQ;
736 }
737
Jason M. Bills6ca31642020-08-06 10:26:19 -0700738 // The target address must be in the valid range
739 if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR)
740 {
741 return PECI_CC_INVALID_REQ;
742 }
743
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700744 // The PECI buffer must be large enough to hold the PCI data
745 if (sizeof(cmd.pci_config) < 4)
746 {
747 return PECI_CC_INVALID_REQ;
748 }
749
750 cmd.addr = target;
751 cmd.bus = u8Bus;
752 cmd.device = u8Device;
753 cmd.function = u8Fcn;
754 cmd.reg = u16Reg;
Jason M. Bills8bb8f372022-03-01 16:04:44 -0800755 cmd.domain_id = domainId;
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700756
757 ret = HW_peci_issue_cmd(PECI_IOC_RD_PCI_CFG, (char*)&cmd, peci_fd);
758 *cc = cmd.cc;
759
760 if (ret == PECI_CC_SUCCESS)
761 {
762 memcpy(pPCIData, cmd.pci_config, 4);
763 }
764
765 return ret;
766}
767
768/*-------------------------------------------------------------------------
Jason M. Bills8bb8f372022-03-01 16:04:44 -0800769 * This function provides read access to the local PCI configuration space
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700770 *------------------------------------------------------------------------*/
771EPECIStatus peci_RdPCIConfigLocal(uint8_t target, uint8_t u8Bus,
772 uint8_t u8Device, uint8_t u8Fcn,
773 uint16_t u16Reg, uint8_t u8ReadLen,
774 uint8_t* pPCIReg, uint8_t* cc)
775{
Jason M. Bills8bb8f372022-03-01 16:04:44 -0800776 // Default to domain ID 0
777 return peci_RdPCIConfigLocal_dom(target, 0, u8Bus, u8Device, u8Fcn, u16Reg,
778 u8ReadLen, pPCIReg, cc);
779}
780
781/*-------------------------------------------------------------------------
782 * This function provides read access to the local PCI configuration space in
783 * the specified domain
784 *------------------------------------------------------------------------*/
785EPECIStatus peci_RdPCIConfigLocal_dom(uint8_t target, uint8_t domainId,
786 uint8_t u8Bus, uint8_t u8Device,
787 uint8_t u8Fcn, uint16_t u16Reg,
788 uint8_t u8ReadLen, uint8_t* pPCIReg,
789 uint8_t* cc)
790{
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700791 int peci_fd = -1;
Jason M. Billsbc641112020-08-19 16:31:53 -0700792 EPECIStatus ret = PECI_CC_SUCCESS;
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700793
794 if (pPCIReg == NULL || cc == NULL)
795 {
796 return PECI_CC_INVALID_REQ;
797 }
798
Jason M. Bills6ca31642020-08-06 10:26:19 -0700799 // The target address must be in the valid range
800 if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR)
801 {
802 return PECI_CC_INVALID_REQ;
803 }
804
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700805 if (peci_Open(&peci_fd) != PECI_CC_SUCCESS)
806 {
807 return PECI_CC_DRIVER_ERR;
808 }
Jason M. Bills8bb8f372022-03-01 16:04:44 -0800809 ret =
810 peci_RdPCIConfigLocal_seq_dom(target, domainId, u8Bus, u8Device, u8Fcn,
811 u16Reg, u8ReadLen, pPCIReg, peci_fd, cc);
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700812
813 peci_Close(peci_fd);
814 return ret;
815}
816
817/*-------------------------------------------------------------------------
818 * This function allows sequential RdPCIConfigLocal with the provided
819 * peci file descriptor.
820 *------------------------------------------------------------------------*/
821EPECIStatus peci_RdPCIConfigLocal_seq(uint8_t target, uint8_t u8Bus,
822 uint8_t u8Device, uint8_t u8Fcn,
823 uint16_t u16Reg, uint8_t u8ReadLen,
824 uint8_t* pPCIReg, int peci_fd,
825 uint8_t* cc)
826{
Jason M. Bills8bb8f372022-03-01 16:04:44 -0800827 // Default to domain ID 0
828 return peci_RdPCIConfigLocal_seq_dom(target, 0, u8Bus, u8Device, u8Fcn,
829 u16Reg, u8ReadLen, pPCIReg, peci_fd,
830 cc);
831}
832
833/*-------------------------------------------------------------------------
834 * This function allows sequential RdPCIConfigLocal with the provided
835 * peci file descriptor in the specified domain.
836 *------------------------------------------------------------------------*/
837EPECIStatus peci_RdPCIConfigLocal_seq_dom(uint8_t target, uint8_t domainId,
838 uint8_t u8Bus, uint8_t u8Device,
839 uint8_t u8Fcn, uint16_t u16Reg,
840 uint8_t u8ReadLen, uint8_t* pPCIReg,
841 int peci_fd, uint8_t* cc)
842{
Nirav Shahfd5dfd52022-03-09 12:29:41 -0800843 struct peci_rd_pci_cfg_local_msg cmd = {0};
Jason M. Billsbc641112020-08-19 16:31:53 -0700844 EPECIStatus ret = PECI_CC_SUCCESS;
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700845
846 if (pPCIReg == NULL || cc == NULL)
847 {
848 return PECI_CC_INVALID_REQ;
849 }
850
Jason M. Bills6ca31642020-08-06 10:26:19 -0700851 // The target address must be in the valid range
852 if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR)
853 {
854 return PECI_CC_INVALID_REQ;
855 }
856
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700857 // Per the PECI spec, the read length must be a byte, word, or dword
858 if (u8ReadLen != 1 && u8ReadLen != 2 && u8ReadLen != 4)
859 {
860 return PECI_CC_INVALID_REQ;
861 }
862
863 // The PECI buffer must be large enough to hold the requested data
864 if (sizeof(cmd.pci_config) < u8ReadLen)
865 {
866 return PECI_CC_INVALID_REQ;
867 }
868
869 cmd.addr = target;
870 cmd.bus = u8Bus;
871 cmd.device = u8Device;
872 cmd.function = u8Fcn;
873 cmd.reg = u16Reg;
874 cmd.rx_len = u8ReadLen;
Jason M. Bills8bb8f372022-03-01 16:04:44 -0800875 cmd.domain_id = domainId;
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700876
877 ret = HW_peci_issue_cmd(PECI_IOC_RD_PCI_CFG_LOCAL, (char*)&cmd, peci_fd);
878 *cc = cmd.cc;
879
880 if (ret == PECI_CC_SUCCESS)
881 {
882 memcpy(pPCIReg, cmd.pci_config, u8ReadLen);
883 }
884
885 return ret;
886}
887
888/*-------------------------------------------------------------------------
Jason M. Bills8bb8f372022-03-01 16:04:44 -0800889 * This function provides write access to the local PCI configuration space
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700890 *------------------------------------------------------------------------*/
891EPECIStatus peci_WrPCIConfigLocal(uint8_t target, uint8_t u8Bus,
892 uint8_t u8Device, uint8_t u8Fcn,
893 uint16_t u16Reg, uint8_t DataLen,
894 uint32_t DataVal, uint8_t* cc)
895{
Jason M. Bills8bb8f372022-03-01 16:04:44 -0800896 // Default to domain ID 0
897 return peci_WrPCIConfigLocal_dom(target, 0, u8Bus, u8Device, u8Fcn, u16Reg,
898 DataLen, DataVal, cc);
899}
900
901/*-------------------------------------------------------------------------
902 * This function provides write access to the local PCI configuration space in
903 * the specified domain
904 *------------------------------------------------------------------------*/
905EPECIStatus peci_WrPCIConfigLocal_dom(uint8_t target, uint8_t domainId,
906 uint8_t u8Bus, uint8_t u8Device,
907 uint8_t u8Fcn, uint16_t u16Reg,
908 uint8_t DataLen, uint32_t DataVal,
909 uint8_t* cc)
910{
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700911 int peci_fd = -1;
Nirav Shahfd5dfd52022-03-09 12:29:41 -0800912 struct peci_wr_pci_cfg_local_msg cmd = {0};
Jason M. Billsbc641112020-08-19 16:31:53 -0700913 EPECIStatus ret = PECI_CC_SUCCESS;
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700914
915 if (cc == NULL)
916 {
917 return PECI_CC_INVALID_REQ;
918 }
919
Jason M. Bills6ca31642020-08-06 10:26:19 -0700920 // The target address must be in the valid range
921 if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR)
922 {
923 return PECI_CC_INVALID_REQ;
924 }
925
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700926 if (peci_Open(&peci_fd) != PECI_CC_SUCCESS)
927 {
928 return PECI_CC_DRIVER_ERR;
929 }
930
931 // Per the PECI spec, the write length must be a byte, word, or dword
932 if (DataLen != 1 && DataLen != 2 && DataLen != 4)
933 {
934 peci_Close(peci_fd);
935 return PECI_CC_INVALID_REQ;
936 }
937
938 cmd.addr = target;
939 cmd.bus = u8Bus;
940 cmd.device = u8Device;
941 cmd.function = u8Fcn;
942 cmd.reg = u16Reg;
943 cmd.tx_len = DataLen;
944 cmd.value = DataVal;
Jason M. Bills8bb8f372022-03-01 16:04:44 -0800945 cmd.domain_id = domainId;
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700946
947 ret = HW_peci_issue_cmd(PECI_IOC_WR_PCI_CFG_LOCAL, (char*)&cmd, peci_fd);
948 *cc = cmd.cc;
949
950 peci_Close(peci_fd);
951 return ret;
952}
953
954/*-------------------------------------------------------------------------
Jason M. Bills8bb8f372022-03-01 16:04:44 -0800955 * This internal function is the common interface for RdEndPointConfig to PCI in
956 * the specified domain
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700957 *------------------------------------------------------------------------*/
Jason M. Bills8bb8f372022-03-01 16:04:44 -0800958static EPECIStatus peci_RdEndPointConfigPciCommon_dom(
959 uint8_t target, uint8_t domainId, uint8_t u8MsgType, uint8_t u8Seg,
960 uint8_t u8Bus, uint8_t u8Device, uint8_t u8Fcn, uint16_t u16Reg,
961 uint8_t u8ReadLen, uint8_t* pPCIData, int peci_fd, uint8_t* cc)
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700962{
Nirav Shahfd5dfd52022-03-09 12:29:41 -0800963 struct peci_rd_end_pt_cfg_msg cmd = {0};
Jason M. Billsbc641112020-08-19 16:31:53 -0700964 EPECIStatus ret = PECI_CC_SUCCESS;
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700965
966 if (pPCIData == NULL || cc == NULL)
967 {
968 return PECI_CC_INVALID_REQ;
969 }
970
Jason M. Bills6ca31642020-08-06 10:26:19 -0700971 // The target address must be in the valid range
972 if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR)
973 {
974 return PECI_CC_INVALID_REQ;
975 }
976
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700977 // The PECI buffer must be large enough to hold the requested data
978 if (sizeof(cmd.data) < u8ReadLen)
979 {
980 return PECI_CC_INVALID_REQ;
981 }
982
983 cmd.addr = target;
984 cmd.msg_type = u8MsgType;
985 cmd.params.pci_cfg.seg = u8Seg;
986 cmd.params.pci_cfg.bus = u8Bus;
987 cmd.params.pci_cfg.device = u8Device;
988 cmd.params.pci_cfg.function = u8Fcn;
989 cmd.params.pci_cfg.reg = u16Reg;
990 cmd.rx_len = u8ReadLen;
Jason M. Bills8bb8f372022-03-01 16:04:44 -0800991 cmd.domain_id = domainId;
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700992
993 ret = HW_peci_issue_cmd(PECI_IOC_RD_END_PT_CFG, (char*)&cmd, peci_fd);
994 *cc = cmd.cc;
995
996 if (ret == PECI_CC_SUCCESS)
997 {
998 memcpy(pPCIData, cmd.data, u8ReadLen);
999 }
1000 else
1001 {
1002 ret = PECI_CC_DRIVER_ERR;
1003 }
1004
1005 return ret;
1006}
1007
1008/*-------------------------------------------------------------------------
1009 * This function provides read access to the PCI configuration space at
1010 * the requested PCI configuration address.
1011 *------------------------------------------------------------------------*/
1012EPECIStatus peci_RdEndPointConfigPci(uint8_t target, uint8_t u8Seg,
1013 uint8_t u8Bus, uint8_t u8Device,
1014 uint8_t u8Fcn, uint16_t u16Reg,
1015 uint8_t u8ReadLen, uint8_t* pPCIData,
1016 uint8_t* cc)
1017{
Jason M. Bills8bb8f372022-03-01 16:04:44 -08001018 // Default to domain ID 0
1019 return peci_RdEndPointConfigPci_dom(target, 0, u8Seg, u8Bus, u8Device,
1020 u8Fcn, u16Reg, u8ReadLen, pPCIData, cc);
1021}
1022
1023/*-------------------------------------------------------------------------
1024 * This function provides read access to the PCI configuration space at
1025 * the requested PCI configuration address in the specified domain.
1026 *------------------------------------------------------------------------*/
1027EPECIStatus peci_RdEndPointConfigPci_dom(uint8_t target, uint8_t domainId,
1028 uint8_t u8Seg, uint8_t u8Bus,
1029 uint8_t u8Device, uint8_t u8Fcn,
1030 uint16_t u16Reg, uint8_t u8ReadLen,
1031 uint8_t* pPCIData, uint8_t* cc)
1032{
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001033 int peci_fd = -1;
Jason M. Billsbc641112020-08-19 16:31:53 -07001034 EPECIStatus ret = PECI_CC_SUCCESS;
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001035
1036 if (pPCIData == NULL || cc == NULL)
1037 {
1038 return PECI_CC_INVALID_REQ;
1039 }
1040
Jason M. Bills6ca31642020-08-06 10:26:19 -07001041 // The target address must be in the valid range
1042 if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR)
1043 {
1044 return PECI_CC_INVALID_REQ;
1045 }
1046
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001047 if (peci_Open(&peci_fd) != PECI_CC_SUCCESS)
1048 {
1049 return PECI_CC_DRIVER_ERR;
1050 }
Jason M. Bills8bb8f372022-03-01 16:04:44 -08001051 ret = peci_RdEndPointConfigPci_seq_dom(target, domainId, u8Seg, u8Bus,
1052 u8Device, u8Fcn, u16Reg, u8ReadLen,
1053 pPCIData, peci_fd, cc);
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001054 peci_Close(peci_fd);
1055 return ret;
1056}
1057
1058/*-------------------------------------------------------------------------
1059 * This function allows sequential RdEndPointConfig to PCI with the provided
1060 * peci file descriptor.
1061 *------------------------------------------------------------------------*/
1062EPECIStatus peci_RdEndPointConfigPci_seq(uint8_t target, uint8_t u8Seg,
1063 uint8_t u8Bus, uint8_t u8Device,
1064 uint8_t u8Fcn, uint16_t u16Reg,
1065 uint8_t u8ReadLen, uint8_t* pPCIData,
1066 int peci_fd, uint8_t* cc)
1067{
Jason M. Bills8bb8f372022-03-01 16:04:44 -08001068 // Default to domain ID 0
1069 return peci_RdEndPointConfigPci_seq_dom(target, 0, u8Seg, u8Bus, u8Device,
1070 u8Fcn, u16Reg, u8ReadLen, pPCIData,
1071 peci_fd, cc);
1072}
1073
1074/*-------------------------------------------------------------------------
1075 * This function allows sequential RdEndPointConfig to PCI with the provided
1076 * peci file descriptor in the specified domain.
1077 *------------------------------------------------------------------------*/
1078EPECIStatus peci_RdEndPointConfigPci_seq_dom(uint8_t target, uint8_t domainId,
1079 uint8_t u8Seg, uint8_t u8Bus,
1080 uint8_t u8Device, uint8_t u8Fcn,
1081 uint16_t u16Reg, uint8_t u8ReadLen,
1082 uint8_t* pPCIData, int peci_fd,
1083 uint8_t* cc)
1084{
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001085 if (pPCIData == NULL || cc == NULL)
1086 {
1087 return PECI_CC_INVALID_REQ;
1088 }
1089
Jason M. Bills6ca31642020-08-06 10:26:19 -07001090 // The target address must be in the valid range
1091 if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR)
1092 {
1093 return PECI_CC_INVALID_REQ;
1094 }
1095
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001096 // Per the PECI spec, the read length must be a byte, word, or dword
1097 if (u8ReadLen != 1 && u8ReadLen != 2 && u8ReadLen != 4)
1098 {
1099 return PECI_CC_INVALID_REQ;
1100 }
1101
Jason M. Bills8bb8f372022-03-01 16:04:44 -08001102 return peci_RdEndPointConfigPciCommon_dom(
1103 target, domainId, PECI_ENDPTCFG_TYPE_PCI, u8Seg, u8Bus, u8Device, u8Fcn,
1104 u16Reg, u8ReadLen, pPCIData, peci_fd, cc);
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001105}
1106
1107/*-------------------------------------------------------------------------
1108 * This function provides read access to the Local PCI configuration space at
1109 * the requested PCI configuration address.
1110 *------------------------------------------------------------------------*/
1111EPECIStatus peci_RdEndPointConfigPciLocal(uint8_t target, uint8_t u8Seg,
1112 uint8_t u8Bus, uint8_t u8Device,
1113 uint8_t u8Fcn, uint16_t u16Reg,
1114 uint8_t u8ReadLen, uint8_t* pPCIData,
1115 uint8_t* cc)
1116{
Jason M. Bills8bb8f372022-03-01 16:04:44 -08001117 // Default to domain ID 0
1118 return peci_RdEndPointConfigPciLocal_dom(target, 0, u8Seg, u8Bus, u8Device,
1119 u8Fcn, u16Reg, u8ReadLen, pPCIData,
1120 cc);
1121}
1122
1123/*-------------------------------------------------------------------------
1124 * This function provides read access to the Local PCI configuration space at
1125 * the requested PCI configuration address in the specified domain.
1126 *------------------------------------------------------------------------*/
1127EPECIStatus peci_RdEndPointConfigPciLocal_dom(uint8_t target, uint8_t domainId,
1128 uint8_t u8Seg, uint8_t u8Bus,
1129 uint8_t u8Device, uint8_t u8Fcn,
1130 uint16_t u16Reg,
1131 uint8_t u8ReadLen,
1132 uint8_t* pPCIData, uint8_t* cc)
1133{
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001134 int peci_fd = -1;
Jason M. Billsbc641112020-08-19 16:31:53 -07001135 EPECIStatus ret = PECI_CC_SUCCESS;
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001136
1137 if (pPCIData == NULL || cc == NULL)
1138 {
1139 return PECI_CC_INVALID_REQ;
1140 }
1141
Jason M. Bills6ca31642020-08-06 10:26:19 -07001142 // The target address must be in the valid range
1143 if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR)
1144 {
1145 return PECI_CC_INVALID_REQ;
1146 }
1147
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001148 if (peci_Open(&peci_fd) != PECI_CC_SUCCESS)
1149 {
1150 return PECI_CC_DRIVER_ERR;
1151 }
Jason M. Bills8bb8f372022-03-01 16:04:44 -08001152 ret = peci_RdEndPointConfigPciLocal_seq_dom(
1153 target, domainId, u8Seg, u8Bus, u8Device, u8Fcn, u16Reg, u8ReadLen,
1154 pPCIData, peci_fd, cc);
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001155 peci_Close(peci_fd);
1156 return ret;
1157}
1158
1159/*-------------------------------------------------------------------------
1160 * This function allows sequential RdEndPointConfig to PCI Local with the
Jason M. Bills8bb8f372022-03-01 16:04:44 -08001161 * provided peci file descriptor.
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001162 *------------------------------------------------------------------------*/
1163EPECIStatus peci_RdEndPointConfigPciLocal_seq(uint8_t target, uint8_t u8Seg,
1164 uint8_t u8Bus, uint8_t u8Device,
1165 uint8_t u8Fcn, uint16_t u16Reg,
1166 uint8_t u8ReadLen,
1167 uint8_t* pPCIData, int peci_fd,
1168 uint8_t* cc)
1169{
Jason M. Bills8bb8f372022-03-01 16:04:44 -08001170 // Default to domain ID 0
1171 return peci_RdEndPointConfigPciLocal_seq_dom(
1172 target, 0, u8Seg, u8Bus, u8Device, u8Fcn, u16Reg, u8ReadLen, pPCIData,
1173 peci_fd, cc);
1174}
1175
1176/*-------------------------------------------------------------------------
1177 * This function allows sequential RdEndPointConfig to PCI Local with the
1178 * provided peci file descriptor in the specified domain.
1179 *------------------------------------------------------------------------*/
1180EPECIStatus peci_RdEndPointConfigPciLocal_seq_dom(
1181 uint8_t target, uint8_t domainId, uint8_t u8Seg, uint8_t u8Bus,
1182 uint8_t u8Device, uint8_t u8Fcn, uint16_t u16Reg, uint8_t u8ReadLen,
1183 uint8_t* pPCIData, int peci_fd, uint8_t* cc)
1184{
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001185 if (pPCIData == NULL || cc == NULL)
1186 {
1187 return PECI_CC_INVALID_REQ;
1188 }
1189
Jason M. Bills6ca31642020-08-06 10:26:19 -07001190 // The target address must be in the valid range
1191 if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR)
1192 {
1193 return PECI_CC_INVALID_REQ;
1194 }
1195
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001196 // Per the PECI spec, the read length must be a byte, word, or dword
1197 if (u8ReadLen != 1 && u8ReadLen != 2 && u8ReadLen != 4)
1198 {
1199 return PECI_CC_INVALID_REQ;
1200 }
1201
Jason M. Bills8bb8f372022-03-01 16:04:44 -08001202 return peci_RdEndPointConfigPciCommon_dom(
1203 target, domainId, PECI_ENDPTCFG_TYPE_LOCAL_PCI, u8Seg, u8Bus, u8Device,
1204 u8Fcn, u16Reg, u8ReadLen, pPCIData, peci_fd, cc);
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001205}
1206
1207/*-------------------------------------------------------------------------
1208 * This function provides read access to PCI MMIO space at
1209 * the requested PCI configuration address.
1210 *------------------------------------------------------------------------*/
1211EPECIStatus peci_RdEndPointConfigMmio(uint8_t target, uint8_t u8Seg,
1212 uint8_t u8Bus, uint8_t u8Device,
1213 uint8_t u8Fcn, uint8_t u8Bar,
1214 uint8_t u8AddrType, uint64_t u64Offset,
1215 uint8_t u8ReadLen, uint8_t* pMmioData,
1216 uint8_t* cc)
1217{
Jason M. Bills8bb8f372022-03-01 16:04:44 -08001218 // Default to domain ID 0
1219 return peci_RdEndPointConfigMmio_dom(target, 0, u8Seg, u8Bus, u8Device,
1220 u8Fcn, u8Bar, u8AddrType, u64Offset,
1221 u8ReadLen, pMmioData, cc);
1222}
1223
1224/*-------------------------------------------------------------------------
1225 * This function provides read access to PCI MMIO space at
1226 * the requested PCI configuration address in the specified domain.
1227 *------------------------------------------------------------------------*/
1228EPECIStatus peci_RdEndPointConfigMmio_dom(uint8_t target, uint8_t domainId,
1229 uint8_t u8Seg, uint8_t u8Bus,
1230 uint8_t u8Device, uint8_t u8Fcn,
1231 uint8_t u8Bar, uint8_t u8AddrType,
1232 uint64_t u64Offset, uint8_t u8ReadLen,
1233 uint8_t* pMmioData, uint8_t* cc)
1234{
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001235 int peci_fd = -1;
Jason M. Billsbc641112020-08-19 16:31:53 -07001236 EPECIStatus ret = PECI_CC_SUCCESS;
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001237
1238 if (pMmioData == NULL || cc == NULL)
1239 {
1240 return PECI_CC_INVALID_REQ;
1241 }
1242
Jason M. Bills6ca31642020-08-06 10:26:19 -07001243 // The target address must be in the valid range
1244 if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR)
1245 {
1246 return PECI_CC_INVALID_REQ;
1247 }
1248
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001249 if (peci_Open(&peci_fd) != PECI_CC_SUCCESS)
1250 {
1251 return PECI_CC_DRIVER_ERR;
1252 }
Jason M. Bills8bb8f372022-03-01 16:04:44 -08001253 ret = peci_RdEndPointConfigMmio_seq_dom(
1254 target, domainId, u8Seg, u8Bus, u8Device, u8Fcn, u8Bar, u8AddrType,
1255 u64Offset, u8ReadLen, pMmioData, peci_fd, cc);
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001256 peci_Close(peci_fd);
1257 return ret;
1258}
1259
1260/*-------------------------------------------------------------------------
1261 * This function allows sequential RdEndPointConfig to PCI MMIO with the
Jason M. Bills8bb8f372022-03-01 16:04:44 -08001262 * provided peci file descriptor.
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001263 *------------------------------------------------------------------------*/
1264EPECIStatus peci_RdEndPointConfigMmio_seq(
1265 uint8_t target, uint8_t u8Seg, uint8_t u8Bus, uint8_t u8Device,
1266 uint8_t u8Fcn, uint8_t u8Bar, uint8_t u8AddrType, uint64_t u64Offset,
1267 uint8_t u8ReadLen, uint8_t* pMmioData, int peci_fd, uint8_t* cc)
1268{
Jason M. Bills8bb8f372022-03-01 16:04:44 -08001269 // Default to domain ID 0
1270 return peci_RdEndPointConfigMmio_seq_dom(
1271 target, 0, u8Seg, u8Bus, u8Device, u8Fcn, u8Bar, u8AddrType, u64Offset,
1272 u8ReadLen, pMmioData, peci_fd, cc);
1273}
1274
1275/*-------------------------------------------------------------------------
1276 * This function allows sequential RdEndPointConfig to PCI MMIO with the
1277 * provided peci file descriptor in the specified domain.
1278 *------------------------------------------------------------------------*/
1279EPECIStatus peci_RdEndPointConfigMmio_seq_dom(
1280 uint8_t target, uint8_t domainId, uint8_t u8Seg, uint8_t u8Bus,
1281 uint8_t u8Device, uint8_t u8Fcn, uint8_t u8Bar, uint8_t u8AddrType,
1282 uint64_t u64Offset, uint8_t u8ReadLen, uint8_t* pMmioData, int peci_fd,
1283 uint8_t* cc)
1284{
Nirav Shahfd5dfd52022-03-09 12:29:41 -08001285 struct peci_rd_end_pt_cfg_msg cmd = {0};
Jason M. Billsbc641112020-08-19 16:31:53 -07001286 EPECIStatus ret = PECI_CC_SUCCESS;
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001287
1288 if (pMmioData == NULL || cc == NULL)
1289 {
1290 return PECI_CC_INVALID_REQ;
1291 }
1292
Jason M. Bills6ca31642020-08-06 10:26:19 -07001293 // The target address must be in the valid range
1294 if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR)
1295 {
1296 return PECI_CC_INVALID_REQ;
1297 }
1298
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001299 // Per the PECI spec, the read length must be a byte, word, dword, or qword
1300 if (u8ReadLen != 1 && u8ReadLen != 2 && u8ReadLen != 4 && u8ReadLen != 8)
1301 {
1302 return PECI_CC_INVALID_REQ;
1303 }
1304
1305 // The PECI buffer must be large enough to hold the requested data
1306 if (sizeof(cmd.data) < u8ReadLen)
1307 {
1308 return PECI_CC_INVALID_REQ;
1309 }
1310
1311 cmd.addr = target;
1312 cmd.msg_type = PECI_ENDPTCFG_TYPE_MMIO;
1313 cmd.params.mmio.seg = u8Seg;
1314 cmd.params.mmio.bus = u8Bus;
1315 cmd.params.mmio.device = u8Device;
1316 cmd.params.mmio.function = u8Fcn;
1317 cmd.params.mmio.bar = u8Bar;
1318 cmd.params.mmio.addr_type = u8AddrType;
1319 cmd.params.mmio.offset = u64Offset;
1320 cmd.rx_len = u8ReadLen;
Jason M. Bills8bb8f372022-03-01 16:04:44 -08001321 cmd.domain_id = domainId;
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001322
1323 ret = HW_peci_issue_cmd(PECI_IOC_RD_END_PT_CFG, (char*)&cmd, peci_fd);
1324 *cc = cmd.cc;
1325
1326 if (ret == PECI_CC_SUCCESS)
1327 {
1328 memcpy(pMmioData, cmd.data, u8ReadLen);
1329 }
1330 else
1331 {
1332 ret = PECI_CC_DRIVER_ERR;
1333 }
1334
1335 return ret;
1336}
1337
1338/*-------------------------------------------------------------------------
1339 * This function allows sequential peci_WrEndPointConfig to PCI EndPoint with
Jason M. Bills8bb8f372022-03-01 16:04:44 -08001340 * the provided peci file descriptor.
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001341 *------------------------------------------------------------------------*/
1342EPECIStatus peci_WrEndPointConfig_seq(uint8_t target, uint8_t u8MsgType,
1343 uint8_t u8Seg, uint8_t u8Bus,
1344 uint8_t u8Device, uint8_t u8Fcn,
1345 uint16_t u16Reg, uint8_t DataLen,
1346 uint32_t DataVal, int peci_fd,
1347 uint8_t* cc)
1348{
Jason M. Bills8bb8f372022-03-01 16:04:44 -08001349 // Default to domain ID 0
1350 return peci_WrEndPointConfig_seq_dom(target, 0, u8MsgType, u8Seg, u8Bus,
1351 u8Device, u8Fcn, u16Reg, DataLen,
1352 DataVal, peci_fd, cc);
1353}
1354
1355/*-------------------------------------------------------------------------
1356 * This function allows sequential peci_WrEndPointConfig to PCI EndPoint with
1357 * the provided peci file descriptor in the specified domain.
1358 *------------------------------------------------------------------------*/
1359EPECIStatus peci_WrEndPointConfig_seq_dom(uint8_t target, uint8_t domainId,
1360 uint8_t u8MsgType, uint8_t u8Seg,
1361 uint8_t u8Bus, uint8_t u8Device,
1362 uint8_t u8Fcn, uint16_t u16Reg,
1363 uint8_t DataLen, uint32_t DataVal,
1364 int peci_fd, uint8_t* cc)
1365{
Nirav Shahfd5dfd52022-03-09 12:29:41 -08001366 struct peci_wr_end_pt_cfg_msg cmd = {0};
Jason M. Billsbc641112020-08-19 16:31:53 -07001367 EPECIStatus ret = PECI_CC_SUCCESS;
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001368
1369 if (cc == NULL)
1370 {
1371 return PECI_CC_INVALID_REQ;
1372 }
1373
Jason M. Bills6ca31642020-08-06 10:26:19 -07001374 // The target address must be in the valid range
1375 if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR)
1376 {
1377 return PECI_CC_INVALID_REQ;
1378 }
1379
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001380 // Per the PECI spec, the write length must be a byte, word, or dword
1381 if (DataLen != 1 && DataLen != 2 && DataLen != 4)
1382 {
1383 return PECI_CC_INVALID_REQ;
1384 }
1385
1386 cmd.addr = target;
1387 cmd.msg_type = u8MsgType;
1388 cmd.params.pci_cfg.seg = u8Seg;
1389 cmd.params.pci_cfg.bus = u8Bus;
1390 cmd.params.pci_cfg.device = u8Device;
1391 cmd.params.pci_cfg.function = u8Fcn;
1392 cmd.params.pci_cfg.reg = u16Reg;
1393 cmd.tx_len = DataLen;
1394 cmd.value = DataVal;
Jason M. Bills8bb8f372022-03-01 16:04:44 -08001395 cmd.domain_id = domainId;
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001396
1397 ret = HW_peci_issue_cmd(PECI_IOC_WR_END_PT_CFG, (char*)&cmd, peci_fd);
1398 *cc = cmd.cc;
1399
1400 return ret;
1401}
1402
1403/*-------------------------------------------------------------------------
Jason M. Bills8bb8f372022-03-01 16:04:44 -08001404 * This function provides write access to the EP local PCI configuration space
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001405 *------------------------------------------------------------------------*/
1406EPECIStatus peci_WrEndPointPCIConfigLocal(uint8_t target, uint8_t u8Seg,
1407 uint8_t u8Bus, uint8_t u8Device,
1408 uint8_t u8Fcn, uint16_t u16Reg,
1409 uint8_t DataLen, uint32_t DataVal,
1410 uint8_t* cc)
1411{
Jason M. Bills8bb8f372022-03-01 16:04:44 -08001412 // Default to domain ID 0
1413 return peci_WrEndPointPCIConfigLocal_dom(
1414 target, 0, u8Seg, u8Bus, u8Device, u8Fcn, u16Reg, DataLen, DataVal, cc);
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001415}
1416
1417/*-------------------------------------------------------------------------
Jason M. Bills8bb8f372022-03-01 16:04:44 -08001418 * This function provides write access to the EP local PCI configuration space
1419 * in the specified domain
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001420 *------------------------------------------------------------------------*/
Jason M. Bills8bb8f372022-03-01 16:04:44 -08001421EPECIStatus peci_WrEndPointPCIConfigLocal_dom(uint8_t target, uint8_t domainId,
1422 uint8_t u8Seg, uint8_t u8Bus,
1423 uint8_t u8Device, uint8_t u8Fcn,
1424 uint16_t u16Reg, uint8_t DataLen,
1425 uint32_t DataVal, uint8_t* cc)
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001426{
1427 int peci_fd = -1;
Jason M. Billsbc641112020-08-19 16:31:53 -07001428 EPECIStatus ret = PECI_CC_SUCCESS;
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001429
1430 if (peci_Open(&peci_fd) != PECI_CC_SUCCESS)
1431 {
1432 return PECI_CC_DRIVER_ERR;
1433 }
Jason M. Bills8bb8f372022-03-01 16:04:44 -08001434
1435 ret = peci_WrEndPointConfig_seq_dom(
1436 target, domainId, PECI_ENDPTCFG_TYPE_LOCAL_PCI, u8Seg, u8Bus, u8Device,
1437 u8Fcn, u16Reg, DataLen, DataVal, peci_fd, cc);
1438 peci_Close(peci_fd);
1439 return ret;
1440}
1441
1442/*-------------------------------------------------------------------------
1443 * This function provides write access to the EP local PCI configuration space
1444 *------------------------------------------------------------------------*/
1445EPECIStatus peci_WrEndPointPCIConfig(uint8_t target, uint8_t u8Seg,
1446 uint8_t u8Bus, uint8_t u8Device,
1447 uint8_t u8Fcn, uint16_t u16Reg,
1448 uint8_t DataLen, uint32_t DataVal,
1449 uint8_t* cc)
1450{
1451 // Default to domain ID 0
1452 return peci_WrEndPointPCIConfig_dom(target, 0, u8Seg, u8Bus, u8Device,
1453 u8Fcn, u16Reg, DataLen, DataVal, cc);
1454}
1455
1456/*-------------------------------------------------------------------------
1457 * This function provides write access to the EP local PCI configuration space
1458 * in the specified domain
1459 *------------------------------------------------------------------------*/
1460EPECIStatus peci_WrEndPointPCIConfig_dom(uint8_t target, uint8_t domainId,
1461 uint8_t u8Seg, uint8_t u8Bus,
1462 uint8_t u8Device, uint8_t u8Fcn,
1463 uint16_t u16Reg, uint8_t DataLen,
1464 uint32_t DataVal, uint8_t* cc)
1465{
1466 int peci_fd = -1;
1467 EPECIStatus ret = PECI_CC_SUCCESS;
1468
1469 if (peci_Open(&peci_fd) != PECI_CC_SUCCESS)
1470 {
1471 return PECI_CC_DRIVER_ERR;
1472 }
1473 ret = peci_WrEndPointConfig_seq_dom(
1474 target, domainId, PECI_ENDPTCFG_TYPE_PCI, u8Seg, u8Bus, u8Device, u8Fcn,
1475 u16Reg, DataLen, DataVal, peci_fd, cc);
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001476 peci_Close(peci_fd);
1477 return ret;
1478}
1479
1480/*-------------------------------------------------------------------------
1481 * This function provides write access to PCI MMIO space at
1482 * the requested PCI configuration address.
1483 *------------------------------------------------------------------------*/
1484EPECIStatus peci_WrEndPointConfigMmio(uint8_t target, uint8_t u8Seg,
1485 uint8_t u8Bus, uint8_t u8Device,
1486 uint8_t u8Fcn, uint8_t u8Bar,
1487 uint8_t u8AddrType, uint64_t u64Offset,
1488 uint8_t u8DataLen, uint64_t u64DataVal,
1489 uint8_t* cc)
1490{
Jason M. Bills8bb8f372022-03-01 16:04:44 -08001491 // Default to domain ID 0
1492 return peci_WrEndPointConfigMmio_dom(target, 0, u8Seg, u8Bus, u8Device,
1493 u8Fcn, u8Bar, u8AddrType, u64Offset,
1494 u8DataLen, u64DataVal, cc);
1495}
1496
1497/*-------------------------------------------------------------------------
1498 * This function provides write access to PCI MMIO space at
1499 * the requested PCI configuration address in the specified domain.
1500 *------------------------------------------------------------------------*/
1501EPECIStatus peci_WrEndPointConfigMmio_dom(uint8_t target, uint8_t domainId,
1502 uint8_t u8Seg, uint8_t u8Bus,
1503 uint8_t u8Device, uint8_t u8Fcn,
1504 uint8_t u8Bar, uint8_t u8AddrType,
1505 uint64_t u64Offset, uint8_t u8DataLen,
1506 uint64_t u64DataVal, uint8_t* cc)
1507{
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001508 int peci_fd = -1;
Jason M. Billsbc641112020-08-19 16:31:53 -07001509 EPECIStatus ret = PECI_CC_SUCCESS;
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001510
1511 if (cc == NULL)
1512 {
1513 return PECI_CC_INVALID_REQ;
1514 }
1515
Jason M. Bills6ca31642020-08-06 10:26:19 -07001516 // The target address must be in the valid range
1517 if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR)
1518 {
1519 return PECI_CC_INVALID_REQ;
1520 }
1521
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001522 if (peci_Open(&peci_fd) != PECI_CC_SUCCESS)
1523 {
1524 return PECI_CC_DRIVER_ERR;
1525 }
Jason M. Bills8bb8f372022-03-01 16:04:44 -08001526 ret = peci_WrEndPointConfigMmio_seq_dom(
1527 target, domainId, u8Seg, u8Bus, u8Device, u8Fcn, u8Bar, u8AddrType,
1528 u64Offset, u8DataLen, u64DataVal, peci_fd, cc);
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001529 peci_Close(peci_fd);
1530 return ret;
1531}
1532
1533/*-------------------------------------------------------------------------
1534 * This function allows sequential WrEndPointConfig to PCI MMIO with the
1535 * provided peci file descriptor.
1536 *------------------------------------------------------------------------*/
1537EPECIStatus peci_WrEndPointConfigMmio_seq(
1538 uint8_t target, uint8_t u8Seg, uint8_t u8Bus, uint8_t u8Device,
1539 uint8_t u8Fcn, uint8_t u8Bar, uint8_t u8AddrType, uint64_t u64Offset,
1540 uint8_t u8DataLen, uint64_t u64DataVal, int peci_fd, uint8_t* cc)
1541{
Jason M. Bills8bb8f372022-03-01 16:04:44 -08001542 // Default to domain ID 0
1543 return peci_WrEndPointConfigMmio_seq_dom(
1544 target, 0, u8Seg, u8Bus, u8Device, u8Fcn, u8Bar, u8AddrType, u64Offset,
1545 u8DataLen, u64DataVal, peci_fd, cc);
1546}
1547
1548/*-------------------------------------------------------------------------
1549 * This function allows sequential WrEndPointConfig to PCI MMIO with the
1550 * provided peci file descriptor in the specified domain.
1551 *------------------------------------------------------------------------*/
1552EPECIStatus peci_WrEndPointConfigMmio_seq_dom(
1553 uint8_t target, uint8_t domainId, uint8_t u8Seg, uint8_t u8Bus,
1554 uint8_t u8Device, uint8_t u8Fcn, uint8_t u8Bar, uint8_t u8AddrType,
1555 uint64_t u64Offset, uint8_t u8DataLen, uint64_t u64DataVal, int peci_fd,
1556 uint8_t* cc)
1557{
Nirav Shahfd5dfd52022-03-09 12:29:41 -08001558 struct peci_wr_end_pt_cfg_msg cmd = {0};
Jason M. Billsbc641112020-08-19 16:31:53 -07001559 EPECIStatus ret = PECI_CC_SUCCESS;
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001560
1561 if (cc == NULL)
1562 {
1563 return PECI_CC_INVALID_REQ;
1564 }
1565
Jason M. Bills6ca31642020-08-06 10:26:19 -07001566 // The target address must be in the valid range
1567 if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR)
1568 {
1569 return PECI_CC_INVALID_REQ;
1570 }
1571
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001572 // Per the PECI spec, the read length must be a byte, word, dword, or qword
1573 if (u8DataLen != 1 && u8DataLen != 2 && u8DataLen != 4 && u8DataLen != 8)
1574 {
1575 return PECI_CC_INVALID_REQ;
1576 }
1577
1578 cmd.addr = target;
1579 cmd.msg_type = PECI_ENDPTCFG_TYPE_MMIO;
1580 cmd.params.mmio.seg = u8Seg;
1581 cmd.params.mmio.bus = u8Bus;
1582 cmd.params.mmio.device = u8Device;
1583 cmd.params.mmio.function = u8Fcn;
1584 cmd.params.mmio.bar = u8Bar;
1585 cmd.params.mmio.addr_type = u8AddrType;
1586 cmd.params.mmio.offset = u64Offset;
1587 cmd.tx_len = u8DataLen;
1588 cmd.value = u64DataVal;
Jason M. Bills8bb8f372022-03-01 16:04:44 -08001589 cmd.domain_id = domainId;
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001590
1591 ret = HW_peci_issue_cmd(PECI_IOC_WR_END_PT_CFG, (char*)&cmd, peci_fd);
1592 *cc = cmd.cc;
1593
1594 return ret;
1595}
1596
1597/*-------------------------------------------------------------------------
Jason M. Bills8bb8f372022-03-01 16:04:44 -08001598 * This function provides crashdump discovery data over PECI
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001599 *------------------------------------------------------------------------*/
1600EPECIStatus peci_CrashDump_Discovery(uint8_t target, uint8_t subopcode,
1601 uint8_t param0, uint16_t param1,
1602 uint8_t param2, uint8_t u8ReadLen,
1603 uint8_t* pData, uint8_t* cc)
1604{
Jason M. Bills8bb8f372022-03-01 16:04:44 -08001605 // Default to domain ID 0
1606 return peci_CrashDump_Discovery_dom(target, 0, subopcode, param0, param1,
1607 param2, u8ReadLen, pData, cc);
1608}
1609
1610/*-------------------------------------------------------------------------
1611 * This function provides crashdump discovery data over PECI in the specified
1612 * domain
1613 *------------------------------------------------------------------------*/
1614EPECIStatus peci_CrashDump_Discovery_dom(uint8_t target, uint8_t domainId,
1615 uint8_t subopcode, uint8_t param0,
1616 uint16_t param1, uint8_t param2,
1617 uint8_t u8ReadLen, uint8_t* pData,
1618 uint8_t* cc)
1619{
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001620 int peci_fd = -1;
Nirav Shahfd5dfd52022-03-09 12:29:41 -08001621 struct peci_crashdump_disc_msg cmd = {0};
Jason M. Billsbc641112020-08-19 16:31:53 -07001622 EPECIStatus ret = PECI_CC_SUCCESS;
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001623
1624 if (pData == NULL || cc == NULL)
1625 {
1626 return PECI_CC_INVALID_REQ;
1627 }
1628
Jason M. Bills6ca31642020-08-06 10:26:19 -07001629 // The target address must be in the valid range
1630 if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR)
1631 {
1632 return PECI_CC_INVALID_REQ;
1633 }
1634
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001635 // Per the PECI spec, the read length must be a byte, word, or qword
1636 if (u8ReadLen != 1 && u8ReadLen != 2 && u8ReadLen != 8)
1637 {
1638 return PECI_CC_INVALID_REQ;
1639 }
1640
1641 // The PECI buffer must be large enough to hold the requested data
1642 if (sizeof(cmd.data) < u8ReadLen)
1643 {
1644 return PECI_CC_INVALID_REQ;
1645 }
1646
1647 if (peci_Open(&peci_fd) != PECI_CC_SUCCESS)
1648 {
1649 return PECI_CC_DRIVER_ERR;
1650 }
1651
1652 cmd.addr = target;
1653 cmd.subopcode = subopcode;
1654 cmd.param0 = param0;
1655 cmd.param1 = param1;
1656 cmd.param2 = param2;
1657 cmd.rx_len = u8ReadLen;
Jason M. Bills8bb8f372022-03-01 16:04:44 -08001658 cmd.domain_id = domainId;
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001659
1660 ret = HW_peci_issue_cmd(PECI_IOC_CRASHDUMP_DISC, (char*)&cmd, peci_fd);
1661 *cc = cmd.cc;
1662 if (ret == PECI_CC_SUCCESS)
1663 {
1664 memcpy(pData, cmd.data, u8ReadLen);
1665 }
1666 else
1667 {
1668 ret = PECI_CC_DRIVER_ERR;
1669 }
1670
1671 peci_Close(peci_fd);
1672 return ret;
1673}
1674
1675/*-------------------------------------------------------------------------
Jason M. Bills8bb8f372022-03-01 16:04:44 -08001676 * This function provides crashdump GetFrame data over PECI
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001677 *------------------------------------------------------------------------*/
1678EPECIStatus peci_CrashDump_GetFrame(uint8_t target, uint16_t param0,
1679 uint16_t param1, uint16_t param2,
1680 uint8_t u8ReadLen, uint8_t* pData,
1681 uint8_t* cc)
1682{
Jason M. Bills8bb8f372022-03-01 16:04:44 -08001683 // Default to domain ID 0
1684 return peci_CrashDump_GetFrame_dom(target, 0, param0, param1, param2,
1685 u8ReadLen, pData, cc);
1686}
1687
1688/*-------------------------------------------------------------------------
1689 * This function provides crashdump GetFrame data over PECI in the specified
1690 * domain
1691 *------------------------------------------------------------------------*/
1692EPECIStatus peci_CrashDump_GetFrame_dom(uint8_t target, uint8_t domainId,
1693 uint16_t param0, uint16_t param1,
1694 uint16_t param2, uint8_t u8ReadLen,
1695 uint8_t* pData, uint8_t* cc)
1696{
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001697 int peci_fd = -1;
Nirav Shahfd5dfd52022-03-09 12:29:41 -08001698 struct peci_crashdump_get_frame_msg cmd = {0};
Jason M. Billsbc641112020-08-19 16:31:53 -07001699 EPECIStatus ret = PECI_CC_SUCCESS;
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001700
1701 if (pData == NULL || cc == NULL)
1702 {
1703 return PECI_CC_INVALID_REQ;
1704 }
1705
Jason M. Bills6ca31642020-08-06 10:26:19 -07001706 // The target address must be in the valid range
1707 if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR)
1708 {
1709 return PECI_CC_INVALID_REQ;
1710 }
1711
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001712 // Per the PECI spec, the read length must be a qword or dqword
1713 if (u8ReadLen != 8 && u8ReadLen != 16)
1714 {
1715 return PECI_CC_INVALID_REQ;
1716 }
1717
1718 // The PECI buffer must be large enough to hold the requested data
1719 if (sizeof(cmd.data) < u8ReadLen)
1720 {
1721 return PECI_CC_INVALID_REQ;
1722 }
1723
1724 if (peci_Open(&peci_fd) != PECI_CC_SUCCESS)
1725 {
1726 return PECI_CC_DRIVER_ERR;
1727 }
1728
1729 cmd.addr = target;
1730 cmd.param0 = param0;
1731 cmd.param1 = param1;
1732 cmd.param2 = param2;
1733 cmd.rx_len = u8ReadLen;
Jason M. Bills8bb8f372022-03-01 16:04:44 -08001734 cmd.domain_id = domainId;
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001735
1736 ret = HW_peci_issue_cmd(PECI_IOC_CRASHDUMP_GET_FRAME, (char*)&cmd, peci_fd);
1737 *cc = cmd.cc;
1738 if (ret == PECI_CC_SUCCESS)
1739 {
1740 memcpy(pData, cmd.data, u8ReadLen);
1741 }
1742 else
1743 {
1744 ret = PECI_CC_DRIVER_ERR;
1745 }
1746
1747 peci_Close(peci_fd);
1748 return ret;
1749}
1750
1751/*-------------------------------------------------------------------------
1752 * This function provides raw PECI command access
1753 *------------------------------------------------------------------------*/
1754EPECIStatus peci_raw(uint8_t target, uint8_t u8ReadLen, const uint8_t* pRawCmd,
1755 const uint32_t cmdSize, uint8_t* pRawResp,
1756 uint32_t respSize)
1757{
1758 int peci_fd = -1;
Nirav Shahfd5dfd52022-03-09 12:29:41 -08001759 struct peci_xfer_msg cmd = {0};
1760 uint8_t u8TxBuf[PECI_BUFFER_SIZE] = {0};
1761 uint8_t u8RxBuf[PECI_BUFFER_SIZE] = {0};
Jason M. Billsbc641112020-08-19 16:31:53 -07001762 EPECIStatus ret = PECI_CC_SUCCESS;
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001763
1764 if (u8ReadLen && pRawResp == NULL)
1765 {
1766 return PECI_CC_INVALID_REQ;
1767 }
1768
Jason M. Bills6ca31642020-08-06 10:26:19 -07001769 // The target address must be in the valid range
1770 if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR)
1771 {
1772 return PECI_CC_INVALID_REQ;
1773 }
1774
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001775 if (peci_Open(&peci_fd) != PECI_CC_SUCCESS)
1776 {
1777 return PECI_CC_DRIVER_ERR;
1778 }
1779
1780 // Check for valid buffer sizes
1781 if (cmdSize > PECI_BUFFER_SIZE || respSize < u8ReadLen ||
1782 u8ReadLen >
1783 (PECI_BUFFER_SIZE - 1)) // response buffer is data + 1 status byte
1784 {
1785 peci_Close(peci_fd);
1786 return PECI_CC_INVALID_REQ;
1787 }
1788
1789 cmd.addr = target;
1790 cmd.tx_len = (uint8_t)cmdSize;
1791 cmd.rx_len = u8ReadLen;
1792
1793 memcpy(u8TxBuf, pRawCmd, cmdSize);
1794
1795 cmd.tx_buf = u8TxBuf;
1796 cmd.rx_buf = u8RxBuf;
1797 ret = HW_peci_issue_cmd(PECI_IOC_XFER, (char*)&cmd, peci_fd);
1798
1799 if (ret == PECI_CC_SUCCESS || ret == PECI_CC_TIMEOUT)
1800 {
1801 memcpy(pRawResp, u8RxBuf, u8ReadLen);
1802 }
1803
1804 peci_Close(peci_fd);
1805 return ret;
1806}
1807
1808/*-------------------------------------------------------------------------
1809 * This function returns the CPUID (Model and stepping) for the given PECI
1810 * client address
1811 *------------------------------------------------------------------------*/
1812EPECIStatus peci_GetCPUID(const uint8_t clientAddr, CPUModel* cpuModel,
1813 uint8_t* stepping, uint8_t* cc)
1814{
1815 EPECIStatus ret = PECI_CC_SUCCESS;
1816 uint32_t cpuid = 0;
1817
1818 if (cpuModel == NULL || stepping == NULL || cc == NULL)
1819 {
1820 return PECI_CC_INVALID_REQ;
1821 }
1822
Jason M. Bills6ca31642020-08-06 10:26:19 -07001823 // The client address must be in the valid range
1824 if (clientAddr < MIN_CLIENT_ADDR || clientAddr > MAX_CLIENT_ADDR)
1825 {
1826 return PECI_CC_INVALID_REQ;
1827 }
1828
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001829 if (peci_Ping(clientAddr) != PECI_CC_SUCCESS)
1830 {
1831 return PECI_CC_CPU_NOT_PRESENT;
1832 }
1833
1834 ret =
1835 peci_RdPkgConfig(clientAddr, PECI_MBX_INDEX_CPU_ID, PECI_PKG_ID_CPU_ID,
1836 sizeof(uint32_t), (uint8_t*)&cpuid, cc);
1837
1838 // Separate out the model and stepping (bits 3:0) from the CPUID
1839 *cpuModel = cpuid & 0xFFFFFFF0;
1840 *stepping = (uint8_t)(cpuid & 0x0000000F);
1841 return ret;
1842}