diff options
| author | msaitoh <msaitoh@NetBSD.org> | 2019-01-29 09:25:52 +0000 |
|---|---|---|
| committer | msaitoh <msaitoh@NetBSD.org> | 2019-01-29 09:25:52 +0000 |
| commit | 94e76cb2d8e636f0fa6b7d402f527c7cfba2f827 (patch) | |
| tree | b484d39e3a9604cecd4e8ee9fdd15a6ca76049dc /sys/dev | |
| parent | c5d0eca830a4802b30515558e74ec8a69969518c (diff) | |
If the secondary bus is configured and the bus mastering is not enabled,
enable it. Suggested by thorpej@.
Diffstat (limited to 'sys/dev')
| -rw-r--r-- | sys/dev/pci/ppb.c | 75 |
1 files changed, 69 insertions, 6 deletions
diff --git a/sys/dev/pci/ppb.c b/sys/dev/pci/ppb.c index 954f296d79a..8ac93b224d4 100644 --- a/sys/dev/pci/ppb.c +++ b/sys/dev/pci/ppb.c @@ -1,4 +1,4 @@ -/* $NetBSD: ppb.c,v 1.66 2019/01/28 04:09:51 msaitoh Exp $ */ +/* $NetBSD: ppb.c,v 1.67 2019/01/29 09:25:52 msaitoh Exp $ */ /* * Copyright (c) 1996, 1998 Christopher G. Demetriou. All rights reserved. @@ -31,7 +31,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: ppb.c,v 1.66 2019/01/28 04:09:51 msaitoh Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ppb.c,v 1.67 2019/01/29 09:25:52 msaitoh Exp $"); #ifdef _KERNEL_OPT #include "opt_ppb.h" @@ -222,6 +222,7 @@ ppbattach(device_t parent, device_t self, void *aux) char intrbuf[PCI_INTRSTR_LEN]; #endif pcireg_t busdata, reg; + bool second_configured = false; pci_aprint_devinfo(pa, NULL); @@ -358,10 +359,72 @@ ppbattach(device_t parent, device_t self, void *aux) } #endif /* PPB_USEINTR */ - /* Enable bus master. */ - reg = pci_conf_read(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG); - pci_conf_write(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, - reg | PCI_COMMAND_MASTER_ENABLE); + /* Configuration test */ + if (PPB_BUSINFO_SECONDARY(busdata) != 0) { + uint32_t base, limit; + + /* I/O region test */ + reg = pci_conf_read(pc, pa->pa_tag, PCI_BRIDGE_STATIO_REG); + base = (reg & PCI_BRIDGE_STATIO_IOBASE_MASK) << 8; + limit = ((reg >> PCI_BRIDGE_STATIO_IOLIMIT_SHIFT) + & PCI_BRIDGE_STATIO_IOLIMIT_MASK) << 8; + limit |= 0x00000fff; + if (PCI_BRIDGE_IO_32BITS(reg)) { + reg = pci_conf_read(pc, pa->pa_tag, + PCI_BRIDGE_IOHIGH_REG); + base |= ((reg >> PCI_BRIDGE_IOHIGH_BASE_SHIFT) + & 0xffff) << 16; + limit |= ((reg >> PCI_BRIDGE_IOHIGH_LIMIT_SHIFT) + & 0xffff) << 16; + } + if (base < limit) { + second_configured = true; + goto configure; + } + + /* Non-prefetchable memory region test */ + reg = pci_conf_read(pc, pa->pa_tag, PCI_BRIDGE_MEMORY_REG); + base = ((reg >> PCI_BRIDGE_MEMORY_BASE_SHIFT) + & PCI_BRIDGE_MEMORY_BASE_MASK) << 20; + limit = (((reg >> PCI_BRIDGE_MEMORY_LIMIT_SHIFT) + & PCI_BRIDGE_MEMORY_LIMIT_MASK) << 20) | 0x000fffff; + if (base < limit) { + second_configured = true; + goto configure; + } + + /* Prefetchable memory region test */ + reg = pci_conf_read(pc, pa->pa_tag, + PCI_BRIDGE_PREFETCHMEM_REG); + base = ((reg >> PCI_BRIDGE_PREFETCHMEM_BASE_SHIFT) + & PCI_BRIDGE_PREFETCHMEM_BASE_MASK) << 20; + limit = (((reg >> PCI_BRIDGE_PREFETCHMEM_LIMIT_SHIFT) + & PCI_BRIDGE_PREFETCHMEM_LIMIT_MASK) << 20) | 0x000fffff; + if (PCI_BRIDGE_PREFETCHMEM_64BITS(reg)) { + reg = pci_conf_read(pc, pa->pa_tag, + PCI_BRIDGE_IOHIGH_REG); + base |= (uint64_t)pci_conf_read(pc, pa->pa_tag, + PCI_BRIDGE_PREFETCHBASE32_REG) << 32; + limit |= (uint64_t)pci_conf_read(pc, pa->pa_tag, + PCI_BRIDGE_PREFETCHLIMIT32_REG) << 32; + } + if (base < limit) { + second_configured = true; + goto configure; + } + } + +configure: + /* + * If the secondary bus is configured and the bus mastering is not + * enabled, enable it. + */ + if (second_configured) { + reg = pci_conf_read(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG); + if ((reg & PCI_COMMAND_MASTER_ENABLE) == 0) + pci_conf_write(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, + reg | PCI_COMMAND_MASTER_ENABLE); + } if (!pmf_device_register(self, ppb_suspend, ppb_resume)) aprint_error_dev(self, "couldn't establish power handler\n"); |
