OpenCores
URL https://opencores.org/ocsvn/openrisc_me/openrisc_me/trunk

Subversion Repositories openrisc_me

[/] [openrisc/] [trunk/] [rtos/] [rtems/] [c/] [src/] [lib/] [libbsp/] [m68k/] [gen68360/] [network/] [network.c] - Blame information for rev 173

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 30 unneback
/*
2
 * RTEMS driver for M68360 SCC1 Ethernet
3
 *
4
 * W. Eric Norum
5
 * Saskatchewan Accelerator Laboratory
6
 * University of Saskatchewan
7
 * Saskatoon, Saskatchewan, CANADA
8
 * eric@skatter.usask.ca
9
 *
10
 *  $Id: network.c,v 1.2 2001-09-27 12:00:08 chris Exp $
11
 */
12
#include <bsp.h>
13
#include <m68360.h>
14
#include <stdio.h>
15
#include <rtems/error.h>
16
#include <rtems/rtems_bsdnet.h>
17
 
18
#include <sys/param.h>
19
#include <sys/mbuf.h>
20
#include <sys/socket.h>
21
#include <sys/sockio.h>
22
 
23
#include <net/if.h>
24
 
25
#include <netinet/in.h>
26
#include <netinet/if_ether.h>
27
 
28
/*
29
 * Number of SCCs supported by this driver
30
 */
31
#define NSCCDRIVER      1
32
 
33
/*
34
 * Default number of buffer descriptors set aside for this driver.
35
 * The number of transmit buffer descriptors has to be quite large
36
 * since a single frame often uses four or more buffer descriptors.
37
 */
38
#define RX_BUF_COUNT     15
39
#define TX_BUF_COUNT     4
40
#define TX_BD_PER_BUF    4
41
 
42
/*
43
 * RTEMS event used by interrupt handler to signal driver tasks.
44
 * This must not be any of the events used by the network task synchronization.
45
 */
46
#define INTERRUPT_EVENT RTEMS_EVENT_1
47
 
48
/*
49
 * RTEMS event used to start transmit daemon.
50
 * This must not be the same as INTERRUPT_EVENT.
51
 */
52
#define START_TRANSMIT_EVENT    RTEMS_EVENT_2
53
 
54
/*
55
 * Receive buffer size -- Allow for a full ethernet packet including CRC
56
 */
57
#define RBUF_SIZE       1520
58
 
59
#if (MCLBYTES < RBUF_SIZE)
60
# error "Driver must have MCLBYTES > RBUF_SIZE"
61
#endif
62
 
63
/*
64
 * Per-device data
65
 */
66
struct scc_softc {
67
        struct arpcom           arpcom;
68
        struct mbuf             **rxMbuf;
69
        struct mbuf             **txMbuf;
70
        int                     acceptBroadcast;
71
        int                     rxBdCount;
72
        int                     txBdCount;
73
        int                     txBdHead;
74
        int                     txBdTail;
75
        int                     txBdActiveCount;
76
        m360BufferDescriptor_t  *rxBdBase;
77
        m360BufferDescriptor_t  *txBdBase;
78
        rtems_id                rxDaemonTid;
79
        rtems_id                txDaemonTid;
80
 
81
        /*
82
         * Statistics
83
         */
84
        unsigned long   rxInterrupts;
85
        unsigned long   rxNotFirst;
86
        unsigned long   rxNotLast;
87
        unsigned long   rxGiant;
88
        unsigned long   rxNonOctet;
89
        unsigned long   rxRunt;
90
        unsigned long   rxBadCRC;
91
        unsigned long   rxOverrun;
92
        unsigned long   rxCollision;
93
 
94
        unsigned long   txInterrupts;
95
        unsigned long   txDeferred;
96
        unsigned long   txHeartbeat;
97
        unsigned long   txLateCollision;
98
        unsigned long   txRetryLimit;
99
        unsigned long   txUnderrun;
100
        unsigned long   txLostCarrier;
101
        unsigned long   txRawWait;
102
        unsigned long   txCoalesced;
103
        unsigned long   txCoalesceFailed;
104
        unsigned long   txRetry;
105
};
106
static struct scc_softc scc_softc[NSCCDRIVER];
107
 
108
/*
109
 * SCC1 interrupt handler
110
 */
111
static rtems_isr
112
m360Enet_interrupt_handler (rtems_vector_number v)
113
{
114
        /*
115
         * Frame received?
116
         */
117
        if ((m360.scc1.sccm & 0x8) && (m360.scc1.scce & 0x8)) {
118
                m360.scc1.scce = 0x8;
119
                m360.scc1.sccm &= ~0x8;
120
                scc_softc[0].rxInterrupts++;
121
                rtems_event_send (scc_softc[0].rxDaemonTid, INTERRUPT_EVENT);
122
        }
123
 
124
        /*
125
         * Buffer transmitted or transmitter error?
126
         */
127
        if ((m360.scc1.sccm & 0x12) && (m360.scc1.scce & 0x12)) {
128
                m360.scc1.scce = 0x12;
129
                m360.scc1.sccm &= ~0x12;
130
                scc_softc[0].txInterrupts++;
131
                rtems_event_send (scc_softc[0].txDaemonTid, INTERRUPT_EVENT);
132
        }
133
        m360.cisr = 1UL << 30;  /* Clear SCC1 interrupt-in-service bit */
134
}
135
 
136
/*
137
 * Initialize the ethernet hardware
138
 */
139
static void
140
m360Enet_initialize_hardware (struct scc_softc *sc)
141
{
142
        int i;
143
        unsigned char *hwaddr;
144
        rtems_status_code status;
145
        rtems_isr_entry old_handler;
146
 
147
        /*
148
         * Configure port A CLK1, CLK2, TXD1 and RXD1 pins
149
         */
150
        m360.papar |=  0x303;
151
        m360.padir &= ~0x303;
152
        m360.paodr &= ~0x303;
153
 
154
        /*
155
         * Configure port C CTS1* and CD1* pins
156
         */
157
        m360.pcpar &= ~0x30;
158
        m360.pcdir &= ~0x30;
159
        m360.pcso  |=  0x30;
160
 
161
        /*
162
         * Connect CLK1 and CLK2 to SCC1
163
         */
164
        m360.sicr &= ~0xFF;
165
        m360.sicr |= (5 << 3) | 4;
166
 
167
        /*
168
         * Allocate mbuf pointers
169
         */
170
        sc->rxMbuf = malloc (sc->rxBdCount * sizeof *sc->rxMbuf, M_MBUF, M_NOWAIT);
171
        sc->txMbuf = malloc (sc->txBdCount * sizeof *sc->txMbuf, M_MBUF, M_NOWAIT);
172
        if (!sc->rxMbuf || !sc->txMbuf)
173
                rtems_panic ("No memory for mbuf pointers");
174
 
175
        /*
176
         * Set receiver and transmitter buffer descriptor bases
177
         */
178
        sc->rxBdBase = M360AllocateBufferDescriptors(sc->rxBdCount);
179
        sc->txBdBase = M360AllocateBufferDescriptors(sc->txBdCount);
180
        m360.scc1p.rbase = (char *)sc->rxBdBase - (char *)&m360;
181
        m360.scc1p.tbase = (char *)sc->txBdBase - (char *)&m360;
182
 
183
        /*
184
         * Send "Init parameters" command
185
         */
186
        M360ExecuteRISC (M360_CR_OP_INIT_RX_TX | M360_CR_CHAN_SCC1);
187
 
188
        /*
189
         * Set receive and transmit function codes
190
         */
191
        m360.scc1p.rfcr = M360_RFCR_MOT | M360_RFCR_DMA_SPACE;
192
        m360.scc1p.tfcr = M360_TFCR_MOT | M360_TFCR_DMA_SPACE;
193
 
194
        /*
195
         * Set maximum receive buffer length
196
         */
197
        m360.scc1p.mrblr = RBUF_SIZE;
198
 
199
        /*
200
         * Set CRC parameters
201
         */
202
        m360.scc1p.un.ethernet.c_pres = 0xFFFFFFFF;
203
        m360.scc1p.un.ethernet.c_mask = 0xDEBB20E3;
204
 
205
        /*
206
         * Clear diagnostic counters
207
         */
208
        m360.scc1p.un.ethernet.crcec = 0;
209
        m360.scc1p.un.ethernet.alec = 0;
210
        m360.scc1p.un.ethernet.disfc = 0;
211
 
212
        /*
213
         * Set pad value
214
         */
215
        m360.scc1p.un.ethernet.pads = 0x8888;
216
 
217
        /*
218
         * Set retry limit
219
         */
220
        m360.scc1p.un.ethernet.ret_lim = 15;
221
 
222
        /*
223
         * Set maximum and minimum frame length
224
         */
225
        m360.scc1p.un.ethernet.mflr = 1518;
226
        m360.scc1p.un.ethernet.minflr = 64;
227
        m360.scc1p.un.ethernet.maxd1 = RBUF_SIZE;
228
        m360.scc1p.un.ethernet.maxd2 = RBUF_SIZE;
229
 
230
        /*
231
         * Clear group address hash table
232
         */
233
        m360.scc1p.un.ethernet.gaddr1 = 0;
234
        m360.scc1p.un.ethernet.gaddr2 = 0;
235
        m360.scc1p.un.ethernet.gaddr3 = 0;
236
        m360.scc1p.un.ethernet.gaddr4 = 0;
237
 
238
        /*
239
         * Set our physical address
240
         */
241
        hwaddr = sc->arpcom.ac_enaddr;
242
        m360.scc1p.un.ethernet.paddr_h = (hwaddr[5] << 8) | hwaddr[4];
243
        m360.scc1p.un.ethernet.paddr_m = (hwaddr[3] << 8) | hwaddr[2];
244
        m360.scc1p.un.ethernet.paddr_l = (hwaddr[1] << 8) | hwaddr[0];
245
 
246
        /*
247
         * Aggressive retry
248
         */
249
        m360.scc1p.un.ethernet.p_per = 0;
250
 
251
        /*
252
         * Clear individual address hash table
253
         */
254
        m360.scc1p.un.ethernet.iaddr1 = 0;
255
        m360.scc1p.un.ethernet.iaddr2 = 0;
256
        m360.scc1p.un.ethernet.iaddr3 = 0;
257
        m360.scc1p.un.ethernet.iaddr4 = 0;
258
 
259
        /*
260
         * Set up receive buffer descriptors
261
         */
262
        for (i = 0 ; i < sc->rxBdCount ; i++)
263
                (sc->rxBdBase + i)->status = 0;
264
 
265
        /*
266
         * Set up transmit buffer descriptors
267
         */
268
        for (i = 0 ; i < sc->txBdCount ; i++) {
269
                (sc->txBdBase + i)->status = 0;
270
                sc->txMbuf[i] = NULL;
271
        }
272
        sc->txBdHead = sc->txBdTail = 0;
273
        sc->txBdActiveCount = 0;
274
 
275
        /*
276
         * Clear any outstanding events
277
         */
278
        m360.scc1.scce = 0xFFFF;
279
 
280
        /*
281
         * Set up interrupts
282
         */
283
        status = rtems_interrupt_catch (m360Enet_interrupt_handler,
284
                                                (m360.cicr & 0xE0) | 0x1E,
285
                                                &old_handler);
286
        if (status != RTEMS_SUCCESSFUL)
287
                rtems_panic ("Can't attach M360 SCC1 interrupt handler: %s\n",
288
                                                rtems_status_text (status));
289
        m360.scc1.sccm = 0;      /* No interrupts unmasked till necessary */
290
        m360.cimr |= (1UL << 30);       /* Enable SCC1 interrupt */
291
 
292
        /*
293
         * Set up General SCC Mode Register
294
         * Ethernet configuration
295
         */
296
        m360.scc1.gsmr_h = 0x0;
297
        m360.scc1.gsmr_l = 0x1088000c;
298
 
299
        /*
300
         * Set up data synchronization register
301
         * Ethernet synchronization pattern
302
         */
303
        m360.scc1.dsr = 0xd555;
304
 
305
        /*
306
         * Set up protocol-specific mode register
307
         *      Heartbeat check
308
         *      No force collision
309
         *      Discard short frames
310
         *      Individual address mode
311
         *      Ethernet CRC
312
         *      Not promisuous
313
         *      Ignore/accept broadcast packets as specified
314
         *      Normal backoff timer
315
         *      No loopback
316
         *      No input sample at end of frame
317
         *      64-byte limit for late collision
318
         *      Wait 22 bits before looking for start of frame delimiter
319
         *      Disable full-duplex operation
320
         */
321
        m360.scc1.psmr = 0x880A | (sc->acceptBroadcast ? 0 : 0x100);
322
 
323
        /*
324
         * Enable the TENA (RTS1*) pin
325
         */
326
#if (defined (M68360_ATLAS_HSB))
327
        m360.pbpar |= 0x1000;
328
        m360.pbdir |= 0x1000;
329
#else
330
        m360.pcpar |=  0x1;
331
        m360.pcdir &= ~0x1;
332
#endif
333
}
334
 
335
/*
336
 * Soak up buffer descriptors that have been sent
337
 * Note that a buffer descriptor can't be retired as soon as it becomes
338
 * ready.  The MC68360 Errata (May 96) says that, "If an Ethernet frame is
339
 *  made up of multiple buffers, the user should not reuse the first buffer
340
 * descriptor until the last buffer descriptor of the frame has had its
341
 * ready bit cleared by the CPM".
342
 */
343
static void
344
m360Enet_retire_tx_bd (struct scc_softc *sc)
345
{
346
        rtems_unsigned16 status;
347
        int i;
348
        int nRetired;
349
        struct mbuf *m, *n;
350
        int retries = 0;
351
        int saveStatus = 0;
352
 
353
        i = sc->txBdTail;
354
        nRetired = 0;
355
        while ((sc->txBdActiveCount != 0)
356
           &&  (((status = (sc->txBdBase + i)->status) & M360_BD_READY) == 0)) {
357
                /*
358
                 * Check for errors which stop the transmitter.
359
                 */
360
                if (status & (M360_BD_LATE_COLLISION |
361
                                M360_BD_RETRY_LIMIT |
362
                                M360_BD_UNDERRUN)) {
363
                        int j;
364
 
365
                        if (status & M360_BD_LATE_COLLISION)
366
                                sc->txLateCollision++;
367
                        if (status & M360_BD_RETRY_LIMIT)
368
                                sc->txRetryLimit++;
369
                        if (status & M360_BD_UNDERRUN)
370
                                sc->txUnderrun++;
371
 
372
                        /*
373
                         * Reenable buffer descriptors
374
                         */
375
                        j = sc->txBdTail;
376
                        for (;;) {
377
                                status = (sc->txBdBase + j)->status;
378
                                if (status & M360_BD_READY)
379
                                        break;
380
                                (sc->txBdBase + j)->status = M360_BD_READY |
381
                                        (status & (M360_BD_PAD |
382
                                                   M360_BD_WRAP |
383
                                                   M360_BD_INTERRUPT |
384
                                                   M360_BD_LAST |
385
                                                   M360_BD_TX_CRC));
386
                                if (status & M360_BD_LAST)
387
                                        break;
388
                                if (++j == sc->txBdCount)
389
                                        j = 0;
390
                        }
391
 
392
                        /*
393
                         * Move transmitter back to the first
394
                         * buffer descriptor in the frame.
395
                         */
396
                        m360.scc1p._tbptr = m360.scc1p.tbase +
397
                                sc->txBdTail * sizeof (m360BufferDescriptor_t);
398
 
399
                        /*
400
                         * Restart the transmitter
401
                         */
402
                        M360ExecuteRISC (M360_CR_OP_RESTART_TX | M360_CR_CHAN_SCC1);
403
                        continue;
404
                }
405
                saveStatus |= status;
406
                retries += (status >> 2) & 0xF;
407
                nRetired++;
408
                if (status & M360_BD_LAST) {
409
                        /*
410
                         * A full frame has been transmitted.
411
                         * Free all the associated buffer descriptors.
412
                         */
413
                        if (saveStatus & M360_BD_DEFER)
414
                                sc->txDeferred++;
415
                        if (saveStatus & M360_BD_HEARTBEAT)
416
                                sc->txHeartbeat++;
417
                        if (saveStatus & M360_BD_CARRIER_LOST)
418
                                sc->txLostCarrier++;
419
                        saveStatus = 0;
420
                        sc->txRetry += retries;
421
                        retries = 0;
422
                        sc->txBdActiveCount -= nRetired;
423
                        while (nRetired) {
424
                                nRetired--;
425
                                m = sc->txMbuf[sc->txBdTail];
426
                                MFREE (m, n);
427
                                if (++sc->txBdTail == sc->txBdCount)
428
                                        sc->txBdTail = 0;
429
                        }
430
                }
431
                if (++i == sc->txBdCount)
432
                        i = 0;
433
        }
434
}
435
 
436
/*
437
 * SCC reader task
438
 */
439
static void
440
scc_rxDaemon (void *arg)
441
{
442
        struct scc_softc *sc = (struct scc_softc *)arg;
443
        struct ifnet *ifp = &sc->arpcom.ac_if;
444
        struct mbuf *m;
445
        rtems_unsigned16 status;
446
        volatile m360BufferDescriptor_t *rxBd;
447
        int rxBdIndex;
448
 
449
        /*
450
         * Allocate space for incoming packets and start reception
451
         */
452
        for (rxBdIndex = 0 ; ;) {
453
                rxBd = sc->rxBdBase + rxBdIndex;
454
                MGETHDR (m, M_WAIT, MT_DATA);
455
                MCLGET (m, M_WAIT);
456
                m->m_pkthdr.rcvif = ifp;
457
                sc->rxMbuf[rxBdIndex] = m;
458
                rxBd->buffer = mtod (m, void *);
459
                if (++rxBdIndex == sc->rxBdCount) {
460
                        rxBd->status = M360_BD_EMPTY | M360_BD_INTERRUPT | M360_BD_WRAP;
461
                        break;
462
                }
463
                rxBd->status = M360_BD_EMPTY | M360_BD_INTERRUPT;
464
        }
465
 
466
        /*
467
         * Input packet handling loop
468
         */
469
        rxBdIndex = 0;
470
        for (;;) {
471
                rxBd = sc->rxBdBase + rxBdIndex;
472
 
473
                /*
474
                 * Wait for packet if there's not one ready
475
                 */
476
                if ((status = rxBd->status) & M360_BD_EMPTY) {
477
                        /*
478
                         * Clear old events
479
                         */
480
                        m360.scc1.scce = 0x8;
481
 
482
                        /*
483
                         * Wait for packet
484
                         * Note that the buffer descriptor is checked
485
                         * *before* the event wait -- this catches the
486
                         * possibility that a packet arrived between the
487
                         * `if' above, and the clearing of the event register.
488
                         */
489
                        while ((status = rxBd->status) & M360_BD_EMPTY) {
490
                                rtems_interrupt_level level;
491
                                rtems_event_set events;
492
 
493
                                /*
494
                                 * Unmask RXF (Full frame received) event
495
                                 */
496
                                rtems_interrupt_disable (level);
497
                                m360.scc1.sccm |= 0x8;
498
                                rtems_interrupt_enable (level);
499
 
500
                                rtems_bsdnet_event_receive (INTERRUPT_EVENT,
501
                                                RTEMS_WAIT|RTEMS_EVENT_ANY,
502
                                                RTEMS_NO_TIMEOUT,
503
                                                &events);
504
                        }
505
                }
506
 
507
                /*
508
                 * Check that packet is valid
509
                 */
510
                if ((status & (M360_BD_LAST |
511
                                M360_BD_FIRST_IN_FRAME |
512
                                M360_BD_LONG |
513
                                M360_BD_NONALIGNED |
514
                                M360_BD_SHORT |
515
                                M360_BD_CRC_ERROR |
516
                                M360_BD_OVERRUN |
517
                                M360_BD_COLLISION)) ==
518
                                                (M360_BD_LAST |
519
                                                M360_BD_FIRST_IN_FRAME)) {
520
                        /*
521
                         * Pass the packet up the chain.
522
                         * FIXME: Packet filtering hook could be done here.
523
                         */
524
                        struct ether_header *eh;
525
 
526
                        m = sc->rxMbuf[rxBdIndex];
527
                        m->m_len = m->m_pkthdr.len = rxBd->length -
528
                                                sizeof(rtems_unsigned32) -
529
                                                sizeof(struct ether_header);
530
                        eh = mtod (m, struct ether_header *);
531
                        m->m_data += sizeof(struct ether_header);
532
                        ether_input (ifp, eh, m);
533
 
534
                        /*
535
                         * Allocate a new mbuf
536
                         */
537
                        MGETHDR (m, M_WAIT, MT_DATA);
538
                        MCLGET (m, M_WAIT);
539
                        m->m_pkthdr.rcvif = ifp;
540
                        sc->rxMbuf[rxBdIndex] = m;
541
                        rxBd->buffer = mtod (m, void *);
542
                }
543
                else {
544
                        /*
545
                         * Something went wrong with the reception
546
                         */
547
                        if (!(status & M360_BD_LAST))
548
                                sc->rxNotLast++;
549
                        if (!(status & M360_BD_FIRST_IN_FRAME))
550
                                sc->rxNotFirst++;
551
                        if (status & M360_BD_LONG)
552
                                sc->rxGiant++;
553
                        if (status & M360_BD_NONALIGNED)
554
                                sc->rxNonOctet++;
555
                        if (status & M360_BD_SHORT)
556
                                sc->rxRunt++;
557
                        if (status & M360_BD_CRC_ERROR)
558
                                sc->rxBadCRC++;
559
                        if (status & M360_BD_OVERRUN)
560
                                sc->rxOverrun++;
561
                        if (status & M360_BD_COLLISION)
562
                                sc->rxCollision++;
563
                }
564
 
565
                /*
566
                 * Reenable the buffer descriptor
567
                 */
568
                rxBd->status = (status & (M360_BD_WRAP | M360_BD_INTERRUPT)) | M360_BD_EMPTY;
569
 
570
                /*
571
                 * Move to next buffer descriptor
572
                 */
573
                if (++rxBdIndex == sc->rxBdCount)
574
                        rxBdIndex = 0;
575
        }
576
}
577
 
578
static void
579
sendpacket (struct ifnet *ifp, struct mbuf *m)
580
{
581
        struct scc_softc *sc = ifp->if_softc;
582
        volatile m360BufferDescriptor_t *firstTxBd, *txBd;
583
        struct mbuf *l = NULL;
584
        rtems_unsigned16 status;
585
        int nAdded;
586
 
587
        /*
588
         * Free up buffer descriptors
589
         */
590
        m360Enet_retire_tx_bd (sc);
591
 
592
        /*
593
         * Set up the transmit buffer descriptors.
594
         * No need to pad out short packets since the
595
         * hardware takes care of that automatically.
596
         * No need to copy the packet to a contiguous buffer
597
         * since the hardware is capable of scatter/gather DMA.
598
         */
599
        status = 0;
600
        nAdded = 0;
601
        txBd = firstTxBd = sc->txBdBase + sc->txBdHead;
602
        while (m) {
603
                /*
604
                 * There are more mbufs in the packet than there
605
                 * are transmit buffer descriptors.
606
                 * Coalesce into a single buffer.
607
                 */
608
                if (nAdded == sc->txBdCount) {
609
                        struct mbuf *nm;
610
                        int j;
611
                        char *dest;
612
 
613
                        /*
614
                         * Get the pointer to the first mbuf of the packet
615
                         */
616
                        if (sc->txBdTail != sc->txBdHead)
617
                                rtems_panic ("sendpacket coalesce");
618
                        m = sc->txMbuf[sc->txBdTail];
619
 
620
                        /*
621
                         * Rescind the buffer descriptor READY bits
622
                         */
623
                        for (j = 0 ; j < sc->txBdCount ; j++)
624
                                (sc->txBdBase + j)->status = 0;
625
 
626
                        /*
627
                         * Allocate an mbuf cluster
628
                         * Toss the packet if allocation fails
629
                         */
630
                        MGETHDR (nm, M_DONTWAIT, MT_DATA);
631
                        if (nm == NULL) {
632
                                sc->txCoalesceFailed++;
633
                                m_freem (m);
634
                                return;
635
                        }
636
                        MCLGET (nm, M_DONTWAIT);
637
                        if (nm->m_ext.ext_buf == NULL) {
638
                                sc->txCoalesceFailed++;
639
                                m_freem (m);
640
                                m_free (nm);
641
                                return;
642
                        }
643
                        nm->m_pkthdr = m->m_pkthdr;
644
                        nm->m_len = nm->m_pkthdr.len;
645
 
646
                        /*
647
                         * Copy data from packet chain to mbuf cluster
648
                         */
649
                        sc->txCoalesced++;
650
                        dest = nm->m_ext.ext_buf;
651
                        while (m) {
652
                                struct mbuf *n;
653
 
654
                                if (m->m_len) {
655
                                        memcpy (dest, mtod(m, caddr_t), m->m_len);
656
                                        dest += m->m_len;
657
                                }
658
                                MFREE (m, n);
659
                                m = n;
660
                        }
661
 
662
                        /*
663
                         * Redo the send with the new mbuf cluster
664
                         */
665
                        m = nm;
666
                        nAdded = 0;
667
                        status = 0;
668
                        continue;
669
                }
670
 
671
                /*
672
                 * Wait for buffer descriptor to become available.
673
                 */
674
                if ((sc->txBdActiveCount + nAdded) == sc->txBdCount) {
675
                        /*
676
                         * Clear old events
677
                         */
678
                        m360.scc1.scce = 0x12;
679
 
680
                        /*
681
                         * Wait for buffer descriptor to become available.
682
                         * Note that the buffer descriptors are checked
683
                         * *before* entering the wait loop -- this catches
684
                         * the possibility that a buffer descriptor became
685
                         * available between the `if' above, and the clearing
686
                         * of the event register.
687
                         * This is to catch the case where the transmitter
688
                         * stops in the middle of a frame -- and only the
689
                         * last buffer descriptor in a frame can generate
690
                         * an interrupt.
691
                         */
692
                        m360Enet_retire_tx_bd (sc);
693
                        while ((sc->txBdActiveCount + nAdded) == sc->txBdCount) {
694
                                rtems_interrupt_level level;
695
                                rtems_event_set events;
696
 
697
                                /*
698
                                 * Unmask TXB (buffer transmitted) and
699
                                 * TXE (transmitter error) events.
700
                                 */
701
                                rtems_interrupt_disable (level);
702
                                m360.scc1.sccm |= 0x12;
703
                                rtems_interrupt_enable (level);
704
                                rtems_bsdnet_event_receive (INTERRUPT_EVENT,
705
                                                RTEMS_WAIT|RTEMS_EVENT_ANY,
706
                                                RTEMS_NO_TIMEOUT,
707
                                                &events);
708
                                m360Enet_retire_tx_bd (sc);
709
                        }
710
                }
711
 
712
                /*
713
                 * The IP fragmentation routine in ip_output
714
                 * can produce packet fragments with zero length.
715
                 */
716
                if (m->m_len) {
717
                        /*
718
                         * Fill in the buffer descriptor.
719
                         * Don't set the READY flag in the first buffer
720
                         * descriptor till the whole packet has been readied.
721
                         */
722
                        txBd = sc->txBdBase + sc->txBdHead;
723
                        txBd->buffer = mtod (m, void *);
724
                        txBd->length = m->m_len;
725
                        sc->txMbuf[sc->txBdHead] = m;
726
                        status = nAdded ? M360_BD_READY : 0;
727
                        if (++sc->txBdHead == sc->txBdCount) {
728
                                status |= M360_BD_WRAP;
729
                                sc->txBdHead = 0;
730
                        }
731
                        txBd->status = status;
732
                        l = m;
733
                        m = m->m_next;
734
                        nAdded++;
735
                }
736
                else {
737
                        /*
738
                         * Just toss empty mbufs
739
                         */
740
                        struct mbuf *n;
741
                        MFREE (m, n);
742
                        m = n;
743
                        if (l != NULL)
744
                                l->m_next = m;
745
                }
746
        }
747
        if (nAdded) {
748
                /*
749
                 * Send the packet
750
                 */
751
                txBd->status = status | M360_BD_PAD | M360_BD_LAST | M360_BD_TX_CRC | M360_BD_INTERRUPT;
752
                firstTxBd->status |= M360_BD_READY;
753
                sc->txBdActiveCount += nAdded;
754
        }
755
}
756
 
757
/*
758
 * Driver transmit daemon
759
 */
760
void
761
scc_txDaemon (void *arg)
762
{
763
        struct scc_softc *sc = (struct scc_softc *)arg;
764
        struct ifnet *ifp = &sc->arpcom.ac_if;
765
        struct mbuf *m;
766
        rtems_event_set events;
767
 
768
        for (;;) {
769
                /*
770
                 * Wait for packet
771
                 */
772
                rtems_bsdnet_event_receive (START_TRANSMIT_EVENT, RTEMS_EVENT_ANY | RTEMS_WAIT, RTEMS_NO_TIMEOUT, &events);
773
 
774
                /*
775
                 * Send packets till queue is empty
776
                 */
777
                for (;;) {
778
                        /*
779
                         * Get the next mbuf chain to transmit.
780
                         */
781
                        IF_DEQUEUE(&ifp->if_snd, m);
782
                        if (!m)
783
                                break;
784
                        sendpacket (ifp, m);
785
                }
786
                ifp->if_flags &= ~IFF_OACTIVE;
787
        }
788
}
789
 
790
/*
791
 * Send packet (caller provides header).
792
 */
793
static void
794
scc_start (struct ifnet *ifp)
795
{
796
        struct scc_softc *sc = ifp->if_softc;
797
 
798
        rtems_event_send (sc->txDaemonTid, START_TRANSMIT_EVENT);
799
        ifp->if_flags |= IFF_OACTIVE;
800
}
801
 
802
/*
803
 * Initialize and start the device
804
 */
805
static void
806
scc_init (void *arg)
807
{
808
        struct scc_softc *sc = arg;
809
        struct ifnet *ifp = &sc->arpcom.ac_if;
810
 
811
        if (sc->txDaemonTid == 0) {
812
 
813
                /*
814
                 * Set up SCC hardware
815
                 */
816
                m360Enet_initialize_hardware (sc);
817
 
818
                /*
819
                 * Start driver tasks
820
                 */
821
                sc->txDaemonTid = rtems_bsdnet_newproc ("SCtx", 4096, scc_txDaemon, sc);
822
                sc->rxDaemonTid = rtems_bsdnet_newproc ("SCrx", 4096, scc_rxDaemon, sc);
823
 
824
        }
825
 
826
        /*
827
         * Set flags appropriately
828
         */
829
        if (ifp->if_flags & IFF_PROMISC)
830
                m360.scc1.psmr |= 0x200;
831
        else
832
                m360.scc1.psmr &= ~0x200;
833
 
834
        /*
835
         * Tell the world that we're running.
836
         */
837
        ifp->if_flags |= IFF_RUNNING;
838
 
839
        /*
840
         * Enable receiver and transmitter
841
         */
842
        m360.scc1.gsmr_l |= 0x30;
843
}
844
 
845
/*
846
 * Stop the device
847
 */
848
static void
849
scc_stop (struct scc_softc *sc)
850
{
851
        struct ifnet *ifp = &sc->arpcom.ac_if;
852
 
853
        ifp->if_flags &= ~IFF_RUNNING;
854
 
855
        /*
856
         * Shut down receiver and transmitter
857
         */
858
        m360.scc1.gsmr_l &= ~0x30;
859
}
860
 
861
 
862
/*
863
 * Show interface statistics
864
 */
865
static void
866
scc_stats (struct scc_softc *sc)
867
{
868
        printf ("      Rx Interrupts:%-8lu", sc->rxInterrupts);
869
        printf ("       Not First:%-8lu", sc->rxNotFirst);
870
        printf ("        Not Last:%-8lu\n", sc->rxNotLast);
871
        printf ("              Giant:%-8lu", sc->rxGiant);
872
        printf ("            Runt:%-8lu", sc->rxRunt);
873
        printf ("       Non-octet:%-8lu\n", sc->rxNonOctet);
874
        printf ("            Bad CRC:%-8lu", sc->rxBadCRC);
875
        printf ("         Overrun:%-8lu", sc->rxOverrun);
876
        printf ("       Collision:%-8lu\n", sc->rxCollision);
877
        printf ("          Discarded:%-8lu\n", (unsigned long)m360.scc1p.un.ethernet.disfc);
878
 
879
        printf ("      Tx Interrupts:%-8lu", sc->txInterrupts);
880
        printf ("        Deferred:%-8lu", sc->txDeferred);
881
        printf (" Missed Hearbeat:%-8lu\n", sc->txHeartbeat);
882
        printf ("         No Carrier:%-8lu", sc->txLostCarrier);
883
        printf ("Retransmit Limit:%-8lu", sc->txRetryLimit);
884
        printf ("  Late Collision:%-8lu\n", sc->txLateCollision);
885
        printf ("           Underrun:%-8lu", sc->txUnderrun);
886
        printf (" Raw output wait:%-8lu", sc->txRawWait);
887
        printf ("       Coalesced:%-8lu\n", sc->txCoalesced);
888
        printf ("    Coalesce failed:%-8lu", sc->txCoalesceFailed);
889
        printf ("         Retries:%-8lu\n", sc->txRetry);
890
}
891
 
892
/*
893
 * Driver ioctl handler
894
 */
895
static int
896
scc_ioctl (struct ifnet *ifp, int command, caddr_t data)
897
{
898
        struct scc_softc *sc = ifp->if_softc;
899
        int error = 0;
900
 
901
        switch (command) {
902
        case SIOCGIFADDR:
903
        case SIOCSIFADDR:
904
                ether_ioctl (ifp, command, data);
905
                break;
906
 
907
        case SIOCSIFFLAGS:
908
                switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) {
909
                case IFF_RUNNING:
910
                        scc_stop (sc);
911
                        break;
912
 
913
                case IFF_UP:
914
                        scc_init (sc);
915
                        break;
916
 
917
                case IFF_UP | IFF_RUNNING:
918
                        scc_stop (sc);
919
                        scc_init (sc);
920
                        break;
921
 
922
                default:
923
                        break;
924
                }
925
                break;
926
 
927
        case SIO_RTEMS_SHOW_STATS:
928
                scc_stats (sc);
929
                break;
930
 
931
        /*
932
         * FIXME: All sorts of multicast commands need to be added here!
933
         */
934
        default:
935
                error = EINVAL;
936
                break;
937
        }
938
        return error;
939
}
940
 
941
/*
942
 * Attach an SCC driver to the system
943
 */
944
int
945
rtems_scc1_driver_attach (struct rtems_bsdnet_ifconfig *config)
946
{
947
        struct scc_softc *sc;
948
        struct ifnet *ifp;
949
        int mtu;
950
        int unitNumber;
951
        char *unitName;
952
 
953
        /*
954
         * Parse driver name
955
         */
956
        if ((unitNumber = rtems_bsdnet_parse_driver_name (config, &unitName)) < 0)
957
                return 0;
958
 
959
        /*
960
         * Is driver free?
961
         */
962
        if ((unitNumber <= 0) || (unitNumber > NSCCDRIVER)) {
963
                printf ("Bad SCC unit number.\n");
964
                return 0;
965
        }
966
        sc = &scc_softc[unitNumber - 1];
967
        ifp = &sc->arpcom.ac_if;
968
        if (ifp->if_softc != NULL) {
969
                printf ("Driver already in use.\n");
970
                return 0;
971
        }
972
 
973
        /*
974
         * Process options
975
         */
976
        if (config->hardware_address) {
977
                memcpy (sc->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN);
978
        }
979
        else {
980
                /*
981
                 * The first 4 bytes of the bootstrap prom
982
                 * contain the value loaded into the stack
983
                 * pointer as part of the CPU32's hardware
984
                 * reset exception handler.  The following
985
                 * 4 bytes contain the value loaded into the
986
                 * program counter.  The boards' Ethernet
987
                 * address is stored in the six bytes
988
                 * immediately preceding this initial
989
                 * program counter value.
990
                 *
991
                 * See start360/start360.s.
992
                 */
993
                extern void *_RomBase;  /* From linkcmds */
994
                const unsigned long *ExceptionVectors;
995
                const unsigned char *entryPoint;
996
 
997
                /*
998
                 * Sanity check -- assume entry point must be
999
                 * within 1 MByte of beginning of boot ROM.
1000
                 */
1001
                ExceptionVectors = (const unsigned long *)&_RomBase;
1002
                entryPoint = (const unsigned char *)ExceptionVectors[1];
1003
                if (((unsigned long)entryPoint - (unsigned long)ExceptionVectors)
1004
                                        >= (1 * 1024 * 1024)) {
1005
                        printf ("Warning -- Ethernet address can not be found in bootstrap PROM.\n");
1006
                        sc->arpcom.ac_enaddr[0] = 0x08;
1007
                        sc->arpcom.ac_enaddr[1] = 0xF3;
1008
                        sc->arpcom.ac_enaddr[2] = 0x3E;
1009
                        sc->arpcom.ac_enaddr[3] = 0xC2;
1010
                        sc->arpcom.ac_enaddr[4] = 0x7E;
1011
                        sc->arpcom.ac_enaddr[5] = 0x38;
1012
                }
1013
                else {
1014
                        memcpy (sc->arpcom.ac_enaddr, entryPoint - ETHER_ADDR_LEN, ETHER_ADDR_LEN);
1015
                }
1016
        }
1017
        if (config->mtu)
1018
                mtu = config->mtu;
1019
        else
1020
                mtu = ETHERMTU;
1021
        if (config->rbuf_count)
1022
                sc->rxBdCount = config->rbuf_count;
1023
        else
1024
                sc->rxBdCount = RX_BUF_COUNT;
1025
        if (config->xbuf_count)
1026
                sc->txBdCount = config->xbuf_count;
1027
        else
1028
                sc->txBdCount = TX_BUF_COUNT * TX_BD_PER_BUF;
1029
        sc->acceptBroadcast = !config->ignore_broadcast;
1030
 
1031
        /*
1032
         * Set up network interface values
1033
         */
1034
        ifp->if_softc = sc;
1035
        ifp->if_unit = unitNumber;
1036
        ifp->if_name = unitName;
1037
        ifp->if_mtu = mtu;
1038
        ifp->if_init = scc_init;
1039
        ifp->if_ioctl = scc_ioctl;
1040
        ifp->if_start = scc_start;
1041
        ifp->if_output = ether_output;
1042
        ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
1043
        if (ifp->if_snd.ifq_maxlen == 0)
1044
                ifp->if_snd.ifq_maxlen = ifqmaxlen;
1045
 
1046
        /*
1047
         * Attach the interface
1048
         */
1049
        if_attach (ifp);
1050
        ether_ifattach (ifp);
1051
        return 1;
1052
};

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.