File indexing completed on 2025-05-11 08:24:07
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042 #include <stdlib.h>
0043
0044 #include <bsp.h>
0045 #include <grlib/grslink.h>
0046 #include <grlib/ambapp.h>
0047 #include <grlib/grlib.h>
0048
0049 #include <grlib/grlib_impl.h>
0050
0051 #ifndef GAISLER_SLINK
0052 #define GAISLER_SLINK 0x02F
0053 #endif
0054
0055
0056
0057
0058 #ifdef DEBUG
0059 #define DBG(x...) printk(x)
0060 #else
0061 #define DBG(x...)
0062 #endif
0063
0064
0065 #define SLINK_RW (1 << 23)
0066 #define SLINK_CHAN_POS 16
0067
0068
0069 typedef struct {
0070 volatile unsigned int clockscale;
0071 volatile unsigned int ctrl;
0072 volatile unsigned int nullwrd;
0073 volatile unsigned int sts;
0074 volatile unsigned int msk;
0075 volatile unsigned int abase;
0076 volatile unsigned int bbase;
0077 volatile unsigned int td;
0078 volatile unsigned int rd;
0079 } SLINK_regs;
0080
0081 typedef struct {
0082 char readstat;
0083 char seqstat;
0084 unsigned char scnt;
0085 } SLINK_status;
0086
0087 typedef struct {
0088 int size;
0089 unsigned int *buf;
0090 unsigned int *first;
0091 unsigned int *last;
0092 unsigned int *max;
0093 int full;
0094 } SLINK_queue;
0095
0096 typedef struct {
0097 SLINK_regs *reg;
0098 SLINK_status *status;
0099 void (*slink_irq_handler)(int);
0100 void (*slink_seq_change)(int);
0101 int rword;
0102 rtems_id read_sem;
0103 SLINK_queue *queues;
0104 #ifdef SLINK_COLLECT_STATISTICS
0105 SLINK_stats *stats;
0106 #endif
0107 } SLINK_cfg;
0108
0109
0110 static SLINK_cfg *cfg = NULL;
0111
0112
0113
0114
0115
0116
0117
0118
0119
0120
0121 static int SLINK_createqueues(int size)
0122 {
0123 SLINK_queue *q;
0124 int i, j;
0125
0126 if ((q = grlib_malloc(SLINK_NUMQUEUES*sizeof(*q))) == NULL)
0127 goto slink_qiniterr1;
0128
0129 for (i = 0; i < SLINK_NUMQUEUES; i++) {
0130 q[i].size = size;
0131 if ((q[i].buf = grlib_malloc(size*sizeof(int))) == NULL)
0132 goto slink_qiniterr2;
0133 q[i].first = q[i].last = q[i].buf;
0134 q[i].max = q[i].buf + (size-1);
0135 q[i].full = 0;
0136 }
0137
0138 cfg->queues = q;
0139
0140 return 0;
0141
0142 slink_qiniterr2:
0143 for (j = 0; j < i; j++)
0144 free(q[i].buf);
0145 free(q);
0146 slink_qiniterr1:
0147 return -1;
0148 }
0149
0150
0151
0152
0153
0154
0155
0156
0157
0158
0159
0160
0161
0162
0163
0164
0165
0166
0167
0168
0169
0170
0171
0172
0173
0174 static void SLINK_enqueue(unsigned int slink_wrd)
0175 {
0176 SLINK_queue *ioq = cfg->queues + SLINK_WRD_CARDNUM(slink_wrd);
0177
0178 if (!ioq->full && SLINK_WRD_CARDNUM(slink_wrd) < SLINK_NUMQUEUES) {
0179 *ioq->last = slink_wrd;
0180 ioq->last = (ioq->last >= ioq->max) ? ioq->buf : ioq->last+1;
0181 ioq->full = ioq->last == ioq->first;
0182 return;
0183 }
0184 #ifdef SLINK_COLLECT_STATISTICS
0185 cfg->stats->lostwords++;
0186 #endif
0187 }
0188
0189
0190
0191
0192
0193
0194
0195
0196
0197
0198
0199 static int SLINK_getaddr(int *base, int *irq)
0200 {
0201 struct ambapp_apb_info c;
0202
0203 if (ambapp_find_apbslv(ambapp_plb(),VENDOR_GAISLER,GAISLER_SLINK,&c) == 1) {
0204 *base = c.start;
0205 *irq = c.common.irq;
0206 return 0;
0207 }
0208 return -1;
0209 }
0210
0211
0212
0213
0214
0215
0216
0217
0218 static int SLINK_calcscaler(int sysfreq)
0219 {
0220 int fact = sysfreq / SLINK_FREQ_HZ;
0221 return ((fact/2-1) << 16) | (fact % 2 ? fact/2 : fact/2-1);
0222 }
0223
0224
0225
0226
0227
0228
0229
0230
0231
0232 static int SLINK_getsysfreq(void)
0233 {
0234 struct ambapp_apb_info t;
0235 struct gptimer_regs *tregs;
0236
0237 if (ambapp_find_apbslv(ambapp_plb(),VENDOR_GAISLER,GAISLER_GPTIMER,&t)==1) {
0238 tregs = (struct gptimer_regs *)t.start;
0239 DBG("SLINK_getsysfreq returning %d\n",
0240 (tregs->scaler_reload+1)*1000*1000);
0241 return (tregs->scaler_reload+1)*1000*1000;
0242 }
0243 return 0;
0244 }
0245
0246
0247
0248
0249
0250
0251
0252
0253
0254
0255
0256
0257
0258 static rtems_isr SLINK_interrupt_handler(void *v)
0259 {
0260 unsigned int sts;
0261 unsigned int wrd;
0262
0263
0264 while ((sts = cfg->reg->sts) & SLINK_S_RNE) {
0265
0266
0267 wrd = cfg->reg->rd;
0268
0269
0270 switch (SLINK_WRD_CHAN(wrd)) {
0271 case 0:
0272 cfg->slink_irq_handler(wrd);
0273 #ifdef SLINK_COLLECT_STATISTICS
0274 cfg->stats->interrupts++;
0275 #endif
0276 break;
0277 case 3:
0278 if (cfg->status->readstat == SLINK_ACTIVE) {
0279 rtems_semaphore_release(cfg->read_sem);
0280 cfg->status->readstat = SLINK_COMPLETED;
0281 cfg->rword = wrd;
0282 break;
0283 }
0284 default:
0285 SLINK_enqueue(wrd);
0286 break;
0287 }
0288 }
0289
0290
0291 if (sts & SLINK_S_SC) {
0292
0293 cfg->status->seqstat = SLINK_COMPLETED;
0294 if (cfg->slink_seq_change)
0295 cfg->slink_seq_change(SLINK_COMPLETED);
0296 #ifdef SLINK_COLLECT_STATISTICS
0297 cfg->stats->seqcomp++;
0298 #endif
0299 } else if (sts & SLINK_S_SA) {
0300
0301 cfg->status->seqstat = SLINK_ABORTED;
0302 cfg->status->scnt = (sts >> SLINK_S_SI_POS);
0303 if (cfg->slink_seq_change)
0304 cfg->slink_seq_change(SLINK_ABORTED);
0305 }
0306
0307
0308 if (sts & SLINK_S_PERR) {
0309
0310
0311
0312
0313
0314 if (cfg->status->seqstat == SLINK_ACTIVE) {
0315 cfg->status->seqstat = SLINK_PARERR;
0316 if (cfg->slink_seq_change)
0317 cfg->slink_seq_change(SLINK_PARERR);
0318 }
0319
0320 if (cfg->status->readstat == SLINK_ACTIVE) {
0321 cfg->status->readstat = SLINK_PARERR;
0322 rtems_semaphore_release(cfg->read_sem);
0323 }
0324 #ifdef SLINK_COLLECT_STATISTICS
0325 cfg->stats->parerr++;
0326 #endif
0327 }
0328 if (sts & SLINK_S_AERR) {
0329
0330 cfg->status->seqstat = SLINK_AMBAERR;
0331 cfg->status->scnt = sts >> SLINK_S_SI_POS;
0332 if (cfg->slink_seq_change)
0333 cfg->slink_seq_change(SLINK_AMBAERR);
0334 }
0335 if (sts & SLINK_S_ROV) {
0336
0337 if (cfg->status->readstat == SLINK_ACTIVE) {
0338 cfg->status->readstat = SLINK_ROV;
0339 rtems_semaphore_release(cfg->read_sem);
0340 }
0341 #ifdef SLINK_COLLECT_STATISICS
0342 cfg->status->recov++;
0343 #endif
0344 }
0345
0346
0347 cfg->reg->sts = sts;
0348 }
0349
0350
0351
0352
0353
0354
0355
0356
0357
0358
0359
0360
0361 int SLINK_init(unsigned int nullwrd, int parity, int qsize,
0362 void (*interrupt_trans_handler)(int),
0363 void (*sequence_callback)(int))
0364 {
0365 int base;
0366 int irq;
0367 rtems_status_code st;
0368
0369
0370 if (cfg == NULL && (cfg = grlib_malloc(sizeof(*cfg))) == NULL) {
0371 DBG("SLINK_init: Could not allocate cfg structure\n");
0372 goto slink_initerr1;
0373 }
0374
0375
0376 st = rtems_semaphore_create(rtems_build_name('S', 'L', 'R', '0'), 0,
0377 (RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|
0378 RTEMS_NO_INHERIT_PRIORITY|RTEMS_LOCAL|
0379 RTEMS_NO_PRIORITY_CEILING), 0,
0380 &cfg->read_sem);
0381 if (st != RTEMS_SUCCESSFUL) {
0382 DBG("SLINK_init: Could not create semaphore\n");
0383 goto slink_initerr1;
0384 }
0385
0386
0387 if (SLINK_getaddr(&base, &irq) == -1) {
0388 DBG("SLINK_init: Could not find core\n");
0389 goto slink_initerr2;
0390 }
0391 cfg->reg = (SLINK_regs*)base;
0392
0393
0394 if ((cfg->status = grlib_calloc(1, sizeof(*cfg->status))) == NULL) {
0395 DBG("SLINK_init: Could not allocate status structure\n");
0396 goto slink_initerr2;
0397 }
0398 cfg->status->seqstat = SLINK_COMPLETED;
0399 cfg->status->readstat = SLINK_COMPLETED;
0400
0401 #ifdef SLINK_COLLECT_STATISTICS
0402
0403 if ((cfg->stats = grlib_calloc(1, sizeof(*cfg->stats))) == NULL) {
0404 DBG("SLINK_init: Could not allocate statistics structure\n");
0405 goto slink_initerr3;
0406 }
0407 #endif
0408
0409
0410 if (SLINK_createqueues(qsize) == -1) {
0411 DBG("SLINK_init: Could not create queues\n");
0412 goto slink_initerr3;
0413 }
0414
0415
0416 cfg->reg->clockscale = SLINK_calcscaler(SLINK_getsysfreq());
0417 cfg->reg->ctrl = parity ? SLINK_C_PAR : 0;
0418 cfg->reg->nullwrd = nullwrd;
0419 cfg->reg->msk = (SLINK_M_PERRE | SLINK_M_AERRE | SLINK_M_ROVE |
0420 SLINK_M_RNEE | SLINK_M_SAE | SLINK_M_SCE);
0421
0422
0423 cfg->slink_irq_handler = interrupt_trans_handler;
0424
0425
0426 cfg->slink_seq_change = sequence_callback;
0427
0428
0429 rtems_interrupt_handler_install(irq, "slink",
0430 RTEMS_INTERRUPT_SHARED,
0431 SLINK_interrupt_handler, NULL);
0432
0433 return 0;
0434
0435 slink_initerr3:
0436 free(cfg->status);
0437 slink_initerr2:
0438 free(cfg);
0439 slink_initerr1:
0440 return -1;
0441 }
0442
0443
0444
0445
0446 void SLINK_start(void)
0447 {
0448 if (cfg != NULL)
0449 cfg->reg->ctrl |= SLINK_C_SLE;
0450 }
0451
0452
0453
0454
0455 void SLINK_stop(void)
0456 {
0457 if (cfg != NULL)
0458 cfg->reg->ctrl &= ~SLINK_C_SLE;
0459 }
0460
0461
0462
0463
0464
0465
0466
0467
0468
0469
0470
0471
0472
0473 int SLINK_read(int data, int channel, int *reply)
0474 {
0475 DBG("SLINK_read: called..");
0476
0477 if (cfg->reg->sts & SLINK_S_TNF) {
0478 cfg->status->readstat = SLINK_ACTIVE;
0479 cfg->reg->td = SLINK_RW | channel << SLINK_CHAN_POS | data;
0480 } else {
0481 DBG("queue FULL\n");
0482 return -SLINK_QFULL;
0483 }
0484
0485
0486 rtems_semaphore_obtain(cfg->read_sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
0487
0488 if (cfg->status->readstat == SLINK_COMPLETED) {
0489 *reply = cfg->rword;
0490 #ifdef SLINK_COLLECT_STATISTICS
0491 cfg->stats->reads++;
0492 #endif
0493 DBG("returning 0\n");
0494 return 0;
0495 } else {
0496 DBG("returning error code\n");
0497 return -cfg->status->readstat;
0498 }
0499 }
0500
0501
0502
0503
0504
0505
0506
0507
0508
0509
0510 int SLINK_write(int data, int channel)
0511 {
0512 if (cfg->reg->sts & SLINK_S_TNF) {
0513 cfg->reg->td = channel << SLINK_CHAN_POS | data;
0514 #ifdef SLINK_COLLECT_STATISTICS
0515 cfg->stats->writes++;
0516 #endif
0517 return 0;
0518 }
0519
0520 return -SLINK_QFULL;
0521 }
0522
0523
0524
0525
0526
0527
0528
0529
0530
0531
0532
0533 int SLINK_seqstart(int *a, int *b, int n, int channel, int reconly)
0534 {
0535
0536 if (cfg->status->seqstat == SLINK_ACTIVE ||
0537 cfg->status->seqstat == SLINK_PARERR)
0538 return -1;
0539
0540
0541 cfg->reg->abase = (int)a;
0542 cfg->reg->bbase = (int)b;
0543
0544
0545 cfg->status->seqstat = SLINK_ACTIVE;
0546
0547
0548 if (reconly == 1) {
0549 cfg->reg->ctrl = (((n-1) << SLINK_C_SLEN_POS) | SLINK_C_SRO |
0550 (channel << SLINK_C_SCN_POS) |
0551 SLINK_C_SE | (cfg->reg->ctrl & 0xC000000F));
0552 } else {
0553 cfg->reg->ctrl = (((n-1) << SLINK_C_SLEN_POS) |
0554 (channel << SLINK_C_SCN_POS) |
0555 SLINK_C_SE | (cfg->reg->ctrl & 0xC000000F));
0556 }
0557
0558 #ifdef SLINK_COLLECT_STATISTICS
0559 cfg->stats->sequences++;
0560 #endif
0561
0562 return 0;
0563 }
0564
0565
0566
0567
0568
0569
0570 void SLINK_seqabort(void)
0571 {
0572 cfg->reg->ctrl = cfg->reg->ctrl | SLINK_C_AS;
0573 }
0574
0575
0576
0577
0578
0579
0580
0581
0582
0583
0584
0585
0586
0587
0588
0589
0590
0591 int SLINK_seqstatus(void)
0592 {
0593 return cfg->status->seqstat;
0594 }
0595
0596
0597
0598
0599
0600
0601
0602
0603 int SLINK_seqwrds(void)
0604 {
0605 switch (cfg->status->seqstat) {
0606 case SLINK_COMPLETED: return 0;
0607 case SLINK_ACTIVE | SLINK_PARERR: return -1;
0608 default: return cfg->status->scnt;
0609 }
0610 }
0611
0612
0613
0614
0615
0616
0617 int SLINK_hwstatus(void)
0618 {
0619 return cfg->reg->sts;
0620 }
0621
0622
0623
0624
0625
0626
0627
0628
0629 int SLINK_queuestatus(int iocard)
0630 {
0631 unsigned int first, last;
0632 SLINK_queue *ioq;
0633
0634 if (iocard >= SLINK_NUMQUEUES)
0635 return -1;
0636
0637 ioq = cfg->queues + iocard;
0638
0639 if (ioq->full)
0640 return ioq->size;
0641 if (ioq->first == ioq->last)
0642 return 0;
0643
0644 first = ((unsigned int)ioq->first)/sizeof(unsigned int);
0645 last = ((unsigned int)ioq->last)/sizeof(unsigned int);
0646
0647 return first < last ? last - first : ioq->size - first + last;
0648 }
0649
0650
0651
0652
0653
0654
0655
0656
0657 int SLINK_dequeue(int iocard, int *elem)
0658 {
0659 if (iocard >= SLINK_NUMQUEUES)
0660 return -1;
0661
0662 SLINK_queue *ioq = cfg->queues + iocard;
0663
0664 if (ioq->last != ioq->first || ioq->full) {
0665 *elem = *ioq->first;
0666 ioq->first = (ioq->first >= ioq->max) ? ioq->buf : ioq->first+1;
0667 ioq->full = 0;
0668 return 0;
0669 }
0670 return -1;
0671 }
0672
0673
0674
0675
0676
0677
0678 SLINK_stats *SLINK_statistics(void)
0679 {
0680 #ifdef SLINK_COLLECT_STATISTICS
0681 return cfg->stats;
0682 #else
0683 return NULL;
0684 #endif
0685 }