Add support for ioctl() accesses to PCI config space registers.

Garrett Wollman sent me this code a few weeks ago for review, and I made
some significant changes, which he in turn accepted ...

In order to make use of these changes, a device entry has to added to /dev.

Submitted by:	wollman
This commit is contained in:
se 1996-10-22 20:20:14 +00:00
parent b74235fd9f
commit c48ec390a8
4 changed files with 334 additions and 8 deletions

View File

@ -1,6 +1,6 @@
/**************************************************************************
**
** $Id: pci.c,v 1.55 1996/09/10 23:30:59 bde Exp $
** $Id: pci.c,v 1.56 1996/10/14 13:04:34 se Exp $
**
** General subroutines for the PCI bus.
** pci_configure ()
@ -52,6 +52,11 @@
#include <sys/errno.h>
#include <sys/kernel.h>
#include <sys/proc.h> /* declaration of wakeup(), used by vm.h */
#include <sys/conf.h>
#ifdef DEVFS
#include <sys/devfsext.h>
#endif /* DEVFS */
#include <sys/fcntl.h>
#include <vm/vm.h>
#include <vm/vm_param.h>
@ -63,6 +68,7 @@
#include <pci/pcivar.h>
#include <pci/pcireg.h>
#include <pci/pcibus.h>
#include <pci/pci_ioctl.h>
#define PCI_MAX_IRQ (16)
@ -114,6 +120,8 @@ pci_bridge_config (void);
static int
pci_mfdev (int bus, int device);
static void pci_remember (int bus, int dev, int func);
/*========================================================
**
** Variables
@ -377,7 +385,7 @@ static int
pci_mfdev (int bus, int device)
{
pcici_t tag0,tag1;
int pci_id0, pci_id1;
unsigned pci_id0, pci_id1;
/*
** Detect a multi-function device that complies to the PCI 2.0 spec
@ -424,7 +432,7 @@ pci_bus_config (void)
u_long data;
int unit;
u_char pciint;
u_char irq;
int irq;
struct pci_device *dvp;
@ -514,6 +522,8 @@ pci_bus_config (void)
maxfunc = 7;
}
pci_remember(bus_no, device, func);
if (dvp==NULL) {
#ifndef PCI_QUIET
if (pci_conf_count)
@ -1720,4 +1730,156 @@ void not_supported (pcici_t tag, u_long type)
}
}
}
/*
* This is the user interface to the PCI configuration space.
*/
static struct pci_conf *pci_dev_list;
static unsigned pci_dev_list_count;
static unsigned pci_dev_list_size;
static void
pci_remember(int bus, int dev, int func)
{
struct pci_conf *p;
pcici_t tag;
if (++pci_dev_list_count > pci_dev_list_size) {
struct pci_conf *new;
pci_dev_list_size += 8;
MALLOC(new, struct pci_conf *, pci_dev_list_size * sizeof *new,
M_DEVL, M_NOWAIT);
if (!new) {
pci_dev_list_size -= 8;
pci_dev_list_count--;
return;
}
if (pci_dev_list) {
bcopy(pci_dev_list, new, ((pci_dev_list_size - 8) *
sizeof *new));
FREE(pci_dev_list, M_DEVL);
}
pci_dev_list = new;
}
p = &pci_dev_list[pci_dev_list_count - 1];
p->pc_sel.pc_bus = bus;
p->pc_sel.pc_dev = dev;
p->pc_sel.pc_func = func;
tag = pcibus->pb_tag (bus, dev, func);
p->pc_devid = pci_conf_read(tag, PCI_ID_REG);
p->pc_subid = pci_conf_read(tag, PCI_SUBID_REG);
p->pc_class = pci_conf_read(tag, PCI_CLASS_REG);
}
static int
pci_open(dev_t dev, int oflags, int devtype, struct proc *p)
{
if ((oflags & FWRITE) && securelevel > 0) {
return EPERM;
}
return 0;
}
static int
pci_close(dev_t dev, int flag, int devtype, struct proc *p)
{
return 0;
}
static int
pci_ioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p)
{
struct pci_conf_io *cio;
struct pci_io *io;
size_t iolen;
int error;
pcici_t tag;
if (cmd != PCIOCGETCONF && !(flag & FWRITE))
return EPERM;
switch(cmd) {
case PCIOCGETCONF:
cio = (struct pci_conf_io *)data;
iolen = min(cio->pci_len,
pci_dev_list_count * sizeof(struct pci_conf));
cio->pci_len = pci_dev_list_count * sizeof(struct pci_conf);
error = copyout(pci_dev_list, cio->pci_buf, iolen);
break;
case PCIOCREAD:
io = (struct pci_io *)data;
switch(io->pi_width) {
case 4:
tag = pcibus->pb_tag (io->pi_sel.pc_bus,
io->pi_sel.pc_dev,
io->pi_sel.pc_func);
io->pi_data = pci_conf_read(tag, io->pi_reg);
error = 0;
break;
case 2:
case 1:
default:
error = ENODEV;
break;
}
break;
case PCIOCWRITE:
io = (struct pci_io *)data;
switch(io->pi_width) {
case 4:
tag = pcibus->pb_tag (io->pi_sel.pc_bus,
io->pi_sel.pc_dev,
io->pi_sel.pc_func);
pci_conf_write(tag, io->pi_reg, io->pi_data);
error = 0;
break;
case 2:
case 1:
default:
error = ENODEV;
break;
}
break;
default:
error = ENOTTY;
break;
}
return (error);
}
#define PCI_CDEV 78
static struct cdevsw pcicdev = {
pci_open, pci_close, noread, nowrite, pci_ioctl, nostop, noreset,
nodevtotty, noselect, nommap, nostrategy, "pci", 0, PCI_CDEV
};
#ifdef DEVFS
static void *pci_devfs_token;
#endif
static void
pci_cdevinit(void *dummy)
{
dev_t dev;
dev = makedev(PCI_CDEV, 0);
cdevsw_add(&dev, &pcicdev, NULL);
#ifdef DEVFS
pci_devfs_token = devfs_add_devswf(&pcicdev, 0, DV_CHR,
UID_ROOT, GID_WHEEL, 0644, "pci");
#endif
}
SYSINIT(pcidev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE+PCI_CDEV, pci_cdevinit, NULL);
#endif /* NPCI */

View File

@ -1,6 +1,6 @@
/**************************************************************************
**
** $Id: pcireg.h,v 1.6 1996/01/19 19:03:47 se Exp $
** $Id: pcireg.h,v 1.7 1996/01/25 18:31:59 se Exp $
**
** Names for PCI configuration space registers.
**
@ -160,6 +160,7 @@
#define PCI_PCI_BRIDGE_MEM_REG 0x20
#define PCI_PCI_BRIDGE_PMEM_REG 0x24
#define PCI_SUBID_REG 0x2c
#define PCI_SUBORDINATE_BUS_MASK 0x00ff0000
#define PCI_SECONDARY_BUS_MASK 0x0000ff00

View File

@ -1,6 +1,6 @@
/**************************************************************************
**
** $Id: pci.c,v 1.55 1996/09/10 23:30:59 bde Exp $
** $Id: pci.c,v 1.56 1996/10/14 13:04:34 se Exp $
**
** General subroutines for the PCI bus.
** pci_configure ()
@ -52,6 +52,11 @@
#include <sys/errno.h>
#include <sys/kernel.h>
#include <sys/proc.h> /* declaration of wakeup(), used by vm.h */
#include <sys/conf.h>
#ifdef DEVFS
#include <sys/devfsext.h>
#endif /* DEVFS */
#include <sys/fcntl.h>
#include <vm/vm.h>
#include <vm/vm_param.h>
@ -63,6 +68,7 @@
#include <pci/pcivar.h>
#include <pci/pcireg.h>
#include <pci/pcibus.h>
#include <pci/pci_ioctl.h>
#define PCI_MAX_IRQ (16)
@ -114,6 +120,8 @@ pci_bridge_config (void);
static int
pci_mfdev (int bus, int device);
static void pci_remember (int bus, int dev, int func);
/*========================================================
**
** Variables
@ -377,7 +385,7 @@ static int
pci_mfdev (int bus, int device)
{
pcici_t tag0,tag1;
int pci_id0, pci_id1;
unsigned pci_id0, pci_id1;
/*
** Detect a multi-function device that complies to the PCI 2.0 spec
@ -424,7 +432,7 @@ pci_bus_config (void)
u_long data;
int unit;
u_char pciint;
u_char irq;
int irq;
struct pci_device *dvp;
@ -514,6 +522,8 @@ pci_bus_config (void)
maxfunc = 7;
}
pci_remember(bus_no, device, func);
if (dvp==NULL) {
#ifndef PCI_QUIET
if (pci_conf_count)
@ -1720,4 +1730,156 @@ void not_supported (pcici_t tag, u_long type)
}
}
}
/*
* This is the user interface to the PCI configuration space.
*/
static struct pci_conf *pci_dev_list;
static unsigned pci_dev_list_count;
static unsigned pci_dev_list_size;
static void
pci_remember(int bus, int dev, int func)
{
struct pci_conf *p;
pcici_t tag;
if (++pci_dev_list_count > pci_dev_list_size) {
struct pci_conf *new;
pci_dev_list_size += 8;
MALLOC(new, struct pci_conf *, pci_dev_list_size * sizeof *new,
M_DEVL, M_NOWAIT);
if (!new) {
pci_dev_list_size -= 8;
pci_dev_list_count--;
return;
}
if (pci_dev_list) {
bcopy(pci_dev_list, new, ((pci_dev_list_size - 8) *
sizeof *new));
FREE(pci_dev_list, M_DEVL);
}
pci_dev_list = new;
}
p = &pci_dev_list[pci_dev_list_count - 1];
p->pc_sel.pc_bus = bus;
p->pc_sel.pc_dev = dev;
p->pc_sel.pc_func = func;
tag = pcibus->pb_tag (bus, dev, func);
p->pc_devid = pci_conf_read(tag, PCI_ID_REG);
p->pc_subid = pci_conf_read(tag, PCI_SUBID_REG);
p->pc_class = pci_conf_read(tag, PCI_CLASS_REG);
}
static int
pci_open(dev_t dev, int oflags, int devtype, struct proc *p)
{
if ((oflags & FWRITE) && securelevel > 0) {
return EPERM;
}
return 0;
}
static int
pci_close(dev_t dev, int flag, int devtype, struct proc *p)
{
return 0;
}
static int
pci_ioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p)
{
struct pci_conf_io *cio;
struct pci_io *io;
size_t iolen;
int error;
pcici_t tag;
if (cmd != PCIOCGETCONF && !(flag & FWRITE))
return EPERM;
switch(cmd) {
case PCIOCGETCONF:
cio = (struct pci_conf_io *)data;
iolen = min(cio->pci_len,
pci_dev_list_count * sizeof(struct pci_conf));
cio->pci_len = pci_dev_list_count * sizeof(struct pci_conf);
error = copyout(pci_dev_list, cio->pci_buf, iolen);
break;
case PCIOCREAD:
io = (struct pci_io *)data;
switch(io->pi_width) {
case 4:
tag = pcibus->pb_tag (io->pi_sel.pc_bus,
io->pi_sel.pc_dev,
io->pi_sel.pc_func);
io->pi_data = pci_conf_read(tag, io->pi_reg);
error = 0;
break;
case 2:
case 1:
default:
error = ENODEV;
break;
}
break;
case PCIOCWRITE:
io = (struct pci_io *)data;
switch(io->pi_width) {
case 4:
tag = pcibus->pb_tag (io->pi_sel.pc_bus,
io->pi_sel.pc_dev,
io->pi_sel.pc_func);
pci_conf_write(tag, io->pi_reg, io->pi_data);
error = 0;
break;
case 2:
case 1:
default:
error = ENODEV;
break;
}
break;
default:
error = ENOTTY;
break;
}
return (error);
}
#define PCI_CDEV 78
static struct cdevsw pcicdev = {
pci_open, pci_close, noread, nowrite, pci_ioctl, nostop, noreset,
nodevtotty, noselect, nommap, nostrategy, "pci", 0, PCI_CDEV
};
#ifdef DEVFS
static void *pci_devfs_token;
#endif
static void
pci_cdevinit(void *dummy)
{
dev_t dev;
dev = makedev(PCI_CDEV, 0);
cdevsw_add(&dev, &pcicdev, NULL);
#ifdef DEVFS
pci_devfs_token = devfs_add_devswf(&pcicdev, 0, DV_CHR,
UID_ROOT, GID_WHEEL, 0644, "pci");
#endif
}
SYSINIT(pcidev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE+PCI_CDEV, pci_cdevinit, NULL);
#endif /* NPCI */

View File

@ -1,6 +1,6 @@
/**************************************************************************
**
** $Id: pcireg.h,v 1.6 1996/01/19 19:03:47 se Exp $
** $Id: pcireg.h,v 1.7 1996/01/25 18:31:59 se Exp $
**
** Names for PCI configuration space registers.
**
@ -160,6 +160,7 @@
#define PCI_PCI_BRIDGE_MEM_REG 0x20
#define PCI_PCI_BRIDGE_PMEM_REG 0x24
#define PCI_SUBID_REG 0x2c
#define PCI_SUBORDINATE_BUS_MASK 0x00ff0000
#define PCI_SECONDARY_BUS_MASK 0x0000ff00