blob: 86d2b6741f1f1124caa0ff61a90d5eba05fabc31 [file] [log] [blame]
Corey Tabakab0bd1832009-04-03 01:17:52 -04001/*
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 int busses = 0, devices = 0, lines = 0, devfn, ret;
45 char c;
46
47 printf("Scanning...\n");
48
49 for (state.bus = 0; state.bus <= pci_get_last_bus(); state.bus++) {
50 busses++;
51
52 for (devfn = 0; devfn < 256; devfn++) {
53 state.dev_fn = devfn;
54
55 ret = pci_read_config_half(&state, PCI_CONFIG_VENDOR_ID, &vendor_id);
56 if (ret != _PCI_SUCCESSFUL) goto error;
57
58 ret = pci_read_config_half(&state, PCI_CONFIG_DEVICE_ID, &device_id);
59 if (ret != _PCI_SUCCESSFUL) goto error;
60
61 ret = pci_read_config_byte(&state, PCI_CONFIG_HEADER_TYPE, &header_type);
62 if (ret != _PCI_SUCCESSFUL) goto error;
63
64 if (vendor_id != 0xffff) {
65 printf("%02x:%02x vendor_id=%04x device_id=%04x, header_type=%02x\n", state.bus, state.dev_fn,
66 vendor_id, device_id, header_type);
67 devices++;
68 lines++;
69 }
70
71 if (~header_type & PCI_HEADER_TYPE_MULTI_FN) {
72 // this is not a multi-function device, so advance to the next device
73 devfn |= 7;
74 }
75
76 if (lines == 23) {
77 printf("... press any key to continue, q to quit ...");
78 while(getc(&c) < 0);
79 printf("\n");
80 lines = 0;
81
82 if (c == 'q' || c == 'Q') goto quit;
83 }
84 }
85 }
86
87 printf("... done. Scanned %d busses, %d device/functions\n", busses, devices);
88quit:
89 return;
90
91error:
92 printf("Error while reading PCI config space: %02x\n", ret);
93}
94
95/*
Corey Tabakaad21b8d2009-04-03 15:34:38 -040096 * a somewhat fugly pci config space examine/modify command. this should probably
Corey Tabakab0bd1832009-04-03 01:17:52 -040097 * be broken up a bit.
98 */
99static int pci_config(int argc, const cmd_args *argv)
100{
101 pci_location_t loc;
102 pci_config_t config;
103 uint32_t offset;
104 unsigned int i;
105 int ret;
106
107 if (argc < 5) {
108 return -1;
109 }
110
111 if (!strcmp(argv[2].str, "dump")) {
112 loc.bus = atoui(argv[3].str);
113 loc.dev_fn = atoui(argv[4].str);
114
115 for (i=0; i < sizeof(pci_config_t); i++) {
116 ret = pci_read_config_byte(&loc, i, (uint8_t *) &config + i);
117 if (ret != _PCI_SUCCESSFUL) goto error;
118 }
119
120 printf("Device at %02x:%02x vendor id=%04x device id=%04x\n", loc.bus,
121 loc.dev_fn, config.vendor_id, config.device_id);
122 printf("command=%04x status=%04x pi=%02x sub cls=%02x base cls=%02x\n",
123 config.command, config.status, config.program_interface,
124 config.sub_class, config.base_class);
125
126 for (i=0; i < 6; i+=2) {
Corey Tabakad890c352009-04-21 10:23:49 -0400127 printf("bar%d=%08x bar%d=%08x\n", i, config.base_addresses[i],
Corey Tabakab0bd1832009-04-03 01:17:52 -0400128 i+1, config.base_addresses[i+1]);
129 }
130 } else if (!strcmp(argv[2].str, "rb") || !strcmp(argv[2].str, "rh") || !strcmp(argv[2].str, "rw")) {
131 if (argc != 6) {
132 return -1;
133 }
134
135 loc.bus = atoui(argv[3].str);
136 loc.dev_fn = atoui(argv[4].str);
137 offset = atoui(argv[5].str);
138
139 switch (argv[2].str[1]) {
140 case 'b': {
141 uint8_t value;
142 ret = pci_read_config_byte(&loc, offset, &value);
143 if (ret != _PCI_SUCCESSFUL) goto error;
144
145 printf("byte at device %02x:%02x config offset %04x: %02x\n", loc.bus, loc.dev_fn, offset, value);
146 }
147 break;
148
149 case 'h': {
150 uint16_t value;
151 ret = pci_read_config_half(&loc, offset, &value);
152 if (ret != _PCI_SUCCESSFUL) goto error;
153
154 printf("half at device %02x:%02x config offset %04x: %04x\n", loc.bus, loc.dev_fn, offset, value);
155 }
156 break;
157
158 case 'w': {
159 uint32_t value;
160 ret = pci_read_config_word(&loc, offset, &value);
161 if (ret != _PCI_SUCCESSFUL) goto error;
162
163 printf("word at device %02x:%02x config offset %04x: %08x\n", loc.bus, loc.dev_fn, offset, value);
164 }
165 break;
166 }
167 } else if (!strcmp(argv[2].str, "mb") || !strcmp(argv[2].str, "mh") || !strcmp(argv[2].str, "mw")) {
168 if (argc != 7) {
169 return -1;
170 }
171
172 loc.bus = atoui(argv[3].str);
173 loc.dev_fn = atoui(argv[4].str);
174 offset = atoui(argv[5].str);
175
176 switch (argv[2].str[1]) {
177 case 'b': {
178 uint8_t value = atoui(argv[6].str);
179 ret = pci_write_config_byte(&loc, offset, value);
180 if (ret != _PCI_SUCCESSFUL) goto error;
181
182 printf("byte to device %02x:%02x config offset %04x: %02x\n", loc.bus, loc.dev_fn, offset, value);
183 }
184 break;
185
186 case 'h': {
187 uint16_t value = atoui(argv[6].str);
188 ret = pci_write_config_half(&loc, offset, value);
189 if (ret != _PCI_SUCCESSFUL) goto error;
190
191 printf("half to device %02x:%02x config offset %04x: %04x\n", loc.bus, loc.dev_fn, offset, value);
192 }
193 break;
194
195 case 'w': {
196 uint32_t value = atoui(argv[6].str);
197 ret = pci_write_config_word(&loc, offset, value);
198 if (ret != _PCI_SUCCESSFUL) goto error;
199
200 printf("word to device %02x:%02x config offset %04x: %08x\n", loc.bus, loc.dev_fn, offset, value);
201 }
202 break;
203 }
204 } else {
205 return -1;
206 }
207
208 return 0;
209
210error:
211 printf("Error while reading PCI config space: %02x\n", ret);
212 return -2;
213}
214
215static int pci_cmd(int argc, const cmd_args *argv)
216{
217 if (argc < 2) {
218 printf("pci commands:\n");
219usage:
220 printf("%s list\n", argv[0].str);
221 printf("%s config dump <bus> <devfn>\n", argv[0].str);
222 printf("%s config <rb|rh|rw> <bus> <devfn> <offset>\n", argv[0].str);
223 printf("%s config <mb|mh|mw> <bus> <devfn> <offset> <value>\n", argv[0].str);
224 goto out;
225 }
226
227 if (!strcmp(argv[1].str, "list")) {
228 pci_list();
229 } else if (!strcmp(argv[1].str, "config")) {
230 if (pci_config(argc, argv)) {
231 goto usage;
232 }
233 } else {
234 goto usage;
235 }
236
237out:
238 return 0;
239}
240
241STATIC_COMMAND_START
242{ "pci", "pci toolbox", &pci_cmd },
243STATIC_COMMAND_END(pcitests);
244
245#endif
246
247APP_START(pcitests)
248APP_END
249