aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFlorian Fainelli <f.fainelli@gmail.com>2018-03-22 21:19:32 -0400
committerDavid S. Miller <davem@davemloft.net>2018-03-25 20:48:25 -0400
commitb6e0e875421ef6debfbe05d3aa99ac788d886074 (patch)
tree6622c4c4151faad1627de5ce223c10e419043fe1
parent9259f134a7dd1372ab142b2860994b993db34917 (diff)
net: systemport: Implement adaptive interrupt coalescing
Implement support for adaptive RX and TX interrupt coalescing using net_dim. We have each of our TX ring and our single RX ring implement a bcm_sysport_net_dim structure which holds an interrupt counter, number of packets, bytes, and a container for a net_dim instance. Signed-off-by: Florian Fainelli <f.fainelli@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/ethernet/broadcom/bcmsysport.c141
-rw-r--r--drivers/net/ethernet/broadcom/bcmsysport.h14
2 files changed, 140 insertions, 15 deletions
diff --git a/drivers/net/ethernet/broadcom/bcmsysport.c b/drivers/net/ethernet/broadcom/bcmsysport.c
index 3fc549b88c43..4e26f606a7f2 100644
--- a/drivers/net/ethernet/broadcom/bcmsysport.c
+++ b/drivers/net/ethernet/broadcom/bcmsysport.c
@@ -15,6 +15,7 @@
15#include <linux/module.h> 15#include <linux/module.h>
16#include <linux/kernel.h> 16#include <linux/kernel.h>
17#include <linux/netdevice.h> 17#include <linux/netdevice.h>
18#include <linux/net_dim.h>
18#include <linux/etherdevice.h> 19#include <linux/etherdevice.h>
19#include <linux/platform_device.h> 20#include <linux/platform_device.h>
20#include <linux/of.h> 21#include <linux/of.h>
@@ -574,21 +575,55 @@ static int bcm_sysport_set_wol(struct net_device *dev,
574 return 0; 575 return 0;
575} 576}
576 577
578static void bcm_sysport_set_rx_coalesce(struct bcm_sysport_priv *priv)
579{
580 u32 reg;
581
582 reg = rdma_readl(priv, RDMA_MBDONE_INTR);
583 reg &= ~(RDMA_INTR_THRESH_MASK |
584 RDMA_TIMEOUT_MASK << RDMA_TIMEOUT_SHIFT);
585 reg |= priv->dim.coal_pkts;
586 reg |= DIV_ROUND_UP(priv->dim.coal_usecs * 1000, 8192) <<
587 RDMA_TIMEOUT_SHIFT;
588 rdma_writel(priv, reg, RDMA_MBDONE_INTR);
589}
590
591static void bcm_sysport_set_tx_coalesce(struct bcm_sysport_tx_ring *ring)
592{
593 struct bcm_sysport_priv *priv = ring->priv;
594 u32 reg;
595
596 reg = tdma_readl(priv, TDMA_DESC_RING_INTR_CONTROL(ring->index));
597 reg &= ~(RING_INTR_THRESH_MASK |
598 RING_TIMEOUT_MASK << RING_TIMEOUT_SHIFT);
599 reg |= ring->dim.coal_pkts;
600 reg |= DIV_ROUND_UP(ring->dim.coal_usecs * 1000, 8192) <<
601 RING_TIMEOUT_SHIFT;
602 tdma_writel(priv, reg, TDMA_DESC_RING_INTR_CONTROL(ring->index));
603}
604
577static int bcm_sysport_get_coalesce(struct net_device *dev, 605static int bcm_sysport_get_coalesce(struct net_device *dev,
578 struct ethtool_coalesce *ec) 606 struct ethtool_coalesce *ec)
579{ 607{
580 struct bcm_sysport_priv *priv = netdev_priv(dev); 608 struct bcm_sysport_priv *priv = netdev_priv(dev);
609 struct bcm_sysport_tx_ring *ring;
610 unsigned int i;
581 u32 reg; 611 u32 reg;
582 612
583 reg = tdma_readl(priv, TDMA_DESC_RING_INTR_CONTROL(0)); 613 reg = tdma_readl(priv, TDMA_DESC_RING_INTR_CONTROL(0));
584 614
585 ec->tx_coalesce_usecs = (reg >> RING_TIMEOUT_SHIFT) * 8192 / 1000; 615 ec->tx_coalesce_usecs = (reg >> RING_TIMEOUT_SHIFT) * 8192 / 1000;
586 ec->tx_max_coalesced_frames = reg & RING_INTR_THRESH_MASK; 616 ec->tx_max_coalesced_frames = reg & RING_INTR_THRESH_MASK;
617 for (i = 0; i < dev->num_tx_queues; i++) {
618 ring = &priv->tx_rings[i];
619 ec->use_adaptive_tx_coalesce |= ring->dim.use_dim;
620 }
587 621
588 reg = rdma_readl(priv, RDMA_MBDONE_INTR); 622 reg = rdma_readl(priv, RDMA_MBDONE_INTR);
589 623
590 ec->rx_coalesce_usecs = (reg >> RDMA_TIMEOUT_SHIFT) * 8192 / 1000; 624 ec->rx_coalesce_usecs = (reg >> RDMA_TIMEOUT_SHIFT) * 8192 / 1000;
591 ec->rx_max_coalesced_frames = reg & RDMA_INTR_THRESH_MASK; 625 ec->rx_max_coalesced_frames = reg & RDMA_INTR_THRESH_MASK;
626 ec->use_adaptive_rx_coalesce = priv->dim.use_dim;
592 627
593 return 0; 628 return 0;
594} 629}
@@ -597,8 +632,8 @@ static int bcm_sysport_set_coalesce(struct net_device *dev,
597 struct ethtool_coalesce *ec) 632 struct ethtool_coalesce *ec)
598{ 633{
599 struct bcm_sysport_priv *priv = netdev_priv(dev); 634 struct bcm_sysport_priv *priv = netdev_priv(dev);
635 struct bcm_sysport_tx_ring *ring;
600 unsigned int i; 636 unsigned int i;
601 u32 reg;
602 637
603 /* Base system clock is 125Mhz, DMA timeout is this reference clock 638 /* Base system clock is 125Mhz, DMA timeout is this reference clock
604 * divided by 1024, which yield roughly 8.192 us, our maximum value has 639 * divided by 1024, which yield roughly 8.192 us, our maximum value has
@@ -615,22 +650,26 @@ static int bcm_sysport_set_coalesce(struct net_device *dev,
615 return -EINVAL; 650 return -EINVAL;
616 651
617 for (i = 0; i < dev->num_tx_queues; i++) { 652 for (i = 0; i < dev->num_tx_queues; i++) {
618 reg = tdma_readl(priv, TDMA_DESC_RING_INTR_CONTROL(i)); 653 ring = &priv->tx_rings[i];
619 reg &= ~(RING_INTR_THRESH_MASK | 654 ring->dim.coal_pkts = ec->tx_max_coalesced_frames;
620 RING_TIMEOUT_MASK << RING_TIMEOUT_SHIFT); 655 ring->dim.coal_usecs = ec->tx_coalesce_usecs;
621 reg |= ec->tx_max_coalesced_frames; 656 if (!ec->use_adaptive_tx_coalesce && ring->dim.use_dim) {
622 reg |= DIV_ROUND_UP(ec->tx_coalesce_usecs * 1000, 8192) << 657 ring->dim.coal_pkts = 1;
623 RING_TIMEOUT_SHIFT; 658 ring->dim.coal_usecs = 0;
624 tdma_writel(priv, reg, TDMA_DESC_RING_INTR_CONTROL(i)); 659 }
660 ring->dim.use_dim = ec->use_adaptive_tx_coalesce;
661 bcm_sysport_set_tx_coalesce(ring);
625 } 662 }
626 663
627 reg = rdma_readl(priv, RDMA_MBDONE_INTR); 664 priv->dim.coal_usecs = ec->rx_coalesce_usecs;
628 reg &= ~(RDMA_INTR_THRESH_MASK | 665 priv->dim.coal_pkts = ec->rx_max_coalesced_frames;
629 RDMA_TIMEOUT_MASK << RDMA_TIMEOUT_SHIFT); 666
630 reg |= ec->rx_max_coalesced_frames; 667 if (!ec->use_adaptive_rx_coalesce && priv->dim.use_dim) {
631 reg |= DIV_ROUND_UP(ec->rx_coalesce_usecs * 1000, 8192) << 668 priv->dim.coal_pkts = 1;
632 RDMA_TIMEOUT_SHIFT; 669 priv->dim.coal_usecs = 0;
633 rdma_writel(priv, reg, RDMA_MBDONE_INTR); 670 }
671 priv->dim.use_dim = ec->use_adaptive_rx_coalesce;
672 bcm_sysport_set_rx_coalesce(priv);
634 673
635 return 0; 674 return 0;
636} 675}
@@ -709,6 +748,7 @@ static unsigned int bcm_sysport_desc_rx(struct bcm_sysport_priv *priv,
709 struct bcm_sysport_stats64 *stats64 = &priv->stats64; 748 struct bcm_sysport_stats64 *stats64 = &priv->stats64;
710 struct net_device *ndev = priv->netdev; 749 struct net_device *ndev = priv->netdev;
711 unsigned int processed = 0, to_process; 750 unsigned int processed = 0, to_process;
751 unsigned int processed_bytes = 0;
712 struct bcm_sysport_cb *cb; 752 struct bcm_sysport_cb *cb;
713 struct sk_buff *skb; 753 struct sk_buff *skb;
714 unsigned int p_index; 754 unsigned int p_index;
@@ -800,6 +840,7 @@ static unsigned int bcm_sysport_desc_rx(struct bcm_sysport_priv *priv,
800 */ 840 */
801 skb_pull(skb, sizeof(*rsb) + 2); 841 skb_pull(skb, sizeof(*rsb) + 2);
802 len -= (sizeof(*rsb) + 2); 842 len -= (sizeof(*rsb) + 2);
843 processed_bytes += len;
803 844
804 /* UniMAC may forward CRC */ 845 /* UniMAC may forward CRC */
805 if (priv->crc_fwd) { 846 if (priv->crc_fwd) {
@@ -824,6 +865,9 @@ next:
824 priv->rx_read_ptr = 0; 865 priv->rx_read_ptr = 0;
825 } 866 }
826 867
868 priv->dim.packets = processed;
869 priv->dim.bytes = processed_bytes;
870
827 return processed; 871 return processed;
828} 872}
829 873
@@ -896,6 +940,8 @@ static unsigned int __bcm_sysport_tx_reclaim(struct bcm_sysport_priv *priv,
896 ring->packets += pkts_compl; 940 ring->packets += pkts_compl;
897 ring->bytes += bytes_compl; 941 ring->bytes += bytes_compl;
898 u64_stats_update_end(&priv->syncp); 942 u64_stats_update_end(&priv->syncp);
943 ring->dim.packets = pkts_compl;
944 ring->dim.bytes = bytes_compl;
899 945
900 ring->c_index = c_index; 946 ring->c_index = c_index;
901 947
@@ -941,6 +987,7 @@ static int bcm_sysport_tx_poll(struct napi_struct *napi, int budget)
941{ 987{
942 struct bcm_sysport_tx_ring *ring = 988 struct bcm_sysport_tx_ring *ring =
943 container_of(napi, struct bcm_sysport_tx_ring, napi); 989 container_of(napi, struct bcm_sysport_tx_ring, napi);
990 struct net_dim_sample dim_sample;
944 unsigned int work_done = 0; 991 unsigned int work_done = 0;
945 992
946 work_done = bcm_sysport_tx_reclaim(ring->priv, ring); 993 work_done = bcm_sysport_tx_reclaim(ring->priv, ring);
@@ -957,6 +1004,12 @@ static int bcm_sysport_tx_poll(struct napi_struct *napi, int budget)
957 return 0; 1004 return 0;
958 } 1005 }
959 1006
1007 if (ring->dim.use_dim) {
1008 net_dim_sample(ring->dim.event_ctr, ring->dim.packets,
1009 ring->dim.bytes, &dim_sample);
1010 net_dim(&ring->dim.dim, dim_sample);
1011 }
1012
960 return budget; 1013 return budget;
961} 1014}
962 1015
@@ -972,6 +1025,7 @@ static int bcm_sysport_poll(struct napi_struct *napi, int budget)
972{ 1025{
973 struct bcm_sysport_priv *priv = 1026 struct bcm_sysport_priv *priv =
974 container_of(napi, struct bcm_sysport_priv, napi); 1027 container_of(napi, struct bcm_sysport_priv, napi);
1028 struct net_dim_sample dim_sample;
975 unsigned int work_done = 0; 1029 unsigned int work_done = 0;
976 1030
977 work_done = bcm_sysport_desc_rx(priv, budget); 1031 work_done = bcm_sysport_desc_rx(priv, budget);
@@ -994,6 +1048,12 @@ static int bcm_sysport_poll(struct napi_struct *napi, int budget)
994 intrl2_0_mask_clear(priv, INTRL2_0_RDMA_MBDONE); 1048 intrl2_0_mask_clear(priv, INTRL2_0_RDMA_MBDONE);
995 } 1049 }
996 1050
1051 if (priv->dim.use_dim) {
1052 net_dim_sample(priv->dim.event_ctr, priv->dim.packets,
1053 priv->dim.bytes, &dim_sample);
1054 net_dim(&priv->dim.dim, dim_sample);
1055 }
1056
997 return work_done; 1057 return work_done;
998} 1058}
999 1059
@@ -1012,6 +1072,40 @@ static void bcm_sysport_resume_from_wol(struct bcm_sysport_priv *priv)
1012 netif_dbg(priv, wol, priv->netdev, "resumed from WOL\n"); 1072 netif_dbg(priv, wol, priv->netdev, "resumed from WOL\n");
1013} 1073}
1014 1074
1075static void bcm_sysport_dim_work(struct work_struct *work)
1076{
1077 struct net_dim *dim = container_of(work, struct net_dim, work);
1078 struct bcm_sysport_net_dim *ndim =
1079 container_of(dim, struct bcm_sysport_net_dim, dim);
1080 struct bcm_sysport_priv *priv =
1081 container_of(ndim, struct bcm_sysport_priv, dim);
1082 struct net_dim_cq_moder cur_profile =
1083 net_dim_get_profile(dim->mode, dim->profile_ix);
1084
1085 priv->dim.coal_usecs = cur_profile.usec;
1086 priv->dim.coal_pkts = cur_profile.pkts;
1087
1088 bcm_sysport_set_rx_coalesce(priv);
1089 dim->state = NET_DIM_START_MEASURE;
1090}
1091
1092static void bcm_sysport_dim_tx_work(struct work_struct *work)
1093{
1094 struct net_dim *dim = container_of(work, struct net_dim, work);
1095 struct bcm_sysport_net_dim *ndim =
1096 container_of(dim, struct bcm_sysport_net_dim, dim);
1097 struct bcm_sysport_tx_ring *ring =
1098 container_of(ndim, struct bcm_sysport_tx_ring, dim);
1099 struct net_dim_cq_moder cur_profile =
1100 net_dim_get_profile(dim->mode, dim->profile_ix);
1101
1102 ring->dim.coal_usecs = cur_profile.usec;
1103 ring->dim.coal_pkts = cur_profile.pkts;
1104
1105 bcm_sysport_set_tx_coalesce(ring);
1106 dim->state = NET_DIM_START_MEASURE;
1107}
1108
1015/* RX and misc interrupt routine */ 1109/* RX and misc interrupt routine */
1016static irqreturn_t bcm_sysport_rx_isr(int irq, void *dev_id) 1110static irqreturn_t bcm_sysport_rx_isr(int irq, void *dev_id)
1017{ 1111{
@@ -1030,6 +1124,7 @@ static irqreturn_t bcm_sysport_rx_isr(int irq, void *dev_id)
1030 } 1124 }
1031 1125
1032 if (priv->irq0_stat & INTRL2_0_RDMA_MBDONE) { 1126 if (priv->irq0_stat & INTRL2_0_RDMA_MBDONE) {
1127 priv->dim.event_ctr++;
1033 if (likely(napi_schedule_prep(&priv->napi))) { 1128 if (likely(napi_schedule_prep(&priv->napi))) {
1034 /* disable RX interrupts */ 1129 /* disable RX interrupts */
1035 intrl2_0_mask_set(priv, INTRL2_0_RDMA_MBDONE); 1130 intrl2_0_mask_set(priv, INTRL2_0_RDMA_MBDONE);
@@ -1057,6 +1152,7 @@ static irqreturn_t bcm_sysport_rx_isr(int irq, void *dev_id)
1057 continue; 1152 continue;
1058 1153
1059 txr = &priv->tx_rings[ring]; 1154 txr = &priv->tx_rings[ring];
1155 txr->dim.event_ctr++;
1060 1156
1061 if (likely(napi_schedule_prep(&txr->napi))) { 1157 if (likely(napi_schedule_prep(&txr->napi))) {
1062 intrl2_0_mask_set(priv, ring_bit); 1158 intrl2_0_mask_set(priv, ring_bit);
@@ -1089,6 +1185,7 @@ static irqreturn_t bcm_sysport_tx_isr(int irq, void *dev_id)
1089 continue; 1185 continue;
1090 1186
1091 txr = &priv->tx_rings[ring]; 1187 txr = &priv->tx_rings[ring];
1188 txr->dim.event_ctr++;
1092 1189
1093 if (likely(napi_schedule_prep(&txr->napi))) { 1190 if (likely(napi_schedule_prep(&txr->napi))) {
1094 intrl2_1_mask_set(priv, BIT(ring)); 1191 intrl2_1_mask_set(priv, BIT(ring));
@@ -1354,6 +1451,16 @@ out:
1354 phy_print_status(phydev); 1451 phy_print_status(phydev);
1355} 1452}
1356 1453
1454static void bcm_sysport_init_dim(struct bcm_sysport_net_dim *dim,
1455 void (*cb)(struct work_struct *work))
1456{
1457 INIT_WORK(&dim->dim.work, cb);
1458 dim->dim.mode = NET_DIM_CQ_PERIOD_MODE_START_FROM_EQE;
1459 dim->event_ctr = 0;
1460 dim->packets = 0;
1461 dim->bytes = 0;
1462}
1463
1357static int bcm_sysport_init_tx_ring(struct bcm_sysport_priv *priv, 1464static int bcm_sysport_init_tx_ring(struct bcm_sysport_priv *priv,
1358 unsigned int index) 1465 unsigned int index)
1359{ 1466{
@@ -1444,6 +1551,7 @@ static int bcm_sysport_init_tx_ring(struct bcm_sysport_priv *priv,
1444 reg |= (1 << index); 1551 reg |= (1 << index);
1445 tdma_writel(priv, reg, TDMA_TIER1_ARB_0_QUEUE_EN); 1552 tdma_writel(priv, reg, TDMA_TIER1_ARB_0_QUEUE_EN);
1446 1553
1554 bcm_sysport_init_dim(&ring->dim, bcm_sysport_dim_tx_work);
1447 napi_enable(&ring->napi); 1555 napi_enable(&ring->napi);
1448 1556
1449 netif_dbg(priv, hw, priv->netdev, 1557 netif_dbg(priv, hw, priv->netdev,
@@ -1474,6 +1582,7 @@ static void bcm_sysport_fini_tx_ring(struct bcm_sysport_priv *priv,
1474 return; 1582 return;
1475 1583
1476 napi_disable(&ring->napi); 1584 napi_disable(&ring->napi);
1585 cancel_work_sync(&ring->dim.dim.work);
1477 netif_napi_del(&ring->napi); 1586 netif_napi_del(&ring->napi);
1478 1587
1479 bcm_sysport_tx_clean(priv, ring); 1588 bcm_sysport_tx_clean(priv, ring);
@@ -1763,6 +1872,7 @@ static void bcm_sysport_netif_start(struct net_device *dev)
1763 struct bcm_sysport_priv *priv = netdev_priv(dev); 1872 struct bcm_sysport_priv *priv = netdev_priv(dev);
1764 1873
1765 /* Enable NAPI */ 1874 /* Enable NAPI */
1875 bcm_sysport_init_dim(&priv->dim, bcm_sysport_dim_work);
1766 napi_enable(&priv->napi); 1876 napi_enable(&priv->napi);
1767 1877
1768 /* Enable RX interrupt and TX ring full interrupt */ 1878 /* Enable RX interrupt and TX ring full interrupt */
@@ -1948,6 +2058,7 @@ static void bcm_sysport_netif_stop(struct net_device *dev)
1948 /* stop all software from updating hardware */ 2058 /* stop all software from updating hardware */
1949 netif_tx_stop_all_queues(dev); 2059 netif_tx_stop_all_queues(dev);
1950 napi_disable(&priv->napi); 2060 napi_disable(&priv->napi);
2061 cancel_work_sync(&priv->dim.dim.work);
1951 phy_stop(dev->phydev); 2062 phy_stop(dev->phydev);
1952 2063
1953 /* mask all interrupts */ 2064 /* mask all interrupts */
diff --git a/drivers/net/ethernet/broadcom/bcmsysport.h b/drivers/net/ethernet/broadcom/bcmsysport.h
index 19c91c76e327..e1c97d4a82b4 100644
--- a/drivers/net/ethernet/broadcom/bcmsysport.h
+++ b/drivers/net/ethernet/broadcom/bcmsysport.h
@@ -12,6 +12,7 @@
12#define __BCM_SYSPORT_H 12#define __BCM_SYSPORT_H
13 13
14#include <linux/if_vlan.h> 14#include <linux/if_vlan.h>
15#include <linux/net_dim.h>
15 16
16/* Receive/transmit descriptor format */ 17/* Receive/transmit descriptor format */
17#define DESC_ADDR_HI_STATUS_LEN 0x00 18#define DESC_ADDR_HI_STATUS_LEN 0x00
@@ -695,6 +696,16 @@ struct bcm_sysport_hw_params {
695 unsigned int num_rx_desc_words; 696 unsigned int num_rx_desc_words;
696}; 697};
697 698
699struct bcm_sysport_net_dim {
700 u16 use_dim;
701 u16 event_ctr;
702 unsigned long packets;
703 unsigned long bytes;
704 u32 coal_usecs;
705 u32 coal_pkts;
706 struct net_dim dim;
707};
708
698/* Software view of the TX ring */ 709/* Software view of the TX ring */
699struct bcm_sysport_tx_ring { 710struct bcm_sysport_tx_ring {
700 spinlock_t lock; /* Ring lock for tx reclaim/xmit */ 711 spinlock_t lock; /* Ring lock for tx reclaim/xmit */
@@ -712,6 +723,7 @@ struct bcm_sysport_tx_ring {
712 struct bcm_sysport_priv *priv; /* private context backpointer */ 723 struct bcm_sysport_priv *priv; /* private context backpointer */
713 unsigned long packets; /* packets statistics */ 724 unsigned long packets; /* packets statistics */
714 unsigned long bytes; /* bytes statistics */ 725 unsigned long bytes; /* bytes statistics */
726 struct bcm_sysport_net_dim dim; /* Net DIM context */
715 unsigned int switch_queue; /* switch port queue number */ 727 unsigned int switch_queue; /* switch port queue number */
716 unsigned int switch_port; /* switch port queue number */ 728 unsigned int switch_port; /* switch port queue number */
717 bool inspect; /* inspect switch port and queue */ 729 bool inspect; /* inspect switch port and queue */
@@ -743,6 +755,8 @@ struct bcm_sysport_priv {
743 unsigned int rx_read_ptr; 755 unsigned int rx_read_ptr;
744 unsigned int rx_c_index; 756 unsigned int rx_c_index;
745 757
758 struct bcm_sysport_net_dim dim;
759
746 /* PHY device */ 760 /* PHY device */
747 struct device_node *phy_dn; 761 struct device_node *phy_dn;
748 phy_interface_t phy_interface; 762 phy_interface_t phy_interface;