2005-10-29 00:25:58 +04:00
/*
* Ethernet on Serial Communications Controller ( SCC ) driver for Motorola MPC8xx and MPC82xx .
*
2007-09-18 20:05:35 +04:00
* Copyright ( c ) 2003 Intracom S . A .
2005-10-29 00:25:58 +04:00
* by Pantelis Antoniou < panto @ intracom . gr >
2007-09-18 20:05:35 +04:00
*
* 2005 ( c ) MontaVista Software , Inc .
2005-10-29 00:25:58 +04:00
* Vitaly Bordug < vbordug @ ru . mvista . com >
*
2007-09-18 20:05:35 +04:00
* This file is licensed under the terms of the GNU General Public License
* version 2. This program is licensed " as is " without any warranty of any
2005-10-29 00:25:58 +04:00
* kind , whether express or implied .
*/
# include <linux/module.h>
# include <linux/kernel.h>
# include <linux/types.h>
# include <linux/string.h>
# include <linux/ptrace.h>
# include <linux/errno.h>
# include <linux/ioport.h>
# include <linux/slab.h>
# include <linux/interrupt.h>
# include <linux/init.h>
# include <linux/delay.h>
# include <linux/netdevice.h>
# include <linux/etherdevice.h>
# include <linux/skbuff.h>
# include <linux/spinlock.h>
# include <linux/mii.h>
# include <linux/ethtool.h>
# include <linux/bitops.h>
# include <linux/fs.h>
2005-11-09 16:00:16 +03:00
# include <linux/platform_device.h>
2005-10-29 00:25:58 +04:00
# include <asm/irq.h>
# include <asm/uaccess.h>
# ifdef CONFIG_8xx
# include <asm/8xx_immap.h>
# include <asm/pgtable.h>
# include <asm/mpc8xx.h>
# include <asm/commproc.h>
# endif
2007-10-02 19:55:58 +04:00
# ifdef CONFIG_PPC_CPM_NEW_BINDING
# include <asm/of_platform.h>
# endif
2005-10-29 00:25:58 +04:00
# include "fs_enet.h"
/*************************************************/
# if defined(CONFIG_CPM1)
/* for a 8xx __raw_xxx's are sufficient */
# define __fs_out32(addr, x) __raw_writel(x, addr)
# define __fs_out16(addr, x) __raw_writew(x, addr)
# define __fs_out8(addr, x) __raw_writeb(x, addr)
# define __fs_in32(addr) __raw_readl(addr)
# define __fs_in16(addr) __raw_readw(addr)
# define __fs_in8(addr) __raw_readb(addr)
# else
/* for others play it safe */
# define __fs_out32(addr, x) out_be32(addr, x)
# define __fs_out16(addr, x) out_be16(addr, x)
# define __fs_in32(addr) in_be32(addr)
# define __fs_in16(addr) in_be16(addr)
# endif
/* write, read, set bits, clear bits */
# define W32(_p, _m, _v) __fs_out32(&(_p)->_m, (_v))
# define R32(_p, _m) __fs_in32(&(_p)->_m)
# define S32(_p, _m, _v) W32(_p, _m, R32(_p, _m) | (_v))
# define C32(_p, _m, _v) W32(_p, _m, R32(_p, _m) & ~(_v))
# define W16(_p, _m, _v) __fs_out16(&(_p)->_m, (_v))
# define R16(_p, _m) __fs_in16(&(_p)->_m)
# define S16(_p, _m, _v) W16(_p, _m, R16(_p, _m) | (_v))
# define C16(_p, _m, _v) W16(_p, _m, R16(_p, _m) & ~(_v))
# define W8(_p, _m, _v) __fs_out8(&(_p)->_m, (_v))
# define R8(_p, _m) __fs_in8(&(_p)->_m)
# define S8(_p, _m, _v) W8(_p, _m, R8(_p, _m) | (_v))
# define C8(_p, _m, _v) W8(_p, _m, R8(_p, _m) & ~(_v))
# define SCC_MAX_MULTICAST_ADDRS 64
/*
2007-09-18 20:05:35 +04:00
* Delay to wait for SCC reset command to complete ( in us )
2005-10-29 00:25:58 +04:00
*/
# define SCC_RESET_DELAY 50
# define MAX_CR_CMD_LOOPS 10000
static inline int scc_cr_cmd ( struct fs_enet_private * fep , u32 op )
{
2007-10-02 19:55:58 +04:00
const struct fs_platform_info * fpi = fep - > fpi ;
int i ;
2005-10-29 00:25:58 +04:00
2007-10-02 19:55:58 +04:00
W16 ( cpmp , cp_cpcr , fpi - > cp_command | CPM_CR_FLG | ( op < < 8 ) ) ;
2005-10-29 00:25:58 +04:00
for ( i = 0 ; i < MAX_CR_CMD_LOOPS ; i + + )
if ( ( R16 ( cpmp , cp_cpcr ) & CPM_CR_FLG ) = = 0 )
2007-10-02 19:55:58 +04:00
return 0 ;
2005-10-29 00:25:58 +04:00
2007-10-02 19:55:58 +04:00
printk ( KERN_ERR " %s(): Not able to issue CPM command \n " ,
__FUNCTION__ ) ;
return 1 ;
2005-10-29 00:25:58 +04:00
}
static int do_pd_setup ( struct fs_enet_private * fep )
{
2007-10-02 19:55:58 +04:00
# ifdef CONFIG_PPC_CPM_NEW_BINDING
struct of_device * ofdev = to_of_device ( fep - > dev ) ;
fep - > interrupt = of_irq_to_resource ( ofdev - > node , 0 , NULL ) ;
if ( fep - > interrupt = = NO_IRQ )
return - EINVAL ;
fep - > scc . sccp = of_iomap ( ofdev - > node , 0 ) ;
if ( ! fep - > scc . sccp )
return - EINVAL ;
fep - > scc . ep = of_iomap ( ofdev - > node , 1 ) ;
if ( ! fep - > scc . ep ) {
iounmap ( fep - > scc . sccp ) ;
return - EINVAL ;
}
# else
2005-10-29 00:25:58 +04:00
struct platform_device * pdev = to_platform_device ( fep - > dev ) ;
struct resource * r ;
/* Fill out IRQ field */
fep - > interrupt = platform_get_irq_byname ( pdev , " interrupt " ) ;
2006-01-19 20:56:29 +03:00
if ( fep - > interrupt < 0 )
return - EINVAL ;
2005-10-29 00:25:58 +04:00
r = platform_get_resource_byname ( pdev , IORESOURCE_MEM , " regs " ) ;
2007-01-27 11:00:04 +03:00
fep - > scc . sccp = ioremap ( r - > start , r - > end - r - > start + 1 ) ;
2005-10-29 00:25:58 +04:00
if ( fep - > scc . sccp = = NULL )
return - EINVAL ;
r = platform_get_resource_byname ( pdev , IORESOURCE_MEM , " pram " ) ;
2007-01-27 11:00:04 +03:00
fep - > scc . ep = ioremap ( r - > start , r - > end - r - > start + 1 ) ;
2005-10-29 00:25:58 +04:00
if ( fep - > scc . ep = = NULL )
return - EINVAL ;
2007-10-02 19:55:58 +04:00
# endif
2005-10-29 00:25:58 +04:00
return 0 ;
}
# define SCC_NAPI_RX_EVENT_MSK (SCCE_ENET_RXF | SCCE_ENET_RXB)
# define SCC_RX_EVENT (SCCE_ENET_RXF)
# define SCC_TX_EVENT (SCCE_ENET_TXB)
# define SCC_ERR_EVENT_MSK (SCCE_ENET_TXE | SCCE_ENET_BSY)
static int setup_data ( struct net_device * dev )
{
struct fs_enet_private * fep = netdev_priv ( dev ) ;
2007-10-02 19:55:58 +04:00
# ifdef CONFIG_PPC_CPM_NEW_BINDING
struct fs_platform_info * fpi = fep - > fpi ;
2005-10-29 00:25:58 +04:00
fep - > scc . idx = fs_get_scc_index ( fpi - > fs_no ) ;
2007-10-02 19:55:58 +04:00
if ( ( unsigned int ) fep - > fcc . idx > = 4 ) /* max 4 SCCs */
2005-10-29 00:25:58 +04:00
return - EINVAL ;
2007-10-02 19:55:58 +04:00
fpi - > cp_command = fep - > fcc . idx < < 6 ;
# endif
2005-10-29 00:25:58 +04:00
do_pd_setup ( fep ) ;
fep - > scc . hthi = 0 ;
fep - > scc . htlo = 0 ;
fep - > ev_napi_rx = SCC_NAPI_RX_EVENT_MSK ;
fep - > ev_rx = SCC_RX_EVENT ;
2007-10-02 19:55:58 +04:00
fep - > ev_tx = SCC_TX_EVENT | SCCE_ENET_TXE ;
2005-10-29 00:25:58 +04:00
fep - > ev_err = SCC_ERR_EVENT_MSK ;
return 0 ;
}
static int allocate_bd ( struct net_device * dev )
{
struct fs_enet_private * fep = netdev_priv ( dev ) ;
const struct fs_platform_info * fpi = fep - > fpi ;
fep - > ring_mem_addr = cpm_dpalloc ( ( fpi - > tx_ring + fpi - > rx_ring ) *
sizeof ( cbd_t ) , 8 ) ;
2007-05-08 23:46:36 +04:00
if ( IS_ERR_VALUE ( fep - > ring_mem_addr ) )
2005-10-29 00:25:58 +04:00
return - ENOMEM ;
2007-10-01 23:20:58 +04:00
fep - > ring_base = ( void __iomem __force * )
cpm_dpram_addr ( fep - > ring_mem_addr ) ;
2005-10-29 00:25:58 +04:00
return 0 ;
}
static void free_bd ( struct net_device * dev )
{
struct fs_enet_private * fep = netdev_priv ( dev ) ;
if ( fep - > ring_base )
cpm_dpfree ( fep - > ring_mem_addr ) ;
}
static void cleanup_data ( struct net_device * dev )
{
/* nothing */
}
static void set_promiscuous_mode ( struct net_device * dev )
2007-09-18 20:05:35 +04:00
{
2005-10-29 00:25:58 +04:00
struct fs_enet_private * fep = netdev_priv ( dev ) ;
2007-10-01 23:20:58 +04:00
scc_t __iomem * sccp = fep - > scc . sccp ;
2005-10-29 00:25:58 +04:00
S16 ( sccp , scc_psmr , SCC_PSMR_PRO ) ;
}
static void set_multicast_start ( struct net_device * dev )
{
struct fs_enet_private * fep = netdev_priv ( dev ) ;
2007-10-01 23:20:58 +04:00
scc_enet_t __iomem * ep = fep - > scc . ep ;
2005-10-29 00:25:58 +04:00
W16 ( ep , sen_gaddr1 , 0 ) ;
W16 ( ep , sen_gaddr2 , 0 ) ;
W16 ( ep , sen_gaddr3 , 0 ) ;
W16 ( ep , sen_gaddr4 , 0 ) ;
}
static void set_multicast_one ( struct net_device * dev , const u8 * mac )
{
struct fs_enet_private * fep = netdev_priv ( dev ) ;
2007-10-01 23:20:58 +04:00
scc_enet_t __iomem * ep = fep - > scc . ep ;
2005-10-29 00:25:58 +04:00
u16 taddrh , taddrm , taddrl ;
taddrh = ( ( u16 ) mac [ 5 ] < < 8 ) | mac [ 4 ] ;
taddrm = ( ( u16 ) mac [ 3 ] < < 8 ) | mac [ 2 ] ;
taddrl = ( ( u16 ) mac [ 1 ] < < 8 ) | mac [ 0 ] ;
W16 ( ep , sen_taddrh , taddrh ) ;
W16 ( ep , sen_taddrm , taddrm ) ;
W16 ( ep , sen_taddrl , taddrl ) ;
scc_cr_cmd ( fep , CPM_CR_SET_GADDR ) ;
}
static void set_multicast_finish ( struct net_device * dev )
{
struct fs_enet_private * fep = netdev_priv ( dev ) ;
2007-10-01 23:20:58 +04:00
scc_t __iomem * sccp = fep - > scc . sccp ;
scc_enet_t __iomem * ep = fep - > scc . ep ;
2005-10-29 00:25:58 +04:00
/* clear promiscuous always */
C16 ( sccp , scc_psmr , SCC_PSMR_PRO ) ;
/* if all multi or too many multicasts; just enable all */
if ( ( dev - > flags & IFF_ALLMULTI ) ! = 0 | |
dev - > mc_count > SCC_MAX_MULTICAST_ADDRS ) {
W16 ( ep , sen_gaddr1 , 0xffff ) ;
W16 ( ep , sen_gaddr2 , 0xffff ) ;
W16 ( ep , sen_gaddr3 , 0xffff ) ;
W16 ( ep , sen_gaddr4 , 0xffff ) ;
}
}
static void set_multicast_list ( struct net_device * dev )
{
struct dev_mc_list * pmc ;
if ( ( dev - > flags & IFF_PROMISC ) = = 0 ) {
set_multicast_start ( dev ) ;
for ( pmc = dev - > mc_list ; pmc ! = NULL ; pmc = pmc - > next )
set_multicast_one ( dev , pmc - > dmi_addr ) ;
set_multicast_finish ( dev ) ;
} else
set_promiscuous_mode ( dev ) ;
}
/*
* This function is called to start or restart the FEC during a link
* change . This only happens when switching between half and full
* duplex .
*/
static void restart ( struct net_device * dev )
{
struct fs_enet_private * fep = netdev_priv ( dev ) ;
2007-10-01 23:20:58 +04:00
scc_t __iomem * sccp = fep - > scc . sccp ;
scc_enet_t __iomem * ep = fep - > scc . ep ;
2005-10-29 00:25:58 +04:00
const struct fs_platform_info * fpi = fep - > fpi ;
u16 paddrh , paddrm , paddrl ;
const unsigned char * mac ;
int i ;
C32 ( sccp , scc_gsmrl , SCC_GSMRL_ENR | SCC_GSMRL_ENT ) ;
/* clear everything (slow & steady does it) */
for ( i = 0 ; i < sizeof ( * ep ) ; i + + )
2007-10-01 23:20:58 +04:00
__fs_out8 ( ( u8 __iomem * ) ep + i , 0 ) ;
2005-10-29 00:25:58 +04:00
/* point to bds */
W16 ( ep , sen_genscc . scc_rbase , fep - > ring_mem_addr ) ;
W16 ( ep , sen_genscc . scc_tbase ,
fep - > ring_mem_addr + sizeof ( cbd_t ) * fpi - > rx_ring ) ;
/* Initialize function code registers for big-endian.
*/
W8 ( ep , sen_genscc . scc_rfcr , SCC_EB ) ;
W8 ( ep , sen_genscc . scc_tfcr , SCC_EB ) ;
/* Set maximum bytes per receive buffer.
* This appears to be an Ethernet frame size , not the buffer
* fragment size . It must be a multiple of four .
*/
W16 ( ep , sen_genscc . scc_mrblr , 0x5f0 ) ;
/* Set CRC preset and mask.
*/
W32 ( ep , sen_cpres , 0xffffffff ) ;
W32 ( ep , sen_cmask , 0xdebb20e3 ) ;
W32 ( ep , sen_crcec , 0 ) ; /* CRC Error counter */
W32 ( ep , sen_alec , 0 ) ; /* alignment error counter */
W32 ( ep , sen_disfc , 0 ) ; /* discard frame counter */
W16 ( ep , sen_pads , 0x8888 ) ; /* Tx short frame pad character */
W16 ( ep , sen_retlim , 15 ) ; /* Retry limit threshold */
W16 ( ep , sen_maxflr , 0x5ee ) ; /* maximum frame length register */
W16 ( ep , sen_minflr , PKT_MINBUF_SIZE ) ; /* minimum frame length register */
W16 ( ep , sen_maxd1 , 0x000005f0 ) ; /* maximum DMA1 length */
W16 ( ep , sen_maxd2 , 0x000005f0 ) ; /* maximum DMA2 length */
/* Clear hash tables.
*/
W16 ( ep , sen_gaddr1 , 0 ) ;
W16 ( ep , sen_gaddr2 , 0 ) ;
W16 ( ep , sen_gaddr3 , 0 ) ;
W16 ( ep , sen_gaddr4 , 0 ) ;
W16 ( ep , sen_iaddr1 , 0 ) ;
W16 ( ep , sen_iaddr2 , 0 ) ;
W16 ( ep , sen_iaddr3 , 0 ) ;
W16 ( ep , sen_iaddr4 , 0 ) ;
2007-09-18 20:05:35 +04:00
/* set address
2005-10-29 00:25:58 +04:00
*/
mac = dev - > dev_addr ;
paddrh = ( ( u16 ) mac [ 5 ] < < 8 ) | mac [ 4 ] ;
paddrm = ( ( u16 ) mac [ 3 ] < < 8 ) | mac [ 2 ] ;
paddrl = ( ( u16 ) mac [ 1 ] < < 8 ) | mac [ 0 ] ;
W16 ( ep , sen_paddrh , paddrh ) ;
W16 ( ep , sen_paddrm , paddrm ) ;
W16 ( ep , sen_paddrl , paddrl ) ;
W16 ( ep , sen_pper , 0 ) ;
W16 ( ep , sen_taddrl , 0 ) ;
W16 ( ep , sen_taddrm , 0 ) ;
W16 ( ep , sen_taddrh , 0 ) ;
fs_init_bds ( dev ) ;
scc_cr_cmd ( fep , CPM_CR_INIT_TRX ) ;
W16 ( sccp , scc_scce , 0xffff ) ;
2007-09-18 20:05:35 +04:00
/* Enable interrupts we wish to service.
2005-10-29 00:25:58 +04:00
*/
W16 ( sccp , scc_sccm , SCCE_ENET_TXE | SCCE_ENET_RXF | SCCE_ENET_TXB ) ;
/* Set GSMR_H to enable all normal operating modes.
* Set GSMR_L to enable Ethernet to MC68160 .
*/
W32 ( sccp , scc_gsmrh , 0 ) ;
W32 ( sccp , scc_gsmrl ,
SCC_GSMRL_TCI | SCC_GSMRL_TPL_48 | SCC_GSMRL_TPP_10 |
SCC_GSMRL_MODE_ENET ) ;
/* Set sync/delimiters.
*/
W16 ( sccp , scc_dsr , 0xd555 ) ;
/* Set processing mode. Use Ethernet CRC, catch broadcast, and
* start frame search 22 bit times after RENA .
*/
W16 ( sccp , scc_psmr , SCC_PSMR_ENCRC | SCC_PSMR_NIB22 ) ;
/* Set full duplex mode if needed */
2006-08-15 10:00:30 +04:00
if ( fep - > phydev - > duplex )
2005-10-29 00:25:58 +04:00
S16 ( sccp , scc_psmr , SCC_PSMR_LPB | SCC_PSMR_FDE ) ;
S32 ( sccp , scc_gsmrl , SCC_GSMRL_ENR | SCC_GSMRL_ENT ) ;
}
2007-09-18 20:05:35 +04:00
static void stop ( struct net_device * dev )
2005-10-29 00:25:58 +04:00
{
struct fs_enet_private * fep = netdev_priv ( dev ) ;
2007-10-01 23:20:58 +04:00
scc_t __iomem * sccp = fep - > scc . sccp ;
2005-10-29 00:25:58 +04:00
int i ;
for ( i = 0 ; ( R16 ( sccp , scc_sccm ) = = 0 ) & & i < SCC_RESET_DELAY ; i + + )
udelay ( 1 ) ;
if ( i = = SCC_RESET_DELAY )
printk ( KERN_WARNING DRV_MODULE_NAME
" : %s SCC timeout on graceful transmit stop \n " ,
dev - > name ) ;
W16 ( sccp , scc_sccm , 0 ) ;
C32 ( sccp , scc_gsmrl , SCC_GSMRL_ENR | SCC_GSMRL_ENT ) ;
fs_cleanup_bds ( dev ) ;
}
static void pre_request_irq ( struct net_device * dev , int irq )
{
2007-01-27 11:00:04 +03:00
# ifndef CONFIG_PPC_MERGE
2005-10-29 00:25:58 +04:00
immap_t * immap = fs_enet_immap ;
u32 siel ;
/* SIU interrupt */
if ( irq > = SIU_IRQ0 & & irq < SIU_LEVEL7 ) {
siel = in_be32 ( & immap - > im_siu_conf . sc_siel ) ;
if ( ( irq & 1 ) = = 0 )
siel | = ( 0x80000000 > > irq ) ;
else
siel & = ~ ( 0x80000000 > > ( irq & ~ 1 ) ) ;
out_be32 ( & immap - > im_siu_conf . sc_siel , siel ) ;
}
2007-01-27 11:00:04 +03:00
# endif
2005-10-29 00:25:58 +04:00
}
static void post_free_irq ( struct net_device * dev , int irq )
{
/* nothing */
}
static void napi_clear_rx_event ( struct net_device * dev )
{
struct fs_enet_private * fep = netdev_priv ( dev ) ;
2007-10-01 23:20:58 +04:00
scc_t __iomem * sccp = fep - > scc . sccp ;
2005-10-29 00:25:58 +04:00
W16 ( sccp , scc_scce , SCC_NAPI_RX_EVENT_MSK ) ;
}
static void napi_enable_rx ( struct net_device * dev )
{
struct fs_enet_private * fep = netdev_priv ( dev ) ;
2007-10-01 23:20:58 +04:00
scc_t __iomem * sccp = fep - > scc . sccp ;
2005-10-29 00:25:58 +04:00
S16 ( sccp , scc_sccm , SCC_NAPI_RX_EVENT_MSK ) ;
}
static void napi_disable_rx ( struct net_device * dev )
{
struct fs_enet_private * fep = netdev_priv ( dev ) ;
2007-10-01 23:20:58 +04:00
scc_t __iomem * sccp = fep - > scc . sccp ;
2005-10-29 00:25:58 +04:00
C16 ( sccp , scc_sccm , SCC_NAPI_RX_EVENT_MSK ) ;
}
static void rx_bd_done ( struct net_device * dev )
{
/* nothing */
}
static void tx_kickstart ( struct net_device * dev )
{
/* nothing */
}
static u32 get_int_events ( struct net_device * dev )
{
struct fs_enet_private * fep = netdev_priv ( dev ) ;
2007-10-01 23:20:58 +04:00
scc_t __iomem * sccp = fep - > scc . sccp ;
2005-10-29 00:25:58 +04:00
return ( u32 ) R16 ( sccp , scc_scce ) ;
}
static void clear_int_events ( struct net_device * dev , u32 int_events )
{
struct fs_enet_private * fep = netdev_priv ( dev ) ;
2007-10-01 23:20:58 +04:00
scc_t __iomem * sccp = fep - > scc . sccp ;
2005-10-29 00:25:58 +04:00
W16 ( sccp , scc_scce , int_events & 0xffff ) ;
}
static void ev_error ( struct net_device * dev , u32 int_events )
{
printk ( KERN_WARNING DRV_MODULE_NAME
" : %s SCC ERROR(s) 0x%x \n " , dev - > name , int_events ) ;
}
static int get_regs ( struct net_device * dev , void * p , int * sizep )
{
struct fs_enet_private * fep = netdev_priv ( dev ) ;
2007-10-01 23:20:58 +04:00
if ( * sizep < sizeof ( scc_t ) + sizeof ( scc_enet_t __iomem * ) )
2005-10-29 00:25:58 +04:00
return - EINVAL ;
memcpy_fromio ( p , fep - > scc . sccp , sizeof ( scc_t ) ) ;
p = ( char * ) p + sizeof ( scc_t ) ;
2007-10-01 23:20:58 +04:00
memcpy_fromio ( p , fep - > scc . ep , sizeof ( scc_enet_t __iomem * ) ) ;
2005-10-29 00:25:58 +04:00
return 0 ;
}
static int get_regs_len ( struct net_device * dev )
{
2007-10-01 23:20:58 +04:00
return sizeof ( scc_t ) + sizeof ( scc_enet_t __iomem * ) ;
2005-10-29 00:25:58 +04:00
}
static void tx_restart ( struct net_device * dev )
{
struct fs_enet_private * fep = netdev_priv ( dev ) ;
scc_cr_cmd ( fep , CPM_CR_RESTART_TX ) ;
}
2006-08-15 10:00:30 +04:00
2005-10-29 00:25:58 +04:00
/*************************************************************************/
const struct fs_ops fs_scc_ops = {
. setup_data = setup_data ,
. cleanup_data = cleanup_data ,
. set_multicast_list = set_multicast_list ,
. restart = restart ,
. stop = stop ,
. pre_request_irq = pre_request_irq ,
. post_free_irq = post_free_irq ,
. napi_clear_rx_event = napi_clear_rx_event ,
. napi_enable_rx = napi_enable_rx ,
. napi_disable_rx = napi_disable_rx ,
. rx_bd_done = rx_bd_done ,
. tx_kickstart = tx_kickstart ,
. get_int_events = get_int_events ,
. clear_int_events = clear_int_events ,
. ev_error = ev_error ,
. get_regs = get_regs ,
. get_regs_len = get_regs_len ,
. tx_restart = tx_restart ,
. allocate_bd = allocate_bd ,
. free_bd = free_bd ,
} ;