273 lines
5.4 KiB
C
273 lines
5.4 KiB
C
/* Copyright (C) Charles Forsyth
|
|
* See /doc/license/NOTICE.Plan9-9k.txt for details about the licensing.
|
|
*/
|
|
/* Portions of this file are Copyright (C) 2015-2018 Giacomo Tesio <giacomo@tesio.it>
|
|
* See /doc/license/gpl-2.0.txt for details about the licensing.
|
|
*/
|
|
/* Portions of this file are Copyright (C) 9front's team.
|
|
* See /doc/license/9front-mit for details about the licensing.
|
|
* See http://git.9front.org/plan9front/plan9front/HEAD/info.html for a list of authors.
|
|
*/
|
|
|
|
/*
|
|
* access to PCI configuration space (devpnp.c without PNP)
|
|
*
|
|
* TODO
|
|
* - extend PCI raw access to configuration space (writes, byte/short access?)
|
|
* - implement PCI access to memory/io space/BIOS ROM
|
|
* - use c->aux instead of performing lookup on each read/write?
|
|
*/
|
|
#include "u.h"
|
|
#include "../port/lib.h"
|
|
#include "mem.h"
|
|
#include "dat.h"
|
|
#include "fns.h"
|
|
#include "io.h"
|
|
#include "../port/error.h"
|
|
|
|
#define DPRINT if(0) print
|
|
#define XPRINT if(1) print
|
|
|
|
enum {
|
|
Qtopdir = 0,
|
|
|
|
Qpcidir,
|
|
Qpcictl,
|
|
Qpciraw,
|
|
};
|
|
|
|
#define TYPE(q) ((uint32_t)(q).path & 0x0F)
|
|
#define QID(c, t) (((c)<<4)|(t))
|
|
|
|
static Dirtab topdir[] = {
|
|
".", { Qtopdir, 0, QTDIR }, 0, 0555,
|
|
"pci", { Qpcidir, 0, QTDIR }, 0, 0555,
|
|
};
|
|
|
|
extern Dev pcidevtab;
|
|
|
|
static int
|
|
pcigen2(Chan *c, int t, int tbdf, Dir *dp)
|
|
{
|
|
Qid q;
|
|
|
|
q = (Qid){BUSBDF(tbdf)|t, 0, 0};
|
|
switch(t) {
|
|
case Qpcictl:
|
|
jehanne_snprint(up->genbuf, sizeof(up->genbuf), "%d.%d.%dctl", BUSBNO(tbdf), BUSDNO(tbdf), BUSFNO(tbdf));
|
|
devdir(c, q, up->genbuf, 0, eve, 0444, dp);
|
|
return 1;
|
|
case Qpciraw:
|
|
jehanne_snprint(up->genbuf, sizeof(up->genbuf), "%d.%d.%draw", BUSBNO(tbdf), BUSDNO(tbdf), BUSFNO(tbdf));
|
|
devdir(c, q, up->genbuf, 128, eve, 0444, dp);
|
|
return 1;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
static int
|
|
pcigen(Chan *c, char * _1, Dirtab* _2, int _3, int s, Dir *dp)
|
|
{
|
|
Qid q;
|
|
Pcidev *p;
|
|
int tbdf;
|
|
|
|
switch(TYPE(c->qid)){
|
|
case Qtopdir:
|
|
if(s == DEVDOTDOT){
|
|
q = (Qid){QID(0, Qtopdir), 0, QTDIR};
|
|
jehanne_snprint(up->genbuf, sizeof(up->genbuf), "#%C", pcidevtab.dc);
|
|
devdir(c, q, up->genbuf, 0, eve, 0555, dp);
|
|
return 1;
|
|
}
|
|
return devgen(c, nil, topdir, nelem(topdir), s, dp);
|
|
case Qpcidir:
|
|
if(s == DEVDOTDOT){
|
|
q = (Qid){QID(0, Qtopdir), 0, QTDIR};
|
|
jehanne_snprint(up->genbuf, sizeof(up->genbuf), "#%C", pcidevtab.dc);
|
|
devdir(c, q, up->genbuf, 0, eve, 0555, dp);
|
|
return 1;
|
|
}
|
|
p = pcimatch(nil, 0, 0);
|
|
while(s >= 2 && p != nil) {
|
|
p = pcimatch(p, 0, 0);
|
|
s -= 2;
|
|
}
|
|
if(p == nil)
|
|
return -1;
|
|
return pcigen2(c, s+Qpcictl, p->tbdf, dp);
|
|
case Qpcictl:
|
|
case Qpciraw:
|
|
tbdf = MKBUS(BusPCI, 0, 0, 0)|BUSBDF((uint32_t)c->qid.path);
|
|
p = pcimatchtbdf(tbdf);
|
|
if(p == nil)
|
|
return -1;
|
|
return pcigen2(c, TYPE(c->qid), tbdf, dp);
|
|
default:
|
|
break;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
static Chan*
|
|
pciattach(Chan *c, Chan *ac, char *spec, int flags)
|
|
{
|
|
return devattach(pcidevtab.dc, spec);
|
|
}
|
|
|
|
Walkqid*
|
|
pciwalk(Chan* c, Chan *nc, char** name, int nname)
|
|
{
|
|
return devwalk(c, nc, name, nname, nil, 0, pcigen);
|
|
}
|
|
|
|
static long
|
|
pcistat(Chan* c, uint8_t* dp, long n)
|
|
{
|
|
return devstat(c, dp, n, nil, 0, pcigen);
|
|
}
|
|
|
|
static Chan*
|
|
pciopen(Chan *c, unsigned long omode)
|
|
{
|
|
return devopen(c, omode, nil, 0, pcigen);
|
|
}
|
|
|
|
static void
|
|
pciclose(Chan* _1)
|
|
{
|
|
}
|
|
|
|
static long
|
|
pciread(Chan *c, void *va, long n, int64_t offset)
|
|
{
|
|
uint32_t x;
|
|
Pcidev *p;
|
|
char buf[256], *ebuf, *w;
|
|
char *a = va;
|
|
int i, tbdf, r;
|
|
|
|
switch(TYPE(c->qid)){
|
|
case Qtopdir:
|
|
case Qpcidir:
|
|
return devdirread(c, a, n, nil, 0, pcigen);
|
|
case Qpcictl:
|
|
tbdf = MKBUS(BusPCI, 0, 0, 0)|BUSBDF((uint32_t)c->qid.path);
|
|
p = pcimatchtbdf(tbdf);
|
|
if(p == nil)
|
|
error(Egreg);
|
|
ebuf = buf+sizeof buf-1; /* -1 for newline */
|
|
w = jehanne_seprint(buf, ebuf, "%.2x.%.2x.%.2x %.4x/%.4x %3d",
|
|
p->ccrb, p->ccru, p->ccrp, p->vid, p->did, p->intl);
|
|
for(i=0; i<nelem(p->mem); i++){
|
|
if(p->mem[i].size == 0)
|
|
continue;
|
|
w = jehanne_seprint(w, ebuf, " %d:%.8lux %d", i, p->mem[i].bar, p->mem[i].size);
|
|
}
|
|
*w++ = '\n';
|
|
*w = '\0';
|
|
return readstr(offset, a, n, buf);
|
|
case Qpciraw:
|
|
tbdf = MKBUS(BusPCI, 0, 0, 0)|BUSBDF((uint32_t)c->qid.path);
|
|
p = pcimatchtbdf(tbdf);
|
|
if(p == nil)
|
|
error(Egreg);
|
|
if(offset > 256)
|
|
return 0;
|
|
if(n+offset > 256)
|
|
n = 256-offset;
|
|
r = offset;
|
|
if(!(r & 3) && n == 4){
|
|
x = pcicfgr32(p, r);
|
|
PBIT32(a, x);
|
|
return 4;
|
|
}
|
|
if(!(r & 1) && n == 2){
|
|
x = pcicfgr16(p, r);
|
|
PBIT16(a, x);
|
|
return 2;
|
|
}
|
|
for(i = 0; i < n; i++){
|
|
x = pcicfgr8(p, r);
|
|
PBIT8(a, x);
|
|
a++;
|
|
r++;
|
|
}
|
|
return i;
|
|
default:
|
|
error(Egreg);
|
|
}
|
|
return n;
|
|
}
|
|
|
|
static long
|
|
pciwrite(Chan *c, void *va, long n, int64_t offset)
|
|
{
|
|
char buf[256];
|
|
Pcidev *p;
|
|
uint32_t x;
|
|
uint8_t *a;
|
|
int i, r, tbdf;
|
|
|
|
if(n >= sizeof(buf))
|
|
n = sizeof(buf)-1;
|
|
jehanne_strncpy(buf, va, n);
|
|
buf[n] = 0;
|
|
|
|
switch(TYPE(c->qid)){
|
|
case Qpciraw:
|
|
tbdf = MKBUS(BusPCI, 0, 0, 0)|BUSBDF((uint32_t)c->qid.path);
|
|
p = pcimatchtbdf(tbdf);
|
|
if(p == nil)
|
|
error(Egreg);
|
|
if(offset > 256)
|
|
return 0;
|
|
if(n+offset > 256)
|
|
n = 256-offset;
|
|
a = va;
|
|
r = offset;
|
|
if(!(r & 3) && n == 4){
|
|
x = GBIT32(a);
|
|
pcicfgw32(p, r, x);
|
|
return 4;
|
|
}
|
|
if(!(r & 1) && n == 2){
|
|
x = GBIT16(a);
|
|
pcicfgw16(p, r, x);
|
|
return 2;
|
|
}
|
|
for(i = 0; i < n; i++){
|
|
x = GBIT8(a);
|
|
pcicfgw8(p, r, x);
|
|
a++;
|
|
r++;
|
|
}
|
|
return i;
|
|
default:
|
|
error(Egreg);
|
|
}
|
|
return n;
|
|
}
|
|
|
|
|
|
Dev pcidevtab = {
|
|
'$',
|
|
"pci",
|
|
|
|
devreset,
|
|
devinit,
|
|
devshutdown,
|
|
pciattach,
|
|
pciwalk,
|
|
pcistat,
|
|
pciopen,
|
|
devcreate,
|
|
pciclose,
|
|
pciread,
|
|
devbread,
|
|
pciwrite,
|
|
devbwrite,
|
|
devremove,
|
|
devwstat,
|
|
};
|