diff options
-rw-r--r-- | drivers/net/davinci_emac.c | 133 |
1 files changed, 131 insertions, 2 deletions
diff --git a/drivers/net/davinci_emac.c b/drivers/net/davinci_emac.c index 25e14d2da75..28633761be2 100644 --- a/drivers/net/davinci_emac.c +++ b/drivers/net/davinci_emac.c | |||
@@ -298,6 +298,11 @@ static const char emac_version_string[] = "TI DaVinci EMAC Linux v6.1"; | |||
298 | #define EMAC_CTRL_EWCTL (0x4) | 298 | #define EMAC_CTRL_EWCTL (0x4) |
299 | #define EMAC_CTRL_EWINTTCNT (0x8) | 299 | #define EMAC_CTRL_EWINTTCNT (0x8) |
300 | 300 | ||
301 | /* EMAC DM644x control module masks */ | ||
302 | #define EMAC_DM644X_EWINTCNT_MASK 0x1FFFF | ||
303 | #define EMAC_DM644X_INTMIN_INTVL 0x1 | ||
304 | #define EMAC_DM644X_INTMAX_INTVL (EMAC_DM644X_EWINTCNT_MASK) | ||
305 | |||
301 | /* EMAC MDIO related */ | 306 | /* EMAC MDIO related */ |
302 | /* Mask & Control defines */ | 307 | /* Mask & Control defines */ |
303 | #define MDIO_CONTROL_CLKDIV (0xFF) | 308 | #define MDIO_CONTROL_CLKDIV (0xFF) |
@@ -318,8 +323,20 @@ static const char emac_version_string[] = "TI DaVinci EMAC Linux v6.1"; | |||
318 | #define MDIO_CONTROL (0x04) | 323 | #define MDIO_CONTROL (0x04) |
319 | 324 | ||
320 | /* EMAC DM646X control module registers */ | 325 | /* EMAC DM646X control module registers */ |
321 | #define EMAC_DM646X_CMRXINTEN (0x14) | 326 | #define EMAC_DM646X_CMINTCTRL 0x0C |
322 | #define EMAC_DM646X_CMTXINTEN (0x18) | 327 | #define EMAC_DM646X_CMRXINTEN 0x14 |
328 | #define EMAC_DM646X_CMTXINTEN 0x18 | ||
329 | #define EMAC_DM646X_CMRXINTMAX 0x70 | ||
330 | #define EMAC_DM646X_CMTXINTMAX 0x74 | ||
331 | |||
332 | /* EMAC DM646X control module masks */ | ||
333 | #define EMAC_DM646X_INTPACEEN (0x3 << 16) | ||
334 | #define EMAC_DM646X_INTPRESCALE_MASK (0x7FF << 0) | ||
335 | #define EMAC_DM646X_CMINTMAX_CNT 63 | ||
336 | #define EMAC_DM646X_CMINTMIN_CNT 2 | ||
337 | #define EMAC_DM646X_CMINTMAX_INTVL (1000 / EMAC_DM646X_CMINTMIN_CNT) | ||
338 | #define EMAC_DM646X_CMINTMIN_INTVL ((1000 / EMAC_DM646X_CMINTMAX_CNT) + 1) | ||
339 | |||
323 | 340 | ||
324 | /* EMAC EOI codes for C0 */ | 341 | /* EMAC EOI codes for C0 */ |
325 | #define EMAC_DM646X_MAC_EOI_C0_RXEN (0x01) | 342 | #define EMAC_DM646X_MAC_EOI_C0_RXEN (0x01) |
@@ -468,6 +485,8 @@ struct emac_priv { | |||
468 | u32 duplex; /* Link duplex: 0=Half, 1=Full */ | 485 | u32 duplex; /* Link duplex: 0=Half, 1=Full */ |
469 | u32 rx_buf_size; | 486 | u32 rx_buf_size; |
470 | u32 isr_count; | 487 | u32 isr_count; |
488 | u32 coal_intvl; | ||
489 | u32 bus_freq_mhz; | ||
471 | u8 rmii_en; | 490 | u8 rmii_en; |
472 | u8 version; | 491 | u8 version; |
473 | u32 mac_hash1; | 492 | u32 mac_hash1; |
@@ -691,6 +710,103 @@ static int emac_set_settings(struct net_device *ndev, struct ethtool_cmd *ecmd) | |||
691 | } | 710 | } |
692 | 711 | ||
693 | /** | 712 | /** |
713 | * emac_get_coalesce : Get interrupt coalesce settings for this device | ||
714 | * @ndev : The DaVinci EMAC network adapter | ||
715 | * @coal : ethtool coalesce settings structure | ||
716 | * | ||
717 | * Fetch the current interrupt coalesce settings | ||
718 | * | ||
719 | */ | ||
720 | static int emac_get_coalesce(struct net_device *ndev, | ||
721 | struct ethtool_coalesce *coal) | ||
722 | { | ||
723 | struct emac_priv *priv = netdev_priv(ndev); | ||
724 | |||
725 | coal->rx_coalesce_usecs = priv->coal_intvl; | ||
726 | return 0; | ||
727 | |||
728 | } | ||
729 | |||
730 | /** | ||
731 | * emac_set_coalesce : Set interrupt coalesce settings for this device | ||
732 | * @ndev : The DaVinci EMAC network adapter | ||
733 | * @coal : ethtool coalesce settings structure | ||
734 | * | ||
735 | * Set interrupt coalesce parameters | ||
736 | * | ||
737 | */ | ||
738 | static int emac_set_coalesce(struct net_device *ndev, | ||
739 | struct ethtool_coalesce *coal) | ||
740 | { | ||
741 | struct emac_priv *priv = netdev_priv(ndev); | ||
742 | u32 int_ctrl, num_interrupts = 0; | ||
743 | u32 prescale = 0, addnl_dvdr = 1, coal_intvl = 0; | ||
744 | |||
745 | if (!coal->rx_coalesce_usecs) | ||
746 | return -EINVAL; | ||
747 | |||
748 | coal_intvl = coal->rx_coalesce_usecs; | ||
749 | |||
750 | switch (priv->version) { | ||
751 | case EMAC_VERSION_2: | ||
752 | int_ctrl = emac_ctrl_read(EMAC_DM646X_CMINTCTRL); | ||
753 | prescale = priv->bus_freq_mhz * 4; | ||
754 | |||
755 | if (coal_intvl < EMAC_DM646X_CMINTMIN_INTVL) | ||
756 | coal_intvl = EMAC_DM646X_CMINTMIN_INTVL; | ||
757 | |||
758 | if (coal_intvl > EMAC_DM646X_CMINTMAX_INTVL) { | ||
759 | /* | ||
760 | * Interrupt pacer works with 4us Pulse, we can | ||
761 | * throttle further by dilating the 4us pulse. | ||
762 | */ | ||
763 | addnl_dvdr = EMAC_DM646X_INTPRESCALE_MASK / prescale; | ||
764 | |||
765 | if (addnl_dvdr > 1) { | ||
766 | prescale *= addnl_dvdr; | ||
767 | if (coal_intvl > (EMAC_DM646X_CMINTMAX_INTVL | ||
768 | * addnl_dvdr)) | ||
769 | coal_intvl = (EMAC_DM646X_CMINTMAX_INTVL | ||
770 | * addnl_dvdr); | ||
771 | } else { | ||
772 | addnl_dvdr = 1; | ||
773 | coal_intvl = EMAC_DM646X_CMINTMAX_INTVL; | ||
774 | } | ||
775 | } | ||
776 | |||
777 | num_interrupts = (1000 * addnl_dvdr) / coal_intvl; | ||
778 | |||
779 | int_ctrl |= EMAC_DM646X_INTPACEEN; | ||
780 | int_ctrl &= (~EMAC_DM646X_INTPRESCALE_MASK); | ||
781 | int_ctrl |= (prescale & EMAC_DM646X_INTPRESCALE_MASK); | ||
782 | emac_ctrl_write(EMAC_DM646X_CMINTCTRL, int_ctrl); | ||
783 | |||
784 | emac_ctrl_write(EMAC_DM646X_CMRXINTMAX, num_interrupts); | ||
785 | emac_ctrl_write(EMAC_DM646X_CMTXINTMAX, num_interrupts); | ||
786 | |||
787 | break; | ||
788 | default: | ||
789 | int_ctrl = emac_ctrl_read(EMAC_CTRL_EWINTTCNT); | ||
790 | int_ctrl &= (~EMAC_DM644X_EWINTCNT_MASK); | ||
791 | prescale = coal_intvl * priv->bus_freq_mhz; | ||
792 | if (prescale > EMAC_DM644X_EWINTCNT_MASK) { | ||
793 | prescale = EMAC_DM644X_EWINTCNT_MASK; | ||
794 | coal_intvl = prescale / priv->bus_freq_mhz; | ||
795 | } | ||
796 | emac_ctrl_write(EMAC_CTRL_EWINTTCNT, (int_ctrl | prescale)); | ||
797 | |||
798 | break; | ||
799 | } | ||
800 | |||
801 | printk(KERN_INFO"Set coalesce to %d usecs.\n", coal_intvl); | ||
802 | priv->coal_intvl = coal_intvl; | ||
803 | |||
804 | return 0; | ||
805 | |||
806 | } | ||
807 | |||
808 | |||
809 | /** | ||
694 | * ethtool_ops: DaVinci EMAC Ethtool structure | 810 | * ethtool_ops: DaVinci EMAC Ethtool structure |
695 | * | 811 | * |
696 | * Ethtool support for EMAC adapter | 812 | * Ethtool support for EMAC adapter |
@@ -701,6 +817,8 @@ static const struct ethtool_ops ethtool_ops = { | |||
701 | .get_settings = emac_get_settings, | 817 | .get_settings = emac_get_settings, |
702 | .set_settings = emac_set_settings, | 818 | .set_settings = emac_set_settings, |
703 | .get_link = ethtool_op_get_link, | 819 | .get_link = ethtool_op_get_link, |
820 | .get_coalesce = emac_get_coalesce, | ||
821 | .set_coalesce = emac_set_coalesce, | ||
704 | }; | 822 | }; |
705 | 823 | ||
706 | /** | 824 | /** |
@@ -2437,6 +2555,14 @@ static int emac_dev_open(struct net_device *ndev) | |||
2437 | /* Start/Enable EMAC hardware */ | 2555 | /* Start/Enable EMAC hardware */ |
2438 | emac_hw_enable(priv); | 2556 | emac_hw_enable(priv); |
2439 | 2557 | ||
2558 | /* Enable Interrupt pacing if configured */ | ||
2559 | if (priv->coal_intvl != 0) { | ||
2560 | struct ethtool_coalesce coal; | ||
2561 | |||
2562 | coal.rx_coalesce_usecs = (priv->coal_intvl << 4); | ||
2563 | emac_set_coalesce(ndev, &coal); | ||
2564 | } | ||
2565 | |||
2440 | /* find the first phy */ | 2566 | /* find the first phy */ |
2441 | priv->phydev = NULL; | 2567 | priv->phydev = NULL; |
2442 | if (priv->phy_mask) { | 2568 | if (priv->phy_mask) { |
@@ -2677,6 +2803,9 @@ static int __devinit davinci_emac_probe(struct platform_device *pdev) | |||
2677 | priv->int_enable = pdata->interrupt_enable; | 2803 | priv->int_enable = pdata->interrupt_enable; |
2678 | priv->int_disable = pdata->interrupt_disable; | 2804 | priv->int_disable = pdata->interrupt_disable; |
2679 | 2805 | ||
2806 | priv->coal_intvl = 0; | ||
2807 | priv->bus_freq_mhz = (u32)(emac_bus_frequency / 1000000); | ||
2808 | |||
2680 | emac_dev = &ndev->dev; | 2809 | emac_dev = &ndev->dev; |
2681 | /* Get EMAC platform data */ | 2810 | /* Get EMAC platform data */ |
2682 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 2811 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |