blob: 9b330438b44023b7a286d901381f88b6ff4cb1ed [file] [log] [blame]
rjw1f884582022-01-06 17:20:42 +08001/*
2 * Copyright (c) 2009 Corey Tabaka
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files
6 * (the "Software"), to deal in the Software without restriction,
7 * including without limitation the rights to use, copy, modify, merge,
8 * publish, distribute, sublicense, and/or sell copies of the Software,
9 * and to permit persons to whom the Software is furnished to do so,
10 * subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23#include <app.h>
24#include <debug.h>
25#include <stdint.h>
26#include <string.h>
27#include <stdio.h>
28#include <stdlib.h>
29#include <compiler.h>
30#include <platform.h>
31#include <dev/pci.h>
32
33#if defined(WITH_LIB_CONSOLE)
34#include <lib/console.h>
35
36/*
37 * enumerates pci devices
38 */
39static void pci_list(void)
40{
41 pci_location_t state;
42 uint16_t device_id, vendor_id;
43 uint8_t header_type;
44 uint8_t base_class, sub_class, interface;
45 int busses = 0, devices = 0, lines = 0, devfn, ret;
46 int c;
47
48 printf("Scanning...\n");
49
50 for (state.bus = 0; state.bus <= pci_get_last_bus(); state.bus++) {
51 busses++;
52
53 for (devfn = 0; devfn < 256; devfn++) {
54 state.dev_fn = devfn;
55
56 ret = pci_read_config_half(&state, PCI_CONFIG_VENDOR_ID, &vendor_id);
57 if (ret != _PCI_SUCCESSFUL) goto error;
58
59 ret = pci_read_config_half(&state, PCI_CONFIG_DEVICE_ID, &device_id);
60 if (ret != _PCI_SUCCESSFUL) goto error;
61
62 ret = pci_read_config_byte(&state, PCI_CONFIG_HEADER_TYPE, &header_type);
63 if (ret != _PCI_SUCCESSFUL) goto error;
64
65 ret = pci_read_config_byte(&state, PCI_CONFIG_CLASS_CODE_BASE, &base_class);
66 if (ret != _PCI_SUCCESSFUL) goto error;
67
68 ret = pci_read_config_byte(&state, PCI_CONFIG_CLASS_CODE_SUB, &sub_class);
69 if (ret != _PCI_SUCCESSFUL) goto error;
70
71 ret = pci_read_config_byte(&state, PCI_CONFIG_CLASS_CODE_INTR, &interface);
72 if (ret != _PCI_SUCCESSFUL) goto error;
73
74 if (vendor_id != 0xffff) {
75 printf("%02x:%02x vendor_id=%04x device_id=%04x, header_type=%02x "
76 "base_class=%02x, sub_class=%02x, interface=%02x\n", state.bus, state.dev_fn,
77 vendor_id, device_id, header_type, base_class, sub_class, interface);
78 devices++;
79 lines++;
80 }
81
82 if (~header_type & PCI_HEADER_TYPE_MULTI_FN) {
83 // this is not a multi-function device, so advance to the next device
84 devfn |= 7;
85 }
86
87 if (lines == 23) {
88 printf("... press any key to continue, q to quit ...");
89 while ((c = getchar()) < 0);
90 printf("\n");
91 lines = 0;
92
93 if (c == 'q' || c == 'Q') goto quit;
94 }
95 }
96 }
97
98 printf("... done. Scanned %d busses, %d device/functions\n", busses, devices);
99quit:
100 return;
101
102error:
103 printf("Error while reading PCI config space: %02x\n", ret);
104}
105
106/*
107 * a somewhat fugly pci config space examine/modify command. this should probably
108 * be broken up a bit.
109 */
110static int pci_config(int argc, const cmd_args *argv)
111{
112 pci_location_t loc;
113 pci_config_t config;
114 uint32_t offset;
115 unsigned int i;
116 int ret;
117
118 if (argc < 5) {
119 return -1;
120 }
121
122 if (!strcmp(argv[2].str, "dump")) {
123 loc.bus = atoui(argv[3].str);
124 loc.dev_fn = atoui(argv[4].str);
125
126 for (i=0; i < sizeof(pci_config_t); i++) {
127 ret = pci_read_config_byte(&loc, i, (uint8_t *) &config + i);
128 if (ret != _PCI_SUCCESSFUL) goto error;
129 }
130
131 printf("Device at %02x:%02x vendor id=%04x device id=%04x\n", loc.bus,
132 loc.dev_fn, config.vendor_id, config.device_id);
133 printf("command=%04x status=%04x pi=%02x sub cls=%02x base cls=%02x\n",
134 config.command, config.status, config.program_interface,
135 config.sub_class, config.base_class);
136
137 for (i=0; i < 6; i+=2) {
138 printf("bar%d=%08x bar%d=%08x\n", i, config.base_addresses[i],
139 i+1, config.base_addresses[i+1]);
140 }
141 } else if (!strcmp(argv[2].str, "rb") || !strcmp(argv[2].str, "rh") || !strcmp(argv[2].str, "rw")) {
142 if (argc != 6) {
143 return -1;
144 }
145
146 loc.bus = atoui(argv[3].str);
147 loc.dev_fn = atoui(argv[4].str);
148 offset = atoui(argv[5].str);
149
150 switch (argv[2].str[1]) {
151 case 'b': {
152 uint8_t value;
153 ret = pci_read_config_byte(&loc, offset, &value);
154 if (ret != _PCI_SUCCESSFUL) goto error;
155
156 printf("byte at device %02x:%02x config offset %04x: %02x\n", loc.bus, loc.dev_fn, offset, value);
157 }
158 break;
159
160 case 'h': {
161 uint16_t value;
162 ret = pci_read_config_half(&loc, offset, &value);
163 if (ret != _PCI_SUCCESSFUL) goto error;
164
165 printf("half at device %02x:%02x config offset %04x: %04x\n", loc.bus, loc.dev_fn, offset, value);
166 }
167 break;
168
169 case 'w': {
170 uint32_t value;
171 ret = pci_read_config_word(&loc, offset, &value);
172 if (ret != _PCI_SUCCESSFUL) goto error;
173
174 printf("word at device %02x:%02x config offset %04x: %08x\n", loc.bus, loc.dev_fn, offset, value);
175 }
176 break;
177 }
178 } else if (!strcmp(argv[2].str, "mb") || !strcmp(argv[2].str, "mh") || !strcmp(argv[2].str, "mw")) {
179 if (argc != 7) {
180 return -1;
181 }
182
183 loc.bus = atoui(argv[3].str);
184 loc.dev_fn = atoui(argv[4].str);
185 offset = atoui(argv[5].str);
186
187 switch (argv[2].str[1]) {
188 case 'b': {
189 uint8_t value = atoui(argv[6].str);
190 ret = pci_write_config_byte(&loc, offset, value);
191 if (ret != _PCI_SUCCESSFUL) goto error;
192
193 printf("byte to device %02x:%02x config offset %04x: %02x\n", loc.bus, loc.dev_fn, offset, value);
194 }
195 break;
196
197 case 'h': {
198 uint16_t value = atoui(argv[6].str);
199 ret = pci_write_config_half(&loc, offset, value);
200 if (ret != _PCI_SUCCESSFUL) goto error;
201
202 printf("half to device %02x:%02x config offset %04x: %04x\n", loc.bus, loc.dev_fn, offset, value);
203 }
204 break;
205
206 case 'w': {
207 uint32_t value = atoui(argv[6].str);
208 ret = pci_write_config_word(&loc, offset, value);
209 if (ret != _PCI_SUCCESSFUL) goto error;
210
211 printf("word to device %02x:%02x config offset %04x: %08x\n", loc.bus, loc.dev_fn, offset, value);
212 }
213 break;
214 }
215 } else {
216 return -1;
217 }
218
219 return 0;
220
221error:
222 printf("Error while reading PCI config space: %02x\n", ret);
223 return -2;
224}
225
226static int pci_cmd(int argc, const cmd_args *argv)
227{
228 if (argc < 2) {
229 printf("pci commands:\n");
230usage:
231 printf("%s list\n", argv[0].str);
232 printf("%s config dump <bus> <devfn>\n", argv[0].str);
233 printf("%s config <rb|rh|rw> <bus> <devfn> <offset>\n", argv[0].str);
234 printf("%s config <mb|mh|mw> <bus> <devfn> <offset> <value>\n", argv[0].str);
235 goto out;
236 }
237
238 if (!strcmp(argv[1].str, "list")) {
239 pci_list();
240 } else if (!strcmp(argv[1].str, "config")) {
241 if (pci_config(argc, argv)) {
242 goto usage;
243 }
244 } else {
245 goto usage;
246 }
247
248out:
249 return 0;
250}
251
252STATIC_COMMAND_START
253STATIC_COMMAND("pci", "pci toolbox", &pci_cmd)
254STATIC_COMMAND_END(pcitests);
255
256#endif
257
258APP_START(pcitests)
259APP_END
260