diff options
| author | root <root@iss-tomyspiel-l> | 2011-06-18 06:37:00 +0200 | 
|---|---|---|
| committer | root <root@iss-tomyspiel-l> | 2011-06-18 06:37:00 +0200 | 
| commit | 70937611e34577151a6607640050e8b164a54e70 (patch) | |
| tree | 23cc1c9573dafd8584e0f0697f79fde3dad49258 | |
| parent | 4b5a2c9625acd583573005ef66d17d919469009d (diff) | |
DMA engine initialization and basic intrastructure for DMA read/write
| -rw-r--r-- | cli.c | 72 | ||||
| -rw-r--r-- | dma/nwl.c | 98 | ||||
| -rw-r--r-- | dma/nwl.h | 5 | ||||
| -rw-r--r-- | pci.c | 38 | ||||
| -rw-r--r-- | pcilib.h | 3 | 
5 files changed, 189 insertions, 27 deletions
| @@ -55,6 +55,12 @@ typedef enum {  } MODE;  typedef enum { +    ACCESS_BAR, +    ACCESS_DMA, +    ACCESS_FIFO +} ACCESS_MODE; + +typedef enum {      OPT_DEVICE = 'd',      OPT_MODEL = 'm',      OPT_BAR = 'b', @@ -112,30 +118,30 @@ void Usage(int argc, char *argv[], const char *format, ...) {  "Usage:\n"  " %s <mode> [options] [hex data]\n"  "  Modes:\n" -"	-i		- Device Info\n" -"	-l		- List Data Banks & Registers\n" -"	-p		- Performance Evaluation\n" -"	-r <addr|reg>	- Read Data/Register\n" -"	-w <addr|reg>	- Write Data/Register\n" -"	-g [event]	- Grab Event\n" -"	--reset		- Reset board\n" -"	--help		- Help message\n" +"	-i			- Device Info\n" +"	-l			- List Data Banks & Registers\n" +"	-p			- Performance Evaluation\n" +"	-r <addr|reg|dmaX>	- Read Data/Register\n" +"	-w <addr|reg|dmaX>	- Write Data/Register\n" +"	-g [event]		- Grab Event\n" +"	--reset			- Reset board\n" +"	--help			- Help message\n"  "\n"  "  Addressing:\n" -"	-d <device>	- FPGA device (/dev/fpga0)\n" -"	-m <model>	- Memory model (autodetected)\n" -"	   pci		- Plain\n" -"	   ipecamera	- IPE Camera\n" -"	-b <bank>	- Data/Register bank (autodetected)\n" +"	-d <device>		- FPGA device (/dev/fpga0)\n" +"	-m <model>		- Memory model (autodetected)\n" +"	   pci			- Plain\n" +"	   ipecamera		- IPE Camera\n" +"	-b <bank>		- Data/Register bank (autodetected)\n"  "\n"  "  Options:\n" -"	-s <size>	- Number of words (default: 1)\n" -"	-a <bitness>	- Bits per word (default: 32)\n" -"	-e <l|b>	- Endianess Little/Big (default: host)\n" -"	-o <file>	- Output to file (default: stdout)\n" +"	-s <size>		- Number of words (default: 1)\n" +"	-a <bitness>		- Bits per word (default: 32)\n" +"	-e <l|b>		- Endianess Little/Big (default: host)\n" +"	-o <file>		- Output to file (default: stdout)\n"  "\n"  "  Information:\n" -"	-q 		- Quiete mode (suppress warnings)\n" +"	-q 			- Quiete mode (suppress warnings)\n"  "\n"  "  Data:\n"  "	Data can be specified as sequence of hexdecimal number or\n" @@ -398,7 +404,7 @@ int Benchmark(pcilib_t *handle, pcilib_bar_t bar) {  #define pci2host16(endianess, value) endianess? -int ReadData(pcilib_t *handle, pcilib_bar_t bar, uintptr_t addr, size_t n, access_t access, int endianess) { +int ReadData(pcilib_t *handle, ACCESS_MODE mode, pcilib_dma_addr_t dma, pcilib_bar_t bar, uintptr_t addr, size_t n, access_t access, int endianess) {      void *buf;      int i, err;      int size = n * abs(access); @@ -416,7 +422,15 @@ int ReadData(pcilib_t *handle, pcilib_bar_t bar, uintptr_t addr, size_t n, acces      err = posix_memalign( (void**)&buf, 256, size );      if ((err)||(!buf)) Error("Allocation of %i bytes of memory have failed", size); -    pcilib_read(handle, bar, addr, size, buf); +    if (mode == ACCESS_DMA) { +	pcilib_dma_t dmaid = pcilib_find_dma_by_addr(handle, PCILIB_DMA_FROM_DEVICE, dma); +	if (dmaid == PCILIB_DMA_INVALID) Error("Invalid DMA engine (%lu) is specified", dma); +	pcilib_read_dma(handle, dmaid, size, buf); + +	addr = 0; +    } else { +	pcilib_read(handle, bar, addr, size, buf); +    }      if (endianess) pcilib_swap(buf, buf, abs(access), n);      for (i = 0; i < n; i++) { @@ -443,6 +457,9 @@ int ReadData(pcilib_t *handle, pcilib_bar_t bar, uintptr_t addr, size_t n, acces      free(buf);  } + + +  int ReadRegister(pcilib_t *handle, pcilib_model_t model, const char *bank, const char *reg) {      int i;      int err; @@ -548,7 +565,7 @@ int ReadRegisterRange(pcilib_t *handle, pcilib_model_t model, const char *bank,      printf("\n\n");  } -int WriteData(pcilib_t *handle, pcilib_bar_t bar, uintptr_t addr, size_t n, access_t access, int endianess, char ** data) { +int WriteData(pcilib_t *handle, ACCESS_MODE mode, pcilib_dma_addr_t dma, pcilib_bar_t bar, uintptr_t addr, size_t n, access_t access, int endianess, char ** data) {      void *buf, *check;      int res, i, err;      int size = n * abs(access); @@ -574,7 +591,7 @@ int WriteData(pcilib_t *handle, pcilib_bar_t bar, uintptr_t addr, size_t n, acce      if (memcmp(buf, check, size)) {  	printf("Write failed: the data written and read differ, the foolowing is read back:\n");          if (endianess) pcilib_swap(check, check, abs(access), n); -	ReadData(handle, bar, addr, n, access, endianess); +	ReadData(handle, mode, dma, bar, addr, n, access, endianess);  	exit(-1);      } @@ -687,6 +704,7 @@ int main(int argc, char **argv) {      pcilib_model_t model = PCILIB_MODEL_DETECT;      MODE mode = MODE_INVALID; +    ACCESS_MODE amode = ACCESS_BAR;      const char *fpga_device = DEFAULT_FPGA_DEVICE;      pcilib_bar_t bar = PCILIB_BAR_DETECT;      const char *addr = NULL; @@ -695,6 +713,7 @@ int main(int argc, char **argv) {      char **data = NULL;      const char *event = NULL; +    pcilib_dma_addr_t dma;      uintptr_t start = -1;      size_t size = 1;      access_t access = 4; @@ -848,7 +867,10 @@ int main(int argc, char **argv) {      }      if (addr) { -	if ((isxnumber(addr))&&(sscanf(addr, "%lx", &start) == 1)) { +	if (!strncmp(addr, "dma", 3)) { +	    dma = atoi(addr + 3); +	    amode = ACCESS_DMA; +	} else if ((isxnumber(addr))&&(sscanf(addr, "%lx", &start) == 1)) {  		// check if the address in the register range  	    pcilib_register_range_t *ranges =  pcilib_model[model].ranges; @@ -896,7 +918,7 @@ int main(int argc, char **argv) {       break;       case MODE_READ:          if (addr) { -	    ReadData(handle, bar, start, size, access, endianess); +	    ReadData(handle, amode, dma, bar, start, size, access, endianess);  	} else {  	    Error("Address to read is not specified");  	} @@ -906,7 +928,7 @@ int main(int argc, char **argv) {  	else ReadRegisterRange(handle, model, bank, start, size);       break;       case MODE_WRITE: -	WriteData(handle, bar, start, size, access, endianess, data); +	WriteData(handle, amode, dma, bar, start, size, access, endianess, data);       break;       case MODE_WRITE_REGISTER:          if (reg) WriteRegister(handle, model, bank, reg, data); @@ -3,6 +3,7 @@  #include <stdio.h>  #include <stdlib.h>  #include <string.h> +#include <sys/time.h>  #include "pci.h"  #include "pcilib.h" @@ -63,10 +64,45 @@  #define DMA_ENG_NUMBER          0x0000FF00  /**< DMA engine number */  #define DMA_ENG_BD_MAX_BC       0x3F000000  /**< DMA engine max buffer size */ +  /* Shift constants for selected masks */  #define DMA_ENG_NUMBER_SHIFT        8  #define DMA_ENG_BD_MAX_BC_SHIFT     24 +/** @name Bitmasks of REG_DMA_ENG_CTRL_STATUS register. + * @{ + */ +/* Interrupt activity and acknowledgement bits */ +#define DMA_ENG_INT_ENABLE          0x00000001  /**< Enable interrupts */ +#define DMA_ENG_INT_DISABLE         0x00000000  /**< Disable interrupts */ +#define DMA_ENG_INT_ACTIVE_MASK     0x00000002  /**< Interrupt active? */ +#define DMA_ENG_INT_ACK             0x00000002  /**< Interrupt ack */ +#define DMA_ENG_INT_BDCOMP          0x00000004  /**< Int - BD completion */ +#define DMA_ENG_INT_BDCOMP_ACK      0x00000004  /**< Acknowledge */ +#define DMA_ENG_INT_ALERR           0x00000008  /**< Int - BD align error */ +#define DMA_ENG_INT_ALERR_ACK       0x00000008  /**< Acknowledge */ +#define DMA_ENG_INT_FETERR          0x00000010  /**< Int - BD fetch error */ +#define DMA_ENG_INT_FETERR_ACK      0x00000010  /**< Acknowledge */ +#define DMA_ENG_INT_ABORTERR        0x00000020  /**< Int - DMA abort error */ +#define DMA_ENG_INT_ABORTERR_ACK    0x00000020  /**< Acknowledge */ +#define DMA_ENG_INT_CHAINEND        0x00000080  /**< Int - BD chain ended */ +#define DMA_ENG_INT_CHAINEND_ACK    0x00000080  /**< Acknowledge */ + +/* DMA engine control */ +#define DMA_ENG_ENABLE_MASK         0x00000100  /**< DMA enabled? */ +#define DMA_ENG_ENABLE              0x00000100  /**< Enable DMA */ +#define DMA_ENG_DISABLE             0x00000000  /**< Disable DMA */ +#define DMA_ENG_STATE_MASK          0x00000C00  /**< Current DMA state? */ +#define DMA_ENG_RUNNING             0x00000400  /**< DMA running */ +#define DMA_ENG_IDLE                0x00000000  /**< DMA idle */ +#define DMA_ENG_WAITING             0x00000800  /**< DMA waiting */ +#define DMA_ENG_STATE_WAITED        0x00001000  /**< DMA waited earlier */ +#define DMA_ENG_WAITED_ACK          0x00001000  /**< Acknowledge */ +#define DMA_ENG_USER_RESET          0x00004000  /**< Reset only user logic */ +#define DMA_ENG_RESET               0x00008000  /**< Reset DMA engine + user */ + +#define DMA_ENG_ALLINT_MASK         0x000000BE  /**< To get only int events */ +  #define DMA_ENGINE_PER_SIZE     0x100   /**< Separation between engine regs */  #define DMA_OFFSET              0       /**< Starting register offset */                                          /**< Size of DMA engine reg space */ @@ -96,6 +132,7 @@ struct nwl_dma_s {      pcilib_register_bank_description_t *dma_bank;      char *base_addr; +    pcilib_dma_t n_engines;      pcilib_nwl_engine_description_t engines[PCILIB_MAX_DMA_ENGINES + 1];  }; @@ -105,6 +142,8 @@ struct nwl_dma_s {  static int nwl_read_engine_config(nwl_dma_t *ctx, pcilib_nwl_engine_description_t *info, char *base) {      uint32_t val; +    info->base_addr = base; +          nwl_read_register(val, ctx, base, REG_DMA_ENG_CAP);      if ((val & DMA_ENG_PRESENT_MASK) == 0) return PCILIB_ERROR_NOTAVAILABLE; @@ -135,6 +174,54 @@ static int nwl_read_engine_config(nwl_dma_t *ctx, pcilib_nwl_engine_description_      return 0;  } +static int nwl_stop_engine(nwl_dma_t *ctx, pcilib_dma_t dma) { +    uint32_t val; +    struct timeval start, cur; +     +    pcilib_nwl_engine_description_t *info = ctx->engines + dma; +    char *base = ctx->engines[dma].base_addr; +     +	// Disable IRQ +    nwl_read_register(val, ctx, base, REG_DMA_ENG_CTRL_STATUS); +    val &= ~(DMA_ENG_INT_ENABLE); +    nwl_write_register(val, ctx, base, REG_DMA_ENG_CTRL_STATUS); + +      +	// Reseting  +    val = DMA_ENG_DISABLE|DMA_ENG_USER_RESET; nwl_write_register(val, ctx, base, REG_DMA_ENG_CTRL_STATUS); +    gettimeofday(&start, NULL); +    do { +	nwl_read_register(val, ctx, base, REG_DMA_ENG_CTRL_STATUS); +        gettimeofday(&cur, NULL); +    } while ((val & (DMA_ENG_STATE_MASK|DMA_ENG_USER_RESET))&&(((cur.tv_sec - start.tv_sec)*1000000 + (cur.tv_usec - start.tv_usec)) < PCILIB_REGISTER_TIMEOUT)); +     +    if (val & DMA_ENG_RESET) { +	pcilib_error("Timeout during reset of DMA engine %i", info->desc.addr); +	return PCILIB_ERROR_TIMEOUT; +    } +     + +    val = DMA_ENG_RESET; nwl_write_register(val, ctx, base, REG_DMA_ENG_CTRL_STATUS); +    gettimeofday(&start, NULL); +    do { +	nwl_read_register(val, ctx, base, REG_DMA_ENG_CTRL_STATUS); +        gettimeofday(&cur, NULL); +    } while ((val & DMA_ENG_RESET)&&(((cur.tv_sec - start.tv_sec)*1000000 + (cur.tv_usec - start.tv_usec)) < PCILIB_REGISTER_TIMEOUT)); +     +    if (val & DMA_ENG_RESET) { +	pcilib_error("Timeout during reset of DMA engine %i", info->desc.addr); +	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); +    } +     +    return 0; +} +  pcilib_dma_context_t *dma_nwl_init(pcilib_t *pcilib) {      int i;      int err; @@ -159,20 +246,31 @@ pcilib_dma_context_t *dma_nwl_init(pcilib_t *pcilib) {  	for (i = 0, n_engines = 0; i < 2 * PCILIB_MAX_DMA_ENGINES; i++) {  	    char *addr = ctx->base_addr + DMA_OFFSET + i * DMA_ENGINE_PER_SIZE;  	    err = nwl_read_engine_config(ctx, ctx->engines + n_engines, addr); +	    if (!err) err = nwl_stop_engine(ctx, n_engines);  	    if (!err) {  		ctx->engines[n_engines].base_addr = addr;  		pcilib_set_dma_engine_description(pcilib, n_engines, (pcilib_dma_engine_description_t*)(ctx->engines + n_engines));  		++n_engines;  	    } +	      	}  	pcilib_set_dma_engine_description(pcilib, n_engines, NULL); +	 +	ctx->n_engines = n_engines;      }      return (pcilib_dma_context_t*)ctx;  }  void  dma_nwl_free(pcilib_dma_context_t *vctx) { +    pcilib_dma_t i;      nwl_dma_t *ctx = (nwl_dma_t*)vctx;      if (ctx) { +	for (i = 0; i < ctx->n_engines; i++) nwl_stop_engine(vctx, i);  	free(ctx);      }  } + +int dma_nwl_read(pcilib_dma_context_t *vctx, pcilib_dma_t dma, size_t size, void *buf) { +    nwl_dma_t *ctx = (nwl_dma_t*)vctx; +    printf("Reading dma: %i\n", dma); +} @@ -17,10 +17,13 @@ typedef struct {  pcilib_dma_context_t *dma_nwl_init(pcilib_t *ctx);  void  dma_nwl_free(pcilib_dma_context_t *vctx); +int dma_nwl_read(pcilib_dma_context_t *ctx, pcilib_dma_t dma, size_t size, void *buf); +  #ifdef _PCILIB_DMA_NWL_C  pcilib_dma_api_description_t nwl_dma_api = {      dma_nwl_init, -    dma_nwl_free +    dma_nwl_free, +    dma_nwl_read  };  #else  extern pcilib_dma_api_description_t nwl_dma_api; @@ -270,6 +270,44 @@ int pcilib_write(pcilib_t *ctx, pcilib_bar_t bar, uintptr_t addr, size_t size, v      pcilib_unmap_bar(ctx, bar, data);      } +pcilib_dma_t pcilib_find_dma_by_addr(pcilib_t *ctx, pcilib_dma_direction_t direction, pcilib_dma_addr_t dma) { +    pcilib_dma_t i; + +    const pcilib_dma_info_t *info =  pcilib_get_dma_info(ctx); +    if (!info) { +	pcilib_error("DMA Engine is not configured in the current model"); +	return PCILIB_ERROR_NOTSUPPORTED; +    } +     +    for (i = 0; info->engines[i]; i++) { +	if ((info->engines[i]->addr == dma)&&((info->engines[i]->direction&direction)==direction)) break; +    } +     +    if (info->engines[i]) return i; +    return PCILIB_DMA_INVALID; +} + +int pcilib_read_dma(pcilib_t *ctx, pcilib_dma_t dma, size_t size, void *buf) { +    const pcilib_dma_info_t *info =  pcilib_get_dma_info(ctx); + +    if (!ctx->model_info->dma_api) { +	pcilib_error("DMA Engine is not configured in the current model"); +	return PCILIB_ERROR_NOTSUPPORTED; +    } +     +    if (!ctx->model_info->dma_api->read) { +	pcilib_error("The DMA read is not supported by configured DMA engine"); +	return PCILIB_ERROR_NOTSUPPORTED; +    } +     +    if (!info->engines[dma]) { +	pcilib_error("The DMA engine (%i) is not supported by device", dma); +	return PCILIB_ERROR_OUTOFRANGE; +    } +     +    return ctx->model_info->dma_api->read(ctx->dma_ctx, dma, size, buf); +} +  pcilib_register_bank_t pcilib_find_bank_by_addr(pcilib_t *ctx, pcilib_register_bank_addr_t bank) {      pcilib_register_bank_t i; @@ -66,6 +66,7 @@ typedef enum {  #define PCILIB_BAR_INVALID		((pcilib_bar_t)-1)  #define PCILIB_BAR0			0  #define PCILIB_BAR1			1 +#define PCILIB_DMA_INVALID		((pcilib_dma_t)-1)  #define PCILIB_REGISTER_INVALID		((pcilib_register_t)-1)  #define PCILIB_ADDRESS_INVALID		((uintptr_t)-1)  #define PCILIB_REGISTER_BANK_INVALID	((pcilib_register_bank_t)-1) @@ -163,7 +164,7 @@ typedef struct {      pcilib_dma_context_t *(*init)(pcilib_t *ctx);      void (*free)(pcilib_dma_context_t *ctx); -//    int (*read)(pcilib_dma_context_t *ctx, pcilib_event_t event_mask, pcilib_callback_t callback, void *user); +    int (*read)(pcilib_dma_context_t *ctx, pcilib_dma_t dma, size_t size, void *buf);  //    int (*write)(pcilib_dma_context_t *ctx);  } pcilib_dma_api_description_t; | 
