source: rtems/bsps/sparc/shared/1553/gr1553rt.c @ 31720925

5
Last change on this file since 31720925 was 31720925, checked in by Sebastian Huber <sebastian.huber@…>, on 12/22/18 at 06:13:44

grlib: Move header files

Update #3678.

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