1*5c47fe09SDavid du Colombier /*
2*5c47fe09SDavid du Colombier * from 9front ../port/usbxhci.c
3*5c47fe09SDavid du Colombier */
4*5c47fe09SDavid du Colombier
5*5c47fe09SDavid du Colombier #include "u.h"
6*5c47fe09SDavid du Colombier #include "../port/lib.h"
7*5c47fe09SDavid du Colombier #include "mem.h"
8*5c47fe09SDavid du Colombier #include "dat.h"
9*5c47fe09SDavid du Colombier #include "fns.h"
10*5c47fe09SDavid du Colombier #include "io.h"
11*5c47fe09SDavid du Colombier #include "pci.h"
12*5c47fe09SDavid du Colombier #include "../port/error.h"
13*5c47fe09SDavid du Colombier #include "usb.h"
14*5c47fe09SDavid du Colombier
15*5c47fe09SDavid du Colombier extern void dmaflush(int, void*, ulong);
16*5c47fe09SDavid du Colombier
17*5c47fe09SDavid du Colombier enum {
18*5c47fe09SDavid du Colombier /* Capability Registers */
19*5c47fe09SDavid du Colombier CAPLENGTH = 0x00/4, // 1
20*5c47fe09SDavid du Colombier HCIVERSION = 0x02/4, // 2
21*5c47fe09SDavid du Colombier HCSPARAMS1 = 0x04/4,
22*5c47fe09SDavid du Colombier HCSPARAMS2 = 0x08/4,
23*5c47fe09SDavid du Colombier HCSPARAMS3 = 0x0C/4,
24*5c47fe09SDavid du Colombier
25*5c47fe09SDavid du Colombier HCCPARAMS = 0x10/4,
26*5c47fe09SDavid du Colombier AC64 = 1<<0,
27*5c47fe09SDavid du Colombier BNC = 1<<1,
28*5c47fe09SDavid du Colombier CSZ = 1<<2,
29*5c47fe09SDavid du Colombier PPC = 1<<3,
30*5c47fe09SDavid du Colombier PIND = 1<<4,
31*5c47fe09SDavid du Colombier LHRC = 1<<5,
32*5c47fe09SDavid du Colombier LTC = 1<<6,
33*5c47fe09SDavid du Colombier NSS = 1<<7,
34*5c47fe09SDavid du Colombier
35*5c47fe09SDavid du Colombier DBOFF = 0x14/4,
36*5c47fe09SDavid du Colombier RTSOFF = 0x18/4,
37*5c47fe09SDavid du Colombier
38*5c47fe09SDavid du Colombier HCCPARAMS2 = 0x1C/4,
39*5c47fe09SDavid du Colombier
40*5c47fe09SDavid du Colombier /* Operational Registers */
41*5c47fe09SDavid du Colombier USBCMD = 0x00/4, /* USB Command Register */
42*5c47fe09SDavid du Colombier RUNSTOP = 1<<0, /* Run/Stop - RW */
43*5c47fe09SDavid du Colombier HCRST = 1<<1, /* Host Controller Reset - RW */
44*5c47fe09SDavid du Colombier INTE = 1<<2, /* Interrupter Enable - RW */
45*5c47fe09SDavid du Colombier HSEE = 1<<3, /* Host System Error Enable - RW */
46*5c47fe09SDavid du Colombier LHCRST = 1<<7, /* Light Host Controller Reset - RO/RW */
47*5c47fe09SDavid du Colombier CSS = 1<<8, /* Controller Save State - RW */
48*5c47fe09SDavid du Colombier CRS = 1<<9, /* Controller Restore State - RW */
49*5c47fe09SDavid du Colombier EWE = 1<<10, /* Enable Wrap Event - RW */
50*5c47fe09SDavid du Colombier EU3S = 1<<11, /* Enable U3 MFINDEX Stop - RW */
51*5c47fe09SDavid du Colombier
52*5c47fe09SDavid du Colombier USBSTS = 0x04/4, /* USB Status Register */
53*5c47fe09SDavid du Colombier HCH = 1<<0, /* HCHalted - RO */
54*5c47fe09SDavid du Colombier HSE = 1<<2, /* Host System Error - RW1C */
55*5c47fe09SDavid du Colombier EINT = 1<<3, /* Event Interrupt - RW1C */
56*5c47fe09SDavid du Colombier PCD = 1<<4, /* Port Change Detect - RW1C */
57*5c47fe09SDavid du Colombier SSS = 1<<8, /* Save State Status - RO */
58*5c47fe09SDavid du Colombier RSS = 1<<9, /* Restore State Status - RO */
59*5c47fe09SDavid du Colombier SRE = 1<<10, /* Save/Restore Error - RW1C */
60*5c47fe09SDavid du Colombier CNR = 1<<11, /* Controller Not Ready - RO */
61*5c47fe09SDavid du Colombier HCE = 1<<12, /* Host Controller Error - RO */
62*5c47fe09SDavid du Colombier
63*5c47fe09SDavid du Colombier PAGESIZE = 0x08/4, /* Page Size - RO */
64*5c47fe09SDavid du Colombier
65*5c47fe09SDavid du Colombier DNCTRL = 0x14/4, /* Device Notification Control Register - RW */
66*5c47fe09SDavid du Colombier
67*5c47fe09SDavid du Colombier CRCR = 0x18/4, /* Command Ring Control Register - RW */
68*5c47fe09SDavid du Colombier RCS = 1<<0, /* Ring Cycle State - RW */
69*5c47fe09SDavid du Colombier CS = 1<<1, /* Command Stop - RW1S */
70*5c47fe09SDavid du Colombier CA = 1<<2, /* Command Abort - RW1S */
71*5c47fe09SDavid du Colombier CRR = 1<<3, /* Command Ring Running - RO */
72*5c47fe09SDavid du Colombier
73*5c47fe09SDavid du Colombier DCBAAP = 0x30/4, // 8
74*5c47fe09SDavid du Colombier
75*5c47fe09SDavid du Colombier CONFIG = 0x38/4, /* Configure Register (MaxSlotEn[7:0]) */
76*5c47fe09SDavid du Colombier
77*5c47fe09SDavid du Colombier /* Port Register Set */
78*5c47fe09SDavid du Colombier PORTSC = 0x00/4, /* Port status and Control Register */
79*5c47fe09SDavid du Colombier CCS = 1<<0, /* Current Connect Status - ROS */
80*5c47fe09SDavid du Colombier PED = 1<<1, /* Port Enable/Disabled - RW1CS */
81*5c47fe09SDavid du Colombier OCA = 1<<3, /* Over-current Active - RO */
82*5c47fe09SDavid du Colombier PR = 1<<4, /* Port Reset - RW1S */
83*5c47fe09SDavid du Colombier PLS = 15<<5, /* Port Link State - RWS */
84*5c47fe09SDavid du Colombier PP = 1<<9, /* Port Power - RWS */
85*5c47fe09SDavid du Colombier PS = 15<<10, /* Port Speed - ROS */
86*5c47fe09SDavid du Colombier PIC = 3<<14, /* Port Indicator Control - RWS */
87*5c47fe09SDavid du Colombier LWS = 1<<16, /* Port Link Write Strobe - RW */
88*5c47fe09SDavid du Colombier CSC = 1<<17, /* Connect Status Change - RW1CS */
89*5c47fe09SDavid du Colombier PEC = 1<<18, /* Port Enabled/Disabled Change - RW1CS */
90*5c47fe09SDavid du Colombier WRC = 1<<19, /* Warm Port Reset Change - RW1CS */
91*5c47fe09SDavid du Colombier OCC = 1<<20, /* Over-current Change - RW1CS */
92*5c47fe09SDavid du Colombier PRC = 1<<21, /* Port Reset Change - RW1CS */
93*5c47fe09SDavid du Colombier PLC = 1<<22, /* Port Link State Change - RW1CS */
94*5c47fe09SDavid du Colombier CEC = 1<<23, /* Port Config Error Change - RW1CS */
95*5c47fe09SDavid du Colombier CAS = 1<<24, /* Cold Attach Status - RO */
96*5c47fe09SDavid du Colombier WCE = 1<<25, /* Wake on Connect Enable - RWS */
97*5c47fe09SDavid du Colombier WDE = 1<<26, /* Wake on Disconnect Enable - RWS */
98*5c47fe09SDavid du Colombier WOE = 1<<27, /* Wake on Over-current Enable - RWS */
99*5c47fe09SDavid du Colombier DR = 1<<30, /* Device Removable - RO */
100*5c47fe09SDavid du Colombier WPR = 1<<31, /* Warm Port Reset - RW1S */
101*5c47fe09SDavid du Colombier
102*5c47fe09SDavid du Colombier PORTPMSC = 0x04/4,
103*5c47fe09SDavid du Colombier PORTLI = 0x08/4,
104*5c47fe09SDavid du Colombier
105*5c47fe09SDavid du Colombier /* Host Controller Runtime Register */
106*5c47fe09SDavid du Colombier MFINDEX = 0x0000/4, /* Microframe Index */
107*5c47fe09SDavid du Colombier IR0 = 0x0020/4, /* Interrupt Register Set 0 */
108*5c47fe09SDavid du Colombier
109*5c47fe09SDavid du Colombier /* Interrupter Registers */
110*5c47fe09SDavid du Colombier IMAN = 0x00/4, /* Interrupter Management */
111*5c47fe09SDavid du Colombier IMOD = 0x04/4, /* Interrupter Moderation */
112*5c47fe09SDavid du Colombier ERSTSZ = 0x08/4, /* Event Ring Segment Table Size */
113*5c47fe09SDavid du Colombier ERSTBA = 0x10/4, /* Event Ring Segment Table Base Address */
114*5c47fe09SDavid du Colombier ERDP = 0x18/4, /* Event Ring Dequeue Pointer */
115*5c47fe09SDavid du Colombier
116*5c47fe09SDavid du Colombier /* TRB flags */
117*5c47fe09SDavid du Colombier TR_ENT = 1<<1,
118*5c47fe09SDavid du Colombier TR_ISP = 1<<2,
119*5c47fe09SDavid du Colombier TR_NS = 1<<3,
120*5c47fe09SDavid du Colombier TR_CH = 1<<4,
121*5c47fe09SDavid du Colombier TR_IOC = 1<<5,
122*5c47fe09SDavid du Colombier TR_IDT = 1<<6,
123*5c47fe09SDavid du Colombier TR_BEI = 1<<9,
124*5c47fe09SDavid du Colombier
125*5c47fe09SDavid du Colombier /* TRB types */
126*5c47fe09SDavid du Colombier TR_RESERVED = 0<<10,
127*5c47fe09SDavid du Colombier TR_NORMAL = 1<<10,
128*5c47fe09SDavid du Colombier TR_SETUPSTAGE = 2<<10,
129*5c47fe09SDavid du Colombier TR_DATASTAGE = 3<<10,
130*5c47fe09SDavid du Colombier TR_STATUSSTAGE = 4<<10,
131*5c47fe09SDavid du Colombier TR_ISOCH = 5<<10,
132*5c47fe09SDavid du Colombier TR_LINK = 6<<10,
133*5c47fe09SDavid du Colombier TR_EVENTDATA = 7<<10,
134*5c47fe09SDavid du Colombier TR_NOOP = 8<<10,
135*5c47fe09SDavid du Colombier
136*5c47fe09SDavid du Colombier CR_ENABLESLOT = 9<<10,
137*5c47fe09SDavid du Colombier CR_DISABLESLOT = 10<<10,
138*5c47fe09SDavid du Colombier CR_ADDRESSDEV = 11<<10,
139*5c47fe09SDavid du Colombier CR_CONFIGEP = 12<<10,
140*5c47fe09SDavid du Colombier CR_EVALCTX = 13<<10,
141*5c47fe09SDavid du Colombier CR_RESETEP = 14<<10,
142*5c47fe09SDavid du Colombier CR_STOPEP = 15<<10,
143*5c47fe09SDavid du Colombier CR_SETTRDQP = 16<<10,
144*5c47fe09SDavid du Colombier CR_RESETDEV = 17<<10,
145*5c47fe09SDavid du Colombier CR_FORCECMD = 18<<10,
146*5c47fe09SDavid du Colombier CR_NEGBW = 19<<10,
147*5c47fe09SDavid du Colombier CR_SETLAT = 20<<10,
148*5c47fe09SDavid du Colombier CR_GETPORTBW = 21<<10,
149*5c47fe09SDavid du Colombier CR_FORCEHDR = 22<<10,
150*5c47fe09SDavid du Colombier CR_NOOP = 23<<10,
151*5c47fe09SDavid du Colombier
152*5c47fe09SDavid du Colombier ER_TRANSFER = 32<<10,
153*5c47fe09SDavid du Colombier ER_CMDCOMPL = 33<<10,
154*5c47fe09SDavid du Colombier ER_PORTSC = 34<<10,
155*5c47fe09SDavid du Colombier ER_BWREQ = 35<<10,
156*5c47fe09SDavid du Colombier ER_DOORBELL = 36<<10,
157*5c47fe09SDavid du Colombier ER_HCE = 37<<10,
158*5c47fe09SDavid du Colombier ER_DEVNOTE = 38<<10,
159*5c47fe09SDavid du Colombier ER_MFINDEXWRAP = 39<<10,
160*5c47fe09SDavid du Colombier };
161*5c47fe09SDavid du Colombier
162*5c47fe09SDavid du Colombier typedef struct Ctlr Ctlr;
163*5c47fe09SDavid du Colombier typedef struct Wait Wait;
164*5c47fe09SDavid du Colombier typedef struct Ring Ring;
165*5c47fe09SDavid du Colombier typedef struct Slot Slot;
166*5c47fe09SDavid du Colombier typedef struct Epio Epio;
167*5c47fe09SDavid du Colombier typedef struct Port Port;
168*5c47fe09SDavid du Colombier
169*5c47fe09SDavid du Colombier struct Wait
170*5c47fe09SDavid du Colombier {
171*5c47fe09SDavid du Colombier Wait *next;
172*5c47fe09SDavid du Colombier Ring *ring;
173*5c47fe09SDavid du Colombier u32int *td;
174*5c47fe09SDavid du Colombier u32int er[4];
175*5c47fe09SDavid du Colombier Rendez *z;
176*5c47fe09SDavid du Colombier };
177*5c47fe09SDavid du Colombier
178*5c47fe09SDavid du Colombier struct Ring
179*5c47fe09SDavid du Colombier {
180*5c47fe09SDavid du Colombier int id;
181*5c47fe09SDavid du Colombier
182*5c47fe09SDavid du Colombier Slot *slot;
183*5c47fe09SDavid du Colombier
184*5c47fe09SDavid du Colombier u32int *base;
185*5c47fe09SDavid du Colombier
186*5c47fe09SDavid du Colombier u32int mask;
187*5c47fe09SDavid du Colombier u32int shift;
188*5c47fe09SDavid du Colombier
189*5c47fe09SDavid du Colombier u32int rp;
190*5c47fe09SDavid du Colombier u32int wp;
191*5c47fe09SDavid du Colombier
192*5c47fe09SDavid du Colombier u32int *ctx;
193*5c47fe09SDavid du Colombier u32int *doorbell;
194*5c47fe09SDavid du Colombier
195*5c47fe09SDavid du Colombier int stopped;
196*5c47fe09SDavid du Colombier
197*5c47fe09SDavid du Colombier Wait *pending;
198*5c47fe09SDavid du Colombier Lock;
199*5c47fe09SDavid du Colombier };
200*5c47fe09SDavid du Colombier
201*5c47fe09SDavid du Colombier struct Slot
202*5c47fe09SDavid du Colombier {
203*5c47fe09SDavid du Colombier int id;
204*5c47fe09SDavid du Colombier
205*5c47fe09SDavid du Colombier int confval; // bConfigurationValue of SET_CONFIGURATION
206*5c47fe09SDavid du Colombier int iface; // bInterfaceNumber of SET_INTERFACE
207*5c47fe09SDavid du Colombier int altc; // bAlternateSetting of SET_INTERFACE
208*5c47fe09SDavid du Colombier
209*5c47fe09SDavid du Colombier Ctlr *ctlr;
210*5c47fe09SDavid du Colombier Udev *dev;
211*5c47fe09SDavid du Colombier
212*5c47fe09SDavid du Colombier u32int *ibase;
213*5c47fe09SDavid du Colombier u32int *obase;
214*5c47fe09SDavid du Colombier
215*5c47fe09SDavid du Colombier /* endpoint rings */
216*5c47fe09SDavid du Colombier int nep;
217*5c47fe09SDavid du Colombier Ring epr[32];
218*5c47fe09SDavid du Colombier };
219*5c47fe09SDavid du Colombier
220*5c47fe09SDavid du Colombier struct Port
221*5c47fe09SDavid du Colombier {
222*5c47fe09SDavid du Colombier char spec[4];
223*5c47fe09SDavid du Colombier int proto;
224*5c47fe09SDavid du Colombier
225*5c47fe09SDavid du Colombier u32int *reg;
226*5c47fe09SDavid du Colombier };
227*5c47fe09SDavid du Colombier
228*5c47fe09SDavid du Colombier struct Ctlr
229*5c47fe09SDavid du Colombier {
230*5c47fe09SDavid du Colombier Pcidev *pcidev;
231*5c47fe09SDavid du Colombier
232*5c47fe09SDavid du Colombier u32int *mmio;
233*5c47fe09SDavid du Colombier
234*5c47fe09SDavid du Colombier u32int *opr; /* operational registers */
235*5c47fe09SDavid du Colombier u32int *rts; /* runtime registers */
236*5c47fe09SDavid du Colombier u32int *dba; /* doorbell array */
237*5c47fe09SDavid du Colombier
238*5c47fe09SDavid du Colombier u64int *dcba; /* device context base array */
239*5c47fe09SDavid du Colombier
240*5c47fe09SDavid du Colombier u64int *sba; /* scratchpad buffer array */
241*5c47fe09SDavid du Colombier void *sbp; /* scratchpad buffer pages */
242*5c47fe09SDavid du Colombier
243*5c47fe09SDavid du Colombier u32int *erst[1]; /* event ring segment table */
244*5c47fe09SDavid du Colombier Ring er[1]; /* event ring segment */
245*5c47fe09SDavid du Colombier Ring cr[1]; /* command ring segment */
246*5c47fe09SDavid du Colombier QLock cmdlock;
247*5c47fe09SDavid du Colombier
248*5c47fe09SDavid du Colombier u32int µframe;
249*5c47fe09SDavid du Colombier
250*5c47fe09SDavid du Colombier QLock slotlock;
251*5c47fe09SDavid du Colombier Slot **slot; /* slots by slot id */
252*5c47fe09SDavid du Colombier Port *port;
253*5c47fe09SDavid du Colombier
254*5c47fe09SDavid du Colombier u32int hccparams;
255*5c47fe09SDavid du Colombier
256*5c47fe09SDavid du Colombier int csz;
257*5c47fe09SDavid du Colombier int pagesize;
258*5c47fe09SDavid du Colombier int nscratch;
259*5c47fe09SDavid du Colombier int nintrs;
260*5c47fe09SDavid du Colombier int nslots;
261*5c47fe09SDavid du Colombier
262*5c47fe09SDavid du Colombier Rendez recover;
263*5c47fe09SDavid du Colombier void *active;
264*5c47fe09SDavid du Colombier uintptr base;
265*5c47fe09SDavid du Colombier };
266*5c47fe09SDavid du Colombier
267*5c47fe09SDavid du Colombier struct Epio
268*5c47fe09SDavid du Colombier {
269*5c47fe09SDavid du Colombier QLock;
270*5c47fe09SDavid du Colombier
271*5c47fe09SDavid du Colombier Ring *ring;
272*5c47fe09SDavid du Colombier Block *b;
273*5c47fe09SDavid du Colombier
274*5c47fe09SDavid du Colombier /* iso */
275*5c47fe09SDavid du Colombier u32int frame;
276*5c47fe09SDavid du Colombier u32int period;
277*5c47fe09SDavid du Colombier u32int incr;
278*5c47fe09SDavid du Colombier u32int tdsz;
279*5c47fe09SDavid du Colombier
280*5c47fe09SDavid du Colombier int nleft;
281*5c47fe09SDavid du Colombier };
282*5c47fe09SDavid du Colombier
283*5c47fe09SDavid du Colombier static char Ebadlen[] = "bad usb request length";
284*5c47fe09SDavid du Colombier static char Enotconfig[] = "usb endpoint not configured";
285*5c47fe09SDavid du Colombier static char Erecover[] = "xhci controller needs reset";
286*5c47fe09SDavid du Colombier
287*5c47fe09SDavid du Colombier static char*
288*5c47fe09SDavid du Colombier ctlrcmd(Ctlr *ctlr, u32int c, u32int s, u64int p, u32int *er);
289*5c47fe09SDavid du Colombier
290*5c47fe09SDavid du Colombier static void
setrptr(u32int * reg,u64int pa)291*5c47fe09SDavid du Colombier setrptr(u32int *reg, u64int pa)
292*5c47fe09SDavid du Colombier {
293*5c47fe09SDavid du Colombier coherence();
294*5c47fe09SDavid du Colombier reg[0] = pa;
295*5c47fe09SDavid du Colombier reg[1] = pa>>32;
296*5c47fe09SDavid du Colombier }
297*5c47fe09SDavid du Colombier
298*5c47fe09SDavid du Colombier static u32int
frame(Ctlr * ctlr)299*5c47fe09SDavid du Colombier µframe(Ctlr *ctlr)
300*5c47fe09SDavid du Colombier {
301*5c47fe09SDavid du Colombier u32int µ;
302*5c47fe09SDavid du Colombier do {
303*5c47fe09SDavid du Colombier µ = (ctlr->rts[MFINDEX] & (1<<14)-1) |
304*5c47fe09SDavid du Colombier (ctlr->µframe & ~((1<<14)-1));
305*5c47fe09SDavid du Colombier } while((int)(µ - ctlr->µframe) < 0);
306*5c47fe09SDavid du Colombier return µ;
307*5c47fe09SDavid du Colombier }
308*5c47fe09SDavid du Colombier
309*5c47fe09SDavid du Colombier static void
freering(Ring * r)310*5c47fe09SDavid du Colombier freering(Ring *r)
311*5c47fe09SDavid du Colombier {
312*5c47fe09SDavid du Colombier if(r == nil)
313*5c47fe09SDavid du Colombier return;
314*5c47fe09SDavid du Colombier if(r->base != nil){
315*5c47fe09SDavid du Colombier dmaflush(0, r->base, 4*4<<r->shift);
316*5c47fe09SDavid du Colombier free(r->base);
317*5c47fe09SDavid du Colombier }
318*5c47fe09SDavid du Colombier memset(r, 0, sizeof(*r));
319*5c47fe09SDavid du Colombier }
320*5c47fe09SDavid du Colombier
321*5c47fe09SDavid du Colombier static Ring*
initring(Ring * r,int shift)322*5c47fe09SDavid du Colombier initring(Ring *r, int shift)
323*5c47fe09SDavid du Colombier {
324*5c47fe09SDavid du Colombier r->id = 0;
325*5c47fe09SDavid du Colombier r->ctx = nil;
326*5c47fe09SDavid du Colombier r->slot = nil;
327*5c47fe09SDavid du Colombier r->doorbell = nil;
328*5c47fe09SDavid du Colombier r->pending = nil;
329*5c47fe09SDavid du Colombier r->stopped = 0;
330*5c47fe09SDavid du Colombier r->shift = shift;
331*5c47fe09SDavid du Colombier r->mask = (1<<shift)-1;
332*5c47fe09SDavid du Colombier r->rp = r->wp = 0;
333*5c47fe09SDavid du Colombier r->base = mallocalign(4*4<<shift, 64, 0, 64*1024);
334*5c47fe09SDavid du Colombier if(r->base == nil){
335*5c47fe09SDavid du Colombier freering(r);
336*5c47fe09SDavid du Colombier error(Enomem);
337*5c47fe09SDavid du Colombier }
338*5c47fe09SDavid du Colombier dmaflush(1, r->base, 4*4<<shift);
339*5c47fe09SDavid du Colombier return r;
340*5c47fe09SDavid du Colombier }
341*5c47fe09SDavid du Colombier
342*5c47fe09SDavid du Colombier static void
flushring(Ring * r)343*5c47fe09SDavid du Colombier flushring(Ring *r)
344*5c47fe09SDavid du Colombier {
345*5c47fe09SDavid du Colombier Rendez *z;
346*5c47fe09SDavid du Colombier Wait *w;
347*5c47fe09SDavid du Colombier
348*5c47fe09SDavid du Colombier while((w = r->pending) != nil){
349*5c47fe09SDavid du Colombier r->pending = w->next;
350*5c47fe09SDavid du Colombier w->next = nil;
351*5c47fe09SDavid du Colombier if((z = w->z) != nil){
352*5c47fe09SDavid du Colombier w->z = nil;
353*5c47fe09SDavid du Colombier wakeup(z);
354*5c47fe09SDavid du Colombier }
355*5c47fe09SDavid du Colombier }
356*5c47fe09SDavid du Colombier }
357*5c47fe09SDavid du Colombier
358*5c47fe09SDavid du Colombier static u64int
resetring(Ring * r)359*5c47fe09SDavid du Colombier resetring(Ring *r)
360*5c47fe09SDavid du Colombier {
361*5c47fe09SDavid du Colombier u64int pa;
362*5c47fe09SDavid du Colombier
363*5c47fe09SDavid du Colombier ilock(r);
364*5c47fe09SDavid du Colombier flushring(r);
365*5c47fe09SDavid du Colombier r->rp = r->wp;
366*5c47fe09SDavid du Colombier pa = PCIWADDR(&r->base[4*(r->wp & r->mask)]) | ((~r->wp>>r->shift) & 1);
367*5c47fe09SDavid du Colombier iunlock(r);
368*5c47fe09SDavid du Colombier
369*5c47fe09SDavid du Colombier return pa;
370*5c47fe09SDavid du Colombier }
371*5c47fe09SDavid du Colombier
372*5c47fe09SDavid du Colombier static u32int*
xecp(Ctlr * ctlr,uchar id,u32int * p)373*5c47fe09SDavid du Colombier xecp(Ctlr *ctlr, uchar id, u32int *p)
374*5c47fe09SDavid du Colombier {
375*5c47fe09SDavid du Colombier u32int x, *e;
376*5c47fe09SDavid du Colombier
377*5c47fe09SDavid du Colombier e = &ctlr->mmio[ctlr->pcidev->mem[0].size/4];
378*5c47fe09SDavid du Colombier if(p == nil){
379*5c47fe09SDavid du Colombier p = ctlr->mmio;
380*5c47fe09SDavid du Colombier x = ctlr->hccparams>>16;
381*5c47fe09SDavid du Colombier } else {
382*5c47fe09SDavid du Colombier assert(p < e);
383*5c47fe09SDavid du Colombier x = (*p>>8) & 255;
384*5c47fe09SDavid du Colombier }
385*5c47fe09SDavid du Colombier while(x != 0){
386*5c47fe09SDavid du Colombier p += x;
387*5c47fe09SDavid du Colombier if(p >= e)
388*5c47fe09SDavid du Colombier break;
389*5c47fe09SDavid du Colombier x = *p;
390*5c47fe09SDavid du Colombier if((x & 255) == id)
391*5c47fe09SDavid du Colombier return p;
392*5c47fe09SDavid du Colombier x >>= 8;
393*5c47fe09SDavid du Colombier x &= 255;
394*5c47fe09SDavid du Colombier }
395*5c47fe09SDavid du Colombier return nil;
396*5c47fe09SDavid du Colombier }
397*5c47fe09SDavid du Colombier
398*5c47fe09SDavid du Colombier static void
handoff(Ctlr * ctlr)399*5c47fe09SDavid du Colombier handoff(Ctlr *ctlr)
400*5c47fe09SDavid du Colombier {
401*5c47fe09SDavid du Colombier u32int *r;
402*5c47fe09SDavid du Colombier int i;
403*5c47fe09SDavid du Colombier
404*5c47fe09SDavid du Colombier if((r = xecp(ctlr, 1, nil)) == nil)
405*5c47fe09SDavid du Colombier return;
406*5c47fe09SDavid du Colombier if(getconf("*noxhcihandoff") == nil){
407*5c47fe09SDavid du Colombier r[0] |= 1<<24; /* request ownership */
408*5c47fe09SDavid du Colombier for(i = 0; (r[0] & (1<<16)) != 0 && i<100; i++)
409*5c47fe09SDavid du Colombier tsleep(&up->sleep, return0, nil, 10);
410*5c47fe09SDavid du Colombier }
411*5c47fe09SDavid du Colombier /* disable SMI interrupts */
412*5c47fe09SDavid du Colombier r[1] &= 7<<1 | 255<<5 | 7<<17 | 7<<29;
413*5c47fe09SDavid du Colombier
414*5c47fe09SDavid du Colombier /* clear BIOS ownership in case of timeout */
415*5c47fe09SDavid du Colombier r[0] &= ~(1<<16);
416*5c47fe09SDavid du Colombier }
417*5c47fe09SDavid du Colombier
418*5c47fe09SDavid du Colombier static void
shutdown(Hci * hp)419*5c47fe09SDavid du Colombier shutdown(Hci *hp)
420*5c47fe09SDavid du Colombier {
421*5c47fe09SDavid du Colombier Ctlr *ctlr = hp->aux;
422*5c47fe09SDavid du Colombier int i;
423*5c47fe09SDavid du Colombier
424*5c47fe09SDavid du Colombier ctlr->opr[USBCMD] = 0;
425*5c47fe09SDavid du Colombier for(i=0; (ctlr->opr[USBSTS] & HCH) == 0 && i < 10; i++)
426*5c47fe09SDavid du Colombier delay(10);
427*5c47fe09SDavid du Colombier pciintrdisable(ctlr->pcidev->tbdf, hp->interrupt, hp);
428*5c47fe09SDavid du Colombier pcidisable(ctlr->pcidev);
429*5c47fe09SDavid du Colombier }
430*5c47fe09SDavid du Colombier
431*5c47fe09SDavid du Colombier static void
release(Ctlr * ctlr)432*5c47fe09SDavid du Colombier release(Ctlr *ctlr)
433*5c47fe09SDavid du Colombier {
434*5c47fe09SDavid du Colombier int i;
435*5c47fe09SDavid du Colombier
436*5c47fe09SDavid du Colombier freering(ctlr->cr);
437*5c47fe09SDavid du Colombier for(i=0; i<nelem(ctlr->er); i++){
438*5c47fe09SDavid du Colombier freering(&ctlr->er[i]);
439*5c47fe09SDavid du Colombier free(ctlr->erst[i]);
440*5c47fe09SDavid du Colombier ctlr->erst[i] = nil;
441*5c47fe09SDavid du Colombier }
442*5c47fe09SDavid du Colombier free(ctlr->port), ctlr->port = nil;
443*5c47fe09SDavid du Colombier free(ctlr->slot), ctlr->slot = nil;
444*5c47fe09SDavid du Colombier free(ctlr->dcba), ctlr->dcba = nil;
445*5c47fe09SDavid du Colombier free(ctlr->sba), ctlr->sba = nil;
446*5c47fe09SDavid du Colombier if(ctlr->sbp != nil){
447*5c47fe09SDavid du Colombier dmaflush(0, ctlr->sbp, ctlr->nscratch*ctlr->pagesize);
448*5c47fe09SDavid du Colombier free(ctlr->sbp);
449*5c47fe09SDavid du Colombier ctlr->sbp = nil;
450*5c47fe09SDavid du Colombier }
451*5c47fe09SDavid du Colombier }
452*5c47fe09SDavid du Colombier
453*5c47fe09SDavid du Colombier static void recover(void *arg);
454*5c47fe09SDavid du Colombier
455*5c47fe09SDavid du Colombier static void
init(Hci * hp)456*5c47fe09SDavid du Colombier init(Hci *hp)
457*5c47fe09SDavid du Colombier {
458*5c47fe09SDavid du Colombier Ctlr *ctlr;
459*5c47fe09SDavid du Colombier Port *pp;
460*5c47fe09SDavid du Colombier u32int *x;
461*5c47fe09SDavid du Colombier uchar *p;
462*5c47fe09SDavid du Colombier int i, j;
463*5c47fe09SDavid du Colombier
464*5c47fe09SDavid du Colombier ctlr = hp->aux;
465*5c47fe09SDavid du Colombier pcienable(ctlr->pcidev);
466*5c47fe09SDavid du Colombier if(ctlr->mmio[CAPLENGTH] == -1){
467*5c47fe09SDavid du Colombier pcidisable(ctlr->pcidev);
468*5c47fe09SDavid du Colombier error("controller vanished");
469*5c47fe09SDavid du Colombier }
470*5c47fe09SDavid du Colombier
471*5c47fe09SDavid du Colombier ctlr->opr = &ctlr->mmio[(ctlr->mmio[CAPLENGTH]&0xFF)/4];
472*5c47fe09SDavid du Colombier ctlr->dba = &ctlr->mmio[ctlr->mmio[DBOFF]/4];
473*5c47fe09SDavid du Colombier ctlr->rts = &ctlr->mmio[ctlr->mmio[RTSOFF]/4];
474*5c47fe09SDavid du Colombier
475*5c47fe09SDavid du Colombier ctlr->hccparams = ctlr->mmio[HCCPARAMS];
476*5c47fe09SDavid du Colombier handoff(ctlr);
477*5c47fe09SDavid du Colombier xhcireset(BUSBNO(hp->tbdf)<<20 | BUSDNO(hp->tbdf)<<15 | BUSFNO(hp->tbdf)<<12);
478*5c47fe09SDavid du Colombier
479*5c47fe09SDavid du Colombier for(i=0; (ctlr->opr[USBSTS] & CNR) != 0 && i<100; i++)
480*5c47fe09SDavid du Colombier tsleep(&up->sleep, return0, nil, 10);
481*5c47fe09SDavid du Colombier if(i == 100)
482*5c47fe09SDavid du Colombier print("%s: controller not ready, status %ux\n", hp->type, ctlr->opr[USBSTS]);
483*5c47fe09SDavid du Colombier
484*5c47fe09SDavid du Colombier ctlr->opr[USBCMD] = HCRST;
485*5c47fe09SDavid du Colombier delay(1);
486*5c47fe09SDavid du Colombier for(i=0; (ctlr->opr[USBSTS] & (CNR|HCH)) != HCH && i<100; i++)
487*5c47fe09SDavid du Colombier tsleep(&up->sleep, return0, nil, 10);
488*5c47fe09SDavid du Colombier if(i == 100)
489*5c47fe09SDavid du Colombier print("%s: controller not halted, status %ux\n", hp->type, ctlr->opr[USBSTS]);
490*5c47fe09SDavid du Colombier
491*5c47fe09SDavid du Colombier pcisetbme(ctlr->pcidev);
492*5c47fe09SDavid du Colombier pciintrenable(ctlr->pcidev->tbdf, hp->interrupt, hp);
493*5c47fe09SDavid du Colombier
494*5c47fe09SDavid du Colombier if(waserror()){
495*5c47fe09SDavid du Colombier shutdown(hp);
496*5c47fe09SDavid du Colombier release(ctlr);
497*5c47fe09SDavid du Colombier nexterror();
498*5c47fe09SDavid du Colombier }
499*5c47fe09SDavid du Colombier
500*5c47fe09SDavid du Colombier ctlr->csz = (ctlr->hccparams & CSZ) != 0;
501*5c47fe09SDavid du Colombier ctlr->pagesize = (ctlr->opr[PAGESIZE] & 0xFFFF) << 12;
502*5c47fe09SDavid du Colombier
503*5c47fe09SDavid du Colombier ctlr->nscratch = (ctlr->mmio[HCSPARAMS2] >> 27) & 0x1F | (ctlr->mmio[HCSPARAMS2] >> 16) & 0x3E0;
504*5c47fe09SDavid du Colombier ctlr->nintrs = (ctlr->mmio[HCSPARAMS1] >> 8) & 0x7FF;
505*5c47fe09SDavid du Colombier ctlr->nslots = (ctlr->mmio[HCSPARAMS1] >> 0) & 0xFF;
506*5c47fe09SDavid du Colombier
507*5c47fe09SDavid du Colombier hp->highspeed = 1;
508*5c47fe09SDavid du Colombier hp->superspeed = 0;
509*5c47fe09SDavid du Colombier hp->nports = (ctlr->mmio[HCSPARAMS1] >> 24) & 0xFF;
510*5c47fe09SDavid du Colombier ctlr->port = malloc(hp->nports * sizeof(Port));
511*5c47fe09SDavid du Colombier if(ctlr->port == nil)
512*5c47fe09SDavid du Colombier error(Enomem);
513*5c47fe09SDavid du Colombier for(i=0; i<hp->nports; i++)
514*5c47fe09SDavid du Colombier ctlr->port[i].reg = &ctlr->opr[0x400/4 + i*4];
515*5c47fe09SDavid du Colombier
516*5c47fe09SDavid du Colombier x = nil;
517*5c47fe09SDavid du Colombier while((x = xecp(ctlr, 2, x)) != nil){
518*5c47fe09SDavid du Colombier i = x[2]&255;
519*5c47fe09SDavid du Colombier j = (x[2]>>8)&255;
520*5c47fe09SDavid du Colombier while(j--){
521*5c47fe09SDavid du Colombier if(i < 1 || i > hp->nports)
522*5c47fe09SDavid du Colombier break;
523*5c47fe09SDavid du Colombier pp = &ctlr->port[i-1];
524*5c47fe09SDavid du Colombier pp->proto = x[0]>>16;
525*5c47fe09SDavid du Colombier memmove(pp->spec, &x[1], 4);
526*5c47fe09SDavid du Colombier if(memcmp(pp->spec, "USB ", 4) == 0 && pp->proto >= 0x0300)
527*5c47fe09SDavid du Colombier hp->superspeed |= 1<<(i-1);
528*5c47fe09SDavid du Colombier i++;
529*5c47fe09SDavid du Colombier }
530*5c47fe09SDavid du Colombier }
531*5c47fe09SDavid du Colombier
532*5c47fe09SDavid du Colombier ctlr->slot = malloc((1+ctlr->nslots)*sizeof(ctlr->slot[0]));
533*5c47fe09SDavid du Colombier ctlr->dcba = mallocalign((1+ctlr->nslots)*sizeof(ctlr->dcba[0]), 64, 0, ctlr->pagesize);
534*5c47fe09SDavid du Colombier if(ctlr->slot == nil || ctlr->dcba == nil)
535*5c47fe09SDavid du Colombier error(Enomem);
536*5c47fe09SDavid du Colombier if(ctlr->nscratch != 0){
537*5c47fe09SDavid du Colombier ctlr->sba = mallocalign(ctlr->nscratch*8, 64, 0, ctlr->pagesize);
538*5c47fe09SDavid du Colombier ctlr->sbp = mallocalign(ctlr->nscratch*ctlr->pagesize, ctlr->pagesize, 0, 0);
539*5c47fe09SDavid du Colombier if(ctlr->sba == nil || ctlr->sbp == nil)
540*5c47fe09SDavid du Colombier error(Enomem);
541*5c47fe09SDavid du Colombier for(i=0, p = ctlr->sbp; i<ctlr->nscratch; i++, p += ctlr->pagesize){
542*5c47fe09SDavid du Colombier memset(p, 0, ctlr->pagesize);
543*5c47fe09SDavid du Colombier ctlr->sba[i] = PCIWADDR(p);
544*5c47fe09SDavid du Colombier }
545*5c47fe09SDavid du Colombier dmaflush(1, ctlr->sbp, ctlr->nscratch*ctlr->pagesize);
546*5c47fe09SDavid du Colombier dmaflush(1, ctlr->sba, ctlr->nscratch*8);
547*5c47fe09SDavid du Colombier ctlr->dcba[0] = PCIWADDR(ctlr->sba);
548*5c47fe09SDavid du Colombier } else {
549*5c47fe09SDavid du Colombier ctlr->dcba[0] = 0;
550*5c47fe09SDavid du Colombier }
551*5c47fe09SDavid du Colombier for(i=1; i<=ctlr->nslots; i++)
552*5c47fe09SDavid du Colombier ctlr->dcba[i] = 0;
553*5c47fe09SDavid du Colombier
554*5c47fe09SDavid du Colombier ctlr->opr[CONFIG] = (ctlr->opr[CONFIG] & 0xFFFFFC00) | ctlr->nslots; /* MaxSlotsEn */
555*5c47fe09SDavid du Colombier
556*5c47fe09SDavid du Colombier dmaflush(1, ctlr->dcba, (1+ctlr->nslots)*sizeof(ctlr->dcba[0]));
557*5c47fe09SDavid du Colombier setrptr(&ctlr->opr[DCBAAP], PCIWADDR(ctlr->dcba));
558*5c47fe09SDavid du Colombier
559*5c47fe09SDavid du Colombier initring(ctlr->cr, 8); /* 256 entries */
560*5c47fe09SDavid du Colombier ctlr->cr->id = 0;
561*5c47fe09SDavid du Colombier ctlr->cr->doorbell = &ctlr->dba[0];
562*5c47fe09SDavid du Colombier setrptr(&ctlr->opr[CRCR], resetring(ctlr->cr));
563*5c47fe09SDavid du Colombier
564*5c47fe09SDavid du Colombier for(i=0; i<ctlr->nintrs; i++){
565*5c47fe09SDavid du Colombier u32int *irs = &ctlr->rts[IR0 + i*8];
566*5c47fe09SDavid du Colombier
567*5c47fe09SDavid du Colombier if(i >= nelem(ctlr->er)){
568*5c47fe09SDavid du Colombier irs[ERSTSZ] = 0; /* disable ring */
569*5c47fe09SDavid du Colombier irs[IMAN] = 1;
570*5c47fe09SDavid du Colombier irs[IMOD] = 0;
571*5c47fe09SDavid du Colombier setrptr(&irs[ERSTBA], 0);
572*5c47fe09SDavid du Colombier setrptr(&irs[ERDP], 0);
573*5c47fe09SDavid du Colombier continue;
574*5c47fe09SDavid du Colombier }
575*5c47fe09SDavid du Colombier
576*5c47fe09SDavid du Colombier /* allocate and link into event ring segment table */
577*5c47fe09SDavid du Colombier initring(&ctlr->er[i], 8); /* 256 entries */
578*5c47fe09SDavid du Colombier ctlr->erst[i] = mallocalign(4*4, 64, 0, 0);
579*5c47fe09SDavid du Colombier if(ctlr->erst[i] == nil)
580*5c47fe09SDavid du Colombier error(Enomem);
581*5c47fe09SDavid du Colombier *((u64int*)ctlr->erst[i]) = PCIWADDR(ctlr->er[i].base);
582*5c47fe09SDavid du Colombier ctlr->erst[i][2] = ctlr->er[i].mask+1;
583*5c47fe09SDavid du Colombier ctlr->erst[i][3] = 0;
584*5c47fe09SDavid du Colombier dmaflush(1, ctlr->erst[i], 4*4);
585*5c47fe09SDavid du Colombier
586*5c47fe09SDavid du Colombier irs[ERSTSZ] = 1; /* just one segment */
587*5c47fe09SDavid du Colombier irs[IMAN] = 3;
588*5c47fe09SDavid du Colombier irs[IMOD] = 0;
589*5c47fe09SDavid du Colombier setrptr(&irs[ERSTBA], PCIWADDR(ctlr->erst[i]));
590*5c47fe09SDavid du Colombier setrptr(&irs[ERDP], PCIWADDR(ctlr->er[i].base) | (1<<3));
591*5c47fe09SDavid du Colombier }
592*5c47fe09SDavid du Colombier poperror();
593*5c47fe09SDavid du Colombier
594*5c47fe09SDavid du Colombier ctlr->µframe = 0;
595*5c47fe09SDavid du Colombier ctlr->opr[USBSTS] = ctlr->opr[USBSTS] & (HSE|EINT|PCD|SRE);
596*5c47fe09SDavid du Colombier coherence();
597*5c47fe09SDavid du Colombier
598*5c47fe09SDavid du Colombier ctlr->opr[USBCMD] = RUNSTOP|INTE|HSEE|EWE;
599*5c47fe09SDavid du Colombier for(i=0; (ctlr->opr[USBSTS] & (CNR|HCH)) != 0 && i<100; i++)
600*5c47fe09SDavid du Colombier tsleep(&up->sleep, return0, nil, 10);
601*5c47fe09SDavid du Colombier
602*5c47fe09SDavid du Colombier kproc("xhcirecover", recover, hp);
603*5c47fe09SDavid du Colombier }
604*5c47fe09SDavid du Colombier
605*5c47fe09SDavid du Colombier static int
needrecover(void * arg)606*5c47fe09SDavid du Colombier needrecover(void *arg)
607*5c47fe09SDavid du Colombier {
608*5c47fe09SDavid du Colombier Ctlr *ctlr = arg;
609*5c47fe09SDavid du Colombier return ctlr->er->stopped ||
610*5c47fe09SDavid du Colombier (ctlr->opr[USBSTS] & (HCH|HCE|HSE)) != 0;
611*5c47fe09SDavid du Colombier }
612*5c47fe09SDavid du Colombier
613*5c47fe09SDavid du Colombier static void
recover(void * arg)614*5c47fe09SDavid du Colombier recover(void *arg)
615*5c47fe09SDavid du Colombier {
616*5c47fe09SDavid du Colombier Hci *hp = arg;
617*5c47fe09SDavid du Colombier Ctlr *ctlr = hp->aux;
618*5c47fe09SDavid du Colombier
619*5c47fe09SDavid du Colombier while(waserror())
620*5c47fe09SDavid du Colombier ;
621*5c47fe09SDavid du Colombier while(!needrecover(ctlr))
622*5c47fe09SDavid du Colombier tsleep(&ctlr->recover, needrecover, ctlr, 10);
623*5c47fe09SDavid du Colombier shutdown(hp);
624*5c47fe09SDavid du Colombier
625*5c47fe09SDavid du Colombier /*
626*5c47fe09SDavid du Colombier * flush all transactions and wait until all devices have
627*5c47fe09SDavid du Colombier * been detached by usbd.
628*5c47fe09SDavid du Colombier */
629*5c47fe09SDavid du Colombier for(;;){
630*5c47fe09SDavid du Colombier int i, j, active;
631*5c47fe09SDavid du Colombier
632*5c47fe09SDavid du Colombier ilock(ctlr->cr);
633*5c47fe09SDavid du Colombier ctlr->cr->stopped = 1;
634*5c47fe09SDavid du Colombier flushring(ctlr->cr);
635*5c47fe09SDavid du Colombier iunlock(ctlr->cr);
636*5c47fe09SDavid du Colombier
637*5c47fe09SDavid du Colombier active = 0;
638*5c47fe09SDavid du Colombier qlock(&ctlr->slotlock);
639*5c47fe09SDavid du Colombier for(i=1; i<=ctlr->nslots; i++){
640*5c47fe09SDavid du Colombier Slot *slot = ctlr->slot[i];
641*5c47fe09SDavid du Colombier if(slot == nil)
642*5c47fe09SDavid du Colombier continue;
643*5c47fe09SDavid du Colombier active++;
644*5c47fe09SDavid du Colombier for(j=0; j < slot->nep; j++){
645*5c47fe09SDavid du Colombier Ring *ring = &slot->epr[j];
646*5c47fe09SDavid du Colombier if(ring->base == nil)
647*5c47fe09SDavid du Colombier continue;
648*5c47fe09SDavid du Colombier ilock(ring);
649*5c47fe09SDavid du Colombier ring->stopped = 1;
650*5c47fe09SDavid du Colombier flushring(ring);
651*5c47fe09SDavid du Colombier iunlock(ring);
652*5c47fe09SDavid du Colombier }
653*5c47fe09SDavid du Colombier }
654*5c47fe09SDavid du Colombier qunlock(&ctlr->slotlock);
655*5c47fe09SDavid du Colombier if(active == 0)
656*5c47fe09SDavid du Colombier break;
657*5c47fe09SDavid du Colombier
658*5c47fe09SDavid du Colombier tsleep(&up->sleep, return0, nil, 100);
659*5c47fe09SDavid du Colombier }
660*5c47fe09SDavid du Colombier
661*5c47fe09SDavid du Colombier qlock(&ctlr->slotlock);
662*5c47fe09SDavid du Colombier qlock(&ctlr->cmdlock);
663*5c47fe09SDavid du Colombier
664*5c47fe09SDavid du Colombier release(ctlr);
665*5c47fe09SDavid du Colombier if(waserror()) {
666*5c47fe09SDavid du Colombier print("xhci recovery failed: %s\n", up->errstr);
667*5c47fe09SDavid du Colombier } else {
668*5c47fe09SDavid du Colombier init(hp);
669*5c47fe09SDavid du Colombier poperror();
670*5c47fe09SDavid du Colombier }
671*5c47fe09SDavid du Colombier
672*5c47fe09SDavid du Colombier qunlock(&ctlr->cmdlock);
673*5c47fe09SDavid du Colombier qunlock(&ctlr->slotlock);
674*5c47fe09SDavid du Colombier
675*5c47fe09SDavid du Colombier pexit("", 1);
676*5c47fe09SDavid du Colombier }
677*5c47fe09SDavid du Colombier
678*5c47fe09SDavid du Colombier static void
dump(Hci *)679*5c47fe09SDavid du Colombier dump(Hci *)
680*5c47fe09SDavid du Colombier {
681*5c47fe09SDavid du Colombier }
682*5c47fe09SDavid du Colombier
683*5c47fe09SDavid du Colombier static void
queuetd(Ring * r,u32int c,u32int s,u64int p,Wait * w)684*5c47fe09SDavid du Colombier queuetd(Ring *r, u32int c, u32int s, u64int p, Wait *w)
685*5c47fe09SDavid du Colombier {
686*5c47fe09SDavid du Colombier u32int *td, x;
687*5c47fe09SDavid du Colombier
688*5c47fe09SDavid du Colombier x = r->wp++;
689*5c47fe09SDavid du Colombier if((x & r->mask) == r->mask){
690*5c47fe09SDavid du Colombier td = r->base + 4*(x & r->mask);
691*5c47fe09SDavid du Colombier *(u64int*)td = PCIWADDR(r->base);
692*5c47fe09SDavid du Colombier td[2] = 0;
693*5c47fe09SDavid du Colombier td[3] = ((~x>>r->shift)&1) | (1<<1) | TR_LINK;
694*5c47fe09SDavid du Colombier dmaflush(1, td, 4*4);
695*5c47fe09SDavid du Colombier x = r->wp++;
696*5c47fe09SDavid du Colombier }
697*5c47fe09SDavid du Colombier td = r->base + 4*(x & r->mask);
698*5c47fe09SDavid du Colombier if(w != nil){
699*5c47fe09SDavid du Colombier w->er[0] = w->er[1] = w->er[2] = w->er[3] = 0;
700*5c47fe09SDavid du Colombier w->ring = r;
701*5c47fe09SDavid du Colombier w->td = td;
702*5c47fe09SDavid du Colombier w->z = &up->sleep;
703*5c47fe09SDavid du Colombier
704*5c47fe09SDavid du Colombier ilock(r);
705*5c47fe09SDavid du Colombier w->next = r->pending;
706*5c47fe09SDavid du Colombier r->pending = w;
707*5c47fe09SDavid du Colombier iunlock(r);
708*5c47fe09SDavid du Colombier }
709*5c47fe09SDavid du Colombier coherence();
710*5c47fe09SDavid du Colombier *(u64int*)td = p;
711*5c47fe09SDavid du Colombier td[2] = s;
712*5c47fe09SDavid du Colombier td[3] = ((~x>>r->shift)&1) | c;
713*5c47fe09SDavid du Colombier dmaflush(1, td, 4*4);
714*5c47fe09SDavid du Colombier }
715*5c47fe09SDavid du Colombier
716*5c47fe09SDavid du Colombier static char *ccerrtab[] = {
717*5c47fe09SDavid du Colombier [2] "Data Buffer Error",
718*5c47fe09SDavid du Colombier [3] "Babble Detected Error",
719*5c47fe09SDavid du Colombier [4] "USB Transaction Error",
720*5c47fe09SDavid du Colombier [5] "TRB Error",
721*5c47fe09SDavid du Colombier [6] "Stall Error",
722*5c47fe09SDavid du Colombier [7] "Resume Error",
723*5c47fe09SDavid du Colombier [8] "Bandwidth Error",
724*5c47fe09SDavid du Colombier [9] "No Slots Available",
725*5c47fe09SDavid du Colombier [10] "Invalid Stream Type",
726*5c47fe09SDavid du Colombier [11] "Slot Not Enabled",
727*5c47fe09SDavid du Colombier [12] "Endpoint Not Enabled",
728*5c47fe09SDavid du Colombier [13] "Short Packet",
729*5c47fe09SDavid du Colombier [14] "Ring Underrun",
730*5c47fe09SDavid du Colombier [15] "Ring Overrun",
731*5c47fe09SDavid du Colombier [16] "VF Event Ring Full",
732*5c47fe09SDavid du Colombier [17] "Parameter Error",
733*5c47fe09SDavid du Colombier [18] "Bandwidth Overrun Error",
734*5c47fe09SDavid du Colombier [19] "Context State Error",
735*5c47fe09SDavid du Colombier [20] "No Ping Response",
736*5c47fe09SDavid du Colombier [21] "Event Ring Full",
737*5c47fe09SDavid du Colombier [22] "Incompatible Device",
738*5c47fe09SDavid du Colombier [23] "Missed Service Error",
739*5c47fe09SDavid du Colombier [24] "Command Ring Stopped",
740*5c47fe09SDavid du Colombier [25] "Command Aborted",
741*5c47fe09SDavid du Colombier [26] "Stopped",
742*5c47fe09SDavid du Colombier [27] "Stopped - Length Invalid",
743*5c47fe09SDavid du Colombier [29] "Max Exit Latency Too Large",
744*5c47fe09SDavid du Colombier [31] "Isoch Buffer Overrun",
745*5c47fe09SDavid du Colombier [32] "Event Lost Error",
746*5c47fe09SDavid du Colombier [33] "Undefined Error",
747*5c47fe09SDavid du Colombier [34] "Invalid Stream ID",
748*5c47fe09SDavid du Colombier [35] "Secondary Bandwidth Error",
749*5c47fe09SDavid du Colombier [36] "Split Transaction Error",
750*5c47fe09SDavid du Colombier };
751*5c47fe09SDavid du Colombier
752*5c47fe09SDavid du Colombier static char*
ccerrstr(u32int cc)753*5c47fe09SDavid du Colombier ccerrstr(u32int cc)
754*5c47fe09SDavid du Colombier {
755*5c47fe09SDavid du Colombier char *s;
756*5c47fe09SDavid du Colombier
757*5c47fe09SDavid du Colombier if(cc == 1 || cc == 13)
758*5c47fe09SDavid du Colombier return nil;
759*5c47fe09SDavid du Colombier if(cc < nelem(ccerrtab) && ccerrtab[cc] != nil)
760*5c47fe09SDavid du Colombier s = ccerrtab[cc];
761*5c47fe09SDavid du Colombier else
762*5c47fe09SDavid du Colombier s = "???";
763*5c47fe09SDavid du Colombier return s;
764*5c47fe09SDavid du Colombier }
765*5c47fe09SDavid du Colombier
766*5c47fe09SDavid du Colombier static int
waitdone(void * a)767*5c47fe09SDavid du Colombier waitdone(void *a)
768*5c47fe09SDavid du Colombier {
769*5c47fe09SDavid du Colombier return ((Wait*)a)->z == nil;
770*5c47fe09SDavid du Colombier }
771*5c47fe09SDavid du Colombier
772*5c47fe09SDavid du Colombier static char*
waittd(Ctlr * ctlr,Wait * w,int tmout)773*5c47fe09SDavid du Colombier waittd(Ctlr *ctlr, Wait *w, int tmout)
774*5c47fe09SDavid du Colombier {
775*5c47fe09SDavid du Colombier Ring *r = w->ring;
776*5c47fe09SDavid du Colombier
777*5c47fe09SDavid du Colombier coherence();
778*5c47fe09SDavid du Colombier *r->doorbell = r->id;
779*5c47fe09SDavid du Colombier
780*5c47fe09SDavid du Colombier while(waserror()){
781*5c47fe09SDavid du Colombier if(r->stopped) {
782*5c47fe09SDavid du Colombier ctlr->er->stopped = 1;
783*5c47fe09SDavid du Colombier wakeup(&ctlr->recover);
784*5c47fe09SDavid du Colombier
785*5c47fe09SDavid du Colombier /* wait for rescue */
786*5c47fe09SDavid du Colombier tmout = 0;
787*5c47fe09SDavid du Colombier continue;
788*5c47fe09SDavid du Colombier }
789*5c47fe09SDavid du Colombier
790*5c47fe09SDavid du Colombier if(r == ctlr->cr)
791*5c47fe09SDavid du Colombier ctlr->opr[CRCR] |= CA;
792*5c47fe09SDavid du Colombier else
793*5c47fe09SDavid du Colombier ctlrcmd(ctlr, CR_STOPEP | (r->id<<16) | (r->slot->id<<24), 0, 0, nil);
794*5c47fe09SDavid du Colombier r->stopped = 1;
795*5c47fe09SDavid du Colombier
796*5c47fe09SDavid du Colombier /* time to abort the transaction */
797*5c47fe09SDavid du Colombier tmout = 5000;
798*5c47fe09SDavid du Colombier }
799*5c47fe09SDavid du Colombier if(tmout > 0){
800*5c47fe09SDavid du Colombier tsleep(&up->sleep, waitdone, w, tmout);
801*5c47fe09SDavid du Colombier if(!waitdone(w))
802*5c47fe09SDavid du Colombier error("timed out");
803*5c47fe09SDavid du Colombier } else {
804*5c47fe09SDavid du Colombier while(!waitdone(w))
805*5c47fe09SDavid du Colombier sleep(&up->sleep, waitdone, w);
806*5c47fe09SDavid du Colombier }
807*5c47fe09SDavid du Colombier poperror();
808*5c47fe09SDavid du Colombier return ccerrstr(w->er[2]>>24);
809*5c47fe09SDavid du Colombier }
810*5c47fe09SDavid du Colombier
811*5c47fe09SDavid du Colombier static char*
ctlrcmd(Ctlr * ctlr,u32int c,u32int s,u64int p,u32int * er)812*5c47fe09SDavid du Colombier ctlrcmd(Ctlr *ctlr, u32int c, u32int s, u64int p, u32int *er)
813*5c47fe09SDavid du Colombier {
814*5c47fe09SDavid du Colombier Wait w[1];
815*5c47fe09SDavid du Colombier char *err;
816*5c47fe09SDavid du Colombier
817*5c47fe09SDavid du Colombier qlock(&ctlr->cmdlock);
818*5c47fe09SDavid du Colombier if(needrecover(ctlr)){
819*5c47fe09SDavid du Colombier qunlock(&ctlr->cmdlock);
820*5c47fe09SDavid du Colombier return Erecover;
821*5c47fe09SDavid du Colombier }
822*5c47fe09SDavid du Colombier ctlr->cr->stopped = 0;
823*5c47fe09SDavid du Colombier queuetd(ctlr->cr, c, s, p, w);
824*5c47fe09SDavid du Colombier err = waittd(ctlr, w, 5000);
825*5c47fe09SDavid du Colombier qunlock(&ctlr->cmdlock);
826*5c47fe09SDavid du Colombier
827*5c47fe09SDavid du Colombier if(er != nil)
828*5c47fe09SDavid du Colombier memmove(er, w->er, 4*4);
829*5c47fe09SDavid du Colombier
830*5c47fe09SDavid du Colombier return err;
831*5c47fe09SDavid du Colombier }
832*5c47fe09SDavid du Colombier
833*5c47fe09SDavid du Colombier static void
completering(Ring * r,u32int * er)834*5c47fe09SDavid du Colombier completering(Ring *r, u32int *er)
835*5c47fe09SDavid du Colombier {
836*5c47fe09SDavid du Colombier Wait *w, **wp;
837*5c47fe09SDavid du Colombier u32int *td, x;
838*5c47fe09SDavid du Colombier u64int pa;
839*5c47fe09SDavid du Colombier
840*5c47fe09SDavid du Colombier pa = (*(u64int*)er) & ~15ULL;
841*5c47fe09SDavid du Colombier ilock(r);
842*5c47fe09SDavid du Colombier
843*5c47fe09SDavid du Colombier for(x = r->rp; (int)(r->wp - x) > 0;){
844*5c47fe09SDavid du Colombier td = &r->base[4*(x++ & r->mask)];
845*5c47fe09SDavid du Colombier if((u64int)PCIWADDR(td) == pa){
846*5c47fe09SDavid du Colombier r->rp = x;
847*5c47fe09SDavid du Colombier break;
848*5c47fe09SDavid du Colombier }
849*5c47fe09SDavid du Colombier }
850*5c47fe09SDavid du Colombier
851*5c47fe09SDavid du Colombier wp = &r->pending;
852*5c47fe09SDavid du Colombier while(w = *wp){
853*5c47fe09SDavid du Colombier if((u64int)PCIWADDR(w->td) == pa){
854*5c47fe09SDavid du Colombier Rendez *z = w->z;
855*5c47fe09SDavid du Colombier
856*5c47fe09SDavid du Colombier memmove(w->er, er, 4*4);
857*5c47fe09SDavid du Colombier *wp = w->next;
858*5c47fe09SDavid du Colombier w->next = nil;
859*5c47fe09SDavid du Colombier
860*5c47fe09SDavid du Colombier if(z != nil){
861*5c47fe09SDavid du Colombier w->z = nil;
862*5c47fe09SDavid du Colombier wakeup(z);
863*5c47fe09SDavid du Colombier }
864*5c47fe09SDavid du Colombier break;
865*5c47fe09SDavid du Colombier } else {
866*5c47fe09SDavid du Colombier wp = &w->next;
867*5c47fe09SDavid du Colombier }
868*5c47fe09SDavid du Colombier }
869*5c47fe09SDavid du Colombier
870*5c47fe09SDavid du Colombier iunlock(r);
871*5c47fe09SDavid du Colombier }
872*5c47fe09SDavid du Colombier
873*5c47fe09SDavid du Colombier static void
interrupt(Ureg *,void * arg)874*5c47fe09SDavid du Colombier interrupt(Ureg*, void *arg)
875*5c47fe09SDavid du Colombier {
876*5c47fe09SDavid du Colombier Hci *hp = arg;
877*5c47fe09SDavid du Colombier Ctlr *ctlr = hp->aux;
878*5c47fe09SDavid du Colombier Ring *ring = ctlr->er;
879*5c47fe09SDavid du Colombier Slot *slot;
880*5c47fe09SDavid du Colombier u32int *irs, *td, x;
881*5c47fe09SDavid du Colombier
882*5c47fe09SDavid du Colombier if(ring->base == nil)
883*5c47fe09SDavid du Colombier return;
884*5c47fe09SDavid du Colombier
885*5c47fe09SDavid du Colombier irs = &ctlr->rts[IR0];
886*5c47fe09SDavid du Colombier x = irs[IMAN];
887*5c47fe09SDavid du Colombier if(x & 1) irs[IMAN] = x & 3;
888*5c47fe09SDavid du Colombier
889*5c47fe09SDavid du Colombier for(x = ring->rp;; x=++ring->rp){
890*5c47fe09SDavid du Colombier td = ring->base + 4*(x & ring->mask);
891*5c47fe09SDavid du Colombier dmaflush(0, td, 4*4);
892*5c47fe09SDavid du Colombier
893*5c47fe09SDavid du Colombier if((((x>>ring->shift)^td[3])&1) == 0)
894*5c47fe09SDavid du Colombier break;
895*5c47fe09SDavid du Colombier
896*5c47fe09SDavid du Colombier switch(td[3] & 0xFC00){
897*5c47fe09SDavid du Colombier case ER_CMDCOMPL:
898*5c47fe09SDavid du Colombier completering(ctlr->cr, td);
899*5c47fe09SDavid du Colombier break;
900*5c47fe09SDavid du Colombier case ER_TRANSFER:
901*5c47fe09SDavid du Colombier x = td[3]>>24;
902*5c47fe09SDavid du Colombier if(x == 0 || x > ctlr->nslots)
903*5c47fe09SDavid du Colombier break;
904*5c47fe09SDavid du Colombier slot = ctlr->slot[x];
905*5c47fe09SDavid du Colombier if(slot == nil)
906*5c47fe09SDavid du Colombier break;
907*5c47fe09SDavid du Colombier completering(&slot->epr[(td[3]>>16)-1&31], td);
908*5c47fe09SDavid du Colombier break;
909*5c47fe09SDavid du Colombier case ER_MFINDEXWRAP:
910*5c47fe09SDavid du Colombier ctlr->µframe = (ctlr->rts[MFINDEX] & (1<<14)-1) |
911*5c47fe09SDavid du Colombier (ctlr->µframe+(1<<14) & ~((1<<14)-1));
912*5c47fe09SDavid du Colombier break;
913*5c47fe09SDavid du Colombier case ER_HCE:
914*5c47fe09SDavid du Colombier iprint("xhci: host controller error: %ux %ux %ux %ux\n",
915*5c47fe09SDavid du Colombier td[0], td[1], td[2], td[3]);
916*5c47fe09SDavid du Colombier ctlr->er->stopped = 1;
917*5c47fe09SDavid du Colombier wakeup(&ctlr->recover);
918*5c47fe09SDavid du Colombier return;
919*5c47fe09SDavid du Colombier case ER_PORTSC:
920*5c47fe09SDavid du Colombier break;
921*5c47fe09SDavid du Colombier case ER_BWREQ:
922*5c47fe09SDavid du Colombier case ER_DOORBELL:
923*5c47fe09SDavid du Colombier case ER_DEVNOTE:
924*5c47fe09SDavid du Colombier default:
925*5c47fe09SDavid du Colombier iprint("xhci: event %ud: %ux %ux %ux %ux\n",
926*5c47fe09SDavid du Colombier x, td[0], td[1], td[2], td[3]);
927*5c47fe09SDavid du Colombier }
928*5c47fe09SDavid du Colombier }
929*5c47fe09SDavid du Colombier
930*5c47fe09SDavid du Colombier setrptr(&irs[ERDP], PCIWADDR(td) | (1<<3));
931*5c47fe09SDavid du Colombier }
932*5c47fe09SDavid du Colombier
933*5c47fe09SDavid du Colombier static void
freeslot(void * arg)934*5c47fe09SDavid du Colombier freeslot(void *arg)
935*5c47fe09SDavid du Colombier {
936*5c47fe09SDavid du Colombier Slot *slot;
937*5c47fe09SDavid du Colombier
938*5c47fe09SDavid du Colombier if(arg == nil)
939*5c47fe09SDavid du Colombier return;
940*5c47fe09SDavid du Colombier slot = arg;
941*5c47fe09SDavid du Colombier if(slot->id != 0){
942*5c47fe09SDavid du Colombier Ctlr *ctlr = slot->ctlr;
943*5c47fe09SDavid du Colombier qlock(&ctlr->slotlock);
944*5c47fe09SDavid du Colombier if(ctlr->slot != nil && ctlr->slot[slot->id] == slot){
945*5c47fe09SDavid du Colombier ctlrcmd(ctlr, CR_DISABLESLOT | (slot->id<<24), 0, 0, nil);
946*5c47fe09SDavid du Colombier dmaflush(0, slot->obase, 32*32 << ctlr->csz);
947*5c47fe09SDavid du Colombier ctlr->dcba[slot->id] = 0;
948*5c47fe09SDavid du Colombier dmaflush(1, &ctlr->dcba[slot->id], sizeof(ctlr->dcba[0]));
949*5c47fe09SDavid du Colombier ctlr->slot[slot->id] = nil;
950*5c47fe09SDavid du Colombier }
951*5c47fe09SDavid du Colombier qunlock(&ctlr->slotlock);
952*5c47fe09SDavid du Colombier }
953*5c47fe09SDavid du Colombier freering(&slot->epr[0]);
954*5c47fe09SDavid du Colombier free(slot->ibase);
955*5c47fe09SDavid du Colombier free(slot->obase);
956*5c47fe09SDavid du Colombier free(slot);
957*5c47fe09SDavid du Colombier }
958*5c47fe09SDavid du Colombier
959*5c47fe09SDavid du Colombier static Slot*
allocslot(Ctlr * ctlr,Udev * dev)960*5c47fe09SDavid du Colombier allocslot(Ctlr *ctlr, Udev *dev)
961*5c47fe09SDavid du Colombier {
962*5c47fe09SDavid du Colombier u32int r[4];
963*5c47fe09SDavid du Colombier Slot *slot;
964*5c47fe09SDavid du Colombier char *err;
965*5c47fe09SDavid du Colombier
966*5c47fe09SDavid du Colombier slot = malloc(sizeof(Slot));
967*5c47fe09SDavid du Colombier if(slot == nil)
968*5c47fe09SDavid du Colombier error(Enomem);
969*5c47fe09SDavid du Colombier
970*5c47fe09SDavid du Colombier slot->ctlr = ctlr;
971*5c47fe09SDavid du Colombier slot->dev = dev;
972*5c47fe09SDavid du Colombier slot->nep = 0;
973*5c47fe09SDavid du Colombier slot->id = 0;
974*5c47fe09SDavid du Colombier
975*5c47fe09SDavid du Colombier slot->confval = 0;
976*5c47fe09SDavid du Colombier slot->iface = 0;
977*5c47fe09SDavid du Colombier slot->altc = 0;
978*5c47fe09SDavid du Colombier
979*5c47fe09SDavid du Colombier qlock(&ctlr->slotlock);
980*5c47fe09SDavid du Colombier if(waserror()){
981*5c47fe09SDavid du Colombier qunlock(&ctlr->slotlock);
982*5c47fe09SDavid du Colombier freeslot(slot);
983*5c47fe09SDavid du Colombier nexterror();
984*5c47fe09SDavid du Colombier }
985*5c47fe09SDavid du Colombier if(ctlr->slot == nil)
986*5c47fe09SDavid du Colombier error(Erecover);
987*5c47fe09SDavid du Colombier slot->ibase = mallocalign(32*33 << ctlr->csz, 64, 0, ctlr->pagesize);
988*5c47fe09SDavid du Colombier slot->obase = mallocalign(32*32 << ctlr->csz, 64, 0, ctlr->pagesize);
989*5c47fe09SDavid du Colombier if(slot->ibase == nil || slot->obase == nil)
990*5c47fe09SDavid du Colombier error(Enomem);
991*5c47fe09SDavid du Colombier
992*5c47fe09SDavid du Colombier if((err = ctlrcmd(ctlr, CR_ENABLESLOT, 0, 0, r)) != nil)
993*5c47fe09SDavid du Colombier error(err);
994*5c47fe09SDavid du Colombier slot->id = r[3]>>24;
995*5c47fe09SDavid du Colombier if(slot->id <= 0 || slot->id > ctlr->nslots || ctlr->slot[slot->id] != nil){
996*5c47fe09SDavid du Colombier slot->id = 0;
997*5c47fe09SDavid du Colombier error("bad slot id from controller");
998*5c47fe09SDavid du Colombier }
999*5c47fe09SDavid du Colombier poperror();
1000*5c47fe09SDavid du Colombier
1001*5c47fe09SDavid du Colombier dmaflush(1, slot->obase, 32*32 << ctlr->csz);
1002*5c47fe09SDavid du Colombier ctlr->dcba[slot->id] = PCIWADDR(slot->obase);
1003*5c47fe09SDavid du Colombier dmaflush(1, &ctlr->dcba[slot->id], sizeof(ctlr->dcba[0]));
1004*5c47fe09SDavid du Colombier
1005*5c47fe09SDavid du Colombier ctlr->slot[slot->id] = slot;
1006*5c47fe09SDavid du Colombier
1007*5c47fe09SDavid du Colombier qunlock(&ctlr->slotlock);
1008*5c47fe09SDavid du Colombier
1009*5c47fe09SDavid du Colombier return slot;
1010*5c47fe09SDavid du Colombier }
1011*5c47fe09SDavid du Colombier
1012*5c47fe09SDavid du Colombier static void
setdebug(Hci *,int)1013*5c47fe09SDavid du Colombier setdebug(Hci *, int)
1014*5c47fe09SDavid du Colombier {
1015*5c47fe09SDavid du Colombier }
1016*5c47fe09SDavid du Colombier
1017*5c47fe09SDavid du Colombier static void
epclose(Ep * ep)1018*5c47fe09SDavid du Colombier epclose(Ep *ep)
1019*5c47fe09SDavid du Colombier {
1020*5c47fe09SDavid du Colombier Ctlr *ctlr;
1021*5c47fe09SDavid du Colombier Slot *slot;
1022*5c47fe09SDavid du Colombier Ring *ring;
1023*5c47fe09SDavid du Colombier Epio *io;
1024*5c47fe09SDavid du Colombier
1025*5c47fe09SDavid du Colombier if(ep->dev->isroot)
1026*5c47fe09SDavid du Colombier return;
1027*5c47fe09SDavid du Colombier
1028*5c47fe09SDavid du Colombier io = ep->aux;
1029*5c47fe09SDavid du Colombier if(io == nil)
1030*5c47fe09SDavid du Colombier return;
1031*5c47fe09SDavid du Colombier ep->aux = nil;
1032*5c47fe09SDavid du Colombier
1033*5c47fe09SDavid du Colombier ctlr = ep->hp->aux;
1034*5c47fe09SDavid du Colombier slot = ep->dev->aux;
1035*5c47fe09SDavid du Colombier
1036*5c47fe09SDavid du Colombier if(ep->nb > 0 && (io[OREAD].ring != nil || io[OWRITE].ring != nil)){
1037*5c47fe09SDavid du Colombier u32int *w;
1038*5c47fe09SDavid du Colombier
1039*5c47fe09SDavid du Colombier /* input control context */
1040*5c47fe09SDavid du Colombier w = slot->ibase;
1041*5c47fe09SDavid du Colombier memset(w, 0, 32<<ctlr->csz);
1042*5c47fe09SDavid du Colombier w[1] = 1;
1043*5c47fe09SDavid du Colombier if((ring = io[OREAD].ring) != nil){
1044*5c47fe09SDavid du Colombier w[0] |= 1 << ring->id;
1045*5c47fe09SDavid du Colombier if(ring->id == slot->nep)
1046*5c47fe09SDavid du Colombier slot->nep--;
1047*5c47fe09SDavid du Colombier ctlrcmd(ctlr, CR_STOPEP | (ring->id<<16) | (slot->id<<24), 0, 0, nil);
1048*5c47fe09SDavid du Colombier }
1049*5c47fe09SDavid du Colombier if((ring = io[OWRITE].ring) != nil){
1050*5c47fe09SDavid du Colombier w[0] |= 1 << ring->id;
1051*5c47fe09SDavid du Colombier if(ring->id == slot->nep)
1052*5c47fe09SDavid du Colombier slot->nep--;
1053*5c47fe09SDavid du Colombier ctlrcmd(ctlr, CR_STOPEP | (ring->id<<16) | (slot->id<<24), 0, 0, nil);
1054*5c47fe09SDavid du Colombier }
1055*5c47fe09SDavid du Colombier
1056*5c47fe09SDavid du Colombier /* (input) slot context */
1057*5c47fe09SDavid du Colombier w += 8<<ctlr->csz;
1058*5c47fe09SDavid du Colombier w[0] = (w[0] & ~(0x1F<<27)) | slot->nep<<27;
1059*5c47fe09SDavid du Colombier
1060*5c47fe09SDavid du Colombier /* (input) ep context */
1061*5c47fe09SDavid du Colombier w += ep->nb*2*8<<ctlr->csz;
1062*5c47fe09SDavid du Colombier memset(w, 0, 2*32<<ctlr->csz);
1063*5c47fe09SDavid du Colombier
1064*5c47fe09SDavid du Colombier dmaflush(1, slot->ibase, 32*33 << ctlr->csz);
1065*5c47fe09SDavid du Colombier ctlrcmd(ctlr, CR_CONFIGEP | (slot->id<<24), 0, PCIWADDR(slot->ibase), nil);
1066*5c47fe09SDavid du Colombier dmaflush(0, slot->obase, 32*32 << ctlr->csz);
1067*5c47fe09SDavid du Colombier
1068*5c47fe09SDavid du Colombier freering(io[OREAD].ring);
1069*5c47fe09SDavid du Colombier freering(io[OWRITE].ring);
1070*5c47fe09SDavid du Colombier }
1071*5c47fe09SDavid du Colombier freeb(io[OREAD].b);
1072*5c47fe09SDavid du Colombier freeb(io[OWRITE].b);
1073*5c47fe09SDavid du Colombier free(io);
1074*5c47fe09SDavid du Colombier }
1075*5c47fe09SDavid du Colombier
1076*5c47fe09SDavid du Colombier static void
initepctx(u32int * w,Ring * r,Ep * ep)1077*5c47fe09SDavid du Colombier initepctx(u32int *w, Ring *r, Ep *ep)
1078*5c47fe09SDavid du Colombier {
1079*5c47fe09SDavid du Colombier int ival;
1080*5c47fe09SDavid du Colombier
1081*5c47fe09SDavid du Colombier if(ep->dev->speed == Lowspeed || ep->dev->speed == Fullspeed){
1082*5c47fe09SDavid du Colombier for(ival=3; ival < 11 && (1<<ival) < ep->pollival; ival++)
1083*5c47fe09SDavid du Colombier ;
1084*5c47fe09SDavid du Colombier } else {
1085*5c47fe09SDavid du Colombier for(ival=0; ival < 15 && (1<<ival) < ep->pollival; ival++)
1086*5c47fe09SDavid du Colombier ;
1087*5c47fe09SDavid du Colombier }
1088*5c47fe09SDavid du Colombier w[0] = ival<<16;
1089*5c47fe09SDavid du Colombier w[1] = ((ep->ttype-Tctl) | (r->id&1)<<2)<<3 | (ep->ntds-1)<<8 | ep->maxpkt<<16;
1090*5c47fe09SDavid du Colombier if(ep->ttype != Tiso)
1091*5c47fe09SDavid du Colombier w[1] |= 3<<1;
1092*5c47fe09SDavid du Colombier *((u64int*)&w[2]) = PCIWADDR(r->base) | 1;
1093*5c47fe09SDavid du Colombier w[4] = 2*ep->maxpkt;
1094*5c47fe09SDavid du Colombier if(ep->ttype == Tintr || ep->ttype == Tiso)
1095*5c47fe09SDavid du Colombier w[4] |= (ep->maxpkt*ep->ntds)<<16;
1096*5c47fe09SDavid du Colombier }
1097*5c47fe09SDavid du Colombier
1098*5c47fe09SDavid du Colombier static void
initisoio(Epio * io,Ep * ep)1099*5c47fe09SDavid du Colombier initisoio(Epio *io, Ep *ep)
1100*5c47fe09SDavid du Colombier {
1101*5c47fe09SDavid du Colombier if(io->ring == nil)
1102*5c47fe09SDavid du Colombier return;
1103*5c47fe09SDavid du Colombier io->frame = 0;
1104*5c47fe09SDavid du Colombier io->period = ep->pollival<<3*(ep->dev->speed == Fullspeed);
1105*5c47fe09SDavid du Colombier io->incr = (ep->hz*io->period<<8)/8000;
1106*5c47fe09SDavid du Colombier io->tdsz = (io->incr+255>>8)*ep->samplesz;
1107*5c47fe09SDavid du Colombier io->b = allocb((io->ring->mask+1)*io->tdsz);
1108*5c47fe09SDavid du Colombier }
1109*5c47fe09SDavid du Colombier
1110*5c47fe09SDavid du Colombier static void
initep(Ep * ep)1111*5c47fe09SDavid du Colombier initep(Ep *ep)
1112*5c47fe09SDavid du Colombier {
1113*5c47fe09SDavid du Colombier Epio *io;
1114*5c47fe09SDavid du Colombier Ctlr *ctlr;
1115*5c47fe09SDavid du Colombier Slot *slot;
1116*5c47fe09SDavid du Colombier Ring *ring;
1117*5c47fe09SDavid du Colombier u32int *w;
1118*5c47fe09SDavid du Colombier char *err;
1119*5c47fe09SDavid du Colombier
1120*5c47fe09SDavid du Colombier io = ep->aux;
1121*5c47fe09SDavid du Colombier ctlr = ep->hp->aux;
1122*5c47fe09SDavid du Colombier slot = ep->dev->aux;
1123*5c47fe09SDavid du Colombier
1124*5c47fe09SDavid du Colombier io[OREAD].ring = io[OWRITE].ring = nil;
1125*5c47fe09SDavid du Colombier if(ep->nb == 0){
1126*5c47fe09SDavid du Colombier io[OWRITE].ring = &slot->epr[0];
1127*5c47fe09SDavid du Colombier return;
1128*5c47fe09SDavid du Colombier }
1129*5c47fe09SDavid du Colombier
1130*5c47fe09SDavid du Colombier /* (input) control context */
1131*5c47fe09SDavid du Colombier w = slot->ibase;
1132*5c47fe09SDavid du Colombier memset(w, 0, 32<<ctlr->csz);
1133*5c47fe09SDavid du Colombier w[1] = 1;
1134*5c47fe09SDavid du Colombier w[31] = slot->altc<<16 | slot->iface<<8 | slot->confval;
1135*5c47fe09SDavid du Colombier
1136*5c47fe09SDavid du Colombier if(waserror()){
1137*5c47fe09SDavid du Colombier freering(io[OWRITE].ring), io[OWRITE].ring = nil;
1138*5c47fe09SDavid du Colombier freering(io[OREAD].ring), io[OREAD].ring = nil;
1139*5c47fe09SDavid du Colombier nexterror();
1140*5c47fe09SDavid du Colombier }
1141*5c47fe09SDavid du Colombier if(ep->mode != OREAD){
1142*5c47fe09SDavid du Colombier ring = initring(io[OWRITE].ring = &slot->epr[ep->nb*2-1], 8);
1143*5c47fe09SDavid du Colombier ring->id = ep->nb*2;
1144*5c47fe09SDavid du Colombier if(ring->id > slot->nep)
1145*5c47fe09SDavid du Colombier slot->nep = ring->id;
1146*5c47fe09SDavid du Colombier ring->slot = slot;
1147*5c47fe09SDavid du Colombier ring->doorbell = &ctlr->dba[slot->id];
1148*5c47fe09SDavid du Colombier ring->ctx = &slot->obase[ring->id*8<<ctlr->csz];
1149*5c47fe09SDavid du Colombier w[1] |= 1 << ring->id;
1150*5c47fe09SDavid du Colombier }
1151*5c47fe09SDavid du Colombier if(ep->mode != OWRITE){
1152*5c47fe09SDavid du Colombier ring = initring(io[OREAD].ring = &slot->epr[ep->nb*2], 8);
1153*5c47fe09SDavid du Colombier ring->id = ep->nb*2+1;
1154*5c47fe09SDavid du Colombier if(ring->id > slot->nep)
1155*5c47fe09SDavid du Colombier slot->nep = ring->id;
1156*5c47fe09SDavid du Colombier ring->slot = slot;
1157*5c47fe09SDavid du Colombier ring->doorbell = &ctlr->dba[slot->id];
1158*5c47fe09SDavid du Colombier ring->ctx = &slot->obase[ring->id*8<<ctlr->csz];
1159*5c47fe09SDavid du Colombier w[1] |= 1 << ring->id;
1160*5c47fe09SDavid du Colombier }
1161*5c47fe09SDavid du Colombier
1162*5c47fe09SDavid du Colombier /* (input) slot context */
1163*5c47fe09SDavid du Colombier w += 8<<ctlr->csz;
1164*5c47fe09SDavid du Colombier w[0] = (w[0] & ~(0x1F<<27)) | slot->nep<<27;
1165*5c47fe09SDavid du Colombier if(!ep->dev->ishub)
1166*5c47fe09SDavid du Colombier w[0] &= ~(1<<25); // MTT
1167*5c47fe09SDavid du Colombier
1168*5c47fe09SDavid du Colombier /* (input) ep context */
1169*5c47fe09SDavid du Colombier w += ep->nb*2*8<<ctlr->csz;
1170*5c47fe09SDavid du Colombier if(io[OWRITE].ring != nil){
1171*5c47fe09SDavid du Colombier memset(w, 0, 5*4);
1172*5c47fe09SDavid du Colombier initepctx(w, io[OWRITE].ring, ep);
1173*5c47fe09SDavid du Colombier }
1174*5c47fe09SDavid du Colombier
1175*5c47fe09SDavid du Colombier w += 8<<ctlr->csz;
1176*5c47fe09SDavid du Colombier if(io[OREAD].ring != nil){
1177*5c47fe09SDavid du Colombier memset(w, 0, 5*4);
1178*5c47fe09SDavid du Colombier initepctx(w, io[OREAD].ring, ep);
1179*5c47fe09SDavid du Colombier }
1180*5c47fe09SDavid du Colombier
1181*5c47fe09SDavid du Colombier dmaflush(1, slot->ibase, 32*33 << ctlr->csz);
1182*5c47fe09SDavid du Colombier err = ctlrcmd(ctlr, CR_CONFIGEP | (slot->id<<24), 0, PCIWADDR(slot->ibase), nil);
1183*5c47fe09SDavid du Colombier dmaflush(0, slot->obase, 32*32 << ctlr->csz);
1184*5c47fe09SDavid du Colombier if(err != nil)
1185*5c47fe09SDavid du Colombier error(err);
1186*5c47fe09SDavid du Colombier
1187*5c47fe09SDavid du Colombier if(ep->ttype == Tiso){
1188*5c47fe09SDavid du Colombier initisoio(io+OWRITE, ep);
1189*5c47fe09SDavid du Colombier initisoio(io+OREAD, ep);
1190*5c47fe09SDavid du Colombier }
1191*5c47fe09SDavid du Colombier poperror();
1192*5c47fe09SDavid du Colombier }
1193*5c47fe09SDavid du Colombier
1194*5c47fe09SDavid du Colombier static int
speedid(int speed)1195*5c47fe09SDavid du Colombier speedid(int speed)
1196*5c47fe09SDavid du Colombier {
1197*5c47fe09SDavid du Colombier switch(speed){
1198*5c47fe09SDavid du Colombier case Fullspeed: return 1;
1199*5c47fe09SDavid du Colombier case Lowspeed: return 2;
1200*5c47fe09SDavid du Colombier case Highspeed: return 3;
1201*5c47fe09SDavid du Colombier case Superspeed: return 4;
1202*5c47fe09SDavid du Colombier }
1203*5c47fe09SDavid du Colombier return 0;
1204*5c47fe09SDavid du Colombier }
1205*5c47fe09SDavid du Colombier
1206*5c47fe09SDavid du Colombier static void
epopen(Ep * ep)1207*5c47fe09SDavid du Colombier epopen(Ep *ep)
1208*5c47fe09SDavid du Colombier {
1209*5c47fe09SDavid du Colombier Ctlr *ctlr = ep->hp->aux;
1210*5c47fe09SDavid du Colombier Slot *slot, *hub;
1211*5c47fe09SDavid du Colombier Ring *ring;
1212*5c47fe09SDavid du Colombier Epio *io;
1213*5c47fe09SDavid du Colombier Udev *dev;
1214*5c47fe09SDavid du Colombier char *err;
1215*5c47fe09SDavid du Colombier u32int *w;
1216*5c47fe09SDavid du Colombier int i;
1217*5c47fe09SDavid du Colombier
1218*5c47fe09SDavid du Colombier if(ep->dev->isroot)
1219*5c47fe09SDavid du Colombier return;
1220*5c47fe09SDavid du Colombier if(needrecover(ctlr))
1221*5c47fe09SDavid du Colombier error(Erecover);
1222*5c47fe09SDavid du Colombier io = malloc(sizeof(Epio)*2);
1223*5c47fe09SDavid du Colombier if(io == nil)
1224*5c47fe09SDavid du Colombier error(Enomem);
1225*5c47fe09SDavid du Colombier ep->aux = io;
1226*5c47fe09SDavid du Colombier if(waserror()){
1227*5c47fe09SDavid du Colombier epclose(ep);
1228*5c47fe09SDavid du Colombier nexterror();
1229*5c47fe09SDavid du Colombier }
1230*5c47fe09SDavid du Colombier dev = ep->dev;
1231*5c47fe09SDavid du Colombier slot = dev->aux;
1232*5c47fe09SDavid du Colombier if(slot != nil && slot->dev == dev){
1233*5c47fe09SDavid du Colombier initep(ep);
1234*5c47fe09SDavid du Colombier poperror();
1235*5c47fe09SDavid du Colombier return;
1236*5c47fe09SDavid du Colombier }
1237*5c47fe09SDavid du Colombier
1238*5c47fe09SDavid du Colombier /* first open has to be control endpoint */
1239*5c47fe09SDavid du Colombier if(ep->nb != 0)
1240*5c47fe09SDavid du Colombier error(Egreg);
1241*5c47fe09SDavid du Colombier
1242*5c47fe09SDavid du Colombier slot = allocslot(ctlr, dev);
1243*5c47fe09SDavid du Colombier if(waserror()){
1244*5c47fe09SDavid du Colombier freeslot(slot);
1245*5c47fe09SDavid du Colombier nexterror();
1246*5c47fe09SDavid du Colombier }
1247*5c47fe09SDavid du Colombier
1248*5c47fe09SDavid du Colombier /* allocate control ep 0 ring */
1249*5c47fe09SDavid du Colombier ring = initring(io[OWRITE].ring = &slot->epr[0], 4);
1250*5c47fe09SDavid du Colombier ring->id = 1;
1251*5c47fe09SDavid du Colombier slot->nep = 1;
1252*5c47fe09SDavid du Colombier ring->slot = slot;
1253*5c47fe09SDavid du Colombier ring->doorbell = &ctlr->dba[slot->id];
1254*5c47fe09SDavid du Colombier ring->ctx = &slot->obase[8];
1255*5c47fe09SDavid du Colombier
1256*5c47fe09SDavid du Colombier /* (input) control context */
1257*5c47fe09SDavid du Colombier w = slot->ibase;
1258*5c47fe09SDavid du Colombier memset(w, 0, 3*32<<ctlr->csz);
1259*5c47fe09SDavid du Colombier w[1] = 3; /* A0, A1 */
1260*5c47fe09SDavid du Colombier
1261*5c47fe09SDavid du Colombier /* (input) slot context */
1262*5c47fe09SDavid du Colombier w += 8<<ctlr->csz;
1263*5c47fe09SDavid du Colombier w[2] = w[3] = 0;
1264*5c47fe09SDavid du Colombier w[0] = dev->routestr | speedid(dev->speed)<<20 |
1265*5c47fe09SDavid du Colombier (dev->speed == Highspeed && dev->ishub != 0)<<25 | // MTT
1266*5c47fe09SDavid du Colombier (dev->ishub != 0)<<26 | slot->nep<<27;
1267*5c47fe09SDavid du Colombier w[1] = dev->rootport<<16;
1268*5c47fe09SDavid du Colombier
1269*5c47fe09SDavid du Colombier /* find the parent hub that this device is conected to */
1270*5c47fe09SDavid du Colombier qlock(&ctlr->slotlock);
1271*5c47fe09SDavid du Colombier for(i=1; i<=ctlr->nslots; i++){
1272*5c47fe09SDavid du Colombier hub = ctlr->slot[i];
1273*5c47fe09SDavid du Colombier if(hub == nil || hub->dev == nil || hub->dev->aux != hub)
1274*5c47fe09SDavid du Colombier continue;
1275*5c47fe09SDavid du Colombier if(hub == slot || hub->dev == dev)
1276*5c47fe09SDavid du Colombier continue;
1277*5c47fe09SDavid du Colombier if(!hub->dev->ishub)
1278*5c47fe09SDavid du Colombier continue;
1279*5c47fe09SDavid du Colombier if(hub->dev->addr != dev->hub)
1280*5c47fe09SDavid du Colombier continue;
1281*5c47fe09SDavid du Colombier if(hub->dev->rootport != dev->rootport)
1282*5c47fe09SDavid du Colombier continue;
1283*5c47fe09SDavid du Colombier
1284*5c47fe09SDavid du Colombier if(dev->speed < Highspeed && hub->dev->speed == Highspeed){
1285*5c47fe09SDavid du Colombier w[0] |= 1<<25; // MTT
1286*5c47fe09SDavid du Colombier w[2] = hub->id | dev->port<<8;
1287*5c47fe09SDavid du Colombier }
1288*5c47fe09SDavid du Colombier break;
1289*5c47fe09SDavid du Colombier }
1290*5c47fe09SDavid du Colombier qunlock(&ctlr->slotlock);
1291*5c47fe09SDavid du Colombier
1292*5c47fe09SDavid du Colombier /* (input) ep context 0 */
1293*5c47fe09SDavid du Colombier w += 8<<ctlr->csz;
1294*5c47fe09SDavid du Colombier initepctx(w, io[OWRITE].ring, ep);
1295*5c47fe09SDavid du Colombier
1296*5c47fe09SDavid du Colombier dmaflush(1, slot->ibase, 32*33 << ctlr->csz);
1297*5c47fe09SDavid du Colombier err = ctlrcmd(ctlr, CR_ADDRESSDEV | (slot->id<<24), 0, PCIWADDR(slot->ibase), nil);
1298*5c47fe09SDavid du Colombier dmaflush(0, slot->obase, 32*32 << ctlr->csz);
1299*5c47fe09SDavid du Colombier if(err != nil)
1300*5c47fe09SDavid du Colombier error(err);
1301*5c47fe09SDavid du Colombier
1302*5c47fe09SDavid du Colombier /* (output) slot context */
1303*5c47fe09SDavid du Colombier w = slot->obase;
1304*5c47fe09SDavid du Colombier
1305*5c47fe09SDavid du Colombier dev->addr = w[3] & 0xFF;
1306*5c47fe09SDavid du Colombier
1307*5c47fe09SDavid du Colombier dev->aux = slot;
1308*5c47fe09SDavid du Colombier dev->free = freeslot;
1309*5c47fe09SDavid du Colombier
1310*5c47fe09SDavid du Colombier poperror();
1311*5c47fe09SDavid du Colombier poperror();
1312*5c47fe09SDavid du Colombier }
1313*5c47fe09SDavid du Colombier
1314*5c47fe09SDavid du Colombier static long
isoread(Ep *,uchar *,long)1315*5c47fe09SDavid du Colombier isoread(Ep *, uchar *, long)
1316*5c47fe09SDavid du Colombier {
1317*5c47fe09SDavid du Colombier error(Egreg);
1318*5c47fe09SDavid du Colombier return 0;
1319*5c47fe09SDavid du Colombier }
1320*5c47fe09SDavid du Colombier
1321*5c47fe09SDavid du Colombier static long
isowrite(Ep * ep,uchar * p,long n)1322*5c47fe09SDavid du Colombier isowrite(Ep *ep, uchar *p, long n)
1323*5c47fe09SDavid du Colombier {
1324*5c47fe09SDavid du Colombier uchar *s, *d;
1325*5c47fe09SDavid du Colombier Ctlr *ctlr;
1326*5c47fe09SDavid du Colombier Epio *io;
1327*5c47fe09SDavid du Colombier u32int i, µ;
1328*5c47fe09SDavid du Colombier long m;
1329*5c47fe09SDavid du Colombier
1330*5c47fe09SDavid du Colombier s = p;
1331*5c47fe09SDavid du Colombier io = (Epio*)ep->aux + OWRITE;
1332*5c47fe09SDavid du Colombier qlock(io);
1333*5c47fe09SDavid du Colombier if(waserror()){
1334*5c47fe09SDavid du Colombier qunlock(io);
1335*5c47fe09SDavid du Colombier nexterror();
1336*5c47fe09SDavid du Colombier }
1337*5c47fe09SDavid du Colombier µ = io->period;
1338*5c47fe09SDavid du Colombier ctlr = ep->hp->aux;
1339*5c47fe09SDavid du Colombier if(needrecover(ctlr))
1340*5c47fe09SDavid du Colombier error(Erecover);
1341*5c47fe09SDavid du Colombier for(i = io->frame;; i++){
1342*5c47fe09SDavid du Colombier for(;;){
1343*5c47fe09SDavid du Colombier m = (int)(io->ring->wp - io->ring->rp);
1344*5c47fe09SDavid du Colombier if(m <= 0)
1345*5c47fe09SDavid du Colombier i = (80 + µframe(ctlr))/µ;
1346*5c47fe09SDavid du Colombier if(m < io->ring->mask)
1347*5c47fe09SDavid du Colombier break;
1348*5c47fe09SDavid du Colombier *io->ring->doorbell = io->ring->id;
1349*5c47fe09SDavid du Colombier tsleep(&up->sleep, return0, nil, 5);
1350*5c47fe09SDavid du Colombier }
1351*5c47fe09SDavid du Colombier m = ((io->incr + (i*io->incr&255))>>8)*ep->samplesz;
1352*5c47fe09SDavid du Colombier d = io->b->rp + (i&io->ring->mask)*io->tdsz;
1353*5c47fe09SDavid du Colombier m -= io->nleft, d += io->nleft;
1354*5c47fe09SDavid du Colombier if(n < m){
1355*5c47fe09SDavid du Colombier memmove(d, p, n);
1356*5c47fe09SDavid du Colombier p += n;
1357*5c47fe09SDavid du Colombier io->nleft += n;
1358*5c47fe09SDavid du Colombier break;
1359*5c47fe09SDavid du Colombier }
1360*5c47fe09SDavid du Colombier memmove(d, p, m);
1361*5c47fe09SDavid du Colombier p += m, n -= m;
1362*5c47fe09SDavid du Colombier m += io->nleft, d -= io->nleft;
1363*5c47fe09SDavid du Colombier io->nleft = 0;
1364*5c47fe09SDavid du Colombier dmaflush(1, d, m);
1365*5c47fe09SDavid du Colombier queuetd(io->ring, TR_ISOCH | (i*µ/8 & 0x7ff)<<20 | TR_IOC, m, PCIWADDR(d), nil);
1366*5c47fe09SDavid du Colombier }
1367*5c47fe09SDavid du Colombier io->frame = i;
1368*5c47fe09SDavid du Colombier while(io->ring->rp != io->ring->wp){
1369*5c47fe09SDavid du Colombier int d = (int)(i*µ - µframe(ctlr))/8;
1370*5c47fe09SDavid du Colombier //d -= ep->sampledelay*1000 / ep->hz;
1371*5c47fe09SDavid du Colombier if(d < 5)
1372*5c47fe09SDavid du Colombier break;
1373*5c47fe09SDavid du Colombier *io->ring->doorbell = io->ring->id;
1374*5c47fe09SDavid du Colombier tsleep(&up->sleep, return0, nil, d);
1375*5c47fe09SDavid du Colombier }
1376*5c47fe09SDavid du Colombier qunlock(io);
1377*5c47fe09SDavid du Colombier poperror();
1378*5c47fe09SDavid du Colombier
1379*5c47fe09SDavid du Colombier return p - s;
1380*5c47fe09SDavid du Colombier }
1381*5c47fe09SDavid du Colombier
1382*5c47fe09SDavid du Colombier static char*
unstall(Ep * ep,Ring * r)1383*5c47fe09SDavid du Colombier unstall(Ep *ep, Ring *r)
1384*5c47fe09SDavid du Colombier {
1385*5c47fe09SDavid du Colombier char *err;
1386*5c47fe09SDavid du Colombier
1387*5c47fe09SDavid du Colombier switch(r->ctx[0]&7){
1388*5c47fe09SDavid du Colombier case 2: /* halted */
1389*5c47fe09SDavid du Colombier case 4: /* error */
1390*5c47fe09SDavid du Colombier ep->clrhalt = 1;
1391*5c47fe09SDavid du Colombier }
1392*5c47fe09SDavid du Colombier if(ep->clrhalt){
1393*5c47fe09SDavid du Colombier ep->clrhalt = 0;
1394*5c47fe09SDavid du Colombier err = ctlrcmd(r->slot->ctlr, CR_RESETEP | (r->id<<16) | (r->slot->id<<24), 0, 0, nil);
1395*5c47fe09SDavid du Colombier dmaflush(0, r->ctx, 8*4 << r->slot->ctlr->csz);
1396*5c47fe09SDavid du Colombier if(err != nil)
1397*5c47fe09SDavid du Colombier return err;
1398*5c47fe09SDavid du Colombier r->stopped = 1;
1399*5c47fe09SDavid du Colombier }
1400*5c47fe09SDavid du Colombier if(r->stopped){
1401*5c47fe09SDavid du Colombier err = ctlrcmd(r->slot->ctlr, CR_SETTRDQP | (r->id<<16) | (r->slot->id<<24), 0, resetring(r), nil);
1402*5c47fe09SDavid du Colombier dmaflush(0, r->ctx, 8*4 << r->slot->ctlr->csz);
1403*5c47fe09SDavid du Colombier if(err != nil)
1404*5c47fe09SDavid du Colombier return err;
1405*5c47fe09SDavid du Colombier r->stopped = 0;
1406*5c47fe09SDavid du Colombier }
1407*5c47fe09SDavid du Colombier if(r->wp - r->rp >= r->mask)
1408*5c47fe09SDavid du Colombier return "Ring Full";
1409*5c47fe09SDavid du Colombier return nil;
1410*5c47fe09SDavid du Colombier }
1411*5c47fe09SDavid du Colombier
1412*5c47fe09SDavid du Colombier static long
epread(Ep * ep,void * va,long n)1413*5c47fe09SDavid du Colombier epread(Ep *ep, void *va, long n)
1414*5c47fe09SDavid du Colombier {
1415*5c47fe09SDavid du Colombier Epio *io;
1416*5c47fe09SDavid du Colombier Ctlr *ctlr;
1417*5c47fe09SDavid du Colombier uchar *p;
1418*5c47fe09SDavid du Colombier char *err;
1419*5c47fe09SDavid du Colombier Wait w[1];
1420*5c47fe09SDavid du Colombier
1421*5c47fe09SDavid du Colombier if(ep->dev->isroot)
1422*5c47fe09SDavid du Colombier error(Egreg);
1423*5c47fe09SDavid du Colombier
1424*5c47fe09SDavid du Colombier p = va;
1425*5c47fe09SDavid du Colombier if(ep->ttype == Tctl){
1426*5c47fe09SDavid du Colombier io = (Epio*)ep->aux + OREAD;
1427*5c47fe09SDavid du Colombier qlock(io);
1428*5c47fe09SDavid du Colombier if(io->b == nil || BLEN(io->b) == 0){
1429*5c47fe09SDavid du Colombier qunlock(io);
1430*5c47fe09SDavid du Colombier return 0;
1431*5c47fe09SDavid du Colombier }
1432*5c47fe09SDavid du Colombier if(n > BLEN(io->b))
1433*5c47fe09SDavid du Colombier n = BLEN(io->b);
1434*5c47fe09SDavid du Colombier memmove(p, io->b->rp, n);
1435*5c47fe09SDavid du Colombier io->b->rp += n;
1436*5c47fe09SDavid du Colombier qunlock(io);
1437*5c47fe09SDavid du Colombier return n;
1438*5c47fe09SDavid du Colombier } else if(ep->ttype == Tiso)
1439*5c47fe09SDavid du Colombier return isoread(ep, p, n);
1440*5c47fe09SDavid du Colombier
1441*5c47fe09SDavid du Colombier if((uintptr)p <= KZERO){
1442*5c47fe09SDavid du Colombier Block *b;
1443*5c47fe09SDavid du Colombier
1444*5c47fe09SDavid du Colombier b = allocb(n);
1445*5c47fe09SDavid du Colombier if(waserror()){
1446*5c47fe09SDavid du Colombier freeb(b);
1447*5c47fe09SDavid du Colombier nexterror();
1448*5c47fe09SDavid du Colombier }
1449*5c47fe09SDavid du Colombier n = epread(ep, b->rp, n);
1450*5c47fe09SDavid du Colombier memmove(p, b->rp, n);
1451*5c47fe09SDavid du Colombier freeb(b);
1452*5c47fe09SDavid du Colombier poperror();
1453*5c47fe09SDavid du Colombier return n;
1454*5c47fe09SDavid du Colombier }
1455*5c47fe09SDavid du Colombier
1456*5c47fe09SDavid du Colombier ctlr = (Ctlr*)ep->hp->aux;
1457*5c47fe09SDavid du Colombier io = (Epio*)ep->aux + OREAD;
1458*5c47fe09SDavid du Colombier qlock(io);
1459*5c47fe09SDavid du Colombier if(waserror()){
1460*5c47fe09SDavid du Colombier dmaflush(0, io->ring->ctx, 8*4 << ctlr->csz);
1461*5c47fe09SDavid du Colombier qunlock(io);
1462*5c47fe09SDavid du Colombier nexterror();
1463*5c47fe09SDavid du Colombier }
1464*5c47fe09SDavid du Colombier
1465*5c47fe09SDavid du Colombier if((err = unstall(ep, io->ring)) != nil)
1466*5c47fe09SDavid du Colombier error(err);
1467*5c47fe09SDavid du Colombier
1468*5c47fe09SDavid du Colombier dmaflush(1, p, n);
1469*5c47fe09SDavid du Colombier queuetd(io->ring, TR_NORMAL | TR_IOC, n, PCIWADDR(p), w);
1470*5c47fe09SDavid du Colombier err = waittd(ctlr, w, ep->tmout);
1471*5c47fe09SDavid du Colombier dmaflush(0, p, n);
1472*5c47fe09SDavid du Colombier if(err != nil)
1473*5c47fe09SDavid du Colombier error(err);
1474*5c47fe09SDavid du Colombier
1475*5c47fe09SDavid du Colombier qunlock(io);
1476*5c47fe09SDavid du Colombier poperror();
1477*5c47fe09SDavid du Colombier
1478*5c47fe09SDavid du Colombier n -= (w->er[2] & 0xFFFFFF);
1479*5c47fe09SDavid du Colombier if(n < 0)
1480*5c47fe09SDavid du Colombier n = 0;
1481*5c47fe09SDavid du Colombier
1482*5c47fe09SDavid du Colombier return n;
1483*5c47fe09SDavid du Colombier }
1484*5c47fe09SDavid du Colombier
1485*5c47fe09SDavid du Colombier static long
epwrite(Ep * ep,void * va,long n)1486*5c47fe09SDavid du Colombier epwrite(Ep *ep, void *va, long n)
1487*5c47fe09SDavid du Colombier {
1488*5c47fe09SDavid du Colombier Wait w[3];
1489*5c47fe09SDavid du Colombier Ctlr *ctlr;
1490*5c47fe09SDavid du Colombier Epio *io;
1491*5c47fe09SDavid du Colombier uchar *p;
1492*5c47fe09SDavid du Colombier char *err;
1493*5c47fe09SDavid du Colombier
1494*5c47fe09SDavid du Colombier if(ep->dev->isroot)
1495*5c47fe09SDavid du Colombier error(Egreg);
1496*5c47fe09SDavid du Colombier
1497*5c47fe09SDavid du Colombier p = va;
1498*5c47fe09SDavid du Colombier if(ep->ttype == Tctl){
1499*5c47fe09SDavid du Colombier int dir, len;
1500*5c47fe09SDavid du Colombier Ring *ring;
1501*5c47fe09SDavid du Colombier Slot *slot;
1502*5c47fe09SDavid du Colombier
1503*5c47fe09SDavid du Colombier if(n < 8)
1504*5c47fe09SDavid du Colombier error(Eshort);
1505*5c47fe09SDavid du Colombier
1506*5c47fe09SDavid du Colombier if(p[0] == 0x00 && p[1] == 0x05)
1507*5c47fe09SDavid du Colombier return n;
1508*5c47fe09SDavid du Colombier
1509*5c47fe09SDavid du Colombier ctlr = (Ctlr*)ep->hp->aux;
1510*5c47fe09SDavid du Colombier io = (Epio*)ep->aux + OREAD;
1511*5c47fe09SDavid du Colombier ring = io[OWRITE-OREAD].ring;
1512*5c47fe09SDavid du Colombier slot = ring->slot;
1513*5c47fe09SDavid du Colombier qlock(io);
1514*5c47fe09SDavid du Colombier if(waserror()){
1515*5c47fe09SDavid du Colombier ilock(ring);
1516*5c47fe09SDavid du Colombier ring->pending = nil;
1517*5c47fe09SDavid du Colombier iunlock(ring);
1518*5c47fe09SDavid du Colombier dmaflush(0, ring->ctx, 8*4 << ctlr->csz);
1519*5c47fe09SDavid du Colombier qunlock(io);
1520*5c47fe09SDavid du Colombier nexterror();
1521*5c47fe09SDavid du Colombier }
1522*5c47fe09SDavid du Colombier if(io->b != nil){
1523*5c47fe09SDavid du Colombier freeb(io->b);
1524*5c47fe09SDavid du Colombier io->b = nil;
1525*5c47fe09SDavid du Colombier }
1526*5c47fe09SDavid du Colombier len = GET2(&p[6]);
1527*5c47fe09SDavid du Colombier dir = (p[0] & Rd2h) != 0;
1528*5c47fe09SDavid du Colombier if(len > 0){
1529*5c47fe09SDavid du Colombier io->b = allocb(len);
1530*5c47fe09SDavid du Colombier if(dir == 0){ /* out */
1531*5c47fe09SDavid du Colombier assert(len >= n-8);
1532*5c47fe09SDavid du Colombier memmove(io->b->wp, p+8, n-8);
1533*5c47fe09SDavid du Colombier } else {
1534*5c47fe09SDavid du Colombier memset(io->b->wp, 0, len);
1535*5c47fe09SDavid du Colombier io->b->wp += len;
1536*5c47fe09SDavid du Colombier }
1537*5c47fe09SDavid du Colombier }
1538*5c47fe09SDavid du Colombier if((err = unstall(ep, ring)) != nil)
1539*5c47fe09SDavid du Colombier error(err);
1540*5c47fe09SDavid du Colombier
1541*5c47fe09SDavid du Colombier if((ring->ctx[1]>>16) != ep->maxpkt){
1542*5c47fe09SDavid du Colombier u32int *w = slot->ibase;
1543*5c47fe09SDavid du Colombier w[0] = 0;
1544*5c47fe09SDavid du Colombier w[1] = 1<<ring->id;
1545*5c47fe09SDavid du Colombier w += (ring->id+1)*8<<ctlr->csz;
1546*5c47fe09SDavid du Colombier initepctx(w, ring, ep);
1547*5c47fe09SDavid du Colombier dmaflush(1, slot->ibase, 32*33 << ctlr->csz);
1548*5c47fe09SDavid du Colombier err = ctlrcmd(ctlr, CR_EVALCTX | (slot->id<<24), 0, PCIWADDR(slot->ibase), nil);
1549*5c47fe09SDavid du Colombier dmaflush(0, slot->obase, 32*32 << ctlr->csz);
1550*5c47fe09SDavid du Colombier if(err != nil)
1551*5c47fe09SDavid du Colombier error(err);
1552*5c47fe09SDavid du Colombier }
1553*5c47fe09SDavid du Colombier
1554*5c47fe09SDavid du Colombier queuetd(ring, TR_SETUPSTAGE | (len > 0 ? 2+dir : 0)<<16 | TR_IDT | TR_IOC, 8,
1555*5c47fe09SDavid du Colombier p[0] | p[1]<<8 | GET2(&p[2])<<16 |
1556*5c47fe09SDavid du Colombier (u64int)(GET2(&p[4]) | len<<16)<<32, &w[0]);
1557*5c47fe09SDavid du Colombier if(len > 0){
1558*5c47fe09SDavid du Colombier dmaflush(1, io->b->rp, len);
1559*5c47fe09SDavid du Colombier queuetd(ring, TR_DATASTAGE | dir<<16 | TR_IOC, len,
1560*5c47fe09SDavid du Colombier PCIWADDR(io->b->rp), &w[1]);
1561*5c47fe09SDavid du Colombier }
1562*5c47fe09SDavid du Colombier queuetd(ring, TR_STATUSSTAGE | (len == 0 || !dir)<<16 | TR_IOC, 0, 0, &w[2]);
1563*5c47fe09SDavid du Colombier
1564*5c47fe09SDavid du Colombier if((err = waittd(ctlr, &w[0], ep->tmout)) != nil)
1565*5c47fe09SDavid du Colombier error(err);
1566*5c47fe09SDavid du Colombier if(len > 0){
1567*5c47fe09SDavid du Colombier if((err = waittd(ctlr, &w[1], ep->tmout)) != nil)
1568*5c47fe09SDavid du Colombier error(err);
1569*5c47fe09SDavid du Colombier if(dir != 0){
1570*5c47fe09SDavid du Colombier dmaflush(0, io->b->rp, len);
1571*5c47fe09SDavid du Colombier io->b->wp -= (w[1].er[2] & 0xFFFFFF);
1572*5c47fe09SDavid du Colombier if(io->b->wp < io->b->rp)
1573*5c47fe09SDavid du Colombier io->b->wp = io->b->rp;
1574*5c47fe09SDavid du Colombier }
1575*5c47fe09SDavid du Colombier }
1576*5c47fe09SDavid du Colombier if((err = waittd(ctlr, &w[2], ep->tmout)) != nil)
1577*5c47fe09SDavid du Colombier error(err);
1578*5c47fe09SDavid du Colombier
1579*5c47fe09SDavid du Colombier if(p[0] == 0x00 && p[1] == 0x09){
1580*5c47fe09SDavid du Colombier slot->confval = GET2(&p[2]);
1581*5c47fe09SDavid du Colombier } else if(p[0] == 0x01 && p[1] == 0x0d){
1582*5c47fe09SDavid du Colombier slot->altc = GET2(&p[2]);
1583*5c47fe09SDavid du Colombier slot->iface = GET2(&p[4]);
1584*5c47fe09SDavid du Colombier }
1585*5c47fe09SDavid du Colombier
1586*5c47fe09SDavid du Colombier qunlock(io);
1587*5c47fe09SDavid du Colombier poperror();
1588*5c47fe09SDavid du Colombier
1589*5c47fe09SDavid du Colombier return n;
1590*5c47fe09SDavid du Colombier } else if(ep->ttype == Tiso)
1591*5c47fe09SDavid du Colombier return isowrite(ep, p, n);
1592*5c47fe09SDavid du Colombier
1593*5c47fe09SDavid du Colombier if((uintptr)p <= KZERO){
1594*5c47fe09SDavid du Colombier Block *b;
1595*5c47fe09SDavid du Colombier
1596*5c47fe09SDavid du Colombier b = allocb(n);
1597*5c47fe09SDavid du Colombier if(waserror()){
1598*5c47fe09SDavid du Colombier freeb(b);
1599*5c47fe09SDavid du Colombier nexterror();
1600*5c47fe09SDavid du Colombier }
1601*5c47fe09SDavid du Colombier memmove(b->wp, p, n);
1602*5c47fe09SDavid du Colombier n = epwrite(ep, b->wp, n);
1603*5c47fe09SDavid du Colombier freeb(b);
1604*5c47fe09SDavid du Colombier poperror();
1605*5c47fe09SDavid du Colombier return n;
1606*5c47fe09SDavid du Colombier }
1607*5c47fe09SDavid du Colombier
1608*5c47fe09SDavid du Colombier ctlr = (Ctlr*)ep->hp->aux;
1609*5c47fe09SDavid du Colombier io = (Epio*)ep->aux + OWRITE;
1610*5c47fe09SDavid du Colombier qlock(io);
1611*5c47fe09SDavid du Colombier if(waserror()){
1612*5c47fe09SDavid du Colombier dmaflush(0, io->ring->ctx, 8*4 << ctlr->csz);
1613*5c47fe09SDavid du Colombier qunlock(io);
1614*5c47fe09SDavid du Colombier nexterror();
1615*5c47fe09SDavid du Colombier }
1616*5c47fe09SDavid du Colombier
1617*5c47fe09SDavid du Colombier if((err = unstall(ep, io->ring)) != nil)
1618*5c47fe09SDavid du Colombier error(err);
1619*5c47fe09SDavid du Colombier
1620*5c47fe09SDavid du Colombier dmaflush(1, p, n);
1621*5c47fe09SDavid du Colombier queuetd(io->ring, TR_NORMAL | TR_IOC, n, PCIWADDR(p), w);
1622*5c47fe09SDavid du Colombier if((err = waittd(ctlr, w, ep->tmout)) != nil)
1623*5c47fe09SDavid du Colombier error(err);
1624*5c47fe09SDavid du Colombier
1625*5c47fe09SDavid du Colombier qunlock(io);
1626*5c47fe09SDavid du Colombier poperror();
1627*5c47fe09SDavid du Colombier
1628*5c47fe09SDavid du Colombier return n;
1629*5c47fe09SDavid du Colombier }
1630*5c47fe09SDavid du Colombier
1631*5c47fe09SDavid du Colombier static char*
seprintep(char * s,char *,Ep *)1632*5c47fe09SDavid du Colombier seprintep(char *s, char*, Ep*)
1633*5c47fe09SDavid du Colombier {
1634*5c47fe09SDavid du Colombier return s;
1635*5c47fe09SDavid du Colombier }
1636*5c47fe09SDavid du Colombier
1637*5c47fe09SDavid du Colombier static int
portstatus(Hci * hp,int port)1638*5c47fe09SDavid du Colombier portstatus(Hci *hp, int port)
1639*5c47fe09SDavid du Colombier {
1640*5c47fe09SDavid du Colombier Ctlr *ctlr = hp->aux;
1641*5c47fe09SDavid du Colombier u32int psc, ps;
1642*5c47fe09SDavid du Colombier
1643*5c47fe09SDavid du Colombier if(ctlr->port == nil || needrecover(ctlr))
1644*5c47fe09SDavid du Colombier return 0;
1645*5c47fe09SDavid du Colombier
1646*5c47fe09SDavid du Colombier ps = 0;
1647*5c47fe09SDavid du Colombier psc = ctlr->port[port-1].reg[PORTSC];
1648*5c47fe09SDavid du Colombier if(psc & CCS) ps |= HPpresent;
1649*5c47fe09SDavid du Colombier if(psc & PED) ps |= HPenable;
1650*5c47fe09SDavid du Colombier if(psc & OCA) ps |= HPovercurrent;
1651*5c47fe09SDavid du Colombier if(psc & PR) ps |= HPreset;
1652*5c47fe09SDavid du Colombier
1653*5c47fe09SDavid du Colombier if((hp->superspeed & (1<<(port-1))) != 0){
1654*5c47fe09SDavid du Colombier ps |= psc & (PLS|PP);
1655*5c47fe09SDavid du Colombier if(psc & CSC) ps |= 1<<0+16;
1656*5c47fe09SDavid du Colombier if(psc & OCC) ps |= 1<<3+16;
1657*5c47fe09SDavid du Colombier if(psc & PRC) ps |= 1<<4+16;
1658*5c47fe09SDavid du Colombier if(psc & WRC) ps |= 1<<5+16;
1659*5c47fe09SDavid du Colombier if(psc & PLC) ps |= 1<<6+16;
1660*5c47fe09SDavid du Colombier if(psc & CEC) ps |= 1<<7+16;
1661*5c47fe09SDavid du Colombier } else {
1662*5c47fe09SDavid du Colombier if((ps & HPreset) == 0){
1663*5c47fe09SDavid du Colombier switch((psc>>10)&15){
1664*5c47fe09SDavid du Colombier case 1:
1665*5c47fe09SDavid du Colombier /* full speed */
1666*5c47fe09SDavid du Colombier break;
1667*5c47fe09SDavid du Colombier case 2:
1668*5c47fe09SDavid du Colombier ps |= HPslow;
1669*5c47fe09SDavid du Colombier break;
1670*5c47fe09SDavid du Colombier case 3:
1671*5c47fe09SDavid du Colombier ps |= HPhigh;
1672*5c47fe09SDavid du Colombier break;
1673*5c47fe09SDavid du Colombier }
1674*5c47fe09SDavid du Colombier }
1675*5c47fe09SDavid du Colombier if(psc & PP) ps |= HPpower;
1676*5c47fe09SDavid du Colombier if(psc & CSC) ps |= HPstatuschg;
1677*5c47fe09SDavid du Colombier if(psc & PRC) ps |= HPchange;
1678*5c47fe09SDavid du Colombier }
1679*5c47fe09SDavid du Colombier
1680*5c47fe09SDavid du Colombier return ps;
1681*5c47fe09SDavid du Colombier }
1682*5c47fe09SDavid du Colombier
1683*5c47fe09SDavid du Colombier static int
portenable(Hci *,int,int)1684*5c47fe09SDavid du Colombier portenable(Hci*, int, int)
1685*5c47fe09SDavid du Colombier {
1686*5c47fe09SDavid du Colombier return 0;
1687*5c47fe09SDavid du Colombier }
1688*5c47fe09SDavid du Colombier
1689*5c47fe09SDavid du Colombier static int
portreset(Hci * hp,int port,int on)1690*5c47fe09SDavid du Colombier portreset(Hci *hp, int port, int on)
1691*5c47fe09SDavid du Colombier {
1692*5c47fe09SDavid du Colombier Ctlr *ctlr = hp->aux;
1693*5c47fe09SDavid du Colombier
1694*5c47fe09SDavid du Colombier if(ctlr->port == nil || needrecover(ctlr))
1695*5c47fe09SDavid du Colombier return 0;
1696*5c47fe09SDavid du Colombier
1697*5c47fe09SDavid du Colombier if(on){
1698*5c47fe09SDavid du Colombier ctlr->port[port-1].reg[PORTSC] |= PR;
1699*5c47fe09SDavid du Colombier tsleep(&up->sleep, return0, nil, 200);
1700*5c47fe09SDavid du Colombier }
1701*5c47fe09SDavid du Colombier return 0;
1702*5c47fe09SDavid du Colombier }
1703*5c47fe09SDavid du Colombier
1704*5c47fe09SDavid du Colombier
1705*5c47fe09SDavid du Colombier static Ctlr *ctlrs[Nhcis];
1706*5c47fe09SDavid du Colombier
1707*5c47fe09SDavid du Colombier static void
scanpci(void)1708*5c47fe09SDavid du Colombier scanpci(void)
1709*5c47fe09SDavid du Colombier {
1710*5c47fe09SDavid du Colombier static int already = 0;
1711*5c47fe09SDavid du Colombier int i;
1712*5c47fe09SDavid du Colombier uintpci io;
1713*5c47fe09SDavid du Colombier Ctlr *ctlr;
1714*5c47fe09SDavid du Colombier Pcidev *p;
1715*5c47fe09SDavid du Colombier u32int *mmio;
1716*5c47fe09SDavid du Colombier
1717*5c47fe09SDavid du Colombier if(already)
1718*5c47fe09SDavid du Colombier return;
1719*5c47fe09SDavid du Colombier already = 1;
1720*5c47fe09SDavid du Colombier p = nil;
1721*5c47fe09SDavid du Colombier while ((p = pcimatch(p, 0, 0)) != nil) {
1722*5c47fe09SDavid du Colombier /*
1723*5c47fe09SDavid du Colombier * Find XHCI controllers (Programming Interface = 0x30).
1724*5c47fe09SDavid du Colombier */
1725*5c47fe09SDavid du Colombier if(p->ccrb != Pcibcserial || p->ccru != Pciscusb || p->ccrp != 0x30)
1726*5c47fe09SDavid du Colombier continue;
1727*5c47fe09SDavid du Colombier io = p->mem[0].bar & ~0x0f;
1728*5c47fe09SDavid du Colombier if(io == 0)
1729*5c47fe09SDavid du Colombier continue;
1730*5c47fe09SDavid du Colombier print("usbxhci: %#x %#x: port %llux size %#x irq %d\n",
1731*5c47fe09SDavid du Colombier p->vid, p->did, io, p->mem[0].size, p->intl);
1732*5c47fe09SDavid du Colombier mmio = (u32int*)mmukmapx(VIRTPCI, io, p->mem[0].size);
1733*5c47fe09SDavid du Colombier if(mmio == nil){
1734*5c47fe09SDavid du Colombier print("usbxhci: cannot map registers\n");
1735*5c47fe09SDavid du Colombier continue;
1736*5c47fe09SDavid du Colombier }
1737*5c47fe09SDavid du Colombier ctlr = malloc(sizeof(Ctlr));
1738*5c47fe09SDavid du Colombier if(ctlr == nil){
1739*5c47fe09SDavid du Colombier print("usbxhci: no memory\n");
1740*5c47fe09SDavid du Colombier continue;
1741*5c47fe09SDavid du Colombier }
1742*5c47fe09SDavid du Colombier ctlr->base = io;
1743*5c47fe09SDavid du Colombier ctlr->active = nil;
1744*5c47fe09SDavid du Colombier ctlr->pcidev = p;
1745*5c47fe09SDavid du Colombier ctlr->mmio = mmio;
1746*5c47fe09SDavid du Colombier for(i = 0; i < nelem(ctlrs); i++)
1747*5c47fe09SDavid du Colombier if(ctlrs[i] == nil){
1748*5c47fe09SDavid du Colombier ctlrs[i] = ctlr;
1749*5c47fe09SDavid du Colombier break;
1750*5c47fe09SDavid du Colombier }
1751*5c47fe09SDavid du Colombier if(i >= nelem(ctlrs))
1752*5c47fe09SDavid du Colombier print("xhci: bug: more than %d controllers\n", nelem(ctlrs));
1753*5c47fe09SDavid du Colombier }
1754*5c47fe09SDavid du Colombier }
1755*5c47fe09SDavid du Colombier
1756*5c47fe09SDavid du Colombier static int
reset(Hci * hp)1757*5c47fe09SDavid du Colombier reset(Hci *hp)
1758*5c47fe09SDavid du Colombier {
1759*5c47fe09SDavid du Colombier Ctlr *ctlr;
1760*5c47fe09SDavid du Colombier int i;
1761*5c47fe09SDavid du Colombier
1762*5c47fe09SDavid du Colombier if(getconf("*nousbxhci"))
1763*5c47fe09SDavid du Colombier return -1;
1764*5c47fe09SDavid du Colombier
1765*5c47fe09SDavid du Colombier scanpci();
1766*5c47fe09SDavid du Colombier
1767*5c47fe09SDavid du Colombier /*
1768*5c47fe09SDavid du Colombier * Any adapter matches if no hp->port is supplied,
1769*5c47fe09SDavid du Colombier * otherwise the ports must match.
1770*5c47fe09SDavid du Colombier */
1771*5c47fe09SDavid du Colombier for(i = 0; i < nelem(ctlrs) && ctlrs[i] != nil; i++){
1772*5c47fe09SDavid du Colombier ctlr = ctlrs[i];
1773*5c47fe09SDavid du Colombier if(ctlr->active == nil)
1774*5c47fe09SDavid du Colombier if(hp->port == 0 || hp->port == ctlr->base){
1775*5c47fe09SDavid du Colombier ctlr->active = hp;
1776*5c47fe09SDavid du Colombier goto Found;
1777*5c47fe09SDavid du Colombier }
1778*5c47fe09SDavid du Colombier }
1779*5c47fe09SDavid du Colombier return -1;
1780*5c47fe09SDavid du Colombier
1781*5c47fe09SDavid du Colombier Found:
1782*5c47fe09SDavid du Colombier hp->aux = ctlr;
1783*5c47fe09SDavid du Colombier hp->port = ctlr->base;
1784*5c47fe09SDavid du Colombier hp->irq = ctlr->pcidev->intl;
1785*5c47fe09SDavid du Colombier hp->tbdf = ctlr->pcidev->tbdf;
1786*5c47fe09SDavid du Colombier
1787*5c47fe09SDavid du Colombier hp->init = init;
1788*5c47fe09SDavid du Colombier hp->dump = dump;
1789*5c47fe09SDavid du Colombier hp->interrupt = interrupt;
1790*5c47fe09SDavid du Colombier hp->epopen = epopen;
1791*5c47fe09SDavid du Colombier hp->epclose = epclose;
1792*5c47fe09SDavid du Colombier hp->epread = epread;
1793*5c47fe09SDavid du Colombier hp->epwrite = epwrite;
1794*5c47fe09SDavid du Colombier hp->seprintep = seprintep;
1795*5c47fe09SDavid du Colombier hp->portenable = portenable;
1796*5c47fe09SDavid du Colombier hp->portreset = portreset;
1797*5c47fe09SDavid du Colombier hp->portstatus = portstatus;
1798*5c47fe09SDavid du Colombier hp->shutdown = shutdown;
1799*5c47fe09SDavid du Colombier hp->debug = setdebug;
1800*5c47fe09SDavid du Colombier hp->type = "xhci";
1801*5c47fe09SDavid du Colombier
1802*5c47fe09SDavid du Colombier return 0;
1803*5c47fe09SDavid du Colombier }
1804*5c47fe09SDavid du Colombier
1805*5c47fe09SDavid du Colombier void
usbxhcilink(void)1806*5c47fe09SDavid du Colombier usbxhcilink(void)
1807*5c47fe09SDavid du Colombier {
1808*5c47fe09SDavid du Colombier addhcitype("xhci", reset);
1809*5c47fe09SDavid du Colombier }
1810*5c47fe09SDavid du Colombier
1811*5c47fe09SDavid du Colombier void
dmaflush(int clean,void * p,ulong len)1812*5c47fe09SDavid du Colombier dmaflush(int clean, void *p, ulong len)
1813*5c47fe09SDavid du Colombier {
1814*5c47fe09SDavid du Colombier uintptr s = (uintptr)p;
1815*5c47fe09SDavid du Colombier uintptr e = (uintptr)p + len;
1816*5c47fe09SDavid du Colombier
1817*5c47fe09SDavid du Colombier if(clean){
1818*5c47fe09SDavid du Colombier s &= ~(BLOCKALIGN-1);
1819*5c47fe09SDavid du Colombier e += BLOCKALIGN-1;
1820*5c47fe09SDavid du Colombier e &= ~(BLOCKALIGN-1);
1821*5c47fe09SDavid du Colombier cachedwbse((void*)s, e - s);
1822*5c47fe09SDavid du Colombier return;
1823*5c47fe09SDavid du Colombier }
1824*5c47fe09SDavid du Colombier if(s & BLOCKALIGN-1){
1825*5c47fe09SDavid du Colombier s &= ~(BLOCKALIGN-1);
1826*5c47fe09SDavid du Colombier cachedwbinvse((void*)s, BLOCKALIGN);
1827*5c47fe09SDavid du Colombier s += BLOCKALIGN;
1828*5c47fe09SDavid du Colombier }
1829*5c47fe09SDavid du Colombier if(e & BLOCKALIGN-1){
1830*5c47fe09SDavid du Colombier e &= ~(BLOCKALIGN-1);
1831*5c47fe09SDavid du Colombier if(e < s)
1832*5c47fe09SDavid du Colombier return;
1833*5c47fe09SDavid du Colombier cachedwbinvse((void*)e, BLOCKALIGN);
1834*5c47fe09SDavid du Colombier }
1835*5c47fe09SDavid du Colombier if(s < e)
1836*5c47fe09SDavid du Colombier cachedinvse((void*)s, e - s);
1837*5c47fe09SDavid du Colombier }
1838