usbehci: introduce dmaflush() function to handle portable cache invalidation for device drivers

This commit is contained in:
cinap_lenrek 2019-07-17 10:24:50 +02:00
parent a4688b0322
commit 19a883ce7a
15 changed files with 163 additions and 297 deletions

View file

@ -175,7 +175,6 @@ struct Ctlr
void* (*tdalloc)(ulong,int,ulong);
void* (*dmaalloc)(ulong);
void (*dmafree)(void*);
void (*dmaflush)(int,void*,ulong len);
int nframes; /* 1024, 512, or 256 frames in the list */
ulong* frames; /* periodic frame list (hw) */
@ -245,3 +244,5 @@ extern int ehcidebug;
void ehcilinkage(Hci *hp);
void ehcimeminit(Ctlr *ctlr);
void ehcirun(Ctlr *ctlr, int on);
#define dmaflush(clean, addr, len)

View file

@ -18,7 +18,6 @@
#include "../port/etherif.h"
#include "../port/flashif.h"
#include "../port/usb.h"
#include "../port/portusbehci.h"
#include "usbehci.h"
#define FREQSEL(x) ((x) << 4)

View file

@ -10,6 +10,7 @@
typedef struct Ctlr Ctlr;
typedef struct Eopio Eopio;
typedef struct Ecapio Ecapio;
typedef struct Isoio Isoio;
typedef struct Poll Poll;
typedef struct Qh Qh;
@ -22,6 +23,116 @@ typedef struct Qtree Qtree;
#pragma incomplete Qh;
#pragma incomplete Qtree;
enum
{
/* Ecapio->parms reg. */
Cnports = 0xF, /* nport bits */
Cdbgportshift = 20, /* debug port */
Cdbgportmask = 0xF,
/* Ecapio->capparms bits */
C64 = 1<<0, /* 64-bits */
Cpfl = 1<<1, /* program'ble frame list: can be <1024 */
Casp = 1<<2, /* asynch. sched. park */
Ceecpshift = 8, /* extended capabilities ptr. */
Ceecpmask = (1<<8) - 1,
Clegacy = 1, /* legacy support cap. id */
CLbiossem = 2, /* legacy cap. bios sem. */
CLossem = 3, /* legacy cap. os sem */
CLcontrol = 4, /* legacy support control & status */
/* typed links */
Lterm = 1,
Litd = 0<<1,
Lqh = 1<<1,
Lsitd = 2<<1,
Lfstn = 3<<1, /* we don't use these */
/* Cmd reg. */
Cstop = 0x00000, /* stop running */
Crun = 0x00001, /* start operation */
Chcreset = 0x00002, /* host controller reset */
Cflsmask = 0x0000C, /* frame list size bits */
Cfls1024 = 0x00000, /* frame list size 1024 */
Cfls512 = 0x00004, /* frame list size 512 frames */
Cfls256 = 0x00008, /* frame list size 256 frames */
Cpse = 0x00010, /* periodic sched. enable */
Case = 0x00020, /* async sched. enable */
Ciasync = 0x00040, /* interrupt on async advance doorbell */
/* interrupt threshold ctl. in µframes (1-32 in powers of 2) */
Citcshift = 16,
Citcmask = 0xff << Citcshift,
/* Sts reg. */
Sasyncss = 0x08000, /* aync schedule status */
Speriodss = 0x04000, /* periodic schedule status */
Srecl = 0x02000, /* reclamnation (empty async sched.) */
Shalted = 0x01000, /* h.c. is halted */
Sasync = 0x00020, /* interrupt on async advance */
Sherr = 0x00010, /* host system error */
Sfrroll = 0x00008, /* frame list roll over */
Sportchg = 0x00004, /* port change detect */
Serrintr = 0x00002, /* error interrupt */
Sintr = 0x00001, /* interrupt */
Sintrs = 0x0003F, /* interrupts status */
/* Intr reg. */
Iusb = 0x01, /* intr. on usb */
Ierr = 0x02, /* intr. on usb error */
Iportchg = 0x04, /* intr. on port change */
Ifrroll = 0x08, /* intr. on frlist roll over */
Ihcerr = 0x10, /* intr. on host error */
Iasync = 0x20, /* intr. on async advance enable */
Iall = 0x3F, /* all interrupts */
/* Config reg. */
Callmine = 1, /* route all ports to us */
/* Portsc reg. */
Pspresent = 0x00000001, /* device present */
Psstatuschg = 0x00000002, /* Pspresent changed */
Psenable = 0x00000004, /* device enabled */
Pschange = 0x00000008, /* Psenable changed */
Psresume = 0x00000040, /* resume detected */
Pssuspend = 0x00000080, /* port suspended */
Psreset = 0x00000100, /* port reset */
Pspower = 0x00001000, /* port power on */
Psowner = 0x00002000, /* port owned by companion */
Pslinemask = 0x00000C00, /* line status bits */
Pslow = 0x00000400, /* low speed device */
/* Debug port csw reg. */
Cowner = 0x40000000, /* port owned by ehci */
Cenable = 0x10000000, /* debug port enabled */
Cdone = 0x00010000, /* request is done */
Cbusy = 0x00000400, /* port in use by a driver */
Cerrmask= 0x00000380, /* error code bits */
Chwerr = 0x00000100, /* hardware error */
Cterr = 0x00000080, /* transaction error */
Cfailed = 0x00000040, /* transaction did fail */
Cgo = 0x00000020, /* execute the transaction */
Cwrite = 0x00000010, /* request is a write */
Clen = 0x0000000F, /* data len */
/* Debug port pid reg. */
Prpidshift = 16, /* received pid */
Prpidmask = 0xFF,
Pspidshift = 8, /* sent pid */
Pspidmask = 0xFF,
Ptokshift = 0, /* token pid */
Ptokmask = 0xFF,
Ptoggle = 0x00008800, /* to update toggles */
Ptogglemask = 0x0000FF00,
/* Debug port addr reg. */
Adevshift = 8, /* device address */
Adevmask = 0x7F,
Aepshift = 0, /* endpoint number */
Aepmask = 0xF,
};
struct Poll
{
Lock;
@ -39,10 +150,9 @@ struct Ctlr
Ecapio* capio; /* Capability i/o regs */
Eopio* opio; /* Operational i/o regs */
void* (*tdalloc)(ulong,int,ulong);
void* (*dmaalloc)(ulong);
void* (*tdalloc)(usize,int,usize);
void* (*dmaalloc)(usize);
void (*dmafree)(void*);
void (*dmaflush)(int,void*,ulong len);
int nframes; /* 1024, 512, or 256 frames in the list */
ulong* frames; /* periodic frame list (hw) */
@ -82,6 +192,17 @@ struct Eopio
ulong insn[6]; /* implementation-specific */
};
/*
* Capability registers (hw)
*/
struct Ecapio
{
ulong cap; /* 00 controller capability register */
ulong parms; /* 04 structural parameters register */
ulong capparms; /* 08 capability parameters */
ulong portroute; /* 0c not on the CS5536 */
};
typedef struct Uhh Uhh;
struct Uhh {
ulong revision; /* ro */
@ -107,3 +228,5 @@ extern int ehcidebug;
void ehcilinkage(Hci *hp);
void ehcimeminit(Ctlr *ctlr);
void ehcirun(Ctlr *ctlr, int on);
#define dmaflush(clean, addr, len)

View file

@ -53,7 +53,7 @@ ehcireset(Ctlr *ctlr)
}
/* requesting more interrupts per µframe may miss interrupts */
opio->cmd |= Citc8; /* 1 intr. per ms */
opio->cmd |= 0x10000; /* 1 intr. per ms */
coherence();
switch(opio->cmd & Cflsmask){
case Cfls1024:
@ -180,7 +180,7 @@ reset(Hci *hp)
ctlr->tdalloc = ucallocalign;
ctlr->dmaalloc = ucalloc;
cltr->dmafree = ucfree;
ctlr->dmafree = ucfree;
ehcireset(ctlr);
ehcimeminit(ctlr);

View file

@ -21,6 +21,7 @@ void cpuidprint(void);
void (*cycles)(uvlong*);
void delay(int);
void* dmabva(int);
#define dmaflush(clean, addr, len)
int dmacount(int);
int dmadone(int);
void dmaend(int);

View file

@ -178,7 +178,6 @@ struct Ctlr
void* (*tdalloc)(ulong,int,ulong);
void* (*dmaalloc)(ulong);
void (*dmafree)(void*);
void (*dmaflush)(int,void*,ulong len);
int nframes; /* 1024, 512, or 256 frames in the list */
ulong* frames; /* periodic frame list (hw) */

View file

@ -21,6 +21,7 @@ void cpuidprint(void);
void (*cycles)(uvlong*);
void delay(int);
void* dmabva(int);
#define dmaflush(clean, addr, len)
int dmacount(int);
int dmadone(int);
void dmaend(int);

View file

@ -1,144 +0,0 @@
/*
* ECHI portable hardware definitions
*/
typedef struct Ecapio Ecapio;
typedef struct Edbgio Edbgio;
#pragma incomplete Ecapio;
#pragma incomplete Edbgio;
/*
* EHCI interface registers and bits
*/
enum
{
/* Ecapio->parms reg. */
Cnports = 0xF, /* nport bits */
Cdbgportshift = 20, /* debug port */
Cdbgportmask = 0xF,
/* Ecapio->capparms bits */
C64 = 1<<0, /* 64-bits */
Cpfl = 1<<1, /* program'ble frame list: can be <1024 */
Casp = 1<<2, /* asynch. sched. park */
Ceecpshift = 8, /* extended capabilities ptr. */
Ceecpmask = (1<<8) - 1,
Clegacy = 1, /* legacy support cap. id */
CLbiossem = 2, /* legacy cap. bios sem. */
CLossem = 3, /* legacy cap. os sem */
CLcontrol = 4, /* legacy support control & status */
/* typed links */
Lterm = 1,
Litd = 0<<1,
Lqh = 1<<1,
Lsitd = 2<<1,
Lfstn = 3<<1, /* we don't use these */
/* Cmd reg. */
Cstop = 0x00000, /* stop running */
Crun = 0x00001, /* start operation */
Chcreset = 0x00002, /* host controller reset */
Cflsmask = 0x0000C, /* frame list size bits */
Cfls1024 = 0x00000, /* frame list size 1024 */
Cfls512 = 0x00004, /* frame list size 512 frames */
Cfls256 = 0x00008, /* frame list size 256 frames */
Cpse = 0x00010, /* periodic sched. enable */
Case = 0x00020, /* async sched. enable */
Ciasync = 0x00040, /* interrupt on async advance doorbell */
/* interrupt threshold ctl. in µframes (1-32 in powers of 2) */
Citcshift = 16,
Citcmask = 0xff << Citcshift,
/* Sts reg. */
Sasyncss = 0x08000, /* aync schedule status */
Speriodss = 0x04000, /* periodic schedule status */
Srecl = 0x02000, /* reclamnation (empty async sched.) */
Shalted = 0x01000, /* h.c. is halted */
Sasync = 0x00020, /* interrupt on async advance */
Sherr = 0x00010, /* host system error */
Sfrroll = 0x00008, /* frame list roll over */
Sportchg = 0x00004, /* port change detect */
Serrintr = 0x00002, /* error interrupt */
Sintr = 0x00001, /* interrupt */
Sintrs = 0x0003F, /* interrupts status */
/* Intr reg. */
Iusb = 0x01, /* intr. on usb */
Ierr = 0x02, /* intr. on usb error */
Iportchg = 0x04, /* intr. on port change */
Ifrroll = 0x08, /* intr. on frlist roll over */
Ihcerr = 0x10, /* intr. on host error */
Iasync = 0x20, /* intr. on async advance enable */
Iall = 0x3F, /* all interrupts */
/* Config reg. */
Callmine = 1, /* route all ports to us */
/* Portsc reg. */
Pspresent = 0x00000001, /* device present */
Psstatuschg = 0x00000002, /* Pspresent changed */
Psenable = 0x00000004, /* device enabled */
Pschange = 0x00000008, /* Psenable changed */
Psresume = 0x00000040, /* resume detected */
Pssuspend = 0x00000080, /* port suspended */
Psreset = 0x00000100, /* port reset */
Pspower = 0x00001000, /* port power on */
Psowner = 0x00002000, /* port owned by companion */
Pslinemask = 0x00000C00, /* line status bits */
Pslow = 0x00000400, /* low speed device */
/* Debug port csw reg. */
Cowner = 0x40000000, /* port owned by ehci */
Cenable = 0x10000000, /* debug port enabled */
Cdone = 0x00010000, /* request is done */
Cbusy = 0x00000400, /* port in use by a driver */
Cerrmask= 0x00000380, /* error code bits */
Chwerr = 0x00000100, /* hardware error */
Cterr = 0x00000080, /* transaction error */
Cfailed = 0x00000040, /* transaction did fail */
Cgo = 0x00000020, /* execute the transaction */
Cwrite = 0x00000010, /* request is a write */
Clen = 0x0000000F, /* data len */
/* Debug port pid reg. */
Prpidshift = 16, /* received pid */
Prpidmask = 0xFF,
Pspidshift = 8, /* sent pid */
Pspidmask = 0xFF,
Ptokshift = 0, /* token pid */
Ptokmask = 0xFF,
Ptoggle = 0x00008800, /* to update toggles */
Ptogglemask = 0x0000FF00,
/* Debug port addr reg. */
Adevshift = 8, /* device address */
Adevmask = 0x7F,
Aepshift = 0, /* endpoint number */
Aepmask = 0xF,
};
/*
* Capability registers (hw)
*/
struct Ecapio
{
ulong cap; /* 00 controller capability register */
ulong parms; /* 04 structural parameters register */
ulong capparms; /* 08 capability parameters */
ulong portroute; /* 0c not on the CS5536 */
};
/*
* Debug port registers (hw)
*/
struct Edbgio
{
ulong csw; /* control and status */
ulong pid; /* USB pid */
uchar data[8]; /* data buffer */
ulong addr; /* device and endpoint addresses */
};

View file

@ -1256,8 +1256,7 @@ itdinit(Ctlr *ctlr, Isoio *iso, Itd *td)
*/
size = td->ndata = td->mdata;
td->posi = td->posp = 0;
if(ctlr->dmaflush != nil)
(*ctlr->dmaflush)(1, td->data, size);
dmaflush(1, td->data, size);
pa = PADDR(td->data);
pg = pa & ~0xFFF;
for(p = 0; p < nelem(td->buffer); p++)
@ -1290,8 +1289,7 @@ itdinit(Ctlr *ctlr, Isoio *iso, Itd *td)
static void
sitdinit(Ctlr *ctlr, Isoio *iso, Sitd *td)
{
if(ctlr->dmaflush != nil)
(*ctlr->dmaflush)(1, td->data, td->mdata);
dmaflush(1, td->data, td->mdata);
td->ndata = td->mdata & Stdlenmask;
td->buffer[0] = PADDR(td->data);
td->buffer[1] = (td->buffer[0] & ~0xFFF) + 0x1000;
@ -1905,8 +1903,7 @@ loop:
dp = tdu->data + tdu->posi * iso->maxsize + tdu->posp;
if(nr > 0){
iunlock(ctlr);
if(ctlr->dmaflush != nil)
(*ctlr->dmaflush)(0, dp, nr);
dmaflush(0, dp, nr);
memmove(b+tot, dp, nr);
ilock(ctlr);
if(iso->tdu != tdu || dp != tdu->data + tdu->posi * iso->maxsize + tdu->posp)
@ -1947,8 +1944,7 @@ isofscpy(Ctlr *ctlr, Isoio* iso, uchar *b, long count)
nr = count - tot;
if(nr > 0) {
iunlock(ctlr); /* We could page fault here */
if(ctlr->dmaflush != nil)
(*ctlr->dmaflush)(0, stdu->data, stdu->mdata);
dmaflush(0, stdu->data, stdu->mdata);
memmove(b+tot, stdu->data, nr);
ilock(ctlr);
if(iso->stdu != stdu)
@ -2192,8 +2188,9 @@ epgettd(Ctlr *ctlr, Qio *io, int flags, void *a, int count, int maxpkt)
}
if(a != nil && count > 0)
memmove(td->data, a, count);
if(ctlr->dmaflush != nil && td->buff != nil)
(*ctlr->dmaflush)(1, td->data, count);
if(td->buff != nil){
dmaflush(1, td->data, count);
}
pa = PADDR(td->data);
for(i = 0; i < nelem(td->buffer); i++){
td->buffer[i] = pa;
@ -2479,8 +2476,9 @@ epio(Ep *ep, Qio *io, void *a, long count, int mustlock)
if((tot + n) > count)
n = count - tot;
if(c != nil && (td->csw & Tdtok) == Tdtokin){
if(ctlr->dmaflush != nil && td->buff != nil)
(*ctlr->dmaflush)(0, td->data, n);
if(td->buff != nil){
dmaflush(0, td->data, n);
}
memmove(c, td->data, n);
c += n;
}

View file

@ -14,9 +14,6 @@
#include "../port/netif.h"
#include "../port/etherif.h"
#include "../port/flashif.h"
#include "../port/usb.h"
#include "../port/portusbehci.h"
#include "usbehci.h"
enum {
/* hardware limits imposed by register contents or layouts */

View file

@ -1,104 +0,0 @@
/* override default macros from ../port/usb.h */
#undef dprint
#undef ddprint
#undef deprint
#undef ddeprint
#define dprint if(ehcidebug)print
#define ddprint if(ehcidebug>1)print
#define deprint if(ehcidebug || ep->debug)print
#define ddeprint if(ehcidebug>1 || ep->debug>1)print
typedef struct Ctlr Ctlr;
typedef struct Eopio Eopio;
typedef struct Isoio Isoio;
typedef struct Poll Poll;
typedef struct Qh Qh;
typedef struct Qtree Qtree;
#pragma incomplete Ctlr;
#pragma incomplete Eopio;
#pragma incomplete Isoio;
#pragma incomplete Poll;
#pragma incomplete Qh;
#pragma incomplete Qtree;
struct Poll
{
Lock;
Rendez;
int must;
int does;
};
struct Ctlr
{
Rendez; /* for waiting to async advance doorbell */
Lock; /* for ilock. qh lists and basic ctlr I/O */
QLock portlck; /* for port resets/enable... (and doorbell) */
int active; /* in use or not */
Ecapio* capio; /* Capability i/o regs */
Eopio* opio; /* Operational i/o regs */
int nframes; /* 1024, 512, or 256 frames in the list */
ulong* frames; /* periodic frame list (hw) */
Qh* qhs; /* async Qh circular list for bulk/ctl */
Qtree* tree; /* tree of Qhs for the periodic list */
int ntree; /* number of dummy qhs in tree */
Qh* intrqhs; /* list of (not dummy) qhs in tree */
Isoio* iso; /* list of active Iso I/O */
ulong load;
ulong isoload;
int nintr; /* number of interrupts attended */
int ntdintr; /* number of intrs. with something to do */
int nqhintr; /* number of async td intrs. */
int nisointr; /* number of periodic td intrs. */
int nreqs;
Poll poll;
};
/*
* Operational registers (hw)
*/
struct Eopio
{
ulong cmd; /* 00 command */
ulong sts; /* 04 status */
ulong intr; /* 08 interrupt enable */
ulong frno; /* 0c frame index */
ulong seg; /* 10 bits 63:32 of EHCI datastructs (unused) */
ulong frbase; /* 14 frame list base addr, 4096-byte boundary */
ulong link; /* 18 link for async list */
uchar d2c[0x40-0x1c]; /* 1c dummy */
ulong config; /* 40 1: all ports default-routed to this HC */
ulong portsc[3]; /* 44 Port status and control, one per port */
/* defined for omap35 ehci at least */
uchar _pad0[0x80 - 0x50];
ulong insn[6]; /* implementation-specific */
};
typedef struct Uhh Uhh;
struct Uhh {
ulong revision; /* ro */
uchar _pad0[0x10-0x4];
ulong sysconfig;
ulong sysstatus; /* ro */
uchar _pad1[0x40-0x18];
ulong hostconfig;
ulong debug_csr;
};
enum {
/* hostconfig bits */
P1ulpi_bypass = 1<<0, /* utmi if set; else ulpi */
};
extern Ecapio *ehcidebugcapio;
extern int ehcidebugport;
extern int ehcidebug;
void ehcilinkage(Hci *hp);
void ehcimeminit(Ctlr *ctlr);
void ehcirun(Ctlr *ctlr, int on);

View file

@ -68,6 +68,7 @@ void clinvdse(void *, void *);
void invaldln(void *);
void cleandln(void *);
void clinvdln(void *);
void dmaflush(int, void*, ulong);
void* ucalloc(ulong);
void clean2pa(uintptr, uintptr);
void inval2pa(uintptr, uintptr);

View file

@ -133,6 +133,25 @@ inval2pa(uintptr start, uintptr end)
l2[0x770/4] = pa;
}
void
dmaflush(int clean, void *data, ulong len)
{
uintptr va, pa;
va = (uintptr)data & ~31;
pa = PADDR(va);
len = ROUND(len, 32);
if(clean){
/* flush cache before write */
cleandse((uchar*)va, (uchar*)va+len);
clean2pa(pa, pa+len);
} else {
/* invalidate cache before read */
invaldse((uchar*)va, (uchar*)va+len);
inval2pa(pa, pa+len);
}
}
static void
options(void)
{

View file

@ -130,7 +130,6 @@ struct Ctlr
void* (*tdalloc)(ulong,int,ulong);
void* (*dmaalloc)(ulong);
void (*dmafree)(void*);
void (*dmaflush)(int,void*,ulong len);
int nframes; /* 1024, 512, or 256 frames in the list */
ulong* frames; /* periodic frame list (hw) */

View file

@ -61,10 +61,6 @@ ehcireset(Ctlr *ctlr)
iunlock(ctlr);
}
enum {
Cls = 64,
};
/* descriptors need to be allocated in uncached memory */
static void*
tdalloc(ulong size, int, ulong)
@ -75,7 +71,7 @@ tdalloc(ulong size, int, ulong)
static void*
dmaalloc(ulong len)
{
return mallocalign(ROUND(len, Cls), Cls, 0, 0);
return mallocalign(ROUND(len, BLOCKALIGN), BLOCKALIGN, 0, 0);
}
static void
dmafree(void *data)
@ -83,25 +79,6 @@ dmafree(void *data)
free(data);
}
static void
dmaflush(int clean, void *data, ulong len)
{
uintptr va, pa;
va = (uintptr)data & ~(Cls-1);
pa = PADDR(va);
len = ROUND(len, Cls);
if(clean){
/* flush cache before write */
cleandse((uchar*)va, (uchar*)va+len);
clean2pa(pa, pa+len);
} else {
/* invalidate cache before read */
invaldse((uchar*)va, (uchar*)va+len);
inval2pa(pa, pa+len);
}
}
static int (*ehciportstatus)(Hci*,int);
static int
@ -152,7 +129,6 @@ reset(Hci *hp)
ctlr->tdalloc = tdalloc;
ctlr->dmaalloc = dmaalloc;
ctlr->dmafree = dmafree;
ctlr->dmaflush = dmaflush;
ehcireset(ctlr);
ctlr->r[USBMODE] |= USBHOST;