blob: 53596f67b6d01a32ccb5a04b948e8a1ffcbc7cbb [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{
42 static char peci_name_new[DEV_NAME_SIZE] = {};
43
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{
Jason M. Billsbc641112020-08-19 16:31:53 -070091 struct timespec sRequest = {};
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;
192 uint8_t u8Reg[4] = {};
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;
278 struct peci_ping_msg cmd = {};
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{
Jason M. Billsbc641112020-08-19 16:31:53 -0700327 struct peci_get_dib_msg cmd = {};
328 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;
Jason M. Billsbc641112020-08-19 16:31:53 -0700359 struct peci_get_temp_msg cmd = {};
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{
400 int peci_fd = -1;
Jason M. Billsbc641112020-08-19 16:31:53 -0700401 EPECIStatus ret = PECI_CC_SUCCESS;
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700402
403 if (pPkgConfig == NULL || cc == NULL)
404 {
405 return PECI_CC_INVALID_REQ;
406 }
407
Jason M. Bills6ca31642020-08-06 10:26:19 -0700408 // The target address must be in the valid range
409 if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR)
410 {
411 return PECI_CC_INVALID_REQ;
412 }
413
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700414 if (peci_Open(&peci_fd) != PECI_CC_SUCCESS)
415 {
416 return PECI_CC_DRIVER_ERR;
417 }
418 ret = peci_RdPkgConfig_seq(target, u8Index, u16Value, u8ReadLen, pPkgConfig,
419 peci_fd, cc);
420
421 peci_Close(peci_fd);
422 return ret;
423}
424
425/*-------------------------------------------------------------------------
426 * This function allows sequential RdPkgConfig with the provided
427 * peci file descriptor.
428 *------------------------------------------------------------------------*/
429EPECIStatus peci_RdPkgConfig_seq(uint8_t target, uint8_t u8Index,
430 uint16_t u16Value, uint8_t u8ReadLen,
431 uint8_t* pPkgConfig, int peci_fd, uint8_t* cc)
432{
Jason M. Billsbc641112020-08-19 16:31:53 -0700433 struct peci_rd_pkg_cfg_msg cmd = {};
434 EPECIStatus ret = PECI_CC_SUCCESS;
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700435
436 if (pPkgConfig == NULL || cc == NULL)
437 {
438 return PECI_CC_INVALID_REQ;
439 }
440
Jason M. Bills6ca31642020-08-06 10:26:19 -0700441 // The target address must be in the valid range
442 if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR)
443 {
444 return PECI_CC_INVALID_REQ;
445 }
446
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700447 // Per the PECI spec, the write length must be a byte, word, or dword
448 if (u8ReadLen != 1 && u8ReadLen != 2 && u8ReadLen != 4)
449 {
450 return PECI_CC_INVALID_REQ;
451 }
452
453 // The PECI buffer must be large enough to hold the requested data
454 if (sizeof(cmd.pkg_config) < u8ReadLen)
455 {
456 return PECI_CC_INVALID_REQ;
457 }
458
459 cmd.addr = target;
460 cmd.index = u8Index; // RdPkgConfig index
461 cmd.param = u16Value; // Config parameter value
462 cmd.rx_len = u8ReadLen;
463
464 ret = HW_peci_issue_cmd(PECI_IOC_RD_PKG_CFG, (char*)&cmd, peci_fd);
465 *cc = cmd.cc;
466 if (ret == PECI_CC_SUCCESS)
467 {
468 memcpy(pPkgConfig, cmd.pkg_config, u8ReadLen);
469 }
470
471 return ret;
472}
473
474/*-------------------------------------------------------------------------
475 * This function provides write access to the package configuration
476 * space within the processor
477 *------------------------------------------------------------------------*/
478EPECIStatus peci_WrPkgConfig(uint8_t target, uint8_t u8Index, uint16_t u16Param,
479 uint32_t u32Value, uint8_t u8WriteLen, uint8_t* cc)
480{
481 int peci_fd = -1;
Jason M. Billsbc641112020-08-19 16:31:53 -0700482 EPECIStatus ret = PECI_CC_SUCCESS;
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700483
484 if (cc == NULL)
485 {
486 return PECI_CC_INVALID_REQ;
487 }
488
Jason M. Bills6ca31642020-08-06 10:26:19 -0700489 // The target address must be in the valid range
490 if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR)
491 {
492 return PECI_CC_INVALID_REQ;
493 }
494
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700495 if (peci_Open(&peci_fd) != PECI_CC_SUCCESS)
496 {
497 return PECI_CC_DRIVER_ERR;
498 }
499 ret = peci_WrPkgConfig_seq(target, u8Index, u16Param, u32Value, u8WriteLen,
500 peci_fd, cc);
501
502 peci_Close(peci_fd);
503 return ret;
504}
505
506/*-------------------------------------------------------------------------
507 * This function allows sequential WrPkgConfig with the provided
508 * peci file descriptor.
509 *------------------------------------------------------------------------*/
510EPECIStatus peci_WrPkgConfig_seq(uint8_t target, uint8_t u8Index,
511 uint16_t u16Param, uint32_t u32Value,
512 uint8_t u8WriteLen, int peci_fd, uint8_t* cc)
513{
Jason M. Billsbc641112020-08-19 16:31:53 -0700514 struct peci_wr_pkg_cfg_msg cmd = {};
515 EPECIStatus ret = PECI_CC_SUCCESS;
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700516
517 if (cc == NULL)
518 {
519 return PECI_CC_INVALID_REQ;
520 }
521
Jason M. Bills6ca31642020-08-06 10:26:19 -0700522 // The target address must be in the valid range
523 if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR)
524 {
525 return PECI_CC_INVALID_REQ;
526 }
527
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700528 // Per the PECI spec, the write length must be a byte, word, or dword
529 if ((u8WriteLen != 1) && (u8WriteLen != 2) && (u8WriteLen != 4))
530 {
531 return PECI_CC_INVALID_REQ;
532 }
533
534 cmd.addr = target;
535 cmd.index = u8Index; // RdPkgConfig index
536 cmd.param = u16Param; // parameter value
537 cmd.tx_len = u8WriteLen;
538 cmd.value = u32Value;
539
540 ret = HW_peci_issue_cmd(PECI_IOC_WR_PKG_CFG, (char*)&cmd, peci_fd);
541 *cc = cmd.cc;
542
543 return ret;
544}
545
546/*-------------------------------------------------------------------------
547 * This function provides read access to Model Specific Registers
548 * defined in the processor doc.
549 *------------------------------------------------------------------------*/
550EPECIStatus peci_RdIAMSR(uint8_t target, uint8_t threadID, uint16_t MSRAddress,
551 uint64_t* u64MsrVal, uint8_t* cc)
552{
553 int peci_fd = -1;
Jason M. Billsbc641112020-08-19 16:31:53 -0700554 struct peci_rd_ia_msr_msg cmd = {};
555 EPECIStatus ret = PECI_CC_SUCCESS;
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700556
557 if (u64MsrVal == NULL || cc == NULL)
558 {
559 return PECI_CC_INVALID_REQ;
560 }
561
Jason M. Bills6ca31642020-08-06 10:26:19 -0700562 // The target address must be in the valid range
563 if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR)
564 {
565 return PECI_CC_INVALID_REQ;
566 }
567
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700568 if (peci_Open(&peci_fd) != PECI_CC_SUCCESS)
569 {
570 return PECI_CC_DRIVER_ERR;
571 }
572
573 cmd.addr = target;
574 cmd.thread_id = threadID; // request byte for thread ID
575 cmd.address = MSRAddress; // MSR Address
576
577 ret = HW_peci_issue_cmd(PECI_IOC_RD_IA_MSR, (char*)&cmd, peci_fd);
578 *cc = cmd.cc;
579 if (ret == PECI_CC_SUCCESS)
580 {
581 *u64MsrVal = cmd.value;
582 }
583
584 peci_Close(peci_fd);
585 return ret;
586}
587
588/*-------------------------------------------------------------------------
589 * This function provides read access to the PCI configuration space at
590 * the requested PCI configuration address.
591 *------------------------------------------------------------------------*/
592EPECIStatus peci_RdPCIConfig(uint8_t target, uint8_t u8Bus, uint8_t u8Device,
593 uint8_t u8Fcn, uint16_t u16Reg, uint8_t* pPCIData,
594 uint8_t* cc)
595{
596 int peci_fd = -1;
Jason M. Billsbc641112020-08-19 16:31:53 -0700597 EPECIStatus ret = PECI_CC_SUCCESS;
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700598
599 if (pPCIData == NULL || cc == NULL)
600 {
601 return PECI_CC_INVALID_REQ;
602 }
603
Jason M. Bills6ca31642020-08-06 10:26:19 -0700604 // The target address must be in the valid range
605 if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR)
606 {
607 return PECI_CC_INVALID_REQ;
608 }
609
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700610 if (peci_Open(&peci_fd) != PECI_CC_SUCCESS)
611 {
612 return PECI_CC_DRIVER_ERR;
613 }
614 ret = peci_RdPCIConfig_seq(target, u8Bus, u8Device, u8Fcn, u16Reg, pPCIData,
615 peci_fd, cc);
616
617 peci_Close(peci_fd);
618 return ret;
619}
620
621/*-------------------------------------------------------------------------
622 * This function allows sequential RdPCIConfig with the provided
623 * peci file descriptor.
624 *------------------------------------------------------------------------*/
625EPECIStatus peci_RdPCIConfig_seq(uint8_t target, uint8_t u8Bus,
626 uint8_t u8Device, uint8_t u8Fcn,
627 uint16_t u16Reg, uint8_t* pPCIData,
628 int peci_fd, uint8_t* cc)
629{
Jason M. Billsbc641112020-08-19 16:31:53 -0700630 struct peci_rd_pci_cfg_msg cmd = {};
631 EPECIStatus ret = PECI_CC_SUCCESS;
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700632
633 if (pPCIData == NULL || cc == NULL)
634 {
635 return PECI_CC_INVALID_REQ;
636 }
637
Jason M. Bills6ca31642020-08-06 10:26:19 -0700638 // The target address must be in the valid range
639 if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR)
640 {
641 return PECI_CC_INVALID_REQ;
642 }
643
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700644 // The PECI buffer must be large enough to hold the PCI data
645 if (sizeof(cmd.pci_config) < 4)
646 {
647 return PECI_CC_INVALID_REQ;
648 }
649
650 cmd.addr = target;
651 cmd.bus = u8Bus;
652 cmd.device = u8Device;
653 cmd.function = u8Fcn;
654 cmd.reg = u16Reg;
655
656 ret = HW_peci_issue_cmd(PECI_IOC_RD_PCI_CFG, (char*)&cmd, peci_fd);
657 *cc = cmd.cc;
658
659 if (ret == PECI_CC_SUCCESS)
660 {
661 memcpy(pPCIData, cmd.pci_config, 4);
662 }
663
664 return ret;
665}
666
667/*-------------------------------------------------------------------------
668 * This function provides read access to the local PCI configuration space
669 *------------------------------------------------------------------------*/
670EPECIStatus peci_RdPCIConfigLocal(uint8_t target, uint8_t u8Bus,
671 uint8_t u8Device, uint8_t u8Fcn,
672 uint16_t u16Reg, uint8_t u8ReadLen,
673 uint8_t* pPCIReg, uint8_t* cc)
674{
675 int peci_fd = -1;
Jason M. Billsbc641112020-08-19 16:31:53 -0700676 EPECIStatus ret = PECI_CC_SUCCESS;
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700677
678 if (pPCIReg == NULL || cc == NULL)
679 {
680 return PECI_CC_INVALID_REQ;
681 }
682
Jason M. Bills6ca31642020-08-06 10:26:19 -0700683 // The target address must be in the valid range
684 if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR)
685 {
686 return PECI_CC_INVALID_REQ;
687 }
688
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700689 if (peci_Open(&peci_fd) != PECI_CC_SUCCESS)
690 {
691 return PECI_CC_DRIVER_ERR;
692 }
693 ret = peci_RdPCIConfigLocal_seq(target, u8Bus, u8Device, u8Fcn, u16Reg,
694 u8ReadLen, pPCIReg, peci_fd, cc);
695
696 peci_Close(peci_fd);
697 return ret;
698}
699
700/*-------------------------------------------------------------------------
701 * This function allows sequential RdPCIConfigLocal with the provided
702 * peci file descriptor.
703 *------------------------------------------------------------------------*/
704EPECIStatus peci_RdPCIConfigLocal_seq(uint8_t target, uint8_t u8Bus,
705 uint8_t u8Device, uint8_t u8Fcn,
706 uint16_t u16Reg, uint8_t u8ReadLen,
707 uint8_t* pPCIReg, int peci_fd,
708 uint8_t* cc)
709{
Jason M. Billsbc641112020-08-19 16:31:53 -0700710 struct peci_rd_pci_cfg_local_msg cmd = {};
711 EPECIStatus ret = PECI_CC_SUCCESS;
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700712
713 if (pPCIReg == NULL || cc == NULL)
714 {
715 return PECI_CC_INVALID_REQ;
716 }
717
Jason M. Bills6ca31642020-08-06 10:26:19 -0700718 // The target address must be in the valid range
719 if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR)
720 {
721 return PECI_CC_INVALID_REQ;
722 }
723
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700724 // Per the PECI spec, the read length must be a byte, word, or dword
725 if (u8ReadLen != 1 && u8ReadLen != 2 && u8ReadLen != 4)
726 {
727 return PECI_CC_INVALID_REQ;
728 }
729
730 // The PECI buffer must be large enough to hold the requested data
731 if (sizeof(cmd.pci_config) < u8ReadLen)
732 {
733 return PECI_CC_INVALID_REQ;
734 }
735
736 cmd.addr = target;
737 cmd.bus = u8Bus;
738 cmd.device = u8Device;
739 cmd.function = u8Fcn;
740 cmd.reg = u16Reg;
741 cmd.rx_len = u8ReadLen;
742
743 ret = HW_peci_issue_cmd(PECI_IOC_RD_PCI_CFG_LOCAL, (char*)&cmd, peci_fd);
744 *cc = cmd.cc;
745
746 if (ret == PECI_CC_SUCCESS)
747 {
748 memcpy(pPCIReg, cmd.pci_config, u8ReadLen);
749 }
750
751 return ret;
752}
753
754/*-------------------------------------------------------------------------
755 * This function provides write access to the local PCI configuration space
756 *------------------------------------------------------------------------*/
757EPECIStatus peci_WrPCIConfigLocal(uint8_t target, uint8_t u8Bus,
758 uint8_t u8Device, uint8_t u8Fcn,
759 uint16_t u16Reg, uint8_t DataLen,
760 uint32_t DataVal, uint8_t* cc)
761{
762 int peci_fd = -1;
Jason M. Billsbc641112020-08-19 16:31:53 -0700763 struct peci_wr_pci_cfg_local_msg cmd = {};
764 EPECIStatus ret = PECI_CC_SUCCESS;
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700765
766 if (cc == NULL)
767 {
768 return PECI_CC_INVALID_REQ;
769 }
770
Jason M. Bills6ca31642020-08-06 10:26:19 -0700771 // The target address must be in the valid range
772 if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR)
773 {
774 return PECI_CC_INVALID_REQ;
775 }
776
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700777 if (peci_Open(&peci_fd) != PECI_CC_SUCCESS)
778 {
779 return PECI_CC_DRIVER_ERR;
780 }
781
782 // Per the PECI spec, the write length must be a byte, word, or dword
783 if (DataLen != 1 && DataLen != 2 && DataLen != 4)
784 {
785 peci_Close(peci_fd);
786 return PECI_CC_INVALID_REQ;
787 }
788
789 cmd.addr = target;
790 cmd.bus = u8Bus;
791 cmd.device = u8Device;
792 cmd.function = u8Fcn;
793 cmd.reg = u16Reg;
794 cmd.tx_len = DataLen;
795 cmd.value = DataVal;
796
797 ret = HW_peci_issue_cmd(PECI_IOC_WR_PCI_CFG_LOCAL, (char*)&cmd, peci_fd);
798 *cc = cmd.cc;
799
800 peci_Close(peci_fd);
801 return ret;
802}
803
804/*-------------------------------------------------------------------------
805 * This internal function is the common interface for RdEndPointConfig to PCI
806 *------------------------------------------------------------------------*/
807static EPECIStatus peci_RdEndPointConfigPciCommon(
808 uint8_t target, uint8_t u8MsgType, uint8_t u8Seg, uint8_t u8Bus,
809 uint8_t u8Device, uint8_t u8Fcn, uint16_t u16Reg, uint8_t u8ReadLen,
810 uint8_t* pPCIData, int peci_fd, uint8_t* cc)
811{
Jason M. Billsbc641112020-08-19 16:31:53 -0700812 struct peci_rd_end_pt_cfg_msg cmd = {};
813 EPECIStatus ret = PECI_CC_SUCCESS;
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700814
815 if (pPCIData == NULL || cc == NULL)
816 {
817 return PECI_CC_INVALID_REQ;
818 }
819
Jason M. Bills6ca31642020-08-06 10:26:19 -0700820 // The target address must be in the valid range
821 if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR)
822 {
823 return PECI_CC_INVALID_REQ;
824 }
825
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700826 // The PECI buffer must be large enough to hold the requested data
827 if (sizeof(cmd.data) < u8ReadLen)
828 {
829 return PECI_CC_INVALID_REQ;
830 }
831
832 cmd.addr = target;
833 cmd.msg_type = u8MsgType;
834 cmd.params.pci_cfg.seg = u8Seg;
835 cmd.params.pci_cfg.bus = u8Bus;
836 cmd.params.pci_cfg.device = u8Device;
837 cmd.params.pci_cfg.function = u8Fcn;
838 cmd.params.pci_cfg.reg = u16Reg;
839 cmd.rx_len = u8ReadLen;
840
841 ret = HW_peci_issue_cmd(PECI_IOC_RD_END_PT_CFG, (char*)&cmd, peci_fd);
842 *cc = cmd.cc;
843
844 if (ret == PECI_CC_SUCCESS)
845 {
846 memcpy(pPCIData, cmd.data, u8ReadLen);
847 }
848 else
849 {
850 ret = PECI_CC_DRIVER_ERR;
851 }
852
853 return ret;
854}
855
856/*-------------------------------------------------------------------------
857 * This function provides read access to the PCI configuration space at
858 * the requested PCI configuration address.
859 *------------------------------------------------------------------------*/
860EPECIStatus peci_RdEndPointConfigPci(uint8_t target, uint8_t u8Seg,
861 uint8_t u8Bus, uint8_t u8Device,
862 uint8_t u8Fcn, uint16_t u16Reg,
863 uint8_t u8ReadLen, uint8_t* pPCIData,
864 uint8_t* cc)
865{
866 int peci_fd = -1;
Jason M. Billsbc641112020-08-19 16:31:53 -0700867 EPECIStatus ret = PECI_CC_SUCCESS;
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700868
869 if (pPCIData == NULL || cc == NULL)
870 {
871 return PECI_CC_INVALID_REQ;
872 }
873
Jason M. Bills6ca31642020-08-06 10:26:19 -0700874 // The target address must be in the valid range
875 if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR)
876 {
877 return PECI_CC_INVALID_REQ;
878 }
879
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700880 if (peci_Open(&peci_fd) != PECI_CC_SUCCESS)
881 {
882 return PECI_CC_DRIVER_ERR;
883 }
884 ret =
885 peci_RdEndPointConfigPci_seq(target, u8Seg, u8Bus, u8Device, u8Fcn,
886 u16Reg, u8ReadLen, pPCIData, peci_fd, cc);
887 peci_Close(peci_fd);
888 return ret;
889}
890
891/*-------------------------------------------------------------------------
892 * This function allows sequential RdEndPointConfig to PCI with the provided
893 * peci file descriptor.
894 *------------------------------------------------------------------------*/
895EPECIStatus peci_RdEndPointConfigPci_seq(uint8_t target, uint8_t u8Seg,
896 uint8_t u8Bus, uint8_t u8Device,
897 uint8_t u8Fcn, uint16_t u16Reg,
898 uint8_t u8ReadLen, uint8_t* pPCIData,
899 int peci_fd, uint8_t* cc)
900{
901 if (pPCIData == NULL || cc == NULL)
902 {
903 return PECI_CC_INVALID_REQ;
904 }
905
Jason M. Bills6ca31642020-08-06 10:26:19 -0700906 // The target address must be in the valid range
907 if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR)
908 {
909 return PECI_CC_INVALID_REQ;
910 }
911
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700912 // Per the PECI spec, the read length must be a byte, word, or dword
913 if (u8ReadLen != 1 && u8ReadLen != 2 && u8ReadLen != 4)
914 {
915 return PECI_CC_INVALID_REQ;
916 }
917
918 return peci_RdEndPointConfigPciCommon(target, PECI_ENDPTCFG_TYPE_PCI, u8Seg,
919 u8Bus, u8Device, u8Fcn, u16Reg,
920 u8ReadLen, pPCIData, peci_fd, cc);
921}
922
923/*-------------------------------------------------------------------------
924 * This function provides read access to the Local PCI configuration space at
925 * the requested PCI configuration address.
926 *------------------------------------------------------------------------*/
927EPECIStatus peci_RdEndPointConfigPciLocal(uint8_t target, uint8_t u8Seg,
928 uint8_t u8Bus, uint8_t u8Device,
929 uint8_t u8Fcn, uint16_t u16Reg,
930 uint8_t u8ReadLen, uint8_t* pPCIData,
931 uint8_t* cc)
932{
933 int peci_fd = -1;
Jason M. Billsbc641112020-08-19 16:31:53 -0700934 EPECIStatus ret = PECI_CC_SUCCESS;
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700935
936 if (pPCIData == NULL || cc == NULL)
937 {
938 return PECI_CC_INVALID_REQ;
939 }
940
Jason M. Bills6ca31642020-08-06 10:26:19 -0700941 // The target address must be in the valid range
942 if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR)
943 {
944 return PECI_CC_INVALID_REQ;
945 }
946
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700947 if (peci_Open(&peci_fd) != PECI_CC_SUCCESS)
948 {
949 return PECI_CC_DRIVER_ERR;
950 }
951 ret = peci_RdEndPointConfigPciLocal_seq(target, u8Seg, u8Bus, u8Device,
952 u8Fcn, u16Reg, u8ReadLen, pPCIData,
953 peci_fd, cc);
954 peci_Close(peci_fd);
955 return ret;
956}
957
958/*-------------------------------------------------------------------------
959 * This function allows sequential RdEndPointConfig to PCI Local with the
960 *provided peci file descriptor.
961 *------------------------------------------------------------------------*/
962EPECIStatus peci_RdEndPointConfigPciLocal_seq(uint8_t target, uint8_t u8Seg,
963 uint8_t u8Bus, uint8_t u8Device,
964 uint8_t u8Fcn, uint16_t u16Reg,
965 uint8_t u8ReadLen,
966 uint8_t* pPCIData, int peci_fd,
967 uint8_t* cc)
968{
969 if (pPCIData == NULL || cc == NULL)
970 {
971 return PECI_CC_INVALID_REQ;
972 }
973
Jason M. Bills6ca31642020-08-06 10:26:19 -0700974 // The target address must be in the valid range
975 if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR)
976 {
977 return PECI_CC_INVALID_REQ;
978 }
979
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700980 // Per the PECI spec, the read length must be a byte, word, or dword
981 if (u8ReadLen != 1 && u8ReadLen != 2 && u8ReadLen != 4)
982 {
983 return PECI_CC_INVALID_REQ;
984 }
985
986 return peci_RdEndPointConfigPciCommon(target, PECI_ENDPTCFG_TYPE_LOCAL_PCI,
987 u8Seg, u8Bus, u8Device, u8Fcn, u16Reg,
988 u8ReadLen, pPCIData, peci_fd, cc);
989}
990
991/*-------------------------------------------------------------------------
992 * This function provides read access to PCI MMIO space at
993 * the requested PCI configuration address.
994 *------------------------------------------------------------------------*/
995EPECIStatus peci_RdEndPointConfigMmio(uint8_t target, uint8_t u8Seg,
996 uint8_t u8Bus, uint8_t u8Device,
997 uint8_t u8Fcn, uint8_t u8Bar,
998 uint8_t u8AddrType, uint64_t u64Offset,
999 uint8_t u8ReadLen, uint8_t* pMmioData,
1000 uint8_t* cc)
1001{
1002 int peci_fd = -1;
Jason M. Billsbc641112020-08-19 16:31:53 -07001003 EPECIStatus ret = PECI_CC_SUCCESS;
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001004
1005 if (pMmioData == NULL || cc == NULL)
1006 {
1007 return PECI_CC_INVALID_REQ;
1008 }
1009
Jason M. Bills6ca31642020-08-06 10:26:19 -07001010 // The target address must be in the valid range
1011 if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR)
1012 {
1013 return PECI_CC_INVALID_REQ;
1014 }
1015
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001016 if (peci_Open(&peci_fd) != PECI_CC_SUCCESS)
1017 {
1018 return PECI_CC_DRIVER_ERR;
1019 }
1020 ret = peci_RdEndPointConfigMmio_seq(target, u8Seg, u8Bus, u8Device, u8Fcn,
1021 u8Bar, u8AddrType, u64Offset, u8ReadLen,
1022 pMmioData, peci_fd, cc);
1023 peci_Close(peci_fd);
1024 return ret;
1025}
1026
1027/*-------------------------------------------------------------------------
1028 * This function allows sequential RdEndPointConfig to PCI MMIO with the
1029 *provided peci file descriptor.
1030 *------------------------------------------------------------------------*/
1031EPECIStatus peci_RdEndPointConfigMmio_seq(
1032 uint8_t target, uint8_t u8Seg, uint8_t u8Bus, uint8_t u8Device,
1033 uint8_t u8Fcn, uint8_t u8Bar, uint8_t u8AddrType, uint64_t u64Offset,
1034 uint8_t u8ReadLen, uint8_t* pMmioData, int peci_fd, uint8_t* cc)
1035{
Jason M. Billsbc641112020-08-19 16:31:53 -07001036 struct peci_rd_end_pt_cfg_msg cmd = {};
1037 EPECIStatus ret = PECI_CC_SUCCESS;
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001038
1039 if (pMmioData == NULL || cc == NULL)
1040 {
1041 return PECI_CC_INVALID_REQ;
1042 }
1043
Jason M. Bills6ca31642020-08-06 10:26:19 -07001044 // The target address must be in the valid range
1045 if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR)
1046 {
1047 return PECI_CC_INVALID_REQ;
1048 }
1049
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001050 // Per the PECI spec, the read length must be a byte, word, dword, or qword
1051 if (u8ReadLen != 1 && u8ReadLen != 2 && u8ReadLen != 4 && u8ReadLen != 8)
1052 {
1053 return PECI_CC_INVALID_REQ;
1054 }
1055
1056 // The PECI buffer must be large enough to hold the requested data
1057 if (sizeof(cmd.data) < u8ReadLen)
1058 {
1059 return PECI_CC_INVALID_REQ;
1060 }
1061
1062 cmd.addr = target;
1063 cmd.msg_type = PECI_ENDPTCFG_TYPE_MMIO;
1064 cmd.params.mmio.seg = u8Seg;
1065 cmd.params.mmio.bus = u8Bus;
1066 cmd.params.mmio.device = u8Device;
1067 cmd.params.mmio.function = u8Fcn;
1068 cmd.params.mmio.bar = u8Bar;
1069 cmd.params.mmio.addr_type = u8AddrType;
1070 cmd.params.mmio.offset = u64Offset;
1071 cmd.rx_len = u8ReadLen;
1072
1073 ret = HW_peci_issue_cmd(PECI_IOC_RD_END_PT_CFG, (char*)&cmd, peci_fd);
1074 *cc = cmd.cc;
1075
1076 if (ret == PECI_CC_SUCCESS)
1077 {
1078 memcpy(pMmioData, cmd.data, u8ReadLen);
1079 }
1080 else
1081 {
1082 ret = PECI_CC_DRIVER_ERR;
1083 }
1084
1085 return ret;
1086}
1087
1088/*-------------------------------------------------------------------------
1089 * This function allows sequential peci_WrEndPointConfig to PCI EndPoint with
1090 *the provided peci file descriptor.
1091 *------------------------------------------------------------------------*/
1092EPECIStatus peci_WrEndPointConfig_seq(uint8_t target, uint8_t u8MsgType,
1093 uint8_t u8Seg, uint8_t u8Bus,
1094 uint8_t u8Device, uint8_t u8Fcn,
1095 uint16_t u16Reg, uint8_t DataLen,
1096 uint32_t DataVal, int peci_fd,
1097 uint8_t* cc)
1098{
Jason M. Billsbc641112020-08-19 16:31:53 -07001099 struct peci_wr_end_pt_cfg_msg cmd = {};
1100 EPECIStatus ret = PECI_CC_SUCCESS;
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001101
1102 if (cc == NULL)
1103 {
1104 return PECI_CC_INVALID_REQ;
1105 }
1106
Jason M. Bills6ca31642020-08-06 10:26:19 -07001107 // The target address must be in the valid range
1108 if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR)
1109 {
1110 return PECI_CC_INVALID_REQ;
1111 }
1112
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001113 // Per the PECI spec, the write length must be a byte, word, or dword
1114 if (DataLen != 1 && DataLen != 2 && DataLen != 4)
1115 {
1116 return PECI_CC_INVALID_REQ;
1117 }
1118
1119 cmd.addr = target;
1120 cmd.msg_type = u8MsgType;
1121 cmd.params.pci_cfg.seg = u8Seg;
1122 cmd.params.pci_cfg.bus = u8Bus;
1123 cmd.params.pci_cfg.device = u8Device;
1124 cmd.params.pci_cfg.function = u8Fcn;
1125 cmd.params.pci_cfg.reg = u16Reg;
1126 cmd.tx_len = DataLen;
1127 cmd.value = DataVal;
1128
1129 ret = HW_peci_issue_cmd(PECI_IOC_WR_END_PT_CFG, (char*)&cmd, peci_fd);
1130 *cc = cmd.cc;
1131
1132 return ret;
1133}
1134
1135/*-------------------------------------------------------------------------
1136 * This function provides write access to the EP local PCI configuration space
1137 *------------------------------------------------------------------------*/
1138EPECIStatus peci_WrEndPointPCIConfigLocal(uint8_t target, uint8_t u8Seg,
1139 uint8_t u8Bus, uint8_t u8Device,
1140 uint8_t u8Fcn, uint16_t u16Reg,
1141 uint8_t DataLen, uint32_t DataVal,
1142 uint8_t* cc)
1143{
1144 int peci_fd = -1;
Jason M. Billsbc641112020-08-19 16:31:53 -07001145 EPECIStatus ret = PECI_CC_SUCCESS;
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001146
1147 if (peci_Open(&peci_fd) != PECI_CC_SUCCESS)
1148 {
1149 return PECI_CC_DRIVER_ERR;
1150 }
1151
1152 ret = peci_WrEndPointConfig_seq(target, PECI_ENDPTCFG_TYPE_LOCAL_PCI, u8Seg,
1153 u8Bus, u8Device, u8Fcn, u16Reg, DataLen,
1154 DataVal, peci_fd, cc);
1155 peci_Close(peci_fd);
1156 return ret;
1157}
1158
1159/*-------------------------------------------------------------------------
1160 * This function provides write access to the EP local PCI configuration space
1161 *------------------------------------------------------------------------*/
1162EPECIStatus peci_WrEndPointPCIConfig(uint8_t target, uint8_t u8Seg,
1163 uint8_t u8Bus, uint8_t u8Device,
1164 uint8_t u8Fcn, uint16_t u16Reg,
1165 uint8_t DataLen, uint32_t DataVal,
1166 uint8_t* cc)
1167{
1168 int peci_fd = -1;
Jason M. Billsbc641112020-08-19 16:31:53 -07001169 EPECIStatus ret = PECI_CC_SUCCESS;
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001170
1171 if (peci_Open(&peci_fd) != PECI_CC_SUCCESS)
1172 {
1173 return PECI_CC_DRIVER_ERR;
1174 }
1175 ret = peci_WrEndPointConfig_seq(target, PECI_ENDPTCFG_TYPE_PCI, u8Seg,
1176 u8Bus, u8Device, u8Fcn, u16Reg, DataLen,
1177 DataVal, peci_fd, cc);
1178 peci_Close(peci_fd);
1179 return ret;
1180}
1181
1182/*-------------------------------------------------------------------------
1183 * This function provides write access to PCI MMIO space at
1184 * the requested PCI configuration address.
1185 *------------------------------------------------------------------------*/
1186EPECIStatus peci_WrEndPointConfigMmio(uint8_t target, uint8_t u8Seg,
1187 uint8_t u8Bus, uint8_t u8Device,
1188 uint8_t u8Fcn, uint8_t u8Bar,
1189 uint8_t u8AddrType, uint64_t u64Offset,
1190 uint8_t u8DataLen, uint64_t u64DataVal,
1191 uint8_t* cc)
1192{
1193 int peci_fd = -1;
Jason M. Billsbc641112020-08-19 16:31:53 -07001194 EPECIStatus ret = PECI_CC_SUCCESS;
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001195
1196 if (cc == NULL)
1197 {
1198 return PECI_CC_INVALID_REQ;
1199 }
1200
Jason M. Bills6ca31642020-08-06 10:26:19 -07001201 // The target address must be in the valid range
1202 if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR)
1203 {
1204 return PECI_CC_INVALID_REQ;
1205 }
1206
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001207 if (peci_Open(&peci_fd) != PECI_CC_SUCCESS)
1208 {
1209 return PECI_CC_DRIVER_ERR;
1210 }
1211 ret = peci_WrEndPointConfigMmio_seq(target, u8Seg, u8Bus, u8Device, u8Fcn,
1212 u8Bar, u8AddrType, u64Offset, u8DataLen,
1213 u64DataVal, peci_fd, cc);
1214 peci_Close(peci_fd);
1215 return ret;
1216}
1217
1218/*-------------------------------------------------------------------------
1219 * This function allows sequential WrEndPointConfig to PCI MMIO with the
1220 * provided peci file descriptor.
1221 *------------------------------------------------------------------------*/
1222EPECIStatus peci_WrEndPointConfigMmio_seq(
1223 uint8_t target, uint8_t u8Seg, uint8_t u8Bus, uint8_t u8Device,
1224 uint8_t u8Fcn, uint8_t u8Bar, uint8_t u8AddrType, uint64_t u64Offset,
1225 uint8_t u8DataLen, uint64_t u64DataVal, int peci_fd, uint8_t* cc)
1226{
Jason M. Billsbc641112020-08-19 16:31:53 -07001227 struct peci_wr_end_pt_cfg_msg cmd = {};
1228 EPECIStatus ret = PECI_CC_SUCCESS;
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001229
1230 if (cc == NULL)
1231 {
1232 return PECI_CC_INVALID_REQ;
1233 }
1234
Jason M. Bills6ca31642020-08-06 10:26:19 -07001235 // The target address must be in the valid range
1236 if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR)
1237 {
1238 return PECI_CC_INVALID_REQ;
1239 }
1240
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001241 // Per the PECI spec, the read length must be a byte, word, dword, or qword
1242 if (u8DataLen != 1 && u8DataLen != 2 && u8DataLen != 4 && u8DataLen != 8)
1243 {
1244 return PECI_CC_INVALID_REQ;
1245 }
1246
1247 cmd.addr = target;
1248 cmd.msg_type = PECI_ENDPTCFG_TYPE_MMIO;
1249 cmd.params.mmio.seg = u8Seg;
1250 cmd.params.mmio.bus = u8Bus;
1251 cmd.params.mmio.device = u8Device;
1252 cmd.params.mmio.function = u8Fcn;
1253 cmd.params.mmio.bar = u8Bar;
1254 cmd.params.mmio.addr_type = u8AddrType;
1255 cmd.params.mmio.offset = u64Offset;
1256 cmd.tx_len = u8DataLen;
1257 cmd.value = u64DataVal;
1258
1259 ret = HW_peci_issue_cmd(PECI_IOC_WR_END_PT_CFG, (char*)&cmd, peci_fd);
1260 *cc = cmd.cc;
1261
1262 return ret;
1263}
1264
1265/*-------------------------------------------------------------------------
1266 * This function provides crashdump discovery data over PECI
1267 *------------------------------------------------------------------------*/
1268EPECIStatus peci_CrashDump_Discovery(uint8_t target, uint8_t subopcode,
1269 uint8_t param0, uint16_t param1,
1270 uint8_t param2, uint8_t u8ReadLen,
1271 uint8_t* pData, uint8_t* cc)
1272{
1273 int peci_fd = -1;
Jason M. Billsbc641112020-08-19 16:31:53 -07001274 struct peci_crashdump_disc_msg cmd = {};
1275 EPECIStatus ret = PECI_CC_SUCCESS;
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001276
1277 if (pData == NULL || cc == NULL)
1278 {
1279 return PECI_CC_INVALID_REQ;
1280 }
1281
Jason M. Bills6ca31642020-08-06 10:26:19 -07001282 // The target address must be in the valid range
1283 if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR)
1284 {
1285 return PECI_CC_INVALID_REQ;
1286 }
1287
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001288 // Per the PECI spec, the read length must be a byte, word, or qword
1289 if (u8ReadLen != 1 && u8ReadLen != 2 && u8ReadLen != 8)
1290 {
1291 return PECI_CC_INVALID_REQ;
1292 }
1293
1294 // The PECI buffer must be large enough to hold the requested data
1295 if (sizeof(cmd.data) < u8ReadLen)
1296 {
1297 return PECI_CC_INVALID_REQ;
1298 }
1299
1300 if (peci_Open(&peci_fd) != PECI_CC_SUCCESS)
1301 {
1302 return PECI_CC_DRIVER_ERR;
1303 }
1304
1305 cmd.addr = target;
1306 cmd.subopcode = subopcode;
1307 cmd.param0 = param0;
1308 cmd.param1 = param1;
1309 cmd.param2 = param2;
1310 cmd.rx_len = u8ReadLen;
1311
1312 ret = HW_peci_issue_cmd(PECI_IOC_CRASHDUMP_DISC, (char*)&cmd, peci_fd);
1313 *cc = cmd.cc;
1314 if (ret == PECI_CC_SUCCESS)
1315 {
1316 memcpy(pData, cmd.data, u8ReadLen);
1317 }
1318 else
1319 {
1320 ret = PECI_CC_DRIVER_ERR;
1321 }
1322
1323 peci_Close(peci_fd);
1324 return ret;
1325}
1326
1327/*-------------------------------------------------------------------------
1328 * This function provides crashdump GetFrame data over PECI
1329 *------------------------------------------------------------------------*/
1330EPECIStatus peci_CrashDump_GetFrame(uint8_t target, uint16_t param0,
1331 uint16_t param1, uint16_t param2,
1332 uint8_t u8ReadLen, uint8_t* pData,
1333 uint8_t* cc)
1334{
1335 int peci_fd = -1;
Jason M. Billsbc641112020-08-19 16:31:53 -07001336 struct peci_crashdump_get_frame_msg cmd = {};
1337 EPECIStatus ret = PECI_CC_SUCCESS;
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001338
1339 if (pData == NULL || cc == NULL)
1340 {
1341 return PECI_CC_INVALID_REQ;
1342 }
1343
Jason M. Bills6ca31642020-08-06 10:26:19 -07001344 // The target address must be in the valid range
1345 if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR)
1346 {
1347 return PECI_CC_INVALID_REQ;
1348 }
1349
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001350 // Per the PECI spec, the read length must be a qword or dqword
1351 if (u8ReadLen != 8 && u8ReadLen != 16)
1352 {
1353 return PECI_CC_INVALID_REQ;
1354 }
1355
1356 // The PECI buffer must be large enough to hold the requested data
1357 if (sizeof(cmd.data) < u8ReadLen)
1358 {
1359 return PECI_CC_INVALID_REQ;
1360 }
1361
1362 if (peci_Open(&peci_fd) != PECI_CC_SUCCESS)
1363 {
1364 return PECI_CC_DRIVER_ERR;
1365 }
1366
1367 cmd.addr = target;
1368 cmd.param0 = param0;
1369 cmd.param1 = param1;
1370 cmd.param2 = param2;
1371 cmd.rx_len = u8ReadLen;
1372
1373 ret = HW_peci_issue_cmd(PECI_IOC_CRASHDUMP_GET_FRAME, (char*)&cmd, peci_fd);
1374 *cc = cmd.cc;
1375 if (ret == PECI_CC_SUCCESS)
1376 {
1377 memcpy(pData, cmd.data, u8ReadLen);
1378 }
1379 else
1380 {
1381 ret = PECI_CC_DRIVER_ERR;
1382 }
1383
1384 peci_Close(peci_fd);
1385 return ret;
1386}
1387
1388/*-------------------------------------------------------------------------
1389 * This function provides raw PECI command access
1390 *------------------------------------------------------------------------*/
1391EPECIStatus peci_raw(uint8_t target, uint8_t u8ReadLen, const uint8_t* pRawCmd,
1392 const uint32_t cmdSize, uint8_t* pRawResp,
1393 uint32_t respSize)
1394{
1395 int peci_fd = -1;
Jason M. Billsbc641112020-08-19 16:31:53 -07001396 struct peci_xfer_msg cmd = {};
1397 uint8_t u8TxBuf[PECI_BUFFER_SIZE] = {};
1398 uint8_t u8RxBuf[PECI_BUFFER_SIZE] = {};
1399 EPECIStatus ret = PECI_CC_SUCCESS;
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001400
1401 if (u8ReadLen && pRawResp == NULL)
1402 {
1403 return PECI_CC_INVALID_REQ;
1404 }
1405
Jason M. Bills6ca31642020-08-06 10:26:19 -07001406 // The target address must be in the valid range
1407 if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR)
1408 {
1409 return PECI_CC_INVALID_REQ;
1410 }
1411
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001412 if (peci_Open(&peci_fd) != PECI_CC_SUCCESS)
1413 {
1414 return PECI_CC_DRIVER_ERR;
1415 }
1416
1417 // Check for valid buffer sizes
1418 if (cmdSize > PECI_BUFFER_SIZE || respSize < u8ReadLen ||
1419 u8ReadLen >
1420 (PECI_BUFFER_SIZE - 1)) // response buffer is data + 1 status byte
1421 {
1422 peci_Close(peci_fd);
1423 return PECI_CC_INVALID_REQ;
1424 }
1425
1426 cmd.addr = target;
1427 cmd.tx_len = (uint8_t)cmdSize;
1428 cmd.rx_len = u8ReadLen;
1429
1430 memcpy(u8TxBuf, pRawCmd, cmdSize);
1431
1432 cmd.tx_buf = u8TxBuf;
1433 cmd.rx_buf = u8RxBuf;
1434 ret = HW_peci_issue_cmd(PECI_IOC_XFER, (char*)&cmd, peci_fd);
1435
1436 if (ret == PECI_CC_SUCCESS || ret == PECI_CC_TIMEOUT)
1437 {
1438 memcpy(pRawResp, u8RxBuf, u8ReadLen);
1439 }
1440
1441 peci_Close(peci_fd);
1442 return ret;
1443}
1444
1445/*-------------------------------------------------------------------------
1446 * This function returns the CPUID (Model and stepping) for the given PECI
1447 * client address
1448 *------------------------------------------------------------------------*/
1449EPECIStatus peci_GetCPUID(const uint8_t clientAddr, CPUModel* cpuModel,
1450 uint8_t* stepping, uint8_t* cc)
1451{
1452 EPECIStatus ret = PECI_CC_SUCCESS;
1453 uint32_t cpuid = 0;
1454
1455 if (cpuModel == NULL || stepping == NULL || cc == NULL)
1456 {
1457 return PECI_CC_INVALID_REQ;
1458 }
1459
Jason M. Bills6ca31642020-08-06 10:26:19 -07001460 // The client address must be in the valid range
1461 if (clientAddr < MIN_CLIENT_ADDR || clientAddr > MAX_CLIENT_ADDR)
1462 {
1463 return PECI_CC_INVALID_REQ;
1464 }
1465
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001466 if (peci_Ping(clientAddr) != PECI_CC_SUCCESS)
1467 {
1468 return PECI_CC_CPU_NOT_PRESENT;
1469 }
1470
1471 ret =
1472 peci_RdPkgConfig(clientAddr, PECI_MBX_INDEX_CPU_ID, PECI_PKG_ID_CPU_ID,
1473 sizeof(uint32_t), (uint8_t*)&cpuid, cc);
1474
1475 // Separate out the model and stepping (bits 3:0) from the CPUID
1476 *cpuModel = cpuid & 0xFFFFFFF0;
1477 *stepping = (uint8_t)(cpuid & 0x0000000F);
1478 return ret;
1479}