aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/sunvnet.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/sunvnet.c')
-rw-r--r--drivers/net/sunvnet.c258
1 files changed, 127 insertions, 131 deletions
diff --git a/drivers/net/sunvnet.c b/drivers/net/sunvnet.c
index 8a667c13faef..b69f55226bd6 100644
--- a/drivers/net/sunvnet.c
+++ b/drivers/net/sunvnet.c
@@ -12,6 +12,7 @@
12#include <linux/netdevice.h> 12#include <linux/netdevice.h>
13#include <linux/ethtool.h> 13#include <linux/ethtool.h>
14#include <linux/etherdevice.h> 14#include <linux/etherdevice.h>
15#include <linux/mutex.h>
15 16
16#include <asm/vio.h> 17#include <asm/vio.h>
17#include <asm/ldc.h> 18#include <asm/ldc.h>
@@ -875,6 +876,115 @@ err_out:
875 return err; 876 return err;
876} 877}
877 878
879static LIST_HEAD(vnet_list);
880static DEFINE_MUTEX(vnet_list_mutex);
881
882static struct vnet * __devinit vnet_new(const u64 *local_mac)
883{
884 struct net_device *dev;
885 struct vnet *vp;
886 int err, i;
887
888 dev = alloc_etherdev(sizeof(*vp));
889 if (!dev) {
890 printk(KERN_ERR PFX "Etherdev alloc failed, aborting.\n");
891 return ERR_PTR(-ENOMEM);
892 }
893
894 for (i = 0; i < ETH_ALEN; i++)
895 dev->dev_addr[i] = (*local_mac >> (5 - i) * 8) & 0xff;
896
897 memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
898
899 vp = netdev_priv(dev);
900
901 spin_lock_init(&vp->lock);
902 vp->dev = dev;
903
904 INIT_LIST_HEAD(&vp->port_list);
905 for (i = 0; i < VNET_PORT_HASH_SIZE; i++)
906 INIT_HLIST_HEAD(&vp->port_hash[i]);
907 INIT_LIST_HEAD(&vp->list);
908 vp->local_mac = *local_mac;
909
910 dev->open = vnet_open;
911 dev->stop = vnet_close;
912 dev->set_multicast_list = vnet_set_rx_mode;
913 dev->set_mac_address = vnet_set_mac_addr;
914 dev->tx_timeout = vnet_tx_timeout;
915 dev->ethtool_ops = &vnet_ethtool_ops;
916 dev->watchdog_timeo = VNET_TX_TIMEOUT;
917 dev->change_mtu = vnet_change_mtu;
918 dev->hard_start_xmit = vnet_start_xmit;
919
920 err = register_netdev(dev);
921 if (err) {
922 printk(KERN_ERR PFX "Cannot register net device, "
923 "aborting.\n");
924 goto err_out_free_dev;
925 }
926
927 printk(KERN_INFO "%s: Sun LDOM vnet ", dev->name);
928
929 for (i = 0; i < 6; i++)
930 printk("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':');
931
932 list_add(&vp->list, &vnet_list);
933
934 return vp;
935
936err_out_free_dev:
937 free_netdev(dev);
938
939 return ERR_PTR(err);
940}
941
942static struct vnet * __devinit vnet_find_or_create(const u64 *local_mac)
943{
944 struct vnet *iter, *vp;
945
946 mutex_lock(&vnet_list_mutex);
947 vp = NULL;
948 list_for_each_entry(iter, &vnet_list, list) {
949 if (iter->local_mac == *local_mac) {
950 vp = iter;
951 break;
952 }
953 }
954 if (!vp)
955 vp = vnet_new(local_mac);
956 mutex_unlock(&vnet_list_mutex);
957
958 return vp;
959}
960
961static const char *local_mac_prop = "local-mac-address";
962
963static struct vnet * __devinit vnet_find_parent(struct mdesc_handle *hp,
964 u64 port_node)
965{
966 const u64 *local_mac = NULL;
967 u64 a;
968
969 mdesc_for_each_arc(a, hp, port_node, MDESC_ARC_TYPE_BACK) {
970 u64 target = mdesc_arc_target(hp, a);
971 const char *name;
972
973 name = mdesc_get_property(hp, target, "name", NULL);
974 if (!name || strcmp(name, "network"))
975 continue;
976
977 local_mac = mdesc_get_property(hp, target,
978 local_mac_prop, NULL);
979 if (local_mac)
980 break;
981 }
982 if (!local_mac)
983 return ERR_PTR(-ENODEV);
984
985 return vnet_find_or_create(local_mac);
986}
987
878static struct ldc_channel_config vnet_ldc_cfg = { 988static struct ldc_channel_config vnet_ldc_cfg = {
879 .event = vnet_event, 989 .event = vnet_event,
880 .mtu = 64, 990 .mtu = 64,
@@ -887,6 +997,14 @@ static struct vio_driver_ops vnet_vio_ops = {
887 .handshake_complete = vnet_handshake_complete, 997 .handshake_complete = vnet_handshake_complete,
888}; 998};
889 999
1000static void print_version(void)
1001{
1002 static int version_printed;
1003
1004 if (version_printed++ == 0)
1005 printk(KERN_INFO "%s", version);
1006}
1007
890const char *remote_macaddr_prop = "remote-mac-address"; 1008const char *remote_macaddr_prop = "remote-mac-address";
891 1009
892static int __devinit vnet_port_probe(struct vio_dev *vdev, 1010static int __devinit vnet_port_probe(struct vio_dev *vdev,
@@ -899,14 +1017,17 @@ static int __devinit vnet_port_probe(struct vio_dev *vdev,
899 const u64 *rmac; 1017 const u64 *rmac;
900 int len, i, err, switch_port; 1018 int len, i, err, switch_port;
901 1019
902 vp = dev_get_drvdata(vdev->dev.parent); 1020 print_version();
903 if (!vp) {
904 printk(KERN_ERR PFX "Cannot find port parent vnet.\n");
905 return -ENODEV;
906 }
907 1021
908 hp = mdesc_grab(); 1022 hp = mdesc_grab();
909 1023
1024 vp = vnet_find_parent(hp, vdev->mp);
1025 if (IS_ERR(vp)) {
1026 printk(KERN_ERR PFX "Cannot find port parent vnet.\n");
1027 err = PTR_ERR(vp);
1028 goto err_out_put_mdesc;
1029 }
1030
910 rmac = mdesc_get_property(hp, vdev->mp, remote_macaddr_prop, &len); 1031 rmac = mdesc_get_property(hp, vdev->mp, remote_macaddr_prop, &len);
911 err = -ENODEV; 1032 err = -ENODEV;
912 if (!rmac) { 1033 if (!rmac) {
@@ -1025,139 +1146,14 @@ static struct vio_driver vnet_port_driver = {
1025 } 1146 }
1026}; 1147};
1027 1148
1028const char *local_mac_prop = "local-mac-address";
1029
1030static int __devinit vnet_probe(struct vio_dev *vdev,
1031 const struct vio_device_id *id)
1032{
1033 static int vnet_version_printed;
1034 struct mdesc_handle *hp;
1035 struct net_device *dev;
1036 struct vnet *vp;
1037 const u64 *mac;
1038 int err, i, len;
1039
1040 if (vnet_version_printed++ == 0)
1041 printk(KERN_INFO "%s", version);
1042
1043 hp = mdesc_grab();
1044
1045 mac = mdesc_get_property(hp, vdev->mp, local_mac_prop, &len);
1046 if (!mac) {
1047 printk(KERN_ERR PFX "vnet lacks %s property.\n",
1048 local_mac_prop);
1049 err = -ENODEV;
1050 goto err_out;
1051 }
1052
1053 dev = alloc_etherdev(sizeof(*vp));
1054 if (!dev) {
1055 printk(KERN_ERR PFX "Etherdev alloc failed, aborting.\n");
1056 err = -ENOMEM;
1057 goto err_out;
1058 }
1059
1060 for (i = 0; i < ETH_ALEN; i++)
1061 dev->dev_addr[i] = (*mac >> (5 - i) * 8) & 0xff;
1062
1063 memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
1064
1065 SET_NETDEV_DEV(dev, &vdev->dev);
1066
1067 vp = netdev_priv(dev);
1068
1069 spin_lock_init(&vp->lock);
1070 vp->dev = dev;
1071 vp->vdev = vdev;
1072
1073 INIT_LIST_HEAD(&vp->port_list);
1074 for (i = 0; i < VNET_PORT_HASH_SIZE; i++)
1075 INIT_HLIST_HEAD(&vp->port_hash[i]);
1076
1077 dev->open = vnet_open;
1078 dev->stop = vnet_close;
1079 dev->set_multicast_list = vnet_set_rx_mode;
1080 dev->set_mac_address = vnet_set_mac_addr;
1081 dev->tx_timeout = vnet_tx_timeout;
1082 dev->ethtool_ops = &vnet_ethtool_ops;
1083 dev->watchdog_timeo = VNET_TX_TIMEOUT;
1084 dev->change_mtu = vnet_change_mtu;
1085 dev->hard_start_xmit = vnet_start_xmit;
1086
1087 err = register_netdev(dev);
1088 if (err) {
1089 printk(KERN_ERR PFX "Cannot register net device, "
1090 "aborting.\n");
1091 goto err_out_free_dev;
1092 }
1093
1094 printk(KERN_INFO "%s: Sun LDOM vnet ", dev->name);
1095
1096 for (i = 0; i < 6; i++)
1097 printk("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':');
1098
1099 dev_set_drvdata(&vdev->dev, vp);
1100
1101 mdesc_release(hp);
1102
1103 return 0;
1104
1105err_out_free_dev:
1106 free_netdev(dev);
1107
1108err_out:
1109 mdesc_release(hp);
1110 return err;
1111}
1112
1113static int vnet_remove(struct vio_dev *vdev)
1114{
1115
1116 struct vnet *vp = dev_get_drvdata(&vdev->dev);
1117
1118 if (vp) {
1119 /* XXX unregister port, or at least check XXX */
1120 unregister_netdevice(vp->dev);
1121 dev_set_drvdata(&vdev->dev, NULL);
1122 }
1123 return 0;
1124}
1125
1126static struct vio_device_id vnet_match[] = {
1127 {
1128 .type = "network",
1129 },
1130 {},
1131};
1132MODULE_DEVICE_TABLE(vio, vnet_match);
1133
1134static struct vio_driver vnet_driver = {
1135 .id_table = vnet_match,
1136 .probe = vnet_probe,
1137 .remove = vnet_remove,
1138 .driver = {
1139 .name = "vnet",
1140 .owner = THIS_MODULE,
1141 }
1142};
1143
1144static int __init vnet_init(void) 1149static int __init vnet_init(void)
1145{ 1150{
1146 int err = vio_register_driver(&vnet_driver); 1151 return vio_register_driver(&vnet_port_driver);
1147
1148 if (!err) {
1149 err = vio_register_driver(&vnet_port_driver);
1150 if (err)
1151 vio_unregister_driver(&vnet_driver);
1152 }
1153
1154 return err;
1155} 1152}
1156 1153
1157static void __exit vnet_exit(void) 1154static void __exit vnet_exit(void)
1158{ 1155{
1159 vio_unregister_driver(&vnet_port_driver); 1156 vio_unregister_driver(&vnet_port_driver);
1160 vio_unregister_driver(&vnet_driver);
1161} 1157}
1162 1158
1163module_init(vnet_init); 1159module_init(vnet_init);