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
787a6212
Commit
787a6212
authored
Apr 21, 2004
by
Ralf Bächle
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[PATCH] meth updates
More work on the meth driver for SGI IP32 aka O2.
parent
c1350c27
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
458 additions
and
482 deletions
+458
-482
drivers/net/meth.c
drivers/net/meth.c
+426
-423
drivers/net/meth.h
drivers/net/meth.h
+32
-59
No files found.
drivers/net/meth.c
View file @
787a6212
/*
* meth.c -- O2 Builtin 10/100 Ethernet driver
*
* Copyright (C) 2001 Ilya Volynets
* Copyright (C) 2001
-2003
Ilya Volynets
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
...
...
@@ -18,9 +18,10 @@
#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/in6.h>
#include <linux/device.h>
/* struct device, et al */
#include <linux/netdevice.h>
/* struct device, and other headers */
#include <linux/etherdevice.h>
/* eth_type_trans */
#include <linux/ip.h>
/* struct iphdr */
...
...
@@ -28,21 +29,22 @@
#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/io.h>
#include <asm/checksum.h>
#include <asm/scatterlist.h>
#include <linux/dma-mapping.h>
#include "meth.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 DPRINTK(str,args...) printk
(KERN_DEBUG "meth: %s: " str
, __FUNCTION__ , ## args)
#define MFE_RX_DEBUG 2
#else
#define DPRINTK(str,args...)
...
...
@@ -50,15 +52,10 @@
#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_AUTHOR
(
"Ilya Volynets
<ilya@theIlya.com>
"
);
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)
...
...
@@ -68,133 +65,95 @@ 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*/
struct
meth_private
{
struct
net_device_stats
stats
;
/* in-memory copy of MAC Control register */
unsigned
long
mac_ctrl
;
/* in-memory copy of DMA Control register */
unsigned
long
dma_ctrl
;
/* address of PHY, used by mdio_* functions, initialized in mdio_probe */
unsigned
long
phy_addr
;
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
;
dma_addr_t
tx_skb_dmas
[
TX_RING_ENTRIES
];
unsigned
long
tx_read
,
tx_write
,
tx_count
;
rx_packet
*
rx_ring
[
RX_RING_ENTRIES
];
dma_addr_t
rx_ring_dmas
[
RX_RING_ENTRIES
];
int
rx_write
;
struct
sk_buff
*
rx_skbs
[
RX_RING_ENTRIES
];
unsigned
long
rx_write
;
spinlock_t
meth_lock
;
}
meth_private
;
spinlock_t
meth_lock
;
};
void
meth_tx_timeout
(
struct
net_device
*
dev
);
void
meth_interrupt
(
int
irq
,
void
*
dev_id
,
struct
pt_regs
*
pregs
);
static
void
meth_tx_timeout
(
struct
net_device
*
dev
);
static
irqreturn_t
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
)
static
inline
void
load_eaddr
(
struct
net_device
*
dev
)
{
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
);
for
(
i
=
0
;
i
<
6
;
i
++
)
dev
->
dev_addr
[
i
]
=
o2meth_eaddr
[
i
];
mace_eth_write
((
*
(
u64
*
)
o2meth_eaddr
)
>>
16
,
mac_addr
);
}
/*
*Waits for BUSY status of mdio bus to clear
*
Waits for BUSY status of mdio bus to clear
*/
#define WAIT_FOR_PHY(___r
egs, ___rval)
\
while
((___rval=___regs->phy_data)&MDIO_BUSY)
{ \
udelay(25);
\
#define WAIT_FOR_PHY(___r
val)
\
while
((___rval = mace_eth_read(phy_data)) & MDIO_BUSY)
{ \
udelay(25); \
}
/*read phy register, return value read */
static
int
mdio_read
(
meth_private
*
priv
,
int
phyreg
)
static
unsigned
long
mdio_read
(
struct
meth_private
*
priv
,
unsigned
long
phyreg
)
{
volatile
meth_regs
*
regs
=
priv
->
regs
;
volatile
u32
rval
;
WAIT_FOR_PHY
(
regs
,
rval
)
regs
->
phy_registers
=
(
priv
->
phy_addr
<<
5
)
|
(
phyreg
&
0x1f
);
unsigned
long
rval
;
WAIT_FOR_PHY
(
rval
);
mace_eth_write
((
priv
->
phy_addr
<<
5
)
|
(
phyreg
&
0x1f
),
phy_regs
);
udelay
(
25
);
regs
->
phy_trans_go
=
1
;
mace_eth_write
(
1
,
phy_trans_go
)
;
udelay
(
25
);
WAIT_FOR_PHY
(
r
egs
,
rval
)
WAIT_FOR_PHY
(
r
val
);
return
rval
&
MDIO_DATA_MASK
;
}
/*write phy register */
static
void
mdio_write
(
meth_private
*
priv
,
int
pfyreg
,
int
val
)
static
int
mdio_probe
(
struct
meth_private
*
priv
)
{
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
"
);
int
i
;
unsigned
long
p2
,
p3
;
/* check if phy is detected already */
if
(
priv
->
phy_addr
>=
0
&&
priv
->
phy_addr
<
32
)
return
0
;
spin_lock
_irq
(
&
priv
->
meth_lock
);
spin_lock
(
&
priv
->
meth_lock
);
for
(
i
=
0
;
i
<
32
;
++
i
){
priv
->
phy_addr
=
(
char
)
i
;
priv
->
phy_addr
=
i
;
p2
=
mdio_read
(
priv
,
2
);
#ifdef MFE_DEBUG
p3
=
mdio_read
(
priv
,
3
);
#if MFE_DEBUG>=2
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
;
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
){
...
...
@@ -202,7 +161,7 @@ static int mdio_probe(meth_private *priv)
break
;
}
}
spin_unlock
_irq
(
&
priv
->
meth_lock
);
spin_unlock
(
&
priv
->
meth_lock
);
if
(
priv
->
phy_addr
<
32
)
{
return
0
;
}
...
...
@@ -214,99 +173,96 @@ static int mdio_probe(meth_private *priv)
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
;
unsigned
long
mii_advertising
=
mdio_read
(
priv
,
4
);
unsigned
long
mii_partner
=
mdio_read
(
priv
,
5
);
unsigned
long
negotiated
=
mii_advertising
&
mii_partner
;
unsigned
long
duplex
,
speed
;
if
(
mii_partner
==
0xffff
)
return
;
duplex
=
((
negotiated
&
0x0100
)
||
(
negotiated
&
0x01C0
)
==
0x0040
)
?
METH_PHY_FDX
:
0
;
speed
=
(
negotiated
&
0x0380
)
?
METH_100MBIT
:
0
;
speed
=
(
negotiated
&
0x0380
)
?
METH_100MBIT
:
0
;
duplex
=
((
negotiated
&
0x0100
)
||
(
negotiated
&
0x01C0
)
==
0x0040
)
?
METH_PHY_FDX
:
0
;
if
((
priv
->
mode
&
METH_PHY_FDX
)
^
duplex
)
{
if
((
priv
->
mac_ctrl
&
METH_PHY_FDX
)
^
duplex
)
{
DPRINTK
(
"Setting %s-duplex
\n
"
,
duplex
?
"full"
:
"half"
);
if
(
duplex
)
priv
->
m
ode
|=
METH_PHY_FDX
;
priv
->
m
ac_ctrl
|=
METH_PHY_FDX
;
else
priv
->
m
ode
&=
~
METH_PHY_FDX
;
priv
->
regs
->
mac_ctrl
=
priv
->
mode
;
priv
->
m
ac_ctrl
&=
~
METH_PHY_FDX
;
mace_eth_write
(
priv
->
mac_ctrl
,
mac_ctrl
)
;
}
if
((
priv
->
mode
&
METH_100MBIT
)
^
speed
)
{
if
((
priv
->
mac_ctrl
&
METH_100MBIT
)
^
speed
)
{
DPRINTK
(
"Setting %dMbs mode
\n
"
,
speed
?
100
:
10
);
if
(
duplex
)
priv
->
m
ode
|=
METH_100MBIT
;
priv
->
m
ac_ctrl
|=
METH_100MBIT
;
else
priv
->
m
ode
&=
~
METH_100MBIT
;
priv
->
regs
->
mac_ctrl
=
priv
->
mode
;
priv
->
m
ac_ctrl
&=
~
METH_100MBIT
;
mace_eth_write
(
priv
->
mac_ctrl
,
mac_ctrl
)
;
}
}
static
int
meth_init_tx_ring
(
meth_private
*
priv
)
static
int
meth_init_tx_ring
(
struct
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
)
priv
->
tx_ring
=
dma_alloc_coherent
(
NULL
,
TX_RING_BUFFER_SIZE
,
&
priv
->
tx_ring_dma
,
GFP_ATOMIC
);
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
;
mace_eth_write
(
priv
->
tx_ring_dma
,
tx_ring_base
);
/* 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
)
static
int
meth_init_rx_ring
(
struct
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
])
);
priv
->
rx_skbs
[
i
]
=
alloc_skb
(
METH_RX_BUFF_SIZE
,
0
);
/*
8byte status vector+3quad padding + 2byte padding,
to put data on 64bit aligned boundary */
skb_reserve
(
priv
->
rx_skbs
[
i
],
METH_RX_HEAD
);
priv
->
rx_ring
[
i
]
=
(
rx_packet
*
)
(
priv
->
rx_skbs
[
i
]
->
head
);
/* 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_ring_dmas
[
i
]
=
dma_map_single
(
NULL
,
priv
->
rx_ring
[
i
],
METH_RX_BUFF_SIZE
,
DMA_FROM_DEVICE
);
mace_eth_write
(
priv
->
rx_ring_dmas
[
i
],
rx_fifo
);
}
priv
->
rx_write
=
0
;
DPRINTK
(
"Done with RX ring
\n
"
);
priv
->
rx_write
=
0
;
return
0
;
}
static
void
meth_free_tx_ring
(
meth_private
*
priv
)
static
void
meth_free_tx_ring
(
struct
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
]);
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
);
dma_free_coherent
(
NULL
,
TX_RING_BUFFER_SIZE
,
priv
->
tx_ring
,
priv
->
tx_ring_dma
);
}
static
void
meth_free_rx_ring
(
meth_private
*
priv
)
/* Presumes RX DMA engine is stopped, and RX fifo ring is reset */
static
void
meth_free_rx_ring
(
struct
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
]);
for
(
i
=
0
;
i
<
RX_RING_ENTRIES
;
i
++
)
{
dma_unmap_single
(
NULL
,
priv
->
rx_ring_dmas
[
i
],
METH_RX_BUFF_SIZE
,
DMA_FROM_DEVICE
);
priv
->
rx_ring
[
i
]
=
0
;
priv
->
rx_ring_dmas
[
i
]
=
0
;
kfree_skb
(
priv
->
rx_skbs
[
i
]);
}
}
int
meth_reset
(
struct
net_device
*
dev
)
...
...
@@ -314,13 +270,12 @@ 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
;
mace_eth_write
(
SGI_MAC_RESET
,
mac_ctrl
)
;
mace_eth_write
(
0
,
mac_ctrl
)
;
udelay
(
25
);
DPRINTK
(
"MAC control after reset: %016lx
\n
"
,
priv
->
regs
->
mac_ctrl
);
/* Load ethernet address */
load_eaddr
(
dev
,
priv
->
regs
);
load_eaddr
(
dev
);
/* Should load some "errata", but later */
/* Check for device */
...
...
@@ -329,20 +284,21 @@ int meth_reset(struct net_device *dev)
return
-
ENODEV
;
}
/* Initial mode
-- 10|Half-duplex|
Accept normal packets */
priv
->
m
ode
=
METH_ACCEPT_MCAST
|
METH_DEFAULT_IPG
;
/* Initial mode
: 10 | Half-duplex |
Accept normal packets */
priv
->
m
ac_ctrl
=
METH_ACCEPT_MCAST
|
METH_DEFAULT_IPG
;
if
(
dev
->
flags
|
IFF_PROMISC
)
priv
->
m
ode
|=
METH_PROMISC
;
priv
->
regs
->
mac_ctrl
=
priv
->
mode
;
priv
->
m
ac_ctrl
|=
METH_PROMISC
;
mace_eth_write
(
priv
->
mac_ctrl
,
mac_ctrl
)
;
/* Autonego
c
iate speed and duplex mode */
/* Autonego
t
iate 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
);
priv
->
dma_ctrl
=
(
4
<<
METH_RX_OFFSET_SHIFT
)
|
(
RX_RING_ENTRIES
<<
METH_RX_DEPTH_SHIFT
);
mace_eth_write
(
priv
->
dma_ctrl
,
dma_ctrl
);
return
(
0
)
;
return
0
;
}
/*============End Helper Routines=====================*/
...
...
@@ -350,110 +306,183 @@ int meth_reset(struct net_device *dev)
/*
* Open and close
*/
int
meth_open
(
struct
net_device
*
dev
)
static
int
meth_open
(
struct
net_device
*
dev
)
{
meth_private
*
priv
=
dev
->
priv
;
volatile
meth_regs
*
regs
=
priv
->
regs
;
struct
meth_private
*
priv
=
dev
->
priv
;
int
ret
;
/* Start DMA */
regs
->
dma_ctrl
|=
METH_DMA_TX_EN
|
/*METH_DMA_TX_INT_EN|*/
METH_DMA_RX_EN
|
METH_DMA_RX_INT_EN
;
priv
->
phy_addr
=
-
1
;
/* No PHY is known yet... */
/* Initialize the hardware */
ret
=
meth_reset
(
dev
);
if
(
ret
<
0
)
return
ret
;
if
(
request_irq
(
dev
->
irq
,
meth_interrupt
,
SA_SHIRQ
,
meth_str
,
dev
)){
/* Allocate the ring buffers */
ret
=
meth_init_tx_ring
(
priv
);
if
(
ret
<
0
)
return
ret
;
ret
=
meth_init_rx_ring
(
priv
);
if
(
ret
<
0
)
goto
out_free_tx_ring
;
ret
=
request_irq
(
dev
->
irq
,
meth_interrupt
,
0
,
meth_str
,
dev
);
if
(
ret
)
{
printk
(
KERN_ERR
"%s: Can't get irq %d
\n
"
,
dev
->
name
,
dev
->
irq
);
return
-
EAGAIN
;
goto
out_free_rx_ring
;
}
/* Start DMA */
priv
->
dma_ctrl
|=
METH_DMA_TX_EN
|
/*METH_DMA_TX_INT_EN |*/
METH_DMA_RX_EN
|
METH_DMA_RX_INT_EN
;
mace_eth_write
(
priv
->
dma_ctrl
,
dma_ctrl
);
DPRINTK
(
"About to start queue
\n
"
);
netif_start_queue
(
dev
);
DPRINTK
(
"Opened... DMA control=0x%08lx
\n
"
,
regs
->
dma_ctrl
);
return
0
;
out_free_rx_ring:
meth_free_rx_ring
(
priv
);
out_free_tx_ring:
meth_free_tx_ring
(
priv
);
return
ret
;
}
int
meth_release
(
struct
net_device
*
dev
)
static
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
);
struct
meth_private
*
priv
=
dev
->
priv
;
DPRINTK
(
"Stopping queue
\n
"
);
netif_stop_queue
(
dev
);
/* can't transmit any more */
/* shut down DMA */
priv
->
dma_ctrl
&=
~
(
METH_DMA_TX_EN
|
METH_DMA_TX_INT_EN
|
METH_DMA_RX_EN
|
METH_DMA_RX_INT_EN
);
mace_eth_write
(
priv
->
dma_ctrl
,
dma_ctrl
);
free_irq
(
dev
->
irq
,
dev
);
return
0
;
meth_free_tx_ring
(
priv
);
meth_free_rx_ring
(
priv
);
return
0
;
}
/*
* Configuration changes (passed on by ifconfig)
*/
int
meth_config
(
struct
net_device
*
dev
,
struct
ifmap
*
map
)
static
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
;
}
/* A
llow changing the IRQ */
if
(
map
->
irq
!=
dev
->
irq
)
{
printk
(
KERN_WARNING
"meth: Can't change IRQ
\n
"
);
return
-
EOPNOTSUPP
;
}
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
;
}
/* Don't a
llow 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
;
/* ignore other fields */
return
0
;
}
/*
* Receive a packet: retrieve, encapsulate and pass over to upper levels
*/
void
meth_rx
(
struct
net_device
*
dev
)
static
void
meth_rx
(
struct
net_device
*
dev
,
unsigned
long
int_status
)
{
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
++
;
struct
sk_buff
*
skb
;
struct
meth_private
*
priv
=
(
struct
meth_private
*
)
dev
->
priv
;
unsigned
long
fifo_rptr
=
(
int_status
&
METH_INT_RX_RPTR_MASK
)
>>
8
;
spin_lock
(
&
priv
->
meth_lock
);
priv
->
dma_ctrl
&=~
METH_DMA_RX_INT_EN
;
mace_eth_write
(
priv
->
dma_ctrl
,
dma_ctrl
);
spin_unlock
(
&
priv
->
meth_lock
);
if
(
int_status
&
METH_INT_RX_UNDERFLOW
){
fifo_rptr
=
(
fifo_rptr
-
1
)
&
(
0xF
);
}
while
(
priv
->
rx_write
!=
fifo_rptr
)
{
u64
status
;
dma_unmap_single
(
NULL
,
priv
->
rx_ring_dmas
[
priv
->
rx_write
],
METH_RX_BUFF_SIZE
,
DMA_FROM_DEVICE
);
status
=
priv
->
rx_ring
[
priv
->
rx_write
]
->
status
.
raw
;
#if MFE_DEBUG
if
(
!
(
status
&
METH_RX_ST_VALID
))
{
DPRINTK
(
"Not received? status=%016lx
\n
"
,
status
);
}
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
++
;
#endif
if
((
!
(
status
&
METH_RX_STATUS_ERRORS
))
&&
(
status
&
METH_RX_ST_VALID
)){
int
len
=
(
status
&
0xFFFF
)
-
4
;
/* omit CRC */
/* length sanity check */
if
(
len
<
60
||
len
>
1518
)
{
printk
(
KERN_DEBUG
"%s: bogus packet size: %d, status=%#2lx.
\n
"
,
dev
->
name
,
priv
->
rx_write
,
priv
->
rx_ring
[
priv
->
rx_write
]
->
status
.
raw
);
priv
->
stats
.
rx_errors
++
;
priv
->
stats
.
rx_length_errors
++
;
skb
=
priv
->
rx_skbs
[
priv
->
rx_write
];
}
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
"
);
skb
=
alloc_skb
(
METH_RX_BUFF_SIZE
,
GFP_ATOMIC
|
GFP_DMA
);
if
(
!
skb
){
/* Ouch! No memory! Drop packet on the floor */
DPRINTK
(
"No mem: dropping packet
\n
"
);
priv
->
stats
.
rx_dropped
++
;
skb
=
priv
->
rx_skbs
[
priv
->
rx_write
];
}
else
{
struct
sk_buff
*
skb_c
=
priv
->
rx_skbs
[
priv
->
rx_write
];
/* 8byte status vector+3quad padding + 2byte padding,
to put data on 64bit aligned boundary */
skb_reserve
(
skb
,
METH_RX_HEAD
);
/* Write metadata, and then pass to the receive level */
skb_put
(
skb_c
,
len
);
priv
->
rx_skbs
[
priv
->
rx_write
]
=
skb
;
skb_c
->
dev
=
dev
;
skb_c
->
protocol
=
eth_type_trans
(
skb_c
,
dev
);
dev
->
last_rx
=
jiffies
;
priv
->
stats
.
rx_packets
++
;
priv
->
stats
.
rx_bytes
+=
len
;
netif_rx
(
skb_c
);
}
}
}
else
{
priv
->
stats
.
rx_errors
++
;
skb
=
priv
->
rx_skbs
[
priv
->
rx_write
];
#if MFE_DEBUG>0
printk
(
KERN_WARNING
"meth: RX error: status=0x%016lx
\n
"
,
status
);
if
(
status
&
METH_RX_ST_RCV_CODE_VIOLATION
)
printk
(
KERN_WARNING
"Receive Code Violation
\n
"
);
if
(
status
&
METH_RX_ST_CRC_ERR
)
printk
(
KERN_WARNING
"CRC error
\n
"
);
if
(
status
&
METH_RX_ST_INV_PREAMBLE_CTX
)
printk
(
KERN_WARNING
"Invalid Preamble Context
\n
"
);
if
(
status
&
METH_RX_ST_LONG_EVT_SEEN
)
printk
(
KERN_WARNING
"Long Event Seen...
\n
"
);
if
(
status
&
METH_RX_ST_BAD_PACKET
)
printk
(
KERN_WARNING
"Bad Packet
\n
"
);
if
(
status
&
METH_RX_ST_CARRIER_EVT_SEEN
)
printk
(
KERN_WARNING
"Carrier Event Seen
\n
"
);
#endif
}
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
);
priv
->
rx_ring
[
priv
->
rx_write
]
=
(
rx_packet
*
)
skb
->
head
;
priv
->
rx_ring
[
priv
->
rx_write
]
->
status
.
raw
=
0
;
priv
->
rx_ring_dmas
[
priv
->
rx_write
]
=
dma_map_single
(
NULL
,
priv
->
rx_ring
[
priv
->
rx_write
],
METH_RX_BUFF_SIZE
,
DMA_FROM_DEVICE
);
mace_eth_write
(
priv
->
rx_ring_dmas
[
priv
->
rx_write
],
rx_fifo
);
ADVANCE_RX_PTR
(
priv
->
rx_write
);
}
spin_lock
(
&
priv
->
meth_lock
);
/* In case there was underflow, and Rx DMA was disabled */
priv
->
dma_ctrl
|=
METH_DMA_RX_INT_EN
|
METH_DMA_RX_EN
;
mace_eth_write
(
priv
->
dma_ctrl
,
dma_ctrl
);
mace_eth_write
(
METH_INT_RX_THRESHOLD
,
int_stat
);
spin_unlock
(
&
priv
->
meth_lock
);
}
static
int
meth_tx_full
(
struct
net_device
*
dev
)
...
...
@@ -463,29 +492,56 @@ static int meth_tx_full(struct net_device *dev)
return
(
priv
->
tx_count
>=
TX_RING_ENTRIES
-
1
);
}
void
meth_tx_cleanup
(
struct
net_device
*
dev
,
int
rptr
)
static
void
meth_tx_cleanup
(
struct
net_device
*
dev
,
unsigned
long
int_status
)
{
meth_private
*
priv
=
dev
->
priv
;
tx_packet
*
status
;
struct
meth_private
*
priv
=
dev
->
priv
;
u64
status
;
struct
sk_buff
*
skb
;
unsigned
long
rptr
=
(
int_status
&
TX_INFO_RPTR
)
>>
16
;
spin_lock
(
&
priv
->
meth_lock
);
/* Stop DMA */
priv
->
regs
->
dma_ctrl
&=
~
(
METH_DMA_TX_INT_EN
);
/* Stop DMA notification */
priv
->
dma_ctrl
&=
~
(
METH_DMA_TX_INT_EN
);
mace_eth_write
(
priv
->
dma_ctrl
,
dma_ctrl
);
while
(
priv
->
tx_read
!=
rptr
){
skb
=
priv
->
tx_skbs
[
priv
->
tx_read
];
status
=
&
priv
->
tx_ring
[
priv
->
tx_read
];
if
(
!
status
->
header
.
res
.
sent
)
status
=
priv
->
tx_ring
[
priv
->
tx_read
].
header
.
raw
;
#if MFE_DEBUG>=1
if
(
priv
->
tx_read
==
priv
->
tx_write
)
DPRINTK
(
"Auchi! tx_read=%d,tx_write=%d,rptr=%d?
\n
"
,
priv
->
tx_read
,
priv
->
tx_write
,
rptr
);
#endif
if
(
status
&
METH_TX_ST_DONE
)
{
if
(
status
&
METH_TX_ST_SUCCESS
){
priv
->
stats
.
tx_packets
++
;
priv
->
stats
.
tx_bytes
+=
skb
->
len
;
}
else
{
priv
->
stats
.
tx_errors
++
;
#if MFE_DEBUG>=1
DPRINTK
(
"TX error: status=%016lx <"
,
status
);
if
(
status
&
METH_TX_ST_SUCCESS
)
printk
(
" SUCCESS"
);
if
(
status
&
METH_TX_ST_TOOLONG
)
printk
(
" TOOLONG"
);
if
(
status
&
METH_TX_ST_UNDERRUN
)
printk
(
" UNDERRUN"
);
if
(
status
&
METH_TX_ST_EXCCOLL
)
printk
(
" EXCCOLL"
);
if
(
status
&
METH_TX_ST_DEFER
)
printk
(
" DEFER"
);
if
(
status
&
METH_TX_ST_LATECOLL
)
printk
(
" LATECOLL"
);
printk
(
" >
\n
"
);
#endif
}
}
else
{
DPRINTK
(
"RPTR points us here, but packet not done?
\n
"
);
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_ring
[
priv
->
tx_read
].
header
.
raw
=
0
;
priv
->
tx_read
=
(
priv
->
tx_read
+
1
)
&
(
TX_RING_ENTRIES
-
1
);
priv
->
tx_count
--
;
}
...
...
@@ -495,94 +551,100 @@ void meth_tx_cleanup(struct net_device* dev, int rptr)
netif_wake_queue
(
dev
);
}
spin_unlock
(
priv
->
meth_lock
);
mace_eth_write
(
METH_INT_TX_EMPTY
|
METH_INT_TX_PKT
,
int_stat
);
spin_unlock
(
&
priv
->
meth_lock
);
}
static
void
meth_error
(
struct
net_device
*
dev
,
u32
status
)
{
struct
meth_private
*
priv
=
(
struct
meth_private
*
)
dev
->
priv
;
printk
(
KERN_WARNING
"meth: error status: 0x%08x
\n
"
,
status
);
/* check for errors too... */
if
(
status
&
(
METH_INT_TX_LINK_FAIL
))
printk
(
KERN_WARNING
"meth: link failure
\n
"
);
/* Should I do full reset in this case? */
if
(
status
&
(
METH_INT_MEM_ERROR
))
printk
(
KERN_WARNING
"meth: memory error
\n
"
);
if
(
status
&
(
METH_INT_TX_ABORT
))
printk
(
KERN_WARNING
"meth: aborted
\n
"
);
if
(
status
&
(
METH_INT_RX_OVERFLOW
))
printk
(
KERN_WARNING
"meth: Rx overflow
\n
"
);
if
(
status
&
(
METH_INT_RX_UNDERFLOW
))
{
printk
(
KERN_WARNING
"meth: Rx underflow
\n
"
);
spin_lock
(
&
priv
->
meth_lock
);
mace_eth_write
(
METH_INT_RX_UNDERFLOW
,
int_stat
);
/* more underflow interrupts will be delivered,
effectively throwing us into an infinite loop.
Thus I stop processing Rx in this case.
*/
priv
->
dma_ctrl
&=~
METH_DMA_RX_EN
;
mace_eth_write
(
priv
->
dma_ctrl
,
dma_ctrl
);
DPRINTK
(
"Disabled meth Rx DMA temporarily
\n
"
);
spin_unlock
(
&
priv
->
meth_lock
);
}
mace_eth_write
(
METH_INT_ERROR
,
int_stat
);
}
/*
* The typical interrupt entry point
*/
void
meth_interrupt
(
int
irq
,
void
*
dev_id
,
struct
pt_regs
*
pregs
)
static
irqreturn_t
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
);
struct
meth_private
*
priv
=
(
struct
meth_private
*
)
dev
->
priv
;
unsigned
long
status
;
status
=
mace_eth_read
(
int_stat
);
while
(
status
&
0xFF
)
{
/* First handle errors - if we get Rx underflow,
Rx DMA will be disabled, and Rx handler will reenable
it. I don't think it's possible to get Rx underflow,
without getting Rx interrupt */
if
(
status
&
METH_INT_ERROR
)
{
meth_error
(
dev
,
status
);
}
if
(
status
&
(
METH_INT_TX_EMPTY
|
METH_INT_TX_PKT
))
{
/* a transmission is over: free the skb */
meth_tx_cleanup
(
dev
,
status
);
}
if
(
status
&
METH_INT_RX_THRESHOLD
)
{
if
(
!
(
priv
->
dma_ctrl
&
METH_DMA_RX_INT_EN
))
break
;
/* send it to meth_rx for handling */
meth_rx
(
dev
,
status
);
}
status
=
mace_eth_read
(
int_stat
);
}
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 */
return
IRQ_HANDLED
;
}
/*
* Transmits packets that fit into TX descriptor (are <=120B)
*/
static
void
meth_tx_short_prepare
(
meth_private
*
priv
,
struct
sk_buff
*
skb
)
static
void
meth_tx_short_prepare
(
struct
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
"
);
desc
->
header
.
raw
=
METH_TX_CMD_INT_EN
|
(
len
-
1
)
|
((
128
-
len
)
<<
16
);
/* 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
)
static
void
meth_tx_1page_prepare
(
struct
meth_private
*
priv
,
struct
sk_buff
*
skb
)
{
tx_packet
*
desc
=&
priv
->
tx_ring
[
priv
->
tx_write
];
void
*
buffer_data
=
(
void
*
)(((
u
64
)
skb
->
data
+
7ULL
)
&
(
~
7ULL
)
);
int
unaligned_len
=
(
int
)((
u
64
)
buffer_data
-
(
u64
)
skb
->
data
);
void
*
buffer_data
=
(
void
*
)(((
u
nsigned
long
)
skb
->
data
+
7
)
&
~
7
);
int
unaligned_len
=
(
int
)((
u
nsigned
long
)
buffer_data
-
(
unsigned
long
)
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 */
...
...
@@ -593,37 +655,23 @@ static void meth_tx_1page_prepare(meth_private* priv, struct sk_buff* skb)
}
/* first page */
catbuf
=
pci_map_single
(
NULL
,
buffer_data
,
buffer_len
,
PCI_DMA_TODEVICE
);
DPRINTK
(
"catbuf=%x
\n
"
,
catbuf
);
catbuf
=
dma_map_single
(
NULL
,
buffer_data
,
buffer_len
,
DMA_TO_DEVICE
);
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
)
static
void
meth_tx_2page_prepare
(
struct
meth_private
*
priv
,
struct
sk_buff
*
skb
)
{
tx_packet
*
desc
=&
priv
->
tx_ring
[
priv
->
tx_write
];
void
*
buffer1_data
=
(
void
*
)(((
u
64
)
skb
->
data
+
7ULL
)
&
(
~
7ULL
)
);
void
*
buffer2_data
=
(
void
*
)
PAGE_ALIGN
((
u
64
)
skb
->
data
);
int
unaligned_len
=
(
int
)((
u
64
)
buffer1_data
-
(
u64
)
skb
->
data
);
int
buffer1_len
=
(
int
)((
u
64
)
buffer2_data
-
(
u64
)
buffer1_data
);
void
*
buffer1_data
=
(
void
*
)(((
u
nsigned
long
)
skb
->
data
+
7
)
&
~
7
);
void
*
buffer2_data
=
(
void
*
)
PAGE_ALIGN
((
u
nsigned
long
)
skb
->
data
);
int
unaligned_len
=
(
int
)((
u
nsigned
long
)
buffer1_data
-
(
unsigned
long
)
skb
->
data
);
int
buffer1_len
=
(
int
)((
u
nsigned
long
)
buffer2_data
-
(
unsigned
long
)
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
){
...
...
@@ -633,70 +681,64 @@ static void meth_tx_2page_prepare(meth_private* priv, struct sk_buff* skb)
}
/* first page */
catbuf1
=
pci_map_single
(
NULL
,
buffer1_data
,
buffer1_len
,
PCI_DMA_TODEVICE
);
DPRINTK
(
"catbuf1=%x
\n
"
,
catbuf1
);
catbuf1
=
dma_map_single
(
NULL
,
buffer1_data
,
buffer1_len
,
DMA_TO_DEVICE
);
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
);
catbuf2
=
dma_map_single
(
NULL
,
buffer2_data
,
buffer2_len
,
DMA_TO_DEVICE
);
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
)
static
void
meth_add_to_tx_ring
(
struct
meth_private
*
priv
,
struct
sk_buff
*
skb
)
{
DPRINTK
(
"Transmitting data...
\n
"
);
/* Remember the skb, so we can free it at interrupt time */
priv
->
tx_skbs
[
priv
->
tx_write
]
=
skb
;
if
(
skb
->
len
<=
120
)
{
/* Whole packet fits into descriptor */
meth_tx_short_prepare
(
priv
,
skb
);
}
else
if
(
PAGE_ALIGN
((
u
64
)
skb
->
data
)
!=
PAGE_ALIGN
((
u
64
)
skb
->
data
+
skb
->
len
-
1
))
{
}
else
if
(
PAGE_ALIGN
((
u
nsigned
long
)
skb
->
data
)
!=
PAGE_ALIGN
((
u
nsigned
long
)
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
;
mace_eth_write
(
priv
->
tx_write
,
tx_info
)
;
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
)
static
int
meth_tx
(
struct
sk_buff
*
skb
,
struct
net_device
*
dev
)
{
struct
meth_private
*
priv
=
(
struct
meth_private
*
)
dev
->
priv
;
unsigned
long
flags
;
spin_lock_irq
(
&
priv
->
meth_lock
);
spin_lock_irqsave
(
&
priv
->
meth_lock
,
flags
);
/* Stop DMA notification */
priv
->
dma_ctrl
&=
~
(
METH_DMA_TX_INT_EN
);
mace_eth_write
(
priv
->
dma_ctrl
,
dma_ctrl
);
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
"
);
printk
(
KERN_DEBUG
"TX full: stopping
\n
"
);
netif_stop_queue
(
dev
);
}
spin_unlock_irq
(
&
priv
->
meth_lock
);
/* Restart DMA notification */
priv
->
dma_ctrl
|=
METH_DMA_TX_INT_EN
;
mace_eth_write
(
priv
->
dma_ctrl
,
dma_ctrl
);
spin_unlock_irqrestore
(
&
priv
->
meth_lock
,
flags
);
return
0
;
}
...
...
@@ -704,17 +746,17 @@ int meth_tx(struct sk_buff *skb, struct net_device *dev)
/*
* Deal with a transmit timeout.
*/
void
meth_tx_timeout
(
struct
net_device
*
dev
)
static
void
meth_tx_timeout
(
struct
net_device
*
dev
)
{
struct
meth_private
*
priv
=
(
struct
meth_private
*
)
dev
->
priv
;
unsigned
long
flags
;
printk
(
KERN_WARNING
"%s: transmit timed out
\n
"
,
dev
->
name
);
/* Protect against concurrent rx interrupts */
spin_lock_irq
(
&
priv
->
meth_lock
);
spin_lock_irq
save
(
&
priv
->
meth_lock
,
flags
);
/* Try to reset the
adaptor
. */
/* Try to reset the
interface
. */
meth_reset
(
dev
);
priv
->
stats
.
tx_errors
++
;
...
...
@@ -726,10 +768,11 @@ void meth_tx_timeout (struct net_device *dev)
meth_init_rx_ring
(
priv
);
/* Restart dma */
priv
->
regs
->
dma_ctrl
|=
METH_DMA_TX_EN
|
METH_DMA_RX_EN
|
METH_DMA_RX_INT_EN
;
priv
->
dma_ctrl
|=
METH_DMA_TX_EN
|
METH_DMA_RX_EN
|
METH_DMA_RX_INT_EN
;
mace_eth_write
(
priv
->
dma_ctrl
,
dma_ctrl
);
/* Enable interrupt */
spin_unlock_irq
(
&
priv
->
meth_lock
);
spin_unlock_irq
restore
(
&
priv
->
meth_lock
,
flags
);
dev
->
trans_start
=
jiffies
;
netif_wake_queue
(
dev
);
...
...
@@ -740,29 +783,28 @@ void meth_tx_timeout (struct net_device *dev)
/*
* Ioctl commands
*/
int
meth_ioctl
(
struct
net_device
*
dev
,
struct
ifreq
*
rq
,
int
cmd
)
static
int
meth_ioctl
(
struct
net_device
*
dev
,
struct
ifreq
*
rq
,
int
cmd
)
{
DPRINTK
(
"ioctl
\n
"
);
return
0
;
DPRINTK
(
"ioctl
\n
"
);
return
0
;
}
/*
* Return statistics to the caller
*/
struct
net_device_stats
*
meth_stats
(
struct
net_device
*
dev
)
st
atic
st
ruct
net_device_stats
*
meth_stats
(
struct
net_device
*
dev
)
{
struct
meth_private
*
priv
=
(
struct
meth_private
*
)
dev
->
priv
;
return
&
priv
->
stats
;
struct
meth_private
*
priv
=
(
struct
meth_private
*
)
dev
->
priv
;
return
&
priv
->
stats
;
}
/*
* The init function
(sometimes called probe)
.
* The init function.
*/
static
struct
net_device
*
meth_init
(
struct
net_device
*
dev
)
static
struct
net_device
*
meth_init
(
void
)
{
struct
net_device
*
dev
;
meth_private
*
priv
;
struct
meth_private
*
priv
;
int
ret
;
dev
=
alloc_etherdev
(
sizeof
(
struct
meth_private
));
...
...
@@ -779,62 +821,26 @@ static struct net_device *meth_init(struct net_device *dev)
dev
->
tx_timeout
=
meth_tx_timeout
;
dev
->
watchdog_timeo
=
timeout
;
#endif
dev
->
irq
=
MACE_ETHERNET_IRQ
;
SET_MODULE_OWNER
(
dev
)
;
dev
->
irq
=
MACE_ETHERNET_IRQ
;
dev
->
base_addr
=
(
unsigned
long
)
&
mace
->
eth
;
priv
=
dev
->
priv
;
priv
=
(
struct
meth_private
*
)
dev
->
priv
;
spin_lock_init
(
&
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 */
ret
=
meth_reset
(
dev
);
if
(
ret
<
0
)
goto
out
;
/* Allocate the ring buffers */
ret
=
meth_init_tx_ring
(
priv
);
if
(
ret
<
0
)
goto
out
;
ret
=
meth_init_rx_ring
(
priv
);
if
(
ret
<
0
)
goto
out1
;
ret
=
register_netdev
(
dev
);
if
(
ret
)
goto
out2
;
printk
(
"SGI O2 Fast Ethernet rev. %ld
\n
"
,
priv
->
regs
->
mac_ctrl
>>
29
);
return
ret
;
if
(
ret
)
{
free_netdev
(
dev
);
return
ERR_PTR
(
ret
);
}
out2:
meth_free_rx_ring
(
priv
);
out1:
meth_free_tx_ring
(
priv
);
out:
free_netdev
(
dev
);
return
ERR_PTR
(
ret
);
printk
(
KERN_INFO
"%s: SGI MACE Ethernet rev. %d
\n
"
,
dev
->
name
,
(
unsigned
int
)
mace_eth_read
(
mac_ctrl
)
>>
29
);
return
0
;
}
/*
* The devices
*/
static
struct
net_device
*
meth_dev
;
struct
net_device
*
meth_dev
;
/*
* Finally, the module stuff
*/
int
meth_init_module
(
void
)
static
int
__init
meth_init_module
(
void
)
{
meth_dev
=
meth_init
();
if
(
IS_ERR
(
meth_dev
))
...
...
@@ -842,14 +848,11 @@ int meth_init_module(void)
return
0
;
}
void
meth_cleanup
(
void
)
static
void
__exit
meth_exit_module
(
void
)
{
meth_private
*
priv
=
meth_dev
->
priv
;
unregister_netdev
(
meth_dev
);
meth_free_rx_ring
(
priv
);
meth_free_tx_ring
(
priv
);
free_netdev
(
meth_dev
);
}
module_init
(
meth_init_module
);
module_exit
(
meth_
cleanup
);
module_exit
(
meth_
exit_module
);
drivers/net/meth.h
View file @
787a6212
...
...
@@ -16,9 +16,6 @@
/* 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?*/
...
...
@@ -27,10 +24,12 @@
#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 METH_RX_HEAD 34
/* status + 3 quad garbage-fill + 2 byte zero-pad */
#define RX_BUFFER_OFFSET (sizeof(rx_status_vector)+2)
/* staus vector + 2 bytes of padding */
#define RX_BUCKET_SIZE 256
#undef BIT
#define BIT(x) (1 << (x))
/* For more detailed explanations of what each field menas,
see Nick's great comments to #defines below (or docs, if
...
...
@@ -85,7 +84,7 @@ typedef struct tx_packet {
}
tx_packet
;
typedef
union
rx_status_vector
{
struct
{
volatile
struct
{
u64
pad1
:
1
;
/*fill it with ones*/
u64
pad2
:
15
;
/*fill with 0*/
u64
ip_chk_sum
:
16
;
...
...
@@ -103,7 +102,7 @@ typedef union rx_status_vector {
u64
rx_code_violation
:
1
;
u64
rx_len
:
16
;
}
parsed
;
u64
raw
;
volatile
u64
raw
;
}
rx_status_vector
;
typedef
struct
rx_packet
{
...
...
@@ -113,50 +112,8 @@ typedef struct rx_packet {
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
;
#define TX_INFO_RPTR 0x00FF0000
#define TX_INFO_WPTR 0x000000FF
/* Bits in METH_MAC */
...
...
@@ -203,9 +160,14 @@ typedef struct meth_regs {
#define METH_DMA_RX_EN BIT(15)
/* Enable RX */
#define METH_DMA_RX_INT_EN BIT(9)
/* Enable interrupt on RX packet */
/* RX FIFO MCL Info bits */
#define METH_RX_FIFO_WPTR(x) (((x)>>16)&0xf)
#define METH_RX_FIFO_RPTR(x) (((x)>>8)&0xf)
#define METH_RX_FIFO_DEPTH(x) ((x)&0x1f)
/* RX status bits */
#define METH_RX_ST_VALID BIT(63)
#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)
...
...
@@ -240,25 +202,34 @@ typedef struct meth_regs {
#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 */
/*#define METH_INT_RX_RPTR_MASK 0x0001F00*/
/* Bits 8 through 12 alias of RX read-pointer */
#define METH_INT_RX_RPTR_MASK 0x0000F00
/* Bits 8 through 11 alias of RX read-pointer - so, is Rx FIFO 16 or 32 entry?*/
/* 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_TX_RPTR_MASK 0x1FF0000
/* Bits 16 through 24 alias of TX read-pointer */
#define METH_INT_RX_SEQ_MASK 0x2E000000
/* Bits 25 through 29 are the starting seq number for the message at the */
#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_ERROR (METH_INT_TX_LINK_FAIL|
\
METH_INT_MEM_ERROR|
\
METH_INT_TX_ABORT|
\
METH_INT_RX_OVERFLOW|
\
METH_INT_RX_UNDERFLOW
)
#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 */
#define METH_TX_ST_DONE BIT(63)
/* TX complete */
#define METH_TX_ST_SUCCESS BIT(23)
/* Packet was transmitted successfully */
#define METH_TX_ST_TOOLONG BIT(24)
/* TX abort due to excessive length */
#define METH_TX_ST_UNDERRUN BIT(25)
/* TX abort due to underrun (?) */
#define METH_TX_ST_EXCCOLL BIT(26)
/* TX abort due to excess collisions */
#define METH_TX_ST_DEFER BIT(27)
/* TX abort due to excess deferals */
#define METH_TX_ST_LATECOLL BIT(28)
/* TX abort due to late collision */
/* Tx command header bits */
#define METH_TX_CMD_INT_EN BIT(24)
/* Generate TX interrupt when packet is sent */
...
...
@@ -271,3 +242,5 @@ typedef struct meth_regs {
#define PHY_ICS1889 0x0015F41
/* ICS FX */
#define PHY_ICS1890 0x0015F42
/* ICS TX */
#define PHY_DP83840 0x20005C0
/* National TX */
#define ADVANCE_RX_PTR(x) x=(x+1)&(RX_RING_ENTRIES-1)
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