source: rtems/c/src/lib/libbsp/sparc/shared/1553/gr1553rt.c @ 4a7d1026

4.11
Last change on this file since 4a7d1026 was 4a7d1026, checked in by Daniel Hellstrom <daniel@…>, on Apr 13, 2015 at 8:25:52 AM

sparc bsps: updated license to rtems.org

  • Property mode set to 100644
File size: 27.9 KB
Line 
1/*  GR1553B RT driver
2 *
3 *  COPYRIGHT (c) 2010.
4 *  Cobham Gaisler AB.
5 *
6 *  The license and distribution terms for this file may be
7 *  found in the file LICENSE in this distribution or at
8 *  http://www.rtems.org/license/LICENSE.
9 */
10
11#include <rtems.h>
12#include <stdlib.h>
13#include <stdio.h>
14#include <string.h>
15
16#include <bsp/gr1553b.h>
17#include <bsp/gr1553rt.h>
18
19#include <drvmgr/drvmgr.h>
20#include <drvmgr/ambapp_bus.h>
21
22#define GR1553RT_WRITE_MEM(adr, val) *(volatile uint32_t *)(adr) = (uint32_t)(val)
23#define GR1553RT_READ_MEM(adr) (*(volatile uint32_t *)(adr))
24
25#define GR1553RT_WRITE_REG(adr, val) *(volatile uint32_t *)(adr) = (uint32_t)(val)
26#define GR1553RT_READ_REG(adr) (*(volatile uint32_t *)(adr))
27
28#ifndef IRQ_GLOBAL_PREPARE
29 #define IRQ_GLOBAL_PREPARE(level) rtems_interrupt_level level
30#endif
31
32#ifndef IRQ_GLOBAL_DISABLE
33 #define IRQ_GLOBAL_DISABLE(level) rtems_interrupt_disable(level)
34#endif
35
36#ifndef IRQ_GLOBAL_ENABLE
37 #define IRQ_GLOBAL_ENABLE(level) rtems_interrupt_enable(level)
38#endif
39
40/* Software representation of one hardware descriptor */
41struct gr1553rt_sw_bd {
42        unsigned short this_next;/* Next entry or this entry. 0xffff: no next */
43        unsigned char listid;   /* ListID of List the descriptor is attached */
44        char unused;
45} __attribute__((packed));
46
47/* Software description of a subaddress */
48struct gr1553rt_subadr {
49        /* RX LIST */
50        unsigned char rxlistid;
51        /* TX LIST */
52        unsigned char txlistid;
53};
54
55struct gr1553rt_irqerr {
56        gr1553rt_irqerr_t func;
57        void *data;
58};
59
60struct gr1553rt_irqmc {
61        gr1553rt_irqmc_t func;
62        void *data;
63};
64
65struct gr1553rt_irq {
66        gr1553rt_irq_t func;
67        void *data;
68};
69
70struct gr1553rt_priv {
71        /* Pointer to Hardware registers */
72        struct gr1553b_regs *regs;
73
74        /* Software State */
75        int started;
76        struct gr1553rt_cfg cfg;
77
78        /* Handle to GR1553B RT device layer */
79        struct drvmgr_dev **pdev;
80
81        /* Each Index represents one RT Subaddress. 31 = Broadcast */
82        struct gr1553rt_subadr subadrs[32];
83
84        /* Pointer to array of Software's description of a hardware
85         * descriptor.
86         */
87#if (RTBD_MAX == 0)
88        struct gr1553rt_sw_bd *swbds;
89#else
90        struct gr1553rt_sw_bd swbds[RTBD_MAX];
91#endif
92
93        /* List of Free descriptors */
94        unsigned short swbd_free;
95        int swbd_free_cnt;
96
97        /* Hardware SubAddress descriptors given for CPU and Hardware */
98        void *satab_buffer;
99        struct gr1553rt_sa *sas_cpu;    /* Translated for CPU */
100        struct gr1553rt_sa *sas_hw;     /* Translated for Hardware */
101
102        /* Hardware descriptors address given for CPU and hardware */
103        void *bd_buffer;
104        int bds_cnt;                    /* Number of descriptors */
105        struct gr1553rt_bd *bds_cpu;    /* Translated for CPU */
106        struct gr1553rt_bd *bds_hw;     /* Translated for Hardware */
107
108
109        /* Event Log buffer in */
110        void *evlog_buffer;
111        unsigned int *evlog_cpu_next;   /* Next LOG entry to be handled */
112        unsigned int *evlog_cpu_base;   /* First Entry in LOG */
113        unsigned int *evlog_cpu_end;    /* Last+1 Entry in LOG */
114        unsigned int *evlog_hw_base;    /* Translated for Hardware */
115
116        /* Each Index represents a LIST ID */
117        struct gr1553rt_list *lists[RTLISTID_MAX];
118
119        /* IRQ handlers, one per SUBADDRESS */
120        struct gr1553rt_irq irq_rx[32];
121        struct gr1553rt_irq irq_tx[32];
122
123        /* ISR called when an ERROR IRQ is received */
124        struct gr1553rt_irqerr irq_err;
125
126        /* ISR called when an Mode Code is received */
127        struct gr1553rt_irqmc irq_mc;
128};
129
130void gr1553rt_sw_init(struct gr1553rt_priv *priv);
131void gr1553rt_sw_free(struct gr1553rt_priv *priv);
132void gr1553rt_isr(void *data);
133
134/* Assign and ID to the list. An LIST ID is needed before scheduling list
135 * on an RT subaddress.
136 *
137 * Only 64 lists can be registered at a time on the same device.
138 */
139static int gr1553rt_list_reg(struct gr1553rt_list *list)
140{
141        struct gr1553rt_priv *priv = list->rt;
142        int i;
143
144        /* Find first free list ID */
145        for ( i=0; i<RTLISTID_MAX; i++) {
146                if ( priv->lists[i] == NULL ) {
147                        priv->lists[i] = list;
148                        list->listid = i;
149                        return i;
150                }
151        }
152
153        /* No available LIST IDs */
154        list->listid = -1;
155
156        return -1;
157}
158
159#if 0 /* unused for now */
160/* Unregister List from device */
161static void gr1553rt_list_unreg(struct gr1553rt_list *list)
162{
163        struct gr1553rt_priv *priv = list->rt;
164
165        priv->lists[list->listid] = NULL;
166        list->listid = -1;
167}
168#endif
169
170static int gr1553rt_bdid(void *rt, struct gr1553rt_sw_bd *bd)
171{
172        struct gr1553rt_priv *priv = rt;
173       
174        unsigned short index;
175
176        /* Get Index of Software BD */
177        index = ((unsigned int)bd - (unsigned int)&priv->swbds[0]) / 
178                sizeof(struct gr1553rt_sw_bd);
179
180        return index;
181}
182
183static void gr1553rt_bd_alloc_init(void *rt, int count)
184{
185        struct gr1553rt_priv *priv = rt;
186        int i;
187
188        for (i=0; i<count-1; i++) {
189                priv->swbds[i].this_next = i+1;
190        }
191        priv->swbds[count-1].this_next = 0xffff;
192        priv->swbd_free = 0;
193        priv->swbd_free_cnt = count;
194}
195
196/* Allocate a Chain of descriptors */
197static int gr1553rt_bd_alloc(void *rt, struct gr1553rt_sw_bd **bd, int cnt)
198{
199        struct gr1553rt_priv *priv = rt;
200        struct gr1553rt_sw_bd *curr;
201        int i;
202
203        if ((priv->swbd_free_cnt < cnt) || (cnt <= 0)) {
204                *bd = NULL;
205                return -1;
206        }
207
208        *bd = &priv->swbds[priv->swbd_free];
209        for (i=0; i<cnt; i++) {
210                if ( i == 0) {
211                        curr = &priv->swbds[priv->swbd_free];
212                } else {
213                        curr = &priv->swbds[curr->this_next];
214                }
215                if ( curr->this_next == 0xffff ) {
216                        *bd = NULL;
217                        return -1;
218                }
219        }
220        priv->swbd_free = curr->this_next;
221        priv->swbd_free_cnt -= cnt;
222        curr->this_next = 0xffff; /* Mark end of chain on last entry */
223
224        return 0;
225}
226
227#if 0 /* unused for now */
228static void gr1553rt_bd_free(void *rt, struct gr1553rt_sw_bd *bd)
229{
230        struct gr1553rt_priv *priv = rt;
231        unsigned short index;
232
233        /* Get Index of Software BD */
234        index = gr1553rt_bdid(priv, bd);
235
236        /* Insert first in list */
237        bd->this_next = priv->swbd_free;
238        priv->swbd_free = index;
239        priv->swbd_free_cnt++;
240}
241#endif
242
243int gr1553rt_list_init
244        (
245        void *rt,
246        struct gr1553rt_list **plist,
247        struct gr1553rt_list_cfg *cfg
248        )
249{
250        struct gr1553rt_priv *priv = rt;
251        int i, size;
252        struct gr1553rt_sw_bd *swbd;
253        unsigned short index;
254        struct gr1553rt_list *list;
255
256        /* The user may provide a pre allocated LIST, or
257         * let the driver handle allocation by using malloc()
258         *
259         * If the IN/OUT plist argument points to NULL a list
260         * dynamically allocated here.
261         */
262        list = *plist;
263        if ( list == NULL ) {
264                /* Dynamically allocate LIST */
265                size = offsetof(struct gr1553rt_list, bds) +
266                        (cfg->bd_cnt * sizeof(unsigned short));
267                list = (struct gr1553rt_list *)malloc(size);
268                if ( list == NULL )
269                        return -1;
270                *plist = list;
271        }
272
273        list->rt = rt;
274        list->subadr = -1;
275        list->listid = gr1553rt_list_reg(list);
276        if ( list->listid == -1 )
277                return -2; /* Too many lists */
278        list->cfg = cfg;
279        list->bd_cnt = cfg->bd_cnt;
280
281        /* Allocate all BDs needed by list */
282        if ( gr1553rt_bd_alloc(rt, &swbd, list->bd_cnt) ) {
283                return -3; /* Too few descriptors */
284        }
285
286        /* Get ID/INDEX of Software BDs */
287        index = gr1553rt_bdid(rt, swbd);
288        list->bds[0] = index;
289        for (i=1; i<list->bd_cnt; i++) {
290                list->bds[i] = priv->swbds[list->bds[i-1]].this_next;
291        }
292
293        /* Now that the next pointer has fullfilled it's job and not
294         * needed anymore, we use it as list entry pointer instead.
295         * The this_next pointer is a list entry number.
296         */
297        for (i=0; i<list->bd_cnt; i++) {
298                priv->swbds[list->bds[i]].this_next = i;
299        }
300
301        return 0;
302}
303
304int gr1553rt_bd_init(
305        struct gr1553rt_list *list,
306        unsigned short entry_no,
307        unsigned int flags,
308        uint16_t *dptr,
309        unsigned short next
310        )
311{
312        struct gr1553rt_priv *priv;
313        unsigned short bdid;
314        struct gr1553rt_bd *bd;
315        unsigned int nextbd, dataptr;
316        IRQ_GLOBAL_PREPARE(oldLevel);
317
318        if ( entry_no >= list->bd_cnt )
319                return -1;
320
321        /* Find Descriptor */
322        bdid = list->bds[entry_no];
323        priv = list->rt;
324        bd = &priv->bds_cpu[bdid];
325
326        if ( next == 0xfffe ) {
327                next = entry_no + 1;
328                if ( next >= list->bd_cnt )
329                        next = 0;
330        }
331
332        /* Find next descriptor in address space that the
333         * Hardware understand.
334         */
335        if ( next >= 0xffff ) {
336                nextbd = 0x3; /* End of list */
337        } else if ( next >= list->bd_cnt ) {
338                return -1;
339        } else {
340                bdid = list->bds[next];
341                nextbd = (unsigned int)&priv->bds_hw[bdid];
342        }
343
344        dataptr = (unsigned int)dptr;
345        if ( dataptr & 1 ) {
346                /* Translate address from CPU-local into remote */
347                dataptr &= ~1;
348                drvmgr_translate(
349                        *priv->pdev,
350                        CPUMEM_TO_DMA,
351                        (void *)dataptr,
352                        (void **)&dataptr
353                        );
354        }
355
356        /* Get current status, and clear */
357        IRQ_GLOBAL_DISABLE(oldLevel);
358        bd->ctrl = flags & GR1553RT_BD_FLAGS_IRQEN;
359        bd->dptr = (unsigned int)dptr;
360        bd->next = nextbd;
361        IRQ_GLOBAL_ENABLE(oldLevel);
362
363        return 0;       
364}
365
366int gr1553rt_bd_update(
367        struct gr1553rt_list *list,
368        int entry_no,
369        unsigned int *status,
370        uint16_t **dptr
371        )
372{
373        struct gr1553rt_priv *priv;
374        unsigned short bdid;
375        struct gr1553rt_bd *bd;
376        unsigned int tmp, dataptr;
377        IRQ_GLOBAL_PREPARE(oldLevel);
378
379        if ( entry_no >= list->bd_cnt )
380                return -1;
381
382        /* Find Descriptor */
383        bdid = list->bds[entry_no];
384        priv = list->rt;
385        bd = &priv->bds_cpu[bdid];
386
387        /* Prepare translation if needed */
388        if ( dptr && (dataptr=(unsigned int)*dptr) ) {
389                if ( dataptr & 1 ) {
390                        /* Translate address from CPU-local into remote. May
391                         * be used when RT core is accessed over the PCI bus.
392                         */
393                        dataptr &= ~1;
394                        drvmgr_translate(
395                                *priv->pdev,
396                                CPUMEM_TO_DMA,
397                                (void *)dataptr,
398                                (void **)&dataptr
399                                );
400                }
401        }
402
403        /* Get current status, and clear */
404        IRQ_GLOBAL_DISABLE(oldLevel);
405        /* READ/WRITE Status/Control word */
406        if ( status ) {
407                tmp = bd->ctrl;
408                if ( *status ) {
409                        bd->ctrl = *status;
410                }
411                *status = tmp;
412        }
413        /* READ/WRITE Data-Pointer word */
414        if ( dptr ) {
415                tmp = bd->dptr;
416                if ( dataptr ) {
417                        bd->dptr = dataptr;
418                }
419                *dptr = (uint16_t *)tmp;
420        }
421        IRQ_GLOBAL_ENABLE(oldLevel);
422
423        return 0;
424}
425
426int gr1553rt_irq_err
427        (
428        void *rt,
429        gr1553rt_irqerr_t func,
430        void *data
431        )
432{
433        struct gr1553rt_priv *priv = rt;
434        IRQ_GLOBAL_PREPARE(oldLevel);
435
436        IRQ_GLOBAL_DISABLE(oldLevel);
437        priv->irq_err.func = func;
438        priv->irq_err.data = data;
439        IRQ_GLOBAL_ENABLE(oldLevel);
440
441        return 0;
442}
443
444int gr1553rt_irq_mc
445        (
446        void *rt,
447        gr1553rt_irqmc_t func,
448        void *data
449        )
450{
451        struct gr1553rt_priv *priv = rt;
452        IRQ_GLOBAL_PREPARE(oldLevel);
453
454        IRQ_GLOBAL_DISABLE(oldLevel);
455        priv->irq_mc.func = func;
456        priv->irq_mc.data = data;
457        IRQ_GLOBAL_ENABLE(oldLevel);
458
459        return 0;
460}
461
462int gr1553rt_irq_sa
463        (
464        void *rt,
465        int subadr,
466        int tx,
467        gr1553rt_irq_t func,
468        void *data
469        )
470{
471        struct gr1553rt_priv *priv = rt;
472        IRQ_GLOBAL_PREPARE(oldLevel);
473
474        IRQ_GLOBAL_DISABLE(oldLevel);
475        if ( tx ) {
476                priv->irq_tx[subadr].func = func;
477                priv->irq_tx[subadr].data = data;
478        } else {
479                priv->irq_rx[subadr].func = func;
480                priv->irq_rx[subadr].data = data;
481        }
482        IRQ_GLOBAL_ENABLE(oldLevel);
483
484        return 0;
485}
486
487/* GR1553-RT Interrupt Service Routine */
488void gr1553rt_isr(void *data)
489{
490        struct gr1553rt_priv *priv = data;
491        unsigned int firstirq, lastpos;
492        int index;
493        unsigned int *last, *curr, entry, hwbd;
494        int type, samc, mcode, subadr;
495        int listid;
496        struct gr1553rt_irq *isr;
497        struct gr1553rt_irqerr *isrerr;
498        struct gr1553rt_irqmc *isrmc;
499        unsigned int irq;
500
501        /* Ack IRQ before reading current write pointer, but after
502         * reading current IRQ pointer. This is because RT_EVIRQ
503         * may be updated after we ACK the IRQ source.
504         */
505        irq = priv->regs->irq &
506                (GR1553B_IRQ_RTTE|GR1553B_IRQ_RTD|GR1553B_IRQ_RTEV);
507        if ( irq == 0 )
508                return;
509
510        firstirq = priv->regs->rt_evirq;
511        priv->regs->irq = irq;
512        lastpos = priv->regs->rt_evlog;
513
514        /* Quit if nothing has been added to the log */
515        if ( lastpos == firstirq )
516                return;
517
518        if ( irq & (GR1553B_IRQ_RTTE|GR1553B_IRQ_RTD) ) {
519                isrerr = &priv->irq_err;
520                if ( isrerr->func ) {
521                        isrerr->func(irq, isrerr->data);
522                }
523
524                /* Stop Hardware and enter non-started mode. This will
525                 * make all future calls to driver result in an error.
526                 */
527                gr1553rt_stop(priv);
528        }
529
530        /* Step between first log entry causing an IRQ to last
531         * entry. Each entry that has caused an IRQ will be handled
532         * by calling user-defined function.
533         *
534         * We convert hardware addresses into CPU accessable addresses
535         * first.
536         */
537        index = (firstirq - (unsigned int)priv->evlog_hw_base) /
538                sizeof(unsigned int);
539        curr = priv->evlog_cpu_base + index;
540        index = (lastpos - (unsigned int)priv->evlog_hw_base) /
541                sizeof(unsigned int);
542        last = priv->evlog_cpu_base + index;
543
544        do {
545                /* Process one entry */
546                entry = *curr;
547
548                if ( entry & 0x80000000 ) {
549                        /* Entry caused IRQ */
550                        type = (entry >> 29) & 0x3;
551                        samc = (entry >> 24) & 0x1f;
552                        if ( (type & 0x2) == 0 ) {
553                                /* Transmit/Receive Data */
554                                subadr = samc;
555                                if ( type ) {
556                                        /* Receive */
557                                        listid = priv->subadrs[subadr].rxlistid;
558                                        hwbd = priv->sas_cpu[subadr].rxptr;
559                                        isr = &priv->irq_rx[subadr];
560                                } else {
561                                        /* Transmit */
562                                        listid = priv->subadrs[subadr].txlistid;
563                                        hwbd = priv->sas_cpu[subadr].txptr;
564                                        isr = &priv->irq_tx[subadr];
565                                }
566
567                                index = ((unsigned int)hwbd - (unsigned int)
568                                        priv->bds_hw)/sizeof(struct gr1553rt_bd);
569
570                                /* Call user ISR of RX/TX transfer */
571                                if ( isr->func ) {
572                                        isr->func(
573                                                priv->lists[listid],
574                                                entry,
575                                                priv->swbds[index].this_next,
576                                                isr->data
577                                                );
578                                }
579                        } else if ( type == 0x2) {
580                                /* Modecode */
581                                mcode = samc;
582                                isrmc = &priv->irq_mc;
583
584                                /* Call user ISR of ModeCodes RX/TX */
585                                if ( isrmc->func ) {
586                                        isrmc->func(
587                                                mcode,
588                                                entry,
589                                                isrmc->data
590                                                );
591                                }
592                        } else {
593                                /* ERROR OF SOME KIND, EVLOG OVERWRITTEN? */
594                                exit(-1);
595                        }
596                }
597
598                /* Calc next entry posistion */
599                curr++;
600                if ( curr == priv->evlog_cpu_end )
601                        curr = priv->evlog_cpu_base;
602
603        } while ( curr != last );
604}
605
606int gr1553rt_indication(void *rt, int subadr, int *txeno, int *rxeno)
607{
608        struct gr1553rt_priv *priv = rt;
609        struct gr1553rt_sa *sa;
610        unsigned int bd, index;
611
612        /*  Sub address valid */
613        if ( (subadr < 0) || (subadr > 31) )
614                return -1;
615
616        /* Get SubAddress Descriptor address as accessed from CPU */
617        sa = &priv->sas_cpu[subadr];
618
619        /* Indication of TX descriptor? */
620        if ( txeno ) {
621                bd = sa->txptr;
622                /* Get Index of Hardware BD */
623                index = ((unsigned int)bd - (unsigned int)&priv->bds_hw[0]) /
624                        sizeof(struct gr1553rt_bd);
625                *txeno = priv->swbds[index].this_next;
626        }
627
628        /* Indication of RX descriptor? */
629        if ( rxeno ) {
630                bd = sa->rxptr;
631                /* Get Index of Hardware BD */
632                index = ((unsigned int)bd - (unsigned int)&priv->bds_hw[0]) /
633                        sizeof(struct gr1553rt_bd);
634                *rxeno = priv->swbds[index].this_next;
635        }
636
637        return 0;
638}
639
640#if 0
641int gr1553rt_bd_irq(
642        struct gr1553rt_list *list,
643        unsigned short entry_no,
644        void (*func)(struct gr1553rt_list *list, int entry, void *data),
645        void *data
646        )
647{
648        struct gr1553rt_priv *priv = list->rt;
649        int irqid;
650        int ret;
651        IRQ_GLOBAL_PREPARE(oldLevel);
652
653        if ( entry_no == 0xffff ) {
654                /* Default interrupt for all list entries without
655                 * assigned IRQ function.
656                 */
657                list->irqs[0].func = func;
658                list->irqs[0].data = data;
659                return 0;
660        }
661
662        if ( entry_no >= list->bd_cnt ) {
663                return -1;
664        }
665
666        bdid = list->bds[entry_no];
667        irqid = priv->swbds[bdid].irqid;
668
669        ret = 0;
670        IRQ_GLOBAL_DISABLE(oldLevel);
671        if ( (irqid != 0) && (func == 0) ) {
672                /* Unassign IRQ function */
673                list->irqs[irqid].func = NULL;
674                list->irqs[irqid].data = NULL;
675                irqid = 0; /* Disable IRQ (default handler) */
676        } else if ( priv->swbds[bdid].irqid != 0 ) {
677                /* reassign IRQ function */
678                list->irqs[irqid].func = func;
679                list->irqs[irqid].data = data;
680        } else {
681                /* Find free IRQ spot. If no free irqid=0 (general IRQ) */
682                ret = -1;
683                for (i=0; i<list->cfg->maxirq; i++) {
684                        if ( list->irqs[i].func == NULL ) {
685                                irqid = i;
686                                list->irqs[i].func = func;
687                                list->irqs[i].data = data;
688                                ret = 0;
689                                break;
690                        }
691                }
692        }
693        priv->swbds[bdid].irqid = irqid;
694        IRQ_GLOBAL_ENABLE(oldLevel);
695
696        return ret;
697}
698#endif
699
700void gr1553rt_hw_stop(struct gr1553rt_priv *priv);
701
702void gr1553rt_register(void)
703{
704        /* The RT driver rely on the GR1553B Driver */
705        gr1553_register();
706}
707
708void *gr1553rt_open(int minor)
709{
710        struct drvmgr_dev **pdev = NULL;
711        struct gr1553rt_priv *priv = NULL;
712        struct amba_dev_info *ambadev;
713        struct ambapp_core *pnpinfo;
714
715        /* Allocate requested device */
716        pdev = gr1553_rt_open(minor);
717        if ( pdev == NULL )
718                goto fail;
719
720        priv = malloc(sizeof(struct gr1553rt_priv));
721        if ( priv == NULL )
722                goto fail;
723        memset(priv, 0, sizeof(struct gr1553rt_priv));
724
725        /* Assign a device private to RT device */
726        priv->pdev = pdev;
727        (*pdev)->priv = priv;
728
729        /* Get device information from AMBA PnP information */
730        ambadev = (struct amba_dev_info *)(*pdev)->businfo;
731        pnpinfo = &ambadev->info;
732        priv->regs = (struct gr1553b_regs *)pnpinfo->apb_slv->start;
733
734        /* Start with default configuration */
735        /*priv->cfg = gr1553rt_default_config;*/
736
737        /* Unmask IRQs and so */
738        gr1553rt_hw_stop(priv);
739
740        /* Register ISR handler. hardware mask IRQ, so it is safe to unmask
741         * at IRQ controller.
742         */
743        if (drvmgr_interrupt_register(*priv->pdev, 0, "gr1553rt", gr1553rt_isr, priv))
744                goto fail;
745
746        return priv;
747
748fail:
749        if ( pdev )
750                gr1553_rt_close(pdev);
751        if ( priv )
752                free(priv);
753        return NULL;
754}
755
756void gr1553rt_close(void *rt)
757{
758        struct gr1553rt_priv *priv = rt;
759
760        if ( priv->started ) {
761                gr1553rt_stop(priv);
762        }
763
764        /* Remove ISR handler */
765        drvmgr_interrupt_unregister(*priv->pdev, 0, gr1553rt_isr, priv);
766
767        /* Free dynamically allocated buffers if any */
768        gr1553rt_sw_free(priv);
769
770        /* Return RT/BC device */
771        gr1553_rt_close(priv->pdev);
772}
773
774/* Stop Hardware and disable IRQ */
775void gr1553rt_hw_stop(struct gr1553rt_priv *priv)
776{
777        uint32_t irqmask;
778
779        /* Disable RT */
780        GR1553RT_WRITE_REG(&priv->regs->rt_cfg, GR1553RT_KEY);
781
782        /* Stop BC if not already stopped: BC can not be used simultaneously
783         * as the RT anyway
784         */
785        GR1553RT_WRITE_REG(&priv->regs->bc_ctrl, GR1553BC_KEY | 0x0204);
786
787        /* Turn off RT IRQ generation */
788        irqmask=GR1553RT_READ_REG(&priv->regs->imask);
789        irqmask&=~(GR1553B_IRQEN_RTEVE|GR1553B_IRQEN_RTDE);
790        GR1553RT_WRITE_REG(&priv->regs->irq, irqmask);
791}
792
793/* Free dynamically allocated buffers, if any */
794void gr1553rt_sw_free(struct gr1553rt_priv *priv)
795{
796        /* Event log */
797        if ( (priv->cfg.evlog_buffer == NULL) && priv->evlog_buffer ) {
798                free(priv->evlog_buffer);
799                priv->evlog_buffer = NULL;
800        }
801
802        /* RX/TX Descriptors */
803        if ( (priv->cfg.bd_buffer == NULL) && priv->bd_buffer ) {
804                free(priv->bd_buffer);
805                priv->bd_buffer = NULL;
806        }
807
808#if (RTBD_MAX == 0)
809        if ( priv->swbds ) {
810                free(priv->swbds);
811                priv->swbds = NULL;
812        }
813#endif
814
815        /* Sub address table */
816        if ( (priv->cfg.satab_buffer == NULL) && priv->satab_buffer ) {
817                free(priv->satab_buffer);
818                priv->satab_buffer = NULL;
819        }
820}
821
822/* Free dynamically allocated buffers, if any */
823static int gr1553rt_sw_alloc(struct gr1553rt_priv *priv)
824{
825        int size;
826
827        /* Allocate Event log */
828        if ((unsigned int)priv->cfg.evlog_buffer & 1) {
829                /* Translate Address from HARDWARE (REMOTE) to CPU-LOCAL */
830                priv->evlog_hw_base = (unsigned int *)
831                        ((unsigned int)priv->cfg.evlog_buffer & ~0x1);
832                priv->evlog_buffer = priv->cfg.evlog_buffer;
833                drvmgr_translate_check(
834                        *priv->pdev,
835                        DMAMEM_TO_CPU,
836                        (void *)priv->evlog_hw_base,
837                        (void **)&priv->evlog_cpu_base,
838                        priv->cfg.evlog_size
839                        );
840        } else {
841                if (priv->cfg.evlog_buffer == NULL) {
842                        priv->evlog_buffer = malloc(priv->cfg.evlog_size * 2);
843                        if (priv->evlog_buffer == NULL)
844                                return -1;
845                } else {
846                        /* Addess already CPU-LOCAL */
847                        priv->evlog_buffer = priv->cfg.evlog_buffer;
848                }
849                /* Align to SIZE bytes boundary */
850                priv->evlog_cpu_base = (unsigned int *)
851                        (((unsigned int)priv->evlog_buffer +
852                        (priv->cfg.evlog_size-1)) & ~(priv->cfg.evlog_size-1));
853
854                drvmgr_translate_check(
855                        *priv->pdev,
856                        CPUMEM_TO_DMA,
857                        (void *)priv->evlog_cpu_base,
858                        (void **)&priv->evlog_hw_base,
859                        priv->cfg.evlog_size
860                        );
861        }
862        priv->evlog_cpu_end = priv->evlog_cpu_base +
863                                priv->cfg.evlog_size/sizeof(unsigned int *);
864
865        /* Allocate Transfer Descriptors */
866        priv->bds_cnt = priv->cfg.bd_count;
867        size = priv->bds_cnt * sizeof(struct gr1553rt_bd);
868        if ((unsigned int)priv->cfg.bd_buffer & 1) {
869                /* Translate Address from HARDWARE (REMOTE) to CPU-LOCAL */
870                priv->bds_hw = (struct gr1553rt_bd *)
871                        ((unsigned int)priv->cfg.bd_buffer & ~0x1);
872                priv->bd_buffer = priv->cfg.bd_buffer;
873                drvmgr_translate_check(
874                        *priv->pdev,
875                        DMAMEM_TO_CPU,
876                        (void *)priv->bds_hw,
877                        (void **)&priv->bds_cpu,
878                        size
879                        );
880        } else {
881                if ( priv->cfg.bd_buffer == NULL ) {
882                        priv->bd_buffer = malloc(size + 0xf);
883                        if (priv->bd_buffer == NULL)
884                                return -1;
885                } else {
886                        /* Addess already CPU-LOCAL */
887                        priv->bd_buffer = priv->cfg.bd_buffer;
888                }
889                /* Align to 16 bytes boundary */
890                priv->bds_cpu = (struct gr1553rt_bd *)
891                                (((unsigned int)priv->bd_buffer + 0xf) & ~0xf);
892
893                /* Translate from CPU address to hardware address */
894                drvmgr_translate_check(
895                        *priv->pdev,
896                        CPUMEM_TO_DMA,
897                        (void *)priv->bds_cpu,
898                        (void **)&priv->bds_hw,
899                        size
900                        );
901        }
902
903#if (RTBD_MAX == 0)
904        /* Allocate software description of */
905        priv->swbds = malloc(priv->cfg.bd_count * sizeof(struct gr1553rt_sw_bd));
906        if ( priv->swbds == NULL ) {
907                return -1;
908        }
909#endif
910
911        /* Allocate Sub address table */
912        if ((unsigned int)priv->cfg.satab_buffer & 1) {
913                /* Translate Address from HARDWARE (REMOTE) to CPU-LOCAL */
914                priv->sas_hw = (struct gr1553rt_sa *)
915                        ((unsigned int)priv->cfg.satab_buffer & ~0x1);
916                priv->satab_buffer = priv->cfg.satab_buffer;
917                drvmgr_translate_check(
918                        *priv->pdev,
919                        DMAMEM_TO_CPU,
920                        (void *)priv->sas_hw,
921                        (void **)&priv->sas_cpu,
922                        16 * 32);
923        } else {
924                if (priv->cfg.satab_buffer == NULL) {
925                        priv->satab_buffer = malloc((16 * 32) * 2);
926                        if (priv->satab_buffer == NULL)
927                                return -1;
928                } else {
929                        /* Addess already CPU-LOCAL */
930                        priv->satab_buffer = priv->cfg.satab_buffer;
931                }
932                /* Align to 512 bytes boundary */
933                priv->sas_cpu = (struct gr1553rt_sa *)
934                                (((unsigned int)priv->satab_buffer + 0x1ff) &
935                                ~0x1ff);
936
937                /* Translate Address from CPU-LOCAL to HARDWARE (REMOTE) */
938                drvmgr_translate_check(
939                        *priv->pdev,
940                        CPUMEM_TO_DMA,
941                        (void *)priv->sas_cpu,
942                        (void **)&priv->sas_hw,
943                        16 * 32);
944        }
945
946        return 0;
947}
948
949void gr1553rt_sw_init(struct gr1553rt_priv *priv)
950{
951        int i;
952
953        /* Clear Sub Address table */
954        memset(priv->sas_cpu, 0, 512);
955
956        /* Clear Transfer descriptors */
957        memset(priv->bds_cpu, 0, priv->bds_cnt * 16);
958
959        /* Clear the Event log */
960        memset(priv->evlog_cpu_base, 0, priv->cfg.evlog_size);
961
962        /* Init descriptor allocation algorithm */
963        gr1553rt_bd_alloc_init(priv, priv->bds_cnt);
964
965        /* Init table used to convert from sub address to list.
966         * Currently non assigned.
967         */
968        for (i=0; i<32; i++) {
969                priv->subadrs[i].rxlistid = 0xff;
970                priv->subadrs[i].txlistid = 0xff;
971        }
972
973        /* Clear all previous IRQ handlers */
974        for (i=0; i<32; i++) {
975                priv->irq_rx[i].func = NULL;
976                priv->irq_tx[i].data = NULL;
977        }
978        priv->irq_err.func = NULL;
979        priv->irq_err.data = NULL;
980        priv->irq_mc.func = NULL;
981        priv->irq_mc.data = NULL;
982
983        /* Clear LIST to LISTID table */
984        for (i=0; i<RTLISTID_MAX; i++) {
985                priv->lists[i] = NULL;
986        }
987}
988
989int gr1553rt_config(void *rt, struct gr1553rt_cfg *cfg)
990{
991        struct gr1553rt_priv *priv = rt;
992
993        if ( priv->started )
994                return -1;
995
996        /*** Free dynamically allocated buffers ***/
997
998        gr1553rt_sw_free(priv);
999
1000        /*** Check new config ***/
1001        if ( cfg->rtaddress > 30 )
1002                return -1;
1003        if ( (cfg->evlog_size & (cfg->evlog_size-1)) != 0)
1004                return -1; /* SIZE: Not aligned to a power of 2 */
1005        if ( ((unsigned int)priv->cfg.evlog_buffer & (cfg->evlog_size-1)) != 0 )
1006                return -1; /* Buffer: Not aligned to size */
1007#if (RTBD_MAX > 0)
1008        if ( cfg->bd_count > RTBD_MAX )
1009                return -1;
1010#endif
1011
1012        /*** Make new config current ***/
1013        priv->cfg = *cfg;
1014
1015        /*** Adapt to new config ***/
1016
1017        if ( gr1553rt_sw_alloc(priv) != 0 ) 
1018                return -1;
1019
1020        gr1553rt_sw_init(priv);
1021
1022        return 0;
1023}
1024
1025int gr1553rt_start(void *rt)
1026{
1027        struct gr1553rt_priv *priv = rt;
1028        IRQ_GLOBAL_PREPARE(oldLevel);
1029
1030        if ( priv->started )
1031                return -1;
1032
1033        /*** Initialize software Pointers and stuff ***/
1034
1035        if ( !priv->satab_buffer || !priv->bd_buffer || !priv->evlog_buffer )
1036                return -2;
1037
1038        priv->evlog_cpu_next = priv->evlog_cpu_base;
1039
1040        /*** Initialize Registers ***/
1041
1042        /* Subaddress table base */
1043        priv->regs->rt_tab = (unsigned int)priv->sas_hw;
1044
1045        /* Mode code configuration */
1046        priv->regs->rt_mcctrl = priv->cfg.modecode;
1047
1048        /* RT Time Tag resolution */
1049        priv->regs->rt_ttag = priv->cfg.time_res << 16;
1050
1051        /* Event LOG base and size */
1052        priv->regs->rt_evsz = ~(priv->cfg.evlog_size - 1);
1053        priv->regs->rt_evlog = (unsigned int)priv->evlog_hw_base;
1054        priv->regs->rt_evirq = 0;
1055
1056        /* Clear and old IRQ flag and Enable IRQ */
1057        IRQ_GLOBAL_DISABLE(oldLevel);
1058        priv->regs->irq = GR1553B_IRQ_RTEV|GR1553B_IRQ_RTD|GR1553B_IRQ_RTTE;
1059        priv->regs->imask |= GR1553B_IRQEN_RTEVE | GR1553B_IRQEN_RTDE |
1060                        GR1553B_IRQEN_RTTEE;
1061
1062        /* Enable and Set RT address */
1063        priv->regs->rt_cfg = GR1553RT_KEY |
1064                        (priv->cfg.rtaddress << GR1553B_RT_CFG_RTADDR_BIT) |
1065                        GR1553B_RT_CFG_RTEN;
1066
1067        /* Tell software RT is started */
1068        priv->started = 1;
1069        IRQ_GLOBAL_ENABLE(oldLevel);
1070
1071        return 0;
1072}
1073
1074void gr1553rt_stop(void *rt)
1075{
1076        struct gr1553rt_priv *priv = rt;
1077        IRQ_GLOBAL_PREPARE(oldLevel);
1078
1079        IRQ_GLOBAL_DISABLE(oldLevel);
1080
1081        /* Stop Hardware */
1082        gr1553rt_hw_stop(priv);
1083
1084        /* Software state */
1085        priv->started = 0;
1086
1087        IRQ_GLOBAL_ENABLE(oldLevel);
1088}
1089
1090void gr1553rt_sa_schedule(
1091        void *rt,
1092        int subadr,
1093        int tx,
1094        struct gr1553rt_list *list
1095        )
1096{
1097        struct gr1553rt_priv *priv = rt;
1098        unsigned short bdid;
1099        struct gr1553rt_bd *bd;
1100
1101        if ( !list || (list->listid == -1) )
1102                return;
1103
1104        /* Get Hardware address of first descriptor in list */
1105        bdid = list->bds[0];
1106        if ( bdid == 0xffff )
1107                return;
1108        bd = &priv->bds_hw[bdid];
1109
1110        list->subadr = subadr;
1111
1112        /* Update Sub address table */
1113        if ( tx ) {
1114                list->subadr |= 0x100;
1115                priv->subadrs[subadr].txlistid = list->listid;
1116                priv->sas_cpu[subadr].txptr = (unsigned int)bd;
1117        } else {
1118                priv->subadrs[subadr].rxlistid = list->listid;
1119                priv->sas_cpu[subadr].rxptr = (unsigned int)bd;
1120        }
1121}
1122
1123void gr1553rt_sa_setopts(
1124        void *rt,
1125        int subadr,
1126        unsigned int mask,
1127        unsigned int options
1128        )
1129{
1130        struct gr1553rt_priv *priv = rt;
1131        unsigned int ctrl;
1132
1133        if ( (subadr > 31) || (priv->sas_cpu == NULL) )
1134                return;
1135
1136        ctrl = priv->sas_cpu[subadr].ctrl;
1137        priv->sas_cpu[subadr].ctrl = (ctrl & ~mask) | options;
1138}
1139
1140void gr1553rt_set_vecword(void *rt, unsigned int mask, unsigned int words)
1141{
1142        struct gr1553rt_priv *priv = rt;
1143        unsigned int vword;
1144
1145        if ( mask == 0 )
1146                return;
1147
1148        vword = priv->regs->rt_statw;
1149
1150        priv->regs->rt_statw = (vword & ~mask) | (words & mask);
1151}
1152
1153void gr1553rt_set_bussts(void *rt, unsigned int mask, unsigned int sts)
1154{
1155        struct gr1553rt_priv *priv = rt;
1156        unsigned int stat;
1157
1158        stat = priv->regs->rt_stat2;
1159        priv->regs->rt_stat2 = (stat & ~mask) | (mask & sts);
1160}
1161
1162void gr1553rt_status(void *rt, struct gr1553rt_status *status)
1163{
1164        struct gr1553rt_priv *priv = rt;
1165        struct gr1553b_regs *regs = priv->regs;
1166        unsigned int tmp;
1167        IRQ_GLOBAL_PREPARE(oldLevel);
1168
1169        IRQ_GLOBAL_DISABLE(oldLevel);
1170        status->status = regs->rt_stat;
1171        status->bus_status = regs->rt_stat2;
1172
1173        tmp = regs->rt_sync;
1174        status->synctime = tmp >> 16;
1175        status->syncword = tmp & 0xffff;
1176
1177        tmp = regs->rt_ttag;
1178        status->time_res = tmp >> 16;
1179        status->time = tmp & 0xffff;
1180
1181        IRQ_GLOBAL_ENABLE(oldLevel);
1182}
1183
1184void gr1553rt_list_sa(struct gr1553rt_list *list, int *subadr, int *tx)
1185{
1186        int sa, trt;
1187
1188        if ( list->subadr == -1 ) {
1189                sa = -1;
1190                trt = -1;
1191        } else {
1192                sa = list->subadr & 0xff;
1193                trt = (list->subadr & 0x100) >> 8;
1194        }
1195
1196        if ( subadr )
1197                *subadr = sa;
1198        if ( tx )
1199                *tx = trt;
1200}
1201
1202int gr1553rt_evlog_read(void *rt, unsigned int *dst, int max)
1203{
1204        struct gr1553rt_priv *priv = rt;
1205        int cnt, top, bot, left;
1206        unsigned int *hwpos;
1207
1208        /* Get address of hardware's current working entry */
1209        hwpos = (unsigned int *)priv->regs->rt_evlog;
1210
1211        /* Convert into CPU address */
1212        hwpos = (unsigned int *)
1213                ((unsigned int)hwpos - (unsigned int)priv->evlog_hw_base +
1214                (unsigned int)priv->evlog_cpu_base);
1215
1216        if ( priv->evlog_cpu_next == hwpos )
1217                return 0;
1218
1219        if ( priv->evlog_cpu_next > hwpos ) {
1220                top = (unsigned int)priv->evlog_cpu_end -
1221                        (unsigned int)priv->evlog_cpu_next;
1222                bot = (unsigned int)hwpos - (unsigned int)priv->evlog_cpu_base;
1223        } else {
1224                top = (unsigned int)hwpos - (unsigned int)priv->evlog_cpu_next;
1225                bot = 0;
1226        }
1227        top = top / 4;
1228        bot = bot / 4;
1229
1230        left = max;
1231        if ( top > 0 ) {
1232                if ( top > left ) {
1233                        cnt = left;
1234                } else {
1235                        cnt = top;
1236                }
1237                memcpy(dst, priv->evlog_cpu_next, cnt*4);
1238                dst += cnt;
1239                left -= cnt;
1240        }
1241
1242        if ( (bot > 0) && (left > 0) ) {
1243                if ( bot > left ) {
1244                        cnt = left;
1245                } else {
1246                        cnt = bot;
1247                }
1248                memcpy(dst, priv->evlog_cpu_base, cnt*4);
1249                left -= cnt;
1250        }
1251
1252        cnt = max - left;
1253        priv->evlog_cpu_next += cnt;
1254        if ( priv->evlog_cpu_next >= priv->evlog_cpu_end ) {
1255                priv->evlog_cpu_next = (unsigned int *)
1256                        ((unsigned int)priv->evlog_cpu_base +
1257                        ((unsigned int)priv->evlog_cpu_next -
1258                         (unsigned int)priv->evlog_cpu_end ));
1259        }
1260
1261        return max - left;
1262}
Note: See TracBrowser for help on using the repository browser.