diff options
-rw-r--r-- | sys/dev/pci/pci.c | 71 | ||||
-rw-r--r-- | sys/dev/pci/pcivar.h | 4 | ||||
-rw-r--r-- | sys/sys/pciio.h | 3 | ||||
-rw-r--r-- | usr.sbin/pcidump/pcidump.c | 53 |
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, ®) != 0) + if (pci_read(bus, dev, func, bar, ®) != 0 || + pci_readmask(bus, dev, func, bar, ®1) != 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, ®) != 0) + if (pci_read(bus, dev, func, bar, ®) != 0 || + pci_readmask(bus, dev, func, bar, ®1) != 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; |