Skip to content

Commit

Permalink
gianfar: Implement PAUSE frame generation support
Browse files Browse the repository at this point in the history
The hardware can automatically generate pause frames when the number
of free buffers drops under a certain threshold, but in order to do this,
the address of the last free buffer needs to be written to a specific
register for each RX queue.

This has to be done in 'gfar_clean_rx_ring' which is called for each
RX queue. In order not to impact performance, by adding a register write
for each incoming packet, this operation is done only when the PAUSE frame
transmission is enabled.

Whenever the link is readjusted, this capability is turned on or off.

Signed-off-by: Matei Pavaluca <matei.pavaluca@freescale.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Matei Pavaluca authored and David S. Miller committed Oct 29, 2014
1 parent 43ef8d2 commit 45b679c
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 2 deletions.
54 changes: 54 additions & 0 deletions drivers/net/ethernet/freescale/gianfar.c
Original file line number Diff line number Diff line change
Expand Up @@ -173,10 +173,12 @@ static void gfar_init_rxbdp(struct gfar_priv_rx_q *rx_queue, struct rxbd8 *bdp,
static int gfar_init_bds(struct net_device *ndev)
{
struct gfar_private *priv = netdev_priv(ndev);
struct gfar __iomem *regs = priv->gfargrp[0].regs;
struct gfar_priv_tx_q *tx_queue = NULL;
struct gfar_priv_rx_q *rx_queue = NULL;
struct txbd8 *txbdp;
struct rxbd8 *rxbdp;
u32 *rfbptr;
int i, j;

for (i = 0; i < priv->num_tx_queues; i++) {
Expand All @@ -201,6 +203,7 @@ static int gfar_init_bds(struct net_device *ndev)
txbdp->status |= TXBD_WRAP;
}

rfbptr = &regs->rfbptr0;
for (i = 0; i < priv->num_rx_queues; i++) {
rx_queue = priv->rx_queue[i];
rx_queue->cur_rx = rx_queue->rx_bd_base;
Expand All @@ -227,6 +230,8 @@ static int gfar_init_bds(struct net_device *ndev)
rxbdp++;
}

rx_queue->rfbptr = rfbptr;
rfbptr += 2;
}

return 0;
Expand Down Expand Up @@ -336,6 +341,20 @@ static void gfar_init_tx_rx_base(struct gfar_private *priv)
}
}

static void gfar_init_rqprm(struct gfar_private *priv)
{
struct gfar __iomem *regs = priv->gfargrp[0].regs;
u32 __iomem *baddr;
int i;

baddr = &regs->rqprm0;
for (i = 0; i < priv->num_rx_queues; i++) {
gfar_write(baddr, priv->rx_queue[i]->rx_ring_size |
(DEFAULT_RX_LFC_THR << FBTHR_SHIFT));
baddr++;
}
}

static void gfar_rx_buff_size_config(struct gfar_private *priv)
{
int frame_size = priv->ndev->mtu + ETH_HLEN + ETH_FCS_LEN;
Expand Down Expand Up @@ -396,6 +415,13 @@ static void gfar_mac_rx_config(struct gfar_private *priv)
if (priv->ndev->features & NETIF_F_HW_VLAN_CTAG_RX)
rctrl |= RCTRL_VLEX | RCTRL_PRSDEP_INIT;

/* Clear the LFC bit */
gfar_write(&regs->rctrl, rctrl);
/* Init flow control threshold values */
gfar_init_rqprm(priv);
gfar_write(&regs->ptv, DEFAULT_LFC_PTVVAL);
rctrl |= RCTRL_LFC;

/* Init rctrl based on our settings */
gfar_write(&regs->rctrl, rctrl);
}
Expand Down Expand Up @@ -2859,6 +2885,10 @@ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit)
/* Setup the new bdp */
gfar_new_rxbdp(rx_queue, bdp, newskb);

/* Update Last Free RxBD pointer for LFC */
if (unlikely(rx_queue->rfbptr && priv->tx_actual_en))
gfar_write(rx_queue->rfbptr, (u32)bdp);

/* Update to the next pointer */
bdp = next_bd(bdp, base, rx_queue->rx_ring_size);

Expand Down Expand Up @@ -3393,6 +3423,9 @@ static noinline void gfar_update_link_state(struct gfar_private *priv)
{
struct gfar __iomem *regs = priv->gfargrp[0].regs;
struct phy_device *phydev = priv->phydev;
struct gfar_priv_rx_q *rx_queue = NULL;
int i;
struct rxbd8 *bdp;

if (unlikely(test_bit(GFAR_RESETTING, &priv->state)))
return;
Expand All @@ -3401,6 +3434,7 @@ static noinline void gfar_update_link_state(struct gfar_private *priv)
u32 tempval1 = gfar_read(&regs->maccfg1);
u32 tempval = gfar_read(&regs->maccfg2);
u32 ecntrl = gfar_read(&regs->ecntrl);
u32 tx_flow_oldval = (tempval & MACCFG1_TX_FLOW);

if (phydev->duplex != priv->oldduplex) {
if (!(phydev->duplex))
Expand Down Expand Up @@ -3445,6 +3479,26 @@ static noinline void gfar_update_link_state(struct gfar_private *priv)
tempval1 &= ~(MACCFG1_TX_FLOW | MACCFG1_RX_FLOW);
tempval1 |= gfar_get_flowctrl_cfg(priv);

/* Turn last free buffer recording on */
if ((tempval1 & MACCFG1_TX_FLOW) && !tx_flow_oldval) {
for (i = 0; i < priv->num_rx_queues; i++) {
rx_queue = priv->rx_queue[i];
bdp = rx_queue->cur_rx;
/* skip to previous bd */
bdp = skip_bd(bdp, rx_queue->rx_ring_size - 1,
rx_queue->rx_bd_base,
rx_queue->rx_ring_size);

if (rx_queue->rfbptr)
gfar_write(rx_queue->rfbptr, (u32)bdp);
}

priv->tx_actual_en = 1;
}

if (unlikely(!(tempval1 & MACCFG1_TX_FLOW) && tx_flow_oldval))
priv->tx_actual_en = 0;

gfar_write(&regs->maccfg1, tempval1);
gfar_write(&regs->maccfg2, tempval);
gfar_write(&regs->ecntrl, ecntrl);
Expand Down
34 changes: 33 additions & 1 deletion drivers/net/ethernet/freescale/gianfar.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,10 @@ extern const char gfar_driver_version[];
#define GFAR_MAX_FIFO_STARVE 511
#define GFAR_MAX_FIFO_STARVE_OFF 511

#define FBTHR_SHIFT 24
#define DEFAULT_RX_LFC_THR 16
#define DEFAULT_LFC_PTVVAL 4

#define DEFAULT_RX_BUFFER_SIZE 1536
#define TX_RING_MOD_MASK(size) (size-1)
#define RX_RING_MOD_MASK(size) (size-1)
Expand Down Expand Up @@ -273,6 +277,7 @@ extern const char gfar_driver_version[];

#define RCTRL_TS_ENABLE 0x01000000
#define RCTRL_PAL_MASK 0x001f0000
#define RCTRL_LFC 0x00004000
#define RCTRL_VLEX 0x00002000
#define RCTRL_FILREN 0x00001000
#define RCTRL_GHTX 0x00000400
Expand Down Expand Up @@ -849,7 +854,32 @@ struct gfar {
u8 res23c[248];
u32 attr; /* 0x.bf8 - Attributes Register */
u32 attreli; /* 0x.bfc - Attributes Extract Length and Extract Index Register */
u8 res24[688];
u32 rqprm0; /* 0x.c00 - Receive queue parameters register 0 */
u32 rqprm1; /* 0x.c04 - Receive queue parameters register 1 */
u32 rqprm2; /* 0x.c08 - Receive queue parameters register 2 */
u32 rqprm3; /* 0x.c0c - Receive queue parameters register 3 */
u32 rqprm4; /* 0x.c10 - Receive queue parameters register 4 */
u32 rqprm5; /* 0x.c14 - Receive queue parameters register 5 */
u32 rqprm6; /* 0x.c18 - Receive queue parameters register 6 */
u32 rqprm7; /* 0x.c1c - Receive queue parameters register 7 */
u8 res24[36];
u32 rfbptr0; /* 0x.c44 - Last free RxBD pointer for ring 0 */
u8 res24a[4];
u32 rfbptr1; /* 0x.c4c - Last free RxBD pointer for ring 1 */
u8 res24b[4];
u32 rfbptr2; /* 0x.c54 - Last free RxBD pointer for ring 2 */
u8 res24c[4];
u32 rfbptr3; /* 0x.c5c - Last free RxBD pointer for ring 3 */
u8 res24d[4];
u32 rfbptr4; /* 0x.c64 - Last free RxBD pointer for ring 4 */
u8 res24e[4];
u32 rfbptr5; /* 0x.c6c - Last free RxBD pointer for ring 5 */
u8 res24f[4];
u32 rfbptr6; /* 0x.c74 - Last free RxBD pointer for ring 6 */
u8 res24g[4];
u32 rfbptr7; /* 0x.c7c - Last free RxBD pointer for ring 7 */
u8 res24h[4];
u8 res24x[556];
u32 isrg0; /* 0x.eb0 - Interrupt steering group 0 register */
u32 isrg1; /* 0x.eb4 - Interrupt steering group 1 register */
u32 isrg2; /* 0x.eb8 - Interrupt steering group 2 register */
Expand Down Expand Up @@ -1009,6 +1039,7 @@ struct gfar_priv_rx_q {
/* RX Coalescing values */
unsigned char rxcoalescing;
unsigned long rxic;
u32 *rfbptr;
};

enum gfar_irqinfo_id {
Expand Down Expand Up @@ -1099,6 +1130,7 @@ struct gfar_private {
unsigned int num_tx_queues;
unsigned int num_rx_queues;
unsigned int num_grps;
int tx_actual_en;

/* Network Statistics */
struct gfar_extra_stats extra_stats;
Expand Down
7 changes: 6 additions & 1 deletion drivers/net/ethernet/freescale/gianfar_ethtool.c
Original file line number Diff line number Diff line change
Expand Up @@ -579,8 +579,13 @@ static int gfar_spauseparam(struct net_device *dev,
u32 tempval;
tempval = gfar_read(&regs->maccfg1);
tempval &= ~(MACCFG1_TX_FLOW | MACCFG1_RX_FLOW);
if (priv->tx_pause_en)

priv->tx_actual_en = 0;
if (priv->tx_pause_en) {
priv->tx_actual_en = 1;
tempval |= MACCFG1_TX_FLOW;
}

if (priv->rx_pause_en)
tempval |= MACCFG1_RX_FLOW;
gfar_write(&regs->maccfg1, tempval);
Expand Down

0 comments on commit 45b679c

Please sign in to comment.