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

4.115
Last change on this file since 226d48d8 was 226d48d8, checked in by Daniel Hellstrom <daniel@…>, on 05/16/12 at 15:20:35

LEON: moved register definitions into grlib header file

Some register layout definitions for LEON3 reside in ambapp.h which
does not really has anything to do with device registers. The
register structures has been incorrectly named LEON3_*, the cores
are not only used on LEON3 but on LEON4 and perhaps on LEON5 when
that day comes. Some structures has been renamed according to the
GRLIB core name instead, which CPU that actually use it is not
relevant. Drivers has been updated with the new names.

Signed-off-by: Daniel Hellstrom <daniel@…>

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