source: rtems/c/src/lib/libbsp/sparc/shared/spw/grspw.c @ b25b7da8

4.8
Last change on this file since b25b7da8 was b25b7da8, checked in by Joel Sherrill <joel.sherrill@…>, on 11/30/07 at 16:53:44

2007-11-30 Daniel Hellstrom <daniel@…>

  • shared/include/grspw.h, shared/spw/grspw.c: GRSPW SpaceWire? Driver. Fixes typecast to volatile integer instead of to integer. Added scanning for GRSPW2 Core, The GRSPW2 core is run in legacy mode.
  • Property mode set to 100644
File size: 69.7 KB
Line 
1/*
2 *  This file contains the GRSPW SpaceWire Driver for LEON2 and LEON3.
3 *
4 *  COPYRIGHT (c) 2007
5 *  Gaisler Research.
6 *
7 *  The license and distribution terms for this file may be
8 *  found in the file LICENSE in this distribution or at
9 *  http://www.rtems.com/license/LICENSE.
10 *
11 * Changes:
12 *
13 * 2007-09-27, Daniel Hellstrom <daniel@gaisler.com>
14 *  Added basic support for GRSPW2 core.
15 *
16 * 2007-07-12, Daniel Hellstrom <daniel@gaisler.com>
17 *  Fixed bug in TXBLOCK mode (normally called flush).
18 *
19 * 2007-05-28, Daniel Hellstrom <daniel@gaisler.com>
20 *  Changed register call from spacewire_register to
21 *  grspw_register. Added one parameter (the AMBA bus
22 *  pointer) for LEON2 and LEON3 PCI compability.
23 *  Typical LEON3 register: grspw_register(&amba_conf);
24 *
25 * 2007-05-28, Daniel Hellstrom <daniel@gaisler.com>
26 *  Changed errno return values, compatible with RASTA
27 *  Spacewire driver
28 *
29 * 2007-05-25, Daniel Hellstrom <daniel@gaisler.com>
30 *  Changed name from /dev/spacewire,/dev/spacewire_b...
31 *  to /dev/grspw0,/dev/grspw1...
32 *
33 * 2007-05-24, Daniel Hellstrom <daniel@gaisler.com>
34 *  Merged LEON3, LEON2 and RASTA driver to one - this.
35 *  The driver is included and configured from grspw_pci.c
36 *  and grspw_rasta.c.
37 *
38 * 2007-05-23, Daniel Hellstrom <daniel@gaisler.com>
39 *  Changed open call, now one need to first call open
40 *  and then ioctl(fd,START,timeout) in order to setup
41 *  hardware for communication.
42 * 
43 * 2007-05-23, Daniel Hellstrom <daniel@gaisler.com>
44 *  Added ioctl(fd,SET_COREFREQ,freq_arg), the command
45 *  can autodetect the register values disconnect and
46 *  timer64. It is still possible to change them manually
47 *  by ioctl(fd,SET_{DISCONNECT,TIMER},arg).
48 *
49 */
50
51/* default name to /dev/grspw0 */
52#if !defined(GRSPW_DEVNAME) || !defined(GRSPW_DEVNAME_NO)
53 #undef GRSPW_DEVNAME
54 #undef GRSPW_DEVNAME_NO
55 #define GRSPW_DEVNAME "/dev/grspw0"
56 #define GRSPW_DEVNAME_NO(devstr,no) ((devstr)[10]='0'+(no))
57#endif
58
59#ifndef GRSPW_PREFIX
60 #define GRSPW_PREFIX(name) grspw##name
61#endif
62
63/* default to no translation */
64#ifndef GRSPW_ADR_TO
65 #define memarea_to_hw(x) ((unsigned int)(x))
66#endif
67#ifndef GRSPW_ADR_FROM
68 #define hw_to_memarea(x) ((unsigned int)(x))
69#endif
70
71#ifndef GRSPW_REG_INT
72 #define GRSPW_REG_INT(handler,irqno,arg) set_vector(handler,irqno+0x10,1)
73 #undef  GRSPW_DEFINE_INTHANDLER
74 #define GRSPW_DEFINE_INTHANDLER
75#endif
76
77#include <bsp.h>
78#include <rtems/libio.h>
79#include <stdlib.h>
80#include <stdio.h>
81#include <string.h>
82#include <assert.h>
83#include <ctype.h>
84#include <rtems/bspIo.h>
85#include <ambapp.h>
86#include <grspw.h>
87
88#define DBGSPW_IOCALLS 1
89#define DBGSPW_TX 2
90#define DBGSPW_RX 4
91#define DBGSPW_IOCTRL 1
92#define DBGSPW_DUMP 16
93#define DEBUG_SPACEWIRE_FLAGS (DBGSPW_IOCALLS | DBGSPW_TX | DBGSPW_RX )
94
95/* #define DEBUG_SPACEWIRE_ONOFF */
96 
97#ifdef DEBUG_SPACEWIRE_ONOFF
98#define SPACEWIRE_DBG(fmt, args...)    do { { printk(" : %03d @ %18s()]:" fmt , __LINE__,__FUNCTION__,## args); }} while(0)
99#define SPACEWIRE_DBG2(fmt)            do { { printk(" : %03d @ %18s()]:" fmt , __LINE__,__FUNCTION__); }} while(0)
100#define SPACEWIRE_DBGC(c,fmt, args...) do { if (DEBUG_SPACEWIRE_FLAGS & c) { printk(" : %03d @ %18s()]:" fmt , __LINE__,__FUNCTION__,## args);  }} while(0)
101#else
102#define SPACEWIRE_DBG(fmt, args...)
103#define SPACEWIRE_DBG2(fmt, args...)
104#define SPACEWIRE_DBGC(c, fmt, args...)
105#endif
106
107typedef struct {
108   volatile unsigned int ctrl;
109   volatile unsigned int status;
110   volatile unsigned int nodeaddr;
111   volatile unsigned int clkdiv;
112   volatile unsigned int destkey;
113   volatile unsigned int time;
114   volatile unsigned int timer;
115   volatile unsigned int pad;
116   
117   volatile unsigned int dma0ctrl;
118   volatile unsigned int dma0rxmax;
119   volatile unsigned int dma0txdesc;
120   volatile unsigned int dma0rxdesc;
121   
122   /* For GRSPW core 2 and onwards */
123   volatile unsigned int dma0addr;
124   
125} LEON3_SPACEWIRE_Regs_Map;
126
127typedef struct {
128   volatile unsigned int ctrl;
129   volatile unsigned int addr;
130} SPACEWIRE_RXBD;
131
132typedef struct {
133   volatile unsigned int ctrl;
134   volatile unsigned int addr_header;
135   volatile unsigned int len;
136   volatile unsigned int addr_data;
137} SPACEWIRE_TXBD;
138
139#define SPACEWIRE_INIT_TIMEOUT 10
140#define SPACEWIRE_BDTABLE_SIZE 0x400
141#define SPACEWIRE_TXD_SIZE 1024
142#define SPACEWIRE_TXH_SIZE 64
143#define SPACEWIRE_RXPCK_SIZE 1024
144#define SPACEWIRE_TXBUFS_NR 64
145#define SPACEWIRE_RXBUFS_NR 128
146
147#define BUFMEM_PER_LINK (SPACEWIRE_TXBUFS_NR*(SPACEWIRE_TXD_SIZE+SPACEWIRE_TXH_SIZE) + SPACEWIRE_RXBUFS_NR*SPACEWIRE_RXPCK_SIZE)
148
149#define SPW_ALIGN(p,c) ((((unsigned int)(p))+((c)-1))&~((c)-1))
150
151typedef struct {
152   /* configuration parameters */
153   spw_config config;
154
155   unsigned int tx_all_in_use;
156   unsigned int tx_sent;
157   unsigned int tx_cur;
158   unsigned int rxcur;
159   unsigned int rxbufcur;
160   unsigned int txdbufsize;
161   unsigned int txhbufsize;
162   unsigned int rxbufsize;
163   unsigned int txbufcnt;
164   unsigned int rxbufcnt;
165
166   /* statistics */
167   spw_stats stat;
168   
169   char *ptr_rxbuf0;
170   char *ptr_txdbuf0;
171   char *ptr_txhbuf0;
172
173   unsigned int irq;
174   int minor;
175   int core_ver;
176   int open;
177   int running;
178   unsigned int core_freq_khz;
179   
180
181   /* semaphores*/
182   rtems_id txsp;
183   rtems_id rxsp;
184   
185   SPACEWIRE_RXBD *rx;
186   SPACEWIRE_TXBD *tx;
187
188#ifdef GRSPW_STATIC_MEM
189   unsigned int membase, memend, mem_bdtable;
190#else
191   char _rxtable[SPACEWIRE_BDTABLE_SIZE*2];
192   char _txtable[SPACEWIRE_BDTABLE_SIZE*2];
193#endif
194
195   LEON3_SPACEWIRE_Regs_Map *regs;
196} GRSPW_DEV;
197
198static int spw_cores;
199static int spw_cores2;
200static unsigned int sys_freq_khz;
201static GRSPW_DEV *grspw_devs;
202
203#ifdef GRSPW_DONT_BYPASS_CACHE
204#define _SPW_READ(address) (*(volatile unsigned int *)(address))
205#define _MEM_READ(address) (*(volatile unsigned char *)(address))
206#else
207static unsigned int _SPW_READ(void *addr) {
208        unsigned int tmp;
209        asm(" lda [%1]1, %0 "
210            : "=r"(tmp)
211            : "r"(addr)
212           );
213        return tmp;
214}
215
216static unsigned int _MEM_READ(void *addr) {
217        unsigned int tmp;
218        asm(" lduba [%1]1, %0 "
219            : "=r"(tmp)
220            : "r"(addr)
221           );
222        return tmp;       
223
224}
225#endif
226
227#define MEM_READ(addr) _MEM_READ((void *)(addr))
228#define SPW_READ(addr) _SPW_READ((void *)(addr))
229#define SPW_WRITE(addr,v) *addr=v
230
231#define SPW_REG(c,r) (c->regs->r)
232#define SPW_REG_CTRL(c) SPW_REG(c,ctrl)
233#define SPW_REG_STATUS(c) SPW_REG(c,status)
234#define SPW_REG_NODEADDR(c) SPW_REG(c,nodeaddr)
235
236#define SPW_CTRL_READ(c)      SPW_READ(&SPW_REG_CTRL(c))
237#define SPW_CTRL_WRITE(c,v)   SPW_WRITE(&SPW_REG_CTRL(c),v)
238#define SPW_STATUS_READ(c)    SPW_READ(&SPW_REG_STATUS(c))
239#define SPW_STATUS_WRITE(c,v) SPW_WRITE(&SPW_REG_STATUS(c),v)
240
241#define SPW_LINKSTATE(c) (((c) >> 21) & 0x7)
242
243#define SPACEWIRE_RXNR(c) ((c&~(SPACEWIRE_BDTABLE_SIZE-1))>>3)
244#define SPACEWIRE_TXNR(c) ((c&~(SPACEWIRE_BDTABLE_SIZE-1))>>4)
245
246#define SPW_RXBD_LENGTH 0x1ffffff
247#define SPW_RXBD_EN (1 << 25)
248#define SPW_RXBD_WR (1 << 26)
249#define SPW_RXBD_IE (1 << 27)
250
251#define SPW_RXBD_EEP (1 << 28)
252#define SPW_RXBD_EHC (1 << 29)
253#define SPW_RXBD_EDC (1 << 30)
254#define SPW_RXBD_ETR (1 << 31)
255
256#define SPW_RXBD_ERROR (SPW_RXBD_EEP | \
257                        SPW_RXBD_ETR)
258
259#define SPW_RXBD_RMAPERROR (SPW_RXBD_EHC | SPW_RXBD_EDC)
260
261#define SPW_TXBD_LENGTH 0xffffff
262
263#define SPW_TXBD_EN (1 << 12)
264#define SPW_TXBD_WR (1 << 13)
265#define SPW_TXBD_IE (1 << 14)
266#define SPW_TXBD_LE (1 << 15)
267
268#define SPW_TXBD_ERROR (SPW_TXBD_LE)
269
270#define SPW_CTRL_LINKDISABLED (1 << 0)
271#define SPW_CTRL_LINKSTART    (1 << 1)
272#define SPW_CTRL_AUTOSTART    (1 << 2)
273#define SPW_CTRL_IE           (1 << 3)
274#define SPW_CTRL_TI           (1 << 4)
275#define SPW_CTRL_PM           (1 << 5)
276#define SPW_CTRL_RESET        (1 << 6)
277#define SPW_CTRL_TQ           (1 << 8)
278#define SPW_CTRL_LI           (1 << 9)
279#define SPW_CTRL_TT           (1 << 10)
280#define SPW_CTRL_TR           (1 << 11)
281#define SPW_CTRL_RE           (1 << 16)
282#define SPW_CTRL_RD           (1 << 17)
283
284#define SPW_CTRL_RC           (1 << 29)
285#define SPW_CTRL_RX           (1 << 30)
286#define SPW_CTRL_RA           (1 << 31)
287
288#define SPW_STATUS_TO (1 << 0)
289#define SPW_STATUS_CE (1 << 1)
290#define SPW_STATUS_ER (1 << 2)
291#define SPW_STATUS_DE (1 << 3)
292#define SPW_STATUS_PE (1 << 4)
293#define SPW_STATUS_WE (1 << 6)
294#define SPW_STATUS_IA (1 << 7)
295#define SPW_STATUS_EE (1 << 8)
296
297#define SPW_DMACTRL_TXEN (1 << 0)
298#define SPW_DMACTRL_RXEN (1 << 1)
299#define SPW_DMACTRL_TXIE (1 << 2)
300#define SPW_DMACTRL_RXIE (1 << 3)
301#define SPW_DMACTRL_AI   (1 << 4)
302#define SPW_DMACTRL_PS   (1 << 5)
303#define SPW_DMACTRL_PR   (1 << 6)
304#define SPW_DMACTRL_TA   (1 << 7)
305#define SPW_DMACTRL_RA   (1 << 8)
306#define SPW_DMACTRL_AT   (1 << 9)
307#define SPW_DMACTRL_RX   (1 << 10)
308#define SPW_DMACTRL_RD   (1 << 11)
309#define SPW_DMACTRL_NS   (1 << 12)
310
311#define SPW_PREPAREMASK_TX (SPW_DMACTRL_RXEN | SPW_DMACTRL_RXIE | SPW_DMACTRL_PS | SPW_DMACTRL_TA | SPW_DMACTRL_RD | SPW_DMACTRL_NS)
312#define SPW_PREPAREMASK_RX (SPW_DMACTRL_TXEN | SPW_DMACTRL_TXIE | SPW_DMACTRL_AI | SPW_DMACTRL_PR | SPW_DMACTRL_RA)
313
314static int grspw_hw_init(GRSPW_DEV *pDev);
315static int grspw_hw_send(GRSPW_DEV *pDev, unsigned int hlen, char *hdr, unsigned int dlen, char *data);
316static int grspw_hw_receive(GRSPW_DEV *pDev,char *b,int c);
317static int grspw_hw_startup (GRSPW_DEV *pDev, int timeout);
318static int grspw_hw_stop (GRSPW_DEV *pDev, int rx, int tx);
319static void grspw_hw_wait_rx_inactive(GRSPW_DEV *pDev);
320static int grspw_hw_waitlink (GRSPW_DEV *pDev, int timeout);
321static void grspw_hw_reset(GRSPW_DEV *pDev);
322static void grspw_hw_read_config(GRSPW_DEV *pDev);
323
324static void check_rx_errors(GRSPW_DEV *pDev, int ctrl);
325static void grspw_rxnext(GRSPW_DEV *pDev);
326static void grspw_interrupt(GRSPW_DEV *pDev);
327
328static rtems_device_driver grspw_initialize(
329        rtems_device_major_number  major,
330        rtems_device_minor_number  minor,
331        void                    * arg
332        );
333
334static rtems_device_driver grspw_open(
335        rtems_device_major_number major,
336        rtems_device_minor_number minor,
337        void                    * arg
338        );
339
340static rtems_device_driver grspw_close(
341        rtems_device_major_number major,
342        rtems_device_minor_number minor,
343        void                    * arg
344        );
345
346static rtems_device_driver grspw_read(
347        rtems_device_major_number major,
348        rtems_device_minor_number minor,
349        void                    * arg
350        );
351
352static rtems_device_driver grspw_write(
353        rtems_device_major_number major,
354        rtems_device_minor_number minor,
355        void                    * arg
356        );
357
358static rtems_device_driver grspw_control(
359        rtems_device_major_number major,
360        rtems_device_minor_number minor,
361        void                    * arg
362        );
363
364#define GRSPW_DRIVER_TABLE_ENTRY \
365  { grspw_initialize, \
366    grspw_open, \
367    grspw_close, \
368    grspw_read, \
369    grspw_write, \
370    grspw_control }
371
372static rtems_driver_address_table grspw_driver = GRSPW_DRIVER_TABLE_ENTRY;
373static amba_confarea_type *amba_bus;
374
375int GRSPW_PREFIX(_register)(amba_confarea_type *bus)
376{
377        rtems_status_code r;
378        rtems_device_major_number m;
379       
380        /* Get System clock frequency */
381        sys_freq_khz = 0;
382       
383        amba_bus = bus;
384       
385        /* Auto Detect the GRSPW core frequency by assuming that the system frequency is
386         * is the same as the GRSPW core frequency.
387         */
388#ifndef SYS_FREQ_KHZ
389#ifdef LEON3
390        /* LEON3: find timer address via AMBA Plug&Play info */
391        {
392                amba_apb_device gptimer;
393                LEON3_Timer_Regs_Map *tregs;
394               
395                if ( amba_find_apbslv(&amba_conf,VENDOR_GAISLER,GAISLER_GPTIMER,&gptimer) == 1 ){
396                        tregs = (LEON3_Timer_Regs_Map *)gptimer.start;
397                        sys_freq_khz = (tregs->scaler_reload+1)*1000;
398                        SPACEWIRE_DBG("GRSPW: detected %dkHZ system frequency\n\r",sys_freq_khz);
399                }else{
400                        sys_freq_khz = 40000; /* Default to 40MHz */
401                        printk("GRSPW: Failed to detect system frequency\n\r");
402                }
403               
404        }
405#elif defined(LEON2)
406        /* LEON2: use hardcoded address to get to timer */
407        {
408                LEON_Register_Map *regs = (LEON_Register_Map *)0x80000000;
409                sys_freq_khz = (regs->Scaler_Reload+1)*1000;
410        }
411#else
412 #error CPU not supported by GRSPW driver
413#endif
414#else
415        /* Use hardcoded frequency */
416        sys_freq_khz = SYS_FREQ_KHZ;
417#endif       
418                       
419        SPACEWIRE_DBG2("register driver\n");
420        if ((r = rtems_io_register_driver(0, &grspw_driver, &m)) == RTEMS_SUCCESSFUL) {
421                SPACEWIRE_DBG2("success\n");
422                return 0;
423        } else {
424                switch(r) {
425                        case RTEMS_TOO_MANY:
426                                SPACEWIRE_DBG2("failed RTEMS_TOO_MANY\n");
427                                break;
428                        case RTEMS_INVALID_NUMBER:
429                                SPACEWIRE_DBG2("failed RTEMS_INVALID_NUMBER\n");
430                                break;
431                        case RTEMS_RESOURCE_IN_USE:
432                                SPACEWIRE_DBG2("failed RTEMS_RESOURCE_IN_USE\n");
433                                break;
434                        default:
435                                SPACEWIRE_DBG("failed %i\n",r);
436                                break;
437                }
438                return 1;
439        }
440       
441}
442
443/* Get a value at least 6.4us in number of clock cycles */
444static unsigned int grspw_calc_timer64(int freq_khz){
445        unsigned int timer64 = (freq_khz*64+9999)/10000;
446        return timer64 & 0xfff;
447}
448
449/* Get a value at least 850ns in number of clock cycles - 3 */
450static unsigned int grspw_calc_disconnect(int freq_khz){
451        unsigned int disconnect = ((freq_khz*85+99999)/100000) - 3;
452        return disconnect & 0x3ff;
453}
454
455#if 0
456static int grspw_buffer_alloc(GRSPW_DEV *pDev) {
457        if (pDev->ptr_rxbuf0) {
458                free(pDev->ptr_rxbuf0);
459        }
460        if (pDev->ptr_txdbuf0) {
461                free(pDev->ptr_txdbuf0);
462        }
463        if (pDev->ptr_txhbuf0) {
464                free(pDev->ptr_txhbuf0);
465        }
466        pDev->ptr_rxbuf0 = (char *) malloc(pDev->rxbufsize * pDev->rxbufcnt);
467        pDev->ptr_txdbuf0 = (char *) malloc(pDev->txdbufsize * pDev->txbufcnt);
468        pDev->ptr_txhbuf0 = (char *) malloc(pDev->txhbufsize * pDev->txbufcnt);
469        if ((pDev->ptr_rxbuf0 == NULL) ||
470            (pDev->ptr_txdbuf0 == NULL) || (pDev->ptr_txhbuf0 == NULL)) {
471                return 1;
472        } else {
473                return 0;
474        }
475}
476#endif
477
478static int grspw_buffer_alloc(GRSPW_DEV *pDev)
479{
480#ifndef GRSPW_STATIC_MEM
481        if (pDev->ptr_rxbuf0) {
482                free(pDev->ptr_rxbuf0);
483        }
484        if (pDev->ptr_txdbuf0) {
485                free(pDev->ptr_txdbuf0);
486        }
487        if (pDev->ptr_txhbuf0) {
488                free(pDev->ptr_txhbuf0);
489        }
490                               
491        pDev->ptr_rxbuf0 = (char *) malloc(pDev->rxbufsize * pDev->rxbufcnt);
492        pDev->ptr_txdbuf0 = (char *) malloc(pDev->txdbufsize * pDev->txbufcnt);
493        pDev->ptr_txhbuf0 = (char *) malloc(pDev->txhbufsize * pDev->txbufcnt);
494        if ((pDev->ptr_rxbuf0 == NULL) ||
495            (pDev->ptr_txdbuf0 == NULL) || (pDev->ptr_txhbuf0 == NULL)) {
496                return 1;
497        } else {
498                return 0;
499        }
500#else
501        if ( (pDev->membase + pDev->rxbufsize*pDev->rxbufcnt + pDev->txdbufsize*pDev->txbufcnt) >= pDev->memend ) {
502                return -1;
503        }
504        pDev->ptr_rxbuf0  = (char *) pDev->membase;
505        pDev->ptr_txdbuf0 = pDev->ptr_rxbuf0 + pDev->rxbufsize * pDev->rxbufcnt;
506        pDev->ptr_txhbuf0 = pDev->ptr_txdbuf0 + pDev->txdbufsize * pDev->txbufcnt;
507        return 0;
508#endif
509
510}
511
512#ifdef GRSPW_DEFINE_INTHANDLER
513/*
514 *  Standard Interrupt handler
515 */
516static rtems_isr grspw_interrupt_handler(rtems_vector_number v)
517{
518        int minor;
519
520        for(minor = 0; minor < spw_cores+spw_cores2; minor++) {
521                if (v == (grspw_devs[minor].irq+0x10) ) {
522                        grspw_interrupt(&grspw_devs[minor]);
523                        break;
524                }
525        }
526}
527#endif
528
529static void grspw_interrupt(GRSPW_DEV *pDev){
530        int dmactrl;
531        int status;
532        int ctrl;
533                               
534        status = SPW_STATUS_READ(pDev);
535        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);
536        dmactrl = SPW_READ(&pDev->regs->dma0ctrl);
537        SPW_WRITE(&pDev->regs->dma0ctrl, dmactrl | SPW_DMACTRL_PR);
538        /* If linkinterrupts are enabled check if it was a linkerror irq and then send an event to the
539           process set in the config */
540        if (pDev->config.link_err_irq) {
541                if (status & (SPW_STATUS_CE | SPW_STATUS_ER | SPW_STATUS_DE | SPW_STATUS_PE | SPW_STATUS_WE)) {
542                        rtems_event_send(pDev->config.event_id, SPW_LINKERR_EVENT);
543                        if (pDev->config.disable_err) {
544                                /* disable link*/
545                                SPW_CTRL_WRITE(pDev, (SPW_CTRL_READ(pDev) & 0xFFFFFFFC) | SPW_CTRL_LINKDISABLED);
546                                pDev->config.linkdisabled = 1;
547                                pDev->config.linkstart = 0;
548                                pDev->running = 0;
549                        }
550                }
551        }
552        if (status & SPW_STATUS_CE) {
553                pDev->stat.credit_err++;
554        }
555        if (status & SPW_STATUS_ER) {
556                pDev->stat.escape_err++;
557        }
558        if (status & SPW_STATUS_DE) {
559                pDev->stat.disconnect_err++;
560        }
561        if (status & SPW_STATUS_PE) {
562                pDev->stat.parity_err++;
563        }
564        if (status & SPW_STATUS_WE) {
565                pDev->stat.write_sync_err++;
566        }
567        if (status & SPW_STATUS_IA) {
568                pDev->stat.invalid_address++;
569        }
570        if (status & SPW_STATUS_EE) {
571                pDev->stat.early_ep++;
572        }
573               
574        /* Check for tx interrupts */
575        while( (pDev->tx_sent != pDev->tx_cur) || pDev->tx_all_in_use) {
576                /* Has this descriptor been sent? */
577                ctrl = SPW_READ((volatile void *)&pDev->tx[pDev->tx_sent].ctrl);
578                if ( ctrl & SPW_TXBD_EN ) {
579                        break;
580                }
581                /* Yes, increment status counters & tx_sent so we can use this descriptor to send more packets with */
582                pDev->stat.packets_sent++;
583                       
584                rtems_semaphore_release(pDev->txsp);
585                       
586                if ( ctrl & SPW_TXBD_LE ) {
587                        pDev->stat.tx_link_err++;
588                }
589                       
590                /* step to next descriptor */
591                pDev->tx_sent = (pDev->tx_sent + 1) % pDev->txbufcnt;
592                pDev->tx_all_in_use = 0; /* not all of the descriptors can be in use since we just freed one. */
593        }
594               
595        /* Check for rx interrupts */
596        if (dmactrl & SPW_DMACTRL_PR) {
597                rtems_semaphore_release(pDev->rxsp);
598        }
599}
600
601static rtems_device_driver grspw_initialize(
602        rtems_device_major_number  major,
603        rtems_device_minor_number  minor,
604        void                      *arg
605)
606{
607        rtems_status_code status;
608        int i=0;
609        char c;
610        GRSPW_DEV *pDev;
611        char console_name[20];
612                                amba_apb_device dev;
613                               
614        SPACEWIRE_DBG2("spacewire driver initialization\n");       
615       
616        /* Copy device name */
617        strcpy(console_name,GRSPW_DEVNAME);
618       
619        /* Get the number of GRSPW cores */
620        i=0; spw_cores = 0; spw_cores2 = 0;
621
622        /* get number of GRSPW cores */
623        spw_cores = amba_get_number_apbslv_devices(amba_bus,VENDOR_GAISLER,GAISLER_SPACEWIRE);
624        spw_cores2 = amba_get_number_apbslv_devices(amba_bus,VENDOR_GAISLER,GAISLER_GRSPW2);
625#if 0
626                                if ( spw_cores > SPACEWIRE_MAX_CORENR )
627                                        spw_cores = SPACEWIRE_MAX_CORENR;
628
629        while (i < amba_conf.apbslv.devnr) {
630                conf = amba_get_confword(amba_conf.apbslv, i, 0);
631                if ((amba_vendor(conf) == VENDOR_GAISLER) && (amba_device(conf) == GAISLER_SPACEWIRE))
632                        spw_cores++;
633                i++;
634        }
635#endif
636       
637        if ( (spw_cores+spw_cores2) < 1 ){
638                /* No GRSPW cores around... */
639                return RTEMS_SUCCESSFUL;
640        }
641       
642        /* Allocate memory for all spacewire cores */
643        grspw_devs = (GRSPW_DEV *)malloc((spw_cores+spw_cores2) * sizeof(GRSPW_DEV));
644       
645        /* Zero out all memory */
646        memset(grspw_devs,0,(spw_cores+spw_cores2) * sizeof(GRSPW_DEV));
647       
648        /* loop all found spacewire cores */
649        i = 0;
650        for(minor=0; minor<(spw_cores+spw_cores2); minor++){
651
652                pDev = &grspw_devs[minor];
653               
654                /* Get device */
655                if ( spw_cores > minor ) {
656                        amba_find_next_apbslv(amba_bus,VENDOR_GAISLER,GAISLER_SPACEWIRE,&dev,minor);
657                        pDev->core_ver = 1;
658                } else {
659                        amba_find_next_apbslv(amba_bus,VENDOR_GAISLER,GAISLER_GRSPW2,&dev,minor-spw_cores);
660                        pDev->core_ver = 2;
661                }
662               
663                pDev->regs = (LEON3_SPACEWIRE_Regs_Map *)dev.start;
664                pDev->irq = dev.irq;
665                pDev->minor = minor;
666                pDev->open = 0;
667
668                /* register interrupt routine */
669                GRSPW_REG_INT(GRSPW_PREFIX(_interrupt_handler), pDev->irq, pDev);
670               
671                SPACEWIRE_DBG("spacewire core at [0x%x]\n", (unsigned int) pDev->regs);
672
673                /* initialize the code with some resonable values,
674                   actual initialization is done later using ioctl(fd)
675                   on the opened device */
676                pDev->config.rxmaxlen = SPACEWIRE_RXPCK_SIZE;
677                pDev->txdbufsize = SPACEWIRE_TXD_SIZE;
678                pDev->txhbufsize = SPACEWIRE_TXH_SIZE;
679                pDev->rxbufsize = SPACEWIRE_RXPCK_SIZE;
680                pDev->txbufcnt = SPACEWIRE_TXBUFS_NR;
681                pDev->rxbufcnt = SPACEWIRE_RXBUFS_NR;
682                pDev->config.check_rmap_err = 0;
683                pDev->config.tx_blocking = 0;
684                pDev->config.tx_block_on_full = 0;
685                pDev->config.rx_blocking = 0;
686                pDev->config.disable_err = 0;
687                pDev->config.link_err_irq = 0;
688                pDev->config.event_id = 0;
689               
690                pDev->ptr_rxbuf0 = 0;
691                pDev->ptr_txdbuf0 = 0;
692                pDev->ptr_txhbuf0 = 0;
693                                                               
694#ifdef GRSPW_STATIC_MEM
695                GRSPW_CALC_MEMOFS(spw_cores,minor,&pDev->membase,&pDev->memend,&pDev->mem_bdtable);
696#endif
697               
698                if (grspw_buffer_alloc(pDev))
699                        return RTEMS_NO_MEMORY;
700               
701        }
702 
703        /*  Register Device Names, /dev/grspw0, /dev/grspw1  ... */
704        for (i = 0; i < spw_cores+spw_cores2; i++) {
705           GRSPW_DEVNAME_NO(console_name,i);
706           SPACEWIRE_DBG("registering minor %i as %s\n", i, console_name);
707           status = rtems_io_register_name( console_name, major, i);
708           if (status != RTEMS_SUCCESSFUL){
709              rtems_fatal_error_occurred(status);
710           }
711        }
712 
713        /* Initialize Hardware and semaphores*/
714        c = 'a';
715        for (i = 0; i < spw_cores+spw_cores2; i++) {
716                pDev = &grspw_devs[i];
717                rtems_semaphore_create(
718                        rtems_build_name('T', 'x', 'S', c),
719                        0,
720                        RTEMS_FIFO | RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_NO_INHERIT_PRIORITY | \
721                        RTEMS_NO_PRIORITY_CEILING,
722                        0,
723                        &(pDev->txsp));
724                rtems_semaphore_create(
725                        rtems_build_name('R', 'x', 'S', c),
726                        0,
727                        RTEMS_FIFO | RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_NO_INHERIT_PRIORITY | \
728                        RTEMS_NO_PRIORITY_CEILING,
729                        0,
730                        &(pDev->rxsp));
731                c++;
732                grspw_hw_init(pDev);
733        }
734       
735        return RTEMS_SUCCESSFUL;
736}
737
738static rtems_device_driver grspw_open(
739        rtems_device_major_number major,
740        rtems_device_minor_number minor,
741        void                    * arg
742        )
743{
744        GRSPW_DEV *pDev;
745        SPACEWIRE_DBGC(DBGSPW_IOCALLS, "open [%i,%i]\n", major, minor);
746        if ( minor >= (spw_cores+spw_cores2) ) {
747                SPACEWIRE_DBG("minor %i too big\n", minor);
748                return RTEMS_INVALID_NAME;
749        }
750        pDev = &grspw_devs[minor];
751       
752        if ( pDev->open )
753                return RTEMS_RESOURCE_IN_USE;
754       
755        /* Mark device open */
756        pDev->open = 1;
757       
758        pDev->stat.tx_link_err = 0;
759        pDev->stat.rx_rmap_header_crc_err = 0;
760        pDev->stat.rx_rmap_data_crc_err = 0;
761        pDev->stat.rx_eep_err = 0;
762        pDev->stat.rx_truncated = 0;
763        pDev->stat.parity_err = 0;
764        pDev->stat.escape_err = 0;
765        pDev->stat.credit_err = 0;
766        pDev->stat.write_sync_err = 0;
767        pDev->stat.disconnect_err = 0;
768        pDev->stat.early_ep = 0;
769        pDev->stat.invalid_address = 0;
770        pDev->stat.packets_sent = 0;
771        pDev->stat.packets_received = 0;
772       
773        pDev->running = 0;
774        pDev->core_freq_khz = 0;
775       
776        /* Reset Core */
777        grspw_hw_reset(pDev);
778       
779        /* Read default configuration */
780        grspw_hw_read_config(pDev);
781       
782        return RTEMS_SUCCESSFUL;
783}
784
785static rtems_device_driver grspw_close(
786        rtems_device_major_number major,
787        rtems_device_minor_number minor,
788        void                    * arg
789        )
790{       
791        GRSPW_DEV *pDev = &grspw_devs[minor];
792       
793        SPACEWIRE_DBGC(DBGSPW_IOCALLS, "close [%i,%i]\n", major, minor);       
794        rtems_semaphore_delete(pDev->txsp);
795        rtems_semaphore_delete(pDev->rxsp);
796
797        grspw_hw_stop(pDev,1,1);
798       
799        grspw_hw_reset(pDev);
800       
801        /* Mark device closed - not open */
802        pDev->open = 0;
803       
804        return RTEMS_SUCCESSFUL;
805}
806
807static rtems_device_driver grspw_read(
808        rtems_device_major_number major,
809        rtems_device_minor_number minor,
810        void                    * arg
811        )
812{
813        GRSPW_DEV *pDev = &grspw_devs[minor];
814        rtems_libio_rw_args_t *rw_args;
815        unsigned int count = 0;
816        rw_args = (rtems_libio_rw_args_t *) arg;
817       
818        /* is link up? */
819        if ( !pDev->running ) {
820                return RTEMS_INVALID_NAME;
821        }
822       
823        if ((rw_args->count < 1) || (rw_args->buffer == NULL)) {
824                return RTEMS_INVALID_NAME;
825        }
826       
827        SPACEWIRE_DBGC(DBGSPW_IOCALLS, "read  [%i,%i]: buf:0x%x len:%i \n", major, minor, (unsigned int)rw_args->buffer, rw_args->count);
828       
829        while ( (count = grspw_hw_receive(pDev, rw_args->buffer, rw_args->count)) == 0) {
830                /* wait a moment for any descriptors to get available
831                 *
832                 * Semaphore is signaled by interrupt handler
833                 */
834                if (pDev->config.rx_blocking) {
835                        SPACEWIRE_DBG2("Rx blocking\n");
836                        rtems_semaphore_obtain(pDev->rxsp, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
837                } else {
838                        SPACEWIRE_DBG2("Rx non blocking\n");
839                        return RTEMS_RESOURCE_IN_USE;
840                }
841        }
842       
843#ifdef DEBUG_SPACEWIRE_ONOFF 
844        if (DEBUG_SPACEWIRE_FLAGS & DBGSPW_DUMP) {
845                int k;
846                for (k = 0; k < count; k++){
847                        if (k % 16 == 0) {
848                                printf ("\n");
849                        }
850                        printf ("%.2x(%c) ", rw_args->buffer[k] & 0xff, isprint(rw_args->buffer[k] & 0xff) ? rw_args->buffer[k] & 0xff : ' ');
851                }
852                printf ("\n");
853        }
854#endif
855       
856        rw_args->bytes_moved = count;
857        return RTEMS_SUCCESSFUL;
858       
859}
860
861static rtems_device_driver grspw_write(
862        rtems_device_major_number major,
863        rtems_device_minor_number minor,
864        void                    * arg
865)
866{
867        GRSPW_DEV *pDev = &grspw_devs[minor];
868        rtems_libio_rw_args_t *rw_args;
869        rw_args = (rtems_libio_rw_args_t *) arg;
870        SPACEWIRE_DBGC(DBGSPW_IOCALLS, "write [%i,%i]: buf:0x%x len:%i\n", major, minor, (unsigned int)rw_args->buffer, rw_args->count);
871
872        /* is link up? */
873        if ( !pDev->running ) {
874                return RTEMS_INVALID_NAME;
875        }
876
877        if ((rw_args->count > pDev->txdbufsize) || (rw_args->count < 1) || (rw_args->buffer == NULL)) {
878                return RTEMS_INVALID_NAME;
879        }
880
881        while ((rw_args->bytes_moved = grspw_hw_send(pDev, 0, NULL, rw_args->count, rw_args->buffer)) == 0) {
882                if (pDev->config.tx_block_on_full == 1) {
883                        SPACEWIRE_DBG2("Tx Block on full \n");
884                        rtems_semaphore_obtain(pDev->txsp, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
885                } else {
886                        SPACEWIRE_DBG2("Tx non blocking return when full \n");
887                        return RTEMS_RESOURCE_IN_USE;
888                }
889        }
890        return RTEMS_SUCCESSFUL;
891}
892
893static rtems_device_driver grspw_control(
894        rtems_device_major_number major,
895        rtems_device_minor_number minor,
896        void                    * arg
897        )
898{
899        GRSPW_DEV *pDev = &grspw_devs[minor];
900        spw_ioctl_pkt_send *args;
901        spw_ioctl_packetsize *ps;
902        int status;
903        unsigned int tmp,nodeaddr,nodemask;
904        int timeout;
905        rtems_device_driver ret;
906        rtems_libio_ioctl_args_t        *ioarg = (rtems_libio_ioctl_args_t *) arg;
907        SPACEWIRE_DBGC(DBGSPW_IOCALLS, "ctrl [%i,%i]\n", major, minor);
908       
909        if (!ioarg)
910                return RTEMS_INVALID_NAME;
911
912       
913        ioarg->ioctl_return = 0;
914        switch(ioarg->command) {
915                case SPACEWIRE_IOCTRL_SET_NODEADDR:
916                        /*set node address*/
917                        SPACEWIRE_DBGC(DBGSPW_IOCTRL, "SPACEWIRE_IOCTRL_SET_NODEADDR %i\n",(unsigned int)ioarg->buffer);
918                        if ((unsigned int)ioarg->buffer > 255) {
919                                return RTEMS_INVALID_NAME;
920                        }
921                        nodeaddr = ((unsigned int)ioarg->buffer) & 0xff;
922                        tmp = SPW_READ(&pDev->regs->nodeaddr);
923                        tmp &= 0xffffff00; /* Remove old address */
924                        tmp |= nodeaddr;
925                        SPW_WRITE(&pDev->regs->nodeaddr, tmp);
926                        if ((SPW_READ(&pDev->regs->nodeaddr)&0xff) != nodeaddr) {
927                                return RTEMS_IO_ERROR;
928                        }
929                        pDev->config.nodeaddr = nodeaddr;
930                        break;
931                case SPACEWIRE_IOCTRL_SET_NODEMASK:
932                        /*set node address*/
933                        SPACEWIRE_DBGC(DBGSPW_IOCTRL, "SPACEWIRE_IOCTRL_SET_NODEMASK %i\n",(unsigned int)ioarg->buffer);
934                        if ( pDev->core_ver > 1 ){
935                          if ((unsigned int)ioarg->buffer > 255) {
936                                  return RTEMS_INVALID_NAME;
937                          }
938                          nodemask = ((unsigned int)ioarg->buffer) & 0xff;
939                          tmp = SPW_READ(&pDev->regs->nodeaddr);
940                          tmp &= 0xffff00ff; /* Remove old mask */
941                          tmp |= nodemask<<8;
942                          SPW_WRITE(&pDev->regs->nodeaddr, tmp);
943                          if (((SPW_READ(&pDev->regs->nodeaddr)>>8)&0xff) != nodemask) {
944                                  return RTEMS_IO_ERROR;
945                          }
946                          pDev->config.nodemask = nodemask;
947                        }else{
948                          SPACEWIRE_DBG("SPACEWIRE_IOCTRL_SET_NODEMASK: not implemented in GRSPW1 HW\n");
949                        }
950                        break;
951                case SPACEWIRE_IOCTRL_SET_RXBLOCK:
952                        SPACEWIRE_DBGC(DBGSPW_IOCTRL, "SPACEWIRE_IOCTRL_SET_RXBLOCK %i \n", (unsigned int)ioarg->buffer);
953                        if ((unsigned int)ioarg->buffer > 1) {
954                                return RTEMS_INVALID_NAME;
955                        }
956                        pDev->config.rx_blocking = (unsigned int)ioarg->buffer;
957                        break;
958                case SPACEWIRE_IOCTRL_SET_DESTKEY:
959                        SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_SET_DESTKEY %i\n", (unsigned int)ioarg->buffer);
960                        if (!pDev->config.is_rmap) {
961                                return RTEMS_NOT_IMPLEMENTED;
962                        }
963                        if ((unsigned int)ioarg->buffer > 255) {
964                                return RTEMS_INVALID_NAME;
965                        }
966                        SPW_WRITE(&pDev->regs->destkey, (unsigned int)ioarg->buffer);
967                        if (SPW_READ(&pDev->regs->destkey) != (unsigned int)ioarg->buffer) {
968                                return RTEMS_IO_ERROR;
969                        }
970                        pDev->config.destkey = (unsigned int)ioarg->buffer;
971                        break;
972                case SPACEWIRE_IOCTRL_SET_CLKDIV:
973                        SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_SET_CLKDIV %i\n", (unsigned int)ioarg->buffer);
974                        if ((unsigned int)ioarg->buffer > 255) {
975                                return RTEMS_INVALID_NAME;
976                        }
977                        tmp = SPW_READ(&pDev->regs->clkdiv);
978                        tmp &= ~0xff; /* Remove old Clockdiv Setting */
979                        tmp |= ((unsigned int)ioarg->buffer) & 0xff; /* add new clockdiv setting */
980                        SPW_WRITE(&pDev->regs->clkdiv, tmp);
981                        if (SPW_READ(&pDev->regs->clkdiv) != tmp) {
982                                return RTEMS_IO_ERROR;
983                        }
984                        pDev->config.clkdiv = tmp;
985                        break;
986                case SPACEWIRE_IOCTRL_SET_CLKDIVSTART:
987                        SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_SET_CLKDIVSTART %i\n", (unsigned int)ioarg->buffer);
988                        if ((unsigned int)ioarg->buffer > 255) {
989                                return RTEMS_INVALID_NAME;
990                        }
991                        tmp = SPW_READ(&pDev->regs->clkdiv);
992                        tmp &= ~0xff00; /* Remove old Clockdiv Start Setting */
993                        tmp |= (((unsigned int)ioarg->buffer) & 0xff)<<8; /* add new clockdiv start setting */
994                        SPW_WRITE(&pDev->regs->clkdiv, tmp);
995                        if (SPW_READ(&pDev->regs->clkdiv) != tmp) {
996                                return RTEMS_IO_ERROR;
997                        }
998                        pDev->config.clkdiv = tmp;
999                        break;                       
1000                case SPACEWIRE_IOCTRL_SET_TIMER:
1001                        SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_SET_TIMER %i\n", (unsigned int)ioarg->buffer);
1002                        if ( pDev->core_ver <= 1 ) {
1003                          if ((unsigned int)ioarg->buffer > 4095) {
1004                                  return RTEMS_INVALID_NAME;
1005                          }
1006                          SPW_WRITE(&pDev->regs->timer, (SPW_READ(&pDev->regs->timer) & 0xFFFFF000) | ((unsigned int)ioarg->buffer & 0xFFF));
1007                          if ((SPW_READ(&pDev->regs->timer) & 0xFFF) != (unsigned int)ioarg->buffer) {
1008                                  return RTEMS_IO_ERROR;
1009                          }
1010                          pDev->config.timer = (unsigned int)ioarg->buffer;
1011                        }else{
1012                          SPACEWIRE_DBG("SPACEWIRE_IOCTRL_SET_TIMER: removed in GRSPW2 HW\n");
1013                        }
1014                        break;
1015                case SPACEWIRE_IOCTRL_SET_DISCONNECT:
1016                        SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_SET_DISCONNECT %i\n", (unsigned int)ioarg->buffer);
1017                        if ( pDev->core_ver <= 1 ) {
1018                          if ((unsigned int)ioarg->buffer > 1023) {
1019                                  return RTEMS_INVALID_NAME;
1020                          }
1021                          SPW_WRITE(&pDev->regs->timer, (SPW_READ(&pDev->regs->timer) & 0xFFC00FFF) | (((unsigned int)ioarg->buffer & 0x3FF) << 12));
1022                          if (((SPW_READ(&pDev->regs->timer) >> 12) & 0x3FF) != (unsigned int)ioarg->buffer) {
1023                                  return RTEMS_IO_ERROR;
1024                          }
1025                          pDev->config.disconnect = (unsigned int)ioarg->buffer;
1026                        }else{
1027                          SPACEWIRE_DBG("SPACEWIRE_IOCTRL_SET_DISCONNECT: not implemented for GRSPW2\n");
1028                        }
1029                        break;
1030                case SPACEWIRE_IOCTRL_SET_PROMISCUOUS:       
1031                        SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_SET_PROMISCUOUS %i \n", (unsigned int)ioarg->buffer);
1032                        if ((unsigned int)ioarg->buffer > 1) {
1033                                return RTEMS_INVALID_NAME;
1034                        }
1035                        SPW_CTRL_WRITE(pDev, SPW_CTRL_READ(pDev) | ((unsigned int)ioarg->buffer << 5));
1036                        if (((SPW_CTRL_READ(pDev) >> 5) & 1) != (unsigned int)ioarg->buffer) {
1037                                return RTEMS_IO_ERROR;
1038                        }
1039                        pDev->config.promiscuous = (unsigned int)ioarg->buffer;
1040                        break;
1041                case SPACEWIRE_IOCTRL_SET_RMAPEN:
1042                        SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_SET_RMAPEN %i \n", (unsigned int)ioarg->buffer);
1043                        if ((unsigned int)ioarg->buffer > 1) {
1044                                return RTEMS_INVALID_NAME;
1045                        }
1046                        SPW_CTRL_WRITE(pDev, (SPW_STATUS_READ(pDev) & 0xFFFEFFFF) | ((unsigned int)ioarg->buffer << 16));
1047                        if (((SPW_CTRL_READ(pDev) >> 16) & 1) != (unsigned int)ioarg->buffer) {
1048                                return RTEMS_IO_ERROR;
1049                        }
1050                        pDev->config.rmapen = (unsigned int)ioarg->buffer;
1051                        break;
1052                case SPACEWIRE_IOCTRL_SET_RMAPBUFDIS:
1053                        SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_SET_RMAPBUFDIS %i \n", (unsigned int)ioarg->buffer);
1054                        if ((unsigned int)ioarg->buffer > 1) {
1055                                return RTEMS_INVALID_NAME;
1056                        }
1057                        SPW_CTRL_WRITE(pDev, (SPW_STATUS_READ(pDev) & 0xFFFDFFFF) | ((unsigned int)ioarg->buffer << 17));
1058                        if (((SPW_CTRL_READ(pDev) >> 17) & 1) != (unsigned int)ioarg->buffer) {
1059                                return RTEMS_IO_ERROR;
1060                        }
1061                        pDev->config.rmapbufdis = (unsigned int)ioarg->buffer;
1062                        break;
1063                case SPACEWIRE_IOCTRL_SET_CHECK_RMAP:
1064                        SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_SET_CHECK_RMAP %i \n", (unsigned int)ioarg->buffer);
1065                        if ((unsigned int)ioarg->buffer > 1) {
1066                                return RTEMS_INVALID_NAME;
1067                        }
1068                        pDev->config.check_rmap_err = (unsigned int)ioarg->buffer;
1069                        break;
1070                case SPACEWIRE_IOCTRL_SET_RM_PROT_ID:
1071                        SPACEWIRE_DBGC(DBGSPW_IOCTRL, "SPACEWIRE_IOCTRL_SET_RM_PROT_ID %i \n", (unsigned int)ioarg->buffer);
1072                        if ((unsigned int)ioarg->buffer > 1) {
1073                                return RTEMS_INVALID_NAME;
1074                        }
1075                        pDev->config.rm_prot_id = (unsigned int)ioarg->buffer;
1076                        break;
1077                case SPACEWIRE_IOCTRL_SET_TXBLOCK:
1078                        SPACEWIRE_DBGC(DBGSPW_IOCTRL, "SPACEWIRE_IOCTRL_SET_TXBLOCK %i \n", (unsigned int)ioarg->buffer);
1079                        if ((unsigned int)ioarg->buffer > 1) {
1080                                return RTEMS_INVALID_NAME;
1081                        }
1082                        pDev->config.tx_blocking = (unsigned int)ioarg->buffer;
1083                        break;
1084                case SPACEWIRE_IOCTRL_SET_TXBLOCK_ON_FULL:
1085                        SPACEWIRE_DBGC(DBGSPW_IOCTRL, "SPACEWIRE_IOCTRL_SET_TXBLOCK_ON_FULL %i \n", (unsigned int)ioarg->buffer);
1086                        if ((unsigned int)ioarg->buffer > 1) {
1087                                return RTEMS_INVALID_NAME;
1088                        }
1089                        pDev->config.tx_block_on_full = (unsigned int)ioarg->buffer;
1090                        break;       
1091                case SPACEWIRE_IOCTRL_SET_DISABLE_ERR:
1092                        SPACEWIRE_DBGC(DBGSPW_IOCTRL, "SPACEWIRE_IOCTRL_SET_DISABLE_ERR %i \n", (unsigned int)ioarg->buffer);
1093                        if ((unsigned int)ioarg->buffer > 1) {
1094                                return RTEMS_INVALID_NAME;
1095                        }
1096                        pDev->config.disable_err = (unsigned int)ioarg->buffer;
1097                        break;
1098                case SPACEWIRE_IOCTRL_SET_LINK_ERR_IRQ:
1099                        SPACEWIRE_DBGC(DBGSPW_IOCTRL, "SPACEWIRE_IOCTRL_SET_LINK_ERR_IRQ %i \n", (unsigned int)ioarg->buffer);
1100                        SPACEWIRE_DBGC(DBGSPW_IOCTRL, "CTRL REG: %x\n", SPW_CTRL_READ(pDev));
1101                        if ((unsigned int)ioarg->buffer > 1) {
1102                                return RTEMS_INVALID_NAME;
1103                        }
1104                        SPW_CTRL_WRITE(pDev, (SPW_CTRL_READ(pDev) & 0xFFFFFDF7) | ((unsigned int)ioarg->buffer << 9) | (pDev->config.link_err_irq << 3));
1105                        SPACEWIRE_DBGC(DBGSPW_IOCTRL, "CTRL REG: %x\n", SPW_CTRL_READ(pDev));
1106                        if (((SPW_CTRL_READ(pDev) >> 9) & 1) != (unsigned int)ioarg->buffer) {
1107                                return RTEMS_IO_ERROR;
1108                        }
1109                        pDev->config.link_err_irq = (unsigned int)ioarg->buffer;
1110                        break;
1111                case SPACEWIRE_IOCTRL_SET_EVENT_ID:
1112                        SPACEWIRE_DBGC(DBGSPW_IOCTRL, "SPACEWIRE_IOCTRL_SET_EVENT_ID %i \n", (unsigned int)ioarg->buffer);
1113                        pDev->config.event_id = (rtems_id)ioarg->buffer;
1114                        SPACEWIRE_DBGC(DBGSPW_IOCTRL, "Event id: %i\n", pDev->config.event_id);
1115                        break;
1116                       
1117                /* Change MAX Packet size by:
1118                 *  - stop RX/TX (if on)
1119                 *  - wait for hw to complete RX DMA (if on)
1120                 *  - reallocate buffers with new size
1121                 *  - tell hw about new size & start RX/TX again (if previously on)
1122                 */
1123                case SPACEWIRE_IOCTRL_SET_PACKETSIZE:
1124                        if (ioarg->buffer == NULL)
1125                                return RTEMS_INVALID_NAME;
1126                        ps = (spw_ioctl_packetsize*) ioarg->buffer;
1127                        SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_SET_RXPACKETSIZE %i \n", (unsigned int)ioarg->buffer);
1128                       
1129                        tmp = pDev->running;
1130                       
1131                        if ( pDev->running ){
1132                                /* Stop RX */
1133                                grspw_hw_stop(pDev,1,1);
1134                               
1135                                /* If packetsize fails it is good to know if in running mode */
1136                                pDev->running = 0;
1137                               
1138                                /* Wait for Receiver to finnish pending DMA transfers if any */
1139                                grspw_hw_wait_rx_inactive(pDev);
1140                        }
1141                       
1142                        /* Save new buffer sizes */
1143                        pDev->rxbufsize = ps->rxsize;
1144                        pDev->txdbufsize = ps->txdsize;
1145                        pDev->txhbufsize = ps->txhsize;
1146                        pDev->config.rxmaxlen = pDev->rxbufsize;
1147
1148                        /* Free previous buffers & allocate buffers with new size */
1149                        if (grspw_buffer_alloc(pDev))
1150                                return RTEMS_NO_MEMORY;
1151                       
1152                        /* if RX was actived before, we reactive it again */
1153                        if ( tmp ) {
1154                                if ( (status = grspw_hw_startup(pDev,-1)) != RTEMS_SUCCESSFUL ) {
1155                                        return status;
1156                                }
1157                                pDev->running = 1;
1158                        }
1159#if 0
1160                        /* Rewrite previous config which was wasted due to reset in hw_startup */
1161                        SPW_WRITE(&pDev->regs->nodeaddr, pDev->config.nodeaddr);
1162                        SPW_WRITE(&pDev->regs->destkey, pDev->config.destkey);
1163                        SPW_WRITE(&pDev->regs->clkdiv, pDev->config.clkdiv);
1164                        SPW_WRITE(&pDev->regs->timer, pDev->config.timer | ( (pDev->config.disconnect & 0x3FF) << 12) );
1165                        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)) | \
1166                                              (pDev->config.promiscuous << 5) | (pDev->config.rmapen << 16) | (pDev->config.rmapbufdis << 17) | \
1167                                              (pDev->config.linkdisabled) | (pDev->config.linkstart << 1));
1168#endif
1169                        break;
1170                case SPACEWIRE_IOCTRL_GET_CONFIG:
1171                        if (ioarg->buffer == NULL)
1172                                return RTEMS_INVALID_NAME;
1173                        SPACEWIRE_DBG2("SPACEWIRE_IOCTRL_GET_CONFIG \n");
1174                        (*(spw_config *)ioarg->buffer).nodeaddr = pDev->config.nodeaddr;
1175                        (*(spw_config *)ioarg->buffer).nodemask = pDev->config.nodemask;
1176                        (*(spw_config *)ioarg->buffer).destkey = pDev->config.destkey;
1177                        (*(spw_config *)ioarg->buffer).clkdiv = pDev->config.clkdiv;
1178                        (*(spw_config *)ioarg->buffer).rxmaxlen = pDev->config.rxmaxlen;
1179                        (*(spw_config *)ioarg->buffer).timer = pDev->config.timer;
1180                        (*(spw_config *)ioarg->buffer).disconnect = pDev->config.disconnect;
1181                        (*(spw_config *)ioarg->buffer).promiscuous = pDev->config.promiscuous;
1182                        (*(spw_config *)ioarg->buffer).rmapen = pDev->config.rmapen;
1183                        (*(spw_config *)ioarg->buffer).rmapbufdis = pDev->config.rmapbufdis;
1184                        (*(spw_config *)ioarg->buffer).check_rmap_err = pDev->config.check_rmap_err;
1185                        (*(spw_config *)ioarg->buffer).rm_prot_id = pDev->config.rm_prot_id;
1186                        (*(spw_config *)ioarg->buffer).tx_blocking = pDev->config.tx_blocking;
1187                        (*(spw_config *)ioarg->buffer).disable_err = pDev->config.disable_err;
1188                        (*(spw_config *)ioarg->buffer).link_err_irq = pDev->config.link_err_irq;
1189                        (*(spw_config *)ioarg->buffer).event_id = pDev->config.event_id;
1190                        (*(spw_config *)ioarg->buffer).is_rmap = pDev->config.is_rmap;
1191                        (*(spw_config *)ioarg->buffer).is_rmapcrc = pDev->config.is_rmapcrc;
1192                        (*(spw_config *)ioarg->buffer).is_rxunaligned = pDev->config.is_rxunaligned;
1193                        (*(spw_config *)ioarg->buffer).linkdisabled = pDev->config.linkdisabled;
1194                        (*(spw_config *)ioarg->buffer).linkstart = pDev->config.linkstart;
1195                        (*(spw_config *)ioarg->buffer).rx_blocking = pDev->config.rx_blocking;
1196                        (*(spw_config *)ioarg->buffer).tx_block_on_full = pDev->config.tx_block_on_full;
1197                        break;
1198                case SPACEWIRE_IOCTRL_GET_LINK_STATUS:
1199                        SPACEWIRE_DBGC(DBGSPW_IOCTRL,"SPACEWIRE_IOCTRL_GET_STATUS=%i \n", (unsigned int)((SPW_STATUS_READ(pDev) >> 21) & 0x7));
1200                        *(unsigned int *)ioarg->buffer = (unsigned int )((SPW_STATUS_READ(pDev) >> 21) & 0x7);
1201                        break;
1202                case SPACEWIRE_IOCTRL_GET_STATISTICS:
1203                        if (ioarg->buffer == NULL)
1204                                return RTEMS_INVALID_NAME;
1205                        SPACEWIRE_DBG2("SPACEWIRE_IOCTRL_GET_STATISTICS \n");
1206                        (*(spw_stats *)ioarg->buffer).tx_link_err = pDev->stat.tx_link_err;
1207                        (*(spw_stats *)ioarg->buffer).rx_rmap_header_crc_err = pDev->stat.rx_rmap_header_crc_err;
1208                        (*(spw_stats *)ioarg->buffer).rx_rmap_data_crc_err = pDev->stat.rx_rmap_data_crc_err;
1209                        (*(spw_stats *)ioarg->buffer).rx_eep_err =  pDev->stat.rx_eep_err;
1210                        (*(spw_stats *)ioarg->buffer).rx_truncated = pDev->stat.rx_truncated;
1211                        (*(spw_stats *)ioarg->buffer).parity_err = pDev->stat.parity_err;
1212                        (*(spw_stats *)ioarg->buffer).escape_err = pDev->stat.escape_err;
1213                        (*(spw_stats *)ioarg->buffer).credit_err = pDev->stat.credit_err;
1214                        (*(spw_stats *)ioarg->buffer).write_sync_err = pDev->stat.write_sync_err;
1215                        (*(spw_stats *)ioarg->buffer).disconnect_err = pDev->stat.disconnect_err;
1216                        (*(spw_stats *)ioarg->buffer).early_ep = pDev->stat.early_ep;
1217                        (*(spw_stats *)ioarg->buffer).invalid_address = pDev->stat.invalid_address;
1218                        (*(spw_stats *)ioarg->buffer).packets_sent = pDev->stat.packets_sent;
1219                        (*(spw_stats *)ioarg->buffer).packets_received = pDev->stat.packets_received;
1220                        break;
1221                case SPACEWIRE_IOCTRL_CLR_STATISTICS:
1222                        SPACEWIRE_DBG2("SPACEWIRE_IOCTRL_CLR_STATISTICS \n");
1223                        pDev->stat.tx_link_err = 0;
1224                        pDev->stat.rx_rmap_header_crc_err = 0;
1225                        pDev->stat.rx_rmap_data_crc_err = 0;
1226                        pDev->stat.rx_eep_err = 0;
1227                        pDev->stat.rx_truncated = 0;
1228                        pDev->stat.parity_err = 0;
1229                        pDev->stat.escape_err = 0;
1230                        pDev->stat.credit_err = 0;
1231                        pDev->stat.write_sync_err = 0;
1232                        pDev->stat.disconnect_err = 0;
1233                        pDev->stat.early_ep = 0;
1234                        pDev->stat.invalid_address = 0;
1235                        pDev->stat.packets_sent = 0;
1236                        pDev->stat.packets_received = 0;
1237                        break;
1238                case SPACEWIRE_IOCTRL_SEND:
1239                        if (ioarg->buffer == NULL)
1240                                return RTEMS_INVALID_NAME;
1241                        args = (spw_ioctl_pkt_send *)ioarg->buffer;
1242                        args->sent = 0;
1243                       
1244                        /* is link up? */
1245                        if ( !pDev->running ) {
1246                                return RTEMS_INVALID_NAME;
1247                        }
1248       
1249                        SPACEWIRE_DBGC(DBGSPW_IOCALLS, "write [%i,%i]: hlen: %i hbuf:0x%x dlen:%i dbuf:0x%x\n", major, minor,
1250                                       (unsigned int)args->hlen, (int)args->hdr,(unsigned int)args->dlen, (int)args->data);
1251                       
1252                        if ((args->hlen > pDev->txhbufsize) || (args->dlen > pDev->txdbufsize) ||
1253                            ((args->hlen+args->dlen) < 1) ||
1254                            ((args->hdr == NULL) && (args->hlen != 0)) || ((args->data == NULL) && (args->dlen != 0))) {
1255                                return RTEMS_INVALID_NAME;
1256                        }
1257                        while ((args->sent = grspw_hw_send(pDev, args->hlen, args->hdr, args->dlen, args->data)) == 0) {
1258                                if (pDev->config.tx_block_on_full == 1) {
1259                                        SPACEWIRE_DBG2("Tx Block on full \n");
1260                                        rtems_semaphore_obtain(pDev->txsp, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
1261                                } else {
1262                                        SPACEWIRE_DBG2("Tx non blocking return when full \n");
1263                                        return RTEMS_RESOURCE_IN_USE;
1264                                }
1265                        }
1266                        SPACEWIRE_DBGC(DBGSPW_IOCALLS, "Tx ioctl return: %i  \n", args->sent);
1267                        break;
1268
1269                case SPACEWIRE_IOCTRL_LINKDISABLE:
1270                        pDev->config.linkdisabled = 1;
1271                        pDev->config.linkstart = 0;
1272                        SPW_CTRL_WRITE(pDev, (SPW_CTRL_READ(pDev) & 0xFFFFFFFC) | 1);
1273                        if ((SPW_CTRL_READ(pDev) & 3) != 1) {
1274                                return RTEMS_IO_ERROR;
1275                        }
1276                        break;
1277
1278                case SPACEWIRE_IOCTRL_LINKSTART:
1279                        pDev->config.linkdisabled = 0;
1280                        pDev->config.linkstart = 1;
1281                        SPW_CTRL_WRITE(pDev, (SPW_CTRL_READ(pDev) & 0xFFFFFFFC) | 2);
1282                        if ((SPW_CTRL_READ(pDev) & 3) != 2) {
1283                                return RTEMS_IO_ERROR;
1284                        }
1285                        break;
1286               
1287                /* Calculate timer register from GRSPW Core frequency
1288                 * Also possible to set disconnect and timer64 from
1289                 *  - SPACEWIRE_IOCTRL_SET_DISCONNECT
1290                 *  - SPACEWIRE_IOCTRL_SET_TIMER
1291                 */
1292                case SPACEWIRE_IOCTRL_SET_COREFREQ:
1293                        pDev->core_freq_khz = (unsigned int)ioarg->buffer;
1294                        if ( pDev->core_freq_khz == 0 ){
1295                                /* Get GRSPW clock frequency from system clock.
1296                                 * System clock has been read from timer inited
1297                                 * by RTEMS loader (mkprom)
1298                                 */
1299                                 pDev->core_freq_khz = sys_freq_khz;
1300                        }
1301                       
1302                        /* Only GRSPW1 needs the Timer64 and Disconnect values
1303                         * GRSPW2 and onwards doesn't have this register.
1304                         */
1305                        if ( pDev->core_ver <= 1 ){
1306                          /* Calculate Timer64 & Disconnect */
1307                          pDev->config.timer = grspw_calc_timer64(pDev->core_freq_khz);
1308                          pDev->config.disconnect = grspw_calc_disconnect(pDev->core_freq_khz);
1309                         
1310                          /* Set Timer64 & Disconnect Register */
1311                          SPW_WRITE(&pDev->regs->timer,
1312                                 (SPW_READ(&pDev->regs->timer) & 0xFFC00000) |
1313                                 ((pDev->config.disconnect & 0x3FF)<<12) |
1314                                 (pDev->config.timer & 0xFFF));
1315                       
1316                          /* Check that the registers were written successfully */
1317                          tmp = SPW_READ(&pDev->regs->timer) & 0x003fffff;
1318                          if ( ((tmp & 0xFFF) != pDev->config.timer) ||
1319                               (((tmp >> 12) & 0x3FF) != pDev->config.disconnect) ) {
1320                                  return RTEMS_IO_ERROR;
1321                          }
1322                        }
1323                        break;
1324                       
1325                case SPACEWIRE_IOCTRL_START:
1326                        if ( pDev->running ){
1327                                return RTEMS_INVALID_NAME;
1328                        }
1329                       
1330                        /* Get timeout from userspace
1331                         *  timeout:
1332                         *   €  -1           = Default timeout
1333                         *   €  less than -1 = forever
1334                         *   €  0            = no wait, proceed if link is up
1335                         *   €  positive     = specifies number of system clock ticks that
1336                         *                     startup will wait for link to enter ready mode.
1337                         */
1338                        timeout = (int)ioarg->buffer;
1339                       
1340                        if ( (ret=grspw_hw_startup(pDev,timeout)) != RTEMS_SUCCESSFUL ) {
1341                                return ret;
1342                        }
1343                        pDev->running = 1;
1344                        break;
1345               
1346                case SPACEWIRE_IOCTRL_STOP:
1347                        if ( !pDev->running ){
1348                                return RTEMS_INVALID_NAME;
1349                        }
1350                        pDev->running = 0;
1351                       
1352                        /* Stop Receiver and transmitter */
1353                        grspw_hw_stop(pDev,1,1);
1354                        break;
1355               
1356                default:
1357                        return RTEMS_NOT_IMPLEMENTED;
1358        }
1359                   
1360        SPACEWIRE_DBGC(DBGSPW_IOCALLS, "SPW_IOCTRL Return\n");
1361        return RTEMS_SUCCESSFUL;
1362}
1363
1364/* ============================================================================== */
1365
1366static int grspw_set_rxmaxlen(GRSPW_DEV *pDev) {
1367        unsigned int rxmax;
1368        SPW_WRITE(&pDev->regs->dma0rxmax,pDev->config.rxmaxlen); /*set rx maxlength*/
1369        rxmax = SPW_READ(&pDev->regs->dma0rxmax);
1370        if (rxmax != pDev->config.rxmaxlen) {
1371                return 0;
1372        }
1373        return 1;
1374}
1375
1376static int grspw_hw_init(GRSPW_DEV *pDev) {
1377        unsigned int ctrl;
1378       
1379        ctrl = SPW_CTRL_READ(pDev);
1380
1381#ifdef GRSPW_STATIC_MEM
1382        pDev->rx = (SPACEWIRE_RXBD *) pDev->mem_bdtable;
1383        pDev->tx = (SPACEWIRE_RXBD *) pDev->mem_bdtable + SPACEWIRE_BDTABLE_SIZE;
1384#else
1385        pDev->rx = (SPACEWIRE_RXBD *) SPW_ALIGN(&pDev->_rxtable, SPACEWIRE_BDTABLE_SIZE);
1386        pDev->tx = (SPACEWIRE_TXBD *) SPW_ALIGN(&pDev->_txtable, SPACEWIRE_BDTABLE_SIZE);
1387#endif
1388        SPACEWIRE_DBG("hw_init [minor %i]\n", pDev->minor);
1389       
1390        pDev->config.is_rmap = ctrl & SPW_CTRL_RA;
1391        pDev->config.is_rxunaligned = ctrl & SPW_CTRL_RX;
1392        pDev->config.is_rmapcrc = ctrl & SPW_CTRL_RC;
1393        return 0;
1394}
1395
1396static int grspw_hw_waitlink (GRSPW_DEV *pDev, int timeout)
1397{
1398        int j;
1399       
1400        if ( timeout == -1 ){
1401                /* Wait default timeout */
1402                timeout = SPACEWIRE_INIT_TIMEOUT;
1403        }
1404       
1405        j=0;
1406        while (SPW_LINKSTATE(SPW_STATUS_READ(pDev)) != 5) {
1407                if ( timeout < -1 ) {
1408                        /* wait forever */
1409                }else if ( j >= timeout ){
1410                        /* timeout reached, return fail */
1411                        return 1;
1412                }
1413               
1414                /* Sleep for 10 ticks */
1415                rtems_task_wake_after(10);
1416                j+=10;
1417        }
1418        return 0;
1419}
1420
1421static void grspw_hw_reset(GRSPW_DEV *pDev)
1422{
1423        SPW_CTRL_WRITE(pDev, SPW_CTRL_RESET); /*reset core*/
1424        SPW_STATUS_WRITE(pDev, SPW_STATUS_TO | SPW_STATUS_CE | SPW_STATUS_ER | SPW_STATUS_DE | SPW_STATUS_PE |
1425                         SPW_STATUS_WE | SPW_STATUS_IA | SPW_STATUS_EE); /*clear status*/
1426        SPW_CTRL_WRITE(pDev, SPW_CTRL_LINKSTART); /*start link core*/
1427}
1428
1429static void grspw_hw_read_config(GRSPW_DEV *pDev)
1430{
1431        unsigned int tmp;
1432       
1433        tmp = SPW_READ(&pDev->regs->nodeaddr);
1434        pDev->config.nodeaddr = 0xFF & tmp;
1435        pDev->config.nodemask = 0xFF & (tmp>>8);
1436        pDev->config.destkey = 0xFF & SPW_READ(&pDev->regs->destkey);
1437        pDev->config.clkdiv = 0xFFFF & SPW_READ(&pDev->regs->clkdiv);
1438       
1439        tmp = SPW_CTRL_READ(pDev);
1440        pDev->config.promiscuous = 1 & (tmp >> 5);
1441        pDev->config.rmapen = 1 & (tmp >> 16);
1442        pDev->config.rmapbufdis = 1 & (tmp >> 17);
1443        pDev->config.is_rmap = 1 & (tmp >> 31);
1444        pDev->config.is_rxunaligned = 1 & (tmp >> 30);
1445        pDev->config.is_rmapcrc = 1 & (tmp >> 29);
1446        pDev->config.linkdisabled = 1 & tmp;
1447        pDev->config.linkstart = 1 & (tmp >> 1);
1448       
1449        if ( pDev->core_ver <= 1 ){
1450          tmp = SPW_READ(&pDev->regs->timer);
1451          pDev->config.timer = 0xFFF & tmp;
1452          pDev->config.disconnect = 0x3FF & (tmp >> 12);
1453        }else{
1454          pDev->config.timer = 0;
1455          pDev->config.disconnect = 0;
1456        }
1457       
1458        return;
1459}
1460
1461/* timeout is given in ticks */
1462static int grspw_hw_startup (GRSPW_DEV *pDev, int timeout)
1463{
1464        int i;
1465        unsigned int dmactrl;
1466       
1467        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*/
1468       
1469        if (grspw_hw_waitlink(pDev,timeout)) {
1470                SPACEWIRE_DBG2("Device open. Link is not up\n");
1471                return RTEMS_TIMEOUT;
1472        }
1473       
1474        SPW_WRITE(&pDev->regs->dma0ctrl, SPW_DMACTRL_PS | SPW_DMACTRL_PR | SPW_DMACTRL_TA | SPW_DMACTRL_RA); /*clear status, set ctrl*/
1475       
1476       
1477        if ((dmactrl = SPW_READ(&pDev->regs->dma0ctrl)) != 0) {
1478                SPACEWIRE_DBG2("DMACtrl is not cleared\n");
1479                return RTEMS_IO_ERROR;
1480        }
1481
1482        /* prepare transmit buffers */
1483        for (i = 0; i < pDev->txbufcnt; i++) {
1484                pDev->tx[i].ctrl = 0;
1485                pDev->tx[i].addr_header = memarea_to_hw(((unsigned int)&pDev->ptr_txhbuf0[0]) + (i * pDev->txhbufsize));
1486                pDev->tx[i].addr_data = memarea_to_hw(((unsigned int)&pDev->ptr_txdbuf0[0]) + (i * pDev->txdbufsize));
1487        }
1488        pDev->tx_cur = 0;
1489        pDev->tx_sent = 0;
1490        pDev->tx_all_in_use = 0;
1491       
1492        /* prepare receive buffers */
1493        for (i = 0; i < pDev->rxbufcnt; i++) {
1494                if (i+1 == pDev->rxbufcnt) {
1495                        pDev->rx[i].ctrl = SPW_RXBD_IE | SPW_RXBD_EN | SPW_RXBD_WR;
1496                } else {
1497                        pDev->rx[i].ctrl = SPW_RXBD_IE | SPW_RXBD_EN;
1498                }
1499                pDev->rx[i].addr = memarea_to_hw(((unsigned int)&pDev->ptr_rxbuf0[0]) + (i * pDev->rxbufsize));
1500        }
1501        pDev->rxcur = 0;
1502        pDev->rxbufcur = -1;
1503        grspw_set_rxmaxlen(pDev);
1504       
1505        SPW_WRITE(&pDev->regs->dma0txdesc, memarea_to_hw((unsigned int) pDev->tx));
1506        SPW_WRITE(&pDev->regs->dma0rxdesc, memarea_to_hw((unsigned int) pDev->rx));
1507       
1508        /* start RX */
1509        dmactrl = SPW_READ(&pDev->regs->dma0ctrl);
1510        SPW_WRITE(&pDev->regs->dma0ctrl, (dmactrl & SPW_PREPAREMASK_RX) | SPW_DMACTRL_RD | SPW_DMACTRL_RXEN | SPW_DMACTRL_NS | SPW_DMACTRL_TXIE | SPW_DMACTRL_RXIE);
1511       
1512        SPACEWIRE_DBGC(DBGSPW_TX,"0x%x: setup complete\n", (unsigned int)pDev->regs);
1513        return RTEMS_SUCCESSFUL;
1514}
1515
1516/* Wait until the receiver is inactive */
1517static void grspw_hw_wait_rx_inactive(GRSPW_DEV *pDev)
1518{
1519        while( SPW_READ(&pDev->regs->dma0ctrl) & SPW_DMACTRL_RX ){
1520                /* switching may be needed:
1521                 *  - low frequency GRSPW
1522                 *  - mega packet incoming
1523                 */
1524                rtems_task_wake_after(1);
1525        }
1526}
1527
1528/* Stop the rx or/and tx by disabling the receiver/transmitter */
1529static int grspw_hw_stop (GRSPW_DEV *pDev, int rx, int tx)
1530{
1531        unsigned int dmactrl;
1532 
1533        /* stop rx and/or tx */
1534        dmactrl = SPW_READ(&pDev->regs->dma0ctrl);
1535        if ( rx ) {
1536                dmactrl &= ~(SPW_DMACTRL_RXEN|SPW_DMACTRL_RXIE|SPW_DMACTRL_RD);
1537        }
1538        if ( tx ) {
1539                dmactrl &= ~(SPW_DMACTRL_TXEN|SPW_DMACTRL_TXIE);
1540        }
1541        /*SPW_WRITE(&pDev->regs->dma0ctrl, (dmactrl & SPW_PREPAREMASK_RX) & ~(SPW_DMACTRL_RD | SPW_DMACTRL_RXEN) & ~(SPW_DMACTRL_TXEN));*/
1542       
1543        /* don't clear status flags */
1544        dmactrl &= ~(SPW_DMACTRL_RA|SPW_DMACTRL_PR|SPW_DMACTRL_AI);
1545        SPW_WRITE(&pDev->regs->dma0ctrl, dmactrl);
1546        return RTEMS_SUCCESSFUL;
1547}
1548
1549int grspw_hw_send(GRSPW_DEV *pDev, unsigned int hlen, char *hdr, unsigned int dlen, char *data)
1550{
1551       
1552        unsigned int dmactrl, ctrl;
1553#ifdef DEBUG_SPACEWIRE_ONOFF
1554                                unsigned int k;
1555#endif
1556        rtems_interrupt_level level;
1557        unsigned int cur = pDev->tx_cur;
1558        char *txh = pDev->ptr_txhbuf0 + (cur * pDev->txhbufsize);
1559        char *txd = pDev->ptr_txdbuf0 + (cur * pDev->txdbufsize);
1560       
1561        ctrl = SPW_READ((volatile void *)&pDev->tx[cur].ctrl);
1562
1563        if (ctrl & SPW_TXBD_EN) {
1564                return 0;
1565        }
1566       
1567        memcpy(&txd[0], data, dlen);
1568        memcpy(&txh[0], hdr, hlen);
1569
1570#ifdef DEBUG_SPACEWIRE_ONOFF 
1571        if (DEBUG_SPACEWIRE_FLAGS & DBGSPW_DUMP) {
1572                for (k = 0; k < hlen; k++){
1573                        if (k % 16 == 0) {
1574                                printf ("\n");
1575                        }
1576                        printf ("%.2x(%c) ",txh[k] & 0xff,isprint(txh[k] & 0xff) ? txh[k] & 0xff : ' ');
1577                }
1578                printf ("\n");
1579        }
1580        if (DEBUG_SPACEWIRE_FLAGS & DBGSPW_DUMP) {
1581                for (k = 0; k < dlen; k++){
1582                        if (k % 16 == 0) {
1583                                printf ("\n");
1584                        }
1585                        printf ("%.2x(%c) ",txd[k] & 0xff,isprint(txd[k] & 0xff) ? txd[k] & 0xff : ' ');
1586                }
1587                printf ("\n");
1588        }
1589#endif
1590       
1591        pDev->tx[cur].addr_header = memarea_to_hw((unsigned int)txh);
1592        pDev->tx[cur].len = dlen;
1593        pDev->tx[cur].addr_data = memarea_to_hw((unsigned int)txd);
1594        if (pDev->tx_cur == (pDev->txbufcnt - 1) ) {
1595                pDev->tx[cur].ctrl = SPW_TXBD_IE | SPW_TXBD_WR | SPW_TXBD_EN | hlen;
1596        } else {
1597                pDev->tx[cur].ctrl = SPW_TXBD_IE | SPW_TXBD_EN | hlen;
1598        }
1599         
1600        dmactrl = SPW_READ(&pDev->regs->dma0ctrl);
1601        SPW_WRITE(&pDev->regs->dma0ctrl, (dmactrl & SPW_PREPAREMASK_TX) | SPW_DMACTRL_TXEN | SPW_DMACTRL_TXIE);
1602       
1603        /* Update counters */
1604        rtems_interrupt_disable(level);
1605       
1606        pDev->tx_cur = (pDev->tx_cur + 1) % pDev->txbufcnt;
1607        if (pDev->tx_cur == pDev->tx_sent) {
1608                pDev->tx_all_in_use = 1;
1609        }
1610        rtems_interrupt_enable(level);
1611       
1612        /* In blocking mode wait until message is sent */
1613        if (pDev->config.tx_blocking) {
1614                while ( SPW_READ(&pDev->regs->dma0ctrl) & SPW_DMACTRL_TXEN) {
1615                        /* if changed to blocking mode  */
1616                        SPACEWIRE_DBGC(DBGSPW_TX, "Tx blocking\n");
1617                        rtems_semaphore_obtain(pDev->txsp, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
1618                }
1619        }
1620        SPACEWIRE_DBGC(DBGSPW_TX, "0x%x: transmitted <%i> bytes\n", (unsigned int) pDev->regs, dlen+hlen);
1621        return hlen + dlen;
1622}
1623
1624static int grspw_hw_receive(GRSPW_DEV *pDev, char *b, int c) {
1625        unsigned int len, rxlen, ctrl;
1626        unsigned int cur;
1627        unsigned int tmp;
1628        unsigned int dump_start_len;
1629        int i;
1630        char *rxb; 
1631       
1632        if ( pDev->config.promiscuous ) {
1633                dump_start_len = 0; /* make sure address and prot can be read in promiscuous mode */
1634        } else if (pDev->config.rm_prot_id) {
1635                dump_start_len = 2; /* skip source address and protocol id */
1636        } else {
1637                dump_start_len = 1; /* default: skip only source address */
1638        }
1639       
1640        rxlen = 0;
1641        cur = pDev->rxcur;
1642        rxb = pDev->ptr_rxbuf0 + (cur * pDev->rxbufsize);
1643
1644        SPACEWIRE_DBGC(DBGSPW_RX, "0x%x: waitin packet at pos %i\n", (unsigned int) pDev->regs, cur);
1645       
1646        ctrl = SPW_READ((volatile void *)&pDev->rx[cur].ctrl);
1647        if (ctrl & SPW_RXBD_EN) {
1648                return rxlen;
1649        }
1650        SPACEWIRE_DBGC(DBGSPW_RX, "checking packet\n");
1651       
1652        len = SPW_RXBD_LENGTH & ctrl;
1653        if (!((ctrl & SPW_RXBD_ERROR) || (pDev->config.check_rmap_err && (ctrl & SPW_RXBD_RMAPERROR)))) {
1654                if (pDev->rxbufcur == -1) {
1655                        SPACEWIRE_DBGC(DBGSPW_RX, "incoming packet len %i\n", len);
1656                        pDev->stat.packets_received++;
1657                        pDev->rxbufcur = dump_start_len;
1658                }
1659                rxlen = tmp = len - pDev->rxbufcur;
1660                SPACEWIRE_DBGC(DBGSPW_RX, "C %i\n", c);
1661                SPACEWIRE_DBGC(DBGSPW_RX, "Dump %i\n", dump_start_len);
1662                SPACEWIRE_DBGC(DBGSPW_RX, "Bufcur %i\n", pDev->rxbufcur);
1663                SPACEWIRE_DBGC(DBGSPW_RX, "Rxlen %i\n", rxlen );
1664                if (rxlen > c) {
1665                        rxlen = c;
1666                }
1667                if (CPU_SPARC_HAS_SNOOPING) {
1668                        memcpy(b, rxb+pDev->rxbufcur, rxlen);
1669                } else {
1670                        for(i = 0; i < rxlen; i++) {
1671                                b[i] = MEM_READ(rxb+pDev->rxbufcur);
1672                        }
1673                }
1674               
1675                pDev->rxbufcur += rxlen;
1676                if (c >= tmp) {
1677                        SPACEWIRE_DBGC(DBGSPW_RX, "Next descriptor\n");
1678                        grspw_rxnext(pDev);
1679                }
1680        } else {
1681                check_rx_errors(pDev, ctrl);
1682        }
1683        return rxlen;
1684}
1685
1686static void grspw_rxnext(GRSPW_DEV *pDev)
1687{
1688        unsigned int dmactrl;
1689        unsigned int cur = pDev->rxcur;
1690        unsigned int ctrl = 0;
1691        if (cur == (pDev->rxbufcnt - 1)) {
1692                pDev->rx[cur].ctrl = ctrl | SPW_RXBD_EN | SPW_RXBD_IE | SPW_RXBD_WR;
1693                cur = 0;
1694        } else {
1695                pDev->rx[cur].ctrl = ctrl | SPW_RXBD_EN | SPW_RXBD_IE;
1696                cur++;
1697        }
1698               
1699        pDev->rxcur = cur;
1700        pDev->rxbufcur = -1;
1701       
1702        /* start RX */
1703        dmactrl = SPW_READ(&pDev->regs->dma0ctrl);
1704        SPW_WRITE(&pDev->regs->dma0ctrl, (dmactrl & SPW_PREPAREMASK_RX) | SPW_DMACTRL_RD | SPW_DMACTRL_RXEN | SPW_DMACTRL_RXIE | SPW_DMACTRL_NS);
1705 
1706}
1707
1708static void check_rx_errors(GRSPW_DEV *pDev, int ctrl)
1709{
1710        if (ctrl & SPW_RXBD_EEP) {
1711                pDev->stat.rx_eep_err++;
1712        }
1713        if (ctrl & SPW_RXBD_EHC) {
1714                if (pDev->config.check_rmap_err) {
1715                        pDev->stat.rx_rmap_header_crc_err++;
1716                }
1717        } 
1718        if (ctrl & SPW_RXBD_EDC) {
1719                if (pDev->config.check_rmap_err) {
1720                        pDev->stat.rx_rmap_data_crc_err++;
1721                }
1722        }
1723        if (ctrl & SPW_RXBD_ETR) {
1724                pDev->stat.rx_truncated++;
1725        }
1726}
1727
1728
Note: See TracBrowser for help on using the repository browser.