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