Ver código fonte

IRQ acknowledgement support in the engine API

Suren A. Chilingaryan 13 anos atrás
pai
commit
9e424252a3
10 arquivos alterados com 116 adições e 30 exclusões
  1. 52 0
      NOTES
  2. 3 3
      ToDo
  3. 7 2
      cli.c
  4. 22 2
      dma.c
  5. 1 0
      dma.h
  6. 2 0
      dma/nwl_dma.h
  7. 4 17
      dma/nwl_engine.c
  8. 15 1
      dma/nwl_irq.c
  9. 2 2
      irq.c
  10. 8 3
      pcilib.h

+ 52 - 0
NOTES

@@ -187,3 +187,55 @@ Register/DMA Configuration
    a) Writting/Reading register values
    b) Wait until <register1>=<value> on <register2>=<value> report error
    c) ... ?
+
+IRQ Handling
+============
+ IRQ types: DMA IRQ, Event IRQ, other types
+ IRQ hardware source: To allow purely user-space implementation, as general
+ rule, only a  single (standard) source should be used.
+ IRQ source: The dma/event engines, however, may detail this hardware source
+ and produce real IRQ source basing on the values of registers. For example, 
+ for DMA IRQs the source may present engine number and for Event IRQs the 
+ source may present event type.
+
+ Only types can be enabled or disabled. The sources are enabled/disabled
+ by enabling/disabling correspondent DMA engines or Event types. The expected
+ workflow is following:
+ * We enabling IRQs in user-space (normally setting some registers). Normally,
+ just an Event IRQs, the DMA if necessary will be managed by DMA engine itself.
+ * We waiting for standard IRQ from hardware (driver)
+ * In the user space, we are checking registers to find out the real source
+ of IRQ (driver reports us just hardware source), generating appropriate 
+ events, and acknowledge IRQ. This is dependent on implementation and should 
+ be managed inside event API.
+ 
+ I.e. the driver implements just two methods pcilib_wait_irq(hw_source), 
+ pcilib_clear_irq(hw_source). Only a few hardware IRQ sources are defined.
+ In most cirstumances, the IRQ_SOURCE_DEFAULT is used. 
+ 
+ The DMA engine may provide 3 additional methods, to enable, disable,
+ and acknowledge IRQ.
+ 
+ ... To be decided in details upon the need...
+
+Updating Firmware
+=================
+ - JTag should be connected to left USB connector on the board
+ - The computer should be tourned off and on before programming
+ - The application is called 'impact'
+    Cancel initial proposals
+    Left click on USB connection 
+    Select "Boundary Scan" and double click
+    Click "Initiate Chain" on right element (left click)
+        Say yes, Select bit file, Cancel
+    Click "Assign new CF file" on right element (left click
+	Select the bit file
+	Select xv6vlx240t
+	Program
+ - Firmwares are in 
+    v.2: /home/uros/Repo/UFO2_last_good_version_UFO2.bit
+    v.3: /home/uros/Repo/UFO3 
+	Step5 - best working revision
+	Step6 - last revision
+
+    

+ 3 - 3
ToDo

@@ -7,15 +7,15 @@ High Priority (we would need it for IPE Camera)
 =============
  1. Serialize access to the registers across applications
  2. Protect kmem_entries in the driver using spinlock
- 3. Use bus-addresses instead of physcial addresses for DMA
- 4. CMake build system
+ 3. CMake build system
  
 Normal Priority (it would make just few things a bit easier)
 ===============
  1. Implement software registers (stored in kernel-memory)
  2. Support FIFO reads/writes from/to registers
  3. Provide OR and AND operations on registers in cli
- 4. Support writting a data from binary file in cli
+ 4. Support writting a data from a binary file in cli
+ 5. Use bus-addresses instead of physcial addresses for DMA
   
 Low Priority (only as generalization for other projects)
 ============

+ 7 - 2
cli.c

@@ -1077,6 +1077,11 @@ int ListKMEM(pcilib_t *handle, const char *device) {
     }
     closedir(dir);
 
+    if ((n_uses == 1)&&(uses[0].count == 0)) {
+	printf("No kernel memory is allocated\n");
+	return 0;
+    }
+    
     printf("Use Type               Count         Total Size        REF           Mode \n");
     printf("--------------------------------------------------------------------------------\n");
     for (useid = 0; useid < n_uses; useid++) {
@@ -1144,7 +1149,7 @@ int FreeKMEM(pcilib_t *handle, const char *device, const char *use, int force) {
     return 0;
 }
 
-int WaitIRQ(pcilib_t *handle, pcilib_model_description_t *model_info, pcilib_irq_source_t irq_source, pcilib_timeout_t timeout) {
+int WaitIRQ(pcilib_t *handle, pcilib_model_description_t *model_info, pcilib_irq_hw_source_t irq_source, pcilib_timeout_t timeout) {
     int err;
     size_t count;
     
@@ -1186,7 +1191,7 @@ int main(int argc, char **argv) {
     const char *event = NULL;
     const char *dma_channel = NULL;
     const char *use = NULL;
-    pcilib_irq_source_t irq_source;
+    pcilib_irq_hw_source_t irq_source;
     pcilib_dma_direction_t dma_direction = PCILIB_DMA_BIDIRECTIONAL;
     
     pcilib_dma_engine_addr_t dma = PCILIB_DMA_ENGINE_ADDR_INVALID;

+ 22 - 2
dma.c

@@ -114,7 +114,6 @@ 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 0;
     }
 
@@ -136,13 +135,34 @@ 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 0;
     }
     
     return ctx->model_info.dma_api->disable_irq(ctx->dma_ctx, flags);
 }
 
+int pcilib_acknowledge_irq(pcilib_t *ctx, pcilib_irq_type_t irq_type, pcilib_irq_source_t irq_source) {
+    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->acknowledge_irq) {
+	return 0;
+    }
+
+    return ctx->model_info.dma_api->acknowledge_irq(ctx->dma_ctx, irq_type, irq_source);
+}
+
+
 
 typedef struct {
     size_t size;

+ 1 - 0
dma.h

@@ -13,6 +13,7 @@ struct pcilib_dma_api_description_s {
 
     int (*enable_irq)(pcilib_dma_context_t *ctx, pcilib_irq_type_t irq_type, pcilib_dma_flags_t flags);
     int (*disable_irq)(pcilib_dma_context_t *ctx, pcilib_dma_flags_t flags);
+    int (*acknowledge_irq)(pcilib_dma_context_t *ctx, pcilib_irq_type_t irq_type, pcilib_irq_source_t irq_source);
 
     int (*start_dma)(pcilib_dma_context_t *ctx, pcilib_dma_engine_t dma, pcilib_dma_flags_t flags);
     int (*stop_dma)(pcilib_dma_context_t *ctx, pcilib_dma_engine_t dma, pcilib_dma_flags_t flags);

+ 2 - 0
dma/nwl_dma.h

@@ -11,6 +11,7 @@ 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_acknowledge_irq(pcilib_dma_context_t *ctx, pcilib_irq_type_t irq_type, pcilib_irq_source_t irq_source);
 
 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);
@@ -26,6 +27,7 @@ pcilib_dma_api_description_t nwl_dma_api = {
     dma_nwl_free,
     dma_nwl_enable_irq,
     dma_nwl_disable_irq,
+    dma_nwl_acknowledge_irq,
     dma_nwl_start,
     dma_nwl_stop,
     dma_nwl_write_fragment,

+ 4 - 17
dma/nwl_engine.c

@@ -77,12 +77,7 @@ int dma_nwl_start_engine(nwl_dma_t *ctx, pcilib_dma_engine_t dma) {
     if (info->reused) {
     	info->preserve = 1;
 
-	    // Acknowledge asserted engine interrupts    
-        nwl_read_register(val, ctx, info->base_addr, REG_DMA_ENG_CTRL_STATUS);
-	if (val & DMA_ENG_INT_ACTIVE_MASK) {
-	    val |= DMA_ENG_ALLINT_MASK;
-	    nwl_write_register(val, ctx, base, REG_DMA_ENG_CTRL_STATUS);
-	}
+	dma_nwl_acknowledge_irq(ctx, PCILIB_DMA_IRQ, dma);
 
 #ifdef NWL_GENERATE_DMA_IRQ
 	dma_nwl_enable_engine_irq(ctx, dma);
@@ -131,11 +126,7 @@ int dma_nwl_start_engine(nwl_dma_t *ctx, pcilib_dma_engine_t dma) {
 	    return PCILIB_ERROR_TIMEOUT;
 	}
     
-	    // Acknowledge asserted engine interrupts    
-	if (val & DMA_ENG_INT_ACTIVE_MASK) {
-	    val |= DMA_ENG_ALLINT_MASK;
-	    nwl_write_register(val, ctx, base, REG_DMA_ENG_CTRL_STATUS);
-	}
+    	dma_nwl_acknowledge_irq(ctx, PCILIB_DMA_IRQ, dma);
 
 	ring_pa = pcilib_kmem_get_pa(ctx->pcilib, info->ring);
 	nwl_write_register(ring_pa, ctx, info->base_addr, REG_DMA_ENG_NEXT_BD);
@@ -206,12 +197,8 @@ int dma_nwl_stop_engine(nwl_dma_t *ctx, pcilib_dma_engine_t dma) {
 	    nwl_write_register(ring_pa, ctx, info->base_addr, REG_SW_NEXT_BD);
 	}
     }
-
-	// Acknowledge asserted engine interrupts    
-    if (val & DMA_ENG_INT_ACTIVE_MASK) {
-	val |= DMA_ENG_ALLINT_MASK;
-	nwl_write_register(val, ctx, base, REG_DMA_ENG_CTRL_STATUS);
-    }
+    
+    dma_nwl_acknowledge_irq(ctx, PCILIB_DMA_IRQ, dma);
 
     if (info->preserve) {
 	flags = PCILIB_KMEM_FLAG_REUSE;

+ 15 - 1
dma/nwl_irq.c

@@ -100,6 +100,20 @@ int dma_nwl_disable_engine_irq(nwl_dma_t *ctx, pcilib_dma_engine_t dma) {
     return 0;
 }
 
+int dma_nwl_acknowledge_irq(pcilib_dma_context_t *vctx, pcilib_irq_type_t irq_type, pcilib_irq_source_t irq_source) {
+    uint32_t val;
+    
+    nwl_dma_t *ctx = (nwl_dma_t*)vctx;
+    pcilib_nwl_engine_description_t *info = ctx->engines + irq_source;
 
+    if (irq_type != PCILIB_DMA_IRQ) return PCILIB_ERROR_NOTSUPPORTED;
+    if (irq_source >= ctx->n_engines) return PCILIB_ERROR_NOTAVAILABLE;
 
-// ACK
+    nwl_read_register(val, ctx, info->base_addr, REG_DMA_ENG_CTRL_STATUS);
+    if (val & DMA_ENG_INT_ACTIVE_MASK) {
+	val |= DMA_ENG_ALLINT_MASK;
+	nwl_write_register(val, ctx, info->base_addr, REG_DMA_ENG_CTRL_STATUS);
+    }
+    
+    return 0;
+}

+ 2 - 2
irq.c

@@ -17,7 +17,7 @@
 #include "tools.h"
 #include "error.h"
 
-int pcilib_wait_irq(pcilib_t *ctx, pcilib_irq_source_t source, pcilib_timeout_t timeout, size_t *count) {
+int pcilib_wait_irq(pcilib_t *ctx, pcilib_irq_hw_source_t source, pcilib_timeout_t timeout, size_t *count) {
     int err;
     
     interrupt_wait_t arg = { 0 };
@@ -40,7 +40,7 @@ int pcilib_wait_irq(pcilib_t *ctx, pcilib_irq_source_t source, pcilib_timeout_t
     return 0;
 }
 
-int pcilib_clear_irq(pcilib_t *ctx, pcilib_irq_source_t source) {
+int pcilib_clear_irq(pcilib_t *ctx, pcilib_irq_hw_source_t source) {
     int err;
     
     err = ioctl(ctx->handle, PCIDRIVER_IOC_CLEAR_IOQ, source);

+ 8 - 3
pcilib.h

@@ -16,7 +16,8 @@ typedef void pcilib_dma_context_t;
 typedef struct pcilib_dma_api_description_s pcilib_dma_api_description_t;
 typedef struct pcilib_event_api_description_s pcilib_event_api_description_t;
 typedef struct  pcilib_protocol_description_s pcilib_protocol_description_t;
-typedef unsigned int pcilib_irq_source_t;
+typedef unsigned int pcilib_irq_hw_source_t;
+typedef uint32_t pcilib_irq_source_t;
 
 typedef uint8_t pcilib_bar_t;			/**< Type holding the PCI Bar number */
 typedef uint8_t pcilib_register_t;		/**< Type holding the register ID within the Bank */
@@ -99,6 +100,7 @@ typedef enum {
 #define PCILIB_TIMEOUT_INFINITE		((pcilib_timeout_t)-1)
 #define PCILIB_TIMEOUT_IMMEDIATE	0
 #define PCILIB_TIMEOUT_TRIGGER		0
+#define PCILIB_IRQ_SOURCE_DEFAULT	0
 
 typedef int (*pcilib_dma_callback_t)(void *ctx, pcilib_dma_flags_t flags, size_t bufsize, void *buf);
 typedef int (*pcilib_event_callback_t)(pcilib_event_t event, pcilib_event_id_t event_id, void *user);
@@ -204,11 +206,14 @@ void pcilib_close(pcilib_t *ctx);
 
 int pcilib_start_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, pcilib_dma_flags_t flags);
 int pcilib_stop_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, pcilib_dma_flags_t flags);
+
+    // Interrupt API is preliminary and can be significantly changed in future
 int pcilib_enable_irq(pcilib_t *ctx, pcilib_irq_type_t irq_type, pcilib_dma_flags_t flags);
+int pcilib_acknowledge_irq(pcilib_t *ctx, pcilib_irq_type_t irq_type, pcilib_irq_source_t irq_source);
 int pcilib_disable_irq(pcilib_t *ctx, pcilib_dma_flags_t flags);
 
-int pcilib_clear_irq(pcilib_t *ctx, pcilib_irq_source_t source);
-int pcilib_wait_irq(pcilib_t *ctx, pcilib_irq_source_t source, pcilib_timeout_t timeout, size_t *count);
+int pcilib_wait_irq(pcilib_t *ctx, pcilib_irq_hw_source_t source, pcilib_timeout_t timeout, size_t *count);
+int pcilib_clear_irq(pcilib_t *ctx, pcilib_irq_hw_source_t source);
 
 void *pcilib_map_bar(pcilib_t *ctx, pcilib_bar_t bar);
 void pcilib_unmap_bar(pcilib_t *ctx, pcilib_bar_t bar, void *data);