aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/virtio_net.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/virtio_net.c')
-rw-r--r--drivers/net/virtio_net.c55
1 files changed, 47 insertions, 8 deletions
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 1abea9dc6f0f..daab9c9b0a40 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -37,7 +37,7 @@ module_param(gso, bool, 0444);
37#define MAX_PACKET_LEN (ETH_HLEN + VLAN_HLEN + ETH_DATA_LEN) 37#define MAX_PACKET_LEN (ETH_HLEN + VLAN_HLEN + ETH_DATA_LEN)
38#define GOOD_COPY_LEN 128 38#define GOOD_COPY_LEN 128
39 39
40#define VIRTNET_SEND_COMMAND_SG_MAX 1 40#define VIRTNET_SEND_COMMAND_SG_MAX 2
41 41
42struct virtnet_info 42struct virtnet_info
43{ 43{
@@ -661,31 +661,70 @@ static int virtnet_set_tx_csum(struct net_device *dev, u32 data)
661static void virtnet_set_rx_mode(struct net_device *dev) 661static void virtnet_set_rx_mode(struct net_device *dev)
662{ 662{
663 struct virtnet_info *vi = netdev_priv(dev); 663 struct virtnet_info *vi = netdev_priv(dev);
664 struct scatterlist sg; 664 struct scatterlist sg[2];
665 u8 promisc, allmulti; 665 u8 promisc, allmulti;
666 struct virtio_net_ctrl_mac *mac_data;
667 struct dev_addr_list *addr;
668 void *buf;
669 int i;
666 670
667 /* We can't dynamicaly set ndo_set_rx_mode, so return gracefully */ 671 /* We can't dynamicaly set ndo_set_rx_mode, so return gracefully */
668 if (!virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_RX)) 672 if (!virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_RX))
669 return; 673 return;
670 674
671 promisc = ((dev->flags & IFF_PROMISC) != 0 || dev->uc_count > 0); 675 promisc = ((dev->flags & IFF_PROMISC) != 0);
672 allmulti = ((dev->flags & IFF_ALLMULTI) != 0 || dev->mc_count > 0); 676 allmulti = ((dev->flags & IFF_ALLMULTI) != 0);
673 677
674 sg_set_buf(&sg, &promisc, sizeof(promisc)); 678 sg_set_buf(sg, &promisc, sizeof(promisc));
675 679
676 if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_RX, 680 if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_RX,
677 VIRTIO_NET_CTRL_RX_PROMISC, 681 VIRTIO_NET_CTRL_RX_PROMISC,
678 &sg, 1, 0)) 682 sg, 1, 0))
679 dev_warn(&dev->dev, "Failed to %sable promisc mode.\n", 683 dev_warn(&dev->dev, "Failed to %sable promisc mode.\n",
680 promisc ? "en" : "dis"); 684 promisc ? "en" : "dis");
681 685
682 sg_set_buf(&sg, &allmulti, sizeof(allmulti)); 686 sg_set_buf(sg, &allmulti, sizeof(allmulti));
683 687
684 if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_RX, 688 if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_RX,
685 VIRTIO_NET_CTRL_RX_ALLMULTI, 689 VIRTIO_NET_CTRL_RX_ALLMULTI,
686 &sg, 1, 0)) 690 sg, 1, 0))
687 dev_warn(&dev->dev, "Failed to %sable allmulti mode.\n", 691 dev_warn(&dev->dev, "Failed to %sable allmulti mode.\n",
688 allmulti ? "en" : "dis"); 692 allmulti ? "en" : "dis");
693
694 /* MAC filter - use one buffer for both lists */
695 mac_data = buf = kzalloc(((dev->uc_count + dev->mc_count) * ETH_ALEN) +
696 (2 * sizeof(mac_data->entries)), GFP_ATOMIC);
697 if (!buf) {
698 dev_warn(&dev->dev, "No memory for MAC address buffer\n");
699 return;
700 }
701
702 /* Store the unicast list and count in the front of the buffer */
703 mac_data->entries = dev->uc_count;
704 addr = dev->uc_list;
705 for (i = 0; i < dev->uc_count; i++, addr = addr->next)
706 memcpy(&mac_data->macs[i][0], addr->da_addr, ETH_ALEN);
707
708 sg_set_buf(&sg[0], mac_data,
709 sizeof(mac_data->entries) + (dev->uc_count * ETH_ALEN));
710
711 /* multicast list and count fill the end */
712 mac_data = (void *)&mac_data->macs[dev->uc_count][0];
713
714 mac_data->entries = dev->mc_count;
715 addr = dev->mc_list;
716 for (i = 0; i < dev->mc_count; i++, addr = addr->next)
717 memcpy(&mac_data->macs[i][0], addr->da_addr, ETH_ALEN);
718
719 sg_set_buf(&sg[1], mac_data,
720 sizeof(mac_data->entries) + (dev->mc_count * ETH_ALEN));
721
722 if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_MAC,
723 VIRTIO_NET_CTRL_MAC_TABLE_SET,
724 sg, 2, 0))
725 dev_warn(&dev->dev, "Failed to set MAC fitler table.\n");
726
727 kfree(buf);
689} 728}
690 729
691static struct ethtool_ops virtnet_ethtool_ops = { 730static struct ethtool_ops virtnet_ethtool_ops = {