shithub: riscv

Download patch

ref: 6abe569ec8f47ba14c3dcd5d5214e7b7a020bf7a
parent: 0294abd5646dc9966cd98ac920b17aea3de3f57f
author: cinap_lenrek <[email protected]>
date: Sun Sep 25 10:02:59 EDT 2022

devpci: provide a #$ device for PCI config access

We want to provide userspace PCI config space
access on platforms that have PCI, but do not
have ISA bus.

For this, provide a stripped down version of
devpnp, wiht only the pci support that can then
be used by pi4 (bcm64) and reform (imx8) kernels.

--- a/sys/src/9/bcm64/pi4
+++ b/sys/src/9/bcm64/pi4
@@ -20,6 +20,7 @@
 	mouse	mouse
 	uart	gpio
 	gpio	gpio
+	pci	pci
 	sd
 	usb
 	dtracy
--- a/sys/src/9/imx8/reform
+++ b/sys/src/9/imx8/reform
@@ -21,6 +21,7 @@
 	usb
 	i2c
 	rtc	devi2c
+	pci	pci
 	sd
 	audio
 
--- /dev/null
+++ b/sys/src/9/port/devpci.c
@@ -1,0 +1,267 @@
+/*
+ *	This is a stripped down copy of port/devpnp.c,
+ *	with the ISA PNP stripped out, only providing
+ *	access to PCI configuration space.
+ */
+#include	"u.h"
+#include	"../port/lib.h"
+#include	"mem.h"
+#include	"dat.h"
+#include	"fns.h"
+#include	"../port/pci.h"
+#include	"../port/error.h"
+
+enum {
+	Qtopdir = 0,
+
+	Qpcidir,
+	Qpcictl,
+	Qpciraw,
+};
+
+#define TYPE(q)		((ulong)(q).path & 0x0F)
+#define QID(c, t)	(((c)<<4)|(t))
+
+static Dirtab topdir[] = {
+	".",	{ Qtopdir, 0, QTDIR },	0,	0555,
+	"pci",	{ Qpcidir, 0, QTDIR },	0,	0555,
+};
+
+static Dirtab pcidir[] = {
+	".",	{ Qpcidir, 0, QTDIR },	0,	0555,
+	"ctl",	{ Qpcictl, 0, 0 },	0,	0666,
+};
+
+extern Dev pcidevtab;
+
+static int
+pcigen(Chan *c, int t, int tbdf, Dir *dp)
+{
+	Qid q;
+
+	q = (Qid){BUSBDF(tbdf)|t, 0, 0};
+	switch(t) {
+	case Qpcictl:
+		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:
+		snprint(up->genbuf, sizeof up->genbuf, "%d.%d.%draw",
+			BUSBNO(tbdf), BUSDNO(tbdf), BUSFNO(tbdf));
+		devdir(c, q, up->genbuf, 128, eve, 0660, dp);
+		return 1;
+	}
+	return -1;
+}
+
+static int
+pcidirgen(Chan *c, char *, Dirtab*, int, 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};
+			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};
+			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 pcigen(c, s+Qpcictl, p->tbdf, dp);
+	case Qpcictl:
+	case Qpciraw:
+		tbdf = MKBUS(BusPCI, 0, 0, 0)|BUSBDF((ulong)c->qid.path);
+		p = pcimatchtbdf(tbdf);
+		if(p == nil)
+			return -1;
+		return pcigen(c, TYPE(c->qid), tbdf, dp);
+	default:
+		break;
+	}
+	return -1;
+}
+
+static Chan*
+pciattach(char *spec)
+{
+	return devattach(pcidevtab.dc, spec);
+}
+
+Walkqid*
+pciwalk(Chan* c, Chan *nc, char** name, int nname)
+{
+	return devwalk(c, nc, name, nname, (Dirtab *)0, 0, pcidirgen);
+}
+
+static int
+pcistat(Chan* c, uchar* dp, int n)
+{
+	return devstat(c, dp, n, (Dirtab *)0, 0L, pcidirgen);
+}
+
+static Chan*
+pciopen(Chan *c, int omode)
+{
+	c = devopen(c, omode, (Dirtab*)0, 0, pcidirgen);
+	switch(TYPE(c->qid)){
+	default:
+		break;
+	}
+	return c;
+}
+
+static void
+pciclose(Chan*)
+{
+}
+
+static long
+pciread(Chan *c, void *va, long n, vlong offset)
+{
+	ulong 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, (Dirtab *)0, 0L, pcidirgen);
+	case Qpcictl:
+		tbdf = MKBUS(BusPCI, 0, 0, 0)|BUSBDF((ulong)c->qid.path);
+		p = pcimatchtbdf(tbdf);
+		if(p == nil)
+			error(Egreg);
+		ebuf = buf+sizeof buf-1;	/* -1 for newline */
+		w = 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 = seprint(w, ebuf, " %d:%.8llux %lld", 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((ulong)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, vlong offset)
+{
+	Pcidev *p;
+	ulong x;
+	char buf[256];
+	uchar *a;
+	int i, r, tbdf;
+
+	if(n >= sizeof(buf))
+		n = sizeof(buf)-1;
+	a = va;
+	strncpy(buf, va, n);
+	buf[n] = 0;
+
+	switch(TYPE(c->qid)){
+	case Qpciraw:
+		tbdf = MKBUS(BusPCI, 0, 0, 0)|BUSBDF((ulong)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 = 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,
+};
--- a/sys/src/9/port/portmkfile
+++ b/sys/src/9/port/portmkfile
@@ -113,4 +113,4 @@
 wifi.$O:	../port/etherif.h ../port/netif.h ../port/wifi.h /sys/include/libsec.h
 wifi.$O:	../ip/ip.h ../ip/ipv6.h
 ethermii.$O:	../port/ethermii.h
-pci.$O devpnp.$O usbxhci.$O:	../port/pci.h
+pci.$O devpnp.$O devpci.$O usbxhci.$O:	../port/pci.h