1
0
mirror of https://github.com/openbsd/src.git synced 2024-12-22 16:42:56 -08:00

Add an ioctl to figure out the non-sticky bits in PCI BARs used for determining

the size of those BARs.  Make pcidump use this new ioctl to print the size
of PCI BARs.

ok deraadt@, miod@
This commit is contained in:
kettenis 2010-09-05 18:14:33 +00:00
parent 311a1debed
commit d01993f357
4 changed files with 113 additions and 18 deletions

View File

@ -1,4 +1,4 @@
/* $OpenBSD: pci.c,v 1.83 2010/08/31 17:13:44 deraadt Exp $ */
/* $OpenBSD: pci.c,v 1.84 2010/09/05 18:14:33 kettenis Exp $ */
/* $NetBSD: pci.c,v 1.31 1997/06/06 23:48:04 thorpej Exp $ */
/*
@ -63,6 +63,7 @@ struct pci_dev {
pcireg_t pd_bhlc;
pcireg_t pd_int;
pcireg_t pd_map[NMAPREG];
pcireg_t pd_mask[NMAPREG];
int pd_pmcsr_state;
};
@ -358,7 +359,7 @@ pci_probe_device(struct pci_softc *sc, pcitag_t tag,
struct pci_attach_args pa;
struct pci_dev *pd;
struct device *dev;
pcireg_t id, csr, class, intr, bhlcr;
pcireg_t id, class, intr, bhlcr;
int ret = 0, pin, bus, device, function;
pci_decompose_tag(pc, tag, &bus, &device, &function);
@ -368,7 +369,6 @@ pci_probe_device(struct pci_softc *sc, pcitag_t tag,
return (0);
id = pci_conf_read(pc, tag, PCI_ID_REG);
csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
class = pci_conf_read(pc, tag, PCI_CLASS_REG);
/* Invalid vendor ID value? */
@ -430,10 +430,48 @@ pci_probe_device(struct pci_softc *sc, pcitag_t tag,
if (ret != 0 && pap != NULL)
*pap = pa;
} else {
pcireg_t address, csr;
int i, reg, reg_start, reg_end;
int s;
pd = malloc(sizeof *pd, M_DEVBUF, M_ZERO | M_WAITOK);
pd->pd_tag = tag;
LIST_INSERT_HEAD(&sc->sc_devs, pd, pd_next);
switch (PCI_HDRTYPE_TYPE(bhlcr)) {
case 0:
reg_start = PCI_MAPREG_START;
reg_end = PCI_MAPREG_END;
break;
case 1: /* PCI-PCI bridge */
reg_start = PCI_MAPREG_START;
reg_end = PCI_MAPREG_PPB_END;
break;
case 2: /* PCI-CardBus bridge */
reg_start = PCI_MAPREG_START;
reg_end = PCI_MAPREG_PCB_END;
break;
default:
return (0);
}
s = splhigh();
csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
if (csr & (PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE))
pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, csr &
~(PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE));
for (reg = reg_start, i = 0; reg < reg_end; reg += 4, i++) {
address = pci_conf_read(pc, tag, reg);
pci_conf_write(pc, tag, reg, 0xffffffff);
pd->pd_mask[i] = pci_conf_read(pc, tag, reg);
pci_conf_write(pc, tag, reg, address);
}
if (csr & (PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE))
pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, csr);
splx(s);
if ((dev = config_found_sm(&sc->sc_dev, &pa, pciprint,
pcisubmatch)))
pci_dev_postattach(dev, &pa);
@ -509,7 +547,7 @@ pci_get_capability(pci_chipset_tag_t pc, pcitag_t tag, int capid,
int
pci_find_device(struct pci_attach_args *pa,
int (*match)(struct pci_attach_args *))
int (*match)(struct pci_attach_args *))
{
extern struct cfdriver pci_cd;
struct device *pcidev;
@ -903,6 +941,7 @@ pciioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
switch (cmd) {
case PCIOCREAD:
case PCIOCREADMASK:
break;
case PCIOCWRITE:
if (!(flag & FWRITE))
@ -971,6 +1010,30 @@ pciioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
}
break;
case PCIOCREADMASK:
{
io = (struct pci_io *)data;
struct pci_dev *pd;
int dev, func, i;
if (io->pi_width != 4 || io->pi_reg & 0x3 ||
io->pi_reg < PCI_MAPREG_START ||
io->pi_reg >= PCI_MAPREG_END)
return (EINVAL);
error = ENODEV;
LIST_FOREACH(pd, &pci->sc_devs, pd_next) {
pci_decompose_tag(pc, pd->pd_tag, NULL, &dev, &func);
if (dev == sel->pc_dev && func == sel->pc_func) {
i = (io->pi_reg - PCI_MAPREG_START) / 4;
io->pi_data = pd->pd_mask[i];
error = 0;
break;
}
}
break;
}
case PCIOCGETROMLEN:
case PCIOCGETROM:
{

View File

@ -1,4 +1,4 @@
/* $OpenBSD: pcivar.h,v 1.61 2010/08/27 20:31:55 kettenis Exp $ */
/* $OpenBSD: pcivar.h,v 1.62 2010/09/05 18:14:33 kettenis Exp $ */
/* $NetBSD: pcivar.h,v 1.23 1997/06/06 23:48:05 thorpej Exp $ */
/*
@ -252,7 +252,7 @@ int pci_vpd_write(pci_chipset_tag_t, pcitag_t, int, int, pcireg_t *);
const char *pci_findvendor(pcireg_t);
const char *pci_findproduct(pcireg_t);
int pci_find_device(struct pci_attach_args *pa,
int (*match)(struct pci_attach_args *));
int (*match)(struct pci_attach_args *));
int pci_probe_device(struct pci_softc *, pcitag_t tag,
int (*)(struct pci_attach_args *), struct pci_attach_args *);
int pci_detach_devices(struct pci_softc *, int);

View File

@ -1,4 +1,4 @@
/* $OpenBSD: pciio.h,v 1.6 2010/04/21 18:55:40 kettenis Exp $ */
/* $OpenBSD: pciio.h,v 1.7 2010/09/05 18:14:33 kettenis Exp $ */
/*-
* Copyright (c) 1997, Stefan Esser <se@FreeBSD.ORG>
@ -73,5 +73,6 @@ struct pci_vga {
#define PCIOCGETROM _IOWR('p', 5, struct pci_rom)
#define PCIOCGETVGA _IOWR('p', 6, struct pci_vga)
#define PCIOCSETVGA _IOWR('p', 7, struct pci_vga)
#define PCIOCREADMASK _IOWR('p', 8, struct pci_io)
#endif /* !_SYS_PCIIO_H_ */

View File

@ -1,4 +1,4 @@
/* $OpenBSD: pcidump.c,v 1.23 2010/08/02 10:17:10 jsg Exp $ */
/* $OpenBSD: pcidump.c,v 1.24 2010/09/05 18:14:33 kettenis Exp $ */
/*
* Copyright (c) 2006, 2007 David Gwynne <loki@animata.net>
@ -43,6 +43,7 @@ void hexdump(int, int, int, int);
const char *str2busdevfunc(const char *, int *, int *, int *);
int pci_nfuncs(int, int);
int pci_read(int, int, int, u_int32_t, u_int32_t *);
int pci_readmask(int, int, int, u_int32_t, u_int32_t *);
void dump_caplist(int, int, int, u_int8_t);
void dump_pcie_linkspeed(int, int, int, uint8_t);
void print_pcie_ls(uint8_t);
@ -344,16 +345,18 @@ dump_type0(int bus, int dev, int func)
{
const char *memtype;
u_int64_t mem;
u_int32_t reg;
u_int64_t mask;
u_int32_t reg, reg1;
int bar;
for (bar = PCI_MAPREG_START; bar < PCI_MAPREG_END; bar += 0x4) {
if (pci_read(bus, dev, func, bar, &reg) != 0)
if (pci_read(bus, dev, func, bar, &reg) != 0 ||
pci_readmask(bus, dev, func, bar, &reg1) != 0)
warn("unable to read PCI_MAPREG 0x%02x", bar);
printf("\t0x%04x: BAR ", bar);
if (reg == 0x0) {
if (reg == 0 && reg1 == 0) {
printf("empty (%08x)\n", reg);
continue;
}
@ -371,28 +374,34 @@ dump_type0(int bus, int dev, int func)
case PCI_MAPREG_MEM_TYPE_32BIT_1M:
printf("%s ", memtype);
printf("addr: 0x%08x\n",
PCI_MAPREG_MEM_ADDR(reg));
printf("addr: 0x%08x/0x%08x\n",
PCI_MAPREG_MEM_ADDR(reg),
PCI_MAPREG_MEM_SIZE(reg1));
break;
case PCI_MAPREG_MEM_TYPE_64BIT:
mem = reg;
mask = reg1;
bar += 0x04;
if (pci_read(bus, dev, func, bar, &reg) != 0)
if (pci_read(bus, dev, func, bar, &reg) != 0 ||
pci_readmask(bus, dev, func, bar, &reg1) != 0)
warn("unable to read 0x%02x", bar);
mem |= (u_int64_t)reg << 32;
mask |= (u_int64_t)reg1 << 32;
printf("64bit addr: 0x%016llx\n",
PCI_MAPREG_MEM64_ADDR(mem));
printf("64bit addr: 0x%016llx/0x%08llx\n",
PCI_MAPREG_MEM64_ADDR(mem),
PCI_MAPREG_MEM64_SIZE(mask));
break;
}
break;
case PCI_MAPREG_TYPE_IO:
printf("io addr: 0x%08x\n",
PCI_MAPREG_IO_ADDR(reg));
printf("io addr: 0x%08x/0x%04x\n",
PCI_MAPREG_IO_ADDR(reg),
PCI_MAPREG_IO_SIZE(reg1));
break;
}
}
@ -658,6 +667,28 @@ pci_read(int bus, int dev, int func, u_int32_t reg, u_int32_t *val)
return (0);
}
int
pci_readmask(int bus, int dev, int func, u_int32_t reg, u_int32_t *val)
{
struct pci_io io;
int rv;
bzero(&io, sizeof(io));
io.pi_sel.pc_bus = bus;
io.pi_sel.pc_dev = dev;
io.pi_sel.pc_func = func;
io.pi_reg = reg;
io.pi_width = 4;
rv = ioctl(pcifd, PCIOCREADMASK, &io);
if (rv != 0)
return (rv);
*val = io.pi_data;
return (0);
}
int
dump_rom(int bus, int dev, int func)
{