// SPDX-License-Identifier: GPL-2.0-only
/*******************************************************************************
This is the driver for the ST MAC 10/100/1000 on-chip Ethernet controllers.
ST Ethernet IPs are built around a Synopsys IP Core.
Copyright(C) 2007-2011 STMicroelectronics Ltd
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
Documentation available at:
http://www.stlinux.com
Support available at:
https://bugzilla.stlinux.com/
*******************************************************************************/
#include <linux/clk.h>
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/skbuff.h>
#include <linux/ethtool.h>
#include <linux/if_ether.h>
#include <linux/crc32.h>
#include <linux/mii.h>
#include <linux/
if.h>
#include <linux/if_vlan.h>
#include <linux/dma-mapping.h>
#include <linux/slab.h>
#include <linux/pm_runtime.h>
#include <linux/prefetch.h>
#include <linux/pinctrl/consumer.h>
#ifdef CONFIG_DEBUG_FS
#include <linux/debugfs.h>
#include <linux/seq_file.h>
#endif /* CONFIG_DEBUG_FS */
#include <linux/net_tstamp.h>
#include <linux/phylink.h>
#include <linux/udp.h>
#include <linux/bpf_trace.h>
#include <net/page_pool/helpers.h>
#include <net/pkt_cls.h>
#include <net/xdp_sock_drv.h>
#include "stmmac_ptp.h"
#include "stmmac_fpe.h"
#include "stmmac.h"
#include "stmmac_xdp.h"
#include <linux/reset.h>
#include <linux/of_mdio.h>
#include "dwmac1000.h"
#include "dwxgmac2.h"
#include "hwif.h"
/* As long as the interface is active, we keep the timestamping counter enabled
* with fine resolution and binary rollover. This avoid non-monotonic behavior
* (clock jumps) when changing timestamping settings at runtime.
*/
#define STMMAC_HWTS_ACTIVE (PTP_TCR_TSENA | PTP_TCR_TSCFUPDT | \
PTP_TCR_TSCTRLSSR)
#define STMMAC_ALIGN(x) ALIGN(ALIGN(x, SMP_CACHE_BYTES), 16)
#define TSO_MAX_BUFF_SIZE (SZ_16K - 1)
/* Module parameters */
#define TX_TIMEO 5000
static int watchdog = TX_TIMEO;
module_param(watchdog,
int, 0644);
MODULE_PARM_DESC(watchdog,
"Transmit timeout in milliseconds (default 5s)");
static int debug = -1;
module_param(debug,
int, 0644);
MODULE_PARM_DESC(debug,
"Message Level (-1: default, 0: no output, 16: all)");
static int phyaddr = -1;
module_param(phyaddr,
int, 0444);
MODULE_PARM_DESC(phyaddr,
"Physical device address");
#define STMMAC_TX_THRESH(x) ((x)->dma_conf.dma_tx_size / 4)
/* Limit to make sure XDP TX and slow path can coexist */
#define STMMAC_XSK_TX_BUDGET_MAX 256
#define STMMAC_TX_XSK_AVAIL 16
#define STMMAC_RX_FILL_BATCH 16
#define STMMAC_XDP_PASS 0
#define STMMAC_XDP_CONSUMED BIT(0)
#define STMMAC_XDP_TX BIT(1)
#define STMMAC_XDP_REDIRECT BIT(2)
static int flow_ctrl = 0xdead;
module_param(flow_ctrl,
int, 0644);
MODULE_PARM_DESC(flow_ctrl,
"Flow control ability [on/off] (obsolete)");
static int pause = PAUSE_TIME;
module_param(pause,
int, 0644);
MODULE_PARM_DESC(pause,
"Flow Control Pause Time (units of 512 bit times)");
#define TC_DEFAULT 64
static int tc = TC_DEFAULT;
module_param(tc,
int, 0644);
MODULE_PARM_DESC(tc,
"DMA threshold control value");
/* This is unused */
#define DEFAULT_BUFSIZE 1536
static int buf_sz = DEFAULT_BUFSIZE;
module_param(buf_sz,
int, 0644);
MODULE_PARM_DESC(buf_sz,
"DMA buffer size");
static const u32 default_msg_level = (NETIF_MSG_DRV | NETIF_MSG_PROBE |
NETIF_MSG_LINK | NETIF_MSG_IFUP |
NETIF_MSG_IFDOWN | NETIF_MSG_TIMER);
#define STMMAC_DEFAULT_LPI_TIMER 1000
static unsigned int eee_timer = STMMAC_DEFAULT_LPI_TIMER;
module_param(eee_timer, uint, 0644);
MODULE_PARM_DESC(eee_timer,
"LPI tx expiration time in msec");
#define STMMAC_LPI_T(x) (jiffies + usecs_to_jiffies(x))
/* By default the driver will use the ring mode to manage tx and rx descriptors,
* but allow user to force to use the chain instead of the ring
*/
static unsigned int chain_mode;
module_param(chain_mode,
int, 0444);
MODULE_PARM_DESC(chain_mode,
"To use chain instead of ring mode");
static irqreturn_t stmmac_interrupt(
int irq,
void *dev_id);
/* For MSI interrupts handling */
static irqreturn_t stmmac_mac_interrupt(
int irq,
void *dev_id);
static irqreturn_t stmmac_safety_interrupt(
int irq,
void *dev_id);
static irqreturn_t stmmac_msi_intr_tx(
int irq,
void *data);
static irqreturn_t stmmac_msi_intr_rx(
int irq,
void *data);
static void stmmac_reset_rx_queue(
struct stmmac_priv *priv, u32 queue);
static void stmmac_reset_tx_queue(
struct stmmac_priv *priv, u32 queue);
static void stmmac_reset_queues_param(
struct stmmac_priv *priv);
static void stmmac_tx_timer_arm(
struct stmmac_priv *priv, u32 queue);
static void stmmac_flush_tx_descriptors(
struct stmmac_priv *priv,
int queue);
static void stmmac_set_dma_operation_mode(
struct stmmac_priv *priv, u32 txmode,
u32 rxmode, u32 chan);
#ifdef CONFIG_DEBUG_FS
static const struct net_device_ops stmmac_netdev_ops;
static void stmmac_init_fs(
struct net_device *dev);
static void stmmac_exit_fs(
struct net_device *dev);
#endif
#define STMMAC_COAL_TIMER(x) (ns_to_ktime((x) * NSEC_PER_USEC))
int stmmac_bus_clks_config(
struct stmmac_priv *priv,
bool enabled)
{
int ret = 0;
if (enabled) {
ret = clk_prepare_enable(priv->plat->stmmac_clk);
if (ret)
return ret;
ret = clk_prepare_enable(priv->plat->pclk);
if (ret) {
clk_disable_unprepare(priv->plat->stmmac_clk);
return ret;
}
if (priv->plat->clks_config) {
ret = priv->plat->clks_config(priv->plat->bsp_priv, enabled);
if (ret) {
clk_disable_unprepare(priv->plat->stmmac_clk);
clk_disable_unprepare(priv->plat->pclk);
return ret;
}
}
}
else {
clk_disable_unprepare(priv->plat->stmmac_clk);
clk_disable_unprepare(priv->plat->pclk);
if (priv->plat->clks_config)
priv->plat->clks_config(priv->plat->bsp_priv, enabled);
}
return ret;
}
EXPORT_SYMBOL_GPL(stmmac_bus_clks_config);
/**
* stmmac_set_clk_tx_rate() - set the clock rate for the MAC transmit clock
* @bsp_priv: BSP private data structure (unused)
* @clk_tx_i: the transmit clock
* @interface: the selected interface mode
* @speed: the speed that the MAC will be operating at
*
* Set the transmit clock rate for the MAC, normally 2.5MHz for 10Mbps,
* 25MHz for 100Mbps and 125MHz for 1Gbps. This is suitable for at least
* MII, GMII, RGMII and RMII interface modes. Platforms can hook this into
* the plat_data->set_clk_tx_rate method directly, call it via their own
* implementation, or implement their own method should they have more
* complex requirements. It is intended to only be used in this method.
*
* plat_data->clk_tx_i must be filled in.
*/
int stmmac_set_clk_tx_rate(
void *bsp_priv,
struct clk *clk_tx_i,
phy_interface_t interface,
int speed)
{
long rate = rgmii_clock(speed);
/* Silently ignore unsupported speeds as rgmii_clock() only
* supports 10, 100 and 1000Mbps. We do not want to spit
* errors for 2500 and higher speeds here.
*/
if (rate < 0)
return 0;
return clk_set_rate(clk_tx_i, rate);
}
EXPORT_SYMBOL_GPL(stmmac_set_clk_tx_rate);
/**
* stmmac_verify_args - verify the driver parameters.
* Description: it checks the driver parameters and set a default in case of
* errors.
*/
static void stmmac_verify_args(
void)
{
if (unlikely(watchdog < 0))
watchdog = TX_TIMEO;
if (unlikely((pause < 0) || (pause > 0xffff)))
pause = PAUSE_TIME;
if (flow_ctrl != 0xdead)
pr_warn(
"stmmac: module parameter 'flow_ctrl' is obsolete - please remove from your module configuration\n");
}
static void __stmmac_disable_all_queues(
struct stmmac_priv *priv)
{
u32 rx_queues_cnt = priv->plat->rx_queues_to_use;
u32 tx_queues_cnt = priv->plat->tx_queues_to_use;
u32 maxq = max(rx_queues_cnt, tx_queues_cnt);
u32 queue;
for (queue = 0; queue < maxq; queue++) {
struct stmmac_channel *ch = &priv->channel[queue];
if (stmmac_xdp_is_enabled(priv) &&
test_bit(queue, priv->af_xdp_zc_qps)) {
napi_disable(&ch->rxtx_napi);
continue;
}
if (queue < rx_queues_cnt)
napi_disable(&ch->rx_napi);
if (queue < tx_queues_cnt)
napi_disable(&ch->tx_napi);
}
}
/**
* stmmac_disable_all_queues - Disable all queues
* @priv: driver private structure
*/
static void stmmac_disable_all_queues(
struct stmmac_priv *priv)
{
u32 rx_queues_cnt = priv->plat->rx_queues_to_use;
struct stmmac_rx_queue *rx_q;
u32 queue;
/* synchronize_rcu() needed for pending XDP buffers to drain */
for (queue = 0; queue < rx_queues_cnt; queue++) {
rx_q = &priv->dma_conf.rx_queue[queue];
if (rx_q->xsk_pool) {
synchronize_rcu();
break;
}
}
__stmmac_disable_all_queues(priv);
}
/**
* stmmac_enable_all_queues - Enable all queues
* @priv: driver private structure
*/
static void stmmac_enable_all_queues(
struct stmmac_priv *priv)
{
u32 rx_queues_cnt = priv->plat->rx_queues_to_use;
u32 tx_queues_cnt = priv->plat->tx_queues_to_use;
u32 maxq = max(rx_queues_cnt, tx_queues_cnt);
u32 queue;
for (queue = 0; queue < maxq; queue++) {
struct stmmac_channel *ch = &priv->channel[queue];
if (stmmac_xdp_is_enabled(priv) &&
test_bit(queue, priv->af_xdp_zc_qps)) {
napi_enable(&ch->rxtx_napi);
continue;
}
if (queue < rx_queues_cnt)
napi_enable(&ch->rx_napi);
if (queue < tx_queues_cnt)
napi_enable(&ch->tx_napi);
}
}
static void stmmac_service_event_schedule(
struct stmmac_priv *priv)
{
if (!test_bit(STMMAC_DOWN, &priv->state) &&
!test_and_set_bit(STMMAC_SERVICE_SCHED, &priv->state))
queue_work(priv->wq, &priv->service_task);
}
static void stmmac_global_err(
struct stmmac_priv *priv)
{
netif_carrier_off(priv->dev);
set_bit(STMMAC_RESET_REQUESTED, &priv->state);
stmmac_service_event_schedule(priv);
}
/**
* stmmac_clk_csr_set - dynamically set the MDC clock
* @priv: driver private structure
* Description: this is to dynamically set the MDC clock according to the csr
* clock input.
* Note:
* If a specific clk_csr value is passed from the platform
* this means that the CSR Clock Range selection cannot be
* changed at run-time and it is fixed (as reported in the driver
* documentation). Viceversa the driver will try to set the MDC
* clock dynamically according to the actual clock input.
*/
static void stmmac_clk_csr_set(
struct stmmac_priv *priv)
{
unsigned long clk_rate;
clk_rate = clk_get_rate(priv->plat->stmmac_clk);
/* Platform provided default clk_csr would be assumed valid
* for all other cases except for the below mentioned ones.
* For values higher than the IEEE 802.3 specified frequency
* we can not estimate the proper divider as it is not known
* the frequency of clk_csr_i. So we do not change the default
* divider.
*/
if (!(priv->clk_csr & MAC_CSR_H_FRQ_MASK)) {
if (clk_rate < CSR_F_35M)
priv->clk_csr = STMMAC_CSR_20_35M;
else if ((clk_rate >= CSR_F_35M) && (clk_rate < CSR_F_60M))
priv->clk_csr = STMMAC_CSR_35_60M;
else if ((clk_rate >= CSR_F_60M) && (clk_rate < CSR_F_100M))
priv->clk_csr = STMMAC_CSR_60_100M;
else if ((clk_rate >= CSR_F_100M) && (clk_rate < CSR_F_150M))
priv->clk_csr = STMMAC_CSR_100_150M;
else if ((clk_rate >= CSR_F_150M) && (clk_rate < CSR_F_250M))
priv->clk_csr = STMMAC_CSR_150_250M;
else if ((clk_rate >= CSR_F_250M) && (clk_rate <= CSR_F_300M))
priv->clk_csr = STMMAC_CSR_250_300M;
else if ((clk_rate >= CSR_F_300M) && (clk_rate < CSR_F_500M))
priv->clk_csr = STMMAC_CSR_300_500M;
else if ((clk_rate >= CSR_F_500M) && (clk_rate < CSR_F_800M))
priv->clk_csr = STMMAC_CSR_500_800M;
}
if (priv->plat->flags & STMMAC_FLAG_HAS_SUN8I) {
if (clk_rate > 160000000)
priv->clk_csr = 0x03;
else if (clk_rate > 80000000)
priv->clk_csr = 0x02;
else if (clk_rate > 40000000)
priv->clk_csr = 0x01;
else
priv->clk_csr = 0;
}
if (priv->plat->has_xgmac) {
if (clk_rate > 400000000)
priv->clk_csr = 0x5;
else if (clk_rate > 350000000)
priv->clk_csr = 0x4;
else if (clk_rate > 300000000)
priv->clk_csr = 0x3;
else if (clk_rate > 250000000)
priv->clk_csr = 0x2;
else if (clk_rate > 150000000)
priv->clk_csr = 0x1;
else
priv->clk_csr = 0x0;
}
}
static void print_pkt(
unsigned char *buf,
int len)
{
pr_debug(
"len = %d byte, buf addr: 0x%p\n", len, buf);
print_hex_dump_bytes(
"", DUMP_PREFIX_OFFSET, buf, len);
}
static inline u32 stmmac_tx_avail(
struct stmmac_priv *priv, u32 queue)
{
struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[queue];
u32 avail;
if (tx_q->dirty_tx > tx_q->cur_tx)
avail = tx_q->dirty_tx - tx_q->cur_tx - 1;
else
avail = priv->dma_conf.dma_tx_size - tx_q->cur_tx + tx_q->dirty_tx - 1;
return avail;
}
/**
* stmmac_rx_dirty - Get RX queue dirty
* @priv: driver private structure
* @queue: RX queue index
*/
static inline u32 stmmac_rx_dirty(
struct stmmac_priv *priv, u32 queue)
{
struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[queue];
u32 dirty;
if (rx_q->dirty_rx <= rx_q->cur_rx)
dirty = rx_q->cur_rx - rx_q->dirty_rx;
else
dirty = priv->dma_conf.dma_rx_size - rx_q->dirty_rx + rx_q->cur_rx;
return dirty;
}
static bool stmmac_eee_tx_busy(
struct stmmac_priv *priv)
{
u32 tx_cnt = priv->plat->tx_queues_to_use;
u32 queue;
/* check if all TX queues have the work finished */
for (queue = 0; queue < tx_cnt; queue++) {
struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[queue];
if (tx_q->dirty_tx != tx_q->cur_tx)
return true;
/* still unfinished work */
}
return false;
}
static void stmmac_restart_sw_lpi_timer(
struct stmmac_priv *priv)
{
mod_timer(&priv->eee_ctrl_timer, STMMAC_LPI_T(priv->tx_lpi_timer));
}
/**
* stmmac_try_to_start_sw_lpi - check and enter in LPI mode
* @priv: driver private structure
* Description: this function is to verify and enter in LPI mode in case of
* EEE.
*/
static void stmmac_try_to_start_sw_lpi(
struct stmmac_priv *priv)
{
if (stmmac_eee_tx_busy(priv)) {
stmmac_restart_sw_lpi_timer(priv);
return;
}
/* Check and enter in LPI mode */
if (!priv->tx_path_in_lpi_mode)
stmmac_set_lpi_mode(priv, priv->hw, STMMAC_LPI_FORCED,
priv->tx_lpi_clk_stop, 0);
}
/**
* stmmac_stop_sw_lpi - stop transmitting LPI
* @priv: driver private structure
* Description: When using software-controlled LPI, stop transmitting LPI state.
*/
static void stmmac_stop_sw_lpi(
struct stmmac_priv *priv)
{
timer_delete_sync(&priv->eee_ctrl_timer);
stmmac_set_lpi_mode(priv, priv->hw, STMMAC_LPI_DISABLE,
false, 0);
priv->tx_path_in_lpi_mode =
false;
}
/**
* stmmac_eee_ctrl_timer - EEE TX SW timer.
* @t: timer_list struct containing private info
* Description:
* if there is no data transfer and if we are not in LPI state,
* then MAC Transmitter can be moved to LPI state.
*/
static void stmmac_eee_ctrl_timer(
struct timer_list *t)
{
struct stmmac_priv *priv = timer_container_of(priv, t, eee_ctrl_timer);
stmmac_try_to_start_sw_lpi(priv);
}
/* stmmac_get_tx_hwtstamp - get HW TX timestamps
* @priv: driver private structure
* @p : descriptor pointer
* @skb : the socket buffer
* Description :
* This function will read timestamp from the descriptor & pass it to stack.
* and also perform some sanity checks.
*/
static void stmmac_get_tx_hwtstamp(
struct stmmac_priv *priv,
struct dma_desc *p,
struct sk_buff *skb)
{
struct skb_shared_hwtstamps shhwtstamp;
bool found =
false;
u64 ns = 0;
if (!priv->hwts_tx_en)
return;
/* exit if skb doesn't support hw tstamp */
if (likely(!skb || !(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS)))
return;
/* check tx tstamp status */
if (stmmac_get_tx_timestamp_status(priv, p)) {
stmmac_get_timestamp(priv, p, priv->adv_ts, &ns);
found =
true;
}
else if (!stmmac_get_mac_tx_timestamp(priv, priv->hw, &ns)) {
found =
true;
}
if (found) {
ns -= priv->plat->cdc_error_adj;
memset(&shhwtstamp, 0,
sizeof(
struct skb_shared_hwtstamps));
shhwtstamp.hwtstamp = ns_to_ktime(ns);
netdev_dbg(priv->dev,
"get valid TX hw timestamp %llu\n", ns);
/* pass tstamp to stack */
skb_tstamp_tx(skb, &shhwtstamp);
}
}
/* stmmac_get_rx_hwtstamp - get HW RX timestamps
* @priv: driver private structure
* @p : descriptor pointer
* @np : next descriptor pointer
* @skb : the socket buffer
* Description :
* This function will read received packet's timestamp from the descriptor
* and pass it to stack. It also perform some sanity checks.
*/
static void stmmac_get_rx_hwtstamp(
struct stmmac_priv *priv,
struct dma_desc *p,
struct dma_desc *np,
struct sk_buff *skb)
{
struct skb_shared_hwtstamps *shhwtstamp = NULL;
struct dma_desc *desc = p;
u64 ns = 0;
if (!priv->hwts_rx_en)
return;
/* For GMAC4, the valid timestamp is from CTX next desc. */
if (priv->plat->has_gmac4 || priv->plat->has_xgmac)
desc = np;
/* Check if timestamp is available */
if (stmmac_get_rx_timestamp_status(priv, p, np, priv->adv_ts)) {
stmmac_get_timestamp(priv, desc, priv->adv_ts, &ns);
ns -= priv->plat->cdc_error_adj;
netdev_dbg(priv->dev,
"get valid RX hw timestamp %llu\n", ns);
shhwtstamp = skb_hwtstamps(skb);
memset(shhwtstamp, 0,
sizeof(
struct skb_shared_hwtstamps));
shhwtstamp->hwtstamp = ns_to_ktime(ns);
}
else {
netdev_dbg(priv->dev,
"cannot get RX hw timestamp\n");
}
}
/**
* stmmac_hwtstamp_set - control hardware timestamping.
* @dev: device pointer.
* @config: the timestamping configuration.
* @extack: netlink extended ack structure for error reporting.
* Description:
* This function configures the MAC to enable/disable both outgoing(TX)
* and incoming(RX) packets time stamping based on user input.
* Return Value:
* 0 on success and an appropriate -ve integer on failure.
*/
static int stmmac_hwtstamp_set(
struct net_device *dev,
struct kernel_hwtstamp_config *config,
struct netlink_ext_ack *extack)
{
struct stmmac_priv *priv = netdev_priv(dev);
u32 ptp_v2 = 0;
u32 tstamp_all = 0;
u32 ptp_over_ipv4_udp = 0;
u32 ptp_over_ipv6_udp = 0;
u32 ptp_over_ethernet = 0;
u32 snap_type_sel = 0;
u32 ts_master_en = 0;
u32 ts_event_en = 0;
if (!(priv->dma_cap.time_stamp || priv->adv_ts)) {
NL_SET_ERR_MSG_MOD(extack,
"No support for HW time stamping");
priv->hwts_tx_en = 0;
priv->hwts_rx_en = 0;
return -EOPNOTSUPP;
}
if (!netif_running(dev)) {
NL_SET_ERR_MSG_MOD(extack,
"Cannot change timestamping configuration while down");
return -ENODEV;
}
netdev_dbg(priv->dev,
"%s config flags:0x%x, tx_type:0x%x, rx_filter:0x%x\n",
__func__, config->flags, config->tx_type, config->rx_filter);
if (config->tx_type != HWTSTAMP_TX_OFF &&
config->tx_type != HWTSTAMP_TX_ON)
return -ERANGE;
if (priv->adv_ts) {
switch (config->rx_filter) {
case HWTSTAMP_FILTER_NONE:
/* time stamp no incoming packet at all */
config->rx_filter = HWTSTAMP_FILTER_NONE;
break;
case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
/* PTP v1, UDP, any kind of event packet */
config->rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_EVENT;
/* 'xmac' hardware can support Sync, Pdelay_Req and
* Pdelay_resp by setting bit14 and bits17/16 to 01
* This leaves Delay_Req timestamps out.
* Enable all events *and* general purpose message
* timestamping
*/
snap_type_sel = PTP_TCR_SNAPTYPSEL_1;
ptp_over_ipv4_udp = PTP_TCR_TSIPV4ENA;
ptp_over_ipv6_udp = PTP_TCR_TSIPV6ENA;
break;
case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
/* PTP v1, UDP, Sync packet */
config->rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_SYNC;
/* take time stamp for SYNC messages only */
ts_event_en = PTP_TCR_TSEVNTENA;
ptp_over_ipv4_udp = PTP_TCR_TSIPV4ENA;
ptp_over_ipv6_udp = PTP_TCR_TSIPV6ENA;
break;
case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
/* PTP v1, UDP, Delay_req packet */
config->rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ;
/* take time stamp for Delay_Req messages only */
ts_master_en = PTP_TCR_TSMSTRENA;
ts_event_en = PTP_TCR_TSEVNTENA;
ptp_over_ipv4_udp = PTP_TCR_TSIPV4ENA;
ptp_over_ipv6_udp = PTP_TCR_TSIPV6ENA;
break;
case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
/* PTP v2, UDP, any kind of event packet */
config->rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_EVENT;
ptp_v2 = PTP_TCR_TSVER2ENA;
/* take time stamp for all event messages */
snap_type_sel = PTP_TCR_SNAPTYPSEL_1;
ptp_over_ipv4_udp = PTP_TCR_TSIPV4ENA;
ptp_over_ipv6_udp = PTP_TCR_TSIPV6ENA;
break;
case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
/* PTP v2, UDP, Sync packet */
config->rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_SYNC;
ptp_v2 = PTP_TCR_TSVER2ENA;
/* take time stamp for SYNC messages only */
ts_event_en = PTP_TCR_TSEVNTENA;
ptp_over_ipv4_udp = PTP_TCR_TSIPV4ENA;
ptp_over_ipv6_udp = PTP_TCR_TSIPV6ENA;
break;
case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
/* PTP v2, UDP, Delay_req packet */
config->rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ;
ptp_v2 = PTP_TCR_TSVER2ENA;
/* take time stamp for Delay_Req messages only */
ts_master_en = PTP_TCR_TSMSTRENA;
ts_event_en = PTP_TCR_TSEVNTENA;
ptp_over_ipv4_udp = PTP_TCR_TSIPV4ENA;
ptp_over_ipv6_udp = PTP_TCR_TSIPV6ENA;
break;
case HWTSTAMP_FILTER_PTP_V2_EVENT:
/* PTP v2/802.AS1 any layer, any kind of event packet */
config->rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
ptp_v2 = PTP_TCR_TSVER2ENA;
snap_type_sel = PTP_TCR_SNAPTYPSEL_1;
if (priv->synopsys_id < DWMAC_CORE_4_10)
ts_event_en = PTP_TCR_TSEVNTENA;
ptp_over_ipv4_udp = PTP_TCR_TSIPV4ENA;
ptp_over_ipv6_udp = PTP_TCR_TSIPV6ENA;
ptp_over_ethernet = PTP_TCR_TSIPENA;
break;
case HWTSTAMP_FILTER_PTP_V2_SYNC:
/* PTP v2/802.AS1, any layer, Sync packet */
config->rx_filter = HWTSTAMP_FILTER_PTP_V2_SYNC;
ptp_v2 = PTP_TCR_TSVER2ENA;
/* take time stamp for SYNC messages only */
ts_event_en = PTP_TCR_TSEVNTENA;
ptp_over_ipv4_udp = PTP_TCR_TSIPV4ENA;
ptp_over_ipv6_udp = PTP_TCR_TSIPV6ENA;
ptp_over_ethernet = PTP_TCR_TSIPENA;
break;
case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
/* PTP v2/802.AS1, any layer, Delay_req packet */
config->rx_filter = HWTSTAMP_FILTER_PTP_V2_DELAY_REQ;
ptp_v2 = PTP_TCR_TSVER2ENA;
/* take time stamp for Delay_Req messages only */
ts_master_en = PTP_TCR_TSMSTRENA;
ts_event_en = PTP_TCR_TSEVNTENA;
ptp_over_ipv4_udp = PTP_TCR_TSIPV4ENA;
ptp_over_ipv6_udp = PTP_TCR_TSIPV6ENA;
ptp_over_ethernet = PTP_TCR_TSIPENA;
break;
case HWTSTAMP_FILTER_NTP_ALL:
case HWTSTAMP_FILTER_ALL:
/* time stamp any incoming packet */
config->rx_filter = HWTSTAMP_FILTER_ALL;
tstamp_all = PTP_TCR_TSENALL;
break;
default:
return -ERANGE;
}
}
else {
switch (config->rx_filter) {
case HWTSTAMP_FILTER_NONE:
config->rx_filter = HWTSTAMP_FILTER_NONE;
break;
default:
/* PTP v1, UDP, any kind of event packet */
config->rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_EVENT;
break;
}
}
priv->hwts_rx_en = config->rx_filter != HWTSTAMP_FILTER_NONE;
priv->hwts_tx_en = config->tx_type == HWTSTAMP_TX_ON;
priv->systime_flags = STMMAC_HWTS_ACTIVE;
if (priv->hwts_tx_en || priv->hwts_rx_en) {
priv->systime_flags |= tstamp_all | ptp_v2 |
ptp_over_ethernet | ptp_over_ipv6_udp |
ptp_over_ipv4_udp | ts_event_en |
ts_master_en | snap_type_sel;
}
stmmac_config_hw_tstamping(priv, priv->ptpaddr, priv->systime_flags);
priv->tstamp_config = *config;
return 0;
}
/**
* stmmac_hwtstamp_get - read hardware timestamping.
* @dev: device pointer.
* @config: the timestamping configuration.
* Description:
* This function obtain the current hardware timestamping settings
* as requested.
*/
static int stmmac_hwtstamp_get(
struct net_device *dev,
struct kernel_hwtstamp_config *config)
{
struct stmmac_priv *priv = netdev_priv(dev);
if (!(priv->dma_cap.time_stamp || priv->dma_cap.atime_stamp))
return -EOPNOTSUPP;
*config = priv->tstamp_config;
return 0;
}
/**
* stmmac_init_tstamp_counter - init hardware timestamping counter
* @priv: driver private structure
* @systime_flags: timestamping flags
* Description:
* Initialize hardware counter for packet timestamping.
* This is valid as long as the interface is open and not suspended.
* Will be rerun after resuming from suspend, case in which the timestamping
* flags updated by stmmac_hwtstamp_set() also need to be restored.
*/
int stmmac_init_tstamp_counter(
struct stmmac_priv *priv, u32 systime_flags)
{
bool xmac = priv->plat->has_gmac4 || priv->plat->has_xgmac;
struct timespec64 now;
u32 sec_inc = 0;
u64 temp = 0;
if (!(priv->dma_cap.time_stamp || priv->dma_cap.atime_stamp))
return -EOPNOTSUPP;
if (!priv->plat->clk_ptp_rate) {
netdev_err(priv->dev,
"Invalid PTP clock rate");
return -EINVAL;
}
stmmac_config_hw_tstamping(priv, priv->ptpaddr, systime_flags);
priv->systime_flags = systime_flags;
/* program Sub Second Increment reg */
stmmac_config_sub_second_increment(priv, priv->ptpaddr,
priv->plat->clk_ptp_rate,
xmac, &sec_inc);
temp = div_u64(1000000000ULL, sec_inc);
/* Store sub second increment for later use */
priv->sub_second_inc = sec_inc;
/* calculate default added value:
* formula is :
* addend = (2^32)/freq_div_ratio;
* where, freq_div_ratio = 1e9ns/sec_inc
*/
temp = (u64)(temp << 32);
priv->default_addend = div_u64(temp, priv->plat->clk_ptp_rate);
stmmac_config_addend(priv, priv->ptpaddr, priv->default_addend);
/* initialize system time */
ktime_get_real_ts64(&now);
/* lower 32 bits of tv_sec are safe until y2106 */
stmmac_init_systime(priv, priv->ptpaddr, (u32)now.tv_sec, now.tv_nsec);
return 0;
}
EXPORT_SYMBOL_GPL(stmmac_init_tstamp_counter);
/**
* stmmac_init_ptp - init PTP
* @priv: driver private structure
* Description: this is to verify if the HW supports the PTPv1 or PTPv2.
* This is done by looking at the HW cap. register.
* This function also registers the ptp driver.
*/
static int stmmac_init_ptp(
struct stmmac_priv *priv)
{
bool xmac = priv->plat->has_gmac4 || priv->plat->has_xgmac;
int ret;
if (priv->plat->ptp_clk_freq_config)
priv->plat->ptp_clk_freq_config(priv);
ret = stmmac_init_tstamp_counter(priv, STMMAC_HWTS_ACTIVE);
if (ret)
return ret;
priv->adv_ts = 0;
/* Check if adv_ts can be enabled for dwmac 4.x / xgmac core */
if (xmac && priv->dma_cap.atime_stamp)
priv->adv_ts = 1;
/* Dwmac 3.x core with extend_desc can support adv_ts */
else if (priv->extend_desc && priv->dma_cap.atime_stamp)
priv->adv_ts = 1;
if (priv->dma_cap.time_stamp)
netdev_info(priv->dev,
"IEEE 1588-2002 Timestamp supported\n");
if (priv->adv_ts)
netdev_info(priv->dev,
"IEEE 1588-2008 Advanced Timestamp supported\n");
priv->hwts_tx_en = 0;
priv->hwts_rx_en = 0;
if (priv->plat->flags & STMMAC_FLAG_HWTSTAMP_CORRECT_LATENCY)
stmmac_hwtstamp_correct_latency(priv, priv);
return 0;
}
static void stmmac_release_ptp(
struct stmmac_priv *priv)
{
clk_disable_unprepare(priv->plat->clk_ptp_ref);
stmmac_ptp_unregister(priv);
}
/**
* stmmac_mac_flow_ctrl - Configure flow control in all queues
* @priv: driver private structure
* @duplex: duplex passed to the next function
* @flow_ctrl: desired flow control modes
* Description: It is used for configuring the flow control in all queues
*/
static void stmmac_mac_flow_ctrl(
struct stmmac_priv *priv, u32 duplex,
unsigned int flow_ctrl)
{
u32 tx_cnt = priv->plat->tx_queues_to_use;
stmmac_flow_ctrl(priv, priv->hw, duplex, flow_ctrl, priv->pause_time,
tx_cnt);
}
static unsigned long stmmac_mac_get_caps(
struct phylink_config *config,
phy_interface_t interface)
{
struct stmmac_priv *priv = netdev_priv(to_net_dev(config->dev));
/* Refresh the MAC-specific capabilities */
stmmac_mac_update_caps(priv);
config->mac_capabilities = priv->hw->link.caps;
if (priv->plat->max_speed)
phylink_limit_mac_speed(config, priv->plat->max_speed);
return config->mac_capabilities;
}
static struct phylink_pcs *stmmac_mac_select_pcs(
struct phylink_config *config,
phy_interface_t interface)
{
struct stmmac_priv *priv = netdev_priv(to_net_dev(config->dev));
struct phylink_pcs *pcs;
if (priv->plat->select_pcs) {
pcs = priv->plat->select_pcs(priv, interface);
if (!IS_ERR(pcs))
return pcs;
}
return NULL;
}
static void stmmac_mac_config(
struct phylink_config *config,
unsigned int mode,
const struct phylink_link_state *state)
{
/* Nothing to do, xpcs_config() handles everything */
}
static void stmmac_mac_link_down(
struct phylink_config *config,
unsigned int mode, phy_interface_t interface)
{
struct stmmac_priv *priv = netdev_priv(to_net_dev(config->dev));
stmmac_mac_set(priv, priv->ioaddr,
false);
if (priv->dma_cap.eee)
stmmac_set_eee_pls(priv, priv->hw,
false);
if (stmmac_fpe_supported(priv))
ethtool_mmsv_link_state_handle(&priv->fpe_cfg.mmsv,
false);
}
static void stmmac_mac_link_up(
struct phylink_config *config,
struct phy_device *phy,
unsigned int mode, phy_interface_t interface,
int speed,
int duplex,
bool tx_pause,
bool rx_pause)
{
struct stmmac_priv *priv = netdev_priv(to_net_dev(config->dev));
unsigned int flow_ctrl;
u32 old_ctrl, ctrl;
int ret;
if ((priv->plat->flags & STMMAC_FLAG_SERDES_UP_AFTER_PHY_LINKUP) &&
priv->plat->serdes_powerup)
priv->plat->serdes_powerup(priv->dev, priv->plat->bsp_priv);
old_ctrl = readl(priv->ioaddr + MAC_CTRL_REG);
ctrl = old_ctrl & ~priv->hw->link.speed_mask;
if (interface == PHY_INTERFACE_MODE_USXGMII) {
switch (speed) {
case SPEED_10000:
ctrl |= priv->hw->link.xgmii.speed10000;
break;
case SPEED_5000:
ctrl |= priv->hw->link.xgmii.speed5000;
break;
case SPEED_2500:
ctrl |= priv->hw->link.xgmii.speed2500;
break;
default:
return;
}
}
else if (interface == PHY_INTERFACE_MODE_XLGMII) {
switch (speed) {
case SPEED_100000:
ctrl |= priv->hw->link.xlgmii.speed100000;
break;
case SPEED_50000:
ctrl |= priv->hw->link.xlgmii.speed50000;
break;
case SPEED_40000:
ctrl |= priv->hw->link.xlgmii.speed40000;
break;
case SPEED_25000:
ctrl |= priv->hw->link.xlgmii.speed25000;
break;
case SPEED_10000:
ctrl |= priv->hw->link.xgmii.speed10000;
break;
case SPEED_2500:
ctrl |= priv->hw->link.speed2500;
break;
case SPEED_1000:
ctrl |= priv->hw->link.speed1000;
break;
default:
return;
}
}
else {
switch (speed) {
case SPEED_2500:
ctrl |= priv->hw->link.speed2500;
break;
case SPEED_1000:
ctrl |= priv->hw->link.speed1000;
break;
case SPEED_100:
ctrl |= priv->hw->link.speed100;
break;
case SPEED_10:
ctrl |= priv->hw->link.speed10;
break;
default:
return;
}
}
if (priv->plat->fix_mac_speed)
priv->plat->fix_mac_speed(priv->plat->bsp_priv, speed, mode);
if (!duplex)
ctrl &= ~priv->hw->link.duplex;
else
ctrl |= priv->hw->link.duplex;
/* Flow Control operation */
if (rx_pause && tx_pause)
flow_ctrl = FLOW_AUTO;
else if (rx_pause && !tx_pause)
flow_ctrl = FLOW_RX;
else if (!rx_pause && tx_pause)
flow_ctrl = FLOW_TX;
else
flow_ctrl = FLOW_OFF;
stmmac_mac_flow_ctrl(priv, duplex, flow_ctrl);
if (ctrl != old_ctrl)
writel(ctrl, priv->ioaddr + MAC_CTRL_REG);
if (priv->plat->set_clk_tx_rate) {
ret = priv->plat->set_clk_tx_rate(priv->plat->bsp_priv,
priv->plat->clk_tx_i,
interface, speed);
if (ret < 0)
netdev_err(priv->dev,
"failed to configure %s transmit clock for %dMbps: %pe\n",
phy_modes(interface), speed, ERR_PTR(ret));
}
stmmac_mac_set(priv, priv->ioaddr,
true);
if (priv->dma_cap.eee)
stmmac_set_eee_pls(priv, priv->hw,
true);
if (stmmac_fpe_supported(priv))
ethtool_mmsv_link_state_handle(&priv->fpe_cfg.mmsv,
true);
if (priv->plat->flags & STMMAC_FLAG_HWTSTAMP_CORRECT_LATENCY)
stmmac_hwtstamp_correct_latency(priv, priv);
}
static void stmmac_mac_disable_tx_lpi(
struct phylink_config *config)
{
struct stmmac_priv *priv = netdev_priv(to_net_dev(config->dev));
priv->eee_active =
false;
mutex_lock(&priv->lock);
priv->eee_enabled =
false;
netdev_dbg(priv->dev,
"disable EEE\n");
priv->eee_sw_timer_en =
false;
timer_delete_sync(&priv->eee_ctrl_timer);
stmmac_set_lpi_mode(priv, priv->hw, STMMAC_LPI_DISABLE,
false, 0);
priv->tx_path_in_lpi_mode =
false;
stmmac_set_eee_timer(priv, priv->hw, 0, STMMAC_DEFAULT_TWT_LS);
mutex_unlock(&priv->lock);
}
static int stmmac_mac_enable_tx_lpi(
struct phylink_config *config, u32 timer,
bool tx_clk_stop)
{
struct stmmac_priv *priv = netdev_priv(to_net_dev(config->dev));
int ret;
priv->tx_lpi_timer = timer;
priv->eee_active =
true;
mutex_lock(&priv->lock);
priv->eee_enabled =
true;
/* Update the transmit clock stop according to PHY capability if
* the platform allows
*/
if (priv->plat->flags & STMMAC_FLAG_EN_TX_LPI_CLK_PHY_CAP)
priv->tx_lpi_clk_stop = tx_clk_stop;
stmmac_set_eee_timer(priv, priv->hw, STMMAC_DEFAULT_LIT_LS,
STMMAC_DEFAULT_TWT_LS);
/* Try to cnfigure the hardware timer. */
ret = stmmac_set_lpi_mode(priv, priv->hw, STMMAC_LPI_TIMER,
priv->tx_lpi_clk_stop, priv->tx_lpi_timer);
if (ret) {
/* Hardware timer mode not supported, or value out of range.
* Fall back to using software LPI mode
*/
priv->eee_sw_timer_en =
true;
stmmac_restart_sw_lpi_timer(priv);
}
mutex_unlock(&priv->lock);
netdev_dbg(priv->dev,
"Energy-Efficient Ethernet initialized\n");
return 0;
}
static int stmmac_mac_finish(
struct phylink_config *config,
unsigned int mode,
phy_interface_t interface)
{
struct net_device *ndev = to_net_dev(config->dev);
struct stmmac_priv *priv = netdev_priv(ndev);
if (priv->plat->mac_finish)
priv->plat->mac_finish(ndev, priv->plat->bsp_priv, mode, interface);
return 0;
}
static const struct phylink_mac_ops stmmac_phylink_mac_ops = {
.mac_get_caps = stmmac_mac_get_caps,
.mac_select_pcs = stmmac_mac_select_pcs,
.mac_config = stmmac_mac_config,
.mac_link_down = stmmac_mac_link_down,
.mac_link_up = stmmac_mac_link_up,
.mac_disable_tx_lpi = stmmac_mac_disable_tx_lpi,
.mac_enable_tx_lpi = stmmac_mac_enable_tx_lpi,
.mac_finish = stmmac_mac_finish,
};
/**
* stmmac_check_pcs_mode - verify if RGMII/SGMII is supported
* @priv: driver private structure
* Description: this is to verify if the HW supports the PCS.
* Physical Coding Sublayer (PCS) interface that can be used when the MAC is
* configured for the TBI, RTBI, or SGMII PHY interface.
*/
static void stmmac_check_pcs_mode(
struct stmmac_priv *priv)
{
int interface = priv->plat->mac_interface;
if (priv->dma_cap.pcs) {
if ((interface == PHY_INTERFACE_MODE_RGMII) ||
(interface == PHY_INTERFACE_MODE_RGMII_ID) ||
(interface == PHY_INTERFACE_MODE_RGMII_RXID) ||
(interface == PHY_INTERFACE_MODE_RGMII_TXID)) {
netdev_dbg(priv->dev,
"PCS RGMII support enabled\n");
priv->hw->pcs = STMMAC_PCS_RGMII;
}
else if (interface == PHY_INTERFACE_MODE_SGMII) {
netdev_dbg(priv->dev,
"PCS SGMII support enabled\n");
priv->hw->pcs = STMMAC_PCS_SGMII;
}
}
}
/**
* stmmac_init_phy - PHY initialization
* @dev: net device structure
* Description: it initializes the driver's PHY state, and attaches the PHY
* to the mac driver.
* Return value:
* 0 on success
*/
static int stmmac_init_phy(
struct net_device *dev)
{
struct stmmac_priv *priv = netdev_priv(dev);
struct fwnode_handle *phy_fwnode;
struct fwnode_handle *fwnode;
int ret;
if (!phylink_expects_phy(priv->phylink))
return 0;
fwnode = priv->plat->port_node;
if (!fwnode)
fwnode = dev_fwnode(priv->device);
if (fwnode)
phy_fwnode = fwnode_get_phy_node(fwnode);
else
phy_fwnode = NULL;
/* Some DT bindings do not set-up the PHY handle. Let's try to
* manually parse it
*/
if (!phy_fwnode || IS_ERR(phy_fwnode)) {
int addr = priv->plat->phy_addr;
struct phy_device *phydev;
if (addr < 0) {
netdev_err(priv->dev,
"no phy found\n");
return -ENODEV;
}
phydev = mdiobus_get_phy(priv->mii, addr);
if (!phydev) {
netdev_err(priv->dev,
"no phy at addr %d\n", addr);
return -ENODEV;
}
ret = phylink_connect_phy(priv->phylink, phydev);
}
else {
fwnode_handle_put(phy_fwnode);
ret = phylink_fwnode_phy_connect(priv->phylink, fwnode, 0);
}
if (ret == 0) {
struct ethtool_keee eee;
/* Configure phylib's copy of the LPI timer. Normally,
* phylink_config.lpi_timer_default would do this, but there is
* a chance that userspace could change the eee_timer setting
* via sysfs before the first open. Thus, preserve existing
* behaviour.
*/
if (!phylink_ethtool_get_eee(priv->phylink, &eee)) {
eee.tx_lpi_timer = priv->tx_lpi_timer;
phylink_ethtool_set_eee(priv->phylink, &eee);
}
}
if (!priv->plat->pmt) {
struct ethtool_wolinfo wol = { .cmd = ETHTOOL_GWOL };
phylink_ethtool_get_wol(priv->phylink, &wol);
device_set_wakeup_capable(priv->device, !!wol.supported);
device_set_wakeup_enable(priv->device, !!wol.wolopts);
}
return ret;
}
static int stmmac_phy_setup(
struct stmmac_priv *priv)
{
struct stmmac_mdio_bus_data *mdio_bus_data;
struct phylink_config *config;
struct fwnode_handle *fwnode;
struct phylink_pcs *pcs;
struct phylink *phylink;
config = &priv->phylink_config;
config->dev = &priv->dev->dev;
config->type = PHYLINK_NETDEV;
config->mac_managed_pm =
true;
/* Stmmac always requires an RX clock for hardware initialization */
config->mac_requires_rxc =
true;
if (!(priv->plat->flags & STMMAC_FLAG_RX_CLK_RUNS_IN_LPI))
config->eee_rx_clk_stop_enable =
true;
/* Set the default transmit clock stop bit based on the platform glue */
priv->tx_lpi_clk_stop = priv->plat->flags &
STMMAC_FLAG_EN_TX_LPI_CLOCKGATING;
mdio_bus_data = priv->plat->mdio_bus_data;
if (mdio_bus_data)
config->default_an_inband = mdio_bus_data->default_an_inband;
/* Get the PHY interface modes (at the PHY end of the link) that
* are supported by the platform.
*/
if (priv->plat->get_interfaces)
priv->plat->get_interfaces(priv, priv->plat->bsp_priv,
config->supported_interfaces);
/* Set the platform/firmware specified interface mode if the
* supported interfaces have not already been provided using
* phy_interface as a last resort.
*/
if (phy_interface_empty(config->supported_interfaces))
__set_bit(priv->plat->phy_interface,
config->supported_interfaces);
/* If we have an xpcs, it defines which PHY interfaces are supported. */
if (priv->hw->xpcs)
pcs = xpcs_to_phylink_pcs(priv->hw->xpcs);
else
pcs = priv->hw->phylink_pcs;
if (pcs)
phy_interface_or(config->supported_interfaces,
config->supported_interfaces,
pcs->supported_interfaces);
if (priv->dma_cap.eee) {
/* Assume all supported interfaces also support LPI */
memcpy(config->lpi_interfaces, config->supported_interfaces,
sizeof(config->lpi_interfaces));
/* All full duplex speeds above 100Mbps are supported */
config->lpi_capabilities = ~(MAC_1000FD - 1) | MAC_100FD;
config->lpi_timer_default = eee_timer * 1000;
config->eee_enabled_default =
true;
}
fwnode = priv->plat->port_node;
if (!fwnode)
fwnode = dev_fwnode(priv->device);
phylink = phylink_create(config, fwnode, priv->plat->phy_interface,
&stmmac_phylink_mac_ops);
if (IS_ERR(phylink))
return PTR_ERR(phylink);
priv->phylink = phylink;
return 0;
}
static void stmmac_display_rx_rings(
struct stmmac_priv *priv,
struct stmmac_dma_conf *dma_conf)
{
u32 rx_cnt = priv->plat->rx_queues_to_use;
unsigned int desc_size;
void *head_rx;
u32 queue;
/* Display RX rings */
for (queue = 0; queue < rx_cnt; queue++) {
struct stmmac_rx_queue *rx_q = &dma_conf->rx_queue[queue];
pr_info(
"\tRX Queue %u rings\n", queue);
if (priv->extend_desc) {
head_rx = (
void *)rx_q->dma_erx;
desc_size =
sizeof(
struct dma_extended_desc);
}
else {
head_rx = (
void *)rx_q->dma_rx;
desc_size =
sizeof(
struct dma_desc);
}
/* Display RX ring */
stmmac_display_ring(priv, head_rx, dma_conf->dma_rx_size,
true,
rx_q->dma_rx_phy, desc_size);
}
}
static void stmmac_display_tx_rings(
struct stmmac_priv *priv,
struct stmmac_dma_conf *dma_conf)
{
u32 tx_cnt = priv->plat->tx_queues_to_use;
unsigned int desc_size;
void *head_tx;
u32 queue;
/* Display TX rings */
for (queue = 0; queue < tx_cnt; queue++) {
struct stmmac_tx_queue *tx_q = &dma_conf->tx_queue[queue];
pr_info(
"\tTX Queue %d rings\n", queue);
if (priv->extend_desc) {
head_tx = (
void *)tx_q->dma_etx;
desc_size =
sizeof(
struct dma_extended_desc);
}
else if (tx_q->tbs & STMMAC_TBS_AVAIL) {
head_tx = (
void *)tx_q->dma_entx;
desc_size =
sizeof(
struct dma_edesc);
}
else {
head_tx = (
void *)tx_q->dma_tx;
desc_size =
sizeof(
struct dma_desc);
}
stmmac_display_ring(priv, head_tx, dma_conf->dma_tx_size,
false,
tx_q->dma_tx_phy, desc_size);
}
}
static void stmmac_display_rings(
struct stmmac_priv *priv,
struct stmmac_dma_conf *dma_conf)
{
/* Display RX ring */
stmmac_display_rx_rings(priv, dma_conf);
/* Display TX ring */
stmmac_display_tx_rings(priv, dma_conf);
}
static unsigned int stmmac_rx_offset(
struct stmmac_priv *priv)
{
if (stmmac_xdp_is_enabled(priv))
return XDP_PACKET_HEADROOM;
return NET_SKB_PAD;
}
static int stmmac_set_bfsize(
int mtu,
int bufsize)
{
int ret = bufsize;
if (mtu >= BUF_SIZE_8KiB)
ret = BUF_SIZE_16KiB;
else if (mtu >= BUF_SIZE_4KiB)
ret = BUF_SIZE_8KiB;
else if (mtu >= BUF_SIZE_2KiB)
ret = BUF_SIZE_4KiB;
else if (mtu > DEFAULT_BUFSIZE)
ret = BUF_SIZE_2KiB;
else
ret = DEFAULT_BUFSIZE;
return ret;
}
/**
* stmmac_clear_rx_descriptors - clear RX descriptors
* @priv: driver private structure
* @dma_conf: structure to take the dma data
* @queue: RX queue index
* Description: this function is called to clear the RX descriptors
* in case of both basic and extended descriptors are used.
*/
static void stmmac_clear_rx_descriptors(
struct stmmac_priv *priv,
struct stmmac_dma_conf *dma_conf,
u32 queue)
{
struct stmmac_rx_queue *rx_q = &dma_conf->rx_queue[queue];
int i;
/* Clear the RX descriptors */
for (i = 0; i < dma_conf->dma_rx_size; i++)
if (priv->extend_desc)
stmmac_init_rx_desc(priv, &rx_q->dma_erx[i].basic,
priv->use_riwt, priv->mode,
(i == dma_conf->dma_rx_size - 1),
dma_conf->dma_buf_sz);
else
stmmac_init_rx_desc(priv, &rx_q->dma_rx[i],
priv->use_riwt, priv->mode,
(i == dma_conf->dma_rx_size - 1),
dma_conf->dma_buf_sz);
}
/**
* stmmac_clear_tx_descriptors - clear tx descriptors
* @priv: driver private structure
* @dma_conf: structure to take the dma data
* @queue: TX queue index.
* Description: this function is called to clear the TX descriptors
* in case of both basic and extended descriptors are used.
*/
static void stmmac_clear_tx_descriptors(
struct stmmac_priv *priv,
struct stmmac_dma_conf *dma_conf,
u32 queue)
{
struct stmmac_tx_queue *tx_q = &dma_conf->tx_queue[queue];
int i;
/* Clear the TX descriptors */
for (i = 0; i < dma_conf->dma_tx_size; i++) {
int last = (i == (dma_conf->dma_tx_size - 1));
struct dma_desc *p;
if (priv->extend_desc)
p = &tx_q->dma_etx[i].basic;
else if (tx_q->tbs & STMMAC_TBS_AVAIL)
p = &tx_q->dma_entx[i].basic;
else
p = &tx_q->dma_tx[i];
stmmac_init_tx_desc(priv, p, priv->mode, last);
}
}
/**
* stmmac_clear_descriptors - clear descriptors
* @priv: driver private structure
* @dma_conf: structure to take the dma data
* Description: this function is called to clear the TX and RX descriptors
* in case of both basic and extended descriptors are used.
*/
static void stmmac_clear_descriptors(
struct stmmac_priv *priv,
struct stmmac_dma_conf *dma_conf)
{
u32 rx_queue_cnt = priv->plat->rx_queues_to_use;
u32 tx_queue_cnt = priv->plat->tx_queues_to_use;
u32 queue;
/* Clear the RX descriptors */
for (queue = 0; queue < rx_queue_cnt; queue++)
stmmac_clear_rx_descriptors(priv, dma_conf, queue);
/* Clear the TX descriptors */
for (queue = 0; queue < tx_queue_cnt; queue++)
stmmac_clear_tx_descriptors(priv, dma_conf, queue);
}
/**
* stmmac_init_rx_buffers - init the RX descriptor buffer.
* @priv: driver private structure
* @dma_conf: structure to take the dma data
* @p: descriptor pointer
* @i: descriptor index
* @flags: gfp flag
* @queue: RX queue index
* Description: this function is called to allocate a receive buffer, perform
* the DMA mapping and init the descriptor.
*/
static int stmmac_init_rx_buffers(
struct stmmac_priv *priv,
struct stmmac_dma_conf *dma_conf,
struct dma_desc *p,
int i, gfp_t flags, u32 queue)
{
struct stmmac_rx_queue *rx_q = &dma_conf->rx_queue[queue];
struct stmmac_rx_buffer *buf = &rx_q->buf_pool[i];
gfp_t gfp = (GFP_ATOMIC | __GFP_NOWARN);
if (priv->dma_cap.host_dma_width <= 32)
gfp |= GFP_DMA32;
if (!buf->page) {
buf->page = page_pool_alloc_pages(rx_q->page_pool, gfp);
if (!buf->page)
return -ENOMEM;
buf->page_offset = stmmac_rx_offset(priv);
}
if (priv->sph && !buf->sec_page) {
buf->sec_page = page_pool_alloc_pages(rx_q->page_pool, gfp);
if (!buf->sec_page)
return -ENOMEM;
buf->sec_addr = page_pool_get_dma_addr(buf->sec_page);
stmmac_set_desc_sec_addr(priv, p, buf->sec_addr,
true);
}
else {
buf->sec_page = NULL;
stmmac_set_desc_sec_addr(priv, p, buf->sec_addr,
false);
}
buf->addr = page_pool_get_dma_addr(buf->page) + buf->page_offset;
stmmac_set_desc_addr(priv, p, buf->addr);
if (dma_conf->dma_buf_sz == BUF_SIZE_16KiB)
stmmac_init_desc3(priv, p);
return 0;
}
/**
* stmmac_free_rx_buffer - free RX dma buffers
* @priv: private structure
* @rx_q: RX queue
* @i: buffer index.
*/
static void stmmac_free_rx_buffer(
struct stmmac_priv *priv,
struct stmmac_rx_queue *rx_q,
int i)
{
struct stmmac_rx_buffer *buf = &rx_q->buf_pool[i];
if (buf->page)
page_pool_put_full_page(rx_q->page_pool, buf->page,
false);
buf->page = NULL;
if (buf->sec_page)
page_pool_put_full_page(rx_q->page_pool, buf->sec_page,
false);
buf->sec_page = NULL;
}
/**
* stmmac_free_tx_buffer - free RX dma buffers
* @priv: private structure
* @dma_conf: structure to take the dma data
* @queue: RX queue index
* @i: buffer index.
*/
static void stmmac_free_tx_buffer(
struct stmmac_priv *priv,
struct stmmac_dma_conf *dma_conf,
u32 queue,
int i)
{
struct stmmac_tx_queue *tx_q = &dma_conf->tx_queue[queue];
if (tx_q->tx_skbuff_dma[i].buf &&
tx_q->tx_skbuff_dma[i].buf_type != STMMAC_TXBUF_T_XDP_TX) {
if (tx_q->tx_skbuff_dma[i].map_as_page)
dma_unmap_page(priv->device,
tx_q->tx_skbuff_dma[i].buf,
tx_q->tx_skbuff_dma[i].len,
DMA_TO_DEVICE);
else
dma_unmap_single(priv->device,
tx_q->tx_skbuff_dma[i].buf,
tx_q->tx_skbuff_dma[i].len,
DMA_TO_DEVICE);
}
if (tx_q->xdpf[i] &&
(tx_q->tx_skbuff_dma[i].buf_type == STMMAC_TXBUF_T_XDP_TX ||
tx_q->tx_skbuff_dma[i].buf_type == STMMAC_TXBUF_T_XDP_NDO)) {
xdp_return_frame(tx_q->xdpf[i]);
tx_q->xdpf[i] = NULL;
}
if (tx_q->tx_skbuff_dma[i].buf_type == STMMAC_TXBUF_T_XSK_TX)
tx_q->xsk_frames_done++;
if (tx_q->tx_skbuff[i] &&
tx_q->tx_skbuff_dma[i].buf_type == STMMAC_TXBUF_T_SKB) {
dev_kfree_skb_any(tx_q->tx_skbuff[i]);
tx_q->tx_skbuff[i] = NULL;
}
tx_q->tx_skbuff_dma[i].buf = 0;
tx_q->tx_skbuff_dma[i].map_as_page =
false;
}
/**
* dma_free_rx_skbufs - free RX dma buffers
* @priv: private structure
* @dma_conf: structure to take the dma data
* @queue: RX queue index
*/
static void dma_free_rx_skbufs(
struct stmmac_priv *priv,
struct stmmac_dma_conf *dma_conf,
u32 queue)
{
struct stmmac_rx_queue *rx_q = &dma_conf->rx_queue[queue];
int i;
for (i = 0; i < dma_conf->dma_rx_size; i++)
stmmac_free_rx_buffer(priv, rx_q, i);
}
static int stmmac_alloc_rx_buffers(
struct stmmac_priv *priv,
struct stmmac_dma_conf *dma_conf,
u32 queue, gfp_t flags)
{
struct stmmac_rx_queue *rx_q = &dma_conf->rx_queue[queue];
int i;
for (i = 0; i < dma_conf->dma_rx_size; i++) {
struct dma_desc *p;
int ret;
if (priv->extend_desc)
p = &((rx_q->dma_erx + i)->basic);
else
p = rx_q->dma_rx + i;
ret = stmmac_init_rx_buffers(priv, dma_conf, p, i, flags,
queue);
if (ret)
return ret;
rx_q->buf_alloc_num++;
}
return 0;
}
/**
* dma_free_rx_xskbufs - free RX dma buffers from XSK pool
* @priv: private structure
* @dma_conf: structure to take the dma data
* @queue: RX queue index
*/
static void dma_free_rx_xskbufs(
struct stmmac_priv *priv,
struct stmmac_dma_conf *dma_conf,
u32 queue)
{
struct stmmac_rx_queue *rx_q = &dma_conf->rx_queue[queue];
int i;
for (i = 0; i < dma_conf->dma_rx_size; i++) {
struct stmmac_rx_buffer *buf = &rx_q->buf_pool[i];
if (!buf->xdp)
continue;
xsk_buff_free(buf->xdp);
buf->xdp = NULL;
}
}
static int stmmac_alloc_rx_buffers_zc(
struct stmmac_priv *priv,
struct stmmac_dma_conf *dma_conf,
u32 queue)
{
struct stmmac_rx_queue *rx_q = &dma_conf->rx_queue[queue];
int i;
/* struct stmmac_xdp_buff is using cb field (maximum size of 24 bytes)
* in struct xdp_buff_xsk to stash driver specific information. Thus,
* use this macro to make sure no size violations.
*/
XSK_CHECK_PRIV_TYPE(
struct stmmac_xdp_buff);
for (i = 0; i < dma_conf->dma_rx_size; i++) {
struct stmmac_rx_buffer *buf;
dma_addr_t dma_addr;
struct dma_desc *p;
if (priv->extend_desc)
p = (
struct dma_desc *)(rx_q->dma_erx + i);
else
p = rx_q->dma_rx + i;
buf = &rx_q->buf_pool[i];
buf->xdp = xsk_buff_alloc(rx_q->xsk_pool);
if (!buf->xdp)
return -ENOMEM;
dma_addr = xsk_buff_xdp_get_dma(buf->xdp);
stmmac_set_desc_addr(priv, p, dma_addr);
rx_q->buf_alloc_num++;
}
return 0;
}
static struct xsk_buff_pool *stmmac_get_xsk_pool(
struct stmmac_priv *priv, u32 queue)
{
if (!stmmac_xdp_is_enabled(priv) || !test_bit(queue, priv->af_xdp_zc_qps))
return NULL;
return xsk_get_pool_from_qid(priv->dev, queue);
}
/**
* __init_dma_rx_desc_rings - init the RX descriptor ring (per queue)
* @priv: driver private structure
* @dma_conf: structure to take the dma data
* @queue: RX queue index
* @flags: gfp flag.
* Description: this function initializes the DMA RX descriptors
* and allocates the socket buffers. It supports the chained and ring
* modes.
*/
static int __init_dma_rx_desc_rings(
struct stmmac_priv *priv,
struct stmmac_dma_conf *dma_conf,
u32 queue, gfp_t flags)
{
struct stmmac_rx_queue *rx_q = &dma_conf->rx_queue[queue];
int ret;
netif_dbg(priv, probe, priv->dev,
"(%s) dma_rx_phy=0x%08x\n", __func__,
(u32)rx_q->dma_rx_phy);
stmmac_clear_rx_descriptors(priv, dma_conf, queue);
xdp_rxq_info_unreg_mem_model(&rx_q->xdp_rxq);
rx_q->xsk_pool = stmmac_get_xsk_pool(priv, queue);
if (rx_q->xsk_pool) {
WARN_ON(xdp_rxq_info_reg_mem_model(&rx_q->xdp_rxq,
MEM_TYPE_XSK_BUFF_POOL,
NULL));
netdev_info(priv->dev,
"Register MEM_TYPE_XSK_BUFF_POOL RxQ-%d\n",
rx_q->queue_index);
xsk_pool_set_rxq_info(rx_q->xsk_pool, &rx_q->xdp_rxq);
}
else {
WARN_ON(xdp_rxq_info_reg_mem_model(&rx_q->xdp_rxq,
MEM_TYPE_PAGE_POOL,
rx_q->page_pool));
netdev_info(priv->dev,
"Register MEM_TYPE_PAGE_POOL RxQ-%d\n",
rx_q->queue_index);
}
if (rx_q->xsk_pool) {
/* RX XDP ZC buffer pool may not be populated, e.g.
* xdpsock TX-only.
*/
stmmac_alloc_rx_buffers_zc(priv, dma_conf, queue);
}
else {
ret = stmmac_alloc_rx_buffers(priv, dma_conf, queue, flags);
if (ret < 0)
return -ENOMEM;
}
/* Setup the chained descriptor addresses */
if (priv->mode == STMMAC_CHAIN_MODE) {
if (priv->extend_desc)
stmmac_mode_init(priv, rx_q->dma_erx,
rx_q->dma_rx_phy,
dma_conf->dma_rx_size, 1);
else
stmmac_mode_init(priv, rx_q->dma_rx,
rx_q->dma_rx_phy,
dma_conf->dma_rx_size, 0);
}
return 0;
}
static int init_dma_rx_desc_rings(
struct net_device *dev,
struct stmmac_dma_conf *dma_conf,
gfp_t flags)
{
struct stmmac_priv *priv = netdev_priv(dev);
u32 rx_count = priv->plat->rx_queues_to_use;
int queue;
int ret;
/* RX INITIALIZATION */
netif_dbg(priv, probe, priv->dev,
"SKB addresses:\nskb\t\tskb data\tdma data\n");
for (queue = 0; queue < rx_count; queue++) {
ret = __init_dma_rx_desc_rings(priv, dma_conf, queue, flags);
if (ret)
goto err_init_rx_buffers;
}
return 0;
err_init_rx_buffers:
while (queue >= 0) {
struct stmmac_rx_queue *rx_q = &dma_conf->rx_queue[queue];
if (rx_q->xsk_pool)
dma_free_rx_xskbufs(priv, dma_conf, queue);
else
dma_free_rx_skbufs(priv, dma_conf, queue);
rx_q->buf_alloc_num = 0;
rx_q->xsk_pool = NULL;
queue--;
}
return ret;
}
/**
* __init_dma_tx_desc_rings - init the TX descriptor ring (per queue)
* @priv: driver private structure
* @dma_conf: structure to take the dma data
* @queue: TX queue index
* Description: this function initializes the DMA TX descriptors
* and allocates the socket buffers. It supports the chained and ring
* modes.
*/
static int __init_dma_tx_desc_rings(
struct stmmac_priv *priv,
struct stmmac_dma_conf *dma_conf,
u32 queue)
{
struct stmmac_tx_queue *tx_q = &dma_conf->tx_queue[queue];
int i;
netif_dbg(priv, probe, priv->dev,
"(%s) dma_tx_phy=0x%08x\n", __func__,
(u32)tx_q->dma_tx_phy);
/* Setup the chained descriptor addresses */
if (priv->mode == STMMAC_CHAIN_MODE) {
if (priv->extend_desc)
stmmac_mode_init(priv, tx_q->dma_etx,
tx_q->dma_tx_phy,
dma_conf->dma_tx_size, 1);
else if (!(tx_q->tbs & STMMAC_TBS_AVAIL))
stmmac_mode_init(priv, tx_q->dma_tx,
tx_q->dma_tx_phy,
dma_conf->dma_tx_size, 0);
}
tx_q->xsk_pool = stmmac_get_xsk_pool(priv, queue);
for (i = 0; i < dma_conf->dma_tx_size; i++) {
struct dma_desc *p;
if (priv->extend_desc)
p = &((tx_q->dma_etx + i)->basic);
else if (tx_q->tbs & STMMAC_TBS_AVAIL)
p = &((tx_q->dma_entx + i)->basic);
else
p = tx_q->dma_tx + i;
stmmac_clear_desc(priv, p);
tx_q->tx_skbuff_dma[i].buf = 0;
tx_q->tx_skbuff_dma[i].map_as_page =
false;
tx_q->tx_skbuff_dma[i].len = 0;
tx_q->tx_skbuff_dma[i].last_segment =
false;
tx_q->tx_skbuff[i] = NULL;
}
return 0;
}
static int init_dma_tx_desc_rings(
struct net_device *dev,
struct stmmac_dma_conf *dma_conf)
{
struct stmmac_priv *priv = netdev_priv(dev);
u32 tx_queue_cnt;
u32 queue;
tx_queue_cnt = priv->plat->tx_queues_to_use;
for (queue = 0; queue < tx_queue_cnt; queue++)
__init_dma_tx_desc_rings(priv, dma_conf, queue);
return 0;
}
/**
* init_dma_desc_rings - init the RX/TX descriptor rings
* @dev: net device structure
* @dma_conf: structure to take the dma data
* @flags: gfp flag.
* Description: this function initializes the DMA RX/TX descriptors
* and allocates the socket buffers. It supports the chained and ring
* modes.
*/
static int init_dma_desc_rings(
struct net_device *dev,
struct stmmac_dma_conf *dma_conf,
gfp_t flags)
{
struct stmmac_priv *priv = netdev_priv(dev);
int ret;
ret = init_dma_rx_desc_rings(dev, dma_conf, flags);
if (ret)
return ret;
ret = init_dma_tx_desc_rings(dev, dma_conf);
stmmac_clear_descriptors(priv, dma_conf);
if (netif_msg_hw(priv))
stmmac_display_rings(priv, dma_conf);
return ret;
}
/**
* dma_free_tx_skbufs - free TX dma buffers
* @priv: private structure
* @dma_conf: structure to take the dma data
* @queue: TX queue index
*/
static void dma_free_tx_skbufs(
struct stmmac_priv *priv,
struct stmmac_dma_conf *dma_conf,
u32 queue)
{
struct stmmac_tx_queue *tx_q = &dma_conf->tx_queue[queue];
int i;
tx_q->xsk_frames_done = 0;
for (i = 0; i < dma_conf->dma_tx_size; i++)
stmmac_free_tx_buffer(priv, dma_conf, queue, i);
if (tx_q->xsk_pool && tx_q->xsk_frames_done) {
xsk_tx_completed(tx_q->xsk_pool, tx_q->xsk_frames_done);
tx_q->xsk_frames_done = 0;
tx_q->xsk_pool = NULL;
}
}
/**
* stmmac_free_tx_skbufs - free TX skb buffers
* @priv: private structure
*/
static void stmmac_free_tx_skbufs(
struct stmmac_priv *priv)
{
u32 tx_queue_cnt = priv->plat->tx_queues_to_use;
u32 queue;
for (queue = 0; queue < tx_queue_cnt; queue++)
dma_free_tx_skbufs(priv, &priv->dma_conf, queue);
}
/**
* __free_dma_rx_desc_resources - free RX dma desc resources (per queue)
* @priv: private structure
* @dma_conf: structure to take the dma data
* @queue: RX queue index
*/
static void __free_dma_rx_desc_resources(
struct stmmac_priv *priv,
struct stmmac_dma_conf *dma_conf,
u32 queue)
{
struct stmmac_rx_queue *rx_q = &dma_conf->rx_queue[queue];
/* Release the DMA RX socket buffers */
if (rx_q->xsk_pool)
dma_free_rx_xskbufs(priv, dma_conf, queue);
else
dma_free_rx_skbufs(priv, dma_conf, queue);
rx_q->buf_alloc_num = 0;
rx_q->xsk_pool = NULL;
/* Free DMA regions of consistent memory previously allocated */
if (!priv->extend_desc)
dma_free_coherent(priv->device, dma_conf->dma_rx_size *
sizeof(
struct dma_desc),
rx_q->dma_rx, rx_q->dma_rx_phy);
else
dma_free_coherent(priv->device, dma_conf->dma_rx_size *
sizeof(
struct dma_extended_desc),
rx_q->dma_erx, rx_q->dma_rx_phy);
if (xdp_rxq_info_is_reg(&rx_q->xdp_rxq))
xdp_rxq_info_unreg(&rx_q->xdp_rxq);
kfree(rx_q->buf_pool);
if (rx_q->page_pool)
page_pool_destroy(rx_q->page_pool);
}
static void free_dma_rx_desc_resources(
struct stmmac_priv *priv,
struct stmmac_dma_conf *dma_conf)
{
u32 rx_count = priv->plat->rx_queues_to_use;
u32 queue;
/* Free RX queue resources */
for (queue = 0; queue < rx_count; queue++)
__free_dma_rx_desc_resources(priv, dma_conf, queue);
}
/**
* __free_dma_tx_desc_resources - free TX dma desc resources (per queue)
* @priv: private structure
* @dma_conf: structure to take the dma data
* @queue: TX queue index
*/
static void __free_dma_tx_desc_resources(
struct stmmac_priv *priv,
struct stmmac_dma_conf *dma_conf,
u32 queue)
{
struct stmmac_tx_queue *tx_q = &dma_conf->tx_queue[queue];
size_t size;
void *addr;
/* Release the DMA TX socket buffers */
dma_free_tx_skbufs(priv, dma_conf, queue);
if (priv->extend_desc) {
size =
sizeof(
struct dma_extended_desc);
addr = tx_q->dma_etx;
}
else if (tx_q->tbs & STMMAC_TBS_AVAIL) {
size =
sizeof(
struct dma_edesc);
addr = tx_q->dma_entx;
}
else {
size =
sizeof(
struct dma_desc);
addr = tx_q->dma_tx;
}
size *= dma_conf->dma_tx_size;
dma_free_coherent(priv->device, size, addr, tx_q->dma_tx_phy);
kfree(tx_q->tx_skbuff_dma);
kfree(tx_q->tx_skbuff);
}
static void free_dma_tx_desc_resources(
struct stmmac_priv *priv,
struct stmmac_dma_conf *dma_conf)
{
u32 tx_count = priv->plat->tx_queues_to_use;
u32 queue;
/* Free TX queue resources */
for (queue = 0; queue < tx_count; queue++)
__free_dma_tx_desc_resources(priv, dma_conf, queue);
}
/**
* __alloc_dma_rx_desc_resources - alloc RX resources (per queue).
* @priv: private structure
* @dma_conf: structure to take the dma data
* @queue: RX queue index
* Description: according to which descriptor can be used (extend or basic)
* this function allocates the resources for TX and RX paths. In case of
* reception, for example, it pre-allocated the RX socket buffer in order to
* allow zero-copy mechanism.
*/
static int __alloc_dma_rx_desc_resources(
struct stmmac_priv *priv,
struct stmmac_dma_conf *dma_conf,
u32 queue)
{
struct stmmac_rx_queue *rx_q = &dma_conf->rx_queue[queue];
struct stmmac_channel *ch = &priv->channel[queue];
bool xdp_prog = stmmac_xdp_is_enabled(priv);
struct page_pool_params pp_params = { 0 };
unsigned int dma_buf_sz_pad, num_pages;
unsigned int napi_id;
int ret;
dma_buf_sz_pad = stmmac_rx_offset(priv) + dma_conf->dma_buf_sz +
SKB_DATA_ALIGN(
sizeof(
struct skb_shared_info));
num_pages = DIV_ROUND_UP(dma_buf_sz_pad, PAGE_SIZE);
rx_q->queue_index = queue;
rx_q->priv_data = priv;
rx_q->napi_skb_frag_size = num_pages * PAGE_SIZE;
pp_params.flags = PP_FLAG_DMA_MAP | PP_FLAG_DMA_SYNC_DEV;
pp_params.pool_size = dma_conf->dma_rx_size;
pp_params.order = order_base_2(num_pages);
pp_params.nid = dev_to_node(priv->device);
pp_params.dev = priv->device;
pp_params.dma_dir = xdp_prog ? DMA_BIDIRECTIONAL : DMA_FROM_DEVICE;
pp_params.offset = stmmac_rx_offset(priv);
pp_params.max_len = dma_conf->dma_buf_sz;
if (priv->sph) {
pp_params.offset = 0;
pp_params.max_len += stmmac_rx_offset(priv);
}
rx_q->page_pool = page_pool_create(&pp_params);
if (IS_ERR(rx_q->page_pool)) {
ret = PTR_ERR(rx_q->page_pool);
rx_q->page_pool = NULL;
return ret;
}
rx_q->buf_pool = kcalloc(dma_conf->dma_rx_size,
sizeof(*rx_q->buf_pool),
GFP_KERNEL);
if (!rx_q->buf_pool)
return -ENOMEM;
if (priv->extend_desc) {
rx_q->dma_erx = dma_alloc_coherent(priv->device,
dma_conf->dma_rx_size *
sizeof(
struct dma_extended_desc),
&rx_q->dma_rx_phy,
GFP_KERNEL);
if (!rx_q->dma_erx)
return -ENOMEM;
}
else {
rx_q->dma_rx = dma_alloc_coherent(priv->device,
dma_conf->dma_rx_size *
sizeof(
struct dma_desc),
&rx_q->dma_rx_phy,
GFP_KERNEL);
if (!rx_q->dma_rx)
return -ENOMEM;
}
if (stmmac_xdp_is_enabled(priv) &&
test_bit(queue, priv->af_xdp_zc_qps))
napi_id = ch->rxtx_napi.napi_id;
else
napi_id = ch->rx_napi.napi_id;
ret = xdp_rxq_info_reg(&rx_q->xdp_rxq, priv->dev,
rx_q->queue_index,
napi_id);
if (ret) {
netdev_err(priv->dev,
"Failed to register xdp rxq info\n");
return -EINVAL;
}
return 0;
}
static int alloc_dma_rx_desc_resources(
struct stmmac_priv *priv,
struct stmmac_dma_conf *dma_conf)
{
u32 rx_count = priv->plat->rx_queues_to_use;
u32 queue;
int ret;
/* RX queues buffers and DMA */
for (queue = 0; queue < rx_count; queue++) {
ret = __alloc_dma_rx_desc_resources(priv, dma_conf, queue);
if (ret)
goto err_dma;
}
return 0;
err_dma:
free_dma_rx_desc_resources(priv, dma_conf);
return ret;
}
/**
* __alloc_dma_tx_desc_resources - alloc TX resources (per queue).
* @priv: private structure
* @dma_conf: structure to take the dma data
* @queue: TX queue index
* Description: according to which descriptor can be used (extend or basic)
* this function allocates the resources for TX and RX paths. In case of
* reception, for example, it pre-allocated the RX socket buffer in order to
* allow zero-copy mechanism.
*/
static int __alloc_dma_tx_desc_resources(
struct stmmac_priv *priv,
struct stmmac_dma_conf *dma_conf,
u32 queue)
{
struct stmmac_tx_queue *tx_q = &dma_conf->tx_queue[queue];
size_t size;
void *addr;
tx_q->queue_index = queue;
tx_q->priv_data = priv;
tx_q->tx_skbuff_dma = kcalloc(dma_conf->dma_tx_size,
sizeof(*tx_q->tx_skbuff_dma),
GFP_KERNEL);
if (!tx_q->tx_skbuff_dma)
return -ENOMEM;
tx_q->tx_skbuff = kcalloc(dma_conf->dma_tx_size,
sizeof(
struct sk_buff *),
GFP_KERNEL);
if (!tx_q->tx_skbuff)
return -ENOMEM;
if (priv->extend_desc)
size =
sizeof(
struct dma_extended_desc);
else if (tx_q->tbs & STMMAC_TBS_AVAIL)
size =
sizeof(
struct dma_edesc);
else
size =
sizeof(
struct dma_desc);
size *= dma_conf->dma_tx_size;
addr = dma_alloc_coherent(priv->device, size,
&tx_q->dma_tx_phy, GFP_KERNEL);
if (!addr)
return -ENOMEM;
if (priv->extend_desc)
tx_q->dma_etx = addr;
else if (tx_q->tbs & STMMAC_TBS_AVAIL)
tx_q->dma_entx = addr;
else
tx_q->dma_tx = addr;
return 0;
}
static int alloc_dma_tx_desc_resources(
struct stmmac_priv *priv,
struct stmmac_dma_conf *dma_conf)
{
u32 tx_count = priv->plat->tx_queues_to_use;
u32 queue;
int ret;
/* TX queues buffers and DMA */
for (queue = 0; queue < tx_count; queue++) {
ret = __alloc_dma_tx_desc_resources(priv, dma_conf, queue);
if (ret)
goto err_dma;
}
return 0;
err_dma:
free_dma_tx_desc_resources(priv, dma_conf);
return ret;
}
/**
* alloc_dma_desc_resources - alloc TX/RX resources.
* @priv: private structure
* @dma_conf: structure to take the dma data
* Description: according to which descriptor can be used (extend or basic)
* this function allocates the resources for TX and RX paths. In case of
* reception, for example, it pre-allocated the RX socket buffer in order to
* allow zero-copy mechanism.
*/
static int alloc_dma_desc_resources(
struct stmmac_priv *priv,
struct stmmac_dma_conf *dma_conf)
{
/* RX Allocation */
int ret = alloc_dma_rx_desc_resources(priv, dma_conf);
if (ret)
return ret;
ret = alloc_dma_tx_desc_resources(priv, dma_conf);
return ret;
}
/**
* free_dma_desc_resources - free dma desc resources
* @priv: private structure
* @dma_conf: structure to take the dma data
*/
static void free_dma_desc_resources(
struct stmmac_priv *priv,
struct stmmac_dma_conf *dma_conf)
{
/* Release the DMA TX socket buffers */
free_dma_tx_desc_resources(priv, dma_conf);
/* Release the DMA RX socket buffers later
* to ensure all pending XDP_TX buffers are returned.
*/
free_dma_rx_desc_resources(priv, dma_conf);
}
/**
* stmmac_mac_enable_rx_queues - Enable MAC rx queues
* @priv: driver private structure
* Description: It is used for enabling the rx queues in the MAC
*/
static void stmmac_mac_enable_rx_queues(
struct stmmac_priv *priv)
{
u32 rx_queues_count = priv->plat->rx_queues_to_use;
int queue;
u8 mode;
for (queue = 0; queue < rx_queues_count; queue++) {
mode = priv->plat->rx_queues_cfg[queue].mode_to_use;
--> --------------------
--> maximum size reached
--> --------------------