master
c 118 lines 2.66 KB
Raw
1 /*
2 * s390x PCI functionality
3 *
4 * Copyright 2025 IBM Corp.
5 * Author(s): Jared Rossi <jrossi@linux.ibm.com>
6 *
7 * SPDX-License-Identifier: GPL-2.0-or-later
8 */
9
10 #include "clp.h"
11 #include "pci.h"
12 #include "bswap.h"
13 #include <stdio.h>
14 #include <stdbool.h>
15
16 /* PCI load */
17 static inline int pcilg(uint64_t *data, uint64_t req, uint64_t offset,
18 uint8_t *status)
19 {
20 union register_pair req_off = {.even = req, .odd = offset};
21 int cc = -1;
22 uint64_t __data;
23
24 asm volatile (
25 " .insn rre,0xb9d20000,%[data],%[req_off]\n"
26 " ipm %[cc]\n"
27 " srl %[cc],28\n"
28 : [cc] "+d" (cc), [data] "=d" (__data),
29 [req_off] "+d" (req_off.pair) :: "cc");
30 *status = req_off.even >> 24 & 0xff;
31 *data = __data;
32 return cc;
33 }
34
35 /* PCI store */
36 static inline int pcistg(uint64_t data, uint64_t req, uint64_t offset,
37 uint8_t *status)
38 {
39 union register_pair req_off = {.even = req, .odd = offset};
40 int cc = -1;
41
42 asm volatile (
43 " .insn rre,0xb9d00000,%[data],%[req_off]\n"
44 " ipm %[cc]\n"
45 " srl %[cc],28\n"
46 : [cc] "+d" (cc), [req_off] "+d" (req_off.pair)
47 : [data] "d" (data)
48 : "cc");
49 *status = req_off.even >> 24 & 0xff;
50 return cc;
51 }
52
53 int pci_write(uint32_t fhandle, uint64_t offset, uint8_t pcias, uint64_t data,
54 uint8_t len)
55 {
56
57 uint64_t req = ZPCI_CREATE_REQ(fhandle, pcias, len);
58 uint8_t status;
59 int rc;
60
61 /* len must be non-zero power of 2 with a maximum of 8 bytes per write */
62 switch (len) {
63 case 1:
64 case 2:
65 case 4:
66 case 8:
67 rc = pcistg(data, req, offset, &status);
68 break;
69 default:
70 return -1;
71 }
72
73 /* Error condition detected */
74 if (rc != 0) {
75 printf("PCI store failed with status condition %d, return code %d\n",
76 status, rc);
77 return -1;
78 }
79
80 return 0;
81 }
82
83 int pci_read(uint32_t fhandle, uint64_t offset, uint8_t pcias, void *buf,
84 uint8_t len)
85 {
86 uint64_t req, data;
87 uint8_t status;
88 int rc;
89
90 req = ZPCI_CREATE_REQ(fhandle, pcias, len);
91 rc = pcilg(&data, req, offset, &status);
92
93 /* Error condition detected */
94 if (rc != 0) {
95 printf("PCI load failed with status condition %d, return code %d\n",
96 status, rc);
97 return -1;
98 }
99
100 switch (len) {
101 case 1:
102 *(uint8_t *)buf = data;
103 break;
104 case 2:
105 *(uint16_t *)buf = data;
106 break;
107 case 4:
108 *(uint32_t *)buf = data;
109 break;
110 case 8:
111 *(uint64_t *)buf = data;
112 break;
113 default:
114 return -1;
115 }
116
117 return 0;
118 }