summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/dev/pci/pci.c71
-rw-r--r--sys/dev/pci/pcivar.h4
-rw-r--r--sys/sys/pciio.h3
-rw-r--r--usr.sbin/pcidump/pcidump.c53
4 files changed, 113 insertions, 18 deletions
diff --git a/sys/dev/pci/pci.c b/sys/dev/pci/pci.c
index 1698fd846f5..6a88d510961 100644
--- a/sys/dev/pci/pci.c
+++ b/sys/dev/pci/pci.c
@@ -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:
{
diff --git a/sys/dev/pci/pcivar.h b/sys/dev/pci/pcivar.h
index 3133c435e69..ad5a5c12649 100644
--- a/sys/dev/pci/pcivar.h
+++ b/sys/dev/pci/pcivar.h
@@ -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);
diff --git a/sys/sys/pciio.h b/sys/sys/pciio.h
index 2e40f411c74..713e798e02f 100644
--- a/sys/sys/pciio.h
+++ b/sys/sys/pciio.h
@@ -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_ */
diff --git a/usr.sbin/pcidump/pcidump.c b/usr.sbin/pcidump/pcidump.c
index 3e846e23a6a..942e86d5c8b 100644
--- a/usr.sbin/pcidump/pcidump.c
+++ b/usr.sbin/pcidump/pcidump.c
@@ -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;
}
}
@@ -659,6 +668,28 @@ pci_read(int bus, int dev, int func, u_int32_t reg, u_int32_t *val)
}
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)
{
struct pci_rom rom;