2013-08-08 13:34:54 +02:00
/* MOXA ART Ethernet (RTL8201CP) driver.
*
* Copyright ( C ) 2013 Jonas Jensen
*
* Jonas Jensen < jonas . jensen @ gmail . com >
*
* Based on code from
* Moxa Technology Co . , Ltd . < www . moxa . com >
*
* 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 kind , whether express or implied .
*/
# include <linux/module.h>
# include <linux/netdevice.h>
# include <linux/etherdevice.h>
# include <linux/skbuff.h>
# include <linux/dma-mapping.h>
# include <linux/ethtool.h>
# include <linux/platform_device.h>
# include <linux/interrupt.h>
# include <linux/irq.h>
# include <linux/of_address.h>
# include <linux/of_irq.h>
# include <linux/crc32.h>
# include <linux/crc32c.h>
# include "moxart_ether.h"
2016-01-28 17:54:33 +01:00
static inline void moxart_desc_write ( u32 data , u32 * desc )
{
* desc = cpu_to_le32 ( data ) ;
}
static inline u32 moxart_desc_read ( u32 * desc )
{
return le32_to_cpu ( * desc ) ;
}
2013-08-08 13:34:54 +02:00
static inline void moxart_emac_write ( struct net_device * ndev ,
unsigned int reg , unsigned long value )
{
struct moxart_mac_priv_t * priv = netdev_priv ( ndev ) ;
writel ( value , priv - > base + reg ) ;
}
static void moxart_update_mac_address ( struct net_device * ndev )
{
moxart_emac_write ( ndev , REG_MAC_MS_ADDRESS ,
( ( ndev - > dev_addr [ 0 ] < < 8 ) | ( ndev - > dev_addr [ 1 ] ) ) ) ;
moxart_emac_write ( ndev , REG_MAC_MS_ADDRESS + 4 ,
( ( ndev - > dev_addr [ 2 ] < < 24 ) |
( ndev - > dev_addr [ 3 ] < < 16 ) |
( ndev - > dev_addr [ 4 ] < < 8 ) |
( ndev - > dev_addr [ 5 ] ) ) ) ;
}
static int moxart_set_mac_address ( struct net_device * ndev , void * addr )
{
struct sockaddr * address = addr ;
if ( ! is_valid_ether_addr ( address - > sa_data ) )
return - EADDRNOTAVAIL ;
memcpy ( ndev - > dev_addr , address - > sa_data , ndev - > addr_len ) ;
moxart_update_mac_address ( ndev ) ;
return 0 ;
}
static void moxart_mac_free_memory ( struct net_device * ndev )
{
struct moxart_mac_priv_t * priv = netdev_priv ( ndev ) ;
int i ;
for ( i = 0 ; i < RX_DESC_NUM ; i + + )
dma_unmap_single ( & ndev - > dev , priv - > rx_mapping [ i ] ,
priv - > rx_buf_size , DMA_FROM_DEVICE ) ;
if ( priv - > tx_desc_base )
dma_free_coherent ( NULL , TX_REG_DESC_SIZE * TX_DESC_NUM ,
priv - > tx_desc_base , priv - > tx_base ) ;
if ( priv - > rx_desc_base )
dma_free_coherent ( NULL , RX_REG_DESC_SIZE * RX_DESC_NUM ,
priv - > rx_desc_base , priv - > rx_base ) ;
kfree ( priv - > tx_buf_base ) ;
kfree ( priv - > rx_buf_base ) ;
}
static void moxart_mac_reset ( struct net_device * ndev )
{
struct moxart_mac_priv_t * priv = netdev_priv ( ndev ) ;
writel ( SW_RST , priv - > base + REG_MAC_CTRL ) ;
while ( readl ( priv - > base + REG_MAC_CTRL ) & SW_RST )
mdelay ( 10 ) ;
writel ( 0 , priv - > base + REG_INTERRUPT_MASK ) ;
priv - > reg_maccr = RX_BROADPKT | FULLDUP | CRC_APD | RX_FTL ;
}
static void moxart_mac_enable ( struct net_device * ndev )
{
struct moxart_mac_priv_t * priv = netdev_priv ( ndev ) ;
writel ( 0x00001010 , priv - > base + REG_INT_TIMER_CTRL ) ;
writel ( 0x00000001 , priv - > base + REG_APOLL_TIMER_CTRL ) ;
writel ( 0x00000390 , priv - > base + REG_DMA_BLEN_CTRL ) ;
priv - > reg_imr | = ( RPKT_FINISH_M | XPKT_FINISH_M ) ;
writel ( priv - > reg_imr , priv - > base + REG_INTERRUPT_MASK ) ;
priv - > reg_maccr | = ( RCV_EN | XMT_EN | RDMA_EN | XDMA_EN ) ;
writel ( priv - > reg_maccr , priv - > base + REG_MAC_CTRL ) ;
}
static void moxart_mac_setup_desc_ring ( struct net_device * ndev )
{
struct moxart_mac_priv_t * priv = netdev_priv ( ndev ) ;
2016-01-28 17:54:33 +01:00
void * desc ;
2013-08-08 13:34:54 +02:00
int i ;
for ( i = 0 ; i < TX_DESC_NUM ; i + + ) {
desc = priv - > tx_desc_base + i * TX_REG_DESC_SIZE ;
memset ( desc , 0 , TX_REG_DESC_SIZE ) ;
priv - > tx_buf [ i ] = priv - > tx_buf_base + priv - > tx_buf_size * i ;
}
2016-01-28 17:54:33 +01:00
moxart_desc_write ( TX_DESC1_END , desc + TX_REG_OFFSET_DESC1 ) ;
2013-08-08 13:34:54 +02:00
priv - > tx_head = 0 ;
priv - > tx_tail = 0 ;
for ( i = 0 ; i < RX_DESC_NUM ; i + + ) {
desc = priv - > rx_desc_base + i * RX_REG_DESC_SIZE ;
memset ( desc , 0 , RX_REG_DESC_SIZE ) ;
2016-01-28 17:54:33 +01:00
moxart_desc_write ( RX_DESC0_DMA_OWN , desc + RX_REG_OFFSET_DESC0 ) ;
moxart_desc_write ( RX_BUF_SIZE & RX_DESC1_BUF_SIZE_MASK ,
2013-08-08 13:34:54 +02:00
desc + RX_REG_OFFSET_DESC1 ) ;
priv - > rx_buf [ i ] = priv - > rx_buf_base + priv - > rx_buf_size * i ;
priv - > rx_mapping [ i ] = dma_map_single ( & ndev - > dev ,
priv - > rx_buf [ i ] ,
priv - > rx_buf_size ,
DMA_FROM_DEVICE ) ;
if ( dma_mapping_error ( & ndev - > dev , priv - > rx_mapping [ i ] ) )
netdev_err ( ndev , " DMA mapping error \n " ) ;
2016-01-28 17:54:33 +01:00
moxart_desc_write ( priv - > rx_mapping [ i ] ,
2013-08-08 13:34:54 +02:00
desc + RX_REG_OFFSET_DESC2 + RX_DESC2_ADDRESS_PHYS ) ;
2016-01-28 17:54:33 +01:00
moxart_desc_write ( ( uintptr_t ) priv - > rx_buf [ i ] ,
2013-08-08 13:34:54 +02:00
desc + RX_REG_OFFSET_DESC2 + RX_DESC2_ADDRESS_VIRT ) ;
}
2016-01-28 17:54:33 +01:00
moxart_desc_write ( RX_DESC1_END , desc + RX_REG_OFFSET_DESC1 ) ;
2013-08-08 13:34:54 +02:00
priv - > rx_head = 0 ;
2015-03-06 20:49:12 -08:00
/* reset the MAC controller TX/RX desciptor base address */
2013-08-08 13:34:54 +02:00
writel ( priv - > tx_base , priv - > base + REG_TXR_BASE_ADDRESS ) ;
writel ( priv - > rx_base , priv - > base + REG_RXR_BASE_ADDRESS ) ;
}
static int moxart_mac_open ( struct net_device * ndev )
{
struct moxart_mac_priv_t * priv = netdev_priv ( ndev ) ;
if ( ! is_valid_ether_addr ( ndev - > dev_addr ) )
return - EADDRNOTAVAIL ;
napi_enable ( & priv - > napi ) ;
moxart_mac_reset ( ndev ) ;
moxart_update_mac_address ( ndev ) ;
moxart_mac_setup_desc_ring ( ndev ) ;
moxart_mac_enable ( ndev ) ;
netif_start_queue ( ndev ) ;
netdev_dbg ( ndev , " %s: IMR=0x%x, MACCR=0x%x \n " ,
__func__ , readl ( priv - > base + REG_INTERRUPT_MASK ) ,
readl ( priv - > base + REG_MAC_CTRL ) ) ;
return 0 ;
}
static int moxart_mac_stop ( struct net_device * ndev )
{
struct moxart_mac_priv_t * priv = netdev_priv ( ndev ) ;
napi_disable ( & priv - > napi ) ;
netif_stop_queue ( ndev ) ;
/* disable all interrupts */
writel ( 0 , priv - > base + REG_INTERRUPT_MASK ) ;
/* disable all functions */
writel ( 0 , priv - > base + REG_MAC_CTRL ) ;
return 0 ;
}
static int moxart_rx_poll ( struct napi_struct * napi , int budget )
{
struct moxart_mac_priv_t * priv = container_of ( napi ,
struct moxart_mac_priv_t ,
napi ) ;
struct net_device * ndev = priv - > ndev ;
struct sk_buff * skb ;
2016-01-28 17:54:33 +01:00
void * desc ;
2013-08-08 13:34:54 +02:00
unsigned int desc0 , len ;
int rx_head = priv - > rx_head ;
int rx = 0 ;
2014-08-25 16:22:40 +02:00
while ( rx < budget ) {
2013-08-08 13:34:54 +02:00
desc = priv - > rx_desc_base + ( RX_REG_DESC_SIZE * rx_head ) ;
2016-01-28 17:54:33 +01:00
desc0 = moxart_desc_read ( desc + RX_REG_OFFSET_DESC0 ) ;
rmb ( ) ; /* ensure desc0 is up to date */
2013-08-08 13:34:54 +02:00
if ( desc0 & RX_DESC0_DMA_OWN )
break ;
if ( desc0 & ( RX_DESC0_ERR | RX_DESC0_CRC_ERR | RX_DESC0_FTL |
RX_DESC0_RUNT | RX_DESC0_ODD_NB ) ) {
net_dbg_ratelimited ( " packet error \n " ) ;
priv - > stats . rx_dropped + + ;
priv - > stats . rx_errors + + ;
2014-08-25 16:22:40 +02:00
goto rx_next ;
2013-08-08 13:34:54 +02:00
}
len = desc0 & RX_DESC0_FRAME_LEN_MASK ;
if ( len > RX_BUF_SIZE )
len = RX_BUF_SIZE ;
2014-08-25 16:22:32 +02:00
dma_sync_single_for_cpu ( & ndev - > dev ,
priv - > rx_mapping [ rx_head ] ,
priv - > rx_buf_size , DMA_FROM_DEVICE ) ;
2014-08-25 16:22:22 +02:00
skb = netdev_alloc_skb_ip_align ( ndev , len ) ;
2013-08-08 13:34:54 +02:00
if ( unlikely ( ! skb ) ) {
2014-08-25 16:22:22 +02:00
net_dbg_ratelimited ( " netdev_alloc_skb_ip_align failed \n " ) ;
2013-08-08 13:34:54 +02:00
priv - > stats . rx_dropped + + ;
priv - > stats . rx_errors + + ;
2014-08-25 16:22:40 +02:00
goto rx_next ;
2013-08-08 13:34:54 +02:00
}
2014-08-25 16:22:22 +02:00
memcpy ( skb - > data , priv - > rx_buf [ rx_head ] , len ) ;
2013-08-08 13:34:54 +02:00
skb_put ( skb , len ) ;
skb - > protocol = eth_type_trans ( skb , ndev ) ;
napi_gro_receive ( & priv - > napi , skb ) ;
rx + + ;
priv - > stats . rx_packets + + ;
priv - > stats . rx_bytes + = len ;
if ( desc0 & RX_DESC0_MULTICAST )
priv - > stats . multicast + + ;
2014-08-25 16:22:40 +02:00
rx_next :
2016-01-28 17:54:33 +01:00
wmb ( ) ; /* prevent setting ownership back too early */
moxart_desc_write ( RX_DESC0_DMA_OWN , desc + RX_REG_OFFSET_DESC0 ) ;
2013-08-08 13:34:54 +02:00
rx_head = RX_NEXT ( rx_head ) ;
priv - > rx_head = rx_head ;
}
if ( rx < budget ) {
2014-08-25 16:22:40 +02:00
napi_complete ( napi ) ;
2013-08-08 13:34:54 +02:00
}
priv - > reg_imr | = RPKT_FINISH_M ;
writel ( priv - > reg_imr , priv - > base + REG_INTERRUPT_MASK ) ;
return rx ;
}
static void moxart_tx_finished ( struct net_device * ndev )
{
struct moxart_mac_priv_t * priv = netdev_priv ( ndev ) ;
unsigned tx_head = priv - > tx_head ;
unsigned tx_tail = priv - > tx_tail ;
while ( tx_tail ! = tx_head ) {
dma_unmap_single ( & ndev - > dev , priv - > tx_mapping [ tx_tail ] ,
priv - > tx_len [ tx_tail ] , DMA_TO_DEVICE ) ;
priv - > stats . tx_packets + + ;
priv - > stats . tx_bytes + = priv - > tx_skb [ tx_tail ] - > len ;
dev_kfree_skb_irq ( priv - > tx_skb [ tx_tail ] ) ;
priv - > tx_skb [ tx_tail ] = NULL ;
tx_tail = TX_NEXT ( tx_tail ) ;
}
priv - > tx_tail = tx_tail ;
}
static irqreturn_t moxart_mac_interrupt ( int irq , void * dev_id )
{
struct net_device * ndev = ( struct net_device * ) dev_id ;
struct moxart_mac_priv_t * priv = netdev_priv ( ndev ) ;
unsigned int ists = readl ( priv - > base + REG_INTERRUPT_STATUS ) ;
if ( ists & XPKT_OK_INT_STS )
moxart_tx_finished ( ndev ) ;
if ( ists & RPKT_FINISH ) {
if ( napi_schedule_prep ( & priv - > napi ) ) {
priv - > reg_imr & = ~ RPKT_FINISH_M ;
writel ( priv - > reg_imr , priv - > base + REG_INTERRUPT_MASK ) ;
__napi_schedule ( & priv - > napi ) ;
}
}
return IRQ_HANDLED ;
}
static int moxart_mac_start_xmit ( struct sk_buff * skb , struct net_device * ndev )
{
struct moxart_mac_priv_t * priv = netdev_priv ( ndev ) ;
2016-01-28 17:54:33 +01:00
void * desc ;
2013-08-08 13:34:54 +02:00
unsigned int len ;
unsigned int tx_head = priv - > tx_head ;
u32 txdes1 ;
2013-08-18 16:09:30 +08:00
int ret = NETDEV_TX_BUSY ;
2013-08-08 13:34:54 +02:00
desc = priv - > tx_desc_base + ( TX_REG_DESC_SIZE * tx_head ) ;
spin_lock_irq ( & priv - > txlock ) ;
2016-01-28 17:54:33 +01:00
if ( moxart_desc_read ( desc + TX_REG_OFFSET_DESC0 ) & TX_DESC0_DMA_OWN ) {
2013-08-08 13:34:54 +02:00
net_dbg_ratelimited ( " no TX space for packet \n " ) ;
priv - > stats . tx_dropped + + ;
2013-08-18 16:09:30 +08:00
goto out_unlock ;
2013-08-08 13:34:54 +02:00
}
2016-01-28 17:54:33 +01:00
rmb ( ) ; /* ensure data is only read that had TX_DESC0_DMA_OWN cleared */
2013-08-08 13:34:54 +02:00
len = skb - > len > TX_BUF_SIZE ? TX_BUF_SIZE : skb - > len ;
priv - > tx_mapping [ tx_head ] = dma_map_single ( & ndev - > dev , skb - > data ,
len , DMA_TO_DEVICE ) ;
if ( dma_mapping_error ( & ndev - > dev , priv - > tx_mapping [ tx_head ] ) ) {
netdev_err ( ndev , " DMA mapping error \n " ) ;
2013-08-18 16:09:30 +08:00
goto out_unlock ;
2013-08-08 13:34:54 +02:00
}
priv - > tx_len [ tx_head ] = len ;
priv - > tx_skb [ tx_head ] = skb ;
2016-01-28 17:54:33 +01:00
moxart_desc_write ( priv - > tx_mapping [ tx_head ] ,
2013-08-08 13:34:54 +02:00
desc + TX_REG_OFFSET_DESC2 + TX_DESC2_ADDRESS_PHYS ) ;
2016-01-28 17:54:33 +01:00
moxart_desc_write ( ( uintptr_t ) skb - > data ,
2013-08-08 13:34:54 +02:00
desc + TX_REG_OFFSET_DESC2 + TX_DESC2_ADDRESS_VIRT ) ;
if ( skb - > len < ETH_ZLEN ) {
memset ( & skb - > data [ skb - > len ] ,
0 , ETH_ZLEN - skb - > len ) ;
len = ETH_ZLEN ;
}
2014-08-25 16:22:32 +02:00
dma_sync_single_for_device ( & ndev - > dev , priv - > tx_mapping [ tx_head ] ,
priv - > tx_buf_size , DMA_TO_DEVICE ) ;
2014-08-25 16:22:11 +02:00
txdes1 = TX_DESC1_LTS | TX_DESC1_FTS | ( len & TX_DESC1_BUF_SIZE_MASK ) ;
if ( tx_head = = TX_DESC_NUM_MASK )
txdes1 | = TX_DESC1_END ;
2016-01-28 17:54:33 +01:00
moxart_desc_write ( txdes1 , desc + TX_REG_OFFSET_DESC1 ) ;
wmb ( ) ; /* flush descriptor before transferring ownership */
moxart_desc_write ( TX_DESC0_DMA_OWN , desc + TX_REG_OFFSET_DESC0 ) ;
2013-08-08 13:34:54 +02:00
/* start to send packet */
writel ( 0xffffffff , priv - > base + REG_TX_POLL_DEMAND ) ;
priv - > tx_head = TX_NEXT ( tx_head ) ;
2016-05-03 16:33:13 +02:00
netif_trans_update ( ndev ) ;
2013-08-18 16:09:30 +08:00
ret = NETDEV_TX_OK ;
out_unlock :
2013-08-08 13:34:54 +02:00
spin_unlock_irq ( & priv - > txlock ) ;
2013-08-18 16:09:30 +08:00
return ret ;
2013-08-08 13:34:54 +02:00
}
static struct net_device_stats * moxart_mac_get_stats ( struct net_device * ndev )
{
struct moxart_mac_priv_t * priv = netdev_priv ( ndev ) ;
return & priv - > stats ;
}
static void moxart_mac_setmulticast ( struct net_device * ndev )
{
struct moxart_mac_priv_t * priv = netdev_priv ( ndev ) ;
struct netdev_hw_addr * ha ;
int crc_val ;
netdev_for_each_mc_addr ( ha , ndev ) {
crc_val = crc32_le ( ~ 0 , ha - > addr , ETH_ALEN ) ;
crc_val = ( crc_val > > 26 ) & 0x3f ;
if ( crc_val > = 32 ) {
writel ( readl ( priv - > base + REG_MCAST_HASH_TABLE1 ) |
( 1UL < < ( crc_val - 32 ) ) ,
priv - > base + REG_MCAST_HASH_TABLE1 ) ;
} else {
writel ( readl ( priv - > base + REG_MCAST_HASH_TABLE0 ) |
( 1UL < < crc_val ) ,
priv - > base + REG_MCAST_HASH_TABLE0 ) ;
}
}
}
static void moxart_mac_set_rx_mode ( struct net_device * ndev )
{
struct moxart_mac_priv_t * priv = netdev_priv ( ndev ) ;
spin_lock_irq ( & priv - > txlock ) ;
( ndev - > flags & IFF_PROMISC ) ? ( priv - > reg_maccr | = RCV_ALL ) :
( priv - > reg_maccr & = ~ RCV_ALL ) ;
( ndev - > flags & IFF_ALLMULTI ) ? ( priv - > reg_maccr | = RX_MULTIPKT ) :
( priv - > reg_maccr & = ~ RX_MULTIPKT ) ;
if ( ( ndev - > flags & IFF_MULTICAST ) & & netdev_mc_count ( ndev ) ) {
priv - > reg_maccr | = HT_MULTI_EN ;
moxart_mac_setmulticast ( ndev ) ;
} else {
priv - > reg_maccr & = ~ HT_MULTI_EN ;
}
writel ( priv - > reg_maccr , priv - > base + REG_MAC_CTRL ) ;
spin_unlock_irq ( & priv - > txlock ) ;
}
static struct net_device_ops moxart_netdev_ops = {
. ndo_open = moxart_mac_open ,
. ndo_stop = moxart_mac_stop ,
. ndo_start_xmit = moxart_mac_start_xmit ,
. ndo_get_stats = moxart_mac_get_stats ,
. ndo_set_rx_mode = moxart_mac_set_rx_mode ,
. ndo_set_mac_address = moxart_set_mac_address ,
. ndo_validate_addr = eth_validate_addr ,
. ndo_change_mtu = eth_change_mtu ,
} ;
static int moxart_mac_probe ( struct platform_device * pdev )
{
struct device * p_dev = & pdev - > dev ;
struct device_node * node = p_dev - > of_node ;
struct net_device * ndev ;
struct moxart_mac_priv_t * priv ;
struct resource * res ;
unsigned int irq ;
int ret ;
ndev = alloc_etherdev ( sizeof ( struct moxart_mac_priv_t ) ) ;
if ( ! ndev )
return - ENOMEM ;
irq = irq_of_parse_and_map ( node , 0 ) ;
if ( irq < = 0 ) {
netdev_err ( ndev , " irq_of_parse_and_map failed \n " ) ;
2013-10-08 11:19:19 +08:00
ret = - EINVAL ;
goto irq_map_fail ;
2013-08-08 13:34:54 +02:00
}
priv = netdev_priv ( ndev ) ;
priv - > ndev = ndev ;
res = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
ndev - > base_addr = res - > start ;
priv - > base = devm_ioremap_resource ( p_dev , res ) ;
2016-03-02 13:11:10 +03:00
if ( IS_ERR ( priv - > base ) ) {
2013-08-08 13:34:54 +02:00
dev_err ( p_dev , " devm_ioremap_resource failed \n " ) ;
2016-03-02 13:11:10 +03:00
ret = PTR_ERR ( priv - > base ) ;
2013-08-08 13:34:54 +02:00
goto init_fail ;
}
spin_lock_init ( & priv - > txlock ) ;
priv - > tx_buf_size = TX_BUF_SIZE ;
2014-08-25 16:22:22 +02:00
priv - > rx_buf_size = RX_BUF_SIZE ;
2013-08-08 13:34:54 +02:00
priv - > tx_desc_base = dma_alloc_coherent ( NULL , TX_REG_DESC_SIZE *
TX_DESC_NUM , & priv - > tx_base ,
GFP_DMA | GFP_KERNEL ) ;
2013-10-08 11:19:19 +08:00
if ( priv - > tx_desc_base = = NULL ) {
ret = - ENOMEM ;
2013-08-08 13:34:54 +02:00
goto init_fail ;
2013-10-08 11:19:19 +08:00
}
2013-08-08 13:34:54 +02:00
priv - > rx_desc_base = dma_alloc_coherent ( NULL , RX_REG_DESC_SIZE *
RX_DESC_NUM , & priv - > rx_base ,
GFP_DMA | GFP_KERNEL ) ;
2013-10-08 11:19:19 +08:00
if ( priv - > rx_desc_base = = NULL ) {
ret = - ENOMEM ;
2013-08-08 13:34:54 +02:00
goto init_fail ;
2013-10-08 11:19:19 +08:00
}
2013-08-08 13:34:54 +02:00
priv - > tx_buf_base = kmalloc ( priv - > tx_buf_size * TX_DESC_NUM ,
GFP_ATOMIC ) ;
2013-10-08 11:19:19 +08:00
if ( ! priv - > tx_buf_base ) {
ret = - ENOMEM ;
2013-08-08 13:34:54 +02:00
goto init_fail ;
2013-10-08 11:19:19 +08:00
}
2013-08-08 13:34:54 +02:00
priv - > rx_buf_base = kmalloc ( priv - > rx_buf_size * RX_DESC_NUM ,
GFP_ATOMIC ) ;
2013-10-08 11:19:19 +08:00
if ( ! priv - > rx_buf_base ) {
ret = - ENOMEM ;
2013-08-08 13:34:54 +02:00
goto init_fail ;
2013-10-08 11:19:19 +08:00
}
2013-08-08 13:34:54 +02:00
platform_set_drvdata ( pdev , ndev ) ;
ret = devm_request_irq ( p_dev , irq , moxart_mac_interrupt , 0 ,
pdev - > name , ndev ) ;
if ( ret ) {
netdev_err ( ndev , " devm_request_irq failed \n " ) ;
goto init_fail ;
}
ndev - > netdev_ops = & moxart_netdev_ops ;
netif_napi_add ( ndev , & priv - > napi , moxart_rx_poll , RX_DESC_NUM ) ;
ndev - > priv_flags | = IFF_UNICAST_FLT ;
ndev - > irq = irq ;
SET_NETDEV_DEV ( ndev , & pdev - > dev ) ;
ret = register_netdev ( ndev ) ;
if ( ret ) {
free_netdev ( ndev ) ;
goto init_fail ;
}
netdev_dbg ( ndev , " %s: IRQ=%d address=%pM \n " ,
__func__ , ndev - > irq , ndev - > dev_addr ) ;
return 0 ;
init_fail :
netdev_err ( ndev , " init failed \n " ) ;
moxart_mac_free_memory ( ndev ) ;
2013-10-08 11:19:19 +08:00
irq_map_fail :
free_netdev ( ndev ) ;
2013-08-08 13:34:54 +02:00
return ret ;
}
static int moxart_remove ( struct platform_device * pdev )
{
struct net_device * ndev = platform_get_drvdata ( pdev ) ;
unregister_netdev ( ndev ) ;
free_irq ( ndev - > irq , ndev ) ;
moxart_mac_free_memory ( ndev ) ;
free_netdev ( ndev ) ;
return 0 ;
}
static const struct of_device_id moxart_mac_match [ ] = {
{ . compatible = " moxa,moxart-mac " } ,
{ }
} ;
2015-09-18 17:56:21 +02:00
MODULE_DEVICE_TABLE ( of , moxart_mac_match ) ;
2013-08-08 13:34:54 +02:00
2013-09-30 15:18:27 +02:00
static struct platform_driver moxart_mac_driver = {
2013-08-08 13:34:54 +02:00
. probe = moxart_mac_probe ,
. remove = moxart_remove ,
. driver = {
. name = " moxart-ethernet " ,
. of_match_table = moxart_mac_match ,
} ,
} ;
module_platform_driver ( moxart_mac_driver ) ;
MODULE_DESCRIPTION ( " MOXART RTL8201CP Ethernet driver " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;
MODULE_AUTHOR ( " Jonas Jensen <jonas.jensen@gmail.com> " ) ;