aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/davinci_emac.c133
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 */
720static 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 */
738static 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);