xref: /openbmc/linux/drivers/net/ethernet/sun/sunvnet.c (revision 31762eaa)
1 /* sunvnet.c: Sun LDOM Virtual Network Driver.
2  *
3  * Copyright (C) 2007, 2008 David S. Miller <davem@davemloft.net>
4  */
5 
6 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
7 
8 #include <linux/module.h>
9 #include <linux/kernel.h>
10 #include <linux/types.h>
11 #include <linux/slab.h>
12 #include <linux/delay.h>
13 #include <linux/init.h>
14 #include <linux/netdevice.h>
15 #include <linux/ethtool.h>
16 #include <linux/etherdevice.h>
17 #include <linux/mutex.h>
18 #include <linux/highmem.h>
19 #include <linux/if_vlan.h>
20 
21 #if IS_ENABLED(CONFIG_IPV6)
22 #include <linux/icmpv6.h>
23 #endif
24 
25 #include <net/ip.h>
26 #include <net/icmp.h>
27 #include <net/route.h>
28 
29 #include <asm/vio.h>
30 #include <asm/ldc.h>
31 
32 #include "sunvnet_common.h"
33 
34 /* length of time before we decide the hardware is borked,
35  * and dev->tx_timeout() should be called to fix the problem
36  */
37 #define VNET_TX_TIMEOUT			(5 * HZ)
38 
39 #define DRV_MODULE_NAME		"sunvnet"
40 #define DRV_MODULE_VERSION	"1.0"
41 #define DRV_MODULE_RELDATE	"June 25, 2007"
42 
43 static char version[] =
44 	DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
45 MODULE_AUTHOR("David S. Miller (davem@davemloft.net)");
46 MODULE_DESCRIPTION("Sun LDOM virtual network driver");
47 MODULE_LICENSE("GPL");
48 MODULE_VERSION(DRV_MODULE_VERSION);
49 
50 /* Ordered from largest major to lowest */
51 static struct vio_version vnet_versions[] = {
52 	{ .major = 1, .minor = 8 },
53 	{ .major = 1, .minor = 7 },
54 	{ .major = 1, .minor = 6 },
55 	{ .major = 1, .minor = 0 },
56 };
57 
58 static void vnet_get_drvinfo(struct net_device *dev,
59 			     struct ethtool_drvinfo *info)
60 {
61 	strlcpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver));
62 	strlcpy(info->version, DRV_MODULE_VERSION, sizeof(info->version));
63 }
64 
65 static u32 vnet_get_msglevel(struct net_device *dev)
66 {
67 	struct vnet *vp = netdev_priv(dev);
68 	return vp->msg_enable;
69 }
70 
71 static void vnet_set_msglevel(struct net_device *dev, u32 value)
72 {
73 	struct vnet *vp = netdev_priv(dev);
74 	vp->msg_enable = value;
75 }
76 
77 static const struct ethtool_ops vnet_ethtool_ops = {
78 	.get_drvinfo		= vnet_get_drvinfo,
79 	.get_msglevel		= vnet_get_msglevel,
80 	.set_msglevel		= vnet_set_msglevel,
81 	.get_link		= ethtool_op_get_link,
82 };
83 
84 static LIST_HEAD(vnet_list);
85 static DEFINE_MUTEX(vnet_list_mutex);
86 
87 static const struct net_device_ops vnet_ops = {
88 	.ndo_open		= sunvnet_open_common,
89 	.ndo_stop		= sunvnet_close_common,
90 	.ndo_set_rx_mode	= sunvnet_set_rx_mode_common,
91 	.ndo_set_mac_address	= sunvnet_set_mac_addr_common,
92 	.ndo_validate_addr	= eth_validate_addr,
93 	.ndo_tx_timeout		= sunvnet_tx_timeout_common,
94 	.ndo_change_mtu		= sunvnet_change_mtu_common,
95 	.ndo_start_xmit		= sunvnet_start_xmit_common,
96 	.ndo_select_queue	= sunvnet_select_queue_common,
97 #ifdef CONFIG_NET_POLL_CONTROLLER
98 	.ndo_poll_controller	= sunvnet_poll_controller_common,
99 #endif
100 };
101 
102 static struct vnet *vnet_new(const u64 *local_mac,
103 			     struct vio_dev *vdev)
104 {
105 	struct net_device *dev;
106 	struct vnet *vp;
107 	int err, i;
108 
109 	dev = alloc_etherdev_mqs(sizeof(*vp), VNET_MAX_TXQS, 1);
110 	if (!dev)
111 		return ERR_PTR(-ENOMEM);
112 	dev->needed_headroom = VNET_PACKET_SKIP + 8;
113 	dev->needed_tailroom = 8;
114 
115 	for (i = 0; i < ETH_ALEN; i++)
116 		dev->dev_addr[i] = (*local_mac >> (5 - i) * 8) & 0xff;
117 
118 	vp = netdev_priv(dev);
119 
120 	spin_lock_init(&vp->lock);
121 	vp->dev = dev;
122 
123 	INIT_LIST_HEAD(&vp->port_list);
124 	for (i = 0; i < VNET_PORT_HASH_SIZE; i++)
125 		INIT_HLIST_HEAD(&vp->port_hash[i]);
126 	INIT_LIST_HEAD(&vp->list);
127 	vp->local_mac = *local_mac;
128 
129 	dev->netdev_ops = &vnet_ops;
130 	dev->ethtool_ops = &vnet_ethtool_ops;
131 	dev->watchdog_timeo = VNET_TX_TIMEOUT;
132 
133 	dev->hw_features = NETIF_F_TSO | NETIF_F_GSO | NETIF_F_GSO_SOFTWARE |
134 			   NETIF_F_HW_CSUM | NETIF_F_SG;
135 	dev->features = dev->hw_features;
136 
137 	SET_NETDEV_DEV(dev, &vdev->dev);
138 
139 	err = register_netdev(dev);
140 	if (err) {
141 		pr_err("Cannot register net device, aborting\n");
142 		goto err_out_free_dev;
143 	}
144 
145 	netdev_info(dev, "Sun LDOM vnet %pM\n", dev->dev_addr);
146 
147 	list_add(&vp->list, &vnet_list);
148 
149 	return vp;
150 
151 err_out_free_dev:
152 	free_netdev(dev);
153 
154 	return ERR_PTR(err);
155 }
156 
157 static struct vnet *vnet_find_or_create(const u64 *local_mac,
158 					struct vio_dev *vdev)
159 {
160 	struct vnet *iter, *vp;
161 
162 	mutex_lock(&vnet_list_mutex);
163 	vp = NULL;
164 	list_for_each_entry(iter, &vnet_list, list) {
165 		if (iter->local_mac == *local_mac) {
166 			vp = iter;
167 			break;
168 		}
169 	}
170 	if (!vp)
171 		vp = vnet_new(local_mac, vdev);
172 	mutex_unlock(&vnet_list_mutex);
173 
174 	return vp;
175 }
176 
177 static void vnet_cleanup(void)
178 {
179 	struct vnet *vp;
180 	struct net_device *dev;
181 
182 	mutex_lock(&vnet_list_mutex);
183 	while (!list_empty(&vnet_list)) {
184 		vp = list_first_entry(&vnet_list, struct vnet, list);
185 		list_del(&vp->list);
186 		dev = vp->dev;
187 		/* vio_unregister_driver() should have cleaned up port_list */
188 		BUG_ON(!list_empty(&vp->port_list));
189 		unregister_netdev(dev);
190 		free_netdev(dev);
191 	}
192 	mutex_unlock(&vnet_list_mutex);
193 }
194 
195 static const char *local_mac_prop = "local-mac-address";
196 
197 static struct vnet *vnet_find_parent(struct mdesc_handle *hp,
198 				     u64 port_node,
199 				     struct vio_dev *vdev)
200 {
201 	const u64 *local_mac = NULL;
202 	u64 a;
203 
204 	mdesc_for_each_arc(a, hp, port_node, MDESC_ARC_TYPE_BACK) {
205 		u64 target = mdesc_arc_target(hp, a);
206 		const char *name;
207 
208 		name = mdesc_get_property(hp, target, "name", NULL);
209 		if (!name || strcmp(name, "network"))
210 			continue;
211 
212 		local_mac = mdesc_get_property(hp, target,
213 					       local_mac_prop, NULL);
214 		if (local_mac)
215 			break;
216 	}
217 	if (!local_mac)
218 		return ERR_PTR(-ENODEV);
219 
220 	return vnet_find_or_create(local_mac, vdev);
221 }
222 
223 static struct ldc_channel_config vnet_ldc_cfg = {
224 	.event		= sunvnet_event_common,
225 	.mtu		= 64,
226 	.mode		= LDC_MODE_UNRELIABLE,
227 };
228 
229 static struct vio_driver_ops vnet_vio_ops = {
230 	.send_attr		= sunvnet_send_attr_common,
231 	.handle_attr		= sunvnet_handle_attr_common,
232 	.handshake_complete	= sunvnet_handshake_complete_common,
233 };
234 
235 static void print_version(void)
236 {
237 	printk_once(KERN_INFO "%s", version);
238 }
239 
240 const char *remote_macaddr_prop = "remote-mac-address";
241 
242 static int vnet_port_probe(struct vio_dev *vdev, const struct vio_device_id *id)
243 {
244 	struct mdesc_handle *hp;
245 	struct vnet_port *port;
246 	unsigned long flags;
247 	struct vnet *vp;
248 	const u64 *rmac;
249 	int len, i, err, switch_port;
250 
251 	print_version();
252 
253 	hp = mdesc_grab();
254 
255 	vp = vnet_find_parent(hp, vdev->mp, vdev);
256 	if (IS_ERR(vp)) {
257 		pr_err("Cannot find port parent vnet\n");
258 		err = PTR_ERR(vp);
259 		goto err_out_put_mdesc;
260 	}
261 
262 	rmac = mdesc_get_property(hp, vdev->mp, remote_macaddr_prop, &len);
263 	err = -ENODEV;
264 	if (!rmac) {
265 		pr_err("Port lacks %s property\n", remote_macaddr_prop);
266 		goto err_out_put_mdesc;
267 	}
268 
269 	port = kzalloc(sizeof(*port), GFP_KERNEL);
270 	err = -ENOMEM;
271 	if (!port)
272 		goto err_out_put_mdesc;
273 
274 	for (i = 0; i < ETH_ALEN; i++)
275 		port->raddr[i] = (*rmac >> (5 - i) * 8) & 0xff;
276 
277 	port->vp = vp;
278 
279 	err = vio_driver_init(&port->vio, vdev, VDEV_NETWORK,
280 			      vnet_versions, ARRAY_SIZE(vnet_versions),
281 			      &vnet_vio_ops, vp->dev->name);
282 	if (err)
283 		goto err_out_free_port;
284 
285 	err = vio_ldc_alloc(&port->vio, &vnet_ldc_cfg, port);
286 	if (err)
287 		goto err_out_free_port;
288 
289 	netif_napi_add(port->vp->dev, &port->napi, sunvnet_poll_common,
290 		       NAPI_POLL_WEIGHT);
291 
292 	INIT_HLIST_NODE(&port->hash);
293 	INIT_LIST_HEAD(&port->list);
294 
295 	switch_port = 0;
296 	if (mdesc_get_property(hp, vdev->mp, "switch-port", NULL) != NULL)
297 		switch_port = 1;
298 	port->switch_port = switch_port;
299 	port->tso = true;
300 	port->tsolen = 0;
301 
302 	spin_lock_irqsave(&vp->lock, flags);
303 	if (switch_port)
304 		list_add_rcu(&port->list, &vp->port_list);
305 	else
306 		list_add_tail_rcu(&port->list, &vp->port_list);
307 	hlist_add_head_rcu(&port->hash,
308 			   &vp->port_hash[vnet_hashfn(port->raddr)]);
309 	sunvnet_port_add_txq_common(port);
310 	spin_unlock_irqrestore(&vp->lock, flags);
311 
312 	dev_set_drvdata(&vdev->dev, port);
313 
314 	pr_info("%s: PORT ( remote-mac %pM%s )\n",
315 		vp->dev->name, port->raddr, switch_port ? " switch-port" : "");
316 
317 	setup_timer(&port->clean_timer, sunvnet_clean_timer_expire_common,
318 		    (unsigned long)port);
319 
320 	napi_enable(&port->napi);
321 	vio_port_up(&port->vio);
322 
323 	mdesc_release(hp);
324 
325 	return 0;
326 
327 err_out_free_port:
328 	kfree(port);
329 
330 err_out_put_mdesc:
331 	mdesc_release(hp);
332 	return err;
333 }
334 
335 static int vnet_port_remove(struct vio_dev *vdev)
336 {
337 	struct vnet_port *port = dev_get_drvdata(&vdev->dev);
338 
339 	if (port) {
340 
341 		del_timer_sync(&port->vio.timer);
342 
343 		napi_disable(&port->napi);
344 
345 		list_del_rcu(&port->list);
346 		hlist_del_rcu(&port->hash);
347 
348 		synchronize_rcu();
349 		del_timer_sync(&port->clean_timer);
350 		sunvnet_port_rm_txq_common(port);
351 		netif_napi_del(&port->napi);
352 		sunvnet_port_free_tx_bufs_common(port);
353 		vio_ldc_free(&port->vio);
354 
355 		dev_set_drvdata(&vdev->dev, NULL);
356 
357 		kfree(port);
358 
359 	}
360 	return 0;
361 }
362 
363 static const struct vio_device_id vnet_port_match[] = {
364 	{
365 		.type = "vnet-port",
366 	},
367 	{},
368 };
369 MODULE_DEVICE_TABLE(vio, vnet_port_match);
370 
371 static struct vio_driver vnet_port_driver = {
372 	.id_table	= vnet_port_match,
373 	.probe		= vnet_port_probe,
374 	.remove		= vnet_port_remove,
375 	.name		= "vnet_port",
376 };
377 
378 static int __init vnet_init(void)
379 {
380 	return vio_register_driver(&vnet_port_driver);
381 }
382 
383 static void __exit vnet_exit(void)
384 {
385 	vio_unregister_driver(&vnet_port_driver);
386 	vnet_cleanup();
387 }
388 
389 module_init(vnet_init);
390 module_exit(vnet_exit);
391