[PATCH] Don't add MTRR for uncached regions. Remove MTRR on unmap.

Keith Packard keithp at keithp.com
Fri Aug 31 13:48:41 PDT 2007


MTRR regions aren't needed for uncached mappings, so don't add them. Also,
when unmapping memory, remove the MTRR entry.
---
 src/linux_sysfs.c |   75 +++++++++++++++++++++++++++++++++++++++++++++++-----
 1 files changed, 67 insertions(+), 8 deletions(-)

diff --git a/src/linux_sysfs.c b/src/linux_sysfs.c
index 1c4e02e..3671f28 100644
--- a/src/linux_sysfs.c
+++ b/src/linux_sysfs.c
@@ -63,6 +63,9 @@ static int pci_device_linux_sysfs_probe( struct pci_device * dev );
 static int pci_device_linux_sysfs_map_range(struct pci_device *dev,
     struct pci_device_mapping *map);
 
+static int pci_device_linux_sysfs_unmap_range(struct pci_device *dev,
+    struct pci_device_mapping *map);
+
 static int pci_device_linux_sysfs_read( struct pci_device * dev, void * data,
     pciaddr_t offset, pciaddr_t size, pciaddr_t * bytes_read );
 
@@ -76,7 +79,7 @@ static const struct pci_system_methods linux_sysfs_methods = {
     .read_rom = pci_device_linux_sysfs_read_rom,
     .probe = pci_device_linux_sysfs_probe,
     .map_range = pci_device_linux_sysfs_map_range,
-    .unmap_range = pci_device_generic_unmap_range,
+    .unmap_range = pci_device_linux_sysfs_unmap_range,
 
     .read = pci_device_linux_sysfs_read,
     .write = pci_device_linux_sysfs_write,
@@ -369,7 +372,7 @@ pci_device_linux_sysfs_read( struct pci_device * dev, void * data,
     pciaddr_t temp_size = size;
     int err = 0;
     int fd;
-
+    char *data_bytes = data;
 
     if ( bytes_read != NULL ) {
 	*bytes_read = 0;
@@ -394,7 +397,7 @@ pci_device_linux_sysfs_read( struct pci_device * dev, void * data,
 
 
     while ( temp_size > 0 ) {
-	const ssize_t bytes = pread64( fd, data, temp_size, offset );
+	const ssize_t bytes = pread64( fd, data_bytes, temp_size, offset );
 
 	/* If zero bytes were read, then we assume it's the end of the
 	 * config file.
@@ -406,7 +409,7 @@ pci_device_linux_sysfs_read( struct pci_device * dev, void * data,
 
 	temp_size -= bytes;
 	offset += bytes;
-	data += bytes;
+	data_bytes += bytes;
     }
     
     if ( bytes_read != NULL ) {
@@ -427,7 +430,7 @@ pci_device_linux_sysfs_write( struct pci_device * dev, const void * data,
     pciaddr_t temp_size = size;
     int err = 0;
     int fd;
-
+    const char *data_bytes = data;
 
     if ( bytes_written != NULL ) {
 	*bytes_written = 0;
@@ -452,7 +455,7 @@ pci_device_linux_sysfs_write( struct pci_device * dev, const void * data,
 
 
     while ( temp_size > 0 ) {
-	const ssize_t bytes = pwrite64( fd, data, temp_size, offset );
+	const ssize_t bytes = pwrite64( fd, data_bytes, temp_size, offset );
 
 	/* If zero bytes were written, then we assume it's the end of the
 	 * config file.
@@ -464,7 +467,7 @@ pci_device_linux_sysfs_write( struct pci_device * dev, const void * data,
 
 	temp_size -= bytes;
 	offset += bytes;
-	data += bytes;
+	data_bytes += bytes;
     }
     
     if ( bytes_written != NULL ) {
@@ -541,7 +544,7 @@ pci_device_linux_sysfs_map_range(struct pci_device *dev,
         sentry.type = MTRR_TYPE_WRCOMB;
     }
 
-    if (pci_sys->mtrr_fd != -1) {
+    if (pci_sys->mtrr_fd != -1 && sentry.type != MTRR_TYPE_UNCACHABLE) {
 	if (ioctl(pci_sys->mtrr_fd, MTRRIOC_ADD_ENTRY, &sentry) < 0) {
 	    /* FIXME: Should we report an error in this case?
 	     */
@@ -556,3 +559,59 @@ pci_device_linux_sysfs_map_range(struct pci_device *dev,
 
     return err;
 }
+
+/**
+ * Unmap a memory region for a device using the Linux sysfs interface.
+ * 
+ * \param dev   Device whose memory region is to be unmapped.
+ * \param map   Parameters of the mapping that is to be destroyed.
+ * 
+ * \return
+ * Zero on success or an \c errno value on failure.
+ *
+ * \sa pci_device_map_rrange, pci_device_linux_sysfs_map_range
+ *
+ * \todo
+ * Some older 2.6.x kernels don't implement the resourceN files.  On those
+ * systems /dev/mem must be used.  On these systems it is also possible that
+ * \c mmap64 may need to be used.
+ */
+static int
+pci_device_linux_sysfs_unmap_range(struct pci_device *dev,
+				   struct pci_device_mapping *map)
+{
+    int err = 0;
+#ifdef HAVE_MTRR
+    struct mtrr_sentry sentry = {
+	.base = map->base,
+        .size = map->size,
+	.type = MTRR_TYPE_UNCACHABLE
+    };
+#endif
+
+    err = pci_device_generic_unmap_range (dev, map);
+    if (err)
+	return err;
+    
+#ifdef HAVE_MTRR
+    if ((map->flags & PCI_DEV_MAP_FLAG_CACHABLE) != 0) {
+        sentry.type = MTRR_TYPE_WRBACK;
+    } else if ((map->flags & PCI_DEV_MAP_FLAG_WRITE_COMBINE) != 0) {
+        sentry.type = MTRR_TYPE_WRCOMB;
+    }
+
+    if (pci_sys->mtrr_fd != -1 && sentry.type != MTRR_TYPE_UNCACHABLE) {
+	if (ioctl(pci_sys->mtrr_fd, MTRRIOC_DEL_ENTRY, &sentry) < 0) {
+	    /* FIXME: Should we report an error in this case?
+	     */
+	    fprintf(stderr, "error setting MTRR "
+		    "(base = 0x%08lx, size = 0x%08x, type = %u) %s (%d)\n",
+		    sentry.base, sentry.size, sentry.type,
+		    strerror(errno), errno);
+/*            err = errno;*/
+	}
+    }
+#endif
+
+    return err;
+}
-- 
1.5.2.5


-- 
keith.packard at intel.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 189 bytes
Desc: This is a digitally signed message part
URL: <http://lists.x.org/archives/xorg/attachments/20070831/24e5091b/attachment.pgp>


More information about the xorg mailing list