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
nexedi
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
Hide 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
the Ethernet-HOWTO, available from
<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
tristate "National DP83902AV support"
depends on NET_ETHERNET && SUPERH
...
...
drivers/net/Makefile
View file @
e3e33952
...
...
@@ -117,6 +117,7 @@ obj-$(CONFIG_SUN3_82586) += sun3_82586.o
obj-$(CONFIG_SUN3LANCE)
+=
sun3lance.o
obj-$(CONFIG_DEFXX)
+=
defxx.o
obj-$(CONFIG_SGISEEQ)
+=
sgiseeq.o
obj-$(CONFIG_SGI_O2MACE_ETH)
+=
meth.o
obj-$(CONFIG_AT1700)
+=
at1700.o
obj-$(CONFIG_FMV18X)
+=
fmv18x.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