From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from gate.crashing.org (gate.crashing.org [63.228.1.57]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 3vsRd021HbzDqC4 for ; Tue, 28 Mar 2017 08:15:16 +1100 (AEDT) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by gate.crashing.org (8.14.1/8.13.8) with ESMTP id v2RLEsXO031339; Mon, 27 Mar 2017 16:14:56 -0500 Message-ID: <1490649293.3177.84.camel@kernel.crashing.org> Subject: Re: [PATCH] net/ftgmac100: Rewrite the driver From: Benjamin Herrenschmidt To: =?ISO-8859-1?Q?C=E9dric?= Le Goater , OpenBMC Maillist Date: Tue, 28 Mar 2017 08:14:53 +1100 In-Reply-To: <8034ac73-e5ee-fd0f-cfd9-9b552e4d5ec8@kaod.org> References: <1490610516.3177.72.camel@kernel.crashing.org> <8034ac73-e5ee-fd0f-cfd9-9b552e4d5ec8@kaod.org> Content-Type: text/plain; charset="UTF-8" X-Mailer: Evolution 3.22.6 (3.22.6-1.fc25) Mime-Version: 1.0 Content-Transfer-Encoding: 8bit X-BeenThere: openbmc@lists.ozlabs.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Development list for OpenBMC List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 27 Mar 2017 21:15:18 -0000 On Mon, 2017-03-27 at 15:52 +0200, Cédric Le Goater wrote: > On 03/27/2017 12:28 PM, Benjamin Herrenschmidt wrote: > > This is an almost-complete rewrite of this driver. > > > > The patch overall multiplies the performance of the driver > > on an AST2500 eval board with a gigabit link. > > > > I get above 360Mbit/s with this vs. about 80Mbit/s with the current > > driver. I've done some tests on NC-SI machines as well, I get close > > to peak (above 90Mbit/s). > > Which tests are you using ?  nuttcp mostly. > > It does that by, among other things, rewriting the receive and > > transmit code, to both simplify the fast path as much as possible, > > avoid flushing of the caches (the aspeed chips have really slow > > little ARM cores), implementing support for fragmented sends, > > fixing HW checksum generation (AST2500 only), etc... > > > > In addition, I've added netpoll support, tx timeout recovery, > > better handling of link speed changes, multicast filter > > and promisc support, various ethtool config additions etc... > > Nice. So I will need to update the QEMU model as it is quite  > basic for the moment. You will need to support fragmented sends yes ;-) > > Finally, the code has been cleaned up and reorganized, and > > various corner cases fixed, such as recovery in some error > > situations. > > > > Signed-off-by: Benjamin Herrenschmidt > > -- > > > > Please give it a good beating before I submit upstream. > > I have used iperf to stress the AST2500 EVB. It first complains with > :   Can you give me a quick description of what exactly you did ? > [  234.910000] ftgmac100 1e660000.ethernet eth0: [ISR] = 0x20f: > NO_RXBUF RPKT_LOST  > [  234.910000] ftgmac100 1e660000.ethernet eth0: [ISR] = 0x204: > NO_RXBUF  > [  234.910000] ftgmac100 1e660000.ethernet eth0: [ISR] = 0x204: > NO_RXBUF  > [  234.910000] ftgmac100 1e660000.ethernet eth0: [ISR] = 0x204: > NO_RXBUF  > [  234.910000] ftgmac100 1e660000.ethernet eth0: [ISR] = 0x204: > NO_RXBUF  > [  234.910000] ftgmac100 1e660000.ethernet eth0: [ISR] = 0x204: > NO_RXBUF  > [  234.910000] ftgmac100 1e660000.ethernet eth0: [ISR] = 0x204: > NO_RXBUF  > [  234.910000] ftgmac100 1e660000.ethernet eth0: [ISR] = 0x204: > NO_RXBUF  > [  234.910000] ftgmac100 1e660000.ethernet eth0: [ISR] = 0x204: > NO_RXBUF  > [  234.910000] ftgmac100 1e660000.ethernet eth0: [ISR] = 0x204: > NO_RXBUF  > > and then blackouts. HW reset was needed. Ok, I'll investigate. I didn't manage to trigger that error with nuttcp. Can you give me the precise iperf commands you used ? Cheers, Ben. > C.  > > > > > While I tried initially to do an incremental series of patch this > > quickly became unrealistic as I rewrote more of the driver. This > > is better reviewed as a new replacement driver for the same chip > > instead. Since the Aspeed SoC is the only in-tree user and we are > > maintaining this for OpenBMC, the risk is limited, I didn't feel > > the need of submitting this as a separate driver and deprecate > > the old one. > > --- > >  arch/arm/boot/dts/aspeed-bmc-opp-palmetto.dts |    1 - > >  arch/arm/boot/dts/aspeed-g4.dtsi              |    6 +- > >  arch/arm/boot/dts/aspeed-g5.dtsi              |    6 +- > >  drivers/net/ethernet/faraday/ftgmac100.c      | 2141 > > ++++++++++++++----------- > >  drivers/net/ethernet/faraday/ftgmac100.h      |  183 ++- > >  5 files changed, 1390 insertions(+), 947 deletions(-) > > > > diff --git a/arch/arm/boot/dts/aspeed-bmc-opp-palmetto.dts > > b/arch/arm/boot/dts/aspeed-bmc-opp-palmetto.dts > > index 6c52f1c..24e2c0f 100644 > > --- a/arch/arm/boot/dts/aspeed-bmc-opp-palmetto.dts > > +++ b/arch/arm/boot/dts/aspeed-bmc-opp-palmetto.dts > > @@ -102,7 +102,6 @@ > >   status = "okay"; > >   > >   use-ncsi; > > - no-hw-checksum; > >  }; > >   > >   > > diff --git a/arch/arm/boot/dts/aspeed-g4.dtsi > > b/arch/arm/boot/dts/aspeed-g4.dtsi > > index 28408a2..80c0867 100644 > > --- a/arch/arm/boot/dts/aspeed-g4.dtsi > > +++ b/arch/arm/boot/dts/aspeed-g4.dtsi > > @@ -42,18 +42,16 @@ > >   }; > >   > >   mac0: ethernet@1e660000 { > > - compatible = "faraday,ftgmac100"; > > + compatible = "aspeed,ast2400-mac", > > "faraday,ftgmac100"; > >   reg = <0x1e660000 0x180>; > >   interrupts = <2>; > > - no-hw-checksum; > >   status = "disabled"; > >   }; > >   > >   mac1: ethernet@1e680000 { > > - compatible = "faraday,ftgmac100"; > > + compatible = "aspeed,ast2400-mac", > > "faraday,ftgmac100"; > >   reg = <0x1e680000 0x180>; > >   interrupts = <3>; > > - no-hw-checksum; > >   status = "disabled"; > >   }; > >   > > diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi > > b/arch/arm/boot/dts/aspeed-g5.dtsi > > index 7c09a26..925cdf7 100644 > > --- a/arch/arm/boot/dts/aspeed-g5.dtsi > > +++ b/arch/arm/boot/dts/aspeed-g5.dtsi > > @@ -141,18 +141,16 @@ > >   }; > >   > >   mac0: ethernet@1e660000 { > > - compatible = "faraday,ftgmac100"; > > + compatible = "aspeed,ast2500-mac", > > "faraday,ftgmac100"; > >   reg = <0x1e660000 0x180>; > >   interrupts = <2>; > > - no-hw-checksum; > >   status = "disabled"; > >   }; > >   > >   mac1: ethernet@1e680000 { > > - compatible = "faraday,ftgmac100"; > > + compatible = "aspeed,ast2500-mac", > > "faraday,ftgmac100"; > >   reg = <0x1e680000 0x180>; > >   interrupts = <3>; > > - no-hw-checksum; > >   status = "disabled"; > >   }; > >   > > diff --git a/drivers/net/ethernet/faraday/ftgmac100.c > > b/drivers/net/ethernet/faraday/ftgmac100.c > > index f40fa92..a81568a 100644 > > --- a/drivers/net/ethernet/faraday/ftgmac100.c > > +++ b/drivers/net/ethernet/faraday/ftgmac100.c > > @@ -4,6 +4,10 @@ > >   * (C) Copyright 2009-2011 Faraday Technology > >   * Po-Yu Chuang > >   * > > + * Largely rewritten by > > + * > > + * Benjamin Herrenschmidt, copyright 2017, IBM Corp. > > + * > >   * 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 > > @@ -18,7 +22,6 @@ > >   * along with this program; if not, write to the Free Software > >   * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. > >   */ > > - > >  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt > >   > >  #include > > @@ -30,900 +33,1384 @@ > >  #include > >  #include > >  #include > > +#include > > +#include > >  #include > >  #include > >   > >  #include "ftgmac100.h" > >   > >  #define DRV_NAME "ftgmac100" > > -#define DRV_VERSION "0.7" > > +#define DRV_VERSION "1.0" > >   > > -#define RX_QUEUE_ENTRIES 256 /* must be power of 2 > > */ > > -#define TX_QUEUE_ENTRIES 512 /* must be power of 2 > > */ > > +/* Arbitrary values, I am not sure the HW has limits */ > > +#define MAX_RX_QUEUE_ENTRIES 1024 > > +#define MAX_TX_QUEUE_ENTRIES 1024 > > +#define MIN_RX_QUEUE_ENTRIES 32 > > +#define MIN_TX_QUEUE_ENTRIES 32 > >   > > -#define MAX_PKT_SIZE 1518 > > -#define RX_BUF_SIZE PAGE_SIZE /* must be > > smaller than 0x3fff */ > > +/* Defaults */ > > +#define DEF_RX_QUEUE_ENTRIES 128 > > +#define DEF_TX_QUEUE_ENTRIES 128 > >   > > -/***************************************************************** > > ************* > > - * private data > > - > > ******************************************************************* > > **********/ > > -struct ftgmac100_descs { > > - struct ftgmac100_rxdes rxdes[RX_QUEUE_ENTRIES]; > > - struct ftgmac100_txdes txdes[TX_QUEUE_ENTRIES]; > > -}; > > +/* We don't do jumbo frames */ > > +#define MAX_PKT_SIZE 1536 > > +#define RX_BUF_SIZE MAX_PKT_SIZE  /* must be > > smaller than 0x3fff */ > >   > >  struct ftgmac100 { > > + /* Registers */ > >   struct resource *res; > >   void __iomem *base; > > - int irq; > > - > > - struct ftgmac100_descs *descs; > > - dma_addr_t descs_dma_addr; > > - > > - struct page *rx_pages[RX_QUEUE_ENTRIES]; > >   > > + /* Rx ring */ > > + unsigned int rx_q_entries; > > + struct ftgmac100_rxdes *rxdes; > > + dma_addr_t rxdes_dma; > > + struct sk_buff **rx_skbs; > >   unsigned int rx_pointer; > > + > > + /* Tx ring */ > > + struct ftgmac100_txdes *txdes; > > + dma_addr_t txdes_dma; > > + unsigned int tx_q_entries; > > + struct sk_buff **tx_skbs; > >   unsigned int tx_clean_pointer; > >   unsigned int tx_pointer; > > - unsigned int tx_pending; > >   > > - spinlock_t tx_lock; > > + /* Used to signal the reset task of ring change request */ > > + unsigned int new_rx_q_entries; > > + unsigned int new_tx_q_entries; > > + > > + /* Scratch page to use when rx skb alloc fails */ > > + void *rx_scratch; > > + dma_addr_t rx_scratch_dma; > >   > > - struct net_device *netdev; > > + /* Component structures */ > > + struct net_device *ndev; > >   struct device *dev; > > - struct ncsi_dev *ndev; > > + struct ncsi_dev *ncsidev; > >   struct napi_struct napi; > > - > > + struct work_struct reset_task; > >   struct mii_bus *mii_bus; > > - int old_speed; > > - int int_mask_all; > > + > > + /* Link management */ > > + int cur_speed; > > + int cur_duplex; > >   bool use_ncsi; > > - bool enabled; > > + > > + /* Multicast filter settings */ > > + u32 maht0; > > + u32 maht1; > > + > > + /* Tells the reset task to skip  */ > > + bool stopping; > > + bool need_mac_restart; > > + > > + /* Flow control settings */ > > + bool tx_pause; > > + bool rx_pause; > > + bool aneg_pause; > >   > >   uint32_t rxdes0_edorr_mask; > >   uint32_t txdes0_edotr_mask; > >  }; > >   > > -static int ftgmac100_alloc_rx_page(struct ftgmac100 *priv, > > -    struct ftgmac100_rxdes *rxdes, > > gfp_t gfp); > > - > > -/***************************************************************** > > ************* > > - * internal functions (hardware register access) > > - > > ******************************************************************* > > **********/ > > -static void ftgmac100_set_rx_ring_base(struct ftgmac100 *priv, > > dma_addr_t addr) > > +static int ftgmac100_alloc_rx_buf(struct ftgmac100 *priv, > > +   unsigned int entry, gfp_t gfp) > >  { > > - iowrite32(addr, priv->base + FTGMAC100_OFFSET_RXR_BADR); > > -} > > + struct net_device *ndev = priv->ndev; > > + struct ftgmac100_rxdes *rxdes = &priv->rxdes[entry]; > > + struct sk_buff *skb; > > + dma_addr_t map; > > + int err = 0; > >   > > -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); > > -} > > + skb = netdev_alloc_skb_ip_align(ndev, RX_BUF_SIZE); > > + if (unlikely(!skb)) { > > + if (net_ratelimit()) > > + netdev_err(ndev, "failed to allocate rx > > skb\n"); > > + err = -ENOMEM; > > + map = priv->rx_scratch_dma; > > + } 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(ndev, "failed to map rx > > page\n"); > > + dev_kfree_skb_any(skb); > > + map = priv->rx_scratch_dma; > > + skb = NULL; > > + err = -ENOMEM; > > + } > > + } > >   > > -static void ftgmac100_set_normal_prio_tx_ring_base(struct > > ftgmac100 *priv, > > -    dma_addr_t > > addr) > > -{ > > - iowrite32(addr, priv->base + FTGMAC100_OFFSET_NPTXR_BADR); > > -} > > + /* Store skb */ > > + priv->rx_skbs[entry] = skb; > >   > > -static void ftgmac100_txdma_normal_prio_start_polling(struct > > ftgmac100 *priv) > > -{ > > - iowrite32(1, priv->base + FTGMAC100_OFFSET_NPTXPD); > > + /* Store DMA address into RX desc */ > > + ftgmac100_rxdes_set_dma_addr(rxdes, map); > > + > > + /* Ensure the above is ordered vs clearing the OWN bit */ > > + dma_wmb(); > > + > > + /* Clean rxdes0 (which resets own bit) */ > > + rxdes->rxdes0 &= cpu_to_le32(priv->rxdes0_edorr_mask); > > + > > + return err; > >  } > >   > > -static int ftgmac100_reset_hw(struct ftgmac100 *priv) > > +static void ftgmac100_free_tx_packet(struct ftgmac100 *priv, > > +      unsigned int pointer, > > +      struct ftgmac100_txdes > > *txdes) > >  { > > - struct net_device *netdev = priv->netdev; > > - int i; > > + struct sk_buff *skb = priv->tx_skbs[pointer]; > > + dma_addr_t map = ftgmac100_txdes_get_dma_addr(txdes); > >   > > - /* NOTE: reset clears all registers */ > > - iowrite32(FTGMAC100_MACCR_SW_RST, priv->base + > > FTGMAC100_OFFSET_MACCR); > > - for (i = 0; i < 5; i++) { > > - unsigned int maccr; > > + if (ftgmac100_txdes_get_first_segment(txdes)) { > > + size_t len = skb_headlen(skb); > >   > > - maccr = ioread32(priv->base + > > FTGMAC100_OFFSET_MACCR); > > - if (!(maccr & FTGMAC100_MACCR_SW_RST)) > > - return 0; > > + if (skb_shinfo(skb)->nr_frags == 0 && len < > > ETH_ZLEN) > > + len = ETH_ZLEN; > > + dma_unmap_single(priv->dev, map, len, > > DMA_TO_DEVICE); > > + } else > > + dma_unmap_page(priv->dev, map, > > +        ftgmac100_txdes_get_buffer_size(txd > > es), > > +        DMA_TO_DEVICE); > >   > > - udelay(1000); > > - } > > - > > - netdev_err(netdev, "software reset failed\n"); > > - return -EIO; > > + if (ftgmac100_txdes_get_last_segment(txdes)) > > + dev_kfree_skb_any(skb); > > + priv->tx_skbs[pointer] = NULL; > >  } > >   > > -static void ftgmac100_set_mac(struct ftgmac100 *priv, const > > unsigned char *mac) > > +static int ftgmac100_next_rx_pointer(struct ftgmac100 *priv, int > > pointer) > >  { > > - 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); > > + return (pointer + 1) & (priv->rx_q_entries - 1); > >  } > >   > > -static void ftgmac100_setup_mac(struct ftgmac100 *priv) > > +static void ftgmac100_rx_packet_error(struct ftgmac100 *priv, > > +       struct ftgmac100_rxdes > > *rxdes) > >  { > > - u8 mac[ETH_ALEN]; > > - unsigned int m; > > - unsigned int l; > > - void *addr; > > + struct net_device *ndev = priv->ndev; > >   > > - 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; > > - } > > + if (unlikely(ftgmac100_rxdes_rx_error(rxdes))) { > > + if (net_ratelimit()) > > + netdev_info(ndev, "rx err\n"); > >   > > - m = ioread32(priv->base + FTGMAC100_OFFSET_MAC_MADR); > > - l = ioread32(priv->base + FTGMAC100_OFFSET_MAC_LADR); > > + ndev->stats.rx_errors++; > > + } > >   > > - 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 (unlikely(ftgmac100_rxdes_crc_error(rxdes))) { > > + if (net_ratelimit()) > > + netdev_info(ndev, "rx crc err\n"); > >   > > - 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); > > + ndev->stats.rx_crc_errors++; > >   } > > -} > >   > > -static int ftgmac100_set_mac_addr(struct net_device *dev, void *p) > > -{ > > - int ret; > > + if (unlikely(ftgmac100_rxdes_frame_too_long(rxdes))) { > > + if (net_ratelimit()) > > + netdev_info(ndev, "rx frame too long\n"); > >   > > - ret = eth_prepare_mac_addr_change(dev, p); > > - if (ret < 0) > > - return ret; > > + ndev->stats.rx_length_errors++; > > + } else if (unlikely(ftgmac100_rxdes_runt(rxdes))) { > > + if (net_ratelimit()) > > + netdev_info(ndev, "rx runt\n"); > >   > > - eth_commit_mac_addr_change(dev, p); > > - ftgmac100_set_mac(netdev_priv(dev), dev->dev_addr); > > + ndev->stats.rx_length_errors++; > > + } else if (unlikely(ftgmac100_rxdes_odd_nibble(rxdes))) { > > + if (net_ratelimit()) > > + netdev_info(ndev, "rx odd nibble\n"); > >   > > - return 0; > > + ndev->stats.rx_length_errors++; > > + } > >  } > >   > > -static void ftgmac100_init_hw(struct ftgmac100 *priv) > > +static bool ftgmac100_rx_packet(struct ftgmac100 *priv, int > > *processed) > >  { > > - /* 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)); > > + struct net_device *ndev = priv->ndev; > > + struct ftgmac100_rxdes *rxdes; > > + struct sk_buff *skb; > > + unsigned int pointer, size; > > + dma_addr_t map; > >   > > - ftgmac100_set_rx_buffer_size(priv, RX_BUF_SIZE); > > + /* Grab next RX descriptor */ > > + pointer = priv->rx_pointer; > > + rxdes = &priv->rxdes[pointer]; > >   > > - iowrite32(FTGMAC100_APTC_RXPOLL_CNT(1), priv->base + > > FTGMAC100_OFFSET_APTC); > > + /* Do we have a packet ? */ > > + if (!ftgmac100_rxdes_packet_ready(rxdes)) > > + return false; > >   > > - ftgmac100_set_mac(priv, priv->netdev->dev_addr); > > -} > > + /* We don't cope with fragmented RX packets */ > > + if (unlikely(!ftgmac100_rxdes_first_segment(rxdes) || > > +      !ftgmac100_rxdes_last_segment(rxdes))) > > + goto drop; > >   > > -#define MACCR_ENABLE_ALL (FTGMAC100_MACCR_TXDMA_EN | > > \ > > -  FTGMAC100_MACCR_RXDMA_EN | > > \ > > -  FTGMAC100_MACCR_TXMAC_EN | > > \ > > -  FTGMAC100_MACCR_RXMAC_EN | > > \ > > -  FTGMAC100_MACCR_FULLDUP | > > \ > > -  FTGMAC100_MACCR_CRC_APD | > > \ > > -  FTGMAC100_MACCR_PHY_LINK_LEVEL | > > \ > > -  FTGMAC100_MACCR_RX_RUNT | > > \ > > -  FTGMAC100_MACCR_RX_BROADPKT) > > - > > -static void ftgmac100_start_hw(struct ftgmac100 *priv, int speed) > > -{ > > - int maccr = MACCR_ENABLE_ALL; > > + /* Any error (other than csum offload) flagged ? */ > > + if (unlikely(ftgmac100_rxdes_any_error(rxdes))) { > > + ftgmac100_rx_packet_error(priv, rxdes); > > + goto drop; > > + } > >   > > - switch (speed) { > > - default: > > - case 10: > > - break; > > + /* Grab the corresponding skb */ > > + skb = priv->rx_skbs[pointer]; > > + if (unlikely(!skb)) { > > + netdev_err(ndev, "Missing skb in rx ring !\n"); > > + goto drop; > > + } > >   > > - case 100: > > - maccr |= FTGMAC100_MACCR_FAST_MODE; > > - break; > > + /* Grab received size */ > > + size = ftgmac100_rxdes_data_length(rxdes); > > + skb_put(skb, size); > >   > > - case 1000: > > - maccr |= FTGMAC100_MACCR_GIGA_MODE; > > - break; > > - } > > + /* Tear down DMA mapping, do necessary cache management */ > > + map = ftgmac100_rxdes_get_dma_addr(rxdes); > >   > > - iowrite32(maccr, priv->base + FTGMAC100_OFFSET_MACCR); > > -} > > +#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 > > + > > + /* Grab protocol and handle rx csum */ > > + skb->protocol = eth_type_trans(skb, ndev); > > + if ((ndev->features & NETIF_F_RXCSUM) && > > +     !ftgmac100_rxdes_csum_err(rxdes)) > > + skb->ip_summed = CHECKSUM_UNNECESSARY; > > + else > > + skb->ip_summed = CHECKSUM_NONE; > >   > > -static void ftgmac100_stop_hw(struct ftgmac100 *priv) > > -{ > > - iowrite32(0, priv->base + FTGMAC100_OFFSET_MACCR); > > -} > > + /* Some stats ... */ > > + if (unlikely(ftgmac100_rxdes_multicast(rxdes))) > > + ndev->stats.multicast++; > > + ndev->stats.rx_packets++; > > + ndev->stats.rx_bytes += size; > >   > > -/***************************************************************** > > ************* > > - * internal functions (receive descriptor) > > - > > ******************************************************************* > > **********/ > > -static bool ftgmac100_rxdes_first_segment(struct ftgmac100_rxdes > > *rxdes) > > -{ > > - return rxdes->rxdes0 & cpu_to_le32(FTGMAC100_RXDES0_FRS); > > -} > > + /* Resplenish rx ring */ > > + ftgmac100_alloc_rx_buf(priv, pointer, GFP_ATOMIC); > > + priv->rx_pointer = ftgmac100_next_rx_pointer(priv, > > pointer); > >   > > -static bool ftgmac100_rxdes_last_segment(struct ftgmac100_rxdes > > *rxdes) > > -{ > > - return rxdes->rxdes0 & cpu_to_le32(FTGMAC100_RXDES0_LRS); > > -} > > + /* push packet to protocol stack */ > > + if (skb->ip_summed == CHECKSUM_NONE) > > + netif_receive_skb(skb); > > + else > > + napi_gro_receive(&priv->napi, skb); > >   > > -static bool ftgmac100_rxdes_packet_ready(struct ftgmac100_rxdes > > *rxdes) > > -{ > > - return rxdes->rxdes0 & > > cpu_to_le32(FTGMAC100_RXDES0_RXPKT_RDY); > > -} > > + (*processed)++; > > + return true; > >   > > -static void ftgmac100_rxdes_set_dma_own(const struct ftgmac100 > > *priv, > > - struct ftgmac100_rxdes *rxdes) > > -{ > > - /* clear status bits */ > > + drop: > > + /* Clean rxdes0 (which resets own bit) */ > >   rxdes->rxdes0 &= cpu_to_le32(priv->rxdes0_edorr_mask); > > + priv->rx_pointer = ftgmac100_next_rx_pointer(priv, priv- > > >rx_pointer); > > + ndev->stats.rx_dropped++; > > + return true; > >  } > >   > > -static bool ftgmac100_rxdes_rx_error(struct ftgmac100_rxdes > > *rxdes) > > +static int ftgmac100_next_tx_pointer(struct ftgmac100 *priv, int > > pointer) > >  { > > - return rxdes->rxdes0 & > > cpu_to_le32(FTGMAC100_RXDES0_RX_ERR); > > + return (pointer + 1) & (priv->tx_q_entries - 1); > >  } > >   > > -static bool ftgmac100_rxdes_crc_error(struct ftgmac100_rxdes > > *rxdes) > > +static u32 ftgmac100_tx_buf_avail(struct ftgmac100 *priv) > >  { > > - return rxdes->rxdes0 & > > cpu_to_le32(FTGMAC100_RXDES0_CRC_ERR); > > + if (priv->tx_clean_pointer <= priv->tx_pointer) > > + return priv->tx_clean_pointer + (priv- > > >tx_q_entries - 1) > > + - priv->tx_pointer; > > + else > > + return priv->tx_clean_pointer - priv->tx_pointer - > > 1; > >  } > >   > > -static bool ftgmac100_rxdes_frame_too_long(struct ftgmac100_rxdes > > *rxdes) > > +static bool ftgmac100_tx_buf_cleanable(struct ftgmac100 *priv) > >  { > > - return rxdes->rxdes0 & cpu_to_le32(FTGMAC100_RXDES0_FTL); > > + return priv->tx_pointer != priv->tx_clean_pointer; > >  } > >   > > -static bool ftgmac100_rxdes_runt(struct ftgmac100_rxdes *rxdes) > > +static bool ftgmac100_tx_complete_packet(struct ftgmac100 *priv) > >  { > > - return rxdes->rxdes0 & cpu_to_le32(FTGMAC100_RXDES0_RUNT); > > -} > > + struct net_device *ndev = priv->ndev; > > + struct ftgmac100_txdes *txdes; > > + struct sk_buff *skb; > > + unsigned int pointer = priv->tx_clean_pointer; > >   > > -static bool ftgmac100_rxdes_odd_nibble(struct ftgmac100_rxdes > > *rxdes) > > -{ > > - return rxdes->rxdes0 & > > cpu_to_le32(FTGMAC100_RXDES0_RX_ODD_NB); > > -} > > + txdes = &priv->txdes[pointer]; > > + if (ftgmac100_txdes_owned_by_dma(txdes)) > > + return false; > >   > > -static unsigned int ftgmac100_rxdes_data_length(struct > > ftgmac100_rxdes *rxdes) > > -{ > > - return le32_to_cpu(rxdes->rxdes0) & FTGMAC100_RXDES0_VDBC; > > -} > > + if (ftgmac100_txdes_get_last_segment(txdes)) { > > + skb = priv->tx_skbs[pointer]; > > + ndev->stats.tx_packets++; > > + ndev->stats.tx_bytes += skb->len; > > + } > > + ftgmac100_free_tx_packet(priv, priv->tx_clean_pointer, > > txdes); > >   > > -static bool ftgmac100_rxdes_multicast(struct ftgmac100_rxdes > > *rxdes) > > -{ > > - return rxdes->rxdes0 & > > cpu_to_le32(FTGMAC100_RXDES0_MULTICAST); > > -} > > + /* Clear except end of ring bit */ > > + txdes->txdes0 &= cpu_to_le32(priv->txdes0_edotr_mask); > > + txdes->txdes1 = 0; > >   > > -static void ftgmac100_rxdes_set_end_of_ring(const struct ftgmac100 > > *priv, > > - struct ftgmac100_rxdes *rxdes) > > -{ > > - rxdes->rxdes0 |= cpu_to_le32(priv->rxdes0_edorr_mask); > > -} > > + priv->tx_clean_pointer = ftgmac100_next_tx_pointer(priv, > > pointer); > >   > > -static void ftgmac100_rxdes_set_dma_addr(struct ftgmac100_rxdes > > *rxdes, > > -  dma_addr_t addr) > > -{ > > - rxdes->rxdes3 = cpu_to_le32(addr); > > + return true; > >  } > >   > > -static dma_addr_t ftgmac100_rxdes_get_dma_addr(struct > > ftgmac100_rxdes *rxdes) > > +static irqreturn_t ftgmac100_interrupt(int irq __always_unused, > > void *dev_id) > >  { > > - return le32_to_cpu(rxdes->rxdes3); > > -} > > + struct net_device *ndev = dev_id; > > + struct ftgmac100 *priv = netdev_priv(ndev); > > + unsigned int status; > >   > > -static bool ftgmac100_rxdes_is_tcp(struct ftgmac100_rxdes *rxdes) > > -{ > > - return (rxdes->rxdes1 & > > cpu_to_le32(FTGMAC100_RXDES1_PROT_MASK)) == > > -        cpu_to_le32(FTGMAC100_RXDES1_PROT_TCPIP); > > -} > > + /* 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)) { > > + if (net_ratelimit()) > > + netdev_warn(ndev, "[ISR] = 0x%x: > > %s%s%s\n", status, > > +     status & > > FTGMAC100_INT_NO_RXBUF ? "NO_RXBUF " : "", > > +     status & > > FTGMAC100_INT_RPKT_LOST ? "RPKT_LOST " : "", > > +     status & FTGMAC100_INT_AHB_ERR > > ? "AHB_ERR " : ""); > >   > > -static bool ftgmac100_rxdes_is_udp(struct ftgmac100_rxdes *rxdes) > > -{ > > - return (rxdes->rxdes1 & > > cpu_to_le32(FTGMAC100_RXDES1_PROT_MASK)) == > > -        cpu_to_le32(FTGMAC100_RXDES1_PROT_UDPIP); > > -} > > + /* RX buffer unavailable */ > > + if (status & FTGMAC100_INT_NO_RXBUF) > > + ndev->stats.rx_over_errors++; > >   > > -static bool ftgmac100_rxdes_tcpcs_err(struct ftgmac100_rxdes > > *rxdes) > > -{ > > - return rxdes->rxdes1 & > > cpu_to_le32(FTGMAC100_RXDES1_TCP_CHKSUM_ERR); > > -} > > + /* Received packet lost due to RX FIFO full */ > > + if (status & FTGMAC100_INT_RPKT_LOST) > > + ndev->stats.rx_fifo_errors++; > >   > > -static bool ftgmac100_rxdes_udpcs_err(struct ftgmac100_rxdes > > *rxdes) > > -{ > > - return rxdes->rxdes1 & > > cpu_to_le32(FTGMAC100_RXDES1_UDP_CHKSUM_ERR); > > -} > > + /* AHB error -> Reset the chip */ > > + if (status & FTGMAC100_INT_AHB_ERR) { > > + iowrite32(0, priv->base + > > FTGMAC100_OFFSET_IER); > > + schedule_work(&priv->reset_task); > > + return IRQ_HANDLED; > > + } > >   > > -static bool ftgmac100_rxdes_ipcs_err(struct ftgmac100_rxdes > > *rxdes) > > -{ > > - return rxdes->rxdes1 & > > cpu_to_le32(FTGMAC100_RXDES1_IP_CHKSUM_ERR); > > -} > > + /* > > +  * 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; > > + } > >   > > -static inline struct page **ftgmac100_rxdes_page_slot(struct > > ftgmac100 *priv, > > - struct ftgmac100_rxdes *rxdes) > > -{ > > - return &priv->rx_pages[rxdes - priv->descs->rxdes]; > > -} > >   > > -/* > > - * rxdes2 is not used by hardware. We use it to keep track of > > page. > > - * Since hardware does not touch it, we can skip > > cpu_to_le32()/le32_to_cpu(). > > - */ > > -static void ftgmac100_rxdes_set_page(struct ftgmac100 *priv, > > - struct ftgmac100_rxdes *rxdes, struct page *page) > > -{ > > - *ftgmac100_rxdes_page_slot(priv, rxdes) = page; > > -} > > + /* Only enable "bad" interrupts while NAPI is on */ > > + iowrite32(FTGMAC100_INT_BAD, priv->base + > > FTGMAC100_OFFSET_IER); > >   > > -static struct page *ftgmac100_rxdes_get_page(struct ftgmac100 > > *priv, > > - struct ftgmac100_rxdes *rxdes) > > -{ > > - return *ftgmac100_rxdes_page_slot(priv, rxdes); > > -} > > + /* Schedule NAPI bh */ > > + napi_schedule(&priv->napi); > >   > > -/***************************************************************** > > ************* > > - * internal functions (receive) > > - > > ******************************************************************* > > **********/ > > -static int ftgmac100_next_rx_pointer(int pointer) > > -{ > > - return (pointer + 1) & (RX_QUEUE_ENTRIES - 1); > > + return IRQ_HANDLED; > >  } > >   > > -static void ftgmac100_rx_pointer_advance(struct ftgmac100 *priv) > > +static int ftgmac100_hard_start_xmit(struct sk_buff *skb, > > +      struct net_device *ndev) > >  { > > - priv->rx_pointer = ftgmac100_next_rx_pointer(priv- > > >rx_pointer); > > -} > > + struct ftgmac100 *priv = netdev_priv(ndev); > > + struct ftgmac100_txdes *txdes, *first; > > + int nfrags; > > + int pointer, len, i, j; > > + dma_addr_t map; > >   > > -static struct ftgmac100_rxdes *ftgmac100_current_rxdes(struct > > ftgmac100 *priv) > > -{ > > - return &priv->descs->rxdes[priv->rx_pointer]; > > -} > > + if (unlikely(skb->len > MAX_PKT_SIZE)) { > > + if (net_ratelimit()) > > + netdev_dbg(ndev, "tx packet too big\n"); > > + goto drop; > > + } > >   > > -static struct ftgmac100_rxdes * > > -ftgmac100_rx_locate_first_segment(struct ftgmac100 *priv) > > -{ > > - struct ftgmac100_rxdes *rxdes = > > ftgmac100_current_rxdes(priv); > > + /* The HW doesn't pad small frames */ > > + if (skb_padto(skb, ETH_ZLEN) < 0) { > > + ndev->stats.tx_dropped ++; > > + return NETDEV_TX_OK; > > + } > >   > > - while (ftgmac100_rxdes_packet_ready(rxdes)) { > > - if (ftgmac100_rxdes_first_segment(rxdes)) > > - return rxdes; > > + /* XXX Do we have a limit on #fragments ? */ > > + nfrags = skb_shinfo(skb)->nr_frags; > >   > > - ftgmac100_rxdes_set_dma_own(priv, rxdes); > > - ftgmac100_rx_pointer_advance(priv); > > - rxdes = ftgmac100_current_rxdes(priv); > > + /* Get header len and pad for non-fragmented packets */ > > + len = skb_headlen(skb); > > + if (nfrags == 0 && len < ETH_ZLEN) > > + len = ETH_ZLEN; > > + > > + /* Map the packet head */ > > + map = dma_map_single(priv->dev, skb->data, len, > > DMA_TO_DEVICE); > > + if (dma_mapping_error(priv->dev, map)) { > > + if (net_ratelimit()) > > + netdev_err(ndev, "map tx packet head > > failed\n"); > > + goto drop; > >   } > >   > > - return NULL; > > -} > > + /* Grab the next free tx descriptor */ > > + pointer = priv->tx_pointer; > > + txdes = first = &priv->txdes[pointer]; > >   > > -static bool ftgmac100_rx_packet_error(struct ftgmac100 *priv, > > -       struct ftgmac100_rxdes > > *rxdes) > > -{ > > - struct net_device *netdev = priv->netdev; > > - bool error = false; > > + /* Setup it up. We don't set the OWN bit yet. */ > > + priv->tx_skbs[pointer] = skb; > > + ftgmac100_txdes_set_dma_addr(txdes, map); > > + ftgmac100_txdes_set_buffer_size(txdes, len); > > + ftgmac100_txdes_set_first_segment(txdes); > >   > > - if (unlikely(ftgmac100_rxdes_rx_error(rxdes))) { > > - if (net_ratelimit()) > > - netdev_info(netdev, "rx err\n"); > > + /* Setup HW checksumming */ > > + if (skb->ip_summed == CHECKSUM_PARTIAL) { > > + __be16 protocol = skb->protocol; > >   > > - netdev->stats.rx_errors++; > > - error = true; > > + 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); > > + } else if (skb_checksum_help(skb)) > > + goto drop; > >   } > >   > > - if (unlikely(ftgmac100_rxdes_crc_error(rxdes))) { > > - if (net_ratelimit()) > > - netdev_info(netdev, "rx crc err\n"); > > + /* Next descriptor */ > > + pointer = ftgmac100_next_tx_pointer(priv, pointer); > >   > > - netdev->stats.rx_crc_errors++; > > - error = true; > > - } else if (unlikely(ftgmac100_rxdes_ipcs_err(rxdes))) { > > - if (net_ratelimit()) > > - netdev_info(netdev, "rx IP checksum > > err\n"); > > + /* Add the fragments */ > > + for (i = 0; i < nfrags; i++) { > > + skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; > > + > > + len = frag->size; > >   > > - error = true; > > + /* Map it */ > > + map = skb_frag_dma_map(priv->dev, frag, 0, len, > > DMA_TO_DEVICE); > > + if (dma_mapping_error(priv->dev, map)) > > + goto dma_err; > > + > > + /* Setup descriptor */ > > + priv->tx_skbs[pointer] = skb; > > + txdes = &priv->txdes[pointer]; > > + ftgmac100_txdes_set_dma_addr(txdes, map); > > + ftgmac100_txdes_set_buffer_size(txdes, len); > > + ftgmac100_txdes_set_dma_own(txdes); > > + > > + /* > > +  * The spec is unclear, whether these need to be > > in the > > +  * first descriptor only or all of them. Gor now, > > do all > > +  * of them. > > +  */ > > +#define CSUM_MASK cpu_to_le32(FTGMAC100_TXDES1_TCP_CHKSUM | \ > > +       FTGMAC100_TXDES1_UDP_CHKSUM | \ > > +       FTGMAC100_TXDES1_IP_CHKSUM) > > + txdes->txdes1 |= first->txdes1 & CSUM_MASK; > > + pointer = ftgmac100_next_tx_pointer(priv, > > pointer); > >   } > >   > > - if (unlikely(ftgmac100_rxdes_frame_too_long(rxdes))) { > > - if (net_ratelimit()) > > - netdev_info(netdev, "rx frame too > > long\n"); > > + /* Tag last fragment */ > > + ftgmac100_txdes_set_last_segment(txdes); > >   > > - netdev->stats.rx_length_errors++; > > - error = true; > > - } else if (unlikely(ftgmac100_rxdes_runt(rxdes))) { > > - if (net_ratelimit()) > > - netdev_info(netdev, "rx runt\n"); > > + /* > > +  * Set the own bit on the first descriptor, this can cause > > the > > +  * HW to transmit, it needs to be ordered after all > > previous > > +  * stores. > > +  */ > > + dma_wmb(); > > + ftgmac100_txdes_set_dma_own(first); > >   > > - netdev->stats.rx_length_errors++; > > - error = true; > > - } else if (unlikely(ftgmac100_rxdes_odd_nibble(rxdes))) { > > - if (net_ratelimit()) > > - netdev_info(netdev, "rx odd nibble\n"); > > + /* Update next TX pointer */ > > + priv->tx_pointer = pointer; > >   > > - netdev->stats.rx_length_errors++; > > - error = true; > > + /* > > +  * If there isn't enough room for all the fragments of a > > new packet > > +  * in the TX ring, stop the queue. The sequence below is > > race free > > +  * vs. a concurrent restart in ftgmac100_poll() > > +  */ > > + if (unlikely(ftgmac100_tx_buf_avail(priv) <= > > (MAX_SKB_FRAGS + 1))) { > > + netif_stop_queue(ndev); > > + smp_mb(); > > + if (ftgmac100_tx_buf_avail(priv) > (MAX_SKB_FRAGS > > + 1)) > > + netif_wake_queue(ndev); > >   } > >   > > - return error; > > -} > > + /* Poke transmitter to read the updated TX descriptors */ > > + iowrite32(1, priv->base + FTGMAC100_OFFSET_NPTXPD); > >   > > -static void ftgmac100_rx_drop_packet(struct ftgmac100 *priv) > > -{ > > - struct net_device *netdev = priv->netdev; > > - struct ftgmac100_rxdes *rxdes = > > ftgmac100_current_rxdes(priv); > > - bool done = false; > > + return NETDEV_TX_OK; > >   > > + dma_err: > >   if (net_ratelimit()) > > - netdev_dbg(netdev, "drop packet %p\n", rxdes); > > + netdev_dbg(ndev, "map tx fragment failed\n"); > >   > > - do { > > - if (ftgmac100_rxdes_last_segment(rxdes)) > > - done = true; > > + /* Free head */ > > + pointer = priv->tx_pointer; > > + ftgmac100_free_tx_packet(priv, pointer, first); > >   > > - ftgmac100_rxdes_set_dma_own(priv, rxdes); > > - ftgmac100_rx_pointer_advance(priv); > > - rxdes = ftgmac100_current_rxdes(priv); > > - } while (!done && ftgmac100_rxdes_packet_ready(rxdes)); > > + /* Then all fragments */ > > + for (j = 0; j < i; j++) { > > + pointer = ftgmac100_next_tx_pointer(priv, > > pointer); > > + txdes = &priv->txdes[pointer]; > > + ftgmac100_free_tx_packet(priv, pointer, txdes); > > + } > >   > > - netdev->stats.rx_dropped++; > > + /* > > +  * This cannot be reached if we successfully mapped the > > +  * last fragment, so we know ftgmac100_free_tx_packet() > > +  * hasn't freed the skb yet. > > +  */ > > + drop: > > + /* Drop the packet */ > > + dev_kfree_skb_any(skb); > > + ndev->stats.tx_dropped++; > > + > > + return NETDEV_TX_OK; > >  } > >   > > -static bool ftgmac100_rx_packet(struct ftgmac100 *priv, int > > *processed) > > +static void ftgmac100_start_mac(struct ftgmac100 *priv) > >  { > > - struct net_device *netdev = priv->netdev; > > - struct ftgmac100_rxdes *rxdes; > > - struct sk_buff *skb; > > - bool done = false; > > + u32 maccr = ioread32(priv->base + FTGMAC100_OFFSET_MACCR); > >   > > - rxdes = ftgmac100_rx_locate_first_segment(priv); > > - if (!rxdes) > > - return false; > > + priv->need_mac_restart = false; > >   > > - if (unlikely(ftgmac100_rx_packet_error(priv, rxdes))) { > > - ftgmac100_rx_drop_packet(priv); > > - return true; > > - } > > + /* Keep the original GMAC and FAST bits */ > > + maccr &= (FTGMAC100_MACCR_FAST_MODE | > > FTGMAC100_MACCR_GIGA_MODE); > >   > > - /* start processing */ > > - skb = netdev_alloc_skb_ip_align(netdev, 128); > > - if (unlikely(!skb)) { > > - if (net_ratelimit()) > > - netdev_err(netdev, "rx skb alloc > > failed\n"); > > + /* 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; > > + > > + /* Add other bits as needed */ > > + if (priv->cur_duplex == DUPLEX_FULL) > > + maccr |= FTGMAC100_MACCR_FULLDUP; > > + if (priv->ndev->flags & IFF_PROMISC) > > + maccr |= FTGMAC100_MACCR_RX_ALL; > > + if (priv->ndev->flags & IFF_ALLMULTI) > > + maccr |= FTGMAC100_MACCR_RX_MULTIPKT; > > + else if (netdev_mc_count(priv->ndev)) > > + maccr |= FTGMAC100_MACCR_HT_MULTI_EN; > > + > > + /* Hit the HW */ > > + iowrite32(maccr, priv->base + FTGMAC100_OFFSET_MACCR); > > +} > > + > > +static void ftgmac100_stop_mac(struct ftgmac100 *priv) > > +{ > > + iowrite32(0, priv->base + FTGMAC100_OFFSET_MACCR); > > +} > >   > > - ftgmac100_rx_drop_packet(priv); > > - return true; > > +static int ftgmac100_poll(struct napi_struct *napi, int budget) > > +{ > > + struct ftgmac100 *priv = container_of(napi, struct > > ftgmac100, napi); > > + struct net_device *ndev = priv->ndev; > > + int work_done = 0; > > + bool more; > > + > > + /* Handle Tx packet reclaim */ > > + if (ftgmac100_tx_buf_cleanable(priv)) { > > + while(ftgmac100_tx_buf_cleanable(priv) && > > +       ftgmac100_tx_complete_packet(priv)) > > + ; > > + /* Restart queue if needed */ > > + smp_mb(); > > + if (unlikely(netif_queue_stopped(ndev) && > > +      ftgmac100_tx_buf_avail(priv) > > > (MAX_SKB_FRAGS + 1))) { > > + struct netdev_queue *txq = > > netdev_get_tx_queue(ndev, 0); > > + __netif_tx_lock(txq, smp_processor_id()); > > + if (netif_queue_stopped(ndev) && > > +     ftgmac100_tx_buf_avail(priv) > > > (MAX_SKB_FRAGS + 1)) > > + netif_wake_queue(ndev); > > + __netif_tx_unlock(txq); > > + } > >   } > >   > > - if (unlikely(ftgmac100_rxdes_multicast(rxdes))) > > - netdev->stats.multicast++; > > + /* Handle RX packets */ > > + do > > + more = ftgmac100_rx_packet(priv, &work_done); > > + while (more && work_done < budget); > >   > >   /* > > -  * It seems that HW does checksum incorrectly with > > fragmented packets, > > -  * so we are conservative here - if HW checksum error, let > > software do > > -  * the checksum again. > > +  * The interrupt is telling us to kick the MAC back to > > life > > +  * after an RX overflow > >    */ > > - if ((ftgmac100_rxdes_is_tcp(rxdes) && > > !ftgmac100_rxdes_tcpcs_err(rxdes)) || > > -     (ftgmac100_rxdes_is_udp(rxdes) && > > !ftgmac100_rxdes_udpcs_err(rxdes))) > > - skb->ip_summed = CHECKSUM_UNNECESSARY; > > - > > - do { > > - dma_addr_t map = > > ftgmac100_rxdes_get_dma_addr(rxdes); > > - struct page *page = ftgmac100_rxdes_get_page(priv, > > rxdes); > > - unsigned int size; > > + if (unlikely(priv->need_mac_restart)) > > + ftgmac100_start_mac(priv); > >   > > - dma_unmap_page(priv->dev, map, RX_BUF_SIZE, > > DMA_FROM_DEVICE); > > + /* > > +  * As long as we are waiting for transmit packets to be > > +  * completed we keep NAPI going > > +  */ > > + if (ftgmac100_tx_buf_cleanable(priv)) > > + work_done = budget; > >   > > - size = ftgmac100_rxdes_data_length(rxdes); > > - skb_fill_page_desc(skb, skb_shinfo(skb)->nr_frags, > > page, 0, size); > > + /* Are we done ? */ > > + if (work_done < budget) { > > + /* NAPI's over for now */ > > + napi_complete(napi); > >   > > - skb->len += size; > > - skb->data_len += size; > > - skb->truesize += PAGE_SIZE; > > + /* Enable all interrupts */ > > + iowrite32(FTGMAC100_INT_ALL, priv->base + > > FTGMAC100_OFFSET_IER); > > + } > >   > > - if (ftgmac100_rxdes_last_segment(rxdes)) > > - done = true; > > + return work_done; > > +} > >   > > - ftgmac100_alloc_rx_page(priv, rxdes, GFP_ATOMIC); > > +static void ftgmac100_write_mac_addr(struct ftgmac100 *priv, const > > u8 *mac) > > +{ > > + unsigned int maddr = mac[0] << 8 | mac[1]; > > + unsigned int laddr = mac[2] << 24 | mac[3] << 16 | mac[4] > > << 8 | mac[5]; > >   > > - ftgmac100_rx_pointer_advance(priv); > > - rxdes = ftgmac100_current_rxdes(priv); > > - } while (!done); > > + iowrite32(maddr, priv->base + FTGMAC100_OFFSET_MAC_MADR); > > + iowrite32(laddr, priv->base + FTGMAC100_OFFSET_MAC_LADR); > > +} > >   > > - /* Small frames are copied into linear part of skb to free > > one page */ > > - if (skb->len <= 128) { > > - skb->truesize -= PAGE_SIZE; > > - __pskb_pull_tail(skb, skb->len); > > - } else { > > - /* We pull the minimum amount into linear part */ > > - __pskb_pull_tail(skb, ETH_HLEN); > > - } > > - skb->protocol = eth_type_trans(skb, netdev); > > +static void ftgmac100_config_pause(struct ftgmac100 *priv) > > +{ > > + u32 fcr = FTGMAC100_FCR_PAUSE_TIME(16); > >   > > - netdev->stats.rx_packets++; > > - netdev->stats.rx_bytes += skb->len; > > + /* > > +  * Throttle tx queue when receiving pause frames. > > +  * XXX Double check with HW vendor the HW bits. > > +  */ > > + if (priv->rx_pause) > > + fcr |= FTGMAC100_FCR_FC_EN; > >   > > - /* push packet to protocol stack */ > > - napi_gro_receive(&priv->napi, skb); > > + /* > > +  * Enables sending pause frames when the RX queue is past > > a > > +  * certain threshold. > > +  * XXX Double check the HW thresholds config... > > +  */ > > + if (priv->tx_pause) > > + fcr |= FTGMAC100_FCR_FCTHR_EN; > >   > > - (*processed)++; > > - return true; > > + iowrite32(fcr, priv->base + FTGMAC100_OFFSET_FCR); > >  } > >   > > -/***************************************************************** > > ************* > > - * internal functions (transmit descriptor) > > - > > ******************************************************************* > > **********/ > > -static void ftgmac100_txdes_reset(const struct ftgmac100 *priv, > > struct ftgmac100_txdes *txdes) > > +static void ftgmac100_init_hw(struct ftgmac100 *priv) > >  { > > - /* clear all except end of ring bit */ > > - txdes->txdes0 &= cpu_to_le32(priv->txdes0_edotr_mask); > > - txdes->txdes1 = 0; > > - txdes->txdes2 = 0; > > - txdes->txdes3 = 0; > > -} > > + u32 reg, rfifo_sz, tfifo_sz; > >   > > -static bool ftgmac100_txdes_owned_by_dma(struct ftgmac100_txdes > > *txdes) > > -{ > > - return txdes->txdes0 & > > cpu_to_le32(FTGMAC100_TXDES0_TXDMA_OWN); > > -} > > + /* Clear stale interrupts */ > > + reg = ioread32(priv->base + FTGMAC100_OFFSET_ISR); > > + iowrite32(reg, priv->base + FTGMAC100_OFFSET_ISR); > > + > > + /* Setup RX ring buffer base */ > > + iowrite32(priv->rxdes_dma, priv->base + > > FTGMAC100_OFFSET_RXR_BADR); > > + > > + /* Setup TX ring buffer base */ > > + iowrite32(priv->txdes_dma, priv->base + > > FTGMAC100_OFFSET_NPTXR_BADR); > > + > > + /* Configure RX buffer size */ > > + iowrite32(FTGMAC100_RBSR_SIZE(RX_BUF_SIZE), > > +   priv->base + FTGMAC100_OFFSET_RBSR); > > + > > + /* Set RX descriptor autopoll */ > > + iowrite32(FTGMAC100_APTC_RXPOLL_CNT(1), > > +   priv->base + FTGMAC100_OFFSET_APTC); > >   > > -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. > > +  * Configure descriptor sizes and increase burst sizes > > according > > +  * to values in Aspeed SDK. The FIFO arbitration is > > enabled and > > +  * the thresholds set based on the recommended values in > > the > > +  * AST2400 specification. > >    */ > > - wmb(); > > - txdes->txdes0 |= cpu_to_le32(FTGMAC100_TXDES0_TXDMA_OWN); > > -} > > + iowrite32(FTGMAC100_DBLAC_RXDES_SIZE(2) |   /* 2*8 bytes > > RX descs */ > > +   FTGMAC100_DBLAC_TXDES_SIZE(2) |   /* 2*8 bytes > > TX descs */ > > +   FTGMAC100_DBLAC_RXBURST_SIZE(3) | /* 512 bytes > > max RX bursts */ > > +   FTGMAC100_DBLAC_TXBURST_SIZE(3) | /* 512 bytes > > max TX bursts */ > > +   FTGMAC100_DBLAC_RX_THR_EN |       /* Enable fifo > > threshold arb */ > > +   FTGMAC100_DBLAC_RXFIFO_HTHR(6) |  /* 6/8 of FIFO > > high threshold */ > > +   FTGMAC100_DBLAC_RXFIFO_LTHR(2),   /* 2/8 of FIFO > > low threshold */ > > +   priv->base + FTGMAC100_OFFSET_DBLAC); > >   > > -static void ftgmac100_txdes_set_end_of_ring(const struct ftgmac100 > > *priv, > > - struct ftgmac100_txdes *txdes) > > -{ > > - txdes->txdes0 |= cpu_to_le32(priv->txdes0_edotr_mask); > > + /* > > +  * Interrupt mitigation configured for 1 interrupt/packet. > > HW interrupt > > +  * mitigation doesn't seem to provide any benefit with > > NAPI so leave > > +  * it at that. > > +  */ > > + iowrite32(FTGMAC100_ITC_RXINT_THR(1) | > > +   FTGMAC100_ITC_TXINT_THR(1), > > +   priv->base + FTGMAC100_OFFSET_ITC); > > + > > + /* Configure FIFO sizes in the TPAFCR register */ > > + reg = ioread32(priv->base + FTGMAC100_OFFSET_FEAR); > > + rfifo_sz = reg & 0x00000007; > > + tfifo_sz = (reg >> 3) & 0x00000007; > > + reg = ioread32(priv->base + FTGMAC100_OFFSET_TPAFCR); > > + reg &= ~0x3f000000; > > + reg |= (tfifo_sz << 27); > > + reg |= (rfifo_sz << 24); > > + iowrite32(reg, priv->base + FTGMAC100_OFFSET_TPAFCR); > > + > > + /* Write MAC address */ > > + ftgmac100_write_mac_addr(priv, priv->ndev->dev_addr); > > + > > + /* Write multicast filters */ > > + iowrite32(priv->maht0, priv->base + > > FTGMAC100_OFFSET_MAHT0); > > + iowrite32(priv->maht1, priv->base + > > FTGMAC100_OFFSET_MAHT1); > >  } > >   > > -static void ftgmac100_txdes_set_first_segment(struct > > ftgmac100_txdes *txdes) > > +static int ftgmac100_reset_mac(struct ftgmac100 *priv, u32 maccr) > >  { > > - txdes->txdes0 |= cpu_to_le32(FTGMAC100_TXDES0_FTS); > > + struct net_device *ndev = priv->ndev; > > + int i; > > + > > + /* NOTE: reset clears all registers */ > > + iowrite32(maccr, priv->base + FTGMAC100_OFFSET_MACCR); > > + iowrite32(maccr | FTGMAC100_MACCR_SW_RST, > > +   priv->base + FTGMAC100_OFFSET_MACCR); > > + for (i = 0; i < 50; i++) { > > + maccr = ioread32(priv->base + > > FTGMAC100_OFFSET_MACCR); > > + if (!(maccr & FTGMAC100_MACCR_SW_RST)) > > + return 0; > > + udelay(100); > > + } > > + > > + netdev_err(ndev, "Hardware reset failed\n"); > > + return -EIO; > >  } > >   > > -static void ftgmac100_txdes_set_last_segment(struct > > ftgmac100_txdes *txdes) > > +static int ftgmac100_reset_and_config_mac(struct ftgmac100 *priv) > >  { > > - txdes->txdes0 |= cpu_to_le32(FTGMAC100_TXDES0_LTS); > > + 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->ndev, "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; > > + > > + /* The doc says reset twice with 10us interval */ > > + if (ftgmac100_reset_mac(priv, maccr)) > > + return -EIO; > > + udelay(10); > > + return ftgmac100_reset_mac(priv, maccr); > >  } > >   > > -static void ftgmac100_txdes_set_buffer_size(struct ftgmac100_txdes > > *txdes, > > -     unsigned int len) > > +static void ftgmac100_calc_mc_hash(struct ftgmac100 *priv) > >  { > > - txdes->txdes0 |= > > cpu_to_le32(FTGMAC100_TXDES0_TXBUF_SIZE(len)); > > + struct netdev_hw_addr *ha; > > + > > + priv->maht1 = 0; > > + priv->maht0 = 0; > > + netdev_for_each_mc_addr(ha, priv->ndev) { > > + u32 crc_val = ether_crc_le(ETH_ALEN, ha->addr); > > + crc_val = (~(crc_val >> 2)) & 0x3f; > > + if (crc_val >= 32) > > + priv->maht1 |= 1ul << (crc_val - 32); > > + else > > + priv->maht0 |= 1ul << (crc_val); > > + } > >  } > >   > > -static void ftgmac100_txdes_set_txint(struct ftgmac100_txdes > > *txdes) > > +static void ftgmac100_set_rx_mode(struct net_device *ndev) > >  { > > - txdes->txdes1 |= cpu_to_le32(FTGMAC100_TXDES1_TXIC); > > + struct ftgmac100 *priv = netdev_priv(ndev); > > + > > + /* If we get passed some MC addresses, setup the hash > > filter */ > > + if (netdev_mc_count(ndev)) { > > + ftgmac100_calc_mc_hash(priv); > > + iowrite32(priv->maht0, priv->base + > > FTGMAC100_OFFSET_MAHT0); > > + iowrite32(priv->maht1, priv->base + > > FTGMAC100_OFFSET_MAHT1); > > + } > > + > > + /* Reconfigure MACCR */ > > + ftgmac100_start_mac(priv); > >  } > >   > > -static void ftgmac100_txdes_set_tcpcs(struct ftgmac100_txdes > > *txdes) > > +static int ftgmac100_set_mac_addr(struct net_device *ndev, void > > *p) > >  { > > - txdes->txdes1 |= cpu_to_le32(FTGMAC100_TXDES1_TCP_CHKSUM); > > + struct ftgmac100 *priv = netdev_priv(ndev); > > + int ret; > > + > > + ret = eth_prepare_mac_addr_change(ndev, p); > > + if (ret < 0) > > + return ret; > > + ftgmac100_write_mac_addr(priv, p); > > + eth_commit_mac_addr_change(ndev, p); > > + return 0; > >  } > >   > > -static void ftgmac100_txdes_set_udpcs(struct ftgmac100_txdes > > *txdes) > > +static int ftgmac100_do_ioctl(struct net_device *ndev, struct > > ifreq *ifr, > > +       int cmd) > >  { > > - txdes->txdes1 |= cpu_to_le32(FTGMAC100_TXDES1_UDP_CHKSUM); > > + if (!ndev->phydev) > > + return -ENXIO; > > + > > + return phy_mii_ioctl(ndev->phydev, ifr, cmd); > >  } > >   > > -static void ftgmac100_txdes_set_ipcs(struct ftgmac100_txdes > > *txdes) > > +static void ftgmac100_get_drvinfo(struct net_device *ndev, > > +   struct ethtool_drvinfo *info) > >  { > > - txdes->txdes1 |= cpu_to_le32(FTGMAC100_TXDES1_IP_CHKSUM); > > + strlcpy(info->driver, DRV_NAME, sizeof(info->driver)); > > + strlcpy(info->version, DRV_VERSION, sizeof(info- > > >version)); > > + strlcpy(info->bus_info, dev_name(&ndev->dev), sizeof(info- > > >bus_info)); > >  } > >   > > -static void ftgmac100_txdes_set_dma_addr(struct ftgmac100_txdes > > *txdes, > > -  dma_addr_t addr) > > +static int ftgmac100_nway_reset(struct net_device *ndev) > >  { > > - txdes->txdes3 = cpu_to_le32(addr); > > + if (!ndev->phydev) > > + return -ENXIO; > > + return phy_start_aneg(ndev->phydev); > >  } > >   > > -static dma_addr_t ftgmac100_txdes_get_dma_addr(struct > > ftgmac100_txdes *txdes) > > +static void ftgmac100_get_ringparam(struct net_device *ndev, > > +     struct ethtool_ringparam > > *ering) > >  { > > - return le32_to_cpu(txdes->txdes3); > > + struct ftgmac100 *priv = netdev_priv(ndev); > > + > > + memset(ering, 0, sizeof(*ering)); > > + ering->rx_max_pending = MAX_RX_QUEUE_ENTRIES; > > + ering->tx_max_pending = MAX_TX_QUEUE_ENTRIES; > > + ering->rx_pending = priv->rx_q_entries; > > + ering->tx_pending = priv->tx_q_entries; > >  } > >   > > -/* > > - * txdes2 is not used by hardware. We use it to keep track of > > socket buffer. > > - * Since hardware does not touch it, we can skip > > cpu_to_le32()/le32_to_cpu(). > > - */ > > -static void ftgmac100_txdes_set_skb(struct ftgmac100_txdes *txdes, > > -     struct sk_buff *skb) > > +static int ftgmac100_set_ringparam(struct net_device *ndev, > > +    struct ethtool_ringparam > > *ering) > >  { > > - txdes->txdes2 = (unsigned int)skb; > > + struct ftgmac100 *priv = netdev_priv(ndev); > > + > > + if (ering->rx_pending > MAX_RX_QUEUE_ENTRIES || > > +     ering->tx_pending > MAX_TX_QUEUE_ENTRIES || > > +     ering->rx_pending < MIN_RX_QUEUE_ENTRIES || > > +     ering->tx_pending < MIN_TX_QUEUE_ENTRIES || > > +     !is_power_of_2(ering->rx_pending) || > > +     !is_power_of_2(ering->tx_pending)) > > + return -EINVAL; > > + > > + priv->new_rx_q_entries = ering->rx_pending; > > + priv->new_tx_q_entries = ering->tx_pending; > > + if (netif_running(ndev)) > > + schedule_work(&priv->reset_task); > > + > > + return 0; > >  } > >   > > -static struct sk_buff *ftgmac100_txdes_get_skb(struct > > ftgmac100_txdes *txdes) > > +static void ftgmac100_get_pauseparam(struct net_device *ndev, > > +      struct ethtool_pauseparam > > *pause) > >  { > > - return (struct sk_buff *)txdes->txdes2; > > + struct ftgmac100 *priv = netdev_priv(ndev); > > + > > + pause->autoneg = priv->aneg_pause; > > + pause->tx_pause = priv->tx_pause; > > + pause->rx_pause = priv->rx_pause; > >  } > >   > > -/***************************************************************** > > ************* > > - * internal functions (transmit) > > - > > ******************************************************************* > > **********/ > > -static int ftgmac100_next_tx_pointer(int pointer) > > +static int ftgmac100_set_pauseparam(struct net_device *ndev, > > +     struct ethtool_pauseparam > > *pause) > >  { > > - return (pointer + 1) & (TX_QUEUE_ENTRIES - 1); > > + struct ftgmac100 *priv = netdev_priv(ndev); > > + struct phy_device *phydev = ndev->phydev; > > + > > + priv->aneg_pause = pause->autoneg; > > + priv->tx_pause = pause->tx_pause; > > + priv->rx_pause = pause->rx_pause; > > + > > + if (phydev) { > > + phydev->advertising &= ~ADVERTISED_Pause; > > + phydev->advertising &= ~ADVERTISED_Asym_Pause; > > + > > + if (pause->rx_pause) { > > + phydev->advertising |= ADVERTISED_Pause; > > + phydev->advertising |= > > ADVERTISED_Asym_Pause; > > + } > > + > > + if (pause->tx_pause) > > + phydev->advertising ^= > > ADVERTISED_Asym_Pause; > > + } > > + if (netif_running(ndev)) { > > + if (phydev && priv->aneg_pause) > > + phy_start_aneg(phydev); > > + else > > + ftgmac100_config_pause(priv); > > + } > > + > > + return 0; > >  } > >   > > -static void ftgmac100_tx_pointer_advance(struct ftgmac100 *priv) > > +static const struct ethtool_ops ftgmac100_ethtool_ops = { > > + .get_drvinfo = ftgmac100_get_drvinfo, > > + .get_link = ethtool_op_get_link, > > + .get_link_ksettings = > > phy_ethtool_get_link_ksettings, > > + .set_link_ksettings = > > phy_ethtool_set_link_ksettings, > > + .nway_reset = ftgmac100_nway_reset, > > + .get_ringparam = ftgmac100_get_ringparam, > > + .set_ringparam = ftgmac100_set_ringparam, > > + .get_pauseparam = ftgmac100_get_pauseparam, > > + .set_pauseparam = ftgmac100_set_pauseparam, > > +}; > > + > > +static void ftgmac100_free_tx_buffers(struct ftgmac100 *priv) > >  { > > - priv->tx_pointer = ftgmac100_next_tx_pointer(priv- > > >tx_pointer); > > + int i; > > + > > + /* Free all tx buffers */ > > + for (i = 0; i < priv->tx_q_entries; i++) { > > + struct ftgmac100_txdes *txdes = &priv->txdes[i]; > > + > > + if (!priv->tx_skbs[i]) > > + continue; > > + ftgmac100_free_tx_packet(priv, i, txdes); > > + } > >  } > >   > > -static void ftgmac100_tx_clean_pointer_advance(struct ftgmac100 > > *priv) > > +static void ftgmac100_free_rx_buffers(struct ftgmac100 *priv) > >  { > > - priv->tx_clean_pointer = ftgmac100_next_tx_pointer(priv- > > >tx_clean_pointer); > > + int i; > > + > > + /* Free all RX buffers */ > > + for (i = 0; i < priv->rx_q_entries; i++) { > > + struct ftgmac100_rxdes *rxdes = &priv->rxdes[i]; > > + struct sk_buff *skb = priv->rx_skbs[i]; > > + dma_addr_t map = > > ftgmac100_rxdes_get_dma_addr(rxdes); > > + > > + if (!skb) > > + continue; > > + > > + priv->rx_skbs[i] = NULL; > > + dma_unmap_page(priv->dev, map, RX_BUF_SIZE, > > DMA_FROM_DEVICE); > > + dev_kfree_skb_any(skb); > > + } > >  } > >   > > -static struct ftgmac100_txdes *ftgmac100_current_txdes(struct > > ftgmac100 *priv) > > +static void ftgmac100_free_descriptors(struct ftgmac100 *priv) > >  { > > - return &priv->descs->txdes[priv->tx_pointer]; > > + /* Free skb arrays */ > > + if (priv->rx_skbs) > > + kfree(priv->rx_skbs); > > + if (priv->tx_skbs) > > + kfree(priv->tx_skbs); > > + > > + /* Free descriptor arrays */ > > + if (priv->rxdes) > > + dma_free_coherent(priv->dev, MAX_RX_QUEUE_ENTRIES > > * > > +   sizeof(struct ftgmac100_rxdes), > > +   priv->rxdes, priv->rxdes_dma); > > + priv->rxdes = NULL; > > + if (priv->txdes) > > + dma_free_coherent(priv->dev, MAX_TX_QUEUE_ENTRIES > > * > > +   sizeof(struct ftgmac100_txdes), > > +   priv->txdes, priv->txdes_dma); > > + priv->txdes = NULL; > > + > > + /* Free scratch packet buffer */ > > + if (priv->rx_scratch) > > + dma_free_coherent(priv->dev, RX_BUF_SIZE, > > +   priv->rx_scratch, priv- > > >rx_scratch_dma); > >  } > >   > > -static struct ftgmac100_txdes * > > -ftgmac100_current_clean_txdes(struct ftgmac100 *priv) > > +static void ftgmac100_init_descriptors(struct ftgmac100 *priv) > >  { > > - return &priv->descs->txdes[priv->tx_clean_pointer]; > > + int i; > > + > > + /* Update entries counts */ > > + priv->rx_q_entries = priv->new_rx_q_entries; > > + priv->tx_q_entries = priv->new_tx_q_entries; > > + > > + /* > > +  * Clean all rx and tx descriptors and set the end-of-ring > > +  * marker on the last entry. For the RX descriptor, > > populate > > +  * all entries with a DMA address pointing to the scratch > > +  * page. > > +  */ > > + for (i = 0; i < priv->rx_q_entries; i++) { > > + priv->rxdes[i].rxdes0 = 0; > > + ftgmac100_rxdes_set_dma_addr(&priv->rxdes[i], > > priv->rx_scratch_dma); > > + } > > + priv->rxdes[i - 1].rxdes0 = cpu_to_le32(priv- > > >rxdes0_edorr_mask); > > + for (i = 0; i < priv->tx_q_entries; i++) > > + priv->txdes[i].txdes0 = 0; > > + priv->txdes[i - 1].txdes0 = cpu_to_le32(priv- > > >txdes0_edotr_mask); > >  } > >   > > -static bool ftgmac100_tx_complete_packet(struct ftgmac100 *priv) > > +static int ftgmac100_alloc_descriptors(struct ftgmac100 *priv) > >  { > > - struct net_device *netdev = priv->netdev; > > - struct ftgmac100_txdes *txdes; > > - struct sk_buff *skb; > > - dma_addr_t map; > > + /* Allocate skb arrays */ > > + priv->rx_skbs = kzalloc(MAX_RX_QUEUE_ENTRIES * sizeof(void > > *), GFP_KERNEL); > > + if (!priv->rx_skbs) > > + return -ENOMEM; > > + priv->tx_skbs = kzalloc(MAX_TX_QUEUE_ENTRIES * sizeof(void > > *), GFP_KERNEL); > > + if (!priv->tx_skbs) > > + return -ENOMEM; > >   > > - if (priv->tx_pending == 0) > > - return false; > > + /* Allocate descriptor arrays */ > > + priv->rxdes = dma_zalloc_coherent(priv->dev, > > +   MAX_RX_QUEUE_ENTRIES * > > +   sizeof(struct > > ftgmac100_rxdes), > > +   &priv->rxdes_dma, > > GFP_KERNEL); > > + if (!priv->rxdes) > > + return -ENOMEM > > +; priv->txdes = dma_zalloc_coherent(priv->dev, > > +   MAX_TX_QUEUE_ENTRIES * > > +   sizeof(struct > > ftgmac100_txdes), > > +   &priv->txdes_dma, > > GFP_KERNEL); > > + if (!priv->txdes) > > + return -ENOMEM; > >   > > - txdes = ftgmac100_current_clean_txdes(priv); > > + /* 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; > >   > > - if (ftgmac100_txdes_owned_by_dma(txdes)) > > - return false; > > + return 0; > > +} > >   > > - skb = ftgmac100_txdes_get_skb(txdes); > > - map = ftgmac100_txdes_get_dma_addr(txdes); > > +static int ftgmac100_alloc_rx_buffers(struct ftgmac100 *priv) > > +{ > > + int i; > >   > > - netdev->stats.tx_packets++; > > - netdev->stats.tx_bytes += skb->len; > > + /* Populate RX ring */ > > + for (i = 0; i < priv->rx_q_entries; i++) { > > + /* > > +  * Give up on error, the entries have been pre- > > populated > > +  * with the address of the scratch page > > +  */ > > + if (ftgmac100_alloc_rx_buf(priv, i, GFP_KERNEL)) > > + return ENOMEM;; > > + } > > + return 0; > > +} > >   > > - dma_unmap_single(priv->dev, map, skb_headlen(skb), > > DMA_TO_DEVICE); > > +static void ftgmac100_init_all(struct ftgmac100 *priv) > > +{ > > + if (!netif_running(priv->ndev)) > > + return; > >   > > - dev_kfree_skb(skb); > > + /* Re-init descriptors (adjust queue sizes) */ > > + ftgmac100_init_descriptors(priv); > >   > > - ftgmac100_txdes_reset(priv, txdes); > > + /* Realloc rx descriptors */ > > + ftgmac100_alloc_rx_buffers(priv); > >   > > - ftgmac100_tx_clean_pointer_advance(priv); > > + /* Reinit and restart HW */ > > + ftgmac100_init_hw(priv); > > + ftgmac100_config_pause(priv); > > + ftgmac100_start_mac(priv); > >   > > - spin_lock(&priv->tx_lock); > > - priv->tx_pending--; > > - spin_unlock(&priv->tx_lock); > > - netif_wake_queue(netdev); > > + /* Re-enable the device */ > > + napi_enable(&priv->napi); > > + netif_start_queue(priv->ndev); > >   > > - return true; > > + /* Enable all interrupts */ > > + iowrite32(FTGMAC100_INT_ALL, priv->base + > > FTGMAC100_OFFSET_IER); > >  } > >   > > -static void ftgmac100_tx_complete(struct ftgmac100 *priv) > > +static int ftgmac100_open(struct net_device *ndev) > >  { > > - while (ftgmac100_tx_complete_packet(priv)) > > - ; > > -} > > + struct ftgmac100 *priv = netdev_priv(ndev); > > + int err; > >   > > -static int ftgmac100_xmit(struct ftgmac100 *priv, struct sk_buff > > *skb, > > -   dma_addr_t map) > > -{ > > - struct net_device *netdev = priv->netdev; > > - struct ftgmac100_txdes *txdes; > > - unsigned int len = (skb->len < ETH_ZLEN) ? ETH_ZLEN : skb- > > >len; > > + /* Clear stale stopping flag */ > > + priv->stopping = false; > >   > > - txdes = ftgmac100_current_txdes(priv); > > - ftgmac100_tx_pointer_advance(priv); > > + /* Allocate ring buffers and populate Rx ring */ > > + err = ftgmac100_alloc_descriptors(priv); > > + if (err) { > > + netdev_err(ndev, "failed to allocate > > descriptors\n"); > > + goto err_alloc; > > + } > >   > > - /* setup TX descriptor */ > > - ftgmac100_txdes_set_skb(txdes, skb); > > - ftgmac100_txdes_set_dma_addr(txdes, map); > > - ftgmac100_txdes_set_buffer_size(txdes, len); > > + /* > > +  * 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; > > + } > >   > > - 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; > > + /* Reset the hardware */ > > + err = ftgmac100_reset_and_config_mac(priv); > > + if (err) > > + goto err_hw; > >   > > - if (protocol == cpu_to_be16(ETH_P_IP)) { > > - u8 ip_proto = ip_hdr(skb)->protocol; > > + /* Initialize NAPI */ > > + netif_napi_add(ndev, &priv->napi, ftgmac100_poll, > > NAPI_POLL_WEIGHT); > > + > > + /* Disable all interrupts */ > > + iowrite32(0, priv->base + FTGMAC100_OFFSET_IER); > > + > > + /* Grab our interrupt */ > > + err = request_irq(ndev->irq, ftgmac100_interrupt, 0, > > +   ndev->name, ndev); > > + if (err) { > > + netdev_err(ndev, "failed to request irq %d\n", > > ndev->irq); > > + goto err_irq; > > + } > > + > > + /* Start thing up */ > > + ftgmac100_init_all(priv); > > + if (ndev->phydev) { > > + /* If we have a PHY, start polling */ > > + phy_start(ndev->phydev); > > + } else if (priv->use_ncsi) { > > + /* If using NC-SI, set our carrier on and start > > the stack */ > > + netif_carrier_on(ndev); > > + > > + /* Start the NCSI device */ > > + err = ncsi_start_dev(priv->ncsidev); > > + if (err) > > + goto err_ncsi; > > + } > > + > > + return 0; > > + > > + err_ncsi: > > + napi_disable(&priv->napi); > > + netif_stop_queue(ndev); > > + free_irq(ndev->irq, ndev); > > + err_irq: > > + netif_napi_del(&priv->napi); > > + err_hw: > > + err_alloc: > > + iowrite32(0, priv->base + FTGMAC100_OFFSET_IER); > > + ftgmac100_free_tx_buffers(priv); > > + ftgmac100_free_rx_buffers(priv); > > + ftgmac100_free_descriptors(priv); > > + return err; > > +} > >   > > - 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); > > - } > > - } > > +static int ftgmac100_stop(struct net_device *ndev) > > +{ > > + struct ftgmac100 *priv = netdev_priv(ndev); > >   > > - spin_lock(&priv->tx_lock); > > - priv->tx_pending++; > > - if (priv->tx_pending == TX_QUEUE_ENTRIES) > > - netif_stop_queue(netdev); > > + /* Block reset task */ > > + priv->stopping = true; > >   > > - /* start transmit */ > > - ftgmac100_txdes_set_dma_own(txdes); > > - spin_unlock(&priv->tx_lock); > > + /* Kill any pending one */ > > + cancel_work_sync(&priv->reset_task); > >   > > - ftgmac100_txdma_normal_prio_start_polling(priv); > > + /* Disable all interrupts */ > > + iowrite32(0, priv->base + FTGMAC100_OFFSET_IER); > >   > > - return NETDEV_TX_OK; > > -} > > + /* Stop the PHY or NCSI */ > > + if (ndev->phydev) > > + phy_stop(ndev->phydev); > > + else if (priv->use_ncsi) > > + ncsi_stop_dev(priv->ncsidev); > >   > > -/***************************************************************** > > ************* > > - * internal functions (buffer) > > - > > ******************************************************************* > > **********/ > > -static int ftgmac100_alloc_rx_page(struct ftgmac100 *priv, > > -    struct ftgmac100_rxdes *rxdes, > > gfp_t gfp) > > -{ > > - struct net_device *netdev = priv->netdev; > > - struct page *page; > > - dma_addr_t map; > > + /* Stop the network stack */ > > + netif_stop_queue(ndev); > > + napi_disable(&priv->napi); > > + netif_napi_del(&priv->napi); > >   > > - page = alloc_page(gfp); > > - if (!page) { > > - if (net_ratelimit()) > > - netdev_err(netdev, "failed to allocate rx > > page\n"); > > - return -ENOMEM; > > - } > > + /* Stop the HW */ > > + ftgmac100_stop_mac(priv); > >   > > - map = dma_map_page(priv->dev, page, 0, 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"); > > - __free_page(page); > > - return -ENOMEM; > > - } > > + /* No more IRQ for us */ > > + free_irq(ndev->irq, ndev); > > + > > + /* Free everything */ > > + ftgmac100_free_tx_buffers(priv); > > + ftgmac100_free_rx_buffers(priv); > > + ftgmac100_free_descriptors(priv); > >   > > - ftgmac100_rxdes_set_page(priv, rxdes, page); > > - ftgmac100_rxdes_set_dma_addr(rxdes, map); > > - ftgmac100_rxdes_set_dma_own(priv, rxdes); > >   return 0; > >  } > >   > > -static void ftgmac100_free_buffers(struct ftgmac100 *priv) > > +static void ftgmac100_reset_task(struct work_struct *work) > >  { > > - int i; > > + struct ftgmac100 *priv = container_of(work, struct > > ftgmac100, reset_task); > > + struct net_device *ndev = priv->ndev; > > + int err; > >   > > - for (i = 0; i < RX_QUEUE_ENTRIES; i++) { > > - struct ftgmac100_rxdes *rxdes = &priv->descs- > > >rxdes[i]; > > - struct page *page = ftgmac100_rxdes_get_page(priv, > > rxdes); > > - dma_addr_t map = > > ftgmac100_rxdes_get_dma_addr(rxdes); > > + /* Adapter is going down */ > > + if (priv->stopping) > > + return; > >   > > - if (!page) > > - continue; > > + netdev_dbg(ndev, "Resetting NIC...\n"); > >   > > - dma_unmap_page(priv->dev, map, RX_BUF_SIZE, > > DMA_FROM_DEVICE); > > - __free_page(page); > > - } > > + /* Block PHY polling */ > > + if (ndev->phydev) > > + mutex_lock(&ndev->phydev->lock); > >   > > - for (i = 0; i < TX_QUEUE_ENTRIES; i++) { > > - struct ftgmac100_txdes *txdes = &priv->descs- > > >txdes[i]; > > - struct sk_buff *skb = > > ftgmac100_txdes_get_skb(txdes); > > - dma_addr_t map = > > ftgmac100_txdes_get_dma_addr(txdes); > > + rtnl_lock(); > >   > > - if (!skb) > > - continue; > > + /* Check if link state changed again */ > > + if (priv->cur_speed == 0) > > + goto bail; > > + > > + /* Stop the network stack */ > > + netif_trans_update(ndev); > > + napi_disable(&priv->napi); > > + netif_tx_disable(ndev); > >   > > - dma_unmap_single(priv->dev, map, skb_headlen(skb), > > DMA_TO_DEVICE); > > - kfree_skb(skb); > > + /* Stop and reset the MAC */ > > + ftgmac100_stop_mac(priv); > > + err = ftgmac100_reset_and_config_mac(priv); > > + if (err) { > > + /* Not much we can do ... it might come back... */ > > + netdev_err(ndev, "attempting to continue...\n"); > >   } > >   > > - dma_free_coherent(priv->dev, sizeof(struct > > ftgmac100_descs), > > -   priv->descs, priv->descs_dma_addr); > > + /* Free all rx and tx buffers */ > > + ftgmac100_free_tx_buffers(priv); > > + ftgmac100_free_rx_buffers(priv); > > + > > + /* Setup everything and restart chip */ > > + ftgmac100_init_all(priv); > > + > > + netdev_dbg(ndev, "Reset done !\n"); > > + bail: > > + rtnl_unlock(); > > + > > + /* Unblock PHY polling */ > > + if (ndev->phydev) > > + mutex_unlock(&ndev->phydev->lock); > >  } > >   > > -static int ftgmac100_alloc_buffers(struct ftgmac100 *priv) > > +static void ftgmac100_tx_timeout(struct net_device *ndev) > >  { > > - int i; > > + struct ftgmac100 *priv = netdev_priv(ndev); > >   > > - priv->descs = dma_zalloc_coherent(priv->dev, > > -   sizeof(struct > > ftgmac100_descs), > > -   &priv->descs_dma_addr, > > GFP_KERNEL); > > - if (!priv->descs) > > - return -ENOMEM; > > - > > - /* initialize RX ring */ > > - ftgmac100_rxdes_set_end_of_ring(priv, > > - &priv->descs->rxdes[RX_QUEUE_ENTRIES - > > 1]); > > + /* Disable all interrupts */ > > + iowrite32(0, priv->base + FTGMAC100_OFFSET_IER); > >   > > - for (i = 0; i < RX_QUEUE_ENTRIES; i++) { > > - struct ftgmac100_rxdes *rxdes = &priv->descs- > > >rxdes[i]; > > + /* Do the reset outside of interrupt context */ > > + schedule_work(&priv->reset_task); > > +} > >   > > - if (ftgmac100_alloc_rx_page(priv, rxdes, > > GFP_KERNEL)) > > - goto err; > > - } > > +#ifdef CONFIG_NET_POLL_CONTROLLER > > +static void ftgmac100_netpoll(struct net_device *ndev) > > +{ > > + disable_irq(dev->irq); > > + ftgmac100_interrupt(dev->irq, ndev); > > + enable_irq(dev->irq); > > +} > > +#endif > >   > > - /* initialize TX ring */ > > - ftgmac100_txdes_set_end_of_ring(priv, > > - &priv->descs->txdes[TX_QUEUE_ENTRIES - > > 1]); > > - return 0; > > +static const struct net_device_ops ftgmac100_netdev_ops = { > > + .ndo_open = ftgmac100_open, > > + .ndo_stop = ftgmac100_stop, > > + .ndo_start_xmit = > > ftgmac100_hard_start_xmit, > > + .ndo_set_mac_address = ftgmac100_set_mac_addr, > > +        .ndo_set_rx_mode = ftgmac100_set_rx_mode, > > + .ndo_validate_addr = eth_validate_addr, > > + .ndo_do_ioctl = ftgmac100_do_ioctl, > > + .ndo_tx_timeout = ftgmac100_tx_timeout, > > +#ifdef CONFIG_NET_POLL_CONTROLLER > > + .ndo_poll_controller = ftgmac100_poll_controller, > > +#endif > > +}; > >   > > -err: > > - ftgmac100_free_buffers(priv); > > - return -ENOMEM; > > +static const char *ftgmac100_fctrl_string(struct ftgmac100 *priv) > > +{ > > + if (priv->tx_pause && priv->rx_pause) > > + return "rx/tx"; > > + else if (priv->rx_pause) > > + return "rx"; > > + else if (priv->tx_pause) > > + return "tx"; > > + else > > + return "no"; > >  } > >   > > -/***************************************************************** > > ************* > > - * internal functions (mdio) > > - > > ******************************************************************* > > **********/ > > -static void ftgmac100_adjust_link(struct net_device *netdev) > > +static void ftgmac100_adjust_link(struct net_device *ndev) > >  { > > - struct ftgmac100 *priv = netdev_priv(netdev); > > - struct phy_device *phydev = netdev->phydev; > > - int ier; > > + struct ftgmac100 *priv = netdev_priv(ndev); > > + struct phy_device *phydev = ndev->phydev; > > + bool tx_pause, rx_pause; > > + > > + /* Link is down */ > > + if (!phydev->link) { > > + if (priv->cur_speed) > > + netdev_info(ndev, "Link down\n"); > > + priv->cur_speed = 0; > >   > > - if (phydev->speed == priv->old_speed) > > + /* > > +  * We just stop the MAC, we'll reset the adapter > > +  * if/when the link comes back up > > +  */ > > + ftgmac100_stop_mac(priv); > >   return; > > + } > > + > > + /* Grab pause settings from PHY if configured to do so */ > > + if (priv->aneg_pause) { > > + rx_pause = tx_pause = phydev->pause; > > + if (phydev->asym_pause) > > + tx_pause = !rx_pause; > > + } else { > > + rx_pause = priv->rx_pause; > > + tx_pause = priv->tx_pause; > > + } > >   > > - priv->old_speed = phydev->speed; > > + /* Link hasn't changed, do nothing */ > > + if (phydev->speed == priv->cur_speed && > > +     phydev->duplex == priv->cur_duplex && > > +     rx_pause == priv->rx_pause && > > +     tx_pause == priv->tx_pause) > > + return; > >   > > - ier = ioread32(priv->base + FTGMAC100_OFFSET_IER); > > + priv->cur_speed = phydev->speed; > > + priv->cur_duplex = phydev->duplex; > > + priv->rx_pause = rx_pause; > > + priv->tx_pause = tx_pause; > >   > > - /* disable all interrupts */ > > - iowrite32(0, priv->base + FTGMAC100_OFFSET_IER); > > + netdev_info(ndev, "Link up at %d Mbit/s %s duplex %s flow > > ctrl\n", > > +     priv->cur_speed, > > +     phydev->duplex == DUPLEX_FULL ? "full" : > > "half", > > +     ftgmac100_fctrl_string(priv)); > >   > > - netif_stop_queue(netdev); > > - ftgmac100_stop_hw(priv); > >   > > - netif_start_queue(netdev); > > - ftgmac100_init_hw(priv); > > - ftgmac100_start_hw(priv, phydev->speed); > > + /* Disable all interrupts */ > > + iowrite32(0, priv->base + FTGMAC100_OFFSET_IER); > >   > > - /* re-enable interrupts */ > > - iowrite32(ier, priv->base + FTGMAC100_OFFSET_IER); > > + /* Reset the adapter asynchronously */ > > + schedule_work(&priv->reset_task); > >  } > >   > >  static int ftgmac100_mii_probe(struct ftgmac100 *priv) > >  { > > - struct net_device *netdev = priv->netdev; > > + struct net_device *ndev = priv->ndev; > >   struct phy_device *phydev; > >   > >   phydev = phy_find_first(priv->mii_bus); > >   if (!phydev) { > > - netdev_info(netdev, "%s: no PHY found\n", netdev- > > >name); > > + netdev_info(ndev, "%s: no PHY found\n", ndev- > > >name); > >   return -ENODEV; > >   } > >   > > - phydev = phy_connect(netdev, phydev_name(phydev), > > + phydev = phy_connect(ndev, phydev_name(phydev), > >        &ftgmac100_adjust_link, > > PHY_INTERFACE_MODE_GMII); > >   > >   if (IS_ERR(phydev)) { > > - netdev_err(netdev, "%s: Could not attach to > > PHY\n", netdev->name); > > + netdev_err(ndev, "%s: Could not attach to PHY\n", > > ndev->name); > >   return PTR_ERR(phydev); > >   } > >   > >   return 0; > >  } > >   > > -/***************************************************************** > > ************* > > - * struct mii_bus functions > > - > > ******************************************************************* > > **********/ > > -static int ftgmac100_mdiobus_read(struct mii_bus *bus, int > > phy_addr, int regnum) > > +static int ftgmac100_mii_read(struct mii_bus *bus, int phy_addr, > > int regnum) > >  { > > - struct net_device *netdev = bus->priv; > > - struct ftgmac100 *priv = netdev_priv(netdev); > > + struct net_device *ndev = bus->priv; > > + struct ftgmac100 *priv = netdev_priv(ndev); > >   unsigned int phycr; > >   int i; > >   > > @@ -951,15 +1438,15 @@ static int ftgmac100_mdiobus_read(struct > > mii_bus *bus, int phy_addr, int regnum) > >   udelay(100); > >   } > >   > > - netdev_err(netdev, "mdio read timed out\n"); > > + netdev_err(ndev, "mdio read timed out\n"); > >   return -EIO; > >  } > >   > > -static int ftgmac100_mdiobus_write(struct mii_bus *bus, int > > phy_addr, > > -    int regnum, u16 value) > > +static int ftgmac100_mii_write(struct mii_bus *bus, int phy_addr, > > +        int regnum, u16 value) > >  { > > - struct net_device *netdev = bus->priv; > > - struct ftgmac100 *priv = netdev_priv(netdev); > > + struct net_device *ndev = bus->priv; > > + struct ftgmac100 *priv = netdev_priv(ndev); > >   unsigned int phycr; > >   int data; > >   int i; > > @@ -987,268 +1474,13 @@ static int ftgmac100_mdiobus_write(struct > > mii_bus *bus, int phy_addr, > >   udelay(100); > >   } > >   > > - netdev_err(netdev, "mdio write timed out\n"); > > + netdev_err(ndev, "mdio write timed out\n"); > >   return -EIO; > >  } > >   > > -/***************************************************************** > > ************* > > - * struct ethtool_ops functions > > - > > ******************************************************************* > > **********/ > > -static void ftgmac100_get_drvinfo(struct net_device *netdev, > > -   struct ethtool_drvinfo *info) > > -{ > > - 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)); > > -} > > - > > -static const struct ethtool_ops ftgmac100_ethtool_ops = { > > - .get_drvinfo = ftgmac100_get_drvinfo, > > - .get_link = ethtool_op_get_link, > > - .get_link_ksettings = > > phy_ethtool_get_link_ksettings, > > - .set_link_ksettings = > > phy_ethtool_set_link_ksettings, > > -}; > > - > > -/***************************************************************** > > ************* > > - * interrupt handler > > - > > ******************************************************************* > > **********/ > > -static irqreturn_t ftgmac100_interrupt(int irq, void *dev_id) > > -{ > > - struct net_device *netdev = dev_id; > > - struct ftgmac100 *priv = netdev_priv(netdev); > > - > > - /* When running in NCSI mode, the interface should be > > ready for > > -  * receiving or transmitting NCSI packets before it's > > opened. > > -  */ > > - if (likely(priv->use_ncsi || netif_running(netdev))) { > > - /* Disable interrupts for polling */ > > - iowrite32(0, priv->base + FTGMAC100_OFFSET_IER); > > - napi_schedule(&priv->napi); > > - } > > - > > - return IRQ_HANDLED; > > -} > > - > > -/***************************************************************** > > ************* > > - * struct napi_struct functions > > - > > ******************************************************************* > > **********/ > > -static int ftgmac100_poll(struct napi_struct *napi, int budget) > > -{ > > - struct ftgmac100 *priv = container_of(napi, struct > > ftgmac100, napi); > > - struct net_device *netdev = priv->netdev; > > - unsigned int status; > > - bool completed = true; > > - int rx = 0; > > - > > - status = ioread32(priv->base + FTGMAC100_OFFSET_ISR); > > - iowrite32(status, priv->base + FTGMAC100_OFFSET_ISR); > > - > > - if (status & (FTGMAC100_INT_RPKT_BUF | > > FTGMAC100_INT_NO_RXBUF)) { > > - /* > > -  * FTGMAC100_INT_RPKT_BUF: > > -  * RX DMA has received packets into RX > > buffer successfully > > -  * > > -  * FTGMAC100_INT_NO_RXBUF: > > -  * RX buffer unavailable > > -  */ > > - bool retry; > > - > > - do { > > - retry = ftgmac100_rx_packet(priv, &rx); > > - } while (retry && rx < budget); > > - > > - if (retry && rx == budget) > > - completed = false; > > - } > > - > > - if (status & (FTGMAC100_INT_XPKT_ETH | > > FTGMAC100_INT_XPKT_LOST)) { > > - /* > > -  * FTGMAC100_INT_XPKT_ETH: > > -  * packet transmitted to ethernet > > successfully > > -  * > > -  * FTGMAC100_INT_XPKT_LOST: > > -  * packet transmitted to ethernet lost due > > to late > > -  * collision or excessive collision > > -  */ > > - ftgmac100_tx_complete(priv); > > - } > > - > > - if (status & priv->int_mask_all & (FTGMAC100_INT_NO_RXBUF > > | > > - FTGMAC100_INT_RPKT_LOST | > > FTGMAC100_INT_AHB_ERR)) { > > - if (net_ratelimit()) > > - netdev_info(netdev, "[ISR] = 0x%x: > > %s%s%s\n", status, > > -     status & > > FTGMAC100_INT_NO_RXBUF ? "NO_RXBUF " : "", > > -     status & > > FTGMAC100_INT_RPKT_LOST ? "RPKT_LOST " : "", > > -     status & FTGMAC100_INT_AHB_ERR > > ? "AHB_ERR " : ""); > > - > > - if (status & FTGMAC100_INT_NO_RXBUF) { > > - /* RX buffer unavailable */ > > - netdev->stats.rx_over_errors++; > > - } > > - > > - if (status & FTGMAC100_INT_RPKT_LOST) { > > - /* received packet lost due to RX FIFO > > full */ > > - netdev->stats.rx_fifo_errors++; > > - } > > - } > > - > > - if (completed) { > > - napi_complete(napi); > > - > > - /* enable all interrupts */ > > - iowrite32(priv->int_mask_all, > > -   priv->base + FTGMAC100_OFFSET_IER); > > - } > > - > > - return rx; > > -} > > - > > -/***************************************************************** > > ************* > > - * struct net_device_ops functions > > - > > ******************************************************************* > > **********/ > > -static int ftgmac100_open(struct net_device *netdev) > > -{ > > - struct ftgmac100 *priv = netdev_priv(netdev); > > - unsigned int status; > > - int err; > > - > > - err = ftgmac100_alloc_buffers(priv); > > - if (err) { > > - netdev_err(netdev, "failed to allocate > > buffers\n"); > > - goto err_alloc; > > - } > > - > > - err = request_irq(priv->irq, ftgmac100_interrupt, 0, > > netdev->name, netdev); > > - if (err) { > > - netdev_err(netdev, "failed to request irq %d\n", > > priv->irq); > > - goto err_irq; > > - } > > - > > - priv->rx_pointer = 0; > > - priv->tx_clean_pointer = 0; > > - priv->tx_pointer = 0; > > - priv->tx_pending = 0; > > - > > - err = ftgmac100_reset_hw(priv); > > - if (err) > > - goto err_hw; > > - > > - ftgmac100_init_hw(priv); > > - ftgmac100_start_hw(priv, priv->use_ncsi ? 100 : 10); > > - > > - /* Clear stale interrupts */ > > - status = ioread32(priv->base + FTGMAC100_OFFSET_ISR); > > - iowrite32(status, priv->base + FTGMAC100_OFFSET_ISR); > > - > > - if (netdev->phydev) > > - phy_start(netdev->phydev); > > - else if (priv->use_ncsi) > > - netif_carrier_on(netdev); > > - > > - napi_enable(&priv->napi); > > - netif_start_queue(netdev); > > - > > - /* enable all interrupts */ > > - iowrite32(priv->int_mask_all, priv->base + > > FTGMAC100_OFFSET_IER); > > - > > - /* Start the NCSI device */ > > - if (priv->use_ncsi) { > > - err = ncsi_start_dev(priv->ndev); > > - if (err) > > - goto err_ncsi; > > - } > > - > > - priv->enabled = true; > > - > > - return 0; > > - > > -err_ncsi: > > - napi_disable(&priv->napi); > > - netif_stop_queue(netdev); > > - iowrite32(0, priv->base + FTGMAC100_OFFSET_IER); > > -err_hw: > > - free_irq(priv->irq, netdev); > > -err_irq: > > - ftgmac100_free_buffers(priv); > > -err_alloc: > > - return err; > > -} > > - > > -static int ftgmac100_stop(struct net_device *netdev) > > -{ > > - struct ftgmac100 *priv = netdev_priv(netdev); > > - > > - if (!priv->enabled) > > - return 0; > > - > > - /* disable all interrupts */ > > - priv->enabled = false; > > - iowrite32(0, priv->base + FTGMAC100_OFFSET_IER); > > - > > - netif_stop_queue(netdev); > > - napi_disable(&priv->napi); > > - if (netdev->phydev) > > - phy_stop(netdev->phydev); > > - else if (priv->use_ncsi) > > - ncsi_stop_dev(priv->ndev); > > - > > - ftgmac100_stop_hw(priv); > > - free_irq(priv->irq, netdev); > > - ftgmac100_free_buffers(priv); > > - > > - return 0; > > -} > > - > > -static int ftgmac100_hard_start_xmit(struct sk_buff *skb, > > -      struct net_device *netdev) > > -{ > > - struct ftgmac100 *priv = netdev_priv(netdev); > > - dma_addr_t map; > > - > > - if (unlikely(skb->len > MAX_PKT_SIZE)) { > > - if (net_ratelimit()) > > - netdev_dbg(netdev, "tx packet too big\n"); > > - > > - netdev->stats.tx_dropped++; > > - kfree_skb(skb); > > - return NETDEV_TX_OK; > > - } > > - > > - 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"); > > - > > - netdev->stats.tx_dropped++; > > - kfree_skb(skb); > > - return NETDEV_TX_OK; > > - } > > - > > - return ftgmac100_xmit(priv, skb, map); > > -} > > - > > -/* optional */ > > -static int ftgmac100_do_ioctl(struct net_device *netdev, struct > > ifreq *ifr, int cmd) > > -{ > > - if (!netdev->phydev) > > - return -ENXIO; > > - > > - return phy_mii_ioctl(netdev->phydev, ifr, cmd); > > -} > > - > > -static const struct net_device_ops ftgmac100_netdev_ops = { > > - .ndo_open = ftgmac100_open, > > - .ndo_stop = ftgmac100_stop, > > - .ndo_start_xmit = > > ftgmac100_hard_start_xmit, > > - .ndo_set_mac_address = ftgmac100_set_mac_addr, > > - .ndo_validate_addr = eth_validate_addr, > > - .ndo_do_ioctl = ftgmac100_do_ioctl, > > -}; > > - > > -static int ftgmac100_setup_mdio(struct net_device *netdev) > > +static int ftgmac100_setup_mdio(struct net_device *ndev) > >  { > > - struct ftgmac100 *priv = netdev_priv(netdev); > > + struct ftgmac100 *priv = netdev_priv(ndev); > >   struct platform_device *pdev = to_platform_device(priv- > > >dev); > >   int i, err = 0; > >   u32 reg; > > @@ -1258,8 +1490,9 @@ static int ftgmac100_setup_mdio(struct > > net_device *netdev) > >   if (!priv->mii_bus) > >   return -EIO; > >   > > - if (of_machine_is_compatible("aspeed,ast2400") || > > -     of_machine_is_compatible("aspeed,ast2500")) { > > + if (pdev->dev.of_node && > > +     (of_device_is_compatible(pdev->dev.of_node, > > "aspeed,ast2400-mac") || > > +      of_device_is_compatible(pdev->dev.of_node, > > "aspeed,ast2500-mac"))) { > >   /* This driver supports the old MDIO interface */ > >   reg = ioread32(priv->base + > > FTGMAC100_OFFSET_REVR); > >   reg &= ~FTGMAC100_REVR_NEW_MDIO_INTERFACE; > > @@ -1269,9 +1502,9 @@ static int ftgmac100_setup_mdio(struct > > net_device *netdev) > >   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; > > + priv->mii_bus->priv = priv->ndev; > > + priv->mii_bus->read = ftgmac100_mii_read; > > + priv->mii_bus->write = ftgmac100_mii_write; > >   > >   for (i = 0; i < PHY_MAX_ADDR; i++) > >   priv->mii_bus->irq[i] = PHY_POLL; > > @@ -1297,14 +1530,14 @@ err_register_mdiobus: > >   return err; > >  } > >   > > -static void ftgmac100_destroy_mdio(struct net_device *netdev) > > +static void ftgmac100_destroy_mdio(struct net_device *ndev) > >  { > > - struct ftgmac100 *priv = netdev_priv(netdev); > > + struct ftgmac100 *priv = netdev_priv(ndev); > >   > > - if (!netdev->phydev) > > + if (!ndev->phydev) > >   return; > >   > > - phy_disconnect(netdev->phydev); > > + phy_disconnect(ndev->phydev); > >   mdiobus_unregister(priv->mii_bus); > >   mdiobus_free(priv->mii_bus); > >  } > > @@ -1318,16 +1551,48 @@ static void ftgmac100_ncsi_handler(struct > > ncsi_dev *nd) > >       nd->link_up ? "up" : "down"); > >  } > >   > > -/***************************************************************** > > ************* > > - * struct platform_driver functions > > - > > ******************************************************************* > > **********/ > > +static void ftgmac100_initial_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->ndev->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->ndev->dev_addr, mac); > > + dev_info(priv->dev, "Read MAC address %pM from > > chip\n", mac); > > + } else { > > + eth_hw_addr_random(priv->ndev); > > + dev_info(priv->dev, "Generated random MAC address > > %pM\n", > > +  priv->ndev->dev_addr); > > + } > > +} > > + > >  static int ftgmac100_probe(struct platform_device *pdev) > >  { > >   struct resource *res; > > - int irq; > > - struct net_device *netdev; > > + struct net_device *ndev; > >   struct ftgmac100 *priv; > > - int err = 0; > > + struct device_node *np; > > + int irq, err = 0; > >   > >   if (!pdev) > >   return -ENODEV; > > @@ -1341,26 +1606,31 @@ static int ftgmac100_probe(struct > > platform_device *pdev) > >   return irq; > >   > >   /* setup net_device */ > > - netdev = alloc_etherdev(sizeof(*priv)); > > - if (!netdev) { > > + ndev = alloc_etherdev(sizeof(*priv)); > > + if (!ndev) { > >   err = -ENOMEM; > >   goto err_alloc_etherdev; > >   } > >   > > - SET_NETDEV_DEV(netdev, &pdev->dev); > > + SET_NETDEV_DEV(ndev, &pdev->dev); > >   > > - netdev->ethtool_ops = &ftgmac100_ethtool_ops; > > - netdev->netdev_ops = &ftgmac100_netdev_ops; > > + ndev->ethtool_ops = &ftgmac100_ethtool_ops; > > + ndev->netdev_ops = &ftgmac100_netdev_ops; > > + ndev->irq = irq; > >   > > - platform_set_drvdata(pdev, netdev); > > + platform_set_drvdata(pdev, ndev); > >   > >   /* setup private data */ > > - priv = netdev_priv(netdev); > > - priv->netdev = netdev; > > + priv = netdev_priv(ndev); > > + priv->ndev = ndev; > >   priv->dev = &pdev->dev; > > + priv->maht1 = 0; > > + priv->maht0 = 0; > > + INIT_WORK(&priv->reset_task, ftgmac100_reset_task); > >   > > - if (of_machine_is_compatible("aspeed,ast2400") || > > -     of_machine_is_compatible("aspeed,ast2500")) { > > + np = pdev->dev.of_node; > > + if (np && (of_device_is_compatible(np, "aspeed,ast2400- > > mac") || > > +    of_device_is_compatible(np, "aspeed,ast2500- > > mac"))) { > >   priv->rxdes0_edorr_mask = BIT(30); > >   priv->txdes0_edotr_mask = BIT(30); > >   } else { > > @@ -1368,11 +1638,6 @@ static int ftgmac100_probe(struct > > platform_device *pdev) > >   priv->txdes0_edotr_mask = BIT(15); > >   } > >   > > - spin_lock_init(&priv->tx_lock); > > - > > - /* initialize NAPI */ > > - netif_napi_add(netdev, &priv->napi, ftgmac100_poll, 64); > > - > >   /* map io memory */ > >   priv->res = request_mem_region(res->start, > > resource_size(res), > >          dev_name(&pdev->dev)); > > @@ -1389,19 +1654,15 @@ static int ftgmac100_probe(struct > > platform_device *pdev) > >   goto err_ioremap; > >   } > >   > > - priv->irq = irq; > > + /* Enable pause */ > > + priv->tx_pause = true; > > + priv->rx_pause = true; > > + priv->aneg_pause = true; > >   > >   /* MAC address from chip or random one */ > > - ftgmac100_setup_mac(priv); > > - > > - priv->int_mask_all = (FTGMAC100_INT_RPKT_LOST | > > -       FTGMAC100_INT_XPKT_ETH | > > -       FTGMAC100_INT_XPKT_LOST | > > -       FTGMAC100_INT_AHB_ERR | > > -       FTGMAC100_INT_RPKT_BUF | > > -       FTGMAC100_INT_NO_RXBUF); > > - if (pdev->dev.of_node && > > -     of_get_property(pdev->dev.of_node, "use-ncsi", NULL)) > > { > > + ftgmac100_initial_mac(priv); > > + > > + if (np && of_get_property(np, "use-ncsi", NULL)) { > >   if (!IS_ENABLED(CONFIG_NET_NCSI)) { > >   dev_err(&pdev->dev, "NCSI stack not > > enabled\n"); > >   goto err_ncsi_dev; > > @@ -1409,67 +1670,81 @@ static int ftgmac100_probe(struct > > platform_device *pdev) > >   > >   dev_info(&pdev->dev, "Using NCSI interface\n"); > >   priv->use_ncsi = true; > > - priv->ndev = ncsi_register_dev(netdev, > > ftgmac100_ncsi_handler); > > + priv->ncsidev = ncsi_register_dev(ndev, > > ftgmac100_ncsi_handler); > >   if (!priv->ndev) > >   goto err_ncsi_dev; > >   } else { > >   priv->use_ncsi = false; > > - err = ftgmac100_setup_mdio(netdev); > > + err = ftgmac100_setup_mdio(ndev); > >   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. > > -  */ > > - netdev->features = NETIF_F_IP_CSUM | NETIF_F_GRO; > > - if (priv->use_ncsi && > > -     of_get_property(pdev->dev.of_node, "no-hw-checksum", > > NULL)) > > - netdev->features &= ~NETIF_F_IP_CSUM; > > + /* Default ring sizes */ > > + priv->rx_q_entries = priv->new_rx_q_entries = > > DEF_RX_QUEUE_ENTRIES; > > + priv->tx_q_entries = priv->new_tx_q_entries = > > DEF_TX_QUEUE_ENTRIES; > >   > > + /* Setup feature set */ > > + ndev->hw_features = NETIF_F_RXCSUM | NETIF_F_GRO | > > NETIF_F_SG; > > + if (np && of_device_is_compatible(np, "aspeed,ast2500- > > mac")) > > + ndev->hw_features |= NETIF_F_IP_CSUM; > > + if (np && of_get_property(np, "no-hw-checksum", NULL)) > > + ndev->hw_features &= ~(NETIF_F_IP_CSUM | > > NETIF_F_RXCSUM); > > + ndev->features |= ndev->hw_features; > >   > >   /* register network device */ > > - err = register_netdev(netdev); > > + err = register_netdev(ndev); > >   if (err) { > >   dev_err(&pdev->dev, "Failed to register > > netdev\n"); > >   goto err_register_netdev; > >   } > >   > > - netdev_info(netdev, "irq %d, mapped at %p\n", priv->irq, > > priv->base); > > + netdev_info(ndev, "irq %d, mapped at %p\n", ndev->irq, > > priv->base); > >   > >   return 0; > >   > >  err_ncsi_dev: > >  err_register_netdev: > > - ftgmac100_destroy_mdio(netdev); > > + ftgmac100_destroy_mdio(ndev); > >  err_setup_mdio: > >   iounmap(priv->base); > >  err_ioremap: > >   release_resource(priv->res); > >  err_req_mem: > > - netif_napi_del(&priv->napi); > > - free_netdev(netdev); > > + free_netdev(ndev); > >  err_alloc_etherdev: > >   return err; > >  } > >   > >  static int __exit ftgmac100_remove(struct platform_device *pdev) > >  { > > - struct net_device *netdev; > > + struct net_device *ndev; > >   struct ftgmac100 *priv; > >   > > - netdev = platform_get_drvdata(pdev); > > - priv = netdev_priv(netdev); > > + ndev = platform_get_drvdata(pdev); > > + priv = netdev_priv(ndev); > > + > > + /* Preent the reset task from kicking early on */ > > + priv->stopping = true; > >   > > - unregister_netdev(netdev); > > - ftgmac100_destroy_mdio(netdev); > > + /* > > +  * Close & unregister the netdevice, at this points > > +  * the interrupt will be disabled > > +  */ > > + unregister_netdev(ndev); > > + > > + /* > > +  * There's a small chance the reset task will have been > > re-queued, > > +  * make sure it's gone before we free the structure > > +  */ > > + /* Kill any pending one */ > > + cancel_work_sync(&priv->reset_task); > > + > > + ftgmac100_destroy_mdio(ndev); > >   > >   iounmap(priv->base); > >   release_resource(priv->res); > > - > > - netif_napi_del(&priv->napi); > > - free_netdev(netdev); > > + free_netdev(ndev); > >   return 0; > >  } > >   > > diff --git a/drivers/net/ethernet/faraday/ftgmac100.h > > b/drivers/net/ethernet/faraday/ftgmac100.h > > index a7ce0ac..dd41763 100644 > > --- a/drivers/net/ethernet/faraday/ftgmac100.h > > +++ b/drivers/net/ethernet/faraday/ftgmac100.h > > @@ -86,6 +86,19 @@ > >  #define FTGMAC100_INT_PHYSTS_CHG (1 << 9) > >  #define FTGMAC100_INT_NO_HPTXBUF (1 << 10) > >   > > +/* These are all the interrupts we care about */ > > +#define FTGMAC100_INT_ALL (FTGMAC100_INT_RPKT_LOST | \ > > +    FTGMAC100_INT_XPKT_ETH | \ > > +    FTGMAC100_INT_XPKT_LOST | \ > > +    FTGMAC100_INT_AHB_ERR | \ > > +    FTGMAC100_INT_RPKT_BUF | \ > > +    FTGMAC100_INT_NO_RXBUF) > > + > > +/* These are the interrupts we care about in NAPI mode */ > > +#define FTGMAC100_INT_BAD (FTGMAC100_INT_RPKT_LOST | \ > > +    FTGMAC100_INT_AHB_ERR | \ > > +    FTGMAC100_INT_NO_RXBUF) > > + > >  /* > >   * Interrupt timer control register > >   */ > > @@ -185,6 +198,13 @@ > >  #define FTGMAC100_PHYDATA_MIIRDATA(phydata) (((phydata) >> > > 16) & 0xffff) > >   > >  /* > > + * Flow control register > > + */ > > +#define FTGMAC100_FCR_FC_EN (1 << 0) > > +#define FTGMAC100_FCR_FCTHR_EN (1 << 2) > > +#define FTGMAC100_FCR_PAUSE_TIME(x) (((x) & 0xffff) << 16) > > + > > +/* > >   * Transmit descriptor, aligned to 16 bytes > >   */ > >  struct ftgmac100_txdes { > > @@ -209,6 +229,79 @@ struct ftgmac100_txdes { > >  #define FTGMAC100_TXDES1_TX2FIC (1 << 30) > >  #define FTGMAC100_TXDES1_TXIC (1 << 31) > >   > > +static inline bool ftgmac100_txdes_owned_by_dma(struct > > ftgmac100_txdes *txdes) > > +{ > > + return txdes->txdes0 & > > cpu_to_le32(FTGMAC100_TXDES0_TXDMA_OWN); > > +} > > + > > +static inline void ftgmac100_txdes_set_dma_own(struct > > ftgmac100_txdes *txdes) > > +{ > > + txdes->txdes0 |= cpu_to_le32(FTGMAC100_TXDES0_TXDMA_OWN); > > +} > > + > > +static inline void ftgmac100_txdes_set_first_segment(struct > > ftgmac100_txdes *txdes) > > +{ > > + txdes->txdes0 |= cpu_to_le32(FTGMAC100_TXDES0_FTS); > > +} > > + > > +static inline bool ftgmac100_txdes_get_first_segment(struct > > ftgmac100_txdes *txdes) > > +{ > > + return (txdes->txdes0 & cpu_to_le32(FTGMAC100_TXDES0_FTS)) > > != 0; > > +} > > + > > +static inline void ftgmac100_txdes_set_last_segment(struct > > ftgmac100_txdes *txdes) > > +{ > > + txdes->txdes0 |= cpu_to_le32(FTGMAC100_TXDES0_LTS); > > +} > > + > > +static inline bool ftgmac100_txdes_get_last_segment(struct > > ftgmac100_txdes *txdes) > > +{ > > + return (txdes->txdes0 & cpu_to_le32(FTGMAC100_TXDES0_LTS)) > > != 0; > > +} > > + > > +static inline void ftgmac100_txdes_set_buffer_size(struct > > ftgmac100_txdes *txdes, > > +     unsigned int len) > > +{ > > + txdes->txdes0 |= > > cpu_to_le32(FTGMAC100_TXDES0_TXBUF_SIZE(len)); > > +} > > + > > +static inline unsigned int ftgmac100_txdes_get_buffer_size(struct > > ftgmac100_txdes *txdes) > > +{ > > + return FTGMAC100_TXDES0_TXBUF_SIZE(cpu_to_le32(txdes- > > >txdes0)); > > +} > > + > > + > > +static inline void ftgmac100_txdes_set_txint(struct > > ftgmac100_txdes *txdes) > > +{ > > + txdes->txdes1 |= cpu_to_le32(FTGMAC100_TXDES1_TXIC); > > +} > > + > > +static inline void ftgmac100_txdes_set_tcpcs(struct > > ftgmac100_txdes *txdes) > > +{ > > + txdes->txdes1 |= cpu_to_le32(FTGMAC100_TXDES1_TCP_CHKSUM); > > +} > > + > > +static inline void ftgmac100_txdes_set_udpcs(struct > > ftgmac100_txdes *txdes) > > +{ > > + txdes->txdes1 |= cpu_to_le32(FTGMAC100_TXDES1_UDP_CHKSUM); > > +} > > + > > +static inline void ftgmac100_txdes_set_ipcs(struct ftgmac100_txdes > > *txdes) > > +{ > > + txdes->txdes1 |= cpu_to_le32(FTGMAC100_TXDES1_IP_CHKSUM); > > +} > > + > > +static inline void ftgmac100_txdes_set_dma_addr(struct > > ftgmac100_txdes *txdes, > > + dma_addr_t addr) > > +{ > > + txdes->txdes3 = cpu_to_le32(addr); > > +} > > + > > +static inline dma_addr_t ftgmac100_txdes_get_dma_addr(struct > > ftgmac100_txdes *txdes) > > +{ > > + return le32_to_cpu(txdes->txdes3); > > +} > > + > >  /* > >   * Receive descriptor, aligned to 16 bytes > >   */ > > @@ -235,11 +328,11 @@ struct ftgmac100_rxdes { > >  #define FTGMAC100_RXDES0_RXPKT_RDY (1 << 31) > >   > >  #define FTGMAC100_RXDES1_VLANTAG_CI 0xffff > > -#define FTGMAC100_RXDES1_PROT_MASK (0x3 << 20) > > -#define FTGMAC100_RXDES1_PROT_NONIP (0x0 << 20) > > -#define FTGMAC100_RXDES1_PROT_IP (0x1 << 20) > > -#define FTGMAC100_RXDES1_PROT_TCPIP (0x2 << 20) > > -#define FTGMAC100_RXDES1_PROT_UDPIP (0x3 << 20) > > +#define FTGMAC100_RXDES1_PROT(x) (((x) >> 20) & 3) > > +#define   FTGMAC100_PROT_NONIP 0 > > +#define   FTGMAC100_PROT_IP 1 > > +#define   FTGMAC100_PROT_TCPIP 2 > > +#define   FTGMAC100_PROT_UDPIP 3 > >  #define FTGMAC100_RXDES1_LLC (1 << 22) > >  #define FTGMAC100_RXDES1_DF (1 << 23) > >  #define FTGMAC100_RXDES1_VLANTAG_AVAIL (1 << 24) > > @@ -247,4 +340,84 @@ struct ftgmac100_rxdes { > >  #define FTGMAC100_RXDES1_UDP_CHKSUM_ERR (1 << 26) > >  #define FTGMAC100_RXDES1_IP_CHKSUM_ERR (1 << 27) > >   > > +static bool ftgmac100_rxdes_first_segment(struct ftgmac100_rxdes > > *rxdes) > > +{ > > + return rxdes->rxdes0 & cpu_to_le32(FTGMAC100_RXDES0_FRS); > > +} > > + > > +static bool ftgmac100_rxdes_last_segment(struct ftgmac100_rxdes > > *rxdes) > > +{ > > + return rxdes->rxdes0 & cpu_to_le32(FTGMAC100_RXDES0_LRS); > > +} > > + > > +static bool ftgmac100_rxdes_packet_ready(struct ftgmac100_rxdes > > *rxdes) > > +{ > > + return rxdes->rxdes0 & > > cpu_to_le32(FTGMAC100_RXDES0_RXPKT_RDY); > > +} > > + > > +#define RXDES0_ANY_ERROR   \ > > + FTGMAC100_RXDES0_RX_ERR | \ > > + FTGMAC100_RXDES0_CRC_ERR | \ > > + FTGMAC100_RXDES0_FTL | \ > > + FTGMAC100_RXDES0_RUNT | \ > > + FTGMAC100_RXDES0_RX_ODD_NB > > + > > +static inline bool ftgmac100_rxdes_any_error(struct > > ftgmac100_rxdes *rxdes) > > +{ > > + return rxdes->rxdes0 & cpu_to_le32(RXDES0_ANY_ERROR); > > +} > > + > > +static inline bool ftgmac100_rxdes_rx_error(struct ftgmac100_rxdes > > *rxdes) > > +{ > > + return rxdes->rxdes0 & > > cpu_to_le32(FTGMAC100_RXDES0_RX_ERR); > > +} > > + > > +static inline bool ftgmac100_rxdes_crc_error(struct > > ftgmac100_rxdes *rxdes) > > +{ > > + return rxdes->rxdes0 & > > cpu_to_le32(FTGMAC100_RXDES0_CRC_ERR); > > +} > > + > > +static inline bool ftgmac100_rxdes_frame_too_long(struct > > ftgmac100_rxdes *rxdes) > > +{ > > + return rxdes->rxdes0 & cpu_to_le32(FTGMAC100_RXDES0_FTL); > > +} > > + > > +static inline bool ftgmac100_rxdes_runt(struct ftgmac100_rxdes > > *rxdes) > > +{ > > + return rxdes->rxdes0 & cpu_to_le32(FTGMAC100_RXDES0_RUNT); > > +} > > + > > +static inline bool ftgmac100_rxdes_odd_nibble(struct > > ftgmac100_rxdes *rxdes) > > +{ > > + return rxdes->rxdes0 & > > cpu_to_le32(FTGMAC100_RXDES0_RX_ODD_NB); > > +} > > + > > +static inline unsigned int ftgmac100_rxdes_data_length(struct > > ftgmac100_rxdes *rxdes) > > +{ > > + return le32_to_cpu(rxdes->rxdes0) & FTGMAC100_RXDES0_VDBC; > > +} > > + > > +static inline bool ftgmac100_rxdes_multicast(struct > > ftgmac100_rxdes *rxdes) > > +{ > > + return rxdes->rxdes0 & > > cpu_to_le32(FTGMAC100_RXDES0_MULTICAST); > > +} > > + > > +static inline void ftgmac100_rxdes_set_dma_addr(struct > > ftgmac100_rxdes *rxdes, > > +  dma_addr_t addr) > > +{ > > + rxdes->rxdes3 = cpu_to_le32(addr); > > +} > > + > > +static inline dma_addr_t ftgmac100_rxdes_get_dma_addr(struct > > ftgmac100_rxdes *rxdes) > > +{ > > + return le32_to_cpu(rxdes->rxdes3); > > +} > > + > > +static inline bool ftgmac100_rxdes_csum_err(struct ftgmac100_rxdes > > *rxdes) > > +{ > > + return !!(rxdes->rxdes1 & > > cpu_to_le32(FTGMAC100_RXDES1_TCP_CHKSUM_ERR | > > +       FTGMAC100_RXDES1_UDP > > _CHKSUM_ERR | > > +       FTGMAC100_RXDES1_IP_ > > CHKSUM_ERR)); > > +} > > + > >  #endif /* __FTGMAC100_H */ > >