aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSriram <srk@ti.com>2010-07-28 22:33:58 -0400
committerDavid S. Miller <davem@davemloft.net>2010-07-31 02:55:36 -0400
commit84da2658a619c2d96fae6741580879cc6d7a4cd1 (patch)
tree0973faa5e5c189f5906f8c5408f234f59b94e398
parent3a7fda06ba48e97650fe44ea8e8a7cc385e1c100 (diff)
TI DaVinci EMAC : Implement interrupt pacing functionality.
DaVinci EMAC module includes an interrupt pacing block that can be programmed to throttle the rate at which interrupts are generated. This patch implements interrupt pacing logic that can be controlled through the ethtool interface(only rx_coalesce_usecs param is honored) Signed-off-by: Sriramakrishnan <srk@ti.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-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);