1 | /************************************************************************** |
---|
2 | * |
---|
3 | * Copyright (c) 2013 Alcatel-Lucent |
---|
4 | * |
---|
5 | * Alcatel Lucent licenses this file to You under the Apache License, |
---|
6 | * Version 2.0 (the "License"); you may not use this file except in |
---|
7 | * compliance with the License. A copy of the License is contained the |
---|
8 | * file LICENSE at the top level of this repository. |
---|
9 | * You may also obtain a copy of the License at: |
---|
10 | * |
---|
11 | * http://www.apache.org/licenses/LICENSE-2.0 |
---|
12 | * |
---|
13 | * Unless required by applicable law or agreed to in writing, software |
---|
14 | * distributed under the License is distributed on an "AS IS" BASIS, |
---|
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
---|
16 | * See the License for the specific language governing permissions and |
---|
17 | * limitations under the License. |
---|
18 | * |
---|
19 | ************************************************************************** |
---|
20 | * |
---|
21 | * pci.c: |
---|
22 | * |
---|
23 | * This file provides the monitor with a reusable mechanism for |
---|
24 | * interfacing with a PCI bus. Four target-specific functions are |
---|
25 | * required: |
---|
26 | * |
---|
27 | * pciCtrl(), pciCfgRead(), pciCfgWrite(), pciShow() |
---|
28 | * |
---|
29 | * The two most important are pciCfgRead() and pciCfgWrite(). Refer to |
---|
30 | * the bottom of pci.h for further details. |
---|
31 | * |
---|
32 | * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) |
---|
33 | * |
---|
34 | */ |
---|
35 | #include "config.h" |
---|
36 | #include "pci.h" |
---|
37 | #include "stddefs.h" |
---|
38 | #include "genlib.h" |
---|
39 | #include "cli.h" |
---|
40 | |
---|
41 | #if INCLUDE_PCI |
---|
42 | int pciVerbose; |
---|
43 | int pciBusNum; |
---|
44 | |
---|
45 | #define IMPLEMENTED 0x80000000 |
---|
46 | |
---|
47 | #ifdef USE_DEFAULT_PCISHOW |
---|
48 | void |
---|
49 | pciShow(int interface) |
---|
50 | { |
---|
51 | printf("No fixed devices on this platform\n"); |
---|
52 | } |
---|
53 | #endif |
---|
54 | |
---|
55 | /* pciCfgAddress(): |
---|
56 | * Return a 32-bit value based on the input |
---|
57 | * bus number, device number, function number and register |
---|
58 | * number: |
---|
59 | * |
---|
60 | * 31 30 .... 24 23 ... 16 15 ... 11 10 .... 8 7 ... 2 1 0 |
---|
61 | * -------------------------------------------------------------- |
---|
62 | * | | | Bus | Device | Function | Register |0|T| |
---|
63 | * |En| Reserved | Number | Number | Number | Number | | | |
---|
64 | * -------------------------------------------------------------- |
---|
65 | * ^ ^ |
---|
66 | * |---- Enable bit 1=enabled, 0=disabled | |
---|
67 | * | |
---|
68 | * Type0: 0 --------------------------------------------| |
---|
69 | * Type1: 1 --------------------------------------------| |
---|
70 | * |
---|
71 | * See pg 32 of the PCI2.2 spec for more details. |
---|
72 | */ |
---|
73 | |
---|
74 | unsigned long |
---|
75 | pciCfgAddress(int busno,int devno,int fncno,int regno) |
---|
76 | { |
---|
77 | int type; |
---|
78 | |
---|
79 | if (busno > 0) |
---|
80 | type = 1; |
---|
81 | else |
---|
82 | type = 0; |
---|
83 | |
---|
84 | return((type | PCICFG_ENABLE_BIT | |
---|
85 | ((busno & PCICFG_BUSNO_MASK) << PCICFG_BUSNO_SHIFT) | |
---|
86 | ((devno & PCICFG_DEVNO_MASK) << PCICFG_DEVNO_SHIFT) | |
---|
87 | ((fncno & PCICFG_FNCNO_MASK) << PCICFG_FNCNO_SHIFT) | |
---|
88 | ((regno & PCICFG_REGNO_MASK) << PCICFG_REGNO_SHIFT))); |
---|
89 | } |
---|
90 | |
---|
91 | /* pciBaseClass(): |
---|
92 | * Based on appendix D of spec, return a simple string that describes |
---|
93 | * the base class of the incoming class code. |
---|
94 | */ |
---|
95 | char * |
---|
96 | pciBaseClass(unsigned long classcode) |
---|
97 | { |
---|
98 | unsigned long baseclass; |
---|
99 | unsigned long subclass_progif; |
---|
100 | |
---|
101 | baseclass = (classcode >> 16) & 0xff; |
---|
102 | subclass_progif = classcode & 0xffff; |
---|
103 | |
---|
104 | switch(baseclass) { |
---|
105 | case 0: |
---|
106 | return("pre-class-code-definitions"); |
---|
107 | case 1: |
---|
108 | return("mass storage ctrlr"); |
---|
109 | case 2: |
---|
110 | return("network ctrlr"); |
---|
111 | case 3: |
---|
112 | return("display ctrlr"); |
---|
113 | case 4: |
---|
114 | return("multimedia device"); |
---|
115 | case 5: |
---|
116 | return("memory ctrlr"); |
---|
117 | case 6: /* Supply additional information for bridge class... |
---|
118 | */ |
---|
119 | switch(subclass_progif) { |
---|
120 | case 0x0000: |
---|
121 | return("host/pci bridge"); |
---|
122 | case 0x0100: |
---|
123 | return("pci/isa bridge"); |
---|
124 | case 0x0200: |
---|
125 | return("pci/eisa bridge"); |
---|
126 | case 0x0300: |
---|
127 | return("pci/microchannel bridge"); |
---|
128 | case 0x0400: |
---|
129 | return("pci/pci bridge"); |
---|
130 | case 0x0500: |
---|
131 | return("pci/pcmcia bridge"); |
---|
132 | case 0x0600: |
---|
133 | return("pci/nubus bridge"); |
---|
134 | case 0x0700: |
---|
135 | return("pci/cardbus bridge"); |
---|
136 | case 0x8000: |
---|
137 | return("other bridge type"); |
---|
138 | default: |
---|
139 | return("bridge device"); |
---|
140 | } |
---|
141 | case 7: |
---|
142 | return("simple communication ctrlr"); |
---|
143 | case 8: |
---|
144 | return("base system peripheral"); |
---|
145 | case 9: |
---|
146 | return("input device"); |
---|
147 | case 10: |
---|
148 | return("docking station"); |
---|
149 | case 11: |
---|
150 | return("processor"); |
---|
151 | case 12: |
---|
152 | return("serial bus ctrlr"); |
---|
153 | case 13: |
---|
154 | return("wireless ctrlr"); |
---|
155 | case 14: |
---|
156 | return("intelligent io ctrlr"); |
---|
157 | case 15: |
---|
158 | return("satellite communication ctrlr"); |
---|
159 | case 16: |
---|
160 | return("encrypt/decrypt ctrlr"); |
---|
161 | case 17: |
---|
162 | return("data acquisition ctrlr"); |
---|
163 | case 256: |
---|
164 | return("no fit"); |
---|
165 | default: |
---|
166 | return("reserved"); |
---|
167 | } |
---|
168 | } |
---|
169 | |
---|
170 | /* pciscan(): |
---|
171 | * This function is used by "pci scan" and "pci enum" to look |
---|
172 | * at the devices on the pci bus. When the enumerate flag is set, |
---|
173 | * this function will recursively nest itself each time it sees a |
---|
174 | * PCI-to-PCI bridge device on the bus, and while doing this, it will |
---|
175 | * assign bus numbers to each bridge appropriately. This function does |
---|
176 | * not assign address ranges or anything else, it simply provides a quick |
---|
177 | * means of scanning all devices on the bus(es). |
---|
178 | * |
---|
179 | * NOTE: This has only been tested with simple PCI bus configurations (one |
---|
180 | * bridge deep) so deeper configurations (bridges on bridges on bridges...) |
---|
181 | * are untested as far as I know. |
---|
182 | */ |
---|
183 | void |
---|
184 | pciscan(long interface, long bus, long func, int showhdr, int enumerate) |
---|
185 | { |
---|
186 | long device; |
---|
187 | uchar hdr_type, rev_id; |
---|
188 | ushort vendor_id, device_id; |
---|
189 | ulong value, class_code; |
---|
190 | |
---|
191 | if (showhdr) { |
---|
192 | printf("\nInterface %ld...\n",interface); |
---|
193 | printf("Bus Dev Vndr Dev Rev Hdr Class\n"); |
---|
194 | printf("Num Num Id Id Id Type Code\n"); |
---|
195 | } |
---|
196 | |
---|
197 | if ((enumerate == 1) && (bus == 0)) |
---|
198 | pciBusNum = 0; |
---|
199 | |
---|
200 | for(device=0;device<=31;device++) { |
---|
201 | /* Retrieve portions of the configuration header that |
---|
202 | * are required by all PCI compliant devices... |
---|
203 | * Vendor, Device and Revision IDs, Class Code and Header Type |
---|
204 | * (see pg 191 of spec). |
---|
205 | */ |
---|
206 | |
---|
207 | /* Read reg_0 for vendor and device ids: |
---|
208 | */ |
---|
209 | value = pciCfgRead(interface,bus,device,func,0); |
---|
210 | if (value == NO_DEVICE) |
---|
211 | continue; |
---|
212 | |
---|
213 | vendor_id = (ushort)(value & 0xffff); |
---|
214 | device_id = (ushort)((value>>16) & 0xffff); |
---|
215 | |
---|
216 | /* Read reg_2 for class code and revision id: |
---|
217 | */ |
---|
218 | value = pciCfgRead(interface,bus,device,func,2); |
---|
219 | rev_id = (uchar)(value & 0xff); |
---|
220 | class_code = (ulong)((value>>8) & 0xffffff); |
---|
221 | |
---|
222 | /* Read reg_3: header type: |
---|
223 | */ |
---|
224 | value = pciCfgRead(interface,bus,device,func,3); |
---|
225 | hdr_type = (uchar)((value>>16) & 0xff); |
---|
226 | |
---|
227 | printf("%2ld %02ld x%04x x%04x",bus, |
---|
228 | device,vendor_id,device_id); |
---|
229 | printf(" x%02x x%02x x%06lx (%s)\n",rev_id, |
---|
230 | hdr_type,class_code,pciBaseClass(class_code)); |
---|
231 | |
---|
232 | /* If enumeration is enabled, see if this is a PCI-to-PCI |
---|
233 | * bridge. If it is, then nest into pciscan... |
---|
234 | */ |
---|
235 | if ((enumerate) && (class_code == 0x060400)) { |
---|
236 | ulong pribus, secbus, subbus; |
---|
237 | |
---|
238 | pribus = pciBusNum & 0x0000ff; |
---|
239 | pciBusNum++; |
---|
240 | secbus = ((pciBusNum << 8) & 0x00ff00); |
---|
241 | subbus = ((pciBusNum << 16) & 0xff0000); |
---|
242 | |
---|
243 | value = pciCfgRead(interface,bus,device,func,6); |
---|
244 | value &= 0xffff0000; |
---|
245 | value |= (pribus | secbus); |
---|
246 | pciCfgWrite(interface,bus,device,func,6,value); |
---|
247 | |
---|
248 | pciscan(interface,pciBusNum,func,0,1); |
---|
249 | |
---|
250 | value = pciCfgRead(interface,bus,device,func,6); |
---|
251 | value &= 0xff000000; |
---|
252 | value |= (subbus | pribus | secbus); |
---|
253 | pciCfgWrite(interface,bus,device,func,6,value); |
---|
254 | } |
---|
255 | } |
---|
256 | } |
---|
257 | |
---|
258 | /* getBarInfo(): |
---|
259 | * Apply the algorithm as specified in PCI spec... |
---|
260 | * Place size information in sizehi & sizelo (to support 64-bit). |
---|
261 | * Return 0 if not implemented; else return value to indicate |
---|
262 | * size (32 or 64 bit) and type (mem or io). |
---|
263 | */ |
---|
264 | ulong |
---|
265 | getBarInfo(long interface,long bus,long device,long func,int barnum, |
---|
266 | ulong *sizehi, ulong *sizelo) |
---|
267 | { |
---|
268 | int barregno; |
---|
269 | ulong implemented, barval1, barval2, barinfo1, barinfo2, cmd; |
---|
270 | |
---|
271 | /* Translate the incoming bar number to a register number |
---|
272 | * in PCI config space: |
---|
273 | */ |
---|
274 | barregno = barnum + 4; |
---|
275 | |
---|
276 | /* Disable decoding through the command register: |
---|
277 | */ |
---|
278 | cmd = pciCfgRead(interface,bus,device,func,1); |
---|
279 | pciCfgWrite(interface,bus,device,func,1, |
---|
280 | cmd & ~(IO_SPACE | MEMORY_SPACE)); |
---|
281 | |
---|
282 | /* Read the BAR: |
---|
283 | */ |
---|
284 | barval1 = pciCfgRead(interface,bus,device,func,barregno); |
---|
285 | |
---|
286 | /* Write 0xffffffff to the BAR: |
---|
287 | */ |
---|
288 | pciCfgWrite(interface,bus,device,func,barregno,0xffffffff); |
---|
289 | |
---|
290 | /* Read the value returned as a result of writing |
---|
291 | * 0xffffffff to the BAR: |
---|
292 | */ |
---|
293 | barinfo1 = pciCfgRead(interface,bus,device,func,barregno); |
---|
294 | |
---|
295 | /* Restore original bar: |
---|
296 | */ |
---|
297 | pciCfgWrite(interface,bus,device,func,barregno,barval1); |
---|
298 | |
---|
299 | if (barinfo1 == 0) { |
---|
300 | implemented = 0; |
---|
301 | } |
---|
302 | else { |
---|
303 | implemented = IMPLEMENTED; |
---|
304 | |
---|
305 | if (barval1 & BASEADDRESS_IO) { |
---|
306 | implemented |= BASEADDRESS_IO; |
---|
307 | |
---|
308 | if (sizelo) { |
---|
309 | /* Clear encoding bits: |
---|
310 | */ |
---|
311 | barinfo1 &= 0xfffffffe; |
---|
312 | /* Invert and add 1: |
---|
313 | */ |
---|
314 | *sizelo = (~barinfo1 + 1) & 0xffff; |
---|
315 | |
---|
316 | if (sizehi) |
---|
317 | *sizehi = 0; |
---|
318 | } |
---|
319 | } |
---|
320 | else { |
---|
321 | implemented |= (barinfo1 & PREFETCHABLE); |
---|
322 | |
---|
323 | if (barval1 & TYPE_64) { |
---|
324 | implemented |= TYPE_64; |
---|
325 | |
---|
326 | /* Apply same sequence as above to the next bar... |
---|
327 | */ |
---|
328 | barregno++; |
---|
329 | barval2 = pciCfgRead(interface,bus,device,func,barregno); |
---|
330 | pciCfgWrite(interface,bus,device,func,barregno,0xffffffff); |
---|
331 | barinfo2 = pciCfgRead(interface,bus,device,func,barregno); |
---|
332 | pciCfgWrite(interface,bus,device,func,barregno,barval2); |
---|
333 | |
---|
334 | |
---|
335 | if (sizelo) { |
---|
336 | barinfo1 &= 0xfffffff0; |
---|
337 | *sizelo = ~barinfo1 + 1; |
---|
338 | if (sizehi) |
---|
339 | *sizehi = ~barinfo2 + 1; |
---|
340 | } |
---|
341 | } |
---|
342 | else { |
---|
343 | if (sizelo) { |
---|
344 | barinfo1 &= 0xfffffff0; |
---|
345 | *sizelo = ~barinfo1 + 1; |
---|
346 | |
---|
347 | if (sizehi) |
---|
348 | *sizehi = 0; |
---|
349 | } |
---|
350 | } |
---|
351 | } |
---|
352 | } |
---|
353 | |
---|
354 | /* Now that we've completed messing with the BARS, |
---|
355 | * restore original cmd: |
---|
356 | */ |
---|
357 | pciCfgWrite(interface,bus,device,func,1,cmd); |
---|
358 | |
---|
359 | return(implemented); |
---|
360 | } |
---|
361 | |
---|
362 | int |
---|
363 | showBar(int barnum,long interface,long bus,long device,long func) |
---|
364 | { |
---|
365 | int rtot; |
---|
366 | ulong bar, barnext, sizehi, sizelo, implemented; |
---|
367 | |
---|
368 | if ((barnum < 0) || (barnum > 5)) |
---|
369 | return(-1); |
---|
370 | |
---|
371 | bar = pciCfgRead(interface,bus,device,func,barnum+4); |
---|
372 | |
---|
373 | implemented = getBarInfo(interface,bus,device,func, |
---|
374 | barnum,&sizehi,&sizelo); |
---|
375 | |
---|
376 | if (!implemented) { |
---|
377 | printf("%02d BAR%d : not implemented\n",barnum+4,barnum); |
---|
378 | return(0); |
---|
379 | } |
---|
380 | |
---|
381 | printf("%02d BAR%d",barnum+4,barnum); |
---|
382 | if (!(implemented & BASEADDRESS_IO) && (implemented & TYPE_64)) { |
---|
383 | barnext = pciCfgRead(interface,bus,device,func,barnum+5); |
---|
384 | printf("-%d: 0x%08lx 0x%08lx", barnum+1,bar,barnext); |
---|
385 | } |
---|
386 | else { |
---|
387 | printf(" : 0x%08lx",bar); |
---|
388 | } |
---|
389 | |
---|
390 | printf(" Size: 0x"); |
---|
391 | if (!(implemented & BASEADDRESS_IO) && (implemented & TYPE_64)) { |
---|
392 | printf("%08lx%08lx ",sizehi,sizelo); |
---|
393 | rtot = 2; |
---|
394 | } |
---|
395 | else { |
---|
396 | printf("%08lx ",sizelo); |
---|
397 | rtot = 1; |
---|
398 | } |
---|
399 | |
---|
400 | if (bar & BASEADDRESS_IO) { |
---|
401 | printf("IO"); |
---|
402 | } |
---|
403 | else { |
---|
404 | printf("MEM %sbit",bar & TYPE_64 ? "64" : "32"); |
---|
405 | } |
---|
406 | |
---|
407 | if (bar & PREFETCHABLE) |
---|
408 | printf(" prefetchable"); |
---|
409 | |
---|
410 | putchar('\n'); |
---|
411 | return(rtot); |
---|
412 | } |
---|
413 | |
---|
414 | void |
---|
415 | dumpRawCfg(long interface,long bus,long device,long func,char *range, |
---|
416 | char* varname) |
---|
417 | { |
---|
418 | int gotone; |
---|
419 | long regno; |
---|
420 | ulong value; |
---|
421 | |
---|
422 | value = 0; |
---|
423 | gotone = 0; |
---|
424 | for(regno=0;regno<64;regno++) { |
---|
425 | if (inRange(range,regno)) { |
---|
426 | value = pciCfgRead(interface,bus,device,func,regno); |
---|
427 | printf("Cfg reg #%02ld: 0x%08lx\n",regno,value); |
---|
428 | gotone = 1; |
---|
429 | } |
---|
430 | } |
---|
431 | if ((varname) && (gotone)) |
---|
432 | shell_sprintf(varname,"0x%08lx",value); |
---|
433 | } |
---|
434 | |
---|
435 | void |
---|
436 | dumpConfig(long interface,long bus,long device,long func) |
---|
437 | { |
---|
438 | int i; |
---|
439 | char *multifunc, *type; |
---|
440 | ulong hdrtype, values[16]; |
---|
441 | |
---|
442 | for(i=0;i<16;i++) |
---|
443 | values[i] = pciCfgRead(interface,bus,device,func,i); |
---|
444 | |
---|
445 | hdrtype = values[3] & HDR_MASK; |
---|
446 | |
---|
447 | if (hdrtype & HDR_MULTIFUNC) { |
---|
448 | multifunc = "multi-function "; |
---|
449 | hdrtype &= ~HDR_MULTIFUNC; |
---|
450 | } |
---|
451 | else { |
---|
452 | multifunc = ""; |
---|
453 | } |
---|
454 | |
---|
455 | switch(hdrtype) { |
---|
456 | case HDR_PCI2PCI: |
---|
457 | type = "PCI-to-PCI"; |
---|
458 | break; |
---|
459 | case HDR_CARDBUS: |
---|
460 | type = "CardBus"; |
---|
461 | break; |
---|
462 | case HDR_STANDARD: |
---|
463 | type = "Standard"; |
---|
464 | break; |
---|
465 | default: |
---|
466 | printf("dumpConfig(): hdrtype 0x%08lx not supported\n",hdrtype); |
---|
467 | return; |
---|
468 | } |
---|
469 | printf("%s %sconfig...\n",type,multifunc); |
---|
470 | |
---|
471 | printf("00 DevId/VendorId: 0x%04lx/%04lx\n", |
---|
472 | (values[0] & 0xffff0000) >> 16,values[0] & 0xffff); |
---|
473 | |
---|
474 | printf("01 Status/Command: 0x%04lx/%04lx\n", |
---|
475 | (values[1] & 0xffff0000) >> 16,values[1] & 0xffff); |
---|
476 | |
---|
477 | printf("02 ClassCode/RevId: 0x%06lx/%02lx\n", |
---|
478 | (values[2] & 0xffffff00) >> 8,values[2] & 0xff); |
---|
479 | |
---|
480 | |
---|
481 | printf("03 BIST/HdrType/LatencyTmr/CacheLnSz: 0x%02lx/%02lx/%02lx/%02lx\n", |
---|
482 | (values[3] & 0xff000000) >> 24, (values[3] & 0xff0000) >> 16, |
---|
483 | (values[3] & 0xff00) >> 8,values[3] & 0xff); |
---|
484 | |
---|
485 | if (showBar(0,interface,bus,device,func) == 1) |
---|
486 | showBar(1,interface,bus,device,func); |
---|
487 | |
---|
488 | if (hdrtype == HDR_STANDARD) { |
---|
489 | if (showBar(2,interface,bus,device,func) == 1) |
---|
490 | showBar(3,interface,bus,device,func); |
---|
491 | if (showBar(4,interface,bus,device,func) == 1) |
---|
492 | showBar(5,interface,bus,device,func); |
---|
493 | |
---|
494 | printf("10 Cardbus CIS Ptr: 0x%08lx\n",values[10]); |
---|
495 | printf("11 SubSysId/SubVendorId: 0x%04lx/%04lx\n", |
---|
496 | (values[11] & 0xffff0000) >> 16,values[11] & 0xffff); |
---|
497 | printf("12 Expansion ROM BaseAddr: 0x%08lx\n",values[12]); |
---|
498 | } |
---|
499 | else if (hdrtype == HDR_PCI2PCI) { |
---|
500 | printf("06 Secondary Latency Tmr: 0x%02lx\n", |
---|
501 | (values[6] & 0xff000000) >> 24); |
---|
502 | printf("06 BusNum Subordinate/Secondary/Primary: 0x%02lx/%02lx/%02lx\n", |
---|
503 | (values[6] & 0xff0000) >> 16, |
---|
504 | (values[6] & 0xff00) >> 8,values[6] & 0xff); |
---|
505 | |
---|
506 | printf("07 Secondary Status: 0x%04lx\n", |
---|
507 | (values[7] & 0xffff0000) >> 16); |
---|
508 | printf("07 IO Limit/Base: 0x%02lx/%02lx\n", |
---|
509 | (values[7] & 0xff00) >> 8,(values[7] & 0xff)); |
---|
510 | |
---|
511 | printf("08 Memory Limit/Base: 0x%04lx/%04lx\n", |
---|
512 | (values[8] & 0xffff0000) >> 16,values[8] & 0xffff); |
---|
513 | |
---|
514 | printf("09 Prefetchable Memory Limit/Base: 0x%04lx/%04lx\n", |
---|
515 | (values[9] & 0xffff0000) >> 16,values[9] & 0xffff); |
---|
516 | |
---|
517 | printf("10 Prefetchable Base Upper 32 bits: 0x%08lx\n",values[10]); |
---|
518 | printf("11 Prefetchable Limit Upper 32 bits: 0x%08lx\n",values[11]); |
---|
519 | |
---|
520 | printf("12 IO Upper 16 Bits Limit/Base: 0x%04lx/%04lx\n", |
---|
521 | (values[12] & 0xffff0000) >> 16,values[12] & 0xffff); |
---|
522 | } |
---|
523 | |
---|
524 | printf("13 Capabilities Ptr: 0x%02lx\n",values[13] & 0xff); |
---|
525 | |
---|
526 | if (hdrtype == HDR_STANDARD) { |
---|
527 | printf("15 MaxLat/MinGnt: 0x%02lx/%02lx\n", |
---|
528 | (values[15] & 0xff000000) >> 24, (values[15] & 0xff0000) >> 16); |
---|
529 | } |
---|
530 | else { |
---|
531 | printf("14 Expansion ROM BaseAddr: 0x%08lx\n", |
---|
532 | values[14]); |
---|
533 | printf("15 BridgeControl: 0x%04lx\n", |
---|
534 | (values[15] & 0xffff0000) >> 16); |
---|
535 | } |
---|
536 | |
---|
537 | printf("15 Interrupt Pin/Line: 0x%02lx/%02lx\n", |
---|
538 | (values[15] & 0xff00) >> 8, values[15] & 0xff); |
---|
539 | } |
---|
540 | |
---|
541 | char *PciHelp[] = { |
---|
542 | "PCI Config Interface", |
---|
543 | "-[b:d:f:i:v] {operation} [args]", |
---|
544 | #if INCLUDE_VERBOSEHELP |
---|
545 | "Options:", |
---|
546 | " -b{###} bus #", |
---|
547 | " -d{###} device #", |
---|
548 | " -f{###} function #", |
---|
549 | " -i{###} interface #", |
---|
550 | " -v verbose", |
---|
551 | "Operations:", |
---|
552 | " scan, enum, bist, show, size {bar#}", |
---|
553 | " crd [reg#] [varname], cwr {reg#} {value}", |
---|
554 | "Note:", |
---|
555 | " bus, device, function & interface default to zero", |
---|
556 | #endif |
---|
557 | 0 |
---|
558 | }; |
---|
559 | |
---|
560 | /* PciCmd(): |
---|
561 | * General purpose command to provide access to the config portion of |
---|
562 | * a PCI interface. |
---|
563 | * |
---|
564 | * Notice that there is reference to an "interface number" as well as a |
---|
565 | * "bus number". In most systems, there will be one host-to-pci interface. |
---|
566 | * and one pci bus. Some targets will have more than one host-to-pci |
---|
567 | * interface (galileo 64260A, for example, has 2 distinct host-to-PCI |
---|
568 | * interface). Some targets will have more than one bus (depends on whether |
---|
569 | * or not there is a pci-to-pci bridge hanging off the bus). |
---|
570 | * |
---|
571 | */ |
---|
572 | int |
---|
573 | PciCmd(int argc, char *argv[]) |
---|
574 | { |
---|
575 | ulong value, bar; |
---|
576 | long bus, device, interface, regno, func; |
---|
577 | int enumerate, opt; |
---|
578 | |
---|
579 | bus = 0; |
---|
580 | func = 0; |
---|
581 | device = 0; |
---|
582 | enumerate = 0; |
---|
583 | interface = 0; |
---|
584 | pciVerbose = 0; |
---|
585 | while ((opt=getopt(argc,argv,"b:d:f:i:v")) != -1) { |
---|
586 | switch(opt) { |
---|
587 | case 'b': |
---|
588 | bus = strtol(optarg,0,0); |
---|
589 | break; |
---|
590 | case 'd': |
---|
591 | device = strtol(optarg,0,0); |
---|
592 | break; |
---|
593 | case 'f': |
---|
594 | func = strtol(optarg,0,0); |
---|
595 | break; |
---|
596 | case 'i': /* Most systems will only have 1 interface */ |
---|
597 | interface = strtol(optarg,0,0); |
---|
598 | break; |
---|
599 | case 'v': |
---|
600 | pciVerbose = 1; |
---|
601 | break; |
---|
602 | default: |
---|
603 | return(CMD_FAILURE); |
---|
604 | } |
---|
605 | } |
---|
606 | |
---|
607 | if (argc < optind+1) |
---|
608 | return(CMD_PARAM_ERROR); |
---|
609 | |
---|
610 | /* The "scan" and "enum" commands are very similar. They both use |
---|
611 | * the pciscan() function. |
---|
612 | * |
---|
613 | * Scan: look at the devices on the specified bus. |
---|
614 | * Enum: a recursive scan... start with bus 0 and attempt to query |
---|
615 | * all devices on all busses, making the necessary bus-number assignments |
---|
616 | * along the way. |
---|
617 | */ |
---|
618 | |
---|
619 | /* For scan, the device number is ignored, all devices on a particular |
---|
620 | * interface/bus are checked. If ths bus number is something other than |
---|
621 | * zero, then this function assumes that the appropriate pci-to-pci |
---|
622 | * bridge device has already had its bus numbers assigned. |
---|
623 | */ |
---|
624 | if (!strcmp(argv[optind],"scan")) { |
---|
625 | if (argc != optind+1) |
---|
626 | return(CMD_PARAM_ERROR); |
---|
627 | |
---|
628 | pciscan(interface,bus,func,1,0); |
---|
629 | return(CMD_SUCCESS); |
---|
630 | } |
---|
631 | |
---|
632 | /* For enum, we start with bus 0, and attempt to enumerate all busses... |
---|
633 | */ |
---|
634 | if (!strcmp(argv[optind],"enum")) { |
---|
635 | if (argc != optind+1) |
---|
636 | return(CMD_PARAM_ERROR); |
---|
637 | |
---|
638 | pciscan(interface,0,func,1,1); |
---|
639 | return(CMD_SUCCESS); |
---|
640 | } |
---|
641 | |
---|
642 | if (!strcmp(argv[optind],"size")) { /* See pg 204 of PCI2.2 spec */ |
---|
643 | int barnum; |
---|
644 | ulong implemented, sizehi, sizelo; |
---|
645 | |
---|
646 | if (argc != optind+2) |
---|
647 | return(CMD_PARAM_ERROR); |
---|
648 | |
---|
649 | /* The argument to size is the BAR #. The value can be a single |
---|
650 | * digit or a range specification... |
---|
651 | */ |
---|
652 | printf(" Bar Type Value Size\n"); |
---|
653 | for(barnum=0;barnum<6;barnum++) { |
---|
654 | setenv("PCISIZE",0); |
---|
655 | if (inRange(argv[optind+1],barnum)) { |
---|
656 | /* Disable decoding through the command register: |
---|
657 | * See section 6.2.2, pg 193. |
---|
658 | */ |
---|
659 | value = pciCfgRead(interface,bus,device,func,1); |
---|
660 | pciCfgWrite(interface,bus,device,0,1, |
---|
661 | value & ~(IO_SPACE | MEMORY_SPACE)); |
---|
662 | |
---|
663 | bar = pciCfgRead(interface,bus,device,func,barnum+4); |
---|
664 | implemented = getBarInfo(interface,bus,device,func, |
---|
665 | barnum,&sizehi,&sizelo); |
---|
666 | |
---|
667 | printf(" %d ",barnum); |
---|
668 | |
---|
669 | if (implemented) { |
---|
670 | shell_sprintf("PCISIZE","0x%08lx",bar); |
---|
671 | printf("%s 0x%08lx ", |
---|
672 | implemented & BASEADDRESS_IO ? "io " : "mem", bar); |
---|
673 | if (implemented & TYPE_64) |
---|
674 | printf("0x%08lx%08lx",sizehi,sizelo); |
---|
675 | else |
---|
676 | printf("0x%08lx",sizelo); |
---|
677 | if (implemented & PREFETCHABLE) |
---|
678 | printf(" (prefetchable)"); |
---|
679 | putchar('\n'); |
---|
680 | } |
---|
681 | else |
---|
682 | printf("not implemented\n"); |
---|
683 | } |
---|
684 | } |
---|
685 | } |
---|
686 | else if (!strcmp(argv[optind],"bist")) { |
---|
687 | if (argc != optind+1) |
---|
688 | return(CMD_PARAM_ERROR); |
---|
689 | |
---|
690 | value = pciCfgRead(interface,bus,device,func,3); |
---|
691 | |
---|
692 | if (value & BIST_CAPABLE) { |
---|
693 | /* Set the BIST_START bit to begin the test, then wait for |
---|
694 | * the BIST_START bit to clear as an indication that the |
---|
695 | * test has completed. |
---|
696 | */ |
---|
697 | pciCfgWrite(interface,bus,device,func,3,value | BIST_START); |
---|
698 | while(1) { |
---|
699 | value = pciCfgRead(interface,bus,device,func,3); |
---|
700 | if ((value & BIST_START) != BIST_START) |
---|
701 | break; |
---|
702 | } |
---|
703 | if ((value & BIST_COMPCODE_MASK) != 0) |
---|
704 | printf("BIST failed: 0x%lx\n",value & BIST_COMPCODE_MASK); |
---|
705 | else |
---|
706 | printf("BIST passed\n"); |
---|
707 | } |
---|
708 | else { |
---|
709 | printf("Device %ld is not BIST-capable\n",device); |
---|
710 | } |
---|
711 | } |
---|
712 | else if (!strcmp(argv[optind],"crd")) { |
---|
713 | char *varname = (char *)0; |
---|
714 | |
---|
715 | if (argc == optind+3) { /* varname specified ? */ |
---|
716 | varname = argv[optind+2]; |
---|
717 | argc--; |
---|
718 | } |
---|
719 | |
---|
720 | if (argc == optind+2) { |
---|
721 | dumpRawCfg(interface,bus,device,func,argv[optind+1],varname); |
---|
722 | } |
---|
723 | else if (argc == optind+1) { |
---|
724 | dumpConfig(interface,bus,device,func); |
---|
725 | } |
---|
726 | else |
---|
727 | return(CMD_PARAM_ERROR); |
---|
728 | } |
---|
729 | else if (!strcmp(argv[optind],"cwr")) { |
---|
730 | if (argc != optind+3) |
---|
731 | return(CMD_PARAM_ERROR); |
---|
732 | |
---|
733 | regno = strtol(argv[optind+1],0,0); |
---|
734 | value = strtol(argv[optind+2],0,0); |
---|
735 | pciCfgWrite(interface,bus,device,func,regno,value); |
---|
736 | } |
---|
737 | else if (!strcmp(argv[optind],"init")) { |
---|
738 | pciCtrl(interface,PCICTRL_INIT,0,0); |
---|
739 | } |
---|
740 | else if (!strcmp(argv[optind],"show")) { |
---|
741 | pciShow(interface); |
---|
742 | } |
---|
743 | else |
---|
744 | return(CMD_PARAM_ERROR); |
---|
745 | return(CMD_SUCCESS); |
---|
746 | } |
---|
747 | #endif |
---|