URL
https://opencores.org/ocsvn/openrisc/openrisc/trunk
Subversion Repositories openrisc
Compare Revisions
- This comparison shows the changes necessary to convert path
/openrisc/trunk/rtos/ecos-2.0/packages/devs/eth/ns
- from Rev 27 to Rev 174
- ↔ Reverse comparison
Rev 27 → Rev 174
/dp83902a/v2_0/cdl/ns_dp83902a_eth_drivers.cdl
0,0 → 1,86
# ==================================================================== |
# |
# ns_dp83902a_eth_drivers.cdl |
# |
# Ethernet drivers - device support for NS DP83902A Ethernet |
# |
# ==================================================================== |
#####ECOSGPLCOPYRIGHTBEGIN#### |
## ------------------------------------------- |
## This file is part of eCos, the Embedded Configurable Operating System. |
## Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. |
## |
## eCos is free software; you can redistribute it and/or modify it under |
## the terms of the GNU General Public License as published by the Free |
## Software Foundation; either version 2 or (at your option) any later version. |
## |
## eCos is distributed in the hope that it will be useful, but WITHOUT ANY |
## WARRANTY; without even the implied warranty of MERCHANTABILITY or |
## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
## for more details. |
## |
## You should have received a copy of the GNU General Public License along |
## with eCos; if not, write to the Free Software Foundation, Inc., |
## 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. |
## |
## As a special exception, if other files instantiate templates or use macros |
## or inline functions from this file, or you compile this file and link it |
## with other works to produce a work based on this file, this file does not |
## by itself cause the resulting work to be covered by the GNU General Public |
## License. However the source code for this file must still be made available |
## in accordance with section (3) of the GNU General Public License. |
## |
## This exception does not invalidate any other reasons why a work based on |
## this file might be covered by the GNU General Public License. |
## |
## Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. |
## at http://sources.redhat.com/ecos/ecos-license/ |
## ------------------------------------------- |
#####ECOSGPLCOPYRIGHTEND#### |
# ==================================================================== |
######DESCRIPTIONBEGIN#### |
# |
# Author(s): gthomas |
# Contributors: gthomas, jskov |
# Date: 2001-06-13 |
# |
#####DESCRIPTIONEND#### |
# |
# ==================================================================== |
|
cdl_package CYGPKG_DEVS_ETH_NS_DP83902A { |
display "NS DP83902A ethernet drivers" |
|
parent CYGPKG_IO_ETH_DRIVERS |
active_if CYGPKG_IO_ETH_DRIVERS |
|
implements CYGHWR_NET_DRIVERS |
|
active_if CYGINT_DEVS_ETH_NS_DP83902A_REQUIRED |
|
include_dir cyg/io |
description "Ethernet driver for NS DP83902A (and DP8390) ethernet controller." |
compile -library=libextras.a if_dp83902a.c |
|
define_proc { |
puts $::cdl_header "#include <pkgconf/system.h>"; |
puts $::cdl_header "#include CYGDAT_DEVS_ETH_NS_DP83902A_CFG"; |
} |
|
cdl_component CYGPKG_DEVS_ETH_NS_DP83902A_OPTIONS { |
display "DP83902A ethernet driver build options" |
flavor none |
no_define |
|
cdl_option CYGPKG_DEVS_ETH_NS_DP83902A_CFLAGS_ADD { |
display "Additional compiler flags" |
flavor data |
no_define |
default_value { "-D_KERNEL -D__ECOS" } |
description " |
This option modifies the set of compiler flags for |
building the National Semiconductor (DP839x) ethernet driver package. |
These flags are used in addition to the set of global flags." |
} |
} |
} |
/dp83902a/v2_0/include/dp83902a.h
0,0 → 1,384
//========================================================================== |
// |
// dev/dp83902a.h |
// |
// National Semiconductor DP83902a ethernet chip |
// |
//========================================================================== |
//####ECOSGPLCOPYRIGHTBEGIN#### |
// ------------------------------------------- |
// This file is part of eCos, the Embedded Configurable Operating System. |
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. |
// |
// eCos is free software; you can redistribute it and/or modify it under |
// the terms of the GNU General Public License as published by the Free |
// Software Foundation; either version 2 or (at your option) any later version. |
// |
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY |
// WARRANTY; without even the implied warranty of MERCHANTABILITY or |
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
// for more details. |
// |
// You should have received a copy of the GNU General Public License along |
// with eCos; if not, write to the Free Software Foundation, Inc., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. |
// |
// As a special exception, if other files instantiate templates or use macros |
// or inline functions from this file, or you compile this file and link it |
// with other works to produce a work based on this file, this file does not |
// by itself cause the resulting work to be covered by the GNU General Public |
// License. However the source code for this file must still be made available |
// in accordance with section (3) of the GNU General Public License. |
// |
// This exception does not invalidate any other reasons why a work based on |
// this file might be covered by the GNU General Public License. |
// |
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. |
// at http://sources.redhat.com/ecos/ecos-license/ |
// ------------------------------------------- |
//####ECOSGPLCOPYRIGHTEND#### |
//####BSDCOPYRIGHTBEGIN#### |
// |
// ------------------------------------------- |
// |
// Portions of this software may have been derived from OpenBSD or other sources, |
// and are covered by the appropriate copyright disclaimers included herein. |
// |
// ------------------------------------------- |
// |
//####BSDCOPYRIGHTEND#### |
//========================================================================== |
//#####DESCRIPTIONBEGIN#### |
// |
// Author(s): gthomas |
// Contributors: gthomas, jskov |
// Date: 2001-06-13 |
// Purpose: |
// Description: |
// |
//####DESCRIPTIONEND#### |
// |
//========================================================================== |
|
#include <cyg/hal/hal_io.h> |
#include <pkgconf/devs_eth_ns_dp83902a.h> |
|
#define __WANT_CONFIG |
#include CYGDAT_DEVS_ETH_NS_DP83902A_INL |
#undef __WANT_CONFIG |
|
// ------------------------------------------------------------------------ |
// Debugging details |
|
// Set to perms of: |
// 0 disables all debug output |
// 1 for process debug output |
// 2 for added data IO output: get_reg, put_reg |
// 4 for packet allocation/free output |
// 8 for only startup status, so we can tell we're installed OK |
#define DEBUG 0x0 |
|
#if DEBUG & 1 |
#define DEBUG_FUNCTION() do { diag_printf("%s\n", __FUNCTION__); } while (0) |
#define DEBUG_LINE() do { diag_printf("%d\n", __LINE__); } while (0) |
#else |
#define DEBUG_FUNCTION() do {} while(0) |
#define DEBUG_LINE() do {} while(0) |
#endif |
|
// ------------------------------------------------------------------------ |
// MAcros for keeping track of statistics |
#if defined(ETH_DRV_GET_IF_STATS) || defined (ETH_DRV_GET_IF_STATS_UD) |
#define KEEP_STATISTICS |
#endif |
|
#ifdef KEEP_STATISTICS |
#define INCR_STAT( _x_ ) (dp->stats. _x_ ++) |
#else |
#define INCR_STAT( _x_ ) CYG_EMPTY_STATEMENT |
#endif |
|
// ------------------------------------------------------------------------ |
// Private driver structure |
typedef struct dp83902a_priv_data { |
cyg_uint8* base; |
cyg_uint8* data; |
cyg_uint8* reset; |
int tx_next; // First free Tx page |
int tx_int; // Expecting interrupt from this buffer |
int rx_next; // First free Rx page |
int tx1, tx2; // Page numbers for Tx buffers |
unsigned long tx1_key, tx2_key; // Used to ack when packet sent |
int tx1_len, tx2_len; |
bool tx_started, running, hardwired_esa; |
struct cyg_netdevtab_entry *tab; |
cyg_uint8 esa[6]; |
cyg_vector_t interrupt; // Interrupt vector used by controller |
cyg_handle_t interrupt_handle; |
cyg_interrupt interrupt_object; |
void* plf_priv; |
|
// For debugging |
volatile int cr_lock; |
volatile int cr_owner; |
|
// Buffer allocation |
int tx_buf1, tx_buf2; |
int rx_buf_start, rx_buf_end; |
} dp83902a_priv_data_t; |
|
// ------------------------------------------------------------------------ |
// Macros for accessing structure elements |
|
#define _SU8( _base_, _offset_) \ |
*((volatile cyg_uint8 *)((CYG_ADDRWORD)_base_+(_offset_))) |
#define _SU16( _base_, _offset_) \ |
*((volatile cyg_uint16 *)((CYG_ADDRWORD)_base_+(_offset_))) |
#define _SU32( _base_, _offset_) \ |
*((volatile cyg_uint32 *)((CYG_ADDRWORD)_base_+(_offset_))) |
|
#define _SI8( _base_, _offset_) \ |
*((volatile cyg_int8 *)((CYG_ADDRWORD)_base_+(_offset_))) |
#define _SI16( _base_, _offset_) \ |
*((volatile cyg_int16 *)((CYG_ADDRWORD)_base_+(_offset_))) |
#define _SI32( _base_, _offset_) \ |
*((volatile cyg_int32 *)((CYG_ADDRWORD)_base_+(_offset_))) |
|
// ------------------------------------------------------------------------ |
// Macros for accessing DP registers |
// These can be overridden by the platform header |
|
#ifndef DP_IN |
# define DP_IN(_b_, _o_, _d_) HAL_READ_UINT8 ((cyg_addrword_t)(_b_)+(_o_), (_d_)) |
# define DP_OUT(_b_, _o_, _d_) HAL_WRITE_UINT8((cyg_addrword_t)(_b_)+(_o_), (_d_)) |
#endif |
|
#ifndef DP_IN_DATA |
# ifdef CYGHWR_NS_DP83902A_PLF_16BIT_DATA |
# ifdef BIGEND |
# define DP_IN_DATA(_b_, _d_) \ |
CYG_MACRO_START \ |
cyg_uint16 _t; \ |
HAL_READ_UINT16 ((cyg_addrword_t)(_b_), _t); \ |
DELAY(); \ |
(_d_) = ((_t >> 8) & 0xff) | ((_t & 0xff) << 8); \ |
CYG_MACRO_END |
|
# define DP_OUT_DATA(_b_, _d_) \ |
CYG_MACRO_START \ |
cyg_uint16 _t; \ |
_t = (_d_); \ |
(_t) = (((_t) >> 8) & 0xff) | ((_t & 0xff) << 8); \ |
HAL_WRITE_UINT16((cyg_addrword_t)(_b_), _t); \ |
DELAY(); \ |
CYG_MACRO_END |
# else |
# define DP_IN_DATA(_b_, _d_) HAL_READ_UINT16 ((cyg_addrword_t)(_b_), (_d_)) |
# define DP_OUT_DATA(_b_, _d_) HAL_WRITE_UINT16 ((cyg_addrword_t)(_b_), (_d_)) |
# endif |
# else |
# define DP_IN_DATA(_b_, _d_) HAL_READ_UINT8 ((cyg_addrword_t)(_b_), (_d_)) |
# define DP_OUT_DATA(_b_, _d_) HAL_WRITE_UINT8 ((cyg_addrword_t)(_b_), (_d_)) |
# endif |
#endif |
|
// ------------------------------------------------------------------------ |
// Macros allowing platform to customize some of the driver details |
|
#ifndef CYGHWR_NS_DP83902A_PLF_RESET |
# define CYGHWR_NS_DP83902A_PLF_RESET(_b_) do { } while (0) |
#endif |
|
#ifndef CYGHWR_NS_DP83902A_PLF_INT_CLEAR |
# define CYGHWR_NS_DP83902A_PLF_INT_CLEAR(_dp_) |
#endif |
|
#ifndef CYGHWR_NS_DP83902A_PLF_INIT |
#define CYGHWR_NS_DP83902A_PLF_INIT(dp) do { } while (0) |
#endif |
|
// ------------------------------------------------------------------------ |
// Hack that should go away, probably |
#define CR_UP() \ |
CYG_MACRO_START \ |
if (++dp->cr_lock > 1) { \ |
diag_printf("*** Race on CR %s:%d owner %d\n", \ |
__FUNCTION__, __LINE__, dp->cr_owner); \ |
for (;;); \ |
} \ |
dp->cr_owner = __LINE__; \ |
CYG_MACRO_END |
|
#define CR_DOWN() \ |
dp->cr_lock--; |
|
// ------------------------------------------------------------------------ |
// Some forward declarations |
static void dp83902a_poll(struct eth_drv_sc *sc); |
|
// ------------------------------------------------------------------------ |
// Register offsets |
|
#define DP_CR 0x00 |
#define DP_CLDA0 0x01 |
#define DP_PSTART 0x01 // write |
#define DP_CLDA1 0x02 |
#define DP_PSTOP 0x02 // write |
#define DP_BNDRY 0x03 |
#define DP_TSR 0x04 |
#define DP_TPSR 0x04 // write |
#define DP_NCR 0x05 |
#define DP_TBCL 0x05 // write |
#define DP_FIFO 0x06 |
#define DP_TBCH 0x06 // write |
#define DP_ISR 0x07 |
#define DP_CRDA0 0x08 |
#define DP_RSAL 0x08 // write |
#define DP_CRDA1 0x09 |
#define DP_RSAH 0x09 // write |
#define DP_RBCL 0x0a // write |
#define DP_RBCH 0x0b // write |
#define DP_RSR 0x0c |
#define DP_RCR 0x0c // write |
#define DP_FER 0x0d |
#define DP_TCR 0x0d // write |
#define DP_CER 0x0e |
#define DP_DCR 0x0e // write |
#define DP_MISSED 0x0f |
#define DP_IMR 0x0f // write |
#define DP_DATAPORT 0x10 // "eprom" data port |
|
#define DP_P1_CR 0x00 |
#define DP_P1_PAR0 0x01 |
#define DP_P1_PAR1 0x02 |
#define DP_P1_PAR2 0x03 |
#define DP_P1_PAR3 0x04 |
#define DP_P1_PAR4 0x05 |
#define DP_P1_PAR5 0x06 |
#define DP_P1_CURP 0x07 |
#define DP_P1_MAR0 0x08 |
#define DP_P1_MAR1 0x09 |
#define DP_P1_MAR2 0x0a |
#define DP_P1_MAR3 0x0b |
#define DP_P1_MAR4 0x0c |
#define DP_P1_MAR5 0x0d |
#define DP_P1_MAR6 0x0e |
#define DP_P1_MAR7 0x0f |
|
#define DP_P2_CR 0x00 |
#define DP_P2_PSTART 0x01 |
#define DP_P2_CLDA0 0x01 // write |
#define DP_P2_PSTOP 0x02 |
#define DP_P2_CLDA1 0x02 // write |
#define DP_P2_RNPP 0x03 |
#define DP_P2_TPSR 0x04 |
#define DP_P2_LNPP 0x05 |
#define DP_P2_ACH 0x06 |
#define DP_P2_ACL 0x07 |
#define DP_P2_RCR 0x0c |
#define DP_P2_TCR 0x0d |
#define DP_P2_DCR 0x0e |
#define DP_P2_IMR 0x0f |
|
// Command register - common to all pages |
|
#define DP_CR_STOP 0x01 // Stop: software reset |
#define DP_CR_START 0x02 // Start: initialize device |
#define DP_CR_TXPKT 0x04 // Transmit packet |
#define DP_CR_RDMA 0x08 // Read DMA (recv data from device) |
#define DP_CR_WDMA 0x10 // Write DMA (send data to device) |
#define DP_CR_SEND 0x18 // Send packet |
#define DP_CR_NODMA 0x20 // Remote (or no) DMA |
#define DP_CR_PAGE0 0x00 // Page select |
#define DP_CR_PAGE1 0x40 |
#define DP_CR_PAGE2 0x80 |
#define DP_CR_PAGEMSK 0x3F // Used to mask out page bits |
|
// Data configuration register |
|
#define DP_DCR_WTS 0x01 // 1=16 bit word transfers |
#define DP_DCR_BOS 0x02 // 1=Little Endian |
#define DP_DCR_LAS 0x04 // 1=Single 32 bit DMA mode |
#define DP_DCR_LS 0x08 // 1=normal mode, 0=loopback |
#define DP_DCR_ARM 0x10 // 0=no send command (program I/O) |
#define DP_DCR_FIFO_1 0x00 // FIFO threshold |
#define DP_DCR_FIFO_2 0x20 |
#define DP_DCR_FIFO_4 0x40 |
#define DP_DCR_FIFO_6 0x60 |
|
#ifdef CYGHWR_NS_DP83902A_PLF_16BIT_DATA |
# ifdef BIGENDIAN |
# define DP_DCR_INIT (DP_DCR_BOS|DP_DCR_WTS|DP_DCR_LS|DP_DCR_FIFO_4) |
# else |
# define DP_DCR_INIT (DP_DCR_WTS|DP_DCR_LS|DP_DCR_FIFO_4) |
# endif |
#else |
# define DP_DCR_INIT (DP_DCR_LS|DP_DCR_FIFO_4) |
#endif |
|
// Interrupt status register |
|
#define DP_ISR_RxP 0x01 // Packet received |
#define DP_ISR_TxP 0x02 // Packet transmitted |
#define DP_ISR_RxE 0x04 // Receive error |
#define DP_ISR_TxE 0x08 // Transmit error |
#define DP_ISR_OFLW 0x10 // Receive overflow |
#define DP_ISR_CNT 0x20 // Tally counters need emptying |
#define DP_ISR_RDC 0x40 // Remote DMA complete |
#define DP_ISR_RESET 0x80 // Device has reset (shutdown, error) |
|
// Interrupt mask register |
|
#define DP_IMR_RxP 0x01 // Packet received |
#define DP_IMR_TxP 0x02 // Packet transmitted |
#define DP_IMR_RxE 0x04 // Receive error |
#define DP_IMR_TxE 0x08 // Transmit error |
#define DP_IMR_OFLW 0x10 // Receive overflow |
#define DP_IMR_CNT 0x20 // Tall counters need emptying |
#define DP_IMR_RDC 0x40 // Remote DMA complete |
|
#define DP_IMR_All 0x3F // Everything but remote DMA |
|
// Receiver control register |
|
#define DP_RCR_SEP 0x01 // Save bad(error) packets |
#define DP_RCR_AR 0x02 // Accept runt packets |
#define DP_RCR_AB 0x04 // Accept broadcast packets |
#define DP_RCR_AM 0x08 // Accept multicast packets |
#define DP_RCR_PROM 0x10 // Promiscuous mode |
#define DP_RCR_MON 0x20 // Monitor mode - 1=accept no packets |
|
// Receiver status register |
|
#define DP_RSR_RxP 0x01 // Packet received |
#define DP_RSR_CRC 0x02 // CRC error |
#define DP_RSR_FRAME 0x04 // Framing error |
#define DP_RSR_FO 0x08 // FIFO overrun |
#define DP_RSR_MISS 0x10 // Missed packet |
#define DP_RSR_PHY 0x20 // 0=pad match, 1=mad match |
#define DP_RSR_DIS 0x40 // Receiver disabled |
#define DP_RSR_DFR 0x80 // Receiver processing deferred |
|
// Transmitter control register |
|
#define DP_TCR_NOCRC 0x01 // 1=inhibit CRC |
#define DP_TCR_NORMAL 0x00 // Normal transmitter operation |
#define DP_TCR_LOCAL 0x02 // Internal NIC loopback |
#define DP_TCR_INLOOP 0x04 // Full internal loopback |
#define DP_TCR_OUTLOOP 0x08 // External loopback |
#define DP_TCR_ATD 0x10 // Auto transmit disable |
#define DP_TCR_OFFSET 0x20 // Collision offset adjust |
|
// Transmit status register |
|
#define DP_TSR_TxP 0x01 // Packet transmitted |
#define DP_TSR_COL 0x04 // Collision (at least one) |
#define DP_TSR_ABT 0x08 // Aborted because of too many collisions |
#define DP_TSR_CRS 0x10 // Lost carrier |
#define DP_TSR_FU 0x20 // FIFO underrun |
#define DP_TSR_CDH 0x40 // Collision Detect Heartbeat |
#define DP_TSR_OWC 0x80 // Collision outside normal window |
|
#define IEEE_8023_MAX_FRAME 1518 // Largest possible ethernet frame |
#define IEEE_8023_MIN_FRAME 64 // Smallest possible ethernet frame |
|
/dp83902a/v2_0/ChangeLog
0,0 → 1,144
2002-06-14 Gary Thomas <gary@chez-thomas.org> |
|
* src/if_dp83902a.c: |
Need to include <pkgconf/io_eth_drivers.h> for proper configuration |
of stand-alone (polled) vs. system (interrupt driven) mode. |
|
2002-05-30 Jonathan Larmour <jlarmour@redhat.com> |
|
* src/if_dp83902a.c: Use CYGINT_IO_ETH_INT_SUPPORT_REQUIRED instead |
of CYGPKG_NET where required. |
|
2002-04-12 Gary Thomas <gthomas@redhat.com> |
|
* src/if_dp83902a.c: Clean up warnings. |
|
2002-03-28 Gary Thomas <gthomas@redhat.com> |
|
* cdl/ns_dp83902a_eth_drivers.cdl: Fix spelling of _OPTIONS |
component as this is magic (CDL requires that it match the |
package or it is ignored). |
|
2002-01-14 Jesper Skov <jskov@redhat.com> |
|
* src/if_dp83902a.c (dp83902a_ClearCounters): Fix warning. |
|
2001-12-10 Richard Sandiford <rsandifo@redhat.com> |
|
* src/if_dp83902a.c (dp83902a_RxEvent): Remove unused argument. |
(dp83902a_TxEvent): Likewise. |
(dp83902a_BufEvent): Remove. |
(dp83902a_ClearCounters): New. |
(dp83902a_Overflow): New. |
(dp83902a_poll): Rework polling loop to use the new functions. |
|
2001-10-16 Jesper Skov <jskov@redhat.com> |
|
* include/dp83902a.h: Removed hardwired buffer |
allocation. Replaced with per-device configuration. |
* src/if_dp83902a.c: Same. |
|
2001-10-15 Jesper Skov <jskov@redhat.com> |
|
* include/dp83902a.h: Added new page allocation layout. |
|
2001-10-12 Gary Thomas <gthomas@redhat.com> |
|
* src/if_dp83902a.c: Leave out interrupt code - not needed in |
non-NET configurations. |
|
2001-10-10 Gary Thomas <gthomas@redhat.com> |
|
* src/if_dp83902a.c: |
* include/dp83902a.h: More flexible setup. Chip reset address is |
now in device data, along with changes to the PLF reset functions. |
Also, a new PLF init function can be defined which allows the driver |
to work in a PCI enviroment (addresses unknown at compile time). |
|
2001-09-12 Jesper Skov <jskov@redhat.com> |
|
* src/if_dp83902a.c: Apply a little more DMA magic. |
|
2001-08-25 Gary Thomas <gthomas@redhat.com> |
|
* include/dp83902a.h (DP_DATAPORT): Add - used by ESA discovery |
on SC/LPE card. |
|
2001-06-21 Jesper Skov <jskov@redhat.com> |
|
* src/if_dp83902a.c: Fix various build problems when net package |
is included. |
|
2001-06-16 Jesper Skov <jskov@redhat.com> |
|
* src/if_dp83902a.c (dp83902a_poll): Ignore spurious Tx events. |
|
2001-06-15 Jesper Skov <jskov@redhat.com> |
|
* src/if_dp83902a.c: Added crude CR race check. Use plf interrupt |
clear to allow for CF driver to use this driver. Cleaned up debug |
output some. |
(dp83902a_send): Added some magic delays to get driver working on |
some (apparently) broken boards. |
|
* src/dp83902a.h: Moved.. |
* include/dp83902a.h: to here. Moved macro definitions here from |
the src file. |
|
* cdl/ns_dp83902a_eth_drivers.cdl: Export header file. |
|
2001-06-14 Jesper Skov <jskov@redhat.com> |
|
* src/if_dp83902a.c: Added some more debug info. |
|
* src/dp83902a.h: Added 16bit/BE macros (untested). |
|
* src/if_dp83902a.c: Add some debug code, fix endian issue. Proper |
handling of odd-length reads in 16bit mode. |
|
2001-06-13 Jesper Skov <jskov@redhat.com> |
|
* src/if_dp83902a.c: Assume LE ordering of read header data. |
|
* src/dp83902a.h: BE/LE versions of data IO. Define proper DCR |
init value depending on data access width. |
|
* Cloned from DP8390 driver. |
|
//=========================================================================== |
//####ECOSGPLCOPYRIGHTBEGIN#### |
// ------------------------------------------- |
// This file is part of eCos, the Embedded Configurable Operating System. |
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. |
// |
// eCos is free software; you can redistribute it and/or modify it under |
// the terms of the GNU General Public License as published by the Free |
// Software Foundation; either version 2 or (at your option) any later version. |
// |
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY |
// WARRANTY; without even the implied warranty of MERCHANTABILITY or |
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
// for more details. |
// |
// You should have received a copy of the GNU General Public License along |
// with eCos; if not, write to the Free Software Foundation, Inc., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. |
// |
// As a special exception, if other files instantiate templates or use macros |
// or inline functions from this file, or you compile this file and link it |
// with other works to produce a work based on this file, this file does not |
// by itself cause the resulting work to be covered by the GNU General Public |
// License. However the source code for this file must still be made available |
// in accordance with section (3) of the GNU General Public License. |
// |
// This exception does not invalidate any other reasons why a work based on |
// this file might be covered by the GNU General Public License. |
// |
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. |
// at http://sources.redhat.com/ecos/ecos-license/ |
// ------------------------------------------- |
//####ECOSGPLCOPYRIGHTEND#### |
//=========================================================================== |
|
|
|
/dp83902a/v2_0/src/if_dp83902a.c
0,0 → 1,784
//========================================================================== |
// |
// dev/if_dp83902a.c |
// |
// Ethernet device driver for NS DP83902a ethernet controller |
// |
//========================================================================== |
//####ECOSGPLCOPYRIGHTBEGIN#### |
// ------------------------------------------- |
// This file is part of eCos, the Embedded Configurable Operating System. |
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. |
// |
// eCos is free software; you can redistribute it and/or modify it under |
// the terms of the GNU General Public License as published by the Free |
// Software Foundation; either version 2 or (at your option) any later version. |
// |
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY |
// WARRANTY; without even the implied warranty of MERCHANTABILITY or |
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
// for more details. |
// |
// You should have received a copy of the GNU General Public License along |
// with eCos; if not, write to the Free Software Foundation, Inc., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. |
// |
// As a special exception, if other files instantiate templates or use macros |
// or inline functions from this file, or you compile this file and link it |
// with other works to produce a work based on this file, this file does not |
// by itself cause the resulting work to be covered by the GNU General Public |
// License. However the source code for this file must still be made available |
// in accordance with section (3) of the GNU General Public License. |
// |
// This exception does not invalidate any other reasons why a work based on |
// this file might be covered by the GNU General Public License. |
// |
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. |
// at http://sources.redhat.com/ecos/ecos-license/ |
// ------------------------------------------- |
//####ECOSGPLCOPYRIGHTEND#### |
//####BSDCOPYRIGHTBEGIN#### |
// |
// ------------------------------------------- |
// |
// Portions of this software may have been derived from OpenBSD or other sources, |
// and are covered by the appropriate copyright disclaimers included herein. |
// |
// ------------------------------------------- |
// |
//####BSDCOPYRIGHTEND#### |
//========================================================================== |
//#####DESCRIPTIONBEGIN#### |
// |
// Author(s): gthomas |
// Contributors: gthomas, jskov, rsandifo |
// Date: 2001-06-13 |
// Purpose: |
// Description: |
// |
// FIXME: Will fail if pinged with large packets (1520 bytes) |
// Add promisc config |
// Add SNMP |
// |
//####DESCRIPTIONEND#### |
// |
//========================================================================== |
|
#include <pkgconf/system.h> |
#include <pkgconf/io_eth_drivers.h> |
|
#include <cyg/infra/cyg_type.h> |
#include <cyg/hal/hal_arch.h> |
#include <cyg/infra/diag.h> |
#include <cyg/hal/drv_api.h> |
#include <cyg/io/eth/eth_drv.h> |
#include <cyg/io/eth/netdev.h> |
|
#include <cyg/io/dp83902a.h> |
|
#define __WANT_DEVS |
#include CYGDAT_DEVS_ETH_NS_DP83902A_INL |
#undef __WANT_DEVS |
|
#ifdef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED |
// This ISR is called when the ethernet interrupt occurs |
static cyg_uint32 |
dp83902a_isr(cyg_vector_t vector, cyg_addrword_t data) |
{ |
dp83902a_priv_data_t *dp = (dp83902a_priv_data_t *)data; |
|
DEBUG_FUNCTION(); |
// INCR_STAT( interrupts ); |
|
cyg_drv_interrupt_mask(dp->interrupt); |
cyg_drv_interrupt_acknowledge(dp->interrupt); |
return (CYG_ISR_HANDLED|CYG_ISR_CALL_DSR); // Run the DSR |
} |
|
static void |
dp83902a_dsr(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data) |
{ |
// This conditioning out is necessary because of explicit calls to this |
// DSR - which would not ever be called in the case of a polled mode |
// usage ie. in RedBoot. |
#ifdef CYGPKG_IO_ETH_DRIVERS_NET |
dp83902a_priv_data_t* dp = (dp83902a_priv_data_t *)data; |
struct cyg_netdevtab_entry *ndp = (struct cyg_netdevtab_entry *)(dp->tab); |
struct eth_drv_sc *sc = (struct eth_drv_sc *)(ndp->device_instance); |
|
DEBUG_FUNCTION(); |
|
// but here, it must be a *sc: |
eth_drv_dsr( vector, count, (cyg_addrword_t)sc ); |
#else |
# ifndef CYGPKG_REDBOOT |
# error Empty DP83902A ethernet DSR is compiled. Is this what you want? |
# endif |
#endif |
} |
#endif // CYGINT_IO_ETH_INT_SUPPORT_REQUIRED |
|
// The deliver function (ex-DSR) handles the ethernet [logical] processing |
static void |
dp83902a_deliver(struct eth_drv_sc *sc) |
{ |
dp83902a_priv_data_t *dp = (dp83902a_priv_data_t *)sc->driver_private; |
|
DEBUG_FUNCTION(); |
|
// Service the interrupt: |
dp83902a_poll(sc); |
// Allow interrupts to happen again |
cyg_drv_interrupt_unmask(dp->interrupt); |
} |
|
static bool |
dp83902a_init(struct cyg_netdevtab_entry *tab) |
{ |
struct eth_drv_sc *sc = (struct eth_drv_sc *)tab->device_instance; |
dp83902a_priv_data_t *dp = (dp83902a_priv_data_t *)sc->driver_private; |
cyg_uint8* base; |
int i; |
|
DEBUG_FUNCTION(); |
|
CYGHWR_NS_DP83902A_PLF_INIT(dp); |
base = dp->base; |
if (!base) return false; // No device found |
|
dp->tab = tab; |
dp->cr_lock = 0; |
|
CYGHWR_NS_DP83902A_PLF_RESET(dp); |
|
DEBUG_LINE(); |
|
// Prepare ESA |
DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE1); // Select page 1 |
if (dp->hardwired_esa) { |
// Force the NIC to use the specified ESA |
for (i = 0; i < 6; i++) |
DP_OUT(base, DP_P1_PAR0+i, dp->esa[i]); |
} else { |
// Use the address from the serial EEPROM |
for (i = 0; i < 6; i++) |
DP_IN(base, DP_P1_PAR0+i, dp->esa[i]); |
} |
DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE0); // Select page 0 |
|
diag_printf("DP83902A - %s ESA: %02x:%02x:%02x:%02x:%02x:%02x\n", |
(dp->hardwired_esa) ? "static" : "eeprom", |
dp->esa[0], |
dp->esa[1], |
dp->esa[2], |
dp->esa[3], |
dp->esa[4], |
dp->esa[5] ); |
|
#ifdef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED |
cyg_drv_interrupt_create( |
dp->interrupt, |
0, // Priority - unused |
(cyg_addrword_t)dp,// Data item passed to ISR & DSR |
dp83902a_isr, // ISR |
dp83902a_dsr, // DSR |
&dp->interrupt_handle, // handle to intr obj |
&dp->interrupt_object ); // space for int obj |
|
cyg_drv_interrupt_attach(dp->interrupt_handle); |
cyg_drv_interrupt_unmask(dp->interrupt); |
#endif |
|
// Initialize upper level driver |
(sc->funs->eth_drv->init)(sc, dp->esa); |
|
return true; |
} |
|
static void |
dp83902a_stop(struct eth_drv_sc *sc) |
{ |
dp83902a_priv_data_t *dp = (dp83902a_priv_data_t *)sc->driver_private; |
cyg_uint8 *base = dp->base; |
|
DEBUG_FUNCTION(); |
|
CR_UP(); |
DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_STOP); // Brutal |
DP_OUT(base, DP_ISR, 0xFF); // Clear any pending interrupts |
DP_OUT(base, DP_IMR, 0x00); // Disable all interrupts |
CR_DOWN(); |
|
dp->running = false; |
} |
|
// |
// This function is called to "start up" the interface. It may be called |
// multiple times, even when the hardware is already running. It will be |
// called whenever something "hardware oriented" changes and should leave |
// the hardware ready to send/receive packets. |
// |
static void |
dp83902a_start(struct eth_drv_sc *sc, unsigned char *enaddr, int flags) |
{ |
dp83902a_priv_data_t *dp = (dp83902a_priv_data_t *)sc->driver_private; |
cyg_uint8 *base = dp->base; |
int i; |
|
DEBUG_FUNCTION(); |
|
CR_UP(); |
DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_STOP); // Brutal |
DP_OUT(base, DP_DCR, DP_DCR_INIT); |
DP_OUT(base, DP_RBCH, 0); // Remote byte count |
DP_OUT(base, DP_RBCL, 0); |
DP_OUT(base, DP_RCR, DP_RCR_MON); // Accept no packets |
DP_OUT(base, DP_TCR, DP_TCR_LOCAL); // Transmitter [virtually] off |
DP_OUT(base, DP_TPSR, dp->tx_buf1); // Transmitter start page |
dp->tx1 = dp->tx2 = 0; |
dp->tx_next = dp->tx_buf1; |
dp->tx_started = false; |
DP_OUT(base, DP_PSTART, dp->rx_buf_start); // Receive ring start page |
DP_OUT(base, DP_BNDRY, dp->rx_buf_end-1); // Receive ring boundary |
DP_OUT(base, DP_PSTOP, dp->rx_buf_end); // Receive ring end page |
dp->rx_next = dp->rx_buf_start-1; |
DP_OUT(base, DP_ISR, 0xFF); // Clear any pending interrupts |
DP_OUT(base, DP_IMR, DP_IMR_All); // Enable all interrupts |
DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE1); // Select page 1 |
DP_OUT(base, DP_P1_CURP, dp->rx_buf_start); // Current page - next free page for Rx |
for (i = 0; i < ETHER_ADDR_LEN; i++) { |
DP_OUT(base, DP_P1_PAR0+i, enaddr[i]); |
} |
// Enable and start device |
DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START); |
DP_OUT(base, DP_TCR, DP_TCR_NORMAL); // Normal transmit operations |
DP_OUT(base, DP_RCR, DP_RCR_AB); // Accept broadcast, no errors, no multicast |
dp->running = true; |
CR_DOWN(); |
} |
|
// |
// This routine is called to perform special "control" opertions |
// |
static int |
dp83902a_control(struct eth_drv_sc *sc, unsigned long key, |
void *data, int data_len) |
{ |
switch (key) { |
case ETH_DRV_SET_MAC_ADDRESS: |
return 0; |
break; |
default: |
return 1; |
break; |
} |
} |
|
// |
// This routine is called to see if it is possible to send another packet. |
// It will return non-zero if a transmit is possible, zero otherwise. |
// |
static int |
dp83902a_can_send(struct eth_drv_sc *sc) |
{ |
dp83902a_priv_data_t *dp = (dp83902a_priv_data_t *)sc->driver_private; |
|
DEBUG_FUNCTION(); |
|
return ((dp->tx1 == 0) || (dp->tx2 == 0)); |
} |
|
// |
// This routine is called to start the transmitter. It is split out from the |
// data handling routine so it may be called either when data becomes first |
// available or when an Tx interrupt occurs |
// |
|
static void |
dp83902a_start_xmit(struct eth_drv_sc *sc, int start_page, int len) |
{ |
dp83902a_priv_data_t *dp = (dp83902a_priv_data_t *)sc->driver_private; |
cyg_uint8 *base = dp->base; |
|
DEBUG_FUNCTION(); |
|
#if DEBUG & 1 |
diag_printf("Tx pkt %d len %d\n", start_page, len); |
if (dp->tx_started) |
diag_printf("TX already started?!?\n"); |
#endif |
|
CR_UP(); |
DP_OUT(base, DP_ISR, (DP_ISR_TxP | DP_ISR_TxE)); |
DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START); |
DP_OUT(base, DP_TBCL, len & 0xFF); |
DP_OUT(base, DP_TBCH, len >> 8); |
DP_OUT(base, DP_TPSR, start_page); |
DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_TXPKT | DP_CR_START); |
|
CR_DOWN(); |
dp->tx_started = true; |
} |
|
// |
// This routine is called to send data to the hardware. It is known a-priori |
// that there is free buffer space (dp->tx_next). |
// |
static void |
dp83902a_send(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len, |
int total_len, unsigned long key) |
{ |
struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *)sc->driver_private; |
cyg_uint8 *base = dp->base; |
int i, len, start_page, pkt_len; |
unsigned char *data; |
cyg_uint8 isr; |
#if DEBUG & 4 |
int dx; |
#endif |
|
DEBUG_FUNCTION(); |
|
pkt_len = total_len; |
if (pkt_len < IEEE_8023_MIN_FRAME) pkt_len = IEEE_8023_MIN_FRAME; |
#ifdef CYGHWR_NS_DP83902A_PLF_16BIT_DATA |
// Make length even when using 16 bit transfers |
if (pkt_len % 2) pkt_len++; |
#endif |
|
start_page = dp->tx_next; |
if (dp->tx_next == dp->tx_buf1) { |
dp->tx1 = start_page; |
dp->tx1_len = pkt_len; |
dp->tx1_key = key; |
dp->tx_next = dp->tx_buf2; |
} else { |
dp->tx2 = start_page; |
dp->tx2_len = pkt_len; |
dp->tx2_key = key; |
dp->tx_next = dp->tx_buf1; |
} |
CR_UP(); |
|
#if DEBUG & 5 |
diag_printf("TX prep page %d len %d\n", start_page, pkt_len); |
#endif |
|
DP_OUT(base, DP_ISR, DP_ISR_RDC); // Clear end of DMA |
{ |
// Dummy read. The manual sez something slightly different, |
// but the code is extended a bit to do what Hitachi's monitor |
// does (i.e., also read data). |
|
cyg_uint16 tmp; |
#ifdef CYGHWR_NS_DP83902A_PLF_16BIT_DATA |
int len = 2; |
#else |
int len = 1; |
#endif |
|
DP_OUT(base, DP_RSAL, 0x100-len); |
DP_OUT(base, DP_RSAH, (start_page-1) & 0xff); |
DP_OUT(base, DP_RBCL, len); |
DP_OUT(base, DP_RBCH, 0); |
DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_RDMA | DP_CR_START); |
DP_IN_DATA(dp->data, tmp); |
} |
|
#ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_TX_DMA |
// Stall for a bit before continuing to work around random data |
// corruption problems on some platforms. |
CYGACC_CALL_IF_DELAY_US(1); |
#endif |
|
// Send data to device buffer(s) |
DP_OUT(base, DP_RSAL, 0); |
DP_OUT(base, DP_RSAH, start_page); |
DP_OUT(base, DP_RBCL, pkt_len & 0xFF); |
DP_OUT(base, DP_RBCH, pkt_len >> 8); |
DP_OUT(base, DP_CR, DP_CR_WDMA | DP_CR_START); |
|
// Put data into buffer |
for (i = 0; i < sg_len; i++) { |
data = (unsigned char *)sg_list[i].buf; |
len = sg_list[i].len; |
#if DEBUG & 4 |
diag_printf(" sg buf %08x len %08x\n ", data, len); |
dx = 0; |
#endif |
while (len > 0) { |
#ifdef CYGHWR_NS_DP83902A_PLF_16BIT_DATA |
cyg_uint16 tmp; |
tmp = *data++ << 8; |
len -= 2; |
if (len >= 0) |
tmp |= *data++; |
DP_OUT_DATA(dp->data, tmp); |
#if DEBUG & 4 |
diag_printf(" %04x", tmp); |
if (0 == (++dx % 8)) diag_printf("\n "); |
#endif |
#else |
#if DEBUG & 4 |
diag_printf(" %02x", *data); |
if (0 == (++dx % 16)) diag_printf("\n "); |
#endif |
DP_OUT_DATA(dp->data, *data++); |
len--; |
#endif |
} |
#if DEBUG & 4 |
diag_printf("\n"); |
#endif |
} |
if (total_len < pkt_len) { |
#if DEBUG & 4 |
diag_printf(" + %d bytes of padding\n", pkt_len - total_len); |
#endif |
// Padding to 802.3 length was required |
for (i = total_len; i < pkt_len;) { |
#ifdef CYGHWR_NS_DP83902A_PLF_16BIT_DATA |
i += 2; |
#else |
i++; |
#endif |
DP_OUT_DATA(dp->data, 0); |
} |
} |
|
#ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_TX_DMA |
// After last data write, delay for a bit before accessing the |
// device again, or we may get random data corruption in the last |
// datum (on some platforms). |
CYGACC_CALL_IF_DELAY_US(1); |
#endif |
|
// Wait for DMA to complete |
do { |
DP_IN(base, DP_ISR, isr); |
} while ((isr & DP_ISR_RDC) == 0); |
// Then disable DMA |
DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START); |
CR_DOWN(); |
|
// Start transmit if not already going |
if (!dp->tx_started) { |
if (start_page == dp->tx1) { |
dp->tx_int = 1; // Expecting interrupt from BUF1 |
} else { |
dp->tx_int = 2; // Expecting interrupt from BUF2 |
} |
dp83902a_start_xmit(sc, start_page, pkt_len); |
} |
} |
|
// |
// This function is called when a packet has been received. It's job is |
// to prepare to unload the packet from the hardware. Once the length of |
// the packet is known, the upper layer of the driver can be told. When |
// the upper layer is ready to unload the packet, the internal function |
// 'dp83902a_recv' will be called to actually fetch it from the hardware. |
// |
static void |
dp83902a_RxEvent(struct eth_drv_sc *sc) |
{ |
struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *)sc->driver_private; |
cyg_uint8 *base = dp->base; |
unsigned char rsr; |
unsigned char rcv_hdr[4]; |
int i, len, pkt, cur; |
|
DEBUG_FUNCTION(); |
|
DP_IN(base, DP_RSR, rsr); |
while (true) { |
CR_UP(); |
// Read incoming packet header |
DP_OUT(base, DP_CR, DP_CR_PAGE1 | DP_CR_NODMA | DP_CR_START); |
DP_IN(base, DP_P1_CURP, cur); |
DP_OUT(base, DP_P1_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START); |
DP_IN(base, DP_BNDRY, pkt); |
pkt += 1; |
if (pkt == cur) { |
CR_DOWN(); |
break; |
} |
if (pkt == dp->rx_buf_end) pkt = dp->rx_buf_start; |
DP_OUT(base, DP_RBCL, sizeof(rcv_hdr)); |
DP_OUT(base, DP_RBCH, 0); |
DP_OUT(base, DP_RSAL, 0); |
DP_OUT(base, DP_RSAH, pkt); |
if (dp->rx_next == pkt) { |
DP_OUT(base, DP_BNDRY, cur-1); // Update pointer |
CR_DOWN(); |
return; |
} |
dp->rx_next = pkt; |
DP_OUT(base, DP_ISR, DP_ISR_RDC); // Clear end of DMA |
DP_OUT(base, DP_CR, DP_CR_RDMA | DP_CR_START); |
|
for (i = 0; i < sizeof(rcv_hdr);) { |
#ifdef CYGHWR_NS_DP83902A_PLF_16BIT_DATA |
cyg_uint16 tmp; |
DP_IN_DATA(dp->data, tmp); |
rcv_hdr[i++] = (tmp >> 8) & 0xff; |
rcv_hdr[i++] = tmp & 0xff; |
#else |
DP_IN_DATA(dp->data, rcv_hdr[i++]); |
#endif |
} |
CR_DOWN(); |
|
#if DEBUG & 5 |
diag_printf("rx hdr %02x %02x %02x %02x\n", |
rcv_hdr[0], rcv_hdr[1], rcv_hdr[2], rcv_hdr[3]); |
#endif |
len = ((rcv_hdr[3] << 8) | rcv_hdr[2]) - sizeof(rcv_hdr); |
(sc->funs->eth_drv->recv)(sc, len); |
DP_OUT(base, DP_BNDRY, rcv_hdr[1]-1); // Update pointer |
} |
} |
|
// |
// This function is called as a result of the "eth_drv_recv()" call above. |
// It's job is to actually fetch data for a packet from the hardware once |
// memory buffers have been allocated for the packet. Note that the buffers |
// may come in pieces, using a scatter-gather list. This allows for more |
// efficient processing in the upper layers of the stack. |
// |
static void |
dp83902a_recv(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len) |
{ |
struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *)sc->driver_private; |
cyg_uint8 *base = dp->base; |
int i, mlen, len; |
unsigned char *data; |
cyg_uint8 saved_char = 0; |
bool saved; |
#if DEBUG & 4 |
int dx; |
#endif |
|
DEBUG_FUNCTION(); |
|
// Compute total packet length |
len = 0; |
for (i = 0; i < sg_len; i++) { |
len += sg_list[i].len; |
} |
|
#if DEBUG & 5 |
diag_printf("Rx packet %d length %d\n", dp->rx_next, len); |
#endif |
|
CR_UP(); |
|
// Read incoming packet data |
DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START); |
DP_OUT(base, DP_RBCL, len & 0xFF); |
DP_OUT(base, DP_RBCH, len >> 8); |
DP_OUT(base, DP_RSAL, 4); // Past header |
DP_OUT(base, DP_RSAH, dp->rx_next); |
DP_OUT(base, DP_ISR, DP_ISR_RDC); // Clear end of DMA |
DP_OUT(base, DP_CR, DP_CR_RDMA | DP_CR_START); |
|
saved = false; |
for (i = 0; i < sg_len; i++) { |
data = (unsigned char *)sg_list[i].buf; |
if (data) { |
mlen = sg_list[i].len; |
#if DEBUG & 4 |
diag_printf(" sg buf %08x len %08x \n", data, mlen); |
dx = 0; |
#endif |
while (0 < mlen) { |
// Saved byte from previous loop? |
if (saved) { |
*data++ = saved_char; |
mlen--; |
saved = false; |
continue; |
} |
|
#ifdef CYGHWR_NS_DP83902A_PLF_16BIT_DATA |
{ |
cyg_uint16 tmp; |
DP_IN_DATA(dp->data, tmp); |
#if DEBUG & 4 |
diag_printf(" %04x", tmp); |
if (0 == (++dx % 8)) diag_printf("\n "); |
#endif |
*data++ = (tmp >> 8) & 0xff; |
mlen--; |
if (0 == mlen) { |
saved_char = tmp & 0xff; |
saved = true; |
} else { |
*data++ = tmp & 0xff; |
mlen--; |
} |
} |
#else |
{ |
cyg_uint8 tmp; |
DP_IN_DATA(dp->data, tmp); |
#if DEBUG & 4 |
diag_printf(" %02x", tmp); |
if (0 == (++dx % 16)) diag_printf("\n "); |
#endif |
*data++ = tmp;; |
mlen--; |
} |
#endif |
} |
#if DEBUG & 4 |
diag_printf("\n"); |
#endif |
} |
} |
CR_DOWN(); |
} |
|
static void |
dp83902a_TxEvent(struct eth_drv_sc *sc) |
{ |
struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *)sc->driver_private; |
cyg_uint8 *base = dp->base; |
unsigned char tsr; |
unsigned long key; |
|
DEBUG_FUNCTION(); |
|
DP_IN(base, DP_TSR, tsr); |
if (dp->tx_int == 1) { |
key = dp->tx1_key; |
dp->tx1 = 0; |
} else { |
key = dp->tx2_key; |
dp->tx2 = 0; |
} |
// Start next packet if one is ready |
dp->tx_started = false; |
if (dp->tx1) { |
dp83902a_start_xmit(sc, dp->tx1, dp->tx1_len); |
dp->tx_int = 1; |
} else if (dp->tx2) { |
dp83902a_start_xmit(sc, dp->tx2, dp->tx2_len); |
dp->tx_int = 2; |
} else { |
dp->tx_int = 0; |
} |
// Tell higher level we sent this packet |
(sc->funs->eth_drv->tx_done)(sc, key, 0); |
} |
|
// Read the tally counters to clear them. Called in response to a CNT |
// interrupt. |
static void |
dp83902a_ClearCounters(struct eth_drv_sc *sc) |
{ |
struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *)sc->driver_private; |
cyg_uint8 *base = dp->base; |
cyg_uint8 cnt1, cnt2, cnt3; |
|
DP_IN(base, DP_FER, cnt1); |
DP_IN(base, DP_CER, cnt2); |
DP_IN(base, DP_MISSED, cnt3); |
DP_OUT(base, DP_ISR, DP_ISR_CNT); |
} |
|
// Deal with an overflow condition. This code follows the procedure set |
// out in section 7.0 of the datasheet. |
static void |
dp83902a_Overflow(struct eth_drv_sc *sc) |
{ |
struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *)sc->driver_private; |
cyg_uint8 *base = dp->base; |
cyg_uint8 isr; |
|
// Issue a stop command and wait 1.6ms for it to complete. |
CR_UP(); |
DP_OUT(base, DP_CR, DP_CR_STOP | DP_CR_NODMA); |
CYGACC_CALL_IF_DELAY_US(1600); |
|
// Clear the remote byte counter registers. |
DP_OUT(base, DP_RBCL, 0); |
DP_OUT(base, DP_RBCH, 0); |
|
// Enter loopback mode while we clear the buffer. |
DP_OUT(base, DP_TCR, DP_TCR_LOCAL); |
DP_OUT(base, DP_CR, DP_CR_START | DP_CR_NODMA); |
CR_DOWN(); |
|
// Read in as many packets as we can and acknowledge any and receive |
// interrupts. Since the buffer has overflowed, a receive event of |
// some kind will have occured. |
dp83902a_RxEvent(sc); |
DP_OUT(base, DP_ISR, DP_ISR_RxP|DP_ISR_RxE); |
|
// Clear the overflow condition and leave loopback mode. |
DP_OUT(base, DP_ISR, DP_ISR_OFLW); |
DP_OUT(base, DP_TCR, DP_TCR_NORMAL); |
|
// If a transmit command was issued, but no transmit event has occured, |
// restart it here. |
DP_IN(base, DP_ISR, isr); |
if (dp->tx_started && !(isr & (DP_ISR_TxP|DP_ISR_TxE))) { |
CR_UP(); |
DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_TXPKT | DP_CR_START); |
CR_DOWN(); |
} |
} |
|
static void |
dp83902a_poll(struct eth_drv_sc *sc) |
{ |
struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *)sc->driver_private; |
cyg_uint8 *base = dp->base; |
unsigned char isr; |
|
// DEBUG_FUNCTION(); |
|
CR_UP(); |
DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE0 | DP_CR_START); |
CR_DOWN(); |
DP_IN(base, DP_ISR, isr); |
while (0 != isr) { |
// The CNT interrupt triggers when the MSB of one of the error |
// counters is set. We don't much care about these counters, but |
// we should read their values to reset them. |
if (isr & DP_ISR_CNT) { |
dp83902a_ClearCounters(sc); |
} |
// Check for overflow. It's a special case, since there's a |
// particular procedure that must be followed to get back into |
// a running state. |
if (isr & DP_ISR_OFLW) { |
dp83902a_Overflow(sc); |
} else { |
// Other kinds of interrupts can be acknowledged simply by |
// clearing the relevant bits of the ISR. Do that now, then |
// handle the interrupts we care about. |
DP_OUT(base, DP_ISR, isr); // Clear set bits |
if (!dp->running) break; // Is this necessary? |
// Check for tx_started on TX event since these may happen |
// spuriously it seems. |
if (isr & (DP_ISR_TxP|DP_ISR_TxE) && dp->tx_started) { |
dp83902a_TxEvent(sc); |
} |
if (isr & (DP_ISR_RxP|DP_ISR_RxE)) { |
dp83902a_RxEvent(sc); |
} |
} |
DP_IN(base, DP_ISR, isr); |
} |
|
CYGHWR_NS_DP83902A_PLF_INT_CLEAR(dp); |
} |
|
static int |
dp83902a_int_vector(struct eth_drv_sc *sc) |
{ |
struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *)sc->driver_private; |
return dp->interrupt; |
} |