162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 10G controller driver for Samsung SoCs 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (C) 2013 Samsung Electronics Co., Ltd. 562306a36Sopenharmony_ci * http://www.samsung.com 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Author: Siva Reddy Kallam <siva.kallam@samsung.com> 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <linux/clk.h> 1362306a36Sopenharmony_ci#include <linux/crc32.h> 1462306a36Sopenharmony_ci#include <linux/dma-mapping.h> 1562306a36Sopenharmony_ci#include <linux/etherdevice.h> 1662306a36Sopenharmony_ci#include <linux/ethtool.h> 1762306a36Sopenharmony_ci#include <linux/if.h> 1862306a36Sopenharmony_ci#include <linux/if_ether.h> 1962306a36Sopenharmony_ci#include <linux/if_vlan.h> 2062306a36Sopenharmony_ci#include <linux/init.h> 2162306a36Sopenharmony_ci#include <linux/interrupt.h> 2262306a36Sopenharmony_ci#include <linux/ip.h> 2362306a36Sopenharmony_ci#include <linux/kernel.h> 2462306a36Sopenharmony_ci#include <linux/mii.h> 2562306a36Sopenharmony_ci#include <linux/module.h> 2662306a36Sopenharmony_ci#include <linux/net_tstamp.h> 2762306a36Sopenharmony_ci#include <linux/netdevice.h> 2862306a36Sopenharmony_ci#include <linux/phy.h> 2962306a36Sopenharmony_ci#include <linux/platform_device.h> 3062306a36Sopenharmony_ci#include <linux/prefetch.h> 3162306a36Sopenharmony_ci#include <linux/skbuff.h> 3262306a36Sopenharmony_ci#include <linux/slab.h> 3362306a36Sopenharmony_ci#include <linux/tcp.h> 3462306a36Sopenharmony_ci#include <linux/sxgbe_platform.h> 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci#include "sxgbe_common.h" 3762306a36Sopenharmony_ci#include "sxgbe_desc.h" 3862306a36Sopenharmony_ci#include "sxgbe_dma.h" 3962306a36Sopenharmony_ci#include "sxgbe_mtl.h" 4062306a36Sopenharmony_ci#include "sxgbe_reg.h" 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci#define SXGBE_ALIGN(x) L1_CACHE_ALIGN(x) 4362306a36Sopenharmony_ci#define JUMBO_LEN 9000 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci/* Module parameters */ 4662306a36Sopenharmony_ci#define TX_TIMEO 5000 4762306a36Sopenharmony_ci#define DMA_TX_SIZE 512 4862306a36Sopenharmony_ci#define DMA_RX_SIZE 1024 4962306a36Sopenharmony_ci#define TC_DEFAULT 64 5062306a36Sopenharmony_ci#define DMA_BUFFER_SIZE BUF_SIZE_2KiB 5162306a36Sopenharmony_ci/* The default timer value as per the sxgbe specification 1 sec(1000 ms) */ 5262306a36Sopenharmony_ci#define SXGBE_DEFAULT_LPI_TIMER 1000 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_cistatic int debug = -1; 5562306a36Sopenharmony_cistatic int eee_timer = SXGBE_DEFAULT_LPI_TIMER; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_cimodule_param(eee_timer, int, 0644); 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_cimodule_param(debug, int, 0644); 6062306a36Sopenharmony_cistatic const u32 default_msg_level = (NETIF_MSG_DRV | NETIF_MSG_PROBE | 6162306a36Sopenharmony_ci NETIF_MSG_LINK | NETIF_MSG_IFUP | 6262306a36Sopenharmony_ci NETIF_MSG_IFDOWN | NETIF_MSG_TIMER); 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cistatic irqreturn_t sxgbe_common_interrupt(int irq, void *dev_id); 6562306a36Sopenharmony_cistatic irqreturn_t sxgbe_tx_interrupt(int irq, void *dev_id); 6662306a36Sopenharmony_cistatic irqreturn_t sxgbe_rx_interrupt(int irq, void *dev_id); 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci#define SXGBE_COAL_TIMER(x) (jiffies + usecs_to_jiffies(x)) 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci#define SXGBE_LPI_TIMER(x) (jiffies + msecs_to_jiffies(x)) 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci/** 7362306a36Sopenharmony_ci * sxgbe_verify_args - verify the driver parameters. 7462306a36Sopenharmony_ci * Description: it verifies if some wrong parameter is passed to the driver. 7562306a36Sopenharmony_ci * Note that wrong parameters are replaced with the default values. 7662306a36Sopenharmony_ci */ 7762306a36Sopenharmony_cistatic void sxgbe_verify_args(void) 7862306a36Sopenharmony_ci{ 7962306a36Sopenharmony_ci if (unlikely(eee_timer < 0)) 8062306a36Sopenharmony_ci eee_timer = SXGBE_DEFAULT_LPI_TIMER; 8162306a36Sopenharmony_ci} 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_cistatic void sxgbe_enable_eee_mode(const struct sxgbe_priv_data *priv) 8462306a36Sopenharmony_ci{ 8562306a36Sopenharmony_ci /* Check and enter in LPI mode */ 8662306a36Sopenharmony_ci if (!priv->tx_path_in_lpi_mode) 8762306a36Sopenharmony_ci priv->hw->mac->set_eee_mode(priv->ioaddr); 8862306a36Sopenharmony_ci} 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_civoid sxgbe_disable_eee_mode(struct sxgbe_priv_data * const priv) 9162306a36Sopenharmony_ci{ 9262306a36Sopenharmony_ci /* Exit and disable EEE in case of we are in LPI state. */ 9362306a36Sopenharmony_ci priv->hw->mac->reset_eee_mode(priv->ioaddr); 9462306a36Sopenharmony_ci del_timer_sync(&priv->eee_ctrl_timer); 9562306a36Sopenharmony_ci priv->tx_path_in_lpi_mode = false; 9662306a36Sopenharmony_ci} 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci/** 9962306a36Sopenharmony_ci * sxgbe_eee_ctrl_timer 10062306a36Sopenharmony_ci * @t: timer list containing a data 10162306a36Sopenharmony_ci * Description: 10262306a36Sopenharmony_ci * If there is no data transfer and if we are not in LPI state, 10362306a36Sopenharmony_ci * then MAC Transmitter can be moved to LPI state. 10462306a36Sopenharmony_ci */ 10562306a36Sopenharmony_cistatic void sxgbe_eee_ctrl_timer(struct timer_list *t) 10662306a36Sopenharmony_ci{ 10762306a36Sopenharmony_ci struct sxgbe_priv_data *priv = from_timer(priv, t, eee_ctrl_timer); 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci sxgbe_enable_eee_mode(priv); 11062306a36Sopenharmony_ci mod_timer(&priv->eee_ctrl_timer, SXGBE_LPI_TIMER(eee_timer)); 11162306a36Sopenharmony_ci} 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci/** 11462306a36Sopenharmony_ci * sxgbe_eee_init 11562306a36Sopenharmony_ci * @priv: private device pointer 11662306a36Sopenharmony_ci * Description: 11762306a36Sopenharmony_ci * If the EEE support has been enabled while configuring the driver, 11862306a36Sopenharmony_ci * if the GMAC actually supports the EEE (from the HW cap reg) and the 11962306a36Sopenharmony_ci * phy can also manage EEE, so enable the LPI state and start the timer 12062306a36Sopenharmony_ci * to verify if the tx path can enter in LPI state. 12162306a36Sopenharmony_ci */ 12262306a36Sopenharmony_cibool sxgbe_eee_init(struct sxgbe_priv_data * const priv) 12362306a36Sopenharmony_ci{ 12462306a36Sopenharmony_ci struct net_device *ndev = priv->dev; 12562306a36Sopenharmony_ci bool ret = false; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci /* MAC core supports the EEE feature. */ 12862306a36Sopenharmony_ci if (priv->hw_cap.eee) { 12962306a36Sopenharmony_ci /* Check if the PHY supports EEE */ 13062306a36Sopenharmony_ci if (phy_init_eee(ndev->phydev, true)) 13162306a36Sopenharmony_ci return false; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci priv->eee_active = 1; 13462306a36Sopenharmony_ci timer_setup(&priv->eee_ctrl_timer, sxgbe_eee_ctrl_timer, 0); 13562306a36Sopenharmony_ci priv->eee_ctrl_timer.expires = SXGBE_LPI_TIMER(eee_timer); 13662306a36Sopenharmony_ci add_timer(&priv->eee_ctrl_timer); 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci priv->hw->mac->set_eee_timer(priv->ioaddr, 13962306a36Sopenharmony_ci SXGBE_DEFAULT_LPI_TIMER, 14062306a36Sopenharmony_ci priv->tx_lpi_timer); 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci pr_info("Energy-Efficient Ethernet initialized\n"); 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci ret = true; 14562306a36Sopenharmony_ci } 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci return ret; 14862306a36Sopenharmony_ci} 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_cistatic void sxgbe_eee_adjust(const struct sxgbe_priv_data *priv) 15162306a36Sopenharmony_ci{ 15262306a36Sopenharmony_ci struct net_device *ndev = priv->dev; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci /* When the EEE has been already initialised we have to 15562306a36Sopenharmony_ci * modify the PLS bit in the LPI ctrl & status reg according 15662306a36Sopenharmony_ci * to the PHY link status. For this reason. 15762306a36Sopenharmony_ci */ 15862306a36Sopenharmony_ci if (priv->eee_enabled) 15962306a36Sopenharmony_ci priv->hw->mac->set_eee_pls(priv->ioaddr, ndev->phydev->link); 16062306a36Sopenharmony_ci} 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci/** 16362306a36Sopenharmony_ci * sxgbe_clk_csr_set - dynamically set the MDC clock 16462306a36Sopenharmony_ci * @priv: driver private structure 16562306a36Sopenharmony_ci * Description: this is to dynamically set the MDC clock according to the csr 16662306a36Sopenharmony_ci * clock input. 16762306a36Sopenharmony_ci */ 16862306a36Sopenharmony_cistatic void sxgbe_clk_csr_set(struct sxgbe_priv_data *priv) 16962306a36Sopenharmony_ci{ 17062306a36Sopenharmony_ci u32 clk_rate = clk_get_rate(priv->sxgbe_clk); 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci /* assign the proper divider, this will be used during 17362306a36Sopenharmony_ci * mdio communication 17462306a36Sopenharmony_ci */ 17562306a36Sopenharmony_ci if (clk_rate < SXGBE_CSR_F_150M) 17662306a36Sopenharmony_ci priv->clk_csr = SXGBE_CSR_100_150M; 17762306a36Sopenharmony_ci else if (clk_rate <= SXGBE_CSR_F_250M) 17862306a36Sopenharmony_ci priv->clk_csr = SXGBE_CSR_150_250M; 17962306a36Sopenharmony_ci else if (clk_rate <= SXGBE_CSR_F_300M) 18062306a36Sopenharmony_ci priv->clk_csr = SXGBE_CSR_250_300M; 18162306a36Sopenharmony_ci else if (clk_rate <= SXGBE_CSR_F_350M) 18262306a36Sopenharmony_ci priv->clk_csr = SXGBE_CSR_300_350M; 18362306a36Sopenharmony_ci else if (clk_rate <= SXGBE_CSR_F_400M) 18462306a36Sopenharmony_ci priv->clk_csr = SXGBE_CSR_350_400M; 18562306a36Sopenharmony_ci else if (clk_rate <= SXGBE_CSR_F_500M) 18662306a36Sopenharmony_ci priv->clk_csr = SXGBE_CSR_400_500M; 18762306a36Sopenharmony_ci} 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci/* minimum number of free TX descriptors required to wake up TX process */ 19062306a36Sopenharmony_ci#define SXGBE_TX_THRESH(x) (x->dma_tx_size/4) 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_cistatic inline u32 sxgbe_tx_avail(struct sxgbe_tx_queue *queue, int tx_qsize) 19362306a36Sopenharmony_ci{ 19462306a36Sopenharmony_ci return queue->dirty_tx + tx_qsize - queue->cur_tx - 1; 19562306a36Sopenharmony_ci} 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci/** 19862306a36Sopenharmony_ci * sxgbe_adjust_link 19962306a36Sopenharmony_ci * @dev: net device structure 20062306a36Sopenharmony_ci * Description: it adjusts the link parameters. 20162306a36Sopenharmony_ci */ 20262306a36Sopenharmony_cistatic void sxgbe_adjust_link(struct net_device *dev) 20362306a36Sopenharmony_ci{ 20462306a36Sopenharmony_ci struct sxgbe_priv_data *priv = netdev_priv(dev); 20562306a36Sopenharmony_ci struct phy_device *phydev = dev->phydev; 20662306a36Sopenharmony_ci u8 new_state = 0; 20762306a36Sopenharmony_ci u8 speed = 0xff; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci if (!phydev) 21062306a36Sopenharmony_ci return; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci /* SXGBE is not supporting auto-negotiation and 21362306a36Sopenharmony_ci * half duplex mode. so, not handling duplex change 21462306a36Sopenharmony_ci * in this function. only handling speed and link status 21562306a36Sopenharmony_ci */ 21662306a36Sopenharmony_ci if (phydev->link) { 21762306a36Sopenharmony_ci if (phydev->speed != priv->speed) { 21862306a36Sopenharmony_ci new_state = 1; 21962306a36Sopenharmony_ci switch (phydev->speed) { 22062306a36Sopenharmony_ci case SPEED_10000: 22162306a36Sopenharmony_ci speed = SXGBE_SPEED_10G; 22262306a36Sopenharmony_ci break; 22362306a36Sopenharmony_ci case SPEED_2500: 22462306a36Sopenharmony_ci speed = SXGBE_SPEED_2_5G; 22562306a36Sopenharmony_ci break; 22662306a36Sopenharmony_ci case SPEED_1000: 22762306a36Sopenharmony_ci speed = SXGBE_SPEED_1G; 22862306a36Sopenharmony_ci break; 22962306a36Sopenharmony_ci default: 23062306a36Sopenharmony_ci netif_err(priv, link, dev, 23162306a36Sopenharmony_ci "Speed (%d) not supported\n", 23262306a36Sopenharmony_ci phydev->speed); 23362306a36Sopenharmony_ci } 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci priv->speed = phydev->speed; 23662306a36Sopenharmony_ci priv->hw->mac->set_speed(priv->ioaddr, speed); 23762306a36Sopenharmony_ci } 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci if (!priv->oldlink) { 24062306a36Sopenharmony_ci new_state = 1; 24162306a36Sopenharmony_ci priv->oldlink = 1; 24262306a36Sopenharmony_ci } 24362306a36Sopenharmony_ci } else if (priv->oldlink) { 24462306a36Sopenharmony_ci new_state = 1; 24562306a36Sopenharmony_ci priv->oldlink = 0; 24662306a36Sopenharmony_ci priv->speed = SPEED_UNKNOWN; 24762306a36Sopenharmony_ci } 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci if (new_state & netif_msg_link(priv)) 25062306a36Sopenharmony_ci phy_print_status(phydev); 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci /* Alter the MAC settings for EEE */ 25362306a36Sopenharmony_ci sxgbe_eee_adjust(priv); 25462306a36Sopenharmony_ci} 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci/** 25762306a36Sopenharmony_ci * sxgbe_init_phy - PHY initialization 25862306a36Sopenharmony_ci * @ndev: net device structure 25962306a36Sopenharmony_ci * Description: it initializes the driver's PHY state, and attaches the PHY 26062306a36Sopenharmony_ci * to the mac driver. 26162306a36Sopenharmony_ci * Return value: 26262306a36Sopenharmony_ci * 0 on success 26362306a36Sopenharmony_ci */ 26462306a36Sopenharmony_cistatic int sxgbe_init_phy(struct net_device *ndev) 26562306a36Sopenharmony_ci{ 26662306a36Sopenharmony_ci char phy_id_fmt[MII_BUS_ID_SIZE + 3]; 26762306a36Sopenharmony_ci char bus_id[MII_BUS_ID_SIZE]; 26862306a36Sopenharmony_ci struct phy_device *phydev; 26962306a36Sopenharmony_ci struct sxgbe_priv_data *priv = netdev_priv(ndev); 27062306a36Sopenharmony_ci int phy_iface = priv->plat->interface; 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci /* assign default link status */ 27362306a36Sopenharmony_ci priv->oldlink = 0; 27462306a36Sopenharmony_ci priv->speed = SPEED_UNKNOWN; 27562306a36Sopenharmony_ci priv->oldduplex = DUPLEX_UNKNOWN; 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci if (priv->plat->phy_bus_name) 27862306a36Sopenharmony_ci snprintf(bus_id, MII_BUS_ID_SIZE, "%s-%x", 27962306a36Sopenharmony_ci priv->plat->phy_bus_name, priv->plat->bus_id); 28062306a36Sopenharmony_ci else 28162306a36Sopenharmony_ci snprintf(bus_id, MII_BUS_ID_SIZE, "sxgbe-%x", 28262306a36Sopenharmony_ci priv->plat->bus_id); 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci snprintf(phy_id_fmt, MII_BUS_ID_SIZE + 3, PHY_ID_FMT, bus_id, 28562306a36Sopenharmony_ci priv->plat->phy_addr); 28662306a36Sopenharmony_ci netdev_dbg(ndev, "%s: trying to attach to %s\n", __func__, phy_id_fmt); 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci phydev = phy_connect(ndev, phy_id_fmt, &sxgbe_adjust_link, phy_iface); 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci if (IS_ERR(phydev)) { 29162306a36Sopenharmony_ci netdev_err(ndev, "Could not attach to PHY\n"); 29262306a36Sopenharmony_ci return PTR_ERR(phydev); 29362306a36Sopenharmony_ci } 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci /* Stop Advertising 1000BASE Capability if interface is not GMII */ 29662306a36Sopenharmony_ci if ((phy_iface == PHY_INTERFACE_MODE_MII) || 29762306a36Sopenharmony_ci (phy_iface == PHY_INTERFACE_MODE_RMII)) 29862306a36Sopenharmony_ci phy_set_max_speed(phydev, SPEED_1000); 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci if (phydev->phy_id == 0) { 30162306a36Sopenharmony_ci phy_disconnect(phydev); 30262306a36Sopenharmony_ci return -ENODEV; 30362306a36Sopenharmony_ci } 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci netdev_dbg(ndev, "%s: attached to PHY (UID 0x%x) Link = %d\n", 30662306a36Sopenharmony_ci __func__, phydev->phy_id, phydev->link); 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci return 0; 30962306a36Sopenharmony_ci} 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci/** 31262306a36Sopenharmony_ci * sxgbe_clear_descriptors: clear descriptors 31362306a36Sopenharmony_ci * @priv: driver private structure 31462306a36Sopenharmony_ci * Description: this function is called to clear the tx and rx descriptors 31562306a36Sopenharmony_ci * in case of both basic and extended descriptors are used. 31662306a36Sopenharmony_ci */ 31762306a36Sopenharmony_cistatic void sxgbe_clear_descriptors(struct sxgbe_priv_data *priv) 31862306a36Sopenharmony_ci{ 31962306a36Sopenharmony_ci int i, j; 32062306a36Sopenharmony_ci unsigned int txsize = priv->dma_tx_size; 32162306a36Sopenharmony_ci unsigned int rxsize = priv->dma_rx_size; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci /* Clear the Rx/Tx descriptors */ 32462306a36Sopenharmony_ci for (j = 0; j < SXGBE_RX_QUEUES; j++) { 32562306a36Sopenharmony_ci for (i = 0; i < rxsize; i++) 32662306a36Sopenharmony_ci priv->hw->desc->init_rx_desc(&priv->rxq[j]->dma_rx[i], 32762306a36Sopenharmony_ci priv->use_riwt, priv->mode, 32862306a36Sopenharmony_ci (i == rxsize - 1)); 32962306a36Sopenharmony_ci } 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci for (j = 0; j < SXGBE_TX_QUEUES; j++) { 33262306a36Sopenharmony_ci for (i = 0; i < txsize; i++) 33362306a36Sopenharmony_ci priv->hw->desc->init_tx_desc(&priv->txq[j]->dma_tx[i]); 33462306a36Sopenharmony_ci } 33562306a36Sopenharmony_ci} 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_cistatic int sxgbe_init_rx_buffers(struct net_device *dev, 33862306a36Sopenharmony_ci struct sxgbe_rx_norm_desc *p, int i, 33962306a36Sopenharmony_ci unsigned int dma_buf_sz, 34062306a36Sopenharmony_ci struct sxgbe_rx_queue *rx_ring) 34162306a36Sopenharmony_ci{ 34262306a36Sopenharmony_ci struct sxgbe_priv_data *priv = netdev_priv(dev); 34362306a36Sopenharmony_ci struct sk_buff *skb; 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci skb = __netdev_alloc_skb_ip_align(dev, dma_buf_sz, GFP_KERNEL); 34662306a36Sopenharmony_ci if (!skb) 34762306a36Sopenharmony_ci return -ENOMEM; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci rx_ring->rx_skbuff[i] = skb; 35062306a36Sopenharmony_ci rx_ring->rx_skbuff_dma[i] = dma_map_single(priv->device, skb->data, 35162306a36Sopenharmony_ci dma_buf_sz, DMA_FROM_DEVICE); 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci if (dma_mapping_error(priv->device, rx_ring->rx_skbuff_dma[i])) { 35462306a36Sopenharmony_ci netdev_err(dev, "%s: DMA mapping error\n", __func__); 35562306a36Sopenharmony_ci dev_kfree_skb_any(skb); 35662306a36Sopenharmony_ci return -EINVAL; 35762306a36Sopenharmony_ci } 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci p->rdes23.rx_rd_des23.buf2_addr = rx_ring->rx_skbuff_dma[i]; 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci return 0; 36262306a36Sopenharmony_ci} 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci/** 36562306a36Sopenharmony_ci * sxgbe_free_rx_buffers - free what sxgbe_init_rx_buffers() allocated 36662306a36Sopenharmony_ci * @dev: net device structure 36762306a36Sopenharmony_ci * @p: dec pointer 36862306a36Sopenharmony_ci * @i: index 36962306a36Sopenharmony_ci * @dma_buf_sz: size 37062306a36Sopenharmony_ci * @rx_ring: ring to be freed 37162306a36Sopenharmony_ci * 37262306a36Sopenharmony_ci * Description: this function initializes the DMA RX descriptor 37362306a36Sopenharmony_ci */ 37462306a36Sopenharmony_cistatic void sxgbe_free_rx_buffers(struct net_device *dev, 37562306a36Sopenharmony_ci struct sxgbe_rx_norm_desc *p, int i, 37662306a36Sopenharmony_ci unsigned int dma_buf_sz, 37762306a36Sopenharmony_ci struct sxgbe_rx_queue *rx_ring) 37862306a36Sopenharmony_ci{ 37962306a36Sopenharmony_ci struct sxgbe_priv_data *priv = netdev_priv(dev); 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci kfree_skb(rx_ring->rx_skbuff[i]); 38262306a36Sopenharmony_ci dma_unmap_single(priv->device, rx_ring->rx_skbuff_dma[i], 38362306a36Sopenharmony_ci dma_buf_sz, DMA_FROM_DEVICE); 38462306a36Sopenharmony_ci} 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci/** 38762306a36Sopenharmony_ci * init_tx_ring - init the TX descriptor ring 38862306a36Sopenharmony_ci * @dev: net device structure 38962306a36Sopenharmony_ci * @queue_no: queue 39062306a36Sopenharmony_ci * @tx_ring: ring to be initialised 39162306a36Sopenharmony_ci * @tx_rsize: ring size 39262306a36Sopenharmony_ci * Description: this function initializes the DMA TX descriptor 39362306a36Sopenharmony_ci */ 39462306a36Sopenharmony_cistatic int init_tx_ring(struct device *dev, u8 queue_no, 39562306a36Sopenharmony_ci struct sxgbe_tx_queue *tx_ring, int tx_rsize) 39662306a36Sopenharmony_ci{ 39762306a36Sopenharmony_ci /* TX ring is not allcoated */ 39862306a36Sopenharmony_ci if (!tx_ring) { 39962306a36Sopenharmony_ci dev_err(dev, "No memory for TX queue of SXGBE\n"); 40062306a36Sopenharmony_ci return -ENOMEM; 40162306a36Sopenharmony_ci } 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci /* allocate memory for TX descriptors */ 40462306a36Sopenharmony_ci tx_ring->dma_tx = dma_alloc_coherent(dev, 40562306a36Sopenharmony_ci tx_rsize * sizeof(struct sxgbe_tx_norm_desc), 40662306a36Sopenharmony_ci &tx_ring->dma_tx_phy, GFP_KERNEL); 40762306a36Sopenharmony_ci if (!tx_ring->dma_tx) 40862306a36Sopenharmony_ci return -ENOMEM; 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci /* allocate memory for TX skbuff array */ 41162306a36Sopenharmony_ci tx_ring->tx_skbuff_dma = devm_kcalloc(dev, tx_rsize, 41262306a36Sopenharmony_ci sizeof(dma_addr_t), GFP_KERNEL); 41362306a36Sopenharmony_ci if (!tx_ring->tx_skbuff_dma) 41462306a36Sopenharmony_ci goto dmamem_err; 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci tx_ring->tx_skbuff = devm_kcalloc(dev, tx_rsize, 41762306a36Sopenharmony_ci sizeof(struct sk_buff *), GFP_KERNEL); 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci if (!tx_ring->tx_skbuff) 42062306a36Sopenharmony_ci goto dmamem_err; 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci /* assign queue number */ 42362306a36Sopenharmony_ci tx_ring->queue_no = queue_no; 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci /* initialise counters */ 42662306a36Sopenharmony_ci tx_ring->dirty_tx = 0; 42762306a36Sopenharmony_ci tx_ring->cur_tx = 0; 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci return 0; 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_cidmamem_err: 43262306a36Sopenharmony_ci dma_free_coherent(dev, tx_rsize * sizeof(struct sxgbe_tx_norm_desc), 43362306a36Sopenharmony_ci tx_ring->dma_tx, tx_ring->dma_tx_phy); 43462306a36Sopenharmony_ci return -ENOMEM; 43562306a36Sopenharmony_ci} 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci/** 43862306a36Sopenharmony_ci * free_rx_ring - free the RX descriptor ring 43962306a36Sopenharmony_ci * @dev: net device structure 44062306a36Sopenharmony_ci * @rx_ring: ring to be initialised 44162306a36Sopenharmony_ci * @rx_rsize: ring size 44262306a36Sopenharmony_ci * Description: this function initializes the DMA RX descriptor 44362306a36Sopenharmony_ci */ 44462306a36Sopenharmony_cistatic void free_rx_ring(struct device *dev, struct sxgbe_rx_queue *rx_ring, 44562306a36Sopenharmony_ci int rx_rsize) 44662306a36Sopenharmony_ci{ 44762306a36Sopenharmony_ci dma_free_coherent(dev, rx_rsize * sizeof(struct sxgbe_rx_norm_desc), 44862306a36Sopenharmony_ci rx_ring->dma_rx, rx_ring->dma_rx_phy); 44962306a36Sopenharmony_ci kfree(rx_ring->rx_skbuff_dma); 45062306a36Sopenharmony_ci kfree(rx_ring->rx_skbuff); 45162306a36Sopenharmony_ci} 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci/** 45462306a36Sopenharmony_ci * init_rx_ring - init the RX descriptor ring 45562306a36Sopenharmony_ci * @dev: net device structure 45662306a36Sopenharmony_ci * @queue_no: queue 45762306a36Sopenharmony_ci * @rx_ring: ring to be initialised 45862306a36Sopenharmony_ci * @rx_rsize: ring size 45962306a36Sopenharmony_ci * Description: this function initializes the DMA RX descriptor 46062306a36Sopenharmony_ci */ 46162306a36Sopenharmony_cistatic int init_rx_ring(struct net_device *dev, u8 queue_no, 46262306a36Sopenharmony_ci struct sxgbe_rx_queue *rx_ring, int rx_rsize) 46362306a36Sopenharmony_ci{ 46462306a36Sopenharmony_ci struct sxgbe_priv_data *priv = netdev_priv(dev); 46562306a36Sopenharmony_ci int desc_index; 46662306a36Sopenharmony_ci unsigned int bfsize = 0; 46762306a36Sopenharmony_ci unsigned int ret = 0; 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci /* Set the max buffer size according to the MTU. */ 47062306a36Sopenharmony_ci bfsize = ALIGN(dev->mtu + ETH_HLEN + ETH_FCS_LEN + NET_IP_ALIGN, 8); 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci netif_dbg(priv, probe, dev, "%s: bfsize %d\n", __func__, bfsize); 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci /* RX ring is not allcoated */ 47562306a36Sopenharmony_ci if (rx_ring == NULL) { 47662306a36Sopenharmony_ci netdev_err(dev, "No memory for RX queue\n"); 47762306a36Sopenharmony_ci return -ENOMEM; 47862306a36Sopenharmony_ci } 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci /* assign queue number */ 48162306a36Sopenharmony_ci rx_ring->queue_no = queue_no; 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci /* allocate memory for RX descriptors */ 48462306a36Sopenharmony_ci rx_ring->dma_rx = dma_alloc_coherent(priv->device, 48562306a36Sopenharmony_ci rx_rsize * sizeof(struct sxgbe_rx_norm_desc), 48662306a36Sopenharmony_ci &rx_ring->dma_rx_phy, GFP_KERNEL); 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci if (rx_ring->dma_rx == NULL) 48962306a36Sopenharmony_ci return -ENOMEM; 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci /* allocate memory for RX skbuff array */ 49262306a36Sopenharmony_ci rx_ring->rx_skbuff_dma = kmalloc_array(rx_rsize, 49362306a36Sopenharmony_ci sizeof(dma_addr_t), GFP_KERNEL); 49462306a36Sopenharmony_ci if (!rx_ring->rx_skbuff_dma) { 49562306a36Sopenharmony_ci ret = -ENOMEM; 49662306a36Sopenharmony_ci goto err_free_dma_rx; 49762306a36Sopenharmony_ci } 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci rx_ring->rx_skbuff = kmalloc_array(rx_rsize, 50062306a36Sopenharmony_ci sizeof(struct sk_buff *), GFP_KERNEL); 50162306a36Sopenharmony_ci if (!rx_ring->rx_skbuff) { 50262306a36Sopenharmony_ci ret = -ENOMEM; 50362306a36Sopenharmony_ci goto err_free_skbuff_dma; 50462306a36Sopenharmony_ci } 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci /* initialise the buffers */ 50762306a36Sopenharmony_ci for (desc_index = 0; desc_index < rx_rsize; desc_index++) { 50862306a36Sopenharmony_ci struct sxgbe_rx_norm_desc *p; 50962306a36Sopenharmony_ci p = rx_ring->dma_rx + desc_index; 51062306a36Sopenharmony_ci ret = sxgbe_init_rx_buffers(dev, p, desc_index, 51162306a36Sopenharmony_ci bfsize, rx_ring); 51262306a36Sopenharmony_ci if (ret) 51362306a36Sopenharmony_ci goto err_free_rx_buffers; 51462306a36Sopenharmony_ci } 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci /* initialise counters */ 51762306a36Sopenharmony_ci rx_ring->cur_rx = 0; 51862306a36Sopenharmony_ci rx_ring->dirty_rx = (unsigned int)(desc_index - rx_rsize); 51962306a36Sopenharmony_ci priv->dma_buf_sz = bfsize; 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci return 0; 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_cierr_free_rx_buffers: 52462306a36Sopenharmony_ci while (--desc_index >= 0) { 52562306a36Sopenharmony_ci struct sxgbe_rx_norm_desc *p; 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci p = rx_ring->dma_rx + desc_index; 52862306a36Sopenharmony_ci sxgbe_free_rx_buffers(dev, p, desc_index, bfsize, rx_ring); 52962306a36Sopenharmony_ci } 53062306a36Sopenharmony_ci kfree(rx_ring->rx_skbuff); 53162306a36Sopenharmony_cierr_free_skbuff_dma: 53262306a36Sopenharmony_ci kfree(rx_ring->rx_skbuff_dma); 53362306a36Sopenharmony_cierr_free_dma_rx: 53462306a36Sopenharmony_ci dma_free_coherent(priv->device, 53562306a36Sopenharmony_ci rx_rsize * sizeof(struct sxgbe_rx_norm_desc), 53662306a36Sopenharmony_ci rx_ring->dma_rx, rx_ring->dma_rx_phy); 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci return ret; 53962306a36Sopenharmony_ci} 54062306a36Sopenharmony_ci/** 54162306a36Sopenharmony_ci * free_tx_ring - free the TX descriptor ring 54262306a36Sopenharmony_ci * @dev: net device structure 54362306a36Sopenharmony_ci * @tx_ring: ring to be initialised 54462306a36Sopenharmony_ci * @tx_rsize: ring size 54562306a36Sopenharmony_ci * Description: this function initializes the DMA TX descriptor 54662306a36Sopenharmony_ci */ 54762306a36Sopenharmony_cistatic void free_tx_ring(struct device *dev, struct sxgbe_tx_queue *tx_ring, 54862306a36Sopenharmony_ci int tx_rsize) 54962306a36Sopenharmony_ci{ 55062306a36Sopenharmony_ci dma_free_coherent(dev, tx_rsize * sizeof(struct sxgbe_tx_norm_desc), 55162306a36Sopenharmony_ci tx_ring->dma_tx, tx_ring->dma_tx_phy); 55262306a36Sopenharmony_ci} 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci/** 55562306a36Sopenharmony_ci * init_dma_desc_rings - init the RX/TX descriptor rings 55662306a36Sopenharmony_ci * @netd: net device structure 55762306a36Sopenharmony_ci * Description: this function initializes the DMA RX/TX descriptors 55862306a36Sopenharmony_ci * and allocates the socket buffers. It suppors the chained and ring 55962306a36Sopenharmony_ci * modes. 56062306a36Sopenharmony_ci */ 56162306a36Sopenharmony_cistatic int init_dma_desc_rings(struct net_device *netd) 56262306a36Sopenharmony_ci{ 56362306a36Sopenharmony_ci int queue_num, ret; 56462306a36Sopenharmony_ci struct sxgbe_priv_data *priv = netdev_priv(netd); 56562306a36Sopenharmony_ci int tx_rsize = priv->dma_tx_size; 56662306a36Sopenharmony_ci int rx_rsize = priv->dma_rx_size; 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci /* Allocate memory for queue structures and TX descs */ 56962306a36Sopenharmony_ci SXGBE_FOR_EACH_QUEUE(SXGBE_TX_QUEUES, queue_num) { 57062306a36Sopenharmony_ci ret = init_tx_ring(priv->device, queue_num, 57162306a36Sopenharmony_ci priv->txq[queue_num], tx_rsize); 57262306a36Sopenharmony_ci if (ret) { 57362306a36Sopenharmony_ci dev_err(&netd->dev, "TX DMA ring allocation failed!\n"); 57462306a36Sopenharmony_ci goto txalloc_err; 57562306a36Sopenharmony_ci } 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci /* save private pointer in each ring this 57862306a36Sopenharmony_ci * pointer is needed during cleaing TX queue 57962306a36Sopenharmony_ci */ 58062306a36Sopenharmony_ci priv->txq[queue_num]->priv_ptr = priv; 58162306a36Sopenharmony_ci } 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci /* Allocate memory for queue structures and RX descs */ 58462306a36Sopenharmony_ci SXGBE_FOR_EACH_QUEUE(SXGBE_RX_QUEUES, queue_num) { 58562306a36Sopenharmony_ci ret = init_rx_ring(netd, queue_num, 58662306a36Sopenharmony_ci priv->rxq[queue_num], rx_rsize); 58762306a36Sopenharmony_ci if (ret) { 58862306a36Sopenharmony_ci netdev_err(netd, "RX DMA ring allocation failed!!\n"); 58962306a36Sopenharmony_ci goto rxalloc_err; 59062306a36Sopenharmony_ci } 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci /* save private pointer in each ring this 59362306a36Sopenharmony_ci * pointer is needed during cleaing TX queue 59462306a36Sopenharmony_ci */ 59562306a36Sopenharmony_ci priv->rxq[queue_num]->priv_ptr = priv; 59662306a36Sopenharmony_ci } 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci sxgbe_clear_descriptors(priv); 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci return 0; 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_citxalloc_err: 60362306a36Sopenharmony_ci while (queue_num--) 60462306a36Sopenharmony_ci free_tx_ring(priv->device, priv->txq[queue_num], tx_rsize); 60562306a36Sopenharmony_ci return ret; 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_cirxalloc_err: 60862306a36Sopenharmony_ci while (queue_num--) 60962306a36Sopenharmony_ci free_rx_ring(priv->device, priv->rxq[queue_num], rx_rsize); 61062306a36Sopenharmony_ci return ret; 61162306a36Sopenharmony_ci} 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_cistatic void tx_free_ring_skbufs(struct sxgbe_tx_queue *txqueue) 61462306a36Sopenharmony_ci{ 61562306a36Sopenharmony_ci int dma_desc; 61662306a36Sopenharmony_ci struct sxgbe_priv_data *priv = txqueue->priv_ptr; 61762306a36Sopenharmony_ci int tx_rsize = priv->dma_tx_size; 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci for (dma_desc = 0; dma_desc < tx_rsize; dma_desc++) { 62062306a36Sopenharmony_ci struct sxgbe_tx_norm_desc *tdesc = txqueue->dma_tx + dma_desc; 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci if (txqueue->tx_skbuff_dma[dma_desc]) 62362306a36Sopenharmony_ci dma_unmap_single(priv->device, 62462306a36Sopenharmony_ci txqueue->tx_skbuff_dma[dma_desc], 62562306a36Sopenharmony_ci priv->hw->desc->get_tx_len(tdesc), 62662306a36Sopenharmony_ci DMA_TO_DEVICE); 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci dev_kfree_skb_any(txqueue->tx_skbuff[dma_desc]); 62962306a36Sopenharmony_ci txqueue->tx_skbuff[dma_desc] = NULL; 63062306a36Sopenharmony_ci txqueue->tx_skbuff_dma[dma_desc] = 0; 63162306a36Sopenharmony_ci } 63262306a36Sopenharmony_ci} 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_cistatic void dma_free_tx_skbufs(struct sxgbe_priv_data *priv) 63662306a36Sopenharmony_ci{ 63762306a36Sopenharmony_ci int queue_num; 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci SXGBE_FOR_EACH_QUEUE(SXGBE_TX_QUEUES, queue_num) { 64062306a36Sopenharmony_ci struct sxgbe_tx_queue *tqueue = priv->txq[queue_num]; 64162306a36Sopenharmony_ci tx_free_ring_skbufs(tqueue); 64262306a36Sopenharmony_ci } 64362306a36Sopenharmony_ci} 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_cistatic void free_dma_desc_resources(struct sxgbe_priv_data *priv) 64662306a36Sopenharmony_ci{ 64762306a36Sopenharmony_ci int queue_num; 64862306a36Sopenharmony_ci int tx_rsize = priv->dma_tx_size; 64962306a36Sopenharmony_ci int rx_rsize = priv->dma_rx_size; 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci /* Release the DMA TX buffers */ 65262306a36Sopenharmony_ci dma_free_tx_skbufs(priv); 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci /* Release the TX ring memory also */ 65562306a36Sopenharmony_ci SXGBE_FOR_EACH_QUEUE(SXGBE_TX_QUEUES, queue_num) { 65662306a36Sopenharmony_ci free_tx_ring(priv->device, priv->txq[queue_num], tx_rsize); 65762306a36Sopenharmony_ci } 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci /* Release the RX ring memory also */ 66062306a36Sopenharmony_ci SXGBE_FOR_EACH_QUEUE(SXGBE_RX_QUEUES, queue_num) { 66162306a36Sopenharmony_ci free_rx_ring(priv->device, priv->rxq[queue_num], rx_rsize); 66262306a36Sopenharmony_ci } 66362306a36Sopenharmony_ci} 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_cistatic int txring_mem_alloc(struct sxgbe_priv_data *priv) 66662306a36Sopenharmony_ci{ 66762306a36Sopenharmony_ci int queue_num; 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci SXGBE_FOR_EACH_QUEUE(SXGBE_TX_QUEUES, queue_num) { 67062306a36Sopenharmony_ci priv->txq[queue_num] = devm_kmalloc(priv->device, 67162306a36Sopenharmony_ci sizeof(struct sxgbe_tx_queue), GFP_KERNEL); 67262306a36Sopenharmony_ci if (!priv->txq[queue_num]) 67362306a36Sopenharmony_ci return -ENOMEM; 67462306a36Sopenharmony_ci } 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci return 0; 67762306a36Sopenharmony_ci} 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_cistatic int rxring_mem_alloc(struct sxgbe_priv_data *priv) 68062306a36Sopenharmony_ci{ 68162306a36Sopenharmony_ci int queue_num; 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci SXGBE_FOR_EACH_QUEUE(SXGBE_RX_QUEUES, queue_num) { 68462306a36Sopenharmony_ci priv->rxq[queue_num] = devm_kmalloc(priv->device, 68562306a36Sopenharmony_ci sizeof(struct sxgbe_rx_queue), GFP_KERNEL); 68662306a36Sopenharmony_ci if (!priv->rxq[queue_num]) 68762306a36Sopenharmony_ci return -ENOMEM; 68862306a36Sopenharmony_ci } 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci return 0; 69162306a36Sopenharmony_ci} 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci/** 69462306a36Sopenharmony_ci * sxgbe_mtl_operation_mode - HW MTL operation mode 69562306a36Sopenharmony_ci * @priv: driver private structure 69662306a36Sopenharmony_ci * Description: it sets the MTL operation mode: tx/rx MTL thresholds 69762306a36Sopenharmony_ci * or Store-And-Forward capability. 69862306a36Sopenharmony_ci */ 69962306a36Sopenharmony_cistatic void sxgbe_mtl_operation_mode(struct sxgbe_priv_data *priv) 70062306a36Sopenharmony_ci{ 70162306a36Sopenharmony_ci int queue_num; 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci /* TX/RX threshold control */ 70462306a36Sopenharmony_ci if (likely(priv->plat->force_sf_dma_mode)) { 70562306a36Sopenharmony_ci /* set TC mode for TX QUEUES */ 70662306a36Sopenharmony_ci SXGBE_FOR_EACH_QUEUE(priv->hw_cap.tx_mtl_queues, queue_num) 70762306a36Sopenharmony_ci priv->hw->mtl->set_tx_mtl_mode(priv->ioaddr, queue_num, 70862306a36Sopenharmony_ci SXGBE_MTL_SFMODE); 70962306a36Sopenharmony_ci priv->tx_tc = SXGBE_MTL_SFMODE; 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci /* set TC mode for RX QUEUES */ 71262306a36Sopenharmony_ci SXGBE_FOR_EACH_QUEUE(priv->hw_cap.rx_mtl_queues, queue_num) 71362306a36Sopenharmony_ci priv->hw->mtl->set_rx_mtl_mode(priv->ioaddr, queue_num, 71462306a36Sopenharmony_ci SXGBE_MTL_SFMODE); 71562306a36Sopenharmony_ci priv->rx_tc = SXGBE_MTL_SFMODE; 71662306a36Sopenharmony_ci } else if (unlikely(priv->plat->force_thresh_dma_mode)) { 71762306a36Sopenharmony_ci /* set TC mode for TX QUEUES */ 71862306a36Sopenharmony_ci SXGBE_FOR_EACH_QUEUE(priv->hw_cap.tx_mtl_queues, queue_num) 71962306a36Sopenharmony_ci priv->hw->mtl->set_tx_mtl_mode(priv->ioaddr, queue_num, 72062306a36Sopenharmony_ci priv->tx_tc); 72162306a36Sopenharmony_ci /* set TC mode for RX QUEUES */ 72262306a36Sopenharmony_ci SXGBE_FOR_EACH_QUEUE(priv->hw_cap.rx_mtl_queues, queue_num) 72362306a36Sopenharmony_ci priv->hw->mtl->set_rx_mtl_mode(priv->ioaddr, queue_num, 72462306a36Sopenharmony_ci priv->rx_tc); 72562306a36Sopenharmony_ci } else { 72662306a36Sopenharmony_ci pr_err("ERROR: %s: Invalid TX threshold mode\n", __func__); 72762306a36Sopenharmony_ci } 72862306a36Sopenharmony_ci} 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci/** 73162306a36Sopenharmony_ci * sxgbe_tx_queue_clean: 73262306a36Sopenharmony_ci * @tqueue: queue pointer 73362306a36Sopenharmony_ci * Description: it reclaims resources after transmission completes. 73462306a36Sopenharmony_ci */ 73562306a36Sopenharmony_cistatic void sxgbe_tx_queue_clean(struct sxgbe_tx_queue *tqueue) 73662306a36Sopenharmony_ci{ 73762306a36Sopenharmony_ci struct sxgbe_priv_data *priv = tqueue->priv_ptr; 73862306a36Sopenharmony_ci unsigned int tx_rsize = priv->dma_tx_size; 73962306a36Sopenharmony_ci struct netdev_queue *dev_txq; 74062306a36Sopenharmony_ci u8 queue_no = tqueue->queue_no; 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci dev_txq = netdev_get_tx_queue(priv->dev, queue_no); 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci __netif_tx_lock(dev_txq, smp_processor_id()); 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci priv->xstats.tx_clean++; 74762306a36Sopenharmony_ci while (tqueue->dirty_tx != tqueue->cur_tx) { 74862306a36Sopenharmony_ci unsigned int entry = tqueue->dirty_tx % tx_rsize; 74962306a36Sopenharmony_ci struct sk_buff *skb = tqueue->tx_skbuff[entry]; 75062306a36Sopenharmony_ci struct sxgbe_tx_norm_desc *p; 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci p = tqueue->dma_tx + entry; 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci /* Check if the descriptor is owned by the DMA. */ 75562306a36Sopenharmony_ci if (priv->hw->desc->get_tx_owner(p)) 75662306a36Sopenharmony_ci break; 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci if (netif_msg_tx_done(priv)) 75962306a36Sopenharmony_ci pr_debug("%s: curr %d, dirty %d\n", 76062306a36Sopenharmony_ci __func__, tqueue->cur_tx, tqueue->dirty_tx); 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci if (likely(tqueue->tx_skbuff_dma[entry])) { 76362306a36Sopenharmony_ci dma_unmap_single(priv->device, 76462306a36Sopenharmony_ci tqueue->tx_skbuff_dma[entry], 76562306a36Sopenharmony_ci priv->hw->desc->get_tx_len(p), 76662306a36Sopenharmony_ci DMA_TO_DEVICE); 76762306a36Sopenharmony_ci tqueue->tx_skbuff_dma[entry] = 0; 76862306a36Sopenharmony_ci } 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci if (likely(skb)) { 77162306a36Sopenharmony_ci dev_kfree_skb(skb); 77262306a36Sopenharmony_ci tqueue->tx_skbuff[entry] = NULL; 77362306a36Sopenharmony_ci } 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci priv->hw->desc->release_tx_desc(p); 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci tqueue->dirty_tx++; 77862306a36Sopenharmony_ci } 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci /* wake up queue */ 78162306a36Sopenharmony_ci if (unlikely(netif_tx_queue_stopped(dev_txq) && 78262306a36Sopenharmony_ci sxgbe_tx_avail(tqueue, tx_rsize) > SXGBE_TX_THRESH(priv))) { 78362306a36Sopenharmony_ci if (netif_msg_tx_done(priv)) 78462306a36Sopenharmony_ci pr_debug("%s: restart transmit\n", __func__); 78562306a36Sopenharmony_ci netif_tx_wake_queue(dev_txq); 78662306a36Sopenharmony_ci } 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci __netif_tx_unlock(dev_txq); 78962306a36Sopenharmony_ci} 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_ci/** 79262306a36Sopenharmony_ci * sxgbe_tx_all_clean: 79362306a36Sopenharmony_ci * @priv: driver private structure 79462306a36Sopenharmony_ci * Description: it reclaims resources after transmission completes. 79562306a36Sopenharmony_ci */ 79662306a36Sopenharmony_cistatic void sxgbe_tx_all_clean(struct sxgbe_priv_data * const priv) 79762306a36Sopenharmony_ci{ 79862306a36Sopenharmony_ci u8 queue_num; 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci SXGBE_FOR_EACH_QUEUE(SXGBE_TX_QUEUES, queue_num) { 80162306a36Sopenharmony_ci struct sxgbe_tx_queue *tqueue = priv->txq[queue_num]; 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci sxgbe_tx_queue_clean(tqueue); 80462306a36Sopenharmony_ci } 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci if ((priv->eee_enabled) && (!priv->tx_path_in_lpi_mode)) { 80762306a36Sopenharmony_ci sxgbe_enable_eee_mode(priv); 80862306a36Sopenharmony_ci mod_timer(&priv->eee_ctrl_timer, SXGBE_LPI_TIMER(eee_timer)); 80962306a36Sopenharmony_ci } 81062306a36Sopenharmony_ci} 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci/** 81362306a36Sopenharmony_ci * sxgbe_restart_tx_queue: irq tx error mng function 81462306a36Sopenharmony_ci * @priv: driver private structure 81562306a36Sopenharmony_ci * @queue_num: queue number 81662306a36Sopenharmony_ci * Description: it cleans the descriptors and restarts the transmission 81762306a36Sopenharmony_ci * in case of errors. 81862306a36Sopenharmony_ci */ 81962306a36Sopenharmony_cistatic void sxgbe_restart_tx_queue(struct sxgbe_priv_data *priv, int queue_num) 82062306a36Sopenharmony_ci{ 82162306a36Sopenharmony_ci struct sxgbe_tx_queue *tx_ring = priv->txq[queue_num]; 82262306a36Sopenharmony_ci struct netdev_queue *dev_txq = netdev_get_tx_queue(priv->dev, 82362306a36Sopenharmony_ci queue_num); 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_ci /* stop the queue */ 82662306a36Sopenharmony_ci netif_tx_stop_queue(dev_txq); 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ci /* stop the tx dma */ 82962306a36Sopenharmony_ci priv->hw->dma->stop_tx_queue(priv->ioaddr, queue_num); 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci /* free the skbuffs of the ring */ 83262306a36Sopenharmony_ci tx_free_ring_skbufs(tx_ring); 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci /* initialise counters */ 83562306a36Sopenharmony_ci tx_ring->cur_tx = 0; 83662306a36Sopenharmony_ci tx_ring->dirty_tx = 0; 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci /* start the tx dma */ 83962306a36Sopenharmony_ci priv->hw->dma->start_tx_queue(priv->ioaddr, queue_num); 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_ci priv->dev->stats.tx_errors++; 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci /* wakeup the queue */ 84462306a36Sopenharmony_ci netif_tx_wake_queue(dev_txq); 84562306a36Sopenharmony_ci} 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ci/** 84862306a36Sopenharmony_ci * sxgbe_reset_all_tx_queues: irq tx error mng function 84962306a36Sopenharmony_ci * @priv: driver private structure 85062306a36Sopenharmony_ci * Description: it cleans all the descriptors and 85162306a36Sopenharmony_ci * restarts the transmission on all queues in case of errors. 85262306a36Sopenharmony_ci */ 85362306a36Sopenharmony_cistatic void sxgbe_reset_all_tx_queues(struct sxgbe_priv_data *priv) 85462306a36Sopenharmony_ci{ 85562306a36Sopenharmony_ci int queue_num; 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci /* On TX timeout of net device, resetting of all queues 85862306a36Sopenharmony_ci * may not be proper way, revisit this later if needed 85962306a36Sopenharmony_ci */ 86062306a36Sopenharmony_ci SXGBE_FOR_EACH_QUEUE(SXGBE_TX_QUEUES, queue_num) 86162306a36Sopenharmony_ci sxgbe_restart_tx_queue(priv, queue_num); 86262306a36Sopenharmony_ci} 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci/** 86562306a36Sopenharmony_ci * sxgbe_get_hw_features: get XMAC capabilities from the HW cap. register. 86662306a36Sopenharmony_ci * @priv: driver private structure 86762306a36Sopenharmony_ci * Description: 86862306a36Sopenharmony_ci * new GMAC chip generations have a new register to indicate the 86962306a36Sopenharmony_ci * presence of the optional feature/functions. 87062306a36Sopenharmony_ci * This can be also used to override the value passed through the 87162306a36Sopenharmony_ci * platform and necessary for old MAC10/100 and GMAC chips. 87262306a36Sopenharmony_ci */ 87362306a36Sopenharmony_cistatic int sxgbe_get_hw_features(struct sxgbe_priv_data * const priv) 87462306a36Sopenharmony_ci{ 87562306a36Sopenharmony_ci int rval = 0; 87662306a36Sopenharmony_ci struct sxgbe_hw_features *features = &priv->hw_cap; 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_ci /* Read First Capability Register CAP[0] */ 87962306a36Sopenharmony_ci rval = priv->hw->mac->get_hw_feature(priv->ioaddr, 0); 88062306a36Sopenharmony_ci if (rval) { 88162306a36Sopenharmony_ci features->pmt_remote_wake_up = 88262306a36Sopenharmony_ci SXGBE_HW_FEAT_PMT_TEMOTE_WOP(rval); 88362306a36Sopenharmony_ci features->pmt_magic_frame = SXGBE_HW_FEAT_PMT_MAGIC_PKT(rval); 88462306a36Sopenharmony_ci features->atime_stamp = SXGBE_HW_FEAT_IEEE1500_2008(rval); 88562306a36Sopenharmony_ci features->tx_csum_offload = 88662306a36Sopenharmony_ci SXGBE_HW_FEAT_TX_CSUM_OFFLOAD(rval); 88762306a36Sopenharmony_ci features->rx_csum_offload = 88862306a36Sopenharmony_ci SXGBE_HW_FEAT_RX_CSUM_OFFLOAD(rval); 88962306a36Sopenharmony_ci features->multi_macaddr = SXGBE_HW_FEAT_MACADDR_COUNT(rval); 89062306a36Sopenharmony_ci features->tstamp_srcselect = SXGBE_HW_FEAT_TSTMAP_SRC(rval); 89162306a36Sopenharmony_ci features->sa_vlan_insert = SXGBE_HW_FEAT_SRCADDR_VLAN(rval); 89262306a36Sopenharmony_ci features->eee = SXGBE_HW_FEAT_EEE(rval); 89362306a36Sopenharmony_ci } 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci /* Read First Capability Register CAP[1] */ 89662306a36Sopenharmony_ci rval = priv->hw->mac->get_hw_feature(priv->ioaddr, 1); 89762306a36Sopenharmony_ci if (rval) { 89862306a36Sopenharmony_ci features->rxfifo_size = SXGBE_HW_FEAT_RX_FIFO_SIZE(rval); 89962306a36Sopenharmony_ci features->txfifo_size = SXGBE_HW_FEAT_TX_FIFO_SIZE(rval); 90062306a36Sopenharmony_ci features->atstmap_hword = SXGBE_HW_FEAT_TX_FIFO_SIZE(rval); 90162306a36Sopenharmony_ci features->dcb_enable = SXGBE_HW_FEAT_DCB(rval); 90262306a36Sopenharmony_ci features->splithead_enable = SXGBE_HW_FEAT_SPLIT_HDR(rval); 90362306a36Sopenharmony_ci features->tcpseg_offload = SXGBE_HW_FEAT_TSO(rval); 90462306a36Sopenharmony_ci features->debug_mem = SXGBE_HW_FEAT_DEBUG_MEM_IFACE(rval); 90562306a36Sopenharmony_ci features->rss_enable = SXGBE_HW_FEAT_RSS(rval); 90662306a36Sopenharmony_ci features->hash_tsize = SXGBE_HW_FEAT_HASH_TABLE_SIZE(rval); 90762306a36Sopenharmony_ci features->l3l4_filer_size = SXGBE_HW_FEAT_L3L4_FILTER_NUM(rval); 90862306a36Sopenharmony_ci } 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci /* Read First Capability Register CAP[2] */ 91162306a36Sopenharmony_ci rval = priv->hw->mac->get_hw_feature(priv->ioaddr, 2); 91262306a36Sopenharmony_ci if (rval) { 91362306a36Sopenharmony_ci features->rx_mtl_queues = SXGBE_HW_FEAT_RX_MTL_QUEUES(rval); 91462306a36Sopenharmony_ci features->tx_mtl_queues = SXGBE_HW_FEAT_TX_MTL_QUEUES(rval); 91562306a36Sopenharmony_ci features->rx_dma_channels = SXGBE_HW_FEAT_RX_DMA_CHANNELS(rval); 91662306a36Sopenharmony_ci features->tx_dma_channels = SXGBE_HW_FEAT_TX_DMA_CHANNELS(rval); 91762306a36Sopenharmony_ci features->pps_output_count = SXGBE_HW_FEAT_PPS_OUTPUTS(rval); 91862306a36Sopenharmony_ci features->aux_input_count = SXGBE_HW_FEAT_AUX_SNAPSHOTS(rval); 91962306a36Sopenharmony_ci } 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_ci return rval; 92262306a36Sopenharmony_ci} 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_ci/** 92562306a36Sopenharmony_ci * sxgbe_check_ether_addr: check if the MAC addr is valid 92662306a36Sopenharmony_ci * @priv: driver private structure 92762306a36Sopenharmony_ci * Description: 92862306a36Sopenharmony_ci * it is to verify if the MAC address is valid, in case of failures it 92962306a36Sopenharmony_ci * generates a random MAC address 93062306a36Sopenharmony_ci */ 93162306a36Sopenharmony_cistatic void sxgbe_check_ether_addr(struct sxgbe_priv_data *priv) 93262306a36Sopenharmony_ci{ 93362306a36Sopenharmony_ci if (!is_valid_ether_addr(priv->dev->dev_addr)) { 93462306a36Sopenharmony_ci u8 addr[ETH_ALEN]; 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ci priv->hw->mac->get_umac_addr((void __iomem *) 93762306a36Sopenharmony_ci priv->ioaddr, addr, 0); 93862306a36Sopenharmony_ci if (is_valid_ether_addr(addr)) 93962306a36Sopenharmony_ci eth_hw_addr_set(priv->dev, addr); 94062306a36Sopenharmony_ci else 94162306a36Sopenharmony_ci eth_hw_addr_random(priv->dev); 94262306a36Sopenharmony_ci } 94362306a36Sopenharmony_ci dev_info(priv->device, "device MAC address %pM\n", 94462306a36Sopenharmony_ci priv->dev->dev_addr); 94562306a36Sopenharmony_ci} 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ci/** 94862306a36Sopenharmony_ci * sxgbe_init_dma_engine: DMA init. 94962306a36Sopenharmony_ci * @priv: driver private structure 95062306a36Sopenharmony_ci * Description: 95162306a36Sopenharmony_ci * It inits the DMA invoking the specific SXGBE callback. 95262306a36Sopenharmony_ci * Some DMA parameters can be passed from the platform; 95362306a36Sopenharmony_ci * in case of these are not passed a default is kept for the MAC or GMAC. 95462306a36Sopenharmony_ci */ 95562306a36Sopenharmony_cistatic int sxgbe_init_dma_engine(struct sxgbe_priv_data *priv) 95662306a36Sopenharmony_ci{ 95762306a36Sopenharmony_ci int pbl = DEFAULT_DMA_PBL, fixed_burst = 0, burst_map = 0; 95862306a36Sopenharmony_ci int queue_num; 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_ci if (priv->plat->dma_cfg) { 96162306a36Sopenharmony_ci pbl = priv->plat->dma_cfg->pbl; 96262306a36Sopenharmony_ci fixed_burst = priv->plat->dma_cfg->fixed_burst; 96362306a36Sopenharmony_ci burst_map = priv->plat->dma_cfg->burst_map; 96462306a36Sopenharmony_ci } 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_ci SXGBE_FOR_EACH_QUEUE(SXGBE_TX_QUEUES, queue_num) 96762306a36Sopenharmony_ci priv->hw->dma->cha_init(priv->ioaddr, queue_num, 96862306a36Sopenharmony_ci fixed_burst, pbl, 96962306a36Sopenharmony_ci (priv->txq[queue_num])->dma_tx_phy, 97062306a36Sopenharmony_ci (priv->rxq[queue_num])->dma_rx_phy, 97162306a36Sopenharmony_ci priv->dma_tx_size, priv->dma_rx_size); 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci return priv->hw->dma->init(priv->ioaddr, fixed_burst, burst_map); 97462306a36Sopenharmony_ci} 97562306a36Sopenharmony_ci 97662306a36Sopenharmony_ci/** 97762306a36Sopenharmony_ci * sxgbe_init_mtl_engine: MTL init. 97862306a36Sopenharmony_ci * @priv: driver private structure 97962306a36Sopenharmony_ci * Description: 98062306a36Sopenharmony_ci * It inits the MTL invoking the specific SXGBE callback. 98162306a36Sopenharmony_ci */ 98262306a36Sopenharmony_cistatic void sxgbe_init_mtl_engine(struct sxgbe_priv_data *priv) 98362306a36Sopenharmony_ci{ 98462306a36Sopenharmony_ci int queue_num; 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_ci SXGBE_FOR_EACH_QUEUE(SXGBE_TX_QUEUES, queue_num) { 98762306a36Sopenharmony_ci priv->hw->mtl->mtl_set_txfifosize(priv->ioaddr, queue_num, 98862306a36Sopenharmony_ci priv->hw_cap.tx_mtl_qsize); 98962306a36Sopenharmony_ci priv->hw->mtl->mtl_enable_txqueue(priv->ioaddr, queue_num); 99062306a36Sopenharmony_ci } 99162306a36Sopenharmony_ci} 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_ci/** 99462306a36Sopenharmony_ci * sxgbe_disable_mtl_engine: MTL disable. 99562306a36Sopenharmony_ci * @priv: driver private structure 99662306a36Sopenharmony_ci * Description: 99762306a36Sopenharmony_ci * It disables the MTL queues by invoking the specific SXGBE callback. 99862306a36Sopenharmony_ci */ 99962306a36Sopenharmony_cistatic void sxgbe_disable_mtl_engine(struct sxgbe_priv_data *priv) 100062306a36Sopenharmony_ci{ 100162306a36Sopenharmony_ci int queue_num; 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_ci SXGBE_FOR_EACH_QUEUE(SXGBE_TX_QUEUES, queue_num) 100462306a36Sopenharmony_ci priv->hw->mtl->mtl_disable_txqueue(priv->ioaddr, queue_num); 100562306a36Sopenharmony_ci} 100662306a36Sopenharmony_ci 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_ci/** 100962306a36Sopenharmony_ci * sxgbe_tx_timer: mitigation sw timer for tx. 101062306a36Sopenharmony_ci * @t: timer pointer 101162306a36Sopenharmony_ci * Description: 101262306a36Sopenharmony_ci * This is the timer handler to directly invoke the sxgbe_tx_clean. 101362306a36Sopenharmony_ci */ 101462306a36Sopenharmony_cistatic void sxgbe_tx_timer(struct timer_list *t) 101562306a36Sopenharmony_ci{ 101662306a36Sopenharmony_ci struct sxgbe_tx_queue *p = from_timer(p, t, txtimer); 101762306a36Sopenharmony_ci sxgbe_tx_queue_clean(p); 101862306a36Sopenharmony_ci} 101962306a36Sopenharmony_ci 102062306a36Sopenharmony_ci/** 102162306a36Sopenharmony_ci * sxgbe_tx_init_coalesce: init tx mitigation options. 102262306a36Sopenharmony_ci * @priv: driver private structure 102362306a36Sopenharmony_ci * Description: 102462306a36Sopenharmony_ci * This inits the transmit coalesce parameters: i.e. timer rate, 102562306a36Sopenharmony_ci * timer handler and default threshold used for enabling the 102662306a36Sopenharmony_ci * interrupt on completion bit. 102762306a36Sopenharmony_ci */ 102862306a36Sopenharmony_cistatic void sxgbe_tx_init_coalesce(struct sxgbe_priv_data *priv) 102962306a36Sopenharmony_ci{ 103062306a36Sopenharmony_ci u8 queue_num; 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_ci SXGBE_FOR_EACH_QUEUE(SXGBE_TX_QUEUES, queue_num) { 103362306a36Sopenharmony_ci struct sxgbe_tx_queue *p = priv->txq[queue_num]; 103462306a36Sopenharmony_ci p->tx_coal_frames = SXGBE_TX_FRAMES; 103562306a36Sopenharmony_ci p->tx_coal_timer = SXGBE_COAL_TX_TIMER; 103662306a36Sopenharmony_ci timer_setup(&p->txtimer, sxgbe_tx_timer, 0); 103762306a36Sopenharmony_ci p->txtimer.expires = SXGBE_COAL_TIMER(p->tx_coal_timer); 103862306a36Sopenharmony_ci add_timer(&p->txtimer); 103962306a36Sopenharmony_ci } 104062306a36Sopenharmony_ci} 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_cistatic void sxgbe_tx_del_timer(struct sxgbe_priv_data *priv) 104362306a36Sopenharmony_ci{ 104462306a36Sopenharmony_ci u8 queue_num; 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_ci SXGBE_FOR_EACH_QUEUE(SXGBE_TX_QUEUES, queue_num) { 104762306a36Sopenharmony_ci struct sxgbe_tx_queue *p = priv->txq[queue_num]; 104862306a36Sopenharmony_ci del_timer_sync(&p->txtimer); 104962306a36Sopenharmony_ci } 105062306a36Sopenharmony_ci} 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_ci/** 105362306a36Sopenharmony_ci * sxgbe_open - open entry point of the driver 105462306a36Sopenharmony_ci * @dev : pointer to the device structure. 105562306a36Sopenharmony_ci * Description: 105662306a36Sopenharmony_ci * This function is the open entry point of the driver. 105762306a36Sopenharmony_ci * Return value: 105862306a36Sopenharmony_ci * 0 on success and an appropriate (-)ve integer as defined in errno.h 105962306a36Sopenharmony_ci * file on failure. 106062306a36Sopenharmony_ci */ 106162306a36Sopenharmony_cistatic int sxgbe_open(struct net_device *dev) 106262306a36Sopenharmony_ci{ 106362306a36Sopenharmony_ci struct sxgbe_priv_data *priv = netdev_priv(dev); 106462306a36Sopenharmony_ci int ret, queue_num; 106562306a36Sopenharmony_ci 106662306a36Sopenharmony_ci clk_prepare_enable(priv->sxgbe_clk); 106762306a36Sopenharmony_ci 106862306a36Sopenharmony_ci sxgbe_check_ether_addr(priv); 106962306a36Sopenharmony_ci 107062306a36Sopenharmony_ci /* Init the phy */ 107162306a36Sopenharmony_ci ret = sxgbe_init_phy(dev); 107262306a36Sopenharmony_ci if (ret) { 107362306a36Sopenharmony_ci netdev_err(dev, "%s: Cannot attach to PHY (error: %d)\n", 107462306a36Sopenharmony_ci __func__, ret); 107562306a36Sopenharmony_ci goto phy_error; 107662306a36Sopenharmony_ci } 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_ci /* Create and initialize the TX/RX descriptors chains. */ 107962306a36Sopenharmony_ci priv->dma_tx_size = SXGBE_ALIGN(DMA_TX_SIZE); 108062306a36Sopenharmony_ci priv->dma_rx_size = SXGBE_ALIGN(DMA_RX_SIZE); 108162306a36Sopenharmony_ci priv->dma_buf_sz = SXGBE_ALIGN(DMA_BUFFER_SIZE); 108262306a36Sopenharmony_ci priv->tx_tc = TC_DEFAULT; 108362306a36Sopenharmony_ci priv->rx_tc = TC_DEFAULT; 108462306a36Sopenharmony_ci init_dma_desc_rings(dev); 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_ci /* DMA initialization and SW reset */ 108762306a36Sopenharmony_ci ret = sxgbe_init_dma_engine(priv); 108862306a36Sopenharmony_ci if (ret < 0) { 108962306a36Sopenharmony_ci netdev_err(dev, "%s: DMA initialization failed\n", __func__); 109062306a36Sopenharmony_ci goto init_error; 109162306a36Sopenharmony_ci } 109262306a36Sopenharmony_ci 109362306a36Sopenharmony_ci /* MTL initialization */ 109462306a36Sopenharmony_ci sxgbe_init_mtl_engine(priv); 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_ci /* Copy the MAC addr into the HW */ 109762306a36Sopenharmony_ci priv->hw->mac->set_umac_addr(priv->ioaddr, dev->dev_addr, 0); 109862306a36Sopenharmony_ci 109962306a36Sopenharmony_ci /* Initialize the MAC Core */ 110062306a36Sopenharmony_ci priv->hw->mac->core_init(priv->ioaddr); 110162306a36Sopenharmony_ci SXGBE_FOR_EACH_QUEUE(SXGBE_RX_QUEUES, queue_num) { 110262306a36Sopenharmony_ci priv->hw->mac->enable_rxqueue(priv->ioaddr, queue_num); 110362306a36Sopenharmony_ci } 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_ci /* Request the IRQ lines */ 110662306a36Sopenharmony_ci ret = devm_request_irq(priv->device, priv->irq, sxgbe_common_interrupt, 110762306a36Sopenharmony_ci IRQF_SHARED, dev->name, dev); 110862306a36Sopenharmony_ci if (unlikely(ret < 0)) { 110962306a36Sopenharmony_ci netdev_err(dev, "%s: ERROR: allocating the IRQ %d (error: %d)\n", 111062306a36Sopenharmony_ci __func__, priv->irq, ret); 111162306a36Sopenharmony_ci goto init_error; 111262306a36Sopenharmony_ci } 111362306a36Sopenharmony_ci 111462306a36Sopenharmony_ci /* If the LPI irq is different from the mac irq 111562306a36Sopenharmony_ci * register a dedicated handler 111662306a36Sopenharmony_ci */ 111762306a36Sopenharmony_ci if (priv->lpi_irq != dev->irq) { 111862306a36Sopenharmony_ci ret = devm_request_irq(priv->device, priv->lpi_irq, 111962306a36Sopenharmony_ci sxgbe_common_interrupt, 112062306a36Sopenharmony_ci IRQF_SHARED, dev->name, dev); 112162306a36Sopenharmony_ci if (unlikely(ret < 0)) { 112262306a36Sopenharmony_ci netdev_err(dev, "%s: ERROR: allocating the LPI IRQ %d (%d)\n", 112362306a36Sopenharmony_ci __func__, priv->lpi_irq, ret); 112462306a36Sopenharmony_ci goto init_error; 112562306a36Sopenharmony_ci } 112662306a36Sopenharmony_ci } 112762306a36Sopenharmony_ci 112862306a36Sopenharmony_ci /* Request TX DMA irq lines */ 112962306a36Sopenharmony_ci SXGBE_FOR_EACH_QUEUE(SXGBE_TX_QUEUES, queue_num) { 113062306a36Sopenharmony_ci ret = devm_request_irq(priv->device, 113162306a36Sopenharmony_ci (priv->txq[queue_num])->irq_no, 113262306a36Sopenharmony_ci sxgbe_tx_interrupt, 0, 113362306a36Sopenharmony_ci dev->name, priv->txq[queue_num]); 113462306a36Sopenharmony_ci if (unlikely(ret < 0)) { 113562306a36Sopenharmony_ci netdev_err(dev, "%s: ERROR: allocating TX IRQ %d (error: %d)\n", 113662306a36Sopenharmony_ci __func__, priv->irq, ret); 113762306a36Sopenharmony_ci goto init_error; 113862306a36Sopenharmony_ci } 113962306a36Sopenharmony_ci } 114062306a36Sopenharmony_ci 114162306a36Sopenharmony_ci /* Request RX DMA irq lines */ 114262306a36Sopenharmony_ci SXGBE_FOR_EACH_QUEUE(SXGBE_RX_QUEUES, queue_num) { 114362306a36Sopenharmony_ci ret = devm_request_irq(priv->device, 114462306a36Sopenharmony_ci (priv->rxq[queue_num])->irq_no, 114562306a36Sopenharmony_ci sxgbe_rx_interrupt, 0, 114662306a36Sopenharmony_ci dev->name, priv->rxq[queue_num]); 114762306a36Sopenharmony_ci if (unlikely(ret < 0)) { 114862306a36Sopenharmony_ci netdev_err(dev, "%s: ERROR: allocating TX IRQ %d (error: %d)\n", 114962306a36Sopenharmony_ci __func__, priv->irq, ret); 115062306a36Sopenharmony_ci goto init_error; 115162306a36Sopenharmony_ci } 115262306a36Sopenharmony_ci } 115362306a36Sopenharmony_ci 115462306a36Sopenharmony_ci /* Enable the MAC Rx/Tx */ 115562306a36Sopenharmony_ci priv->hw->mac->enable_tx(priv->ioaddr, true); 115662306a36Sopenharmony_ci priv->hw->mac->enable_rx(priv->ioaddr, true); 115762306a36Sopenharmony_ci 115862306a36Sopenharmony_ci /* Set the HW DMA mode and the COE */ 115962306a36Sopenharmony_ci sxgbe_mtl_operation_mode(priv); 116062306a36Sopenharmony_ci 116162306a36Sopenharmony_ci /* Extra statistics */ 116262306a36Sopenharmony_ci memset(&priv->xstats, 0, sizeof(struct sxgbe_extra_stats)); 116362306a36Sopenharmony_ci 116462306a36Sopenharmony_ci priv->xstats.tx_threshold = priv->tx_tc; 116562306a36Sopenharmony_ci priv->xstats.rx_threshold = priv->rx_tc; 116662306a36Sopenharmony_ci 116762306a36Sopenharmony_ci /* Start the ball rolling... */ 116862306a36Sopenharmony_ci netdev_dbg(dev, "DMA RX/TX processes started...\n"); 116962306a36Sopenharmony_ci priv->hw->dma->start_tx(priv->ioaddr, SXGBE_TX_QUEUES); 117062306a36Sopenharmony_ci priv->hw->dma->start_rx(priv->ioaddr, SXGBE_RX_QUEUES); 117162306a36Sopenharmony_ci 117262306a36Sopenharmony_ci if (dev->phydev) 117362306a36Sopenharmony_ci phy_start(dev->phydev); 117462306a36Sopenharmony_ci 117562306a36Sopenharmony_ci /* initialise TX coalesce parameters */ 117662306a36Sopenharmony_ci sxgbe_tx_init_coalesce(priv); 117762306a36Sopenharmony_ci 117862306a36Sopenharmony_ci if ((priv->use_riwt) && (priv->hw->dma->rx_watchdog)) { 117962306a36Sopenharmony_ci priv->rx_riwt = SXGBE_MAX_DMA_RIWT; 118062306a36Sopenharmony_ci priv->hw->dma->rx_watchdog(priv->ioaddr, SXGBE_MAX_DMA_RIWT); 118162306a36Sopenharmony_ci } 118262306a36Sopenharmony_ci 118362306a36Sopenharmony_ci priv->tx_lpi_timer = SXGBE_DEFAULT_LPI_TIMER; 118462306a36Sopenharmony_ci priv->eee_enabled = sxgbe_eee_init(priv); 118562306a36Sopenharmony_ci 118662306a36Sopenharmony_ci napi_enable(&priv->napi); 118762306a36Sopenharmony_ci netif_start_queue(dev); 118862306a36Sopenharmony_ci 118962306a36Sopenharmony_ci return 0; 119062306a36Sopenharmony_ci 119162306a36Sopenharmony_ciinit_error: 119262306a36Sopenharmony_ci free_dma_desc_resources(priv); 119362306a36Sopenharmony_ci if (dev->phydev) 119462306a36Sopenharmony_ci phy_disconnect(dev->phydev); 119562306a36Sopenharmony_ciphy_error: 119662306a36Sopenharmony_ci clk_disable_unprepare(priv->sxgbe_clk); 119762306a36Sopenharmony_ci 119862306a36Sopenharmony_ci return ret; 119962306a36Sopenharmony_ci} 120062306a36Sopenharmony_ci 120162306a36Sopenharmony_ci/** 120262306a36Sopenharmony_ci * sxgbe_release - close entry point of the driver 120362306a36Sopenharmony_ci * @dev : device pointer. 120462306a36Sopenharmony_ci * Description: 120562306a36Sopenharmony_ci * This is the stop entry point of the driver. 120662306a36Sopenharmony_ci */ 120762306a36Sopenharmony_cistatic int sxgbe_release(struct net_device *dev) 120862306a36Sopenharmony_ci{ 120962306a36Sopenharmony_ci struct sxgbe_priv_data *priv = netdev_priv(dev); 121062306a36Sopenharmony_ci 121162306a36Sopenharmony_ci if (priv->eee_enabled) 121262306a36Sopenharmony_ci del_timer_sync(&priv->eee_ctrl_timer); 121362306a36Sopenharmony_ci 121462306a36Sopenharmony_ci /* Stop and disconnect the PHY */ 121562306a36Sopenharmony_ci if (dev->phydev) { 121662306a36Sopenharmony_ci phy_stop(dev->phydev); 121762306a36Sopenharmony_ci phy_disconnect(dev->phydev); 121862306a36Sopenharmony_ci } 121962306a36Sopenharmony_ci 122062306a36Sopenharmony_ci netif_tx_stop_all_queues(dev); 122162306a36Sopenharmony_ci 122262306a36Sopenharmony_ci napi_disable(&priv->napi); 122362306a36Sopenharmony_ci 122462306a36Sopenharmony_ci /* delete TX timers */ 122562306a36Sopenharmony_ci sxgbe_tx_del_timer(priv); 122662306a36Sopenharmony_ci 122762306a36Sopenharmony_ci /* Stop TX/RX DMA and clear the descriptors */ 122862306a36Sopenharmony_ci priv->hw->dma->stop_tx(priv->ioaddr, SXGBE_TX_QUEUES); 122962306a36Sopenharmony_ci priv->hw->dma->stop_rx(priv->ioaddr, SXGBE_RX_QUEUES); 123062306a36Sopenharmony_ci 123162306a36Sopenharmony_ci /* disable MTL queue */ 123262306a36Sopenharmony_ci sxgbe_disable_mtl_engine(priv); 123362306a36Sopenharmony_ci 123462306a36Sopenharmony_ci /* Release and free the Rx/Tx resources */ 123562306a36Sopenharmony_ci free_dma_desc_resources(priv); 123662306a36Sopenharmony_ci 123762306a36Sopenharmony_ci /* Disable the MAC Rx/Tx */ 123862306a36Sopenharmony_ci priv->hw->mac->enable_tx(priv->ioaddr, false); 123962306a36Sopenharmony_ci priv->hw->mac->enable_rx(priv->ioaddr, false); 124062306a36Sopenharmony_ci 124162306a36Sopenharmony_ci clk_disable_unprepare(priv->sxgbe_clk); 124262306a36Sopenharmony_ci 124362306a36Sopenharmony_ci return 0; 124462306a36Sopenharmony_ci} 124562306a36Sopenharmony_ci/* Prepare first Tx descriptor for doing TSO operation */ 124662306a36Sopenharmony_cistatic void sxgbe_tso_prepare(struct sxgbe_priv_data *priv, 124762306a36Sopenharmony_ci struct sxgbe_tx_norm_desc *first_desc, 124862306a36Sopenharmony_ci struct sk_buff *skb) 124962306a36Sopenharmony_ci{ 125062306a36Sopenharmony_ci unsigned int total_hdr_len, tcp_hdr_len; 125162306a36Sopenharmony_ci 125262306a36Sopenharmony_ci /* Write first Tx descriptor with appropriate value */ 125362306a36Sopenharmony_ci tcp_hdr_len = tcp_hdrlen(skb); 125462306a36Sopenharmony_ci total_hdr_len = skb_transport_offset(skb) + tcp_hdr_len; 125562306a36Sopenharmony_ci 125662306a36Sopenharmony_ci first_desc->tdes01 = dma_map_single(priv->device, skb->data, 125762306a36Sopenharmony_ci total_hdr_len, DMA_TO_DEVICE); 125862306a36Sopenharmony_ci if (dma_mapping_error(priv->device, first_desc->tdes01)) 125962306a36Sopenharmony_ci pr_err("%s: TX dma mapping failed!!\n", __func__); 126062306a36Sopenharmony_ci 126162306a36Sopenharmony_ci first_desc->tdes23.tx_rd_des23.first_desc = 1; 126262306a36Sopenharmony_ci priv->hw->desc->tx_desc_enable_tse(first_desc, 1, total_hdr_len, 126362306a36Sopenharmony_ci tcp_hdr_len, 126462306a36Sopenharmony_ci skb->len - total_hdr_len); 126562306a36Sopenharmony_ci} 126662306a36Sopenharmony_ci 126762306a36Sopenharmony_ci/** 126862306a36Sopenharmony_ci * sxgbe_xmit: Tx entry point of the driver 126962306a36Sopenharmony_ci * @skb : the socket buffer 127062306a36Sopenharmony_ci * @dev : device pointer 127162306a36Sopenharmony_ci * Description : this is the tx entry point of the driver. 127262306a36Sopenharmony_ci * It programs the chain or the ring and supports oversized frames 127362306a36Sopenharmony_ci * and SG feature. 127462306a36Sopenharmony_ci */ 127562306a36Sopenharmony_cistatic netdev_tx_t sxgbe_xmit(struct sk_buff *skb, struct net_device *dev) 127662306a36Sopenharmony_ci{ 127762306a36Sopenharmony_ci unsigned int entry, frag_num; 127862306a36Sopenharmony_ci int cksum_flag = 0; 127962306a36Sopenharmony_ci struct netdev_queue *dev_txq; 128062306a36Sopenharmony_ci unsigned txq_index = skb_get_queue_mapping(skb); 128162306a36Sopenharmony_ci struct sxgbe_priv_data *priv = netdev_priv(dev); 128262306a36Sopenharmony_ci unsigned int tx_rsize = priv->dma_tx_size; 128362306a36Sopenharmony_ci struct sxgbe_tx_queue *tqueue = priv->txq[txq_index]; 128462306a36Sopenharmony_ci struct sxgbe_tx_norm_desc *tx_desc, *first_desc; 128562306a36Sopenharmony_ci struct sxgbe_tx_ctxt_desc *ctxt_desc = NULL; 128662306a36Sopenharmony_ci int nr_frags = skb_shinfo(skb)->nr_frags; 128762306a36Sopenharmony_ci int no_pagedlen = skb_headlen(skb); 128862306a36Sopenharmony_ci int is_jumbo = 0; 128962306a36Sopenharmony_ci u16 cur_mss = skb_shinfo(skb)->gso_size; 129062306a36Sopenharmony_ci u32 ctxt_desc_req = 0; 129162306a36Sopenharmony_ci 129262306a36Sopenharmony_ci /* get the TX queue handle */ 129362306a36Sopenharmony_ci dev_txq = netdev_get_tx_queue(dev, txq_index); 129462306a36Sopenharmony_ci 129562306a36Sopenharmony_ci if (unlikely(skb_is_gso(skb) && tqueue->prev_mss != cur_mss)) 129662306a36Sopenharmony_ci ctxt_desc_req = 1; 129762306a36Sopenharmony_ci 129862306a36Sopenharmony_ci if (unlikely(skb_vlan_tag_present(skb) || 129962306a36Sopenharmony_ci ((skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) && 130062306a36Sopenharmony_ci tqueue->hwts_tx_en))) 130162306a36Sopenharmony_ci ctxt_desc_req = 1; 130262306a36Sopenharmony_ci 130362306a36Sopenharmony_ci if (priv->tx_path_in_lpi_mode) 130462306a36Sopenharmony_ci sxgbe_disable_eee_mode(priv); 130562306a36Sopenharmony_ci 130662306a36Sopenharmony_ci if (unlikely(sxgbe_tx_avail(tqueue, tx_rsize) < nr_frags + 1)) { 130762306a36Sopenharmony_ci if (!netif_tx_queue_stopped(dev_txq)) { 130862306a36Sopenharmony_ci netif_tx_stop_queue(dev_txq); 130962306a36Sopenharmony_ci netdev_err(dev, "%s: Tx Ring is full when %d queue is awake\n", 131062306a36Sopenharmony_ci __func__, txq_index); 131162306a36Sopenharmony_ci } 131262306a36Sopenharmony_ci return NETDEV_TX_BUSY; 131362306a36Sopenharmony_ci } 131462306a36Sopenharmony_ci 131562306a36Sopenharmony_ci entry = tqueue->cur_tx % tx_rsize; 131662306a36Sopenharmony_ci tx_desc = tqueue->dma_tx + entry; 131762306a36Sopenharmony_ci 131862306a36Sopenharmony_ci first_desc = tx_desc; 131962306a36Sopenharmony_ci if (ctxt_desc_req) 132062306a36Sopenharmony_ci ctxt_desc = (struct sxgbe_tx_ctxt_desc *)first_desc; 132162306a36Sopenharmony_ci 132262306a36Sopenharmony_ci /* save the skb address */ 132362306a36Sopenharmony_ci tqueue->tx_skbuff[entry] = skb; 132462306a36Sopenharmony_ci 132562306a36Sopenharmony_ci if (!is_jumbo) { 132662306a36Sopenharmony_ci if (likely(skb_is_gso(skb))) { 132762306a36Sopenharmony_ci /* TSO support */ 132862306a36Sopenharmony_ci if (unlikely(tqueue->prev_mss != cur_mss)) { 132962306a36Sopenharmony_ci priv->hw->desc->tx_ctxt_desc_set_mss( 133062306a36Sopenharmony_ci ctxt_desc, cur_mss); 133162306a36Sopenharmony_ci priv->hw->desc->tx_ctxt_desc_set_tcmssv( 133262306a36Sopenharmony_ci ctxt_desc); 133362306a36Sopenharmony_ci priv->hw->desc->tx_ctxt_desc_reset_ostc( 133462306a36Sopenharmony_ci ctxt_desc); 133562306a36Sopenharmony_ci priv->hw->desc->tx_ctxt_desc_set_ctxt( 133662306a36Sopenharmony_ci ctxt_desc); 133762306a36Sopenharmony_ci priv->hw->desc->tx_ctxt_desc_set_owner( 133862306a36Sopenharmony_ci ctxt_desc); 133962306a36Sopenharmony_ci 134062306a36Sopenharmony_ci entry = (++tqueue->cur_tx) % tx_rsize; 134162306a36Sopenharmony_ci first_desc = tqueue->dma_tx + entry; 134262306a36Sopenharmony_ci 134362306a36Sopenharmony_ci tqueue->prev_mss = cur_mss; 134462306a36Sopenharmony_ci } 134562306a36Sopenharmony_ci sxgbe_tso_prepare(priv, first_desc, skb); 134662306a36Sopenharmony_ci } else { 134762306a36Sopenharmony_ci tx_desc->tdes01 = dma_map_single(priv->device, 134862306a36Sopenharmony_ci skb->data, no_pagedlen, DMA_TO_DEVICE); 134962306a36Sopenharmony_ci if (dma_mapping_error(priv->device, tx_desc->tdes01)) 135062306a36Sopenharmony_ci netdev_err(dev, "%s: TX dma mapping failed!!\n", 135162306a36Sopenharmony_ci __func__); 135262306a36Sopenharmony_ci 135362306a36Sopenharmony_ci priv->hw->desc->prepare_tx_desc(tx_desc, 1, no_pagedlen, 135462306a36Sopenharmony_ci no_pagedlen, cksum_flag); 135562306a36Sopenharmony_ci } 135662306a36Sopenharmony_ci } 135762306a36Sopenharmony_ci 135862306a36Sopenharmony_ci for (frag_num = 0; frag_num < nr_frags; frag_num++) { 135962306a36Sopenharmony_ci const skb_frag_t *frag = &skb_shinfo(skb)->frags[frag_num]; 136062306a36Sopenharmony_ci int len = skb_frag_size(frag); 136162306a36Sopenharmony_ci 136262306a36Sopenharmony_ci entry = (++tqueue->cur_tx) % tx_rsize; 136362306a36Sopenharmony_ci tx_desc = tqueue->dma_tx + entry; 136462306a36Sopenharmony_ci tx_desc->tdes01 = skb_frag_dma_map(priv->device, frag, 0, len, 136562306a36Sopenharmony_ci DMA_TO_DEVICE); 136662306a36Sopenharmony_ci 136762306a36Sopenharmony_ci tqueue->tx_skbuff_dma[entry] = tx_desc->tdes01; 136862306a36Sopenharmony_ci tqueue->tx_skbuff[entry] = NULL; 136962306a36Sopenharmony_ci 137062306a36Sopenharmony_ci /* prepare the descriptor */ 137162306a36Sopenharmony_ci priv->hw->desc->prepare_tx_desc(tx_desc, 0, len, 137262306a36Sopenharmony_ci len, cksum_flag); 137362306a36Sopenharmony_ci /* memory barrier to flush descriptor */ 137462306a36Sopenharmony_ci wmb(); 137562306a36Sopenharmony_ci 137662306a36Sopenharmony_ci /* set the owner */ 137762306a36Sopenharmony_ci priv->hw->desc->set_tx_owner(tx_desc); 137862306a36Sopenharmony_ci } 137962306a36Sopenharmony_ci 138062306a36Sopenharmony_ci /* close the descriptors */ 138162306a36Sopenharmony_ci priv->hw->desc->close_tx_desc(tx_desc); 138262306a36Sopenharmony_ci 138362306a36Sopenharmony_ci /* memory barrier to flush descriptor */ 138462306a36Sopenharmony_ci wmb(); 138562306a36Sopenharmony_ci 138662306a36Sopenharmony_ci tqueue->tx_count_frames += nr_frags + 1; 138762306a36Sopenharmony_ci if (tqueue->tx_count_frames > tqueue->tx_coal_frames) { 138862306a36Sopenharmony_ci priv->hw->desc->clear_tx_ic(tx_desc); 138962306a36Sopenharmony_ci priv->xstats.tx_reset_ic_bit++; 139062306a36Sopenharmony_ci mod_timer(&tqueue->txtimer, 139162306a36Sopenharmony_ci SXGBE_COAL_TIMER(tqueue->tx_coal_timer)); 139262306a36Sopenharmony_ci } else { 139362306a36Sopenharmony_ci tqueue->tx_count_frames = 0; 139462306a36Sopenharmony_ci } 139562306a36Sopenharmony_ci 139662306a36Sopenharmony_ci /* set owner for first desc */ 139762306a36Sopenharmony_ci priv->hw->desc->set_tx_owner(first_desc); 139862306a36Sopenharmony_ci 139962306a36Sopenharmony_ci /* memory barrier to flush descriptor */ 140062306a36Sopenharmony_ci wmb(); 140162306a36Sopenharmony_ci 140262306a36Sopenharmony_ci tqueue->cur_tx++; 140362306a36Sopenharmony_ci 140462306a36Sopenharmony_ci /* display current ring */ 140562306a36Sopenharmony_ci netif_dbg(priv, pktdata, dev, "%s: curr %d dirty=%d entry=%d, first=%p, nfrags=%d\n", 140662306a36Sopenharmony_ci __func__, tqueue->cur_tx % tx_rsize, 140762306a36Sopenharmony_ci tqueue->dirty_tx % tx_rsize, entry, 140862306a36Sopenharmony_ci first_desc, nr_frags); 140962306a36Sopenharmony_ci 141062306a36Sopenharmony_ci if (unlikely(sxgbe_tx_avail(tqueue, tx_rsize) <= (MAX_SKB_FRAGS + 1))) { 141162306a36Sopenharmony_ci netif_dbg(priv, hw, dev, "%s: stop transmitted packets\n", 141262306a36Sopenharmony_ci __func__); 141362306a36Sopenharmony_ci netif_tx_stop_queue(dev_txq); 141462306a36Sopenharmony_ci } 141562306a36Sopenharmony_ci 141662306a36Sopenharmony_ci dev->stats.tx_bytes += skb->len; 141762306a36Sopenharmony_ci 141862306a36Sopenharmony_ci if (unlikely((skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) && 141962306a36Sopenharmony_ci tqueue->hwts_tx_en)) { 142062306a36Sopenharmony_ci /* declare that device is doing timestamping */ 142162306a36Sopenharmony_ci skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; 142262306a36Sopenharmony_ci priv->hw->desc->tx_enable_tstamp(first_desc); 142362306a36Sopenharmony_ci } 142462306a36Sopenharmony_ci 142562306a36Sopenharmony_ci skb_tx_timestamp(skb); 142662306a36Sopenharmony_ci 142762306a36Sopenharmony_ci priv->hw->dma->enable_dma_transmission(priv->ioaddr, txq_index); 142862306a36Sopenharmony_ci 142962306a36Sopenharmony_ci return NETDEV_TX_OK; 143062306a36Sopenharmony_ci} 143162306a36Sopenharmony_ci 143262306a36Sopenharmony_ci/** 143362306a36Sopenharmony_ci * sxgbe_rx_refill: refill used skb preallocated buffers 143462306a36Sopenharmony_ci * @priv: driver private structure 143562306a36Sopenharmony_ci * Description : this is to reallocate the skb for the reception process 143662306a36Sopenharmony_ci * that is based on zero-copy. 143762306a36Sopenharmony_ci */ 143862306a36Sopenharmony_cistatic void sxgbe_rx_refill(struct sxgbe_priv_data *priv) 143962306a36Sopenharmony_ci{ 144062306a36Sopenharmony_ci unsigned int rxsize = priv->dma_rx_size; 144162306a36Sopenharmony_ci int bfsize = priv->dma_buf_sz; 144262306a36Sopenharmony_ci u8 qnum = priv->cur_rx_qnum; 144362306a36Sopenharmony_ci 144462306a36Sopenharmony_ci for (; priv->rxq[qnum]->cur_rx - priv->rxq[qnum]->dirty_rx > 0; 144562306a36Sopenharmony_ci priv->rxq[qnum]->dirty_rx++) { 144662306a36Sopenharmony_ci unsigned int entry = priv->rxq[qnum]->dirty_rx % rxsize; 144762306a36Sopenharmony_ci struct sxgbe_rx_norm_desc *p; 144862306a36Sopenharmony_ci 144962306a36Sopenharmony_ci p = priv->rxq[qnum]->dma_rx + entry; 145062306a36Sopenharmony_ci 145162306a36Sopenharmony_ci if (likely(priv->rxq[qnum]->rx_skbuff[entry] == NULL)) { 145262306a36Sopenharmony_ci struct sk_buff *skb; 145362306a36Sopenharmony_ci 145462306a36Sopenharmony_ci skb = netdev_alloc_skb_ip_align(priv->dev, bfsize); 145562306a36Sopenharmony_ci 145662306a36Sopenharmony_ci if (unlikely(skb == NULL)) 145762306a36Sopenharmony_ci break; 145862306a36Sopenharmony_ci 145962306a36Sopenharmony_ci priv->rxq[qnum]->rx_skbuff[entry] = skb; 146062306a36Sopenharmony_ci priv->rxq[qnum]->rx_skbuff_dma[entry] = 146162306a36Sopenharmony_ci dma_map_single(priv->device, skb->data, bfsize, 146262306a36Sopenharmony_ci DMA_FROM_DEVICE); 146362306a36Sopenharmony_ci 146462306a36Sopenharmony_ci p->rdes23.rx_rd_des23.buf2_addr = 146562306a36Sopenharmony_ci priv->rxq[qnum]->rx_skbuff_dma[entry]; 146662306a36Sopenharmony_ci } 146762306a36Sopenharmony_ci 146862306a36Sopenharmony_ci /* Added memory barrier for RX descriptor modification */ 146962306a36Sopenharmony_ci wmb(); 147062306a36Sopenharmony_ci priv->hw->desc->set_rx_owner(p); 147162306a36Sopenharmony_ci priv->hw->desc->set_rx_int_on_com(p); 147262306a36Sopenharmony_ci /* Added memory barrier for RX descriptor modification */ 147362306a36Sopenharmony_ci wmb(); 147462306a36Sopenharmony_ci } 147562306a36Sopenharmony_ci} 147662306a36Sopenharmony_ci 147762306a36Sopenharmony_ci/** 147862306a36Sopenharmony_ci * sxgbe_rx: receive the frames from the remote host 147962306a36Sopenharmony_ci * @priv: driver private structure 148062306a36Sopenharmony_ci * @limit: napi bugget. 148162306a36Sopenharmony_ci * Description : this the function called by the napi poll method. 148262306a36Sopenharmony_ci * It gets all the frames inside the ring. 148362306a36Sopenharmony_ci */ 148462306a36Sopenharmony_cistatic int sxgbe_rx(struct sxgbe_priv_data *priv, int limit) 148562306a36Sopenharmony_ci{ 148662306a36Sopenharmony_ci u8 qnum = priv->cur_rx_qnum; 148762306a36Sopenharmony_ci unsigned int rxsize = priv->dma_rx_size; 148862306a36Sopenharmony_ci unsigned int entry = priv->rxq[qnum]->cur_rx; 148962306a36Sopenharmony_ci unsigned int next_entry = 0; 149062306a36Sopenharmony_ci unsigned int count = 0; 149162306a36Sopenharmony_ci int checksum; 149262306a36Sopenharmony_ci int status; 149362306a36Sopenharmony_ci 149462306a36Sopenharmony_ci while (count < limit) { 149562306a36Sopenharmony_ci struct sxgbe_rx_norm_desc *p; 149662306a36Sopenharmony_ci struct sk_buff *skb; 149762306a36Sopenharmony_ci int frame_len; 149862306a36Sopenharmony_ci 149962306a36Sopenharmony_ci p = priv->rxq[qnum]->dma_rx + entry; 150062306a36Sopenharmony_ci 150162306a36Sopenharmony_ci if (priv->hw->desc->get_rx_owner(p)) 150262306a36Sopenharmony_ci break; 150362306a36Sopenharmony_ci 150462306a36Sopenharmony_ci count++; 150562306a36Sopenharmony_ci 150662306a36Sopenharmony_ci next_entry = (++priv->rxq[qnum]->cur_rx) % rxsize; 150762306a36Sopenharmony_ci prefetch(priv->rxq[qnum]->dma_rx + next_entry); 150862306a36Sopenharmony_ci 150962306a36Sopenharmony_ci /* Read the status of the incoming frame and also get checksum 151062306a36Sopenharmony_ci * value based on whether it is enabled in SXGBE hardware or 151162306a36Sopenharmony_ci * not. 151262306a36Sopenharmony_ci */ 151362306a36Sopenharmony_ci status = priv->hw->desc->rx_wbstatus(p, &priv->xstats, 151462306a36Sopenharmony_ci &checksum); 151562306a36Sopenharmony_ci if (unlikely(status < 0)) { 151662306a36Sopenharmony_ci entry = next_entry; 151762306a36Sopenharmony_ci continue; 151862306a36Sopenharmony_ci } 151962306a36Sopenharmony_ci if (unlikely(!priv->rxcsum_insertion)) 152062306a36Sopenharmony_ci checksum = CHECKSUM_NONE; 152162306a36Sopenharmony_ci 152262306a36Sopenharmony_ci skb = priv->rxq[qnum]->rx_skbuff[entry]; 152362306a36Sopenharmony_ci 152462306a36Sopenharmony_ci if (unlikely(!skb)) 152562306a36Sopenharmony_ci netdev_err(priv->dev, "rx descriptor is not consistent\n"); 152662306a36Sopenharmony_ci 152762306a36Sopenharmony_ci prefetch(skb->data - NET_IP_ALIGN); 152862306a36Sopenharmony_ci priv->rxq[qnum]->rx_skbuff[entry] = NULL; 152962306a36Sopenharmony_ci 153062306a36Sopenharmony_ci frame_len = priv->hw->desc->get_rx_frame_len(p); 153162306a36Sopenharmony_ci 153262306a36Sopenharmony_ci skb_put(skb, frame_len); 153362306a36Sopenharmony_ci 153462306a36Sopenharmony_ci skb->ip_summed = checksum; 153562306a36Sopenharmony_ci if (checksum == CHECKSUM_NONE) 153662306a36Sopenharmony_ci netif_receive_skb(skb); 153762306a36Sopenharmony_ci else 153862306a36Sopenharmony_ci napi_gro_receive(&priv->napi, skb); 153962306a36Sopenharmony_ci 154062306a36Sopenharmony_ci entry = next_entry; 154162306a36Sopenharmony_ci } 154262306a36Sopenharmony_ci 154362306a36Sopenharmony_ci sxgbe_rx_refill(priv); 154462306a36Sopenharmony_ci 154562306a36Sopenharmony_ci return count; 154662306a36Sopenharmony_ci} 154762306a36Sopenharmony_ci 154862306a36Sopenharmony_ci/** 154962306a36Sopenharmony_ci * sxgbe_poll - sxgbe poll method (NAPI) 155062306a36Sopenharmony_ci * @napi : pointer to the napi structure. 155162306a36Sopenharmony_ci * @budget : maximum number of packets that the current CPU can receive from 155262306a36Sopenharmony_ci * all interfaces. 155362306a36Sopenharmony_ci * Description : 155462306a36Sopenharmony_ci * To look at the incoming frames and clear the tx resources. 155562306a36Sopenharmony_ci */ 155662306a36Sopenharmony_cistatic int sxgbe_poll(struct napi_struct *napi, int budget) 155762306a36Sopenharmony_ci{ 155862306a36Sopenharmony_ci struct sxgbe_priv_data *priv = container_of(napi, 155962306a36Sopenharmony_ci struct sxgbe_priv_data, napi); 156062306a36Sopenharmony_ci int work_done = 0; 156162306a36Sopenharmony_ci u8 qnum = priv->cur_rx_qnum; 156262306a36Sopenharmony_ci 156362306a36Sopenharmony_ci priv->xstats.napi_poll++; 156462306a36Sopenharmony_ci /* first, clean the tx queues */ 156562306a36Sopenharmony_ci sxgbe_tx_all_clean(priv); 156662306a36Sopenharmony_ci 156762306a36Sopenharmony_ci work_done = sxgbe_rx(priv, budget); 156862306a36Sopenharmony_ci if (work_done < budget) { 156962306a36Sopenharmony_ci napi_complete_done(napi, work_done); 157062306a36Sopenharmony_ci priv->hw->dma->enable_dma_irq(priv->ioaddr, qnum); 157162306a36Sopenharmony_ci } 157262306a36Sopenharmony_ci 157362306a36Sopenharmony_ci return work_done; 157462306a36Sopenharmony_ci} 157562306a36Sopenharmony_ci 157662306a36Sopenharmony_ci/** 157762306a36Sopenharmony_ci * sxgbe_tx_timeout 157862306a36Sopenharmony_ci * @dev : Pointer to net device structure 157962306a36Sopenharmony_ci * @txqueue: index of the hanging queue 158062306a36Sopenharmony_ci * Description: this function is called when a packet transmission fails to 158162306a36Sopenharmony_ci * complete within a reasonable time. The driver will mark the error in the 158262306a36Sopenharmony_ci * netdev structure and arrange for the device to be reset to a sane state 158362306a36Sopenharmony_ci * in order to transmit a new packet. 158462306a36Sopenharmony_ci */ 158562306a36Sopenharmony_cistatic void sxgbe_tx_timeout(struct net_device *dev, unsigned int txqueue) 158662306a36Sopenharmony_ci{ 158762306a36Sopenharmony_ci struct sxgbe_priv_data *priv = netdev_priv(dev); 158862306a36Sopenharmony_ci 158962306a36Sopenharmony_ci sxgbe_reset_all_tx_queues(priv); 159062306a36Sopenharmony_ci} 159162306a36Sopenharmony_ci 159262306a36Sopenharmony_ci/** 159362306a36Sopenharmony_ci * sxgbe_common_interrupt - main ISR 159462306a36Sopenharmony_ci * @irq: interrupt number. 159562306a36Sopenharmony_ci * @dev_id: to pass the net device pointer. 159662306a36Sopenharmony_ci * Description: this is the main driver interrupt service routine. 159762306a36Sopenharmony_ci * It calls the DMA ISR and also the core ISR to manage PMT, MMC, LPI 159862306a36Sopenharmony_ci * interrupts. 159962306a36Sopenharmony_ci */ 160062306a36Sopenharmony_cistatic irqreturn_t sxgbe_common_interrupt(int irq, void *dev_id) 160162306a36Sopenharmony_ci{ 160262306a36Sopenharmony_ci struct net_device *netdev = (struct net_device *)dev_id; 160362306a36Sopenharmony_ci struct sxgbe_priv_data *priv = netdev_priv(netdev); 160462306a36Sopenharmony_ci int status; 160562306a36Sopenharmony_ci 160662306a36Sopenharmony_ci status = priv->hw->mac->host_irq_status(priv->ioaddr, &priv->xstats); 160762306a36Sopenharmony_ci /* For LPI we need to save the tx status */ 160862306a36Sopenharmony_ci if (status & TX_ENTRY_LPI_MODE) { 160962306a36Sopenharmony_ci priv->xstats.tx_lpi_entry_n++; 161062306a36Sopenharmony_ci priv->tx_path_in_lpi_mode = true; 161162306a36Sopenharmony_ci } 161262306a36Sopenharmony_ci if (status & TX_EXIT_LPI_MODE) { 161362306a36Sopenharmony_ci priv->xstats.tx_lpi_exit_n++; 161462306a36Sopenharmony_ci priv->tx_path_in_lpi_mode = false; 161562306a36Sopenharmony_ci } 161662306a36Sopenharmony_ci if (status & RX_ENTRY_LPI_MODE) 161762306a36Sopenharmony_ci priv->xstats.rx_lpi_entry_n++; 161862306a36Sopenharmony_ci if (status & RX_EXIT_LPI_MODE) 161962306a36Sopenharmony_ci priv->xstats.rx_lpi_exit_n++; 162062306a36Sopenharmony_ci 162162306a36Sopenharmony_ci return IRQ_HANDLED; 162262306a36Sopenharmony_ci} 162362306a36Sopenharmony_ci 162462306a36Sopenharmony_ci/** 162562306a36Sopenharmony_ci * sxgbe_tx_interrupt - TX DMA ISR 162662306a36Sopenharmony_ci * @irq: interrupt number. 162762306a36Sopenharmony_ci * @dev_id: to pass the net device pointer. 162862306a36Sopenharmony_ci * Description: this is the tx dma interrupt service routine. 162962306a36Sopenharmony_ci */ 163062306a36Sopenharmony_cistatic irqreturn_t sxgbe_tx_interrupt(int irq, void *dev_id) 163162306a36Sopenharmony_ci{ 163262306a36Sopenharmony_ci int status; 163362306a36Sopenharmony_ci struct sxgbe_tx_queue *txq = (struct sxgbe_tx_queue *)dev_id; 163462306a36Sopenharmony_ci struct sxgbe_priv_data *priv = txq->priv_ptr; 163562306a36Sopenharmony_ci 163662306a36Sopenharmony_ci /* get the channel status */ 163762306a36Sopenharmony_ci status = priv->hw->dma->tx_dma_int_status(priv->ioaddr, txq->queue_no, 163862306a36Sopenharmony_ci &priv->xstats); 163962306a36Sopenharmony_ci /* check for normal path */ 164062306a36Sopenharmony_ci if (likely((status & handle_tx))) 164162306a36Sopenharmony_ci napi_schedule(&priv->napi); 164262306a36Sopenharmony_ci 164362306a36Sopenharmony_ci /* check for unrecoverable error */ 164462306a36Sopenharmony_ci if (unlikely((status & tx_hard_error))) 164562306a36Sopenharmony_ci sxgbe_restart_tx_queue(priv, txq->queue_no); 164662306a36Sopenharmony_ci 164762306a36Sopenharmony_ci /* check for TC configuration change */ 164862306a36Sopenharmony_ci if (unlikely((status & tx_bump_tc) && 164962306a36Sopenharmony_ci (priv->tx_tc != SXGBE_MTL_SFMODE) && 165062306a36Sopenharmony_ci (priv->tx_tc < 512))) { 165162306a36Sopenharmony_ci /* step of TX TC is 32 till 128, otherwise 64 */ 165262306a36Sopenharmony_ci priv->tx_tc += (priv->tx_tc < 128) ? 32 : 64; 165362306a36Sopenharmony_ci priv->hw->mtl->set_tx_mtl_mode(priv->ioaddr, 165462306a36Sopenharmony_ci txq->queue_no, priv->tx_tc); 165562306a36Sopenharmony_ci priv->xstats.tx_threshold = priv->tx_tc; 165662306a36Sopenharmony_ci } 165762306a36Sopenharmony_ci 165862306a36Sopenharmony_ci return IRQ_HANDLED; 165962306a36Sopenharmony_ci} 166062306a36Sopenharmony_ci 166162306a36Sopenharmony_ci/** 166262306a36Sopenharmony_ci * sxgbe_rx_interrupt - RX DMA ISR 166362306a36Sopenharmony_ci * @irq: interrupt number. 166462306a36Sopenharmony_ci * @dev_id: to pass the net device pointer. 166562306a36Sopenharmony_ci * Description: this is the rx dma interrupt service routine. 166662306a36Sopenharmony_ci */ 166762306a36Sopenharmony_cistatic irqreturn_t sxgbe_rx_interrupt(int irq, void *dev_id) 166862306a36Sopenharmony_ci{ 166962306a36Sopenharmony_ci int status; 167062306a36Sopenharmony_ci struct sxgbe_rx_queue *rxq = (struct sxgbe_rx_queue *)dev_id; 167162306a36Sopenharmony_ci struct sxgbe_priv_data *priv = rxq->priv_ptr; 167262306a36Sopenharmony_ci 167362306a36Sopenharmony_ci /* get the channel status */ 167462306a36Sopenharmony_ci status = priv->hw->dma->rx_dma_int_status(priv->ioaddr, rxq->queue_no, 167562306a36Sopenharmony_ci &priv->xstats); 167662306a36Sopenharmony_ci 167762306a36Sopenharmony_ci if (likely((status & handle_rx) && (napi_schedule_prep(&priv->napi)))) { 167862306a36Sopenharmony_ci priv->hw->dma->disable_dma_irq(priv->ioaddr, rxq->queue_no); 167962306a36Sopenharmony_ci __napi_schedule(&priv->napi); 168062306a36Sopenharmony_ci } 168162306a36Sopenharmony_ci 168262306a36Sopenharmony_ci /* check for TC configuration change */ 168362306a36Sopenharmony_ci if (unlikely((status & rx_bump_tc) && 168462306a36Sopenharmony_ci (priv->rx_tc != SXGBE_MTL_SFMODE) && 168562306a36Sopenharmony_ci (priv->rx_tc < 128))) { 168662306a36Sopenharmony_ci /* step of TC is 32 */ 168762306a36Sopenharmony_ci priv->rx_tc += 32; 168862306a36Sopenharmony_ci priv->hw->mtl->set_rx_mtl_mode(priv->ioaddr, 168962306a36Sopenharmony_ci rxq->queue_no, priv->rx_tc); 169062306a36Sopenharmony_ci priv->xstats.rx_threshold = priv->rx_tc; 169162306a36Sopenharmony_ci } 169262306a36Sopenharmony_ci 169362306a36Sopenharmony_ci return IRQ_HANDLED; 169462306a36Sopenharmony_ci} 169562306a36Sopenharmony_ci 169662306a36Sopenharmony_cistatic inline u64 sxgbe_get_stat64(void __iomem *ioaddr, int reg_lo, int reg_hi) 169762306a36Sopenharmony_ci{ 169862306a36Sopenharmony_ci u64 val = readl(ioaddr + reg_lo); 169962306a36Sopenharmony_ci 170062306a36Sopenharmony_ci val |= ((u64)readl(ioaddr + reg_hi)) << 32; 170162306a36Sopenharmony_ci 170262306a36Sopenharmony_ci return val; 170362306a36Sopenharmony_ci} 170462306a36Sopenharmony_ci 170562306a36Sopenharmony_ci 170662306a36Sopenharmony_ci/* sxgbe_get_stats64 - entry point to see statistical information of device 170762306a36Sopenharmony_ci * @dev : device pointer. 170862306a36Sopenharmony_ci * @stats : pointer to hold all the statistical information of device. 170962306a36Sopenharmony_ci * Description: 171062306a36Sopenharmony_ci * This function is a driver entry point whenever ifconfig command gets 171162306a36Sopenharmony_ci * executed to see device statistics. Statistics are number of 171262306a36Sopenharmony_ci * bytes sent or received, errors occurred etc. 171362306a36Sopenharmony_ci */ 171462306a36Sopenharmony_cistatic void sxgbe_get_stats64(struct net_device *dev, 171562306a36Sopenharmony_ci struct rtnl_link_stats64 *stats) 171662306a36Sopenharmony_ci{ 171762306a36Sopenharmony_ci struct sxgbe_priv_data *priv = netdev_priv(dev); 171862306a36Sopenharmony_ci void __iomem *ioaddr = priv->ioaddr; 171962306a36Sopenharmony_ci u64 count; 172062306a36Sopenharmony_ci 172162306a36Sopenharmony_ci spin_lock(&priv->stats_lock); 172262306a36Sopenharmony_ci /* Freeze the counter registers before reading value otherwise it may 172362306a36Sopenharmony_ci * get updated by hardware while we are reading them 172462306a36Sopenharmony_ci */ 172562306a36Sopenharmony_ci writel(SXGBE_MMC_CTRL_CNT_FRZ, ioaddr + SXGBE_MMC_CTL_REG); 172662306a36Sopenharmony_ci 172762306a36Sopenharmony_ci stats->rx_bytes = sxgbe_get_stat64(ioaddr, 172862306a36Sopenharmony_ci SXGBE_MMC_RXOCTETLO_GCNT_REG, 172962306a36Sopenharmony_ci SXGBE_MMC_RXOCTETHI_GCNT_REG); 173062306a36Sopenharmony_ci 173162306a36Sopenharmony_ci stats->rx_packets = sxgbe_get_stat64(ioaddr, 173262306a36Sopenharmony_ci SXGBE_MMC_RXFRAMELO_GBCNT_REG, 173362306a36Sopenharmony_ci SXGBE_MMC_RXFRAMEHI_GBCNT_REG); 173462306a36Sopenharmony_ci 173562306a36Sopenharmony_ci stats->multicast = sxgbe_get_stat64(ioaddr, 173662306a36Sopenharmony_ci SXGBE_MMC_RXMULTILO_GCNT_REG, 173762306a36Sopenharmony_ci SXGBE_MMC_RXMULTIHI_GCNT_REG); 173862306a36Sopenharmony_ci 173962306a36Sopenharmony_ci stats->rx_crc_errors = sxgbe_get_stat64(ioaddr, 174062306a36Sopenharmony_ci SXGBE_MMC_RXCRCERRLO_REG, 174162306a36Sopenharmony_ci SXGBE_MMC_RXCRCERRHI_REG); 174262306a36Sopenharmony_ci 174362306a36Sopenharmony_ci stats->rx_length_errors = sxgbe_get_stat64(ioaddr, 174462306a36Sopenharmony_ci SXGBE_MMC_RXLENERRLO_REG, 174562306a36Sopenharmony_ci SXGBE_MMC_RXLENERRHI_REG); 174662306a36Sopenharmony_ci 174762306a36Sopenharmony_ci stats->rx_missed_errors = sxgbe_get_stat64(ioaddr, 174862306a36Sopenharmony_ci SXGBE_MMC_RXFIFOOVERFLOWLO_GBCNT_REG, 174962306a36Sopenharmony_ci SXGBE_MMC_RXFIFOOVERFLOWHI_GBCNT_REG); 175062306a36Sopenharmony_ci 175162306a36Sopenharmony_ci stats->tx_bytes = sxgbe_get_stat64(ioaddr, 175262306a36Sopenharmony_ci SXGBE_MMC_TXOCTETLO_GCNT_REG, 175362306a36Sopenharmony_ci SXGBE_MMC_TXOCTETHI_GCNT_REG); 175462306a36Sopenharmony_ci 175562306a36Sopenharmony_ci count = sxgbe_get_stat64(ioaddr, SXGBE_MMC_TXFRAMELO_GBCNT_REG, 175662306a36Sopenharmony_ci SXGBE_MMC_TXFRAMEHI_GBCNT_REG); 175762306a36Sopenharmony_ci 175862306a36Sopenharmony_ci stats->tx_errors = sxgbe_get_stat64(ioaddr, SXGBE_MMC_TXFRAMELO_GCNT_REG, 175962306a36Sopenharmony_ci SXGBE_MMC_TXFRAMEHI_GCNT_REG); 176062306a36Sopenharmony_ci stats->tx_errors = count - stats->tx_errors; 176162306a36Sopenharmony_ci stats->tx_packets = count; 176262306a36Sopenharmony_ci stats->tx_fifo_errors = sxgbe_get_stat64(ioaddr, SXGBE_MMC_TXUFLWLO_GBCNT_REG, 176362306a36Sopenharmony_ci SXGBE_MMC_TXUFLWHI_GBCNT_REG); 176462306a36Sopenharmony_ci writel(0, ioaddr + SXGBE_MMC_CTL_REG); 176562306a36Sopenharmony_ci spin_unlock(&priv->stats_lock); 176662306a36Sopenharmony_ci} 176762306a36Sopenharmony_ci 176862306a36Sopenharmony_ci/* sxgbe_set_features - entry point to set offload features of the device. 176962306a36Sopenharmony_ci * @dev : device pointer. 177062306a36Sopenharmony_ci * @features : features which are required to be set. 177162306a36Sopenharmony_ci * Description: 177262306a36Sopenharmony_ci * This function is a driver entry point and called by Linux kernel whenever 177362306a36Sopenharmony_ci * any device features are set or reset by user. 177462306a36Sopenharmony_ci * Return value: 177562306a36Sopenharmony_ci * This function returns 0 after setting or resetting device features. 177662306a36Sopenharmony_ci */ 177762306a36Sopenharmony_cistatic int sxgbe_set_features(struct net_device *dev, 177862306a36Sopenharmony_ci netdev_features_t features) 177962306a36Sopenharmony_ci{ 178062306a36Sopenharmony_ci struct sxgbe_priv_data *priv = netdev_priv(dev); 178162306a36Sopenharmony_ci netdev_features_t changed = dev->features ^ features; 178262306a36Sopenharmony_ci 178362306a36Sopenharmony_ci if (changed & NETIF_F_RXCSUM) { 178462306a36Sopenharmony_ci if (features & NETIF_F_RXCSUM) { 178562306a36Sopenharmony_ci priv->hw->mac->enable_rx_csum(priv->ioaddr); 178662306a36Sopenharmony_ci priv->rxcsum_insertion = true; 178762306a36Sopenharmony_ci } else { 178862306a36Sopenharmony_ci priv->hw->mac->disable_rx_csum(priv->ioaddr); 178962306a36Sopenharmony_ci priv->rxcsum_insertion = false; 179062306a36Sopenharmony_ci } 179162306a36Sopenharmony_ci } 179262306a36Sopenharmony_ci 179362306a36Sopenharmony_ci return 0; 179462306a36Sopenharmony_ci} 179562306a36Sopenharmony_ci 179662306a36Sopenharmony_ci/* sxgbe_change_mtu - entry point to change MTU size for the device. 179762306a36Sopenharmony_ci * @dev : device pointer. 179862306a36Sopenharmony_ci * @new_mtu : the new MTU size for the device. 179962306a36Sopenharmony_ci * Description: the Maximum Transfer Unit (MTU) is used by the network layer 180062306a36Sopenharmony_ci * to drive packet transmission. Ethernet has an MTU of 1500 octets 180162306a36Sopenharmony_ci * (ETH_DATA_LEN). This value can be changed with ifconfig. 180262306a36Sopenharmony_ci * Return value: 180362306a36Sopenharmony_ci * 0 on success and an appropriate (-)ve integer as defined in errno.h 180462306a36Sopenharmony_ci * file on failure. 180562306a36Sopenharmony_ci */ 180662306a36Sopenharmony_cistatic int sxgbe_change_mtu(struct net_device *dev, int new_mtu) 180762306a36Sopenharmony_ci{ 180862306a36Sopenharmony_ci dev->mtu = new_mtu; 180962306a36Sopenharmony_ci 181062306a36Sopenharmony_ci if (!netif_running(dev)) 181162306a36Sopenharmony_ci return 0; 181262306a36Sopenharmony_ci 181362306a36Sopenharmony_ci /* Recevice ring buffer size is needed to be set based on MTU. If MTU is 181462306a36Sopenharmony_ci * changed then reinitilisation of the receive ring buffers need to be 181562306a36Sopenharmony_ci * done. Hence bring interface down and bring interface back up 181662306a36Sopenharmony_ci */ 181762306a36Sopenharmony_ci sxgbe_release(dev); 181862306a36Sopenharmony_ci return sxgbe_open(dev); 181962306a36Sopenharmony_ci} 182062306a36Sopenharmony_ci 182162306a36Sopenharmony_cistatic void sxgbe_set_umac_addr(void __iomem *ioaddr, unsigned char *addr, 182262306a36Sopenharmony_ci unsigned int reg_n) 182362306a36Sopenharmony_ci{ 182462306a36Sopenharmony_ci unsigned long data; 182562306a36Sopenharmony_ci 182662306a36Sopenharmony_ci data = (addr[5] << 8) | addr[4]; 182762306a36Sopenharmony_ci /* For MAC Addr registers se have to set the Address Enable (AE) 182862306a36Sopenharmony_ci * bit that has no effect on the High Reg 0 where the bit 31 (MO) 182962306a36Sopenharmony_ci * is RO. 183062306a36Sopenharmony_ci */ 183162306a36Sopenharmony_ci writel(data | SXGBE_HI_REG_AE, ioaddr + SXGBE_ADDR_HIGH(reg_n)); 183262306a36Sopenharmony_ci data = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0]; 183362306a36Sopenharmony_ci writel(data, ioaddr + SXGBE_ADDR_LOW(reg_n)); 183462306a36Sopenharmony_ci} 183562306a36Sopenharmony_ci 183662306a36Sopenharmony_ci/** 183762306a36Sopenharmony_ci * sxgbe_set_rx_mode - entry point for setting different receive mode of 183862306a36Sopenharmony_ci * a device. unicast, multicast addressing 183962306a36Sopenharmony_ci * @dev : pointer to the device structure 184062306a36Sopenharmony_ci * Description: 184162306a36Sopenharmony_ci * This function is a driver entry point which gets called by the kernel 184262306a36Sopenharmony_ci * whenever different receive mode like unicast, multicast and promiscuous 184362306a36Sopenharmony_ci * must be enabled/disabled. 184462306a36Sopenharmony_ci * Return value: 184562306a36Sopenharmony_ci * void. 184662306a36Sopenharmony_ci */ 184762306a36Sopenharmony_cistatic void sxgbe_set_rx_mode(struct net_device *dev) 184862306a36Sopenharmony_ci{ 184962306a36Sopenharmony_ci struct sxgbe_priv_data *priv = netdev_priv(dev); 185062306a36Sopenharmony_ci void __iomem *ioaddr = (void __iomem *)priv->ioaddr; 185162306a36Sopenharmony_ci unsigned int value = 0; 185262306a36Sopenharmony_ci u32 mc_filter[2]; 185362306a36Sopenharmony_ci struct netdev_hw_addr *ha; 185462306a36Sopenharmony_ci int reg = 1; 185562306a36Sopenharmony_ci 185662306a36Sopenharmony_ci netdev_dbg(dev, "%s: # mcasts %d, # unicast %d\n", 185762306a36Sopenharmony_ci __func__, netdev_mc_count(dev), netdev_uc_count(dev)); 185862306a36Sopenharmony_ci 185962306a36Sopenharmony_ci if (dev->flags & IFF_PROMISC) { 186062306a36Sopenharmony_ci value = SXGBE_FRAME_FILTER_PR; 186162306a36Sopenharmony_ci 186262306a36Sopenharmony_ci } else if ((netdev_mc_count(dev) > SXGBE_HASH_TABLE_SIZE) || 186362306a36Sopenharmony_ci (dev->flags & IFF_ALLMULTI)) { 186462306a36Sopenharmony_ci value = SXGBE_FRAME_FILTER_PM; /* pass all multi */ 186562306a36Sopenharmony_ci writel(0xffffffff, ioaddr + SXGBE_HASH_HIGH); 186662306a36Sopenharmony_ci writel(0xffffffff, ioaddr + SXGBE_HASH_LOW); 186762306a36Sopenharmony_ci 186862306a36Sopenharmony_ci } else if (!netdev_mc_empty(dev)) { 186962306a36Sopenharmony_ci /* Hash filter for multicast */ 187062306a36Sopenharmony_ci value = SXGBE_FRAME_FILTER_HMC; 187162306a36Sopenharmony_ci 187262306a36Sopenharmony_ci memset(mc_filter, 0, sizeof(mc_filter)); 187362306a36Sopenharmony_ci netdev_for_each_mc_addr(ha, dev) { 187462306a36Sopenharmony_ci /* The upper 6 bits of the calculated CRC are used to 187562306a36Sopenharmony_ci * index the contens of the hash table 187662306a36Sopenharmony_ci */ 187762306a36Sopenharmony_ci int bit_nr = bitrev32(~crc32_le(~0, ha->addr, 6)) >> 26; 187862306a36Sopenharmony_ci 187962306a36Sopenharmony_ci /* The most significant bit determines the register to 188062306a36Sopenharmony_ci * use (H/L) while the other 5 bits determine the bit 188162306a36Sopenharmony_ci * within the register. 188262306a36Sopenharmony_ci */ 188362306a36Sopenharmony_ci mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31); 188462306a36Sopenharmony_ci } 188562306a36Sopenharmony_ci writel(mc_filter[0], ioaddr + SXGBE_HASH_LOW); 188662306a36Sopenharmony_ci writel(mc_filter[1], ioaddr + SXGBE_HASH_HIGH); 188762306a36Sopenharmony_ci } 188862306a36Sopenharmony_ci 188962306a36Sopenharmony_ci /* Handle multiple unicast addresses (perfect filtering) */ 189062306a36Sopenharmony_ci if (netdev_uc_count(dev) > SXGBE_MAX_PERFECT_ADDRESSES) 189162306a36Sopenharmony_ci /* Switch to promiscuous mode if more than 16 addrs 189262306a36Sopenharmony_ci * are required 189362306a36Sopenharmony_ci */ 189462306a36Sopenharmony_ci value |= SXGBE_FRAME_FILTER_PR; 189562306a36Sopenharmony_ci else { 189662306a36Sopenharmony_ci netdev_for_each_uc_addr(ha, dev) { 189762306a36Sopenharmony_ci sxgbe_set_umac_addr(ioaddr, ha->addr, reg); 189862306a36Sopenharmony_ci reg++; 189962306a36Sopenharmony_ci } 190062306a36Sopenharmony_ci } 190162306a36Sopenharmony_ci#ifdef FRAME_FILTER_DEBUG 190262306a36Sopenharmony_ci /* Enable Receive all mode (to debug filtering_fail errors) */ 190362306a36Sopenharmony_ci value |= SXGBE_FRAME_FILTER_RA; 190462306a36Sopenharmony_ci#endif 190562306a36Sopenharmony_ci writel(value, ioaddr + SXGBE_FRAME_FILTER); 190662306a36Sopenharmony_ci 190762306a36Sopenharmony_ci netdev_dbg(dev, "Filter: 0x%08x\n\tHash: HI 0x%08x, LO 0x%08x\n", 190862306a36Sopenharmony_ci readl(ioaddr + SXGBE_FRAME_FILTER), 190962306a36Sopenharmony_ci readl(ioaddr + SXGBE_HASH_HIGH), 191062306a36Sopenharmony_ci readl(ioaddr + SXGBE_HASH_LOW)); 191162306a36Sopenharmony_ci} 191262306a36Sopenharmony_ci 191362306a36Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER 191462306a36Sopenharmony_ci/** 191562306a36Sopenharmony_ci * sxgbe_poll_controller - entry point for polling receive by device 191662306a36Sopenharmony_ci * @dev : pointer to the device structure 191762306a36Sopenharmony_ci * Description: 191862306a36Sopenharmony_ci * This function is used by NETCONSOLE and other diagnostic tools 191962306a36Sopenharmony_ci * to allow network I/O with interrupts disabled. 192062306a36Sopenharmony_ci * Return value: 192162306a36Sopenharmony_ci * Void. 192262306a36Sopenharmony_ci */ 192362306a36Sopenharmony_cistatic void sxgbe_poll_controller(struct net_device *dev) 192462306a36Sopenharmony_ci{ 192562306a36Sopenharmony_ci struct sxgbe_priv_data *priv = netdev_priv(dev); 192662306a36Sopenharmony_ci 192762306a36Sopenharmony_ci disable_irq(priv->irq); 192862306a36Sopenharmony_ci sxgbe_rx_interrupt(priv->irq, dev); 192962306a36Sopenharmony_ci enable_irq(priv->irq); 193062306a36Sopenharmony_ci} 193162306a36Sopenharmony_ci#endif 193262306a36Sopenharmony_ci 193362306a36Sopenharmony_ci/* sxgbe_ioctl - Entry point for the Ioctl 193462306a36Sopenharmony_ci * @dev: Device pointer. 193562306a36Sopenharmony_ci * @rq: An IOCTL specefic structure, that can contain a pointer to 193662306a36Sopenharmony_ci * a proprietary structure used to pass information to the driver. 193762306a36Sopenharmony_ci * @cmd: IOCTL command 193862306a36Sopenharmony_ci * Description: 193962306a36Sopenharmony_ci * Currently it supports the phy_mii_ioctl(...) and HW time stamping. 194062306a36Sopenharmony_ci */ 194162306a36Sopenharmony_cistatic int sxgbe_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) 194262306a36Sopenharmony_ci{ 194362306a36Sopenharmony_ci int ret = -EOPNOTSUPP; 194462306a36Sopenharmony_ci 194562306a36Sopenharmony_ci if (!netif_running(dev)) 194662306a36Sopenharmony_ci return -EINVAL; 194762306a36Sopenharmony_ci 194862306a36Sopenharmony_ci switch (cmd) { 194962306a36Sopenharmony_ci case SIOCGMIIPHY: 195062306a36Sopenharmony_ci case SIOCGMIIREG: 195162306a36Sopenharmony_ci case SIOCSMIIREG: 195262306a36Sopenharmony_ci ret = phy_do_ioctl(dev, rq, cmd); 195362306a36Sopenharmony_ci break; 195462306a36Sopenharmony_ci default: 195562306a36Sopenharmony_ci break; 195662306a36Sopenharmony_ci } 195762306a36Sopenharmony_ci 195862306a36Sopenharmony_ci return ret; 195962306a36Sopenharmony_ci} 196062306a36Sopenharmony_ci 196162306a36Sopenharmony_cistatic const struct net_device_ops sxgbe_netdev_ops = { 196262306a36Sopenharmony_ci .ndo_open = sxgbe_open, 196362306a36Sopenharmony_ci .ndo_start_xmit = sxgbe_xmit, 196462306a36Sopenharmony_ci .ndo_stop = sxgbe_release, 196562306a36Sopenharmony_ci .ndo_get_stats64 = sxgbe_get_stats64, 196662306a36Sopenharmony_ci .ndo_change_mtu = sxgbe_change_mtu, 196762306a36Sopenharmony_ci .ndo_set_features = sxgbe_set_features, 196862306a36Sopenharmony_ci .ndo_set_rx_mode = sxgbe_set_rx_mode, 196962306a36Sopenharmony_ci .ndo_tx_timeout = sxgbe_tx_timeout, 197062306a36Sopenharmony_ci .ndo_eth_ioctl = sxgbe_ioctl, 197162306a36Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER 197262306a36Sopenharmony_ci .ndo_poll_controller = sxgbe_poll_controller, 197362306a36Sopenharmony_ci#endif 197462306a36Sopenharmony_ci .ndo_set_mac_address = eth_mac_addr, 197562306a36Sopenharmony_ci}; 197662306a36Sopenharmony_ci 197762306a36Sopenharmony_ci/* Get the hardware ops */ 197862306a36Sopenharmony_cistatic void sxgbe_get_ops(struct sxgbe_ops * const ops_ptr) 197962306a36Sopenharmony_ci{ 198062306a36Sopenharmony_ci ops_ptr->mac = sxgbe_get_core_ops(); 198162306a36Sopenharmony_ci ops_ptr->desc = sxgbe_get_desc_ops(); 198262306a36Sopenharmony_ci ops_ptr->dma = sxgbe_get_dma_ops(); 198362306a36Sopenharmony_ci ops_ptr->mtl = sxgbe_get_mtl_ops(); 198462306a36Sopenharmony_ci 198562306a36Sopenharmony_ci /* set the MDIO communication Address/Data regisers */ 198662306a36Sopenharmony_ci ops_ptr->mii.addr = SXGBE_MDIO_SCMD_ADD_REG; 198762306a36Sopenharmony_ci ops_ptr->mii.data = SXGBE_MDIO_SCMD_DATA_REG; 198862306a36Sopenharmony_ci 198962306a36Sopenharmony_ci /* Assigning the default link settings 199062306a36Sopenharmony_ci * no SXGBE defined default values to be set in registers, 199162306a36Sopenharmony_ci * so assigning as 0 for port and duplex 199262306a36Sopenharmony_ci */ 199362306a36Sopenharmony_ci ops_ptr->link.port = 0; 199462306a36Sopenharmony_ci ops_ptr->link.duplex = 0; 199562306a36Sopenharmony_ci ops_ptr->link.speed = SXGBE_SPEED_10G; 199662306a36Sopenharmony_ci} 199762306a36Sopenharmony_ci 199862306a36Sopenharmony_ci/** 199962306a36Sopenharmony_ci * sxgbe_hw_init - Init the GMAC device 200062306a36Sopenharmony_ci * @priv: driver private structure 200162306a36Sopenharmony_ci * Description: this function checks the HW capability 200262306a36Sopenharmony_ci * (if supported) and sets the driver's features. 200362306a36Sopenharmony_ci */ 200462306a36Sopenharmony_cistatic int sxgbe_hw_init(struct sxgbe_priv_data * const priv) 200562306a36Sopenharmony_ci{ 200662306a36Sopenharmony_ci u32 ctrl_ids; 200762306a36Sopenharmony_ci 200862306a36Sopenharmony_ci priv->hw = kmalloc(sizeof(*priv->hw), GFP_KERNEL); 200962306a36Sopenharmony_ci if(!priv->hw) 201062306a36Sopenharmony_ci return -ENOMEM; 201162306a36Sopenharmony_ci 201262306a36Sopenharmony_ci /* get the hardware ops */ 201362306a36Sopenharmony_ci sxgbe_get_ops(priv->hw); 201462306a36Sopenharmony_ci 201562306a36Sopenharmony_ci /* get the controller id */ 201662306a36Sopenharmony_ci ctrl_ids = priv->hw->mac->get_controller_version(priv->ioaddr); 201762306a36Sopenharmony_ci priv->hw->ctrl_uid = (ctrl_ids & 0x00ff0000) >> 16; 201862306a36Sopenharmony_ci priv->hw->ctrl_id = (ctrl_ids & 0x000000ff); 201962306a36Sopenharmony_ci pr_info("user ID: 0x%x, Controller ID: 0x%x\n", 202062306a36Sopenharmony_ci priv->hw->ctrl_uid, priv->hw->ctrl_id); 202162306a36Sopenharmony_ci 202262306a36Sopenharmony_ci /* get the H/W features */ 202362306a36Sopenharmony_ci if (!sxgbe_get_hw_features(priv)) 202462306a36Sopenharmony_ci pr_info("Hardware features not found\n"); 202562306a36Sopenharmony_ci 202662306a36Sopenharmony_ci if (priv->hw_cap.tx_csum_offload) 202762306a36Sopenharmony_ci pr_info("TX Checksum offload supported\n"); 202862306a36Sopenharmony_ci 202962306a36Sopenharmony_ci if (priv->hw_cap.rx_csum_offload) 203062306a36Sopenharmony_ci pr_info("RX Checksum offload supported\n"); 203162306a36Sopenharmony_ci 203262306a36Sopenharmony_ci return 0; 203362306a36Sopenharmony_ci} 203462306a36Sopenharmony_ci 203562306a36Sopenharmony_cistatic int sxgbe_sw_reset(void __iomem *addr) 203662306a36Sopenharmony_ci{ 203762306a36Sopenharmony_ci int retry_count = 10; 203862306a36Sopenharmony_ci 203962306a36Sopenharmony_ci writel(SXGBE_DMA_SOFT_RESET, addr + SXGBE_DMA_MODE_REG); 204062306a36Sopenharmony_ci while (retry_count--) { 204162306a36Sopenharmony_ci if (!(readl(addr + SXGBE_DMA_MODE_REG) & 204262306a36Sopenharmony_ci SXGBE_DMA_SOFT_RESET)) 204362306a36Sopenharmony_ci break; 204462306a36Sopenharmony_ci mdelay(10); 204562306a36Sopenharmony_ci } 204662306a36Sopenharmony_ci 204762306a36Sopenharmony_ci if (retry_count < 0) 204862306a36Sopenharmony_ci return -EBUSY; 204962306a36Sopenharmony_ci 205062306a36Sopenharmony_ci return 0; 205162306a36Sopenharmony_ci} 205262306a36Sopenharmony_ci 205362306a36Sopenharmony_ci/** 205462306a36Sopenharmony_ci * sxgbe_drv_probe 205562306a36Sopenharmony_ci * @device: device pointer 205662306a36Sopenharmony_ci * @plat_dat: platform data pointer 205762306a36Sopenharmony_ci * @addr: iobase memory address 205862306a36Sopenharmony_ci * Description: this is the main probe function used to 205962306a36Sopenharmony_ci * call the alloc_etherdev, allocate the priv structure. 206062306a36Sopenharmony_ci */ 206162306a36Sopenharmony_cistruct sxgbe_priv_data *sxgbe_drv_probe(struct device *device, 206262306a36Sopenharmony_ci struct sxgbe_plat_data *plat_dat, 206362306a36Sopenharmony_ci void __iomem *addr) 206462306a36Sopenharmony_ci{ 206562306a36Sopenharmony_ci struct sxgbe_priv_data *priv; 206662306a36Sopenharmony_ci struct net_device *ndev; 206762306a36Sopenharmony_ci int ret; 206862306a36Sopenharmony_ci u8 queue_num; 206962306a36Sopenharmony_ci 207062306a36Sopenharmony_ci ndev = alloc_etherdev_mqs(sizeof(struct sxgbe_priv_data), 207162306a36Sopenharmony_ci SXGBE_TX_QUEUES, SXGBE_RX_QUEUES); 207262306a36Sopenharmony_ci if (!ndev) 207362306a36Sopenharmony_ci return NULL; 207462306a36Sopenharmony_ci 207562306a36Sopenharmony_ci SET_NETDEV_DEV(ndev, device); 207662306a36Sopenharmony_ci 207762306a36Sopenharmony_ci priv = netdev_priv(ndev); 207862306a36Sopenharmony_ci priv->device = device; 207962306a36Sopenharmony_ci priv->dev = ndev; 208062306a36Sopenharmony_ci 208162306a36Sopenharmony_ci sxgbe_set_ethtool_ops(ndev); 208262306a36Sopenharmony_ci priv->plat = plat_dat; 208362306a36Sopenharmony_ci priv->ioaddr = addr; 208462306a36Sopenharmony_ci 208562306a36Sopenharmony_ci ret = sxgbe_sw_reset(priv->ioaddr); 208662306a36Sopenharmony_ci if (ret) 208762306a36Sopenharmony_ci goto error_free_netdev; 208862306a36Sopenharmony_ci 208962306a36Sopenharmony_ci /* Verify driver arguments */ 209062306a36Sopenharmony_ci sxgbe_verify_args(); 209162306a36Sopenharmony_ci 209262306a36Sopenharmony_ci /* Init MAC and get the capabilities */ 209362306a36Sopenharmony_ci ret = sxgbe_hw_init(priv); 209462306a36Sopenharmony_ci if (ret) 209562306a36Sopenharmony_ci goto error_free_netdev; 209662306a36Sopenharmony_ci 209762306a36Sopenharmony_ci /* allocate memory resources for Descriptor rings */ 209862306a36Sopenharmony_ci ret = txring_mem_alloc(priv); 209962306a36Sopenharmony_ci if (ret) 210062306a36Sopenharmony_ci goto error_free_hw; 210162306a36Sopenharmony_ci 210262306a36Sopenharmony_ci ret = rxring_mem_alloc(priv); 210362306a36Sopenharmony_ci if (ret) 210462306a36Sopenharmony_ci goto error_free_hw; 210562306a36Sopenharmony_ci 210662306a36Sopenharmony_ci ndev->netdev_ops = &sxgbe_netdev_ops; 210762306a36Sopenharmony_ci 210862306a36Sopenharmony_ci ndev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | 210962306a36Sopenharmony_ci NETIF_F_RXCSUM | NETIF_F_TSO | NETIF_F_TSO6 | 211062306a36Sopenharmony_ci NETIF_F_GRO; 211162306a36Sopenharmony_ci ndev->features |= ndev->hw_features | NETIF_F_HIGHDMA; 211262306a36Sopenharmony_ci ndev->watchdog_timeo = msecs_to_jiffies(TX_TIMEO); 211362306a36Sopenharmony_ci 211462306a36Sopenharmony_ci /* assign filtering support */ 211562306a36Sopenharmony_ci ndev->priv_flags |= IFF_UNICAST_FLT; 211662306a36Sopenharmony_ci 211762306a36Sopenharmony_ci /* MTU range: 68 - 9000 */ 211862306a36Sopenharmony_ci ndev->min_mtu = MIN_MTU; 211962306a36Sopenharmony_ci ndev->max_mtu = MAX_MTU; 212062306a36Sopenharmony_ci 212162306a36Sopenharmony_ci priv->msg_enable = netif_msg_init(debug, default_msg_level); 212262306a36Sopenharmony_ci 212362306a36Sopenharmony_ci /* Enable TCP segmentation offload for all DMA channels */ 212462306a36Sopenharmony_ci if (priv->hw_cap.tcpseg_offload) { 212562306a36Sopenharmony_ci SXGBE_FOR_EACH_QUEUE(SXGBE_TX_QUEUES, queue_num) { 212662306a36Sopenharmony_ci priv->hw->dma->enable_tso(priv->ioaddr, queue_num); 212762306a36Sopenharmony_ci } 212862306a36Sopenharmony_ci } 212962306a36Sopenharmony_ci 213062306a36Sopenharmony_ci /* Enable Rx checksum offload */ 213162306a36Sopenharmony_ci if (priv->hw_cap.rx_csum_offload) { 213262306a36Sopenharmony_ci priv->hw->mac->enable_rx_csum(priv->ioaddr); 213362306a36Sopenharmony_ci priv->rxcsum_insertion = true; 213462306a36Sopenharmony_ci } 213562306a36Sopenharmony_ci 213662306a36Sopenharmony_ci /* Initialise pause frame settings */ 213762306a36Sopenharmony_ci priv->rx_pause = 1; 213862306a36Sopenharmony_ci priv->tx_pause = 1; 213962306a36Sopenharmony_ci 214062306a36Sopenharmony_ci /* Rx Watchdog is available, enable depend on platform data */ 214162306a36Sopenharmony_ci if (!priv->plat->riwt_off) { 214262306a36Sopenharmony_ci priv->use_riwt = 1; 214362306a36Sopenharmony_ci pr_info("Enable RX Mitigation via HW Watchdog Timer\n"); 214462306a36Sopenharmony_ci } 214562306a36Sopenharmony_ci 214662306a36Sopenharmony_ci netif_napi_add(ndev, &priv->napi, sxgbe_poll); 214762306a36Sopenharmony_ci 214862306a36Sopenharmony_ci spin_lock_init(&priv->stats_lock); 214962306a36Sopenharmony_ci 215062306a36Sopenharmony_ci priv->sxgbe_clk = clk_get(priv->device, SXGBE_RESOURCE_NAME); 215162306a36Sopenharmony_ci if (IS_ERR(priv->sxgbe_clk)) { 215262306a36Sopenharmony_ci netdev_warn(ndev, "%s: warning: cannot get CSR clock\n", 215362306a36Sopenharmony_ci __func__); 215462306a36Sopenharmony_ci goto error_napi_del; 215562306a36Sopenharmony_ci } 215662306a36Sopenharmony_ci 215762306a36Sopenharmony_ci /* If a specific clk_csr value is passed from the platform 215862306a36Sopenharmony_ci * this means that the CSR Clock Range selection cannot be 215962306a36Sopenharmony_ci * changed at run-time and it is fixed. Viceversa the driver'll try to 216062306a36Sopenharmony_ci * set the MDC clock dynamically according to the csr actual 216162306a36Sopenharmony_ci * clock input. 216262306a36Sopenharmony_ci */ 216362306a36Sopenharmony_ci if (!priv->plat->clk_csr) 216462306a36Sopenharmony_ci sxgbe_clk_csr_set(priv); 216562306a36Sopenharmony_ci else 216662306a36Sopenharmony_ci priv->clk_csr = priv->plat->clk_csr; 216762306a36Sopenharmony_ci 216862306a36Sopenharmony_ci /* MDIO bus Registration */ 216962306a36Sopenharmony_ci ret = sxgbe_mdio_register(ndev); 217062306a36Sopenharmony_ci if (ret < 0) { 217162306a36Sopenharmony_ci netdev_dbg(ndev, "%s: MDIO bus (id: %d) registration failed\n", 217262306a36Sopenharmony_ci __func__, priv->plat->bus_id); 217362306a36Sopenharmony_ci goto error_clk_put; 217462306a36Sopenharmony_ci } 217562306a36Sopenharmony_ci 217662306a36Sopenharmony_ci ret = register_netdev(ndev); 217762306a36Sopenharmony_ci if (ret) { 217862306a36Sopenharmony_ci pr_err("%s: ERROR %i registering the device\n", __func__, ret); 217962306a36Sopenharmony_ci goto error_mdio_unregister; 218062306a36Sopenharmony_ci } 218162306a36Sopenharmony_ci 218262306a36Sopenharmony_ci sxgbe_check_ether_addr(priv); 218362306a36Sopenharmony_ci 218462306a36Sopenharmony_ci return priv; 218562306a36Sopenharmony_ci 218662306a36Sopenharmony_cierror_mdio_unregister: 218762306a36Sopenharmony_ci sxgbe_mdio_unregister(ndev); 218862306a36Sopenharmony_cierror_clk_put: 218962306a36Sopenharmony_ci clk_put(priv->sxgbe_clk); 219062306a36Sopenharmony_cierror_napi_del: 219162306a36Sopenharmony_ci netif_napi_del(&priv->napi); 219262306a36Sopenharmony_cierror_free_hw: 219362306a36Sopenharmony_ci kfree(priv->hw); 219462306a36Sopenharmony_cierror_free_netdev: 219562306a36Sopenharmony_ci free_netdev(ndev); 219662306a36Sopenharmony_ci 219762306a36Sopenharmony_ci return NULL; 219862306a36Sopenharmony_ci} 219962306a36Sopenharmony_ci 220062306a36Sopenharmony_ci/** 220162306a36Sopenharmony_ci * sxgbe_drv_remove 220262306a36Sopenharmony_ci * @ndev: net device pointer 220362306a36Sopenharmony_ci * Description: this function resets the TX/RX processes, disables the MAC RX/TX 220462306a36Sopenharmony_ci * changes the link status, releases the DMA descriptor rings. 220562306a36Sopenharmony_ci */ 220662306a36Sopenharmony_civoid sxgbe_drv_remove(struct net_device *ndev) 220762306a36Sopenharmony_ci{ 220862306a36Sopenharmony_ci struct sxgbe_priv_data *priv = netdev_priv(ndev); 220962306a36Sopenharmony_ci u8 queue_num; 221062306a36Sopenharmony_ci 221162306a36Sopenharmony_ci netdev_info(ndev, "%s: removing driver\n", __func__); 221262306a36Sopenharmony_ci 221362306a36Sopenharmony_ci SXGBE_FOR_EACH_QUEUE(SXGBE_RX_QUEUES, queue_num) { 221462306a36Sopenharmony_ci priv->hw->mac->disable_rxqueue(priv->ioaddr, queue_num); 221562306a36Sopenharmony_ci } 221662306a36Sopenharmony_ci 221762306a36Sopenharmony_ci priv->hw->dma->stop_rx(priv->ioaddr, SXGBE_RX_QUEUES); 221862306a36Sopenharmony_ci priv->hw->dma->stop_tx(priv->ioaddr, SXGBE_TX_QUEUES); 221962306a36Sopenharmony_ci 222062306a36Sopenharmony_ci priv->hw->mac->enable_tx(priv->ioaddr, false); 222162306a36Sopenharmony_ci priv->hw->mac->enable_rx(priv->ioaddr, false); 222262306a36Sopenharmony_ci 222362306a36Sopenharmony_ci unregister_netdev(ndev); 222462306a36Sopenharmony_ci 222562306a36Sopenharmony_ci sxgbe_mdio_unregister(ndev); 222662306a36Sopenharmony_ci 222762306a36Sopenharmony_ci clk_put(priv->sxgbe_clk); 222862306a36Sopenharmony_ci 222962306a36Sopenharmony_ci netif_napi_del(&priv->napi); 223062306a36Sopenharmony_ci 223162306a36Sopenharmony_ci kfree(priv->hw); 223262306a36Sopenharmony_ci 223362306a36Sopenharmony_ci free_netdev(ndev); 223462306a36Sopenharmony_ci} 223562306a36Sopenharmony_ci 223662306a36Sopenharmony_ci#ifdef CONFIG_PM 223762306a36Sopenharmony_ciint sxgbe_suspend(struct net_device *ndev) 223862306a36Sopenharmony_ci{ 223962306a36Sopenharmony_ci return 0; 224062306a36Sopenharmony_ci} 224162306a36Sopenharmony_ci 224262306a36Sopenharmony_ciint sxgbe_resume(struct net_device *ndev) 224362306a36Sopenharmony_ci{ 224462306a36Sopenharmony_ci return 0; 224562306a36Sopenharmony_ci} 224662306a36Sopenharmony_ci 224762306a36Sopenharmony_ciint sxgbe_freeze(struct net_device *ndev) 224862306a36Sopenharmony_ci{ 224962306a36Sopenharmony_ci return -ENOSYS; 225062306a36Sopenharmony_ci} 225162306a36Sopenharmony_ci 225262306a36Sopenharmony_ciint sxgbe_restore(struct net_device *ndev) 225362306a36Sopenharmony_ci{ 225462306a36Sopenharmony_ci return -ENOSYS; 225562306a36Sopenharmony_ci} 225662306a36Sopenharmony_ci#endif /* CONFIG_PM */ 225762306a36Sopenharmony_ci 225862306a36Sopenharmony_ci/* Driver is configured as Platform driver */ 225962306a36Sopenharmony_cistatic int __init sxgbe_init(void) 226062306a36Sopenharmony_ci{ 226162306a36Sopenharmony_ci int ret; 226262306a36Sopenharmony_ci 226362306a36Sopenharmony_ci ret = sxgbe_register_platform(); 226462306a36Sopenharmony_ci if (ret) 226562306a36Sopenharmony_ci goto err; 226662306a36Sopenharmony_ci return 0; 226762306a36Sopenharmony_cierr: 226862306a36Sopenharmony_ci pr_err("driver registration failed\n"); 226962306a36Sopenharmony_ci return ret; 227062306a36Sopenharmony_ci} 227162306a36Sopenharmony_ci 227262306a36Sopenharmony_cistatic void __exit sxgbe_exit(void) 227362306a36Sopenharmony_ci{ 227462306a36Sopenharmony_ci sxgbe_unregister_platform(); 227562306a36Sopenharmony_ci} 227662306a36Sopenharmony_ci 227762306a36Sopenharmony_cimodule_init(sxgbe_init); 227862306a36Sopenharmony_cimodule_exit(sxgbe_exit); 227962306a36Sopenharmony_ci 228062306a36Sopenharmony_ci#ifndef MODULE 228162306a36Sopenharmony_cistatic int __init sxgbe_cmdline_opt(char *str) 228262306a36Sopenharmony_ci{ 228362306a36Sopenharmony_ci char *opt; 228462306a36Sopenharmony_ci 228562306a36Sopenharmony_ci if (!str || !*str) 228662306a36Sopenharmony_ci return 1; 228762306a36Sopenharmony_ci while ((opt = strsep(&str, ",")) != NULL) { 228862306a36Sopenharmony_ci if (!strncmp(opt, "eee_timer:", 10)) { 228962306a36Sopenharmony_ci if (kstrtoint(opt + 10, 0, &eee_timer)) 229062306a36Sopenharmony_ci goto err; 229162306a36Sopenharmony_ci } 229262306a36Sopenharmony_ci } 229362306a36Sopenharmony_ci return 1; 229462306a36Sopenharmony_ci 229562306a36Sopenharmony_cierr: 229662306a36Sopenharmony_ci pr_err("%s: ERROR broken module parameter conversion\n", __func__); 229762306a36Sopenharmony_ci return 1; 229862306a36Sopenharmony_ci} 229962306a36Sopenharmony_ci 230062306a36Sopenharmony_ci__setup("sxgbeeth=", sxgbe_cmdline_opt); 230162306a36Sopenharmony_ci#endif /* MODULE */ 230262306a36Sopenharmony_ci 230362306a36Sopenharmony_ci 230462306a36Sopenharmony_ci 230562306a36Sopenharmony_ciMODULE_DESCRIPTION("Samsung 10G/2.5G/1G Ethernet PLATFORM driver"); 230662306a36Sopenharmony_ci 230762306a36Sopenharmony_ciMODULE_PARM_DESC(debug, "Message Level (-1: default, 0: no output, 16: all)"); 230862306a36Sopenharmony_ciMODULE_PARM_DESC(eee_timer, "EEE-LPI Default LS timer value"); 230962306a36Sopenharmony_ci 231062306a36Sopenharmony_ciMODULE_AUTHOR("Siva Reddy Kallam <siva.kallam@samsung.com>"); 231162306a36Sopenharmony_ciMODULE_AUTHOR("ByungHo An <bh74.an@samsung.com>"); 231262306a36Sopenharmony_ciMODULE_AUTHOR("Girish K S <ks.giri@samsung.com>"); 231362306a36Sopenharmony_ciMODULE_AUTHOR("Vipul Pandya <vipul.pandya@samsung.com>"); 231462306a36Sopenharmony_ci 231562306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 2316