Date: Sat, 21 Feb 2015 22:38:32 +0000 (UTC) From: Konstantin Belousov <kib@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r279117 - head/sys/x86/iommu Message-ID: <201502212238.t1LMcWVB015893@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: kib Date: Sat Feb 21 22:38:32 2015 New Revision: 279117 URL: https://svnweb.freebsd.org/changeset/base/279117 Log: Revert r276949 and redo the fix for PCIe/PCI bridges, which do not follow specification and do not provide PCIe capability. Verify if the port above such bridge is downstream PCIe (or root port) and treat the bridge as PCIe/PCI then. This allows to avoid maintaining the table of device ids for bridges without capability, while still calculate correct request originator for devices behind the bridge. Submitted by: Jason Harmening <jason.harmening@gmail.com> MFC after: 1 week Modified: head/sys/x86/iommu/busdma_dmar.c Modified: head/sys/x86/iommu/busdma_dmar.c ============================================================================== --- head/sys/x86/iommu/busdma_dmar.c Sat Feb 21 22:27:57 2015 (r279116) +++ head/sys/x86/iommu/busdma_dmar.c Sat Feb 21 22:38:32 2015 (r279117) @@ -98,6 +98,8 @@ dmar_get_requester(device_t dev, uint16_ devclass_t pci_class; device_t l, pci, pcib, pcip, pcibp, requester; int cap_offset; + uint16_t pcie_flags; + bool bridge_is_pcie; pci_class = devclass_find("pci"); l = requester = dev; @@ -144,13 +146,30 @@ dmar_get_requester(device_t dev, uint16_ } else { /* * Device is not PCIe, it cannot be seen as a - * requester by DMAR unit. + * requester by DMAR unit. Check whether the + * bridge is PCIe. */ - requester = pcibp; + bridge_is_pcie = pci_find_cap(pcib, PCIY_EXPRESS, + &cap_offset) == 0; + requester = pcib; - /* Check whether the bus above the bridge is PCIe. */ - if (pci_find_cap(pcibp, PCIY_EXPRESS, - &cap_offset) == 0) { + /* + * Check for a buggy PCIe/PCI bridge that + * doesn't report the express capability. If + * the bridge above it is express but isn't a + * PCI bridge, then we know pcib is actually a + * PCIe/PCI bridge. + */ + if (!bridge_is_pcie && pci_find_cap(pcibp, + PCIY_EXPRESS, &cap_offset) == 0) { + pcie_flags = pci_read_config(pcibp, + cap_offset + PCIER_FLAGS, 2); + if ((pcie_flags & PCIEM_FLAGS_TYPE) != + PCIEM_TYPE_PCI_BRIDGE) + bridge_is_pcie = true; + } + + if (bridge_is_pcie) { /* * The current device is not PCIe, but * the bridge above it is. This is a @@ -168,6 +187,7 @@ dmar_get_requester(device_t dev, uint16_ * non-taken transactions. */ *rid = PCI_RID(pci_get_bus(l), 0, 0); + l = pcibp; } else { /* * Neither the device nor the bridge @@ -177,8 +197,8 @@ dmar_get_requester(device_t dev, uint16_ * requester ID. */ *rid = pci_get_rid(pcib); + l = pcib; } - l = pcibp; } } return (requester);
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201502212238.t1LMcWVB015893>