diff options
author | Lennert Buytenhek <buytenh@wantstofly.org> | 2008-06-01 18:51:05 -0400 |
---|---|---|
committer | Lennert Buytenhek <buytenh@wantstofly.org> | 2008-06-12 02:40:36 -0400 |
commit | 89df5fdc5290681e17b8755675c59ed9607a487a (patch) | |
tree | 5a1885f872a59ca525aef8c0a7bfdad6555fe248 /drivers | |
parent | fc32b0e28df6655a15b488aaddfc1339f82dc13a (diff) |
mv643xx_eth: add tx rate control
Add an interface for the hardware's per-port and per-subqueue
TX rate control. In this stage, this is mainly so that we can
disable the bandwidth limits during initialisation of the port.
Signed-off-by: Lennert Buytenhek <buytenh@marvell.com>
Acked-by: Dale Farnsworth <dale@farnsworth.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/mv643xx_eth.c | 104 |
1 files changed, 103 insertions, 1 deletions
diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index cf18419f96ab..9ce7be09e295 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c | |||
@@ -91,7 +91,10 @@ static char mv643xx_eth_driver_version[] = "1.0"; | |||
91 | #define PORT_STATUS(p) (0x0444 + ((p) << 10)) | 91 | #define PORT_STATUS(p) (0x0444 + ((p) << 10)) |
92 | #define TX_FIFO_EMPTY 0x00000400 | 92 | #define TX_FIFO_EMPTY 0x00000400 |
93 | #define TXQ_COMMAND(p) (0x0448 + ((p) << 10)) | 93 | #define TXQ_COMMAND(p) (0x0448 + ((p) << 10)) |
94 | #define TXQ_FIX_PRIO_CONF(p) (0x044c + ((p) << 10)) | ||
95 | #define TX_BW_RATE(p) (0x0450 + ((p) << 10)) | ||
94 | #define TX_BW_MTU(p) (0x0458 + ((p) << 10)) | 96 | #define TX_BW_MTU(p) (0x0458 + ((p) << 10)) |
97 | #define TX_BW_BURST(p) (0x045c + ((p) << 10)) | ||
95 | #define INT_CAUSE(p) (0x0460 + ((p) << 10)) | 98 | #define INT_CAUSE(p) (0x0460 + ((p) << 10)) |
96 | #define INT_RX 0x00000804 | 99 | #define INT_RX 0x00000804 |
97 | #define INT_EXT 0x00000002 | 100 | #define INT_EXT 0x00000002 |
@@ -107,6 +110,9 @@ static char mv643xx_eth_driver_version[] = "1.0"; | |||
107 | #define RXQ_CURRENT_DESC_PTR(p) (0x060c + ((p) << 10)) | 110 | #define RXQ_CURRENT_DESC_PTR(p) (0x060c + ((p) << 10)) |
108 | #define RXQ_COMMAND(p) (0x0680 + ((p) << 10)) | 111 | #define RXQ_COMMAND(p) (0x0680 + ((p) << 10)) |
109 | #define TXQ_CURRENT_DESC_PTR(p) (0x06c0 + ((p) << 10)) | 112 | #define TXQ_CURRENT_DESC_PTR(p) (0x06c0 + ((p) << 10)) |
113 | #define TXQ_BW_TOKENS(p) (0x0700 + ((p) << 10)) | ||
114 | #define TXQ_BW_CONF(p) (0x0704 + ((p) << 10)) | ||
115 | #define TXQ_BW_WRR_CONF(p) (0x0708 + ((p) << 10)) | ||
110 | #define MIB_COUNTERS(p) (0x1000 + ((p) << 7)) | 116 | #define MIB_COUNTERS(p) (0x1000 + ((p) << 7)) |
111 | #define SPECIAL_MCAST_TABLE(p) (0x1400 + ((p) << 10)) | 117 | #define SPECIAL_MCAST_TABLE(p) (0x1400 + ((p) << 10)) |
112 | #define OTHER_MCAST_TABLE(p) (0x1500 + ((p) << 10)) | 118 | #define OTHER_MCAST_TABLE(p) (0x1500 + ((p) << 10)) |
@@ -775,6 +781,95 @@ static int mv643xx_eth_xmit(struct sk_buff *skb, struct net_device *dev) | |||
775 | } | 781 | } |
776 | 782 | ||
777 | 783 | ||
784 | /* tx rate control **********************************************************/ | ||
785 | /* | ||
786 | * Set total maximum TX rate (shared by all TX queues for this port) | ||
787 | * to 'rate' bits per second, with a maximum burst of 'burst' bytes. | ||
788 | */ | ||
789 | static void tx_set_rate(struct mv643xx_eth_private *mp, int rate, int burst) | ||
790 | { | ||
791 | int token_rate; | ||
792 | int mtu; | ||
793 | int bucket_size; | ||
794 | |||
795 | token_rate = ((rate / 1000) * 64) / (mp->shared->t_clk / 1000); | ||
796 | if (token_rate > 1023) | ||
797 | token_rate = 1023; | ||
798 | |||
799 | mtu = (mp->dev->mtu + 255) >> 8; | ||
800 | if (mtu > 63) | ||
801 | mtu = 63; | ||
802 | |||
803 | bucket_size = (burst + 255) >> 8; | ||
804 | if (bucket_size > 65535) | ||
805 | bucket_size = 65535; | ||
806 | |||
807 | wrl(mp, TX_BW_RATE(mp->port_num), token_rate); | ||
808 | wrl(mp, TX_BW_MTU(mp->port_num), mtu); | ||
809 | wrl(mp, TX_BW_BURST(mp->port_num), bucket_size); | ||
810 | } | ||
811 | |||
812 | static void txq_set_rate(struct tx_queue *txq, int rate, int burst) | ||
813 | { | ||
814 | struct mv643xx_eth_private *mp = txq_to_mp(txq); | ||
815 | int token_rate; | ||
816 | int bucket_size; | ||
817 | |||
818 | token_rate = ((rate / 1000) * 64) / (mp->shared->t_clk / 1000); | ||
819 | if (token_rate > 1023) | ||
820 | token_rate = 1023; | ||
821 | |||
822 | bucket_size = (burst + 255) >> 8; | ||
823 | if (bucket_size > 65535) | ||
824 | bucket_size = 65535; | ||
825 | |||
826 | wrl(mp, TXQ_BW_TOKENS(mp->port_num), token_rate << 14); | ||
827 | wrl(mp, TXQ_BW_CONF(mp->port_num), | ||
828 | (bucket_size << 10) | token_rate); | ||
829 | } | ||
830 | |||
831 | static void txq_set_fixed_prio_mode(struct tx_queue *txq) | ||
832 | { | ||
833 | struct mv643xx_eth_private *mp = txq_to_mp(txq); | ||
834 | int off; | ||
835 | u32 val; | ||
836 | |||
837 | /* | ||
838 | * Turn on fixed priority mode. | ||
839 | */ | ||
840 | off = TXQ_FIX_PRIO_CONF(mp->port_num); | ||
841 | |||
842 | val = rdl(mp, off); | ||
843 | val |= 1; | ||
844 | wrl(mp, off, val); | ||
845 | } | ||
846 | |||
847 | static void txq_set_wrr(struct tx_queue *txq, int weight) | ||
848 | { | ||
849 | struct mv643xx_eth_private *mp = txq_to_mp(txq); | ||
850 | int off; | ||
851 | u32 val; | ||
852 | |||
853 | /* | ||
854 | * Turn off fixed priority mode. | ||
855 | */ | ||
856 | off = TXQ_FIX_PRIO_CONF(mp->port_num); | ||
857 | |||
858 | val = rdl(mp, off); | ||
859 | val &= ~1; | ||
860 | wrl(mp, off, val); | ||
861 | |||
862 | /* | ||
863 | * Configure WRR weight for this queue. | ||
864 | */ | ||
865 | off = TXQ_BW_WRR_CONF(mp->port_num); | ||
866 | |||
867 | val = rdl(mp, off); | ||
868 | val = (val & ~0xff) | (weight & 0xff); | ||
869 | wrl(mp, off, val); | ||
870 | } | ||
871 | |||
872 | |||
778 | /* mii management interface *************************************************/ | 873 | /* mii management interface *************************************************/ |
779 | #define SMI_BUSY 0x10000000 | 874 | #define SMI_BUSY 0x10000000 |
780 | #define SMI_READ_VALID 0x08000000 | 875 | #define SMI_READ_VALID 0x08000000 |
@@ -1581,7 +1676,7 @@ static void port_start(struct mv643xx_eth_private *mp) | |||
1581 | /* | 1676 | /* |
1582 | * Configure TX path and queues. | 1677 | * Configure TX path and queues. |
1583 | */ | 1678 | */ |
1584 | wrl(mp, TX_BW_MTU(mp->port_num), 0); | 1679 | tx_set_rate(mp, 1000000000, 16777216); |
1585 | for (i = 0; i < 1; i++) { | 1680 | for (i = 0; i < 1; i++) { |
1586 | struct tx_queue *txq = mp->txq; | 1681 | struct tx_queue *txq = mp->txq; |
1587 | int off = TXQ_CURRENT_DESC_PTR(mp->port_num); | 1682 | int off = TXQ_CURRENT_DESC_PTR(mp->port_num); |
@@ -1590,6 +1685,9 @@ static void port_start(struct mv643xx_eth_private *mp) | |||
1590 | addr = (u32)txq->tx_desc_dma; | 1685 | addr = (u32)txq->tx_desc_dma; |
1591 | addr += txq->tx_curr_desc * sizeof(struct tx_desc); | 1686 | addr += txq->tx_curr_desc * sizeof(struct tx_desc); |
1592 | wrl(mp, off, addr); | 1687 | wrl(mp, off, addr); |
1688 | |||
1689 | txq_set_rate(txq, 1000000000, 16777216); | ||
1690 | txq_set_fixed_prio_mode(txq); | ||
1593 | } | 1691 | } |
1594 | 1692 | ||
1595 | /* | 1693 | /* |
@@ -1749,10 +1847,14 @@ static int mv643xx_eth_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) | |||
1749 | 1847 | ||
1750 | static int mv643xx_eth_change_mtu(struct net_device *dev, int new_mtu) | 1848 | static int mv643xx_eth_change_mtu(struct net_device *dev, int new_mtu) |
1751 | { | 1849 | { |
1850 | struct mv643xx_eth_private *mp = netdev_priv(dev); | ||
1851 | |||
1752 | if (new_mtu < 64 || new_mtu > 9500) | 1852 | if (new_mtu < 64 || new_mtu > 9500) |
1753 | return -EINVAL; | 1853 | return -EINVAL; |
1754 | 1854 | ||
1755 | dev->mtu = new_mtu; | 1855 | dev->mtu = new_mtu; |
1856 | tx_set_rate(mp, 1000000000, 16777216); | ||
1857 | |||
1756 | if (!netif_running(dev)) | 1858 | if (!netif_running(dev)) |
1757 | return 0; | 1859 | return 0; |
1758 | 1860 | ||