diff options
-rw-r--r-- | NOTES | 52 | ||||
-rw-r--r-- | ToDo | 6 | ||||
-rw-r--r-- | cli.c | 9 | ||||
-rw-r--r-- | dma.c | 24 | ||||
-rw-r--r-- | dma.h | 1 | ||||
-rw-r--r-- | dma/nwl_dma.h | 2 | ||||
-rw-r--r-- | dma/nwl_engine.c | 21 | ||||
-rw-r--r-- | dma/nwl_irq.c | 16 | ||||
-rw-r--r-- | irq.c | 4 | ||||
-rw-r--r-- | pcilib.h | 11 |
10 files changed, 116 insertions, 30 deletions
@@ -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 + +
\ No newline at end of file @@ -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) ============ @@ -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; @@ -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; @@ -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); diff --git a/dma/nwl_dma.h b/dma/nwl_dma.h index bdb3df0..d5068e2 100644 --- a/dma/nwl_dma.h +++ b/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, diff --git a/dma/nwl_engine.c b/dma/nwl_engine.c index 669dbbd..277ad23 100644 --- a/dma/nwl_engine.c +++ b/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; diff --git a/dma/nwl_irq.c b/dma/nwl_irq.c index 86f1845..ae4aacc 100644 --- a/dma/nwl_irq.c +++ b/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; +} @@ -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); @@ -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); |