From 3681925508c0da88fee6325ea35ead7b112856c6 Mon Sep 17 00:00:00 2001 From: Daniel Hellstrom Date: Tue, 20 Dec 2011 16:27:54 +0100 Subject: LEON: updated shared drivers to Driver Manger framework Some bugfixes at the same time. After this patch the drivers may be used on RASTA systems having a big-endian PCI layout. Removed not up to date changelogs, rely on git log instead. --- c/src/lib/libbsp/sparc/shared/spw/grspw.c | 2838 ++++++++++++++++------------- 1 file changed, 1540 insertions(+), 1298 deletions(-) (limited to 'c/src/lib/libbsp/sparc/shared/spw') diff --git a/c/src/lib/libbsp/sparc/shared/spw/grspw.c b/c/src/lib/libbsp/sparc/shared/spw/grspw.c index d869d17b42..83f3b971cd 100644 --- a/c/src/lib/libbsp/sparc/shared/spw/grspw.c +++ b/c/src/lib/libbsp/sparc/shared/spw/grspw.c @@ -1,81 +1,14 @@ /* * This file contains the GRSPW SpaceWire Driver for LEON2 and LEON3. * - * COPYRIGHT (c) 2007 - * Gaisler Research. + * COPYRIGHT (c) 2006 + * Cobham Gaisler AB. * * The license and distribution terms for this file may be * found in the file LICENSE in this distribution or at * http://www.rtems.org/license/LICENSE. - * - * Changes: - * - * 2007-09-27, Daniel Hellstrom - * Added basic support for GRSPW2 core. - * - * 2007-07-12, Daniel Hellstrom - * Fixed bug in TXBLOCK mode (normally called flush). - * - * 2007-05-28, Daniel Hellstrom - * Changed register call from spacewire_register to - * grspw_register. Added one parameter (the AMBA bus - * pointer) for LEON2 and LEON3 PCI compability. - * Typical LEON3 register: grspw_register(&amba_conf); - * - * 2007-05-28, Daniel Hellstrom - * Changed errno return values, compatible with RASTA - * Spacewire driver - * - * 2007-05-25, Daniel Hellstrom - * Changed name from /dev/spacewire,/dev/spacewire_b... - * to /dev/grspw0,/dev/grspw1... - * - * 2007-05-24, Daniel Hellstrom - * Merged LEON3, LEON2 and RASTA driver to one - this. - * The driver is included and configured from grspw_pci.c - * and grspw_rasta.c. - * - * 2007-05-23, Daniel Hellstrom - * Changed open call, now one need to first call open - * and then ioctl(fd,START,timeout) in order to setup - * hardware for communication. - * - * 2007-05-23, Daniel Hellstrom - * Added ioctl(fd,SET_COREFREQ,freq_arg), the command - * can autodetect the register values disconnect and - * timer64. It is still possible to change them manually - * by ioctl(fd,SET_{DISCONNECT,TIMER},arg). - * */ -/* default name to /dev/grspw0 */ -#if !defined(GRSPW_DEVNAME) || !defined(GRSPW_DEVNAME_NO) - #undef GRSPW_DEVNAME - #undef GRSPW_DEVNAME_NO - #define GRSPW_DEVNAME "/dev/grspw0" - #define GRSPW_DEVNAME_NO(devstr,no) ((devstr)[10]='0'+(no)) -#endif - -#ifndef GRSPW_PREFIX - #define GRSPW_PREFIX(name) grspw##name -#else - #define GRSPW_REGISTER_STATIC -#endif - -/* default to no translation */ -#ifndef GRSPW_ADR_TO - #define memarea_to_hw(x) ((unsigned int)(x)) -#endif -#ifndef GRSPW_ADR_FROM - #define hw_to_memarea(x) ((unsigned int)(x)) -#endif - -#ifndef GRSPW_REG_INT - #define GRSPW_REG_INT(handler,irqno,arg) set_vector(handler,irqno+0x10,1) - #undef GRSPW_DEFINE_INTHANDLER - #define GRSPW_DEFINE_INTHANDLER -#endif - #include #include #include @@ -86,7 +19,9 @@ #include #include #include -#include + +#include +#include #include #define DBGSPW_IOCALLS 1 @@ -97,7 +32,7 @@ #define DEBUG_SPACEWIRE_FLAGS (DBGSPW_IOCALLS | DBGSPW_TX | DBGSPW_RX ) /* #define DEBUG_SPACEWIRE_ONOFF */ - + #ifdef DEBUG_SPACEWIRE_ONOFF #define SPACEWIRE_DBG(fmt, args...) do { { printk(" : %03d @ %18s()]:" fmt , __LINE__,__FUNCTION__,## args); }} while(0) #define SPACEWIRE_DBG2(fmt) do { { printk(" : %03d @ %18s()]:" fmt , __LINE__,__FUNCTION__); }} while(0) @@ -117,15 +52,15 @@ typedef struct { volatile unsigned int time; volatile unsigned int timer; volatile unsigned int pad; - - volatile unsigned int dma0ctrl; + + volatile unsigned int dma0ctrl; volatile unsigned int dma0rxmax; volatile unsigned int dma0txdesc; volatile unsigned int dma0rxdesc; - + /* For GRSPW core 2 and onwards */ volatile unsigned int dma0addr; - + } LEON3_SPACEWIRE_Regs_Map; typedef struct { @@ -151,7 +86,10 @@ typedef struct { #define BUFMEM_PER_LINK (SPACEWIRE_TXBUFS_NR*(SPACEWIRE_TXD_SIZE+SPACEWIRE_TXH_SIZE) + SPACEWIRE_RXBUFS_NR*SPACEWIRE_RXPCK_SIZE) typedef struct { - /* configuration parameters */ + /* configuration parameters */ + struct drvmgr_dev *dev; /* Driver manager device */ + char devName[32]; /* Device Name */ + LEON3_SPACEWIRE_Regs_Map *regs; spw_config config; unsigned int tx_all_in_use; @@ -165,12 +103,23 @@ typedef struct { unsigned int txbufcnt; unsigned int rxbufcnt; + /* DMA Area set by user */ + unsigned int rx_dma_area; + unsigned int tx_data_dma_area; + unsigned int tx_hdr_dma_area; + unsigned int bd_dma_area; + /* statistics */ spw_stats stat; char *ptr_rxbuf0; char *ptr_txdbuf0; char *ptr_txhbuf0; + char *ptr_bd0; + + char *ptr_rxbuf0_remote; + char *ptr_txdbuf0_remote; + char *ptr_txhbuf0_remote; unsigned int irq; int minor; @@ -178,7 +127,7 @@ typedef struct { int open; int running; unsigned int core_freq_khz; - + unsigned int rtimeout; /* semaphores*/ rtems_id txsp; @@ -187,23 +136,20 @@ typedef struct { SPACEWIRE_RXBD *rx; SPACEWIRE_TXBD *tx; -#ifdef GRSPW_STATIC_MEM - unsigned int membase, memend, mem_bdtable; -#endif - - LEON3_SPACEWIRE_Regs_Map *regs; + unsigned int rx_remote; + unsigned int tx_remote; } GRSPW_DEV; -static int spw_cores; -static int spw_cores2; -static unsigned int sys_freq_khz; -static GRSPW_DEV *grspw_devs; +/* Function pointer called upon timecode receive */ +void (*grspw_timecode_callback) + (void *pDev, void *regs, int minor, unsigned int tc) = NULL; #ifdef GRSPW_DONT_BYPASS_CACHE #define _SPW_READ(address) (*(volatile unsigned int *)(address)) -#define _MEM_READ(address) (*(volatile unsigned char *)(address)) +#define _MEM_READ8(address) (*(volatile unsigned char *)(address)) +#define _MEM_READ32(address) (*(volatile unsigned int *)(address)) #else -static unsigned int _SPW_READ(void *addr) { +static inline unsigned int _SPW_READ(volatile void *addr) { unsigned int tmp; __asm__ (" lda [%1]1, %0 " : "=r"(tmp) @@ -212,20 +158,29 @@ static unsigned int _SPW_READ(void *addr) { return tmp; } -static unsigned int _MEM_READ(void *addr) { +static inline unsigned int _MEM_READ8(volatile void *addr) { unsigned int tmp; __asm__ (" lduba [%1]1, %0 " : "=r"(tmp) : "r"(addr) ); return tmp; +} +static inline unsigned int _MEM_READ32(volatile void *addr) { + unsigned int tmp; + __asm__ (" lda [%1]1, %0 " + : "=r"(tmp) + : "r"(addr) + ); + return tmp; } #endif -#define MEM_READ(addr) _MEM_READ((void *)(addr)) -#define SPW_READ(addr) _SPW_READ((void *)(addr)) -#define SPW_WRITE(addr,v) *addr=v +#define MEM_READ8(addr) _MEM_READ8((volatile void *)(addr)) +#define MEM_READ32(addr) _MEM_READ32((volatile void *)(addr)) +#define SPW_READ(addr) _SPW_READ((volatile void *)(addr)) +#define SPW_WRITE(addr,v) (*(volatile unsigned int *)addr)=v #define SPW_REG(c,r) (c->regs->r) #define SPW_REG_CTRL(c) SPW_REG(c,ctrl) @@ -263,6 +218,8 @@ static unsigned int _MEM_READ(void *addr) { #define SPW_TXBD_WR (1 << 13) #define SPW_TXBD_IE (1 << 14) #define SPW_TXBD_LE (1 << 15) +#define SPW_TXBD_HC (1 << 16) +#define SPW_TXBD_DC (1 << 17) #define SPW_TXBD_ERROR (SPW_TXBD_LE) @@ -311,7 +268,7 @@ static unsigned int _MEM_READ(void *addr) { #define SPW_PREPAREMASK_RX (SPW_DMACTRL_TXEN | SPW_DMACTRL_TXIE | SPW_DMACTRL_AI | SPW_DMACTRL_PR | SPW_DMACTRL_RA) static int grspw_hw_init(GRSPW_DEV *pDev); -static int grspw_hw_send(GRSPW_DEV *pDev, unsigned int hlen, char *hdr, unsigned int dlen, char *data); +static int grspw_hw_send(GRSPW_DEV *pDev, unsigned int hlen, char *hdr, unsigned int dlen, char *data, unsigned int options); static int grspw_hw_receive(GRSPW_DEV *pDev,char *b,int c); static int grspw_hw_startup (GRSPW_DEV *pDev, int timeout); static int grspw_hw_stop (GRSPW_DEV *pDev, int rx, int tx); @@ -322,7 +279,8 @@ static void grspw_hw_read_config(GRSPW_DEV *pDev); static void check_rx_errors(GRSPW_DEV *pDev, int ctrl); static void grspw_rxnext(GRSPW_DEV *pDev); -static void grspw_interrupt(GRSPW_DEV *pDev); +static void grspw_interrupt(void *arg); +static int grspw_buffer_alloc(GRSPW_DEV *pDev); static rtems_device_driver grspw_initialize( rtems_device_major_number major, @@ -369,78 +327,271 @@ static rtems_device_driver grspw_control( grspw_control } static rtems_driver_address_table grspw_driver = GRSPW_DRIVER_TABLE_ENTRY; -static struct ambapp_bus *amba_bus; +static int grspw_driver_io_registered = 0; +static rtems_device_major_number grspw_driver_io_major = 0; -#ifdef GRSPW_REGISTER_STATIC -static -#endif -int GRSPW_PREFIX(_register)(struct ambapp_bus *bus) -{ - rtems_status_code r; - rtems_device_major_number m; +/******************* Driver manager interface ***********************/ - /* Get System clock frequency */ - sys_freq_khz = 0; +/* Driver prototypes */ +int grspw_register_io(rtems_device_major_number *m); +int grspw_device_init(GRSPW_DEV *pDev); - amba_bus = bus; +int grspw_init2(struct drvmgr_dev *dev); +int grspw_init3(struct drvmgr_dev *dev); - /* Auto Detect the GRSPW core frequency by assuming that the system frequency is - * is the same as the GRSPW core frequency. - */ -#ifndef SYS_FREQ_KHZ -#ifdef LEON3 - /* LEON3: find timer address via AMBA Plug&Play info */ +struct drvmgr_drv_ops grspw_ops = +{ + .init = {NULL, grspw_init2, grspw_init3, NULL}, + .remove = NULL, + .info = NULL +}; + +struct amba_dev_id grspw_ids[] = +{ + {VENDOR_GAISLER, GAISLER_SPW}, + {VENDOR_GAISLER, GAISLER_SPW2}, + {VENDOR_GAISLER, GAISLER_SPW2_DMA}, + {0, 0} /* Mark end of table */ +}; + +struct amba_drv_info grspw_drv_info = +{ { - struct ambapp_apb_info gptimer; - struct gptimer_regs *tregs; - - if ( ambapp_find_apbslv(&ambapp_plb, VENDOR_GAISLER, - GAISLER_GPTIMER, &gptimer) == 1 ) { - tregs = (struct gptimer_regs *)gptimer.start; - sys_freq_khz = (tregs->scaler_reload+1)*1000; - SPACEWIRE_DBG("GRSPW: detected %dkHZ system frequency\n\r",sys_freq_khz); - }else{ - sys_freq_khz = 40000; /* Default to 40MHz */ - printk("GRSPW: Failed to detect system frequency\n\r"); + DRVMGR_OBJ_DRV, /* Driver */ + NULL, /* Next driver */ + NULL, /* Device list */ + DRIVER_AMBAPP_GAISLER_GRSPW_ID, /* Driver ID */ + "GRSPW_DRV", /* Driver Name */ + DRVMGR_BUS_TYPE_AMBAPP, /* Bus Type */ + &grspw_ops, + NULL, /* Funcs */ + 0, /* No devices yet */ + 0, + }, + &grspw_ids[0] +}; + +void grspw_register_drv (void) +{ + SPACEWIRE_DBG("Registering GRSPW driver\n"); + drvmgr_drv_register(&grspw_drv_info.general); +} + +int grspw_init2(struct drvmgr_dev *dev) +{ + GRSPW_DEV *priv; + + SPACEWIRE_DBG("GRSPW[%d] on bus %s\n", dev->minor_drv, + dev->parent->dev->name); + priv = dev->priv = malloc(sizeof(GRSPW_DEV)); + if ( !priv ) + return DRVMGR_NOMEM; + memset(priv, 0, sizeof(*priv)); + priv->dev = dev; + + /* This core will not find other cores, so we wait for init2() */ + + return DRVMGR_OK; +} + +int grspw_init3(struct drvmgr_dev *dev) +{ + GRSPW_DEV *priv; + char prefix[32]; + rtems_status_code status; + + priv = dev->priv; + + /* Do initialization */ + + if ( grspw_driver_io_registered == 0) { + /* Register the I/O driver only once for all cores */ + if ( grspw_register_io(&grspw_driver_io_major) ) { + /* Failed to register I/O driver */ + free(dev->priv); + dev->priv = NULL; + return DRVMGR_FAIL; } + grspw_driver_io_registered = 1; } -#elif defined(LEON2) - /* LEON2: use hardcoded address to get to timer */ - { - LEON_Register_Map *regs = (LEON_Register_Map *)0x80000000; - sys_freq_khz = (regs->Scaler_Reload+1)*1000; - } -#else - #error CPU not supported by GRSPW driver -#endif -#else - /* Use hardcoded frequency */ - sys_freq_khz = SYS_FREQ_KHZ; -#endif - SPACEWIRE_DBG2("register driver\n"); - if ((r = rtems_io_register_driver(0, &grspw_driver, &m)) == RTEMS_SUCCESSFUL) { - SPACEWIRE_DBG2("success\n"); - return 0; - } else { - switch(r) { - case RTEMS_TOO_MANY: - SPACEWIRE_DBG2("failed RTEMS_TOO_MANY\n"); - break; - case RTEMS_INVALID_NUMBER: - SPACEWIRE_DBG2("failed RTEMS_INVALID_NUMBER\n"); - break; - case RTEMS_RESOURCE_IN_USE: - SPACEWIRE_DBG2("failed RTEMS_RESOURCE_IN_USE\n"); - break; - default: - SPACEWIRE_DBG("failed %i\n",r); - break; - } - return 1; - } + /* I/O system registered and initialized + * Now we take care of device initialization. + */ + + /* Get frequency in Hz */ + if ( drvmgr_freq_get(dev, DEV_APB_SLV, &priv->core_freq_khz) ) { + return DRVMGR_FAIL; + } + /* Convert from Hz -> kHz */ + priv->core_freq_khz = priv->core_freq_khz / 1000; + if ( grspw_device_init(priv) ) { + return DRVMGR_FAIL; + } + + /* Get Filesystem name prefix */ + prefix[0] = '\0'; + if ( drvmgr_get_dev_prefix(dev, prefix) ) { + /* Failed to get prefix, make sure of a unique FS name + * by using the driver minor. + */ + sprintf(priv->devName, "/dev/grspw%d", dev->minor_drv); + } else { + /* Got special prefix, this means we have a bus prefix + * And we should use our "bus minor" + */ + sprintf(priv->devName, "/dev/%sgrspw%d", prefix, dev->minor_bus); + } + + /* Register Device */ + status = rtems_io_register_name(priv->devName, grspw_driver_io_major, dev->minor_drv); + if (status != RTEMS_SUCCESSFUL) { + return DRVMGR_FAIL; + } + + return DRVMGR_OK; +} + +/******************* Driver Implementation ***********************/ + +int grspw_register_io(rtems_device_major_number *m) +{ + rtems_status_code r; + + if ((r = rtems_io_register_driver(0, &grspw_driver, m)) == RTEMS_SUCCESSFUL) { + SPACEWIRE_DBG("GRSPW driver successfully registered, major: %d\n", *m); + } else { + switch(r) { + case RTEMS_TOO_MANY: + printk("GRSPW rtems_io_register_driver failed: RTEMS_TOO_MANY\n"); + return -1; + case RTEMS_INVALID_NUMBER: + printk("GRSPW rtems_io_register_driver failed: RTEMS_INVALID_NUMBER\n"); + return -1; + case RTEMS_RESOURCE_IN_USE: + printk("GRSPW rtems_io_register_driver failed: RTEMS_RESOURCE_IN_USE\n"); + return -1; + default: + printk("GRSPW rtems_io_register_driver failed\n"); + return -1; + } + } + return 0; +} + +int grspw_device_init(GRSPW_DEV *pDev) +{ + struct amba_dev_info *ambadev; + struct ambapp_core *pnpinfo; + union drvmgr_key_value *value; + + /* Get device information from AMBA PnP information */ + ambadev = (struct amba_dev_info *)pDev->dev->businfo; + if ( ambadev == NULL ) { + return -1; + } + pnpinfo = &ambadev->info; + pDev->irq = pnpinfo->irq; + pDev->regs = (LEON3_SPACEWIRE_Regs_Map *)pnpinfo->apb_slv->start; + pDev->minor = pDev->dev->minor_drv; + + /* Get SpaceWire core version */ + switch( pnpinfo->device ) { + case GAISLER_SPW: + pDev->core_ver = 1; + break; + case GAISLER_SPW2: + pDev->core_ver = 2; + break; + case GAISLER_SPW2_DMA: + pDev->core_ver = 3; + break; + default: + return -1; + } + + /* initialize the code with some resonable values, + * actual initialization is done later using ioctl(fd) + * on the opened device */ + pDev->config.rxmaxlen = SPACEWIRE_RXPCK_SIZE; + pDev->txdbufsize = SPACEWIRE_TXD_SIZE; + pDev->txhbufsize = SPACEWIRE_TXH_SIZE; + pDev->rxbufsize = SPACEWIRE_RXPCK_SIZE; + pDev->txbufcnt = SPACEWIRE_TXBUFS_NR; + pDev->rxbufcnt = SPACEWIRE_RXBUFS_NR; + + pDev->ptr_rxbuf0 = 0; + pDev->ptr_txdbuf0 = 0; + pDev->ptr_txhbuf0 = 0; + pDev->ptr_bd0 = 0; + pDev->rx_dma_area = 0; + pDev->tx_data_dma_area = 0; + pDev->tx_hdr_dma_area = 0; + pDev->bd_dma_area = 0; + + /* Get Configuration from Bus resources (Let user override defaults) */ + + value = drvmgr_dev_key_get(pDev->dev, "txBdCnt", KEY_TYPE_INT); + if ( value ) + pDev->txbufcnt = value->i; + + value = drvmgr_dev_key_get(pDev->dev, "rxBdCnt", KEY_TYPE_INT); + if ( value ) + pDev->rxbufcnt = value->i; + + value = drvmgr_dev_key_get(pDev->dev, "txDataSize", KEY_TYPE_INT); + if ( value ) + pDev->txdbufsize = value->i; + + value = drvmgr_dev_key_get(pDev->dev, "txHdrSize", KEY_TYPE_INT); + if ( value ) + pDev->txhbufsize = value->i; + + value = drvmgr_dev_key_get(pDev->dev, "rxPktSize", KEY_TYPE_INT); + if ( value ) + pDev->rxbufsize = value->i; + + value = drvmgr_dev_key_get(pDev->dev, "rxDmaArea", KEY_TYPE_INT); + if ( value ) + pDev->rx_dma_area = value->i; + + value = drvmgr_dev_key_get(pDev->dev, "txDataDmaArea", KEY_TYPE_INT); + if ( value ) + pDev->tx_data_dma_area = value->i; + + value = drvmgr_dev_key_get(pDev->dev, "txHdrDmaArea", KEY_TYPE_INT); + if ( value ) + pDev->tx_hdr_dma_area = value->i; + + value = drvmgr_dev_key_get(pDev->dev, "bdDmaArea", KEY_TYPE_INT); + if ( value ) + pDev->bd_dma_area = value->i; + + if (grspw_buffer_alloc(pDev)) + return RTEMS_NO_MEMORY; + + /* Create semaphores */ + rtems_semaphore_create( + rtems_build_name('T', 'x', 'S', '0' + pDev->minor), + 0, + RTEMS_FIFO | RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_NO_INHERIT_PRIORITY | \ + RTEMS_NO_PRIORITY_CEILING, + 0, + &(pDev->txsp)); + + rtems_semaphore_create( + rtems_build_name('R', 'x', 'S', '0' + pDev->minor), + 0, + RTEMS_FIFO | RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_NO_INHERIT_PRIORITY | \ + RTEMS_NO_PRIORITY_CEILING, + 0, + &(pDev->rxsp)); + + grspw_hw_init(pDev); + + return 0; } /* Get a value at least 6.4us in number of clock cycles */ @@ -455,1182 +606,1212 @@ static unsigned int grspw_calc_disconnect(int freq_khz){ return disconnect & 0x3ff; } -#if 0 -static int grspw_buffer_alloc(GRSPW_DEV *pDev) { - if (pDev->ptr_rxbuf0) { - free(pDev->ptr_rxbuf0); - } - if (pDev->ptr_txdbuf0) { - free(pDev->ptr_txdbuf0); - } - if (pDev->ptr_txhbuf0) { - free(pDev->ptr_txhbuf0); - } - pDev->ptr_rxbuf0 = (char *) malloc(pDev->rxbufsize * pDev->rxbufcnt); - pDev->ptr_txdbuf0 = (char *) malloc(pDev->txdbufsize * pDev->txbufcnt); - pDev->ptr_txhbuf0 = (char *) malloc(pDev->txhbufsize * pDev->txbufcnt); - if ((pDev->ptr_rxbuf0 == NULL) || - (pDev->ptr_txdbuf0 == NULL) || (pDev->ptr_txhbuf0 == NULL)) { - return 1; - } else { - return 0; - } -} -#endif - static int grspw_buffer_alloc(GRSPW_DEV *pDev) { -#ifndef GRSPW_STATIC_MEM - if (pDev->ptr_rxbuf0) { - free(pDev->ptr_rxbuf0); - } - if (pDev->ptr_txdbuf0) { - free(pDev->ptr_txdbuf0); - } - if (pDev->ptr_txhbuf0) { - free(pDev->ptr_txhbuf0); - } - - pDev->ptr_rxbuf0 = (char *) malloc(pDev->rxbufsize * pDev->rxbufcnt); - pDev->ptr_txdbuf0 = (char *) malloc(pDev->txdbufsize * pDev->txbufcnt); - pDev->ptr_txhbuf0 = (char *) malloc(pDev->txhbufsize * pDev->txbufcnt); - if ((pDev->ptr_rxbuf0 == NULL) || - (pDev->ptr_txdbuf0 == NULL) || (pDev->ptr_txhbuf0 == NULL)) { - return 1; - } else { - return 0; - } -#else - if ( (pDev->membase + pDev->rxbufsize*pDev->rxbufcnt + pDev->txdbufsize*pDev->txbufcnt) >= pDev->memend ) { - return -1; - } - pDev->ptr_rxbuf0 = (char *) pDev->membase; - pDev->ptr_txdbuf0 = pDev->ptr_rxbuf0 + pDev->rxbufsize * pDev->rxbufcnt; - pDev->ptr_txhbuf0 = pDev->ptr_txdbuf0 + pDev->txdbufsize * pDev->txbufcnt; - return 0; -#endif + if ( pDev->rx_dma_area ) { +#warning Check size? + if ( pDev->rx_dma_area & 1 ) { + /* Address given in remote address */ + drvmgr_translate(pDev->dev, 1, 1, (void *)(pDev->rx_dma_area & ~1), (void **)&pDev->ptr_rxbuf0); + } else { + pDev->ptr_rxbuf0 = pDev->rx_dma_area; + } + } else { + if (pDev->ptr_rxbuf0) { + free(pDev->ptr_rxbuf0); + } + pDev->ptr_rxbuf0 = (char *) malloc(pDev->rxbufsize * pDev->rxbufcnt); + if ( !pDev->ptr_rxbuf0 ) + return 1; + } + if ( pDev->tx_data_dma_area ) { + if ( pDev->tx_data_dma_area & 1 ) { + /* Address given in remote address */ + drvmgr_translate(pDev->dev, 1, 1, (void *)(pDev->tx_data_dma_area & ~1), (void **)&pDev->ptr_txdbuf0); + } else { + pDev->ptr_txdbuf0 = pDev->tx_data_dma_area; + } + } else { + if (pDev->ptr_txdbuf0) { + free(pDev->ptr_txdbuf0); + } + pDev->ptr_txdbuf0 = (char *) malloc(pDev->txdbufsize * pDev->txbufcnt); + if ( !pDev->ptr_txdbuf0 ) + return 1; + } + if ( pDev->tx_hdr_dma_area ) { + if ( pDev->tx_hdr_dma_area & 1 ) { + /* Address given in remote address */ + drvmgr_translate(pDev->dev, 1, 1, (void *)(pDev->tx_hdr_dma_area & ~1), (void **)&pDev->ptr_txhbuf0); + } else { + pDev->ptr_txhbuf0 = pDev->tx_hdr_dma_area; + } + } else { + if (pDev->ptr_txhbuf0) { + free(pDev->ptr_txhbuf0); + } + pDev->ptr_txhbuf0 = (char *) malloc(pDev->txhbufsize * pDev->txbufcnt); + if ( !pDev->ptr_txhbuf0 ) + return 1; + } + if ( pDev->bd_dma_area ) { + if ( pDev->bd_dma_area & 1 ) { + /* Address given in remote address */ + drvmgr_translate(pDev->dev, 1, 1, (void *)(pDev->bd_dma_area & ~1), (void **)&pDev->ptr_bd0); + } else { + pDev->ptr_bd0 = pDev->bd_dma_area; + } + } else { + if (pDev->ptr_bd0) { + free(pDev->ptr_bd0); + } + pDev->ptr_bd0 = (char *) + rtems_heap_allocate_aligned_with_boundary(SPACEWIRE_BDTABLE_SIZE*2, 1024, 0); + if ( !pDev->ptr_bd0 ) + return 1; + } + /* Translate into remote address */ + drvmgr_translate(pDev->dev, 0, 0, (void *)pDev->ptr_rxbuf0, (void **)&pDev->ptr_rxbuf0_remote); + drvmgr_translate(pDev->dev, 0, 0, (void *)pDev->ptr_txdbuf0,(void **)&pDev->ptr_txdbuf0_remote); + drvmgr_translate(pDev->dev, 0, 0, (void *)pDev->ptr_txhbuf0, (void **)&pDev->ptr_txhbuf0_remote); + return 0; } -#ifdef GRSPW_DEFINE_INTHANDLER -/* - * Standard Interrupt handler - */ -static rtems_isr grspw_interrupt_handler(rtems_vector_number v) +static void grspw_interrupt(void *arg) { - int minor; - - for(minor = 0; minor < spw_cores+spw_cores2; minor++) { - if (v == (grspw_devs[minor].irq+0x10) ) { - grspw_interrupt(&grspw_devs[minor]); - break; - } - } -} -#endif + GRSPW_DEV *pDev = (GRSPW_DEV *)arg; + int dmactrl; + int status; + int ctrl; + unsigned int timecode; + + status = SPW_STATUS_READ(pDev); + /*SPW_STATUS_WRITE(pDev, SPW_STATUS_CE | SPW_STATUS_ER | SPW_STATUS_DE | SPW_STATUS_PE | SPW_STATUS_WE | SPW_STATUS_IA | SPW_STATUS_EE | SPW_STATUS_TO);*/ + SPW_STATUS_WRITE(pDev, status & (SPW_STATUS_CE | SPW_STATUS_ER | SPW_STATUS_DE | SPW_STATUS_PE | SPW_STATUS_WE | SPW_STATUS_IA | SPW_STATUS_EE)); + + /* Make sure to put the timecode handling first in order to get the smallest + * possible interrupt latency + */ + if ( (status & SPW_STATUS_TO) && (grspw_timecode_callback != NULL) ) { + /* Timecode received. Let custom function handle this */ + SPW_STATUS_WRITE(pDev, SPW_STATUS_TO); + timecode = SPW_READ(&pDev->regs->time); + (grspw_timecode_callback)(pDev,pDev->regs,pDev->minor,timecode); + } + + /* Clear SPW_DMACTRL_PR if set */ + dmactrl = SPW_READ(&pDev->regs->dma0ctrl); + /*SPW_WRITE(&pDev->regs->dma0ctrl, dmactrl | SPW_DMACTRL_PR);*/ + SPW_WRITE(&pDev->regs->dma0ctrl, dmactrl); + + /* If linkinterrupts are enabled check if it was a linkerror irq and then send an event to the + process set in the config */ + if (pDev->config.link_err_irq) { + if (status & (SPW_STATUS_CE | SPW_STATUS_ER | SPW_STATUS_DE | SPW_STATUS_PE | SPW_STATUS_WE)) { + rtems_event_send(pDev->config.event_id, SPW_LINKERR_EVENT); + if (pDev->config.disable_err) { + /* disable link*/ + SPW_CTRL_WRITE(pDev, (SPW_CTRL_READ(pDev) & 0xFFFFFFFC) | SPW_CTRL_LINKDISABLED); + pDev->config.linkdisabled = 1; + pDev->config.linkstart = 0; + pDev->running = 0; + } + } + } + if (status & SPW_STATUS_CE) { + pDev->stat.credit_err++; + } + if (status & SPW_STATUS_ER) { + pDev->stat.escape_err++; + } + if (status & SPW_STATUS_DE) { + pDev->stat.disconnect_err++; + } + if (status & SPW_STATUS_PE) { + pDev->stat.parity_err++; + } + if (status & SPW_STATUS_WE) { + pDev->stat.write_sync_err++; + } + if (status & SPW_STATUS_IA) { + pDev->stat.invalid_address++; + } + if (status & SPW_STATUS_EE) { + pDev->stat.early_ep++; + } + + /* Check for tx interrupts */ + while( (pDev->tx_sent != pDev->tx_cur) || pDev->tx_all_in_use) { + /* Has this descriptor been sent? */ + ctrl = SPW_READ((volatile void *)&pDev->tx[pDev->tx_sent].ctrl); + if ( ctrl & SPW_TXBD_EN ) { + break; + } + /* Yes, increment status counters & tx_sent so we can use this descriptor to send more packets with */ + pDev->stat.packets_sent++; -static void grspw_interrupt(GRSPW_DEV *pDev){ - int dmactrl; - int status; - int ctrl; - - status = SPW_STATUS_READ(pDev); - SPW_STATUS_WRITE(pDev, SPW_STATUS_CE | SPW_STATUS_ER | SPW_STATUS_DE | SPW_STATUS_PE | SPW_STATUS_WE | SPW_STATUS_IA | SPW_STATUS_EE); - dmactrl = SPW_READ(&pDev->regs->dma0ctrl); - SPW_WRITE(&pDev->regs->dma0ctrl, dmactrl | SPW_DMACTRL_PR); - /* If linkinterrupts are enabled check if it was a linkerror irq and then send an event to the - process set in the config */ - if (pDev->config.link_err_irq) { - if (status & (SPW_STATUS_CE | SPW_STATUS_ER | SPW_STATUS_DE | SPW_STATUS_PE | SPW_STATUS_WE)) { - rtems_event_send(pDev->config.event_id, SPW_LINKERR_EVENT); - if (pDev->config.disable_err) { - /* disable link*/ - SPW_CTRL_WRITE(pDev, (SPW_CTRL_READ(pDev) & 0xFFFFFFFC) | SPW_CTRL_LINKDISABLED); - pDev->config.linkdisabled = 1; - pDev->config.linkstart = 0; - pDev->running = 0; - } - } - } - if (status & SPW_STATUS_CE) { - pDev->stat.credit_err++; - } - if (status & SPW_STATUS_ER) { - pDev->stat.escape_err++; - } - if (status & SPW_STATUS_DE) { - pDev->stat.disconnect_err++; - } - if (status & SPW_STATUS_PE) { - pDev->stat.parity_err++; - } - if (status & SPW_STATUS_WE) { - pDev->stat.write_sync_err++; - } - if (status & SPW_STATUS_IA) { - pDev->stat.invalid_address++; - } - if (status & SPW_STATUS_EE) { - pDev->stat.early_ep++; - } - - /* Check for tx interrupts */ - while( (pDev->tx_sent != pDev->tx_cur) || pDev->tx_all_in_use) { - /* Has this descriptor been sent? */ - ctrl = SPW_READ((volatile void *)&pDev->tx[pDev->tx_sent].ctrl); - if ( ctrl & SPW_TXBD_EN ) { - break; - } - /* Yes, increment status counters & tx_sent so we can use this descriptor to send more packets with */ - pDev->stat.packets_sent++; - - rtems_semaphore_release(pDev->txsp); - - if ( ctrl & SPW_TXBD_LE ) { - pDev->stat.tx_link_err++; - } - - /* step to next descriptor */ - pDev->tx_sent = (pDev->tx_sent + 1) % pDev->txbufcnt; - pDev->tx_all_in_use = 0; /* not all of the descriptors can be in use since we just freed one. */ - } - - /* Check for rx interrupts */ - if (dmactrl & SPW_DMACTRL_PR) { - rtems_semaphore_release(pDev->rxsp); - } + rtems_semaphore_release(pDev->txsp); + + if ( ctrl & SPW_TXBD_LE ) { + pDev->stat.tx_link_err++; + } + + /* step to next descriptor */ + pDev->tx_sent = (pDev->tx_sent + 1) % pDev->txbufcnt; + pDev->tx_all_in_use = 0; /* not all of the descriptors can be in use since we just freed one. */ + } + + /* Check for rx interrupts */ + if (dmactrl & SPW_DMACTRL_PR) { + rtems_semaphore_release(pDev->rxsp); + } } static rtems_device_driver grspw_initialize( - rtems_device_major_number major, - rtems_device_minor_number minor, - void *arg + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg ) { - rtems_status_code status; - int i=0; - char c; - GRSPW_DEV *pDev; - char console_name[20]; - struct ambapp_apb_info dev; - - SPACEWIRE_DBG2("spacewire driver initialization\n"); - - /* Copy device name */ - strcpy(console_name,GRSPW_DEVNAME); - - /* Get the number of GRSPW cores */ - i=0; spw_cores = 0; spw_cores2 = 0; - - /* get number of GRSPW cores */ - spw_cores = ambapp_get_number_apbslv_devices(amba_bus, VENDOR_GAISLER, - GAISLER_SPW); - spw_cores2 = ambapp_get_number_apbslv_devices(amba_bus, VENDOR_GAISLER, - GAISLER_SPW2); - - if ( (spw_cores+spw_cores2) < 1 ){ - /* No GRSPW cores around... */ - return RTEMS_SUCCESSFUL; - } - - /* Allocate memory for all spacewire cores */ - grspw_devs = (GRSPW_DEV *)malloc((spw_cores+spw_cores2) * sizeof(GRSPW_DEV)); - - /* Zero out all memory */ - memset(grspw_devs,0,(spw_cores+spw_cores2) * sizeof(GRSPW_DEV)); - - /* loop all found spacewire cores */ - i = 0; - for(minor=0; minor<(spw_cores+spw_cores2); minor++){ - - pDev = &grspw_devs[minor]; - - /* Get device */ - if ( spw_cores > minor ) { - ambapp_find_apbslv_next(amba_bus, VENDOR_GAISLER, - GAISLER_SPW, &dev, minor); - pDev->core_ver = 1; - } else { - ambapp_find_apbslv_next(amba_bus, VENDOR_GAISLER, - GAISLER_SPW2, &dev, - minor - spw_cores); - pDev->core_ver = 2; - } - - pDev->regs = (LEON3_SPACEWIRE_Regs_Map *)dev.start; - pDev->irq = dev.irq; - pDev->minor = minor; - pDev->open = 0; - - /* register interrupt routine */ - GRSPW_REG_INT(GRSPW_PREFIX(_interrupt_handler), pDev->irq, pDev); - - SPACEWIRE_DBG("spacewire core at [0x%x]\n", (unsigned int) pDev->regs); - - /* initialize the code with some resonable values, - actual initialization is done later using ioctl(fd) - on the opened device */ - pDev->config.rxmaxlen = SPACEWIRE_RXPCK_SIZE; - pDev->txdbufsize = SPACEWIRE_TXD_SIZE; - pDev->txhbufsize = SPACEWIRE_TXH_SIZE; - pDev->rxbufsize = SPACEWIRE_RXPCK_SIZE; - pDev->txbufcnt = SPACEWIRE_TXBUFS_NR; - pDev->rxbufcnt = SPACEWIRE_RXBUFS_NR; - pDev->config.check_rmap_err = 0; - pDev->config.tx_blocking = 0; - pDev->config.tx_block_on_full = 0; - pDev->config.rx_blocking = 0; - pDev->config.disable_err = 0; - pDev->config.link_err_irq = 0; - pDev->config.event_id = 0; - - pDev->ptr_rxbuf0 = 0; - pDev->ptr_txdbuf0 = 0; - pDev->ptr_txhbuf0 = 0; - -#ifdef GRSPW_STATIC_MEM - GRSPW_CALC_MEMOFS(spw_cores,minor,&pDev->membase,&pDev->memend,&pDev->mem_bdtable); -#endif - - if (grspw_buffer_alloc(pDev)) - return RTEMS_NO_MEMORY; - - } - - /* Register Device Names, /dev/grspw0, /dev/grspw1 ... */ - for (i = 0; i < spw_cores+spw_cores2; i++) { - GRSPW_DEVNAME_NO(console_name,i); - SPACEWIRE_DBG("registering minor %i as %s\n", i, console_name); - status = rtems_io_register_name( console_name, major, i); - if (status != RTEMS_SUCCESSFUL){ - rtems_fatal_error_occurred(status); - } - } - - /* Initialize Hardware and semaphores*/ - c = 'a'; - for (i = 0; i < spw_cores+spw_cores2; i++) { - pDev = &grspw_devs[i]; - rtems_semaphore_create( - rtems_build_name('T', 'x', 'S', c), - 0, - RTEMS_FIFO | RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_NO_INHERIT_PRIORITY | \ - RTEMS_NO_PRIORITY_CEILING, - 0, - &(pDev->txsp)); - rtems_semaphore_create( - rtems_build_name('R', 'x', 'S', c), - 0, - RTEMS_FIFO | RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_NO_INHERIT_PRIORITY | \ - RTEMS_NO_PRIORITY_CEILING, - 0, - &(pDev->rxsp)); - c++; - grspw_hw_init(pDev); - } - - return RTEMS_SUCCESSFUL; + /* Initialize device-common data structures here */ + return RTEMS_SUCCESSFUL; } static rtems_device_driver grspw_open( rtems_device_major_number major, rtems_device_minor_number minor, - void * arg - ) + void * arg + ) { - GRSPW_DEV *pDev; - SPACEWIRE_DBGC(DBGSPW_IOCALLS, "open [%i,%i]\n", major, minor); - if ( minor >= (spw_cores+spw_cores2) ) { - SPACEWIRE_DBG("minor %i too big\n", minor); - return RTEMS_INVALID_NAME; - } - pDev = &grspw_devs[minor]; - - if ( pDev->open ) - return RTEMS_RESOURCE_IN_USE; - - /* Mark device open */ - pDev->open = 1; - - pDev->stat.tx_link_err = 0; - pDev->stat.rx_rmap_header_crc_err = 0; - pDev->stat.rx_rmap_data_crc_err = 0; - pDev->stat.rx_eep_err = 0; - pDev->stat.rx_truncated = 0; - pDev->stat.parity_err = 0; - pDev->stat.escape_err = 0; - pDev->stat.credit_err = 0; - pDev->stat.write_sync_err = 0; - pDev->stat.disconnect_err = 0; - pDev->stat.early_ep = 0; - pDev->stat.invalid_address = 0; - pDev->stat.packets_sent = 0; - pDev->stat.packets_received = 0; - - pDev->running = 0; - pDev->core_freq_khz = 0; - - /* Reset Core */ - grspw_hw_reset(pDev); - - /* Read default configuration */ - grspw_hw_read_config(pDev); - - return RTEMS_SUCCESSFUL; + GRSPW_DEV *pDev; + struct drvmgr_dev *dev; + SPACEWIRE_DBGC(DBGSPW_IOCALLS, "open [%i,%i]\n", major, minor); + + if ( drvmgr_get_dev(&grspw_drv_info.general, minor, &dev) ) { + SPACEWIRE_DBG("Wrong minor %d\n", minor); + return RTEMS_INVALID_NAME; + } + pDev = (GRSPW_DEV *)dev->priv; + + if ( pDev->open ) + return RTEMS_RESOURCE_IN_USE; + + /* Mark device open */ + pDev->open = 1; + + pDev->stat.tx_link_err = 0; + pDev->stat.rx_rmap_header_crc_err = 0; + pDev->stat.rx_rmap_data_crc_err = 0; + pDev->stat.rx_eep_err = 0; + pDev->stat.rx_truncated = 0; + pDev->stat.parity_err = 0; + pDev->stat.escape_err = 0; + pDev->stat.credit_err = 0; + pDev->stat.write_sync_err = 0; + pDev->stat.disconnect_err = 0; + pDev->stat.early_ep = 0; + pDev->stat.invalid_address = 0; + pDev->stat.packets_sent = 0; + pDev->stat.packets_received = 0; + + pDev->config.rm_prot_id = 0; + pDev->config.keep_source = 0; + pDev->config.check_rmap_err = 0; + pDev->config.tx_blocking = 0; + pDev->config.tx_block_on_full = 0; + pDev->config.rx_blocking = 0; + pDev->config.disable_err = 0; + pDev->config.link_err_irq = 0; + pDev->config.event_id = 0; + pDev->config.rtimeout = 0; + + pDev->running = 0; + pDev->core_freq_khz = 0; + + /* Reset Core */ + grspw_hw_reset(pDev); + + /* Read default configuration */ + grspw_hw_read_config(pDev); + + return RTEMS_SUCCESSFUL; } static rtems_device_driver grspw_close( - rtems_device_major_number major, - rtems_device_minor_number minor, - void * arg - ) -{ - GRSPW_DEV *pDev = &grspw_devs[minor]; + rtems_device_major_number major, + rtems_device_minor_number minor, + void * arg + ) +{ + GRSPW_DEV *pDev; + struct drvmgr_dev *dev; + + if ( drvmgr_get_dev(&grspw_drv_info.general, minor, &dev) ) { + return RTEMS_INVALID_NAME; + } + pDev = (GRSPW_DEV *)dev->priv; - SPACEWIRE_DBGC(DBGSPW_IOCALLS, "close [%i,%i]\n", major, minor); - rtems_semaphore_delete(pDev->txsp); - rtems_semaphore_delete(pDev->rxsp); + SPACEWIRE_DBGC(DBGSPW_IOCALLS, "close [%i,%i]\n", major, minor); + rtems_semaphore_delete(pDev->txsp); + rtems_semaphore_delete(pDev->rxsp); - grspw_hw_stop(pDev,1,1); + grspw_hw_stop(pDev,1,1); - grspw_hw_reset(pDev); + grspw_hw_reset(pDev); - /* Mark device closed - not open */ - pDev->open = 0; + /* Mark device closed - not open */ + pDev->open = 0; - return RTEMS_SUCCESSFUL; + return RTEMS_SUCCESSFUL; } static rtems_device_driver grspw_read( - rtems_device_major_number major, - rtems_device_minor_number minor, - void * arg - ) + rtems_device_major_number major, + rtems_device_minor_number minor, + void * arg + ) { - GRSPW_DEV *pDev = &grspw_devs[minor]; - rtems_libio_rw_args_t *rw_args; - unsigned int count = 0; - rw_args = (rtems_libio_rw_args_t *) arg; + rtems_libio_rw_args_t *rw_args; + unsigned int count = 0; + GRSPW_DEV *pDev; + struct drvmgr_dev *dev; + int status; + + if ( drvmgr_get_dev(&grspw_drv_info.general, minor, &dev) ) { + return RTEMS_INVALID_NAME; + } + pDev = (GRSPW_DEV *)dev->priv; + + rw_args = (rtems_libio_rw_args_t *) arg; - /* is link up? */ - if ( !pDev->running ) { - return RTEMS_INVALID_NAME; - } + /* is link up? */ + if ( !pDev->running ) { + return RTEMS_INVALID_NAME; + } - if ((rw_args->count < 1) || (rw_args->buffer == NULL)) { - return RTEMS_INVALID_NAME; - } + if ((rw_args->count < 1) || (rw_args->buffer == NULL)) { + return RTEMS_INVALID_NAME; + } - SPACEWIRE_DBGC(DBGSPW_IOCALLS, "read [%i,%i]: buf:0x%x len:%i \n", major, minor, (unsigned int)rw_args->buffer, rw_args->count); + SPACEWIRE_DBGC(DBGSPW_IOCALLS, "read [%i,%i]: buf:0x%x len:%i \n", major, minor, (unsigned int)rw_args->buffer, rw_args->count); - while ( (count = grspw_hw_receive(pDev, rw_args->buffer, rw_args->count)) == 0) { - /* wait a moment for any descriptors to get available - * + while ( (count = grspw_hw_receive(pDev, rw_args->buffer, rw_args->count)) == 0) { + /* wait a moment for any descriptors to get available + * * Semaphore is signaled by interrupt handler */ if (pDev->config.rx_blocking) { SPACEWIRE_DBG2("Rx blocking\n"); - rtems_semaphore_obtain(pDev->rxsp, RTEMS_WAIT, RTEMS_NO_TIMEOUT); + if ( pDev->config.rtimeout ) { + status = rtems_semaphore_obtain(pDev->rxsp, RTEMS_WAIT, pDev->config.rtimeout); + if ( status == RTEMS_TIMEOUT ) + return RTEMS_TIMEOUT; + } else { + rtems_semaphore_obtain(pDev->rxsp, RTEMS_WAIT, RTEMS_NO_TIMEOUT); + } } else { - SPACEWIRE_DBG2("Rx non blocking\n"); + SPACEWIRE_DBG2("Rx non blocking\n"); return RTEMS_RESOURCE_IN_USE; } } -#ifdef DEBUG_SPACEWIRE_ONOFF - if (DEBUG_SPACEWIRE_FLAGS & DBGSPW_DUMP) { - int k; - for (k = 0; k < count; k++){ - if (k % 16 == 0) { - printf ("\n"); - } - printf ("%.2x(%c) ", rw_args->buffer[k] & 0xff, isprint(rw_args->buffer[k] & 0xff) ? rw_args->buffer[k] & 0xff : ' '); - } - printf ("\n"); - } +#ifdef DEBUG_SPACEWIRE_ONOFF + if (DEBUG_SPACEWIRE_FLAGS & DBGSPW_DUMP) { + int k; + for (k = 0; k < count; k++){ + if (k % 16 == 0) { + printf ("\n"); + } + printf ("%.2x(%c) ", rw_args->buffer[k] & 0xff, isprint(rw_args->buffer[k] & 0xff) ? rw_args->buffer[k] & 0xff : ' '); + } + printf ("\n"); + } #endif - rw_args->bytes_moved = count; - return RTEMS_SUCCESSFUL; - + rw_args->bytes_moved = count; + return RTEMS_SUCCESSFUL; } static rtems_device_driver grspw_write( - rtems_device_major_number major, - rtems_device_minor_number minor, - void * arg + rtems_device_major_number major, + rtems_device_minor_number minor, + void * arg ) { - GRSPW_DEV *pDev = &grspw_devs[minor]; - rtems_libio_rw_args_t *rw_args; - rw_args = (rtems_libio_rw_args_t *) arg; - SPACEWIRE_DBGC(DBGSPW_IOCALLS, "write [%i,%i]: buf:0x%x len:%i\n", major, minor, (unsigned int)rw_args->buffer, rw_args->count); - - /* is link up? */ - if ( !pDev->running ) { - return RTEMS_INVALID_NAME; - } - - if ((rw_args->count > pDev->txdbufsize) || (rw_args->count < 1) || (rw_args->buffer == NULL)) { - return RTEMS_INVALID_NAME; - } - - while ((rw_args->bytes_moved = grspw_hw_send(pDev, 0, NULL, rw_args->count, rw_args->buffer)) == 0) { - if (pDev->config.tx_block_on_full == 1) { - SPACEWIRE_DBG2("Tx Block on full \n"); - rtems_semaphore_obtain(pDev->txsp, RTEMS_WAIT, RTEMS_NO_TIMEOUT); - } else { - SPACEWIRE_DBG2("Tx non blocking return when full \n"); - return RTEMS_RESOURCE_IN_USE; - } - } - return RTEMS_SUCCESSFUL; + rtems_libio_rw_args_t *rw_args; + GRSPW_DEV *pDev; + struct drvmgr_dev *dev; + + if ( drvmgr_get_dev(&grspw_drv_info.general, minor, &dev) ) { + return RTEMS_INVALID_NAME; + } + pDev = (GRSPW_DEV *)dev->priv; + + rw_args = (rtems_libio_rw_args_t *) arg; + SPACEWIRE_DBGC(DBGSPW_IOCALLS, "write [%i,%i]: buf:0x%x len:%i\n", major, minor, (unsigned int)rw_args->buffer, rw_args->count); + + /* is link up? */ + if ( !pDev->running ) { + return RTEMS_INVALID_NAME; + } + + if ((rw_args->count > pDev->txdbufsize) || (rw_args->count < 1) || (rw_args->buffer == NULL)) { + return RTEMS_INVALID_NAME; + } + + while ((rw_args->bytes_moved = grspw_hw_send(pDev, 0, NULL, rw_args->count, rw_args->buffer, 0)) == 0) { + if (pDev->config.tx_block_on_full == 1) { + SPACEWIRE_DBG2("Tx Block on full \n"); + rtems_semaphore_obtain(pDev->txsp, RTEMS_WAIT, RTEMS_NO_TIMEOUT); + } else { + SPACEWIRE_DBG2("Tx non blocking return when full \n"); + return RTEMS_RESOURCE_IN_USE; + } + } + return RTEMS_SUCCESSFUL; } static rtems_device_driver grspw_control( - rtems_device_major_number major, - rtems_device_minor_number minor, - void * arg - ) + rtems_device_major_number major, + rtems_device_minor_number minor, + void * arg + ) { - GRSPW_DEV *pDev = &grspw_devs[minor]; - spw_ioctl_pkt_send *args; - spw_ioctl_packetsize *ps; - int status; - unsigned int tmp,nodeaddr,nodemask; - int timeout; - rtems_device_driver ret; - rtems_libio_ioctl_args_t *ioarg = (rtems_libio_ioctl_args_t *) arg; - SPACEWIRE_DBGC(DBGSPW_IOCALLS, "ctrl [%i,%i]\n", major, minor); - - if (!ioarg) - return RTEMS_INVALID_NAME; - - - ioarg->ioctl_return = 0; - switch(ioarg->command) { - case SPACEWIRE_IOCTRL_SET_NODEADDR: - /*set node address*/ - SPACEWIRE_DBGC(DBGSPW_IOCTRL, "SPACEWIRE_IOCTRL_SET_NODEADDR %i\n",(unsigned int)ioarg->buffer); - if ((unsigned int)ioarg->buffer > 255) { - return RTEMS_INVALID_NAME; - } - nodeaddr = ((unsigned int)ioarg->buffer) & 0xff; - tmp = SPW_READ(&pDev->regs->nodeaddr); - tmp &= 0xffffff00; /* Remove old address */ - tmp |= nodeaddr; - SPW_WRITE(&pDev->regs->nodeaddr, tmp); - if ((SPW_READ(&pDev->regs->nodeaddr)&0xff) != nodeaddr) { - return RTEMS_IO_ERROR; - } - pDev->config.nodeaddr = nodeaddr; - break; - case SPACEWIRE_IOCTRL_SET_NODEMASK: - /*set node address*/ - SPACEWIRE_DBGC(DBGSPW_IOCTRL, "SPACEWIRE_IOCTRL_SET_NODEMASK %i\n",(unsigned int)ioarg->buffer); - if ( pDev->core_ver > 1 ){ - if ((unsigned int)ioarg->buffer > 255) { - return RTEMS_INVALID_NAME; - } - nodemask = ((unsigned int)ioarg->buffer) & 0xff; - tmp = SPW_READ(&pDev->regs->nodeaddr); - tmp &= 0xffff00ff; /* Remove old mask */ - tmp |= nodemask<<8; - SPW_WRITE(&pDev->regs->nodeaddr, tmp); - if (((SPW_READ(&pDev->regs->nodeaddr)>>8)&0xff) != nodemask) { - return RTEMS_IO_ERROR; - } - pDev->config.nodemask = nodemask; - }else{ - SPACEWIRE_DBG("SPACEWIRE_IOCTRL_SET_NODEMASK: not implemented in GRSPW1 HW\n"); - } - break; - case SPACEWIRE_IOCTRL_SET_RXBLOCK: - SPACEWIRE_DBGC(DBGSPW_IOCTRL, "SPACEWIRE_IOCTRL_SET_RXBLOCK %i \n", (unsigned int)ioarg->buffer); - if ((unsigned int)ioarg->buffer > 1) { - return RTEMS_INVALID_NAME; - } - pDev->config.rx_blocking = (unsigned int)ioarg->buffer; - break; - case SPACEWIRE_IOCTRL_SET_DESTKEY: - SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_SET_DESTKEY %i\n", (unsigned int)ioarg->buffer); - if (!pDev->config.is_rmap) { - return RTEMS_NOT_IMPLEMENTED; - } - if ((unsigned int)ioarg->buffer > 255) { - return RTEMS_INVALID_NAME; - } - SPW_WRITE(&pDev->regs->destkey, (unsigned int)ioarg->buffer); - if (SPW_READ(&pDev->regs->destkey) != (unsigned int)ioarg->buffer) { - return RTEMS_IO_ERROR; - } - pDev->config.destkey = (unsigned int)ioarg->buffer; - break; - case SPACEWIRE_IOCTRL_SET_CLKDIV: - SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_SET_CLKDIV %i\n", (unsigned int)ioarg->buffer); - if ((unsigned int)ioarg->buffer > 255) { - return RTEMS_INVALID_NAME; - } - tmp = SPW_READ(&pDev->regs->clkdiv); - tmp &= ~0xff; /* Remove old Clockdiv Setting */ - tmp |= ((unsigned int)ioarg->buffer) & 0xff; /* add new clockdiv setting */ - SPW_WRITE(&pDev->regs->clkdiv, tmp); - if (SPW_READ(&pDev->regs->clkdiv) != tmp) { - return RTEMS_IO_ERROR; - } - pDev->config.clkdiv = tmp; - break; - case SPACEWIRE_IOCTRL_SET_CLKDIVSTART: - SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_SET_CLKDIVSTART %i\n", (unsigned int)ioarg->buffer); - if ((unsigned int)ioarg->buffer > 255) { - return RTEMS_INVALID_NAME; - } - tmp = SPW_READ(&pDev->regs->clkdiv); - tmp &= ~0xff00; /* Remove old Clockdiv Start Setting */ - tmp |= (((unsigned int)ioarg->buffer) & 0xff)<<8; /* add new clockdiv start setting */ - SPW_WRITE(&pDev->regs->clkdiv, tmp); - if (SPW_READ(&pDev->regs->clkdiv) != tmp) { - return RTEMS_IO_ERROR; - } - pDev->config.clkdiv = tmp; - break; - case SPACEWIRE_IOCTRL_SET_TIMER: - SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_SET_TIMER %i\n", (unsigned int)ioarg->buffer); - if ( pDev->core_ver <= 1 ) { - if ((unsigned int)ioarg->buffer > 4095) { - return RTEMS_INVALID_NAME; - } - SPW_WRITE(&pDev->regs->timer, (SPW_READ(&pDev->regs->timer) & 0xFFFFF000) | ((unsigned int)ioarg->buffer & 0xFFF)); - if ((SPW_READ(&pDev->regs->timer) & 0xFFF) != (unsigned int)ioarg->buffer) { - return RTEMS_IO_ERROR; - } - pDev->config.timer = (unsigned int)ioarg->buffer; - }else{ - SPACEWIRE_DBG("SPACEWIRE_IOCTRL_SET_TIMER: removed in GRSPW2 HW\n"); - } - break; - case SPACEWIRE_IOCTRL_SET_DISCONNECT: - SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_SET_DISCONNECT %i\n", (unsigned int)ioarg->buffer); - if ( pDev->core_ver <= 1 ) { - if ((unsigned int)ioarg->buffer > 1023) { - return RTEMS_INVALID_NAME; - } - SPW_WRITE(&pDev->regs->timer, (SPW_READ(&pDev->regs->timer) & 0xFFC00FFF) | (((unsigned int)ioarg->buffer & 0x3FF) << 12)); - if (((SPW_READ(&pDev->regs->timer) >> 12) & 0x3FF) != (unsigned int)ioarg->buffer) { - return RTEMS_IO_ERROR; - } - pDev->config.disconnect = (unsigned int)ioarg->buffer; - }else{ - SPACEWIRE_DBG("SPACEWIRE_IOCTRL_SET_DISCONNECT: not implemented for GRSPW2\n"); - } - break; - case SPACEWIRE_IOCTRL_SET_PROMISCUOUS: - SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_SET_PROMISCUOUS %i \n", (unsigned int)ioarg->buffer); - if ((unsigned int)ioarg->buffer > 1) { - return RTEMS_INVALID_NAME; - } - SPW_CTRL_WRITE(pDev, SPW_CTRL_READ(pDev) | ((unsigned int)ioarg->buffer << 5)); - if (((SPW_CTRL_READ(pDev) >> 5) & 1) != (unsigned int)ioarg->buffer) { - return RTEMS_IO_ERROR; - } - pDev->config.promiscuous = (unsigned int)ioarg->buffer; - break; - case SPACEWIRE_IOCTRL_SET_RMAPEN: - SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_SET_RMAPEN %i \n", (unsigned int)ioarg->buffer); - if ((unsigned int)ioarg->buffer > 1) { - return RTEMS_INVALID_NAME; - } - SPW_CTRL_WRITE(pDev, (SPW_STATUS_READ(pDev) & 0xFFFEFFFF) | ((unsigned int)ioarg->buffer << 16)); - if (((SPW_CTRL_READ(pDev) >> 16) & 1) != (unsigned int)ioarg->buffer) { - return RTEMS_IO_ERROR; - } - pDev->config.rmapen = (unsigned int)ioarg->buffer; - break; - case SPACEWIRE_IOCTRL_SET_RMAPBUFDIS: - SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_SET_RMAPBUFDIS %i \n", (unsigned int)ioarg->buffer); - if ((unsigned int)ioarg->buffer > 1) { - return RTEMS_INVALID_NAME; - } - SPW_CTRL_WRITE(pDev, (SPW_STATUS_READ(pDev) & 0xFFFDFFFF) | ((unsigned int)ioarg->buffer << 17)); - if (((SPW_CTRL_READ(pDev) >> 17) & 1) != (unsigned int)ioarg->buffer) { - return RTEMS_IO_ERROR; - } - pDev->config.rmapbufdis = (unsigned int)ioarg->buffer; - break; - case SPACEWIRE_IOCTRL_SET_CHECK_RMAP: - SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_SET_CHECK_RMAP %i \n", (unsigned int)ioarg->buffer); - if ((unsigned int)ioarg->buffer > 1) { - return RTEMS_INVALID_NAME; - } - pDev->config.check_rmap_err = (unsigned int)ioarg->buffer; - break; - case SPACEWIRE_IOCTRL_SET_RM_PROT_ID: - SPACEWIRE_DBGC(DBGSPW_IOCTRL, "SPACEWIRE_IOCTRL_SET_RM_PROT_ID %i \n", (unsigned int)ioarg->buffer); - if ((unsigned int)ioarg->buffer > 1) { - return RTEMS_INVALID_NAME; - } - pDev->config.rm_prot_id = (unsigned int)ioarg->buffer; - break; - case SPACEWIRE_IOCTRL_SET_TXBLOCK: - SPACEWIRE_DBGC(DBGSPW_IOCTRL, "SPACEWIRE_IOCTRL_SET_TXBLOCK %i \n", (unsigned int)ioarg->buffer); - if ((unsigned int)ioarg->buffer > 1) { - return RTEMS_INVALID_NAME; - } - pDev->config.tx_blocking = (unsigned int)ioarg->buffer; - break; - case SPACEWIRE_IOCTRL_SET_TXBLOCK_ON_FULL: - SPACEWIRE_DBGC(DBGSPW_IOCTRL, "SPACEWIRE_IOCTRL_SET_TXBLOCK_ON_FULL %i \n", (unsigned int)ioarg->buffer); - if ((unsigned int)ioarg->buffer > 1) { - return RTEMS_INVALID_NAME; - } - pDev->config.tx_block_on_full = (unsigned int)ioarg->buffer; - break; - case SPACEWIRE_IOCTRL_SET_DISABLE_ERR: - SPACEWIRE_DBGC(DBGSPW_IOCTRL, "SPACEWIRE_IOCTRL_SET_DISABLE_ERR %i \n", (unsigned int)ioarg->buffer); - if ((unsigned int)ioarg->buffer > 1) { - return RTEMS_INVALID_NAME; - } - pDev->config.disable_err = (unsigned int)ioarg->buffer; - break; - case SPACEWIRE_IOCTRL_SET_LINK_ERR_IRQ: - SPACEWIRE_DBGC(DBGSPW_IOCTRL, "SPACEWIRE_IOCTRL_SET_LINK_ERR_IRQ %i \n", (unsigned int)ioarg->buffer); - SPACEWIRE_DBGC(DBGSPW_IOCTRL, "CTRL REG: %x\n", SPW_CTRL_READ(pDev)); - if ((unsigned int)ioarg->buffer > 1) { - return RTEMS_INVALID_NAME; - } - SPW_CTRL_WRITE(pDev, (SPW_CTRL_READ(pDev) & 0xFFFFFDF7) | ((unsigned int)ioarg->buffer << 9) | (pDev->config.link_err_irq << 3)); - SPACEWIRE_DBGC(DBGSPW_IOCTRL, "CTRL REG: %x\n", SPW_CTRL_READ(pDev)); - if (((SPW_CTRL_READ(pDev) >> 9) & 1) != (unsigned int)ioarg->buffer) { - return RTEMS_IO_ERROR; - } - pDev->config.link_err_irq = (unsigned int)ioarg->buffer; - break; - case SPACEWIRE_IOCTRL_SET_EVENT_ID: - SPACEWIRE_DBGC(DBGSPW_IOCTRL, "SPACEWIRE_IOCTRL_SET_EVENT_ID %i \n", (unsigned int)ioarg->buffer); - pDev->config.event_id = (rtems_id)ioarg->buffer; - SPACEWIRE_DBGC(DBGSPW_IOCTRL, "Event id: %i\n", pDev->config.event_id); - break; - - /* Change MAX Packet size by: - * - stop RX/TX (if on) - * - wait for hw to complete RX DMA (if on) - * - reallocate buffers with new size - * - tell hw about new size & start RX/TX again (if previously on) - */ - case SPACEWIRE_IOCTRL_SET_PACKETSIZE: - if (ioarg->buffer == NULL) - return RTEMS_INVALID_NAME; - ps = (spw_ioctl_packetsize*) ioarg->buffer; - SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_SET_RXPACKETSIZE %i \n", (unsigned int)ioarg->buffer); - - tmp = pDev->running; - - if ( pDev->running ){ - /* Stop RX */ - grspw_hw_stop(pDev,1,1); - - /* If packetsize fails it is good to know if in running mode */ - pDev->running = 0; - - /* Wait for Receiver to finnish pending DMA transfers if any */ - grspw_hw_wait_rx_inactive(pDev); - } - - /* Save new buffer sizes */ - pDev->rxbufsize = ps->rxsize; - pDev->txdbufsize = ps->txdsize; - pDev->txhbufsize = ps->txhsize; - pDev->config.rxmaxlen = pDev->rxbufsize; - - /* Free previous buffers & allocate buffers with new size */ - if (grspw_buffer_alloc(pDev)) - return RTEMS_NO_MEMORY; - - /* if RX was actived before, we reactive it again */ - if ( tmp ) { - if ( (status = grspw_hw_startup(pDev,-1)) != RTEMS_SUCCESSFUL ) { - return status; - } - pDev->running = 1; - } + spw_ioctl_pkt_send *args; + spw_ioctl_packetsize *ps; + int status; + unsigned int tmp,mask,nodeaddr,nodemask; + int timeout; + rtems_device_driver ret; + rtems_libio_ioctl_args_t *ioarg = (rtems_libio_ioctl_args_t *) arg; + GRSPW_DEV *pDev; + struct drvmgr_dev *dev; + + SPACEWIRE_DBGC(DBGSPW_IOCALLS, "ctrl [%i,%i]\n", major, minor); + + if ( drvmgr_get_dev(&grspw_drv_info.general, minor, &dev) ) { + return RTEMS_INVALID_NAME; + } + pDev = (GRSPW_DEV *)dev->priv; + + if (!ioarg) + return RTEMS_INVALID_NAME; + + ioarg->ioctl_return = 0; + switch(ioarg->command) { + case SPACEWIRE_IOCTRL_SET_NODEADDR: + /*set node address*/ + SPACEWIRE_DBGC(DBGSPW_IOCTRL, "SPACEWIRE_IOCTRL_SET_NODEADDR %i\n",(unsigned int)ioarg->buffer); + if ((unsigned int)ioarg->buffer > 255) { + return RTEMS_INVALID_NAME; + } + nodeaddr = ((unsigned int)ioarg->buffer) & 0xff; + tmp = SPW_READ(&pDev->regs->nodeaddr); + tmp &= 0xffffff00; /* Remove old address */ + tmp |= nodeaddr; + SPW_WRITE(&pDev->regs->nodeaddr, tmp); + if ((SPW_READ(&pDev->regs->nodeaddr)&0xff) != nodeaddr) { + return RTEMS_IO_ERROR; + } + pDev->config.nodeaddr = nodeaddr; + break; + case SPACEWIRE_IOCTRL_SET_NODEMASK: + /*set node address*/ + SPACEWIRE_DBGC(DBGSPW_IOCTRL, "SPACEWIRE_IOCTRL_SET_NODEMASK %i\n",(unsigned int)ioarg->buffer); + if ( pDev->core_ver > 1 ){ + if ((unsigned int)ioarg->buffer > 255) { + return RTEMS_INVALID_NAME; + } + nodemask = ((unsigned int)ioarg->buffer) & 0xff; + tmp = SPW_READ(&pDev->regs->nodeaddr); + tmp &= 0xffff00ff; /* Remove old mask */ + tmp |= nodemask<<8; + SPW_WRITE(&pDev->regs->nodeaddr, tmp); + if (((SPW_READ(&pDev->regs->nodeaddr)>>8)&0xff) != nodemask) { + return RTEMS_IO_ERROR; + } + pDev->config.nodemask = nodemask; + }else{ + SPACEWIRE_DBG("SPACEWIRE_IOCTRL_SET_NODEMASK: not implemented in GRSPW1 HW\n"); + } + break; + case SPACEWIRE_IOCTRL_SET_RXBLOCK: + SPACEWIRE_DBGC(DBGSPW_IOCTRL, "SPACEWIRE_IOCTRL_SET_RXBLOCK %i \n", (unsigned int)ioarg->buffer); + if ((unsigned int)ioarg->buffer > 1) { + return RTEMS_INVALID_NAME; + } + pDev->config.rx_blocking = (unsigned int)ioarg->buffer; + break; + case SPACEWIRE_IOCTRL_SET_DESTKEY: + SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_SET_DESTKEY %i\n", (unsigned int)ioarg->buffer); + if (!pDev->config.is_rmap) { + return RTEMS_NOT_IMPLEMENTED; + } + if ((unsigned int)ioarg->buffer > 255) { + return RTEMS_INVALID_NAME; + } + SPW_WRITE(&pDev->regs->destkey, (unsigned int)ioarg->buffer); + if (SPW_READ(&pDev->regs->destkey) != (unsigned int)ioarg->buffer) { + return RTEMS_IO_ERROR; + } + pDev->config.destkey = (unsigned int)ioarg->buffer; + break; + case SPACEWIRE_IOCTRL_SET_CLKDIV: + SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_SET_CLKDIV %i\n", (unsigned int)ioarg->buffer); + if ((unsigned int)ioarg->buffer > 255) { + return RTEMS_INVALID_NAME; + } + if ( pDev->core_ver == 3 ) + break; + tmp = SPW_READ(&pDev->regs->clkdiv); + tmp &= ~0xff; /* Remove old Clockdiv Setting */ + tmp |= ((unsigned int)ioarg->buffer) & 0xff; /* add new clockdiv setting */ + SPW_WRITE(&pDev->regs->clkdiv, tmp); + if (SPW_READ(&pDev->regs->clkdiv) != tmp) { + return RTEMS_IO_ERROR; + } + pDev->config.clkdiv = tmp; + break; + case SPACEWIRE_IOCTRL_SET_CLKDIVSTART: + SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_SET_CLKDIVSTART %i\n", (unsigned int)ioarg->buffer); + if ((unsigned int)ioarg->buffer > 255) { + return RTEMS_INVALID_NAME; + } + if ( pDev->core_ver == 3 ) + break; + tmp = SPW_READ(&pDev->regs->clkdiv); + tmp &= ~0xff00; /* Remove old Clockdiv Start Setting */ + tmp |= (((unsigned int)ioarg->buffer) & 0xff)<<8; /* add new clockdiv start setting */ + SPW_WRITE(&pDev->regs->clkdiv, tmp); + if (SPW_READ(&pDev->regs->clkdiv) != tmp) { + return RTEMS_IO_ERROR; + } + pDev->config.clkdiv = tmp; + break; + case SPACEWIRE_IOCTRL_SET_TIMER: + SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_SET_TIMER %i\n", (unsigned int)ioarg->buffer); + if ( pDev->core_ver <= 1 ) { + if ((unsigned int)ioarg->buffer > 4095) { + return RTEMS_INVALID_NAME; + } + SPW_WRITE(&pDev->regs->timer, (SPW_READ(&pDev->regs->timer) & 0xFFFFF000) | ((unsigned int)ioarg->buffer & 0xFFF)); + if ((SPW_READ(&pDev->regs->timer) & 0xFFF) != (unsigned int)ioarg->buffer) { + return RTEMS_IO_ERROR; + } + pDev->config.timer = (unsigned int)ioarg->buffer; + }else{ + SPACEWIRE_DBG("SPACEWIRE_IOCTRL_SET_TIMER: removed in GRSPW2 HW\n"); + } + break; + case SPACEWIRE_IOCTRL_SET_DISCONNECT: + SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_SET_DISCONNECT %i\n", (unsigned int)ioarg->buffer); + if ( pDev->core_ver <= 1 ) { + if ((unsigned int)ioarg->buffer > 1023) { + return RTEMS_INVALID_NAME; + } + SPW_WRITE(&pDev->regs->timer, (SPW_READ(&pDev->regs->timer) & 0xFFC00FFF) | (((unsigned int)ioarg->buffer & 0x3FF) << 12)); + if (((SPW_READ(&pDev->regs->timer) >> 12) & 0x3FF) != (unsigned int)ioarg->buffer) { + return RTEMS_IO_ERROR; + } + pDev->config.disconnect = (unsigned int)ioarg->buffer; + }else{ + SPACEWIRE_DBG("SPACEWIRE_IOCTRL_SET_DISCONNECT: not implemented for GRSPW2\n"); + } + break; + case SPACEWIRE_IOCTRL_SET_PROMISCUOUS: + SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_SET_PROMISCUOUS %i \n", (unsigned int)ioarg->buffer); + if ((unsigned int)ioarg->buffer > 1) { + return RTEMS_INVALID_NAME; + } + SPW_CTRL_WRITE(pDev, SPW_CTRL_READ(pDev) | ((unsigned int)ioarg->buffer << 5)); + if (((SPW_CTRL_READ(pDev) >> 5) & 1) != (unsigned int)ioarg->buffer) { + return RTEMS_IO_ERROR; + } + pDev->config.promiscuous = (unsigned int)ioarg->buffer; + break; + case SPACEWIRE_IOCTRL_SET_RMAPEN: + SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_SET_RMAPEN %i \n", (unsigned int)ioarg->buffer); + if ((unsigned int)ioarg->buffer > 1) { + return RTEMS_INVALID_NAME; + } + SPW_CTRL_WRITE(pDev, (SPW_STATUS_READ(pDev) & 0xFFFEFFFF) | ((unsigned int)ioarg->buffer << 16)); + if (((SPW_CTRL_READ(pDev) >> 16) & 1) != (unsigned int)ioarg->buffer) { + return RTEMS_IO_ERROR; + } + pDev->config.rmapen = (unsigned int)ioarg->buffer; + break; + case SPACEWIRE_IOCTRL_SET_RMAPBUFDIS: + SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_SET_RMAPBUFDIS %i \n", (unsigned int)ioarg->buffer); + if ((unsigned int)ioarg->buffer > 1) { + return RTEMS_INVALID_NAME; + } + SPW_CTRL_WRITE(pDev, (SPW_STATUS_READ(pDev) & 0xFFFDFFFF) | ((unsigned int)ioarg->buffer << 17)); + if (((SPW_CTRL_READ(pDev) >> 17) & 1) != (unsigned int)ioarg->buffer) { + return RTEMS_IO_ERROR; + } + pDev->config.rmapbufdis = (unsigned int)ioarg->buffer; + break; + case SPACEWIRE_IOCTRL_SET_CHECK_RMAP: + SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_SET_CHECK_RMAP %i \n", (unsigned int)ioarg->buffer); + if ((unsigned int)ioarg->buffer > 1) { + return RTEMS_INVALID_NAME; + } + pDev->config.check_rmap_err = (unsigned int)ioarg->buffer; + break; + case SPACEWIRE_IOCTRL_SET_RM_PROT_ID: + SPACEWIRE_DBGC(DBGSPW_IOCTRL, "SPACEWIRE_IOCTRL_SET_RM_PROT_ID %i \n", (unsigned int)ioarg->buffer); + if ((unsigned int)ioarg->buffer > 1) { + return RTEMS_INVALID_NAME; + } + pDev->config.rm_prot_id = (unsigned int)ioarg->buffer; + break; + case SPACEWIRE_IOCTRL_SET_KEEP_SOURCE: + SPACEWIRE_DBGC(DBGSPW_IOCTRL, "SPACEWIRE_IOCTRL_SET_KEEP_SOURCE %i \n", (unsigned int)ioarg->buffer); + if ((unsigned int)ioarg->buffer > 1) { + return RTEMS_INVALID_NAME; + } + pDev->config.keep_source = (unsigned int)ioarg->buffer; + break; + case SPACEWIRE_IOCTRL_SET_TXBLOCK: + SPACEWIRE_DBGC(DBGSPW_IOCTRL, "SPACEWIRE_IOCTRL_SET_TXBLOCK %i \n", (unsigned int)ioarg->buffer); + if ((unsigned int)ioarg->buffer > 1) { + return RTEMS_INVALID_NAME; + } + pDev->config.tx_blocking = (unsigned int)ioarg->buffer; + break; + case SPACEWIRE_IOCTRL_SET_TXBLOCK_ON_FULL: + SPACEWIRE_DBGC(DBGSPW_IOCTRL, "SPACEWIRE_IOCTRL_SET_TXBLOCK_ON_FULL %i \n", (unsigned int)ioarg->buffer); + if ((unsigned int)ioarg->buffer > 1) { + return RTEMS_INVALID_NAME; + } + pDev->config.tx_block_on_full = (unsigned int)ioarg->buffer; + break; + case SPACEWIRE_IOCTRL_SET_DISABLE_ERR: + SPACEWIRE_DBGC(DBGSPW_IOCTRL, "SPACEWIRE_IOCTRL_SET_DISABLE_ERR %i \n", (unsigned int)ioarg->buffer); + if ((unsigned int)ioarg->buffer > 1) { + return RTEMS_INVALID_NAME; + } + pDev->config.disable_err = (unsigned int)ioarg->buffer; + break; + case SPACEWIRE_IOCTRL_SET_LINK_ERR_IRQ: + SPACEWIRE_DBGC(DBGSPW_IOCTRL, "SPACEWIRE_IOCTRL_SET_LINK_ERR_IRQ %i \n", (unsigned int)ioarg->buffer); + SPACEWIRE_DBGC(DBGSPW_IOCTRL, "CTRL REG: %x\n", SPW_CTRL_READ(pDev)); + if ((unsigned int)ioarg->buffer > 1) { + return RTEMS_INVALID_NAME; + } + tmp = (SPW_CTRL_READ(pDev) & 0xFFFFFDF7) | ((unsigned int)ioarg->buffer << 9); + if (tmp & (SPW_CTRL_LI|SPW_CTRL_TQ)) + tmp |= SPW_CTRL_IE; + SPW_CTRL_WRITE(pDev, tmp); + SPACEWIRE_DBGC(DBGSPW_IOCTRL, "CTRL REG: %x\n", SPW_CTRL_READ(pDev)); + if (((SPW_CTRL_READ(pDev) >> 9) & 1) != (unsigned int)ioarg->buffer) { + return RTEMS_IO_ERROR; + } + pDev->config.link_err_irq = (unsigned int)ioarg->buffer; + break; + case SPACEWIRE_IOCTRL_SET_EVENT_ID: + SPACEWIRE_DBGC(DBGSPW_IOCTRL, "SPACEWIRE_IOCTRL_SET_EVENT_ID %i \n", (unsigned int)ioarg->buffer); + pDev->config.event_id = (rtems_id)ioarg->buffer; + SPACEWIRE_DBGC(DBGSPW_IOCTRL, "Event id: %i\n", pDev->config.event_id); + break; + + /* Change MAX Packet size by: + * - stop RX/TX (if on) + * - wait for hw to complete RX DMA (if on) + * - reallocate buffers with new size + * - tell hw about new size & start RX/TX again (if previously on) + */ + case SPACEWIRE_IOCTRL_SET_PACKETSIZE: + if (ioarg->buffer == NULL) + return RTEMS_INVALID_NAME; + ps = (spw_ioctl_packetsize*) ioarg->buffer; + SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_SET_RXPACKETSIZE %i \n", (unsigned int)ioarg->buffer); + + tmp = pDev->running; + + if ( pDev->running ){ + /* Stop RX */ + grspw_hw_stop(pDev,1,1); + + /* If packetsize fails it is good to know if in running mode */ + pDev->running = 0; + + /* Wait for Receiver to finnish pending DMA transfers if any */ + grspw_hw_wait_rx_inactive(pDev); + } + + /* Save new buffer sizes */ + pDev->rxbufsize = ps->rxsize; + pDev->txdbufsize = ps->txdsize; + pDev->txhbufsize = ps->txhsize; + pDev->config.rxmaxlen = pDev->rxbufsize; + + /* Free previous buffers & allocate buffers with new size */ + if (grspw_buffer_alloc(pDev)) + return RTEMS_NO_MEMORY; + + /* if RX was actived before, we reactive it again */ + if ( tmp ) { + if ( (status = grspw_hw_startup(pDev,-1)) != RTEMS_SUCCESSFUL ) { + return status; + } + pDev->running = 1; + } #if 0 - /* Rewrite previous config which was wasted due to reset in hw_startup */ - SPW_WRITE(&pDev->regs->nodeaddr, pDev->config.nodeaddr); - SPW_WRITE(&pDev->regs->destkey, pDev->config.destkey); - SPW_WRITE(&pDev->regs->clkdiv, pDev->config.clkdiv); - SPW_WRITE(&pDev->regs->timer, pDev->config.timer | ( (pDev->config.disconnect & 0x3FF) << 12) ); - SPW_CTRL_WRITE(pDev, (SPW_CTRL_READ(pDev) & !(SPW_CTRL_LINKSTART | SPW_CTRL_PM | SPW_CTRL_RE | SPW_CTRL_RD | SPW_CTRL_TT | SPW_CTRL_TR)) | \ - (pDev->config.promiscuous << 5) | (pDev->config.rmapen << 16) | (pDev->config.rmapbufdis << 17) | \ - (pDev->config.linkdisabled) | (pDev->config.linkstart << 1)); + /* Rewrite previous config which was wasted due to reset in hw_startup */ + SPW_WRITE(&pDev->regs->nodeaddr, pDev->config.nodeaddr); + SPW_WRITE(&pDev->regs->destkey, pDev->config.destkey); + SPW_WRITE(&pDev->regs->clkdiv, pDev->config.clkdiv); + SPW_WRITE(&pDev->regs->timer, pDev->config.timer | ( (pDev->config.disconnect & 0x3FF) << 12) ); + SPW_CTRL_WRITE(pDev, (SPW_CTRL_READ(pDev) & !(SPW_CTRL_LINKSTART | SPW_CTRL_PM | SPW_CTRL_RE | SPW_CTRL_RD | SPW_CTRL_TT | SPW_CTRL_TR)) | \ + (pDev->config.promiscuous << 5) | (pDev->config.rmapen << 16) | (pDev->config.rmapbufdis << 17) | \ + (pDev->config.linkdisabled) | (pDev->config.linkstart << 1)); #endif - break; - case SPACEWIRE_IOCTRL_GET_CONFIG: - if (ioarg->buffer == NULL) - return RTEMS_INVALID_NAME; - SPACEWIRE_DBG2("SPACEWIRE_IOCTRL_GET_CONFIG \n"); - (*(spw_config *)ioarg->buffer).nodeaddr = pDev->config.nodeaddr; - (*(spw_config *)ioarg->buffer).nodemask = pDev->config.nodemask; - (*(spw_config *)ioarg->buffer).destkey = pDev->config.destkey; - (*(spw_config *)ioarg->buffer).clkdiv = pDev->config.clkdiv; - (*(spw_config *)ioarg->buffer).rxmaxlen = pDev->config.rxmaxlen; - (*(spw_config *)ioarg->buffer).timer = pDev->config.timer; - (*(spw_config *)ioarg->buffer).disconnect = pDev->config.disconnect; - (*(spw_config *)ioarg->buffer).promiscuous = pDev->config.promiscuous; - (*(spw_config *)ioarg->buffer).rmapen = pDev->config.rmapen; - (*(spw_config *)ioarg->buffer).rmapbufdis = pDev->config.rmapbufdis; - (*(spw_config *)ioarg->buffer).check_rmap_err = pDev->config.check_rmap_err; - (*(spw_config *)ioarg->buffer).rm_prot_id = pDev->config.rm_prot_id; - (*(spw_config *)ioarg->buffer).tx_blocking = pDev->config.tx_blocking; - (*(spw_config *)ioarg->buffer).disable_err = pDev->config.disable_err; - (*(spw_config *)ioarg->buffer).link_err_irq = pDev->config.link_err_irq; - (*(spw_config *)ioarg->buffer).event_id = pDev->config.event_id; - (*(spw_config *)ioarg->buffer).is_rmap = pDev->config.is_rmap; - (*(spw_config *)ioarg->buffer).is_rmapcrc = pDev->config.is_rmapcrc; - (*(spw_config *)ioarg->buffer).is_rxunaligned = pDev->config.is_rxunaligned; - (*(spw_config *)ioarg->buffer).linkdisabled = pDev->config.linkdisabled; - (*(spw_config *)ioarg->buffer).linkstart = pDev->config.linkstart; - (*(spw_config *)ioarg->buffer).rx_blocking = pDev->config.rx_blocking; - (*(spw_config *)ioarg->buffer).tx_block_on_full = pDev->config.tx_block_on_full; - break; - case SPACEWIRE_IOCTRL_GET_LINK_STATUS: - SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_GET_STATUS=%i \n", (unsigned int)((SPW_STATUS_READ(pDev) >> 21) & 0x7)); - *(unsigned int *)ioarg->buffer = (unsigned int )((SPW_STATUS_READ(pDev) >> 21) & 0x7); - break; - case SPACEWIRE_IOCTRL_GET_STATISTICS: - if (ioarg->buffer == NULL) - return RTEMS_INVALID_NAME; - SPACEWIRE_DBG2("SPACEWIRE_IOCTRL_GET_STATISTICS \n"); - (*(spw_stats *)ioarg->buffer).tx_link_err = pDev->stat.tx_link_err; - (*(spw_stats *)ioarg->buffer).rx_rmap_header_crc_err = pDev->stat.rx_rmap_header_crc_err; - (*(spw_stats *)ioarg->buffer).rx_rmap_data_crc_err = pDev->stat.rx_rmap_data_crc_err; - (*(spw_stats *)ioarg->buffer).rx_eep_err = pDev->stat.rx_eep_err; - (*(spw_stats *)ioarg->buffer).rx_truncated = pDev->stat.rx_truncated; - (*(spw_stats *)ioarg->buffer).parity_err = pDev->stat.parity_err; - (*(spw_stats *)ioarg->buffer).escape_err = pDev->stat.escape_err; - (*(spw_stats *)ioarg->buffer).credit_err = pDev->stat.credit_err; - (*(spw_stats *)ioarg->buffer).write_sync_err = pDev->stat.write_sync_err; - (*(spw_stats *)ioarg->buffer).disconnect_err = pDev->stat.disconnect_err; - (*(spw_stats *)ioarg->buffer).early_ep = pDev->stat.early_ep; - (*(spw_stats *)ioarg->buffer).invalid_address = pDev->stat.invalid_address; - (*(spw_stats *)ioarg->buffer).packets_sent = pDev->stat.packets_sent; - (*(spw_stats *)ioarg->buffer).packets_received = pDev->stat.packets_received; - break; - case SPACEWIRE_IOCTRL_CLR_STATISTICS: - SPACEWIRE_DBG2("SPACEWIRE_IOCTRL_CLR_STATISTICS \n"); - pDev->stat.tx_link_err = 0; - pDev->stat.rx_rmap_header_crc_err = 0; - pDev->stat.rx_rmap_data_crc_err = 0; - pDev->stat.rx_eep_err = 0; - pDev->stat.rx_truncated = 0; - pDev->stat.parity_err = 0; - pDev->stat.escape_err = 0; - pDev->stat.credit_err = 0; - pDev->stat.write_sync_err = 0; - pDev->stat.disconnect_err = 0; - pDev->stat.early_ep = 0; - pDev->stat.invalid_address = 0; - pDev->stat.packets_sent = 0; - pDev->stat.packets_received = 0; - break; - case SPACEWIRE_IOCTRL_SEND: - if (ioarg->buffer == NULL) - return RTEMS_INVALID_NAME; - args = (spw_ioctl_pkt_send *)ioarg->buffer; - args->sent = 0; - - /* is link up? */ - if ( !pDev->running ) { - return RTEMS_INVALID_NAME; - } - - SPACEWIRE_DBGC(DBGSPW_IOCALLS, "write [%i,%i]: hlen: %i hbuf:0x%x dlen:%i dbuf:0x%x\n", major, minor, - (unsigned int)args->hlen, (int)args->hdr,(unsigned int)args->dlen, (int)args->data); - - if ((args->hlen > pDev->txhbufsize) || (args->dlen > pDev->txdbufsize) || - ((args->hlen+args->dlen) < 1) || - ((args->hdr == NULL) && (args->hlen != 0)) || ((args->data == NULL) && (args->dlen != 0))) { - return RTEMS_INVALID_NAME; - } - while ((args->sent = grspw_hw_send(pDev, args->hlen, args->hdr, args->dlen, args->data)) == 0) { - if (pDev->config.tx_block_on_full == 1) { - SPACEWIRE_DBG2("Tx Block on full \n"); - rtems_semaphore_obtain(pDev->txsp, RTEMS_WAIT, RTEMS_NO_TIMEOUT); - } else { - SPACEWIRE_DBG2("Tx non blocking return when full \n"); - return RTEMS_RESOURCE_IN_USE; - } - } - SPACEWIRE_DBGC(DBGSPW_IOCALLS, "Tx ioctl return: %i \n", args->sent); - break; - - case SPACEWIRE_IOCTRL_LINKDISABLE: - pDev->config.linkdisabled = 1; - pDev->config.linkstart = 0; - SPW_CTRL_WRITE(pDev, (SPW_CTRL_READ(pDev) & 0xFFFFFFFC) | 1); - if ((SPW_CTRL_READ(pDev) & 3) != 1) { - return RTEMS_IO_ERROR; - } - break; - - case SPACEWIRE_IOCTRL_LINKSTART: - pDev->config.linkdisabled = 0; - pDev->config.linkstart = 1; - SPW_CTRL_WRITE(pDev, (SPW_CTRL_READ(pDev) & 0xFFFFFFFC) | 2); - if ((SPW_CTRL_READ(pDev) & 3) != 2) { - return RTEMS_IO_ERROR; - } - break; - - /* Calculate timer register from GRSPW Core frequency - * Also possible to set disconnect and timer64 from - * - SPACEWIRE_IOCTRL_SET_DISCONNECT - * - SPACEWIRE_IOCTRL_SET_TIMER - */ - case SPACEWIRE_IOCTRL_SET_COREFREQ: - pDev->core_freq_khz = (unsigned int)ioarg->buffer; - if ( pDev->core_freq_khz == 0 ){ - /* Get GRSPW clock frequency from system clock. - * System clock has been read from timer inited - * by RTEMS loader (mkprom) - */ - pDev->core_freq_khz = sys_freq_khz; - } - - /* Only GRSPW1 needs the Timer64 and Disconnect values - * GRSPW2 and onwards doesn't have this register. - */ - if ( pDev->core_ver <= 1 ){ - /* Calculate Timer64 & Disconnect */ - pDev->config.timer = grspw_calc_timer64(pDev->core_freq_khz); - pDev->config.disconnect = grspw_calc_disconnect(pDev->core_freq_khz); - - /* Set Timer64 & Disconnect Register */ - SPW_WRITE(&pDev->regs->timer, - (SPW_READ(&pDev->regs->timer) & 0xFFC00000) | - ((pDev->config.disconnect & 0x3FF)<<12) | - (pDev->config.timer & 0xFFF)); - - /* Check that the registers were written successfully */ - tmp = SPW_READ(&pDev->regs->timer) & 0x003fffff; - if ( ((tmp & 0xFFF) != pDev->config.timer) || - (((tmp >> 12) & 0x3FF) != pDev->config.disconnect) ) { - return RTEMS_IO_ERROR; - } - } - break; - - case SPACEWIRE_IOCTRL_START: - if ( pDev->running ){ - return RTEMS_INVALID_NAME; - } - - /* Get timeout from userspace - * timeout: - * ¤ -1 = Default timeout - * ¤ less than -1 = forever - * ¤ 0 = no wait, proceed if link is up - * ¤ positive = specifies number of system clock ticks that - * startup will wait for link to enter ready mode. - */ - timeout = (int)ioarg->buffer; - - if ( (ret=grspw_hw_startup(pDev,timeout)) != RTEMS_SUCCESSFUL ) { - return ret; - } - pDev->running = 1; - break; - - case SPACEWIRE_IOCTRL_STOP: - if ( !pDev->running ){ - return RTEMS_INVALID_NAME; - } - pDev->running = 0; - - /* Stop Receiver and transmitter */ - grspw_hw_stop(pDev,1,1); - break; - - default: - return RTEMS_NOT_IMPLEMENTED; - } - - SPACEWIRE_DBGC(DBGSPW_IOCALLS, "SPW_IOCTRL Return\n"); - return RTEMS_SUCCESSFUL; + break; + case SPACEWIRE_IOCTRL_GET_CONFIG: + if (ioarg->buffer == NULL) + return RTEMS_INVALID_NAME; + SPACEWIRE_DBG2("SPACEWIRE_IOCTRL_GET_CONFIG \n"); + (*(spw_config *)ioarg->buffer).nodeaddr = pDev->config.nodeaddr; + (*(spw_config *)ioarg->buffer).nodemask = pDev->config.nodemask; + (*(spw_config *)ioarg->buffer).destkey = pDev->config.destkey; + (*(spw_config *)ioarg->buffer).clkdiv = pDev->config.clkdiv; + (*(spw_config *)ioarg->buffer).rxmaxlen = pDev->config.rxmaxlen; + (*(spw_config *)ioarg->buffer).timer = pDev->config.timer; + (*(spw_config *)ioarg->buffer).disconnect = pDev->config.disconnect; + (*(spw_config *)ioarg->buffer).promiscuous = pDev->config.promiscuous; + (*(spw_config *)ioarg->buffer).rmapen = pDev->config.rmapen; + (*(spw_config *)ioarg->buffer).rmapbufdis = pDev->config.rmapbufdis; + (*(spw_config *)ioarg->buffer).check_rmap_err = pDev->config.check_rmap_err; + (*(spw_config *)ioarg->buffer).rm_prot_id = pDev->config.rm_prot_id; + (*(spw_config *)ioarg->buffer).tx_blocking = pDev->config.tx_blocking; + (*(spw_config *)ioarg->buffer).disable_err = pDev->config.disable_err; + (*(spw_config *)ioarg->buffer).link_err_irq = pDev->config.link_err_irq; + (*(spw_config *)ioarg->buffer).event_id = pDev->config.event_id; + (*(spw_config *)ioarg->buffer).is_rmap = pDev->config.is_rmap; + (*(spw_config *)ioarg->buffer).is_rmapcrc = pDev->config.is_rmapcrc; + (*(spw_config *)ioarg->buffer).is_rxunaligned = pDev->config.is_rxunaligned; + (*(spw_config *)ioarg->buffer).linkdisabled = pDev->config.linkdisabled; + (*(spw_config *)ioarg->buffer).linkstart = pDev->config.linkstart; + (*(spw_config *)ioarg->buffer).rx_blocking = pDev->config.rx_blocking; + (*(spw_config *)ioarg->buffer).tx_block_on_full = pDev->config.tx_block_on_full; + (*(spw_config *)ioarg->buffer).keep_source = pDev->config.keep_source; + (*(spw_config *)ioarg->buffer).rtimeout = pDev->config.rtimeout; + break; + case SPACEWIRE_IOCTRL_GET_LINK_STATUS: + SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_GET_STATUS=%i \n", (unsigned int)((SPW_STATUS_READ(pDev) >> 21) & 0x7)); + *(unsigned int *)ioarg->buffer = (unsigned int )((SPW_STATUS_READ(pDev) >> 21) & 0x7); + break; + case SPACEWIRE_IOCTRL_GET_STATISTICS: + if (ioarg->buffer == NULL) + return RTEMS_INVALID_NAME; + SPACEWIRE_DBG2("SPACEWIRE_IOCTRL_GET_STATISTICS \n"); + (*(spw_stats *)ioarg->buffer).tx_link_err = pDev->stat.tx_link_err; + (*(spw_stats *)ioarg->buffer).rx_rmap_header_crc_err = pDev->stat.rx_rmap_header_crc_err; + (*(spw_stats *)ioarg->buffer).rx_rmap_data_crc_err = pDev->stat.rx_rmap_data_crc_err; + (*(spw_stats *)ioarg->buffer).rx_eep_err = pDev->stat.rx_eep_err; + (*(spw_stats *)ioarg->buffer).rx_truncated = pDev->stat.rx_truncated; + (*(spw_stats *)ioarg->buffer).parity_err = pDev->stat.parity_err; + (*(spw_stats *)ioarg->buffer).escape_err = pDev->stat.escape_err; + (*(spw_stats *)ioarg->buffer).credit_err = pDev->stat.credit_err; + (*(spw_stats *)ioarg->buffer).write_sync_err = pDev->stat.write_sync_err; + (*(spw_stats *)ioarg->buffer).disconnect_err = pDev->stat.disconnect_err; + (*(spw_stats *)ioarg->buffer).early_ep = pDev->stat.early_ep; + (*(spw_stats *)ioarg->buffer).invalid_address = pDev->stat.invalid_address; + (*(spw_stats *)ioarg->buffer).packets_sent = pDev->stat.packets_sent; + (*(spw_stats *)ioarg->buffer).packets_received = pDev->stat.packets_received; + break; + case SPACEWIRE_IOCTRL_CLR_STATISTICS: + SPACEWIRE_DBG2("SPACEWIRE_IOCTRL_CLR_STATISTICS \n"); + pDev->stat.tx_link_err = 0; + pDev->stat.rx_rmap_header_crc_err = 0; + pDev->stat.rx_rmap_data_crc_err = 0; + pDev->stat.rx_eep_err = 0; + pDev->stat.rx_truncated = 0; + pDev->stat.parity_err = 0; + pDev->stat.escape_err = 0; + pDev->stat.credit_err = 0; + pDev->stat.write_sync_err = 0; + pDev->stat.disconnect_err = 0; + pDev->stat.early_ep = 0; + pDev->stat.invalid_address = 0; + pDev->stat.packets_sent = 0; + pDev->stat.packets_received = 0; + break; + case SPACEWIRE_IOCTRL_SEND: + if (ioarg->buffer == NULL) + return RTEMS_INVALID_NAME; + args = (spw_ioctl_pkt_send *)ioarg->buffer; + args->sent = 0; + + /* is link up? */ + if ( !pDev->running ) { + return RTEMS_INVALID_NAME; + } + + SPACEWIRE_DBGC(DBGSPW_IOCALLS, "write [%i,%i]: hlen: %i hbuf:0x%x dlen:%i dbuf:0x%x\n", major, minor, + (unsigned int)args->hlen, (int)args->hdr,(unsigned int)args->dlen, (int)args->data); + + if ((args->hlen > pDev->txhbufsize) || (args->dlen > pDev->txdbufsize) || + ((args->hlen+args->dlen) < 1) || + ((args->hdr == NULL) && (args->hlen != 0)) || ((args->data == NULL) && (args->dlen != 0))) { + return RTEMS_INVALID_NAME; + } + while ((args->sent = grspw_hw_send(pDev, args->hlen, args->hdr, args->dlen, args->data, args->options)) == 0) { + if (pDev->config.tx_block_on_full == 1) { + SPACEWIRE_DBG2("Tx Block on full \n"); + rtems_semaphore_obtain(pDev->txsp, RTEMS_WAIT, RTEMS_NO_TIMEOUT); + } else { + SPACEWIRE_DBG2("Tx non blocking return when full \n"); + return RTEMS_RESOURCE_IN_USE; + } + } + SPACEWIRE_DBGC(DBGSPW_IOCALLS, "Tx ioctl return: %i \n", args->sent); + break; + + case SPACEWIRE_IOCTRL_LINKDISABLE: + pDev->config.linkdisabled = 1; + pDev->config.linkstart = 0; + if ( pDev->core_ver != 3 ) { + SPW_CTRL_WRITE(pDev, (SPW_CTRL_READ(pDev) & 0xFFFFFFFC) | 1); + if ((SPW_CTRL_READ(pDev) & 3) != 1) { + return RTEMS_IO_ERROR; + } + } + break; + + case SPACEWIRE_IOCTRL_LINKSTART: + pDev->config.linkdisabled = 0; + pDev->config.linkstart = 1; + if ( pDev->core_ver != 3 ) { + SPW_CTRL_WRITE(pDev, (SPW_CTRL_READ(pDev) & 0xFFFFFFFC) | 2); + if ((SPW_CTRL_READ(pDev) & 3) != 2) { + return RTEMS_IO_ERROR; + } + } + break; + + /* Calculate timer register from GRSPW Core frequency + * Also possible to set disconnect and timer64 from + * - SPACEWIRE_IOCTRL_SET_DISCONNECT + * - SPACEWIRE_IOCTRL_SET_TIMER + */ + case SPACEWIRE_IOCTRL_SET_COREFREQ: + pDev->core_freq_khz = (unsigned int)ioarg->buffer; + if ( pDev->core_freq_khz == 0 ){ + /* Get GRSPW clock frequency from system clock. + * System clock has been read from timer inited + * by RTEMS loader (mkprom) + */ + drvmgr_freq_get(pDev->dev, DEV_APB_SLV, + &pDev->core_freq_khz); + /* Convert from Hz -> kHz */ + pDev->core_freq_khz = pDev->core_freq_khz / 1000; + } + + /* Only GRSPW1 needs the Timer64 and Disconnect values + * GRSPW2 and onwards doesn't have this register. + */ + if ( pDev->core_ver <= 1 ){ + /* Calculate Timer64 & Disconnect */ + pDev->config.timer = grspw_calc_timer64(pDev->core_freq_khz); + pDev->config.disconnect = grspw_calc_disconnect(pDev->core_freq_khz); + + /* Set Timer64 & Disconnect Register */ + SPW_WRITE(&pDev->regs->timer, + (SPW_READ(&pDev->regs->timer) & 0xFFC00000) | + ((pDev->config.disconnect & 0x3FF)<<12) | + (pDev->config.timer & 0xFFF)); + + /* Check that the registers were written successfully */ + tmp = SPW_READ(&pDev->regs->timer) & 0x003fffff; + if ( ((tmp & 0xFFF) != pDev->config.timer) || + (((tmp >> 12) & 0x3FF) != pDev->config.disconnect) ) { + return RTEMS_IO_ERROR; + } + } + break; + + case SPACEWIRE_IOCTRL_START: + if ( pDev->running ){ + return RTEMS_INVALID_NAME; + } + + /* Get timeout from userspace + * timeout: + * ¤ -1 = Default timeout + * ¤ less than -1 = forever + * ¤ 0 = no wait, proceed if link is up + * ¤ positive = specifies number of system clock ticks that + * startup will wait for link to enter ready mode. + */ + timeout = (int)ioarg->buffer; + + if ( (ret=grspw_hw_startup(pDev,timeout)) != RTEMS_SUCCESSFUL ) { + return ret; + } + pDev->running = 1; + /* Register interrupt routine and unmask IRQ */ + drvmgr_interrupt_register(pDev->dev, 0, "grspw", grspw_interrupt, pDev); + + break; + + case SPACEWIRE_IOCTRL_STOP: + if ( !pDev->running ){ + return RTEMS_INVALID_NAME; + } + /* Disable interrupts */ + drvmgr_interrupt_unregister(dev, 0, grspw_interrupt, pDev); + + pDev->running = 0; + + /* Stop Receiver and transmitter */ + grspw_hw_stop(pDev,1,1); + break; + + /* Set time-code control register bits, and Enables/Disables + * Time code interrupt, make sure to connect the callback + * grspw_timecode_callback if using interrupts. + */ + case SPACEWIRE_IOCTRL_SET_TCODE_CTRL: + tmp = (unsigned int)ioarg->buffer; + mask = tmp & (SPACEWIRE_TCODE_CTRL_IE_MSK|SPACEWIRE_TCODE_CTRL_TT_MSK|SPACEWIRE_TCODE_CTRL_TR_MSK); + mask <<= 8; + tmp &= mask; + tmp = (SPW_CTRL_READ(pDev) & ~(mask | SPW_CTRL_IE)) | tmp; + if (tmp & (SPW_CTRL_LI|SPW_CTRL_TQ)) + tmp |= SPW_CTRL_IE; + SPW_CTRL_WRITE(pDev, tmp); + break; + + /* Set time register and optionaly send a time code */ + case SPACEWIRE_IOCTRL_SET_TCODE: + tmp = (unsigned int)ioarg->buffer; + /* Set timecode register */ + if (tmp & SPACEWIRE_TCODE_SET) { + SPW_WRITE(&pDev->regs->time, + ((SPW_READ(&pDev->regs->time) & ~(0xff)) | + (tmp & SPACEWIRE_TCODE_TCODE))); + } + /* Send timecode directly (tick-in) ? */ + if (tmp & SPACEWIRE_TCODE_TX) { + SPW_CTRL_WRITE(pDev, + ((SPW_CTRL_READ(pDev) & ~(SPW_CTRL_TI)) | SPW_CTRL_TI)); + } + break; + + /* Read time code register and tick-out status bit */ + case SPACEWIRE_IOCTRL_GET_TCODE: + tmp = (unsigned int)ioarg->buffer; + if ( !tmp ){ + return RTEMS_INVALID_NAME; + } + + /* Copy timecode register */ + if (SPW_READ(&pDev->regs->status) & SPW_STATUS_TO) { + *(unsigned int *)tmp = (1 << 8) | SPW_READ(&pDev->regs->time); + } else { + *(unsigned int *)tmp = SPW_READ(&pDev->regs->time); + } + break; + + case SPACEWIRE_IOCTRL_SET_READ_TIMEOUT: + pDev->config.rtimeout = (unsigned int)ioarg->buffer; + break; + + default: + return RTEMS_NOT_IMPLEMENTED; + } + + SPACEWIRE_DBGC(DBGSPW_IOCALLS, "SPW_IOCTRL Return\n"); + return RTEMS_SUCCESSFUL; } /* ============================================================================== */ static int grspw_set_rxmaxlen(GRSPW_DEV *pDev) { - unsigned int rxmax; - SPW_WRITE(&pDev->regs->dma0rxmax,pDev->config.rxmaxlen); /*set rx maxlength*/ - rxmax = SPW_READ(&pDev->regs->dma0rxmax); - if (rxmax != pDev->config.rxmaxlen) { - return 0; - } - return 1; + unsigned int rxmax; + SPW_WRITE(&pDev->regs->dma0rxmax,pDev->config.rxmaxlen); /*set rx maxlength*/ + rxmax = SPW_READ(&pDev->regs->dma0rxmax); + if (rxmax != pDev->config.rxmaxlen) { + return 0; + } + return 1; } static int grspw_hw_init(GRSPW_DEV *pDev) { - unsigned int ctrl; + unsigned int ctrl; - ctrl = SPW_CTRL_READ(pDev); + ctrl = SPW_CTRL_READ(pDev); -#ifdef GRSPW_STATIC_MEM - pDev->rx = (SPACEWIRE_RXBD *) pDev->mem_bdtable; - pDev->tx = (SPACEWIRE_RXBD *) pDev->mem_bdtable + SPACEWIRE_BDTABLE_SIZE; -#else - pDev->rx = (SPACEWIRE_RXBD *) rtems_heap_allocate_aligned_with_boundary( SPACEWIRE_BDTABLE_SIZE, 1024, 0 ); - pDev->tx = (SPACEWIRE_TXBD *) rtems_heap_allocate_aligned_with_boundary( SPACEWIRE_BDTABLE_SIZE, 1024, 0 ); -#endif - SPACEWIRE_DBG("hw_init [minor %i]\n", pDev->minor); + pDev->rx = (SPACEWIRE_RXBD *) pDev->ptr_bd0; + pDev->tx = (SPACEWIRE_TXBD *) &pDev->rx[SPACEWIRE_RXBUFS_NR]; + + /* Translate into remote address */ + drvmgr_translate(pDev->dev, 0, 0, (void *)pDev->rx, (void **)&pDev->rx_remote); + drvmgr_translate(pDev->dev, 0, 0, (void *)pDev->tx, (void **)&pDev->tx_remote); + + SPACEWIRE_DBG("hw_init [minor %i]\n", pDev->minor); - pDev->config.is_rmap = ctrl & SPW_CTRL_RA; - pDev->config.is_rxunaligned = ctrl & SPW_CTRL_RX; - pDev->config.is_rmapcrc = ctrl & SPW_CTRL_RC; - return 0; + pDev->config.is_rmap = ctrl & SPW_CTRL_RA; + pDev->config.is_rxunaligned = ctrl & SPW_CTRL_RX; + pDev->config.is_rmapcrc = ctrl & SPW_CTRL_RC; + return 0; } -static int grspw_hw_waitlink (GRSPW_DEV *pDev, int timeout) +static int grspw_hw_waitlink (GRSPW_DEV *pDev, int timeout) { - int j; - - if ( timeout == -1 ){ - /* Wait default timeout */ - timeout = SPACEWIRE_INIT_TIMEOUT; - } - - j=0; - while (SPW_LINKSTATE(SPW_STATUS_READ(pDev)) != 5) { - if ( timeout < -1 ) { - /* wait forever */ - }else if ( j >= timeout ){ - /* timeout reached, return fail */ - return 1; - } - - /* Sleep for 10 ticks */ - rtems_task_wake_after(10); - j+=10; - } - return 0; + int j; + + /* No actual link interface on a DMA-only GRSPW2 connected to the + * SPW router + */ + if (pDev->core_ver == 3) + return 0; + + if ( timeout == -1 ){ + /* Wait default timeout */ + timeout = SPACEWIRE_INIT_TIMEOUT; + } + + j=0; + while (SPW_LINKSTATE(SPW_STATUS_READ(pDev)) != 5) { + if ( timeout < -1 ) { + /* wait forever */ + }else if ( j >= timeout ){ + /* timeout reached, return fail */ + return 1; + } + + /* Sleep for 10 ticks */ + rtems_task_wake_after(10); + j+=10; + } + return 0; } static void grspw_hw_reset(GRSPW_DEV *pDev) { - SPW_CTRL_WRITE(pDev, SPW_CTRL_RESET); /*reset core*/ - SPW_STATUS_WRITE(pDev, SPW_STATUS_TO | SPW_STATUS_CE | SPW_STATUS_ER | SPW_STATUS_DE | SPW_STATUS_PE | - SPW_STATUS_WE | SPW_STATUS_IA | SPW_STATUS_EE); /*clear status*/ - SPW_CTRL_WRITE(pDev, SPW_CTRL_LINKSTART); /*start link core*/ - #ifndef GRSPW_STATIC_MEM - free(pDev->rx); - free(pDev->tx); - #endif + SPW_CTRL_WRITE(pDev, SPW_CTRL_RESET); /*reset core*/ + SPW_STATUS_WRITE(pDev, SPW_STATUS_TO | SPW_STATUS_CE | SPW_STATUS_ER | SPW_STATUS_DE | SPW_STATUS_PE | + SPW_STATUS_WE | SPW_STATUS_IA | SPW_STATUS_EE); /*clear status*/ + SPW_CTRL_WRITE(pDev, SPW_CTRL_LINKSTART); /*start link core*/ } static void grspw_hw_read_config(GRSPW_DEV *pDev) { - unsigned int tmp; + unsigned int tmp; + + tmp = SPW_READ(&pDev->regs->nodeaddr); + pDev->config.nodeaddr = 0xFF & tmp; + pDev->config.nodemask = 0xFF & (tmp>>8); + pDev->config.destkey = 0xFF & SPW_READ(&pDev->regs->destkey); + pDev->config.clkdiv = 0xFFFF & SPW_READ(&pDev->regs->clkdiv); + + tmp = SPW_CTRL_READ(pDev); + pDev->config.promiscuous = 1 & (tmp >> 5); + pDev->config.rmapen = 1 & (tmp >> 16); + pDev->config.rmapbufdis = 1 & (tmp >> 17); + pDev->config.is_rmap = 1 & (tmp >> 31); + pDev->config.is_rxunaligned = 1 & (tmp >> 30); + pDev->config.is_rmapcrc = 1 & (tmp >> 29); + pDev->config.linkdisabled = 1 & tmp; + pDev->config.linkstart = 1 & (tmp >> 1); + + if ( pDev->core_ver <= 1 ){ + tmp = SPW_READ(&pDev->regs->timer); + pDev->config.timer = 0xFFF & tmp; + pDev->config.disconnect = 0x3FF & (tmp >> 12); + }else{ + pDev->config.timer = 0; + pDev->config.disconnect = 0; + } - tmp = SPW_READ(&pDev->regs->nodeaddr); - pDev->config.nodeaddr = 0xFF & tmp; - pDev->config.nodemask = 0xFF & (tmp>>8); - pDev->config.destkey = 0xFF & SPW_READ(&pDev->regs->destkey); - pDev->config.clkdiv = 0xFFFF & SPW_READ(&pDev->regs->clkdiv); - - tmp = SPW_CTRL_READ(pDev); - pDev->config.promiscuous = 1 & (tmp >> 5); - pDev->config.rmapen = 1 & (tmp >> 16); - pDev->config.rmapbufdis = 1 & (tmp >> 17); - pDev->config.is_rmap = 1 & (tmp >> 31); - pDev->config.is_rxunaligned = 1 & (tmp >> 30); - pDev->config.is_rmapcrc = 1 & (tmp >> 29); - pDev->config.linkdisabled = 1 & tmp; - pDev->config.linkstart = 1 & (tmp >> 1); - - if ( pDev->core_ver <= 1 ){ - tmp = SPW_READ(&pDev->regs->timer); - pDev->config.timer = 0xFFF & tmp; - pDev->config.disconnect = 0x3FF & (tmp >> 12); - }else{ - pDev->config.timer = 0; - pDev->config.disconnect = 0; - } - - return; + return; } /* timeout is given in ticks */ static int grspw_hw_startup (GRSPW_DEV *pDev, int timeout) { - int i; - unsigned int dmactrl; - - SPW_WRITE(&pDev->regs->status, (SPW_STATUS_TO|SPW_STATUS_CE|SPW_STATUS_ER|SPW_STATUS_DE|SPW_STATUS_PE|SPW_STATUS_WE|SPW_STATUS_IA|SPW_STATUS_EE)); /*clear status*/ - - if (grspw_hw_waitlink(pDev,timeout)) { - SPACEWIRE_DBG2("Device open. Link is not up\n"); - return RTEMS_TIMEOUT; - } - - SPW_WRITE(&pDev->regs->dma0ctrl, SPW_DMACTRL_PS | SPW_DMACTRL_PR | SPW_DMACTRL_TA | SPW_DMACTRL_RA); /*clear status, set ctrl*/ - - - if ((dmactrl = SPW_READ(&pDev->regs->dma0ctrl)) != 0) { - SPACEWIRE_DBG2("DMACtrl is not cleared\n"); - return RTEMS_IO_ERROR; - } - - /* prepare transmit buffers */ - for (i = 0; i < pDev->txbufcnt; i++) { - pDev->tx[i].ctrl = 0; - pDev->tx[i].addr_header = memarea_to_hw(((unsigned int)&pDev->ptr_txhbuf0[0]) + (i * pDev->txhbufsize)); - pDev->tx[i].addr_data = memarea_to_hw(((unsigned int)&pDev->ptr_txdbuf0[0]) + (i * pDev->txdbufsize)); - } - pDev->tx_cur = 0; - pDev->tx_sent = 0; - pDev->tx_all_in_use = 0; - - /* prepare receive buffers */ - for (i = 0; i < pDev->rxbufcnt; i++) { - if (i+1 == pDev->rxbufcnt) { - pDev->rx[i].ctrl = SPW_RXBD_IE | SPW_RXBD_EN | SPW_RXBD_WR; - } else { - pDev->rx[i].ctrl = SPW_RXBD_IE | SPW_RXBD_EN; - } - pDev->rx[i].addr = memarea_to_hw(((unsigned int)&pDev->ptr_rxbuf0[0]) + (i * pDev->rxbufsize)); - } - pDev->rxcur = 0; - pDev->rxbufcur = -1; - grspw_set_rxmaxlen(pDev); - - SPW_WRITE(&pDev->regs->dma0txdesc, memarea_to_hw((unsigned int) pDev->tx)); - SPW_WRITE(&pDev->regs->dma0rxdesc, memarea_to_hw((unsigned int) pDev->rx)); - - /* start RX */ - dmactrl = SPW_READ(&pDev->regs->dma0ctrl); - SPW_WRITE(&pDev->regs->dma0ctrl, (dmactrl & SPW_PREPAREMASK_RX) | SPW_DMACTRL_RD | SPW_DMACTRL_RXEN | SPW_DMACTRL_NS | SPW_DMACTRL_TXIE | SPW_DMACTRL_RXIE); - - SPACEWIRE_DBGC(DBGSPW_TX,"0x%x: setup complete\n", (unsigned int)pDev->regs); - return RTEMS_SUCCESSFUL; + int i; + unsigned int dmactrl; + + SPW_WRITE(&pDev->regs->status, (SPW_STATUS_TO|SPW_STATUS_CE|SPW_STATUS_ER|SPW_STATUS_DE|SPW_STATUS_PE|SPW_STATUS_WE|SPW_STATUS_IA|SPW_STATUS_EE)); /*clear status*/ + + if (grspw_hw_waitlink(pDev,timeout)) { + SPACEWIRE_DBG2("Device open. Link is not up\n"); + return RTEMS_TIMEOUT; + } + + SPW_WRITE(&pDev->regs->dma0ctrl, SPW_DMACTRL_PS | SPW_DMACTRL_PR | SPW_DMACTRL_TA | SPW_DMACTRL_RA); /*clear status, set ctrl*/ + + if ((dmactrl = SPW_READ(&pDev->regs->dma0ctrl)) != 0) { + SPACEWIRE_DBG2("DMACtrl is not cleared\n"); + return RTEMS_IO_ERROR; + } + + /* prepare transmit buffers */ + for (i = 0; i < pDev->txbufcnt; i++) { + pDev->tx[i].ctrl = 0; + pDev->tx[i].addr_header = ((unsigned int)&pDev->ptr_txhbuf0_remote[0]) + (i * pDev->txhbufsize); + pDev->tx[i].addr_data = ((unsigned int)&pDev->ptr_txdbuf0_remote[0]) + (i * pDev->txdbufsize); + } + pDev->tx_cur = 0; + pDev->tx_sent = 0; + pDev->tx_all_in_use = 0; + + /* prepare receive buffers */ + for (i = 0; i < pDev->rxbufcnt; i++) { + if (i+1 == pDev->rxbufcnt) { + pDev->rx[i].ctrl = SPW_RXBD_IE | SPW_RXBD_EN | SPW_RXBD_WR; + } else { + pDev->rx[i].ctrl = SPW_RXBD_IE | SPW_RXBD_EN; + } + pDev->rx[i].addr = ((unsigned int)&pDev->ptr_rxbuf0_remote[0]) + (i * pDev->rxbufsize); + } + pDev->rxcur = 0; + pDev->rxbufcur = -1; + grspw_set_rxmaxlen(pDev); + + SPW_WRITE(&pDev->regs->dma0txdesc, pDev->tx_remote); + SPW_WRITE(&pDev->regs->dma0rxdesc, pDev->rx_remote); + + /* start RX */ + dmactrl = SPW_READ(&pDev->regs->dma0ctrl); + SPW_WRITE(&pDev->regs->dma0ctrl, (dmactrl & SPW_PREPAREMASK_RX) | SPW_DMACTRL_RD | SPW_DMACTRL_RXEN | SPW_DMACTRL_NS | SPW_DMACTRL_TXIE | SPW_DMACTRL_RXIE); + + SPACEWIRE_DBGC(DBGSPW_TX,"0x%x: setup complete\n", (unsigned int)pDev->regs); + return RTEMS_SUCCESSFUL; } /* Wait until the receiver is inactive */ static void grspw_hw_wait_rx_inactive(GRSPW_DEV *pDev) { - while( SPW_READ(&pDev->regs->dma0ctrl) & SPW_DMACTRL_RX ){ - /* switching may be needed: - * - low frequency GRSPW - * - mega packet incoming - */ - rtems_task_wake_after(1); - } + while( SPW_READ(&pDev->regs->dma0ctrl) & SPW_DMACTRL_RX ){ + /* switching may be needed: + * - low frequency GRSPW + * - mega packet incoming + */ + rtems_task_wake_after(1); + } } /* Stop the rx or/and tx by disabling the receiver/transmitter */ -static int grspw_hw_stop (GRSPW_DEV *pDev, int rx, int tx) -{ - unsigned int dmactrl; - - /* stop rx and/or tx */ - dmactrl = SPW_READ(&pDev->regs->dma0ctrl); - if ( rx ) { - dmactrl &= ~(SPW_DMACTRL_RXEN|SPW_DMACTRL_RXIE|SPW_DMACTRL_RD); - } - if ( tx ) { - dmactrl &= ~(SPW_DMACTRL_TXEN|SPW_DMACTRL_TXIE); - } - /*SPW_WRITE(&pDev->regs->dma0ctrl, (dmactrl & SPW_PREPAREMASK_RX) & ~(SPW_DMACTRL_RD | SPW_DMACTRL_RXEN) & ~(SPW_DMACTRL_TXEN));*/ - - /* don't clear status flags */ - dmactrl &= ~(SPW_DMACTRL_RA|SPW_DMACTRL_PR|SPW_DMACTRL_AI); - SPW_WRITE(&pDev->regs->dma0ctrl, dmactrl); - return RTEMS_SUCCESSFUL; -} - -int grspw_hw_send(GRSPW_DEV *pDev, unsigned int hlen, char *hdr, unsigned int dlen, char *data) +static int grspw_hw_stop (GRSPW_DEV *pDev, int rx, int tx) { + unsigned int dmactrl; - unsigned int dmactrl, ctrl; -#ifdef DEBUG_SPACEWIRE_ONOFF - unsigned int k; -#endif - rtems_interrupt_level level; - unsigned int cur = pDev->tx_cur; - char *txh = pDev->ptr_txhbuf0 + (cur * pDev->txhbufsize); - char *txd = pDev->ptr_txdbuf0 + (cur * pDev->txdbufsize); + /* stop rx and/or tx */ + dmactrl = SPW_READ(&pDev->regs->dma0ctrl); + if ( rx ) { + dmactrl &= ~(SPW_DMACTRL_RXEN|SPW_DMACTRL_RXIE|SPW_DMACTRL_RD); + } + if ( tx ) { + dmactrl &= ~(SPW_DMACTRL_TXEN|SPW_DMACTRL_TXIE); + } + /*SPW_WRITE(&pDev->regs->dma0ctrl, (dmactrl & SPW_PREPAREMASK_RX) & ~(SPW_DMACTRL_RD | SPW_DMACTRL_RXEN) & ~(SPW_DMACTRL_TXEN));*/ - ctrl = SPW_READ((volatile void *)&pDev->tx[cur].ctrl); + /* don't clear status flags */ + dmactrl &= ~(SPW_DMACTRL_RA|SPW_DMACTRL_PR|SPW_DMACTRL_AI); + SPW_WRITE(&pDev->regs->dma0ctrl, dmactrl); + return RTEMS_SUCCESSFUL; +} - if (ctrl & SPW_TXBD_EN) { - return 0; - } - memcpy(&txd[0], data, dlen); - memcpy(&txh[0], hdr, hlen); +int grspw_hw_send(GRSPW_DEV *pDev, unsigned int hlen, char *hdr, unsigned int dlen, char *data, unsigned int options) +{ + unsigned int dmactrl, ctrl; #ifdef DEBUG_SPACEWIRE_ONOFF - if (DEBUG_SPACEWIRE_FLAGS & DBGSPW_DUMP) { - for (k = 0; k < hlen; k++){ - if (k % 16 == 0) { - printf ("\n"); - } - printf ("%.2x(%c) ",txh[k] & 0xff,isprint(txh[k] & 0xff) ? txh[k] & 0xff : ' '); - } - printf ("\n"); - } - if (DEBUG_SPACEWIRE_FLAGS & DBGSPW_DUMP) { - for (k = 0; k < dlen; k++){ - if (k % 16 == 0) { - printf ("\n"); - } - printf ("%.2x(%c) ",txd[k] & 0xff,isprint(txd[k] & 0xff) ? txd[k] & 0xff : ' '); - } - printf ("\n"); - } + unsigned int k; #endif + rtems_interrupt_level level; + unsigned int cur = pDev->tx_cur, bdctrl; + char *txh = pDev->ptr_txhbuf0 + (cur * pDev->txhbufsize); + char *txd = pDev->ptr_txdbuf0 + (cur * pDev->txdbufsize); + char *txh_remote = pDev->ptr_txhbuf0_remote + (cur * pDev->txhbufsize); + char *txd_remote = pDev->ptr_txdbuf0_remote + (cur * pDev->txdbufsize); + unsigned int tmp, tmp2; + + ctrl = SPW_READ((volatile void *)&pDev->tx[cur].ctrl); + + if (ctrl & SPW_TXBD_EN) { + return 0; + } - pDev->tx[cur].addr_header = memarea_to_hw((unsigned int)txh); - pDev->tx[cur].len = dlen; - pDev->tx[cur].addr_data = memarea_to_hw((unsigned int)txd); - if (pDev->tx_cur == (pDev->txbufcnt - 1) ) { - pDev->tx[cur].ctrl = SPW_TXBD_IE | SPW_TXBD_WR | SPW_TXBD_EN | hlen; - } else { - pDev->tx[cur].ctrl = SPW_TXBD_IE | SPW_TXBD_EN | hlen; - } + memcpy(&txd[0], data, dlen); + memcpy(&txh[0], hdr, hlen); - dmactrl = SPW_READ(&pDev->regs->dma0ctrl); - SPW_WRITE(&pDev->regs->dma0ctrl, (dmactrl & SPW_PREPAREMASK_TX) | SPW_DMACTRL_TXEN | SPW_DMACTRL_TXIE); +#ifdef DEBUG_SPACEWIRE_ONOFF + if (DEBUG_SPACEWIRE_FLAGS & DBGSPW_DUMP) { + for (k = 0; k < hlen; k++){ + if (k % 16 == 0) { + printf ("\n"); + } + printf ("%.2x(%c) ",txh[k] & 0xff,isprint(txh[k] & 0xff) ? txh[k] & 0xff : ' '); + } + printf ("\n"); + } + if (DEBUG_SPACEWIRE_FLAGS & DBGSPW_DUMP) { + for (k = 0; k < dlen; k++){ + if (k % 16 == 0) { + printf ("\n"); + } + printf ("%.2x(%c) ",txd[k] & 0xff,isprint(txd[k] & 0xff) ? txd[k] & 0xff : ' '); + } + printf ("\n"); + } +#endif + + pDev->tx[cur].addr_header = (unsigned int)txh_remote; + pDev->tx[cur].len = dlen; + pDev->tx[cur].addr_data = (unsigned int)txd_remote; + + bdctrl = SPW_TXBD_IE | SPW_TXBD_EN | hlen; + if ( options & GRSPW_PKTSEND_OPTION_HDR_CRC ) + bdctrl |= SPW_TXBD_HC; + if ( options & GRSPW_PKTSEND_OPTION_DATA_CRC ) + bdctrl |= SPW_TXBD_DC; + bdctrl |= options & GRSPW_PKTSEND_OPTION_NOCRCLEN_MASK; + + /* Update counters */ + rtems_interrupt_disable(level); + if (pDev->tx_cur == (pDev->txbufcnt - 1) ) { + bdctrl |= SPW_TXBD_WR; + } + pDev->tx[cur].ctrl = bdctrl; - /* Update counters */ - rtems_interrupt_disable(level); + dmactrl = SPW_READ(&pDev->regs->dma0ctrl); + SPW_WRITE(&pDev->regs->dma0ctrl, (dmactrl & SPW_PREPAREMASK_TX) | SPW_DMACTRL_TXEN | SPW_DMACTRL_TXIE); - pDev->tx_cur = (pDev->tx_cur + 1) % pDev->txbufcnt; - if (pDev->tx_cur == pDev->tx_sent) { - pDev->tx_all_in_use = 1; - } - rtems_interrupt_enable(level); + pDev->tx_cur = (pDev->tx_cur + 1) % pDev->txbufcnt; + if (pDev->tx_cur == pDev->tx_sent) { + pDev->tx_all_in_use = 1; + } + rtems_interrupt_enable(level); - /* In blocking mode wait until message is sent */ + /* In blocking mode wait until message is sent */ if (pDev->config.tx_blocking) { while ( SPW_READ(&pDev->regs->dma0ctrl) & SPW_DMACTRL_TXEN) { /* if changed to blocking mode */ - SPACEWIRE_DBGC(DBGSPW_TX, "Tx blocking\n"); - rtems_semaphore_obtain(pDev->txsp, RTEMS_WAIT, RTEMS_NO_TIMEOUT); + SPACEWIRE_DBGC(DBGSPW_TX, "Tx blocking\n"); + rtems_semaphore_obtain(pDev->txsp, RTEMS_WAIT, RTEMS_NO_TIMEOUT); } } - SPACEWIRE_DBGC(DBGSPW_TX, "0x%x: transmitted <%i> bytes\n", (unsigned int) pDev->regs, dlen+hlen); - return hlen + dlen; + SPACEWIRE_DBGC(DBGSPW_TX, "0x%x: transmitted <%i> bytes\n", (unsigned int) pDev->regs, dlen+hlen); + return hlen + dlen; } static int grspw_hw_receive(GRSPW_DEV *pDev, char *b, int c) { - unsigned int len, rxlen, ctrl; - unsigned int cur; - unsigned int tmp; - unsigned int dump_start_len; - int i; - char *rxb; - - if ( pDev->config.promiscuous ) { + unsigned int len, rxlen, ctrl; + unsigned int cur; + unsigned int tmp; + unsigned int dump_start_len; + int i; + char *rxb; + + if ( pDev->config.promiscuous || pDev->config.keep_source ) { dump_start_len = 0; /* make sure address and prot can be read in promiscuous mode */ } else if (pDev->config.rm_prot_id) { dump_start_len = 2; /* skip source address and protocol id */ @@ -1638,92 +1819,153 @@ static int grspw_hw_receive(GRSPW_DEV *pDev, char *b, int c) { dump_start_len = 1; /* default: skip only source address */ } - rxlen = 0; - cur = pDev->rxcur; - rxb = pDev->ptr_rxbuf0 + (cur * pDev->rxbufsize); - - SPACEWIRE_DBGC(DBGSPW_RX, "0x%x: waitin packet at pos %i\n", (unsigned int) pDev->regs, cur); - - ctrl = SPW_READ((volatile void *)&pDev->rx[cur].ctrl); - if (ctrl & SPW_RXBD_EN) { - return rxlen; - } - SPACEWIRE_DBGC(DBGSPW_RX, "checking packet\n"); - - len = SPW_RXBD_LENGTH & ctrl; - if (!((ctrl & SPW_RXBD_ERROR) || (pDev->config.check_rmap_err && (ctrl & SPW_RXBD_RMAPERROR)))) { - if (pDev->rxbufcur == -1) { - SPACEWIRE_DBGC(DBGSPW_RX, "incoming packet len %i\n", len); - pDev->stat.packets_received++; - pDev->rxbufcur = dump_start_len; - } - rxlen = tmp = len - pDev->rxbufcur; - SPACEWIRE_DBGC(DBGSPW_RX, "C %i\n", c); - SPACEWIRE_DBGC(DBGSPW_RX, "Dump %i\n", dump_start_len); - SPACEWIRE_DBGC(DBGSPW_RX, "Bufcur %i\n", pDev->rxbufcur); - SPACEWIRE_DBGC(DBGSPW_RX, "Rxlen %i\n", rxlen ); - if (rxlen > c) { - rxlen = c; - } - if (CPU_SPARC_HAS_SNOOPING) { - memcpy(b, rxb+pDev->rxbufcur, rxlen); - } else { - for(i = 0; i < rxlen; i++) { - b[i] = MEM_READ(rxb+pDev->rxbufcur); - } - } - - pDev->rxbufcur += rxlen; - if (c >= tmp) { - SPACEWIRE_DBGC(DBGSPW_RX, "Next descriptor\n"); - grspw_rxnext(pDev); - } - } else { - check_rx_errors(pDev, ctrl); - } - return rxlen; + rxlen = 0; + cur = pDev->rxcur; + rxb = pDev->ptr_rxbuf0 + (cur * pDev->rxbufsize); + + SPACEWIRE_DBGC(DBGSPW_RX, "0x%x: waitin packet at pos %i\n", (unsigned int) pDev->regs, cur); + + ctrl = SPW_READ((volatile void *)&pDev->rx[cur].ctrl); + if (ctrl & SPW_RXBD_EN) { + return rxlen; + } + SPACEWIRE_DBGC(DBGSPW_RX, "checking packet\n"); + + len = SPW_RXBD_LENGTH & ctrl; + if (!((ctrl & SPW_RXBD_ERROR) || (pDev->config.check_rmap_err && (ctrl & SPW_RXBD_RMAPERROR)))) { + if (pDev->rxbufcur == -1) { + SPACEWIRE_DBGC(DBGSPW_RX, "incoming packet len %i\n", len); + pDev->stat.packets_received++; + pDev->rxbufcur = dump_start_len; + } + rxlen = tmp = len - pDev->rxbufcur; + SPACEWIRE_DBGC(DBGSPW_RX, "C %i\n", c); + SPACEWIRE_DBGC(DBGSPW_RX, "Dump %i\n", dump_start_len); + SPACEWIRE_DBGC(DBGSPW_RX, "Bufcur %i\n", pDev->rxbufcur); + SPACEWIRE_DBGC(DBGSPW_RX, "Rxlen %i\n", rxlen ); + if (rxlen > c) { + rxlen = c; + } + if (CPU_SPARC_HAS_SNOOPING) { +/* if ( 1 ) {*/ + /*printf("RX_MEMCPY(0x%x, 0x%x, 0x%x)\n", (unsigned int)b, (unsigned int)(rxb+pDev->rxbufcur), (unsigned int)rxlen);*/ + memcpy(b, rxb+pDev->rxbufcur, rxlen); + } else { + int left = rxlen; + /* Copy word wise if Aligned */ + if ( (((int)b & 3) == 0) && (((int)(rxb+pDev->rxbufcur) & 3) == 0) ){ + while(left>=32){ + *(int *)(b+0) = MEM_READ32(rxb+pDev->rxbufcur+0); + *(int *)(b+4) = MEM_READ32(rxb+pDev->rxbufcur+4); + *(int *)(b+8) = MEM_READ32(rxb+pDev->rxbufcur+8); + *(int *)(b+12) = MEM_READ32(rxb+pDev->rxbufcur+12); + *(int *)(b+16) = MEM_READ32(rxb+pDev->rxbufcur+16); + *(int *)(b+20) = MEM_READ32(rxb+pDev->rxbufcur+20); + *(int *)(b+24) = MEM_READ32(rxb+pDev->rxbufcur+24); + *(int *)(b+28) = MEM_READ32(rxb+pDev->rxbufcur+28); + rxb+=32; + b+=32; + left-=32; + } + while(left>=4){ + *(int *)b = MEM_READ32(rxb+pDev->rxbufcur); + rxb+=4; + b+=4; + left-=4; + } + } + for(i = 0; i < left; i++) { + b[i] = MEM_READ8(rxb+pDev->rxbufcur+i); + } + } + + pDev->rxbufcur += rxlen; + if (c >= tmp) { + SPACEWIRE_DBGC(DBGSPW_RX, "Next descriptor\n"); + grspw_rxnext(pDev); + } + } else { + check_rx_errors(pDev, ctrl); + grspw_rxnext(pDev); + } + return rxlen; } -static void grspw_rxnext(GRSPW_DEV *pDev) +static void grspw_rxnext(GRSPW_DEV *pDev) { - unsigned int dmactrl; - unsigned int cur = pDev->rxcur; - unsigned int ctrl = 0; - if (cur == (pDev->rxbufcnt - 1)) { - pDev->rx[cur].ctrl = ctrl | SPW_RXBD_EN | SPW_RXBD_IE | SPW_RXBD_WR; - cur = 0; - } else { - pDev->rx[cur].ctrl = ctrl | SPW_RXBD_EN | SPW_RXBD_IE; - cur++; - } - - pDev->rxcur = cur; - pDev->rxbufcur = -1; - - /* start RX */ - dmactrl = SPW_READ(&pDev->regs->dma0ctrl); - SPW_WRITE(&pDev->regs->dma0ctrl, (dmactrl & SPW_PREPAREMASK_RX) | SPW_DMACTRL_RD | SPW_DMACTRL_RXEN | SPW_DMACTRL_RXIE | SPW_DMACTRL_NS); + unsigned int dmactrl; + unsigned int cur = pDev->rxcur; + unsigned int ctrl = 0; + rtems_interrupt_level level; + + rtems_interrupt_disable(level); + + if (cur == (pDev->rxbufcnt - 1)) { + pDev->rx[cur].ctrl = ctrl | SPW_RXBD_EN | SPW_RXBD_IE | SPW_RXBD_WR; + cur = 0; + } else { + pDev->rx[cur].ctrl = ctrl | SPW_RXBD_EN | SPW_RXBD_IE; + cur++; + } + + pDev->rxcur = cur; + pDev->rxbufcur = -1; + + /* start RX */ + dmactrl = SPW_READ(&pDev->regs->dma0ctrl); + SPW_WRITE(&pDev->regs->dma0ctrl, (dmactrl & SPW_PREPAREMASK_RX) | SPW_DMACTRL_RD | SPW_DMACTRL_RXEN | SPW_DMACTRL_RXIE | SPW_DMACTRL_NS); + rtems_interrupt_enable(level); +} + +static void check_rx_errors(GRSPW_DEV *pDev, int ctrl) +{ + if (ctrl & SPW_RXBD_EEP) { + pDev->stat.rx_eep_err++; + } + if (ctrl & SPW_RXBD_EHC) { + if (pDev->config.check_rmap_err) { + pDev->stat.rx_rmap_header_crc_err++; + } + } + if (ctrl & SPW_RXBD_EDC) { + if (pDev->config.check_rmap_err) { + pDev->stat.rx_rmap_data_crc_err++; + } + } + if (ctrl & SPW_RXBD_ETR) { + pDev->stat.rx_truncated++; + } } -static void check_rx_errors(GRSPW_DEV *pDev, int ctrl) + +void grspw_print_dev(struct drvmgr_dev *dev, int options) { - if (ctrl & SPW_RXBD_EEP) { - pDev->stat.rx_eep_err++; - } - if (ctrl & SPW_RXBD_EHC) { - if (pDev->config.check_rmap_err) { - pDev->stat.rx_rmap_header_crc_err++; - } - } - if (ctrl & SPW_RXBD_EDC) { - if (pDev->config.check_rmap_err) { - pDev->stat.rx_rmap_data_crc_err++; - } - } - if (ctrl & SPW_RXBD_ETR) { - pDev->stat.rx_truncated++; - } + GRSPW_DEV *pDev = dev->priv; + struct amba_dev_info *devinfo; + + devinfo = (struct amba_dev_info *)pDev->dev->businfo; + + /* Print */ + printf("--- GRSPW %s ---\n", pDev->devName); + printf(" REGS: 0x%x\n", (unsigned int)pDev->regs); + printf(" IRQ: %d\n", pDev->irq); + printf(" CORE VERSION: %d\n", pDev->core_ver); + printf(" CTRL: 0x%x\n", pDev->regs->ctrl); + printf(" STATUS: 0x%x\n", pDev->regs->status); + printf(" DMA0CTRL: 0x%x\n", pDev->regs->dma0ctrl); + printf(" TXBD: 0x%x\n", (unsigned int)pDev->tx); + printf(" RXBD: 0x%x\n", (unsigned int)pDev->rx); } +void grspw_print(int options) +{ + struct amba_drv_info *drv = &grspw_drv_info; + struct drvmgr_dev *dev; + dev = drv->general.dev; + while(dev) { + grspw_print_dev(dev, options); + dev = dev->next_in_drv; + } +} -- cgit v1.2.3