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