Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
e3e33952
Commit
e3e33952
authored
Jun 25, 2003
by
Ralf Bächle
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[netdrvr] add driver "meth", for SGI O2 MACE fast eth
parent
6acd6bab
Changes
4
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
1140 additions
and
0 deletions
+1140
-0
drivers/net/Kconfig
drivers/net/Kconfig
+4
-0
drivers/net/Makefile
drivers/net/Makefile
+1
-0
drivers/net/meth.c
drivers/net/meth.c
+862
-0
drivers/net/meth.h
drivers/net/meth.h
+273
-0
No files found.
drivers/net/Kconfig
View file @
e3e33952
...
@@ -511,6 +511,10 @@ config SGI_IOC3_ETH
...
@@ -511,6 +511,10 @@ config SGI_IOC3_ETH
the Ethernet-HOWTO, available from
the Ethernet-HOWTO, available from
<http://www.tldp.org/docs.html#howto>.
<http://www.tldp.org/docs.html#howto>.
config SGI_O2MACE_ETH
tristate "SGI O2 MACE Fast Ethernet support"
depends on NET_ETHERNET && SGI_IP32=y
config STNIC
config STNIC
tristate "National DP83902AV support"
tristate "National DP83902AV support"
depends on NET_ETHERNET && SUPERH
depends on NET_ETHERNET && SUPERH
...
...
drivers/net/Makefile
View file @
e3e33952
...
@@ -117,6 +117,7 @@ obj-$(CONFIG_SUN3_82586) += sun3_82586.o
...
@@ -117,6 +117,7 @@ obj-$(CONFIG_SUN3_82586) += sun3_82586.o
obj-$(CONFIG_SUN3LANCE)
+=
sun3lance.o
obj-$(CONFIG_SUN3LANCE)
+=
sun3lance.o
obj-$(CONFIG_DEFXX)
+=
defxx.o
obj-$(CONFIG_DEFXX)
+=
defxx.o
obj-$(CONFIG_SGISEEQ)
+=
sgiseeq.o
obj-$(CONFIG_SGISEEQ)
+=
sgiseeq.o
obj-$(CONFIG_SGI_O2MACE_ETH)
+=
meth.o
obj-$(CONFIG_AT1700)
+=
at1700.o
obj-$(CONFIG_AT1700)
+=
at1700.o
obj-$(CONFIG_FMV18X)
+=
fmv18x.o
obj-$(CONFIG_FMV18X)
+=
fmv18x.o
obj-$(CONFIG_EL1)
+=
3c501.o
obj-$(CONFIG_EL1)
+=
3c501.o
...
...
drivers/net/meth.c
0 → 100644
View file @
e3e33952
/*
* meth.c -- O2 Builtin 10/100 Ethernet driver
*
* Copyright (C) 2001 Ilya Volynets
*
* This program 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 of the License, or (at your option) any later version.
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/kernel.h>
/* printk() */
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/errno.h>
/* error codes */
#include <linux/types.h>
/* size_t */
#include <linux/interrupt.h>
/* mark_bh */
#include <linux/pci.h>
#include <linux/in.h>
#include <linux/netdevice.h>
/* struct device, and other headers */
#include <linux/etherdevice.h>
/* eth_type_trans */
#include <linux/ip.h>
/* struct iphdr */
#include <linux/tcp.h>
/* struct tcphdr */
#include <linux/skbuff.h>
#include <linux/mii.h>
/*MII definitions */
#include <asm/ip32/crime.h>
#include <asm/ip32/mace.h>
#include <asm/ip32/ip32_ints.h>
#include "meth.h"
#include <linux/in6.h>
#include <asm/checksum.h>
#ifndef MFE_DEBUG
#define MFE_DEBUG 0
#endif
#if MFE_DEBUG>=1
#define DPRINTK(str,args...) printk (KERN_DEBUG "meth(%ld): %s: " str, jiffies, __FUNCTION__ , ## args)
#define MFE_RX_DEBUG 2
#else
#define DPRINTK(str,args...)
#define MFE_RX_DEBUG 0
#endif
static
const
char
*
version
=
"meth.c: Ilya Volynets (ilya@theIlya.com)"
;
static
const
char
*
meth_str
=
"SGI O2 Fast Ethernet"
;
MODULE_AUTHOR
(
"Ilya Volynets"
);
MODULE_DESCRIPTION
(
"SGI O2 Builtin Fast Ethernet driver"
);
/* This is a load-time options */
/*static int eth = 0;
MODULE_PARM(eth, "i");*/
#define HAVE_TX_TIMEOUT
/* The maximum time waited (in jiffies) before assuming a Tx failed. (400ms) */
#define TX_TIMEOUT (400*HZ/1000)
#ifdef HAVE_TX_TIMEOUT
static
int
timeout
=
TX_TIMEOUT
;
MODULE_PARM
(
timeout
,
"i"
);
#endif
int
meth_eth
;
/*
* This structure is private to each device. It is used to pass
* packets in and out, so there is place for a packet
*/
typedef
struct
meth_private
{
struct
net_device_stats
stats
;
volatile
struct
meth_regs
*
regs
;
u64
mode
;
/* in-memory copy of MAC control register */
int
phy_addr
;
/* address of phy, used by mdio_* functions, initialized in mdio_probe*/
tx_packet
*
tx_ring
;
dma_addr_t
tx_ring_dma
;
int
free_space
;
struct
sk_buff
*
tx_skbs
[
TX_RING_ENTRIES
];
dma_addr_t
tx_skb_dmas
[
TX_RING_ENTRIES
];
int
tx_read
,
tx_write
;
int
tx_count
;
rx_packet
*
rx_ring
[
RX_RING_ENTRIES
];
dma_addr_t
rx_ring_dmas
[
RX_RING_ENTRIES
];
int
rx_write
;
spinlock_t
meth_lock
;
}
meth_private
;
extern
struct
net_device
meth_devs
[];
void
meth_tx_timeout
(
struct
net_device
*
dev
);
void
meth_interrupt
(
int
irq
,
void
*
dev_id
,
struct
pt_regs
*
pregs
);
/* global, initialized in ip32-setup.c */
char
o2meth_eaddr
[
8
]
=
{
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
};
static
inline
void
load_eaddr
(
struct
net_device
*
dev
,
volatile
struct
meth_regs
*
regs
)
{
int
i
;
DPRINTK
(
"Loading MAC Address: %02x:%02x:%02x:%02x:%02x:%02x
\n
"
,
(
int
)
o2meth_eaddr
[
0
]
&
0xFF
,(
int
)
o2meth_eaddr
[
1
]
&
0xFF
,(
int
)
o2meth_eaddr
[
2
]
&
0xFF
,
(
int
)
o2meth_eaddr
[
3
]
&
0xFF
,(
int
)
o2meth_eaddr
[
4
]
&
0xFF
,(
int
)
o2meth_eaddr
[
5
]
&
0xFF
);
//memcpy(dev->dev_addr,o2meth_eaddr+2,6);
for
(
i
=
0
;
i
<
6
;
i
++
)
dev
->
dev_addr
[
i
]
=
o2meth_eaddr
[
i
];
regs
->
mac_addr
=
//dev->dev_addr[0]|(dev->dev_addr[1]<<8)|
//dev->dev_addr[2]<<16|(dev->dev_addr[3]<<24)|
//dev->dev_addr[4]<<32|(dev->dev_addr[5]<<40);
(
*
(
u64
*
)
o2meth_eaddr
)
>>
16
;
DPRINTK
(
"MAC, finally is %0lx
\n
"
,
regs
->
mac_addr
);
}
/*
*Waits for BUSY status of mdio bus to clear
*/
#define WAIT_FOR_PHY(___regs, ___rval) \
while((___rval=___regs->phy_data)&MDIO_BUSY){ \
udelay(25); \
}
/*read phy register, return value read */
static
int
mdio_read
(
meth_private
*
priv
,
int
phyreg
)
{
volatile
meth_regs
*
regs
=
priv
->
regs
;
volatile
u32
rval
;
WAIT_FOR_PHY
(
regs
,
rval
)
regs
->
phy_registers
=
(
priv
->
phy_addr
<<
5
)
|
(
phyreg
&
0x1f
);
udelay
(
25
);
regs
->
phy_trans_go
=
1
;
udelay
(
25
);
WAIT_FOR_PHY
(
regs
,
rval
)
return
rval
&
MDIO_DATA_MASK
;
}
/*write phy register */
static
void
mdio_write
(
meth_private
*
priv
,
int
pfyreg
,
int
val
)
{
volatile
meth_regs
*
regs
=
priv
->
regs
;
int
rval
;
/// DPRINTK("Trying to write value %i to reguster %i\n",val, pfyreg);
spin_lock_irq
(
&
priv
->
meth_lock
);
WAIT_FOR_PHY
(
regs
,
rval
)
regs
->
phy_registers
=
(
priv
->
phy_addr
<<
5
)
|
(
pfyreg
&
0x1f
);
regs
->
phy_data
=
val
;
udelay
(
25
);
WAIT_FOR_PHY
(
regs
,
rval
)
spin_unlock_irq
(
&
priv
->
meth_lock
);
}
/* Modify phy register using given mask and value */
static
void
mdio_update
(
meth_private
*
priv
,
int
phyreg
,
int
val
,
int
mask
)
{
int
rval
;
DPRINTK
(
"RMW value %i to PHY register %i with mask %i
\n
"
,
val
,
phyreg
,
mask
);
rval
=
mdio_read
(
priv
,
phyreg
);
rval
=
(
rval
&~
mask
)
|
(
val
&
mask
);
mdio_write
(
priv
,
phyreg
,
rval
);
}
/* handle errata data on MDIO bus */
//static void mdio_errata(meth_private *priv)
//{
/* Hmmm... what the hell is phyerrata? does it come from sys init parameters in IRIX */
//}
static
int
mdio_probe
(
meth_private
*
priv
)
{
int
i
,
p2
,
p3
;
DPRINTK
(
"Detecting PHY kind
\n
"
);
/* check if phy is detected already */
if
(
priv
->
phy_addr
>=
0
&&
priv
->
phy_addr
<
32
)
return
0
;
spin_lock_irq
(
&
priv
->
meth_lock
);
for
(
i
=
0
;
i
<
32
;
++
i
){
priv
->
phy_addr
=
(
char
)
i
;
p2
=
mdio_read
(
priv
,
2
);
#ifdef MFE_DEBUG
p3
=
mdio_read
(
priv
,
3
);
switch
((
p2
<<
12
)
|
(
p3
>>
4
)){
case
PHY_QS6612X
:
DPRINTK
(
"PHY is QS6612X
\n
"
);
break
;
case
PHY_ICS1889
:
DPRINTK
(
"PHY is ICS1889
\n
"
);
break
;
case
PHY_ICS1890
:
DPRINTK
(
"PHY is ICS1890
\n
"
);
break
;
case
PHY_DP83840
:
DPRINTK
(
"PHY is DP83840
\n
"
);
break
;
}
#endif
if
(
p2
!=
0xffff
&&
p2
!=
0x0000
){
DPRINTK
(
"PHY code: %x
\n
"
,(
p2
<<
12
)
|
(
p3
>>
4
));
break
;
}
}
spin_unlock_irq
(
&
priv
->
meth_lock
);
if
(
priv
->
phy_addr
<
32
)
{
return
0
;
}
DPRINTK
(
"Oopsie! PHY is not known!
\n
"
);
priv
->
phy_addr
=-
1
;
return
-
ENODEV
;
}
static
void
meth_check_link
(
struct
net_device
*
dev
)
{
struct
meth_private
*
priv
=
(
struct
meth_private
*
)
dev
->
priv
;
int
mii_partner
=
mdio_read
(
priv
,
5
);
int
mii_advertising
=
mdio_read
(
priv
,
4
);
int
negotiated
=
mii_advertising
&
mii_partner
;
int
duplex
,
speed
;
if
(
mii_partner
==
0xffff
)
return
;
duplex
=
((
negotiated
&
0x0100
)
||
(
negotiated
&
0x01C0
)
==
0x0040
)
?
METH_PHY_FDX
:
0
;
speed
=
(
negotiated
&
0x0380
)
?
METH_100MBIT
:
0
;
if
((
priv
->
mode
&
METH_PHY_FDX
)
^
duplex
)
{
DPRINTK
(
"Setting %s-duplex
\n
"
,
duplex
?
"full"
:
"half"
);
if
(
duplex
)
priv
->
mode
|=
METH_PHY_FDX
;
else
priv
->
mode
&=
~
METH_PHY_FDX
;
priv
->
regs
->
mac_ctrl
=
priv
->
mode
;
}
if
((
priv
->
mode
&
METH_100MBIT
)
^
speed
)
{
DPRINTK
(
"Setting %dMbs mode
\n
"
,
speed
?
100
:
10
);
if
(
duplex
)
priv
->
mode
|=
METH_100MBIT
;
else
priv
->
mode
&=
~
METH_100MBIT
;
priv
->
regs
->
mac_ctrl
=
priv
->
mode
;
}
}
static
int
meth_init_tx_ring
(
meth_private
*
priv
)
{
/* Init TX ring */
DPRINTK
(
"Initializing TX ring
\n
"
);
priv
->
tx_ring
=
(
tx_packet
*
)
pci_alloc_consistent
(
NULL
,
TX_RING_BUFFER_SIZE
,
&
(
priv
->
tx_ring_dma
));
if
(
!
priv
->
tx_ring
)
return
-
ENOMEM
;
memset
(
priv
->
tx_ring
,
0
,
TX_RING_BUFFER_SIZE
);
priv
->
tx_count
=
priv
->
tx_read
=
priv
->
tx_write
=
0
;
priv
->
regs
->
tx_ring_base
=
priv
->
tx_ring_dma
;
priv
->
free_space
=
TX_RING_ENTRIES
;
/* Now init skb save area */
memset
(
priv
->
tx_skbs
,
0
,
sizeof
(
priv
->
tx_skbs
));
memset
(
priv
->
tx_skb_dmas
,
0
,
sizeof
(
priv
->
tx_skb_dmas
));
DPRINTK
(
"Done with TX ring init
\n
"
);
return
0
;
}
static
int
meth_init_rx_ring
(
meth_private
*
priv
)
{
int
i
;
DPRINTK
(
"Initializing RX ring
\n
"
);
for
(
i
=
0
;
i
<
RX_RING_ENTRIES
;
i
++
){
DPRINTK
(
"
\t
1:
\t
%i
\t
"
,
i
);
/*if(!(priv->rx_ring[i]=get_free_page(GFP_KERNEL)))
return -ENOMEM;
DPRINTK("\t2:\t%i\n",i);*/
priv
->
rx_ring
[
i
]
=
(
rx_packet
*
)
pci_alloc_consistent
(
NULL
,
METH_RX_BUFF_SIZE
,
&
(
priv
->
rx_ring_dmas
[
i
]));
/* I'll need to re-sync it after each RX */
DPRINTK
(
"
\t
%p
\n
"
,
priv
->
rx_ring
[
i
]);
priv
->
regs
->
rx_fifo
=
priv
->
rx_ring_dmas
[
i
];
}
priv
->
rx_write
=
0
;
DPRINTK
(
"Done with RX ring
\n
"
);
return
0
;
}
static
void
meth_free_tx_ring
(
meth_private
*
priv
)
{
int
i
;
/* Remove any pending skb */
for
(
i
=
0
;
i
<
TX_RING_ENTRIES
;
i
++
)
{
if
(
priv
->
tx_skbs
[
i
])
dev_kfree_skb
(
priv
->
tx_skbs
[
i
]);
priv
->
tx_skbs
[
i
]
=
NULL
;
}
pci_free_consistent
(
NULL
,
TX_RING_BUFFER_SIZE
,
priv
->
tx_ring
,
priv
->
tx_ring_dma
);
}
static
void
meth_free_rx_ring
(
meth_private
*
priv
)
{
int
i
;
for
(
i
=
0
;
i
<
RX_RING_ENTRIES
;
i
++
)
pci_free_consistent
(
NULL
,
METH_RX_BUFF_SIZE
,
priv
->
rx_ring
[
i
],
priv
->
rx_ring_dmas
[
i
]);
}
int
meth_reset
(
struct
net_device
*
dev
)
{
struct
meth_private
*
priv
=
(
struct
meth_private
*
)
dev
->
priv
;
/* Reset card */
priv
->
regs
->
mac_ctrl
=
SGI_MAC_RESET
;
priv
->
regs
->
mac_ctrl
=
0
;
udelay
(
25
);
DPRINTK
(
"MAC control after reset: %016lx
\n
"
,
priv
->
regs
->
mac_ctrl
);
/* Load ethernet address */
load_eaddr
(
dev
,
priv
->
regs
);
/* Should load some "errata", but later */
/* Check for device */
if
(
mdio_probe
(
priv
)
<
0
)
{
DPRINTK
(
"Unable to find PHY
\n
"
);
return
-
ENODEV
;
}
/* Initial mode -- 10|Half-duplex|Accept normal packets */
priv
->
mode
=
METH_ACCEPT_MCAST
|
METH_DEFAULT_IPG
;
if
(
dev
->
flags
|
IFF_PROMISC
)
priv
->
mode
|=
METH_PROMISC
;
priv
->
regs
->
mac_ctrl
=
priv
->
mode
;
/* Autonegociate speed and duplex mode */
meth_check_link
(
dev
);
/* Now set dma control, but don't enable DMA, yet */
priv
->
regs
->
dma_ctrl
=
(
4
<<
METH_RX_OFFSET_SHIFT
)
|
(
RX_RING_ENTRIES
<<
METH_RX_DEPTH_SHIFT
);
return
(
0
);
}
/*============End Helper Routines=====================*/
/*
* Open and close
*/
int
meth_open
(
struct
net_device
*
dev
)
{
meth_private
*
priv
=
dev
->
priv
;
volatile
meth_regs
*
regs
=
priv
->
regs
;
MOD_INC_USE_COUNT
;
/* Start DMA */
regs
->
dma_ctrl
|=
METH_DMA_TX_EN
|
/*METH_DMA_TX_INT_EN|*/
METH_DMA_RX_EN
|
METH_DMA_RX_INT_EN
;
if
(
request_irq
(
dev
->
irq
,
meth_interrupt
,
SA_SHIRQ
,
meth_str
,
dev
)){
printk
(
KERN_ERR
"%s: Can't get irq %d
\n
"
,
dev
->
name
,
dev
->
irq
);
return
-
EAGAIN
;
}
netif_start_queue
(
dev
);
DPRINTK
(
"Opened... DMA control=0x%08lx
\n
"
,
regs
->
dma_ctrl
);
return
0
;
}
int
meth_release
(
struct
net_device
*
dev
)
{
netif_stop_queue
(
dev
);
/* can't transmit any more */
/* shut down dma */
((
meth_private
*
)(
dev
->
priv
))
->
regs
->
dma_ctrl
&=
~
(
METH_DMA_TX_EN
|
METH_DMA_TX_INT_EN
|
METH_DMA_RX_EN
|
METH_DMA_RX_INT_EN
);
free_irq
(
dev
->
irq
,
dev
);
MOD_DEC_USE_COUNT
;
return
0
;
}
/*
* Configuration changes (passed on by ifconfig)
*/
int
meth_config
(
struct
net_device
*
dev
,
struct
ifmap
*
map
)
{
if
(
dev
->
flags
&
IFF_UP
)
/* can't act on a running interface */
return
-
EBUSY
;
/* Don't allow changing the I/O address */
if
(
map
->
base_addr
!=
dev
->
base_addr
)
{
printk
(
KERN_WARNING
"meth: Can't change I/O address
\n
"
);
return
-
EOPNOTSUPP
;
}
/* Allow changing the IRQ */
if
(
map
->
irq
!=
dev
->
irq
)
{
printk
(
KERN_WARNING
"meth: Can't change IRQ
\n
"
);
return
-
EOPNOTSUPP
;
}
DPRINTK
(
"Configured
\n
"
);
/* ignore other fields */
return
0
;
}
/*
* Receive a packet: retrieve, encapsulate and pass over to upper levels
*/
void
meth_rx
(
struct
net_device
*
dev
)
{
struct
sk_buff
*
skb
;
struct
meth_private
*
priv
=
(
struct
meth_private
*
)
dev
->
priv
;
rx_packet
*
rxb
;
DPRINTK
(
"RX...
\n
"
);
// TEMP while((rxb=priv->rx_ring[priv->rx_write])->status.raw&0x8000000000000000){
while
((
rxb
=
priv
->
rx_ring
[
priv
->
rx_write
])
->
status
.
raw
&
0x8000000000000000
){
int
len
=
rxb
->
status
.
parsed
.
rx_len
-
4
;
/* omit CRC */
DPRINTK
(
"(%i)
\n
"
,
priv
->
rx_write
);
/* length sanity check */
if
(
len
<
60
||
len
>
1518
)
{
printk
(
KERN_DEBUG
"%s: bogus packet size: %d, status=%#2x.
\n
"
,
dev
->
name
,
priv
->
rx_write
,
rxb
->
status
.
raw
);
priv
->
stats
.
rx_errors
++
;
priv
->
stats
.
rx_length_errors
++
;
}
if
(
!
(
rxb
->
status
.
raw
&
METH_RX_STATUS_ERRORS
)){
skb
=
alloc_skb
(
len
+
2
,
GFP_ATOMIC
);
/* Should be atomic -- we are in interrupt */
if
(
!
skb
){
/* Ouch! No memory! Drop packet on the floor */
DPRINTK
(
"!!!>>>Ouch! Not enough Memory for RX buffer!
\n
"
);
priv
->
stats
.
rx_dropped
++
;
}
else
{
skb_reserve
(
skb
,
2
);
/* align IP on 16B boundary */
memcpy
(
skb_put
(
skb
,
len
),
rxb
->
buf
,
len
);
/* Write metadata, and then pass to the receive level */
skb
->
dev
=
dev
;
skb
->
protocol
=
eth_type_trans
(
skb
,
dev
);
//skb->ip_summed = CHECKSUM_UNNECESSARY; /* don't check it */
DPRINTK
(
"passing packet
\n
"
);
DPRINTK
(
"len = %d rxb->status = %x
\n
"
,
len
,
rxb
->
status
.
raw
);
netif_rx
(
skb
);
dev
->
last_rx
=
jiffies
;
priv
->
stats
.
rx_packets
++
;
priv
->
stats
.
rx_bytes
+=
len
;
DPRINTK
(
"There we go... Whew...
\n
"
);
}
}
priv
->
regs
->
rx_fifo
=
priv
->
rx_ring_dmas
[
priv
->
rx_write
];
rxb
->
status
.
raw
=
0
;
priv
->
rx_write
=
(
priv
->
rx_write
+
1
)
&
(
RX_RING_ENTRIES
-
1
);
}
}
static
int
meth_tx_full
(
struct
net_device
*
dev
)
{
struct
meth_private
*
priv
=
(
struct
meth_private
*
)
dev
->
priv
;
return
(
priv
->
tx_count
>=
TX_RING_ENTRIES
-
1
);
}
void
meth_tx_cleanup
(
struct
net_device
*
dev
,
int
rptr
)
{
meth_private
*
priv
=
dev
->
priv
;
tx_packet
*
status
;
struct
sk_buff
*
skb
;
spin_lock
(
&
priv
->
meth_lock
);
/* Stop DMA */
priv
->
regs
->
dma_ctrl
&=
~
(
METH_DMA_TX_INT_EN
);
while
(
priv
->
tx_read
!=
rptr
){
skb
=
priv
->
tx_skbs
[
priv
->
tx_read
];
status
=
&
priv
->
tx_ring
[
priv
->
tx_read
];
if
(
!
status
->
header
.
res
.
sent
)
break
;
if
(
status
->
header
.
raw
&
METH_TX_STATUS_DONE
)
{
priv
->
stats
.
tx_packets
++
;
priv
->
stats
.
tx_bytes
+=
skb
->
len
;
}
dev_kfree_skb_irq
(
skb
);
priv
->
tx_skbs
[
priv
->
tx_read
]
=
NULL
;
status
->
header
.
raw
=
0
;
priv
->
tx_read
=
(
priv
->
tx_read
+
1
)
&
(
TX_RING_ENTRIES
-
1
);
priv
->
tx_count
--
;
}
/* wake up queue if it was stopped */
if
(
netif_queue_stopped
(
dev
)
&&
!
meth_tx_full
(
dev
))
{
netif_wake_queue
(
dev
);
}
spin_unlock
(
priv
->
meth_lock
);
}
/*
* The typical interrupt entry point
*/
void
meth_interrupt
(
int
irq
,
void
*
dev_id
,
struct
pt_regs
*
pregs
)
{
struct
meth_private
*
priv
;
union
{
u32
reg
;
/*Whole status register */
struct
{
u32
:
2
,
rx_seq
:
5
,
tx_read
:
9
,
rx_read
:
8
,
int_mask:
8
;
}
parsed
;
}
status
;
/*
* As usual, check the "device" pointer for shared handlers.
* Then assign "struct device *dev"
*/
struct
net_device
*
dev
=
(
struct
net_device
*
)
dev_id
;
/* ... and check with hw if it's really ours */
if
(
!
dev
/*paranoid*/
)
return
;
/* Lock the device */
priv
=
(
struct
meth_private
*
)
dev
->
priv
;
status
.
reg
=
priv
->
regs
->
int_flags
;
DPRINTK
(
"Interrupt, status %08x...
\n
"
,
status
.
reg
);
if
(
status
.
parsed
.
int_mask
&
METH_INT_RX_THRESHOLD
)
{
/* send it to meth_rx for handling */
meth_rx
(
dev
);
}
if
(
status
.
parsed
.
int_mask
&
(
METH_INT_TX_EMPTY
|
METH_INT_TX_PKT
))
{
/* a transmission is over: free the skb */
meth_tx_cleanup
(
dev
,
status
.
parsed
.
tx_read
);
}
/* check for errors too... */
if
(
status
.
parsed
.
int_mask
&
(
METH_INT_TX_LINK_FAIL
))
printk
(
KERN_WARNING
"meth: link failure
\n
"
);
if
(
status
.
parsed
.
int_mask
&
(
METH_INT_MEM_ERROR
))
printk
(
KERN_WARNING
"meth: memory error
\n
"
);
if
(
status
.
parsed
.
int_mask
&
(
METH_INT_TX_ABORT
))
printk
(
KERN_WARNING
"meth: aborted
\n
"
);
DPRINTK
(
"Interrupt handling done...
\n
"
);
priv
->
regs
->
int_flags
=
status
.
reg
&
0xff
;
/* clear interrupts */
}
/*
* Transmits packets that fit into TX descriptor (are <=120B)
*/
static
void
meth_tx_short_prepare
(
meth_private
*
priv
,
struct
sk_buff
*
skb
)
{
tx_packet
*
desc
=&
priv
->
tx_ring
[
priv
->
tx_write
];
int
len
=
(
skb
->
len
<
ETH_ZLEN
)
?
ETH_ZLEN
:
skb
->
len
;
DPRINTK
(
"preparing short packet
\n
"
);
/* maybe I should set whole thing to 0 first... */
memcpy
(
desc
->
data
.
dt
+
(
120
-
len
),
skb
->
data
,
skb
->
len
);
if
(
skb
->
len
<
len
)
memset
(
desc
->
data
.
dt
+
120
-
len
+
skb
->
len
,
0
,
len
-
skb
->
len
);
desc
->
header
.
raw
=
METH_TX_CMD_INT_EN
|
(
len
-
1
)
|
((
128
-
len
)
<<
16
);
DPRINTK
(
"desc=%016lx
\n
"
,
desc
->
header
.
raw
);
}
#define TX_CATBUF1 BIT(25)
static
void
meth_tx_1page_prepare
(
meth_private
*
priv
,
struct
sk_buff
*
skb
)
{
tx_packet
*
desc
=&
priv
->
tx_ring
[
priv
->
tx_write
];
void
*
buffer_data
=
(
void
*
)(((
u64
)
skb
->
data
+
7ULL
)
&
(
~
7ULL
));
int
unaligned_len
=
(
int
)((
u64
)
buffer_data
-
(
u64
)
skb
->
data
);
int
buffer_len
=
skb
->
len
-
unaligned_len
;
dma_addr_t
catbuf
;
DPRINTK
(
"preparing 1 page...
\n
"
);
DPRINTK
(
"length=%d data=%p
\n
"
,
skb
->
len
,
skb
->
data
);
DPRINTK
(
"unaligned_len=%d
\n
"
,
unaligned_len
);
DPRINTK
(
"buffer_data=%p buffer_len=%d
\n
"
,
buffer_data
,
buffer_len
);
desc
->
header
.
raw
=
METH_TX_CMD_INT_EN
|
TX_CATBUF1
|
(
skb
->
len
-
1
);
/* unaligned part */
if
(
unaligned_len
){
memcpy
(
desc
->
data
.
dt
+
(
120
-
unaligned_len
),
skb
->
data
,
unaligned_len
);
desc
->
header
.
raw
|=
(
128
-
unaligned_len
)
<<
16
;
}
/* first page */
catbuf
=
pci_map_single
(
NULL
,
buffer_data
,
buffer_len
,
PCI_DMA_TODEVICE
);
DPRINTK
(
"catbuf=%x
\n
"
,
catbuf
);
desc
->
data
.
cat_buf
[
0
].
form
.
start_addr
=
catbuf
>>
3
;
desc
->
data
.
cat_buf
[
0
].
form
.
len
=
buffer_len
-
1
;
DPRINTK
(
"desc=%016lx
\n
"
,
desc
->
header
.
raw
);
DPRINTK
(
"cat_buf[0].raw=%016lx
\n
"
,
desc
->
data
.
cat_buf
[
0
].
raw
);
}
#define TX_CATBUF2 BIT(26)
static
void
meth_tx_2page_prepare
(
meth_private
*
priv
,
struct
sk_buff
*
skb
)
{
tx_packet
*
desc
=&
priv
->
tx_ring
[
priv
->
tx_write
];
void
*
buffer1_data
=
(
void
*
)(((
u64
)
skb
->
data
+
7ULL
)
&
(
~
7ULL
));
void
*
buffer2_data
=
(
void
*
)
PAGE_ALIGN
((
u64
)
skb
->
data
);
int
unaligned_len
=
(
int
)((
u64
)
buffer1_data
-
(
u64
)
skb
->
data
);
int
buffer1_len
=
(
int
)((
u64
)
buffer2_data
-
(
u64
)
buffer1_data
);
int
buffer2_len
=
skb
->
len
-
buffer1_len
-
unaligned_len
;
dma_addr_t
catbuf1
,
catbuf2
;
DPRINTK
(
"preparing 2 pages...
\n
"
);
DPRINTK
(
"length=%d data=%p
\n
"
,
skb
->
len
,
skb
->
data
);
DPRINTK
(
"unaligned_len=%d
\n
"
,
unaligned_len
);
DPRINTK
(
"buffer1_data=%p buffer1_len=%d
\n
"
,
buffer1_data
,
buffer1_len
);
DPRINTK
(
"buffer2_data=%p buffer2_len=%d
\n
"
,
buffer2_data
,
buffer2_len
);
desc
->
header
.
raw
=
METH_TX_CMD_INT_EN
|
TX_CATBUF1
|
TX_CATBUF2
|
(
skb
->
len
-
1
);
/* unaligned part */
if
(
unaligned_len
){
memcpy
(
desc
->
data
.
dt
+
(
120
-
unaligned_len
),
skb
->
data
,
unaligned_len
);
desc
->
header
.
raw
|=
(
128
-
unaligned_len
)
<<
16
;
}
/* first page */
catbuf1
=
pci_map_single
(
NULL
,
buffer1_data
,
buffer1_len
,
PCI_DMA_TODEVICE
);
DPRINTK
(
"catbuf1=%x
\n
"
,
catbuf1
);
desc
->
data
.
cat_buf
[
0
].
form
.
start_addr
=
catbuf1
>>
3
;
desc
->
data
.
cat_buf
[
0
].
form
.
len
=
buffer1_len
-
1
;
/* second page */
catbuf2
=
pci_map_single
(
NULL
,
buffer2_data
,
buffer2_len
,
PCI_DMA_TODEVICE
);
DPRINTK
(
"catbuf2=%x
\n
"
,
catbuf2
);
desc
->
data
.
cat_buf
[
1
].
form
.
start_addr
=
catbuf2
>>
3
;
desc
->
data
.
cat_buf
[
1
].
form
.
len
=
buffer2_len
-
1
;
DPRINTK
(
"desc=%016lx
\n
"
,
desc
->
header
.
raw
);
DPRINTK
(
"cat_buf[0].raw=%016lx
\n
"
,
desc
->
data
.
cat_buf
[
0
].
raw
);
DPRINTK
(
"cat_buf[1].raw=%016lx
\n
"
,
desc
->
data
.
cat_buf
[
1
].
raw
);
}
void
meth_add_to_tx_ring
(
meth_private
*
priv
,
struct
sk_buff
*
skb
)
{
DPRINTK
(
"Transmitting data...
\n
"
);
if
(
skb
->
len
<=
120
)
{
/* Whole packet fits into descriptor */
meth_tx_short_prepare
(
priv
,
skb
);
}
else
if
(
PAGE_ALIGN
((
u64
)
skb
->
data
)
!=
PAGE_ALIGN
((
u64
)
skb
->
data
+
skb
->
len
-
1
))
{
/* Packet crosses page boundary */
meth_tx_2page_prepare
(
priv
,
skb
);
}
else
{
/* Packet is in one page */
meth_tx_1page_prepare
(
priv
,
skb
);
}
/* Remember the skb, so we can free it at interrupt time */
priv
->
tx_skbs
[
priv
->
tx_write
]
=
skb
;
priv
->
tx_write
=
(
priv
->
tx_write
+
1
)
&
(
TX_RING_ENTRIES
-
1
);
priv
->
regs
->
tx_info
.
wptr
=
priv
->
tx_write
;
priv
->
tx_count
++
;
/* Enable DMA transfer */
priv
->
regs
->
dma_ctrl
|=
METH_DMA_TX_INT_EN
;
}
/*
* Transmit a packet (called by the kernel)
*/
int
meth_tx
(
struct
sk_buff
*
skb
,
struct
net_device
*
dev
)
{
struct
meth_private
*
priv
=
(
struct
meth_private
*
)
dev
->
priv
;
spin_lock_irq
(
&
priv
->
meth_lock
);
meth_add_to_tx_ring
(
priv
,
skb
);
dev
->
trans_start
=
jiffies
;
/* save the timestamp */
/* If TX ring is full, tell the upper layer to stop sending packets */
if
(
meth_tx_full
(
dev
))
{
DPRINTK
(
"TX full: stopping
\n
"
);
netif_stop_queue
(
dev
);
}
spin_unlock_irq
(
&
priv
->
meth_lock
);
return
0
;
}
/*
* Deal with a transmit timeout.
*/
void
meth_tx_timeout
(
struct
net_device
*
dev
)
{
struct
meth_private
*
priv
=
(
struct
meth_private
*
)
dev
->
priv
;
printk
(
KERN_WARNING
"%s: transmit timed out
\n
"
,
dev
->
name
);
/* Protect against concurrent rx interrupts */
spin_lock_irq
(
&
priv
->
meth_lock
);
/* Try to reset the adaptor. */
meth_reset
(
dev
);
priv
->
stats
.
tx_errors
++
;
/* Clear all rings */
meth_free_tx_ring
(
priv
);
meth_free_rx_ring
(
priv
);
meth_init_tx_ring
(
priv
);
meth_init_rx_ring
(
priv
);
/* Restart dma */
priv
->
regs
->
dma_ctrl
|=
METH_DMA_TX_EN
|
METH_DMA_RX_EN
|
METH_DMA_RX_INT_EN
;
/* Enable interrupt */
spin_unlock_irq
(
&
priv
->
meth_lock
);
dev
->
trans_start
=
jiffies
;
netif_wake_queue
(
dev
);
return
;
}
/*
* Ioctl commands
*/
int
meth_ioctl
(
struct
net_device
*
dev
,
struct
ifreq
*
rq
,
int
cmd
)
{
DPRINTK
(
"ioctl
\n
"
);
return
0
;
}
/*
* Return statistics to the caller
*/
struct
net_device_stats
*
meth_stats
(
struct
net_device
*
dev
)
{
struct
meth_private
*
priv
=
(
struct
meth_private
*
)
dev
->
priv
;
return
&
priv
->
stats
;
}
/*
* The init function (sometimes called probe).
* It is invoked by register_netdev()
*/
int
meth_init
(
struct
net_device
*
dev
)
{
meth_private
*
priv
;
int
ret
;
/*
* Then, assign other fields in dev, using ether_setup() and some
* hand assignments
*/
ether_setup
(
dev
);
/* assign some of the fields */
dev
->
open
=
meth_open
;
dev
->
stop
=
meth_release
;
dev
->
set_config
=
meth_config
;
dev
->
hard_start_xmit
=
meth_tx
;
dev
->
do_ioctl
=
meth_ioctl
;
dev
->
get_stats
=
meth_stats
;
#ifdef HAVE_TX_TIMEOUT
dev
->
tx_timeout
=
meth_tx_timeout
;
dev
->
watchdog_timeo
=
timeout
;
#endif
dev
->
irq
=
MACE_ETHERNET_IRQ
;
SET_MODULE_OWNER
(
dev
);
/*
* Then, allocate the priv field. This encloses the statistics
* and a few private fields.
*/
priv
=
kmalloc
(
sizeof
(
struct
meth_private
),
GFP_KERNEL
);
if
(
priv
==
NULL
)
return
-
ENOMEM
;
dev
->
priv
=
priv
;
memset
(
priv
,
0
,
sizeof
(
struct
meth_private
));
spin_lock_init
(
&
((
struct
meth_private
*
)
dev
->
priv
)
->
meth_lock
);
/*
* Make the usual checks: check_region(), probe irq, ... -ENODEV
* should be returned if no device found. No resource should be
* grabbed: this is done on open().
*/
priv
->
regs
=
(
meth_regs
*
)
SGI_MFE
;
dev
->
base_addr
=
SGI_MFE
;
priv
->
phy_addr
=
-
1
;
/* No phy is known yet... */
/* Initialize the hardware */
if
((
ret
=
meth_reset
(
dev
))
<
0
)
return
ret
;
/* Allocate the ring buffers */
if
((
ret
=
meth_init_tx_ring
(
priv
))
<
0
||
(
ret
=
meth_init_rx_ring
(
priv
))
<
0
){
meth_free_tx_ring
(
priv
);
meth_free_rx_ring
(
priv
);
return
ret
;
}
printk
(
"SGI O2 Fast Ethernet rev. %ld
\n
"
,
priv
->
regs
->
mac_ctrl
>>
29
);
return
0
;
}
/*
* The devices
*/
struct
net_device
meth_devs
[
1
]
=
{
{
init
:
meth_init
,
}
/* init, nothing more */
};
/*
* Finally, the module stuff
*/
int
meth_init_module
(
void
)
{
int
result
,
device_present
=
0
;
strcpy
(
meth_devs
[
0
].
name
,
"eth%d"
);
if
(
(
result
=
register_netdev
(
meth_devs
))
)
printk
(
"meth: error %i registering device
\"
%s
\"\n
"
,
result
,
meth_devs
->
name
);
else
device_present
++
;
#ifndef METH_DEBUG
EXPORT_NO_SYMBOLS
;
#endif
return
device_present
?
0
:
-
ENODEV
;
}
void
meth_cleanup
(
void
)
{
kfree
(
meth_devs
->
priv
);
unregister_netdev
(
meth_devs
);
return
;
}
module_init
(
meth_init_module
);
module_exit
(
meth_cleanup
);
drivers/net/meth.h
0 → 100644
View file @
e3e33952
/*
* snull.h -- definitions for the network module
*
* Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet
* Copyright (C) 2001 O'Reilly & Associates
*
* The source code in this file can be freely used, adapted,
* and redistributed in source or binary form, so long as an
* acknowledgment appears in derived source files. The citation
* should list that the code comes from the book "Linux Device
* Drivers" by Alessandro Rubini and Jonathan Corbet, published
* by O'Reilly & Associates. No warranty is attached;
* we cannot take responsibility for errors or fitness for use.
*/
/* version dependencies have been confined to a separate file */
#define SGI_MFE (MACE_BASE+MACE_ENET)
/* (0xBF280000)*/
/* Tunable parameters */
#define TX_RING_ENTRIES 64
/* 64-512?*/
#define RX_RING_ENTRIES 16
/* Do not change */
/* Internal constants */
#define TX_RING_BUFFER_SIZE (TX_RING_ENTRIES*sizeof(tx_packet))
#define RX_BUFFER_SIZE 1546
/* ethenet packet size */
#define METH_RX_BUFF_SIZE 4096
#define RX_BUFFER_OFFSET (sizeof(rx_status_vector)+2)
/* staus vector + 2 bytes of padding */
#define RX_BUCKET_SIZE 256
/* For more detailed explanations of what each field menas,
see Nick's great comments to #defines below (or docs, if
you are lucky enough toget hold of them :)*/
/* tx status vector is written over tx command header upon
dma completion. */
typedef
struct
tx_status_vector
{
u64
sent
:
1
;
/* always set to 1...*/
u64
pad0
:
34
;
/* always set to 0 */
u64
flags
:
9
;
/*I'm too lazy to specify each one separately at the moment*/
u64
col_retry_cnt
:
4
;
/*collision retry count*/
u64
len
:
16
;
/*Transmit length in bytes*/
}
tx_status_vector
;
/*
* Each packet is 128 bytes long.
* It consists of header, 0-3 concatination
* buffer pointers and up to 120 data bytes.
*/
typedef
struct
tx_packet_hdr
{
u64
pad1
:
36
;
/*should be filled with 0 */
u64
cat_ptr3_valid
:
1
,
/*Concatination pointer valid flags*/
cat_ptr2_valid:
1
,
cat_ptr1_valid:
1
;
u64
tx_int_flag
:
1
;
/*Generate TX intrrupt when packet has been sent*/
u64
term_dma_flag
:
1
;
/*Terminate transmit DMA on transmit abort conditions*/
u64
data_offset
:
7
;
/*Starting byte offset in ring data block*/
u64
data_len
:
16
;
/*Length of valid data in bytes-1*/
}
tx_packet_hdr
;
typedef
union
tx_cat_ptr
{
struct
{
u64
pad2
:
16
;
/* should be 0 */
u64
len
:
16
;
/*length of buffer data - 1*/
u64
start_addr
:
29
;
/*Physical starting address*/
u64
pad1
:
3
;
/* should be zero */
}
form
;
u64
raw
;
}
tx_cat_ptr
;
typedef
struct
tx_packet
{
union
{
tx_packet_hdr
header
;
tx_status_vector
res
;
u64
raw
;
}
header
;
union
{
tx_cat_ptr
cat_buf
[
3
];
char
dt
[
120
];
}
data
;
}
tx_packet
;
typedef
union
rx_status_vector
{
struct
{
u64
pad1
:
1
;
/*fill it with ones*/
u64
pad2
:
15
;
/*fill with 0*/
u64
ip_chk_sum
:
16
;
u64
seq_num
:
5
;
u64
mac_addr_match
:
1
;
u64
mcast_addr_match
:
1
;
u64
carrier_event_seen
:
1
;
u64
bad_packet
:
1
;
u64
long_event_seen
:
1
;
u64
invalid_preamble
:
1
;
u64
broadcast
:
1
;
u64
multicast
:
1
;
u64
crc_error
:
1
;
u64
huh
:
1
;
/*???*/
u64
rx_code_violation
:
1
;
u64
rx_len
:
16
;
}
parsed
;
u64
raw
;
}
rx_status_vector
;
typedef
struct
rx_packet
{
rx_status_vector
status
;
u64
pad
[
3
];
/* For whatever reason, there needs to be 4 double-word offset */
u16
pad2
;
char
buf
[
METH_RX_BUFF_SIZE
-
sizeof
(
rx_status_vector
)
-
3
*
sizeof
(
u64
)
-
sizeof
(
u16
)];
/* data */
}
rx_packet
;
typedef
struct
meth_regs
{
u64
mac_ctrl
;
/*0x00,rw,31:0*/
u64
int_flags
;
/*0x08,rw,30:0*/
u64
dma_ctrl
;
/*0x10,rw,15:0*/
u64
timer
;
/*0x18,rw,5:0*/
u64
int_tx
;
/*0x20,wo,0:0*/
u64
int_rx
;
/*0x28,wo,9:4*/
struct
{
u32
tx_info_pad
;
u32
rptr
:
16
,
wptr
:
16
;
}
tx_info
;
/*0x30,rw,31:0*/
u64
tx_info_al
;
/*0x38,rw,31:0*/
struct
{
u32
rx_buff_pad1
;
u32
rx_buff_pad2
:
8
,
wptr:
8
,
rptr:
8
,
depth:
8
;
}
rx_buff
;
/*0x40,ro,23:0*/
u64
rx_buff_al1
;
/*0x48,ro,23:0*/
u64
rx_buff_al2
;
/*0x50,ro,23:0*/
u64
int_update
;
/*0x58,wo,31:0*/
u32
phy_data_pad
;
u32
phy_data
;
/*0x60,rw,16:0*/
u32
phy_reg_pad
;
u32
phy_registers
;
/*0x68,rw,9:0*/
u64
phy_trans_go
;
/*0x70,wo,0:0*/
u64
backoff_seed
;
/*0x78,wo,10:0*/
u64
imq_reserved
[
4
];
/*0x80,ro,64:0(x4)*/
/*===================================*/
u64
mac_addr
;
/*0xA0,rw,47:0, I think it's MAC address, but I'm not sure*/
u64
mcast_addr
;
/*0xA8,rw,47:0, This seems like secondary MAC address*/
u64
mcast_filter
;
/*0xB0,rw,63:0*/
u64
tx_ring_base
;
/*0xB8,rw,31:13*/
/* Following are read-only debugging info register */
u64
tx_pkt1_hdr
;
/*0xC0,ro,63:0*/
u64
tx_pkt1_ptr
[
3
];
/*0xC8,ro,63:0(x3)*/
u64
tx_pkt2_hdr
;
/*0xE0,ro,63:0*/
u64
tx_pkt2_ptr
[
3
];
/*0xE8,ro,63:0(x3)*/
/*===================================*/
u32
rx_pad
;
u32
rx_fifo
;
u64
reserved
[
31
];
}
meth_regs
;
/* Bits in METH_MAC */
#define SGI_MAC_RESET BIT(0)
/* 0: MAC110 active in run mode, 1: Global reset signal to MAC110 core is active */
#define METH_PHY_FDX BIT(1)
/* 0: Disable full duplex, 1: Enable full duplex */
#define METH_PHY_LOOP BIT(2)
/* 0: Normal operation, follows 10/100mbit and M10T/MII select, 1: loops internal MII bus */
/* selects ignored */
#define METH_100MBIT BIT(3)
/* 0: 10meg mode, 1: 100meg mode */
#define METH_PHY_MII BIT(4)
/* 0: MII selected, 1: SIA selected */
/* Note: when loopback is set this bit becomes collision control. Setting this bit will */
/* cause a collision to be reported. */
/* Bits 5 and 6 are used to determine the the Destination address filter mode */
#define METH_ACCEPT_MY 0
/* 00: Accept PHY address only */
#define METH_ACCEPT_MCAST 0x20
/* 01: Accept physical, broadcast, and multicast filter matches only */
#define METH_ACCEPT_AMCAST 0x40
/* 10: Accept physical, broadcast, and all multicast packets */
#define METH_PROMISC 0x60
/* 11: Promiscious mode */
#define METH_PHY_LINK_FAIL BIT(7)
/* 0: Link failure detection disabled, 1: Hardware scans for link failure in PHY */
#define METH_MAC_IPG 0x1ffff00
#define METH_DEFAULT_IPG ((17<<15) | (11<<22) | (21<<8))
/* 0x172e5c00 */
/* 23, 23, 23 */
/*0x54A9500 *//*21,21,21*/
/* Bits 8 through 14 are used to determine Inter-Packet Gap between "Back to Back" packets */
/* The gap depends on the clock speed of the link, 80ns per increment for 100baseT, 800ns */
/* per increment for 10BaseT */
/* Bits 15 through 21 are used to determine IPGR1 */
/* Bits 22 through 28 are used to determine IPGR2 */
#define METH_REV_SHIFT 29
/* Bits 29 through 31 are used to determine the revision */
/* 000: Inital revision */
/* 001: First revision, Improved TX concatenation */
/* DMA control bits */
#define METH_RX_OFFSET_SHIFT 12
/* Bits 12:14 of DMA control register indicate starting offset of packet data for RX operation */
#define METH_RX_DEPTH_SHIFT 4
/* Bits 8:4 define RX fifo depth -- when # of RX fifo entries != depth, interrupt is generted */
#define METH_DMA_TX_EN BIT(1)
/* enable TX DMA */
#define METH_DMA_TX_INT_EN BIT(0)
/* enable TX Buffer Empty interrupt */
#define METH_DMA_RX_EN BIT(15)
/* Enable RX */
#define METH_DMA_RX_INT_EN BIT(9)
/* Enable interrupt on RX packet */
/* RX status bits */
#define METH_RX_ST_RCV_CODE_VIOLATION BIT(16)
#define METH_RX_ST_DRBL_NBL BIT(17)
#define METH_RX_ST_CRC_ERR BIT(18)
#define METH_RX_ST_MCAST_PKT BIT(19)
#define METH_RX_ST_BCAST_PKT BIT(20)
#define METH_RX_ST_INV_PREAMBLE_CTX BIT(21)
#define METH_RX_ST_LONG_EVT_SEEN BIT(22)
#define METH_RX_ST_BAD_PACKET BIT(23)
#define METH_RX_ST_CARRIER_EVT_SEEN BIT(24)
#define METH_RX_ST_MCAST_FILTER_MATCH BIT(25)
#define METH_RX_ST_PHYS_ADDR_MATCH BIT(26)
#define METH_RX_STATUS_ERRORS \
( \
METH_RX_ST_RCV_CODE_VIOLATION| \
METH_RX_ST_CRC_ERR| \
METH_RX_ST_INV_PREAMBLE_CTX| \
METH_RX_ST_LONG_EVT_SEEN| \
METH_RX_ST_BAD_PACKET| \
METH_RX_ST_CARRIER_EVT_SEEN \
)
/* Bits in METH_INT */
/* Write _1_ to corresponding bit to clear */
#define METH_INT_TX_EMPTY BIT(0)
/* 0: No interrupt pending, 1: The TX ring buffer is empty */
#define METH_INT_TX_PKT BIT(1)
/* 0: No interrupt pending */
/* 1: A TX message had the INT request bit set, the packet has been sent. */
#define METH_INT_TX_LINK_FAIL BIT(2)
/* 0: No interrupt pending, 1: PHY has reported a link failure */
#define METH_INT_MEM_ERROR BIT(3)
/* 0: No interrupt pending */
/* 1: A memory error occurred durring DMA, DMA stopped, Fatal */
#define METH_INT_TX_ABORT BIT(4)
/* 0: No interrupt pending, 1: The TX aborted operation, DMA stopped, FATAL */
#define METH_INT_RX_THRESHOLD BIT(5)
/* 0: No interrupt pending, 1: Selected receive threshold condition Valid */
#define METH_INT_RX_UNDERFLOW BIT(6)
/* 0: No interrupt pending, 1: FIFO was empty, packet could not be queued */
#define METH_INT_RX_OVERFLOW BIT(7)
/* 0: No interrupt pending, 1: DMA FIFO Overflow, DMA stopped, FATAL */
#define METH_INT_RX_RPTR_MASK 0x0001F00
/* Bits 8 through 12 alias of RX read-pointer */
/* Bits 13 through 15 are always 0. */
#define METH_INT_TX_RPTR_MASK 0x1FF0000
/* Bits 16 through 24 alias of TX read-pointer */
#define METH_INT_SEQ_MASK 0x2E000000
/* Bits 25 through 29 are the starting seq number for the message at the */
/* top of the queue */
#define METH_ERRORS ( \
METH_INT_RX_OVERFLOW| \
METH_INT_RX_UNDERFLOW| \
METH_INT_MEM_ERROR| \
METH_INT_TX_ABORT)
#define METH_INT_MCAST_HASH BIT(30)
/* If RX DMA is enabled the hash select logic output is latched here */
/* TX status bits */
#define METH_TX_STATUS_DONE BIT(23)
/* Packet was transmitted successfully */
/* Tx command header bits */
#define METH_TX_CMD_INT_EN BIT(24)
/* Generate TX interrupt when packet is sent */
/* Phy MDIO interface busy flag */
#define MDIO_BUSY BIT(16)
#define MDIO_DATA_MASK 0xFFFF
/* PHY defines */
#define PHY_QS6612X 0x0181441
/* Quality TX */
#define PHY_ICS1889 0x0015F41
/* ICS FX */
#define PHY_ICS1890 0x0015F42
/* ICS TX */
#define PHY_DP83840 0x20005C0
/* National TX */
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment