aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/freescale
diff options
context:
space:
mode:
authorMatei Pavaluca <matei.pavaluca@freescale.com>2014-10-27 04:42:44 -0400
committerDavid S. Miller <davem@davemloft.net>2014-10-29 14:33:16 -0400
commit45b679c9a3ccd9e34f28e6ec677b812a860eb8eb (patch)
tree2be284741c04e285cc42a11b2a021c045bc44bd5 /drivers/net/ethernet/freescale
parent43ef8d29eebb6f533f11439d48a927426c5a1918 (diff)
gianfar: Implement PAUSE frame generation support
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>
Diffstat (limited to 'drivers/net/ethernet/freescale')
-rw-r--r--drivers/net/ethernet/freescale/gianfar.c54
-rw-r--r--drivers/net/ethernet/freescale/gianfar.h34
-rw-r--r--drivers/net/ethernet/freescale/gianfar_ethtool.c7
3 files changed, 93 insertions, 2 deletions
diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c
index 329efcad4fe0..86dccb26fecc 100644
--- a/drivers/net/ethernet/freescale/gianfar.c
+++ b/drivers/net/ethernet/freescale/gianfar.c
@@ -173,10 +173,12 @@ static void gfar_init_rxbdp(struct gfar_priv_rx_q *rx_queue, struct rxbd8 *bdp,
173static int gfar_init_bds(struct net_device *ndev) 173static int gfar_init_bds(struct net_device *ndev)
174{ 174{
175 struct gfar_private *priv = netdev_priv(ndev); 175 struct gfar_private *priv = netdev_priv(ndev);
176 struct gfar __iomem *regs = priv->gfargrp[0].regs;
176 struct gfar_priv_tx_q *tx_queue = NULL; 177 struct gfar_priv_tx_q *tx_queue = NULL;
177 struct gfar_priv_rx_q *rx_queue = NULL; 178 struct gfar_priv_rx_q *rx_queue = NULL;
178 struct txbd8 *txbdp; 179 struct txbd8 *txbdp;
179 struct rxbd8 *rxbdp; 180 struct rxbd8 *rxbdp;
181 u32 *rfbptr;
180 int i, j; 182 int i, j;
181 183
182 for (i = 0; i < priv->num_tx_queues; i++) { 184 for (i = 0; i < priv->num_tx_queues; i++) {
@@ -201,6 +203,7 @@ static int gfar_init_bds(struct net_device *ndev)
201 txbdp->status |= TXBD_WRAP; 203 txbdp->status |= TXBD_WRAP;
202 } 204 }
203 205
206 rfbptr = &regs->rfbptr0;
204 for (i = 0; i < priv->num_rx_queues; i++) { 207 for (i = 0; i < priv->num_rx_queues; i++) {
205 rx_queue = priv->rx_queue[i]; 208 rx_queue = priv->rx_queue[i];
206 rx_queue->cur_rx = rx_queue->rx_bd_base; 209 rx_queue->cur_rx = rx_queue->rx_bd_base;
@@ -227,6 +230,8 @@ static int gfar_init_bds(struct net_device *ndev)
227 rxbdp++; 230 rxbdp++;
228 } 231 }
229 232
233 rx_queue->rfbptr = rfbptr;
234 rfbptr += 2;
230 } 235 }
231 236
232 return 0; 237 return 0;
@@ -336,6 +341,20 @@ static void gfar_init_tx_rx_base(struct gfar_private *priv)
336 } 341 }
337} 342}
338 343
344static void gfar_init_rqprm(struct gfar_private *priv)
345{
346 struct gfar __iomem *regs = priv->gfargrp[0].regs;
347 u32 __iomem *baddr;
348 int i;
349
350 baddr = &regs->rqprm0;
351 for (i = 0; i < priv->num_rx_queues; i++) {
352 gfar_write(baddr, priv->rx_queue[i]->rx_ring_size |
353 (DEFAULT_RX_LFC_THR << FBTHR_SHIFT));
354 baddr++;
355 }
356}
357
339static void gfar_rx_buff_size_config(struct gfar_private *priv) 358static void gfar_rx_buff_size_config(struct gfar_private *priv)
340{ 359{
341 int frame_size = priv->ndev->mtu + ETH_HLEN + ETH_FCS_LEN; 360 int frame_size = priv->ndev->mtu + ETH_HLEN + ETH_FCS_LEN;
@@ -396,6 +415,13 @@ static void gfar_mac_rx_config(struct gfar_private *priv)
396 if (priv->ndev->features & NETIF_F_HW_VLAN_CTAG_RX) 415 if (priv->ndev->features & NETIF_F_HW_VLAN_CTAG_RX)
397 rctrl |= RCTRL_VLEX | RCTRL_PRSDEP_INIT; 416 rctrl |= RCTRL_VLEX | RCTRL_PRSDEP_INIT;
398 417
418 /* Clear the LFC bit */
419 gfar_write(&regs->rctrl, rctrl);
420 /* Init flow control threshold values */
421 gfar_init_rqprm(priv);
422 gfar_write(&regs->ptv, DEFAULT_LFC_PTVVAL);
423 rctrl |= RCTRL_LFC;
424
399 /* Init rctrl based on our settings */ 425 /* Init rctrl based on our settings */
400 gfar_write(&regs->rctrl, rctrl); 426 gfar_write(&regs->rctrl, rctrl);
401} 427}
@@ -2859,6 +2885,10 @@ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit)
2859 /* Setup the new bdp */ 2885 /* Setup the new bdp */
2860 gfar_new_rxbdp(rx_queue, bdp, newskb); 2886 gfar_new_rxbdp(rx_queue, bdp, newskb);
2861 2887
2888 /* Update Last Free RxBD pointer for LFC */
2889 if (unlikely(rx_queue->rfbptr && priv->tx_actual_en))
2890 gfar_write(rx_queue->rfbptr, (u32)bdp);
2891
2862 /* Update to the next pointer */ 2892 /* Update to the next pointer */
2863 bdp = next_bd(bdp, base, rx_queue->rx_ring_size); 2893 bdp = next_bd(bdp, base, rx_queue->rx_ring_size);
2864 2894
@@ -3393,6 +3423,9 @@ static noinline void gfar_update_link_state(struct gfar_private *priv)
3393{ 3423{
3394 struct gfar __iomem *regs = priv->gfargrp[0].regs; 3424 struct gfar __iomem *regs = priv->gfargrp[0].regs;
3395 struct phy_device *phydev = priv->phydev; 3425 struct phy_device *phydev = priv->phydev;
3426 struct gfar_priv_rx_q *rx_queue = NULL;
3427 int i;
3428 struct rxbd8 *bdp;
3396 3429
3397 if (unlikely(test_bit(GFAR_RESETTING, &priv->state))) 3430 if (unlikely(test_bit(GFAR_RESETTING, &priv->state)))
3398 return; 3431 return;
@@ -3401,6 +3434,7 @@ static noinline void gfar_update_link_state(struct gfar_private *priv)
3401 u32 tempval1 = gfar_read(&regs->maccfg1); 3434 u32 tempval1 = gfar_read(&regs->maccfg1);
3402 u32 tempval = gfar_read(&regs->maccfg2); 3435 u32 tempval = gfar_read(&regs->maccfg2);
3403 u32 ecntrl = gfar_read(&regs->ecntrl); 3436 u32 ecntrl = gfar_read(&regs->ecntrl);
3437 u32 tx_flow_oldval = (tempval & MACCFG1_TX_FLOW);
3404 3438
3405 if (phydev->duplex != priv->oldduplex) { 3439 if (phydev->duplex != priv->oldduplex) {
3406 if (!(phydev->duplex)) 3440 if (!(phydev->duplex))
@@ -3445,6 +3479,26 @@ static noinline void gfar_update_link_state(struct gfar_private *priv)
3445 tempval1 &= ~(MACCFG1_TX_FLOW | MACCFG1_RX_FLOW); 3479 tempval1 &= ~(MACCFG1_TX_FLOW | MACCFG1_RX_FLOW);
3446 tempval1 |= gfar_get_flowctrl_cfg(priv); 3480 tempval1 |= gfar_get_flowctrl_cfg(priv);
3447 3481
3482 /* Turn last free buffer recording on */
3483 if ((tempval1 & MACCFG1_TX_FLOW) && !tx_flow_oldval) {
3484 for (i = 0; i < priv->num_rx_queues; i++) {
3485 rx_queue = priv->rx_queue[i];
3486 bdp = rx_queue->cur_rx;
3487 /* skip to previous bd */
3488 bdp = skip_bd(bdp, rx_queue->rx_ring_size - 1,
3489 rx_queue->rx_bd_base,
3490 rx_queue->rx_ring_size);
3491
3492 if (rx_queue->rfbptr)
3493 gfar_write(rx_queue->rfbptr, (u32)bdp);
3494 }
3495
3496 priv->tx_actual_en = 1;
3497 }
3498
3499 if (unlikely(!(tempval1 & MACCFG1_TX_FLOW) && tx_flow_oldval))
3500 priv->tx_actual_en = 0;
3501
3448 gfar_write(&regs->maccfg1, tempval1); 3502 gfar_write(&regs->maccfg1, tempval1);
3449 gfar_write(&regs->maccfg2, tempval); 3503 gfar_write(&regs->maccfg2, tempval);
3450 gfar_write(&regs->ecntrl, ecntrl); 3504 gfar_write(&regs->ecntrl, ecntrl);
diff --git a/drivers/net/ethernet/freescale/gianfar.h b/drivers/net/ethernet/freescale/gianfar.h
index 6b008685837c..b581b8823a2a 100644
--- a/drivers/net/ethernet/freescale/gianfar.h
+++ b/drivers/net/ethernet/freescale/gianfar.h
@@ -99,6 +99,10 @@ extern const char gfar_driver_version[];
99#define GFAR_MAX_FIFO_STARVE 511 99#define GFAR_MAX_FIFO_STARVE 511
100#define GFAR_MAX_FIFO_STARVE_OFF 511 100#define GFAR_MAX_FIFO_STARVE_OFF 511
101 101
102#define FBTHR_SHIFT 24
103#define DEFAULT_RX_LFC_THR 16
104#define DEFAULT_LFC_PTVVAL 4
105
102#define DEFAULT_RX_BUFFER_SIZE 1536 106#define DEFAULT_RX_BUFFER_SIZE 1536
103#define TX_RING_MOD_MASK(size) (size-1) 107#define TX_RING_MOD_MASK(size) (size-1)
104#define RX_RING_MOD_MASK(size) (size-1) 108#define RX_RING_MOD_MASK(size) (size-1)
@@ -273,6 +277,7 @@ extern const char gfar_driver_version[];
273 277
274#define RCTRL_TS_ENABLE 0x01000000 278#define RCTRL_TS_ENABLE 0x01000000
275#define RCTRL_PAL_MASK 0x001f0000 279#define RCTRL_PAL_MASK 0x001f0000
280#define RCTRL_LFC 0x00004000
276#define RCTRL_VLEX 0x00002000 281#define RCTRL_VLEX 0x00002000
277#define RCTRL_FILREN 0x00001000 282#define RCTRL_FILREN 0x00001000
278#define RCTRL_GHTX 0x00000400 283#define RCTRL_GHTX 0x00000400
@@ -849,7 +854,32 @@ struct gfar {
849 u8 res23c[248]; 854 u8 res23c[248];
850 u32 attr; /* 0x.bf8 - Attributes Register */ 855 u32 attr; /* 0x.bf8 - Attributes Register */
851 u32 attreli; /* 0x.bfc - Attributes Extract Length and Extract Index Register */ 856 u32 attreli; /* 0x.bfc - Attributes Extract Length and Extract Index Register */
852 u8 res24[688]; 857 u32 rqprm0; /* 0x.c00 - Receive queue parameters register 0 */
858 u32 rqprm1; /* 0x.c04 - Receive queue parameters register 1 */
859 u32 rqprm2; /* 0x.c08 - Receive queue parameters register 2 */
860 u32 rqprm3; /* 0x.c0c - Receive queue parameters register 3 */
861 u32 rqprm4; /* 0x.c10 - Receive queue parameters register 4 */
862 u32 rqprm5; /* 0x.c14 - Receive queue parameters register 5 */
863 u32 rqprm6; /* 0x.c18 - Receive queue parameters register 6 */
864 u32 rqprm7; /* 0x.c1c - Receive queue parameters register 7 */
865 u8 res24[36];
866 u32 rfbptr0; /* 0x.c44 - Last free RxBD pointer for ring 0 */
867 u8 res24a[4];
868 u32 rfbptr1; /* 0x.c4c - Last free RxBD pointer for ring 1 */
869 u8 res24b[4];
870 u32 rfbptr2; /* 0x.c54 - Last free RxBD pointer for ring 2 */
871 u8 res24c[4];
872 u32 rfbptr3; /* 0x.c5c - Last free RxBD pointer for ring 3 */
873 u8 res24d[4];
874 u32 rfbptr4; /* 0x.c64 - Last free RxBD pointer for ring 4 */
875 u8 res24e[4];
876 u32 rfbptr5; /* 0x.c6c - Last free RxBD pointer for ring 5 */
877 u8 res24f[4];
878 u32 rfbptr6; /* 0x.c74 - Last free RxBD pointer for ring 6 */
879 u8 res24g[4];
880 u32 rfbptr7; /* 0x.c7c - Last free RxBD pointer for ring 7 */
881 u8 res24h[4];
882 u8 res24x[556];
853 u32 isrg0; /* 0x.eb0 - Interrupt steering group 0 register */ 883 u32 isrg0; /* 0x.eb0 - Interrupt steering group 0 register */
854 u32 isrg1; /* 0x.eb4 - Interrupt steering group 1 register */ 884 u32 isrg1; /* 0x.eb4 - Interrupt steering group 1 register */
855 u32 isrg2; /* 0x.eb8 - Interrupt steering group 2 register */ 885 u32 isrg2; /* 0x.eb8 - Interrupt steering group 2 register */
@@ -1009,6 +1039,7 @@ struct gfar_priv_rx_q {
1009 /* RX Coalescing values */ 1039 /* RX Coalescing values */
1010 unsigned char rxcoalescing; 1040 unsigned char rxcoalescing;
1011 unsigned long rxic; 1041 unsigned long rxic;
1042 u32 *rfbptr;
1012}; 1043};
1013 1044
1014enum gfar_irqinfo_id { 1045enum gfar_irqinfo_id {
@@ -1099,6 +1130,7 @@ struct gfar_private {
1099 unsigned int num_tx_queues; 1130 unsigned int num_tx_queues;
1100 unsigned int num_rx_queues; 1131 unsigned int num_rx_queues;
1101 unsigned int num_grps; 1132 unsigned int num_grps;
1133 int tx_actual_en;
1102 1134
1103 /* Network Statistics */ 1135 /* Network Statistics */
1104 struct gfar_extra_stats extra_stats; 1136 struct gfar_extra_stats extra_stats;
diff --git a/drivers/net/ethernet/freescale/gianfar_ethtool.c b/drivers/net/ethernet/freescale/gianfar_ethtool.c
index 76d70708f864..3e1a9c1a67a9 100644
--- a/drivers/net/ethernet/freescale/gianfar_ethtool.c
+++ b/drivers/net/ethernet/freescale/gianfar_ethtool.c
@@ -579,8 +579,13 @@ static int gfar_spauseparam(struct net_device *dev,
579 u32 tempval; 579 u32 tempval;
580 tempval = gfar_read(&regs->maccfg1); 580 tempval = gfar_read(&regs->maccfg1);
581 tempval &= ~(MACCFG1_TX_FLOW | MACCFG1_RX_FLOW); 581 tempval &= ~(MACCFG1_TX_FLOW | MACCFG1_RX_FLOW);
582 if (priv->tx_pause_en) 582
583 priv->tx_actual_en = 0;
584 if (priv->tx_pause_en) {
585 priv->tx_actual_en = 1;
583 tempval |= MACCFG1_TX_FLOW; 586 tempval |= MACCFG1_TX_FLOW;
587 }
588
584 if (priv->rx_pause_en) 589 if (priv->rx_pause_en)
585 tempval |= MACCFG1_RX_FLOW; 590 tempval |= MACCFG1_RX_FLOW;
586 gfar_write(&regs->maccfg1, tempval); 591 gfar_write(&regs->maccfg1, tempval);