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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-2.0/] [packages/] [devs/] [eth/] [amd/] [pcnet/] [v2_0/] [src/] [if_pcnet.c] - Blame information for rev 174

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

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