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
8e21c010
Commit
8e21c010
authored
Jun 25, 2003
by
Ralf Bächle
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[netdrvr] update sb1250-mac
parent
aadf0cf9
Changes
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
497 additions
and
234 deletions
+497
-234
drivers/net/sb1250-mac.c
drivers/net/sb1250-mac.c
+497
-234
No files found.
drivers/net/sb1250-mac.c
View file @
8e21c010
/*
* Copyright (C) 2001 Broadcom Corporation
* Copyright (C) 2001
,2002,2003
Broadcom Corporation
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
...
...
@@ -17,17 +17,21 @@
*/
/*
This driver is designed for the Broadcom
BCM12500 SOC chip's
built-in
This driver is designed for the Broadcom
SiByte SOC
built-in
Ethernet controllers.
The author may be reached as mpl@broadcom.com
Written by Mitch Lichtenberg at Broadcom Corp.
*/
#define CONFIG_SBMAC_COALESCE
/* A few user-configurable values.
These may be modified when a driver module is loaded. */
static
int
debug
=
1
;
/* 1 normal messages, 0 quiet .. 7 verbose. */
static
int
noisy_mii
=
1
;
/* mii status msgs */
/* Used to pass the media type, etc.
Both 'options[]' and 'full_duplex[]' should exist for driver
...
...
@@ -41,6 +45,10 @@ static int options[MAX_UNITS] = {-1, -1, -1};
static
int
full_duplex
[
MAX_UNITS
]
=
{
-
1
,
-
1
,
-
1
};
#endif
#ifdef CONFIG_SBMAC_COALESCE
static
int
int_pktcnt
=
0
;
static
int
int_timeout
=
0
;
#endif
/* Operational parameters that usually are not changed. */
...
...
@@ -59,22 +67,21 @@ static int full_duplex[MAX_UNITS] = {-1, -1, -1};
#include <linux/timer.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/config.h>
#include <asm/processor.h>
/* Processor type for cache alignment. */
#include <asm/bitops.h>
#include <asm/io.h>
#include <asm/sibyte/sb1250.h>
#include <asm/sibyte/64bit.h>
#include <asm/cache.h>
/* This is only here until the firmware is ready. In that case,
the firmware leaves the ethernet address in the register for us. */
#ifdef CONFIG_S
WARM
_STANDALONE
#ifdef CONFIG_S
IBYTE
_STANDALONE
#define SBMAC_ETH0_HWADDR "40:00:00:00:01:00"
#define SBMAC_ETH1_HWADDR "40:00:00:00:01:01"
#define SBMAC_ETH2_HWADDR "40:00:00:00:01:02"
...
...
@@ -84,23 +91,29 @@ static int full_duplex[MAX_UNITS] = {-1, -1, -1};
/* These identify the driver base version and may not be removed. */
#if 0
static char version1[] __devinitdata =
"sb1250-mac.c:1.00 1/11/2001 Written by Mitch Lichtenberg
(mpl@broadcom.com)
\n";
"sb1250-mac.c:1.00 1/11/2001 Written by Mitch Lichtenberg\n";
#endif
MODULE_AUTHOR
(
"Mitch Lichtenberg (
mpl@broadcom.com
)"
);
MODULE_DESCRIPTION
(
"Broadcom
BCM12500
SOC GB Ethernet driver"
);
MODULE_AUTHOR
(
"Mitch Lichtenberg (
Broadcom Corp.
)"
);
MODULE_DESCRIPTION
(
"Broadcom
SiByte
SOC GB Ethernet driver"
);
MODULE_PARM
(
debug
,
"i"
);
MODULE_PARM
(
noisy_mii
,
"i"
);
MODULE_PARM
(
options
,
"1-"
__MODULE_STRING
(
MAX_UNITS
)
"i"
);
MODULE_PARM
(
full_duplex
,
"1-"
__MODULE_STRING
(
MAX_UNITS
)
"i"
);
MODULE_PARM
(
int_pktcnt
,
"i"
);
MODULE_PARM
(
int_timeout
,
"i"
);
#include <asm/sibyte/sb1250.h>
#include <asm/sibyte/sb1250_defs.h>
#include <asm/sibyte/sb1250_regs.h>
#include <asm/sibyte/sb1250_mac.h>
#include <asm/sibyte/sb1250_dma.h>
#include <asm/sibyte/sb1250_int.h>
#include <asm/sibyte/sb1250_scd.h>
#include <asm/sibyte/64bit.h>
/**********************************************************************
...
...
@@ -109,8 +122,6 @@ MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
typedef
unsigned
long
sbmac_port_t
;
typedef
uint64_t
sbmac_physaddr_t
;
typedef
uint64_t
sbmac_enetaddr_t
;
typedef
enum
{
sbmac_speed_auto
,
sbmac_speed_10
,
sbmac_speed_100
,
sbmac_speed_1000
}
sbmac_speed_t
;
...
...
@@ -134,17 +145,11 @@ typedef enum { sbmac_state_uninit, sbmac_state_off, sbmac_state_on,
(d)->sbdma_dscrtable : (d)->f+1)
#define CACHELINESIZE 32
#define NUMCACHEBLKS(x) (((x)+CACHELINESIZE-1)/CACHELINESIZE)
#define KMALLOC(x) kmalloc((x),GFP_KERNEL)
#define KFREE(x) kfree(x)
#define KVTOPHYS(x) virt_to_bus((void *)(x))
#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) (in64((unsigned long)(t)))
#define SBMAC_WRITECSR(t,v) (out64(v, (unsigned long)(t)))
#define PKSEG1(x) ((sbmac_port_t) KSEG1ADDR(x))
#define SBMAC_MAX_TXDESCR 32
#define SBMAC_MAX_RXDESCR 32
...
...
@@ -152,6 +157,7 @@ typedef enum { sbmac_state_uninit, sbmac_state_off, sbmac_state_on,
#define ETHER_ALIGN 2
#define ETHER_ADDR_LEN 6
#define ENET_PACKET_SIZE 1518
/*#define ENET_PACKET_SIZE 9216 */
/**********************************************************************
* DMA Descriptor structure
...
...
@@ -163,7 +169,6 @@ typedef struct sbdmadscr_s {
}
sbdmadscr_t
;
typedef
unsigned
long
paddr_t
;
typedef
unsigned
long
vaddr_t
;
/**********************************************************************
* DMA Controller structure
...
...
@@ -180,6 +185,11 @@ typedef struct sbmacdma_s {
int
sbdma_channel
;
/* channel number */
int
sbdma_txdir
;
/* direction (1=transmit) */
int
sbdma_maxdescr
;
/* total # of descriptors in ring */
#ifdef CONFIG_SBMAC_COALESCE
int
sbdma_int_pktcnt
;
/* # descriptors rx/tx before interrupt*/
int
sbdma_int_timeout
;
/* # usec rx/tx interrupt */
#endif
sbmac_port_t
sbdma_config0
;
/* DMA config register 0 */
sbmac_port_t
sbdma_config1
;
/* DMA config register 1 */
sbmac_port_t
sbdma_dscrbase
;
/* Descriptor base address */
...
...
@@ -198,7 +208,6 @@ typedef struct sbmacdma_s {
paddr_t
sbdma_dscrtable_phys
;
/* and also the phys addr */
sbdmadscr_t
*
sbdma_addptr
;
/* next dscr for sw to add */
sbdmadscr_t
*
sbdma_remptr
;
/* next dscr for sw to remove */
}
sbmacdma_t
;
...
...
@@ -230,7 +239,7 @@ struct sbmac_softc {
* Controller-specific things
*/
sbmac_port_t
sbm_base
;
/* MAC's base address */
unsigned
long
sbm_base
;
/* MAC's base address */
sbmac_state_t
sbm_state
;
/* current state */
sbmac_port_t
sbm_macenable
;
/* MAC Enable Register */
...
...
@@ -246,11 +255,12 @@ struct sbmac_softc {
sbmac_duplex_t
sbm_duplex
;
/* current duplex */
sbmac_fc_t
sbm_fc
;
/* current flow control setting */
u
_char
sbm_hwaddr
[
ETHER_ADDR_LEN
];
u
nsigned
char
sbm_hwaddr
[
ETHER_ADDR_LEN
];
sbmacdma_t
sbm_txdma
;
/* for now, only use channel 0 */
sbmacdma_t
sbm_rxdma
;
int
rx_hw_checksum
;
int
sbe_idx
;
};
...
...
@@ -267,7 +277,7 @@ static void sbdma_initctx(sbmacdma_t *d,
int
chan
,
int
txrx
,
int
maxdescr
);
static
void
sbdma_channel_start
(
sbmacdma_t
*
d
);
static
void
sbdma_channel_start
(
sbmacdma_t
*
d
,
int
rxtx
);
static
int
sbdma_add_rcvbuffer
(
sbmacdma_t
*
d
,
struct
sk_buff
*
m
);
static
int
sbdma_add_txbuffer
(
sbmacdma_t
*
d
,
struct
sk_buff
*
m
);
static
void
sbdma_emptyring
(
sbmacdma_t
*
d
);
...
...
@@ -279,12 +289,11 @@ static void sbmac_channel_start(struct sbmac_softc *s);
static
void
sbmac_channel_stop
(
struct
sbmac_softc
*
s
);
static
sbmac_state_t
sbmac_set_channel_state
(
struct
sbmac_softc
*
,
sbmac_state_t
);
static
void
sbmac_promiscuous_mode
(
struct
sbmac_softc
*
sc
,
int
onoff
);
/*static void sbmac_init_and_start(struct sbmac_softc *sc);*/
static
uint64_t
sbmac_addr2reg
(
unsigned
char
*
ptr
);
static
irqreturn_t
sbmac_intr
(
int
irq
,
void
*
dev_instance
,
struct
pt_regs
*
rgs
);
static
int
sbmac_start_tx
(
struct
sk_buff
*
skb
,
struct
net_device
*
dev
);
static
void
sbmac_setmulti
(
struct
sbmac_softc
*
sc
);
static
int
sbmac_init
(
struct
net_device
*
dev
);
static
int
sbmac_init
(
struct
net_device
*
dev
,
int
idx
);
static
int
sbmac_set_speed
(
struct
sbmac_softc
*
s
,
sbmac_speed_t
speed
);
static
int
sbmac_set_duplex
(
struct
sbmac_softc
*
s
,
sbmac_duplex_t
duplex
,
sbmac_fc_t
fc
);
...
...
@@ -308,6 +317,8 @@ static void sbmac_mii_write(struct sbmac_softc *s,int phyaddr,int regidx,
* Globals
********************************************************************* */
static
uint64_t
sbmac_orig_hwaddr
[
MAX_UNITS
];
/**********************************************************************
* MDIO constants
...
...
@@ -328,8 +339,8 @@ static void sbmac_mii_write(struct sbmac_softc *s,int phyaddr,int regidx,
#define BMCR_DUPLEX 0x0100
#define BMCR_COLTEST 0x0080
#define BMCR_SPEED1 0x0040
#define BMCR_SPEED1000
(BMCR_SPEED1|BMCR_SPEED0)
#define BMCR_SPEED100
(BMCR_SPEED0)
#define BMCR_SPEED1000
BMCR_SPEED1
#define BMCR_SPEED100
BMCR_SPEED0
#define BMCR_SPEED10 0
#define BMSR_100BT4 0x8000
...
...
@@ -437,6 +448,8 @@ static void sbmac_mii_write(struct sbmac_softc *s,int phyaddr,int regidx,
#define M_MAC_MDIO_DIR_OUTPUT 0
/* for clarity */
#define ENABLE 1
#define DISABLE 0
/**********************************************************************
* SBMAC_MII_SYNC(s)
...
...
@@ -490,7 +503,8 @@ static void sbmac_mii_senddata(struct sbmac_softc *s,unsigned int data, int bitc
curmask
=
1
<<
(
bitcnt
-
1
);
for
(
i
=
0
;
i
<
bitcnt
;
i
++
)
{
if
(
data
&
curmask
)
bits
|=
M_MAC_MDIO_OUT
;
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
);
...
...
@@ -571,7 +585,8 @@ static unsigned int sbmac_mii_read(struct sbmac_softc *s,int phyaddr,int regidx)
regval
<<=
1
;
if
(
error
==
0
)
{
if
(
SBMAC_READCSR
(
s
->
sbm_mdio
)
&
M_MAC_MDIO_IN
)
regval
|=
1
;
if
(
SBMAC_READCSR
(
s
->
sbm_mdio
)
&
M_MAC_MDIO_IN
)
regval
|=
1
;
}
SBMAC_WRITECSR
(
s
->
sbm_mdio
,
M_MAC_MDIO_DIR_INPUT
|
M_MAC_MDC
);
...
...
@@ -581,7 +596,8 @@ static unsigned int sbmac_mii_read(struct sbmac_softc *s,int phyaddr,int regidx)
/* Switch back to output */
SBMAC_WRITECSR
(
s
->
sbm_mdio
,
M_MAC_MDIO_DIR_OUTPUT
);
if
(
error
==
0
)
return
regval
;
if
(
error
==
0
)
return
regval
;
return
0
;
}
...
...
@@ -651,20 +667,68 @@ static void sbdma_initctx(sbmacdma_t *d,
d
->
sbdma_channel
=
chan
;
d
->
sbdma_txdir
=
txrx
;
#if 0
/* RMON clearing */
s->sbe_idx =(s->sbm_base - A_MAC_BASE_0)/MAC_SPACING;
#endif
SBMAC_WRITECSR
(
KSEG1ADDR
(
A_MAC_REGISTER
(
s
->
sbe_idx
,
R_MAC_RMON_TX_BYTES
)),
0
);
SBMAC_WRITECSR
(
KSEG1ADDR
(
A_MAC_REGISTER
(
s
->
sbe_idx
,
R_MAC_RMON_COLLISIONS
)),
0
);
SBMAC_WRITECSR
(
KSEG1ADDR
(
A_MAC_REGISTER
(
s
->
sbe_idx
,
R_MAC_RMON_LATE_COL
)),
0
);
SBMAC_WRITECSR
(
KSEG1ADDR
(
A_MAC_REGISTER
(
s
->
sbe_idx
,
R_MAC_RMON_EX_COL
)),
0
);
SBMAC_WRITECSR
(
KSEG1ADDR
(
A_MAC_REGISTER
(
s
->
sbe_idx
,
R_MAC_RMON_FCS_ERROR
)),
0
);
SBMAC_WRITECSR
(
KSEG1ADDR
(
A_MAC_REGISTER
(
s
->
sbe_idx
,
R_MAC_RMON_TX_ABORT
)),
0
);
SBMAC_WRITECSR
(
KSEG1ADDR
(
A_MAC_REGISTER
(
s
->
sbe_idx
,
R_MAC_RMON_TX_BAD
)),
0
);
SBMAC_WRITECSR
(
KSEG1ADDR
(
A_MAC_REGISTER
(
s
->
sbe_idx
,
R_MAC_RMON_TX_GOOD
)),
0
);
SBMAC_WRITECSR
(
KSEG1ADDR
(
A_MAC_REGISTER
(
s
->
sbe_idx
,
R_MAC_RMON_TX_RUNT
)),
0
);
SBMAC_WRITECSR
(
KSEG1ADDR
(
A_MAC_REGISTER
(
s
->
sbe_idx
,
R_MAC_RMON_TX_OVERSIZE
)),
0
);
SBMAC_WRITECSR
(
KSEG1ADDR
(
A_MAC_REGISTER
(
s
->
sbe_idx
,
R_MAC_RMON_RX_BYTES
)),
0
);
SBMAC_WRITECSR
(
KSEG1ADDR
(
A_MAC_REGISTER
(
s
->
sbe_idx
,
R_MAC_RMON_RX_MCAST
)),
0
);
SBMAC_WRITECSR
(
KSEG1ADDR
(
A_MAC_REGISTER
(
s
->
sbe_idx
,
R_MAC_RMON_RX_BCAST
)),
0
);
SBMAC_WRITECSR
(
KSEG1ADDR
(
A_MAC_REGISTER
(
s
->
sbe_idx
,
R_MAC_RMON_RX_BAD
)),
0
);
SBMAC_WRITECSR
(
KSEG1ADDR
(
A_MAC_REGISTER
(
s
->
sbe_idx
,
R_MAC_RMON_RX_GOOD
)),
0
);
SBMAC_WRITECSR
(
KSEG1ADDR
(
A_MAC_REGISTER
(
s
->
sbe_idx
,
R_MAC_RMON_RX_RUNT
)),
0
);
SBMAC_WRITECSR
(
KSEG1ADDR
(
A_MAC_REGISTER
(
s
->
sbe_idx
,
R_MAC_RMON_RX_OVERSIZE
)),
0
);
SBMAC_WRITECSR
(
KSEG1ADDR
(
A_MAC_REGISTER
(
s
->
sbe_idx
,
R_MAC_RMON_RX_FCS_ERROR
)),
0
);
SBMAC_WRITECSR
(
KSEG1ADDR
(
A_MAC_REGISTER
(
s
->
sbe_idx
,
R_MAC_RMON_RX_LENGTH_ERROR
)),
0
);
SBMAC_WRITECSR
(
KSEG1ADDR
(
A_MAC_REGISTER
(
s
->
sbe_idx
,
R_MAC_RMON_RX_CODE_ERROR
)),
0
);
SBMAC_WRITECSR
(
KSEG1ADDR
(
A_MAC_REGISTER
(
s
->
sbe_idx
,
R_MAC_RMON_RX_ALIGN_ERROR
)),
0
);
/*
* initialize register pointers
*/
d
->
sbdma_config0
=
PKSEG1
(
s
->
sbm_base
+
R_MAC_DMA_REGISTER
(
txrx
,
chan
,
R_MAC_DMA_CONFIG0
)
);
s
->
sbm_base
+
R_MAC_DMA_REGISTER
(
txrx
,
chan
,
R_MAC_DMA_CONFIG0
);
d
->
sbdma_config1
=
PKSEG1
(
s
->
sbm_base
+
R_MAC_DMA_REGISTER
(
txrx
,
chan
,
R_MAC_DMA_CONFIG0
)
);
s
->
sbm_base
+
R_MAC_DMA_REGISTER
(
txrx
,
chan
,
R_MAC_DMA_CONFIG1
);
d
->
sbdma_dscrbase
=
PKSEG1
(
s
->
sbm_base
+
R_MAC_DMA_REGISTER
(
txrx
,
chan
,
R_MAC_DMA_DSCR_BASE
)
);
s
->
sbm_base
+
R_MAC_DMA_REGISTER
(
txrx
,
chan
,
R_MAC_DMA_DSCR_BASE
);
d
->
sbdma_dscrcnt
=
PKSEG1
(
s
->
sbm_base
+
R_MAC_DMA_REGISTER
(
txrx
,
chan
,
R_MAC_DMA_DSCR_CNT
)
);
s
->
sbm_base
+
R_MAC_DMA_REGISTER
(
txrx
,
chan
,
R_MAC_DMA_DSCR_CNT
);
d
->
sbdma_curdscr
=
PKSEG1
(
s
->
sbm_base
+
R_MAC_DMA_REGISTER
(
txrx
,
chan
,
R_MAC_DMA_CUR_DSCRADDR
)
);
s
->
sbm_base
+
R_MAC_DMA_REGISTER
(
txrx
,
chan
,
R_MAC_DMA_CUR_DSCRADDR
);
/*
* Allocate memory for the ring
...
...
@@ -673,23 +737,41 @@ static void sbdma_initctx(sbmacdma_t *d,
d
->
sbdma_maxdescr
=
maxdescr
;
d
->
sbdma_dscrtable
=
(
sbdmadscr_t
*
)
KMALLOC
(
d
->
sbdma_maxdescr
*
sizeof
(
sbdmadscr_t
)
);
kmalloc
(
d
->
sbdma_maxdescr
*
sizeof
(
sbdmadscr_t
),
GFP_KERNEL
);
memset
(
d
->
sbdma_dscrtable
,
0
,
d
->
sbdma_maxdescr
*
sizeof
(
sbdmadscr_t
));
d
->
sbdma_dscrtable_end
=
d
->
sbdma_dscrtable
+
d
->
sbdma_maxdescr
;
d
->
sbdma_dscrtable_phys
=
KVTOPHYS
(
d
->
sbdma_dscrtable
);
d
->
sbdma_dscrtable_phys
=
virt_to_phys
(
d
->
sbdma_dscrtable
);
/*
* And context table
*/
d
->
sbdma_ctxtable
=
(
struct
sk_buff
**
)
KMALLOC
(
d
->
sbdma_maxdescr
*
sizeof
(
struct
sk_buff
*
)
);
kmalloc
(
d
->
sbdma_maxdescr
*
sizeof
(
struct
sk_buff
*
),
GFP_KERNEL
);
memset
(
d
->
sbdma_ctxtable
,
0
,
d
->
sbdma_maxdescr
*
sizeof
(
struct
sk_buff
*
));
#ifdef CONFIG_SBMAC_COALESCE
/*
* Setup Rx/Tx DMA coalescing defaults
*/
if
(
int_pktcnt
)
{
d
->
sbdma_int_pktcnt
=
int_pktcnt
;
}
else
{
d
->
sbdma_int_pktcnt
=
1
;
}
if
(
int_timeout
)
{
d
->
sbdma_int_timeout
=
int_timeout
;
}
else
{
d
->
sbdma_int_timeout
=
0
;
}
#endif
}
/**********************************************************************
...
...
@@ -699,24 +781,35 @@ static void sbdma_initctx(sbmacdma_t *d,
*
* Input parameters:
* d - DMA channel to init (context must be previously init'd
* rxtx - DMA_RX or DMA_TX depending on what type of channel
*
* Return value:
* nothing
********************************************************************* */
static
void
sbdma_channel_start
(
sbmacdma_t
*
d
)
static
void
sbdma_channel_start
(
sbmacdma_t
*
d
,
int
rxtx
)
{
/*
* Turn on the DMA channel
*/
#ifdef CONFIG_SBMAC_COALESCE
SBMAC_WRITECSR
(
d
->
sbdma_config1
,
V_DMA_INT_TIMEOUT
(
d
->
sbdma_int_timeout
)
|
0
);
SBMAC_WRITECSR
(
d
->
sbdma_config0
,
M_DMA_EOP_INT_EN
|
V_DMA_RINGSZ
(
d
->
sbdma_maxdescr
)
|
V_DMA_INT_PKTCNT
(
d
->
sbdma_int_pktcnt
)
|
0
);
#else
SBMAC_WRITECSR
(
d
->
sbdma_config1
,
0
);
SBMAC_WRITECSR
(
d
->
sbdma_dscrbase
,
d
->
sbdma_dscrtable_phys
);
SBMAC_WRITECSR
(
d
->
sbdma_config0
,
V_DMA_RINGSZ
(
d
->
sbdma_maxdescr
)
|
0
);
#endif
SBMAC_WRITECSR
(
d
->
sbdma_dscrbase
,
d
->
sbdma_dscrtable_phys
);
/*
* Initialize ring pointers
...
...
@@ -726,6 +819,37 @@ static void sbdma_channel_start(sbmacdma_t *d)
d
->
sbdma_remptr
=
d
->
sbdma_dscrtable
;
}
/**********************************************************************
* SBDMA_CHANNEL_STOP(d)
*
* Initialize the hardware registers for a DMA channel.
*
* Input parameters:
* d - DMA channel to init (context must be previously init'd
*
* Return value:
* nothing
********************************************************************* */
static
void
sbdma_channel_stop
(
sbmacdma_t
*
d
)
{
/*
* Turn off the DMA channel
*/
SBMAC_WRITECSR
(
d
->
sbdma_config1
,
0
);
SBMAC_WRITECSR
(
d
->
sbdma_dscrbase
,
0
);
SBMAC_WRITECSR
(
d
->
sbdma_config0
,
0
);
/*
* Zero ring pointers
*/
d
->
sbdma_addptr
=
0
;
d
->
sbdma_remptr
=
0
;
}
static
void
sbdma_align_skb
(
struct
sk_buff
*
skb
,
int
power2
,
int
offset
)
{
...
...
@@ -791,21 +915,21 @@ static int sbdma_add_rcvbuffer(sbmacdma_t *d,struct sk_buff *sb)
* 3. The buffer can be aligned such that the IP addresses are
* naturally aligned.
*
* Remember, the S
B1250'
s MAC writes whole cache lines at a time,
* Remember, the S
OC
s MAC writes whole cache lines at a time,
* without reading the old contents first. So, if the sk_buff's
* data portion starts in the middle of a cache line, the S
B1250
* data portion starts in the middle of a cache line, the S
OC
* DMA will trash the beginning (and ending) portions.
*/
if
(
sb
==
NULL
)
{
sb_new
=
dev_alloc_skb
(
ENET_PACKET_SIZE
+
CACHELINESIZE
*
2
+
ETHER_ALIGN
);
sb_new
=
dev_alloc_skb
(
ENET_PACKET_SIZE
+
SMP_CACHE_BYTES
*
2
+
ETHER_ALIGN
);
if
(
sb_new
==
NULL
)
{
printk
(
KERN_INFO
"%s: sk_buff allocation failed
\n
"
,
d
->
sbdma_eth
->
sbm_dev
->
name
);
return
-
ENOBUFS
;
}
sbdma_align_skb
(
sb_new
,
CACHELINESIZE
,
ETHER_ALIGN
);
sbdma_align_skb
(
sb_new
,
SMP_CACHE_BYTES
,
ETHER_ALIGN
);
/* mark skbuff owned by our device */
sb_new
->
dev
=
d
->
sbdma_eth
->
sbm_dev
;
...
...
@@ -814,7 +938,7 @@ static int sbdma_add_rcvbuffer(sbmacdma_t *d,struct sk_buff *sb)
sb_new
=
sb
;
/*
* nothing special to reinit buffer, it's already aligned
* and sb->
tail
already points to a good place.
* and sb->
data
already points to a good place.
*/
}
...
...
@@ -822,9 +946,18 @@ static int sbdma_add_rcvbuffer(sbmacdma_t *d,struct sk_buff *sb)
* fill in the descriptor
*/
dsc
->
dscr_a
=
KVTOPHYS
(
sb_new
->
tail
)
|
#ifdef CONFIG_SBMAC_COALESCE
/*
* Do not interrupt per DMA transfer.
*/
dsc
->
dscr_a
=
virt_to_phys
(
sb_new
->
tail
)
|
V_DMA_DSCRA_A_SIZE
(
NUMCACHEBLKS
(
pktsize
+
ETHER_ALIGN
))
|
0
;
#else
dsc
->
dscr_a
=
virt_to_phys
(
sb_new
->
tail
)
|
V_DMA_DSCRA_A_SIZE
(
NUMCACHEBLKS
(
pktsize
+
ETHER_ALIGN
))
|
M_DMA_DSCRA_INTERRUPT
;
#endif
/* receiving: no options */
dsc
->
dscr_b
=
0
;
...
...
@@ -904,12 +1037,14 @@ static int sbdma_add_txbuffer(sbmacdma_t *d,struct sk_buff *sb)
* while doing the calculation.
*/
phys
=
KVTOPHYS
(
sb
->
data
);
ncb
=
NUMCACHEBLKS
(
length
+
(
phys
&
(
CACHELINESIZE
-
1
)));
phys
=
virt_to_phys
(
sb
->
data
);
ncb
=
NUMCACHEBLKS
(
length
+
(
phys
&
(
SMP_CACHE_BYTES
-
1
)));
dsc
->
dscr_a
=
phys
|
V_DMA_DSCRA_A_SIZE
(
ncb
)
|
#ifndef CONFIG_SBMAC_COALESCE
M_DMA_DSCRA_INTERRUPT
|
#endif
M_DMA_ETHTX_SOP
;
/* transmitting: set outbound options and length */
...
...
@@ -986,7 +1121,8 @@ static void sbdma_fillring(sbmacdma_t *d)
int
idx
;
for
(
idx
=
0
;
idx
<
SBMAC_MAX_RXDESCR
-
1
;
idx
++
)
{
if
(
sbdma_add_rcvbuffer
(
d
,
NULL
)
!=
0
)
break
;
if
(
sbdma_add_rcvbuffer
(
d
,
NULL
)
!=
0
)
break
;
}
}
...
...
@@ -1037,7 +1173,8 @@ static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d)
* the hardware is working on right now.
*/
if
(
curidx
==
hwidx
)
break
;
if
(
curidx
==
hwidx
)
break
;
/*
* Otherwise, get the packet's sk_buff ptr back
...
...
@@ -1057,11 +1194,6 @@ static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d)
if
(
!
(
dsc
->
dscr_a
&
M_DMA_ETHRX_BAD
))
{
/*
* Set length into the packet
*/
skb_put
(
sb
,
len
);
/*
* Add a new buffer to replace the old one. If we fail
* to allocate a buffer, we're going to drop this
...
...
@@ -1069,24 +1201,45 @@ static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d)
*/
if
(
sbdma_add_rcvbuffer
(
d
,
NULL
)
==
-
ENOBUFS
)
{
sc
->
sbm_stats
.
rx_dropped
++
;
sbdma_add_rcvbuffer
(
d
,
sb
);
/* re-add old buffer */
}
else
{
}
else
{
/*
* Buffer has been replaced on the receive ring.
* Pass the buffer to the kernel
* Set length into the packet
*/
skb_put
(
sb
,
len
);
/*
* Buffer has been replaced on the
* receive ring. Pass the buffer to
* the kernel */
sc
->
sbm_stats
.
rx_bytes
+=
len
;
sc
->
sbm_stats
.
rx_packets
++
;
sb
->
protocol
=
eth_type_trans
(
sb
,
d
->
sbdma_eth
->
sbm_dev
);
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
"
);
sb
->
ip_summed
=
CHECKSUM_UNNECESSARY
;
}
}
/* rx_hw_checksum */
netif_rx
(
sb
);
}
}
else
{
}
else
{
/*
* Packet was mangled somehow. Just drop it and
* put it back on the receive ring.
*/
sc
->
sbm_stats
.
rx_errors
++
;
sbdma_add_rcvbuffer
(
d
,
sb
);
}
...
...
@@ -1143,19 +1296,25 @@ 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
/* 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
*/
uint64_t
tmp
=
SBMAC_READCSR
(
d
->
sbdma_curdscr
);
...
...
@@ -1171,7 +1330,8 @@ static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d)
* the hardware is working on right now.
*/
if
(
curidx
==
hwidx
)
break
;
if
(
curidx
==
hwidx
)
break
;
/*
* Otherwise, get the packet's sk_buff ptr back
...
...
@@ -1238,14 +1398,14 @@ static int sbmac_initctx(struct sbmac_softc *s)
* figure out the addresses of some ports
*/
s
->
sbm_macenable
=
PKSEG1
(
s
->
sbm_base
+
R_MAC_ENABLE
)
;
s
->
sbm_maccfg
=
PKSEG1
(
s
->
sbm_base
+
R_MAC_CFG
)
;
s
->
sbm_fifocfg
=
PKSEG1
(
s
->
sbm_base
+
R_MAC_THRSH_CFG
)
;
s
->
sbm_framecfg
=
PKSEG1
(
s
->
sbm_base
+
R_MAC_FRAMECFG
)
;
s
->
sbm_rxfilter
=
PKSEG1
(
s
->
sbm_base
+
R_MAC_ADFILTER_CFG
)
;
s
->
sbm_isr
=
PKSEG1
(
s
->
sbm_base
+
R_MAC_STATUS
)
;
s
->
sbm_imr
=
PKSEG1
(
s
->
sbm_base
+
R_MAC_INT_MASK
)
;
s
->
sbm_mdio
=
PKSEG1
(
s
->
sbm_base
+
R_MAC_MDIO
)
;
s
->
sbm_macenable
=
s
->
sbm_base
+
R_MAC_ENABLE
;
s
->
sbm_maccfg
=
s
->
sbm_base
+
R_MAC_CFG
;
s
->
sbm_fifocfg
=
s
->
sbm_base
+
R_MAC_THRSH_CFG
;
s
->
sbm_framecfg
=
s
->
sbm_base
+
R_MAC_FRAMECFG
;
s
->
sbm_rxfilter
=
s
->
sbm_base
+
R_MAC_ADFILTER_CFG
;
s
->
sbm_isr
=
s
->
sbm_base
+
R_MAC_STATUS
;
s
->
sbm_imr
=
s
->
sbm_base
+
R_MAC_INT_MASK
;
s
->
sbm_mdio
=
s
->
sbm_base
+
R_MAC_MDIO
;
s
->
sbm_phys
[
0
]
=
1
;
s
->
sbm_phys
[
1
]
=
0
;
...
...
@@ -1284,12 +1444,12 @@ static int sbmac_initctx(struct sbmac_softc *s)
static
void
sbdma_uninitctx
(
struct
sbmacdma_s
*
d
)
{
if
(
d
->
sbdma_dscrtable
)
{
KFREE
(
d
->
sbdma_dscrtable
);
kfree
(
d
->
sbdma_dscrtable
);
d
->
sbdma_dscrtable
=
NULL
;
}
if
(
d
->
sbdma_ctxtable
)
{
KFREE
(
d
->
sbdma_ctxtable
);
kfree
(
d
->
sbdma_ctxtable
);
d
->
sbdma_ctxtable
=
NULL
;
}
}
...
...
@@ -1319,13 +1479,14 @@ static void sbmac_channel_start(struct sbmac_softc *s)
uint64_t
reg
;
sbmac_port_t
port
;
uint64_t
cfg
,
fifo
,
framecfg
;
int
idx
;
int
idx
,
th_value
;
/*
* Don't do this if running
*/
if
(
s
->
sbm_state
==
sbmac_state_on
)
return
;
if
(
s
->
sbm_state
==
sbmac_state_on
)
return
;
/*
* Bring the controller out of reset, but leave it off.
...
...
@@ -1351,8 +1512,19 @@ static void sbmac_channel_start(struct sbmac_softc *s)
M_MAC_SS_EN
|
0
;
/*
* Be sure that RD_THRSH+WR_THRSH <= 32 for pass1 pars
* and make sure that RD_THRSH + WR_THRSH <=128 for pass2 and above
* Use a larger RD_THRSH for gigabit
*/
if
(
periph_rev
>=
2
)
th_value
=
64
;
else
th_value
=
28
;
fifo
=
V_MAC_TX_WR_THRSH
(
4
)
|
/* Must be '4' or '8' */
V_MAC_TX_RD_THRSH
(
4
)
|
((
s
->
sbm_speed
==
sbmac_speed_1000
)
?
V_MAC_TX_RD_THRSH
(
th_value
)
:
V_MAC_TX_RD_THRSH
(
4
))
|
V_MAC_TX_RL_THRSH
(
4
)
|
V_MAC_RX_PL_THRSH
(
4
)
|
V_MAC_RX_RD_THRSH
(
4
)
|
/* Must be '4' */
...
...
@@ -1364,12 +1536,11 @@ static void sbmac_channel_start(struct sbmac_softc *s)
V_MAC_MAX_FRAMESZ_DEFAULT
|
V_MAC_BACKOFF_SEL
(
1
);
/*
* Clear out the hash address map
*/
port
=
PKSEG1
(
s
->
sbm_base
+
R_MAC_HASH_BASE
)
;
port
=
s
->
sbm_base
+
R_MAC_HASH_BASE
;
for
(
idx
=
0
;
idx
<
MAC_HASH_COUNT
;
idx
++
)
{
SBMAC_WRITECSR
(
port
,
0
);
port
+=
sizeof
(
uint64_t
);
...
...
@@ -1379,7 +1550,7 @@ static void sbmac_channel_start(struct sbmac_softc *s)
* Clear out the exact-match table
*/
port
=
PKSEG1
(
s
->
sbm_base
+
R_MAC_ADDR_BASE
)
;
port
=
s
->
sbm_base
+
R_MAC_ADDR_BASE
;
for
(
idx
=
0
;
idx
<
MAC_ADDR_COUNT
;
idx
++
)
{
SBMAC_WRITECSR
(
port
,
0
);
port
+=
sizeof
(
uint64_t
);
...
...
@@ -1389,14 +1560,14 @@ static void sbmac_channel_start(struct sbmac_softc *s)
* Clear out the DMA Channel mapping table registers
*/
port
=
PKSEG1
(
s
->
sbm_base
+
R_MAC_CHUP0_BASE
)
;
port
=
s
->
sbm_base
+
R_MAC_CHUP0_BASE
;
for
(
idx
=
0
;
idx
<
MAC_CHMAP_COUNT
;
idx
++
)
{
SBMAC_WRITECSR
(
port
,
0
);
port
+=
sizeof
(
uint64_t
);
}
port
=
PKSEG1
(
s
->
sbm_base
+
R_MAC_CHLO0_BASE
)
;
port
=
s
->
sbm_base
+
R_MAC_CHLO0_BASE
;
for
(
idx
=
0
;
idx
<
MAC_CHMAP_COUNT
;
idx
++
)
{
SBMAC_WRITECSR
(
port
,
0
);
port
+=
sizeof
(
uint64_t
);
...
...
@@ -1409,13 +1580,13 @@ static void sbmac_channel_start(struct sbmac_softc *s)
reg
=
sbmac_addr2reg
(
s
->
sbm_hwaddr
);
port
=
PKSEG1
(
s
->
sbm_base
+
R_MAC_ADDR_BASE
)
;
port
=
s
->
sbm_base
+
R_MAC_ADDR_BASE
;
SBMAC_WRITECSR
(
port
,
reg
);
port
=
PKSEG1
(
s
->
sbm_base
+
R_MAC_ETHERNET_ADDR
)
;
port
=
s
->
sbm_base
+
R_MAC_ETHERNET_ADDR
;
#ifdef CONFIG_SB1_PASS_1_WORKAROUNDS
/*
* Pass1 S
B1250
s do not receive packets addressed to the
* Pass1 S
OC
s do not receive packets addressed to the
* destination address in the R_MAC_ETHERNET_ADDR register.
* Set the value to zero.
*/
...
...
@@ -1439,8 +1610,8 @@ static void sbmac_channel_start(struct sbmac_softc *s)
* Initialize DMA channels (rings should be ok now)
*/
sbdma_channel_start
(
&
(
s
->
sbm_rxdma
));
sbdma_channel_start
(
&
(
s
->
sbm_txdma
));
sbdma_channel_start
(
&
(
s
->
sbm_rxdma
)
,
DMA_RX
);
sbdma_channel_start
(
&
(
s
->
sbm_txdma
)
,
DMA_TX
);
/*
* Configure the speed, duplex, and flow control
...
...
@@ -1467,12 +1638,22 @@ static void sbmac_channel_start(struct sbmac_softc *s)
#ifdef CONFIG_SBMAC_COALESCE
/*
* Accept any TX interrupt and EOP count/timer RX interrupts on ch 0
*/
SBMAC_WRITECSR
(
s
->
sbm_imr
,
((
M_MAC_INT_EOP_COUNT
|
M_MAC_INT_EOP_TIMER
)
<<
S_MAC_TX_CH0
)
|
((
M_MAC_INT_EOP_COUNT
|
M_MAC_INT_EOP_TIMER
)
<<
S_MAC_RX_CH0
));
#else
/*
* Accept any kind of interrupt on TX and RX DMA channel 0
*/
SBMAC_WRITECSR
(
s
->
sbm_imr
,
(
M_MAC_INT_CHANNEL
<<
S_MAC_TX_CH0
)
|
(
M_MAC_INT_CHANNEL
<<
S_MAC_RX_CH0
));
#endif
/*
* Enable receiving unicasts and broadcasts
...
...
@@ -1517,11 +1698,10 @@ static void sbmac_channel_start(struct sbmac_softc *s)
static
void
sbmac_channel_stop
(
struct
sbmac_softc
*
s
)
{
uint64_t
ctl
;
/* don't do this if already stopped */
if
(
s
->
sbm_state
==
sbmac_state_off
)
return
;
if
(
s
->
sbm_state
==
sbmac_state_off
)
return
;
/* don't accept any packets, disable all interrupts */
...
...
@@ -1534,14 +1714,18 @@ static void sbmac_channel_stop(struct sbmac_softc *s)
/* turn off receiver and transmitter */
ctl
=
SBMAC_READCSR
(
s
->
sbm_macenable
);
ctl
&=
~
(
M_MAC_RXDMA_EN0
|
M_MAC_TXDMA_EN0
);
SBMAC_WRITECSR
(
s
->
sbm_macenable
,
ctl
);
SBMAC_WRITECSR
(
s
->
sbm_macenable
,
0
);
/* We're stopped now. */
s
->
sbm_state
=
sbmac_state_off
;
/*
* Stop DMA channels (rings should be ok now)
*/
sbdma_channel_stop
(
&
(
s
->
sbm_rxdma
));
sbdma_channel_stop
(
&
(
s
->
sbm_txdma
));
/* Empty the receive and transmit rings */
...
...
@@ -1610,7 +1794,8 @@ static void sbmac_promiscuous_mode(struct sbmac_softc *sc,int onoff)
{
uint64_t
reg
;
if
(
sc
->
sbm_state
!=
sbmac_state_on
)
return
;
if
(
sc
->
sbm_state
!=
sbmac_state_on
)
return
;
if
(
onoff
)
{
reg
=
SBMAC_READCSR
(
sc
->
sbm_rxfilter
);
...
...
@@ -1624,31 +1809,36 @@ static void sbmac_promiscuous_mode(struct sbmac_softc *sc,int onoff)
}
}
#if 0
/**********************************************************************
* SBMAC_
INIT_AND_START(sc
)
* SBMAC_
SETIPHDR_OFFSET(sc,onoff
)
*
* Stop the channel and restart it. This is generally used
* when we have to do something to the channel that requires
* a swift kick.
* Set the iphdr offset as 15 assuming ethernet encapsulation
*
* Input parameters:
* sc - softc
*
* Return value:
* nothing
********************************************************************* */
static void sbmac_
init_and_star
t(struct sbmac_softc *sc)
static
void
sbmac_
set_iphdr_offse
t
(
struct
sbmac_softc
*
sc
)
{
unsigned long flags;
spin_lock_irqsave(&(sc->sbm_lock),flags);
uint64_t
reg
;
sbmac_set_channel_state(sc,sbmac_state_on);
/* Hard code the off set to 15 for now */
reg
=
SBMAC_READCSR
(
sc
->
sbm_rxfilter
);
reg
&=
~
M_MAC_IPHDR_OFFSET
|
V_MAC_IPHDR_OFFSET
(
15
);
SBMAC_WRITECSR
(
sc
->
sbm_rxfilter
,
reg
);
spin_unlock_irqrestore(&(sc->sbm_lock),flags);
/* read system identification to determine revision */
if
(
periph_rev
>=
2
)
{
printk
(
KERN_INFO
"%s: enabling TCP rcv checksum
\n
"
,
sc
->
sbm_dev
->
name
);
sc
->
rx_hw_checksum
=
ENABLE
;
}
else
{
sc
->
rx_hw_checksum
=
DISABLE
;
}
}
#endif
/**********************************************************************
...
...
@@ -1712,7 +1902,8 @@ static int sbmac_set_speed(struct sbmac_softc *s,sbmac_speed_t speed)
s
->
sbm_speed
=
speed
;
if
(
s
->
sbm_state
==
sbmac_state_on
)
return
0
;
/* save for next restart */
if
(
s
->
sbm_state
==
sbmac_state_on
)
return
0
;
/* save for next restart */
/*
* Read current register values
...
...
@@ -1772,7 +1963,6 @@ static int sbmac_set_speed(struct sbmac_softc *s,sbmac_speed_t speed)
SBMAC_WRITECSR
(
s
->
sbm_maccfg
,
cfg
);
return
1
;
}
/**********************************************************************
...
...
@@ -1802,7 +1992,8 @@ static int sbmac_set_duplex(struct sbmac_softc *s,sbmac_duplex_t duplex,sbmac_fc
s
->
sbm_duplex
=
duplex
;
s
->
sbm_fc
=
fc
;
if
(
s
->
sbm_state
==
sbmac_state_on
)
return
0
;
/* save for next restart */
if
(
s
->
sbm_state
==
sbmac_state_on
)
return
0
;
/* save for next restart */
/*
* Read current register values
...
...
@@ -1886,7 +2077,7 @@ static int sbmac_set_duplex(struct sbmac_softc *s,sbmac_duplex_t duplex,sbmac_fc
* Return value:
* nothing
********************************************************************* */
static
void
sbmac_intr
(
int
irq
,
void
*
dev_instance
,
struct
pt_regs
*
rgs
)
static
irqreturn_t
sbmac_intr
(
int
irq
,
void
*
dev_instance
,
struct
pt_regs
*
rgs
)
{
struct
net_device
*
dev
=
(
struct
net_device
*
)
dev_instance
;
struct
sbmac_softc
*
sc
=
(
struct
sbmac_softc
*
)
(
dev
->
priv
);
...
...
@@ -1896,14 +2087,17 @@ static void sbmac_intr(int irq,void *dev_instance,struct pt_regs *rgs)
for
(;;)
{
/*
* Read the ISR (this clears the bits in the real register)
* Read the ISR (this clears the bits in the real
* register, except for counter addr)
*/
isr
=
SBMAC_READCSR
(
sc
->
sbm_isr
);
isr
=
SBMAC_READCSR
(
sc
->
sbm_isr
)
&
~
M_MAC_COUNTER_ADDR
;
if
(
isr
==
0
)
break
;
handled
=
1
;
/*
* Transmits on channel 0
*/
...
...
@@ -1916,6 +2110,23 @@ static void sbmac_intr(int irq,void *dev_instance,struct pt_regs *rgs)
* Receives on channel 0
*/
/*
* It's important to test all the bits (or at least the
* EOP_SEEN bit) when deciding to do the RX process
* particularly when coalescing, to make sure we
* take care of the following:
*
* If you have some packets waiting (have been received
* but no interrupt) and get a TX interrupt before
* the RX timer or counter expires, reading the ISR
* above will clear the timer and counter, and you
* won't get another interrupt until a packet shows
* up to start the timer again. Testing
* EOP_SEEN here takes care of this case.
* (EOP_SEEN is part of M_MAC_INT_CHANNEL << S_MAC_RX_CH0)
*/
if
(
isr
&
(
M_MAC_INT_CHANNEL
<<
S_MAC_RX_CH0
))
{
sbdma_rx_process
(
sc
,
&
(
sc
->
sbm_rxdma
));
}
...
...
@@ -1952,6 +2163,9 @@ static int sbmac_start_tx(struct sk_buff *skb, struct net_device *dev)
if
(
sbdma_add_txbuffer
(
&
(
sc
->
sbm_txdma
),
skb
))
{
/* XXX save skb that we could not send */
netif_stop_queue
(
dev
);
spin_unlock_irq
(
&
sc
->
sbm_lock
);
return
1
;
}
dev
->
trans_start
=
jiffies
;
...
...
@@ -1990,12 +2204,12 @@ static void sbmac_setmulti(struct sbmac_softc *sc)
*/
for
(
idx
=
1
;
idx
<
MAC_ADDR_COUNT
;
idx
++
)
{
port
=
PKSEG1
(
sc
->
sbm_base
+
R_MAC_ADDR_BASE
+
(
idx
*
sizeof
(
uint64_t
)
));
port
=
sc
->
sbm_base
+
R_MAC_ADDR_BASE
+
(
idx
*
sizeof
(
uint64_t
));
SBMAC_WRITECSR
(
port
,
0
);
}
for
(
idx
=
0
;
idx
<
MAC_HASH_COUNT
;
idx
++
)
{
port
=
PKSEG1
(
sc
->
sbm_base
+
R_MAC_HASH_BASE
+
(
idx
*
sizeof
(
uint64_t
)
));
port
=
sc
->
sbm_base
+
R_MAC_HASH_BASE
+
(
idx
*
sizeof
(
uint64_t
));
SBMAC_WRITECSR
(
port
,
0
);
}
...
...
@@ -2032,8 +2246,7 @@ static void sbmac_setmulti(struct sbmac_softc *sc)
mclist
=
dev
->
mc_list
;
while
(
mclist
&&
(
idx
<
MAC_ADDR_COUNT
))
{
reg
=
sbmac_addr2reg
(
mclist
->
dmi_addr
);
port
=
PKSEG1
(
sc
->
sbm_base
+
R_MAC_ADDR_BASE
+
(
idx
*
sizeof
(
uint64_t
)));
port
=
sc
->
sbm_base
+
R_MAC_ADDR_BASE
+
(
idx
*
sizeof
(
uint64_t
));
SBMAC_WRITECSR
(
port
,
reg
);
idx
++
;
mclist
=
mclist
->
next
;
...
...
@@ -2070,10 +2283,14 @@ static int sbmac_parse_xdigit(char str)
{
int
digit
;
if
((
str
>=
'0'
)
&&
(
str
<=
'9'
))
digit
=
str
-
'0'
;
else
if
((
str
>=
'a'
)
&&
(
str
<=
'f'
))
digit
=
str
-
'a'
+
10
;
else
if
((
str
>=
'A'
)
&&
(
str
<=
'F'
))
digit
=
str
-
'A'
+
10
;
else
return
-
1
;
if
((
str
>=
'0'
)
&&
(
str
<=
'9'
))
digit
=
str
-
'0'
;
else
if
((
str
>=
'a'
)
&&
(
str
<=
'f'
))
digit
=
str
-
'a'
+
10
;
else
if
((
str
>=
'A'
)
&&
(
str
<=
'F'
))
digit
=
str
-
'A'
+
10
;
else
return
-
1
;
return
digit
;
}
...
...
@@ -2092,16 +2309,18 @@ static int sbmac_parse_xdigit(char str)
* 0 if ok, else -1
********************************************************************* */
static
int
sbmac_parse_hwaddr
(
char
*
str
,
u_
char
*
hwaddr
)
static
int
sbmac_parse_hwaddr
(
char
*
str
,
unsigned
char
*
hwaddr
)
{
int
digit1
,
digit2
;
int
idx
=
6
;
while
(
*
str
&&
(
idx
>
0
))
{
digit1
=
sbmac_parse_xdigit
(
*
str
);
if
(
digit1
<
0
)
return
-
1
;
if
(
digit1
<
0
)
return
-
1
;
str
++
;
if
(
!*
str
)
return
-
1
;
if
(
!*
str
)
return
-
1
;
if
((
*
str
==
':'
)
||
(
*
str
==
'-'
))
{
digit2
=
digit1
;
...
...
@@ -2109,20 +2328,32 @@ static int sbmac_parse_hwaddr(char *str,u_char *hwaddr)
}
else
{
digit2
=
sbmac_parse_xdigit
(
*
str
);
if
(
digit2
<
0
)
return
-
1
;
if
(
digit2
<
0
)
return
-
1
;
str
++
;
}
*
hwaddr
++
=
(
digit1
<<
4
)
|
digit2
;
idx
--
;
if
(
*
str
==
'-'
)
str
++
;
if
(
*
str
==
':'
)
str
++
;
if
(
*
str
==
'-'
)
str
++
;
if
(
*
str
==
':'
)
str
++
;
}
return
0
;
}
#endif
static
int
sb1250_change_mtu
(
struct
net_device
*
_dev
,
int
new_mtu
)
{
if
(
new_mtu
>
ENET_PACKET_SIZE
)
return
-
EINVAL
;
_dev
->
mtu
=
new_mtu
;
printk
(
KERN_INFO
"changing the mtu to %d
\n
"
,
new_mtu
);
return
0
;
}
/**********************************************************************
* SBMAC_INIT(dev)
*
...
...
@@ -2135,19 +2366,20 @@ static int sbmac_parse_hwaddr(char *str,u_char *hwaddr)
* status
********************************************************************* */
static
int
sbmac_init
(
struct
net_device
*
dev
)
static
int
sbmac_init
(
struct
net_device
*
dev
,
int
idx
)
{
struct
sbmac_softc
*
sc
;
u
_
char
*
eaddr
;
u
nsigned
char
*
eaddr
;
uint64_t
ea_reg
;
int
i
dx
;
int
i
;
sc
=
(
struct
sbmac_softc
*
)
dev
->
priv
;
/* Determine controller base address */
sc
->
sbm_base
=
(
sbmac_port_t
)
dev
->
base_addr
;
sc
->
sbm_base
=
KSEG1ADDR
(
dev
->
base_addr
)
;
sc
->
sbm_dev
=
dev
;
sc
->
sbe_idx
=
idx
;
eaddr
=
sc
->
sbm_hwaddr
;
...
...
@@ -2156,16 +2388,15 @@ static int sbmac_init(struct net_device *dev)
* for us in the ethernet address register for each mac.
*/
ea_reg
=
SBMAC_READCSR
(
PKSEG1
(
sc
->
sbm_base
+
R_MAC_ETHERNET_ADDR
)
);
SBMAC_WRITECSR
(
PKSEG1
(
sc
->
sbm_base
+
R_MAC_ETHERNET_ADDR
)
,
0
);
for
(
i
dx
=
0
;
idx
<
6
;
idx
++
)
{
eaddr
[
i
dx
]
=
(
uint8_t
)
(
ea_reg
&
0xFF
);
ea_reg
=
SBMAC_READCSR
(
sc
->
sbm_base
+
R_MAC_ETHERNET_ADDR
);
SBMAC_WRITECSR
(
sc
->
sbm_base
+
R_MAC_ETHERNET_ADDR
,
0
);
for
(
i
=
0
;
i
<
6
;
i
++
)
{
eaddr
[
i
]
=
(
uint8_t
)
(
ea_reg
&
0xFF
);
ea_reg
>>=
8
;
}
for
(
idx
=
0
;
idx
<
6
;
idx
++
)
{
dev
->
dev_addr
[
idx
]
=
eaddr
[
idx
];
for
(
i
=
0
;
i
<
6
;
i
++
)
{
dev
->
dev_addr
[
i
]
=
eaddr
[
i
];
}
...
...
@@ -2173,7 +2404,7 @@ static int sbmac_init(struct net_device *dev)
* Init packet size
*/
sc
->
sbm_buffersize
=
ENET_PACKET_SIZE
+
CACHELINESIZE
*
2
+
ETHER_ALIGN
;
sc
->
sbm_buffersize
=
ENET_PACKET_SIZE
+
SMP_CACHE_BYTES
*
2
+
ETHER_ALIGN
;
/*
* Initialize context (get pointers to registers and stuff), then
...
...
@@ -2184,13 +2415,13 @@ static int sbmac_init(struct net_device *dev)
/*
* Display Ethernet address (this is called during the config process
* so we need to finish off the config message that was being displayed)
* 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: SB1250 Ethernet at 0x%08lX, address: %02X-%02X-%02X-%02X-%02X-%02X
\n
"
,
dev
->
name
,
(
unsigned
long
)
sc
->
sbm_base
,
"%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
]);
/*
...
...
@@ -2209,8 +2440,12 @@ static int sbmac_init(struct net_device *dev)
dev
->
tx_timeout
=
sbmac_tx_timeout
;
dev
->
watchdog_timeo
=
TX_TIMEOUT
;
return
0
;
dev
->
change_mtu
=
sb1250_change_mtu
;
/* This is needed for PASS2 for Rx H/W checksum feature */
sbmac_set_iphdr_offset
(
sc
);
return
0
;
}
...
...
@@ -2237,7 +2472,7 @@ static int sbmac_open(struct net_device *dev)
* Configure default speed
*/
sbmac_mii_poll
(
sc
,
1
);
sbmac_mii_poll
(
sc
,
noisy_mii
);
/*
* Turn on the channel
...
...
@@ -2319,7 +2554,8 @@ static int sbmac_mii_poll(struct sbmac_softc *s,int noisy)
chg
=
1
;
}
if
(
chg
==
0
)
return
0
;
if
(
chg
==
0
)
return
0
;
p
+=
sprintf
(
p
,
"Link speed: "
);
...
...
@@ -2371,8 +2607,6 @@ static int sbmac_mii_poll(struct sbmac_softc *s,int noisy)
}
static
void
sbmac_timer
(
unsigned
long
data
)
{
struct
net_device
*
dev
=
(
struct
net_device
*
)
data
;
...
...
@@ -2399,7 +2633,7 @@ static void sbmac_timer(unsigned long data)
* Poll the PHY to see what speed we should be running at
*/
if
(
sbmac_mii_poll
(
sc
,
1
))
{
if
(
sbmac_mii_poll
(
sc
,
noisy_mii
))
{
if
(
sc
->
sbm_state
!=
sbmac_state_off
)
{
/*
* something changed, restart the channel
...
...
@@ -2479,7 +2713,8 @@ static void sbmac_set_rx_mode(struct net_device *dev)
spin_unlock_irqrestore
(
&
sc
->
sbm_lock
,
flags
);
if
(
msg_flag
)
{
printk
(
KERN_NOTICE
"%s: Promiscuous mode %sabled.
\n
"
,
dev
->
name
,(
msg_flag
==
1
)
?
"en"
:
"dis"
);
printk
(
KERN_NOTICE
"%s: Promiscuous mode %sabled.
\n
"
,
dev
->
name
,(
msg_flag
==
1
)
?
"en"
:
"dis"
);
}
/*
...
...
@@ -2530,6 +2765,7 @@ static int sbmac_close(struct net_device *dev)
{
struct
sbmac_softc
*
sc
=
(
struct
sbmac_softc
*
)
dev
->
priv
;
unsigned
long
flags
;
int
irq
;
sbmac_set_channel_state
(
sc
,
sbmac_state_off
);
...
...
@@ -2545,10 +2781,9 @@ static int sbmac_close(struct net_device *dev)
spin_unlock_irqrestore
(
&
sc
->
sbm_lock
,
flags
);
/* Make sure there is no irq-handler running on a different CPU. */
synchronize_irq
(
dev
->
irq
);
free_irq
(
dev
->
irq
,
dev
);
irq
=
dev
->
irq
;
synchronize_irq
(
irq
);
free_irq
(
irq
,
dev
);
sbdma_emptyring
(
&
(
sc
->
sbm_txdma
));
sbdma_emptyring
(
&
(
sc
->
sbm_rxdma
));
...
...
@@ -2571,8 +2806,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
(
PKSEG1
(
port
+
R_MAC_ETHERNET_ADDR
),
val
);
val
=
SBMAC_READCSR
(
PKSEG1
(
port
+
R_MAC_ETHERNET_ADDR
));
SBMAC_WRITECSR
(
KSEG1ADDR
(
port
+
R_MAC_ETHERNET_ADDR
),
val
);
val
=
SBMAC_READCSR
(
KSEG1ADDR
(
port
+
R_MAC_ETHERNET_ADDR
));
}
#endif
...
...
@@ -2585,6 +2820,7 @@ sbmac_init_module(void)
int
macidx
=
0
;
struct
net_device
*
dev
;
sbmac_port_t
port
;
int
chip_max_units
;
/*
* For bringup when not using the firmware, we can pre-fill
...
...
@@ -2605,8 +2841,25 @@ sbmac_init_module(void)
* Walk through the Ethernet controllers and find
* those who have their MAC addresses set.
*/
switch
(
soc_type
)
{
case
K_SYS_SOC_TYPE_BCM1250
:
case
K_SYS_SOC_TYPE_BCM1250_ALT
:
chip_max_units
=
3
;
break
;
case
K_SYS_SOC_TYPE_BCM1120
:
case
K_SYS_SOC_TYPE_BCM1125
:
case
K_SYS_SOC_TYPE_BCM1125H
:
case
K_SYS_SOC_TYPE_BCM1250_ALT2
:
/* Hybrid */
chip_max_units
=
2
;
break
;
default:
chip_max_units
=
0
;
break
;
}
if
(
chip_max_units
>
MAX_UNITS
)
chip_max_units
=
MAX_UNITS
;
for
(
idx
=
0
;
idx
<
MAX_UNITS
;
idx
++
)
{
for
(
idx
=
0
;
idx
<
chip_max_units
;
idx
++
)
{
/*
* This is the base address of the MAC.
...
...
@@ -2620,7 +2873,10 @@ sbmac_init_module(void)
* If we find a zero, skip this MAC.
*/
if
(
SBMAC_READCSR
(
PKSEG1
(
port
+
R_MAC_ETHERNET_ADDR
))
==
0
)
{
sbmac_orig_hwaddr
[
idx
]
=
SBMAC_READCSR
(
KSEG1ADDR
(
port
+
R_MAC_ETHERNET_ADDR
));
if
(
sbmac_orig_hwaddr
[
idx
]
==
0
)
{
printk
(
KERN_DEBUG
"sbmac: not configuring MAC at "
"%lx
\n
"
,
port
);
continue
;
}
...
...
@@ -2629,16 +2885,19 @@ sbmac_init_module(void)
*/
dev
=
init_etherdev
(
NULL
,
sizeof
(
struct
sbmac_softc
));
if
(
!
dev
)
break
;
/* problems, get out now. */
if
(
!
dev
)
return
-
ENOMEM
;
/* return ENOMEM */
printk
(
KERN_DEBUG
"sbmac: configuring MAC at %lx
\n
"
,
port
);
dev
->
irq
=
K_INT_MAC_0
+
idx
;
dev
->
base_addr
=
port
;
dev
->
mem_end
=
0
;
/*dev->init = sbmac_init;*/
sbmac_init
(
dev
);
sbmac_init
(
dev
,
macidx
);
dev_sbmac
[
macidx
]
=
dev
;
macidx
++
;
}
/*
...
...
@@ -2654,9 +2913,11 @@ sbmac_cleanup_module(void)
{
int
idx
;
struct
net_device
*
dev
;
sbmac_port_t
port
;
for
(
idx
=
0
;
idx
<
MAX_UNITS
;
idx
++
)
{
dev
=
dev_sbmac
[
idx
];
if
(
dev
==
NULL
)
continue
;
if
(
dev
==
NULL
)
continue
;
if
(
dev
->
priv
!=
NULL
)
{
struct
sbmac_softc
*
sc
=
(
struct
sbmac_softc
*
)
dev
->
priv
;
...
...
@@ -2664,9 +2925,11 @@ sbmac_cleanup_module(void)
sbmac_uninitctx
(
sc
);
KFREE
(
sc
);
}
KFREE
(
dev
);
port
=
A_MAC_CHANNEL_BASE
(
idx
);
SBMAC_WRITECSR
(
KSEG1ADDR
(
port
+
R_MAC_ETHERNET_ADDR
),
sbmac_orig_hwaddr
[
idx
]
);
kfree
(
dev
);
dev_sbmac
[
idx
]
=
NULL
;
}
}
...
...
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