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
fc3b6177
Commit
fc3b6177
authored
Apr 25, 2004
by
Jeff Garzik
Browse files
Options
Browse Files
Download
Plain Diff
Merge redhat.com:/spare/repo/netdev-2.6/mips
into redhat.com:/spare/repo/net-drivers-2.6
parents
2d095b6c
8cee2695
Changes
9
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
1353 additions
and
1554 deletions
+1353
-1554
drivers/net/Kconfig
drivers/net/Kconfig
+22
-1
drivers/net/bagetlance.c
drivers/net/bagetlance.c
+1
-1
drivers/net/declance.c
drivers/net/declance.c
+47
-20
drivers/net/ioc3-eth.c
drivers/net/ioc3-eth.c
+555
-796
drivers/net/irda/au1k_ir.c
drivers/net/irda/au1k_ir.c
+61
-49
drivers/net/meth.c
drivers/net/meth.c
+426
-423
drivers/net/meth.h
drivers/net/meth.h
+32
-59
drivers/net/sb1250-mac.c
drivers/net/sb1250-mac.c
+106
-110
drivers/net/sgiseeq.c
drivers/net/sgiseeq.c
+103
-95
No files found.
drivers/net/Kconfig
View file @
fc3b6177
...
...
@@ -471,11 +471,32 @@ config SGI_IOC3_ETH
bool "SGI IOC3 Ethernet"
depends on NET_ETHERNET && SGI_IP27
select CRC32
select MII
help
If you have a network (Ethernet) card of this type, say Y and read
the Ethernet-HOWTO, available from
<http://www.tldp.org/docs.html#howto>.
config SGI_IOC3_ETH_HW_RX_CSUM
bool "Receive hardware checksums"
depends on SGI_IOC3_ETH && INET
default y
help
The SGI IOC3 network adapter supports TCP and UDP checksums in
hardware to offload processing of these checksums from the CPU. At
the moment only acceleration of IPv4 is supported. This option
enables offloading for checksums on receive. If unsure, say Y.
config SGI_IOC3_ETH_HW_TX_CSUM
bool "Transmit hardware checksums"
depends on SGI_IOC3_ETH && INET
default y
help
The SGI IOC3 network adapter supports TCP and UDP checksums in
hardware to offload processing of these checksums from the CPU. At
the moment only acceleration of IPv4 is supported. This option
enables offloading for checksums on transmit. If unsure, say Y.
config SGI_O2MACE_ETH
tristate "SGI O2 MACE Fast Ethernet support"
depends on NET_ETHERNET && SGI_IP32=y
...
...
@@ -1777,7 +1798,7 @@ config SGISEEQ
config DECLANCE
tristate "DEC LANCE ethernet controller support"
depends on NET_ETHERNET && DECSTATION
depends on NET_ETHERNET &&
MACH_
DECSTATION
select CRC32
help
This driver is for the series of Ethernet controllers produced by
...
...
drivers/net/bagetlance.c
View file @
fc3b6177
/*
$Id$
/*
* bagetlance.c: Ethernet driver for VME Lance cards on Baget/MIPS
* This code stealed and adopted from linux/drivers/net/atarilance.c
* See that for author info
...
...
drivers/net/declance.c
View file @
fc3b6177
...
...
@@ -786,7 +786,7 @@ static int lance_open(struct net_device *dev)
/* Associate IRQ with lance_interrupt */
if
(
request_irq
(
dev
->
irq
,
&
lance_interrupt
,
0
,
"lance"
,
dev
))
{
printk
(
"
lance: Can't get IRQ %d
\n
"
,
dev
->
irq
);
printk
(
"
%s: Can't get IRQ %d
\n
"
,
dev
->
name
,
dev
->
irq
);
return
-
EAGAIN
;
}
if
(
lp
->
dma_irq
>=
0
)
{
...
...
@@ -795,7 +795,8 @@ static int lance_open(struct net_device *dev)
if
(
request_irq
(
lp
->
dma_irq
,
&
lance_dma_merr_int
,
0
,
"lance error"
,
dev
))
{
free_irq
(
dev
->
irq
,
dev
);
printk
(
"lance: Can't get DMA IRQ %d
\n
"
,
lp
->
dma_irq
);
printk
(
"%s: Can't get DMA IRQ %d
\n
"
,
dev
->
name
,
lp
->
dma_irq
);
return
-
EAGAIN
;
}
...
...
@@ -877,8 +878,8 @@ static void lance_tx_timeout(struct net_device *dev)
volatile
struct
lance_regs
*
ll
=
lp
->
ll
;
printk
(
KERN_ERR
"%s: transmit timed out, status %04x, reset
\n
"
,
dev
->
name
,
ll
->
rdp
);
lance_reset
(
dev
);
dev
->
name
,
ll
->
rdp
);
lance_reset
(
dev
);
netif_wake_queue
(
dev
);
}
...
...
@@ -1025,6 +1026,8 @@ static void lance_set_multicast_retry(unsigned long _opaque)
static
int
__init
dec_lance_init
(
const
int
type
,
const
int
slot
)
{
static
unsigned
version_printed
;
static
const
char
fmt
[]
=
"declance%d"
;
char
name
[
10
];
struct
net_device
*
dev
;
struct
lance_private
*
lp
;
volatile
struct
lance_regs
*
ll
;
...
...
@@ -1039,10 +1042,22 @@ static int __init dec_lance_init(const int type, const int slot)
if
(
dec_lance_debug
&&
version_printed
++
==
0
)
printk
(
version
);
i
=
0
;
dev
=
root_lance_dev
;
while
(
dev
)
{
i
++
;
lp
=
(
struct
lance_private
*
)
dev
->
priv
;
dev
=
lp
->
next
;
}
snprintf
(
name
,
sizeof
(
name
),
fmt
,
i
);
dev
=
alloc_etherdev
(
sizeof
(
struct
lance_private
));
if
(
!
dev
)
return
-
ENOMEM
;
SET_MODULE_OWNER
(
dev
);
if
(
!
dev
)
{
printk
(
KERN_ERR
"%s: Unable to allocate etherdev, aborting.
\n
"
,
name
);
ret
=
-
ENOMEM
;
goto
err_out
;
}
/*
* alloc_etherdev ensures the data structures used by the LANCE
...
...
@@ -1160,9 +1175,10 @@ static int __init dec_lance_init(const int type, const int slot)
break
;
default:
printk
(
"declance_init called with unknown type
\n
"
);
printk
(
KERN_ERR
"%s: declance_init called with unknown type
\n
"
,
name
);
ret
=
-
ENODEV
;
goto
err_out
;
goto
err_out
_free_dev
;
}
ll
=
(
struct
lance_regs
*
)
dev
->
base_addr
;
...
...
@@ -1172,19 +1188,21 @@ static int __init dec_lance_init(const int type, const int slot)
/* First, check for test pattern */
if
(
esar
[
0x60
]
!=
0xff
&&
esar
[
0x64
]
!=
0x00
&&
esar
[
0x68
]
!=
0x55
&&
esar
[
0x6c
]
!=
0xaa
)
{
printk
(
"Ethernet station address prom not found!
\n
"
);
printk
(
KERN_ERR
"%s: Ethernet station address prom not found!
\n
"
,
name
);
ret
=
-
ENODEV
;
goto
err_out
;
goto
err_out
_free_dev
;
}
/* Check the prom contents */
for
(
i
=
0
;
i
<
8
;
i
++
)
{
if
(
esar
[
i
*
4
]
!=
esar
[
0x3c
-
i
*
4
]
&&
esar
[
i
*
4
]
!=
esar
[
0x40
+
i
*
4
]
&&
esar
[
0x3c
-
i
*
4
]
!=
esar
[
0x40
+
i
*
4
])
{
printk
(
"Something is wrong with the ethernet
"
"station address prom!
\n
"
);
printk
(
KERN_ERR
"%s: Something is wrong with the
"
"ethernet station address prom!
\n
"
,
name
);
ret
=
-
ENODEV
;
goto
err_out
;
goto
err_out
_free_dev
;
}
}
...
...
@@ -1194,13 +1212,13 @@ static int __init dec_lance_init(const int type, const int slot)
*/
switch
(
type
)
{
case
ASIC_LANCE
:
printk
(
"%s: IOASIC onboard LANCE, addr = "
,
dev
->
name
);
printk
(
"%s: IOASIC onboard LANCE, addr = "
,
name
);
break
;
case
PMAD_LANCE
:
printk
(
"%s: PMAD-AA, addr = "
,
dev
->
name
);
printk
(
"%s: PMAD-AA, addr = "
,
name
);
break
;
case
PMAX_LANCE
:
printk
(
"%s: PMAX onboard LANCE, addr = "
,
dev
->
name
);
printk
(
"%s: PMAX onboard LANCE, addr = "
,
name
);
break
;
}
for
(
i
=
0
;
i
<
6
;
i
++
)
{
...
...
@@ -1236,15 +1254,24 @@ static int __init dec_lance_init(const int type, const int slot)
init_timer
(
&
lp
->
multicast_timer
);
lp
->
multicast_timer
.
data
=
(
unsigned
long
)
dev
;
lp
->
multicast_timer
.
function
=
&
lance_set_multicast_retry
;
ret
=
register_netdev
(
dev
);
if
(
ret
)
goto
err_out
;
if
(
ret
)
{
printk
(
KERN_ERR
"%s: Unable to register netdev, aborting.
\n
"
,
name
);
goto
err_out_free_dev
;
}
lp
->
next
=
root_lance_dev
;
root_lance_dev
=
dev
;
printk
(
"%s: registered as %s.
\n
"
,
name
,
dev
->
name
);
return
0
;
err_out_free_dev:
kfree
(
dev
);
err_out:
free_netdev
(
dev
);
return
ret
;
}
...
...
drivers/net/ioc3-eth.c
View file @
fc3b6177
...
...
@@ -26,6 +26,10 @@
* which workarounds are required for them? Do we ever have Lucent's?
* o For the 2.5 branch kill the mii-tool ioctls.
*/
#define IOC3_NAME "ioc3-eth"
#define IOC3_VERSION "2.6.3-3"
#include <linux/config.h>
#include <linux/init.h>
#include <linux/delay.h>
...
...
@@ -35,6 +39,11 @@
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/crc32.h>
#include <linux/mii.h>
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/udp.h>
#ifdef CONFIG_SERIAL_8250
#include <linux/serial.h>
...
...
@@ -48,8 +57,10 @@
#include <linux/ethtool.h>
#include <linux/skbuff.h>
#include <linux/dp83840.h>
#include <net/ip.h>
#include <asm/byteorder.h>
#include <asm/checksum.h>
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/uaccess.h>
...
...
@@ -68,18 +79,12 @@
*/
#define RX_BUFFS 64
/* Timer state engine. */
enum
ioc3_timer_state
{
arbwait
=
0
,
/* Waiting for auto negotiation to complete. */
lupwait
=
1
,
/* Auto-neg complete, awaiting link-up status. */
ltrywait
=
2
,
/* Forcing try of all modes, from fastest to slowest. */
asleep
=
3
,
/* Time inactive. */
};
#define ETCSR_FD ((17<<ETCSR_IPGR2_SHIFT) | (11<<ETCSR_IPGR1_SHIFT) | 21)
#define ETCSR_HD ((21<<ETCSR_IPGR2_SHIFT) | (21<<ETCSR_IPGR1_SHIFT) | 21)
/* Private per NIC data of the driver. */
struct
ioc3_private
{
struct
ioc3
*
regs
;
int
phy
;
unsigned
long
*
rxr
;
/* pointer to receiver ring */
struct
ioc3_etxd
*
txr
;
struct
sk_buff
*
rx_skbs
[
512
];
...
...
@@ -92,50 +97,69 @@ struct ioc3_private {
int
txqlen
;
u32
emcr
,
ehar_h
,
ehar_l
;
spinlock_t
ioc3_lock
;
struct
net_device
*
dev
;
struct
mii_if_info
mii
;
struct
pci_dev
*
pdev
;
/* Members used by autonegotiation */
struct
timer_list
ioc3_timer
;
enum
ioc3_timer_state
timer_state
;
/* State of auto-neg timer. */
unsigned
int
timer_ticks
;
/* Number of clicks at each state */
unsigned
short
sw_bmcr
;
/* sw copy of MII config register */
unsigned
short
sw_bmsr
;
/* sw copy of MII status register */
unsigned
short
sw_physid1
;
/* sw copy of PHYSID1 */
unsigned
short
sw_physid2
;
/* sw copy of PHYSID2 */
unsigned
short
sw_advertise
;
/* sw copy of ADVERTISE */
unsigned
short
sw_lpa
;
/* sw copy of LPA */
unsigned
short
sw_csconfig
;
/* sw copy of CSCONFIG */
};
static
inline
struct
net_device
*
priv_netdev
(
struct
ioc3_private
*
dev
)
{
return
(
void
*
)
dev
-
((
sizeof
(
struct
net_device
)
+
31
)
&
~
31
);
}
static
int
ioc3_ioctl
(
struct
net_device
*
dev
,
struct
ifreq
*
rq
,
int
cmd
);
static
void
ioc3_set_multicast_list
(
struct
net_device
*
dev
);
static
int
ioc3_start_xmit
(
struct
sk_buff
*
skb
,
struct
net_device
*
dev
);
static
void
ioc3_timeout
(
struct
net_device
*
dev
);
static
inline
unsigned
int
ioc3_hash
(
const
unsigned
char
*
addr
);
static
inline
void
ioc3_stop
(
struct
ioc3_private
*
ip
);
static
void
ioc3_init
(
struct
ioc3_private
*
ip
);
static
void
ioc3_init
(
struct
net_device
*
dev
);
static
const
char
ioc3_str
[]
=
"IOC3 Ethernet"
;
static
struct
ethtool_ops
ioc3_ethtool_ops
;
/* We use this to acquire receive skb's that we can DMA directly into. */
#define ALIGNED_RX_SKB_ADDR(addr) \
((((unsigned long)(addr) + (128 - 1)) & ~(128 - 1)) - (unsigned long)(addr))
#define ioc3_alloc_skb(__length, __gfp_flags) \
({ struct sk_buff *__skb; \
__skb = alloc_skb((__length) + 128, (__gfp_flags)); \
if (__skb) { \
int __offset = ALIGNED_RX_SKB_ADDR(__skb->data); \
if(__offset) \
skb_reserve(__skb, __offset); \
} \
__skb; \
})
#define IOC3_CACHELINE 128UL
static
inline
unsigned
long
aligned_rx_skb_addr
(
unsigned
long
addr
)
{
return
(
~
addr
+
1
)
&
(
IOC3_CACHELINE
-
1UL
);
}
static
inline
struct
sk_buff
*
ioc3_alloc_skb
(
unsigned
long
length
,
unsigned
int
gfp_mask
)
{
struct
sk_buff
*
skb
;
skb
=
alloc_skb
(
length
+
IOC3_CACHELINE
-
1
,
gfp_mask
);
if
(
likely
(
skb
))
{
int
offset
=
aligned_rx_skb_addr
((
unsigned
long
)
skb
->
data
);
if
(
offset
)
skb_reserve
(
skb
,
offset
);
}
return
skb
;
}
static
inline
unsigned
long
ioc3_map
(
void
*
ptr
,
unsigned
long
vdev
)
{
#ifdef CONFIG_SGI_IP27
vdev
<<=
58
;
/* Shift to PCI64_ATTR_VIRTUAL */
return
vdev
|
(
0xaUL
<<
PCI64_ATTR_TARG_SHFT
)
|
PCI64_ATTR_PREF
|
((
unsigned
long
)
ptr
&
TO_PHYS_MASK
);
#else
return
virt_to_bus
(
ptr
);
#endif
}
/* BEWARE: The IOC3 documentation documents the size of rx buffers as
1644 while it's actually 1664. This one was nasty to track down ... */
#define RX_OFFSET 10
#define RX_BUF_ALLOC_SIZE (1664 + RX_OFFSET +
128
)
#define RX_BUF_ALLOC_SIZE (1664 + RX_OFFSET +
IOC3_CACHELINE
)
/* DMA barrier to separate cached and uncached accesses. */
#define BARRIER() \
...
...
@@ -144,70 +168,114 @@ static const char ioc3_str[] = "IOC3 Ethernet";
#define IOC3_SIZE 0x100000
#define ioc3_r(reg) \
({ \
u32 __res; \
__res = ioc3->reg; \
__res; \
})
#define ioc3_w(reg,val) \
do { \
(ioc3->reg = (val)); \
} while(0)
static
inline
u32
mcr_pack
(
u32
pulse
,
u32
sample
)
/*
* IOC3 is a big endian device
*
* Unorthodox but makes the users of these macros more readable - the pointer
* to the IOC3's memory mapped registers is expected as struct ioc3 * ioc3
* in the environment.
*/
#define ioc3_r_mcr() be32_to_cpu(ioc3->mcr)
#define ioc3_w_mcr(v) do { ioc3->mcr = cpu_to_be32(v); } while (0)
#define ioc3_w_gpcr_s(v) do { ioc3->gpcr_s = cpu_to_be32(v); } while (0)
#define ioc3_r_emcr() be32_to_cpu(ioc3->emcr)
#define ioc3_w_emcr(v) do { ioc3->emcr = cpu_to_be32(v); } while (0)
#define ioc3_r_eisr() be32_to_cpu(ioc3->eisr)
#define ioc3_w_eisr(v) do { ioc3->eisr = cpu_to_be32(v); } while (0)
#define ioc3_r_eier() be32_to_cpu(ioc3->eier)
#define ioc3_w_eier(v) do { ioc3->eier = cpu_to_be32(v); } while (0)
#define ioc3_r_ercsr() be32_to_cpu(ioc3->ercsr)
#define ioc3_w_ercsr(v) do { ioc3->ercsr = cpu_to_be32(v); } while (0)
#define ioc3_r_erbr_h() be32_to_cpu(ioc3->erbr_h)
#define ioc3_w_erbr_h(v) do { ioc3->erbr_h = cpu_to_be32(v); } while (0)
#define ioc3_r_erbr_l() be32_to_cpu(ioc3->erbr_l)
#define ioc3_w_erbr_l(v) do { ioc3->erbr_l = cpu_to_be32(v); } while (0)
#define ioc3_r_erbar() be32_to_cpu(ioc3->erbar)
#define ioc3_w_erbar(v) do { ioc3->erbar = cpu_to_be32(v); } while (0)
#define ioc3_r_ercir() be32_to_cpu(ioc3->ercir)
#define ioc3_w_ercir(v) do { ioc3->ercir = cpu_to_be32(v); } while (0)
#define ioc3_r_erpir() be32_to_cpu(ioc3->erpir)
#define ioc3_w_erpir(v) do { ioc3->erpir = cpu_to_be32(v); } while (0)
#define ioc3_r_ertr() be32_to_cpu(ioc3->ertr)
#define ioc3_w_ertr(v) do { ioc3->ertr = cpu_to_be32(v); } while (0)
#define ioc3_r_etcsr() be32_to_cpu(ioc3->etcsr)
#define ioc3_w_etcsr(v) do { ioc3->etcsr = cpu_to_be32(v); } while (0)
#define ioc3_r_ersr() be32_to_cpu(ioc3->ersr)
#define ioc3_w_ersr(v) do { ioc3->ersr = cpu_to_be32(v); } while (0)
#define ioc3_r_etcdc() be32_to_cpu(ioc3->etcdc)
#define ioc3_w_etcdc(v) do { ioc3->etcdc = cpu_to_be32(v); } while (0)
#define ioc3_r_ebir() be32_to_cpu(ioc3->ebir)
#define ioc3_w_ebir(v) do { ioc3->ebir = cpu_to_be32(v); } while (0)
#define ioc3_r_etbr_h() be32_to_cpu(ioc3->etbr_h)
#define ioc3_w_etbr_h(v) do { ioc3->etbr_h = cpu_to_be32(v); } while (0)
#define ioc3_r_etbr_l() be32_to_cpu(ioc3->etbr_l)
#define ioc3_w_etbr_l(v) do { ioc3->etbr_l = cpu_to_be32(v); } while (0)
#define ioc3_r_etcir() be32_to_cpu(ioc3->etcir)
#define ioc3_w_etcir(v) do { ioc3->etcir = cpu_to_be32(v); } while (0)
#define ioc3_r_etpir() be32_to_cpu(ioc3->etpir)
#define ioc3_w_etpir(v) do { ioc3->etpir = cpu_to_be32(v); } while (0)
#define ioc3_r_emar_h() be32_to_cpu(ioc3->emar_h)
#define ioc3_w_emar_h(v) do { ioc3->emar_h = cpu_to_be32(v); } while (0)
#define ioc3_r_emar_l() be32_to_cpu(ioc3->emar_l)
#define ioc3_w_emar_l(v) do { ioc3->emar_l = cpu_to_be32(v); } while (0)
#define ioc3_r_ehar_h() be32_to_cpu(ioc3->ehar_h)
#define ioc3_w_ehar_h(v) do { ioc3->ehar_h = cpu_to_be32(v); } while (0)
#define ioc3_r_ehar_l() be32_to_cpu(ioc3->ehar_l)
#define ioc3_w_ehar_l(v) do { ioc3->ehar_l = cpu_to_be32(v); } while (0)
#define ioc3_r_micr() be32_to_cpu(ioc3->micr)
#define ioc3_w_micr(v) do { ioc3->micr = cpu_to_be32(v); } while (0)
#define ioc3_r_midr_r() be32_to_cpu(ioc3->midr_r)
#define ioc3_w_midr_r(v) do { ioc3->midr_r = cpu_to_be32(v); } while (0)
#define ioc3_r_midr_w() be32_to_cpu(ioc3->midr_w)
#define ioc3_w_midr_w(v) do { ioc3->midr_w = cpu_to_be32(v); } while (0)
static
inline
u32
mcr_pack
(
u32
pulse
,
u32
sample
)
{
return
(
pulse
<<
10
)
|
(
sample
<<
2
);
}
static
int
nic_wait
(
struct
ioc3
*
ioc3
)
static
int
nic_wait
(
struct
ioc3
*
ioc3
)
{
u32
mcr
;
do
{
mcr
=
ioc3_r
(
mcr
);
mcr
=
ioc3_r
_mcr
(
);
}
while
(
!
(
mcr
&
2
));
return
mcr
&
1
;
}
static
int
nic_reset
(
struct
ioc3
*
ioc3
)
static
int
nic_reset
(
struct
ioc3
*
ioc3
)
{
int
presence
;
ioc3_w
(
mcr
,
mcr_pack
(
500
,
65
));
ioc3_w
_mcr
(
mcr_pack
(
500
,
65
));
presence
=
nic_wait
(
ioc3
);
ioc3_w
(
mcr
,
mcr_pack
(
0
,
500
));
ioc3_w
_mcr
(
mcr_pack
(
0
,
500
));
nic_wait
(
ioc3
);
return
presence
;
}
static
inline
int
nic_read_bit
(
struct
ioc3
*
ioc3
)
static
inline
int
nic_read_bit
(
struct
ioc3
*
ioc3
)
{
int
result
;
ioc3_w
(
mcr
,
mcr_pack
(
6
,
13
));
ioc3_w
_mcr
(
mcr_pack
(
6
,
13
));
result
=
nic_wait
(
ioc3
);
ioc3_w
(
mcr
,
mcr_pack
(
0
,
100
));
ioc3_w
_mcr
(
mcr_pack
(
0
,
100
));
nic_wait
(
ioc3
);
return
result
;
}
static
inline
void
nic_write_bit
(
struct
ioc3
*
ioc3
,
int
bit
)
static
inline
void
nic_write_bit
(
struct
ioc3
*
ioc3
,
int
bit
)
{
if
(
bit
)
ioc3_w
(
mcr
,
mcr_pack
(
6
,
110
));
ioc3_w
_mcr
(
mcr_pack
(
6
,
110
));
else
ioc3_w
(
mcr
,
mcr_pack
(
80
,
30
));
ioc3_w
_mcr
(
mcr_pack
(
80
,
30
));
nic_wait
(
ioc3
);
}
...
...
@@ -215,8 +283,7 @@ nic_write_bit(struct ioc3 *ioc3, int bit)
/*
* Read a byte from an iButton device
*/
static
u32
nic_read_byte
(
struct
ioc3
*
ioc3
)
static
u32
nic_read_byte
(
struct
ioc3
*
ioc3
)
{
u32
result
=
0
;
int
i
;
...
...
@@ -230,8 +297,7 @@ nic_read_byte(struct ioc3 *ioc3)
/*
* Write a byte to an iButton device
*/
static
void
nic_write_byte
(
struct
ioc3
*
ioc3
,
int
byte
)
static
void
nic_write_byte
(
struct
ioc3
*
ioc3
,
int
byte
)
{
int
i
,
bit
;
...
...
@@ -243,8 +309,7 @@ nic_write_byte(struct ioc3 *ioc3, int byte)
}
}
static
u64
nic_find
(
struct
ioc3
*
ioc3
,
int
*
last
)
static
u64
nic_find
(
struct
ioc3
*
ioc3
,
int
*
last
)
{
int
a
,
b
,
index
,
disc
;
u64
address
=
0
;
...
...
@@ -352,7 +417,7 @@ static void ioc3_get_eaddr_nic(struct ioc3_private *ip)
int
tries
=
2
;
/* There may be some problem with the battery? */
int
i
;
ioc3_w
(
gpcr_s
,
(
1
<<
21
)
);
ioc3_w
_gpcr_s
(
1
<<
21
);
while
(
tries
--
)
{
if
(
!
nic_init
(
ioc3
))
...
...
@@ -374,7 +439,7 @@ static void ioc3_get_eaddr_nic(struct ioc3_private *ip)
nic
[
i
]
=
nic_read_byte
(
ioc3
);
for
(
i
=
2
;
i
<
8
;
i
++
)
ip
->
dev
->
dev_addr
[
i
-
2
]
=
nic
[
i
];
priv_netdev
(
ip
)
->
dev_addr
[
i
-
2
]
=
nic
[
i
];
}
/*
...
...
@@ -391,7 +456,7 @@ static void ioc3_get_eaddr(struct ioc3_private *ip)
printk
(
"Ethernet address is "
);
for
(
i
=
0
;
i
<
6
;
i
++
)
{
printk
(
"%02x"
,
ip
->
dev
->
dev_addr
[
i
]);
printk
(
"%02x"
,
priv_netdev
(
ip
)
->
dev_addr
[
i
]);
if
(
i
<
5
)
printk
(
":"
);
}
...
...
@@ -403,42 +468,112 @@ static void ioc3_get_eaddr(struct ioc3_private *ip)
* Caller must hold the ioc3_lock ever for MII readers. This is also
* used to protect the transmitter side but it's low contention.
*/
static
u16
mii_read
(
struct
ioc3_private
*
ip
,
int
reg
)
static
int
ioc3_mdio_read
(
struct
net_device
*
dev
,
int
phy
,
int
reg
)
{
struct
ioc3_private
*
ip
=
netdev_priv
(
dev
);
struct
ioc3
*
ioc3
=
ip
->
regs
;
int
phy
=
ip
->
phy
;
while
(
ioc3
->
micr
&
MICR_BUSY
);
ioc3
->
micr
=
(
phy
<<
MICR_PHYADDR_SHIFT
)
|
reg
|
MICR_READTRIG
;
while
(
ioc3
->
micr
&
MICR_BUSY
);
while
(
ioc3
_r_micr
()
&
MICR_BUSY
);
ioc3
_w_micr
((
phy
<<
MICR_PHYADDR_SHIFT
)
|
reg
|
MICR_READTRIG
)
;
while
(
ioc3
_r_micr
()
&
MICR_BUSY
);
return
ioc3
->
midr_r
&
MIDR_DATA_MASK
;
return
ioc3
_r_micr
()
&
MIDR_DATA_MASK
;
}
static
void
mii_write
(
struct
ioc3_private
*
ip
,
int
reg
,
u16
data
)
static
void
ioc3_mdio_write
(
struct
net_device
*
dev
,
int
phy
,
int
reg
,
int
data
)
{
struct
ioc3_private
*
ip
=
netdev_priv
(
dev
);
struct
ioc3
*
ioc3
=
ip
->
regs
;
int
phy
=
ip
->
phy
;
while
(
ioc3
->
micr
&
MICR_BUSY
);
ioc3
->
midr_w
=
data
;
ioc3
->
micr
=
(
phy
<<
MICR_PHYADDR_SHIFT
)
|
reg
;
while
(
ioc3
->
micr
&
MICR_BUSY
);
while
(
ioc3
_r_micr
()
&
MICR_BUSY
);
ioc3
_w_midr_w
(
data
)
;
ioc3
_w_micr
((
phy
<<
MICR_PHYADDR_SHIFT
)
|
reg
)
;
while
(
ioc3
_r_micr
()
&
MICR_BUSY
);
}
static
int
ioc3_mii_init
(
struct
ioc3_private
*
ip
);
static
struct
net_device_stats
*
ioc3_get_stats
(
struct
net_device
*
dev
)
{
struct
ioc3_private
*
ip
=
dev
->
priv
;
struct
ioc3_private
*
ip
=
netdev_priv
(
dev
)
;
struct
ioc3
*
ioc3
=
ip
->
regs
;
ip
->
stats
.
collisions
+=
(
ioc3
->
etcdc
&
ETCDC_COLLCNT_MASK
);
ip
->
stats
.
collisions
+=
(
ioc3
_r_etcdc
()
&
ETCDC_COLLCNT_MASK
);
return
&
ip
->
stats
;
}
static
inline
void
ioc3_rx
(
struct
ioc3_private
*
ip
)
#ifdef CONFIG_SGI_IOC3_ETH_HW_RX_CSUM
static
void
ioc3_tcpudp_checksum
(
struct
sk_buff
*
skb
,
uint32_t
hwsum
,
int
len
)
{
struct
ethhdr
*
eh
=
skb
->
mac
.
ethernet
;
uint32_t
csum
,
ehsum
;
unsigned
int
proto
;
struct
iphdr
*
ih
;
uint16_t
*
ew
;
unsigned
char
*
cp
;
/*
* Did hardware handle the checksum at all? The cases we can handle
* are:
*
* - TCP and UDP checksums of IPv4 only.
* - IPv6 would be doable but we keep that for later ...
* - Only unfragmented packets. Did somebody already tell you
* fragmentation is evil?
* - don't care about packet size. Worst case when processing a
* malformed packet we'll try to access the packet at ip header +
* 64 bytes which is still inside the skb. Even in the unlikely
* case where the checksum is right the higher layers will still
* drop the packet as appropriate.
*/
if
(
eh
->
h_proto
!=
ntohs
(
ETH_P_IP
))
return
;
ih
=
(
struct
iphdr
*
)
((
char
*
)
eh
+
ETH_HLEN
);
if
(
ih
->
frag_off
&
htons
(
IP_MF
|
IP_OFFSET
))
return
;
proto
=
ih
->
protocol
;
if
(
proto
!=
IPPROTO_TCP
&&
proto
!=
IPPROTO_UDP
)
return
;
/* Same as tx - compute csum of pseudo header */
csum
=
hwsum
+
(
ih
->
tot_len
-
(
ih
->
ihl
<<
2
))
+
htons
((
uint16_t
)
ih
->
protocol
)
+
(
ih
->
saddr
>>
16
)
+
(
ih
->
saddr
&
0xffff
)
+
(
ih
->
daddr
>>
16
)
+
(
ih
->
daddr
&
0xffff
);
/* Sum up ethernet dest addr, src addr and protocol */
ew
=
(
uint16_t
*
)
eh
;
ehsum
=
ew
[
0
]
+
ew
[
1
]
+
ew
[
2
]
+
ew
[
3
]
+
ew
[
4
]
+
ew
[
5
]
+
ew
[
6
];
ehsum
=
(
ehsum
&
0xffff
)
+
(
ehsum
>>
16
);
ehsum
=
(
ehsum
&
0xffff
)
+
(
ehsum
>>
16
);
csum
+=
0xffff
^
ehsum
;
/* In the next step we also subtract the 1's complement
checksum of the trailing ethernet CRC. */
cp
=
(
char
*
)
eh
+
len
;
/* points at trailing CRC */
if
(
len
&
1
)
{
csum
+=
0xffff
^
(
uint16_t
)
((
cp
[
1
]
<<
8
)
|
cp
[
0
]);
csum
+=
0xffff
^
(
uint16_t
)
((
cp
[
3
]
<<
8
)
|
cp
[
2
]);
}
else
{
csum
+=
0xffff
^
(
uint16_t
)
((
cp
[
0
]
<<
8
)
|
cp
[
1
]);
csum
+=
0xffff
^
(
uint16_t
)
((
cp
[
2
]
<<
8
)
|
cp
[
3
]);
}
csum
=
(
csum
&
0xffff
)
+
(
csum
>>
16
);
csum
=
(
csum
&
0xffff
)
+
(
csum
>>
16
);
if
(
csum
==
0xffff
)
skb
->
ip_summed
=
CHECKSUM_UNNECESSARY
;
}
#endif
/* CONFIG_SGI_IOC3_ETH_HW_RX_CSUM */
static
inline
void
ioc3_rx
(
struct
ioc3_private
*
ip
)
{
struct
sk_buff
*
skb
,
*
new_skb
;
struct
ioc3
*
ioc3
=
ip
->
regs
;
...
...
@@ -460,7 +595,7 @@ ioc3_rx(struct ioc3_private *ip)
if
(
err
&
ERXBUF_GOODPKT
)
{
len
=
((
w0
>>
ERXBUF_BYTECNT_SHIFT
)
&
0x7ff
)
-
4
;
skb_trim
(
skb
,
len
);
skb
->
protocol
=
eth_type_trans
(
skb
,
ip
->
dev
);
skb
->
protocol
=
eth_type_trans
(
skb
,
priv_netdev
(
ip
)
);
new_skb
=
ioc3_alloc_skb
(
RX_BUF_ALLOC_SIZE
,
GFP_ATOMIC
);
if
(
!
new_skb
)
{
...
...
@@ -470,18 +605,23 @@ ioc3_rx(struct ioc3_private *ip)
new_skb
=
skb
;
goto
next
;
}
#ifdef CONFIG_SGI_IOC3_ETH_HW_RX_CSUM
ioc3_tcpudp_checksum
(
skb
,
w0
&
ERXBUF_IPCKSUM_MASK
,
len
);
#endif
netif_rx
(
skb
);
ip
->
rx_skbs
[
rx_entry
]
=
NULL
;
/* Poison */
new_skb
->
dev
=
ip
->
dev
;
new_skb
->
dev
=
priv_netdev
(
ip
)
;
/* Because we reserve afterwards. */
skb_put
(
new_skb
,
(
1664
+
RX_OFFSET
));
rxb
=
(
struct
ioc3_erxbuf
*
)
new_skb
->
data
;
skb_reserve
(
new_skb
,
RX_OFFSET
);
ip
->
dev
->
last_rx
=
jiffies
;
priv_netdev
(
ip
)
->
last_rx
=
jiffies
;
ip
->
stats
.
rx_packets
++
;
/* Statistics */
ip
->
stats
.
rx_bytes
+=
len
;
}
else
{
...
...
@@ -497,8 +637,7 @@ ioc3_rx(struct ioc3_private *ip)
ip
->
stats
.
rx_frame_errors
++
;
next:
ip
->
rx_skbs
[
n_entry
]
=
new_skb
;
rxr
[
n_entry
]
=
cpu_to_be64
((
0xa5UL
<<
56
)
|
((
unsigned
long
)
rxb
&
TO_PHYS_MASK
));
rxr
[
n_entry
]
=
cpu_to_be64
(
ioc3_map
(
rxb
,
1
));
rxb
->
w0
=
0
;
/* Clear valid flag */
n_entry
=
(
n_entry
+
1
)
&
511
;
/* Update erpir */
...
...
@@ -508,13 +647,12 @@ ioc3_rx(struct ioc3_private *ip)
rxb
=
(
struct
ioc3_erxbuf
*
)
(
skb
->
data
-
RX_OFFSET
);
w0
=
be32_to_cpu
(
rxb
->
w0
);
}
ioc3
->
erpir
=
(
n_entry
<<
3
)
|
ERPIR_ARM
;
ioc3
_w_erpir
((
n_entry
<<
3
)
|
ERPIR_ARM
)
;
ip
->
rx_pi
=
n_entry
;
ip
->
rx_ci
=
rx_entry
;
}
static
inline
void
ioc3_tx
(
struct
ioc3_private
*
ip
)
static
inline
void
ioc3_tx
(
struct
ioc3_private
*
ip
)
{
unsigned
long
packets
,
bytes
;
struct
ioc3
*
ioc3
=
ip
->
regs
;
...
...
@@ -523,7 +661,7 @@ ioc3_tx(struct ioc3_private *ip)
u32
etcir
;
spin_lock
(
&
ip
->
ioc3_lock
);
etcir
=
ioc3
->
etcir
;
etcir
=
ioc3
_r_etcir
()
;
tx_entry
=
(
etcir
>>
7
)
&
127
;
o_entry
=
ip
->
tx_ci
;
...
...
@@ -539,7 +677,7 @@ ioc3_tx(struct ioc3_private *ip)
o_entry
=
(
o_entry
+
1
)
&
127
;
/* Next */
etcir
=
ioc3
->
etcir
;
/* More pkts sent? */
etcir
=
ioc3
_r_etcir
()
;
/* More pkts sent? */
tx_entry
=
(
etcir
>>
7
)
&
127
;
}
...
...
@@ -548,7 +686,7 @@ ioc3_tx(struct ioc3_private *ip)
ip
->
txqlen
-=
packets
;
if
(
ip
->
txqlen
<
128
)
netif_wake_queue
(
ip
->
dev
);
netif_wake_queue
(
priv_netdev
(
ip
)
);
ip
->
tx_ci
=
o_entry
;
spin_unlock
(
&
ip
->
ioc3_lock
);
...
...
@@ -561,12 +699,13 @@ ioc3_tx(struct ioc3_private *ip)
* with such error interrupts if something really goes wrong, so we might
* also consider to take the interface down.
*/
static
void
ioc3_error
(
struct
ioc3_private
*
ip
,
u32
eisr
)
static
void
ioc3_error
(
struct
ioc3_private
*
ip
,
u32
eisr
)
{
struct
net_device
*
dev
=
ip
->
dev
;
struct
net_device
*
dev
=
priv_netdev
(
ip
)
;
unsigned
char
*
iface
=
dev
->
name
;
spin_lock
(
&
ip
->
ioc3_lock
);
if
(
eisr
&
EISR_RXOFLO
)
printk
(
KERN_ERR
"%s: RX overflow.
\n
"
,
iface
);
if
(
eisr
&
EISR_RXBUFOFLO
)
...
...
@@ -581,11 +720,12 @@ ioc3_error(struct ioc3_private *ip, u32 eisr)
printk
(
KERN_ERR
"%s: TX PCI error.
\n
"
,
iface
);
ioc3_stop
(
ip
);
ioc3_init
(
ip
);
ioc3_init
(
dev
);
ioc3_mii_init
(
ip
);
dev
->
trans_start
=
jiffies
;
netif_wake_queue
(
dev
);
spin_unlock
(
&
ip
->
ioc3_lock
);
}
/* The interrupt handler does all of the Rx thread work and cleans up
...
...
@@ -593,524 +733,100 @@ ioc3_error(struct ioc3_private *ip, u32 eisr)
static
irqreturn_t
ioc3_interrupt
(
int
irq
,
void
*
_dev
,
struct
pt_regs
*
regs
)
{
struct
net_device
*
dev
=
(
struct
net_device
*
)
_dev
;
struct
ioc3_private
*
ip
=
dev
->
priv
;
struct
ioc3_private
*
ip
=
netdev_priv
(
dev
)
;
struct
ioc3
*
ioc3
=
ip
->
regs
;
const
u32
enabled
=
EISR_RXTIMERINT
|
EISR_RXOFLO
|
EISR_RXBUFOFLO
|
EISR_RXMEMERR
|
EISR_RXPARERR
|
EISR_TXBUFUFLO
|
EISR_TXEXPLICIT
|
EISR_TXMEMERR
;
u32
eisr
;
eisr
=
ioc3
->
eisr
&
enabled
;
eisr
=
ioc3
_r_eisr
()
&
enabled
;
while
(
eisr
)
{
ioc3
->
eisr
=
eisr
;
ioc3
->
eisr
;
/* Flush */
ioc3_w_eisr
(
eisr
);
(
void
)
ioc3_r_eisr
();
/* Flush */
if
(
eisr
&
(
EISR_RXOFLO
|
EISR_RXBUFOFLO
|
EISR_RXMEMERR
|
EISR_RXPARERR
|
EISR_TXBUFUFLO
|
EISR_TXMEMERR
))
ioc3_error
(
ip
,
eisr
);
if
(
eisr
&
EISR_RXTIMERINT
)
ioc3_rx
(
ip
);
if
(
eisr
&
EISR_TXEXPLICIT
)
ioc3_tx
(
ip
);
if
(
eisr
&
(
EISR_RXOFLO
|
EISR_RXBUFOFLO
|
EISR_RXMEMERR
|
EISR_RXPARERR
|
EISR_TXBUFUFLO
|
EISR_TXMEMERR
))
ioc3_error
(
ip
,
eisr
);
if
(
eisr
&
EISR_RXTIMERINT
)
ioc3_rx
(
ip
);
if
(
eisr
&
EISR_TXEXPLICIT
)
ioc3_tx
(
ip
);
eisr
=
ioc3
->
eisr
&
enabled
;
}
return
IRQ_HANDLED
;
}
/*
* Auto negotiation. The scheme is very simple. We have a timer routine that
* keeps watching the auto negotiation process as it progresses. The DP83840
* is first told to start doing it's thing, we set up the time and place the
* timer state machine in it's initial state.
*
* Here the timer peeks at the DP83840 status registers at each click to see
* if the auto negotiation has completed, we assume here that the DP83840 PHY
* will time out at some point and just tell us what (didn't) happen. For
* complete coverage we only allow so many of the ticks at this level to run,
* when this has expired we print a warning message and try another strategy.
* This "other" strategy is to force the interface into various speed/duplex
* configurations and we stop when we see a link-up condition before the
* maximum number of "peek" ticks have occurred.
*
* Once a valid link status has been detected we configure the IOC3 to speak
* the most efficient protocol we could get a clean link for. The priority
* for link configurations, highest first is:
*
* 100 Base-T Full Duplex
* 100 Base-T Half Duplex
* 10 Base-T Full Duplex
* 10 Base-T Half Duplex
*
* We start a new timer now, after a successful auto negotiation status has
* been detected. This timer just waits for the link-up bit to get set in
* the BMCR of the DP83840. When this occurs we print a kernel log message
* describing the link type in use and the fact that it is up.
*
* If a fatal error of some sort is signalled and detected in the interrupt
* service routine, and the chip is reset, or the link is ifconfig'd down
* and then back up, this entire process repeats itself all over again.
*/
static
int
ioc3_try_next_permutation
(
struct
ioc3_private
*
ip
)
{
ip
->
sw_bmcr
=
mii_read
(
ip
,
MII_BMCR
);
/* Downgrade from full to half duplex. Only possible via ethtool. */
if
(
ip
->
sw_bmcr
&
BMCR_FULLDPLX
)
{
ip
->
sw_bmcr
&=
~
BMCR_FULLDPLX
;
mii_write
(
ip
,
MII_BMCR
,
ip
->
sw_bmcr
);
return
0
;
}
/* Downgrade from 100 to 10. */
if
(
ip
->
sw_bmcr
&
BMCR_SPEED100
)
{
ip
->
sw_bmcr
&=
~
BMCR_SPEED100
;
mii_write
(
ip
,
MII_BMCR
,
ip
->
sw_bmcr
);
return
0
;
}
/* We've tried everything. */
return
-
1
;
}
static
void
ioc3_display_link_mode
(
struct
ioc3_private
*
ip
)
{
char
*
tmode
=
""
;
ip
->
sw_lpa
=
mii_read
(
ip
,
MII_LPA
);
if
(
ip
->
sw_lpa
&
(
LPA_100HALF
|
LPA_100FULL
))
{
if
(
ip
->
sw_lpa
&
LPA_100FULL
)
tmode
=
"100Mb/s, Full Duplex"
;
else
tmode
=
"100Mb/s, Half Duplex"
;
}
else
{
if
(
ip
->
sw_lpa
&
LPA_10FULL
)
tmode
=
"10Mb/s, Full Duplex"
;
else
tmode
=
"10Mb/s, Half Duplex"
;
}
printk
(
KERN_INFO
"%s: Link is up at %s.
\n
"
,
ip
->
dev
->
name
,
tmode
);
}
static
void
ioc3_display_forced_link_mode
(
struct
ioc3_private
*
ip
)
{
char
*
speed
=
""
,
*
duplex
=
""
;
ip
->
sw_bmcr
=
mii_read
(
ip
,
MII_BMCR
);
if
(
ip
->
sw_bmcr
&
BMCR_SPEED100
)
speed
=
"100Mb/s, "
;
else
speed
=
"10Mb/s, "
;
if
(
ip
->
sw_bmcr
&
BMCR_FULLDPLX
)
duplex
=
"Full Duplex.
\n
"
;
else
duplex
=
"Half Duplex.
\n
"
;
printk
(
KERN_INFO
"%s: Link has been forced up at %s%s"
,
ip
->
dev
->
name
,
speed
,
duplex
);
}
static
int
ioc3_set_link_modes
(
struct
ioc3_private
*
ip
)
static
inline
void
ioc3_setup_duplex
(
struct
ioc3_private
*
ip
)
{
struct
ioc3
*
ioc3
=
ip
->
regs
;
int
full
;
/*
* All we care about is making sure the bigmac tx_cfg has a
* proper duplex setting.
*/
if
(
ip
->
timer_state
==
arbwait
)
{
ip
->
sw_lpa
=
mii_read
(
ip
,
MII_LPA
);
if
(
!
(
ip
->
sw_lpa
&
(
LPA_10HALF
|
LPA_10FULL
|
LPA_100HALF
|
LPA_100FULL
)))
goto
no_response
;
if
(
ip
->
sw_lpa
&
LPA_100FULL
)
full
=
1
;
else
if
(
ip
->
sw_lpa
&
LPA_100HALF
)
full
=
0
;
else
if
(
ip
->
sw_lpa
&
LPA_10FULL
)
full
=
1
;
else
full
=
0
;
}
else
{
/* Forcing a link mode. */
ip
->
sw_bmcr
=
mii_read
(
ip
,
MII_BMCR
);
if
(
ip
->
sw_bmcr
&
BMCR_FULLDPLX
)
full
=
1
;
else
full
=
0
;
}
if
(
full
)
if
(
ip
->
mii
.
full_duplex
)
{
ioc3_w_etcsr
(
ETCSR_FD
);
ip
->
emcr
|=
EMCR_DUPLEX
;
else
}
else
{
ioc3_w_etcsr
(
ETCSR_HD
);
ip
->
emcr
&=
~
EMCR_DUPLEX
;
ioc3
->
emcr
=
ip
->
emcr
;
ioc3
->
emcr
;
return
0
;
no_response:
return
1
;
}
static
int
is_lucent_phy
(
struct
ioc3_private
*
ip
)
{
unsigned
short
mr2
,
mr3
;
int
ret
=
0
;
mr2
=
mii_read
(
ip
,
MII_PHYSID1
);
mr3
=
mii_read
(
ip
,
MII_PHYSID2
);
if
((
mr2
&
0xffff
)
==
0x0180
&&
((
mr3
&
0xffff
)
>>
10
)
==
0x1d
)
{
ret
=
1
;
}
return
ret
;
ioc3_w_emcr
(
ip
->
emcr
);
}
static
void
ioc3_timer
(
unsigned
long
data
)
{
struct
ioc3_private
*
ip
=
(
struct
ioc3_private
*
)
data
;
int
restart_timer
=
0
;
ip
->
timer_ticks
++
;
switch
(
ip
->
timer_state
)
{
case
arbwait
:
/*
* Only allow for 5 ticks, thats 10 seconds and much too
* long to wait for arbitration to complete.
*/
if
(
ip
->
timer_ticks
>=
10
)
{
/* Enter force mode. */
do_force_mode:
ip
->
sw_bmcr
=
mii_read
(
ip
,
MII_BMCR
);
printk
(
KERN_NOTICE
"%s: Auto-Negotiation unsuccessful,"
" trying force link mode
\n
"
,
ip
->
dev
->
name
);
ip
->
sw_bmcr
=
BMCR_SPEED100
;
mii_write
(
ip
,
MII_BMCR
,
ip
->
sw_bmcr
);
if
(
!
is_lucent_phy
(
ip
))
{
/*
* OK, seems we need do disable the transceiver
* for the first tick to make sure we get an
* accurate link state at the second tick.
*/
ip
->
sw_csconfig
=
mii_read
(
ip
,
MII_CSCONFIG
);
ip
->
sw_csconfig
&=
~
(
CSCONFIG_TCVDISAB
);
mii_write
(
ip
,
MII_CSCONFIG
,
ip
->
sw_csconfig
);
}
ip
->
timer_state
=
ltrywait
;
ip
->
timer_ticks
=
0
;
restart_timer
=
1
;
}
else
{
/* Anything interesting happen? */
ip
->
sw_bmsr
=
mii_read
(
ip
,
MII_BMSR
);
if
(
ip
->
sw_bmsr
&
BMSR_ANEGCOMPLETE
)
{
int
ret
;
/* Just what we've been waiting for... */
ret
=
ioc3_set_link_modes
(
ip
);
if
(
ret
)
{
/* Ooops, something bad happened, go to
* force mode.
*
* XXX Broken hubs which don't support
* XXX 802.3u auto-negotiation make this
* XXX happen as well.
*/
goto
do_force_mode
;
}
/*
* Success, at least so far, advance our state
* engine.
*/
ip
->
timer_state
=
lupwait
;
restart_timer
=
1
;
}
else
{
restart_timer
=
1
;
}
}
break
;
case
lupwait
:
/*
* Auto negotiation was successful and we are awaiting a
* link up status. I have decided to let this timer run
* forever until some sort of error is signalled, reporting
* a message to the user at 10 second intervals.
*/
ip
->
sw_bmsr
=
mii_read
(
ip
,
MII_BMSR
);
if
(
ip
->
sw_bmsr
&
BMSR_LSTATUS
)
{
/*
* Wheee, it's up, display the link mode in use and put
* the timer to sleep.
*/
ioc3_display_link_mode
(
ip
);
ip
->
timer_state
=
asleep
;
restart_timer
=
0
;
}
else
{
if
(
ip
->
timer_ticks
>=
10
)
{
printk
(
KERN_NOTICE
"%s: Auto negotiation successful, link still "
"not completely up.
\n
"
,
ip
->
dev
->
name
);
ip
->
timer_ticks
=
0
;
restart_timer
=
1
;
}
else
{
restart_timer
=
1
;
}
}
break
;
/* Print the link status if it has changed */
mii_check_media
(
&
ip
->
mii
,
1
,
0
);
ioc3_setup_duplex
(
ip
);
case
ltrywait
:
/*
* Making the timeout here too long can make it take
* annoyingly long to attempt all of the link mode
* permutations, but then again this is essentially
* error recovery code for the most part.
*/
ip
->
sw_bmsr
=
mii_read
(
ip
,
MII_BMSR
);
ip
->
sw_csconfig
=
mii_read
(
ip
,
MII_CSCONFIG
);
if
(
ip
->
timer_ticks
==
1
)
{
if
(
!
is_lucent_phy
(
ip
))
{
/*
* Re-enable transceiver, we'll re-enable the
* transceiver next tick, then check link state
* on the following tick.
*/
ip
->
sw_csconfig
|=
CSCONFIG_TCVDISAB
;
mii_write
(
ip
,
MII_CSCONFIG
,
ip
->
sw_csconfig
);
}
restart_timer
=
1
;
break
;
}
if
(
ip
->
timer_ticks
==
2
)
{
if
(
!
is_lucent_phy
(
ip
))
{
ip
->
sw_csconfig
&=
~
(
CSCONFIG_TCVDISAB
);
mii_write
(
ip
,
MII_CSCONFIG
,
ip
->
sw_csconfig
);
}
restart_timer
=
1
;
break
;
}
if
(
ip
->
sw_bmsr
&
BMSR_LSTATUS
)
{
/* Force mode selection success. */
ioc3_display_forced_link_mode
(
ip
);
ioc3_set_link_modes
(
ip
);
/* XXX error? then what? */
ip
->
timer_state
=
asleep
;
restart_timer
=
0
;
}
else
{
if
(
ip
->
timer_ticks
>=
4
)
{
/* 6 seconds or so... */
int
ret
;
ret
=
ioc3_try_next_permutation
(
ip
);
if
(
ret
==
-
1
)
{
/*
* Aieee, tried them all, reset the
* chip and try all over again.
*/
printk
(
KERN_NOTICE
"%s: Link down, "
"cable problem?
\n
"
,
ip
->
dev
->
name
);
ioc3_init
(
ip
);
return
;
}
if
(
!
is_lucent_phy
(
ip
))
{
ip
->
sw_csconfig
=
mii_read
(
ip
,
MII_CSCONFIG
);
ip
->
sw_csconfig
|=
CSCONFIG_TCVDISAB
;
mii_write
(
ip
,
MII_CSCONFIG
,
ip
->
sw_csconfig
);
}
ip
->
timer_ticks
=
0
;
restart_timer
=
1
;
}
else
{
restart_timer
=
1
;
}
}
break
;
case
asleep
:
default:
/* Can't happens.... */
printk
(
KERN_ERR
"%s: Aieee, link timer is asleep but we got "
"one anyways!
\n
"
,
ip
->
dev
->
name
);
restart_timer
=
0
;
ip
->
timer_ticks
=
0
;
ip
->
timer_state
=
asleep
;
/* foo on you */
break
;
};
if
(
restart_timer
)
{
ip
->
ioc3_timer
.
expires
=
jiffies
+
((
12
*
HZ
)
/
10
);
/* 1.2s */
add_timer
(
&
ip
->
ioc3_timer
);
}
}
static
void
ioc3_start_auto_negotiation
(
struct
ioc3_private
*
ip
,
struct
ethtool_cmd
*
ep
)
{
int
timeout
;
/* Read all of the registers we are interested in now. */
ip
->
sw_bmsr
=
mii_read
(
ip
,
MII_BMSR
);
ip
->
sw_bmcr
=
mii_read
(
ip
,
MII_BMCR
);
ip
->
sw_physid1
=
mii_read
(
ip
,
MII_PHYSID1
);
ip
->
sw_physid2
=
mii_read
(
ip
,
MII_PHYSID2
);
/* XXX Check BMSR_ANEGCAPABLE, should not be necessary though. */
ip
->
sw_advertise
=
mii_read
(
ip
,
MII_ADVERTISE
);
if
(
ep
==
NULL
||
ep
->
autoneg
==
AUTONEG_ENABLE
)
{
/* Advertise everything we can support. */
if
(
ip
->
sw_bmsr
&
BMSR_10HALF
)
ip
->
sw_advertise
|=
ADVERTISE_10HALF
;
else
ip
->
sw_advertise
&=
~
ADVERTISE_10HALF
;
if
(
ip
->
sw_bmsr
&
BMSR_10FULL
)
ip
->
sw_advertise
|=
ADVERTISE_10FULL
;
else
ip
->
sw_advertise
&=
~
ADVERTISE_10FULL
;
if
(
ip
->
sw_bmsr
&
BMSR_100HALF
)
ip
->
sw_advertise
|=
ADVERTISE_100HALF
;
else
ip
->
sw_advertise
&=
~
ADVERTISE_100HALF
;
if
(
ip
->
sw_bmsr
&
BMSR_100FULL
)
ip
->
sw_advertise
|=
ADVERTISE_100FULL
;
else
ip
->
sw_advertise
&=
~
ADVERTISE_100FULL
;
mii_write
(
ip
,
MII_ADVERTISE
,
ip
->
sw_advertise
);
/*
* XXX Currently no IOC3 card I know off supports 100BaseT4,
* XXX and this is because the DP83840 does not support it,
* XXX changes XXX would need to be made to the tx/rx logic in
* XXX the driver as well so I completely skip checking for it
* XXX in the BMSR for now.
*/
#ifdef AUTO_SWITCH_DEBUG
ASD
((
"%s: Advertising [ "
,
ip
->
dev
->
name
));
if
(
ip
->
sw_advertise
&
ADVERTISE_10HALF
)
ASD
((
"10H "
));
if
(
ip
->
sw_advertise
&
ADVERTISE_10FULL
)
ASD
((
"10F "
));
if
(
ip
->
sw_advertise
&
ADVERTISE_100HALF
)
ASD
((
"100H "
));
if
(
ip
->
sw_advertise
&
ADVERTISE_100FULL
)
ASD
((
"100F "
));
#endif
/* Enable Auto-Negotiation, this is usually on already... */
ip
->
sw_bmcr
|=
BMCR_ANENABLE
;
mii_write
(
ip
,
MII_BMCR
,
ip
->
sw_bmcr
);
/* Restart it to make sure it is going. */
ip
->
sw_bmcr
|=
BMCR_ANRESTART
;
mii_write
(
ip
,
MII_BMCR
,
ip
->
sw_bmcr
);
/* BMCR_ANRESTART self clears when the process has begun. */
timeout
=
64
;
/* More than enough. */
while
(
--
timeout
)
{
ip
->
sw_bmcr
=
mii_read
(
ip
,
MII_BMCR
);
if
(
!
(
ip
->
sw_bmcr
&
BMCR_ANRESTART
))
break
;
/* got it. */
udelay
(
10
);
}
if
(
!
timeout
)
{
printk
(
KERN_ERR
"%s: IOC3 would not start auto "
"negotiation BMCR=0x%04x
\n
"
,
ip
->
dev
->
name
,
ip
->
sw_bmcr
);
printk
(
KERN_NOTICE
"%s: Performing force link "
"detection.
\n
"
,
ip
->
dev
->
name
);
goto
force_link
;
}
else
{
ip
->
timer_state
=
arbwait
;
}
}
else
{
force_link:
/*
* Force the link up, trying first a particular mode. Either
* we are here at the request of ethtool or because the IOC3
* would not start to autoneg.
*/
/*
* Disable auto-negotiation in BMCR, enable the duplex and
* speed setting, init the timer state machine, and fire it off.
*/
if
(
ep
==
NULL
||
ep
->
autoneg
==
AUTONEG_ENABLE
)
{
ip
->
sw_bmcr
=
BMCR_SPEED100
;
}
else
{
if
(
ep
->
speed
==
SPEED_100
)
ip
->
sw_bmcr
=
BMCR_SPEED100
;
else
ip
->
sw_bmcr
=
0
;
if
(
ep
->
duplex
==
DUPLEX_FULL
)
ip
->
sw_bmcr
|=
BMCR_FULLDPLX
;
}
mii_write
(
ip
,
MII_BMCR
,
ip
->
sw_bmcr
);
if
(
!
is_lucent_phy
(
ip
))
{
/*
* OK, seems we need do disable the transceiver for the
* first tick to make sure we get an accurate link
* state at the second tick.
*/
ip
->
sw_csconfig
=
mii_read
(
ip
,
MII_CSCONFIG
);
ip
->
sw_csconfig
&=
~
(
CSCONFIG_TCVDISAB
);
mii_write
(
ip
,
MII_CSCONFIG
,
ip
->
sw_csconfig
);
}
ip
->
timer_state
=
ltrywait
;
}
del_timer
(
&
ip
->
ioc3_timer
);
ip
->
timer_ticks
=
0
;
ip
->
ioc3_timer
.
expires
=
jiffies
+
(
12
*
HZ
)
/
10
;
/* 1.2 sec. */
ip
->
ioc3_timer
.
data
=
(
unsigned
long
)
ip
;
ip
->
ioc3_timer
.
function
=
&
ioc3_timer
;
ip
->
ioc3_timer
.
expires
=
jiffies
+
((
12
*
HZ
)
/
10
);
/* 1.2s */
add_timer
(
&
ip
->
ioc3_timer
);
}
/*
* Try to find a PHY. There is no apparent relation between the MII addresses
* in the SGI documentation and what we find in reality, so we simply probe
* for the PHY. It seems IOC3 PHYs usually live on address 31. One of my
* onboard IOC3s has the special oddity that probing doesn't seem to find it
* yet the interface seems to work fine, so if probing fails we for now will
* simply default to PHY 31 instead of bailing out.
*/
static
int
ioc3_mii_init
(
struct
ioc3_private
*
ip
)
{
int
i
,
found
;
struct
net_device
*
dev
=
priv_netdev
(
ip
);
int
i
,
found
=
0
,
res
=
0
;
int
ioc3_phy_workaround
=
1
;
u16
word
;
found
=
0
;
spin_lock_irq
(
&
ip
->
ioc3_lock
);
for
(
i
=
0
;
i
<
32
;
i
++
)
{
ip
->
phy
=
i
;
word
=
mii_read
(
ip
,
2
);
if
(
(
word
!=
0xffff
)
&&
(
word
!=
0x0000
)
)
{
word
=
ioc3_mdio_read
(
dev
,
i
,
MII_PHYSID1
)
;
if
(
word
!=
0xffff
&&
word
!=
0x0000
)
{
found
=
1
;
break
;
/* Found a PHY */
}
}
if
(
!
found
)
{
spin_unlock_irq
(
&
ip
->
ioc3_lock
);
return
-
ENODEV
;
if
(
ioc3_phy_workaround
)
i
=
31
;
else
{
ip
->
mii
.
phy_id
=
-
1
;
res
=
-
ENODEV
;
goto
out
;
}
}
ioc3_start_auto_negotiation
(
ip
,
NULL
);
// XXX ethtool
spin_unlock_irq
(
&
ip
->
ioc3_lock
);
ip
->
mii
.
phy_id
=
i
;
ip
->
ioc3_timer
.
expires
=
jiffies
+
(
12
*
HZ
)
/
10
;
/* 1.2 sec. */
ip
->
ioc3_timer
.
data
=
(
unsigned
long
)
ip
;
ip
->
ioc3_timer
.
function
=
&
ioc3_timer
;
add_timer
(
&
ip
->
ioc3_timer
);
return
0
;
out:
return
res
;
}
static
inline
void
ioc3_clean_rx_ring
(
struct
ioc3_private
*
ip
)
static
inline
void
ioc3_clean_rx_ring
(
struct
ioc3_private
*
ip
)
{
struct
sk_buff
*
skb
;
int
i
;
...
...
@@ -1130,8 +846,7 @@ ioc3_clean_rx_ring(struct ioc3_private *ip)
}
}
static
inline
void
ioc3_clean_tx_ring
(
struct
ioc3_private
*
ip
)
static
inline
void
ioc3_clean_tx_ring
(
struct
ioc3_private
*
ip
)
{
struct
sk_buff
*
skb
;
int
i
;
...
...
@@ -1148,8 +863,7 @@ ioc3_clean_tx_ring(struct ioc3_private *ip)
ip
->
tx_ci
=
0
;
}
static
void
ioc3_free_rings
(
struct
ioc3_private
*
ip
)
static
void
ioc3_free_rings
(
struct
ioc3_private
*
ip
)
{
struct
sk_buff
*
skb
;
int
rx_entry
,
n_entry
;
...
...
@@ -1176,10 +890,9 @@ ioc3_free_rings(struct ioc3_private *ip)
}
}
static
void
ioc3_alloc_rings
(
struct
net_device
*
dev
,
struct
ioc3_private
*
ip
,
struct
ioc3
*
ioc3
)
static
void
ioc3_alloc_rings
(
struct
net_device
*
dev
)
{
struct
ioc3_private
*
ip
=
netdev_priv
(
dev
);
struct
ioc3_erxbuf
*
rxb
;
unsigned
long
*
rxr
;
int
i
;
...
...
@@ -1209,8 +922,7 @@ ioc3_alloc_rings(struct net_device *dev, struct ioc3_private *ip,
/* Because we reserve afterwards. */
skb_put
(
skb
,
(
1664
+
RX_OFFSET
));
rxb
=
(
struct
ioc3_erxbuf
*
)
skb
->
data
;
rxr
[
i
]
=
cpu_to_be64
((
0xa5UL
<<
56
)
|
((
unsigned
long
)
rxb
&
TO_PHYS_MASK
));
rxr
[
i
]
=
cpu_to_be64
(
ioc3_map
(
rxb
,
1
));
skb_reserve
(
skb
,
RX_OFFSET
);
}
ip
->
rx_ci
=
0
;
...
...
@@ -1227,39 +939,38 @@ ioc3_alloc_rings(struct net_device *dev, struct ioc3_private *ip,
}
}
static
void
ioc3_init_rings
(
struct
net_device
*
dev
,
struct
ioc3_private
*
ip
,
struct
ioc3
*
ioc3
)
static
void
ioc3_init_rings
(
struct
net_device
*
dev
)
{
struct
ioc3_private
*
ip
=
netdev_priv
(
dev
);
struct
ioc3
*
ioc3
=
ip
->
regs
;
unsigned
long
ring
;
ioc3_free_rings
(
ip
);
ioc3_alloc_rings
(
dev
,
ip
,
ioc3
);
ioc3_alloc_rings
(
dev
);
ioc3_clean_rx_ring
(
ip
);
ioc3_clean_tx_ring
(
ip
);
/* Now the rx ring base, consume & produce registers. */
ring
=
(
0xa5UL
<<
56
)
|
((
unsigned
long
)
ip
->
rxr
&
TO_PHYS_MASK
);
ioc3
->
erbr_h
=
ring
>>
32
;
ioc3
->
erbr_l
=
ring
&
0xffffffff
;
ioc3
->
ercir
=
(
ip
->
rx_ci
<<
3
);
ioc3
->
erpir
=
(
ip
->
rx_pi
<<
3
)
|
ERPIR_ARM
;
ring
=
ioc3_map
(
ip
->
rxr
,
0
);
ioc3
_w_erbr_h
(
ring
>>
32
)
;
ioc3
_w_erbr_l
(
ring
&
0xffffffff
)
;
ioc3
_w_ercir
(
ip
->
rx_ci
<<
3
);
ioc3
_w_erpir
((
ip
->
rx_pi
<<
3
)
|
ERPIR_ARM
)
;
ring
=
(
0xa5UL
<<
56
)
|
((
unsigned
long
)
ip
->
txr
&
TO_PHYS_MASK
);
ring
=
ioc3_map
(
ip
->
txr
,
0
);
ip
->
txqlen
=
0
;
/* nothing queued */
/* Now the tx ring base, consume & produce registers. */
ioc3
->
etbr_h
=
ring
>>
32
;
ioc3
->
etbr_l
=
ring
&
0xffffffff
;
ioc3
->
etpir
=
(
ip
->
tx_pi
<<
7
);
ioc3
->
etcir
=
(
ip
->
tx_ci
<<
7
);
ioc3
->
etcir
;
/* Flush */
ioc3
_w_etbr_h
(
ring
>>
32
)
;
ioc3
_w_etbr_l
(
ring
&
0xffffffff
)
;
ioc3
_w_etpir
(
ip
->
tx_pi
<<
7
);
ioc3
_w_etcir
(
ip
->
tx_ci
<<
7
);
(
void
)
ioc3_r_etcir
();
/* Flush */
}
static
inline
void
ioc3_ssram_disc
(
struct
ioc3_private
*
ip
)
static
inline
void
ioc3_ssram_disc
(
struct
ioc3_private
*
ip
)
{
struct
ioc3
*
ioc3
=
ip
->
regs
;
volatile
u32
*
ssram0
=
&
ioc3
->
ssram
[
0x0000
];
...
...
@@ -1267,7 +978,7 @@ ioc3_ssram_disc(struct ioc3_private *ip)
unsigned
int
pattern
=
0x5555
;
/* Assume the larger size SSRAM and enable parity checking */
ioc3
->
emcr
|=
(
EMCR_BUFSIZ
|
EMCR_RAMPAR
);
ioc3
_w_emcr
(
ioc3_r_emcr
()
|
(
EMCR_BUFSIZ
|
EMCR_RAMPAR
)
);
*
ssram0
=
pattern
;
*
ssram1
=
~
pattern
&
IOC3_SSRAM_DM
;
...
...
@@ -1276,62 +987,63 @@ ioc3_ssram_disc(struct ioc3_private *ip)
(
*
ssram1
&
IOC3_SSRAM_DM
)
!=
(
~
pattern
&
IOC3_SSRAM_DM
))
{
/* set ssram size to 64 KB */
ip
->
emcr
=
EMCR_RAMPAR
;
ioc3
->
emcr
&=
~
EMCR_BUFSIZ
;
}
else
{
ioc3
_w_emcr
(
ioc3_r_emcr
()
&
~
EMCR_BUFSIZ
)
;
}
else
ip
->
emcr
=
EMCR_BUFSIZ
|
EMCR_RAMPAR
;
}
}
static
void
ioc3_init
(
struct
ioc3_private
*
ip
)
static
void
ioc3_init
(
struct
net_device
*
dev
)
{
struct
net_device
*
dev
=
ip
->
dev
;
struct
ioc3_private
*
ip
=
netdev_priv
(
dev
)
;
struct
ioc3
*
ioc3
=
ip
->
regs
;
del_timer
(
&
ip
->
ioc3_timer
);
/* Kill if running */
ioc3
->
emcr
=
EMCR_RST
;
/* Reset */
ioc3
->
emcr
;
/* Flush WB */
ioc3
_w_emcr
(
EMCR_RST
)
;
/* Reset */
(
void
)
ioc3_r_emcr
();
/* Flush WB */
udelay
(
4
);
/* Give it time ... */
ioc3
->
emcr
=
0
;
ioc3
->
emcr
;
ioc3
_w_emcr
(
0
)
;
(
void
)
ioc3_r_emcr
()
;
/* Misc registers */
ioc3
->
erbar
=
0
;
ioc3
->
etcsr
=
(
17
<<
ETCSR_IPGR2_SHIFT
)
|
(
11
<<
ETCSR_IPGR1_SHIFT
)
|
21
;
ioc3
->
etcdc
;
/* Clear on read */
ioc3
->
ercsr
=
15
;
/* RX low watermark */
ioc3
->
ertr
=
0
;
/* Interrupt immediately */
ioc3
->
emar_h
=
(
dev
->
dev_addr
[
5
]
<<
8
)
|
dev
->
dev_addr
[
4
];
ioc3
->
emar_l
=
(
dev
->
dev_addr
[
3
]
<<
24
)
|
(
dev
->
dev_addr
[
2
]
<<
16
)
|
(
dev
->
dev_addr
[
1
]
<<
8
)
|
dev
->
dev_addr
[
0
];
ioc3
->
ehar_h
=
ip
->
ehar_h
;
ioc3
->
ehar_l
=
ip
->
ehar_l
;
ioc3
->
ersr
=
42
;
/* XXX should be random */
ioc3_init_rings
(
ip
->
dev
,
ip
,
ioc3
);
#ifdef CONFIG_SGI_IP27
ioc3_w_erbar
(
PCI64_ATTR_BAR
>>
32
);
/* Barrier on last store */
#else
ioc3_w_erbar
(
0
);
/* Let PCI API get it right */
#endif
(
void
)
ioc3_r_etcdc
();
/* Clear on read */
ioc3_w_ercsr
(
15
);
/* RX low watermark */
ioc3_w_ertr
(
0
);
/* Interrupt immediately */
ioc3_w_emar_h
((
dev
->
dev_addr
[
5
]
<<
8
)
|
dev
->
dev_addr
[
4
]);
ioc3_w_emar_l
((
dev
->
dev_addr
[
3
]
<<
24
)
|
(
dev
->
dev_addr
[
2
]
<<
16
)
|
(
dev
->
dev_addr
[
1
]
<<
8
)
|
dev
->
dev_addr
[
0
]);
ioc3_w_ehar_h
(
ip
->
ehar_h
);
ioc3_w_ehar_l
(
ip
->
ehar_l
);
ioc3_w_ersr
(
42
);
/* XXX should be random */
ioc3_init_rings
(
dev
);
ip
->
emcr
|=
((
RX_OFFSET
/
2
)
<<
EMCR_RXOFF_SHIFT
)
|
EMCR_TXDMAEN
|
EMCR_TXEN
|
EMCR_RXDMAEN
|
EMCR_RXEN
;
ioc3
->
emcr
=
ip
->
emcr
;
ioc3
->
eier
=
EISR_RXTIMERINT
|
EISR_RXOFLO
|
EISR_RXBUFOFLO
|
EISR_RXMEMERR
|
EISR_RXPARERR
|
EISR_TXBUFUFLO
|
EISR_TXEXPLICIT
|
EISR_TXMEMERR
;
ioc3
->
eier
;
EMCR_TXEN
|
EMCR_RXDMAEN
|
EMCR_RXEN
|
EMCR_PADEN
;
ioc3
_w_emcr
(
ip
->
emcr
)
;
ioc3
_w_eier
(
EISR_RXTIMERINT
|
EISR_RXOFLO
|
EISR_RXBUFOFLO
|
EISR_RXMEMERR
|
EISR_RXPARERR
|
EISR_TXBUFUFLO
|
EISR_TXEXPLICIT
|
EISR_TXMEMERR
)
;
(
void
)
ioc3_r_eier
()
;
}
static
inline
void
ioc3_stop
(
struct
ioc3_private
*
ip
)
{
struct
ioc3
*
ioc3
=
ip
->
regs
;
ioc3
->
emcr
=
0
;
/* Shutup */
ioc3
->
eier
=
0
;
/* Disable interrupts */
ioc3
->
eier
;
/* Flush */
ioc3
_w_emcr
(
0
)
;
/* Shutup */
ioc3
_w_eier
(
0
)
;
/* Disable interrupts */
(
void
)
ioc3_r_eier
();
/* Flush */
}
static
int
ioc3_open
(
struct
net_device
*
dev
)
static
int
ioc3_open
(
struct
net_device
*
dev
)
{
struct
ioc3_private
*
ip
=
dev
->
priv
;
struct
ioc3_private
*
ip
=
netdev_priv
(
dev
)
;
if
(
request_irq
(
dev
->
irq
,
ioc3_interrupt
,
SA_SHIRQ
,
ioc3_str
,
dev
))
{
printk
(
KERN_ERR
"%s: Can't get irq %d
\n
"
,
dev
->
name
,
dev
->
irq
);
...
...
@@ -1341,16 +1053,15 @@ ioc3_open(struct net_device *dev)
ip
->
ehar_h
=
0
;
ip
->
ehar_l
=
0
;
ioc3_init
(
ip
);
ioc3_init
(
dev
);
netif_start_queue
(
dev
);
return
0
;
}
static
int
ioc3_close
(
struct
net_device
*
dev
)
static
int
ioc3_close
(
struct
net_device
*
dev
)
{
struct
ioc3_private
*
ip
=
dev
->
priv
;
struct
ioc3_private
*
ip
=
netdev_priv
(
dev
)
;
del_timer
(
&
ip
->
ioc3_timer
);
...
...
@@ -1389,6 +1100,34 @@ static inline int ioc3_is_menet(struct pci_dev *pdev)
&&
dev
->
device
==
PCI_DEVICE_ID_SGI_IOC3
;
}
/*
* Note about serial ports and consoles:
* For console output, everyone uses the IOC3 UARTA (offset 0x178)
* connected to the master node (look in ip27_setup_console() and
* ip27prom_console_write()).
*
* For serial (/dev/ttyS0 etc), we can not have hardcoded serial port
* addresses on a partitioned machine. Since we currently use the ioc3
* serial ports, we use dynamic serial port discovery that the serial.c
* driver uses for pci/pnp ports (there is an entry for the SGI ioc3
* boards in pci_boards[]). Unfortunately, UARTA's pio address is greater
* than UARTB's, although UARTA on o200s has traditionally been known as
* port 0. So, we just use one serial port from each ioc3 (since the
* serial driver adds addresses to get to higher ports).
*
* The first one to do a register_console becomes the preferred console
* (if there is no kernel command line console= directive). /dev/console
* (ie 5, 1) is then "aliased" into the device number returned by the
* "device" routine referred to in this console structure
* (ip27prom_console_dev).
*
* Also look in ip27-pci.c:pci_fixuop_ioc3() for some comments on working
* around ioc3 oddities in this respect.
*
* The IOC3 serials use a 22MHz clock rate with an additional divider by 3.
* (IOC3_BAUD = (22000000 / (3*16)))
*/
static
inline
void
ioc3_serial_probe
(
struct
pci_dev
*
pdev
,
struct
ioc3
*
ioc3
)
{
...
...
@@ -1425,6 +1164,7 @@ static inline void ioc3_serial_probe(struct pci_dev *pdev,
static
int
__devinit
ioc3_probe
(
struct
pci_dev
*
pdev
,
const
struct
pci_device_id
*
ent
)
{
unsigned
int
sw_physid1
,
sw_physid2
;
struct
net_device
*
dev
=
NULL
;
struct
ioc3_private
*
ip
;
struct
ioc3
*
ioc3
;
...
...
@@ -1443,8 +1183,7 @@ static int __devinit ioc3_probe(struct pci_dev *pdev,
SET_MODULE_OWNER
(
dev
);
SET_NETDEV_DEV
(
dev
,
&
pdev
->
dev
);
ip
=
dev
->
priv
;
ip
->
dev
=
dev
;
ip
=
netdev_priv
(
dev
);
dev
->
irq
=
pdev
->
irq
;
...
...
@@ -1464,14 +1203,22 @@ static int __devinit ioc3_probe(struct pci_dev *pdev,
#endif
spin_lock_init
(
&
ip
->
ioc3_lock
);
init_timer
(
&
ip
->
ioc3_timer
);
ioc3_stop
(
ip
);
ioc3_init
(
ip
);
ioc3_init
(
dev
);
ip
->
pdev
=
pdev
;
ip
->
mii
.
phy_id_mask
=
0x1f
;
ip
->
mii
.
reg_num_mask
=
0x1f
;
ip
->
mii
.
dev
=
dev
;
ip
->
mii
.
mdio_read
=
ioc3_mdio_read
;
ip
->
mii
.
mdio_write
=
ioc3_mdio_write
;
init_timer
(
&
ip
->
ioc3_timer
);
ioc3_mii_init
(
ip
);
if
(
ip
->
phy
==
-
1
)
{
if
(
ip
->
mii
.
phy_id
==
-
1
)
{
printk
(
KERN_CRIT
"ioc3-eth(%s): Didn't find a PHY, goodbye.
\n
"
,
pci_name
(
pdev
));
err
=
-
ENODEV
;
...
...
@@ -1490,16 +1237,26 @@ static int __devinit ioc3_probe(struct pci_dev *pdev,
dev
->
get_stats
=
ioc3_get_stats
;
dev
->
do_ioctl
=
ioc3_ioctl
;
dev
->
set_multicast_list
=
ioc3_set_multicast_list
;
dev
->
ethtool_ops
=
&
ioc3_ethtool_ops
;
#ifdef CONFIG_SGI_IOC3_ETH_HW_TX_CSUM
dev
->
features
=
NETIF_F_IP_CSUM
;
#endif
ioc3_setup_duplex
(
ip
);
sw_physid1
=
ioc3_mdio_read
(
dev
,
ip
->
mii
.
phy_id
,
MII_PHYSID1
);
sw_physid2
=
ioc3_mdio_read
(
dev
,
ip
->
mii
.
phy_id
,
MII_PHYSID2
);
err
=
register_netdev
(
dev
);
if
(
err
)
goto
out_stop
;
vendor
=
(
ip
->
sw_physid1
<<
12
)
|
(
ip
->
sw_physid2
>>
4
);
model
=
(
ip
->
sw_physid2
>>
4
)
&
0x3f
;
rev
=
ip
->
sw_physid2
&
0xf
;
mii_check_media
(
&
ip
->
mii
,
1
,
1
);
vendor
=
(
sw_physid1
<<
12
)
|
(
sw_physid2
>>
4
);
model
=
(
sw_physid2
>>
4
)
&
0x3f
;
rev
=
sw_physid2
&
0xf
;
printk
(
KERN_INFO
"%s: Using PHY %d, vendor 0x%x, model %d, "
"rev %d.
\n
"
,
dev
->
name
,
ip
->
phy
,
vendor
,
model
,
rev
);
"rev %d.
\n
"
,
dev
->
name
,
ip
->
mii
.
phy_id
,
vendor
,
model
,
rev
);
printk
(
KERN_INFO
"%s: IOC3 SSRAM has %d kbyte.
\n
"
,
dev
->
name
,
ip
->
emcr
&
EMCR_BUFSIZ
?
128
:
64
);
...
...
@@ -1507,7 +1264,6 @@ static int __devinit ioc3_probe(struct pci_dev *pdev,
out_stop:
ioc3_stop
(
ip
);
free_irq
(
dev
->
irq
,
dev
);
ioc3_free_rings
(
ip
);
out_res:
pci_release_regions
(
pdev
);
...
...
@@ -1519,7 +1275,7 @@ static int __devinit ioc3_probe(struct pci_dev *pdev,
static
void
__devexit
ioc3_remove_one
(
struct
pci_dev
*
pdev
)
{
struct
net_device
*
dev
=
pci_get_drvdata
(
pdev
);
struct
ioc3_private
*
ip
=
dev
->
priv
;
struct
ioc3_private
*
ip
=
netdev_priv
(
dev
)
;
struct
ioc3
*
ioc3
=
ip
->
regs
;
unregister_netdev
(
dev
);
...
...
@@ -1551,16 +1307,66 @@ static void __exit ioc3_cleanup_module(void)
pci_unregister_driver
(
&
ioc3_driver
);
}
static
int
ioc3_start_xmit
(
struct
sk_buff
*
skb
,
struct
net_device
*
dev
)
static
int
ioc3_start_xmit
(
struct
sk_buff
*
skb
,
struct
net_device
*
dev
)
{
unsigned
long
data
;
struct
ioc3_private
*
ip
=
dev
->
priv
;
struct
ioc3_private
*
ip
=
netdev_priv
(
dev
)
;
struct
ioc3
*
ioc3
=
ip
->
regs
;
unsigned
int
len
;
struct
ioc3_etxd
*
desc
;
uint32_t
w0
=
0
;
int
produce
;
#ifdef CONFIG_SGI_IOC3_ETH_HW_TX_CSUM
/*
* IOC3 has a fairly simple minded checksumming hardware which simply
* adds up the 1's complement checksum for the entire packet and
* inserts it at an offset which can be specified in the descriptor
* into the transmit packet. This means we have to compensate for the
* MAC header which should not be summed and the TCP/UDP pseudo headers
* manually.
*/
if
(
skb
->
ip_summed
==
CHECKSUM_HW
)
{
int
proto
=
ntohs
(
skb
->
nh
.
iph
->
protocol
);
unsigned
int
csoff
;
struct
iphdr
*
ih
=
skb
->
nh
.
iph
;
uint32_t
csum
,
ehsum
;
uint16_t
*
eh
;
/* The MAC header. skb->mac.ethernet seem the logic approach
to find the MAC header - except it's a NULL pointer ... */
eh
=
(
uint16_t
*
)
skb
->
data
;
/* Sum up dest addr, src addr and protocol */
ehsum
=
eh
[
0
]
+
eh
[
1
]
+
eh
[
2
]
+
eh
[
3
]
+
eh
[
4
]
+
eh
[
5
]
+
eh
[
6
];
/* Fold ehsum. can't use csum_fold which negates also ... */
ehsum
=
(
ehsum
&
0xffff
)
+
(
ehsum
>>
16
);
ehsum
=
(
ehsum
&
0xffff
)
+
(
ehsum
>>
16
);
/* Skip IP header; it's sum is always zero and was
already filled in by ip_output.c */
csum
=
csum_tcpudp_nofold
(
ih
->
saddr
,
ih
->
daddr
,
ih
->
tot_len
-
(
ih
->
ihl
<<
2
),
proto
,
0xffff
^
ehsum
);
csum
=
(
csum
&
0xffff
)
+
(
csum
>>
16
);
/* Fold again */
csum
=
(
csum
&
0xffff
)
+
(
csum
>>
16
);
csoff
=
ETH_HLEN
+
(
ih
->
ihl
<<
2
);
if
(
proto
==
IPPROTO_UDP
)
{
csoff
+=
offsetof
(
struct
udphdr
,
check
);
skb
->
h
.
uh
->
check
=
csum
;
}
if
(
proto
==
IPPROTO_TCP
)
{
csoff
+=
offsetof
(
struct
tcphdr
,
check
);
skb
->
h
.
th
->
check
=
csum
;
}
w0
=
ETXD_DOCHECKSUM
|
(
csoff
<<
ETXD_CHKOFF_SHIFT
);
}
#endif
/* CONFIG_SGI_IOC3_ETH_HW_TX_CSUM */
spin_lock_irq
(
&
ip
->
ioc3_lock
);
data
=
(
unsigned
long
)
skb
->
data
;
...
...
@@ -1577,29 +1383,24 @@ ioc3_start_xmit(struct sk_buff *skb, struct net_device *dev)
memset
(
desc
->
data
+
len
,
0
,
ETH_ZLEN
-
len
);
len
=
ETH_ZLEN
;
}
desc
->
cmd
=
cpu_to_be32
(
len
|
ETXD_INTWHENDONE
|
ETXD_D0V
);
desc
->
cmd
=
cpu_to_be32
(
len
|
ETXD_INTWHENDONE
|
ETXD_D0V
|
w0
);
desc
->
bufcnt
=
cpu_to_be32
(
len
);
}
else
if
((
data
^
(
data
+
len
))
&
0x4000
)
{
unsigned
long
b2
,
s1
,
s2
;
b2
=
(
data
|
0x3fffUL
)
+
1UL
;
s1
=
b2
-
data
;
s2
=
data
+
len
-
b2
;
}
else
if
((
data
^
(
data
+
len
-
1
))
&
0x4000
)
{
unsigned
long
b2
=
(
data
|
0x3fffUL
)
+
1UL
;
unsigned
long
s1
=
b2
-
data
;
unsigned
long
s2
=
data
+
len
-
b2
;
desc
->
cmd
=
cpu_to_be32
(
len
|
ETXD_INTWHENDONE
|
ETXD_B1V
|
ETXD_B2V
);
desc
->
bufcnt
=
cpu_to_be32
((
s1
<<
ETXD_B1CNT_SHIFT
)
|
(
s2
<<
ETXD_B2CNT_SHIFT
));
desc
->
p1
=
cpu_to_be64
((
0xa5UL
<<
56
)
|
(
data
&
TO_PHYS_MASK
));
desc
->
p2
=
cpu_to_be64
((
0xa5UL
<<
56
)
|
(
data
&
TO_PHYS_MASK
));
ETXD_B1V
|
ETXD_B2V
|
w0
);
desc
->
bufcnt
=
cpu_to_be32
((
s1
<<
ETXD_B1CNT_SHIFT
)
|
(
s2
<<
ETXD_B2CNT_SHIFT
));
desc
->
p1
=
cpu_to_be64
(
ioc3_map
(
skb
->
data
,
1
));
desc
->
p2
=
cpu_to_be64
(
ioc3_map
((
void
*
)
b2
,
1
));
}
else
{
/* Normal sized packet that doesn't cross a page boundary. */
desc
->
cmd
=
cpu_to_be32
(
len
|
ETXD_INTWHENDONE
|
ETXD_B1V
);
desc
->
cmd
=
cpu_to_be32
(
len
|
ETXD_INTWHENDONE
|
ETXD_B1V
|
w0
);
desc
->
bufcnt
=
cpu_to_be32
(
len
<<
ETXD_B1CNT_SHIFT
);
desc
->
p1
=
cpu_to_be64
((
0xa5UL
<<
56
)
|
(
data
&
TO_PHYS_MASK
));
desc
->
p1
=
cpu_to_be64
(
ioc3_map
(
skb
->
data
,
1
));
}
BARRIER
();
...
...
@@ -1608,11 +1409,11 @@ ioc3_start_xmit(struct sk_buff *skb, struct net_device *dev)
ip
->
tx_skbs
[
produce
]
=
skb
;
/* Remember skb */
produce
=
(
produce
+
1
)
&
127
;
ip
->
tx_pi
=
produce
;
ioc3
->
etpir
=
produce
<<
7
;
/* Fire ... */
ioc3
_w_etpir
(
produce
<<
7
)
;
/* Fire ... */
ip
->
txqlen
++
;
if
(
ip
->
txqlen
>
127
)
if
(
ip
->
txqlen
>
=
127
)
netif_stop_queue
(
dev
);
spin_unlock_irq
(
&
ip
->
ioc3_lock
);
...
...
@@ -1622,15 +1423,18 @@ ioc3_start_xmit(struct sk_buff *skb, struct net_device *dev)
static
void
ioc3_timeout
(
struct
net_device
*
dev
)
{
struct
ioc3_private
*
ip
=
dev
->
priv
;
struct
ioc3_private
*
ip
=
netdev_priv
(
dev
)
;
printk
(
KERN_ERR
"%s: transmit timed out, resetting
\n
"
,
dev
->
name
);
spin_lock_irq
(
&
ip
->
ioc3_lock
);
ioc3_stop
(
ip
);
ioc3_init
(
ip
);
ioc3_init
(
dev
);
ioc3_mii_init
(
ip
);
dev
->
trans_start
=
jiffies
;
spin_unlock_irq
(
&
ip
->
ioc3_lock
);
netif_wake_queue
(
dev
);
}
...
...
@@ -1639,11 +1443,9 @@ static void ioc3_timeout(struct net_device *dev)
* address's bit index in the logical address filter mask
*/
static
inline
unsigned
int
ioc3_hash
(
const
unsigned
char
*
addr
)
static
inline
unsigned
int
ioc3_hash
(
const
unsigned
char
*
addr
)
{
unsigned
int
temp
=
0
;
unsigned
char
byte
;
u32
crc
;
int
bits
;
...
...
@@ -1659,132 +1461,89 @@ ioc3_hash(const unsigned char *addr)
return
temp
;
}
static
void
ioc3_get_drvinfo
(
struct
net_device
*
dev
,
struct
ethtool_drvinfo
*
info
)
{
struct
ioc3_private
*
ip
=
netdev_priv
(
dev
);
strcpy
(
info
->
driver
,
IOC3_NAME
);
strcpy
(
info
->
version
,
IOC3_VERSION
);
strcpy
(
info
->
bus_info
,
pci_name
(
ip
->
pdev
));
}
/* We provide both the mii-tools and the ethtool ioctls. */
static
int
ioc3_ioctl
(
struct
net_device
*
dev
,
struct
ifreq
*
rq
,
int
cmd
)
static
int
ioc3_get_settings
(
struct
net_device
*
dev
,
struct
ethtool_cmd
*
cmd
)
{
struct
ioc3_private
*
ip
=
dev
->
priv
;
struct
ethtool_cmd
*
ep_user
=
(
struct
ethtool_cmd
*
)
rq
->
ifr_data
;
u16
*
data
=
(
u16
*
)
&
rq
->
ifr_data
;
struct
ioc3
*
ioc3
=
ip
->
regs
;
struct
ethtool_cmd
ecmd
;
struct
ioc3_private
*
ip
=
netdev_priv
(
dev
);
int
rc
;
switch
(
cmd
)
{
case
SIOCGMIIPHY
:
/* Get the address of the PHY in use. */
if
(
ip
->
phy
==
-
1
)
return
-
ENODEV
;
data
[
0
]
=
ip
->
phy
;
return
0
;
spin_lock_irq
(
&
ip
->
ioc3_lock
);
rc
=
mii_ethtool_gset
(
&
ip
->
mii
,
cmd
);
spin_unlock_irq
(
&
ip
->
ioc3_lock
);
case
SIOCGMIIREG
:
{
/* Read a PHY register. */
unsigned
int
phy
=
data
[
0
];
unsigned
int
reg
=
data
[
1
];
return
rc
;
}
if
(
phy
>
0x1f
||
reg
>
0x1f
)
return
-
EINVAL
;
static
int
ioc3_set_settings
(
struct
net_device
*
dev
,
struct
ethtool_cmd
*
cmd
)
{
struct
ioc3_private
*
ip
=
netdev_priv
(
dev
);
int
rc
;
spin_lock_irq
(
&
ip
->
ioc3_lock
);
while
(
ioc3
->
micr
&
MICR_BUSY
);
ioc3
->
micr
=
(
phy
<<
MICR_PHYADDR_SHIFT
)
|
reg
|
MICR_READTRIG
;
while
(
ioc3
->
micr
&
MICR_BUSY
);
data
[
3
]
=
(
ioc3
->
midr_r
&
MIDR_DATA_MASK
)
;
spin_unlock_irq
(
&
ip
->
ioc3_lock
);
spin_lock_irq
(
&
ip
->
ioc3_lock
);
rc
=
mii_ethtool_sset
(
&
ip
->
mii
,
cmd
);
spin_unlock_irq
(
&
ip
->
ioc3_lock
)
;
return
rc
;
}
return
0
;
static
int
ioc3_nway_reset
(
struct
net_device
*
dev
)
{
struct
ioc3_private
*
ip
=
netdev_priv
(
dev
);
int
rc
;
case
SIOCSMIIREG
:
/* Write a PHY register. */
phy
=
data
[
0
]
;
reg
=
data
[
1
]
;
spin_lock_irq
(
&
ip
->
ioc3_lock
);
rc
=
mii_nway_restart
(
&
ip
->
mii
)
;
spin_unlock_irq
(
&
ip
->
ioc3_lock
)
;
if
(
!
capable
(
CAP_NET_ADMIN
))
return
-
EPERM
;
return
rc
;
}
if
(
phy
>
0x1f
||
reg
>
0x1f
)
return
-
EINVAL
;
static
u32
ioc3_get_link
(
struct
net_device
*
dev
)
{
struct
ioc3_private
*
ip
=
netdev_priv
(
dev
);
int
rc
;
spin_lock_irq
(
&
ip
->
ioc3_lock
);
while
(
ioc3
->
micr
&
MICR_BUSY
);
ioc3
->
midr_w
=
data
[
2
];
ioc3
->
micr
=
(
phy
<<
MICR_PHYADDR_SHIFT
)
|
reg
;
while
(
ioc3
->
micr
&
MICR_BUSY
);
spin_unlock_irq
(
&
ip
->
ioc3_lock
);
spin_lock_irq
(
&
ip
->
ioc3_lock
);
rc
=
mii_link_ok
(
&
ip
->
mii
);
spin_unlock_irq
(
&
ip
->
ioc3_lock
);
return
0
;
}
case
SIOCETHTOOL
:
if
(
copy_from_user
(
&
ecmd
,
ep_user
,
sizeof
(
ecmd
)))
return
-
EFAULT
;
if
(
ecmd
.
cmd
==
ETHTOOL_GSET
)
{
ecmd
.
supported
=
(
SUPPORTED_10baseT_Half
|
SUPPORTED_10baseT_Full
|
SUPPORTED_100baseT_Half
|
SUPPORTED_100baseT_Full
|
SUPPORTED_Autoneg
|
SUPPORTED_TP
|
SUPPORTED_MII
);
ecmd
.
port
=
PORT_TP
;
ecmd
.
transceiver
=
XCVR_INTERNAL
;
ecmd
.
phy_address
=
ip
->
phy
;
/* Record PHY settings. */
spin_lock_irq
(
&
ip
->
ioc3_lock
);
ip
->
sw_bmcr
=
mii_read
(
ip
,
MII_BMCR
);
ip
->
sw_lpa
=
mii_read
(
ip
,
MII_LPA
);
spin_unlock_irq
(
&
ip
->
ioc3_lock
);
if
(
ip
->
sw_bmcr
&
BMCR_ANENABLE
)
{
ecmd
.
autoneg
=
AUTONEG_ENABLE
;
ecmd
.
speed
=
(
ip
->
sw_lpa
&
(
LPA_100HALF
|
LPA_100FULL
))
?
SPEED_100
:
SPEED_10
;
if
(
ecmd
.
speed
==
SPEED_100
)
ecmd
.
duplex
=
(
ip
->
sw_lpa
&
(
LPA_100FULL
))
?
DUPLEX_FULL
:
DUPLEX_HALF
;
else
ecmd
.
duplex
=
(
ip
->
sw_lpa
&
(
LPA_10FULL
))
?
DUPLEX_FULL
:
DUPLEX_HALF
;
}
else
{
ecmd
.
autoneg
=
AUTONEG_DISABLE
;
ecmd
.
speed
=
(
ip
->
sw_bmcr
&
BMCR_SPEED100
)
?
SPEED_100
:
SPEED_10
;
ecmd
.
duplex
=
(
ip
->
sw_bmcr
&
BMCR_FULLDPLX
)
?
DUPLEX_FULL
:
DUPLEX_HALF
;
}
if
(
copy_to_user
(
ep_user
,
&
ecmd
,
sizeof
(
ecmd
)))
return
-
EFAULT
;
return
0
;
}
else
if
(
ecmd
.
cmd
==
ETHTOOL_SSET
)
{
/* Verify the settings we care about. */
if
(
ecmd
.
autoneg
!=
AUTONEG_ENABLE
&&
ecmd
.
autoneg
!=
AUTONEG_DISABLE
)
return
-
EINVAL
;
if
(
ecmd
.
autoneg
==
AUTONEG_DISABLE
&&
((
ecmd
.
speed
!=
SPEED_100
&&
ecmd
.
speed
!=
SPEED_10
)
||
(
ecmd
.
duplex
!=
DUPLEX_HALF
&&
ecmd
.
duplex
!=
DUPLEX_FULL
)))
return
-
EINVAL
;
/* Ok, do it to it. */
del_timer
(
&
ip
->
ioc3_timer
);
spin_lock_irq
(
&
ip
->
ioc3_lock
);
ioc3_start_auto_negotiation
(
ip
,
&
ecmd
);
spin_unlock_irq
(
&
ip
->
ioc3_lock
);
return
rc
;
}
return
0
;
}
else
default:
return
-
EOPNOTSUPP
;
}
static
struct
ethtool_ops
ioc3_ethtool_ops
=
{
.
get_drvinfo
=
ioc3_get_drvinfo
,
.
get_settings
=
ioc3_get_settings
,
.
set_settings
=
ioc3_set_settings
,
.
nway_reset
=
ioc3_nway_reset
,
.
get_link
=
ioc3_get_link
,
};
static
int
ioc3_ioctl
(
struct
net_device
*
dev
,
struct
ifreq
*
rq
,
int
cmd
)
{
struct
mii_ioctl_data
*
data
=
(
struct
mii_ioctl_data
*
)
&
rq
->
ifr_data
;
struct
ioc3_private
*
ip
=
netdev_priv
(
dev
);
int
rc
;
spin_lock_irq
(
&
ip
->
ioc3_lock
);
rc
=
generic_mii_ioctl
(
&
ip
->
mii
,
data
,
cmd
,
NULL
);
spin_unlock_irq
(
&
ip
->
ioc3_lock
);
return
-
EOPNOTSUPP
;
return
rc
;
}
static
void
ioc3_set_multicast_list
(
struct
net_device
*
dev
)
{
struct
dev_mc_list
*
dmi
=
dev
->
mc_list
;
struct
ioc3_private
*
ip
=
dev
->
priv
;
struct
ioc3_private
*
ip
=
netdev_priv
(
dev
)
;
struct
ioc3
*
ioc3
=
ip
->
regs
;
u64
ehar
=
0
;
int
i
;
...
...
@@ -1795,12 +1554,12 @@ static void ioc3_set_multicast_list(struct net_device *dev)
/* Unconditionally log net taps. */
printk
(
KERN_INFO
"%s: Promiscuous mode enabled.
\n
"
,
dev
->
name
);
ip
->
emcr
|=
EMCR_PROMISC
;
ioc3
->
emcr
=
ip
->
emcr
;
ioc3
->
emcr
;
ioc3
_w_emcr
(
ip
->
emcr
)
;
(
void
)
ioc3_r_emcr
()
;
}
else
{
ip
->
emcr
&=
~
EMCR_PROMISC
;
ioc3
->
emcr
=
ip
->
emcr
;
/* Clear promiscuous. */
ioc3
->
emcr
;
ioc3
_w_emcr
(
ip
->
emcr
)
;
/* Clear promiscuous. */
(
void
)
ioc3_r_emcr
()
;
if
((
dev
->
flags
&
IFF_ALLMULTI
)
||
(
dev
->
mc_count
>
64
))
{
/* Too many for hashing to make sense or we want all
...
...
@@ -1821,14 +1580,14 @@ static void ioc3_set_multicast_list(struct net_device *dev)
ip
->
ehar_h
=
ehar
>>
32
;
ip
->
ehar_l
=
ehar
&
0xffffffff
;
}
ioc3
->
ehar_h
=
ip
->
ehar_h
;
ioc3
->
ehar_l
=
ip
->
ehar_l
;
ioc3
_w_ehar_h
(
ip
->
ehar_h
)
;
ioc3
_w_ehar_l
(
ip
->
ehar_l
)
;
}
netif_wake_queue
(
dev
);
/* Let us get going again. */
}
MODULE_AUTHOR
(
"Ralf Baechle <ralf@
oss.sgi.com
>"
);
MODULE_AUTHOR
(
"Ralf Baechle <ralf@
linux-mips.org
>"
);
MODULE_DESCRIPTION
(
"SGI IOC3 Ethernet driver"
);
MODULE_LICENSE
(
"GPL"
);
...
...
drivers/net/irda/au1k_ir.c
View file @
fc3b6177
/*
*
* Alchemy Semi Au1000 IrDA driver
*
* Copyright 2001 MontaVista Software Inc.
* Author: MontaVista Software, Inc.
* ppopov@mvista.com or source@mvista.com
*
* ########################################################################
*
* This program is free software; you can distribute it and/or modify it
* under the terms of the GNU General Public License (Version 2) as
* published by the Free Software Foundation.
...
...
@@ -20,17 +17,7 @@
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
*
* ########################################################################
*
*
*/
#ifndef __mips__
#error This driver only works with MIPS architectures!
#endif
#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
...
...
@@ -46,7 +33,13 @@
#include <asm/bitops.h>
#include <asm/io.h>
#include <asm/au1000.h>
#if defined(CONFIG_MIPS_PB1000) || defined(CONFIG_MIPS_PB1100)
#include <asm/pb1000.h>
#elif defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100)
#include <asm/db1x00.h>
#else
#error au1k_ir: unsupported board
#endif
#include <net/irda/irda.h>
#include <net/irda/irmod.h>
...
...
@@ -71,10 +64,14 @@ static void dma_free(void *, size_t);
static
int
qos_mtt_bits
=
0x07
;
/* 1 ms or more */
static
struct
net_device
*
ir_devs
[
NUM_IR_IFF
];
static
char
version
[]
__devinitdata
=
"au1k_ircc:1.
0
ppopov@mvista.com
\n
"
;
"au1k_ircc:1.
2
ppopov@mvista.com
\n
"
;
#define RUN_AT(x) (jiffies + (x))
#if defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100)
static
BCSR
*
const
bcsr
=
(
BCSR
*
)
0xAE000000
;
#endif
static
spinlock_t
ir_lock
=
SPIN_LOCK_UNLOCKED
;
/*
...
...
@@ -128,7 +125,7 @@ static void *dma_alloc(size_t size, dma_addr_t * dma_handle)
if
(
ret
!=
NULL
)
{
memset
(
ret
,
0
,
size
);
*
dma_handle
=
virt_to_bus
(
ret
);
ret
=
KSEG0ADDR
(
ret
);
ret
=
(
void
*
)
KSEG0ADDR
(
ret
);
}
return
ret
;
}
...
...
@@ -136,7 +133,7 @@ static void *dma_alloc(size_t size, dma_addr_t * dma_handle)
static
void
dma_free
(
void
*
vaddr
,
size_t
size
)
{
vaddr
=
KSEG0ADDR
(
vaddr
);
vaddr
=
(
void
*
)
KSEG0ADDR
(
vaddr
);
free_pages
((
unsigned
long
)
vaddr
,
get_order
(
size
));
}
...
...
@@ -180,7 +177,7 @@ static int au1k_irda_init(void)
return
0
;
out1:
aup
=
dev
->
priv
;
aup
=
netdev_priv
(
dev
)
;
dma_free
((
void
*
)
aup
->
db
[
0
].
vaddr
,
MAX_BUF_SIZE
*
2
*
NUM_IR_DESC
);
dma_free
((
void
*
)
aup
->
rx_ring
[
0
],
...
...
@@ -205,10 +202,10 @@ static int au1k_irda_init_iobuf(iobuff_t *io, int size)
static
int
au1k_irda_net_init
(
struct
net_device
*
dev
)
{
struct
au1k_private
*
aup
=
dev
->
priv
;
struct
au1k_private
*
aup
=
netdev_priv
(
dev
)
;
int
i
,
retval
=
0
,
err
;
db_dest_t
*
pDB
,
*
pDBfree
;
unsigned
long
temp
;
dma_addr_t
temp
;
err
=
au1k_irda_init_iobuf
(
&
aup
->
rx_buff
,
14384
);
if
(
err
)
...
...
@@ -281,6 +278,14 @@ static int au1k_irda_net_init(struct net_device *dev)
aup
->
tx_ring
[
i
]
->
flags
=
0
;
aup
->
tx_db_inuse
[
i
]
=
pDB
;
}
#if defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100)
/* power on */
bcsr
->
resets
&=
~
BCSR_RESETS_IRDA_MODE_MASK
;
bcsr
->
resets
|=
BCSR_RESETS_IRDA_MODE_FULL
;
au_sync
();
#endif
return
0
;
out3:
...
...
@@ -296,7 +301,7 @@ static int au1k_irda_net_init(struct net_device *dev)
static
int
au1k_init
(
struct
net_device
*
dev
)
{
struct
au1k_private
*
aup
=
(
struct
au1k_private
*
)
dev
->
priv
;
struct
au1k_private
*
aup
=
netdev_priv
(
dev
)
;
int
i
;
u32
control
;
u32
ring_address
;
...
...
@@ -340,13 +345,10 @@ static int au1k_irda_start(struct net_device *dev)
{
int
retval
;
char
hwname
[
32
];
struct
au1k_private
*
aup
=
(
struct
au1k_private
*
)
dev
->
priv
;
MOD_INC_USE_COUNT
;
struct
au1k_private
*
aup
=
netdev_priv
(
dev
);
if
((
retval
=
au1k_init
(
dev
)))
{
printk
(
KERN_ERR
"%s: error in au1k_init
\n
"
,
dev
->
name
);
MOD_DEC_USE_COUNT
;
return
retval
;
}
...
...
@@ -354,7 +356,6 @@ static int au1k_irda_start(struct net_device *dev)
0
,
dev
->
name
,
dev
)))
{
printk
(
KERN_ERR
"%s: unable to get IRQ %d
\n
"
,
dev
->
name
,
dev
->
irq
);
MOD_DEC_USE_COUNT
;
return
retval
;
}
if
((
retval
=
request_irq
(
AU1000_IRDA_RX_INT
,
&
au1k_irda_interrupt
,
...
...
@@ -362,7 +363,6 @@ static int au1k_irda_start(struct net_device *dev)
free_irq
(
AU1000_IRDA_TX_INT
,
dev
);
printk
(
KERN_ERR
"%s: unable to get IRQ %d
\n
"
,
dev
->
name
,
dev
->
irq
);
MOD_DEC_USE_COUNT
;
return
retval
;
}
...
...
@@ -380,7 +380,7 @@ static int au1k_irda_start(struct net_device *dev)
static
int
au1k_irda_stop
(
struct
net_device
*
dev
)
{
struct
au1k_private
*
aup
=
(
struct
au1k_private
*
)
dev
->
priv
;
struct
au1k_private
*
aup
=
netdev_priv
(
dev
)
;
/* disable interrupts */
writel
(
read_ir_reg
(
IR_CONFIG_2
)
&
~
(
1
<<
8
),
IR_CONFIG_2
);
...
...
@@ -399,14 +399,13 @@ static int au1k_irda_stop(struct net_device *dev)
/* disable the interrupt */
free_irq
(
AU1000_IRDA_TX_INT
,
dev
);
free_irq
(
AU1000_IRDA_RX_INT
,
dev
);
MOD_DEC_USE_COUNT
;
return
0
;
}
static
void
__exit
au1k_irda_exit
(
void
)
{
struct
net_device
*
dev
=
ir_devs
[
0
];
struct
au1k_private
*
aup
=
(
struct
au1k_private
*
)
dev
->
priv
;
struct
au1k_private
*
aup
=
netdev_priv
(
dev
)
;
unregister_netdev
(
dev
);
...
...
@@ -422,7 +421,7 @@ static void __exit au1k_irda_exit(void)
static
inline
void
update_tx_stats
(
struct
net_device
*
dev
,
u32
status
,
u32
pkt_len
)
{
struct
au1k_private
*
aup
=
(
struct
au1k_private
*
)
dev
->
priv
;
struct
au1k_private
*
aup
=
netdev_priv
(
dev
)
;
struct
net_device_stats
*
ps
=
&
aup
->
stats
;
ps
->
tx_packets
++
;
...
...
@@ -437,7 +436,7 @@ update_tx_stats(struct net_device *dev, u32 status, u32 pkt_len)
static
void
au1k_tx_ack
(
struct
net_device
*
dev
)
{
struct
au1k_private
*
aup
=
(
struct
au1k_private
*
)
dev
->
priv
;
struct
au1k_private
*
aup
=
netdev_priv
(
dev
)
;
volatile
ring_dest_t
*
ptxd
;
ptxd
=
aup
->
tx_ring
[
aup
->
tx_tail
];
...
...
@@ -480,7 +479,7 @@ static void au1k_tx_ack(struct net_device *dev)
*/
static
int
au1k_irda_hard_xmit
(
struct
sk_buff
*
skb
,
struct
net_device
*
dev
)
{
struct
au1k_private
*
aup
=
(
struct
au1k_private
*
)
dev
->
priv
;
struct
au1k_private
*
aup
=
netdev_priv
(
dev
)
;
int
speed
=
irda_get_next_speed
(
skb
);
volatile
ring_dest_t
*
ptxd
;
u32
len
;
...
...
@@ -505,13 +504,13 @@ static int au1k_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev)
flags
=
ptxd
->
flags
;
if
(
flags
&
AU_OWN
)
{
printk
(
KERN_
INFO
"%s: tx_full
\n
"
,
dev
->
name
);
printk
(
KERN_
DEBUG
"%s: tx_full
\n
"
,
dev
->
name
);
netif_stop_queue
(
dev
);
aup
->
tx_full
=
1
;
return
1
;
}
else
if
(((
aup
->
tx_head
+
1
)
&
(
NUM_IR_DESC
-
1
))
==
aup
->
tx_tail
)
{
printk
(
KERN_
INFO
"%s: tx_full
\n
"
,
dev
->
name
);
printk
(
KERN_
DEBUG
"%s: tx_full
\n
"
,
dev
->
name
);
netif_stop_queue
(
dev
);
aup
->
tx_full
=
1
;
return
1
;
...
...
@@ -531,6 +530,7 @@ static int au1k_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev)
memcpy
((
void
*
)
pDB
->
vaddr
,
skb
->
data
,
skb
->
len
);
ptxd
->
count_0
=
skb
->
len
&
0xff
;
ptxd
->
count_1
=
(
skb
->
len
>>
8
)
&
0xff
;
}
else
{
/* SIR */
...
...
@@ -538,6 +538,7 @@ static int au1k_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev)
ptxd
->
count_0
=
len
&
0xff
;
ptxd
->
count_1
=
(
len
>>
8
)
&
0xff
;
ptxd
->
flags
|=
IR_DIS_CRC
;
au_writel
(
au_readl
(
0xae00000c
)
&
~
(
1
<<
13
),
0xae00000c
);
}
ptxd
->
flags
|=
AU_OWN
;
au_sync
();
...
...
@@ -556,7 +557,7 @@ static int au1k_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev)
static
inline
void
update_rx_stats
(
struct
net_device
*
dev
,
u32
status
,
u32
count
)
{
struct
au1k_private
*
aup
=
(
struct
au1k_private
*
)
dev
->
priv
;
struct
au1k_private
*
aup
=
netdev_priv
(
dev
)
;
struct
net_device_stats
*
ps
=
&
aup
->
stats
;
ps
->
rx_packets
++
;
...
...
@@ -579,7 +580,7 @@ update_rx_stats(struct net_device *dev, u32 status, u32 count)
*/
static
int
au1k_irda_rx
(
struct
net_device
*
dev
)
{
struct
au1k_private
*
aup
=
(
struct
au1k_private
*
)
dev
->
priv
;
struct
au1k_private
*
aup
=
netdev_priv
(
dev
)
;
struct
sk_buff
*
skb
;
volatile
ring_dest_t
*
prxd
;
u32
flags
,
count
;
...
...
@@ -650,7 +651,7 @@ void au1k_irda_interrupt(int irq, void *dev_id, struct pt_regs *regs)
static
void
au1k_tx_timeout
(
struct
net_device
*
dev
)
{
u32
speed
;
struct
au1k_private
*
aup
=
(
struct
au1k_private
*
)
dev
->
priv
;
struct
au1k_private
*
aup
=
netdev_priv
(
dev
)
;
printk
(
KERN_ERR
"%s: tx timeout
\n
"
,
dev
->
name
);
speed
=
aup
->
speed
;
...
...
@@ -668,10 +669,13 @@ static int
au1k_irda_set_speed
(
struct
net_device
*
dev
,
int
speed
)
{
unsigned
long
flags
;
struct
au1k_private
*
aup
=
(
struct
au1k_private
*
)
dev
->
priv
;
struct
au1k_private
*
aup
=
netdev_priv
(
dev
)
;
u32
control
;
int
ret
=
0
,
timeout
=
10
,
i
;
volatile
ring_dest_t
*
ptxd
;
#if defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100)
unsigned
long
irda_resets
;
#endif
if
(
speed
==
aup
->
speed
)
return
ret
;
...
...
@@ -717,10 +721,20 @@ au1k_irda_set_speed(struct net_device *dev, int speed)
ptxd
->
flags
=
AU_OWN
;
}
if
(
speed
==
4000000
)
if
(
speed
==
4000000
)
{
#if defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100)
bcsr
->
resets
|=
BCSR_RESETS_FIR_SEL
;
#else
/* Pb1000 and Pb1100 */
writel
(
1
<<
13
,
CPLD_AUX1
);
else
#endif
}
else
{
#if defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100)
bcsr
->
resets
&=
~
BCSR_RESETS_FIR_SEL
;
#else
/* Pb1000 and Pb1100 */
writel
(
readl
(
CPLD_AUX1
)
&
~
(
1
<<
13
),
CPLD_AUX1
);
#endif
}
switch
(
speed
)
{
case
9600
:
...
...
@@ -766,15 +780,15 @@ au1k_irda_set_speed(struct net_device *dev, int speed)
}
else
{
if
(
control
&
(
1
<<
11
))
printk
(
KERN_
INFO
"%s Valid SIR config
\n
"
,
dev
->
name
);
printk
(
KERN_
DEBUG
"%s Valid SIR config
\n
"
,
dev
->
name
);
if
(
control
&
(
1
<<
12
))
printk
(
KERN_
INFO
"%s Valid MIR config
\n
"
,
dev
->
name
);
printk
(
KERN_
DEBUG
"%s Valid MIR config
\n
"
,
dev
->
name
);
if
(
control
&
(
1
<<
13
))
printk
(
KERN_
INFO
"%s Valid FIR config
\n
"
,
dev
->
name
);
printk
(
KERN_
DEBUG
"%s Valid FIR config
\n
"
,
dev
->
name
);
if
(
control
&
(
1
<<
10
))
printk
(
KERN_
INFO
"%s TX enabled
\n
"
,
dev
->
name
);
printk
(
KERN_
DEBUG
"%s TX enabled
\n
"
,
dev
->
name
);
if
(
control
&
(
1
<<
9
))
printk
(
KERN_
INFO
"%s RX enabled
\n
"
,
dev
->
name
);
printk
(
KERN_
DEBUG
"%s RX enabled
\n
"
,
dev
->
name
);
}
spin_unlock_irqrestore
(
&
ir_lock
,
flags
);
...
...
@@ -785,7 +799,7 @@ static int
au1k_irda_ioctl
(
struct
net_device
*
dev
,
struct
ifreq
*
ifreq
,
int
cmd
)
{
struct
if_irda_req
*
rq
=
(
struct
if_irda_req
*
)
ifreq
;
struct
au1k_private
*
aup
=
dev
->
priv
;
struct
au1k_private
*
aup
=
netdev_priv
(
dev
)
;
int
ret
=
-
EOPNOTSUPP
;
switch
(
cmd
)
{
...
...
@@ -826,14 +840,12 @@ au1k_irda_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd)
static
struct
net_device_stats
*
au1k_irda_stats
(
struct
net_device
*
dev
)
{
struct
au1k_private
*
aup
=
(
struct
au1k_private
*
)
dev
->
priv
;
struct
au1k_private
*
aup
=
netdev_priv
(
dev
)
;
return
&
aup
->
stats
;
}
#ifdef MODULE
MODULE_AUTHOR
(
"Pete Popov <ppopov@mvista.com>"
);
MODULE_DESCRIPTION
(
"Au1000 IrDA Device Driver"
);
module_init
(
au1k_irda_init
);
module_exit
(
au1k_irda_exit
);
#endif
/* MODULE */
drivers/net/meth.c
View file @
fc3b6177
/*
* 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 @
fc3b6177
...
...
@@ -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)
drivers/net/sb1250-mac.c
View file @
fc3b6177
...
...
@@ -113,7 +113,6 @@ MODULE_PARM(int_timeout, "i");
#include <asm/sibyte/sb1250_dma.h>
#include <asm/sibyte/sb1250_int.h>
#include <asm/sibyte/sb1250_scd.h>
#include <asm/sibyte/64bit.h>
/**********************************************************************
...
...
@@ -147,8 +146,8 @@ typedef enum { sbmac_state_uninit, sbmac_state_off, sbmac_state_on,
#define NUMCACHEBLKS(x) (((x)+SMP_CACHE_BYTES-1)/SMP_CACHE_BYTES)
#define SBMAC_READCSR(t)
in64
((unsigned long)t)
#define SBMAC_WRITECSR(t,v)
out64
(v, (unsigned long)t)
#define SBMAC_READCSR(t)
__raw_readq
((unsigned long)t)
#define SBMAC_WRITECSR(t,v)
__raw_writeq
(v, (unsigned long)t)
#define SBMAC_MAX_TXDESCR 32
...
...
@@ -468,14 +467,17 @@ static void sbmac_mii_sync(struct sbmac_softc *s)
{
int
cnt
;
uint64_t
bits
;
int
mac_mdio_genc
;
mac_mdio_genc
=
SBMAC_READCSR
(
s
->
sbm_mdio
)
&
M_MAC_GENC
;
bits
=
M_MAC_MDIO_DIR_OUTPUT
|
M_MAC_MDIO_OUT
;
SBMAC_WRITECSR
(
s
->
sbm_mdio
,
bits
);
SBMAC_WRITECSR
(
s
->
sbm_mdio
,
bits
|
mac_mdio_genc
);
for
(
cnt
=
0
;
cnt
<
32
;
cnt
++
)
{
SBMAC_WRITECSR
(
s
->
sbm_mdio
,
bits
|
M_MAC_MDC
);
SBMAC_WRITECSR
(
s
->
sbm_mdio
,
bits
);
SBMAC_WRITECSR
(
s
->
sbm_mdio
,
bits
|
M_MAC_MDC
|
mac_mdio_genc
);
SBMAC_WRITECSR
(
s
->
sbm_mdio
,
bits
|
mac_mdio_genc
);
}
}
...
...
@@ -496,9 +498,12 @@ static void sbmac_mii_senddata(struct sbmac_softc *s,unsigned int data, int bitc
int
i
;
uint64_t
bits
;
unsigned
int
curmask
;
int
mac_mdio_genc
;
mac_mdio_genc
=
SBMAC_READCSR
(
s
->
sbm_mdio
)
&
M_MAC_GENC
;
bits
=
M_MAC_MDIO_DIR_OUTPUT
;
SBMAC_WRITECSR
(
s
->
sbm_mdio
,
bits
);
SBMAC_WRITECSR
(
s
->
sbm_mdio
,
bits
|
mac_mdio_genc
);
curmask
=
1
<<
(
bitcnt
-
1
);
...
...
@@ -506,9 +511,9 @@ static void sbmac_mii_senddata(struct sbmac_softc *s,unsigned int data, int bitc
if
(
data
&
curmask
)
bits
|=
M_MAC_MDIO_OUT
;
else
bits
&=
~
M_MAC_MDIO_OUT
;
SBMAC_WRITECSR
(
s
->
sbm_mdio
,
bits
);
SBMAC_WRITECSR
(
s
->
sbm_mdio
,
bits
|
M_MAC_MDC
);
SBMAC_WRITECSR
(
s
->
sbm_mdio
,
bits
);
SBMAC_WRITECSR
(
s
->
sbm_mdio
,
bits
|
mac_mdio_genc
);
SBMAC_WRITECSR
(
s
->
sbm_mdio
,
bits
|
M_MAC_MDC
|
mac_mdio_genc
);
SBMAC_WRITECSR
(
s
->
sbm_mdio
,
bits
|
mac_mdio_genc
);
curmask
>>=
1
;
}
}
...
...
@@ -534,7 +539,8 @@ static unsigned int sbmac_mii_read(struct sbmac_softc *s,int phyaddr,int regidx)
int
idx
;
int
error
;
int
regval
;
int
mac_mdio_genc
;
/*
* Synchronize ourselves so that the PHY knows the next
* thing coming down is a command
...
...
@@ -555,17 +561,20 @@ static unsigned int sbmac_mii_read(struct sbmac_softc *s,int phyaddr,int regidx)
sbmac_mii_senddata
(
s
,
phyaddr
,
5
);
sbmac_mii_senddata
(
s
,
regidx
,
5
);
mac_mdio_genc
=
SBMAC_READCSR
(
s
->
sbm_mdio
)
&
M_MAC_GENC
;
/*
* Switch the port around without a clock transition.
*/
SBMAC_WRITECSR
(
s
->
sbm_mdio
,
M_MAC_MDIO_DIR_INPUT
);
SBMAC_WRITECSR
(
s
->
sbm_mdio
,
M_MAC_MDIO_DIR_INPUT
|
mac_mdio_genc
);
/*
* Send out a clock pulse to signal we want the status
*/
SBMAC_WRITECSR
(
s
->
sbm_mdio
,
M_MAC_MDIO_DIR_INPUT
|
M_MAC_MDC
);
SBMAC_WRITECSR
(
s
->
sbm_mdio
,
M_MAC_MDIO_DIR_INPUT
);
SBMAC_WRITECSR
(
s
->
sbm_mdio
,
M_MAC_MDIO_DIR_INPUT
|
M_MAC_MDC
|
mac_mdio_genc
);
SBMAC_WRITECSR
(
s
->
sbm_mdio
,
M_MAC_MDIO_DIR_INPUT
|
mac_mdio_genc
);
/*
* If an error occurred, the PHY will signal '1' back
...
...
@@ -576,8 +585,9 @@ static unsigned int sbmac_mii_read(struct sbmac_softc *s,int phyaddr,int regidx)
* Issue an 'idle' clock pulse, but keep the direction
* the same.
*/
SBMAC_WRITECSR
(
s
->
sbm_mdio
,
M_MAC_MDIO_DIR_INPUT
|
M_MAC_MDC
);
SBMAC_WRITECSR
(
s
->
sbm_mdio
,
M_MAC_MDIO_DIR_INPUT
);
SBMAC_WRITECSR
(
s
->
sbm_mdio
,
M_MAC_MDIO_DIR_INPUT
|
M_MAC_MDC
|
mac_mdio_genc
);
SBMAC_WRITECSR
(
s
->
sbm_mdio
,
M_MAC_MDIO_DIR_INPUT
|
mac_mdio_genc
);
regval
=
0
;
...
...
@@ -589,12 +599,14 @@ static unsigned int sbmac_mii_read(struct sbmac_softc *s,int phyaddr,int regidx)
regval
|=
1
;
}
SBMAC_WRITECSR
(
s
->
sbm_mdio
,
M_MAC_MDIO_DIR_INPUT
|
M_MAC_MDC
);
SBMAC_WRITECSR
(
s
->
sbm_mdio
,
M_MAC_MDIO_DIR_INPUT
);
SBMAC_WRITECSR
(
s
->
sbm_mdio
,
M_MAC_MDIO_DIR_INPUT
|
M_MAC_MDC
|
mac_mdio_genc
);
SBMAC_WRITECSR
(
s
->
sbm_mdio
,
M_MAC_MDIO_DIR_INPUT
|
mac_mdio_genc
);
}
/* Switch back to output */
SBMAC_WRITECSR
(
s
->
sbm_mdio
,
M_MAC_MDIO_DIR_OUTPUT
);
SBMAC_WRITECSR
(
s
->
sbm_mdio
,
M_MAC_MDIO_DIR_OUTPUT
|
mac_mdio_genc
);
if
(
error
==
0
)
return
regval
;
...
...
@@ -620,7 +632,8 @@ static unsigned int sbmac_mii_read(struct sbmac_softc *s,int phyaddr,int regidx)
static
void
sbmac_mii_write
(
struct
sbmac_softc
*
s
,
int
phyaddr
,
int
regidx
,
unsigned
int
regval
)
{
int
mac_mdio_genc
;
sbmac_mii_sync
(
s
);
sbmac_mii_senddata
(
s
,
MII_COMMAND_START
,
2
);
...
...
@@ -629,8 +642,10 @@ static void sbmac_mii_write(struct sbmac_softc *s,int phyaddr,int regidx,
sbmac_mii_senddata
(
s
,
regidx
,
5
);
sbmac_mii_senddata
(
s
,
MII_COMMAND_ACK
,
2
);
sbmac_mii_senddata
(
s
,
regval
,
16
);
SBMAC_WRITECSR
(
s
->
sbm_mdio
,
M_MAC_MDIO_DIR_OUTPUT
);
mac_mdio_genc
=
SBMAC_READCSR
(
s
->
sbm_mdio
)
&
M_MAC_GENC
;
SBMAC_WRITECSR
(
s
->
sbm_mdio
,
M_MAC_MDIO_DIR_OUTPUT
|
mac_mdio_genc
);
}
...
...
@@ -672,47 +687,47 @@ static void sbdma_initctx(sbmacdma_t *d,
s->sbe_idx =(s->sbm_base - A_MAC_BASE_0)/MAC_SPACING;
#endif
SBMAC_WRITECSR
(
KSEG1
ADDR
(
SBMAC_WRITECSR
(
IO
ADDR
(
A_MAC_REGISTER
(
s
->
sbe_idx
,
R_MAC_RMON_TX_BYTES
)),
0
);
SBMAC_WRITECSR
(
KSEG1
ADDR
(
SBMAC_WRITECSR
(
IO
ADDR
(
A_MAC_REGISTER
(
s
->
sbe_idx
,
R_MAC_RMON_COLLISIONS
)),
0
);
SBMAC_WRITECSR
(
KSEG1
ADDR
(
SBMAC_WRITECSR
(
IO
ADDR
(
A_MAC_REGISTER
(
s
->
sbe_idx
,
R_MAC_RMON_LATE_COL
)),
0
);
SBMAC_WRITECSR
(
KSEG1
ADDR
(
SBMAC_WRITECSR
(
IO
ADDR
(
A_MAC_REGISTER
(
s
->
sbe_idx
,
R_MAC_RMON_EX_COL
)),
0
);
SBMAC_WRITECSR
(
KSEG1
ADDR
(
SBMAC_WRITECSR
(
IO
ADDR
(
A_MAC_REGISTER
(
s
->
sbe_idx
,
R_MAC_RMON_FCS_ERROR
)),
0
);
SBMAC_WRITECSR
(
KSEG1
ADDR
(
SBMAC_WRITECSR
(
IO
ADDR
(
A_MAC_REGISTER
(
s
->
sbe_idx
,
R_MAC_RMON_TX_ABORT
)),
0
);
SBMAC_WRITECSR
(
KSEG1
ADDR
(
SBMAC_WRITECSR
(
IO
ADDR
(
A_MAC_REGISTER
(
s
->
sbe_idx
,
R_MAC_RMON_TX_BAD
)),
0
);
SBMAC_WRITECSR
(
KSEG1
ADDR
(
SBMAC_WRITECSR
(
IO
ADDR
(
A_MAC_REGISTER
(
s
->
sbe_idx
,
R_MAC_RMON_TX_GOOD
)),
0
);
SBMAC_WRITECSR
(
KSEG1
ADDR
(
SBMAC_WRITECSR
(
IO
ADDR
(
A_MAC_REGISTER
(
s
->
sbe_idx
,
R_MAC_RMON_TX_RUNT
)),
0
);
SBMAC_WRITECSR
(
KSEG1
ADDR
(
SBMAC_WRITECSR
(
IO
ADDR
(
A_MAC_REGISTER
(
s
->
sbe_idx
,
R_MAC_RMON_TX_OVERSIZE
)),
0
);
SBMAC_WRITECSR
(
KSEG1
ADDR
(
SBMAC_WRITECSR
(
IO
ADDR
(
A_MAC_REGISTER
(
s
->
sbe_idx
,
R_MAC_RMON_RX_BYTES
)),
0
);
SBMAC_WRITECSR
(
KSEG1
ADDR
(
SBMAC_WRITECSR
(
IO
ADDR
(
A_MAC_REGISTER
(
s
->
sbe_idx
,
R_MAC_RMON_RX_MCAST
)),
0
);
SBMAC_WRITECSR
(
KSEG1
ADDR
(
SBMAC_WRITECSR
(
IO
ADDR
(
A_MAC_REGISTER
(
s
->
sbe_idx
,
R_MAC_RMON_RX_BCAST
)),
0
);
SBMAC_WRITECSR
(
KSEG1
ADDR
(
SBMAC_WRITECSR
(
IO
ADDR
(
A_MAC_REGISTER
(
s
->
sbe_idx
,
R_MAC_RMON_RX_BAD
)),
0
);
SBMAC_WRITECSR
(
KSEG1
ADDR
(
SBMAC_WRITECSR
(
IO
ADDR
(
A_MAC_REGISTER
(
s
->
sbe_idx
,
R_MAC_RMON_RX_GOOD
)),
0
);
SBMAC_WRITECSR
(
KSEG1
ADDR
(
SBMAC_WRITECSR
(
IO
ADDR
(
A_MAC_REGISTER
(
s
->
sbe_idx
,
R_MAC_RMON_RX_RUNT
)),
0
);
SBMAC_WRITECSR
(
KSEG1
ADDR
(
SBMAC_WRITECSR
(
IO
ADDR
(
A_MAC_REGISTER
(
s
->
sbe_idx
,
R_MAC_RMON_RX_OVERSIZE
)),
0
);
SBMAC_WRITECSR
(
KSEG1
ADDR
(
SBMAC_WRITECSR
(
IO
ADDR
(
A_MAC_REGISTER
(
s
->
sbe_idx
,
R_MAC_RMON_RX_FCS_ERROR
)),
0
);
SBMAC_WRITECSR
(
KSEG1
ADDR
(
SBMAC_WRITECSR
(
IO
ADDR
(
A_MAC_REGISTER
(
s
->
sbe_idx
,
R_MAC_RMON_RX_LENGTH_ERROR
)),
0
);
SBMAC_WRITECSR
(
KSEG1
ADDR
(
SBMAC_WRITECSR
(
IO
ADDR
(
A_MAC_REGISTER
(
s
->
sbe_idx
,
R_MAC_RMON_RX_CODE_ERROR
)),
0
);
SBMAC_WRITECSR
(
KSEG1
ADDR
(
SBMAC_WRITECSR
(
IO
ADDR
(
A_MAC_REGISTER
(
s
->
sbe_idx
,
R_MAC_RMON_RX_ALIGN_ERROR
)),
0
);
/*
...
...
@@ -1212,25 +1227,21 @@ static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d)
/*
* Buffer has been replaced on the
* receive ring. Pass the buffer to
* the kernel */
* the kernel
*/
sc
->
sbm_stats
.
rx_bytes
+=
len
;
sc
->
sbm_stats
.
rx_packets
++
;
sb
->
protocol
=
eth_type_trans
(
sb
,
d
->
sbdma_eth
->
sbm_dev
);
/* Check hw IPv4/TCP checksum if supported */
if
(
sc
->
rx_hw_checksum
==
ENABLE
)
{
/* if the ip checksum is good
indicate in skb. else set
CHECKSUM_NONE as device
failed to checksum the
packet */
if
(((
dsc
->
dscr_b
)
|
M_DMA_ETHRX_BADTCPCS
)
||
((
dsc
->
dscr_a
)
|
M_DMA_ETHRX_BADIP4CS
))
{
sb
->
ip_summed
=
CHECKSUM_NONE
;
}
else
{
printk
(
KERN_DEBUG
"hw checksum fail .
\n
"
);
if
(
!
((
dsc
->
dscr_a
)
&
M_DMA_ETHRX_BADIP4CS
)
&&
!
((
dsc
->
dscr_a
)
&
M_DMA_ETHRX_BADTCPCS
))
{
sb
->
ip_summed
=
CHECKSUM_UNNECESSARY
;
/* don't need to set sb->csum */
}
else
{
sb
->
ip_summed
=
CHECKSUM_NONE
;
}
}
/* rx_hw_checksum */
}
netif_rx
(
sb
);
}
...
...
@@ -1295,35 +1306,9 @@ static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d)
*/
curidx
=
d
->
sbdma_remptr
-
d
->
sbdma_dscrtable
;
{
/* XXX This is gross, ugly, and only here
* because justin hacked it in to fix a
* problem without really understanding it.
*
* It seems that, for whatever reason, this
* routine is invoked immediately upon the
* enabling of interrupts. So then the Read
* below returns zero, making hwidx a negative
* number, and anti-hilarity ensues.
*
* I'm guessing there's a proper fix involving
* clearing out interrupt state from old
* packets before enabling interrupts, but I'm
* not sure.
*
* Anyways, this hack seems to work, and is
* Good Enough for 11 PM. :)
*
* -Justin
*/
hwidx
=
(
int
)
(((
SBMAC_READCSR
(
d
->
sbdma_curdscr
)
&
M_DMA_CURDSCR_ADDR
)
-
d
->
sbdma_dscrtable_phys
)
/
sizeof
(
sbdmadscr_t
));
uint64_t
tmp
=
SBMAC_READCSR
(
d
->
sbdma_curdscr
);
if
(
!
tmp
)
{
break
;
}
hwidx
=
(
int
)
(((
tmp
&
M_DMA_CURDSCR_ADDR
)
-
d
->
sbdma_dscrtable_phys
)
/
sizeof
(
sbdmadscr_t
));
}
/*
* If they're the same, that means we've processed all
* of the descriptors up to (but not including) the one that
...
...
@@ -2378,7 +2363,7 @@ static int sbmac_init(struct net_device *dev, int idx)
/* Determine controller base address */
sc
->
sbm_base
=
KSEG1
ADDR
(
dev
->
base_addr
);
sc
->
sbm_base
=
IO
ADDR
(
dev
->
base_addr
);
sc
->
sbm_dev
=
dev
;
sc
->
sbe_idx
=
idx
;
...
...
@@ -2414,17 +2399,6 @@ static int sbmac_init(struct net_device *dev, int idx)
sbmac_initctx
(
sc
);
/*
* Display Ethernet address (this is called during the config
* process so we need to finish off the config message that
* was being displayed)
*/
printk
(
KERN_INFO
"%s: SiByte Ethernet at 0x%08lX, address: %02X-%02X-%02X-%02X-%02X-%02X
\n
"
,
dev
->
name
,
dev
->
base_addr
,
eaddr
[
0
],
eaddr
[
1
],
eaddr
[
2
],
eaddr
[
3
],
eaddr
[
4
],
eaddr
[
5
]);
/*
* Set up Linux device callins
*/
...
...
@@ -2447,7 +2421,24 @@ static int sbmac_init(struct net_device *dev, int idx)
err
=
register_netdev
(
dev
);
if
(
err
)
sbmac_uninitctx
(
sc
);
goto
out_uninit
;
/*
* Display Ethernet address (this is called during the config
* process so we need to finish off the config message that
* was being displayed)
*/
printk
(
KERN_INFO
"%s: SiByte Ethernet at 0x%08lX, address: %02X:%02X:%02X:%02X:%02X:%02X
\n
"
,
dev
->
name
,
dev
->
base_addr
,
eaddr
[
0
],
eaddr
[
1
],
eaddr
[
2
],
eaddr
[
3
],
eaddr
[
4
],
eaddr
[
5
]);
return
0
;
out_uninit:
sbmac_uninitctx
(
sc
);
return
err
;
}
...
...
@@ -2461,12 +2452,15 @@ static int sbmac_open(struct net_device *dev)
}
/*
* map/route interrupt
* map/route interrupt (clear status first, in case something
* weird is pending; we haven't initialized the mac registers
* yet)
*/
SBMAC_READCSR
(
sc
->
sbm_isr
);
if
(
request_irq
(
dev
->
irq
,
&
sbmac_intr
,
SA_SHIRQ
,
dev
->
name
,
dev
))
return
-
EBUSY
;
/*
* Configure default speed
*/
...
...
@@ -2803,8 +2797,8 @@ sbmac_setup_hwaddr(int chan,char *addr)
port
=
A_MAC_CHANNEL_BASE
(
chan
);
sbmac_parse_hwaddr
(
addr
,
eaddr
);
val
=
sbmac_addr2reg
(
eaddr
);
SBMAC_WRITECSR
(
KSEG1
ADDR
(
port
+
R_MAC_ETHERNET_ADDR
),
val
);
val
=
SBMAC_READCSR
(
KSEG1
ADDR
(
port
+
R_MAC_ETHERNET_ADDR
));
SBMAC_WRITECSR
(
IO
ADDR
(
port
+
R_MAC_ETHERNET_ADDR
),
val
);
val
=
SBMAC_READCSR
(
IO
ADDR
(
port
+
R_MAC_ETHERNET_ADDR
));
}
#endif
...
...
@@ -2869,7 +2863,7 @@ sbmac_init_module(void)
* If we find a zero, skip this MAC.
*/
sbmac_orig_hwaddr
[
idx
]
=
SBMAC_READCSR
(
KSEG1
ADDR
(
port
+
R_MAC_ETHERNET_ADDR
));
sbmac_orig_hwaddr
[
idx
]
=
SBMAC_READCSR
(
IO
ADDR
(
port
+
R_MAC_ETHERNET_ADDR
));
if
(
sbmac_orig_hwaddr
[
idx
]
==
0
)
{
printk
(
KERN_DEBUG
"sbmac: not configuring MAC at "
"%lx
\n
"
,
port
);
...
...
@@ -2905,17 +2899,19 @@ sbmac_init_module(void)
static
void
__exit
sbmac_cleanup_module
(
void
)
{
int
idx
;
struct
net_device
*
dev
;
sbmac_port_t
port
;
int
idx
;
for
(
idx
=
0
;
idx
<
MAX_UNITS
;
idx
++
)
{
dev
=
dev_sbmac
[
idx
];
if
(
!
dev
)
{
struct
sbmac_softc
*
sc
=
netdev_priv
(
dev
);
unregister_netdev
(
dev
);
sbmac_uninitctx
(
sc
);
free_netdev
(
dev
);
}
if
(
!
dev
)
continue
;
struct
sbmac_softc
*
sc
=
netdev_priv
(
dev
);
unregister_netdev
(
dev
);
sbmac_uninitctx
(
sc
);
free_netdev
(
dev
);
}
}
...
...
drivers/net/sgiseeq.c
View file @
fc3b6177
...
...
@@ -5,17 +5,17 @@
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/socket.h>
#include <linux/in.h>
#include <linux/route.h>
#include <linux/slab.h>
#include <linux/socket.h>
#include <linux/string.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
...
...
@@ -32,19 +32,18 @@
#include "sgiseeq.h"
static
char
*
version
=
"sgiseeq.c: David S. Miller (dm@engr.sgi.com)
\n
"
;
static
char
*
version
=
"sgiseeq.c: David S. Miller (dm@engr.sgi.com)
\n
"
;
static
char
*
sgiseeqstr
=
"SGI Seeq8003"
;
/*
If you want speed, you do something silly, it always has worked
*
for me. So, with that in mind, I've decided to make this driver
*
look completely like a stupid Lance from a driver architecture
*
perspective. Only difference is that here our "ring buffer" looks
*
and acts like a real Lance one does but is layed out like how the
*
HPC DMA and the Seeq want it to. You'd be surprised how a stupi
d
*
idea like this can pay off in performance, not to mention making
* this driver 2,000 times easier to write. ;-)
/*
*
If you want speed, you do something silly, it always has worked for me. So,
*
with that in mind, I've decided to make this driver look completely like a
*
stupid Lance from a driver architecture perspective. Only difference is that
*
here our "ring buffer" looks and acts like a real Lance one does but is
*
layed out like how the HPC DMA and the Seeq want it to. You'd be surprise
d
*
how a stupid idea like this can pay off in performance, not to mention
*
making
this driver 2,000 times easier to write. ;-)
*/
/* Tune these if we tend to run out often etc. */
...
...
@@ -74,9 +73,10 @@ struct sgiseeq_tx_desc {
signed
int
buf_vaddr
;
};
/* Warning: This structure is layed out in a certain way because
* HPC dma descriptors must be 8-byte aligned. So don't
* touch this without some care.
/*
* Warning: This structure is layed out in a certain way because HPC dma
* descriptors must be 8-byte aligned. So don't touch this without
* some care.
*/
struct
sgiseeq_init_block
{
/* Note the name ;-) */
/* Ptrs to the descriptors in KSEG1 uncached space. */
...
...
@@ -105,6 +105,7 @@ struct sgiseeq_private {
struct
net_device_stats
stats
;
struct
net_device
*
next_module
;
spinlock_t
tx_lock
;
};
/* A list of all installed seeq devices, for removing the driver module. */
...
...
@@ -112,7 +113,7 @@ static struct net_device *root_sgiseeq_dev;
static
inline
void
hpc3_eth_reset
(
struct
hpc3_ethregs
*
hregs
)
{
hregs
->
rx_reset
=
(
HPC3_ERXRST_CRESET
|
HPC3_ERXRST_CLRIRQ
)
;
hregs
->
rx_reset
=
HPC3_ERXRST_CRESET
|
HPC3_ERXRST_CLRIRQ
;
udelay
(
20
);
hregs
->
rx_reset
=
0
;
}
...
...
@@ -169,16 +170,16 @@ static int seeq_init_ring(struct net_device *dev)
/* Setup tx ring. */
for
(
i
=
0
;
i
<
SEEQ_TX_BUFFERS
;
i
++
)
{
if
(
!
ib
->
tx_desc
[
i
].
tdma
.
pbuf
)
{
if
(
!
ib
->
tx_desc
[
i
].
tdma
.
pbuf
)
{
unsigned
long
buffer
;
buffer
=
(
unsigned
long
)
kmalloc
(
PKT_BUF_SZ
,
GFP_KERNEL
);
if
(
!
buffer
)
return
-
ENOMEM
;
ib
->
tx_desc
[
i
].
buf_vaddr
=
KSEG1ADDR
(
buffer
);
ib
->
tx_desc
[
i
].
tdma
.
pbuf
=
PHYSADDR
(
buffer
);
ib
->
tx_desc
[
i
].
tdma
.
pbuf
=
C
PHYSADDR
(
buffer
);
}
ib
->
tx_desc
[
i
].
tdma
.
cntinfo
=
(
TCNTINFO_INIT
)
;
ib
->
tx_desc
[
i
].
tdma
.
cntinfo
=
TCNTINFO_INIT
;
}
/* And now the rx ring. */
...
...
@@ -190,11 +191,11 @@ static int seeq_init_ring(struct net_device *dev)
if
(
!
buffer
)
return
-
ENOMEM
;
ib
->
rx_desc
[
i
].
buf_vaddr
=
KSEG1ADDR
(
buffer
);
ib
->
rx_desc
[
i
].
rdma
.
pbuf
=
PHYSADDR
(
buffer
);
ib
->
rx_desc
[
i
].
rdma
.
pbuf
=
C
PHYSADDR
(
buffer
);
}
ib
->
rx_desc
[
i
].
rdma
.
cntinfo
=
(
RCNTINFO_INIT
)
;
ib
->
rx_desc
[
i
].
rdma
.
cntinfo
=
RCNTINFO_INIT
;
}
ib
->
rx_desc
[
i
-
1
].
rdma
.
cntinfo
|=
(
HPCDMA_EOR
)
;
ib
->
rx_desc
[
i
-
1
].
rdma
.
cntinfo
|=
HPCDMA_EOR
;
return
0
;
}
...
...
@@ -210,7 +211,7 @@ void sgiseeq_dump_rings(void)
struct
hpc3_ethregs
*
hregs
=
gpriv
->
hregs
;
int
i
;
if
(
once
)
if
(
once
)
return
;
once
++
;
printk
(
"RING DUMP:
\n
"
);
...
...
@@ -258,17 +259,17 @@ static int init_seeq(struct net_device *dev, struct sgiseeq_private *sp,
/* Setup to field the proper interrupt types. */
if
(
sp
->
is_edlc
)
{
sregs
->
tstat
=
(
TSTAT_INIT_EDLC
)
;
sregs
->
tstat
=
TSTAT_INIT_EDLC
;
sregs
->
rw
.
wregs
.
control
=
sp
->
control
;
sregs
->
rw
.
wregs
.
frame_gap
=
0
;
}
else
{
sregs
->
tstat
=
(
TSTAT_INIT_SEEQ
)
;
sregs
->
tstat
=
TSTAT_INIT_SEEQ
;
}
hregs
->
rx_dconfig
|=
RDMACFG_INIT
;
hregs
->
rx_ndptr
=
PHYSADDR
(
&
sp
->
srings
.
rx_desc
[
0
]
);
hregs
->
tx_ndptr
=
PHYSADDR
(
&
sp
->
srings
.
tx_desc
[
0
]
);
hregs
->
rx_ndptr
=
CPHYSADDR
(
sp
->
srings
.
rx_desc
);
hregs
->
tx_ndptr
=
CPHYSADDR
(
sp
->
srings
.
tx_desc
);
seeq_go
(
sp
,
hregs
,
sregs
);
return
0
;
...
...
@@ -293,7 +294,7 @@ static inline void rx_maybe_restart(struct sgiseeq_private *sp,
struct
sgiseeq_regs
*
sregs
)
{
if
(
!
(
hregs
->
rx_ctrl
&
HPC3_ERXCTRL_ACTIVE
))
{
hregs
->
rx_ndptr
=
PHYSADDR
(
&
sp
->
srings
.
rx_desc
[
sp
->
rx_new
]
);
hregs
->
rx_ndptr
=
CPHYSADDR
(
sp
->
srings
.
rx_desc
+
sp
->
rx_new
);
seeq_go
(
sp
,
hregs
,
sregs
);
}
}
...
...
@@ -315,7 +316,7 @@ static inline void sgiseeq_rx(struct net_device *dev, struct sgiseeq_private *sp
/* Service every received packet. */
for_each_rx
(
rd
,
sp
)
{
len
=
(
PKT_BUF_SZ
-
(
rd
->
rdma
.
cntinfo
&
HPCDMA_BCNT
)
-
3
)
;
len
=
PKT_BUF_SZ
-
(
rd
->
rdma
.
cntinfo
&
HPCDMA_BCNT
)
-
3
;
pkt_pointer
=
(
unsigned
char
*
)(
long
)
rd
->
buf_vaddr
;
pkt_status
=
pkt_pointer
[
len
+
2
];
...
...
@@ -345,7 +346,7 @@ static inline void sgiseeq_rx(struct net_device *dev, struct sgiseeq_private *sp
}
/* Return the entry to the ring pool. */
rd
->
rdma
.
cntinfo
=
(
RCNTINFO_INIT
)
;
rd
->
rdma
.
cntinfo
=
RCNTINFO_INIT
;
sp
->
rx_new
=
NEXT_RX
(
sp
->
rx_new
);
}
sp
->
srings
.
rx_desc
[
orig_end
].
rdma
.
cntinfo
&=
~
(
HPCDMA_EOR
);
...
...
@@ -375,7 +376,7 @@ static inline void kick_tx(struct sgiseeq_tx_desc *td,
(
HPCDMA_XIU
|
HPCDMA_ETXD
))
td
=
(
struct
sgiseeq_tx_desc
*
)(
long
)
KSEG1ADDR
(
td
->
tdma
.
pnext
);
if
(
td
->
tdma
.
cntinfo
&
HPCDMA_XIU
)
{
hregs
->
tx_ndptr
=
PHYSADDR
(
td
);
hregs
->
tx_ndptr
=
C
PHYSADDR
(
td
);
hregs
->
tx_ctrl
=
HPC3_ETXCTRL_ACTIVE
;
}
}
...
...
@@ -407,8 +408,8 @@ static inline void sgiseeq_tx(struct net_device *dev, struct sgiseeq_private *sp
if
(
!
(
td
->
tdma
.
cntinfo
&
(
HPCDMA_XIU
)))
break
;
if
(
!
(
td
->
tdma
.
cntinfo
&
(
HPCDMA_ETXD
)))
{
if
(
!
(
status
&
HPC3_ETXCTRL_ACTIVE
))
{
hregs
->
tx_ndptr
=
PHYSADDR
(
td
);
if
(
!
(
status
&
HPC3_ETXCTRL_ACTIVE
))
{
hregs
->
tx_ndptr
=
C
PHYSADDR
(
td
);
hregs
->
tx_ctrl
=
HPC3_ETXCTRL_ACTIVE
;
}
break
;
...
...
@@ -427,6 +428,8 @@ static irqreturn_t sgiseeq_interrupt(int irq, void *dev_id, struct pt_regs *regs
struct
hpc3_ethregs
*
hregs
=
sp
->
hregs
;
struct
sgiseeq_regs
*
sregs
=
sp
->
sregs
;
spin_lock
(
&
sp
->
tx_lock
);
/* Ack the IRQ and set software state. */
hregs
->
rx_reset
=
HPC3_ERXRST_CLRIRQ
;
...
...
@@ -440,6 +443,8 @@ static irqreturn_t sgiseeq_interrupt(int irq, void *dev_id, struct pt_regs *regs
if
((
TX_BUFFS_AVAIL
(
sp
)
>
0
)
&&
netif_queue_stopped
(
dev
))
{
netif_wake_queue
(
dev
);
}
spin_unlock
(
&
sp
->
tx_lock
);
return
IRQ_HANDLED
;
}
...
...
@@ -500,7 +505,7 @@ static int sgiseeq_start_xmit(struct sk_buff *skb, struct net_device *dev)
struct
sgiseeq_tx_desc
*
td
;
int
skblen
,
len
,
entry
;
local_irq_save
(
flags
);
spin_lock_irqsave
(
&
sp
->
tx_lock
,
flags
);
/* Setup... */
skblen
=
skb
->
len
;
...
...
@@ -526,12 +531,12 @@ static int sgiseeq_start_xmit(struct sk_buff *skb, struct net_device *dev)
if
(
len
!=
skblen
)
memset
((
char
*
)(
long
)
td
->
buf_vaddr
+
skb
->
len
,
0
,
len
-
skblen
);
td
->
tdma
.
cntinfo
=
(
len
&
HPCDMA_BCNT
)
|
(
HPCDMA_XIU
|
HPCDMA_EOXP
|
HPCDMA_XIE
|
HPCDMA_EOX
)
;
HPCDMA_XIU
|
HPCDMA_EOXP
|
HPCDMA_XIE
|
HPCDMA_EOX
;
if
(
sp
->
tx_old
!=
sp
->
tx_new
)
{
struct
sgiseeq_tx_desc
*
backend
;
backend
=
&
sp
->
srings
.
tx_desc
[
PREV_TX
(
sp
->
tx_new
)];
backend
->
tdma
.
cntinfo
&=
~
(
HPCDMA_EOX
)
;
backend
->
tdma
.
cntinfo
&=
~
HPCDMA_EOX
;
}
sp
->
tx_new
=
NEXT_TX
(
sp
->
tx_new
);
/* Advance. */
...
...
@@ -544,7 +549,7 @@ static int sgiseeq_start_xmit(struct sk_buff *skb, struct net_device *dev)
if
(
!
TX_BUFFS_AVAIL
(
sp
))
netif_stop_queue
(
dev
);
local_irq_restore
(
flags
);
spin_unlock_irqrestore
(
&
sp
->
tx_lock
,
flags
);
return
0
;
}
...
...
@@ -574,11 +579,11 @@ static inline void setup_tx_ring(struct sgiseeq_tx_desc *buf, int nbufs)
int
i
=
0
;
while
(
i
<
(
nbufs
-
1
))
{
buf
[
i
].
tdma
.
pnext
=
PHYSADDR
(
&
buf
[
i
+
1
]
);
buf
[
i
].
tdma
.
pnext
=
CPHYSADDR
(
buf
+
i
+
1
);
buf
[
i
].
tdma
.
pbuf
=
0
;
i
++
;
}
buf
[
i
].
tdma
.
pnext
=
PHYSADDR
(
&
buf
[
0
]
);
buf
[
i
].
tdma
.
pnext
=
CPHYSADDR
(
buf
);
}
static
inline
void
setup_rx_ring
(
struct
sgiseeq_rx_desc
*
buf
,
int
nbufs
)
...
...
@@ -586,12 +591,12 @@ static inline void setup_rx_ring(struct sgiseeq_rx_desc *buf, int nbufs)
int
i
=
0
;
while
(
i
<
(
nbufs
-
1
))
{
buf
[
i
].
rdma
.
pnext
=
PHYSADDR
(
&
buf
[
i
+
1
]
);
buf
[
i
].
rdma
.
pnext
=
CPHYSADDR
(
buf
+
i
+
1
);
buf
[
i
].
rdma
.
pbuf
=
0
;
i
++
;
}
buf
[
i
].
rdma
.
pbuf
=
0
;
buf
[
i
].
rdma
.
pnext
=
PHYSADDR
(
&
buf
[
0
]
);
buf
[
i
].
rdma
.
pnext
=
CPHYSADDR
(
buf
);
}
#define ALIGNED(x) ((((unsigned long)(x)) + 0xf) & ~(0xf))
...
...
@@ -600,45 +605,36 @@ int sgiseeq_init(struct hpc3_regs* regs, int irq)
{
struct
net_device
*
dev
;
struct
sgiseeq_private
*
sp
;
int
err
=
-
ENOMEM
;
int
i
;
sp
=
(
struct
sgiseeq_private
*
)
get_zeroed_page
(
GFP_KERNEL
);
if
(
!
sp
)
{
printk
(
KERN_ERR
"Seeq8003: Could not allocate private data.
\n
"
);
return
-
ENOMEM
;
}
int
err
,
i
;
dev
=
alloc_etherdev
(
0
);
if
(
!
dev
)
{
printk
(
KERN_ERR
"Seeq8003: Could not allocate memory for device.
\n
"
);
goto
out
;
printk
(
KERN_ERR
"Sgiseeq: Etherdev alloc failed, aborting.
\n
"
);
err
=
-
ENOMEM
;
goto
err_out
;
}
/* Make private data page aligned */
sp
=
(
struct
sgiseeq_private
*
)
get_zeroed_page
(
GFP_KERNEL
);
if
(
!
sp
)
{
printk
(
KERN_ERR
"Sgiseeq: Page alloc failed, aborting.
\n
"
);
err
=
-
ENOMEM
;
goto
err_out_free_dev
;
}
if
(
request_irq
(
irq
,
sgiseeq_interrupt
,
0
,
sgiseeqstr
,
dev
))
{
printk
(
KERN_ERR
"Seeq8003: Can't get irq %d
\n
"
,
irq
);
printk
(
KERN_ERR
"Seeq8003: Can't get irq %d
\n
"
,
dev
->
irq
);
err
=
-
EAGAIN
;
goto
out1
;
goto
err_out_free_page
;
}
printk
(
KERN_INFO
"%s: SGI Seeq8003 "
,
dev
->
name
);
#define EADDR_NVOFS 250
for
(
i
=
0
;
i
<
3
;
i
++
)
{
unsigned
short
tmp
=
ip22_nvram_read
(
EADDR_NVOFS
/
2
+
i
);
printk
(
"%2.2x:%2.2x%c"
,
dev
->
dev_addr
[
2
*
i
]
=
tmp
>>
8
,
dev
->
dev_addr
[
2
*
i
+
1
]
=
tmp
&
0xff
,
i
==
2
?
' '
:
':'
);
dev
->
dev_addr
[
2
*
i
]
=
tmp
>>
8
;
dev
->
dev_addr
[
2
*
i
+
1
]
=
tmp
&
0xff
;
}
printk
(
"
\n
"
);
SET_MODULE_OWNER
(
dev
);
dev
->
priv
=
sp
;
#ifdef DEBUG
gpriv
=
sp
;
gdev
=
dev
;
...
...
@@ -648,11 +644,11 @@ int sgiseeq_init(struct hpc3_regs* regs, int irq)
sp
->
name
=
sgiseeqstr
;
sp
->
srings
.
rx_desc
=
(
struct
sgiseeq_rx_desc
*
)
(
KSEG1ADDR
(
ALIGNED
(
&
sp
->
srings
.
rxvector
[
0
])
));
KSEG1ADDR
(
ALIGNED
(
&
sp
->
srings
.
rxvector
[
0
]
));
dma_cache_wback_inv
((
unsigned
long
)
&
sp
->
srings
.
rxvector
,
sizeof
(
sp
->
srings
.
rxvector
));
sp
->
srings
.
tx_desc
=
(
struct
sgiseeq_tx_desc
*
)
(
KSEG1ADDR
(
ALIGNED
(
&
sp
->
srings
.
txvector
[
0
])
));
KSEG1ADDR
(
ALIGNED
(
&
sp
->
srings
.
txvector
[
0
]
));
dma_cache_wback_inv
((
unsigned
long
)
&
sp
->
srings
.
txvector
,
sizeof
(
sp
->
srings
.
txvector
));
...
...
@@ -665,34 +661,45 @@ int sgiseeq_init(struct hpc3_regs* regs, int irq)
sp
->
is_edlc
=
!
(
sp
->
sregs
->
rw
.
rregs
.
collision_tx
[
0
]
&
0xff
);
if
(
sp
->
is_edlc
)
sp
->
control
=
(
SEEQ_CTRL_XCNT
|
SEEQ_CTRL_ACCNT
|
SEEQ_CTRL_SFLAG
|
SEEQ_CTRL_ESHORT
|
SEEQ_CTRL_ENCARR
);
dev
->
open
=
sgiseeq_open
;
dev
->
stop
=
sgiseeq_close
;
dev
->
hard_start_xmit
=
sgiseeq_start_xmit
;
dev
->
tx_timeout
=
timeout
;
dev
->
watchdog_timeo
=
(
200
*
HZ
)
/
1000
;
dev
->
get_stats
=
sgiseeq_get_stats
;
dev
->
set_multicast_list
=
sgiseeq_set_multicast
;
dev
->
irq
=
irq
;
dev
->
dma
=
0
;
err
=
register_netdev
(
dev
);
if
(
err
)
goto
out2
;
sp
->
control
=
SEEQ_CTRL_XCNT
|
SEEQ_CTRL_ACCNT
|
SEEQ_CTRL_SFLAG
|
SEEQ_CTRL_ESHORT
|
SEEQ_CTRL_ENCARR
;
dev
->
open
=
sgiseeq_open
;
dev
->
stop
=
sgiseeq_close
;
dev
->
hard_start_xmit
=
sgiseeq_start_xmit
;
dev
->
tx_timeout
=
timeout
;
dev
->
watchdog_timeo
=
(
200
*
HZ
)
/
1000
;
dev
->
get_stats
=
sgiseeq_get_stats
;
dev
->
set_multicast_list
=
sgiseeq_set_multicast
;
dev
->
irq
=
irq
;
dev
->
dma
=
0
;
dev
->
priv
=
sp
;
if
(
register_netdev
(
dev
))
{
printk
(
KERN_ERR
"Sgiseeq: Cannot register net device, "
"aborting.
\n
"
);
err
=
-
ENODEV
;
goto
err_out_free_irq
;
}
printk
(
KERN_INFO
"%s: SGI Seeq8003 "
,
dev
->
name
);
for
(
i
=
0
;
i
<
6
;
i
++
)
printk
(
"%2.2x%c"
,
dev
->
dev_addr
[
i
],
i
==
5
?
'\n'
:
':'
);
sp
->
next_module
=
root_sgiseeq_dev
;
root_sgiseeq_dev
=
dev
;
return
0
;
out2:
free_irq
(
dev
->
irq
,
dev
);
out1:
free_netdev
(
dev
);
out:
err_out_free_irq:
free_irq
(
irq
,
dev
);
err_out_free_page:
free_page
((
unsigned
long
)
sp
);
err_out_free_dev:
kfree
(
dev
);
err_out:
return
err
;
}
...
...
@@ -706,17 +713,18 @@ static int __init sgiseeq_probe(void)
static
void
__exit
sgiseeq_exit
(
void
)
{
struct
net_device
*
next
,
*
dev
;
struct
sgiseeq_private
*
sp
;
struct
net_device
*
next
,
*
dev
=
root_sgiseeq_dev
;
int
irq
;
while
(
dev
)
{
sp
=
dev
->
priv
;
for
(
dev
=
root_sgiseeq_dev
;
dev
;
dev
=
next
)
{
sp
=
(
struct
sgiseeq_private
*
)
dev
->
priv
;
next
=
sp
->
next_module
;
irq
=
dev
->
irq
;
unregister_netdev
(
dev
);
free_irq
(
dev
->
irq
,
dev
);
free_page
((
unsigned
long
)
sp
);
free_irq
(
irq
,
dev
);
free_page
((
unsigned
long
)
dev
->
priv
);
free_netdev
(
dev
);
dev
=
next
;
}
}
...
...
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