2011-06-08 23:32:48 +00:00
/*
* Faraday FTGMAC100 Gigabit Ethernet
*
* ( C ) Copyright 2009 - 2011 Faraday Technology
* Po - Yu Chuang < ratbert @ faraday - tech . com >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* 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 . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
# define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
# include <linux/dma-mapping.h>
# include <linux/etherdevice.h>
# include <linux/ethtool.h>
2012-01-18 13:45:44 +00:00
# include <linux/interrupt.h>
2011-06-08 23:32:48 +00:00
# include <linux/io.h>
# include <linux/module.h>
# include <linux/netdevice.h>
2017-03-30 17:00:12 +01:00
# include <linux/of.h>
2011-06-08 23:32:48 +00:00
# include <linux/phy.h>
# include <linux/platform_device.h>
2017-03-30 17:00:12 +01:00
# include <linux/property.h>
2011-06-08 23:32:48 +00:00
# include <net/ip.h>
2016-07-19 11:54:23 +10:00
# include <net/ncsi.h>
2011-06-08 23:32:48 +00:00
# include "ftgmac100.h"
# define DRV_NAME "ftgmac100"
# define DRV_VERSION "0.7"
# define RX_QUEUE_ENTRIES 256 /* must be power of 2 */
# define TX_QUEUE_ENTRIES 512 /* must be power of 2 */
2017-04-06 11:02:49 +10:00
# define MAX_PKT_SIZE 1536
# define RX_BUF_SIZE MAX_PKT_SIZE /* must be smaller than 0x3fff */
2011-06-08 23:32:48 +00:00
struct ftgmac100_descs {
struct ftgmac100_rxdes rxdes [ RX_QUEUE_ENTRIES ] ;
struct ftgmac100_txdes txdes [ TX_QUEUE_ENTRIES ] ;
} ;
struct ftgmac100 {
2017-04-05 12:28:43 +10:00
/* Registers */
2011-06-08 23:32:48 +00:00
struct resource * res ;
void __iomem * base ;
struct ftgmac100_descs * descs ;
dma_addr_t descs_dma_addr ;
2017-04-05 12:28:43 +10:00
/* Rx ring */
2017-04-06 11:02:49 +10:00
struct sk_buff * rx_skbs [ RX_QUEUE_ENTRIES ] ;
2011-06-08 23:32:48 +00:00
unsigned int rx_pointer ;
2017-04-05 12:28:43 +10:00
u32 rxdes0_edorr_mask ;
/* Tx ring */
2017-04-10 11:15:20 +10:00
struct sk_buff * tx_skbs [ TX_QUEUE_ENTRIES ] ;
2011-06-08 23:32:48 +00:00
unsigned int tx_clean_pointer ;
unsigned int tx_pointer ;
unsigned int tx_pending ;
2017-04-05 12:28:43 +10:00
u32 txdes0_edotr_mask ;
2011-06-08 23:32:48 +00:00
spinlock_t tx_lock ;
2017-04-06 11:02:45 +10:00
/* Scratch page to use when rx skb alloc fails */
void * rx_scratch ;
dma_addr_t rx_scratch_dma ;
2017-04-05 12:28:43 +10:00
/* Component structures */
2011-06-08 23:32:48 +00:00
struct net_device * netdev ;
struct device * dev ;
2016-07-19 11:54:23 +10:00
struct ncsi_dev * ndev ;
2011-06-08 23:32:48 +00:00
struct napi_struct napi ;
2017-04-05 12:28:50 +10:00
struct work_struct reset_task ;
2011-06-08 23:32:48 +00:00
struct mii_bus * mii_bus ;
2017-04-05 12:28:43 +10:00
/* Link management */
2017-04-05 12:28:45 +10:00
int cur_speed ;
int cur_duplex ;
2016-07-19 11:54:23 +10:00
bool use_ncsi ;
2016-09-22 08:34:59 +09:30
2017-04-05 12:28:43 +10:00
/* Misc */
2017-04-05 12:28:53 +10:00
bool need_mac_restart ;
2011-06-08 23:32:48 +00:00
} ;
static void ftgmac100_set_rx_ring_base ( struct ftgmac100 * priv , dma_addr_t addr )
{
iowrite32 ( addr , priv - > base + FTGMAC100_OFFSET_RXR_BADR ) ;
}
static void ftgmac100_set_rx_buffer_size ( struct ftgmac100 * priv ,
unsigned int size )
{
size = FTGMAC100_RBSR_SIZE ( size ) ;
iowrite32 ( size , priv - > base + FTGMAC100_OFFSET_RBSR ) ;
}
static void ftgmac100_set_normal_prio_tx_ring_base ( struct ftgmac100 * priv ,
dma_addr_t addr )
{
iowrite32 ( addr , priv - > base + FTGMAC100_OFFSET_NPTXR_BADR ) ;
}
static void ftgmac100_txdma_normal_prio_start_polling ( struct ftgmac100 * priv )
{
iowrite32 ( 1 , priv - > base + FTGMAC100_OFFSET_NPTXPD ) ;
}
2017-04-05 12:28:51 +10:00
static int ftgmac100_reset_mac ( struct ftgmac100 * priv , u32 maccr )
2011-06-08 23:32:48 +00:00
{
struct net_device * netdev = priv - > netdev ;
int i ;
/* NOTE: reset clears all registers */
2017-04-05 12:28:51 +10:00
iowrite32 ( maccr , priv - > base + FTGMAC100_OFFSET_MACCR ) ;
iowrite32 ( maccr | FTGMAC100_MACCR_SW_RST ,
priv - > base + FTGMAC100_OFFSET_MACCR ) ;
for ( i = 0 ; i < 50 ; i + + ) {
2011-06-08 23:32:48 +00:00
unsigned int maccr ;
maccr = ioread32 ( priv - > base + FTGMAC100_OFFSET_MACCR ) ;
if ( ! ( maccr & FTGMAC100_MACCR_SW_RST ) )
return 0 ;
2017-04-05 12:28:51 +10:00
udelay ( 1 ) ;
2011-06-08 23:32:48 +00:00
}
2017-04-05 12:28:51 +10:00
netdev_err ( netdev , " Hardware reset failed \n " ) ;
2011-06-08 23:32:48 +00:00
return - EIO ;
}
2017-04-05 12:28:51 +10:00
static int ftgmac100_reset_and_config_mac ( struct ftgmac100 * priv )
{
u32 maccr = 0 ;
switch ( priv - > cur_speed ) {
case SPEED_10 :
case 0 : /* no link */
break ;
case SPEED_100 :
maccr | = FTGMAC100_MACCR_FAST_MODE ;
break ;
case SPEED_1000 :
maccr | = FTGMAC100_MACCR_GIGA_MODE ;
break ;
default :
netdev_err ( priv - > netdev , " Unknown speed %d ! \n " ,
priv - > cur_speed ) ;
break ;
}
/* (Re)initialize the queue pointers */
priv - > rx_pointer = 0 ;
priv - > tx_clean_pointer = 0 ;
priv - > tx_pointer = 0 ;
priv - > tx_pending = 0 ;
/* The doc says reset twice with 10us interval */
if ( ftgmac100_reset_mac ( priv , maccr ) )
return - EIO ;
usleep_range ( 10 , 1000 ) ;
return ftgmac100_reset_mac ( priv , maccr ) ;
}
2011-06-08 23:32:48 +00:00
static void ftgmac100_set_mac ( struct ftgmac100 * priv , const unsigned char * mac )
{
unsigned int maddr = mac [ 0 ] < < 8 | mac [ 1 ] ;
unsigned int laddr = mac [ 2 ] < < 24 | mac [ 3 ] < < 16 | mac [ 4 ] < < 8 | mac [ 5 ] ;
iowrite32 ( maddr , priv - > base + FTGMAC100_OFFSET_MAC_MADR ) ;
iowrite32 ( laddr , priv - > base + FTGMAC100_OFFSET_MAC_LADR ) ;
}
2016-07-19 11:54:22 +10:00
static void ftgmac100_setup_mac ( struct ftgmac100 * priv )
{
u8 mac [ ETH_ALEN ] ;
unsigned int m ;
unsigned int l ;
void * addr ;
addr = device_get_mac_address ( priv - > dev , mac , ETH_ALEN ) ;
if ( addr ) {
ether_addr_copy ( priv - > netdev - > dev_addr , mac ) ;
dev_info ( priv - > dev , " Read MAC address %pM from device tree \n " ,
mac ) ;
return ;
}
m = ioread32 ( priv - > base + FTGMAC100_OFFSET_MAC_MADR ) ;
l = ioread32 ( priv - > base + FTGMAC100_OFFSET_MAC_LADR ) ;
mac [ 0 ] = ( m > > 8 ) & 0xff ;
mac [ 1 ] = m & 0xff ;
mac [ 2 ] = ( l > > 24 ) & 0xff ;
mac [ 3 ] = ( l > > 16 ) & 0xff ;
mac [ 4 ] = ( l > > 8 ) & 0xff ;
mac [ 5 ] = l & 0xff ;
if ( is_valid_ether_addr ( mac ) ) {
ether_addr_copy ( priv - > netdev - > dev_addr , mac ) ;
dev_info ( priv - > dev , " Read MAC address %pM from chip \n " , mac ) ;
} else {
eth_hw_addr_random ( priv - > netdev ) ;
dev_info ( priv - > dev , " Generated random MAC address %pM \n " ,
priv - > netdev - > dev_addr ) ;
}
}
static int ftgmac100_set_mac_addr ( struct net_device * dev , void * p )
{
int ret ;
ret = eth_prepare_mac_addr_change ( dev , p ) ;
if ( ret < 0 )
return ret ;
eth_commit_mac_addr_change ( dev , p ) ;
ftgmac100_set_mac ( netdev_priv ( dev ) , dev - > dev_addr ) ;
return 0 ;
}
2011-06-08 23:32:48 +00:00
static void ftgmac100_init_hw ( struct ftgmac100 * priv )
{
/* setup ring buffer base registers */
ftgmac100_set_rx_ring_base ( priv ,
priv - > descs_dma_addr +
offsetof ( struct ftgmac100_descs , rxdes ) ) ;
ftgmac100_set_normal_prio_tx_ring_base ( priv ,
priv - > descs_dma_addr +
offsetof ( struct ftgmac100_descs , txdes ) ) ;
ftgmac100_set_rx_buffer_size ( priv , RX_BUF_SIZE ) ;
iowrite32 ( FTGMAC100_APTC_RXPOLL_CNT ( 1 ) , priv - > base + FTGMAC100_OFFSET_APTC ) ;
ftgmac100_set_mac ( priv , priv - > netdev - > dev_addr ) ;
}
2017-04-05 12:28:45 +10:00
static void ftgmac100_start_hw ( struct ftgmac100 * priv )
2011-06-08 23:32:48 +00:00
{
2017-04-05 12:28:51 +10:00
u32 maccr = ioread32 ( priv - > base + FTGMAC100_OFFSET_MACCR ) ;
2011-06-08 23:32:48 +00:00
2017-04-05 12:28:51 +10:00
/* Keep the original GMAC and FAST bits */
maccr & = ( FTGMAC100_MACCR_FAST_MODE | FTGMAC100_MACCR_GIGA_MODE ) ;
2011-06-08 23:32:48 +00:00
2017-04-05 12:28:51 +10:00
/* Add all the main enable bits */
maccr | = FTGMAC100_MACCR_TXDMA_EN |
FTGMAC100_MACCR_RXDMA_EN |
FTGMAC100_MACCR_TXMAC_EN |
FTGMAC100_MACCR_RXMAC_EN |
FTGMAC100_MACCR_CRC_APD |
FTGMAC100_MACCR_PHY_LINK_LEVEL |
FTGMAC100_MACCR_RX_RUNT |
FTGMAC100_MACCR_RX_BROADPKT ;
2011-06-08 23:32:48 +00:00
2017-04-05 12:28:51 +10:00
/* Add other bits as needed */
2017-04-05 12:28:45 +10:00
if ( priv - > cur_duplex = = DUPLEX_FULL )
maccr | = FTGMAC100_MACCR_FULLDUP ;
2017-04-05 12:28:51 +10:00
/* Hit the HW */
2011-06-08 23:32:48 +00:00
iowrite32 ( maccr , priv - > base + FTGMAC100_OFFSET_MACCR ) ;
}
static void ftgmac100_stop_hw ( struct ftgmac100 * priv )
{
iowrite32 ( 0 , priv - > base + FTGMAC100_OFFSET_MACCR ) ;
}
2017-04-06 11:02:49 +10:00
static int ftgmac100_alloc_rx_buf ( struct ftgmac100 * priv , unsigned int entry ,
struct ftgmac100_rxdes * rxdes , gfp_t gfp )
2017-04-06 11:02:43 +10:00
{
struct net_device * netdev = priv - > netdev ;
2017-04-06 11:02:49 +10:00
struct sk_buff * skb ;
2017-04-06 11:02:43 +10:00
dma_addr_t map ;
2017-04-06 11:02:45 +10:00
int err ;
2017-04-06 11:02:43 +10:00
2017-04-06 11:02:49 +10:00
skb = netdev_alloc_skb_ip_align ( netdev , RX_BUF_SIZE ) ;
if ( unlikely ( ! skb ) ) {
2017-04-06 11:02:43 +10:00
if ( net_ratelimit ( ) )
2017-04-06 11:02:49 +10:00
netdev_warn ( netdev , " failed to allocate rx skb \n " ) ;
2017-04-06 11:02:45 +10:00
err = - ENOMEM ;
map = priv - > rx_scratch_dma ;
2017-04-06 11:02:49 +10:00
} else {
map = dma_map_single ( priv - > dev , skb - > data , RX_BUF_SIZE ,
DMA_FROM_DEVICE ) ;
if ( unlikely ( dma_mapping_error ( priv - > dev , map ) ) ) {
if ( net_ratelimit ( ) )
netdev_err ( netdev , " failed to map rx page \n " ) ;
dev_kfree_skb_any ( skb ) ;
map = priv - > rx_scratch_dma ;
skb = NULL ;
err = - ENOMEM ;
}
2017-04-06 11:02:43 +10:00
}
2017-04-06 11:02:49 +10:00
/* Store skb */
priv - > rx_skbs [ entry ] = skb ;
2017-04-06 11:02:43 +10:00
2017-04-06 11:02:49 +10:00
/* Store DMA address into RX desc */
2017-04-06 11:02:51 +10:00
rxdes - > rxdes3 = cpu_to_le32 ( map ) ;
2017-04-06 11:02:49 +10:00
/* Ensure the above is ordered vs clearing the OWN bit */
dma_wmb ( ) ;
2017-04-06 11:02:51 +10:00
/* Clean status (which resets own bit) */
if ( entry = = ( RX_QUEUE_ENTRIES - 1 ) )
rxdes - > rxdes0 = cpu_to_le32 ( priv - > rxdes0_edorr_mask ) ;
else
rxdes - > rxdes0 = 0 ;
2017-04-06 11:02:49 +10:00
2017-04-06 11:02:43 +10:00
return 0 ;
}
2011-06-08 23:32:48 +00:00
static int ftgmac100_next_rx_pointer ( int pointer )
{
return ( pointer + 1 ) & ( RX_QUEUE_ENTRIES - 1 ) ;
}
2017-04-06 11:02:51 +10:00
static void ftgmac100_rx_packet_error ( struct ftgmac100 * priv , u32 status )
2011-06-08 23:32:48 +00:00
{
struct net_device * netdev = priv - > netdev ;
2017-04-06 11:02:51 +10:00
if ( status & FTGMAC100_RXDES0_RX_ERR )
2011-06-08 23:32:48 +00:00
netdev - > stats . rx_errors + + ;
2017-04-06 11:02:51 +10:00
if ( status & FTGMAC100_RXDES0_CRC_ERR )
2011-06-08 23:32:48 +00:00
netdev - > stats . rx_crc_errors + + ;
2017-04-06 11:02:51 +10:00
if ( status & ( FTGMAC100_RXDES0_FTL |
FTGMAC100_RXDES0_RUNT |
FTGMAC100_RXDES0_RX_ODD_NB ) )
2011-06-08 23:32:48 +00:00
netdev - > stats . rx_length_errors + + ;
}
static bool ftgmac100_rx_packet ( struct ftgmac100 * priv , int * processed )
{
struct net_device * netdev = priv - > netdev ;
struct ftgmac100_rxdes * rxdes ;
struct sk_buff * skb ;
2017-04-06 11:02:48 +10:00
unsigned int pointer , size ;
2017-04-06 11:02:52 +10:00
u32 status , csum_vlan ;
2017-04-06 11:02:44 +10:00
dma_addr_t map ;
2011-06-08 23:32:48 +00:00
2017-04-06 11:02:48 +10:00
/* Grab next RX descriptor */
pointer = priv - > rx_pointer ;
rxdes = & priv - > descs - > rxdes [ pointer ] ;
2017-04-06 11:02:51 +10:00
/* Grab descriptor status */
status = le32_to_cpu ( rxdes - > rxdes0 ) ;
2017-04-06 11:02:48 +10:00
/* Do we have a packet ? */
2017-04-06 11:02:51 +10:00
if ( ! ( status & FTGMAC100_RXDES0_RXPKT_RDY ) )
2011-06-08 23:32:48 +00:00
return false ;
2017-04-06 11:02:50 +10:00
/* Order subsequent reads with the test for the ready bit */
dma_rmb ( ) ;
2017-04-06 11:02:48 +10:00
/* We don't cope with fragmented RX packets */
2017-04-06 11:02:51 +10:00
if ( unlikely ( ! ( status & FTGMAC100_RXDES0_FRS ) | |
! ( status & FTGMAC100_RXDES0_LRS ) ) )
2017-04-06 11:02:48 +10:00
goto drop ;
2017-04-06 11:02:52 +10:00
/* Grab received size and csum vlan field in the descriptor */
size = status & FTGMAC100_RXDES0_VDBC ;
csum_vlan = le32_to_cpu ( rxdes - > rxdes1 ) ;
2017-04-06 11:02:48 +10:00
/* Any error (other than csum offload) flagged ? */
2017-04-06 11:02:51 +10:00
if ( unlikely ( status & RXDES0_ANY_ERROR ) ) {
2017-04-06 11:02:52 +10:00
/* Correct for incorrect flagging of runt packets
* with vlan tags . . . Just accept a runt packet that
* has been flagged as vlan and whose size is at
* least 60 bytes .
*/
if ( ( status & FTGMAC100_RXDES0_RUNT ) & &
( csum_vlan & FTGMAC100_RXDES1_VLANTAG_AVAIL ) & &
( size > = 60 ) )
status & = ~ FTGMAC100_RXDES0_RUNT ;
/* Any error still in there ? */
if ( status & RXDES0_ANY_ERROR ) {
ftgmac100_rx_packet_error ( priv , status ) ;
goto drop ;
}
2011-06-08 23:32:48 +00:00
}
2017-04-06 11:02:49 +10:00
/* If the packet had no skb (failed to allocate earlier)
2017-04-06 11:02:45 +10:00
* then try to allocate one and skip
*/
2017-04-06 11:02:49 +10:00
skb = priv - > rx_skbs [ pointer ] ;
if ( ! unlikely ( skb ) ) {
ftgmac100_alloc_rx_buf ( priv , pointer , rxdes , GFP_ATOMIC ) ;
2017-04-06 11:02:48 +10:00
goto drop ;
2011-06-08 23:32:48 +00:00
}
2017-04-06 11:02:51 +10:00
if ( unlikely ( status & FTGMAC100_RXDES0_MULTICAST ) )
2011-06-08 23:32:48 +00:00
netdev - > stats . multicast + + ;
2017-04-06 11:02:46 +10:00
/* If the HW found checksum errors, bounce it to software.
*
* If we didn ' t , we need to see if the packet was recognized
* by HW as one of the supported checksummed protocols before
* we accept the HW test results .
2011-06-08 23:32:48 +00:00
*/
2017-04-06 11:02:46 +10:00
if ( netdev - > features & NETIF_F_RXCSUM ) {
2017-04-06 11:02:52 +10:00
u32 err_bits = FTGMAC100_RXDES1_TCP_CHKSUM_ERR |
FTGMAC100_RXDES1_UDP_CHKSUM_ERR |
FTGMAC100_RXDES1_IP_CHKSUM_ERR ;
2017-04-06 11:02:46 +10:00
if ( ( csum_vlan & err_bits ) | |
2017-04-06 11:02:52 +10:00
! ( csum_vlan & FTGMAC100_RXDES1_PROT_MASK ) )
2017-04-06 11:02:46 +10:00
skb - > ip_summed = CHECKSUM_NONE ;
else
skb - > ip_summed = CHECKSUM_UNNECESSARY ;
}
2011-06-08 23:32:48 +00:00
2017-04-06 11:02:52 +10:00
/* Transfer received size to skb */
2017-04-06 11:02:49 +10:00
skb_put ( skb , size ) ;
2011-06-08 23:32:48 +00:00
2017-04-06 11:02:49 +10:00
/* Tear down DMA mapping, do necessary cache management */
2017-04-06 11:02:51 +10:00
map = le32_to_cpu ( rxdes - > rxdes3 ) ;
2017-04-06 11:02:49 +10:00
# if defined(CONFIG_ARM) && !defined(CONFIG_ARM_DMA_USE_IOMMU)
/* When we don't have an iommu, we can save cycles by not
* invalidating the cache for the part of the packet that
* wasn ' t received .
*/
dma_unmap_single ( priv - > dev , map , size , DMA_FROM_DEVICE ) ;
# else
dma_unmap_single ( priv - > dev , map , RX_BUF_SIZE , DMA_FROM_DEVICE ) ;
# endif
2011-06-08 23:32:48 +00:00
2017-04-06 11:02:49 +10:00
/* Resplenish rx ring */
ftgmac100_alloc_rx_buf ( priv , pointer , rxdes , GFP_ATOMIC ) ;
2017-04-06 11:02:48 +10:00
priv - > rx_pointer = ftgmac100_next_rx_pointer ( pointer ) ;
2011-06-08 23:32:48 +00:00
skb - > protocol = eth_type_trans ( skb , netdev ) ;
netdev - > stats . rx_packets + + ;
2017-04-06 11:02:49 +10:00
netdev - > stats . rx_bytes + = size ;
2011-06-08 23:32:48 +00:00
/* push packet to protocol stack */
2017-04-06 11:02:46 +10:00
if ( skb - > ip_summed = = CHECKSUM_NONE )
netif_receive_skb ( skb ) ;
else
napi_gro_receive ( & priv - > napi , skb ) ;
2011-06-08 23:32:48 +00:00
( * processed ) + + ;
return true ;
2017-04-06 11:02:48 +10:00
drop :
/* Clean rxdes0 (which resets own bit) */
2017-04-06 11:02:51 +10:00
rxdes - > rxdes0 = cpu_to_le32 ( status & priv - > rxdes0_edorr_mask ) ;
2017-04-06 11:02:48 +10:00
priv - > rx_pointer = ftgmac100_next_rx_pointer ( pointer ) ;
netdev - > stats . rx_dropped + + ;
return true ;
2011-06-08 23:32:48 +00:00
}
2016-09-22 08:34:59 +09:30
static void ftgmac100_txdes_reset ( const struct ftgmac100 * priv ,
struct ftgmac100_txdes * txdes )
2011-06-08 23:32:48 +00:00
{
/* clear all except end of ring bit */
2016-09-22 08:34:59 +09:30
txdes - > txdes0 & = cpu_to_le32 ( priv - > txdes0_edotr_mask ) ;
2011-06-08 23:32:48 +00:00
txdes - > txdes1 = 0 ;
txdes - > txdes2 = 0 ;
txdes - > txdes3 = 0 ;
}
static bool ftgmac100_txdes_owned_by_dma ( struct ftgmac100_txdes * txdes )
{
return txdes - > txdes0 & cpu_to_le32 ( FTGMAC100_TXDES0_TXDMA_OWN ) ;
}
static void ftgmac100_txdes_set_dma_own ( struct ftgmac100_txdes * txdes )
{
/*
* Make sure dma own bit will not be set before any other
* descriptor fields .
*/
wmb ( ) ;
txdes - > txdes0 | = cpu_to_le32 ( FTGMAC100_TXDES0_TXDMA_OWN ) ;
}
2016-09-22 08:34:59 +09:30
static void ftgmac100_txdes_set_end_of_ring ( const struct ftgmac100 * priv ,
struct ftgmac100_txdes * txdes )
2011-06-08 23:32:48 +00:00
{
2016-09-22 08:34:59 +09:30
txdes - > txdes0 | = cpu_to_le32 ( priv - > txdes0_edotr_mask ) ;
2011-06-08 23:32:48 +00:00
}
static void ftgmac100_txdes_set_first_segment ( struct ftgmac100_txdes * txdes )
{
txdes - > txdes0 | = cpu_to_le32 ( FTGMAC100_TXDES0_FTS ) ;
}
static void ftgmac100_txdes_set_last_segment ( struct ftgmac100_txdes * txdes )
{
txdes - > txdes0 | = cpu_to_le32 ( FTGMAC100_TXDES0_LTS ) ;
}
static void ftgmac100_txdes_set_buffer_size ( struct ftgmac100_txdes * txdes ,
unsigned int len )
{
txdes - > txdes0 | = cpu_to_le32 ( FTGMAC100_TXDES0_TXBUF_SIZE ( len ) ) ;
}
static void ftgmac100_txdes_set_txint ( struct ftgmac100_txdes * txdes )
{
txdes - > txdes1 | = cpu_to_le32 ( FTGMAC100_TXDES1_TXIC ) ;
}
static void ftgmac100_txdes_set_tcpcs ( struct ftgmac100_txdes * txdes )
{
txdes - > txdes1 | = cpu_to_le32 ( FTGMAC100_TXDES1_TCP_CHKSUM ) ;
}
static void ftgmac100_txdes_set_udpcs ( struct ftgmac100_txdes * txdes )
{
txdes - > txdes1 | = cpu_to_le32 ( FTGMAC100_TXDES1_UDP_CHKSUM ) ;
}
static void ftgmac100_txdes_set_ipcs ( struct ftgmac100_txdes * txdes )
{
txdes - > txdes1 | = cpu_to_le32 ( FTGMAC100_TXDES1_IP_CHKSUM ) ;
}
static void ftgmac100_txdes_set_dma_addr ( struct ftgmac100_txdes * txdes ,
dma_addr_t addr )
{
txdes - > txdes3 = cpu_to_le32 ( addr ) ;
}
static dma_addr_t ftgmac100_txdes_get_dma_addr ( struct ftgmac100_txdes * txdes )
{
return le32_to_cpu ( txdes - > txdes3 ) ;
}
static int ftgmac100_next_tx_pointer ( int pointer )
{
return ( pointer + 1 ) & ( TX_QUEUE_ENTRIES - 1 ) ;
}
static bool ftgmac100_tx_complete_packet ( struct ftgmac100 * priv )
{
struct net_device * netdev = priv - > netdev ;
struct ftgmac100_txdes * txdes ;
2017-04-10 11:15:20 +10:00
unsigned int pointer ;
2011-06-08 23:32:48 +00:00
struct sk_buff * skb ;
dma_addr_t map ;
if ( priv - > tx_pending = = 0 )
return false ;
2017-04-10 11:15:20 +10:00
pointer = priv - > tx_clean_pointer ;
txdes = & priv - > descs - > txdes [ pointer ] ;
2011-06-08 23:32:48 +00:00
if ( ftgmac100_txdes_owned_by_dma ( txdes ) )
return false ;
2017-04-10 11:15:20 +10:00
skb = priv - > tx_skbs [ pointer ] ;
2011-06-08 23:32:48 +00:00
map = ftgmac100_txdes_get_dma_addr ( txdes ) ;
netdev - > stats . tx_packets + + ;
netdev - > stats . tx_bytes + = skb - > len ;
dma_unmap_single ( priv - > dev , map , skb_headlen ( skb ) , DMA_TO_DEVICE ) ;
dev_kfree_skb ( skb ) ;
2017-04-10 11:15:20 +10:00
priv - > tx_skbs [ pointer ] = NULL ;
2011-06-08 23:32:48 +00:00
2016-09-22 08:34:59 +09:30
ftgmac100_txdes_reset ( priv , txdes ) ;
2011-06-08 23:32:48 +00:00
2017-04-10 11:15:20 +10:00
priv - > tx_clean_pointer = ftgmac100_next_tx_pointer ( pointer ) ;
2011-06-08 23:32:48 +00:00
spin_lock ( & priv - > tx_lock ) ;
priv - > tx_pending - - ;
spin_unlock ( & priv - > tx_lock ) ;
netif_wake_queue ( netdev ) ;
return true ;
}
static void ftgmac100_tx_complete ( struct ftgmac100 * priv )
{
while ( ftgmac100_tx_complete_packet ( priv ) )
;
}
2017-04-10 11:15:17 +10:00
static int ftgmac100_hard_start_xmit ( struct sk_buff * skb ,
struct net_device * netdev )
2011-06-08 23:32:48 +00:00
{
2017-04-10 11:15:17 +10:00
struct ftgmac100 * priv = netdev_priv ( netdev ) ;
struct ftgmac100_txdes * txdes ;
2017-04-10 11:15:20 +10:00
unsigned int pointer ;
2017-04-10 11:15:17 +10:00
dma_addr_t map ;
2017-04-10 11:15:19 +10:00
/* The HW doesn't pad small frames */
if ( eth_skb_pad ( skb ) ) {
netdev - > stats . tx_dropped + + ;
return NETDEV_TX_OK ;
}
/* Reject oversize packets */
2017-04-10 11:15:17 +10:00
if ( unlikely ( skb - > len > MAX_PKT_SIZE ) ) {
if ( net_ratelimit ( ) )
netdev_dbg ( netdev , " tx packet too big \n " ) ;
2017-04-10 11:15:18 +10:00
goto drop ;
2017-04-10 11:15:17 +10:00
}
map = dma_map_single ( priv - > dev , skb - > data , skb_headlen ( skb ) , DMA_TO_DEVICE ) ;
if ( unlikely ( dma_mapping_error ( priv - > dev , map ) ) ) {
/* drop packet */
if ( net_ratelimit ( ) )
netdev_err ( netdev , " map socket buffer failed \n " ) ;
2017-04-10 11:15:18 +10:00
goto drop ;
2017-04-10 11:15:17 +10:00
}
2011-06-08 23:32:48 +00:00
2017-04-10 11:15:20 +10:00
/* Grab the next free tx descriptor */
pointer = priv - > tx_pointer ;
txdes = & priv - > descs - > txdes [ pointer ] ;
2011-06-08 23:32:48 +00:00
/* setup TX descriptor */
2017-04-10 11:15:20 +10:00
priv - > tx_skbs [ pointer ] = skb ;
2011-06-08 23:32:48 +00:00
ftgmac100_txdes_set_dma_addr ( txdes , map ) ;
2017-04-10 11:15:19 +10:00
ftgmac100_txdes_set_buffer_size ( txdes , skb - > len ) ;
2011-06-08 23:32:48 +00:00
ftgmac100_txdes_set_first_segment ( txdes ) ;
ftgmac100_txdes_set_last_segment ( txdes ) ;
ftgmac100_txdes_set_txint ( txdes ) ;
if ( skb - > ip_summed = = CHECKSUM_PARTIAL ) {
__be16 protocol = skb - > protocol ;
if ( protocol = = cpu_to_be16 ( ETH_P_IP ) ) {
u8 ip_proto = ip_hdr ( skb ) - > protocol ;
ftgmac100_txdes_set_ipcs ( txdes ) ;
if ( ip_proto = = IPPROTO_TCP )
ftgmac100_txdes_set_tcpcs ( txdes ) ;
else if ( ip_proto = = IPPROTO_UDP )
ftgmac100_txdes_set_udpcs ( txdes ) ;
}
}
2017-04-10 11:15:20 +10:00
/* Update next TX pointer */
priv - > tx_pointer = ftgmac100_next_tx_pointer ( pointer ) ;
2011-06-08 23:32:48 +00:00
spin_lock ( & priv - > tx_lock ) ;
priv - > tx_pending + + ;
if ( priv - > tx_pending = = TX_QUEUE_ENTRIES )
netif_stop_queue ( netdev ) ;
/* start transmit */
ftgmac100_txdes_set_dma_own ( txdes ) ;
spin_unlock ( & priv - > tx_lock ) ;
ftgmac100_txdma_normal_prio_start_polling ( priv ) ;
2017-04-10 11:15:18 +10:00
return NETDEV_TX_OK ;
drop :
/* Drop the packet */
dev_kfree_skb_any ( skb ) ;
netdev - > stats . tx_dropped + + ;
2011-06-08 23:32:48 +00:00
return NETDEV_TX_OK ;
}
static void ftgmac100_free_buffers ( struct ftgmac100 * priv )
{
int i ;
2017-04-05 12:28:46 +10:00
/* Free all RX buffers */
2011-06-08 23:32:48 +00:00
for ( i = 0 ; i < RX_QUEUE_ENTRIES ; i + + ) {
struct ftgmac100_rxdes * rxdes = & priv - > descs - > rxdes [ i ] ;
2017-04-06 11:02:49 +10:00
struct sk_buff * skb = priv - > rx_skbs [ i ] ;
2017-04-06 11:02:51 +10:00
dma_addr_t map = le32_to_cpu ( rxdes - > rxdes3 ) ;
2011-06-08 23:32:48 +00:00
2017-04-06 11:02:49 +10:00
if ( ! skb )
2011-06-08 23:32:48 +00:00
continue ;
2017-04-06 11:02:49 +10:00
priv - > rx_skbs [ i ] = NULL ;
dma_unmap_single ( priv - > dev , map , RX_BUF_SIZE , DMA_FROM_DEVICE ) ;
dev_kfree_skb_any ( skb ) ;
2011-06-08 23:32:48 +00:00
}
2017-04-05 12:28:46 +10:00
/* Free all TX buffers */
2011-06-08 23:32:48 +00:00
for ( i = 0 ; i < TX_QUEUE_ENTRIES ; i + + ) {
struct ftgmac100_txdes * txdes = & priv - > descs - > txdes [ i ] ;
2017-04-10 11:15:20 +10:00
struct sk_buff * skb = priv - > tx_skbs [ i ] ;
2011-06-08 23:32:48 +00:00
dma_addr_t map = ftgmac100_txdes_get_dma_addr ( txdes ) ;
if ( ! skb )
continue ;
dma_unmap_single ( priv - > dev , map , skb_headlen ( skb ) , DMA_TO_DEVICE ) ;
2014-01-16 23:38:24 -08:00
kfree_skb ( skb ) ;
2011-06-08 23:32:48 +00:00
}
}
2017-04-05 12:28:46 +10:00
static void ftgmac100_free_rings ( struct ftgmac100 * priv )
2011-06-08 23:32:48 +00:00
{
2017-04-05 12:28:46 +10:00
/* Free descriptors */
if ( priv - > descs )
dma_free_coherent ( priv - > dev , sizeof ( struct ftgmac100_descs ) ,
priv - > descs , priv - > descs_dma_addr ) ;
2017-04-06 11:02:45 +10:00
/* Free scratch packet buffer */
if ( priv - > rx_scratch )
dma_free_coherent ( priv - > dev , RX_BUF_SIZE ,
priv - > rx_scratch , priv - > rx_scratch_dma ) ;
2017-04-05 12:28:46 +10:00
}
2011-06-08 23:32:48 +00:00
2017-04-05 12:28:46 +10:00
static int ftgmac100_alloc_rings ( struct ftgmac100 * priv )
{
/* Allocate descriptors */
2013-08-26 22:45:23 -07:00
priv - > descs = dma_zalloc_coherent ( priv - > dev ,
sizeof ( struct ftgmac100_descs ) ,
& priv - > descs_dma_addr , GFP_KERNEL ) ;
2011-06-08 23:32:48 +00:00
if ( ! priv - > descs )
return - ENOMEM ;
2017-04-06 11:02:45 +10:00
/* Allocate scratch packet buffer */
priv - > rx_scratch = dma_alloc_coherent ( priv - > dev ,
RX_BUF_SIZE ,
& priv - > rx_scratch_dma ,
GFP_KERNEL ) ;
if ( ! priv - > rx_scratch )
return - ENOMEM ;
2017-04-05 12:28:46 +10:00
return 0 ;
}
static void ftgmac100_init_rings ( struct ftgmac100 * priv )
{
2017-04-06 11:02:51 +10:00
struct ftgmac100_rxdes * rxdes ;
2017-04-05 12:28:46 +10:00
int i ;
/* Initialize RX ring */
2017-04-06 11:02:45 +10:00
for ( i = 0 ; i < RX_QUEUE_ENTRIES ; i + + ) {
2017-04-06 11:02:51 +10:00
rxdes = & priv - > descs - > rxdes [ i ] ;
2017-04-06 11:02:45 +10:00
rxdes - > rxdes0 = 0 ;
2017-04-06 11:02:51 +10:00
rxdes - > rxdes3 = cpu_to_le32 ( priv - > rx_scratch_dma ) ;
2017-04-06 11:02:45 +10:00
}
2017-04-06 11:02:51 +10:00
/* Mark the end of the ring */
rxdes - > rxdes0 | = cpu_to_le32 ( priv - > rxdes0_edorr_mask ) ;
2017-04-05 12:28:46 +10:00
/* Initialize TX ring */
for ( i = 0 ; i < TX_QUEUE_ENTRIES ; i + + )
priv - > descs - > txdes [ i ] . txdes0 = 0 ;
ftgmac100_txdes_set_end_of_ring ( priv , & priv - > descs - > txdes [ i - 1 ] ) ;
}
static int ftgmac100_alloc_rx_buffers ( struct ftgmac100 * priv )
{
int i ;
2011-06-08 23:32:48 +00:00
for ( i = 0 ; i < RX_QUEUE_ENTRIES ; i + + ) {
struct ftgmac100_rxdes * rxdes = & priv - > descs - > rxdes [ i ] ;
2017-04-06 11:02:49 +10:00
if ( ftgmac100_alloc_rx_buf ( priv , i , rxdes , GFP_KERNEL ) )
2017-04-05 12:28:46 +10:00
return - ENOMEM ;
2011-06-08 23:32:48 +00:00
}
return 0 ;
}
static void ftgmac100_adjust_link ( struct net_device * netdev )
{
struct ftgmac100 * priv = netdev_priv ( netdev ) ;
2016-05-16 01:35:13 +02:00
struct phy_device * phydev = netdev - > phydev ;
2017-04-05 12:28:45 +10:00
int new_speed ;
2011-06-08 23:32:48 +00:00
2017-04-05 12:28:45 +10:00
/* We store "no link" as speed 0 */
if ( ! phydev - > link )
new_speed = 0 ;
else
new_speed = phydev - > speed ;
if ( phydev - > speed = = priv - > cur_speed & &
phydev - > duplex = = priv - > cur_duplex )
2011-06-08 23:32:48 +00:00
return ;
2017-04-05 12:28:45 +10:00
/* Print status if we have a link or we had one and just lost it,
* don ' t print otherwise .
*/
if ( new_speed | | priv - > cur_speed )
phy_print_status ( phydev ) ;
priv - > cur_speed = new_speed ;
priv - > cur_duplex = phydev - > duplex ;
/* Link is down, do nothing else */
if ( ! new_speed )
return ;
2011-06-08 23:32:48 +00:00
2017-04-05 12:28:50 +10:00
/* Disable all interrupts */
2011-06-08 23:32:48 +00:00
iowrite32 ( 0 , priv - > base + FTGMAC100_OFFSET_IER ) ;
2017-04-05 12:28:50 +10:00
/* Reset the adapter asynchronously */
schedule_work ( & priv - > reset_task ) ;
2011-06-08 23:32:48 +00:00
}
static int ftgmac100_mii_probe ( struct ftgmac100 * priv )
{
struct net_device * netdev = priv - > netdev ;
2016-01-10 12:04:32 -08:00
struct phy_device * phydev ;
2011-06-08 23:32:48 +00:00
2016-01-10 12:04:32 -08:00
phydev = phy_find_first ( priv - > mii_bus ) ;
2011-06-08 23:32:48 +00:00
if ( ! phydev ) {
netdev_info ( netdev , " %s: no PHY found \n " , netdev - > name ) ;
return - ENODEV ;
}
2016-01-06 20:11:10 +01:00
phydev = phy_connect ( netdev , phydev_name ( phydev ) ,
2013-01-14 00:52:52 +00:00
& ftgmac100_adjust_link , PHY_INTERFACE_MODE_GMII ) ;
2011-06-08 23:32:48 +00:00
if ( IS_ERR ( phydev ) ) {
netdev_err ( netdev , " %s: Could not attach to PHY \n " , netdev - > name ) ;
return PTR_ERR ( phydev ) ;
}
return 0 ;
}
static int ftgmac100_mdiobus_read ( struct mii_bus * bus , int phy_addr , int regnum )
{
struct net_device * netdev = bus - > priv ;
struct ftgmac100 * priv = netdev_priv ( netdev ) ;
unsigned int phycr ;
int i ;
phycr = ioread32 ( priv - > base + FTGMAC100_OFFSET_PHYCR ) ;
/* preserve MDC cycle threshold */
phycr & = FTGMAC100_PHYCR_MDC_CYCTHR_MASK ;
phycr | = FTGMAC100_PHYCR_PHYAD ( phy_addr ) |
FTGMAC100_PHYCR_REGAD ( regnum ) |
FTGMAC100_PHYCR_MIIRD ;
iowrite32 ( phycr , priv - > base + FTGMAC100_OFFSET_PHYCR ) ;
for ( i = 0 ; i < 10 ; i + + ) {
phycr = ioread32 ( priv - > base + FTGMAC100_OFFSET_PHYCR ) ;
if ( ( phycr & FTGMAC100_PHYCR_MIIRD ) = = 0 ) {
int data ;
data = ioread32 ( priv - > base + FTGMAC100_OFFSET_PHYDATA ) ;
return FTGMAC100_PHYDATA_MIIRDATA ( data ) ;
}
udelay ( 100 ) ;
}
netdev_err ( netdev , " mdio read timed out \n " ) ;
return - EIO ;
}
static int ftgmac100_mdiobus_write ( struct mii_bus * bus , int phy_addr ,
int regnum , u16 value )
{
struct net_device * netdev = bus - > priv ;
struct ftgmac100 * priv = netdev_priv ( netdev ) ;
unsigned int phycr ;
int data ;
int i ;
phycr = ioread32 ( priv - > base + FTGMAC100_OFFSET_PHYCR ) ;
/* preserve MDC cycle threshold */
phycr & = FTGMAC100_PHYCR_MDC_CYCTHR_MASK ;
phycr | = FTGMAC100_PHYCR_PHYAD ( phy_addr ) |
FTGMAC100_PHYCR_REGAD ( regnum ) |
FTGMAC100_PHYCR_MIIWR ;
data = FTGMAC100_PHYDATA_MIIWDATA ( value ) ;
iowrite32 ( data , priv - > base + FTGMAC100_OFFSET_PHYDATA ) ;
iowrite32 ( phycr , priv - > base + FTGMAC100_OFFSET_PHYCR ) ;
for ( i = 0 ; i < 10 ; i + + ) {
phycr = ioread32 ( priv - > base + FTGMAC100_OFFSET_PHYCR ) ;
if ( ( phycr & FTGMAC100_PHYCR_MIIWR ) = = 0 )
return 0 ;
udelay ( 100 ) ;
}
netdev_err ( netdev , " mdio write timed out \n " ) ;
return - EIO ;
}
static void ftgmac100_get_drvinfo ( struct net_device * netdev ,
struct ethtool_drvinfo * info )
{
2013-01-06 00:44:26 +00:00
strlcpy ( info - > driver , DRV_NAME , sizeof ( info - > driver ) ) ;
strlcpy ( info - > version , DRV_VERSION , sizeof ( info - > version ) ) ;
strlcpy ( info - > bus_info , dev_name ( & netdev - > dev ) , sizeof ( info - > bus_info ) ) ;
2011-06-08 23:32:48 +00:00
}
static const struct ethtool_ops ftgmac100_ethtool_ops = {
. get_drvinfo = ftgmac100_get_drvinfo ,
. get_link = ethtool_op_get_link ,
2016-05-16 01:35:14 +02:00
. get_link_ksettings = phy_ethtool_get_link_ksettings ,
. set_link_ksettings = phy_ethtool_set_link_ksettings ,
2011-06-08 23:32:48 +00:00
} ;
static irqreturn_t ftgmac100_interrupt ( int irq , void * dev_id )
{
struct net_device * netdev = dev_id ;
struct ftgmac100 * priv = netdev_priv ( netdev ) ;
2017-04-05 12:28:53 +10:00
unsigned int status , new_mask = FTGMAC100_INT_BAD ;
2011-06-08 23:32:48 +00:00
2017-04-05 12:28:53 +10:00
/* Fetch and clear interrupt bits, process abnormal ones */
status = ioread32 ( priv - > base + FTGMAC100_OFFSET_ISR ) ;
iowrite32 ( status , priv - > base + FTGMAC100_OFFSET_ISR ) ;
if ( unlikely ( status & FTGMAC100_INT_BAD ) ) {
/* RX buffer unavailable */
if ( status & FTGMAC100_INT_NO_RXBUF )
netdev - > stats . rx_over_errors + + ;
/* received packet lost due to RX FIFO full */
if ( status & FTGMAC100_INT_RPKT_LOST )
netdev - > stats . rx_fifo_errors + + ;
/* sent packet lost due to excessive TX collision */
if ( status & FTGMAC100_INT_XPKT_LOST )
netdev - > stats . tx_fifo_errors + + ;
/* AHB error -> Reset the chip */
if ( status & FTGMAC100_INT_AHB_ERR ) {
if ( net_ratelimit ( ) )
netdev_warn ( netdev ,
" AHB bus error ! Resetting chip. \n " ) ;
iowrite32 ( 0 , priv - > base + FTGMAC100_OFFSET_IER ) ;
schedule_work ( & priv - > reset_task ) ;
return IRQ_HANDLED ;
}
/* We may need to restart the MAC after such errors, delay
* this until after we have freed some Rx buffers though
*/
priv - > need_mac_restart = true ;
/* Disable those errors until we restart */
new_mask & = ~ status ;
}
/* Only enable "bad" interrupts while NAPI is on */
iowrite32 ( new_mask , priv - > base + FTGMAC100_OFFSET_IER ) ;
/* Schedule NAPI bh */
napi_schedule_irqoff ( & priv - > napi ) ;
2011-06-08 23:32:48 +00:00
return IRQ_HANDLED ;
}
2017-04-06 11:02:51 +10:00
static bool ftgmac100_check_rx ( struct ftgmac100 * priv )
{
struct ftgmac100_rxdes * rxdes = & priv - > descs - > rxdes [ priv - > rx_pointer ] ;
/* Do we have a packet ? */
return ! ! ( rxdes - > rxdes0 & cpu_to_le32 ( FTGMAC100_RXDES0_RXPKT_RDY ) ) ;
}
2011-06-08 23:32:48 +00:00
static int ftgmac100_poll ( struct napi_struct * napi , int budget )
{
struct ftgmac100 * priv = container_of ( napi , struct ftgmac100 , napi ) ;
2017-04-05 12:28:53 +10:00
bool more , completed = true ;
2011-06-08 23:32:48 +00:00
int rx = 0 ;
2017-04-05 12:28:53 +10:00
ftgmac100_tx_complete ( priv ) ;
2011-06-08 23:32:48 +00:00
2017-04-05 12:28:53 +10:00
do {
more = ftgmac100_rx_packet ( priv , & rx ) ;
} while ( more & & rx < budget ) ;
2011-06-08 23:32:48 +00:00
2017-04-05 12:28:53 +10:00
if ( more & & rx = = budget )
completed = false ;
2011-06-08 23:32:48 +00:00
2017-04-05 12:28:53 +10:00
/* The interrupt is telling us to kick the MAC back to life
* after an RX overflow
*/
if ( unlikely ( priv - > need_mac_restart ) ) {
ftgmac100_start_hw ( priv ) ;
2011-06-08 23:32:48 +00:00
2017-04-05 12:28:53 +10:00
/* Re-enable "bad" interrupts */
iowrite32 ( FTGMAC100_INT_BAD ,
priv - > base + FTGMAC100_OFFSET_IER ) ;
2011-06-08 23:32:48 +00:00
}
2017-04-05 12:28:53 +10:00
/* Keep NAPI going if we have still packets to reclaim */
if ( priv - > tx_pending )
return budget ;
2011-06-08 23:32:48 +00:00
if ( completed ) {
2017-04-05 12:28:53 +10:00
/* We are about to re-enable all interrupts. However
* the HW has been latching RX / TX packet interrupts while
* they were masked . So we clear them first , then we need
* to re - check if there ' s something to process
*/
iowrite32 ( FTGMAC100_INT_RXTX ,
priv - > base + FTGMAC100_OFFSET_ISR ) ;
2017-04-06 11:02:51 +10:00
if ( ftgmac100_check_rx ( priv ) | | priv - > tx_pending )
2017-04-05 12:28:53 +10:00
return budget ;
/* deschedule NAPI */
2011-06-08 23:32:48 +00:00
napi_complete ( napi ) ;
/* enable all interrupts */
2017-04-05 12:28:53 +10:00
iowrite32 ( FTGMAC100_INT_ALL ,
2016-07-19 11:54:25 +10:00
priv - > base + FTGMAC100_OFFSET_IER ) ;
2011-06-08 23:32:48 +00:00
}
return rx ;
}
2017-04-05 12:28:49 +10:00
static int ftgmac100_init_all ( struct ftgmac100 * priv , bool ignore_alloc_err )
{
int err = 0 ;
/* Re-init descriptors (adjust queue sizes) */
ftgmac100_init_rings ( priv ) ;
/* Realloc rx descriptors */
err = ftgmac100_alloc_rx_buffers ( priv ) ;
if ( err & & ! ignore_alloc_err )
return err ;
/* Reinit and restart HW */
ftgmac100_init_hw ( priv ) ;
ftgmac100_start_hw ( priv ) ;
/* Re-enable the device */
napi_enable ( & priv - > napi ) ;
netif_start_queue ( priv - > netdev ) ;
/* Enable all interrupts */
2017-04-05 12:28:53 +10:00
iowrite32 ( FTGMAC100_INT_ALL , priv - > base + FTGMAC100_OFFSET_IER ) ;
2017-04-05 12:28:49 +10:00
return err ;
}
2017-04-05 12:28:50 +10:00
static void ftgmac100_reset_task ( struct work_struct * work )
{
struct ftgmac100 * priv = container_of ( work , struct ftgmac100 ,
reset_task ) ;
struct net_device * netdev = priv - > netdev ;
int err ;
netdev_dbg ( netdev , " Resetting NIC... \n " ) ;
/* Lock the world */
rtnl_lock ( ) ;
if ( netdev - > phydev )
mutex_lock ( & netdev - > phydev - > lock ) ;
if ( priv - > mii_bus )
mutex_lock ( & priv - > mii_bus - > mdio_lock ) ;
/* Check if the interface is still up */
if ( ! netif_running ( netdev ) )
goto bail ;
/* Stop the network stack */
netif_trans_update ( netdev ) ;
napi_disable ( & priv - > napi ) ;
netif_tx_disable ( netdev ) ;
/* Stop and reset the MAC */
ftgmac100_stop_hw ( priv ) ;
2017-04-05 12:28:51 +10:00
err = ftgmac100_reset_and_config_mac ( priv ) ;
2017-04-05 12:28:50 +10:00
if ( err ) {
/* Not much we can do ... it might come back... */
netdev_err ( netdev , " attempting to continue... \n " ) ;
}
/* Free all rx and tx buffers */
ftgmac100_free_buffers ( priv ) ;
/* Setup everything again and restart chip */
ftgmac100_init_all ( priv , true ) ;
netdev_dbg ( netdev , " Reset done ! \n " ) ;
bail :
if ( priv - > mii_bus )
mutex_unlock ( & priv - > mii_bus - > mdio_lock ) ;
if ( netdev - > phydev )
mutex_unlock ( & netdev - > phydev - > lock ) ;
rtnl_unlock ( ) ;
}
2011-06-08 23:32:48 +00:00
static int ftgmac100_open ( struct net_device * netdev )
{
struct ftgmac100 * priv = netdev_priv ( netdev ) ;
int err ;
2017-04-05 12:28:46 +10:00
/* Allocate ring buffers */
err = ftgmac100_alloc_rings ( priv ) ;
2011-06-08 23:32:48 +00:00
if ( err ) {
2017-04-05 12:28:46 +10:00
netdev_err ( netdev , " Failed to allocate descriptors \n " ) ;
return err ;
2011-06-08 23:32:48 +00:00
}
2017-04-05 12:28:45 +10:00
/* When using NC-SI we force the speed to 100Mbit/s full duplex,
*
* Otherwise we leave it set to 0 ( no link ) , the link
* message from the PHY layer will handle setting it up to
* something else if needed .
*/
if ( priv - > use_ncsi ) {
priv - > cur_duplex = DUPLEX_FULL ;
priv - > cur_speed = SPEED_100 ;
} else {
priv - > cur_duplex = 0 ;
priv - > cur_speed = 0 ;
}
2017-04-05 12:28:51 +10:00
/* Reset the hardware */
err = ftgmac100_reset_and_config_mac ( priv ) ;
2011-06-08 23:32:48 +00:00
if ( err )
goto err_hw ;
2017-04-05 12:28:47 +10:00
/* Initialize NAPI */
netif_napi_add ( netdev , & priv - > napi , ftgmac100_poll , 64 ) ;
2017-04-05 12:28:48 +10:00
/* Grab our interrupt */
err = request_irq ( netdev - > irq , ftgmac100_interrupt , 0 , netdev - > name , netdev ) ;
if ( err ) {
netdev_err ( netdev , " failed to request irq %d \n " , netdev - > irq ) ;
goto err_irq ;
}
2017-04-05 12:28:49 +10:00
/* Start things up */
err = ftgmac100_init_all ( priv , false ) ;
if ( err ) {
netdev_err ( netdev , " Failed to allocate packet buffers \n " ) ;
goto err_alloc ;
}
2016-09-22 08:35:01 +09:30
2017-04-05 12:28:49 +10:00
if ( netdev - > phydev ) {
/* If we have a PHY, start polling */
2016-07-19 11:54:23 +10:00
phy_start ( netdev - > phydev ) ;
2017-04-05 12:28:49 +10:00
} else if ( priv - > use_ncsi ) {
/* If using NC-SI, set our carrier on and start the stack */
2016-07-19 11:54:23 +10:00
netif_carrier_on ( netdev ) ;
2011-06-08 23:32:48 +00:00
2017-04-05 12:28:49 +10:00
/* Start the NCSI device */
2016-07-19 11:54:23 +10:00
err = ncsi_start_dev ( priv - > ndev ) ;
if ( err )
goto err_ncsi ;
}
2011-06-08 23:32:48 +00:00
return 0 ;
2017-04-05 12:28:49 +10:00
err_ncsi :
2016-07-19 11:54:23 +10:00
napi_disable ( & priv - > napi ) ;
netif_stop_queue ( netdev ) ;
2017-04-05 12:28:49 +10:00
err_alloc :
ftgmac100_free_buffers ( priv ) ;
2017-04-05 12:28:41 +10:00
free_irq ( netdev - > irq , netdev ) ;
2017-04-05 12:28:49 +10:00
err_irq :
2017-04-05 12:28:48 +10:00
netif_napi_del ( & priv - > napi ) ;
2017-04-05 12:28:49 +10:00
err_hw :
2017-04-05 12:28:48 +10:00
iowrite32 ( 0 , priv - > base + FTGMAC100_OFFSET_IER ) ;
2017-04-05 12:28:46 +10:00
ftgmac100_free_rings ( priv ) ;
2011-06-08 23:32:48 +00:00
return err ;
}
static int ftgmac100_stop ( struct net_device * netdev )
{
struct ftgmac100 * priv = netdev_priv ( netdev ) ;
2017-04-05 12:28:50 +10:00
/* Note about the reset task: We are called with the rtnl lock
* held , so we are synchronized against the core of the reset
* task . We must not try to synchronously cancel it otherwise
* we can deadlock . But since it will test for netif_running ( )
* which has already been cleared by the net core , we don ' t
* anything special to do .
*/
2011-06-08 23:32:48 +00:00
/* disable all interrupts */
iowrite32 ( 0 , priv - > base + FTGMAC100_OFFSET_IER ) ;
netif_stop_queue ( netdev ) ;
napi_disable ( & priv - > napi ) ;
2017-04-05 12:28:47 +10:00
netif_napi_del ( & priv - > napi ) ;
2016-07-19 11:54:23 +10:00
if ( netdev - > phydev )
phy_stop ( netdev - > phydev ) ;
2016-10-04 11:25:54 +11:00
else if ( priv - > use_ncsi )
ncsi_stop_dev ( priv - > ndev ) ;
2011-06-08 23:32:48 +00:00
ftgmac100_stop_hw ( priv ) ;
2017-04-05 12:28:41 +10:00
free_irq ( netdev - > irq , netdev ) ;
2011-06-08 23:32:48 +00:00
ftgmac100_free_buffers ( priv ) ;
2017-04-05 12:28:46 +10:00
ftgmac100_free_rings ( priv ) ;
2011-06-08 23:32:48 +00:00
return 0 ;
}
/* optional */
static int ftgmac100_do_ioctl ( struct net_device * netdev , struct ifreq * ifr , int cmd )
{
2016-07-19 11:54:23 +10:00
if ( ! netdev - > phydev )
return - ENXIO ;
2016-05-16 01:35:13 +02:00
return phy_mii_ioctl ( netdev - > phydev , ifr , cmd ) ;
2011-06-08 23:32:48 +00:00
}
2017-04-10 11:15:15 +10:00
static void ftgmac100_tx_timeout ( struct net_device * netdev )
{
struct ftgmac100 * priv = netdev_priv ( netdev ) ;
/* Disable all interrupts */
iowrite32 ( 0 , priv - > base + FTGMAC100_OFFSET_IER ) ;
/* Do the reset outside of interrupt context */
schedule_work ( & priv - > reset_task ) ;
}
2011-06-08 23:32:48 +00:00
static const struct net_device_ops ftgmac100_netdev_ops = {
. ndo_open = ftgmac100_open ,
. ndo_stop = ftgmac100_stop ,
. ndo_start_xmit = ftgmac100_hard_start_xmit ,
2016-07-19 11:54:22 +10:00
. ndo_set_mac_address = ftgmac100_set_mac_addr ,
2011-06-08 23:32:48 +00:00
. ndo_validate_addr = eth_validate_addr ,
. ndo_do_ioctl = ftgmac100_do_ioctl ,
2017-04-10 11:15:15 +10:00
. ndo_tx_timeout = ftgmac100_tx_timeout ,
2011-06-08 23:32:48 +00:00
} ;
2016-07-19 11:54:21 +10:00
static int ftgmac100_setup_mdio ( struct net_device * netdev )
{
struct ftgmac100 * priv = netdev_priv ( netdev ) ;
struct platform_device * pdev = to_platform_device ( priv - > dev ) ;
int i , err = 0 ;
2016-09-22 08:35:02 +09:30
u32 reg ;
2016-07-19 11:54:21 +10:00
/* initialize mdio bus */
priv - > mii_bus = mdiobus_alloc ( ) ;
if ( ! priv - > mii_bus )
return - EIO ;
2016-09-22 08:35:02 +09:30
if ( of_machine_is_compatible ( " aspeed,ast2400 " ) | |
of_machine_is_compatible ( " aspeed,ast2500 " ) ) {
/* This driver supports the old MDIO interface */
reg = ioread32 ( priv - > base + FTGMAC100_OFFSET_REVR ) ;
reg & = ~ FTGMAC100_REVR_NEW_MDIO_INTERFACE ;
iowrite32 ( reg , priv - > base + FTGMAC100_OFFSET_REVR ) ;
} ;
2016-07-19 11:54:21 +10:00
priv - > mii_bus - > name = " ftgmac100_mdio " ;
snprintf ( priv - > mii_bus - > id , MII_BUS_ID_SIZE , " %s-%d " ,
pdev - > name , pdev - > id ) ;
priv - > mii_bus - > priv = priv - > netdev ;
priv - > mii_bus - > read = ftgmac100_mdiobus_read ;
priv - > mii_bus - > write = ftgmac100_mdiobus_write ;
for ( i = 0 ; i < PHY_MAX_ADDR ; i + + )
priv - > mii_bus - > irq [ i ] = PHY_POLL ;
err = mdiobus_register ( priv - > mii_bus ) ;
if ( err ) {
dev_err ( priv - > dev , " Cannot register MDIO bus! \n " ) ;
goto err_register_mdiobus ;
}
err = ftgmac100_mii_probe ( priv ) ;
if ( err ) {
dev_err ( priv - > dev , " MII Probe failed! \n " ) ;
goto err_mii_probe ;
}
return 0 ;
err_mii_probe :
mdiobus_unregister ( priv - > mii_bus ) ;
err_register_mdiobus :
mdiobus_free ( priv - > mii_bus ) ;
return err ;
}
static void ftgmac100_destroy_mdio ( struct net_device * netdev )
{
struct ftgmac100 * priv = netdev_priv ( netdev ) ;
if ( ! netdev - > phydev )
return ;
phy_disconnect ( netdev - > phydev ) ;
mdiobus_unregister ( priv - > mii_bus ) ;
mdiobus_free ( priv - > mii_bus ) ;
}
2016-07-19 11:54:23 +10:00
static void ftgmac100_ncsi_handler ( struct ncsi_dev * nd )
{
if ( unlikely ( nd - > state ! = ncsi_dev_state_functional ) )
return ;
netdev_info ( nd - > dev , " NCSI interface %s \n " ,
nd - > link_up ? " up " : " down " ) ;
}
2011-06-08 23:32:48 +00:00
static int ftgmac100_probe ( struct platform_device * pdev )
{
struct resource * res ;
int irq ;
struct net_device * netdev ;
struct ftgmac100 * priv ;
2016-07-19 11:54:23 +10:00
int err = 0 ;
2011-06-08 23:32:48 +00:00
if ( ! pdev )
return - ENODEV ;
res = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
if ( ! res )
return - ENXIO ;
irq = platform_get_irq ( pdev , 0 ) ;
if ( irq < 0 )
return irq ;
/* setup net_device */
netdev = alloc_etherdev ( sizeof ( * priv ) ) ;
if ( ! netdev ) {
err = - ENOMEM ;
goto err_alloc_etherdev ;
}
SET_NETDEV_DEV ( netdev , & pdev - > dev ) ;
2014-05-11 00:12:32 +00:00
netdev - > ethtool_ops = & ftgmac100_ethtool_ops ;
2011-06-08 23:32:48 +00:00
netdev - > netdev_ops = & ftgmac100_netdev_ops ;
2017-04-10 11:15:15 +10:00
netdev - > watchdog_timeo = 5 * HZ ;
2011-06-08 23:32:48 +00:00
platform_set_drvdata ( pdev , netdev ) ;
/* setup private data */
priv = netdev_priv ( netdev ) ;
priv - > netdev = netdev ;
priv - > dev = & pdev - > dev ;
2017-04-05 12:28:50 +10:00
INIT_WORK ( & priv - > reset_task , ftgmac100_reset_task ) ;
2011-06-08 23:32:48 +00:00
spin_lock_init ( & priv - > tx_lock ) ;
/* map io memory */
priv - > res = request_mem_region ( res - > start , resource_size ( res ) ,
dev_name ( & pdev - > dev ) ) ;
if ( ! priv - > res ) {
dev_err ( & pdev - > dev , " Could not reserve memory region \n " ) ;
err = - ENOMEM ;
goto err_req_mem ;
}
priv - > base = ioremap ( res - > start , resource_size ( res ) ) ;
if ( ! priv - > base ) {
dev_err ( & pdev - > dev , " Failed to ioremap ethernet registers \n " ) ;
err = - EIO ;
goto err_ioremap ;
}
2017-04-05 12:28:41 +10:00
netdev - > irq = irq ;
2011-06-08 23:32:48 +00:00
2016-07-19 11:54:22 +10:00
/* MAC address from chip or random one */
ftgmac100_setup_mac ( priv ) ;
2016-09-22 08:35:00 +09:30
if ( of_machine_is_compatible ( " aspeed,ast2400 " ) | |
of_machine_is_compatible ( " aspeed,ast2500 " ) ) {
priv - > rxdes0_edorr_mask = BIT ( 30 ) ;
priv - > txdes0_edotr_mask = BIT ( 30 ) ;
} else {
priv - > rxdes0_edorr_mask = BIT ( 15 ) ;
priv - > txdes0_edotr_mask = BIT ( 15 ) ;
}
2016-07-19 11:54:23 +10:00
if ( pdev - > dev . of_node & &
of_get_property ( pdev - > dev . of_node , " use-ncsi " , NULL ) ) {
if ( ! IS_ENABLED ( CONFIG_NET_NCSI ) ) {
dev_err ( & pdev - > dev , " NCSI stack not enabled \n " ) ;
goto err_ncsi_dev ;
}
dev_info ( & pdev - > dev , " Using NCSI interface \n " ) ;
priv - > use_ncsi = true ;
priv - > ndev = ncsi_register_dev ( netdev , ftgmac100_ncsi_handler ) ;
if ( ! priv - > ndev )
goto err_ncsi_dev ;
} else {
priv - > use_ncsi = false ;
err = ftgmac100_setup_mdio ( netdev ) ;
if ( err )
goto err_setup_mdio ;
}
/* We have to disable on-chip IP checksum functionality
* when NCSI is enabled on the interface . It doesn ' t work
* in that case .
*/
2017-04-06 11:02:46 +10:00
netdev - > features = NETIF_F_RXCSUM | NETIF_F_IP_CSUM | NETIF_F_GRO ;
2016-07-19 11:54:23 +10:00
if ( priv - > use_ncsi & &
of_get_property ( pdev - > dev . of_node , " no-hw-checksum " , NULL ) )
netdev - > features & = ~ NETIF_F_IP_CSUM ;
2011-06-08 23:32:48 +00:00
/* register network device */
err = register_netdev ( netdev ) ;
if ( err ) {
dev_err ( & pdev - > dev , " Failed to register netdev \n " ) ;
goto err_register_netdev ;
}
2017-04-05 12:28:41 +10:00
netdev_info ( netdev , " irq %d, mapped at %p \n " , netdev - > irq , priv - > base ) ;
2011-06-08 23:32:48 +00:00
return 0 ;
2016-07-19 11:54:23 +10:00
err_ncsi_dev :
2011-06-08 23:32:48 +00:00
err_register_netdev :
2016-07-19 11:54:21 +10:00
ftgmac100_destroy_mdio ( netdev ) ;
err_setup_mdio :
2011-06-08 23:32:48 +00:00
iounmap ( priv - > base ) ;
err_ioremap :
release_resource ( priv - > res ) ;
err_req_mem :
netif_napi_del ( & priv - > napi ) ;
free_netdev ( netdev ) ;
err_alloc_etherdev :
return err ;
}
2017-03-01 17:24:47 -08:00
static int ftgmac100_remove ( struct platform_device * pdev )
2011-06-08 23:32:48 +00:00
{
struct net_device * netdev ;
struct ftgmac100 * priv ;
netdev = platform_get_drvdata ( pdev ) ;
priv = netdev_priv ( netdev ) ;
unregister_netdev ( netdev ) ;
2017-04-05 12:28:50 +10:00
/* There's a small chance the reset task will have been re-queued,
* during stop , make sure it ' s gone before we free the structure .
*/
cancel_work_sync ( & priv - > reset_task ) ;
2016-07-19 11:54:21 +10:00
ftgmac100_destroy_mdio ( netdev ) ;
2011-06-08 23:32:48 +00:00
iounmap ( priv - > base ) ;
release_resource ( priv - > res ) ;
netif_napi_del ( & priv - > napi ) ;
free_netdev ( netdev ) ;
return 0 ;
}
2016-07-19 11:54:24 +10:00
static const struct of_device_id ftgmac100_of_match [ ] = {
{ . compatible = " faraday,ftgmac100 " } ,
{ }
} ;
MODULE_DEVICE_TABLE ( of , ftgmac100_of_match ) ;
2011-06-08 23:32:48 +00:00
static struct platform_driver ftgmac100_driver = {
2016-07-19 11:54:24 +10:00
. probe = ftgmac100_probe ,
2017-03-01 17:24:47 -08:00
. remove = ftgmac100_remove ,
2016-07-19 11:54:24 +10:00
. driver = {
. name = DRV_NAME ,
. of_match_table = ftgmac100_of_match ,
2011-06-08 23:32:48 +00:00
} ,
} ;
2013-03-18 01:50:48 +00:00
module_platform_driver ( ftgmac100_driver ) ;
2011-06-08 23:32:48 +00:00
MODULE_AUTHOR ( " Po-Yu Chuang <ratbert@faraday-tech.com> " ) ;
MODULE_DESCRIPTION ( " FTGMAC100 driver " ) ;
MODULE_LICENSE ( " GPL " ) ;