aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/skge.c
diff options
context:
space:
mode:
authorStephen Hemminger <shemminger@linux-foundation.org>2007-02-23 17:03:00 -0500
committerJeff Garzik <jeff@garzik.org>2007-02-27 04:16:04 -0500
commitc4cd29d2058808b7a68e3f2e6cbbcfe19ca7233d (patch)
tree36a0139a9ab4df2e7b63f20d3a1184f638a5db81 /drivers/net/skge.c
parent9dc6f0e789ac8cdd4a7912a9c27027d937a6e784 (diff)
skge: fix transmitter flow control
It looks like the skge driver inherited another bug from the sk98lin code. If I send from 1000mbit port to a machine on 100mbit port, the switch should be doing hardware flow control, but no pause frames show up in the statistics. This is the analog of the recent sky2 fixes. The device needs to listen for multicast pause frames and then not discard them. Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org> Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers/net/skge.c')
-rw-r--r--drivers/net/skge.c43
1 files changed, 32 insertions, 11 deletions
diff --git a/drivers/net/skge.c b/drivers/net/skge.c
index c3d2e0a2c4e6..f59f37aaccec 100644
--- a/drivers/net/skge.c
+++ b/drivers/net/skge.c
@@ -2767,6 +2767,17 @@ static int skge_change_mtu(struct net_device *dev, int new_mtu)
2767 return err; 2767 return err;
2768} 2768}
2769 2769
2770static const u8 pause_mc_addr[ETH_ALEN] = { 0x1, 0x80, 0xc2, 0x0, 0x0, 0x1 };
2771
2772static void genesis_add_filter(u8 filter[8], const u8 *addr)
2773{
2774 u32 crc, bit;
2775
2776 crc = ether_crc_le(ETH_ALEN, addr);
2777 bit = ~crc & 0x3f;
2778 filter[bit/8] |= 1 << (bit%8);
2779}
2780
2770static void genesis_set_multicast(struct net_device *dev) 2781static void genesis_set_multicast(struct net_device *dev)
2771{ 2782{
2772 struct skge_port *skge = netdev_priv(dev); 2783 struct skge_port *skge = netdev_priv(dev);
@@ -2788,24 +2799,33 @@ static void genesis_set_multicast(struct net_device *dev)
2788 memset(filter, 0xff, sizeof(filter)); 2799 memset(filter, 0xff, sizeof(filter));
2789 else { 2800 else {
2790 memset(filter, 0, sizeof(filter)); 2801 memset(filter, 0, sizeof(filter));
2791 for (i = 0; list && i < count; i++, list = list->next) { 2802
2792 u32 crc, bit; 2803 if (skge->flow_status == FLOW_STAT_REM_SEND
2793 crc = ether_crc_le(ETH_ALEN, list->dmi_addr); 2804 || skge->flow_status == FLOW_STAT_SYMMETRIC)
2794 bit = ~crc & 0x3f; 2805 genesis_add_filter(filter, pause_mc_addr);
2795 filter[bit/8] |= 1 << (bit%8); 2806
2796 } 2807 for (i = 0; list && i < count; i++, list = list->next)
2808 genesis_add_filter(filter, list->dmi_addr);
2797 } 2809 }
2798 2810
2799 xm_write32(hw, port, XM_MODE, mode); 2811 xm_write32(hw, port, XM_MODE, mode);
2800 xm_outhash(hw, port, XM_HSM, filter); 2812 xm_outhash(hw, port, XM_HSM, filter);
2801} 2813}
2802 2814
2815static void yukon_add_filter(u8 filter[8], const u8 *addr)
2816{
2817 u32 bit = ether_crc(ETH_ALEN, addr) & 0x3f;
2818 filter[bit/8] |= 1 << (bit%8);
2819}
2820
2803static void yukon_set_multicast(struct net_device *dev) 2821static void yukon_set_multicast(struct net_device *dev)
2804{ 2822{
2805 struct skge_port *skge = netdev_priv(dev); 2823 struct skge_port *skge = netdev_priv(dev);
2806 struct skge_hw *hw = skge->hw; 2824 struct skge_hw *hw = skge->hw;
2807 int port = skge->port; 2825 int port = skge->port;
2808 struct dev_mc_list *list = dev->mc_list; 2826 struct dev_mc_list *list = dev->mc_list;
2827 int rx_pause = (skge->flow_status == FLOW_STAT_REM_SEND
2828 || skge->flow_status == FLOW_STAT_SYMMETRIC);
2809 u16 reg; 2829 u16 reg;
2810 u8 filter[8]; 2830 u8 filter[8];
2811 2831
@@ -2818,16 +2838,17 @@ static void yukon_set_multicast(struct net_device *dev)
2818 reg &= ~(GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA); 2838 reg &= ~(GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA);
2819 else if (dev->flags & IFF_ALLMULTI) /* all multicast */ 2839 else if (dev->flags & IFF_ALLMULTI) /* all multicast */
2820 memset(filter, 0xff, sizeof(filter)); 2840 memset(filter, 0xff, sizeof(filter));
2821 else if (dev->mc_count == 0) /* no multicast */ 2841 else if (dev->mc_count == 0 && !rx_pause)/* no multicast */
2822 reg &= ~GM_RXCR_MCF_ENA; 2842 reg &= ~GM_RXCR_MCF_ENA;
2823 else { 2843 else {
2824 int i; 2844 int i;
2825 reg |= GM_RXCR_MCF_ENA; 2845 reg |= GM_RXCR_MCF_ENA;
2826 2846
2827 for (i = 0; list && i < dev->mc_count; i++, list = list->next) { 2847 if (rx_pause)
2828 u32 bit = ether_crc(ETH_ALEN, list->dmi_addr) & 0x3f; 2848 yukon_add_filter(filter, pause_mc_addr);
2829 filter[bit/8] |= 1 << (bit%8); 2849
2830 } 2850 for (i = 0; list && i < dev->mc_count; i++, list = list->next)
2851 yukon_add_filter(filter, list->dmi_addr);
2831 } 2852 }
2832 2853
2833 2854