summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSuren A. Chilingaryan <csa@suren.me>2015-05-08 16:35:09 +0200
committerSuren A. Chilingaryan <csa@suren.me>2015-05-08 16:35:09 +0200
commita1889bc2f45b3d944652be6436569980f189922d (patch)
treee4fe4ad383fd190f1269aff4e51cf538642881ef
parent8f241478d649bfafb73f7fe0e4ae5e3d80b73bab (diff)
downloadpcitool-a1889bc2f45b3d944652be6436569980f189922d.tar.gz
pcitool-a1889bc2f45b3d944652be6436569980f189922d.tar.bz2
pcitool-a1889bc2f45b3d944652be6436569980f189922d.tar.xz
pcitool-a1889bc2f45b3d944652be6436569980f189922d.zip
Predict next accessed DMA block in the driver (to speed-up buffer syncing)
-rw-r--r--driver/common.h3
-rw-r--r--driver/kmem.c36
2 files changed, 35 insertions, 4 deletions
diff --git a/driver/common.h b/driver/common.h
index 75005e9..6bc1329 100644
--- a/driver/common.h
+++ b/driver/common.h
@@ -1,7 +1,7 @@
#ifndef _PCIDRIVER_COMMON_H
#define _PCIDRIVER_COMMON_H
-#include "../kmem.h"
+#include "../pcilib/kmem.h"
/*************************************************************************/
/* Private data types and structures */
@@ -64,6 +64,7 @@ typedef struct {
spinlock_t kmemlist_lock; /* Spinlock to lock kmem list operations */
struct list_head kmem_list; /* List of 'kmem_list_entry's associated with this device */
+ pcidriver_kmem_entry_t *kmem_last_sync; /* Last accessed kmem entry */
atomic_t kmem_count; /* id for next kmem entry */
int kmem_cur_id; /* Currently selected kmem buffer, for mmap */
diff --git a/driver/kmem.c b/driver/kmem.c
index b323272..9b3ab14 100644
--- a/driver/kmem.c
+++ b/driver/kmem.c
@@ -396,11 +396,39 @@ int pcidriver_kmem_sync_entry( pcidriver_privdata_t *privdata, pcidriver_kmem_en
*/
int pcidriver_kmem_sync( pcidriver_privdata_t *privdata, kmem_sync_t *kmem_sync )
{
- pcidriver_kmem_entry_t *kmem_entry;
+ pcidriver_kmem_entry_t *kmem_entry = NULL;
- /* Find the associated kmem_entry for this buffer */
- if ((kmem_entry = pcidriver_kmem_find_entry(privdata, &(kmem_sync->handle))) == NULL)
+ /*
+ * This is a shortcut to quickly find a next item in big multi-page kernel buffers
+ */
+ spin_lock(&(privdata->kmemlist_lock));
+ if (privdata->kmem_last_sync) {
+ if (privdata->kmem_last_sync->id == kmem_sync->handle.handle_id)
+ kmem_entry = privdata->kmem_last_sync;
+ else {
+ privdata->kmem_last_sync = container_of(privdata->kmem_last_sync->list.next, pcidriver_kmem_entry_t, list);
+
+ if (privdata->kmem_last_sync) {
+ if (privdata->kmem_last_sync->id == kmem_sync->handle.handle_id)
+ kmem_entry = privdata->kmem_last_sync;
+ else
+ privdata->kmem_last_sync = NULL;
+ }
+ }
+ }
+ spin_unlock(&(privdata->kmemlist_lock));
+
+ /*
+ * If not found go the standard way
+ */
+ if (!kmem_entry) {
+ if ((kmem_entry = pcidriver_kmem_find_entry(privdata, &(kmem_sync->handle))) == NULL)
return -EINVAL; /* kmem_handle is not valid */
+
+ spin_lock(&(privdata->kmemlist_lock));
+ privdata->kmem_last_sync = kmem_entry;
+ spin_unlock(&(privdata->kmemlist_lock));
+ }
return pcidriver_kmem_sync_entry(privdata, kmem_entry, kmem_sync->dir);
}
@@ -466,6 +494,8 @@ int pcidriver_kmem_free_entry(pcidriver_privdata_t *privdata, pcidriver_kmem_ent
/* Remove the kmem list entry */
spin_lock( &(privdata->kmemlist_lock) );
+ if (privdata->kmem_last_sync == kmem_entry)
+ privdata->kmem_last_sync = NULL;
list_del( &(kmem_entry->list) );
spin_unlock( &(privdata->kmemlist_lock) );