From owner-svn-src-all@FreeBSD.ORG Sat Jan 10 23:12:50 2015 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id 9974D6DF; Sat, 10 Jan 2015 23:12:50 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 85FA412F; Sat, 10 Jan 2015 23:12:50 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.9/8.14.9) with ESMTP id t0ANCob4021435; Sat, 10 Jan 2015 23:12:50 GMT (envelope-from kib@FreeBSD.org) Received: (from kib@localhost) by svn.freebsd.org (8.14.9/8.14.9/Submit) id t0ANCoi9021434; Sat, 10 Jan 2015 23:12:50 GMT (envelope-from kib@FreeBSD.org) Message-Id: <201501102312.t0ANCoi9021434@svn.freebsd.org> X-Authentication-Warning: svn.freebsd.org: kib set sender to kib@FreeBSD.org using -f From: Konstantin Belousov Date: Sat, 10 Jan 2015 23:12:50 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r276949 - head/sys/x86/iommu X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 10 Jan 2015 23:12:50 -0000 Author: kib Date: Sat Jan 10 23:12:49 2015 New Revision: 276949 URL: https://svnweb.freebsd.org/changeset/base/276949 Log: Fix calculation of requester for PCI device behind PCIe/PCI bridge. In my case on the test machine, I have hierarchy of pcib2 (PCIe port on host bridge with PCIe capability) -> pci2 -> pcib3 (ITE PCIe/PCI bridge) -> pci3 -> em1 The device to check PCIe capability is pcib2 and not pcib3, as it is currently done in the code. Also, in case of the bridge, we shall step to pcib2 for the loop iteration, since pcib3 does not carry PCIe capability info and would force wrong recalculation of rid. Also change the returned requester to the PCIe bus which provides port for the bridge. This only results in changing hw.busdma.pciX.X.X.X.bounce tunable to force identity-mapped context for the device. Sponsored by: The FreeBSD Foundation 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 Jan 10 22:57:08 2015 (r276948) +++ head/sys/x86/iommu/busdma_dmar.c Sat Jan 10 23:12:49 2015 (r276949) @@ -96,11 +96,11 @@ static device_t dmar_get_requester(device_t dev, uint16_t *rid) { devclass_t pci_class; - device_t pci, pcib, requester; + device_t l, pci, pcib, pcip, pcibp, requester; int cap_offset; pci_class = devclass_find("pci"); - requester = dev; + l = requester = dev; *rid = pci_get_rid(dev); @@ -110,19 +110,17 @@ dmar_get_requester(device_t dev, uint16_ * unit. */ for (;;) { - pci = device_get_parent(dev); - KASSERT(pci != NULL, ("NULL parent for pci%d:%d:%d:%d", - pci_get_domain(dev), pci_get_bus(dev), pci_get_slot(dev), - pci_get_function(dev))); + pci = device_get_parent(l); + KASSERT(pci != NULL, ("dmar_get_requester(%s): NULL parent " + "for %s", device_get_name(dev), device_get_name(l))); KASSERT(device_get_devclass(pci) == pci_class, - ("Non-pci parent for pci%d:%d:%d:%d", - pci_get_domain(dev), pci_get_bus(dev), pci_get_slot(dev), - pci_get_function(dev))); + ("dmar_get_requester(%s): non-pci parent %s for %s", + device_get_name(dev), device_get_name(pci), + device_get_name(l))); pcib = device_get_parent(pci); - KASSERT(pcib != NULL, ("NULL bridge for pci%d:%d:%d:%d", - pci_get_domain(dev), pci_get_bus(dev), pci_get_slot(dev), - pci_get_function(dev))); + KASSERT(pcib != NULL, ("dmar_get_requester(%s): NULL bridge " + "for %s", device_get_name(dev), device_get_name(pci))); /* * The parent of our "bridge" isn't another PCI bus, @@ -130,18 +128,28 @@ dmar_get_requester(device_t dev, uint16_ * port, and the requester ID won't be translated * further. */ - if (device_get_devclass(device_get_parent(pcib)) != pci_class) + pcip = device_get_parent(pcib); + if (device_get_devclass(pcip) != pci_class) break; + pcibp = device_get_parent(pcip); - if (pci_find_cap(dev, PCIY_EXPRESS, &cap_offset) != 0) { + if (pci_find_cap(l, PCIY_EXPRESS, &cap_offset) == 0) { + /* + * Do not stop the loop even if the target + * device is PCIe, because it is possible (but + * unlikely) to have a PCI->PCIe bridge + * somewhere in the hierarchy. + */ + l = pcib; + } else { /* * Device is not PCIe, it cannot be seen as a * requester by DMAR unit. */ - requester = pcib; + requester = pcibp; - /* Check whether the bus above is PCIe. */ - if (pci_find_cap(pcib, PCIY_EXPRESS, + /* Check whether the bus above the bridge is PCIe. */ + if (pci_find_cap(pcibp, PCIY_EXPRESS, &cap_offset) == 0) { /* * The current device is not PCIe, but @@ -159,7 +167,7 @@ dmar_get_requester(device_t dev, uint16_ * same page tables for taken and * non-taken transactions. */ - *rid = PCI_RID(pci_get_bus(dev), 0, 0); + *rid = PCI_RID(pci_get_bus(l), 0, 0); } else { /* * Neither the device nor the bridge @@ -170,14 +178,8 @@ dmar_get_requester(device_t dev, uint16_ */ *rid = pci_get_rid(pcib); } + l = pcibp; } - /* - * Do not stop the loop even if the target device is - * PCIe, because it is possible (but unlikely) to have - * a PCI->PCIe bridge somewhere in the hierarchy. - */ - - dev = pcib; } return (requester); }