diff options
author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-07-18 13:23:37 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-07-18 13:23:37 -0400 |
commit | 31bdc5dc7666aa2fe04c626cea30fe3c20cf481c (patch) | |
tree | a1a78a39379e081e9982c3273a71b4e93e8c1fd0 /drivers/net | |
parent | 5cc97bf2d8eaa6cab60727c3eba3e85e29062669 (diff) | |
parent | a5f8967e171a6fa27da8e6d06d3ef85f7fed43c1 (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]: Set vio->desc_buf to NULL after freeing.
[SPARC]: Mark sparc and sparc64 as not having virt_to_bus
[SPARC64]: Fix reset handling in VNET driver.
[SPARC64]: Handle reset events in vio_link_state_change().
[SPARC64]: Handle LDC resets properly in domain-services driver.
[SPARC64]: Massively simplify VIO device layer and support hot add/remove.
[SPARC64]: Simplify VNET probing.
[SPARC64]: Simplify VDC device probing.
[SPARC64]: Add basic infrastructure for MD add/remove notification.
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/sunvnet.c | 260 | ||||
-rw-r--r-- | drivers/net/sunvnet.h | 4 |
2 files changed, 132 insertions, 132 deletions
diff --git a/drivers/net/sunvnet.c b/drivers/net/sunvnet.c index 8a667c13faef..b801e3b3a11a 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> |
@@ -497,6 +498,8 @@ static void vnet_event(void *arg, int event) | |||
497 | vio_link_state_change(vio, event); | 498 | vio_link_state_change(vio, event); |
498 | spin_unlock_irqrestore(&vio->lock, flags); | 499 | spin_unlock_irqrestore(&vio->lock, flags); |
499 | 500 | ||
501 | if (event == LDC_EVENT_RESET) | ||
502 | vio_port_up(vio); | ||
500 | return; | 503 | return; |
501 | } | 504 | } |
502 | 505 | ||
@@ -875,6 +878,115 @@ err_out: | |||
875 | return err; | 878 | return err; |
876 | } | 879 | } |
877 | 880 | ||
881 | static LIST_HEAD(vnet_list); | ||
882 | static DEFINE_MUTEX(vnet_list_mutex); | ||
883 | |||
884 | static struct vnet * __devinit vnet_new(const u64 *local_mac) | ||
885 | { | ||
886 | struct net_device *dev; | ||
887 | struct vnet *vp; | ||
888 | int err, i; | ||
889 | |||
890 | dev = alloc_etherdev(sizeof(*vp)); | ||
891 | if (!dev) { | ||
892 | printk(KERN_ERR PFX "Etherdev alloc failed, aborting.\n"); | ||
893 | return ERR_PTR(-ENOMEM); | ||
894 | } | ||
895 | |||
896 | for (i = 0; i < ETH_ALEN; i++) | ||
897 | dev->dev_addr[i] = (*local_mac >> (5 - i) * 8) & 0xff; | ||
898 | |||
899 | memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); | ||
900 | |||
901 | vp = netdev_priv(dev); | ||
902 | |||
903 | spin_lock_init(&vp->lock); | ||
904 | vp->dev = dev; | ||
905 | |||
906 | INIT_LIST_HEAD(&vp->port_list); | ||
907 | for (i = 0; i < VNET_PORT_HASH_SIZE; i++) | ||
908 | INIT_HLIST_HEAD(&vp->port_hash[i]); | ||
909 | INIT_LIST_HEAD(&vp->list); | ||
910 | vp->local_mac = *local_mac; | ||
911 | |||
912 | dev->open = vnet_open; | ||
913 | dev->stop = vnet_close; | ||
914 | dev->set_multicast_list = vnet_set_rx_mode; | ||
915 | dev->set_mac_address = vnet_set_mac_addr; | ||
916 | dev->tx_timeout = vnet_tx_timeout; | ||
917 | dev->ethtool_ops = &vnet_ethtool_ops; | ||
918 | dev->watchdog_timeo = VNET_TX_TIMEOUT; | ||
919 | dev->change_mtu = vnet_change_mtu; | ||
920 | dev->hard_start_xmit = vnet_start_xmit; | ||
921 | |||
922 | err = register_netdev(dev); | ||
923 | if (err) { | ||
924 | printk(KERN_ERR PFX "Cannot register net device, " | ||
925 | "aborting.\n"); | ||
926 | goto err_out_free_dev; | ||
927 | } | ||
928 | |||
929 | printk(KERN_INFO "%s: Sun LDOM vnet ", dev->name); | ||
930 | |||
931 | for (i = 0; i < 6; i++) | ||
932 | printk("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':'); | ||
933 | |||
934 | list_add(&vp->list, &vnet_list); | ||
935 | |||
936 | return vp; | ||
937 | |||
938 | err_out_free_dev: | ||
939 | free_netdev(dev); | ||
940 | |||
941 | return ERR_PTR(err); | ||
942 | } | ||
943 | |||
944 | static struct vnet * __devinit vnet_find_or_create(const u64 *local_mac) | ||
945 | { | ||
946 | struct vnet *iter, *vp; | ||
947 | |||
948 | mutex_lock(&vnet_list_mutex); | ||
949 | vp = NULL; | ||
950 | list_for_each_entry(iter, &vnet_list, list) { | ||
951 | if (iter->local_mac == *local_mac) { | ||
952 | vp = iter; | ||
953 | break; | ||
954 | } | ||
955 | } | ||
956 | if (!vp) | ||
957 | vp = vnet_new(local_mac); | ||
958 | mutex_unlock(&vnet_list_mutex); | ||
959 | |||
960 | return vp; | ||
961 | } | ||
962 | |||
963 | static const char *local_mac_prop = "local-mac-address"; | ||
964 | |||
965 | static struct vnet * __devinit vnet_find_parent(struct mdesc_handle *hp, | ||
966 | u64 port_node) | ||
967 | { | ||
968 | const u64 *local_mac = NULL; | ||
969 | u64 a; | ||
970 | |||
971 | mdesc_for_each_arc(a, hp, port_node, MDESC_ARC_TYPE_BACK) { | ||
972 | u64 target = mdesc_arc_target(hp, a); | ||
973 | const char *name; | ||
974 | |||
975 | name = mdesc_get_property(hp, target, "name", NULL); | ||
976 | if (!name || strcmp(name, "network")) | ||
977 | continue; | ||
978 | |||
979 | local_mac = mdesc_get_property(hp, target, | ||
980 | local_mac_prop, NULL); | ||
981 | if (local_mac) | ||
982 | break; | ||
983 | } | ||
984 | if (!local_mac) | ||
985 | return ERR_PTR(-ENODEV); | ||
986 | |||
987 | return vnet_find_or_create(local_mac); | ||
988 | } | ||
989 | |||
878 | static struct ldc_channel_config vnet_ldc_cfg = { | 990 | static struct ldc_channel_config vnet_ldc_cfg = { |
879 | .event = vnet_event, | 991 | .event = vnet_event, |
880 | .mtu = 64, | 992 | .mtu = 64, |
@@ -887,6 +999,14 @@ static struct vio_driver_ops vnet_vio_ops = { | |||
887 | .handshake_complete = vnet_handshake_complete, | 999 | .handshake_complete = vnet_handshake_complete, |
888 | }; | 1000 | }; |
889 | 1001 | ||
1002 | static void print_version(void) | ||
1003 | { | ||
1004 | static int version_printed; | ||
1005 | |||
1006 | if (version_printed++ == 0) | ||
1007 | printk(KERN_INFO "%s", version); | ||
1008 | } | ||
1009 | |||
890 | const char *remote_macaddr_prop = "remote-mac-address"; | 1010 | const char *remote_macaddr_prop = "remote-mac-address"; |
891 | 1011 | ||
892 | static int __devinit vnet_port_probe(struct vio_dev *vdev, | 1012 | static int __devinit vnet_port_probe(struct vio_dev *vdev, |
@@ -899,14 +1019,17 @@ static int __devinit vnet_port_probe(struct vio_dev *vdev, | |||
899 | const u64 *rmac; | 1019 | const u64 *rmac; |
900 | int len, i, err, switch_port; | 1020 | int len, i, err, switch_port; |
901 | 1021 | ||
902 | vp = dev_get_drvdata(vdev->dev.parent); | 1022 | print_version(); |
903 | if (!vp) { | ||
904 | printk(KERN_ERR PFX "Cannot find port parent vnet.\n"); | ||
905 | return -ENODEV; | ||
906 | } | ||
907 | 1023 | ||
908 | hp = mdesc_grab(); | 1024 | hp = mdesc_grab(); |
909 | 1025 | ||
1026 | vp = vnet_find_parent(hp, vdev->mp); | ||
1027 | if (IS_ERR(vp)) { | ||
1028 | printk(KERN_ERR PFX "Cannot find port parent vnet.\n"); | ||
1029 | err = PTR_ERR(vp); | ||
1030 | goto err_out_put_mdesc; | ||
1031 | } | ||
1032 | |||
910 | rmac = mdesc_get_property(hp, vdev->mp, remote_macaddr_prop, &len); | 1033 | rmac = mdesc_get_property(hp, vdev->mp, remote_macaddr_prop, &len); |
911 | err = -ENODEV; | 1034 | err = -ENODEV; |
912 | if (!rmac) { | 1035 | if (!rmac) { |
@@ -1025,139 +1148,14 @@ static struct vio_driver vnet_port_driver = { | |||
1025 | } | 1148 | } |
1026 | }; | 1149 | }; |
1027 | 1150 | ||
1028 | const char *local_mac_prop = "local-mac-address"; | ||
1029 | |||
1030 | static 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 | |||
1105 | err_out_free_dev: | ||
1106 | free_netdev(dev); | ||
1107 | |||
1108 | err_out: | ||
1109 | mdesc_release(hp); | ||
1110 | return err; | ||
1111 | } | ||
1112 | |||
1113 | static 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 | |||
1126 | static struct vio_device_id vnet_match[] = { | ||
1127 | { | ||
1128 | .type = "network", | ||
1129 | }, | ||
1130 | {}, | ||
1131 | }; | ||
1132 | MODULE_DEVICE_TABLE(vio, vnet_match); | ||
1133 | |||
1134 | static 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 | |||
1144 | static int __init vnet_init(void) | 1151 | static int __init vnet_init(void) |
1145 | { | 1152 | { |
1146 | int err = vio_register_driver(&vnet_driver); | 1153 | 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 | } | 1154 | } |
1156 | 1155 | ||
1157 | static void __exit vnet_exit(void) | 1156 | static void __exit vnet_exit(void) |
1158 | { | 1157 | { |
1159 | vio_unregister_driver(&vnet_port_driver); | 1158 | vio_unregister_driver(&vnet_port_driver); |
1160 | vio_unregister_driver(&vnet_driver); | ||
1161 | } | 1159 | } |
1162 | 1160 | ||
1163 | module_init(vnet_init); | 1161 | module_init(vnet_init); |
diff --git a/drivers/net/sunvnet.h b/drivers/net/sunvnet.h index 1c887302d46d..7d3a0cac727b 100644 --- a/drivers/net/sunvnet.h +++ b/drivers/net/sunvnet.h | |||
@@ -60,11 +60,13 @@ struct vnet { | |||
60 | struct net_device *dev; | 60 | struct net_device *dev; |
61 | 61 | ||
62 | u32 msg_enable; | 62 | u32 msg_enable; |
63 | struct vio_dev *vdev; | ||
64 | 63 | ||
65 | struct list_head port_list; | 64 | struct list_head port_list; |
66 | 65 | ||
67 | struct hlist_head port_hash[VNET_PORT_HASH_SIZE]; | 66 | struct hlist_head port_hash[VNET_PORT_HASH_SIZE]; |
67 | |||
68 | struct list_head list; | ||
69 | u64 local_mac; | ||
68 | }; | 70 | }; |
69 | 71 | ||
70 | #endif /* _SUNVNET_H */ | 72 | #endif /* _SUNVNET_H */ |