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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [devs/] [eth/] [powerpc/] [ppc405/] [current/] [src/] [if_ppc405.c] - Blame information for rev 817

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 786 skrzyp
//==========================================================================
2
//
3
//      dev/if_ppc405.c
4
//
5
//      Ethernet device driver for PowerPC PPC405 boards
6
//
7
//==========================================================================
8
// ####ECOSGPLCOPYRIGHTBEGIN####                                            
9
// -------------------------------------------                              
10
// This file is part of eCos, the Embedded Configurable Operating System.   
11
// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2005 Free Software Foundation, Inc.
12
//
13
// eCos is free software; you can redistribute it and/or modify it under    
14
// the terms of the GNU General Public License as published by the Free     
15
// Software Foundation; either version 2 or (at your option) any later      
16
// version.                                                                 
17
//
18
// eCos is distributed in the hope that it will be useful, but WITHOUT      
19
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or    
20
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License    
21
// for more details.                                                        
22
//
23
// You should have received a copy of the GNU General Public License        
24
// along with eCos; if not, write to the Free Software Foundation, Inc.,    
25
// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.            
26
//
27
// As a special exception, if other files instantiate templates or use      
28
// macros or inline functions from this file, or you compile this file      
29
// and link it with other works to produce a work based on this file,       
30
// this file does not by itself cause the resulting work to be covered by   
31
// the GNU General Public License. However the source code for this file    
32
// must still be made available in accordance with section (3) of the GNU   
33
// General Public License v2.                                               
34
//
35
// This exception does not invalidate any other reasons why a work based    
36
// on this file might be covered by the GNU General Public License.         
37
// -------------------------------------------                              
38
// ####ECOSGPLCOPYRIGHTEND####                                              
39
//==========================================================================
40
//#####DESCRIPTIONBEGIN####
41
//
42
// Author(s):    gthomas
43
// Contributors: gthomas
44
// Date:         2003-08-15
45
// Purpose:      
46
// Description:  hardware driver for PPC405
47
//              
48
//
49
//####DESCRIPTIONEND####
50
//
51
//==========================================================================
52
 
53
// Ethernet device driver for PPC405
54
 
55
#include <pkgconf/system.h>
56
#include <pkgconf/devs_eth_powerpc_ppc405.h>
57
#include <pkgconf/io_eth_drivers.h>
58
 
59
#ifdef CYGPKG_NET
60
#include <pkgconf/net.h>
61
#endif
62
 
63
#include <cyg/infra/cyg_type.h>
64
#include <cyg/infra/diag.h>
65
 
66
#include <cyg/hal/hal_arch.h>
67
#include <cyg/hal/hal_cache.h>
68
#include <cyg/hal/hal_intr.h>
69
#include <cyg/hal/drv_api.h>
70
#include <cyg/hal/hal_if.h>
71
#include <cyg/hal/ppc_regs.h>
72
 
73
#include <cyg/io/eth/netdev.h>
74
#include <cyg/io/eth/eth_drv.h>
75
#include <cyg/io/eth_phy.h>
76
 
77
//
78
// PHY access functions
79
//
80
static void ppc405_eth_phy_init(void);
81
static void ppc405_eth_phy_put_reg(int reg, int phy, unsigned short data);
82
static bool ppc405_eth_phy_get_reg(int reg, int phy, unsigned short *val);
83
 
84
#include "ppc405_enet.h"
85
#include CYGDAT_DEVS_PPC405_ETH_INL
86
 
87
#define os_printf diag_printf
88
 
89
// For fetching the ESA from RedBoot
90
#include <cyg/hal/hal_if.h>
91
#ifndef CONFIG_ESA
92
#define CONFIG_ESA 6
93
#endif
94
 
95
static void          ppc405_eth_int(struct eth_drv_sc *data);
96
 
97
#ifdef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED
98
 
99
static cyg_interrupt ppc405_emac_interrupt;
100
static cyg_handle_t  ppc405_emac_interrupt_handle;
101
static cyg_interrupt ppc405_mal_txeob_interrupt;
102
static cyg_handle_t  ppc405_mal_txeob_interrupt_handle;
103
static cyg_interrupt ppc405_mal_rxeob_interrupt;
104
static cyg_handle_t  ppc405_mal_rxeob_interrupt_handle;
105
static cyg_interrupt ppc405_mal_txde_interrupt;
106
static cyg_handle_t  ppc405_mal_txde_interrupt_handle;
107
static cyg_interrupt ppc405_mal_rxde_interrupt;
108
static cyg_handle_t  ppc405_mal_rxde_interrupt_handle;
109
static cyg_interrupt ppc405_mal_serr_interrupt;
110
static cyg_handle_t  ppc405_mal_serr_interrupt_handle;
111
 
112
#define EMAC_INTERRUPT_HANDLER(_int_,_hdlr_)                                                    \
113
    cyg_drv_interrupt_create(_int_,                                                             \
114
                             0,                                                                 \
115
                             (cyg_addrword_t)sc, /*  Data item passed to interrupt handler */   \
116
                             (cyg_ISR_t *)ppc405_eth_isr,                                       \
117
                             (cyg_DSR_t *)eth_drv_dsr,                                          \
118
                             &ppc405_##_hdlr_##_interrupt_handle,                               \
119
                             &ppc405_##_hdlr_##_interrupt);                                     \
120
    cyg_drv_interrupt_attach(ppc405_##_hdlr_##_interrupt_handle);                               \
121
    cyg_drv_interrupt_acknowledge(_int_);                                                       \
122
    cyg_drv_interrupt_unmask(_int_);
123
 
124
// This ISR is called when the ethernet interrupt occurs
125
static int
126
ppc405_eth_isr(cyg_vector_t vector, cyg_addrword_t data, HAL_SavedRegisters *regs)
127
{
128
    struct eth_drv_sc *sc = (struct eth_drv_sc *)data;
129
    struct ppc405_eth_info *qi = (struct ppc405_eth_info *)sc->driver_private;
130
 
131
    cyg_drv_interrupt_mask(CYGNUM_HAL_INTERRUPT_MAL_SERR);
132
    cyg_drv_interrupt_mask(CYGNUM_HAL_INTERRUPT_MAL_TX_EOB);
133
    cyg_drv_interrupt_mask(CYGNUM_HAL_INTERRUPT_MAL_RX_EOB);
134
    cyg_drv_interrupt_mask(CYGNUM_HAL_INTERRUPT_MAL_TX_DE);
135
    cyg_drv_interrupt_mask(CYGNUM_HAL_INTERRUPT_MAL_RX_DE);
136
    cyg_drv_interrupt_mask(CYGNUM_HAL_INTERRUPT_EMAC0);
137
    qi->ints = vector;
138
    return (CYG_ISR_HANDLED|CYG_ISR_CALL_DSR);  // Run the DSR
139
}
140
#endif
141
 
142
// Deliver function (ex-DSR) handles the ethernet [logical] processing
143
static void
144
ppc405_eth_deliver(struct eth_drv_sc *sc)
145
{
146
#ifdef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED
147
    struct ppc405_eth_info *qi = (struct ppc405_eth_info *)sc->driver_private;
148
    cyg_uint32 old_ints;
149
#endif
150
    ppc405_eth_int(sc);
151
#ifdef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED
152
    // Allow interrupts to happen again
153
    HAL_DISABLE_INTERRUPTS(old_ints);
154
    cyg_drv_interrupt_acknowledge(qi->ints);
155
    cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_MAL_SERR);
156
    cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_MAL_TX_EOB);
157
    cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_MAL_RX_EOB);
158
    cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_MAL_TX_DE);
159
    cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_MAL_RX_DE);
160
    cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_EMAC0);
161
    HAL_RESTORE_INTERRUPTS(old_ints);
162
#endif
163
}
164
 
165
//
166
// PHY unit access
167
//
168
static void
169
ppc405_eth_phy_init(void)
170
{
171
    // Set up MII hardware - nothing to do on this platform
172
}
173
 
174
static void
175
ppc405_eth_phy_put_reg(int reg, int phy, unsigned short data)
176
{
177
    unsigned long reg_val;
178
 
179
    reg_val = EMAC0_STACR_STAC_WRITE | EMAC0_STACR_OPBC_66;
180
    reg_val |= (phy << EMAC0_STACR_PCDA_SHIFT) | reg;
181
    reg_val |= (data << EMAC0_STACR_PHYD_SHIFT);
182
#ifdef PHY_DEBUG
183
    os_printf("PHY PUT - reg: %d, phy: %d, val: %04x [%08x]\n", reg, phy, data, reg_val);
184
#endif
185
    while ((EMAC0_STACR & EMAC0_STACR_OC) == 0) ;  // Wait for MII free
186
    EMAC0_STACR = reg_val;
187
    while ((EMAC0_STACR & EMAC0_STACR_OC) == 0) ;  // Wait for MII complete
188
}
189
 
190
static bool
191
ppc405_eth_phy_get_reg(int reg, int phy, unsigned short *val)
192
{
193
    unsigned long reg_val;
194
 
195
    reg_val = EMAC0_STACR_STAC_READ | EMAC0_STACR_OPBC_66;
196
    reg_val |= (phy << EMAC0_STACR_PCDA_SHIFT) | reg;
197
#ifdef PHY_DEBUG
198
    os_printf("PHY GET - reg: %d, phy: %d [%08x] = ", reg, phy, reg_val);
199
#endif
200
    while ((EMAC0_STACR & EMAC0_STACR_OC) == 0) ;  // Wait for MII free
201
    EMAC0_STACR = reg_val;
202
    while ((EMAC0_STACR & EMAC0_STACR_OC) == 0) ;  // Wait for MII complete
203
    if ((EMAC0_STACR & EMAC0_STACR_PHYE) == 0) {
204
        // Operation completed with no error
205
        *val = (EMAC0_STACR & EMAC0_STACR_PHYD) >> EMAC0_STACR_PHYD_SHIFT;
206
#ifdef PHY_DEBUG
207
        os_printf("%04x\n", *val);
208
#endif
209
        return true;
210
    } else {
211
        // No response
212
#ifdef PHY_DEBUG
213
        os_printf("***ERROR***\n");
214
#endif
215
        return false;
216
    }
217
}
218
 
219
//
220
// [re]Initialize the ethernet controller
221
//   Done separately since shutting down the device requires a 
222
//   full reconfiguration when re-enabling.
223
//   when 
224
static bool
225
ppc405_eth_reset(struct eth_drv_sc *sc, unsigned char *enaddr, int flags)
226
{
227
    struct ppc405_eth_info *qi = (struct ppc405_eth_info *)sc->driver_private;
228
    volatile mal_bd_t *rxbd, *RxBD, *txbd, *TxBD;
229
    unsigned char *RxBUF, *TxBUF;
230
    int i, int_state;
231
    unsigned long mal_status, mode;
232
    unsigned short phy_state = 0;
233
 
234
    // Ignore unless device is idle/stopped
235
    if ((EMAC0_MR0 & (EMAC0_MR0_RXI|EMAC0_MR0_TXI)) != (EMAC0_MR0_RXI|EMAC0_MR0_TXI)) {
236
        return true;
237
    }
238
 
239
    // Make sure interrupts are off while we mess with the device
240
    HAL_DISABLE_INTERRUPTS(int_state);
241
 
242
    // Reset EMAC controller
243
    EMAC0_MR0 |= EMAC0_MR0_SRST;
244
    i = 0;
245
    while ((EMAC0_MR0 & EMAC0_MR0_SRST) != 0) {
246
        if (++i >= 500000) {
247
            os_printf("PPC405 Ethernet does not reset\n");
248
            HAL_RESTORE_INTERRUPTS(int_state);
249
            return false;
250
        }
251
    }
252
 
253
    TxBD = qi->txbd_table;
254
    txbd = (mal_bd_t *)CYGARC_UNCACHED_ADDRESS(TxBD);
255
    RxBD = qi->rxbd_table;
256
    rxbd = (mal_bd_t *)CYGARC_UNCACHED_ADDRESS(RxBD);
257
    qi->tbase = qi->txbd = qi->tnext = txbd;
258
    qi->rbase = qi->rxbd = qi->rnext = rxbd;
259
    qi->txactive = 0;
260
 
261
    RxBUF = qi->rxbuf;
262
    TxBUF = qi->txbuf;
263
 
264
    // setup buffer descriptors
265
    for (i = 0;  i < CYGNUM_DEVS_ETH_POWERPC_PPC405_RxNUM;  i++) {
266
        rxbd->length = 0;
267
        rxbd->buffer = (unsigned long)RxBUF;
268
        rxbd->status = MAL_BD_R | MAL_BD_I;
269
        RxBUF += CYGNUM_DEVS_ETH_POWERPC_PPC405_BUFSIZE;
270
        rxbd++;
271
    }
272
    rxbd--;
273
    rxbd->status |= MAL_BD_W;  // Last buffer
274
    for (i = 0;  i < CYGNUM_DEVS_ETH_POWERPC_PPC405_TxNUM;  i++) {
275
        txbd->length = 0;
276
        txbd->buffer = (unsigned long)TxBUF;
277
        txbd->status = 0;
278
        TxBUF += CYGNUM_DEVS_ETH_POWERPC_PPC405_BUFSIZE;
279
        txbd++;
280
    }
281
    txbd--;
282
    txbd->status |= MAL_BD_W;  // Last buffer
283
 
284
    // Tell memory access layer where the buffer descriptors are
285
    CYGARC_MTDCR(MAL0_TXCARR, MAL_CASR_C0|MAL_CASR_C1);  // Disable/reset channel #0 & #1
286
    CYGARC_MTDCR(MAL0_RXCARR, MAL_CASR_C0);  // Disable/reset channel #0
287
    CYGARC_MTDCR(MAL0_CFG, MAL_CFG_SR);
288
    i = 0;
289
    CYGARC_MFDCR(MAL0_CFG, mal_status);
290
    while ((mal_status & MAL_CFG_SR) != 0) {
291
        if (++i >= 500000) {
292
            os_printf("PPC405 MAL does not reset\n");
293
            HAL_RESTORE_INTERRUPTS(int_state);
294
            return false;
295
        }
296
    }
297
    CYGARC_MTDCR(MAL0_CFG, MAL_CFG_PLBB | MAL_CFG_OPBBL | MAL_CFG_LEA | MAL_CFG_PLBT_DEFAULT);
298
    CYGARC_MTDCR(MAL0_TXCTP0R, TxBD);
299
    CYGARC_MTDCR(MAL0_RXCTP0R, RxBD);
300
    CYGARC_MTDCR(MAL0_RXBS0, (CYGNUM_DEVS_ETH_POWERPC_PPC405_BUFSIZE/16));  // Receive buffer size
301
 
302
    // Set device physical address (ESA)
303
    EMAC0_IAHR = (enaddr[0]<<8) | (enaddr[1]<<0);
304
    EMAC0_IALR = (enaddr[2]<<24) | (enaddr[3]<<16) | (enaddr[4]<<8) | (enaddr[5]<<0);
305
 
306
    // Operating mode
307
    if (!_eth_phy_init(qi->phy)) {
308
        return false;
309
    }
310
    phy_state = _eth_phy_state(qi->phy);
311
    os_printf("PPC405 ETH: ");
312
    mode = EMAC0_MR1_RFS_4096 | EMAC0_MR1_TFS_2048 | EMAC0_MR1_TR0_MULTI | EMAC0_MR1_APP;
313
    if ((phy_state & ETH_PHY_STAT_LINK) != 0) {
314
        if ((phy_state & ETH_PHY_STAT_100MB) != 0) {
315
            // Link can handle 100Mb
316
            mode |= EMAC0_MR1_MF_100MB;
317
            os_printf("100Mb");
318
            if ((phy_state & ETH_PHY_STAT_FDX) != 0) {
319
                mode |= EMAC0_MR1_FDE | EMAC0_MR1_EIFC | EMAC0_MR1_IST;
320
                os_printf("/Full Duplex");
321
            }
322
        } else {
323
            // Assume 10Mb, half duplex
324
            mode |= EMAC0_MR1_MF_10MB;
325
            os_printf("10Mb");
326
        }
327
    } else {
328
        os_printf("/***NO LINK***");
329
        return false;
330
    }
331
    os_printf("\n");
332
    EMAC0_MR1 = mode;
333
 
334
    // Configure receiver
335
    EMAC0_RMR = EMAC0_RMR_IAE | EMAC0_RMR_BAE | EMAC0_RMR_RRP | EMAC0_RMR_RFP;
336
 
337
    // Transmit threshold to 256 bytes
338
    EMAC0_TRTR = ((256/EMAC0_TRTR_TRT_SCALE)-1) << EMAC0_TRTR_TRT_SHIFT;
339
 
340
    // Receive FIFO watermarks
341
    EMAC0_RWMR = (0x1F<<EMAC0_RWMR_RLWM_SHIFT) | (0x10<<EMAC0_RWMR_RHWM_SHIFT);
342
 
343
    // Frame gap
344
    EMAC0_IPGVR = 8;
345
 
346
    // Enable MAL
347
    CYGARC_MTDCR(MAL0_TXCASR, MAL_CASR_C0);
348
    CYGARC_MTDCR(MAL0_RXCASR, MAL_CASR_C0);
349
 
350
    // Reset all interrupts
351
    EMAC0_ISR = 0xFFFFFFFF;
352
#ifdef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED
353
    qi->ints = 0;
354
#endif
355
 
356
    // Enable interface
357
    EMAC0_MR0 |= (EMAC0_MR0_RXE|EMAC0_MR0_TXE);
358
 
359
    // Restore interrupts
360
    HAL_RESTORE_INTERRUPTS(int_state);
361
    return true;
362
}
363
 
364
//
365
// Initialize the interface - performed at system startup
366
// This function must set up the interface, including arranging to
367
// handle interrupts, etc, so that it may be "started" cheaply later.
368
//
369
 
370
static bool
371
ppc405_eth_init(struct cyg_netdevtab_entry *tab)
372
{
373
    struct eth_drv_sc *sc = (struct eth_drv_sc *)tab->device_instance;
374
    struct ppc405_eth_info *qi = (struct ppc405_eth_info *)sc->driver_private;
375
    bool esa_ok;
376
    unsigned char enaddr[6];
377
 
378
    ppc405_eth_stop(sc);  // Make sure it's not running yet
379
 
380
#ifdef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED
381
    // Set up to handle interrupts
382
    EMAC_INTERRUPT_HANDLER(CYGNUM_HAL_INTERRUPT_MAL_SERR, mal_serr);
383
    EMAC_INTERRUPT_HANDLER(CYGNUM_HAL_INTERRUPT_MAL_TX_EOB, mal_txeob);
384
    EMAC_INTERRUPT_HANDLER(CYGNUM_HAL_INTERRUPT_MAL_RX_EOB, mal_rxeob);
385
    EMAC_INTERRUPT_HANDLER(CYGNUM_HAL_INTERRUPT_MAL_TX_DE, mal_txde);
386
    EMAC_INTERRUPT_HANDLER(CYGNUM_HAL_INTERRUPT_MAL_RX_DE, mal_rxde);
387
    EMAC_INTERRUPT_HANDLER(CYGNUM_HAL_INTERRUPT_EMAC0, emac);
388
#endif
389
 
390
    // Get physical device address
391
#ifdef CYGPKG_REDBOOT
392
#ifdef CYGSEM_REDBOOT_FLASH_CONFIG
393
    esa_ok = flash_get_config(qi->esa_key, enaddr, CONFIG_ESA);
394
#else
395
    esa_ok = false;
396
#endif
397
#else
398
    esa_ok = CYGACC_CALL_IF_FLASH_CFG_OP(CYGNUM_CALL_IF_FLASH_CFG_GET,
399
                                         qi->esa_key, enaddr, CONFIG_ESA);
400
#endif
401
    if (!esa_ok) {
402
        // Can't figure out ESA
403
        os_printf("PPC405_ETH - Warning! ESA unknown\n");
404
        memcpy(&enaddr, qi->enaddr, sizeof(enaddr));
405
    }
406
    memcpy(qi->cfg_enaddr, enaddr, sizeof(enaddr));
407
 
408
    // Configure the device
409
    if (!ppc405_eth_reset(sc, enaddr, 0)) {
410
        return false;
411
    }
412
 
413
    // Initialize upper level driver
414
    (sc->funs->eth_drv->init)(sc, (unsigned char *)&enaddr);
415
 
416
    return true;
417
}
418
 
419
//
420
// This function is called to shut down the interface.
421
//
422
static void
423
ppc405_eth_stop(struct eth_drv_sc *sc)
424
{
425
    EMAC0_MR0 &= ~(EMAC0_MR0_RXE|EMAC0_MR0_TXE);
426
}
427
 
428
//
429
// This function is called to "start up" the interface.  It may be called
430
// multiple times, even when the hardware is already running.  It will be
431
// called whenever something "hardware oriented" changes and should leave
432
// the hardware ready to send/receive packets.
433
//
434
static void
435
ppc405_eth_start(struct eth_drv_sc *sc, unsigned char *enaddr, int flags)
436
{
437
    EMAC0_MR0 |= (EMAC0_MR0_RXE|EMAC0_MR0_TXE);
438
}
439
 
440
//
441
// This function is called for low level "control" operations
442
//
443
static int
444
ppc405_eth_control(struct eth_drv_sc *sc, unsigned long key,
445
                  void *data, int length)
446
{
447
    os_printf("%s.%d\n", __FUNCTION__, __LINE__);
448
    return 1;
449
#if 0
450
#ifdef ETH_DRV_SET_MC_ALL
451
    struct ppc405_eth_info *qi = (struct ppc405_eth_info *)sc->driver_private;
452
    volatile struct ppc405 *ppc405 = qi->ppc405;
453
#endif
454
 
455
    switch (key) {
456
    case ETH_DRV_SET_MAC_ADDRESS:
457
        return 0;
458
        break;
459
#ifdef ETH_DRV_SET_MC_ALL
460
    case ETH_DRV_SET_MC_ALL:
461
    case ETH_DRV_SET_MC_LIST:
462
        ppc405->RxControl &= ~RxControl_PROM;
463
        ppc405->hash[0] = 0xFFFFFFFF;
464
        ppc405->hash[1] = 0xFFFFFFFF;
465
        return 0;
466
        break;
467
#endif
468
    default:
469
        return 1;
470
        break;
471
    }
472
#endif
473
}
474
 
475
//
476
// This function is called to see if another packet can be sent.
477
// It should return the number of packets which can be handled.
478
// Zero should be returned if the interface is busy and can not send any more.
479
//
480
static int
481
ppc405_eth_can_send(struct eth_drv_sc *sc)
482
{
483
    struct ppc405_eth_info *qi = (struct ppc405_eth_info *)sc->driver_private;
484
 
485
    return (qi->txactive < CYGNUM_DEVS_ETH_POWERPC_PPC405_TxNUM);
486
}
487
 
488
//
489
// This routine is called to send data to the hardware.
490
 
491
static void
492
ppc405_eth_send(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len,
493
               int total_len, unsigned long key)
494
{
495
    struct ppc405_eth_info *qi = (struct ppc405_eth_info *)sc->driver_private;
496
    volatile mal_bd_t *txbd;
497
    volatile char *bp;
498
    int i, txindex;
499
 
500
    // Find a free buffer
501
    txbd = qi->txbd;
502
    // Set up buffer
503
    bp = (volatile char *)CYGARC_UNCACHED_ADDRESS(txbd->buffer);
504
    for (i = 0;  i < sg_len;  i++) {
505
        memcpy((void *)bp, (void *)sg_list[i].buf, sg_list[i].len);
506
        bp += sg_list[i].len;
507
    }
508
    txbd->length = total_len;
509
    txindex = ((unsigned long)txbd - (unsigned long)qi->tbase) / sizeof(*txbd);
510
    qi->txkey[txindex] = key;
511
    // Send it on it's way
512
    txbd->status = (txbd->status & MAL_BD_W) | MAL_BD_R | MAL_BD_L | MAL_BD_I |
513
        MAL_BD_TX_GFCS | MAL_BD_TX_GPAD;
514
    qi->txactive++;
515
    EMAC0_TMR0 = EMAC0_TMR0_GNP0;  // Start channel 0
516
    // Remember the next buffer to try
517
    if (txbd->status & MAL_BD_W) {
518
        qi->txbd = qi->tbase;
519
    } else {
520
        qi->txbd = txbd+1;
521
    }
522
}
523
 
524
//
525
// This function is called when a packet has been received.  It's job is
526
// to prepare to unload the packet from the hardware.  Once the length of
527
// the packet is known, the upper layer of the driver can be told.  When
528
// the upper layer is ready to unload the packet, the internal function
529
// 'ppc405_eth_recv' will be called to actually fetch it from the hardware.
530
//
531
static void
532
ppc405_eth_RxEvent(struct eth_drv_sc *sc)
533
{
534
    struct ppc405_eth_info *qi = (struct ppc405_eth_info *)sc->driver_private;
535
    volatile mal_bd_t *rxbd, *rxfirst;
536
 
537
    rxbd = rxfirst = qi->rnext;
538
    while ((rxbd->status & MAL_BD_R) == 0) {
539
        qi->rxbd = rxbd;  // Save for callback
540
        (sc->funs->eth_drv->recv)(sc, rxbd->length-4);  // Adjust for FCS
541
        if (rxbd->status & MAL_BD_W) {
542
            rxbd = qi->rbase;
543
        } else {
544
            rxbd++;
545
        }
546
    }
547
    // Remember where we left off
548
    qi->rnext = (mal_bd_t *)rxbd;
549
}
550
 
551
//
552
// This function is called as a result of the "eth_drv_recv()" call above.
553
// It's job is to actually fetch data for a packet from the hardware once
554
// memory buffers have been allocated for the packet.  Note that the buffers
555
// may come in pieces, using a scatter-gather list.  This allows for more
556
// efficient processing in the upper layers of the stack.
557
//
558
static void
559
ppc405_eth_recv(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len)
560
{
561
    struct ppc405_eth_info *qi = (struct ppc405_eth_info *)sc->driver_private;
562
    unsigned char *bp;
563
    int i;
564
 
565
    bp = (unsigned char *)CYGARC_UNCACHED_ADDRESS(qi->rxbd->buffer);
566
    for (i = 0;  i < sg_len;  i++) {
567
        if (sg_list[i].buf != 0) {
568
            memcpy((void *)sg_list[i].buf, bp, sg_list[i].len);
569
            bp += sg_list[i].len;
570
        }
571
    }
572
    qi->rxbd->status = (qi->rxbd->status & (MAL_BD_W|MAL_BD_I)) | MAL_BD_R;
573
}
574
 
575
static void
576
ppc405_eth_TxEvent(struct eth_drv_sc *sc)
577
{
578
    struct ppc405_eth_info *qi = (struct ppc405_eth_info *)sc->driver_private;
579
    volatile mal_bd_t *txbd;
580
    int key, txindex;
581
 
582
    txbd = qi->tnext;
583
    while ((txbd->status & (MAL_BD_R|MAL_BD_I)) == MAL_BD_I) {
584
        txindex = ((unsigned long)txbd - (unsigned long)qi->tbase) / sizeof(*txbd);
585
        if ((key = qi->txkey[txindex]) != 0) {
586
            qi->txkey[txindex] = 0;
587
            (sc->funs->eth_drv->tx_done)(sc, key, 0);
588
        }
589
        qi->txactive -= 1;
590
        txbd->status &= MAL_BD_W;  //  Only preserve wrap bit
591
        if ((txbd->status & MAL_BD_W) != 0) {
592
            txbd = qi->tbase;
593
        } else {
594
            txbd++;
595
        }
596
        if (txbd == qi->tnext) {
597
            break;  // Went through whole list
598
        }
599
    }
600
    // Remember where we left off
601
    qi->tnext = (mal_bd_t *)txbd;
602
}
603
 
604
//
605
// Interrupt processing
606
//
607
int dump_mal0_esr = 0;
608
 
609
static void
610
ppc405_eth_int(struct eth_drv_sc *sc)
611
{
612
    struct ppc405_eth_info *qi = (struct ppc405_eth_info *)sc->driver_private;
613
    unsigned long event, tx_event, rx_event, tx_deir, rx_deir;
614
    bool need_reset = false;
615
 
616
    CYGARC_MFDCR(MAL0_TXEOBISR, tx_event);
617
    if (tx_event != 0) {
618
        ppc405_eth_TxEvent(sc);
619
        CYGARC_MTDCR(MAL0_TXEOBISR, tx_event);
620
    }
621
    CYGARC_MFDCR(MAL0_RXEOBISR, rx_event);
622
    if (rx_event != 0) {
623
        ppc405_eth_RxEvent(sc);
624
        CYGARC_MTDCR(MAL0_RXEOBISR, rx_event);
625
    }
626
    if ((event = EMAC0_ISR) != 0) {
627
        if ((event & ~(EMAC0_ISR_SE0|EMAC0_ISR_SE1)) != 0) {
628
            // Error other than signal quality
629
            os_printf("EMAC0_ISR: %x\n", event);
630
            if ((event & (EMAC0_ISR_TE0|EMAC0_ISR_TE1)) != 0) {
631
                // Some problem with transmit - should be easily recoverable
632
                CYGARC_MTDCR(MAL0_TXCASR, MAL_CASR_C0);
633
                qi->tnext = qi->tbase;
634
            }
635
            if ((event & (EMAC0_ISR_OVR|EMAC0_ISR_BP|EMAC0_ISR_RP|EMAC0_ISR_ALE|EMAC0_ISR_BFCS)) != 0) {
636
                // Rx errors - reset device
637
                need_reset = true;
638
            }
639
        }
640
        EMAC0_ISR = event;  // Reset the bits we handled
641
    }
642
    CYGARC_MFDCR(MAL0_ESR, event);
643
    if ((event & MAL_ESR_INT_MASK) != 0) {
644
        CYGARC_MFDCR(MAL0_TXDEIR, tx_deir);
645
        CYGARC_MFDCR(MAL0_RXDEIR, rx_deir);
646
        if (dump_mal0_esr) {
647
            os_printf("MAL0_ESR: %x, Tx: %x, Rx: %x\n", event, tx_deir, rx_deir);
648
            os_printf("Tx buffer headers\n");
649
            diag_dump_buf((void *)qi->tbase, qi->txnum*sizeof(mal_bd_t));
650
            os_printf("Rx buffer headers\n");
651
            diag_dump_buf((void *)qi->rbase, qi->rxnum*sizeof(mal_bd_t));
652
        }
653
        if (tx_deir != 0) {
654
            // Fix Tx descriptor problems
655
            CYGARC_MTDCR(MAL0_TXDEIR, tx_deir);  // Clear interrupt indicator
656
            CYGARC_MTDCR(MAL0_TXCASR, MAL_CASR_C0);
657
            qi->tnext = qi->tbase;
658
        }
659
        if (rx_deir != 0) {
660
            // Fix Rx descriptor problems
661
            CYGARC_MTDCR(MAL0_RXDEIR, rx_deir);  // Clear interrupt indicator
662
            CYGARC_MTDCR(MAL0_RXCASR, MAL_CASR_C0);
663
            qi->rnext = qi->rbase;
664
        }
665
        CYGARC_MTDCR(MAL0_ESR, event);  // Clear events just handled
666
    }
667
    if (need_reset) {
668
        // Something has gone awry - try resetting the device
669
        os_printf("\n... PPC405 ethernet - hard reset after failure\n");
670
        ppc405_eth_stop(sc);
671
        if (!ppc405_eth_reset(sc, qi->cfg_enaddr, 0)) {
672
            os_printf("!! Failed? !!\n");
673
        }
674
    }
675
}
676
 
677
//
678
// Interrupt vector
679
//
680
static int
681
ppc405_eth_int_vector(struct eth_drv_sc *sc)
682
{
683
    struct ppc405_eth_info *qi = (struct ppc405_eth_info *)sc->driver_private;
684
    return qi->int_vector;
685
}

powered by: WebSVN 2.1.0

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