aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/gianfar_ethtool.c
diff options
context:
space:
mode:
authorKumar Gala <galak@freescale.com>2005-06-20 11:54:21 -0400
committerJeff Garzik <jgarzik@pobox.com>2005-06-27 00:40:33 -0400
commit0bbaf069f053957e8d733784e18a2992afd1dd3c (patch)
tree5fd2250138b0486aaa5b135e70afe551b92d8374 /drivers/net/gianfar_ethtool.c
parentbe83668a253149d99085ca4afe6cd8dc8a43fcd0 (diff)
[PATCH] gianfar: Add support enhanced TSEC features on the MPC 8548
Jeff, Just incase this got lost in the recent netdev mailing list transition here is a nicer version of Andy's patch for gianfar. - kumar * TCP/IP/UDP checksumming and verification * VLAN tag insertion/extraction * Larger multicast hash-table * Padding to align IP headers Also added: * msg lvl support * Some whitespace cleanup Signed-off-by: Andy Fleming <afleming@freescale.com> Signed-off-by: Kumar Gala <kumar.gala@freescale.com>
Diffstat (limited to 'drivers/net/gianfar_ethtool.c')
-rw-r--r--drivers/net/gianfar_ethtool.c277
1 files changed, 153 insertions, 124 deletions
diff --git a/drivers/net/gianfar_ethtool.c b/drivers/net/gianfar_ethtool.c
index 28046e9e88ba..a451de629197 100644
--- a/drivers/net/gianfar_ethtool.c
+++ b/drivers/net/gianfar_ethtool.c
@@ -46,16 +46,18 @@
46 46
47extern int startup_gfar(struct net_device *dev); 47extern int startup_gfar(struct net_device *dev);
48extern void stop_gfar(struct net_device *dev); 48extern void stop_gfar(struct net_device *dev);
49extern void gfar_receive(int irq, void *dev_id, struct pt_regs *regs); 49extern void gfar_halt(struct net_device *dev);
50extern void gfar_start(struct net_device *dev);
51extern int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit);
50 52
51void gfar_fill_stats(struct net_device *dev, struct ethtool_stats *dummy, 53static void gfar_fill_stats(struct net_device *dev, struct ethtool_stats *dummy,
52 u64 * buf); 54 u64 * buf);
53void gfar_gstrings(struct net_device *dev, u32 stringset, u8 * buf); 55static void gfar_gstrings(struct net_device *dev, u32 stringset, u8 * buf);
54int gfar_gcoalesce(struct net_device *dev, struct ethtool_coalesce *cvals); 56static int gfar_gcoalesce(struct net_device *dev, struct ethtool_coalesce *cvals);
55int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals); 57static int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals);
56void gfar_gringparam(struct net_device *dev, struct ethtool_ringparam *rvals); 58static void gfar_gringparam(struct net_device *dev, struct ethtool_ringparam *rvals);
57int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rvals); 59static int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rvals);
58void gfar_gdrvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo); 60static void gfar_gdrvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo);
59 61
60static char stat_gstrings[][ETH_GSTRING_LEN] = { 62static char stat_gstrings[][ETH_GSTRING_LEN] = {
61 "rx-dropped-by-kernel", 63 "rx-dropped-by-kernel",
@@ -118,57 +120,56 @@ static char stat_gstrings[][ETH_GSTRING_LEN] = {
118 "tx-fragmented-frames", 120 "tx-fragmented-frames",
119}; 121};
120 122
123/* Fill in a buffer with the strings which correspond to the
124 * stats */
125static void gfar_gstrings(struct net_device *dev, u32 stringset, u8 * buf)
126{
127 struct gfar_private *priv = netdev_priv(dev);
128
129 if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_RMON)
130 memcpy(buf, stat_gstrings, GFAR_STATS_LEN * ETH_GSTRING_LEN);
131 else
132 memcpy(buf, stat_gstrings,
133 GFAR_EXTRA_STATS_LEN * ETH_GSTRING_LEN);
134}
135
121/* Fill in an array of 64-bit statistics from various sources. 136/* Fill in an array of 64-bit statistics from various sources.
122 * This array will be appended to the end of the ethtool_stats 137 * This array will be appended to the end of the ethtool_stats
123 * structure, and returned to user space 138 * structure, and returned to user space
124 */ 139 */
125void gfar_fill_stats(struct net_device *dev, struct ethtool_stats *dummy, u64 * buf) 140static void gfar_fill_stats(struct net_device *dev, struct ethtool_stats *dummy, u64 * buf)
126{ 141{
127 int i; 142 int i;
128 struct gfar_private *priv = netdev_priv(dev); 143 struct gfar_private *priv = netdev_priv(dev);
129 u32 *rmon = (u32 *) & priv->regs->rmon;
130 u64 *extra = (u64 *) & priv->extra_stats; 144 u64 *extra = (u64 *) & priv->extra_stats;
131 struct gfar_stats *stats = (struct gfar_stats *) buf;
132 145
133 for (i = 0; i < GFAR_RMON_LEN; i++) { 146 if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_RMON) {
134 stats->rmon[i] = (u64) (rmon[i]); 147 u32 *rmon = (u32 *) & priv->regs->rmon;
135 } 148 struct gfar_stats *stats = (struct gfar_stats *) buf;
136
137 for (i = 0; i < GFAR_EXTRA_STATS_LEN; i++) {
138 stats->extra[i] = extra[i];
139 }
140}
141 149
142/* Returns the number of stats (and their corresponding strings) */ 150 for (i = 0; i < GFAR_RMON_LEN; i++)
143int gfar_stats_count(struct net_device *dev) 151 stats->rmon[i] = (u64) (rmon[i]);
144{
145 return GFAR_STATS_LEN;
146}
147 152
148void gfar_gstrings_normon(struct net_device *dev, u32 stringset, u8 * buf) 153 for (i = 0; i < GFAR_EXTRA_STATS_LEN; i++)
149{ 154 stats->extra[i] = extra[i];
150 memcpy(buf, stat_gstrings, GFAR_EXTRA_STATS_LEN * ETH_GSTRING_LEN); 155 } else
156 for (i = 0; i < GFAR_EXTRA_STATS_LEN; i++)
157 buf[i] = extra[i];
151} 158}
152 159
153void gfar_fill_stats_normon(struct net_device *dev, 160/* Returns the number of stats (and their corresponding strings) */
154 struct ethtool_stats *dummy, u64 * buf) 161static int gfar_stats_count(struct net_device *dev)
155{ 162{
156 int i;
157 struct gfar_private *priv = netdev_priv(dev); 163 struct gfar_private *priv = netdev_priv(dev);
158 u64 *extra = (u64 *) & priv->extra_stats;
159 164
160 for (i = 0; i < GFAR_EXTRA_STATS_LEN; i++) { 165 if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_RMON)
161 buf[i] = extra[i]; 166 return GFAR_STATS_LEN;
162 } 167 else
168 return GFAR_EXTRA_STATS_LEN;
163} 169}
164 170
165
166int gfar_stats_count_normon(struct net_device *dev)
167{
168 return GFAR_EXTRA_STATS_LEN;
169}
170/* Fills in the drvinfo structure with some basic info */ 171/* Fills in the drvinfo structure with some basic info */
171void gfar_gdrvinfo(struct net_device *dev, struct 172static void gfar_gdrvinfo(struct net_device *dev, struct
172 ethtool_drvinfo *drvinfo) 173 ethtool_drvinfo *drvinfo)
173{ 174{
174 strncpy(drvinfo->driver, DRV_NAME, GFAR_INFOSTR_LEN); 175 strncpy(drvinfo->driver, DRV_NAME, GFAR_INFOSTR_LEN);
@@ -182,7 +183,7 @@ void gfar_gdrvinfo(struct net_device *dev, struct
182} 183}
183 184
184/* Return the current settings in the ethtool_cmd structure */ 185/* Return the current settings in the ethtool_cmd structure */
185int gfar_gsettings(struct net_device *dev, struct ethtool_cmd *cmd) 186static int gfar_gsettings(struct net_device *dev, struct ethtool_cmd *cmd)
186{ 187{
187 struct gfar_private *priv = netdev_priv(dev); 188 struct gfar_private *priv = netdev_priv(dev);
188 uint gigabit_support = 189 uint gigabit_support =
@@ -216,13 +217,13 @@ int gfar_gsettings(struct net_device *dev, struct ethtool_cmd *cmd)
216} 217}
217 218
218/* Return the length of the register structure */ 219/* Return the length of the register structure */
219int gfar_reglen(struct net_device *dev) 220static int gfar_reglen(struct net_device *dev)
220{ 221{
221 return sizeof (struct gfar); 222 return sizeof (struct gfar);
222} 223}
223 224
224/* Return a dump of the GFAR register space */ 225/* Return a dump of the GFAR register space */
225void gfar_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *regbuf) 226static void gfar_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *regbuf)
226{ 227{
227 int i; 228 int i;
228 struct gfar_private *priv = netdev_priv(dev); 229 struct gfar_private *priv = netdev_priv(dev);
@@ -233,13 +234,6 @@ void gfar_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *regb
233 buf[i] = theregs[i]; 234 buf[i] = theregs[i];
234} 235}
235 236
236/* Fill in a buffer with the strings which correspond to the
237 * stats */
238void gfar_gstrings(struct net_device *dev, u32 stringset, u8 * buf)
239{
240 memcpy(buf, stat_gstrings, GFAR_STATS_LEN * ETH_GSTRING_LEN);
241}
242
243/* Convert microseconds to ethernet clock ticks, which changes 237/* Convert microseconds to ethernet clock ticks, which changes
244 * depending on what speed the controller is running at */ 238 * depending on what speed the controller is running at */
245static unsigned int gfar_usecs2ticks(struct gfar_private *priv, unsigned int usecs) 239static unsigned int gfar_usecs2ticks(struct gfar_private *priv, unsigned int usecs)
@@ -291,9 +285,12 @@ static unsigned int gfar_ticks2usecs(struct gfar_private *priv, unsigned int tic
291 285
292/* Get the coalescing parameters, and put them in the cvals 286/* Get the coalescing parameters, and put them in the cvals
293 * structure. */ 287 * structure. */
294int gfar_gcoalesce(struct net_device *dev, struct ethtool_coalesce *cvals) 288static int gfar_gcoalesce(struct net_device *dev, struct ethtool_coalesce *cvals)
295{ 289{
296 struct gfar_private *priv = netdev_priv(dev); 290 struct gfar_private *priv = netdev_priv(dev);
291
292 if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_COALESCE))
293 return -EOPNOTSUPP;
297 294
298 cvals->rx_coalesce_usecs = gfar_ticks2usecs(priv, priv->rxtime); 295 cvals->rx_coalesce_usecs = gfar_ticks2usecs(priv, priv->rxtime);
299 cvals->rx_max_coalesced_frames = priv->rxcount; 296 cvals->rx_max_coalesced_frames = priv->rxcount;
@@ -337,10 +334,13 @@ int gfar_gcoalesce(struct net_device *dev, struct ethtool_coalesce *cvals)
337 * Both cvals->*_usecs and cvals->*_frames have to be > 0 334 * Both cvals->*_usecs and cvals->*_frames have to be > 0
338 * in order for coalescing to be active 335 * in order for coalescing to be active
339 */ 336 */
340int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals) 337static int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals)
341{ 338{
342 struct gfar_private *priv = netdev_priv(dev); 339 struct gfar_private *priv = netdev_priv(dev);
343 340
341 if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_COALESCE))
342 return -EOPNOTSUPP;
343
344 /* Set up rx coalescing */ 344 /* Set up rx coalescing */
345 if ((cvals->rx_coalesce_usecs == 0) || 345 if ((cvals->rx_coalesce_usecs == 0) ||
346 (cvals->rx_max_coalesced_frames == 0)) 346 (cvals->rx_max_coalesced_frames == 0))
@@ -379,7 +379,7 @@ int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals)
379/* Fills in rvals with the current ring parameters. Currently, 379/* Fills in rvals with the current ring parameters. Currently,
380 * rx, rx_mini, and rx_jumbo rings are the same size, as mini and 380 * rx, rx_mini, and rx_jumbo rings are the same size, as mini and
381 * jumbo are ignored by the driver */ 381 * jumbo are ignored by the driver */
382void gfar_gringparam(struct net_device *dev, struct ethtool_ringparam *rvals) 382static void gfar_gringparam(struct net_device *dev, struct ethtool_ringparam *rvals)
383{ 383{
384 struct gfar_private *priv = netdev_priv(dev); 384 struct gfar_private *priv = netdev_priv(dev);
385 385
@@ -401,9 +401,8 @@ void gfar_gringparam(struct net_device *dev, struct ethtool_ringparam *rvals)
401 * necessary so that we don't mess things up while we're in 401 * necessary so that we don't mess things up while we're in
402 * motion. We wait for the ring to be clean before reallocating 402 * motion. We wait for the ring to be clean before reallocating
403 * the rings. */ 403 * the rings. */
404int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rvals) 404static int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rvals)
405{ 405{
406 u32 tempval;
407 struct gfar_private *priv = netdev_priv(dev); 406 struct gfar_private *priv = netdev_priv(dev);
408 int err = 0; 407 int err = 0;
409 408
@@ -425,37 +424,54 @@ int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rvals)
425 return -EINVAL; 424 return -EINVAL;
426 } 425 }
427 426
428 /* Stop the controller so we don't rx any more frames */ 427 if (dev->flags & IFF_UP) {
429 /* But first, make sure we clear the bits */ 428 unsigned long flags;
430 tempval = gfar_read(&priv->regs->dmactrl);
431 tempval &= ~(DMACTRL_GRS | DMACTRL_GTS);
432 gfar_write(&priv->regs->dmactrl, tempval);
433 429
434 tempval = gfar_read(&priv->regs->dmactrl); 430 /* Halt TX and RX, and process the frames which
435 tempval |= (DMACTRL_GRS | DMACTRL_GTS); 431 * have already been received */
436 gfar_write(&priv->regs->dmactrl, tempval); 432 spin_lock_irqsave(&priv->lock, flags);
433 gfar_halt(dev);
434 gfar_clean_rx_ring(dev, priv->rx_ring_size);
435 spin_unlock_irqrestore(&priv->lock, flags);
437 436
438 while (!(gfar_read(&priv->regs->ievent) & (IEVENT_GRSC | IEVENT_GTSC))) 437 /* Now we take down the rings to rebuild them */
439 cpu_relax(); 438 stop_gfar(dev);
439 }
440 440
441 /* Note that rx is not clean right now */ 441 /* Change the size */
442 priv->rxclean = 0; 442 priv->rx_ring_size = rvals->rx_pending;
443 priv->tx_ring_size = rvals->tx_pending;
443 444
444 if (dev->flags & IFF_UP) { 445 /* Rebuild the rings with the new size */
445 /* Tell the driver to process the rest of the frames */ 446 if (dev->flags & IFF_UP)
446 gfar_receive(0, (void *) dev, NULL); 447 err = startup_gfar(dev);
447 448
448 /* Now wait for it to be done */ 449 return err;
449 wait_event_interruptible(priv->rxcleanupq, priv->rxclean); 450}
450 451
451 /* Ok, all packets have been handled. Now we bring it down, 452static int gfar_set_rx_csum(struct net_device *dev, uint32_t data)
452 * change the ring size, and bring it up */ 453{
454 struct gfar_private *priv = netdev_priv(dev);
455 int err = 0;
453 456
457 if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_CSUM))
458 return -EOPNOTSUPP;
459
460 if (dev->flags & IFF_UP) {
461 unsigned long flags;
462
463 /* Halt TX and RX, and process the frames which
464 * have already been received */
465 spin_lock_irqsave(&priv->lock, flags);
466 gfar_halt(dev);
467 gfar_clean_rx_ring(dev, priv->rx_ring_size);
468 spin_unlock_irqrestore(&priv->lock, flags);
469
470 /* Now we take down the rings to rebuild them */
454 stop_gfar(dev); 471 stop_gfar(dev);
455 } 472 }
456 473
457 priv->rx_ring_size = rvals->rx_pending; 474 priv->rx_csum_enable = data;
458 priv->tx_ring_size = rvals->tx_pending;
459 475
460 if (dev->flags & IFF_UP) 476 if (dev->flags & IFF_UP)
461 err = startup_gfar(dev); 477 err = startup_gfar(dev);
@@ -463,6 +479,61 @@ int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rvals)
463 return err; 479 return err;
464} 480}
465 481
482static uint32_t gfar_get_rx_csum(struct net_device *dev)
483{
484 struct gfar_private *priv = netdev_priv(dev);
485
486 if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_CSUM))
487 return 0;
488
489 return priv->rx_csum_enable;
490}
491
492static int gfar_set_tx_csum(struct net_device *dev, uint32_t data)
493{
494 unsigned long flags;
495 struct gfar_private *priv = netdev_priv(dev);
496
497 if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_CSUM))
498 return -EOPNOTSUPP;
499
500 spin_lock_irqsave(&priv->lock, flags);
501 gfar_halt(dev);
502
503 if (data)
504 dev->features |= NETIF_F_IP_CSUM;
505 else
506 dev->features &= ~NETIF_F_IP_CSUM;
507
508 gfar_start(dev);
509 spin_unlock_irqrestore(&priv->lock, flags);
510
511 return 0;
512}
513
514static uint32_t gfar_get_tx_csum(struct net_device *dev)
515{
516 struct gfar_private *priv = netdev_priv(dev);
517
518 if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_CSUM))
519 return 0;
520
521 return (dev->features & NETIF_F_IP_CSUM) != 0;
522}
523
524static uint32_t gfar_get_msglevel(struct net_device *dev)
525{
526 struct gfar_private *priv = netdev_priv(dev);
527 return priv->msg_enable;
528}
529
530static void gfar_set_msglevel(struct net_device *dev, uint32_t data)
531{
532 struct gfar_private *priv = netdev_priv(dev);
533 priv->msg_enable = data;
534}
535
536
466struct ethtool_ops gfar_ethtool_ops = { 537struct ethtool_ops gfar_ethtool_ops = {
467 .get_settings = gfar_gsettings, 538 .get_settings = gfar_gsettings,
468 .get_drvinfo = gfar_gdrvinfo, 539 .get_drvinfo = gfar_gdrvinfo,
@@ -476,52 +547,10 @@ struct ethtool_ops gfar_ethtool_ops = {
476 .get_strings = gfar_gstrings, 547 .get_strings = gfar_gstrings,
477 .get_stats_count = gfar_stats_count, 548 .get_stats_count = gfar_stats_count,
478 .get_ethtool_stats = gfar_fill_stats, 549 .get_ethtool_stats = gfar_fill_stats,
479}; 550 .get_rx_csum = gfar_get_rx_csum,
480 551 .get_tx_csum = gfar_get_tx_csum,
481struct ethtool_ops gfar_normon_nocoalesce_ethtool_ops = { 552 .set_rx_csum = gfar_set_rx_csum,
482 .get_settings = gfar_gsettings, 553 .set_tx_csum = gfar_set_tx_csum,
483 .get_drvinfo = gfar_gdrvinfo, 554 .get_msglevel = gfar_get_msglevel,
484 .get_regs_len = gfar_reglen, 555 .set_msglevel = gfar_set_msglevel,
485 .get_regs = gfar_get_regs,
486 .get_link = ethtool_op_get_link,
487 .get_ringparam = gfar_gringparam,
488 .set_ringparam = gfar_sringparam,
489 .get_strings = gfar_gstrings_normon,
490 .get_stats_count = gfar_stats_count_normon,
491 .get_ethtool_stats = gfar_fill_stats_normon,
492};
493
494struct ethtool_ops gfar_nocoalesce_ethtool_ops = {
495 .get_settings = gfar_gsettings,
496 .get_drvinfo = gfar_gdrvinfo,
497 .get_regs_len = gfar_reglen,
498 .get_regs = gfar_get_regs,
499 .get_link = ethtool_op_get_link,
500 .get_ringparam = gfar_gringparam,
501 .set_ringparam = gfar_sringparam,
502 .get_strings = gfar_gstrings,
503 .get_stats_count = gfar_stats_count,
504 .get_ethtool_stats = gfar_fill_stats,
505};
506
507struct ethtool_ops gfar_normon_ethtool_ops = {
508 .get_settings = gfar_gsettings,
509 .get_drvinfo = gfar_gdrvinfo,
510 .get_regs_len = gfar_reglen,
511 .get_regs = gfar_get_regs,
512 .get_link = ethtool_op_get_link,
513 .get_coalesce = gfar_gcoalesce,
514 .set_coalesce = gfar_scoalesce,
515 .get_ringparam = gfar_gringparam,
516 .set_ringparam = gfar_sringparam,
517 .get_strings = gfar_gstrings_normon,
518 .get_stats_count = gfar_stats_count_normon,
519 .get_ethtool_stats = gfar_fill_stats_normon,
520};
521
522struct ethtool_ops *gfar_op_array[] = {
523 &gfar_ethtool_ops,
524 &gfar_normon_ethtool_ops,
525 &gfar_nocoalesce_ethtool_ops,
526 &gfar_normon_nocoalesce_ethtool_ops
527}; 556};