Browse Source

Separate NWL loopback code, provide DMA start/stop interfaces

Suren A. Chilingaryan 13 years ago
parent
commit
e455f83ca2
11 changed files with 181 additions and 82 deletions
  1. 1 1
      Makefile
  2. 42 4
      dma.c
  3. 50 58
      dma/nwl.c
  4. 4 2
      dma/nwl.h
  5. 5 2
      dma/nwl_dma.h
  6. 7 8
      dma/nwl_engine.c
  7. 3 0
      dma/nwl_engine.h
  8. 7 7
      dma/nwl_irq.c
  9. 53 0
      dma/nwl_loopback.c
  10. 7 0
      dma/nwl_loopback.h
  11. 2 0
      pcilib.h

+ 1 - 1
Makefile

@@ -14,7 +14,7 @@ include common.mk
 ###############################################################
 # Target definitions
 
-OBJECTS = pci.o register.o kmem.o irq.o dma.o event.o default.o tools.o dma/nwl.o dma/nwl_register.o dma/nwl_irq.o dma/nwl_engine.o ipecamera/model.o ipecamera/image.o 
+OBJECTS = pci.o register.o kmem.o irq.o dma.o event.o default.o tools.o dma/nwl.o dma/nwl_register.o dma/nwl_irq.o dma/nwl_engine.o dma/nwl_loopback.o ipecamera/model.o ipecamera/image.o 
 
 libpcilib.so: $(OBJECTS)
 	echo -e "LD \t$@"

+ 42 - 4
dma.c

@@ -55,9 +55,47 @@ int pcilib_set_dma_engine_description(pcilib_t *ctx, pcilib_dma_engine_t engine,
 }
 
 int pcilib_start_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, pcilib_dma_flags_t flags) {
+    int err; 
+
+    const pcilib_dma_info_t *info =  pcilib_get_dma_info(ctx);
+    if (!info) {
+	pcilib_error("DMA is not supported by the device");
+	return PCILIB_ERROR_NOTSUPPORTED;
+    }
+
+    if (!ctx->model_info.dma_api) {
+	pcilib_error("DMA Engine is not configured in the current model");
+	return PCILIB_ERROR_NOTAVAILABLE;
+    }
+    
+    if (!ctx->model_info.dma_api->start_dma) {
+	//pcilib_error("The IRQs are not supported by configured DMA engine");
+	return 0;
+    }
+    
+    return ctx->model_info.dma_api->start_dma(ctx->dma_ctx, dma, flags);
 }
 
 int pcilib_stop_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, pcilib_dma_flags_t flags) {
+    int err; 
+
+    const pcilib_dma_info_t *info =  pcilib_get_dma_info(ctx);
+    if (!info) {
+	pcilib_error("DMA is not supported by the device");
+	return PCILIB_ERROR_NOTSUPPORTED;
+    }
+
+    if (!ctx->model_info.dma_api) {
+	pcilib_error("DMA Engine is not configured in the current model");
+	return PCILIB_ERROR_NOTAVAILABLE;
+    }
+    
+    if (!ctx->model_info.dma_api->stop_dma) {
+	//pcilib_error("The IRQs are not supported by configured DMA engine");
+	return 0;
+    }
+    
+    return ctx->model_info.dma_api->stop_dma(ctx->dma_ctx, dma, flags);
 }
 
 int pcilib_enable_irq(pcilib_t *ctx, pcilib_irq_type_t irq_type, pcilib_dma_flags_t flags) {
@@ -75,8 +113,8 @@ int pcilib_enable_irq(pcilib_t *ctx, pcilib_irq_type_t irq_type, pcilib_dma_flag
     }
     
     if (!ctx->model_info.dma_api->enable_irq) {
-	pcilib_error("The IRQs are not supported by configured DMA engine");
-	return PCILIB_ERROR_NOTSUPPORTED;
+	//pcilib_error("The IRQs are not supported by configured DMA engine");
+	return 0;
     }
     
     return ctx->model_info.dma_api->enable_irq(ctx->dma_ctx, irq_type, flags);
@@ -97,8 +135,8 @@ int pcilib_disable_irq(pcilib_t *ctx, pcilib_dma_flags_t flags) {
     }
     
     if (!ctx->model_info.dma_api->disable_irq) {
-	pcilib_error("The IRQs are not supported by configured DMA engine");
-	return PCILIB_ERROR_NOTSUPPORTED;
+	//pcilib_error("The IRQs are not supported by configured DMA engine");
+	return 0;
     }
     
     return ctx->model_info.dma_api->disable_irq(ctx->dma_ctx, flags);

+ 50 - 58
dma/nwl.c

@@ -15,73 +15,62 @@
 
 #include "nwl_defines.h"
 
+int dma_nwl_start(pcilib_dma_context_t *vctx, pcilib_dma_engine_t dma, pcilib_dma_flags_t flags) {
+    nwl_dma_t *ctx = (nwl_dma_t*)vctx;
 
-
-int dma_nwl_start_loopback(nwl_dma_t *ctx,  pcilib_dma_direction_t direction, size_t packet_size) {
-    uint32_t val;
-    
-    val = packet_size;
-    nwl_write_register(val, ctx, ctx->base_addr, PKT_SIZE_ADDRESS);
-
-    switch (direction) {
-      case PCILIB_DMA_BIDIRECTIONAL:
-	val = LOOPBACK;
-	break;
-      case PCILIB_DMA_TO_DEVICE:
-	return -1;
-      case PCILIB_DMA_FROM_DEVICE:
-        val = PKTGENR;
-	break;
+    if (!ctx->started) {
+	// global initialization, should we do anything?
+	ctx->started = 1;
     }
 
-    nwl_write_register(val, ctx, ctx->base_addr, TX_CONFIG_ADDRESS);
-    nwl_write_register(val, ctx, ctx->base_addr, RX_CONFIG_ADDRESS);
-    
-    return 0;
-}
-
-int dma_nwl_stop_loopback(nwl_dma_t *ctx) {
-    uint32_t val;
-
-    val = 0;
-    nwl_write_register(val, ctx, ctx->base_addr, TX_CONFIG_ADDRESS);
-    nwl_write_register(val, ctx, ctx->base_addr, RX_CONFIG_ADDRESS);
-    
-    return 0;
-}
-
-
-int dma_nwl_start(nwl_dma_t *ctx) {
-    if (ctx->started) return 0;
-    
-#ifdef NWL_GENERATE_DMA_IRQ
-    dma_nwl_enable_irq(ctx, PCILIB_DMA_IRQ, 0);
-#endif /* NWL_GENERATE_DMA_IRQ */
-
-    ctx->started = 1;
+    if (dma == PCILIB_DMA_ENGINE_INVALID) return 0;
+    else if (dma > ctx->n_engines) return PCILIB_ERROR_INVALID_BANK;
 
-    return 0;
+    if (flags&PCILIB_DMA_FLAG_PERMANENT) ctx->engines[dma].preserve = 1;
+    return dma_nwl_start_engine(ctx, dma);
 }
 
-int dma_nwl_stop(nwl_dma_t *ctx) {
+int dma_nwl_stop(pcilib_dma_context_t *vctx, pcilib_dma_engine_t dma, pcilib_dma_flags_t flags) {
     int err;
+    int preserving = 0;
 
-    pcilib_dma_engine_t i;
+    nwl_dma_t *ctx = (nwl_dma_t*)vctx;
     
-    ctx->started = 0;
+    if (!ctx->started) return 0;
     
-    err = dma_nwl_free_irq(ctx);
-    if (err) return err;
+	// stop everything
+    if (dma == PCILIB_DMA_ENGINE_INVALID) {
+        for (dma = 0; dma < ctx->n_engines; dma++) {
+	    if (flags&PCILIB_DMA_FLAG_PERMANENT) {
+		ctx->engines[dma].preserve = 0;
+	    }
+	
+	    if (ctx->engines[dma].preserve) preserving = 1;
+	    else {
+	        err = dma_nwl_stop_engine(ctx, dma);
+		if (err) return err;
+	    }
+	}
+	    
+	    // global cleanup, should we do anything?
+	if (!preserving) {
+	    ctx->started = 0;
+	}
+	
+	return 0;
+    }
     
-    err = dma_nwl_stop_loopback(ctx);
-    if (err) return err;
+    if (dma > ctx->n_engines) return PCILIB_ERROR_INVALID_BANK;
     
-    for (i = 0; i < ctx->n_engines; i++) {
-	err = dma_nwl_stop_engine(ctx, i);
-	if (err) return err;
+	    // ignorign previous setting if flag specified
+    if (flags&PCILIB_DMA_FLAG_PERMANENT) {
+	ctx->engines[dma].preserve = 0;
     }
     
-    return 0;
+	// Do not close DMA if preservation mode is set
+    if (ctx->engines[dma].preserve) return 0;
+    
+    return dma_nwl_stop_engine(ctx, dma);
 }
 
 
@@ -134,13 +123,16 @@ pcilib_dma_context_t *dma_nwl_init(pcilib_t *pcilib) {
 }
 
 void  dma_nwl_free(pcilib_dma_context_t *vctx) {
+    int err;
+    
     pcilib_dma_engine_t i;
     nwl_dma_t *ctx = (nwl_dma_t*)vctx;
-    if (ctx) {
-	for (i = 0; i < ctx->n_engines; i++) dma_nwl_stop_engine(ctx, i);
-	dma_nwl_stop(ctx);
-	free(ctx);
-    }
+
+    dma_nwl_stop_loopback(ctx);
+    dma_nwl_free_irq(ctx);
+    dma_nwl_stop(ctx, PCILIB_DMA_ENGINE_ALL, PCILIB_DMA_FLAGS_DEFAULT);
+    
+    free(ctx);
 }
 
 

+ 4 - 2
dma/nwl.h

@@ -19,6 +19,7 @@ typedef struct pcilib_nwl_engine_description_s pcilib_nwl_engine_description_t;
 #include "nwl_irq.h"
 #include "nwl_register.h"
 #include "nwl_engine.h"
+#include "nwl_loopback.h"
 
 #define nwl_read_register(var, ctx, base, reg) pcilib_datacpy(&var, base + reg, 4, 1, ctx->dma_bank->raw_endianess)
 #define nwl_write_register(var, ctx, base, reg) pcilib_datacpy(base + reg, &var, 4, 1, ctx->dma_bank->raw_endianess)
@@ -44,11 +45,12 @@ struct nwl_dma_s {
     pcilib_register_bank_description_t *dma_bank;
     char *base_addr;
 
-    int irq_init;			/**< indicates that IRQ subsystem is initialized (detecting which types should be preserverd) */    
     pcilib_irq_type_t irq_enabled;	/**< indicates that IRQs are enabled */
     pcilib_irq_type_t irq_preserve;	/**< indicates that IRQs should not be disabled during clean-up */
     int started;			/**< indicates that DMA subsystem is initialized and DMA engine can start */
-    
+    int irq_started;			/**< indicates that IRQ subsystem is initialized (detecting which types should be preserverd) */    
+    int loopback_started;		/**< indicates that benchmarking subsystem is initialized */
+
     pcilib_dma_engine_t n_engines;
     pcilib_nwl_engine_description_t engines[PCILIB_MAX_DMA_ENGINES + 1];
 };

+ 5 - 2
dma/nwl_dma.h

@@ -10,6 +10,9 @@ void  dma_nwl_free(pcilib_dma_context_t *vctx);
 int dma_nwl_enable_irq(pcilib_dma_context_t *vctx, pcilib_irq_type_t type, pcilib_dma_flags_t flags);
 int dma_nwl_disable_irq(pcilib_dma_context_t *vctx, pcilib_dma_flags_t flags);
 
+int dma_nwl_start(pcilib_dma_context_t *ctx, pcilib_dma_engine_t dma, pcilib_dma_flags_t flags);
+int dma_nwl_stop(pcilib_dma_context_t *ctx, pcilib_dma_engine_t dma, pcilib_dma_flags_t flags);
+
 int dma_nwl_write_fragment(pcilib_dma_context_t *vctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, pcilib_dma_flags_t flags, pcilib_timeout_t timeout, void *data, size_t *written);
 int dma_nwl_stream_read(pcilib_dma_context_t *vctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, pcilib_dma_flags_t flags, pcilib_timeout_t timeout, pcilib_dma_callback_t cb, void *cbattr);
 double dma_nwl_benchmark(pcilib_dma_context_t *vctx, pcilib_dma_engine_addr_t dma, uintptr_t addr, size_t size, size_t iterations, pcilib_dma_direction_t direction);
@@ -21,8 +24,8 @@ pcilib_dma_api_description_t nwl_dma_api = {
     dma_nwl_free,
     dma_nwl_enable_irq,
     dma_nwl_disable_irq,
-    NULL,
-    NULL,
+    dma_nwl_start,
+    dma_nwl_stop,
     dma_nwl_write_fragment,
     dma_nwl_stream_read,
     dma_nwl_benchmark

+ 7 - 8
dma/nwl_engine.c

@@ -1,3 +1,5 @@
+#define _BSD_SOURCE
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -12,6 +14,8 @@
 
 #include "nwl_defines.h"
 
+#include "nwl_buffers.h"    
+
 int dma_nwl_read_engine_config(nwl_dma_t *ctx, pcilib_nwl_engine_description_t *info, char *base) {
     uint32_t val;
     
@@ -58,7 +62,7 @@ int dma_nwl_start_engine(nwl_dma_t *ctx, pcilib_dma_engine_t dma) {
 
     pcilib_nwl_engine_description_t *info = ctx->engines + dma;
     char *base = ctx->engines[dma].base_addr;
-
+    
     if (info->started) return 0;
 
 	// Disable IRQs
@@ -100,9 +104,6 @@ int dma_nwl_start_engine(nwl_dma_t *ctx, pcilib_dma_engine_t dma) {
 	nwl_write_register(val, ctx, base, REG_DMA_ENG_CTRL_STATUS);
     }
 
-    err = dma_nwl_start(ctx);
-    if (err) return err;
-    
     err = dma_nwl_allocate_engine_buffers(ctx, info);
     if (err) return err;
     
@@ -182,8 +183,6 @@ int dma_nwl_stop_engine(nwl_dma_t *ctx, pcilib_dma_engine_t dma) {
     return 0;
 }
 
-#include "nwl_buffers.h"    
-
 int dma_nwl_write_fragment(pcilib_dma_context_t *vctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, pcilib_dma_flags_t flags, pcilib_timeout_t timeout, void *data, size_t *written) {
     int err;
     size_t pos;
@@ -192,7 +191,7 @@ int dma_nwl_write_fragment(pcilib_dma_context_t *vctx, pcilib_dma_engine_t dma,
 
     pcilib_nwl_engine_description_t *info = ctx->engines + dma;
 
-    err = dma_nwl_start_engine(ctx, dma);
+    err = dma_nwl_start(ctx, dma, PCILIB_DMA_FLAGS_DEFAULT);
     if (err) return err;
 
     if (data) {
@@ -238,7 +237,7 @@ int dma_nwl_stream_read(pcilib_dma_context_t *vctx, pcilib_dma_engine_t dma, uin
 
     pcilib_nwl_engine_description_t *info = ctx->engines + dma;
 
-    err = dma_nwl_start_engine(ctx, dma);
+    err = dma_nwl_start(ctx, dma, PCILIB_DMA_FLAGS_DEFAULT);
     if (err) return err;
 
     do {

+ 3 - 0
dma/nwl_engine.h

@@ -2,6 +2,9 @@
 #define _PCILIB_DMA_NWL_ENGINE_H
 
 int dma_nwl_read_engine_config(nwl_dma_t *ctx, pcilib_nwl_engine_description_t *info, char *base);
+int dma_nwl_start_engine(nwl_dma_t *ctx, pcilib_dma_engine_t dma);
+int dma_nwl_stop_engine(nwl_dma_t *ctx, pcilib_dma_engine_t dma);
+
 
 #endif /* _PCILIB_DMA_NWL_ENGINE_H */
 

+ 7 - 7
dma/nwl_irq.c

@@ -19,16 +19,16 @@ int dma_nwl_init_irq(nwl_dma_t *ctx, uint32_t val) {
 	if (val&DMA_USER_INT_ENABLE) ctx->irq_preserve |= PCILIB_EVENT_IRQ;
     }
     
-    ctx->irq_init = 1;
+    ctx->irq_started = 1;
     return 0;
 }
 
 int dma_nwl_free_irq(nwl_dma_t *ctx) {
-    if (ctx->irq_init) {
+    if (ctx->irq_started) {
 	dma_nwl_disable_irq((pcilib_dma_context_t*)ctx, 0);
 	if (ctx->irq_preserve) dma_nwl_enable_irq((pcilib_dma_context_t*)ctx, ctx->irq_preserve, 0);
 	ctx->irq_enabled = 0;
-	ctx->irq_init = 0;
+	ctx->irq_started = 0;
     }
     return 0;
 }
@@ -39,12 +39,12 @@ int dma_nwl_enable_irq(pcilib_dma_context_t *vctx, pcilib_irq_type_t type, pcili
     
     if (flags&PCILIB_DMA_FLAG_PERMANENT) ctx->irq_preserve |= type;
 
-    if (ctx->irq_enabled == type) return 0;
+    if ((ctx->irq_enabled&type) == type) return 0;
     
     type |= ctx->irq_enabled;
     
     nwl_read_register(val, ctx, ctx->base_addr, REG_DMA_CTRL_STATUS);
-    if (!ctx->irq_init) dma_nwl_init_irq(ctx, val);
+    if (!ctx->irq_started) dma_nwl_init_irq(ctx, val);
 
     val &= ~(DMA_INT_ENABLE|DMA_USER_INT_ENABLE);
     nwl_write_register(val, ctx, ctx->base_addr, REG_DMA_CTRL_STATUS);
@@ -68,7 +68,7 @@ int dma_nwl_disable_irq(pcilib_dma_context_t *vctx, pcilib_dma_flags_t flags) {
     ctx->irq_enabled = 0;
     
     nwl_read_register(val, ctx, ctx->base_addr, REG_DMA_CTRL_STATUS);
-    if (!ctx->irq_init) dma_nwl_init_irq(ctx, val);
+    if (!ctx->irq_started) dma_nwl_init_irq(ctx, val);
     val &= ~(DMA_INT_ENABLE|DMA_USER_INT_ENABLE);
     nwl_write_register(val, ctx, ctx->base_addr, REG_DMA_CTRL_STATUS);
     
@@ -81,7 +81,7 @@ int dma_nwl_disable_irq(pcilib_dma_context_t *vctx, pcilib_dma_flags_t flags) {
 int dma_nwl_enable_engine_irq(nwl_dma_t *ctx, pcilib_dma_engine_t dma) {
     uint32_t val;
     
-    dma_nwl_enable_irq(ctx, ctx->irq_enabled|PCILIB_DMA_IRQ, 0);
+    dma_nwl_enable_irq(ctx, PCILIB_DMA_IRQ, 0);
 
     nwl_read_register(val, ctx, ctx->engines[dma].base_addr, REG_DMA_ENG_CTRL_STATUS);
     val |= (DMA_ENG_INT_ENABLE);

+ 53 - 0
dma/nwl_loopback.c

@@ -0,0 +1,53 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/time.h>
+
+#include "pci.h"
+#include "pcilib.h"
+#include "error.h"
+#include "tools.h"
+#include "nwl.h"
+
+#include "nwl_defines.h"
+
+
+int dma_nwl_start_loopback(nwl_dma_t *ctx,  pcilib_dma_direction_t direction, size_t packet_size) {
+    uint32_t val;
+
+	// Re-initializing always
+    
+    val = packet_size;
+    nwl_write_register(val, ctx, ctx->base_addr, PKT_SIZE_ADDRESS);
+
+    switch (direction) {
+      case PCILIB_DMA_BIDIRECTIONAL:
+	val = LOOPBACK;
+	break;
+      case PCILIB_DMA_TO_DEVICE:
+	return -1;
+      case PCILIB_DMA_FROM_DEVICE:
+        val = PKTGENR;
+	break;
+    }
+
+    nwl_write_register(val, ctx, ctx->base_addr, TX_CONFIG_ADDRESS);
+    nwl_write_register(val, ctx, ctx->base_addr, RX_CONFIG_ADDRESS);
+
+    ctx->loopback_started = 1;
+        
+    return 0;
+}
+
+int dma_nwl_stop_loopback(nwl_dma_t *ctx) {
+    uint32_t val = 0;
+
+    if (ctx->loopback_started) {
+	nwl_write_register(val, ctx, ctx->base_addr, TX_CONFIG_ADDRESS);
+	nwl_write_register(val, ctx, ctx->base_addr, RX_CONFIG_ADDRESS);
+	ctx->loopback_started = 0;
+    }
+    
+    return 0;
+}

+ 7 - 0
dma/nwl_loopback.h

@@ -0,0 +1,7 @@
+#ifndef _PCILIB_NWL_LOOPBACK_H
+#define _PCILIB_NWL_LOOPBACK_H
+
+int dma_nwl_start_loopback(nwl_dma_t *ctx,  pcilib_dma_direction_t direction, size_t packet_size);
+int dma_nwl_stop_loopback(nwl_dma_t *ctx);
+
+#endif /* _PCILIB_NWL_LOOPBACK_H */

+ 2 - 0
pcilib.h

@@ -86,6 +86,8 @@ typedef enum {
 #define PCILIB_BAR0			0
 #define PCILIB_BAR1			1
 #define PCILIB_DMA_ENGINE_INVALID	((pcilib_dma_engine_t)-1)
+#define PCILIB_DMA_ENGINE_ALL		((pcilib_dma_engine_t)-1)
+#define PCILIB_DMA_FLAGS_DEFAULT	((pcilib_dma_flags_t)0)
 #define PCILIB_DMA_ENGINE_ADDR_INVALID	((pcilib_dma_engine_addr_t)-1)
 #define PCILIB_REGISTER_INVALID		((pcilib_register_t)-1)
 #define PCILIB_ADDRESS_INVALID		((uintptr_t)-1)