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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [devs/] [eth/] [amd/] [pcnet/] [current/] [src/] [if_pcnet.c] - Blame information for rev 786

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 786 skrzyp
//==========================================================================
2
//
3
//      dev/if_pcnet.c
4
//
5
//      Ethernet device driver for AMD PCNET compatible controllers
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 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):    jskov, based on lan91cxx driver by hmt & jskov
43
// Contributors: gthomas, jskov, hmt
44
// Date:         2001-04-02
45
// Purpose:      
46
// Description:  hardware driver for AMD PCNet (and possibly Lance) ethernet
47
// Notes:        The controller is used in its 16bit mode. That means that
48
//               all addresses are 24bit only - and that all controller
49
//               accessed memory must be within the same 16MB region
50
//               (starting at 0 on older controllers).
51
//
52
//               The KEEP_STATISTICS code is not implemented yet. Look
53
//               for FIXME macro.
54
//
55
//####DESCRIPTIONEND####
56
//
57
//==========================================================================
58
 
59
#include <pkgconf/system.h>
60
#include <pkgconf/devs_eth_amd_pcnet.h>
61
#include <pkgconf/io_eth_drivers.h>
62
 
63
#include <cyg/infra/cyg_type.h>
64
#include <cyg/hal/hal_arch.h>
65
#include <cyg/hal/hal_intr.h>
66
#include <cyg/infra/cyg_ass.h>
67
#include <cyg/infra/diag.h>
68
#include <cyg/hal/drv_api.h>
69
#include <cyg/hal/hal_if.h>             // delays
70
#include <string.h>
71
#include <cyg/io/eth/netdev.h>
72
#include <cyg/io/eth/eth_drv.h>
73
#ifdef CYGPKG_NET
74
#include <pkgconf/net.h>
75
#include <cyg/kernel/kapi.h>
76
#include <net/if.h>  /* Needed for struct ifnet */
77
#include <pkgconf/io_eth_drivers.h>
78
#endif
79
#include CYGHWR_MEMORY_LAYOUT_H
80
 
81
#ifdef CYGPKG_IO_PCI
82
#include <cyg/io/pci.h>
83
#else
84
#error "Need PCI package here"
85
#endif
86
 
87
#define FIXME 0
88
 
89
#define _BUF_SIZE 1544
90
 
91
#ifdef CYGPKG_INFRA_DEBUG
92
// Then we log, OOI, the number of times we get a bad packet number
93
// from the tx done fifo.
94
int pcnet_txfifo_good = 0;
95
int pcnet_txfifo_bad = 0;
96
#endif
97
 
98
#include "amd_pcnet.h"
99
#define __WANT_DEVS
100
#include CYGDAT_DEVS_ETH_AMD_PCNET_INL
101
#undef  __WANT_DEVS
102
 
103
#if defined(CYGPKG_REDBOOT) && DEBUG
104
 
105
static void db_printf( char *fmt, ... )
106
{
107
    extern int start_console(void);
108
    extern void end_console(int);
109
    va_list a;
110
    int old_console;
111
    va_start( a, fmt );
112
    old_console = start_console();
113
    diag_vprintf( fmt, a );
114
    end_console(old_console);
115
    va_end( a );
116
}
117
 
118
#else
119
 
120
#define db_printf diag_printf
121
 
122
#endif
123
 
124
static void pcnet_poll(struct eth_drv_sc *sc);
125
 
126
// This ISR is called when the ethernet interrupt occurs
127
static cyg_uint32
128
pcnet_isr(cyg_vector_t vector, cyg_addrword_t data)
129
{
130
    struct pcnet_priv_data *cpd = (struct pcnet_priv_data *)data;
131
 
132
    DEBUG_FUNCTION();
133
 
134
    INCR_STAT( interrupts );
135
 
136
    cyg_drv_interrupt_mask(cpd->interrupt);
137
    cyg_drv_interrupt_acknowledge(cpd->interrupt);
138
    return (CYG_ISR_HANDLED|CYG_ISR_CALL_DSR);  // Run the DSR
139
}
140
 
141
static void
142
pcnet_dsr(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
143
{
144
    // This conditioning out is necessary because of explicit calls to this
145
    // DSR - which would not ever be called in the case of a polled mode
146
    // usage ie. in RedBoot.
147
#ifdef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED
148
    struct pcnet_priv_data* cpd = (struct pcnet_priv_data *)data;
149
    struct cyg_netdevtab_entry *ndp = (struct cyg_netdevtab_entry *)(cpd->ndp);
150
    struct eth_drv_sc *sc = (struct eth_drv_sc *)(ndp->device_instance);
151
 
152
    // but here, it must be a *sc:
153
    eth_drv_dsr( vector, count, (cyg_addrword_t)sc );
154
#else
155
# ifndef CYGPKG_REDBOOT
156
#  error Empty PCnet ethernet DSR is compiled.  Is this what you want?
157
# endif
158
#endif
159
}
160
 
161
 
162
// The deliver function (ex-DSR)  handles the ethernet [logical] processing
163
static void
164
pcnet_deliver(struct eth_drv_sc *sc)
165
{
166
    struct pcnet_priv_data *cpd =
167
        (struct pcnet_priv_data *)sc->driver_private;
168
 
169
    DEBUG_FUNCTION();
170
 
171
    // Service the interrupt:
172
    pcnet_poll(sc);
173
    // Allow interrupts to happen again
174
    cyg_drv_interrupt_unmask(cpd->interrupt);
175
}
176
 
177
static int
178
pcnet_int_vector(struct eth_drv_sc *sc)
179
{
180
    struct pcnet_priv_data *cpd =
181
        (struct pcnet_priv_data *)sc->driver_private;
182
 
183
    return (cpd->interrupt);
184
}
185
 
186
// ------------------------------------------------------------------------
187
// Memory management
188
//
189
// Simply carve off from the front of the PCI mapped window into real memory
190
static cyg_uint32 pcnet_heap_size;
191
static cyg_uint8 *pcnet_heap_base;
192
static cyg_uint8 *pcnet_heap_free;
193
 
194
static void*
195
pciwindow_mem_alloc(int size)
196
{
197
    void *p_memory;
198
    int _size = size;
199
 
200
    CYG_ASSERT(
201
        (CYGHWR_AMD_PCNET_PCI_MEM_MAP_BASE <= (int)pcnet_heap_free)
202
        &&
203
        ((CYGHWR_AMD_PCNET_PCI_MEM_MAP_BASE +
204
          CYGHWR_AMD_PCNET_PCI_MEM_MAP_SIZE) > (int)pcnet_heap_free)
205
        &&
206
        (0 < pcnet_heap_size)
207
        &&
208
        (CYGHWR_AMD_PCNET_PCI_MEM_MAP_SIZE >= pcnet_heap_size)
209
        &&
210
        (CYGHWR_AMD_PCNET_PCI_MEM_MAP_BASE == (int)pcnet_heap_base),
211
        "Heap variables corrupted" );
212
 
213
    p_memory = (void *)0;
214
    size = (size + 3) & ~3;
215
    if ( (pcnet_heap_free+size) < (pcnet_heap_base+pcnet_heap_size) ) {
216
        cyg_uint32 *p;
217
        p_memory = (void *)pcnet_heap_free;
218
        pcnet_heap_free += size;
219
        for ( p = (cyg_uint32 *)p_memory; _size > 0; _size -= 4 )
220
            *p++ = 0;
221
    }
222
 
223
#if DEBUG & 9
224
    db_printf("Allocated %d bytes at 0x%08x\n", size, p_memory);
225
#endif
226
 
227
    return p_memory;
228
}
229
 
230
static cyg_pci_match_func find_pcnet_match_func;
231
 
232
static cyg_bool
233
find_pcnet_match_func( cyg_uint16 v, cyg_uint16 d, cyg_uint32 c, void *p )
234
{
235
#if DEBUG & 9
236
    db_printf("PCI match vendor 0x%04x device 0x%04x\n", v, d);
237
#endif
238
    return (0x1022 == v) && (0x2000 == d);
239
}
240
 
241
static int
242
pci_init_find_pcnet( void )
243
{
244
    cyg_pci_device_id devid;
245
    cyg_pci_device dev_info;
246
    cyg_uint16 cmd;
247
    int device_index;
248
    int found_devices = 0;
249
 
250
    DEBUG_FUNCTION();
251
 
252
#ifdef CYGARC_UNCACHED_ADDRESS
253
    CYG_ASSERT( CYGARC_UNCACHED_ADDRESS((CYG_ADDRWORD)CYGMEM_SECTION_pci_window) ==
254
                CYGHWR_AMD_PCNET_PCI_MEM_MAP_BASE,
255
      "PCI window configured does not match PCI memory section base" );
256
#else
257
    CYG_ASSERT( (CYG_ADDRWORD)CYGMEM_SECTION_pci_window ==
258
                CYGHWR_AMD_PCNET_PCI_MEM_MAP_BASE,
259
      "PCI window configured does not match PCI memory section base" );
260
#endif
261
    CYG_ASSERT( CYGMEM_SECTION_pci_window_SIZE ==
262
                CYGHWR_AMD_PCNET_PCI_MEM_MAP_SIZE,
263
        "PCI window configured does not match PCI memory section size" );
264
 
265
    if (
266
#ifdef CYGARC_UNCACHED_ADDRESS
267
         CYGARC_UNCACHED_ADDRESS((CYG_ADDRWORD)CYGMEM_SECTION_pci_window) !=
268
#else
269
         (CYG_ADDRWORD)CYGMEM_SECTION_pci_window !=
270
#endif
271
         CYGHWR_AMD_PCNET_PCI_MEM_MAP_BASE
272
         ||
273
         CYGMEM_SECTION_pci_window_SIZE !=
274
         CYGHWR_AMD_PCNET_PCI_MEM_MAP_SIZE ) {
275
#if DEBUG & 8
276
        db_printf("pci_init_find_pcnets(): PCI window misconfigured\n");
277
#endif
278
        return 0;
279
    }
280
 
281
    // First initialize the heap in PCI window'd memory
282
    pcnet_heap_size = CYGHWR_AMD_PCNET_PCI_MEM_MAP_SIZE;
283
    pcnet_heap_base = (cyg_uint8 *)CYGHWR_AMD_PCNET_PCI_MEM_MAP_BASE;
284
    pcnet_heap_free = pcnet_heap_base;
285
#if DEBUG & 9
286
    db_printf("pcimem : 0x%08x size: 0x%08x\n", pcnet_heap_base, pcnet_heap_size);
287
#endif
288
 
289
    cyg_pci_init();
290
#if DEBUG & 8
291
    db_printf("Finished cyg_pci_init();\n");
292
#endif
293
 
294
    devid = CYG_PCI_NULL_DEVID;
295
 
296
    for (device_index = 0;
297
         device_index < CYGNUM_DEVS_ETH_AMD_PCNET_DEV_COUNT;
298
         device_index++) {
299
        struct pcnet_priv_data* cpd = pcnet_priv_array[device_index];
300
 
301
        cpd->index = device_index;
302
 
303
        // See above for find_pcnet_match_func - it selects any of several
304
        // variants.  This is necessary in case we have multiple mixed-type
305
        // devices on one board in arbitrary orders.
306
        if (cyg_pci_find_matching( &find_pcnet_match_func, NULL, &devid )) {
307
#if DEBUG & 8
308
            db_printf("eth%d = pcnet\n", device_index);
309
#endif
310
            cyg_pci_get_device_info(devid, &dev_info);
311
 
312
            cpd->interrupt_handle = 0; // Flag not attached.
313
            if (cyg_pci_translate_interrupt(&dev_info, &cpd->interrupt)) {
314
#if DEBUG & 8
315
                db_printf(" Wired to HAL vector %d\n", cpd->interrupt);
316
#endif
317
                cyg_drv_interrupt_create(
318
                    cpd->interrupt,
319
                    1,                  // Priority - unused
320
                    (cyg_addrword_t)cpd,// Data item passed to ISR & DSR
321
                    pcnet_isr,          // ISR
322
                    pcnet_dsr,          // DSR
323
                    &cpd->interrupt_handle, // handle to intr obj
324
                    &cpd->interrupt_object ); // space for int obj
325
 
326
                cyg_drv_interrupt_attach(cpd->interrupt_handle);
327
 
328
                // Don't unmask the interrupt yet, that could get us into a
329
                // race.
330
            }
331
            else {
332
                cpd->interrupt = 0;
333
#if DEBUG & 8
334
                db_printf(" Does not generate interrupts.\n");
335
#endif
336
            }
337
 
338
            if (cyg_pci_configure_device(&dev_info)) {
339
#if DEBUG & 8
340
                int i;
341
                db_printf("Found device on bus %d, devfn 0x%02x:\n",
342
                          CYG_PCI_DEV_GET_BUS(devid),
343
                          CYG_PCI_DEV_GET_DEVFN(devid));
344
 
345
                if (dev_info.command & CYG_PCI_CFG_COMMAND_ACTIVE) {
346
                    db_printf(" Note that board is active. Probed"
347
                              " sizes and CPU addresses invalid!\n");
348
                }
349
                db_printf(" Vendor    0x%04x", dev_info.vendor);
350
                db_printf("\n Device    0x%04x", dev_info.device);
351
                db_printf("\n Command   0x%04x, Status 0x%04x\n",
352
                          dev_info.command, dev_info.status);
353
 
354
                db_printf(" Class/Rev 0x%08x", dev_info.class_rev);
355
                db_printf("\n Header 0x%02x\n", dev_info.header_type);
356
 
357
                db_printf(" SubVendor 0x%04x, Sub ID 0x%04x\n",
358
                          dev_info.header.normal.sub_vendor,
359
                          dev_info.header.normal.sub_id);
360
 
361
                for(i = 0; i < CYG_PCI_MAX_BAR; i++) {
362
                    db_printf(" BAR[%d]    0x%08x /", i, dev_info.base_address[i]);
363
                    db_printf(" probed size 0x%08x / CPU addr 0x%08x\n",
364
                              dev_info.base_size[i], dev_info.base_map[i]);
365
                }
366
                db_printf(" eth%d configured\n", device_index);
367
#endif
368
                found_devices++;
369
                cpd->found = 1;
370
                cpd->active = 0;
371
                cpd->devid = devid;
372
                cpd->base = (unsigned char*) dev_info.base_map[0];
373
#if DEBUG & 8
374
                db_printf(" I/O address = 0x%08x\n", cpd->base);
375
#endif
376
 
377
                // Don't use cyg_pci_set_device_info since it clears
378
                // some of the fields we want to print out below.
379
                cyg_pci_read_config_uint16(dev_info.devid,
380
                                           CYG_PCI_CFG_COMMAND, &cmd);
381
                cmd |= (CYG_PCI_CFG_COMMAND_IO         // enable I/O space
382
                        | CYG_PCI_CFG_COMMAND_MEMORY   // enable memory space
383
                        | CYG_PCI_CFG_COMMAND_MASTER); // enable bus master
384
                cyg_pci_write_config_uint16(dev_info.devid,
385
                                            CYG_PCI_CFG_COMMAND, cmd);
386
 
387
                // This is the indicator for "uses an interrupt"
388
                if (cpd->interrupt_handle != 0) {
389
                    cyg_drv_interrupt_acknowledge(cpd->interrupt);
390
                    cyg_drv_interrupt_unmask(cpd->interrupt);
391
#if DEBUG & 8
392
                    db_printf(" Enabled interrupt %d\n", cpd->interrupt);
393
#endif
394
                }
395
#if DEBUG & 8
396
                db_printf(" **** Device enabled for I/O and Memory "
397
                            "and Bus Master\n");
398
#endif
399
            }
400
            else {
401
                cpd->found = 0;
402
                cpd->active = 0;
403
#if DEBUG & 8
404
                db_printf("Failed to configure device %d\n", device_index);
405
#endif
406
            }
407
        }
408
        else {
409
            cpd->found = 0;
410
            cpd->active = 0;
411
#if DEBUG & 8
412
            db_printf("eth%d not found\n", device_index);
413
#endif
414
        }
415
    }
416
 
417
    if (0 == found_devices)
418
        return 0;
419
 
420
    return 1;
421
}
422
 
423
 
424
static bool
425
amd_pcnet_init(struct cyg_netdevtab_entry *tab)
426
{
427
    static int initialized = 0; // only probe PCI et al *once*
428
    struct eth_drv_sc *sc = (struct eth_drv_sc *)tab->device_instance;
429
    struct pcnet_priv_data *cpd =
430
        (struct pcnet_priv_data *)sc->driver_private;
431
    cyg_uint16 val;
432
    cyg_uint32 b;
433
    cyg_uint8* p;
434
    cyg_uint8* d;
435
    cyg_uint8* init_table;
436
    int i;
437
 
438
    DEBUG_FUNCTION();
439
 
440
 
441
    if ( 0 == initialized++ ) {
442
        // then this is the first time ever:
443
        if ( ! pci_init_find_pcnet() ) {
444
#if DEBUG & 8
445
            db_printf( "pci_init_find_pcnet failed" );
446
#endif
447
            return false;
448
        }
449
    }
450
 
451
    // If this device is not present, exit
452
    if (0 == cpd->found)
453
        return 0;
454
 
455
    cpd->txbusy = 0;
456
 
457
#if DEBUG & 8
458
    db_printf("PCNet at base 0x%08x, EEPROM key 0x%04x\n",
459
                cpd->base, _SU16(cpd->base, PCNET_IO_ID));
460
#endif
461
 
462
#if 0
463
    // FIXME: Doesn't work with non-conforming EEPROMS
464
    if (PCNET_IO_ID_KEY != _SU16(cpd->base, PCNET_IO_ID) ) {
465
        db_printf("PCNet EPROM key not found\n");
466
        return false;
467
    }
468
#endif
469
 
470
#if DEBUG & 9
471
    db_printf("pcimem : %08x size: %08x\n", pcnet_heap_base, pcnet_heap_size);
472
#endif
473
 
474
    // Prepare ESA
475
    if (!cpd->hardwired_esa) {
476
        // Use the address from the serial EEPROM
477
        p = cpd->base + PCNET_IO_EEPROM;
478
        for (i = 0; i < 6; i++)
479
            cpd->esa[i] = *p++;
480
    }
481
#if DEBUG & 9
482
    db_printf("PCNET - %s ESA: %02x:%02x:%02x:%02x:%02x:%02x\n",
483
                (cpd->hardwired_esa) ? "static" : "eeprom",
484
                cpd->esa[0], cpd->esa[1], cpd->esa[2],
485
                cpd->esa[3], cpd->esa[4], cpd->esa[5] );
486
#endif
487
 
488
#ifdef CYGSEM_DEVS_ETH_AMD_PCNET_FORCE_10MBPS
489
    if (get_reg(sc,PCNET_ANR_AAR) & PCNET_ANR_AAR_100) {
490
        cyg_uint16 anr;
491
        int loop;
492
 
493
#if DEBUG & 9
494
        db_printf("%s: Forcing 10Mbps negotiation\n", __FUNCTION__);
495
#endif
496
        // adjust speed/duplex auto-negotiation mask to clear 100Mbps bits
497
        anr = get_reg(sc,PCNET_ANR_AAR);
498
        anr &= ~PCNET_ANR_AAR_100;
499
        put_reg(sc,PCNET_ANR_AAR,anr);
500
        // renegotiate
501
        anr = get_reg(sc,PCNET_ANR_PHYCTRL);
502
        anr |= PCNET_ANR_PHYCTRL_RENEGOTIATE;
503
        put_reg(sc,PCNET_ANR_PHYCTRL,anr);
504
        loop = 100000;
505
        while (loop>0 && !(get_reg(sc,PCNET_ANR_PHYSTAT) & PCNET_ANR_PHYSTAT_AUTONEG_COMP))
506
                loop--;
507
#if DEBUG & 9
508
        db_printf("ANR0: %04x\n",get_reg(sc,PCNET_ANR_PHYCTRL));
509
        db_printf("ANR1: %04x\n",get_reg(sc,PCNET_ANR_PHYSTAT));
510
        db_printf("ANR4: %04x\n",get_reg(sc,PCNET_ANR_AAR));
511
#endif
512
    }
513
#endif
514
 
515
    // Prepare RX and TX rings
516
    p = cpd->rx_ring = (cyg_uint8*) CYGARC_UNCACHED_ADDRESS((cyg_uint32)pciwindow_mem_alloc((1<<cpd->rx_ring_log_cnt)*PCNET_RD_SIZE));
517
    memset(cpd->rx_ring,0,(1<<cpd->rx_ring_log_cnt)*PCNET_RD_SIZE);
518
 
519
    d = cpd->rx_buffers = (cyg_uint8*) CYGARC_UNCACHED_ADDRESS((cyg_uint32)pciwindow_mem_alloc(_BUF_SIZE*cpd->rx_ring_cnt));
520
    memset(cpd->rx_buffers,0,_BUF_SIZE*cpd->rx_ring_cnt);
521
 
522
    for (i = 0; i < cpd->rx_ring_cnt; i++) {
523
        HAL_PCI_CPU_TO_BUS(d, b);
524
        _SU32(p, PCNET_RD_PTR) = (b & PCNET_RD_PTR_MASK) | PCNET_RD_PTR_OWN;
525
        _SU16(p, PCNET_RD_BLEN) = (-_BUF_SIZE);
526
        p += PCNET_RD_SIZE;
527
        d += _BUF_SIZE;
528
    }
529
    cpd->rx_ring_next = 0;
530
 
531
    p = cpd->tx_ring = (cyg_uint8*) CYGARC_UNCACHED_ADDRESS((cyg_uint32)pciwindow_mem_alloc((1<<cpd->tx_ring_log_cnt)*PCNET_TD_SIZE));
532
    memset(cpd->tx_ring,0,(1<<cpd->tx_ring_log_cnt)*PCNET_TD_SIZE);
533
 
534
    d = cpd->tx_buffers = (cyg_uint8*) CYGARC_UNCACHED_ADDRESS((cyg_uint32)pciwindow_mem_alloc(_BUF_SIZE*cpd->tx_ring_cnt));
535
    for (i = 0; i < cpd->tx_ring_cnt; i++) {
536
        HAL_PCI_CPU_TO_BUS(d, b);
537
        _SU32(p, PCNET_RD_PTR) = b & PCNET_TD_PTR_MASK;
538
        p += PCNET_TD_SIZE;
539
        d += _BUF_SIZE;
540
    }
541
    cpd->tx_ring_free = cpd->tx_ring_alloc = cpd->tx_ring_owned = 0;
542
 
543
    // Initialization table
544
    init_table = (cyg_uint8*)CYGARC_UNCACHED_ADDRESS((cyg_uint32)pciwindow_mem_alloc(PCNET_IB_SIZE));
545
    _SU16(init_table, PCNET_IB_MODE) = 0x0000;
546
    for (i = 0; i < 6; i++)
547
        _SU8(init_table, PCNET_IB_PADR0+i) = cpd->esa[i];
548
    for (i = 0; i < 8; i++)
549
        _SU8(init_table, PCNET_IB_LADRF0+i) = 0;
550
 
551
    HAL_PCI_CPU_TO_BUS(cpd->rx_ring, b);
552
    _SU32(init_table, PCNET_IB_RDRA) = ((b & PCNET_IB_RDRA_PTR_mask)
553
                                        | (cpd->rx_ring_log_cnt << PCNET_IB_RDRA_CNT_shift));
554
    HAL_PCI_CPU_TO_BUS(cpd->tx_ring, b);
555
    _SU32(init_table, PCNET_IB_TDRA) = ((b & PCNET_IB_TDRA_PTR_mask)
556
                                        | (cpd->tx_ring_log_cnt << PCNET_IB_TDRA_CNT_shift));
557
 
558
#if DEBUG & 9
559
    db_printf("Loading up PCNet controller from table at 0x%08x\n", init_table);
560
    db_printf(" Mode 0x%04x\n", _SU16(init_table, PCNET_IB_MODE));
561
    db_printf(" PADR %02x:%02x:%02x:%02x:%02x:%02x ",
562
                _SU8(init_table, PCNET_IB_PADR0+0), _SU8(init_table, PCNET_IB_PADR0+1),
563
                _SU8(init_table, PCNET_IB_PADR0+2), _SU8(init_table, PCNET_IB_PADR0+3),
564
                _SU8(init_table, PCNET_IB_PADR0+4), _SU8(init_table, PCNET_IB_PADR0+5));
565
    db_printf("LADR %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
566
                _SU8(init_table, PCNET_IB_LADRF0+0), _SU8(init_table, PCNET_IB_LADRF0+1),
567
                _SU8(init_table, PCNET_IB_LADRF0+2), _SU8(init_table, PCNET_IB_LADRF0+3),
568
                _SU8(init_table, PCNET_IB_LADRF0+4), _SU8(init_table, PCNET_IB_LADRF0+5),
569
                _SU8(init_table, PCNET_IB_LADRF0+5), _SU8(init_table, PCNET_IB_LADRF0+7));
570
    db_printf(" RX 0x%08x (len %d) TX 0x%08x (len %d)\n",
571
                _SU32(init_table, PCNET_IB_RDRA) & 0x1fffffff,
572
                (_SU32(init_table, PCNET_IB_RDRA) >> PCNET_IB_RDRA_CNT_shift) & 7,
573
                _SU32(init_table, PCNET_IB_TDRA) & 0x1fffffff,
574
                (_SU32(init_table, PCNET_IB_TDRA) >> PCNET_IB_TDRA_CNT_shift) & 7);
575
#endif
576
 
577
    // Reset chip
578
    HAL_PCI_IO_READ_UINT16(cpd->base+PCNET_IO_RESET, val);
579
 
580
    // Load up chip with buffers.
581
    // Note: There is a 16M limit on the addresses used by the driver
582
    // since the top 8 bits of the init_table address is appended to
583
    // all other addresses used by the controller.
584
    HAL_PCI_CPU_TO_BUS(init_table, b);
585
    put_reg(sc, PCNET_CSR_IBA0, (b >>  0) & 0xffff);
586
    put_reg(sc, PCNET_CSR_IBA1, (b >> 16) & 0xffff);
587
    // Disable automatic TX polling (_send will force a poll), pad
588
    // XT frames to legal length, mask status interrupts.
589
    put_reg(sc, PCNET_CSR_TFC, (PCNET_CSR_TFC_TXDPOLL | PCNET_CSR_TFC_APAD_XMT
590
                                | PCNET_CSR_TFC_MFCOM | PCNET_CSR_TFC_RCVCCOM
591
                                | PCNET_CSR_TFC_TXSTRTM));
592
    // Recover after TX FIFO underflow
593
    put_reg(sc, PCNET_CSR_IM, PCNET_CSR_IM_DXSUFLO);
594
    // Initialize controller - load up init_table
595
    put_reg(sc, PCNET_CSR_CSCR, PCNET_CSR_CSCR_INIT);
596
    while (0 == (get_reg(sc, PCNET_CSR_CSCR) & PCNET_CSR_CSCR_IDON));
597
 
598
    // Stop controller
599
    put_reg(sc, PCNET_CSR_CSCR, PCNET_CSR_CSCR_STOP);
600
 
601
#if DEBUG & 9
602
    db_printf("PCNet controller state is now:\n");
603
    db_printf(" Mode 0x%04x  TFC 0x%04x\n", _SU16(init_table, PCNET_IB_MODE), get_reg(sc, PCNET_CSR_TFC));
604
    db_printf(" PADR %04x:%04x:%04x ",
605
                get_reg(sc, PCNET_CSR_PAR0),
606
                get_reg(sc, PCNET_CSR_PAR1),
607
                get_reg(sc, PCNET_CSR_PAR2));
608
    db_printf("LADR %04x:%04x:%04x:%04x\n",
609
                get_reg(sc, PCNET_CSR_LAR0),
610
                get_reg(sc, PCNET_CSR_LAR1),
611
                get_reg(sc, PCNET_CSR_LAR2),
612
                get_reg(sc, PCNET_CSR_LAR3));
613
    db_printf(" RX 0x%04x%04x (len 0x%04x) TX 0x%04x%04x (len 0x%04x)\n",
614
                get_reg(sc, PCNET_CSR_BARRU), get_reg(sc, PCNET_CSR_BARRL),
615
                get_reg(sc, PCNET_CSR_RRLEN),
616
                get_reg(sc, PCNET_CSR_BATRU), get_reg(sc, PCNET_CSR_BATRL),
617
                get_reg(sc, PCNET_CSR_TRLEN));
618
 
619
    val = get_reg(sc, PCNET_CSR_ID_LO);
620
    db_printf("PCnet ID 0x%04x (%s) ",
621
                val,
622
                (0x5003 == val) ? "Am79C973" : (0x7003 == val) ? "Am79C975" : "Unknown");
623
    val = get_reg(sc, PCNET_CSR_ID_HI);
624
    db_printf("Part IDU 0x%03x Silicon rev %d\n",
625
                val & 0x0fff, (val >> 12) & 0xf);
626
#endif
627
 
628
    // and record the net dev pointer
629
    cpd->ndp = (void *)tab;
630
 
631
    // Start controller, but put it in suspended mode
632
    put_reg(sc, PCNET_CSR_CSCR, PCNET_CSR_CSCR_STOP);
633
    put_reg(sc, PCNET_CSR_CSCR, (PCNET_CSR_CSCR_IENA | PCNET_CSR_CSCR_STRT));
634
    i = 0;
635
    while (0 == (PCNET_CSR_CSCR_STRT & get_reg(sc, PCNET_CSR_CSCR))) {
636
        CYGACC_CALL_IF_DELAY_US(1000);
637
        put_reg(sc, PCNET_CSR_CSCR, (PCNET_CSR_CSCR_IENA | PCNET_CSR_CSCR_STRT));
638
        if (i++ == 1000) {
639
#if DEBUG & 9
640
            db_printf("Failed to start the controller\n");
641
#endif
642
            return false;
643
        }
644
    }
645
 
646
    val = get_reg(sc, PCNET_CSR_ECI);
647
    val |= PCNET_CSR_ECI_SPND;
648
    put_reg(sc, PCNET_CSR_ECI, val);
649
    // Wait for device to suspend
650
    do {
651
        val = get_reg(sc, PCNET_CSR_ECI);
652
    } while (0 == (val & PCNET_CSR_ECI_SPND));
653
    cpd->active = 0;
654
 
655
    // Initialize upper level driver
656
    (sc->funs->eth_drv->init)(sc, cpd->esa);
657
 
658
#if DEBUG & 9
659
    db_printf("Done\n");
660
#endif
661
    return true;
662
}
663
 
664
static void
665
pcnet_stop(struct eth_drv_sc *sc)
666
{
667
    cyg_uint16 reg;
668
    struct pcnet_priv_data *cpd =
669
        (struct pcnet_priv_data *)sc->driver_private;
670
 
671
    DEBUG_FUNCTION();
672
 
673
    reg = get_reg(sc, PCNET_CSR_ECI);
674
    reg |= PCNET_CSR_ECI_SPND;
675
    put_reg(sc, PCNET_CSR_ECI, reg);
676
    // Wait for device to suspend
677
    do {
678
        reg = get_reg(sc, PCNET_CSR_ECI);
679
    } while (0 == (reg & PCNET_CSR_ECI_SPND));
680
    cpd->active = 0;
681
}
682
 
683
//
684
// This function is called to "start up" the interface.  It may be called
685
// multiple times, even when the hardware is already running.  It will be
686
// called whenever something "hardware oriented" changes and should leave
687
// the hardware ready to send/receive packets.
688
//
689
static void
690
pcnet_start(struct eth_drv_sc *sc, unsigned char *enaddr, int flags)
691
{
692
    cyg_uint16 reg;
693
    struct pcnet_priv_data *cpd =
694
        (struct pcnet_priv_data *)sc->driver_private;
695
#ifdef CYGPKG_NET
696
    struct ifnet *ifp = &sc->sc_arpcom.ac_if;
697
#endif
698
    DEBUG_FUNCTION();
699
 
700
    // If device is already active, suspend it
701
    if (cpd->active) {
702
        reg = get_reg(sc, PCNET_CSR_ECI);
703
        reg |= PCNET_CSR_ECI_SPND;
704
        put_reg(sc, PCNET_CSR_ECI, reg);
705
        // Wait for device to suspend
706
        do {
707
            reg = get_reg(sc, PCNET_CSR_ECI);
708
        } while (0 == (reg & PCNET_CSR_ECI_SPND));
709
        cpd->active = 0;
710
    }
711
 
712
#ifdef CYGPKG_NET
713
    if (( 0
714
#ifdef ETH_DRV_FLAGS_PROMISC_MODE
715
         != (flags & ETH_DRV_FLAGS_PROMISC_MODE)
716
#endif
717
        ) || (ifp->if_flags & IFF_PROMISC)
718
        ) {
719
        // Then we select promiscuous mode.
720
        cyg_uint16 rcr;
721
        rcr = get_reg(sc, PCNET_CSR_MODE );
722
        rcr |= PCNET_CSR_MODE_PROM;
723
        put_reg(sc, PCNET_CSR_MODE, rcr );
724
    }
725
#endif
726
 
727
    // Unsuspend the device
728
    reg = get_reg(sc, PCNET_CSR_ECI);
729
    reg &= ~PCNET_CSR_ECI_SPND;
730
    put_reg(sc, PCNET_CSR_ECI, reg);
731
    cpd->active = 1;
732
}
733
 
734
//
735
// This routine is called to perform special "control" opertions
736
//
737
static int
738
pcnet_control(struct eth_drv_sc *sc, unsigned long key,
739
               void *data, int data_length)
740
{
741
    cyg_uint8 *esa = (cyg_uint8 *)data;
742
    int i, res;
743
    cyg_uint16 reg;
744
    struct pcnet_priv_data *cpd =
745
        (struct pcnet_priv_data *)sc->driver_private;
746
    cyg_bool was_active = cpd->active;
747
 
748
    DEBUG_FUNCTION();
749
 
750
    // If device is already active, suspend it
751
    if (cpd->active) {
752
        reg = get_reg(sc, PCNET_CSR_ECI);
753
        reg |= PCNET_CSR_ECI_SPND;
754
        put_reg(sc, PCNET_CSR_ECI, reg);
755
        // Wait for device to suspend
756
        do {
757
            reg = get_reg(sc, PCNET_CSR_ECI);
758
        } while (0 == (reg & PCNET_CSR_ECI_SPND));
759
        cpd->active = 0;
760
    }
761
 
762
    res = 0;                            // expect success
763
    switch (key) {
764
    case ETH_DRV_SET_MAC_ADDRESS:
765
#if 9 & DEBUG
766
        db_printf("PCNET - set ESA: %02x:%02x:%02x:%02x:%02x:%02x\n",
767
                esa[0], esa[1], esa[2], esa[3], esa[4], esa[5] );
768
#endif // DEBUG
769
 
770
        for ( i = 0; i < sizeof(cpd->esa);  i++ )
771
            cpd->esa[i] = esa[i];
772
        for (i = 0;  i < sizeof(cpd->esa);  i += 2) {
773
            reg = cpd->esa[i] | (cpd->esa[i+1] << 8);
774
            put_reg(sc, PCNET_CSR_PAR0+i/2, reg );
775
        }
776
        break;
777
 
778
#ifdef ETH_DRV_GET_MAC_ADDRESS
779
    case ETH_DRV_GET_MAC_ADDRESS:
780
        // Extract the MAC address that is in the chip, and tell the
781
        // system about it.
782
        for (i = 0;  i < sizeof(cpd->esa);  i += 2) {
783
            cyg_uint16 z = get_reg(sc, PCNET_CSR_PAR0+i/2 );
784
            esa[i] =   (cyg_uint8)(0xff & z);
785
            esa[i+1] = (cyg_uint8)(0xff & (z >> 8));
786
        }
787
        break;
788
#endif
789
 
790
#ifdef ETH_DRV_GET_IF_STATS_UD
791
    case ETH_DRV_GET_IF_STATS_UD: // UD == UPDATE
792
#endif
793
        // drop through
794
#ifdef ETH_DRV_GET_IF_STATS
795
    case ETH_DRV_GET_IF_STATS:
796
#endif
797
 
798
#if defined(ETH_DRV_GET_IF_STATS) || defined (ETH_DRV_GET_IF_STATS_UD)
799
    {
800
        cyg_uint16 anr;
801
        struct ether_drv_stats *p = (struct ether_drv_stats *)data;
802
        // Chipset entry is no longer supported; RFC1573.
803
        for ( i = 0; i < SNMP_CHIPSET_LEN; i++ )
804
            p->snmp_chipset[i] = 0;
805
 
806
        // This perhaps should be a config opt, so you can make up your own
807
        // description, or supply it from the instantiation.
808
        strcpy( p->description, "AMD PCNet" );
809
        // CYG_ASSERT( 48 > strlen(p->description), "Description too long" );
810
 
811
        anr = get_reg(sc, PCNET_ANR_PHYSTAT);
812
        if ((anr & PCNET_ANR_PHYSTAT_LINK) == 0) {
813
            p->operational = 2;         // LINK DOWN
814
            p->duplex = 1;              // UNKNOWN
815
            p->speed = 0;
816
        }
817
        else {
818
            p->operational = 3;         // LINK UP
819
            anr = get_reg(sc, PCNET_ANR_PHYCTRL);
820
 
821
            if (anr & PCNET_ANR_PHYCTRL_DUPLEX)
822
                p->duplex = 3;              // 3 = DUPLEX
823
            else
824
                p->duplex = 2;              // 2 = SIMPLEX
825
            p->speed = (anr & PCNET_ANR_PHYCTRL_100MBPS) ? 100 * 1000000 : 10 * 1000000;
826
        }
827
 
828
#if FIXME
829
#ifdef KEEP_STATISTICS
830
        {
831
            struct amd_pcnet_stats *ps = &(cpd->stats);
832
 
833
            // Admit to it...
834
            p->supports_dot3        = true;
835
 
836
            p->tx_good              = ps->tx_good             ;
837
            p->tx_max_collisions    = ps->tx_max_collisions   ;
838
            p->tx_late_collisions   = ps->tx_late_collisions  ;
839
            p->tx_underrun          = ps->tx_underrun         ;
840
            p->tx_carrier_loss      = ps->tx_carrier_loss     ;
841
            p->tx_deferred          = ps->tx_deferred         ;
842
            p->tx_sqetesterrors     = ps->tx_sqetesterrors    ;
843
            p->tx_single_collisions = ps->tx_single_collisions;
844
            p->tx_mult_collisions   = ps->tx_mult_collisions  ;
845
            p->tx_total_collisions  = ps->tx_total_collisions ;
846
            p->rx_good              = ps->rx_good             ;
847
            p->rx_crc_errors        = ps->rx_crc_errors       ;
848
            p->rx_align_errors      = ps->rx_align_errors     ;
849
            p->rx_resource_errors   = ps->rx_resource_errors  ;
850
            p->rx_overrun_errors    = ps->rx_overrun_errors   ;
851
            p->rx_collisions        = ps->rx_collisions       ;
852
            p->rx_short_frames      = ps->rx_short_frames     ;
853
            p->rx_too_long_frames   = ps->rx_too_long_frames  ;
854
            p->rx_symbol_errors     = ps->rx_symbol_errors    ;
855
 
856
            p->interrupts           = ps->interrupts          ;
857
            p->rx_count             = ps->rx_count            ;
858
            p->rx_deliver           = ps->rx_deliver          ;
859
            p->rx_resource          = ps->rx_resource         ;
860
            p->rx_restart           = ps->rx_restart          ;
861
            p->tx_count             = ps->tx_count            ;
862
            p->tx_complete          = ps->tx_complete         ;
863
            p->tx_dropped           = ps->tx_dropped          ;
864
        }
865
#endif // KEEP_STATISTICS
866
#endif // FIXME
867
 
868
        p->tx_queue_len = 1;
869
        break;
870
    }
871
#endif
872
    default:
873
        res = 1;
874
        break;
875
    }
876
 
877
    // Restore controller state
878
    if (was_active) {
879
        // Unsuspend the device
880
        reg = get_reg(sc, PCNET_CSR_ECI);
881
        reg &= ~PCNET_CSR_ECI_SPND;
882
        put_reg(sc, PCNET_CSR_ECI, reg);
883
    }
884
 
885
    return res;
886
}
887
 
888
//
889
// This routine is called to see if it is possible to send another packet.
890
// It will return non-zero if a transmit is possible, zero otherwise.
891
//
892
static int
893
pcnet_can_send(struct eth_drv_sc *sc)
894
{
895
    struct pcnet_priv_data *cpd =
896
        (struct pcnet_priv_data *)sc->driver_private;
897
    cyg_uint16 stat;
898
 
899
    DEBUG_FUNCTION();
900
 
901
    stat = get_reg(sc, PCNET_ANR_PHYSTAT);
902
    if ((stat & PCNET_ANR_PHYSTAT_LINK) == 0) {
903
        return 0;                       // Link not connected
904
    }
905
 
906
    return (0 == cpd->txbusy);
907
}
908
 
909
//
910
// This routine is called to send data to the hardware.
911
static void
912
pcnet_send(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len,
913
            int total_len, unsigned long key)
914
{
915
    struct pcnet_priv_data *cpd =
916
        (struct pcnet_priv_data *)sc->driver_private;
917
    int i, len, plen, ring_entry;
918
 
919
    cyg_uint8* sdata = NULL;
920
    cyg_uint8 *d, *buf, *txd;
921
    cyg_uint16 ints;
922
    cyg_uint32 b;
923
 
924
    DEBUG_FUNCTION();
925
 
926
    INCR_STAT( tx_count );
927
 
928
    cpd->txbusy = 1;
929
    cpd->txkey = key;
930
 
931
    // Find packet length
932
    plen = 0;
933
    for (i = 0;  i < sg_len;  i++)
934
        plen += sg_list[i].len;
935
 
936
    CYG_ASSERT( plen == total_len, "sg data length mismatch" );
937
 
938
    // Get next TX descriptor
939
    ring_entry = cpd->tx_ring_free;
940
    do {
941
        if (cpd->tx_ring_owned == cpd->tx_ring_cnt) {
942
            // Is this a dead end? Probably is.
943
#if DEBUG & 1
944
            db_printf("%s: Allocation failed! Retrying...\n", __FUNCTION__ );
945
#endif
946
            continue;
947
        }
948
 
949
        cpd->tx_ring_free++;
950
        cpd->tx_ring_owned++;
951
        if (cpd->tx_ring_free == cpd->tx_ring_cnt)
952
            cpd->tx_ring_free = 0;
953
    } while (0);
954
 
955
    txd = cpd->tx_ring + ring_entry*PCNET_TD_SIZE;
956
    buf = cpd->tx_buffers + ring_entry*_BUF_SIZE;
957
    CYG_ASSERT(0 == (_SU32(txd, PCNET_TD_PTR) & PCNET_TD_PTR_OWN),
958
               "TX descriptor not free");
959
 
960
#if DEBUG & 4
961
    db_printf("#####Tx descriptor 0x%08x buffer 0x%08x\n",
962
                txd, buf);
963
#endif
964
 
965
    // Put data into buffer
966
    d = buf;
967
    for (i = 0;  i < sg_len;  i++) {
968
        sdata = (cyg_uint8 *)sg_list[i].buf;
969
        len = sg_list[i].len;
970
 
971
        CYG_ASSERT( sdata, "No sg data pointer here" );
972
        while(len--)
973
            *d++ = *sdata++;
974
    }
975
    CYG_ASSERT( sdata, "No sg data pointer outside" );
976
 
977
#if DEBUG & 1
978
    db_printf("CSCR %04x\n", get_reg(sc, PCNET_CSR_CSCR));
979
#endif
980
    _SU16(txd, PCNET_TD_LEN) = (-plen);
981
    _SU16(txd, PCNET_TD_MISC) = 0;
982
    HAL_PCI_CPU_TO_BUS(buf, b);
983
    _SU32(txd, PCNET_TD_PTR) = ((b & PCNET_TD_PTR_MASK)
984
                                | PCNET_TD_PTR_OWN | PCNET_TD_PTR_STP | PCNET_TD_PTR_ENP);
985
 
986
#if DEBUG & 1
987
    db_printf("Last TX: LEN %04x MISC %04x PTR %08x\n",
988
                _SU16(txd, PCNET_TD_LEN),
989
                _SU16(txd, PCNET_TD_MISC),
990
                _SU32(txd, PCNET_TD_PTR));
991
#endif
992
 
993
    // This delay seems to be necessary on some platforms 
994
    // (Malta 5kc for example).
995
    // Why it is needed is not clear, but removing it or
996
    // reducing it cause transmission failures in RedBoot (at least).
997
    CYGACC_CALL_IF_DELAY_US(100);
998
 
999
 
1000
    // Set transmit demand
1001
    ints = get_reg(sc, PCNET_CSR_CSCR);
1002
    ints &= PCNET_CSR_CSCR_EV_MASK;
1003
    ints |= PCNET_CSR_CSCR_TDMD;
1004
    put_reg(sc, PCNET_CSR_CSCR, ints);
1005
 
1006
#if DEBUG & 1
1007
    ints = get_reg(sc, PCNET_CSR_CSCR);
1008
    db_printf("%s:END: ints at TX: 0x%04x\n", __FUNCTION__, ints);
1009
#endif
1010
 
1011
    // This is another mystery delay like the one above. This one is
1012
    // even stranger, since waiting here at the _end_ of the function
1013
    // should have no effect.
1014
    CYGACC_CALL_IF_DELAY_US(200);
1015
}
1016
 
1017
static void
1018
pcnet_TxEvent(struct eth_drv_sc *sc, int stat)
1019
{
1020
     struct pcnet_priv_data *cpd =
1021
        (struct pcnet_priv_data *)sc->driver_private;
1022
    int success = 1;
1023
    cyg_uint8 *txd;
1024
    cyg_uint16 ints;
1025
    cyg_uint32 pkt_stat;
1026
 
1027
    DEBUG_FUNCTION();
1028
 
1029
    if (0 == cpd->tx_ring_owned) {
1030
#if DEBUG & 1
1031
        db_printf("%s: got TX completion when no outstanding packets\n", __FUNCTION__);
1032
#endif
1033
        return;
1034
    }
1035
 
1036
    INCR_STAT( tx_complete );
1037
 
1038
    txd = cpd->tx_ring + cpd->tx_ring_alloc*PCNET_TD_SIZE;
1039
    pkt_stat = _SU32(txd, PCNET_TD_PTR);
1040
    if (pkt_stat & PCNET_TD_PTR_OWN) {
1041
#if DEBUG & 1
1042
        db_printf("%s: got TX completion when buffer is still owned\n", __FUNCTION__);
1043
#endif
1044
        // first dirty ring entry not freed - wtf?
1045
    }
1046
 
1047
    if (pkt_stat & PCNET_TD_PTR_ERR) {
1048
        // We had an error. Tell the stack.
1049
        success = 0;
1050
#if DEBUG & 1
1051
        db_printf("%s: TX failure, retrying...\n", __FUNCTION__);
1052
#endif
1053
    }
1054
 
1055
    cpd->tx_ring_alloc++;
1056
    if (cpd->tx_ring_alloc == cpd->tx_ring_cnt)
1057
        cpd->tx_ring_alloc = 0;
1058
    cpd->tx_ring_owned--;
1059
 
1060
#if FIXME
1061
#ifdef KEEP_STATISTICS
1062
    {
1063
        cyg_uint16 reg;
1064
 
1065
        reg = get_reg( sc, PCNET_CSR_CSCR );
1066
 
1067
        // Covering each bit in turn...
1068
        if ( reg & PCNET_STATUS_TX_UNRN   ) INCR_STAT( tx_underrun );
1069
        //if ( reg & PCNET_STATUS_LINK_OK ) INCR_STAT(  );
1070
        //if ( reg & PCNET_STATUS_CTR_ROL ) INCR_STAT(  );
1071
        //if ( reg & PCNET_STATUS_EXC_DEF ) INCR_STAT(  );
1072
        if ( reg & PCNET_STATUS_LOST_CARR ) INCR_STAT( tx_carrier_loss );
1073
        if ( reg & PCNET_STATUS_LATCOL    ) INCR_STAT( tx_late_collisions );
1074
        //if ( reg & PCNET_STATUS_WAKEUP  ) INCR_STAT(  );
1075
        if ( reg & PCNET_STATUS_TX_DEFR   ) INCR_STAT( tx_deferred );
1076
        //if ( reg & PCNET_STATUS_LTX_BRD ) INCR_STAT(  );
1077
        if ( reg & PCNET_STATUS_SQET      ) INCR_STAT( tx_sqetesterrors );
1078
        if ( reg & PCNET_STATUS_16COL     ) INCR_STAT( tx_max_collisions );
1079
        //if ( reg & PCNET_STATUS_LTX_MULT) INCR_STAT(  );
1080
        if ( reg & PCNET_STATUS_MUL_COL   ) INCR_STAT( tx_mult_collisions );
1081
        if ( reg & PCNET_STATUS_SNGL_COL  ) INCR_STAT( tx_single_collisions );
1082
        if ( reg & PCNET_STATUS_TX_SUC    ) INCR_STAT( tx_good );
1083
 
1084
        cpd->stats.tx_total_collisions =
1085
            cpd->stats.tx_late_collisions +
1086
            cpd->stats.tx_max_collisions +
1087
            cpd->stats.tx_mult_collisions +
1088
            cpd->stats.tx_single_collisions;
1089
 
1090
        // We do not need to look in the Counter Register (PCNET_COUNTER)
1091
        // because it just mimics the info we already have above.
1092
    }
1093
#endif // KEEP_STATISTICS
1094
#endif // FIXME
1095
 
1096
    // Ack the TX int which clears the packet from the TX completion
1097
    // queue.
1098
    ints = get_reg(sc, PCNET_CSR_CSCR);
1099
    ints |= PCNET_CSR_CSCR_TINT;
1100
    put_reg(sc, PCNET_CSR_CSCR, ints);
1101
 
1102
#if DEBUG & 4
1103
    db_printf("#####Tx packet freed 0x%08x\n", txd );
1104
#endif
1105
 
1106
    if ( cpd->txbusy ) {
1107
        cpd->txbusy = 0;
1108
        (sc->funs->eth_drv->tx_done)(sc, cpd->txkey, success);
1109
    }
1110
}
1111
 
1112
 
1113
//
1114
// This function is called when a packet has been received.  Its job is
1115
// to prepare to unload the packet from the hardware.  Once the length of
1116
// the packet is known, the upper layer of the driver can be told.  When
1117
// the upper layer is ready to unload the packet, the internal function
1118
// 'pcnet_recv' will be called to actually fetch it from the hardware.
1119
//
1120
static void
1121
pcnet_RxEvent(struct eth_drv_sc *sc)
1122
{
1123
    struct pcnet_priv_data *cpd =
1124
        (struct pcnet_priv_data *)sc->driver_private;
1125
    cyg_uint8 *rxd;
1126
    cyg_uint32 rstat;
1127
    cyg_uint16 ints, len;
1128
 
1129
    DEBUG_FUNCTION();
1130
 
1131
    ints = get_reg(sc, PCNET_CSR_CSCR);
1132
#if DEBUG & 1
1133
    db_printf("RxEvent - CSR: 0x%04x\n", ints);
1134
#endif
1135
 
1136
    while (1) {
1137
        // Get state of next (supposedly) full ring entry
1138
        cpd->rxpacket = cpd->rx_ring_next;
1139
        rxd = cpd->rx_ring + cpd->rxpacket*PCNET_RD_SIZE;
1140
        rstat = _SU32(rxd, PCNET_RD_PTR);
1141
 
1142
        // Keep going until we hit an entry that is owned by the
1143
        // controller.
1144
        if (rstat & PCNET_RD_PTR_OWN) {
1145
#if DEBUG & 1
1146
            int i;
1147
            for (i = 0; i < cpd->rx_ring_cnt; i++) {
1148
                rxd = cpd->rx_ring + i*PCNET_RD_SIZE;
1149
                rstat = _SU32(rxd, PCNET_RD_PTR);
1150
 
1151
                if (!(rstat & PCNET_RD_PTR_OWN)) {
1152
                    int i;
1153
                    cyg_uint32 rstat;
1154
                    cyg_uint16 mlen, blen;
1155
                    cyg_uint8* rxd;
1156
 
1157
                    db_printf("%s: Inconsistent RX state\n", __FUNCTION__);
1158
                    for (i = 0; i < cpd->rx_ring_cnt; i++) {
1159
                        rxd = cpd->rx_ring + i*PCNET_RD_SIZE;
1160
 
1161
                        rstat = _SU32(rxd, PCNET_RD_PTR);
1162
                        blen = _SU16(rxd, PCNET_RD_BLEN);
1163
                        mlen = _SU16(rxd, PCNET_RD_MLEN);
1164
                        db_printf(" %02d: 0x%08x:0x%04x:0x%04x\n", i, rstat, blen, mlen);
1165
                    }
1166
                }
1167
            }
1168
#endif
1169
            break;
1170
        }
1171
 
1172
#if DEBUG & 4
1173
        db_printf("#####Rx packet at index %d\n", cpd->rxpacket);
1174
#endif
1175
 
1176
        // Increment counts
1177
        INCR_STAT( rx_count );
1178
        cpd->rx_ring_next++;
1179
        if (cpd->rx_ring_next == cpd->rx_ring_cnt) cpd->rx_ring_next = 0;
1180
 
1181
        len = _SU16(rxd, PCNET_RD_MLEN);
1182
 
1183
#ifdef KEEP_STATISTICS
1184
        //if ( rstat & PCNET_RD_PTR_FRAM ) INCR_STAT( rx_frame_errors );
1185
        //if ( rstat & PCNET_RD_PTR_OFLO ) INCR_STAT(  );
1186
        if ( rstat & PCNET_RD_PTR_CRC ) INCR_STAT( rx_crc_errors );
1187
        //if ( rstat & PCNET_RD_PTR_BUFF ) INCR_STAT(  );
1188
#endif // KEEP_STATISTICS
1189
 
1190
        if (0 == (rstat & PCNET_RD_PTR_ERR)) {
1191
            // It's OK
1192
            INCR_STAT( rx_good );
1193
 
1194
#if DEBUG & 1
1195
            db_printf("RxEvent good rx - stat: 0x%08x, len: 0x%04x\n", rstat, len);
1196
#endif
1197
            // Check for bogusly short packets; can happen in promisc
1198
            // mode: Asserted against and checked by upper layer
1199
            // driver.
1200
#ifdef CYGPKG_NET
1201
            if ( len > sizeof( struct ether_header ) )
1202
                // then it is acceptable; offer the data to the network stack
1203
#endif
1204
                (sc->funs->eth_drv->recv)(sc, len);
1205
        } else {
1206
            // Not OK for one reason or another...
1207
#if DEBUG & 1
1208
            db_printf("RxEvent - No RX bit: stat: 0x%08x, len: 0x%04x\n",
1209
                        rstat, len);
1210
#endif
1211
        }
1212
 
1213
        // Free packet (clear all status flags, and set OWN)
1214
        _SU32(rxd, PCNET_RD_PTR) &= PCNET_RD_PTR_MASK;
1215
        _SU32(rxd, PCNET_RD_PTR) |= PCNET_RD_PTR_OWN;
1216
    }
1217
 
1218
    // Ack RX interrupt set
1219
    ints = get_reg(sc, PCNET_CSR_CSCR);
1220
    ints &= PCNET_CSR_CSCR_EV_MASK;
1221
    ints |= PCNET_CSR_CSCR_RINT;
1222
    put_reg(sc, PCNET_CSR_CSCR, ints);
1223
}
1224
 
1225
//
1226
// This function is called as a result of the "eth_drv_recv()" call above.
1227
// Its job is to actually fetch data for a packet from the hardware once
1228
// memory buffers have been allocated for the packet.  Note that the buffers
1229
// may come in pieces, using a scatter-gather list.  This allows for more
1230
// efficient processing in the upper layers of the stack.
1231
//
1232
static void
1233
pcnet_recv(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len)
1234
{
1235
    struct pcnet_priv_data *cpd =
1236
        (struct pcnet_priv_data *)sc->driver_private;
1237
    int i, mlen=0, plen;
1238
    cyg_uint8 *data, *rxd, *buf;
1239
 
1240
    DEBUG_FUNCTION();
1241
 
1242
    rxd = cpd->rx_ring + cpd->rxpacket*PCNET_RD_SIZE;
1243
    buf = cpd->rx_buffers + cpd->rxpacket*_BUF_SIZE;
1244
 
1245
    INCR_STAT( rx_deliver );
1246
 
1247
    plen = _SU16(rxd, PCNET_RD_MLEN);
1248
 
1249
    for (i = 0;  i < sg_len;  i++) {
1250
        data = (cyg_uint8*)sg_list[i].buf;
1251
        mlen = sg_list[i].len;
1252
 
1253
#if DEBUG & 1
1254
        db_printf("%s : mlen %x, plen %x\n", __FUNCTION__, mlen, plen);
1255
#endif
1256
        if (data) {
1257
            while (mlen > 0) {
1258
                *data++ = *buf++;
1259
                mlen--;
1260
                plen--;
1261
            }
1262
        }
1263
    }
1264
}
1265
 
1266
static void
1267
pcnet_poll(struct eth_drv_sc *sc)
1268
{
1269
    cyg_uint16 event;
1270
 
1271
//  DEBUG_FUNCTION();
1272
 
1273
    while (1) {
1274
        // Get the (unmasked) requests
1275
        event = get_reg(sc, PCNET_CSR_CSCR);
1276
        if (!((PCNET_CSR_CSCR_ERR|PCNET_CSR_CSCR_INTR) & event))
1277
            break;
1278
 
1279
        if (event & PCNET_CSR_CSCR_RINT) {
1280
            pcnet_RxEvent(sc);
1281
        }
1282
        else if (event & PCNET_CSR_CSCR_TINT) {
1283
            pcnet_TxEvent(sc, event);
1284
        }
1285
        else if (event & PCNET_CSR_CSCR_MISS) {
1286
#if DEBUG & 1
1287
            int i;
1288
            cyg_uint32 rstat;
1289
            cyg_uint16 mlen, blen;
1290
            cyg_uint8* rxd;
1291
            struct pcnet_priv_data *cpd =
1292
                (struct pcnet_priv_data *)sc->driver_private;
1293
 
1294
            db_printf("%s: Ran out of RX buffers (%04x)\n", __FUNCTION__, event);
1295
            for (i = 0; i < cpd->rx_ring_cnt; i++) {
1296
                rxd = cpd->rx_ring + i*PCNET_TD_SIZE;
1297
 
1298
                rstat = _SU32(rxd, PCNET_RD_PTR);
1299
                blen = _SU16(rxd, PCNET_RD_BLEN);
1300
                mlen = _SU16(rxd, PCNET_RD_MLEN);
1301
                db_printf(" %02d: 0x%08x:0x%04x:0x%04x\n", i, rstat, blen, mlen);
1302
            }
1303
#endif
1304
            event &= PCNET_CSR_CSCR_EV_MASK;
1305
            event |= PCNET_CSR_CSCR_MISS;
1306
            put_reg(sc, PCNET_CSR_CSCR, event);
1307
        }
1308
        else {
1309
#if DEBUG & 1
1310
            db_printf("%s: Unknown interrupt: 0x%04x\n", __FUNCTION__, event);
1311
#endif
1312
            put_reg(sc, PCNET_CSR_CSCR, event);
1313
        }
1314
    }
1315
}
1316
 
1317
// EOF if_pcnet.c

powered by: WebSVN 2.1.0

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