diff options
| author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-07-20 20:35:25 -0400 | 
|---|---|---|
| committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-07-20 20:35:25 -0400 | 
| commit | c2e68052429fdf87702fccd272951282bef1c60a (patch) | |
| tree | b9f3bf3918526af068ed264190a85fb18dd3d8b0 /drivers/net/sunvnet.c | |
| parent | d6f410bdbcb435c744c4f8259d6659ae2c6e447a (diff) | |
| parent | 1256efd5519a8eca2dfa6039ce5cf58f44d1626d (diff) | |
Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/sparc-2.6
* 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/sparc-2.6:
  [SPARC64]: fix section mismatch warning in mdesc.c
  [SPARC64]: fix section mismatch warning in pci_sunv4
  [SPARC64]: Stop using drivers/char/rtc.c
  [SPARC64]: Convert parport to of_platform_driver.
  [SPARC]: Implement fb_is_primary_device().
  [SPARC64]: Fix virq decomposition.
  [SPARC64]: Use KERN_ERR in IRQ manipulation error printks.
  [SPARC64]: Do not flood log with failed DS messages.
  [SPARC64]: Add proper multicast support to VNET driver.
  [SPARC64]: Handle multiple domain-services-port nodes properly.
  [SPARC64]: Improve VIO device naming further.
  [SPARC]: Make sure dev_archdata is filled in for all devices.
  [SPARC]: Define minimal struct dev_archdata, similarly to sparc64.
  [SPARC]: Fix serial console device detection.
Diffstat (limited to 'drivers/net/sunvnet.c')
| -rw-r--r-- | drivers/net/sunvnet.c | 137 | 
1 files changed, 135 insertions, 2 deletions
diff --git a/drivers/net/sunvnet.c b/drivers/net/sunvnet.c index ef0066bab2cf..61f98251feab 100644 --- a/drivers/net/sunvnet.c +++ b/drivers/net/sunvnet.c  | |||
| @@ -459,6 +459,22 @@ static int vnet_nack(struct vnet_port *port, void *msgbuf) | |||
| 459 | return 0; | 459 | return 0; | 
| 460 | } | 460 | } | 
| 461 | 461 | ||
| 462 | static int handle_mcast(struct vnet_port *port, void *msgbuf) | ||
| 463 | { | ||
| 464 | struct vio_net_mcast_info *pkt = msgbuf; | ||
| 465 | |||
| 466 | if (pkt->tag.stype != VIO_SUBTYPE_ACK) | ||
| 467 | printk(KERN_ERR PFX "%s: Got unexpected MCAST reply " | ||
| 468 | "[%02x:%02x:%04x:%08x]\n", | ||
| 469 | port->vp->dev->name, | ||
| 470 | pkt->tag.type, | ||
| 471 | pkt->tag.stype, | ||
| 472 | pkt->tag.stype_env, | ||
| 473 | pkt->tag.sid); | ||
| 474 | |||
| 475 | return 0; | ||
| 476 | } | ||
| 477 | |||
| 462 | static void maybe_tx_wakeup(struct vnet *vp) | 478 | static void maybe_tx_wakeup(struct vnet *vp) | 
| 463 | { | 479 | { | 
| 464 | struct net_device *dev = vp->dev; | 480 | struct net_device *dev = vp->dev; | 
| @@ -544,7 +560,10 @@ static void vnet_event(void *arg, int event) | |||
| 544 | err = vnet_nack(port, &msgbuf); | 560 | err = vnet_nack(port, &msgbuf); | 
| 545 | } | 561 | } | 
| 546 | } else if (msgbuf.tag.type == VIO_TYPE_CTRL) { | 562 | } else if (msgbuf.tag.type == VIO_TYPE_CTRL) { | 
| 547 | err = vio_control_pkt_engine(vio, &msgbuf); | 563 | if (msgbuf.tag.stype_env == VNET_MCAST_INFO) | 
| 564 | err = handle_mcast(port, &msgbuf); | ||
| 565 | else | ||
| 566 | err = vio_control_pkt_engine(vio, &msgbuf); | ||
| 548 | if (err) | 567 | if (err) | 
| 549 | break; | 568 | break; | 
| 550 | } else { | 569 | } else { | 
| @@ -731,9 +750,122 @@ static int vnet_close(struct net_device *dev) | |||
| 731 | return 0; | 750 | return 0; | 
| 732 | } | 751 | } | 
| 733 | 752 | ||
| 753 | static struct vnet_mcast_entry *__vnet_mc_find(struct vnet *vp, u8 *addr) | ||
| 754 | { | ||
| 755 | struct vnet_mcast_entry *m; | ||
| 756 | |||
| 757 | for (m = vp->mcast_list; m; m = m->next) { | ||
| 758 | if (!memcmp(m->addr, addr, ETH_ALEN)) | ||
| 759 | return m; | ||
| 760 | } | ||
| 761 | return NULL; | ||
| 762 | } | ||
| 763 | |||
| 764 | static void __update_mc_list(struct vnet *vp, struct net_device *dev) | ||
| 765 | { | ||
| 766 | struct dev_addr_list *p; | ||
| 767 | |||
| 768 | for (p = dev->mc_list; p; p = p->next) { | ||
| 769 | struct vnet_mcast_entry *m; | ||
| 770 | |||
| 771 | m = __vnet_mc_find(vp, p->dmi_addr); | ||
| 772 | if (m) { | ||
| 773 | m->hit = 1; | ||
| 774 | continue; | ||
| 775 | } | ||
| 776 | |||
| 777 | if (!m) { | ||
| 778 | m = kzalloc(sizeof(*m), GFP_ATOMIC); | ||
| 779 | if (!m) | ||
| 780 | continue; | ||
| 781 | memcpy(m->addr, p->dmi_addr, ETH_ALEN); | ||
| 782 | m->hit = 1; | ||
| 783 | |||
| 784 | m->next = vp->mcast_list; | ||
| 785 | vp->mcast_list = m; | ||
| 786 | } | ||
| 787 | } | ||
| 788 | } | ||
| 789 | |||
| 790 | static void __send_mc_list(struct vnet *vp, struct vnet_port *port) | ||
| 791 | { | ||
| 792 | struct vio_net_mcast_info info; | ||
| 793 | struct vnet_mcast_entry *m, **pp; | ||
| 794 | int n_addrs; | ||
| 795 | |||
| 796 | memset(&info, 0, sizeof(info)); | ||
| 797 | |||
| 798 | info.tag.type = VIO_TYPE_CTRL; | ||
| 799 | info.tag.stype = VIO_SUBTYPE_INFO; | ||
| 800 | info.tag.stype_env = VNET_MCAST_INFO; | ||
| 801 | info.tag.sid = vio_send_sid(&port->vio); | ||
| 802 | info.set = 1; | ||
| 803 | |||
| 804 | n_addrs = 0; | ||
| 805 | for (m = vp->mcast_list; m; m = m->next) { | ||
| 806 | if (m->sent) | ||
| 807 | continue; | ||
| 808 | m->sent = 1; | ||
| 809 | memcpy(&info.mcast_addr[n_addrs * ETH_ALEN], | ||
| 810 | m->addr, ETH_ALEN); | ||
| 811 | if (++n_addrs == VNET_NUM_MCAST) { | ||
| 812 | info.count = n_addrs; | ||
| 813 | |||
| 814 | (void) vio_ldc_send(&port->vio, &info, | ||
| 815 | sizeof(info)); | ||
| 816 | n_addrs = 0; | ||
| 817 | } | ||
| 818 | } | ||
| 819 | if (n_addrs) { | ||
| 820 | info.count = n_addrs; | ||
| 821 | (void) vio_ldc_send(&port->vio, &info, sizeof(info)); | ||
| 822 | } | ||
| 823 | |||
| 824 | info.set = 0; | ||
| 825 | |||
| 826 | n_addrs = 0; | ||
| 827 | pp = &vp->mcast_list; | ||
| 828 | while ((m = *pp) != NULL) { | ||
| 829 | if (m->hit) { | ||
| 830 | m->hit = 0; | ||
| 831 | pp = &m->next; | ||
| 832 | continue; | ||
| 833 | } | ||
| 834 | |||
| 835 | memcpy(&info.mcast_addr[n_addrs * ETH_ALEN], | ||
| 836 | m->addr, ETH_ALEN); | ||
| 837 | if (++n_addrs == VNET_NUM_MCAST) { | ||
| 838 | info.count = n_addrs; | ||
| 839 | (void) vio_ldc_send(&port->vio, &info, | ||
| 840 | sizeof(info)); | ||
| 841 | n_addrs = 0; | ||
| 842 | } | ||
| 843 | |||
| 844 | *pp = m->next; | ||
| 845 | kfree(m); | ||
| 846 | } | ||
| 847 | if (n_addrs) { | ||
| 848 | info.count = n_addrs; | ||
| 849 | (void) vio_ldc_send(&port->vio, &info, sizeof(info)); | ||
| 850 | } | ||
| 851 | } | ||
| 852 | |||
| 734 | static void vnet_set_rx_mode(struct net_device *dev) | 853 | static void vnet_set_rx_mode(struct net_device *dev) | 
| 735 | { | 854 | { | 
| 736 | /* XXX Implement multicast support XXX */ | 855 | struct vnet *vp = netdev_priv(dev); | 
| 856 | struct vnet_port *port; | ||
| 857 | unsigned long flags; | ||
| 858 | |||
| 859 | spin_lock_irqsave(&vp->lock, flags); | ||
| 860 | if (!list_empty(&vp->port_list)) { | ||
| 861 | port = list_entry(vp->port_list.next, struct vnet_port, list); | ||
| 862 | |||
| 863 | if (port->switch_port) { | ||
| 864 | __update_mc_list(vp, dev); | ||
| 865 | __send_mc_list(vp, port); | ||
| 866 | } | ||
| 867 | } | ||
| 868 | spin_unlock_irqrestore(&vp->lock, flags); | ||
| 737 | } | 869 | } | 
| 738 | 870 | ||
| 739 | static int vnet_change_mtu(struct net_device *dev, int new_mtu) | 871 | static int vnet_change_mtu(struct net_device *dev, int new_mtu) | 
| @@ -1070,6 +1202,7 @@ static int __devinit vnet_port_probe(struct vio_dev *vdev, | |||
| 1070 | switch_port = 0; | 1202 | switch_port = 0; | 
| 1071 | if (mdesc_get_property(hp, vdev->mp, "switch-port", NULL) != NULL) | 1203 | if (mdesc_get_property(hp, vdev->mp, "switch-port", NULL) != NULL) | 
| 1072 | switch_port = 1; | 1204 | switch_port = 1; | 
| 1205 | port->switch_port = switch_port; | ||
| 1073 | 1206 | ||
| 1074 | spin_lock_irqsave(&vp->lock, flags); | 1207 | spin_lock_irqsave(&vp->lock, flags); | 
| 1075 | if (switch_port) | 1208 | if (switch_port) | 
