svn commit: r339432 - in head/sys/amd64: amd64 include pci

Konstantin Belousov kib at FreeBSD.org
Thu Oct 18 20:49:18 UTC 2018


Author: kib
Date: Thu Oct 18 20:49:16 2018
New Revision: 339432
URL: https://svnweb.freebsd.org/changeset/base/339432

Log:
  Do not flush cache for PCIe config window.
  
  Apparently AMD machines cannot tolerate this. This was uncovered by
  r339386, where cache flush started really flushing the requested range.
  
  Introduce pmap_mapdev_pciecfg(), which simply does not flush cache
  comparing with pmap_mapdev().  It assumes that the MCFG region was
  never accessed through the cacheable mapping, which is most likely
  true for machine to boot at all.
  
  Note that i386 does not need the change, since the architecture
  handles access per-page due to the KVA shortage, and page remapping
  already does not flush the cache.
  
  Reported and tested by:	mjg, Mike Tancsa <mike at sentex.net>
  Reviewed by:	alc
  Sponsored by:	The FreeBSD Foundation
  Approved by:	re (gjb)
  MFC after:	2 weeks
  Differential revision:	https://reviews.freebsd.org/D17612

Modified:
  head/sys/amd64/amd64/pmap.c
  head/sys/amd64/include/pmap.h
  head/sys/amd64/pci/pci_cfgreg.c

Modified: head/sys/amd64/amd64/pmap.c
==============================================================================
--- head/sys/amd64/amd64/pmap.c	Thu Oct 18 20:20:41 2018	(r339431)
+++ head/sys/amd64/amd64/pmap.c	Thu Oct 18 20:49:16 2018	(r339432)
@@ -637,7 +637,8 @@ static void	pmap_pvh_free(struct md_page *pvh, pmap_t 
 static pv_entry_t pmap_pvh_remove(struct md_page *pvh, pmap_t pmap,
 		    vm_offset_t va);
 
-static int pmap_change_attr_locked(vm_offset_t va, vm_size_t size, int mode);
+static int pmap_change_attr_locked(vm_offset_t va, vm_size_t size, int mode,
+    bool noflush);
 static boolean_t pmap_demote_pde(pmap_t pmap, pd_entry_t *pde, vm_offset_t va);
 static boolean_t pmap_demote_pde_locked(pmap_t pmap, pd_entry_t *pde,
     vm_offset_t va, struct rwlock **lockp);
@@ -7098,8 +7099,8 @@ pmap_pde_attr(pd_entry_t *pde, int cache_bits, int mas
  * routine is intended to be used for mapping device memory,
  * NOT real memory.
  */
-void *
-pmap_mapdev_attr(vm_paddr_t pa, vm_size_t size, int mode)
+static void *
+pmap_mapdev_internal(vm_paddr_t pa, vm_size_t size, int mode, bool noflush)
 {
 	struct pmap_preinit_mapping *ppim;
 	vm_offset_t va, offset;
@@ -7142,7 +7143,10 @@ pmap_mapdev_attr(vm_paddr_t pa, vm_size_t size, int mo
 		 */
 		if (pa < dmaplimit && pa + size <= dmaplimit) {
 			va = PHYS_TO_DMAP(pa);
-			if (!pmap_change_attr(va, size, mode))
+			PMAP_LOCK(kernel_pmap);
+			i = pmap_change_attr_locked(va, size, mode, noflush);
+			PMAP_UNLOCK(kernel_pmap);
+			if (!i)
 				return ((void *)(va + offset));
 		}
 		va = kva_alloc(size);
@@ -7152,22 +7156,37 @@ pmap_mapdev_attr(vm_paddr_t pa, vm_size_t size, int mo
 	for (tmpsize = 0; tmpsize < size; tmpsize += PAGE_SIZE)
 		pmap_kenter_attr(va + tmpsize, pa + tmpsize, mode);
 	pmap_invalidate_range(kernel_pmap, va, va + tmpsize);
-	pmap_invalidate_cache_range(va, va + tmpsize);
+	if (!noflush)
+		pmap_invalidate_cache_range(va, va + tmpsize);
 	return ((void *)(va + offset));
 }
 
 void *
+pmap_mapdev_attr(vm_paddr_t pa, vm_size_t size, int mode)
+{
+
+	return (pmap_mapdev_internal(pa, size, mode, false));
+}
+
+void *
 pmap_mapdev(vm_paddr_t pa, vm_size_t size)
 {
 
-	return (pmap_mapdev_attr(pa, size, PAT_UNCACHEABLE));
+	return (pmap_mapdev_internal(pa, size, PAT_UNCACHEABLE, false));
 }
 
 void *
+pmap_mapdev_pciecfg(vm_paddr_t pa, vm_size_t size)
+{
+
+	return (pmap_mapdev_internal(pa, size, PAT_UNCACHEABLE, true));
+}
+
+void *
 pmap_mapbios(vm_paddr_t pa, vm_size_t size)
 {
 
-	return (pmap_mapdev_attr(pa, size, PAT_WRITE_BACK));
+	return (pmap_mapdev_internal(pa, size, PAT_WRITE_BACK, false));
 }
 
 void
@@ -7306,13 +7325,13 @@ pmap_change_attr(vm_offset_t va, vm_size_t size, int m
 	int error;
 
 	PMAP_LOCK(kernel_pmap);
-	error = pmap_change_attr_locked(va, size, mode);
+	error = pmap_change_attr_locked(va, size, mode, false);
 	PMAP_UNLOCK(kernel_pmap);
 	return (error);
 }
 
 static int
-pmap_change_attr_locked(vm_offset_t va, vm_size_t size, int mode)
+pmap_change_attr_locked(vm_offset_t va, vm_size_t size, int mode, bool noflush)
 {
 	vm_offset_t base, offset, tmpva;
 	vm_paddr_t pa_start, pa_end, pa_end1;
@@ -7429,7 +7448,7 @@ pmap_change_attr_locked(vm_offset_t va, vm_size_t size
 					/* Run ended, update direct map. */
 					error = pmap_change_attr_locked(
 					    PHYS_TO_DMAP(pa_start),
-					    pa_end - pa_start, mode);
+					    pa_end - pa_start, mode, noflush);
 					if (error != 0)
 						break;
 					/* Start physical address run. */
@@ -7459,7 +7478,7 @@ pmap_change_attr_locked(vm_offset_t va, vm_size_t size
 					/* Run ended, update direct map. */
 					error = pmap_change_attr_locked(
 					    PHYS_TO_DMAP(pa_start),
-					    pa_end - pa_start, mode);
+					    pa_end - pa_start, mode, noflush);
 					if (error != 0)
 						break;
 					/* Start physical address run. */
@@ -7487,7 +7506,7 @@ pmap_change_attr_locked(vm_offset_t va, vm_size_t size
 					/* Run ended, update direct map. */
 					error = pmap_change_attr_locked(
 					    PHYS_TO_DMAP(pa_start),
-					    pa_end - pa_start, mode);
+					    pa_end - pa_start, mode, noflush);
 					if (error != 0)
 						break;
 					/* Start physical address run. */
@@ -7502,7 +7521,7 @@ pmap_change_attr_locked(vm_offset_t va, vm_size_t size
 		pa_end1 = MIN(pa_end, dmaplimit);
 		if (pa_start != pa_end1)
 			error = pmap_change_attr_locked(PHYS_TO_DMAP(pa_start),
-			    pa_end1 - pa_start, mode);
+			    pa_end1 - pa_start, mode, noflush);
 	}
 
 	/*
@@ -7511,7 +7530,8 @@ pmap_change_attr_locked(vm_offset_t va, vm_size_t size
 	 */
 	if (changed) {
 		pmap_invalidate_range(kernel_pmap, base, tmpva);
-		pmap_invalidate_cache_range(base, tmpva);
+		if (!noflush)
+			pmap_invalidate_cache_range(base, tmpva);
 	}
 	return (error);
 }

Modified: head/sys/amd64/include/pmap.h
==============================================================================
--- head/sys/amd64/include/pmap.h	Thu Oct 18 20:20:41 2018	(r339431)
+++ head/sys/amd64/include/pmap.h	Thu Oct 18 20:49:16 2018	(r339432)
@@ -430,6 +430,7 @@ void	pmap_large_unmap(void *sva, vm_size_t len);
 void	*pmap_mapbios(vm_paddr_t, vm_size_t);
 void	*pmap_mapdev(vm_paddr_t, vm_size_t);
 void	*pmap_mapdev_attr(vm_paddr_t, vm_size_t, int);
+void	*pmap_mapdev_pciecfg(vm_paddr_t pa, vm_size_t size);
 boolean_t pmap_page_is_mapped(vm_page_t m);
 void	pmap_page_set_memattr(vm_page_t m, vm_memattr_t ma);
 void	pmap_pinit_pml4(vm_page_t);

Modified: head/sys/amd64/pci/pci_cfgreg.c
==============================================================================
--- head/sys/amd64/pci/pci_cfgreg.c	Thu Oct 18 20:20:41 2018	(r339431)
+++ head/sys/amd64/pci/pci_cfgreg.c	Thu Oct 18 20:49:16 2018	(r339432)
@@ -271,7 +271,7 @@ pcie_cfgregopen(uint64_t base, uint8_t minbus, uint8_t
 		    base);
 
 	/* XXX: We should make sure this really fits into the direct map. */
-	pcie_base = (vm_offset_t)pmap_mapdev(base, (maxbus + 1) << 20);
+	pcie_base = (vm_offset_t)pmap_mapdev_pciecfg(base, (maxbus + 1) << 20);
 	pcie_minbus = minbus;
 	pcie_maxbus = maxbus;
 	cfgmech = CFGMECH_PCIE;


More information about the svn-src-all mailing list