pci.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853
  1. /*
  2. * PCI support code.
  3. * Needs a massive rewrite.
  4. */
  5. #include "u.h"
  6. #include "../port/lib.h"
  7. #include "mem.h"
  8. #include "dat.h"
  9. #include "fns.h"
  10. #include "io.h"
  11. #define DBG if(0) pcilog
  12. typedef struct Pci Pci;
  13. struct
  14. {
  15. char output[PCICONSSIZE];
  16. int ptr;
  17. }PCICONS;
  18. int
  19. pcilog(char *fmt, ...)
  20. {
  21. int n;
  22. va_list arg;
  23. char buf[PRINTSIZE];
  24. va_start(arg, fmt);
  25. n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf;
  26. va_end(arg);
  27. memmove(PCICONS.output+PCICONS.ptr, buf, n);
  28. PCICONS.ptr += n;
  29. return n;
  30. }
  31. enum
  32. {
  33. MaxFNO = 7,
  34. MaxUBN = 255,
  35. };
  36. enum
  37. { /* command register */
  38. IOen = (1<<0),
  39. MEMen = (1<<1),
  40. MASen = (1<<2),
  41. MemWrInv = (1<<4),
  42. PErrEn = (1<<6),
  43. SErrEn = (1<<8),
  44. };
  45. typedef struct {
  46. ulong cap;
  47. ulong ctl;
  48. } Capctl;
  49. typedef struct {
  50. Capctl dev;
  51. Capctl link;
  52. Capctl slot;
  53. } Devlinkslot;
  54. /* capability list id 0x10 is pci-e */
  55. struct Pci {
  56. /* pci-compatible config */
  57. /* what io.h calls type 0 & type 1 pre-defined header */
  58. ulong id;
  59. ulong cs;
  60. ulong revclass;
  61. ulong misc; /* cache line size, latency timer, header type, bist */
  62. ulong bar[2]; /* always 0 on tegra 2 */
  63. /* types 1 & 2 pre-defined header */
  64. ulong bus;
  65. ulong ioaddrs;
  66. ulong memaddrs;
  67. ulong prefmem;
  68. ulong prefbasehi;
  69. ulong preflimhi;
  70. /* type 2 pre-defined header only */
  71. ulong ioaddrhi;
  72. ulong cfgcapoff; /* offset in cfg. space to cap. list (0x40) */
  73. ulong rom;
  74. ulong intr; /* PciINT[LP] */
  75. /* subsystem capability regs */
  76. ulong subsysid;
  77. ulong subsyscap;
  78. /* */
  79. Capctl pwrmgmt;
  80. /* msi */
  81. ulong msictlcap;
  82. ulong msimsgaddr[2]; /* little-endian */
  83. ulong msimsgdata;
  84. /* pci-e cap. */
  85. uchar _pad0[0x80-0x60];
  86. ulong pciecap;
  87. Devlinkslot port0;
  88. ulong rootctl;
  89. ulong rootsts;
  90. Devlinkslot port1;
  91. /* 0xbc */
  92. };
  93. enum {
  94. /* offsets from soc.pci */
  95. Port0 = 0,
  96. Port1 = 0x1000,
  97. Pads = 0x3000,
  98. Afi = 0x3800,
  99. Aficfg = Afi + 0xac,
  100. Cfgspace = 0x4000,
  101. Ecfgspace = 0x104000,
  102. /* cs bits */
  103. Iospace = 1<<0,
  104. Memspace = 1<<1,
  105. Busmaster = 1<<2,
  106. /* Aficfg bits */
  107. Fpcion = 1<<0,
  108. };
  109. struct Pcictlr {
  110. union {
  111. uchar _padpci[0x1000];
  112. Pci;
  113. } ports[2];
  114. uchar _padpads[0x1000];
  115. uchar pads[0x800];
  116. uchar afi[0x800];
  117. ulong cfg[0x1000];
  118. ulong extcfg[0x1000];
  119. };
  120. static Lock pcicfglock;
  121. static Lock pcicfginitlock;
  122. static int pcicfgmode = -1;
  123. static int pcimaxbno = 1; /* was 7; only 2 pci buses; touching 3rd hangs */
  124. static int pcimaxdno;
  125. static Pcidev* pciroot;
  126. static Pcidev* pcilist;
  127. static Pcidev* pcitail;
  128. static int pcicfgrw8(int, int, int, int);
  129. static int pcicfgrw16(int, int, int, int);
  130. static int pcicfgrw32(int, int, int, int);
  131. static char* bustypes[] = {
  132. "CBUSI",
  133. "CBUSII",
  134. "EISA",
  135. "FUTURE",
  136. "INTERN",
  137. "ISA",
  138. "MBI",
  139. "MBII",
  140. "MCA",
  141. "MPI",
  142. "MPSA",
  143. "NUBUS",
  144. "PCI",
  145. "PCMCIA",
  146. "TC",
  147. "VL",
  148. "VME",
  149. "XPRESS",
  150. };
  151. static int
  152. tbdffmt(Fmt* fmt)
  153. {
  154. char *p;
  155. int l, r;
  156. uint type, tbdf;
  157. if((p = malloc(READSTR)) == nil)
  158. return fmtstrcpy(fmt, "(tbdfconv)");
  159. switch(fmt->r){
  160. case 'T':
  161. tbdf = va_arg(fmt->args, int);
  162. if(tbdf == BUSUNKNOWN)
  163. snprint(p, READSTR, "unknown");
  164. else{
  165. type = BUSTYPE(tbdf);
  166. if(type < nelem(bustypes))
  167. l = snprint(p, READSTR, bustypes[type]);
  168. else
  169. l = snprint(p, READSTR, "%d", type);
  170. snprint(p+l, READSTR-l, ".%d.%d.%d",
  171. BUSBNO(tbdf), BUSDNO(tbdf), BUSFNO(tbdf));
  172. }
  173. break;
  174. default:
  175. snprint(p, READSTR, "(tbdfconv)");
  176. break;
  177. }
  178. r = fmtstrcpy(fmt, p);
  179. free(p);
  180. return r;
  181. }
  182. ulong
  183. pcibarsize(Pcidev *p, int rno)
  184. {
  185. ulong v, size;
  186. v = pcicfgrw32(p->tbdf, rno, 0, 1);
  187. pcicfgrw32(p->tbdf, rno, 0xFFFFFFF0, 0);
  188. size = pcicfgrw32(p->tbdf, rno, 0, 1);
  189. if(v & 1)
  190. size |= 0xFFFF0000;
  191. pcicfgrw32(p->tbdf, rno, v, 0);
  192. return -(size & ~0x0F);
  193. }
  194. static int
  195. pcilscan(int bno, Pcidev** list)
  196. {
  197. Pcidev *p, *head, *tail;
  198. int dno, fno, i, hdt, l, maxfno, maxubn, rno, sbn, tbdf, ubn;
  199. maxubn = bno;
  200. head = nil;
  201. tail = nil;
  202. for(dno = 0; dno <= pcimaxdno; dno++){
  203. maxfno = 0;
  204. for(fno = 0; fno <= maxfno; fno++){
  205. /*
  206. * For this possible device, form the
  207. * bus+device+function triplet needed to address it
  208. * and try to read the vendor and device ID.
  209. * If successful, allocate a device struct and
  210. * start to fill it in with some useful information
  211. * from the device's configuration space.
  212. */
  213. tbdf = MKBUS(BusPCI, bno, dno, fno);
  214. l = pcicfgrw32(tbdf, PciVID, 0, 1);
  215. if(l == 0xFFFFFFFF || l == 0)
  216. continue;
  217. p = malloc(sizeof(*p));
  218. if(p == nil)
  219. panic("pcilscan: no memory");
  220. p->tbdf = tbdf;
  221. p->vid = l;
  222. p->did = l>>16;
  223. if(pcilist != nil)
  224. pcitail->list = p;
  225. else
  226. pcilist = p;
  227. pcitail = p;
  228. p->pcr = pcicfgr16(p, PciPCR);
  229. p->rid = pcicfgr8(p, PciRID);
  230. p->ccrp = pcicfgr8(p, PciCCRp);
  231. p->ccru = pcicfgr8(p, PciCCRu);
  232. p->ccrb = pcicfgr8(p, PciCCRb);
  233. p->cls = pcicfgr8(p, PciCLS);
  234. p->ltr = pcicfgr8(p, PciLTR);
  235. p->intl = pcicfgr8(p, PciINTL);
  236. /*
  237. * If the device is a multi-function device adjust the
  238. * loop count so all possible functions are checked.
  239. */
  240. hdt = pcicfgr8(p, PciHDT);
  241. if(hdt & 0x80)
  242. maxfno = MaxFNO;
  243. /*
  244. * If appropriate, read the base address registers
  245. * and work out the sizes.
  246. */
  247. switch(p->ccrb) {
  248. case 0x03: /* display controller */
  249. /* fall through */
  250. case 0x01: /* mass storage controller */
  251. case 0x02: /* network controller */
  252. case 0x04: /* multimedia device */
  253. case 0x07: /* simple comm. controllers */
  254. case 0x08: /* base system peripherals */
  255. case 0x09: /* input devices */
  256. case 0x0A: /* docking stations */
  257. case 0x0B: /* processors */
  258. case 0x0C: /* serial bus controllers */
  259. if((hdt & 0x7F) != 0)
  260. break;
  261. rno = PciBAR0 - 4;
  262. for(i = 0; i < nelem(p->mem); i++) {
  263. rno += 4;
  264. p->mem[i].bar = pcicfgr32(p, rno);
  265. p->mem[i].size = pcibarsize(p, rno);
  266. }
  267. break;
  268. case 0x00:
  269. case 0x05: /* memory controller */
  270. case 0x06: /* bridge device */
  271. default:
  272. break;
  273. }
  274. if(head != nil)
  275. tail->link = p;
  276. else
  277. head = p;
  278. tail = p;
  279. }
  280. }
  281. *list = head;
  282. for(p = head; p != nil; p = p->link){
  283. /*
  284. * Find PCI-PCI bridges and recursively descend the tree.
  285. */
  286. if(p->ccrb != 0x06 || p->ccru != 0x04)
  287. continue;
  288. /*
  289. * If the secondary or subordinate bus number is not
  290. * initialised try to do what the PCI BIOS should have
  291. * done and fill in the numbers as the tree is descended.
  292. * On the way down the subordinate bus number is set to
  293. * the maximum as it's not known how many buses are behind
  294. * this one; the final value is set on the way back up.
  295. */
  296. sbn = pcicfgr8(p, PciSBN);
  297. ubn = pcicfgr8(p, PciUBN);
  298. if(sbn == 0 || ubn == 0) {
  299. sbn = maxubn+1;
  300. /*
  301. * Make sure memory, I/O and master enables are
  302. * off, set the primary, secondary and subordinate
  303. * bus numbers and clear the secondary status before
  304. * attempting to scan the secondary bus.
  305. *
  306. * Initialisation of the bridge should be done here.
  307. */
  308. pcicfgw32(p, PciPCR, 0xFFFF0000);
  309. l = (MaxUBN<<16)|(sbn<<8)|bno;
  310. pcicfgw32(p, PciPBN, l);
  311. pcicfgw16(p, PciSPSR, 0xFFFF);
  312. maxubn = pcilscan(sbn, &p->bridge);
  313. l = (maxubn<<16)|(sbn<<8)|bno;
  314. pcicfgw32(p, PciPBN, l);
  315. }
  316. else {
  317. if(ubn > maxubn)
  318. maxubn = ubn;
  319. pcilscan(sbn, &p->bridge);
  320. }
  321. }
  322. return maxubn;
  323. }
  324. extern void rtl8169interrupt(Ureg*, void* arg);
  325. /* not used yet */
  326. static void
  327. pciintr(Ureg *ureg, void *p)
  328. {
  329. rtl8169interrupt(ureg, p); /* HACK */
  330. }
  331. static void
  332. pcicfginit(void)
  333. {
  334. char *p;
  335. Pci *pci = (Pci *)soc.pci;
  336. Pcidev **list;
  337. int bno, n;
  338. lock(&pcicfginitlock);
  339. if(pcicfgmode != -1) {
  340. unlock(&pcicfginitlock);
  341. return;
  342. }
  343. /*
  344. * TrimSlice # pci 0 1
  345. * Scanning PCI devices on bus 0 1
  346. * BusDevFun VendorId DeviceId Device Class Sub-Class
  347. * _____________________________________________________________
  348. * 00.00.00 0x10de 0x0bf0 Bridge device 0x04
  349. * 01.00.00 0x10ec 0x8168 Network controller 0x00
  350. *
  351. * thus pci bus 0 has a bridge with, perhaps, an ide/sata ctlr behind,
  352. * and pci bus 1 has the realtek 8169 on it:
  353. *
  354. * TrimSlice # pci 1 long
  355. * Scanning PCI devices on bus 1
  356. *
  357. * Found PCI device 01.00.00:
  358. * vendor ID = 0x10ec
  359. * device ID = 0x8168
  360. * command register = 0x0007
  361. * status register = 0x0010
  362. * revision ID = 0x03
  363. * class code = 0x02 (Network controller)
  364. * sub class code = 0x00
  365. * programming interface = 0x00
  366. * cache line = 0x08
  367. * base address 0 = 0x80400001 config
  368. * base address 1 = 0x00000000 (ext. config)
  369. * base address 2 = 0xa000000c "downstream"
  370. * base address 3 = 0x00000000 (prefetchable)
  371. * base address 4 = 0xa000400c not "
  372. * base address 5 = 0x00000000 (unused)
  373. */
  374. n = pci->id >> 16;
  375. if (((pci->id & MASK(16)) != Vnvidia || (n != 0xbf0 && n != 0xbf1)) &&
  376. (pci->id & MASK(16)) != Vrealtek) {
  377. print("no pci controller at %#p\n", pci);
  378. unlock(&pcicfginitlock);
  379. return;
  380. }
  381. if (0)
  382. iprint("pci: %#p: nvidia, rev %#ux class %#6.6lux misc %#8.8lux\n",
  383. pci, (uchar)pci->revclass, pci->revclass >> 8,
  384. pci->misc);
  385. pci->cs &= Iospace;
  386. pci->cs |= Memspace | Busmaster;
  387. coherence();
  388. pcicfgmode = 1;
  389. // pcimaxdno = 31;
  390. pcimaxdno = 15; /* for trimslice */
  391. fmtinstall('T', tbdffmt);
  392. if(p = getconf("*pcimaxbno")){
  393. n = strtoul(p, 0, 0);
  394. if(n < pcimaxbno)
  395. pcimaxbno = n;
  396. }
  397. if(p = getconf("*pcimaxdno")){
  398. n = strtoul(p, 0, 0);
  399. if(n < pcimaxdno)
  400. pcimaxdno = n;
  401. }
  402. list = &pciroot;
  403. /* was bno = 0; trimslice needs to start at 1 */
  404. for(bno = 1; bno <= pcimaxbno; bno++) {
  405. bno = pcilscan(bno, list);
  406. while(*list)
  407. list = &(*list)->link;
  408. }
  409. unlock(&pcicfginitlock);
  410. if(getconf("*pcihinv"))
  411. pcihinv(nil);
  412. }
  413. enum {
  414. Afiintrcode = 0xb8,
  415. };
  416. void
  417. pcieintrdone(void) /* dismiss pci-e intr */
  418. {
  419. ulong *afi;
  420. afi = (ulong *)(soc.pci + Afi);
  421. afi[Afiintrcode/sizeof *afi] = 0; /* magic */
  422. coherence();
  423. }
  424. /*
  425. * whole config space for tbdf should be at (return address - rno).
  426. */
  427. static void *
  428. tegracfgaddr(int tbdf, int rno)
  429. {
  430. uintptr addr;
  431. addr = soc.pci + (rno < 256? Cfgspace: Ecfgspace) + BUSBDF(tbdf) + rno;
  432. // if (BUSBNO(tbdf) == 1)
  433. // addr += Port1;
  434. return (void *)addr;
  435. }
  436. static int
  437. pcicfgrw8(int tbdf, int rno, int data, int read)
  438. {
  439. int x;
  440. void *addr;
  441. if(pcicfgmode == -1)
  442. pcicfginit();
  443. x = -1;
  444. if(BUSDNO(tbdf) > pcimaxdno)
  445. return x;
  446. addr = tegracfgaddr(tbdf, rno);
  447. lock(&pcicfglock);
  448. if(read)
  449. x = *(uchar *)addr;
  450. else
  451. *(uchar *)addr = data;
  452. unlock(&pcicfglock);
  453. return x;
  454. }
  455. int
  456. pcicfgr8(Pcidev* pcidev, int rno)
  457. {
  458. return pcicfgrw8(pcidev->tbdf, rno, 0, 1);
  459. }
  460. void
  461. pcicfgw8(Pcidev* pcidev, int rno, int data)
  462. {
  463. pcicfgrw8(pcidev->tbdf, rno, data, 0);
  464. }
  465. static int
  466. pcicfgrw16(int tbdf, int rno, int data, int read)
  467. {
  468. int x;
  469. void *addr;
  470. if(pcicfgmode == -1)
  471. pcicfginit();
  472. x = -1;
  473. if(BUSDNO(tbdf) > pcimaxdno)
  474. return x;
  475. addr = tegracfgaddr(tbdf, rno);
  476. lock(&pcicfglock);
  477. if(read)
  478. x = *(ushort *)addr;
  479. else
  480. *(ushort *)addr = data;
  481. unlock(&pcicfglock);
  482. return x;
  483. }
  484. int
  485. pcicfgr16(Pcidev* pcidev, int rno)
  486. {
  487. return pcicfgrw16(pcidev->tbdf, rno, 0, 1);
  488. }
  489. void
  490. pcicfgw16(Pcidev* pcidev, int rno, int data)
  491. {
  492. pcicfgrw16(pcidev->tbdf, rno, data, 0);
  493. }
  494. static int
  495. pcicfgrw32(int tbdf, int rno, int data, int read)
  496. {
  497. int x;
  498. vlong v;
  499. void *addr;
  500. if(pcicfgmode == -1)
  501. pcicfginit();
  502. x = -1;
  503. if(BUSDNO(tbdf) > pcimaxdno)
  504. return x;
  505. addr = tegracfgaddr(tbdf, rno);
  506. v = probeaddr((uintptr)addr);
  507. if (v < 0)
  508. return -1;
  509. lock(&pcicfglock);
  510. if(read)
  511. x = *(ulong *)addr;
  512. else
  513. *(ulong *)addr = data;
  514. unlock(&pcicfglock);
  515. return x;
  516. }
  517. int
  518. pcicfgr32(Pcidev* pcidev, int rno)
  519. {
  520. return pcicfgrw32(pcidev->tbdf, rno, 0, 1);
  521. }
  522. void
  523. pcicfgw32(Pcidev* pcidev, int rno, int data)
  524. {
  525. pcicfgrw32(pcidev->tbdf, rno, data, 0);
  526. }
  527. Pcidev*
  528. pcimatch(Pcidev* prev, int vid, int did)
  529. {
  530. if(pcicfgmode == -1)
  531. pcicfginit();
  532. if(prev == nil)
  533. prev = pcilist;
  534. else
  535. prev = prev->list;
  536. while(prev != nil){
  537. if((vid == 0 || prev->vid == vid)
  538. && (did == 0 || prev->did == did))
  539. break;
  540. prev = prev->list;
  541. }
  542. return prev;
  543. }
  544. Pcidev*
  545. pcimatchtbdf(int tbdf)
  546. {
  547. Pcidev *pcidev;
  548. if(pcicfgmode == -1)
  549. pcicfginit();
  550. for(pcidev = pcilist; pcidev != nil; pcidev = pcidev->list) {
  551. if(pcidev->tbdf == tbdf)
  552. break;
  553. }
  554. return pcidev;
  555. }
  556. static void
  557. pcilhinv(Pcidev* p)
  558. {
  559. int i;
  560. Pcidev *t;
  561. if(p == nil) {
  562. putstrn(PCICONS.output, PCICONS.ptr);
  563. p = pciroot;
  564. print("bus dev type vid did intl memory\n");
  565. }
  566. for(t = p; t != nil; t = t->link) {
  567. print("%d %2d/%d %.2ux %.2ux %.2ux %.4ux %.4ux %3d ",
  568. BUSBNO(t->tbdf), BUSDNO(t->tbdf), BUSFNO(t->tbdf),
  569. t->ccrb, t->ccru, t->ccrp, t->vid, t->did, t->intl);
  570. for(i = 0; i < nelem(p->mem); i++) {
  571. if(t->mem[i].size == 0)
  572. continue;
  573. print("%d:%.8lux %d ", i,
  574. t->mem[i].bar, t->mem[i].size);
  575. }
  576. if(t->bridge)
  577. print("->%d", BUSBNO(t->bridge->tbdf));
  578. print("\n");
  579. }
  580. while(p != nil) {
  581. if(p->bridge != nil)
  582. pcilhinv(p->bridge);
  583. p = p->link;
  584. }
  585. }
  586. void
  587. pcihinv(Pcidev* p)
  588. {
  589. if(pcicfgmode == -1)
  590. pcicfginit();
  591. lock(&pcicfginitlock);
  592. pcilhinv(p);
  593. unlock(&pcicfginitlock);
  594. }
  595. void
  596. pcireset(void)
  597. {
  598. Pcidev *p;
  599. if(pcicfgmode == -1)
  600. pcicfginit();
  601. for(p = pcilist; p != nil; p = p->list) {
  602. /* don't mess with the bridges */
  603. if(p->ccrb == 0x06)
  604. continue;
  605. pciclrbme(p);
  606. }
  607. }
  608. void
  609. pcisetioe(Pcidev* p)
  610. {
  611. p->pcr |= IOen;
  612. pcicfgw16(p, PciPCR, p->pcr);
  613. }
  614. void
  615. pciclrioe(Pcidev* p)
  616. {
  617. p->pcr &= ~IOen;
  618. pcicfgw16(p, PciPCR, p->pcr);
  619. }
  620. void
  621. pcisetbme(Pcidev* p)
  622. {
  623. p->pcr |= MASen;
  624. pcicfgw16(p, PciPCR, p->pcr);
  625. }
  626. void
  627. pciclrbme(Pcidev* p)
  628. {
  629. p->pcr &= ~MASen;
  630. pcicfgw16(p, PciPCR, p->pcr);
  631. }
  632. void
  633. pcisetmwi(Pcidev* p)
  634. {
  635. p->pcr |= MemWrInv;
  636. pcicfgw16(p, PciPCR, p->pcr);
  637. }
  638. void
  639. pciclrmwi(Pcidev* p)
  640. {
  641. p->pcr &= ~MemWrInv;
  642. pcicfgw16(p, PciPCR, p->pcr);
  643. }
  644. static int
  645. pcigetpmrb(Pcidev* p)
  646. {
  647. int ptr;
  648. if(p->pmrb != 0)
  649. return p->pmrb;
  650. p->pmrb = -1;
  651. /*
  652. * If there are no extended capabilities implemented,
  653. * (bit 4 in the status register) assume there's no standard
  654. * power management method.
  655. * Find the capabilities pointer based on PCI header type.
  656. */
  657. if(!(pcicfgr16(p, PciPSR) & 0x0010))
  658. return -1;
  659. switch(pcicfgr8(p, PciHDT)){
  660. default:
  661. return -1;
  662. case 0: /* all other */
  663. case 1: /* PCI to PCI bridge */
  664. ptr = 0x34;
  665. break;
  666. case 2: /* CardBus bridge */
  667. ptr = 0x14;
  668. break;
  669. }
  670. ptr = pcicfgr32(p, ptr);
  671. while(ptr != 0){
  672. /*
  673. * Check for validity.
  674. * Can't be in standard header and must be double
  675. * word aligned.
  676. */
  677. if(ptr < 0x40 || (ptr & ~0xFC))
  678. return -1;
  679. if(pcicfgr8(p, ptr) == 0x01){
  680. p->pmrb = ptr;
  681. return ptr;
  682. }
  683. ptr = pcicfgr8(p, ptr+1);
  684. }
  685. return -1;
  686. }
  687. int
  688. pcigetpms(Pcidev* p)
  689. {
  690. int pmcsr, ptr;
  691. if((ptr = pcigetpmrb(p)) == -1)
  692. return -1;
  693. /*
  694. * Power Management Register Block:
  695. * offset 0: Capability ID
  696. * 1: next item pointer
  697. * 2: capabilities
  698. * 4: control/status
  699. * 6: bridge support extensions
  700. * 7: data
  701. */
  702. pmcsr = pcicfgr16(p, ptr+4);
  703. return pmcsr & 0x0003;
  704. }
  705. int
  706. pcisetpms(Pcidev* p, int state)
  707. {
  708. int ostate, pmc, pmcsr, ptr;
  709. if((ptr = pcigetpmrb(p)) == -1)
  710. return -1;
  711. pmc = pcicfgr16(p, ptr+2);
  712. pmcsr = pcicfgr16(p, ptr+4);
  713. ostate = pmcsr & 0x0003;
  714. pmcsr &= ~0x0003;
  715. switch(state){
  716. default:
  717. return -1;
  718. case 0:
  719. break;
  720. case 1:
  721. if(!(pmc & 0x0200))
  722. return -1;
  723. break;
  724. case 2:
  725. if(!(pmc & 0x0400))
  726. return -1;
  727. break;
  728. case 3:
  729. break;
  730. }
  731. pmcsr |= state;
  732. pcicfgw16(p, ptr+4, pmcsr);
  733. return ostate;
  734. }