blob: ab69234d80f6e704f78768e22fe94375ef0ce2a9 [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 }
V-Sanjana258161b2023-01-18 20:56:30 +0530119 break;
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700120 default:
121 while (-1 == *peci_fd && timeout_count < timeout_ms)
122 {
123 nanosleep(&sRequest, NULL);
124 timeout_count += PECI_TIMEOUT_RESOLUTION_MS;
Anna Platash03d7dae2021-02-05 13:52:05 +0100125 *peci_fd = open(peci_device, O_RDWR | O_CLOEXEC);
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700126 }
127 }
128 if (-1 == *peci_fd)
129 {
130 syslog(LOG_ERR, " >>> PECI Device Busy <<< \n");
131 return PECI_CC_DRIVER_ERR;
132 }
133 return PECI_CC_SUCCESS;
134}
135
136/*-------------------------------------------------------------------------
137 * This function closes the peci interface
138 *------------------------------------------------------------------------*/
139static void peci_Close(int peci_fd)
140{
141 peci_Unlock(peci_fd);
142}
143
144/*-------------------------------------------------------------------------
145 * This function opens the peci interface and returns a file descriptor
146 *------------------------------------------------------------------------*/
147static EPECIStatus peci_Open(int* peci_fd)
148{
149 if (NULL == peci_fd)
150 {
151 return PECI_CC_INVALID_REQ;
152 }
153
154 // Lock the PECI driver with a default timeout
155 return peci_Lock(peci_fd, PECI_TIMEOUT_MS);
156}
157
158/*-------------------------------------------------------------------------
159 * This function issues peci commands to peci driver
160 *------------------------------------------------------------------------*/
161static EPECIStatus HW_peci_issue_cmd(unsigned int cmd, char* cmdPtr,
162 int peci_fd)
163{
164 if (cmdPtr == NULL)
165 {
166 return PECI_CC_INVALID_REQ;
167 }
168
169 if (ioctl(peci_fd, cmd, cmdPtr) != 0)
170 {
171 if (errno == ETIMEDOUT)
172 {
173 return PECI_CC_TIMEOUT;
174 }
175 return PECI_CC_DRIVER_ERR;
176 }
177
178 return PECI_CC_SUCCESS;
179}
180
181/*-------------------------------------------------------------------------
182 * Find the specified PCI bus number value
183 *------------------------------------------------------------------------*/
184EPECIStatus FindBusNumber(uint8_t u8Bus, uint8_t u8Cpu, uint8_t* pu8BusValue)
185{
186 uint8_t u8CpuBus0[] = {
187 PECI_PCI_BUS0_CPU0,
188 PECI_PCI_BUS0_CPU1,
189 };
190 uint8_t u8Bus0 = 0;
191 uint8_t u8Offset = 0;
Jason M. Billsbc641112020-08-19 16:31:53 -0700192 EPECIStatus ret = PECI_CC_SUCCESS;
Nirav Shahfd5dfd52022-03-09 12:29:41 -0800193 uint8_t u8Reg[4] = {0};
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700194 uint8_t cc = 0;
195
196 // First check for valid inputs
197 // Check cpu and bus numbers, only support buses [5:0]
198 if ((u8Bus > 5) || (u8Cpu >= (sizeof(u8CpuBus0) / sizeof(uint8_t))) ||
199 (pu8BusValue == NULL))
200 {
201 return PECI_CC_INVALID_REQ;
202 }
203
204 // Get the Bus 0 value for the requested CPU
205 u8Bus0 = u8CpuBus0[u8Cpu];
206
207 // Next check that the bus numbers are valid
208 // CPUBUSNO_VALID register - Above registers valid? - B(0) D5 F0 offset
209 // D4h
210 ret = peci_RdPCIConfig(u8Cpu, u8Bus0, PECI_PCI_CPUBUSNO_DEV,
211 PECI_PCI_CPUBUSNO_FUNC, PECI_PCI_CPUBUSNO_VALID,
212 u8Reg, &cc);
213 if (ret != PECI_CC_SUCCESS)
214 {
215 return ret;
216 }
217 // BIOS will set bit 31 of CPUBUSNO_VALID when the bus numbers are valid
218 if ((u8Reg[3] & 0x80) == 0)
219 {
220 return PECI_CC_HW_ERR;
221 }
222
223 // Bus numbers are valid so read the correct offset for the requested
224 // bus CPUBUSNO register - CPU Internal Bus Numbers [3:0] - B(0) D5 F0
225 // offset CCh CPUBUSNO_1 register - CPU Internal Bus Numbers [5:4] -
226 // B(0) D5 F0 offset D0h
227 u8Offset = u8Bus <= 3 ? PECI_PCI_CPUBUSNO : PECI_PCI_CPUBUSNO_1;
228 ret = peci_RdPCIConfig(u8Cpu, u8Bus0, PECI_PCI_CPUBUSNO_DEV,
229 PECI_PCI_CPUBUSNO_FUNC, u8Offset, u8Reg, &cc);
230 if (ret != PECI_CC_SUCCESS)
231 {
232 return ret;
233 }
234
235 // Now return the bus value for the requested bus
236 *pu8BusValue = u8Reg[u8Bus % 4];
237
238 // Unused bus numbers are set to zero which is only valid for bus 0
239 // so, return an error for any other bus set to zero
240 if (*pu8BusValue == 0 && u8Bus != 0)
241 {
242 return PECI_CC_CPU_NOT_PRESENT;
243 }
244
245 return PECI_CC_SUCCESS;
246}
247
248/*-------------------------------------------------------------------------
249 * This function checks the CPU PECI interface
250 *------------------------------------------------------------------------*/
251EPECIStatus peci_Ping(uint8_t target)
252{
253 int peci_fd = -1;
Jason M. Billsbc641112020-08-19 16:31:53 -0700254 EPECIStatus ret = PECI_CC_SUCCESS;
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700255
Jason M. Bills6ca31642020-08-06 10:26:19 -0700256 // The target address must be in the valid range
257 if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR)
258 {
259 return PECI_CC_INVALID_REQ;
260 }
261
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700262 if (peci_Open(&peci_fd) != PECI_CC_SUCCESS)
263 {
264 return PECI_CC_DRIVER_ERR;
265 }
266 ret = peci_Ping_seq(target, peci_fd);
267
268 peci_Close(peci_fd);
269 return ret;
270}
271
272/*-------------------------------------------------------------------------
273 * This function allows sequential Ping with the provided
274 * peci file descriptor.
275 *------------------------------------------------------------------------*/
276EPECIStatus peci_Ping_seq(uint8_t target, int peci_fd)
277{
Jason M. Billsbc641112020-08-19 16:31:53 -0700278 EPECIStatus ret = PECI_CC_SUCCESS;
Nirav Shahfd5dfd52022-03-09 12:29:41 -0800279 struct peci_ping_msg cmd = {0};
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700280
Jason M. Bills6ca31642020-08-06 10:26:19 -0700281 // The target address must be in the valid range
282 if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR)
283 {
284 return PECI_CC_INVALID_REQ;
285 }
286
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700287 cmd.addr = target;
288 ret = HW_peci_issue_cmd(PECI_IOC_PING, (char*)&cmd, peci_fd);
289
290 return ret;
291}
292
293/*-------------------------------------------------------------------------
294 * This function gets PECI device information
295 *------------------------------------------------------------------------*/
296EPECIStatus peci_GetDIB(uint8_t target, uint64_t* dib)
297{
298 int peci_fd = -1;
Jason M. Billsbc641112020-08-19 16:31:53 -0700299 EPECIStatus ret = PECI_CC_SUCCESS;
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700300
301 if (dib == NULL)
302 {
303 return PECI_CC_INVALID_REQ;
304 }
305
Jason M. Bills6ca31642020-08-06 10:26:19 -0700306 // The target address must be in the valid range
307 if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR)
308 {
309 return PECI_CC_INVALID_REQ;
310 }
311
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700312 if (peci_Open(&peci_fd) != PECI_CC_SUCCESS)
313 {
314 return PECI_CC_DRIVER_ERR;
315 }
316 ret = peci_GetDIB_seq(target, dib, peci_fd);
317
318 peci_Close(peci_fd);
319 return ret;
320}
321
322/*-------------------------------------------------------------------------
323 * This function allows sequential GetDIB with the provided
324 * peci file descriptor.
325 *------------------------------------------------------------------------*/
326EPECIStatus peci_GetDIB_seq(uint8_t target, uint64_t* dib, int peci_fd)
327{
Nirav Shahfd5dfd52022-03-09 12:29:41 -0800328 struct peci_get_dib_msg cmd = {0};
Jason M. Billsbc641112020-08-19 16:31:53 -0700329 EPECIStatus ret = PECI_CC_SUCCESS;
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700330 cmd.addr = target;
331
332 if (dib == NULL)
333 {
334 return PECI_CC_INVALID_REQ;
335 }
336
Jason M. Bills6ca31642020-08-06 10:26:19 -0700337 // The target address must be in the valid range
338 if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR)
339 {
340 return PECI_CC_INVALID_REQ;
341 }
342
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700343 ret = HW_peci_issue_cmd(PECI_IOC_GET_DIB, (char*)&cmd, peci_fd);
344
345 if (ret == PECI_CC_SUCCESS)
346 {
347 *dib = cmd.dib;
348 }
349
350 return ret;
351}
352
353/*-------------------------------------------------------------------------
354 * This function get PECI Thermal temperature
355 * Expressed in signed fixed point value of 1/64 degrees celsius
356 *------------------------------------------------------------------------*/
357EPECIStatus peci_GetTemp(uint8_t target, int16_t* temperature)
358{
359 int peci_fd = -1;
Nirav Shahfd5dfd52022-03-09 12:29:41 -0800360 struct peci_get_temp_msg cmd = {0};
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700361
362 if (temperature == NULL)
363 {
364 return PECI_CC_INVALID_REQ;
365 }
366
Jason M. Bills6ca31642020-08-06 10:26:19 -0700367 // The target address must be in the valid range
368 if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR)
369 {
370 return PECI_CC_INVALID_REQ;
371 }
372
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700373 if (peci_Open(&peci_fd) != PECI_CC_SUCCESS)
374 {
375 return PECI_CC_DRIVER_ERR;
376 }
377
378 cmd.addr = target;
379
Patrick Williams7169faa2023-05-10 07:51:24 -0500380 EPECIStatus ret = HW_peci_issue_cmd(PECI_IOC_GET_TEMP, (char*)&cmd,
381 peci_fd);
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700382
383 if (ret == PECI_CC_SUCCESS)
384 {
385 *temperature = cmd.temp_raw;
386 }
387
388 peci_Close(peci_fd);
389
390 return ret;
391}
392
393/*-------------------------------------------------------------------------
394 * This function provides read access to the package configuration
395 * space within the processor.
396 *------------------------------------------------------------------------*/
397EPECIStatus peci_RdPkgConfig(uint8_t target, uint8_t u8Index, uint16_t u16Value,
398 uint8_t u8ReadLen, uint8_t* pPkgConfig,
399 uint8_t* cc)
400{
Jason M. Bills8bb8f372022-03-01 16:04:44 -0800401 // Default to domain ID 0
402 return peci_RdPkgConfig_dom(target, 0, u8Index, u16Value, u8ReadLen,
403 pPkgConfig, cc);
404}
405
406/*-------------------------------------------------------------------------
407 * This function provides read access to the package configuration
408 * space within the processor in the specified domain.
409 *------------------------------------------------------------------------*/
410EPECIStatus peci_RdPkgConfig_dom(uint8_t target, uint8_t domainId,
411 uint8_t u8Index, uint16_t u16Value,
412 uint8_t u8ReadLen, uint8_t* pPkgConfig,
413 uint8_t* cc)
414{
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700415 int peci_fd = -1;
Jason M. Billsbc641112020-08-19 16:31:53 -0700416 EPECIStatus ret = PECI_CC_SUCCESS;
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700417
418 if (pPkgConfig == NULL || cc == NULL)
419 {
420 return PECI_CC_INVALID_REQ;
421 }
422
Jason M. Bills6ca31642020-08-06 10:26:19 -0700423 // The target address must be in the valid range
424 if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR)
425 {
426 return PECI_CC_INVALID_REQ;
427 }
428
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700429 if (peci_Open(&peci_fd) != PECI_CC_SUCCESS)
430 {
431 return PECI_CC_DRIVER_ERR;
432 }
Jason M. Bills8bb8f372022-03-01 16:04:44 -0800433 ret = peci_RdPkgConfig_seq_dom(target, domainId, u8Index, u16Value,
434 u8ReadLen, pPkgConfig, peci_fd, cc);
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700435
436 peci_Close(peci_fd);
437 return ret;
438}
439
440/*-------------------------------------------------------------------------
441 * This function allows sequential RdPkgConfig with the provided
442 * peci file descriptor.
443 *------------------------------------------------------------------------*/
444EPECIStatus peci_RdPkgConfig_seq(uint8_t target, uint8_t u8Index,
445 uint16_t u16Value, uint8_t u8ReadLen,
446 uint8_t* pPkgConfig, int peci_fd, uint8_t* cc)
447{
Jason M. Bills8bb8f372022-03-01 16:04:44 -0800448 // Default to domain ID 0
449 return peci_RdPkgConfig_seq_dom(target, 0, u8Index, u16Value, u8ReadLen,
450 pPkgConfig, peci_fd, cc);
451}
452
453/*-------------------------------------------------------------------------
454 * This function allows sequential RdPkgConfig with the provided
455 * peci file descriptor in the specified domain.
456 *------------------------------------------------------------------------*/
457EPECIStatus peci_RdPkgConfig_seq_dom(uint8_t target, uint8_t domainId,
458 uint8_t u8Index, uint16_t u16Value,
459 uint8_t u8ReadLen, uint8_t* pPkgConfig,
460 int peci_fd, uint8_t* cc)
461{
Nirav Shahfd5dfd52022-03-09 12:29:41 -0800462 struct peci_rd_pkg_cfg_msg cmd = {0};
Jason M. Billsbc641112020-08-19 16:31:53 -0700463 EPECIStatus ret = PECI_CC_SUCCESS;
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700464
465 if (pPkgConfig == NULL || cc == NULL)
466 {
467 return PECI_CC_INVALID_REQ;
468 }
469
Jason M. Bills6ca31642020-08-06 10:26:19 -0700470 // The target address must be in the valid range
471 if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR)
472 {
473 return PECI_CC_INVALID_REQ;
474 }
475
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700476 // Per the PECI spec, the write length must be a byte, word, or dword
477 if (u8ReadLen != 1 && u8ReadLen != 2 && u8ReadLen != 4)
478 {
479 return PECI_CC_INVALID_REQ;
480 }
481
482 // The PECI buffer must be large enough to hold the requested data
483 if (sizeof(cmd.pkg_config) < u8ReadLen)
484 {
485 return PECI_CC_INVALID_REQ;
486 }
487
488 cmd.addr = target;
489 cmd.index = u8Index; // RdPkgConfig index
490 cmd.param = u16Value; // Config parameter value
491 cmd.rx_len = u8ReadLen;
Jason M. Bills8bb8f372022-03-01 16:04:44 -0800492 cmd.domain_id = domainId;
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700493
494 ret = HW_peci_issue_cmd(PECI_IOC_RD_PKG_CFG, (char*)&cmd, peci_fd);
495 *cc = cmd.cc;
496 if (ret == PECI_CC_SUCCESS)
497 {
498 memcpy(pPkgConfig, cmd.pkg_config, u8ReadLen);
499 }
500
501 return ret;
502}
503
504/*-------------------------------------------------------------------------
505 * This function provides write access to the package configuration
506 * space within the processor
507 *------------------------------------------------------------------------*/
508EPECIStatus peci_WrPkgConfig(uint8_t target, uint8_t u8Index, uint16_t u16Param,
509 uint32_t u32Value, uint8_t u8WriteLen, uint8_t* cc)
510{
Jason M. Bills8bb8f372022-03-01 16:04:44 -0800511 // Default to domain ID 0
512 return peci_WrPkgConfig_dom(target, 0, u8Index, u16Param, u32Value,
513 u8WriteLen, cc);
514}
515
516/*-------------------------------------------------------------------------
517 * This function provides write access to the package configuration
518 * space within the processor in the specified domain
519 *------------------------------------------------------------------------*/
520EPECIStatus peci_WrPkgConfig_dom(uint8_t target, uint8_t domainId,
521 uint8_t u8Index, uint16_t u16Param,
522 uint32_t u32Value, uint8_t u8WriteLen,
523 uint8_t* cc)
524{
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700525 int peci_fd = -1;
Jason M. Billsbc641112020-08-19 16:31:53 -0700526 EPECIStatus ret = PECI_CC_SUCCESS;
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700527
528 if (cc == NULL)
529 {
530 return PECI_CC_INVALID_REQ;
531 }
532
Jason M. Bills6ca31642020-08-06 10:26:19 -0700533 // The target address must be in the valid range
534 if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR)
535 {
536 return PECI_CC_INVALID_REQ;
537 }
538
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700539 if (peci_Open(&peci_fd) != PECI_CC_SUCCESS)
540 {
541 return PECI_CC_DRIVER_ERR;
542 }
Jason M. Bills8bb8f372022-03-01 16:04:44 -0800543 ret = peci_WrPkgConfig_seq_dom(target, domainId, u8Index, u16Param,
544 u32Value, u8WriteLen, peci_fd, cc);
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700545
546 peci_Close(peci_fd);
547 return ret;
548}
549
550/*-------------------------------------------------------------------------
551 * This function allows sequential WrPkgConfig with the provided
552 * peci file descriptor.
553 *------------------------------------------------------------------------*/
554EPECIStatus peci_WrPkgConfig_seq(uint8_t target, uint8_t u8Index,
555 uint16_t u16Param, uint32_t u32Value,
556 uint8_t u8WriteLen, int peci_fd, uint8_t* cc)
557{
Jason M. Bills8bb8f372022-03-01 16:04:44 -0800558 // Default to domain ID 0
559 return peci_WrPkgConfig_seq_dom(target, 0, u8Index, u16Param, u32Value,
560 u8WriteLen, peci_fd, cc);
561}
562
563/*-------------------------------------------------------------------------
564 * This function allows sequential WrPkgConfig with the provided
565 * peci file descriptor in the specified domain.
566 *------------------------------------------------------------------------*/
567EPECIStatus peci_WrPkgConfig_seq_dom(uint8_t target, uint8_t domainId,
568 uint8_t u8Index, uint16_t u16Param,
569 uint32_t u32Value, uint8_t u8WriteLen,
570 int peci_fd, uint8_t* cc)
571{
Nirav Shahfd5dfd52022-03-09 12:29:41 -0800572 struct peci_wr_pkg_cfg_msg cmd = {0};
Jason M. Billsbc641112020-08-19 16:31:53 -0700573 EPECIStatus ret = PECI_CC_SUCCESS;
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700574
575 if (cc == NULL)
576 {
577 return PECI_CC_INVALID_REQ;
578 }
579
Jason M. Bills6ca31642020-08-06 10:26:19 -0700580 // The target address must be in the valid range
581 if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR)
582 {
583 return PECI_CC_INVALID_REQ;
584 }
585
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700586 // Per the PECI spec, the write length must be a byte, word, or dword
587 if ((u8WriteLen != 1) && (u8WriteLen != 2) && (u8WriteLen != 4))
588 {
589 return PECI_CC_INVALID_REQ;
590 }
591
592 cmd.addr = target;
593 cmd.index = u8Index; // RdPkgConfig index
594 cmd.param = u16Param; // parameter value
595 cmd.tx_len = u8WriteLen;
596 cmd.value = u32Value;
Jason M. Bills8bb8f372022-03-01 16:04:44 -0800597 cmd.domain_id = domainId;
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700598
599 ret = HW_peci_issue_cmd(PECI_IOC_WR_PKG_CFG, (char*)&cmd, peci_fd);
600 *cc = cmd.cc;
601
602 return ret;
603}
604
605/*-------------------------------------------------------------------------
606 * This function provides read access to Model Specific Registers
607 * defined in the processor doc.
608 *------------------------------------------------------------------------*/
609EPECIStatus peci_RdIAMSR(uint8_t target, uint8_t threadID, uint16_t MSRAddress,
610 uint64_t* u64MsrVal, uint8_t* cc)
611{
Jason M. Bills8bb8f372022-03-01 16:04:44 -0800612 // Default to domain ID 0
613 return peci_RdIAMSR_dom(target, 0, threadID, MSRAddress, u64MsrVal, cc);
614}
615
616/*-------------------------------------------------------------------------
617 * This function provides read access to Model Specific Registers
618 * defined in the processor doc in the specified domain.
619 *------------------------------------------------------------------------*/
620EPECIStatus peci_RdIAMSR_dom(uint8_t target, uint8_t domainId, uint8_t threadID,
621 uint16_t MSRAddress, uint64_t* u64MsrVal,
622 uint8_t* cc)
623{
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700624 int peci_fd = -1;
Nirav Shahfd5dfd52022-03-09 12:29:41 -0800625 struct peci_rd_ia_msr_msg cmd = {0};
Jason M. Billsbc641112020-08-19 16:31:53 -0700626 EPECIStatus ret = PECI_CC_SUCCESS;
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700627
628 if (u64MsrVal == NULL || cc == NULL)
629 {
630 return PECI_CC_INVALID_REQ;
631 }
632
Jason M. Bills6ca31642020-08-06 10:26:19 -0700633 // The target address must be in the valid range
634 if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR)
635 {
636 return PECI_CC_INVALID_REQ;
637 }
638
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700639 if (peci_Open(&peci_fd) != PECI_CC_SUCCESS)
640 {
641 return PECI_CC_DRIVER_ERR;
642 }
643
644 cmd.addr = target;
645 cmd.thread_id = threadID; // request byte for thread ID
646 cmd.address = MSRAddress; // MSR Address
Jason M. Bills8bb8f372022-03-01 16:04:44 -0800647 cmd.domain_id = domainId;
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700648
649 ret = HW_peci_issue_cmd(PECI_IOC_RD_IA_MSR, (char*)&cmd, peci_fd);
650 *cc = cmd.cc;
651 if (ret == PECI_CC_SUCCESS)
652 {
653 *u64MsrVal = cmd.value;
654 }
655
656 peci_Close(peci_fd);
657 return ret;
658}
659
660/*-------------------------------------------------------------------------
661 * This function provides read access to the PCI configuration space at
662 * the requested PCI configuration address.
663 *------------------------------------------------------------------------*/
664EPECIStatus peci_RdPCIConfig(uint8_t target, uint8_t u8Bus, uint8_t u8Device,
665 uint8_t u8Fcn, uint16_t u16Reg, uint8_t* pPCIData,
666 uint8_t* cc)
667{
Jason M. Bills8bb8f372022-03-01 16:04:44 -0800668 // Default to domain ID 0
669 return peci_RdPCIConfig_dom(target, 0, u8Bus, u8Device, u8Fcn, u16Reg,
670 pPCIData, cc);
671}
672
673/*-------------------------------------------------------------------------
674 * This function provides read access to the PCI configuration space at
675 * the requested PCI configuration address in the specified domain.
676 *------------------------------------------------------------------------*/
677EPECIStatus peci_RdPCIConfig_dom(uint8_t target, uint8_t domainId,
678 uint8_t u8Bus, uint8_t u8Device, uint8_t u8Fcn,
679 uint16_t u16Reg, uint8_t* pPCIData,
680 uint8_t* cc)
681{
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700682 int peci_fd = -1;
Jason M. Billsbc641112020-08-19 16:31:53 -0700683 EPECIStatus ret = PECI_CC_SUCCESS;
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700684
685 if (pPCIData == NULL || cc == NULL)
686 {
687 return PECI_CC_INVALID_REQ;
688 }
689
Jason M. Bills6ca31642020-08-06 10:26:19 -0700690 // The target address must be in the valid range
691 if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR)
692 {
693 return PECI_CC_INVALID_REQ;
694 }
695
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700696 if (peci_Open(&peci_fd) != PECI_CC_SUCCESS)
697 {
698 return PECI_CC_DRIVER_ERR;
699 }
Jason M. Bills8bb8f372022-03-01 16:04:44 -0800700 ret = peci_RdPCIConfig_seq_dom(target, domainId, u8Bus, u8Device, u8Fcn,
701 u16Reg, pPCIData, peci_fd, cc);
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700702
703 peci_Close(peci_fd);
704 return ret;
705}
706
707/*-------------------------------------------------------------------------
708 * This function allows sequential RdPCIConfig with the provided
709 * peci file descriptor.
710 *------------------------------------------------------------------------*/
711EPECIStatus peci_RdPCIConfig_seq(uint8_t target, uint8_t u8Bus,
712 uint8_t u8Device, uint8_t u8Fcn,
713 uint16_t u16Reg, uint8_t* pPCIData,
714 int peci_fd, uint8_t* cc)
715{
Jason M. Bills8bb8f372022-03-01 16:04:44 -0800716 // Default to domain ID 0
717 return peci_RdPCIConfig_seq_dom(target, 0, u8Bus, u8Device, u8Fcn, u16Reg,
718 pPCIData, peci_fd, cc);
719}
720
721/*-------------------------------------------------------------------------
722 * This function allows sequential RdPCIConfig with the provided
723 * peci file descriptor in the specified domain.
724 *------------------------------------------------------------------------*/
725EPECIStatus peci_RdPCIConfig_seq_dom(uint8_t target, uint8_t domainId,
726 uint8_t u8Bus, uint8_t u8Device,
727 uint8_t u8Fcn, uint16_t u16Reg,
728 uint8_t* pPCIData, int peci_fd,
729 uint8_t* cc)
730{
Nirav Shahfd5dfd52022-03-09 12:29:41 -0800731 struct peci_rd_pci_cfg_msg cmd = {0};
Jason M. Billsbc641112020-08-19 16:31:53 -0700732 EPECIStatus ret = PECI_CC_SUCCESS;
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700733
734 if (pPCIData == NULL || cc == NULL)
735 {
736 return PECI_CC_INVALID_REQ;
737 }
738
Jason M. Bills6ca31642020-08-06 10:26:19 -0700739 // The target address must be in the valid range
740 if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR)
741 {
742 return PECI_CC_INVALID_REQ;
743 }
744
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700745 // The PECI buffer must be large enough to hold the PCI data
746 if (sizeof(cmd.pci_config) < 4)
747 {
748 return PECI_CC_INVALID_REQ;
749 }
750
751 cmd.addr = target;
752 cmd.bus = u8Bus;
753 cmd.device = u8Device;
754 cmd.function = u8Fcn;
755 cmd.reg = u16Reg;
Jason M. Bills8bb8f372022-03-01 16:04:44 -0800756 cmd.domain_id = domainId;
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700757
758 ret = HW_peci_issue_cmd(PECI_IOC_RD_PCI_CFG, (char*)&cmd, peci_fd);
759 *cc = cmd.cc;
760
761 if (ret == PECI_CC_SUCCESS)
762 {
763 memcpy(pPCIData, cmd.pci_config, 4);
764 }
765
766 return ret;
767}
768
769/*-------------------------------------------------------------------------
Jason M. Bills8bb8f372022-03-01 16:04:44 -0800770 * This function provides read access to the local PCI configuration space
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700771 *------------------------------------------------------------------------*/
772EPECIStatus peci_RdPCIConfigLocal(uint8_t target, uint8_t u8Bus,
773 uint8_t u8Device, uint8_t u8Fcn,
774 uint16_t u16Reg, uint8_t u8ReadLen,
775 uint8_t* pPCIReg, uint8_t* cc)
776{
Jason M. Bills8bb8f372022-03-01 16:04:44 -0800777 // Default to domain ID 0
778 return peci_RdPCIConfigLocal_dom(target, 0, u8Bus, u8Device, u8Fcn, u16Reg,
779 u8ReadLen, pPCIReg, cc);
780}
781
782/*-------------------------------------------------------------------------
783 * This function provides read access to the local PCI configuration space in
784 * the specified domain
785 *------------------------------------------------------------------------*/
786EPECIStatus peci_RdPCIConfigLocal_dom(uint8_t target, uint8_t domainId,
787 uint8_t u8Bus, uint8_t u8Device,
788 uint8_t u8Fcn, uint16_t u16Reg,
789 uint8_t u8ReadLen, uint8_t* pPCIReg,
790 uint8_t* cc)
791{
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700792 int peci_fd = -1;
Jason M. Billsbc641112020-08-19 16:31:53 -0700793 EPECIStatus ret = PECI_CC_SUCCESS;
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700794
795 if (pPCIReg == NULL || cc == NULL)
796 {
797 return PECI_CC_INVALID_REQ;
798 }
799
Jason M. Bills6ca31642020-08-06 10:26:19 -0700800 // The target address must be in the valid range
801 if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR)
802 {
803 return PECI_CC_INVALID_REQ;
804 }
805
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700806 if (peci_Open(&peci_fd) != PECI_CC_SUCCESS)
807 {
808 return PECI_CC_DRIVER_ERR;
809 }
Patrick Williams7169faa2023-05-10 07:51:24 -0500810 ret = peci_RdPCIConfigLocal_seq_dom(target, domainId, u8Bus, u8Device,
811 u8Fcn, u16Reg, u8ReadLen, pPCIReg,
812 peci_fd, cc);
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700813
814 peci_Close(peci_fd);
815 return ret;
816}
817
818/*-------------------------------------------------------------------------
819 * This function allows sequential RdPCIConfigLocal with the provided
820 * peci file descriptor.
821 *------------------------------------------------------------------------*/
822EPECIStatus peci_RdPCIConfigLocal_seq(uint8_t target, uint8_t u8Bus,
823 uint8_t u8Device, uint8_t u8Fcn,
824 uint16_t u16Reg, uint8_t u8ReadLen,
825 uint8_t* pPCIReg, int peci_fd,
826 uint8_t* cc)
827{
Jason M. Bills8bb8f372022-03-01 16:04:44 -0800828 // Default to domain ID 0
829 return peci_RdPCIConfigLocal_seq_dom(target, 0, u8Bus, u8Device, u8Fcn,
830 u16Reg, u8ReadLen, pPCIReg, peci_fd,
831 cc);
832}
833
834/*-------------------------------------------------------------------------
835 * This function allows sequential RdPCIConfigLocal with the provided
836 * peci file descriptor in the specified domain.
837 *------------------------------------------------------------------------*/
838EPECIStatus peci_RdPCIConfigLocal_seq_dom(uint8_t target, uint8_t domainId,
839 uint8_t u8Bus, uint8_t u8Device,
840 uint8_t u8Fcn, uint16_t u16Reg,
841 uint8_t u8ReadLen, uint8_t* pPCIReg,
842 int peci_fd, uint8_t* cc)
843{
Nirav Shahfd5dfd52022-03-09 12:29:41 -0800844 struct peci_rd_pci_cfg_local_msg cmd = {0};
Jason M. Billsbc641112020-08-19 16:31:53 -0700845 EPECIStatus ret = PECI_CC_SUCCESS;
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700846
847 if (pPCIReg == NULL || cc == NULL)
848 {
849 return PECI_CC_INVALID_REQ;
850 }
851
Jason M. Bills6ca31642020-08-06 10:26:19 -0700852 // The target address must be in the valid range
853 if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR)
854 {
855 return PECI_CC_INVALID_REQ;
856 }
857
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700858 // Per the PECI spec, the read length must be a byte, word, or dword
859 if (u8ReadLen != 1 && u8ReadLen != 2 && u8ReadLen != 4)
860 {
861 return PECI_CC_INVALID_REQ;
862 }
863
864 // The PECI buffer must be large enough to hold the requested data
865 if (sizeof(cmd.pci_config) < u8ReadLen)
866 {
867 return PECI_CC_INVALID_REQ;
868 }
869
870 cmd.addr = target;
871 cmd.bus = u8Bus;
872 cmd.device = u8Device;
873 cmd.function = u8Fcn;
874 cmd.reg = u16Reg;
875 cmd.rx_len = u8ReadLen;
Jason M. Bills8bb8f372022-03-01 16:04:44 -0800876 cmd.domain_id = domainId;
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700877
878 ret = HW_peci_issue_cmd(PECI_IOC_RD_PCI_CFG_LOCAL, (char*)&cmd, peci_fd);
879 *cc = cmd.cc;
880
881 if (ret == PECI_CC_SUCCESS)
882 {
883 memcpy(pPCIReg, cmd.pci_config, u8ReadLen);
884 }
885
886 return ret;
887}
888
889/*-------------------------------------------------------------------------
Jason M. Bills8bb8f372022-03-01 16:04:44 -0800890 * This function provides write access to the local PCI configuration space
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700891 *------------------------------------------------------------------------*/
892EPECIStatus peci_WrPCIConfigLocal(uint8_t target, uint8_t u8Bus,
893 uint8_t u8Device, uint8_t u8Fcn,
894 uint16_t u16Reg, uint8_t DataLen,
895 uint32_t DataVal, uint8_t* cc)
896{
Jason M. Bills8bb8f372022-03-01 16:04:44 -0800897 // Default to domain ID 0
898 return peci_WrPCIConfigLocal_dom(target, 0, u8Bus, u8Device, u8Fcn, u16Reg,
899 DataLen, DataVal, cc);
900}
901
902/*-------------------------------------------------------------------------
903 * This function provides write access to the local PCI configuration space in
904 * the specified domain
905 *------------------------------------------------------------------------*/
906EPECIStatus peci_WrPCIConfigLocal_dom(uint8_t target, uint8_t domainId,
907 uint8_t u8Bus, uint8_t u8Device,
908 uint8_t u8Fcn, uint16_t u16Reg,
909 uint8_t DataLen, uint32_t DataVal,
910 uint8_t* cc)
911{
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700912 int peci_fd = -1;
Nirav Shahfd5dfd52022-03-09 12:29:41 -0800913 struct peci_wr_pci_cfg_local_msg cmd = {0};
Jason M. Billsbc641112020-08-19 16:31:53 -0700914 EPECIStatus ret = PECI_CC_SUCCESS;
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700915
916 if (cc == NULL)
917 {
918 return PECI_CC_INVALID_REQ;
919 }
920
Jason M. Bills6ca31642020-08-06 10:26:19 -0700921 // The target address must be in the valid range
922 if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR)
923 {
924 return PECI_CC_INVALID_REQ;
925 }
926
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700927 if (peci_Open(&peci_fd) != PECI_CC_SUCCESS)
928 {
929 return PECI_CC_DRIVER_ERR;
930 }
931
932 // Per the PECI spec, the write length must be a byte, word, or dword
933 if (DataLen != 1 && DataLen != 2 && DataLen != 4)
934 {
935 peci_Close(peci_fd);
936 return PECI_CC_INVALID_REQ;
937 }
938
939 cmd.addr = target;
940 cmd.bus = u8Bus;
941 cmd.device = u8Device;
942 cmd.function = u8Fcn;
943 cmd.reg = u16Reg;
944 cmd.tx_len = DataLen;
945 cmd.value = DataVal;
Jason M. Bills8bb8f372022-03-01 16:04:44 -0800946 cmd.domain_id = domainId;
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700947
948 ret = HW_peci_issue_cmd(PECI_IOC_WR_PCI_CFG_LOCAL, (char*)&cmd, peci_fd);
949 *cc = cmd.cc;
950
951 peci_Close(peci_fd);
952 return ret;
953}
954
955/*-------------------------------------------------------------------------
Jason M. Bills8bb8f372022-03-01 16:04:44 -0800956 * This internal function is the common interface for RdEndPointConfig to PCI in
957 * the specified domain
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700958 *------------------------------------------------------------------------*/
Jason M. Bills8bb8f372022-03-01 16:04:44 -0800959static EPECIStatus peci_RdEndPointConfigPciCommon_dom(
960 uint8_t target, uint8_t domainId, uint8_t u8MsgType, uint8_t u8Seg,
961 uint8_t u8Bus, uint8_t u8Device, uint8_t u8Fcn, uint16_t u16Reg,
962 uint8_t u8ReadLen, uint8_t* pPCIData, int peci_fd, uint8_t* cc)
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700963{
Nirav Shahfd5dfd52022-03-09 12:29:41 -0800964 struct peci_rd_end_pt_cfg_msg cmd = {0};
Jason M. Billsbc641112020-08-19 16:31:53 -0700965 EPECIStatus ret = PECI_CC_SUCCESS;
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700966
967 if (pPCIData == NULL || cc == NULL)
968 {
969 return PECI_CC_INVALID_REQ;
970 }
971
Jason M. Bills6ca31642020-08-06 10:26:19 -0700972 // The target address must be in the valid range
973 if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR)
974 {
975 return PECI_CC_INVALID_REQ;
976 }
977
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700978 // The PECI buffer must be large enough to hold the requested data
979 if (sizeof(cmd.data) < u8ReadLen)
980 {
981 return PECI_CC_INVALID_REQ;
982 }
983
984 cmd.addr = target;
985 cmd.msg_type = u8MsgType;
986 cmd.params.pci_cfg.seg = u8Seg;
987 cmd.params.pci_cfg.bus = u8Bus;
988 cmd.params.pci_cfg.device = u8Device;
989 cmd.params.pci_cfg.function = u8Fcn;
990 cmd.params.pci_cfg.reg = u16Reg;
991 cmd.rx_len = u8ReadLen;
Jason M. Bills8bb8f372022-03-01 16:04:44 -0800992 cmd.domain_id = domainId;
Jason M. Bills7ef5a552020-04-06 14:58:44 -0700993
994 ret = HW_peci_issue_cmd(PECI_IOC_RD_END_PT_CFG, (char*)&cmd, peci_fd);
995 *cc = cmd.cc;
996
997 if (ret == PECI_CC_SUCCESS)
998 {
999 memcpy(pPCIData, cmd.data, u8ReadLen);
1000 }
1001 else
1002 {
1003 ret = PECI_CC_DRIVER_ERR;
1004 }
1005
1006 return ret;
1007}
1008
1009/*-------------------------------------------------------------------------
1010 * This function provides read access to the PCI configuration space at
1011 * the requested PCI configuration address.
1012 *------------------------------------------------------------------------*/
1013EPECIStatus peci_RdEndPointConfigPci(uint8_t target, uint8_t u8Seg,
1014 uint8_t u8Bus, uint8_t u8Device,
1015 uint8_t u8Fcn, uint16_t u16Reg,
1016 uint8_t u8ReadLen, uint8_t* pPCIData,
1017 uint8_t* cc)
1018{
Jason M. Bills8bb8f372022-03-01 16:04:44 -08001019 // Default to domain ID 0
1020 return peci_RdEndPointConfigPci_dom(target, 0, u8Seg, u8Bus, u8Device,
1021 u8Fcn, u16Reg, u8ReadLen, pPCIData, cc);
1022}
1023
1024/*-------------------------------------------------------------------------
1025 * This function provides read access to the PCI configuration space at
1026 * the requested PCI configuration address in the specified domain.
1027 *------------------------------------------------------------------------*/
1028EPECIStatus peci_RdEndPointConfigPci_dom(uint8_t target, uint8_t domainId,
1029 uint8_t u8Seg, uint8_t u8Bus,
1030 uint8_t u8Device, uint8_t u8Fcn,
1031 uint16_t u16Reg, uint8_t u8ReadLen,
1032 uint8_t* pPCIData, uint8_t* cc)
1033{
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001034 int peci_fd = -1;
Jason M. Billsbc641112020-08-19 16:31:53 -07001035 EPECIStatus ret = PECI_CC_SUCCESS;
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001036
1037 if (pPCIData == NULL || cc == NULL)
1038 {
1039 return PECI_CC_INVALID_REQ;
1040 }
1041
Jason M. Bills6ca31642020-08-06 10:26:19 -07001042 // The target address must be in the valid range
1043 if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR)
1044 {
1045 return PECI_CC_INVALID_REQ;
1046 }
1047
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001048 if (peci_Open(&peci_fd) != PECI_CC_SUCCESS)
1049 {
1050 return PECI_CC_DRIVER_ERR;
1051 }
Jason M. Bills8bb8f372022-03-01 16:04:44 -08001052 ret = peci_RdEndPointConfigPci_seq_dom(target, domainId, u8Seg, u8Bus,
1053 u8Device, u8Fcn, u16Reg, u8ReadLen,
1054 pPCIData, peci_fd, cc);
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001055 peci_Close(peci_fd);
1056 return ret;
1057}
1058
1059/*-------------------------------------------------------------------------
1060 * This function allows sequential RdEndPointConfig to PCI with the provided
1061 * peci file descriptor.
1062 *------------------------------------------------------------------------*/
1063EPECIStatus peci_RdEndPointConfigPci_seq(uint8_t target, uint8_t u8Seg,
1064 uint8_t u8Bus, uint8_t u8Device,
1065 uint8_t u8Fcn, uint16_t u16Reg,
1066 uint8_t u8ReadLen, uint8_t* pPCIData,
1067 int peci_fd, uint8_t* cc)
1068{
Jason M. Bills8bb8f372022-03-01 16:04:44 -08001069 // Default to domain ID 0
1070 return peci_RdEndPointConfigPci_seq_dom(target, 0, u8Seg, u8Bus, u8Device,
1071 u8Fcn, u16Reg, u8ReadLen, pPCIData,
1072 peci_fd, cc);
1073}
1074
1075/*-------------------------------------------------------------------------
1076 * This function allows sequential RdEndPointConfig to PCI with the provided
1077 * peci file descriptor in the specified domain.
1078 *------------------------------------------------------------------------*/
1079EPECIStatus peci_RdEndPointConfigPci_seq_dom(uint8_t target, uint8_t domainId,
1080 uint8_t u8Seg, uint8_t u8Bus,
1081 uint8_t u8Device, uint8_t u8Fcn,
1082 uint16_t u16Reg, uint8_t u8ReadLen,
1083 uint8_t* pPCIData, int peci_fd,
1084 uint8_t* cc)
1085{
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001086 if (pPCIData == NULL || cc == NULL)
1087 {
1088 return PECI_CC_INVALID_REQ;
1089 }
1090
Jason M. Bills6ca31642020-08-06 10:26:19 -07001091 // The target address must be in the valid range
1092 if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR)
1093 {
1094 return PECI_CC_INVALID_REQ;
1095 }
1096
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001097 // Per the PECI spec, the read length must be a byte, word, or dword
1098 if (u8ReadLen != 1 && u8ReadLen != 2 && u8ReadLen != 4)
1099 {
1100 return PECI_CC_INVALID_REQ;
1101 }
1102
Jason M. Bills8bb8f372022-03-01 16:04:44 -08001103 return peci_RdEndPointConfigPciCommon_dom(
1104 target, domainId, PECI_ENDPTCFG_TYPE_PCI, u8Seg, u8Bus, u8Device, u8Fcn,
1105 u16Reg, u8ReadLen, pPCIData, peci_fd, cc);
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001106}
1107
1108/*-------------------------------------------------------------------------
1109 * This function provides read access to the Local PCI configuration space at
1110 * the requested PCI configuration address.
1111 *------------------------------------------------------------------------*/
1112EPECIStatus peci_RdEndPointConfigPciLocal(uint8_t target, uint8_t u8Seg,
1113 uint8_t u8Bus, uint8_t u8Device,
1114 uint8_t u8Fcn, uint16_t u16Reg,
1115 uint8_t u8ReadLen, uint8_t* pPCIData,
1116 uint8_t* cc)
1117{
Jason M. Bills8bb8f372022-03-01 16:04:44 -08001118 // Default to domain ID 0
1119 return peci_RdEndPointConfigPciLocal_dom(target, 0, u8Seg, u8Bus, u8Device,
1120 u8Fcn, u16Reg, u8ReadLen, pPCIData,
1121 cc);
1122}
1123
1124/*-------------------------------------------------------------------------
1125 * This function provides read access to the Local PCI configuration space at
1126 * the requested PCI configuration address in the specified domain.
1127 *------------------------------------------------------------------------*/
1128EPECIStatus peci_RdEndPointConfigPciLocal_dom(uint8_t target, uint8_t domainId,
1129 uint8_t u8Seg, uint8_t u8Bus,
1130 uint8_t u8Device, uint8_t u8Fcn,
1131 uint16_t u16Reg,
1132 uint8_t u8ReadLen,
1133 uint8_t* pPCIData, uint8_t* cc)
1134{
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001135 int peci_fd = -1;
Jason M. Billsbc641112020-08-19 16:31:53 -07001136 EPECIStatus ret = PECI_CC_SUCCESS;
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001137
1138 if (pPCIData == NULL || cc == NULL)
1139 {
1140 return PECI_CC_INVALID_REQ;
1141 }
1142
Jason M. Bills6ca31642020-08-06 10:26:19 -07001143 // The target address must be in the valid range
1144 if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR)
1145 {
1146 return PECI_CC_INVALID_REQ;
1147 }
1148
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001149 if (peci_Open(&peci_fd) != PECI_CC_SUCCESS)
1150 {
1151 return PECI_CC_DRIVER_ERR;
1152 }
Jason M. Bills8bb8f372022-03-01 16:04:44 -08001153 ret = peci_RdEndPointConfigPciLocal_seq_dom(
1154 target, domainId, u8Seg, u8Bus, u8Device, u8Fcn, u16Reg, u8ReadLen,
1155 pPCIData, peci_fd, cc);
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001156 peci_Close(peci_fd);
1157 return ret;
1158}
1159
1160/*-------------------------------------------------------------------------
1161 * This function allows sequential RdEndPointConfig to PCI Local with the
Jason M. Bills8bb8f372022-03-01 16:04:44 -08001162 * provided peci file descriptor.
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001163 *------------------------------------------------------------------------*/
1164EPECIStatus peci_RdEndPointConfigPciLocal_seq(uint8_t target, uint8_t u8Seg,
1165 uint8_t u8Bus, uint8_t u8Device,
1166 uint8_t u8Fcn, uint16_t u16Reg,
1167 uint8_t u8ReadLen,
1168 uint8_t* pPCIData, int peci_fd,
1169 uint8_t* cc)
1170{
Jason M. Bills8bb8f372022-03-01 16:04:44 -08001171 // Default to domain ID 0
1172 return peci_RdEndPointConfigPciLocal_seq_dom(
1173 target, 0, u8Seg, u8Bus, u8Device, u8Fcn, u16Reg, u8ReadLen, pPCIData,
1174 peci_fd, cc);
1175}
1176
1177/*-------------------------------------------------------------------------
1178 * This function allows sequential RdEndPointConfig to PCI Local with the
1179 * provided peci file descriptor in the specified domain.
1180 *------------------------------------------------------------------------*/
1181EPECIStatus peci_RdEndPointConfigPciLocal_seq_dom(
1182 uint8_t target, uint8_t domainId, uint8_t u8Seg, uint8_t u8Bus,
1183 uint8_t u8Device, uint8_t u8Fcn, uint16_t u16Reg, uint8_t u8ReadLen,
1184 uint8_t* pPCIData, int peci_fd, uint8_t* cc)
1185{
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001186 if (pPCIData == NULL || cc == NULL)
1187 {
1188 return PECI_CC_INVALID_REQ;
1189 }
1190
Jason M. Bills6ca31642020-08-06 10:26:19 -07001191 // The target address must be in the valid range
1192 if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR)
1193 {
1194 return PECI_CC_INVALID_REQ;
1195 }
1196
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001197 // Per the PECI spec, the read length must be a byte, word, or dword
1198 if (u8ReadLen != 1 && u8ReadLen != 2 && u8ReadLen != 4)
1199 {
1200 return PECI_CC_INVALID_REQ;
1201 }
1202
Jason M. Bills8bb8f372022-03-01 16:04:44 -08001203 return peci_RdEndPointConfigPciCommon_dom(
1204 target, domainId, PECI_ENDPTCFG_TYPE_LOCAL_PCI, u8Seg, u8Bus, u8Device,
1205 u8Fcn, u16Reg, u8ReadLen, pPCIData, peci_fd, cc);
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001206}
1207
1208/*-------------------------------------------------------------------------
1209 * This function provides read access to PCI MMIO space at
1210 * the requested PCI configuration address.
1211 *------------------------------------------------------------------------*/
1212EPECIStatus peci_RdEndPointConfigMmio(uint8_t target, uint8_t u8Seg,
1213 uint8_t u8Bus, uint8_t u8Device,
1214 uint8_t u8Fcn, uint8_t u8Bar,
1215 uint8_t u8AddrType, uint64_t u64Offset,
1216 uint8_t u8ReadLen, uint8_t* pMmioData,
1217 uint8_t* cc)
1218{
Jason M. Bills8bb8f372022-03-01 16:04:44 -08001219 // Default to domain ID 0
1220 return peci_RdEndPointConfigMmio_dom(target, 0, u8Seg, u8Bus, u8Device,
1221 u8Fcn, u8Bar, u8AddrType, u64Offset,
1222 u8ReadLen, pMmioData, cc);
1223}
1224
1225/*-------------------------------------------------------------------------
1226 * This function provides read access to PCI MMIO space at
1227 * the requested PCI configuration address in the specified domain.
1228 *------------------------------------------------------------------------*/
1229EPECIStatus peci_RdEndPointConfigMmio_dom(uint8_t target, uint8_t domainId,
1230 uint8_t u8Seg, uint8_t u8Bus,
1231 uint8_t u8Device, uint8_t u8Fcn,
1232 uint8_t u8Bar, uint8_t u8AddrType,
1233 uint64_t u64Offset, uint8_t u8ReadLen,
1234 uint8_t* pMmioData, uint8_t* cc)
1235{
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001236 int peci_fd = -1;
Jason M. Billsbc641112020-08-19 16:31:53 -07001237 EPECIStatus ret = PECI_CC_SUCCESS;
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001238
1239 if (pMmioData == NULL || cc == NULL)
1240 {
1241 return PECI_CC_INVALID_REQ;
1242 }
1243
Jason M. Bills6ca31642020-08-06 10:26:19 -07001244 // The target address must be in the valid range
1245 if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR)
1246 {
1247 return PECI_CC_INVALID_REQ;
1248 }
1249
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001250 if (peci_Open(&peci_fd) != PECI_CC_SUCCESS)
1251 {
1252 return PECI_CC_DRIVER_ERR;
1253 }
Jason M. Bills8bb8f372022-03-01 16:04:44 -08001254 ret = peci_RdEndPointConfigMmio_seq_dom(
1255 target, domainId, u8Seg, u8Bus, u8Device, u8Fcn, u8Bar, u8AddrType,
1256 u64Offset, u8ReadLen, pMmioData, peci_fd, cc);
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001257 peci_Close(peci_fd);
1258 return ret;
1259}
1260
1261/*-------------------------------------------------------------------------
1262 * This function allows sequential RdEndPointConfig to PCI MMIO with the
Jason M. Bills8bb8f372022-03-01 16:04:44 -08001263 * provided peci file descriptor.
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001264 *------------------------------------------------------------------------*/
1265EPECIStatus peci_RdEndPointConfigMmio_seq(
1266 uint8_t target, uint8_t u8Seg, uint8_t u8Bus, uint8_t u8Device,
1267 uint8_t u8Fcn, uint8_t u8Bar, uint8_t u8AddrType, uint64_t u64Offset,
1268 uint8_t u8ReadLen, uint8_t* pMmioData, int peci_fd, uint8_t* cc)
1269{
Jason M. Bills8bb8f372022-03-01 16:04:44 -08001270 // Default to domain ID 0
1271 return peci_RdEndPointConfigMmio_seq_dom(
1272 target, 0, u8Seg, u8Bus, u8Device, u8Fcn, u8Bar, u8AddrType, u64Offset,
1273 u8ReadLen, pMmioData, peci_fd, cc);
1274}
1275
1276/*-------------------------------------------------------------------------
1277 * This function allows sequential RdEndPointConfig to PCI MMIO with the
1278 * provided peci file descriptor in the specified domain.
1279 *------------------------------------------------------------------------*/
1280EPECIStatus peci_RdEndPointConfigMmio_seq_dom(
1281 uint8_t target, uint8_t domainId, uint8_t u8Seg, uint8_t u8Bus,
1282 uint8_t u8Device, uint8_t u8Fcn, uint8_t u8Bar, uint8_t u8AddrType,
1283 uint64_t u64Offset, uint8_t u8ReadLen, uint8_t* pMmioData, int peci_fd,
1284 uint8_t* cc)
1285{
Nirav Shahfd5dfd52022-03-09 12:29:41 -08001286 struct peci_rd_end_pt_cfg_msg cmd = {0};
Jason M. Billsbc641112020-08-19 16:31:53 -07001287 EPECIStatus ret = PECI_CC_SUCCESS;
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001288
1289 if (pMmioData == NULL || cc == NULL)
1290 {
1291 return PECI_CC_INVALID_REQ;
1292 }
1293
Jason M. Bills6ca31642020-08-06 10:26:19 -07001294 // The target address must be in the valid range
1295 if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR)
1296 {
1297 return PECI_CC_INVALID_REQ;
1298 }
1299
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001300 // Per the PECI spec, the read length must be a byte, word, dword, or qword
1301 if (u8ReadLen != 1 && u8ReadLen != 2 && u8ReadLen != 4 && u8ReadLen != 8)
1302 {
1303 return PECI_CC_INVALID_REQ;
1304 }
1305
1306 // The PECI buffer must be large enough to hold the requested data
1307 if (sizeof(cmd.data) < u8ReadLen)
1308 {
1309 return PECI_CC_INVALID_REQ;
1310 }
1311
1312 cmd.addr = target;
1313 cmd.msg_type = PECI_ENDPTCFG_TYPE_MMIO;
1314 cmd.params.mmio.seg = u8Seg;
1315 cmd.params.mmio.bus = u8Bus;
1316 cmd.params.mmio.device = u8Device;
1317 cmd.params.mmio.function = u8Fcn;
1318 cmd.params.mmio.bar = u8Bar;
1319 cmd.params.mmio.addr_type = u8AddrType;
1320 cmd.params.mmio.offset = u64Offset;
1321 cmd.rx_len = u8ReadLen;
Jason M. Bills8bb8f372022-03-01 16:04:44 -08001322 cmd.domain_id = domainId;
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001323
1324 ret = HW_peci_issue_cmd(PECI_IOC_RD_END_PT_CFG, (char*)&cmd, peci_fd);
1325 *cc = cmd.cc;
1326
1327 if (ret == PECI_CC_SUCCESS)
1328 {
1329 memcpy(pMmioData, cmd.data, u8ReadLen);
1330 }
1331 else
1332 {
1333 ret = PECI_CC_DRIVER_ERR;
1334 }
1335
1336 return ret;
1337}
1338
1339/*-------------------------------------------------------------------------
1340 * This function allows sequential peci_WrEndPointConfig to PCI EndPoint with
Jason M. Bills8bb8f372022-03-01 16:04:44 -08001341 * the provided peci file descriptor.
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001342 *------------------------------------------------------------------------*/
1343EPECIStatus peci_WrEndPointConfig_seq(uint8_t target, uint8_t u8MsgType,
1344 uint8_t u8Seg, uint8_t u8Bus,
1345 uint8_t u8Device, uint8_t u8Fcn,
1346 uint16_t u16Reg, uint8_t DataLen,
1347 uint32_t DataVal, int peci_fd,
1348 uint8_t* cc)
1349{
Jason M. Bills8bb8f372022-03-01 16:04:44 -08001350 // Default to domain ID 0
1351 return peci_WrEndPointConfig_seq_dom(target, 0, u8MsgType, u8Seg, u8Bus,
1352 u8Device, u8Fcn, u16Reg, DataLen,
1353 DataVal, peci_fd, cc);
1354}
1355
1356/*-------------------------------------------------------------------------
1357 * This function allows sequential peci_WrEndPointConfig to PCI EndPoint with
1358 * the provided peci file descriptor in the specified domain.
1359 *------------------------------------------------------------------------*/
1360EPECIStatus peci_WrEndPointConfig_seq_dom(uint8_t target, uint8_t domainId,
1361 uint8_t u8MsgType, uint8_t u8Seg,
1362 uint8_t u8Bus, uint8_t u8Device,
1363 uint8_t u8Fcn, uint16_t u16Reg,
1364 uint8_t DataLen, uint32_t DataVal,
1365 int peci_fd, uint8_t* cc)
1366{
Nirav Shahfd5dfd52022-03-09 12:29:41 -08001367 struct peci_wr_end_pt_cfg_msg cmd = {0};
Jason M. Billsbc641112020-08-19 16:31:53 -07001368 EPECIStatus ret = PECI_CC_SUCCESS;
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001369
1370 if (cc == NULL)
1371 {
1372 return PECI_CC_INVALID_REQ;
1373 }
1374
Jason M. Bills6ca31642020-08-06 10:26:19 -07001375 // The target address must be in the valid range
1376 if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR)
1377 {
1378 return PECI_CC_INVALID_REQ;
1379 }
1380
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001381 // Per the PECI spec, the write length must be a byte, word, or dword
1382 if (DataLen != 1 && DataLen != 2 && DataLen != 4)
1383 {
1384 return PECI_CC_INVALID_REQ;
1385 }
1386
1387 cmd.addr = target;
1388 cmd.msg_type = u8MsgType;
1389 cmd.params.pci_cfg.seg = u8Seg;
1390 cmd.params.pci_cfg.bus = u8Bus;
1391 cmd.params.pci_cfg.device = u8Device;
1392 cmd.params.pci_cfg.function = u8Fcn;
1393 cmd.params.pci_cfg.reg = u16Reg;
1394 cmd.tx_len = DataLen;
1395 cmd.value = DataVal;
Jason M. Bills8bb8f372022-03-01 16:04:44 -08001396 cmd.domain_id = domainId;
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001397
1398 ret = HW_peci_issue_cmd(PECI_IOC_WR_END_PT_CFG, (char*)&cmd, peci_fd);
1399 *cc = cmd.cc;
1400
1401 return ret;
1402}
1403
1404/*-------------------------------------------------------------------------
Jason M. Bills8bb8f372022-03-01 16:04:44 -08001405 * This function provides write access to the EP local PCI configuration space
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001406 *------------------------------------------------------------------------*/
1407EPECIStatus peci_WrEndPointPCIConfigLocal(uint8_t target, uint8_t u8Seg,
1408 uint8_t u8Bus, uint8_t u8Device,
1409 uint8_t u8Fcn, uint16_t u16Reg,
1410 uint8_t DataLen, uint32_t DataVal,
1411 uint8_t* cc)
1412{
Jason M. Bills8bb8f372022-03-01 16:04:44 -08001413 // Default to domain ID 0
1414 return peci_WrEndPointPCIConfigLocal_dom(
1415 target, 0, u8Seg, u8Bus, u8Device, u8Fcn, u16Reg, DataLen, DataVal, cc);
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001416}
1417
1418/*-------------------------------------------------------------------------
Jason M. Bills8bb8f372022-03-01 16:04:44 -08001419 * This function provides write access to the EP local PCI configuration space
1420 * in the specified domain
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001421 *------------------------------------------------------------------------*/
Jason M. Bills8bb8f372022-03-01 16:04:44 -08001422EPECIStatus peci_WrEndPointPCIConfigLocal_dom(uint8_t target, uint8_t domainId,
1423 uint8_t u8Seg, uint8_t u8Bus,
1424 uint8_t u8Device, uint8_t u8Fcn,
1425 uint16_t u16Reg, uint8_t DataLen,
1426 uint32_t DataVal, uint8_t* cc)
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001427{
1428 int peci_fd = -1;
Jason M. Billsbc641112020-08-19 16:31:53 -07001429 EPECIStatus ret = PECI_CC_SUCCESS;
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001430
1431 if (peci_Open(&peci_fd) != PECI_CC_SUCCESS)
1432 {
1433 return PECI_CC_DRIVER_ERR;
1434 }
Jason M. Bills8bb8f372022-03-01 16:04:44 -08001435
1436 ret = peci_WrEndPointConfig_seq_dom(
1437 target, domainId, PECI_ENDPTCFG_TYPE_LOCAL_PCI, u8Seg, u8Bus, u8Device,
1438 u8Fcn, u16Reg, DataLen, DataVal, peci_fd, cc);
1439 peci_Close(peci_fd);
1440 return ret;
1441}
1442
1443/*-------------------------------------------------------------------------
1444 * This function provides write access to the EP local PCI configuration space
1445 *------------------------------------------------------------------------*/
1446EPECIStatus peci_WrEndPointPCIConfig(uint8_t target, uint8_t u8Seg,
1447 uint8_t u8Bus, uint8_t u8Device,
1448 uint8_t u8Fcn, uint16_t u16Reg,
1449 uint8_t DataLen, uint32_t DataVal,
1450 uint8_t* cc)
1451{
1452 // Default to domain ID 0
1453 return peci_WrEndPointPCIConfig_dom(target, 0, u8Seg, u8Bus, u8Device,
1454 u8Fcn, u16Reg, DataLen, DataVal, cc);
1455}
1456
1457/*-------------------------------------------------------------------------
1458 * This function provides write access to the EP local PCI configuration space
1459 * in the specified domain
1460 *------------------------------------------------------------------------*/
1461EPECIStatus peci_WrEndPointPCIConfig_dom(uint8_t target, uint8_t domainId,
1462 uint8_t u8Seg, uint8_t u8Bus,
1463 uint8_t u8Device, uint8_t u8Fcn,
1464 uint16_t u16Reg, uint8_t DataLen,
1465 uint32_t DataVal, uint8_t* cc)
1466{
1467 int peci_fd = -1;
1468 EPECIStatus ret = PECI_CC_SUCCESS;
1469
1470 if (peci_Open(&peci_fd) != PECI_CC_SUCCESS)
1471 {
1472 return PECI_CC_DRIVER_ERR;
1473 }
1474 ret = peci_WrEndPointConfig_seq_dom(
1475 target, domainId, PECI_ENDPTCFG_TYPE_PCI, u8Seg, u8Bus, u8Device, u8Fcn,
1476 u16Reg, DataLen, DataVal, peci_fd, cc);
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001477 peci_Close(peci_fd);
1478 return ret;
1479}
1480
1481/*-------------------------------------------------------------------------
1482 * This function provides write access to PCI MMIO space at
1483 * the requested PCI configuration address.
1484 *------------------------------------------------------------------------*/
1485EPECIStatus peci_WrEndPointConfigMmio(uint8_t target, uint8_t u8Seg,
1486 uint8_t u8Bus, uint8_t u8Device,
1487 uint8_t u8Fcn, uint8_t u8Bar,
1488 uint8_t u8AddrType, uint64_t u64Offset,
1489 uint8_t u8DataLen, uint64_t u64DataVal,
1490 uint8_t* cc)
1491{
Jason M. Bills8bb8f372022-03-01 16:04:44 -08001492 // Default to domain ID 0
1493 return peci_WrEndPointConfigMmio_dom(target, 0, u8Seg, u8Bus, u8Device,
1494 u8Fcn, u8Bar, u8AddrType, u64Offset,
1495 u8DataLen, u64DataVal, cc);
1496}
1497
1498/*-------------------------------------------------------------------------
1499 * This function provides write access to PCI MMIO space at
1500 * the requested PCI configuration address in the specified domain.
1501 *------------------------------------------------------------------------*/
1502EPECIStatus peci_WrEndPointConfigMmio_dom(uint8_t target, uint8_t domainId,
1503 uint8_t u8Seg, uint8_t u8Bus,
1504 uint8_t u8Device, uint8_t u8Fcn,
1505 uint8_t u8Bar, uint8_t u8AddrType,
1506 uint64_t u64Offset, uint8_t u8DataLen,
1507 uint64_t u64DataVal, uint8_t* cc)
1508{
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001509 int peci_fd = -1;
Jason M. Billsbc641112020-08-19 16:31:53 -07001510 EPECIStatus ret = PECI_CC_SUCCESS;
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001511
1512 if (cc == NULL)
1513 {
1514 return PECI_CC_INVALID_REQ;
1515 }
1516
Jason M. Bills6ca31642020-08-06 10:26:19 -07001517 // The target address must be in the valid range
1518 if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR)
1519 {
1520 return PECI_CC_INVALID_REQ;
1521 }
1522
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001523 if (peci_Open(&peci_fd) != PECI_CC_SUCCESS)
1524 {
1525 return PECI_CC_DRIVER_ERR;
1526 }
Jason M. Bills8bb8f372022-03-01 16:04:44 -08001527 ret = peci_WrEndPointConfigMmio_seq_dom(
1528 target, domainId, u8Seg, u8Bus, u8Device, u8Fcn, u8Bar, u8AddrType,
1529 u64Offset, u8DataLen, u64DataVal, peci_fd, cc);
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001530 peci_Close(peci_fd);
1531 return ret;
1532}
1533
1534/*-------------------------------------------------------------------------
1535 * This function allows sequential WrEndPointConfig to PCI MMIO with the
1536 * provided peci file descriptor.
1537 *------------------------------------------------------------------------*/
1538EPECIStatus peci_WrEndPointConfigMmio_seq(
1539 uint8_t target, uint8_t u8Seg, uint8_t u8Bus, uint8_t u8Device,
1540 uint8_t u8Fcn, uint8_t u8Bar, uint8_t u8AddrType, uint64_t u64Offset,
1541 uint8_t u8DataLen, uint64_t u64DataVal, int peci_fd, uint8_t* cc)
1542{
Jason M. Bills8bb8f372022-03-01 16:04:44 -08001543 // Default to domain ID 0
1544 return peci_WrEndPointConfigMmio_seq_dom(
1545 target, 0, u8Seg, u8Bus, u8Device, u8Fcn, u8Bar, u8AddrType, u64Offset,
1546 u8DataLen, u64DataVal, peci_fd, cc);
1547}
1548
1549/*-------------------------------------------------------------------------
1550 * This function allows sequential WrEndPointConfig to PCI MMIO with the
1551 * provided peci file descriptor in the specified domain.
1552 *------------------------------------------------------------------------*/
1553EPECIStatus peci_WrEndPointConfigMmio_seq_dom(
1554 uint8_t target, uint8_t domainId, uint8_t u8Seg, uint8_t u8Bus,
1555 uint8_t u8Device, uint8_t u8Fcn, uint8_t u8Bar, uint8_t u8AddrType,
1556 uint64_t u64Offset, uint8_t u8DataLen, uint64_t u64DataVal, int peci_fd,
1557 uint8_t* cc)
1558{
Nirav Shahfd5dfd52022-03-09 12:29:41 -08001559 struct peci_wr_end_pt_cfg_msg cmd = {0};
Jason M. Billsbc641112020-08-19 16:31:53 -07001560 EPECIStatus ret = PECI_CC_SUCCESS;
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001561
1562 if (cc == NULL)
1563 {
1564 return PECI_CC_INVALID_REQ;
1565 }
1566
Jason M. Bills6ca31642020-08-06 10:26:19 -07001567 // The target address must be in the valid range
1568 if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR)
1569 {
1570 return PECI_CC_INVALID_REQ;
1571 }
1572
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001573 // Per the PECI spec, the read length must be a byte, word, dword, or qword
1574 if (u8DataLen != 1 && u8DataLen != 2 && u8DataLen != 4 && u8DataLen != 8)
1575 {
1576 return PECI_CC_INVALID_REQ;
1577 }
1578
1579 cmd.addr = target;
1580 cmd.msg_type = PECI_ENDPTCFG_TYPE_MMIO;
1581 cmd.params.mmio.seg = u8Seg;
1582 cmd.params.mmio.bus = u8Bus;
1583 cmd.params.mmio.device = u8Device;
1584 cmd.params.mmio.function = u8Fcn;
1585 cmd.params.mmio.bar = u8Bar;
1586 cmd.params.mmio.addr_type = u8AddrType;
1587 cmd.params.mmio.offset = u64Offset;
1588 cmd.tx_len = u8DataLen;
1589 cmd.value = u64DataVal;
Jason M. Bills8bb8f372022-03-01 16:04:44 -08001590 cmd.domain_id = domainId;
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001591
1592 ret = HW_peci_issue_cmd(PECI_IOC_WR_END_PT_CFG, (char*)&cmd, peci_fd);
1593 *cc = cmd.cc;
1594
1595 return ret;
1596}
1597
1598/*-------------------------------------------------------------------------
Jason M. Bills8bb8f372022-03-01 16:04:44 -08001599 * This function provides crashdump discovery data over PECI
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001600 *------------------------------------------------------------------------*/
1601EPECIStatus peci_CrashDump_Discovery(uint8_t target, uint8_t subopcode,
1602 uint8_t param0, uint16_t param1,
1603 uint8_t param2, uint8_t u8ReadLen,
1604 uint8_t* pData, uint8_t* cc)
1605{
Jason M. Bills8bb8f372022-03-01 16:04:44 -08001606 // Default to domain ID 0
1607 return peci_CrashDump_Discovery_dom(target, 0, subopcode, param0, param1,
1608 param2, u8ReadLen, pData, cc);
1609}
1610
1611/*-------------------------------------------------------------------------
1612 * This function provides crashdump discovery data over PECI in the specified
1613 * domain
1614 *------------------------------------------------------------------------*/
1615EPECIStatus peci_CrashDump_Discovery_dom(uint8_t target, uint8_t domainId,
1616 uint8_t subopcode, uint8_t param0,
1617 uint16_t param1, uint8_t param2,
1618 uint8_t u8ReadLen, uint8_t* pData,
1619 uint8_t* cc)
1620{
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001621 int peci_fd = -1;
Nirav Shahfd5dfd52022-03-09 12:29:41 -08001622 struct peci_crashdump_disc_msg cmd = {0};
Jason M. Billsbc641112020-08-19 16:31:53 -07001623 EPECIStatus ret = PECI_CC_SUCCESS;
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001624
1625 if (pData == NULL || cc == NULL)
1626 {
1627 return PECI_CC_INVALID_REQ;
1628 }
1629
Jason M. Bills6ca31642020-08-06 10:26:19 -07001630 // The target address must be in the valid range
1631 if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR)
1632 {
1633 return PECI_CC_INVALID_REQ;
1634 }
1635
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001636 // Per the PECI spec, the read length must be a byte, word, or qword
1637 if (u8ReadLen != 1 && u8ReadLen != 2 && u8ReadLen != 8)
1638 {
1639 return PECI_CC_INVALID_REQ;
1640 }
1641
1642 // The PECI buffer must be large enough to hold the requested data
1643 if (sizeof(cmd.data) < u8ReadLen)
1644 {
1645 return PECI_CC_INVALID_REQ;
1646 }
1647
1648 if (peci_Open(&peci_fd) != PECI_CC_SUCCESS)
1649 {
1650 return PECI_CC_DRIVER_ERR;
1651 }
1652
1653 cmd.addr = target;
1654 cmd.subopcode = subopcode;
1655 cmd.param0 = param0;
1656 cmd.param1 = param1;
1657 cmd.param2 = param2;
1658 cmd.rx_len = u8ReadLen;
Jason M. Bills8bb8f372022-03-01 16:04:44 -08001659 cmd.domain_id = domainId;
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001660
1661 ret = HW_peci_issue_cmd(PECI_IOC_CRASHDUMP_DISC, (char*)&cmd, peci_fd);
1662 *cc = cmd.cc;
1663 if (ret == PECI_CC_SUCCESS)
1664 {
1665 memcpy(pData, cmd.data, u8ReadLen);
1666 }
1667 else
1668 {
1669 ret = PECI_CC_DRIVER_ERR;
1670 }
1671
1672 peci_Close(peci_fd);
1673 return ret;
1674}
1675
1676/*-------------------------------------------------------------------------
Jason M. Bills8bb8f372022-03-01 16:04:44 -08001677 * This function provides crashdump GetFrame data over PECI
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001678 *------------------------------------------------------------------------*/
1679EPECIStatus peci_CrashDump_GetFrame(uint8_t target, uint16_t param0,
1680 uint16_t param1, uint16_t param2,
1681 uint8_t u8ReadLen, uint8_t* pData,
1682 uint8_t* cc)
1683{
Jason M. Bills8bb8f372022-03-01 16:04:44 -08001684 // Default to domain ID 0
1685 return peci_CrashDump_GetFrame_dom(target, 0, param0, param1, param2,
1686 u8ReadLen, pData, cc);
1687}
1688
1689/*-------------------------------------------------------------------------
1690 * This function provides crashdump GetFrame data over PECI in the specified
1691 * domain
1692 *------------------------------------------------------------------------*/
1693EPECIStatus peci_CrashDump_GetFrame_dom(uint8_t target, uint8_t domainId,
1694 uint16_t param0, uint16_t param1,
1695 uint16_t param2, uint8_t u8ReadLen,
1696 uint8_t* pData, uint8_t* cc)
1697{
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001698 int peci_fd = -1;
Nirav Shahfd5dfd52022-03-09 12:29:41 -08001699 struct peci_crashdump_get_frame_msg cmd = {0};
Jason M. Billsbc641112020-08-19 16:31:53 -07001700 EPECIStatus ret = PECI_CC_SUCCESS;
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001701
1702 if (pData == NULL || cc == NULL)
1703 {
1704 return PECI_CC_INVALID_REQ;
1705 }
1706
Jason M. Bills6ca31642020-08-06 10:26:19 -07001707 // The target address must be in the valid range
1708 if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR)
1709 {
1710 return PECI_CC_INVALID_REQ;
1711 }
1712
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001713 // Per the PECI spec, the read length must be a qword or dqword
1714 if (u8ReadLen != 8 && u8ReadLen != 16)
1715 {
1716 return PECI_CC_INVALID_REQ;
1717 }
1718
1719 // The PECI buffer must be large enough to hold the requested data
1720 if (sizeof(cmd.data) < u8ReadLen)
1721 {
1722 return PECI_CC_INVALID_REQ;
1723 }
1724
1725 if (peci_Open(&peci_fd) != PECI_CC_SUCCESS)
1726 {
1727 return PECI_CC_DRIVER_ERR;
1728 }
1729
1730 cmd.addr = target;
1731 cmd.param0 = param0;
1732 cmd.param1 = param1;
1733 cmd.param2 = param2;
1734 cmd.rx_len = u8ReadLen;
Jason M. Bills8bb8f372022-03-01 16:04:44 -08001735 cmd.domain_id = domainId;
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001736
1737 ret = HW_peci_issue_cmd(PECI_IOC_CRASHDUMP_GET_FRAME, (char*)&cmd, peci_fd);
1738 *cc = cmd.cc;
1739 if (ret == PECI_CC_SUCCESS)
1740 {
1741 memcpy(pData, cmd.data, u8ReadLen);
1742 }
1743 else
1744 {
1745 ret = PECI_CC_DRIVER_ERR;
1746 }
1747
1748 peci_Close(peci_fd);
1749 return ret;
1750}
1751
1752/*-------------------------------------------------------------------------
1753 * This function provides raw PECI command access
1754 *------------------------------------------------------------------------*/
1755EPECIStatus peci_raw(uint8_t target, uint8_t u8ReadLen, const uint8_t* pRawCmd,
1756 const uint32_t cmdSize, uint8_t* pRawResp,
1757 uint32_t respSize)
1758{
1759 int peci_fd = -1;
Nirav Shahfd5dfd52022-03-09 12:29:41 -08001760 struct peci_xfer_msg cmd = {0};
1761 uint8_t u8TxBuf[PECI_BUFFER_SIZE] = {0};
1762 uint8_t u8RxBuf[PECI_BUFFER_SIZE] = {0};
Jason M. Billsbc641112020-08-19 16:31:53 -07001763 EPECIStatus ret = PECI_CC_SUCCESS;
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001764
1765 if (u8ReadLen && pRawResp == NULL)
1766 {
1767 return PECI_CC_INVALID_REQ;
1768 }
1769
Jason M. Bills6ca31642020-08-06 10:26:19 -07001770 // The target address must be in the valid range
1771 if (target < MIN_CLIENT_ADDR || target > MAX_CLIENT_ADDR)
1772 {
1773 return PECI_CC_INVALID_REQ;
1774 }
1775
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001776 if (peci_Open(&peci_fd) != PECI_CC_SUCCESS)
1777 {
1778 return PECI_CC_DRIVER_ERR;
1779 }
1780
1781 // Check for valid buffer sizes
1782 if (cmdSize > PECI_BUFFER_SIZE || respSize < u8ReadLen ||
1783 u8ReadLen >
1784 (PECI_BUFFER_SIZE - 1)) // response buffer is data + 1 status byte
1785 {
1786 peci_Close(peci_fd);
1787 return PECI_CC_INVALID_REQ;
1788 }
1789
1790 cmd.addr = target;
1791 cmd.tx_len = (uint8_t)cmdSize;
1792 cmd.rx_len = u8ReadLen;
1793
1794 memcpy(u8TxBuf, pRawCmd, cmdSize);
1795
1796 cmd.tx_buf = u8TxBuf;
1797 cmd.rx_buf = u8RxBuf;
1798 ret = HW_peci_issue_cmd(PECI_IOC_XFER, (char*)&cmd, peci_fd);
1799
1800 if (ret == PECI_CC_SUCCESS || ret == PECI_CC_TIMEOUT)
1801 {
1802 memcpy(pRawResp, u8RxBuf, u8ReadLen);
1803 }
1804
1805 peci_Close(peci_fd);
1806 return ret;
1807}
1808
1809/*-------------------------------------------------------------------------
1810 * This function returns the CPUID (Model and stepping) for the given PECI
1811 * client address
1812 *------------------------------------------------------------------------*/
1813EPECIStatus peci_GetCPUID(const uint8_t clientAddr, CPUModel* cpuModel,
1814 uint8_t* stepping, uint8_t* cc)
1815{
1816 EPECIStatus ret = PECI_CC_SUCCESS;
1817 uint32_t cpuid = 0;
1818
1819 if (cpuModel == NULL || stepping == NULL || cc == NULL)
1820 {
1821 return PECI_CC_INVALID_REQ;
1822 }
1823
Jason M. Bills6ca31642020-08-06 10:26:19 -07001824 // The client address must be in the valid range
1825 if (clientAddr < MIN_CLIENT_ADDR || clientAddr > MAX_CLIENT_ADDR)
1826 {
1827 return PECI_CC_INVALID_REQ;
1828 }
1829
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001830 if (peci_Ping(clientAddr) != PECI_CC_SUCCESS)
1831 {
1832 return PECI_CC_CPU_NOT_PRESENT;
1833 }
1834
Patrick Williams7169faa2023-05-10 07:51:24 -05001835 ret = peci_RdPkgConfig(clientAddr, PECI_MBX_INDEX_CPU_ID,
1836 PECI_PKG_ID_CPU_ID, sizeof(uint32_t),
1837 (uint8_t*)&cpuid, cc);
Jason M. Bills7ef5a552020-04-06 14:58:44 -07001838
1839 // Separate out the model and stepping (bits 3:0) from the CPUID
1840 *cpuModel = cpuid & 0xFFFFFFF0;
1841 *stepping = (uint8_t)(cpuid & 0x0000000F);
1842 return ret;
1843}