162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Xenbus code for netif backend
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2005 Rusty Russell <rusty@rustcorp.com.au>
662306a36Sopenharmony_ci * Copyright (C) 2005 XenSource Ltd
762306a36Sopenharmony_ci*/
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include "common.h"
1062306a36Sopenharmony_ci#include <linux/vmalloc.h>
1162306a36Sopenharmony_ci#include <linux/rtnetlink.h>
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_cistatic int connect_data_rings(struct backend_info *be,
1462306a36Sopenharmony_ci			      struct xenvif_queue *queue);
1562306a36Sopenharmony_cistatic void connect(struct backend_info *be);
1662306a36Sopenharmony_cistatic int read_xenbus_vif_flags(struct backend_info *be);
1762306a36Sopenharmony_cistatic int backend_create_xenvif(struct backend_info *be);
1862306a36Sopenharmony_cistatic void unregister_hotplug_status_watch(struct backend_info *be);
1962306a36Sopenharmony_cistatic void xen_unregister_watchers(struct xenvif *vif);
2062306a36Sopenharmony_cistatic void set_backend_state(struct backend_info *be,
2162306a36Sopenharmony_ci			      enum xenbus_state state);
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS
2462306a36Sopenharmony_cistruct dentry *xen_netback_dbg_root = NULL;
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_cistatic int xenvif_read_io_ring(struct seq_file *m, void *v)
2762306a36Sopenharmony_ci{
2862306a36Sopenharmony_ci	struct xenvif_queue *queue = m->private;
2962306a36Sopenharmony_ci	struct xen_netif_tx_back_ring *tx_ring = &queue->tx;
3062306a36Sopenharmony_ci	struct xen_netif_rx_back_ring *rx_ring = &queue->rx;
3162306a36Sopenharmony_ci	struct netdev_queue *dev_queue;
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci	if (tx_ring->sring) {
3462306a36Sopenharmony_ci		struct xen_netif_tx_sring *sring = tx_ring->sring;
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci		seq_printf(m, "Queue %d\nTX: nr_ents %u\n", queue->id,
3762306a36Sopenharmony_ci			   tx_ring->nr_ents);
3862306a36Sopenharmony_ci		seq_printf(m, "req prod %u (%d) cons %u (%d) event %u (%d)\n",
3962306a36Sopenharmony_ci			   sring->req_prod,
4062306a36Sopenharmony_ci			   sring->req_prod - sring->rsp_prod,
4162306a36Sopenharmony_ci			   tx_ring->req_cons,
4262306a36Sopenharmony_ci			   tx_ring->req_cons - sring->rsp_prod,
4362306a36Sopenharmony_ci			   sring->req_event,
4462306a36Sopenharmony_ci			   sring->req_event - sring->rsp_prod);
4562306a36Sopenharmony_ci		seq_printf(m, "rsp prod %u (base) pvt %u (%d) event %u (%d)\n",
4662306a36Sopenharmony_ci			   sring->rsp_prod,
4762306a36Sopenharmony_ci			   tx_ring->rsp_prod_pvt,
4862306a36Sopenharmony_ci			   tx_ring->rsp_prod_pvt - sring->rsp_prod,
4962306a36Sopenharmony_ci			   sring->rsp_event,
5062306a36Sopenharmony_ci			   sring->rsp_event - sring->rsp_prod);
5162306a36Sopenharmony_ci		seq_printf(m, "pending prod %u pending cons %u nr_pending_reqs %u\n",
5262306a36Sopenharmony_ci			   queue->pending_prod,
5362306a36Sopenharmony_ci			   queue->pending_cons,
5462306a36Sopenharmony_ci			   nr_pending_reqs(queue));
5562306a36Sopenharmony_ci		seq_printf(m, "dealloc prod %u dealloc cons %u dealloc_queue %u\n\n",
5662306a36Sopenharmony_ci			   queue->dealloc_prod,
5762306a36Sopenharmony_ci			   queue->dealloc_cons,
5862306a36Sopenharmony_ci			   queue->dealloc_prod - queue->dealloc_cons);
5962306a36Sopenharmony_ci	}
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	if (rx_ring->sring) {
6262306a36Sopenharmony_ci		struct xen_netif_rx_sring *sring = rx_ring->sring;
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci		seq_printf(m, "RX: nr_ents %u\n", rx_ring->nr_ents);
6562306a36Sopenharmony_ci		seq_printf(m, "req prod %u (%d) cons %u (%d) event %u (%d)\n",
6662306a36Sopenharmony_ci			   sring->req_prod,
6762306a36Sopenharmony_ci			   sring->req_prod - sring->rsp_prod,
6862306a36Sopenharmony_ci			   rx_ring->req_cons,
6962306a36Sopenharmony_ci			   rx_ring->req_cons - sring->rsp_prod,
7062306a36Sopenharmony_ci			   sring->req_event,
7162306a36Sopenharmony_ci			   sring->req_event - sring->rsp_prod);
7262306a36Sopenharmony_ci		seq_printf(m, "rsp prod %u (base) pvt %u (%d) event %u (%d)\n\n",
7362306a36Sopenharmony_ci			   sring->rsp_prod,
7462306a36Sopenharmony_ci			   rx_ring->rsp_prod_pvt,
7562306a36Sopenharmony_ci			   rx_ring->rsp_prod_pvt - sring->rsp_prod,
7662306a36Sopenharmony_ci			   sring->rsp_event,
7762306a36Sopenharmony_ci			   sring->rsp_event - sring->rsp_prod);
7862306a36Sopenharmony_ci	}
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	seq_printf(m, "NAPI state: %lx NAPI weight: %d TX queue len %u\n"
8162306a36Sopenharmony_ci		   "Credit timer_pending: %d, credit: %lu, usec: %lu\n"
8262306a36Sopenharmony_ci		   "remaining: %lu, expires: %lu, now: %lu\n",
8362306a36Sopenharmony_ci		   queue->napi.state, queue->napi.weight,
8462306a36Sopenharmony_ci		   skb_queue_len(&queue->tx_queue),
8562306a36Sopenharmony_ci		   timer_pending(&queue->credit_timeout),
8662306a36Sopenharmony_ci		   queue->credit_bytes,
8762306a36Sopenharmony_ci		   queue->credit_usec,
8862306a36Sopenharmony_ci		   queue->remaining_credit,
8962306a36Sopenharmony_ci		   queue->credit_timeout.expires,
9062306a36Sopenharmony_ci		   jiffies);
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	dev_queue = netdev_get_tx_queue(queue->vif->dev, queue->id);
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	seq_printf(m, "\nRx internal queue: len %u max %u pkts %u %s\n",
9562306a36Sopenharmony_ci		   queue->rx_queue_len, queue->rx_queue_max,
9662306a36Sopenharmony_ci		   skb_queue_len(&queue->rx_queue),
9762306a36Sopenharmony_ci		   netif_tx_queue_stopped(dev_queue) ? "stopped" : "running");
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	return 0;
10062306a36Sopenharmony_ci}
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci#define XENVIF_KICK_STR "kick"
10362306a36Sopenharmony_ci#define BUFFER_SIZE     32
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_cistatic ssize_t
10662306a36Sopenharmony_cixenvif_write_io_ring(struct file *filp, const char __user *buf, size_t count,
10762306a36Sopenharmony_ci		     loff_t *ppos)
10862306a36Sopenharmony_ci{
10962306a36Sopenharmony_ci	struct xenvif_queue *queue =
11062306a36Sopenharmony_ci		((struct seq_file *)filp->private_data)->private;
11162306a36Sopenharmony_ci	int len;
11262306a36Sopenharmony_ci	char write[BUFFER_SIZE];
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	/* don't allow partial writes and check the length */
11562306a36Sopenharmony_ci	if (*ppos != 0)
11662306a36Sopenharmony_ci		return 0;
11762306a36Sopenharmony_ci	if (count >= sizeof(write))
11862306a36Sopenharmony_ci		return -ENOSPC;
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	len = simple_write_to_buffer(write,
12162306a36Sopenharmony_ci				     sizeof(write) - 1,
12262306a36Sopenharmony_ci				     ppos,
12362306a36Sopenharmony_ci				     buf,
12462306a36Sopenharmony_ci				     count);
12562306a36Sopenharmony_ci	if (len < 0)
12662306a36Sopenharmony_ci		return len;
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	write[len] = '\0';
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	if (!strncmp(write, XENVIF_KICK_STR, sizeof(XENVIF_KICK_STR) - 1))
13162306a36Sopenharmony_ci		xenvif_interrupt(0, (void *)queue);
13262306a36Sopenharmony_ci	else {
13362306a36Sopenharmony_ci		pr_warn("Unknown command to io_ring_q%d. Available: kick\n",
13462306a36Sopenharmony_ci			queue->id);
13562306a36Sopenharmony_ci		count = -EINVAL;
13662306a36Sopenharmony_ci	}
13762306a36Sopenharmony_ci	return count;
13862306a36Sopenharmony_ci}
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_cistatic int xenvif_io_ring_open(struct inode *inode, struct file *filp)
14162306a36Sopenharmony_ci{
14262306a36Sopenharmony_ci	int ret;
14362306a36Sopenharmony_ci	void *queue = NULL;
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	if (inode->i_private)
14662306a36Sopenharmony_ci		queue = inode->i_private;
14762306a36Sopenharmony_ci	ret = single_open(filp, xenvif_read_io_ring, queue);
14862306a36Sopenharmony_ci	filp->f_mode |= FMODE_PWRITE;
14962306a36Sopenharmony_ci	return ret;
15062306a36Sopenharmony_ci}
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_cistatic const struct file_operations xenvif_dbg_io_ring_ops_fops = {
15362306a36Sopenharmony_ci	.owner = THIS_MODULE,
15462306a36Sopenharmony_ci	.open = xenvif_io_ring_open,
15562306a36Sopenharmony_ci	.read = seq_read,
15662306a36Sopenharmony_ci	.llseek = seq_lseek,
15762306a36Sopenharmony_ci	.release = single_release,
15862306a36Sopenharmony_ci	.write = xenvif_write_io_ring,
15962306a36Sopenharmony_ci};
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_cistatic int xenvif_ctrl_show(struct seq_file *m, void *v)
16262306a36Sopenharmony_ci{
16362306a36Sopenharmony_ci	struct xenvif *vif = m->private;
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	xenvif_dump_hash_info(vif, m);
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	return 0;
16862306a36Sopenharmony_ci}
16962306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(xenvif_ctrl);
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_cistatic void xenvif_debugfs_addif(struct xenvif *vif)
17262306a36Sopenharmony_ci{
17362306a36Sopenharmony_ci	int i;
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	vif->xenvif_dbg_root = debugfs_create_dir(vif->dev->name,
17662306a36Sopenharmony_ci						  xen_netback_dbg_root);
17762306a36Sopenharmony_ci	for (i = 0; i < vif->num_queues; ++i) {
17862306a36Sopenharmony_ci		char filename[sizeof("io_ring_q") + 4];
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci		snprintf(filename, sizeof(filename), "io_ring_q%d", i);
18162306a36Sopenharmony_ci		debugfs_create_file(filename, 0600, vif->xenvif_dbg_root,
18262306a36Sopenharmony_ci				    &vif->queues[i],
18362306a36Sopenharmony_ci				    &xenvif_dbg_io_ring_ops_fops);
18462306a36Sopenharmony_ci	}
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	if (vif->ctrl_irq)
18762306a36Sopenharmony_ci		debugfs_create_file("ctrl", 0400, vif->xenvif_dbg_root, vif,
18862306a36Sopenharmony_ci				    &xenvif_ctrl_fops);
18962306a36Sopenharmony_ci}
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_cistatic void xenvif_debugfs_delif(struct xenvif *vif)
19262306a36Sopenharmony_ci{
19362306a36Sopenharmony_ci	debugfs_remove_recursive(vif->xenvif_dbg_root);
19462306a36Sopenharmony_ci	vif->xenvif_dbg_root = NULL;
19562306a36Sopenharmony_ci}
19662306a36Sopenharmony_ci#endif /* CONFIG_DEBUG_FS */
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci/*
19962306a36Sopenharmony_ci * Handle the creation of the hotplug script environment.  We add the script
20062306a36Sopenharmony_ci * and vif variables to the environment, for the benefit of the vif-* hotplug
20162306a36Sopenharmony_ci * scripts.
20262306a36Sopenharmony_ci */
20362306a36Sopenharmony_cistatic int netback_uevent(const struct xenbus_device *xdev,
20462306a36Sopenharmony_ci			  struct kobj_uevent_env *env)
20562306a36Sopenharmony_ci{
20662306a36Sopenharmony_ci	struct backend_info *be = dev_get_drvdata(&xdev->dev);
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	if (!be)
20962306a36Sopenharmony_ci		return 0;
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	if (add_uevent_var(env, "script=%s", be->hotplug_script))
21262306a36Sopenharmony_ci		return -ENOMEM;
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	if (!be->vif)
21562306a36Sopenharmony_ci		return 0;
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	return add_uevent_var(env, "vif=%s", be->vif->dev->name);
21862306a36Sopenharmony_ci}
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_cistatic int backend_create_xenvif(struct backend_info *be)
22262306a36Sopenharmony_ci{
22362306a36Sopenharmony_ci	int err;
22462306a36Sopenharmony_ci	long handle;
22562306a36Sopenharmony_ci	struct xenbus_device *dev = be->dev;
22662306a36Sopenharmony_ci	struct xenvif *vif;
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	if (be->vif != NULL)
22962306a36Sopenharmony_ci		return 0;
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	err = xenbus_scanf(XBT_NIL, dev->nodename, "handle", "%li", &handle);
23262306a36Sopenharmony_ci	if (err != 1) {
23362306a36Sopenharmony_ci		xenbus_dev_fatal(dev, err, "reading handle");
23462306a36Sopenharmony_ci		return (err < 0) ? err : -EINVAL;
23562306a36Sopenharmony_ci	}
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	vif = xenvif_alloc(&dev->dev, dev->otherend_id, handle);
23862306a36Sopenharmony_ci	if (IS_ERR(vif)) {
23962306a36Sopenharmony_ci		err = PTR_ERR(vif);
24062306a36Sopenharmony_ci		xenbus_dev_fatal(dev, err, "creating interface");
24162306a36Sopenharmony_ci		return err;
24262306a36Sopenharmony_ci	}
24362306a36Sopenharmony_ci	be->vif = vif;
24462306a36Sopenharmony_ci	vif->be = be;
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci	kobject_uevent(&dev->dev.kobj, KOBJ_ONLINE);
24762306a36Sopenharmony_ci	return 0;
24862306a36Sopenharmony_ci}
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_cistatic void backend_disconnect(struct backend_info *be)
25162306a36Sopenharmony_ci{
25262306a36Sopenharmony_ci	struct xenvif *vif = be->vif;
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	if (vif) {
25562306a36Sopenharmony_ci		unsigned int num_queues = vif->num_queues;
25662306a36Sopenharmony_ci		unsigned int queue_index;
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci		xen_unregister_watchers(vif);
25962306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS
26062306a36Sopenharmony_ci		xenvif_debugfs_delif(vif);
26162306a36Sopenharmony_ci#endif /* CONFIG_DEBUG_FS */
26262306a36Sopenharmony_ci		xenvif_disconnect_data(vif);
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci		/* At this point some of the handlers may still be active
26562306a36Sopenharmony_ci		 * so we need to have additional synchronization here.
26662306a36Sopenharmony_ci		 */
26762306a36Sopenharmony_ci		vif->num_queues = 0;
26862306a36Sopenharmony_ci		synchronize_net();
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci		for (queue_index = 0; queue_index < num_queues; ++queue_index)
27162306a36Sopenharmony_ci			xenvif_deinit_queue(&vif->queues[queue_index]);
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci		vfree(vif->queues);
27462306a36Sopenharmony_ci		vif->queues = NULL;
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci		xenvif_disconnect_ctrl(vif);
27762306a36Sopenharmony_ci	}
27862306a36Sopenharmony_ci}
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_cistatic void backend_connect(struct backend_info *be)
28162306a36Sopenharmony_ci{
28262306a36Sopenharmony_ci	if (be->vif)
28362306a36Sopenharmony_ci		connect(be);
28462306a36Sopenharmony_ci}
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_cistatic inline void backend_switch_state(struct backend_info *be,
28762306a36Sopenharmony_ci					enum xenbus_state state)
28862306a36Sopenharmony_ci{
28962306a36Sopenharmony_ci	struct xenbus_device *dev = be->dev;
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	pr_debug("%s -> %s\n", dev->nodename, xenbus_strstate(state));
29262306a36Sopenharmony_ci	be->state = state;
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	/* If we are waiting for a hotplug script then defer the
29562306a36Sopenharmony_ci	 * actual xenbus state change.
29662306a36Sopenharmony_ci	 */
29762306a36Sopenharmony_ci	if (!be->have_hotplug_status_watch)
29862306a36Sopenharmony_ci		xenbus_switch_state(dev, state);
29962306a36Sopenharmony_ci}
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci/* Handle backend state transitions:
30262306a36Sopenharmony_ci *
30362306a36Sopenharmony_ci * The backend state starts in Initialising and the following transitions are
30462306a36Sopenharmony_ci * allowed.
30562306a36Sopenharmony_ci *
30662306a36Sopenharmony_ci * Initialising -> InitWait -> Connected
30762306a36Sopenharmony_ci *          \
30862306a36Sopenharmony_ci *           \        ^    \         |
30962306a36Sopenharmony_ci *            \       |     \        |
31062306a36Sopenharmony_ci *             \      |      \       |
31162306a36Sopenharmony_ci *              \     |       \      |
31262306a36Sopenharmony_ci *               \    |        \     |
31362306a36Sopenharmony_ci *                \   |         \    |
31462306a36Sopenharmony_ci *                 V  |          V   V
31562306a36Sopenharmony_ci *
31662306a36Sopenharmony_ci *                  Closed  <-> Closing
31762306a36Sopenharmony_ci *
31862306a36Sopenharmony_ci * The state argument specifies the eventual state of the backend and the
31962306a36Sopenharmony_ci * function transitions to that state via the shortest path.
32062306a36Sopenharmony_ci */
32162306a36Sopenharmony_cistatic void set_backend_state(struct backend_info *be,
32262306a36Sopenharmony_ci			      enum xenbus_state state)
32362306a36Sopenharmony_ci{
32462306a36Sopenharmony_ci	while (be->state != state) {
32562306a36Sopenharmony_ci		switch (be->state) {
32662306a36Sopenharmony_ci		case XenbusStateInitialising:
32762306a36Sopenharmony_ci			switch (state) {
32862306a36Sopenharmony_ci			case XenbusStateInitWait:
32962306a36Sopenharmony_ci			case XenbusStateConnected:
33062306a36Sopenharmony_ci			case XenbusStateClosing:
33162306a36Sopenharmony_ci				backend_switch_state(be, XenbusStateInitWait);
33262306a36Sopenharmony_ci				break;
33362306a36Sopenharmony_ci			case XenbusStateClosed:
33462306a36Sopenharmony_ci				backend_switch_state(be, XenbusStateClosed);
33562306a36Sopenharmony_ci				break;
33662306a36Sopenharmony_ci			default:
33762306a36Sopenharmony_ci				BUG();
33862306a36Sopenharmony_ci			}
33962306a36Sopenharmony_ci			break;
34062306a36Sopenharmony_ci		case XenbusStateClosed:
34162306a36Sopenharmony_ci			switch (state) {
34262306a36Sopenharmony_ci			case XenbusStateInitWait:
34362306a36Sopenharmony_ci			case XenbusStateConnected:
34462306a36Sopenharmony_ci				backend_switch_state(be, XenbusStateInitWait);
34562306a36Sopenharmony_ci				break;
34662306a36Sopenharmony_ci			case XenbusStateClosing:
34762306a36Sopenharmony_ci				backend_switch_state(be, XenbusStateClosing);
34862306a36Sopenharmony_ci				break;
34962306a36Sopenharmony_ci			default:
35062306a36Sopenharmony_ci				BUG();
35162306a36Sopenharmony_ci			}
35262306a36Sopenharmony_ci			break;
35362306a36Sopenharmony_ci		case XenbusStateInitWait:
35462306a36Sopenharmony_ci			switch (state) {
35562306a36Sopenharmony_ci			case XenbusStateConnected:
35662306a36Sopenharmony_ci				backend_connect(be);
35762306a36Sopenharmony_ci				backend_switch_state(be, XenbusStateConnected);
35862306a36Sopenharmony_ci				break;
35962306a36Sopenharmony_ci			case XenbusStateClosing:
36062306a36Sopenharmony_ci			case XenbusStateClosed:
36162306a36Sopenharmony_ci				backend_switch_state(be, XenbusStateClosing);
36262306a36Sopenharmony_ci				break;
36362306a36Sopenharmony_ci			default:
36462306a36Sopenharmony_ci				BUG();
36562306a36Sopenharmony_ci			}
36662306a36Sopenharmony_ci			break;
36762306a36Sopenharmony_ci		case XenbusStateConnected:
36862306a36Sopenharmony_ci			switch (state) {
36962306a36Sopenharmony_ci			case XenbusStateInitWait:
37062306a36Sopenharmony_ci			case XenbusStateClosing:
37162306a36Sopenharmony_ci			case XenbusStateClosed:
37262306a36Sopenharmony_ci				backend_disconnect(be);
37362306a36Sopenharmony_ci				backend_switch_state(be, XenbusStateClosing);
37462306a36Sopenharmony_ci				break;
37562306a36Sopenharmony_ci			default:
37662306a36Sopenharmony_ci				BUG();
37762306a36Sopenharmony_ci			}
37862306a36Sopenharmony_ci			break;
37962306a36Sopenharmony_ci		case XenbusStateClosing:
38062306a36Sopenharmony_ci			switch (state) {
38162306a36Sopenharmony_ci			case XenbusStateInitWait:
38262306a36Sopenharmony_ci			case XenbusStateConnected:
38362306a36Sopenharmony_ci			case XenbusStateClosed:
38462306a36Sopenharmony_ci				backend_switch_state(be, XenbusStateClosed);
38562306a36Sopenharmony_ci				break;
38662306a36Sopenharmony_ci			default:
38762306a36Sopenharmony_ci				BUG();
38862306a36Sopenharmony_ci			}
38962306a36Sopenharmony_ci			break;
39062306a36Sopenharmony_ci		default:
39162306a36Sopenharmony_ci			BUG();
39262306a36Sopenharmony_ci		}
39362306a36Sopenharmony_ci	}
39462306a36Sopenharmony_ci}
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_cistatic void read_xenbus_frontend_xdp(struct backend_info *be,
39762306a36Sopenharmony_ci				      struct xenbus_device *dev)
39862306a36Sopenharmony_ci{
39962306a36Sopenharmony_ci	struct xenvif *vif = be->vif;
40062306a36Sopenharmony_ci	u16 headroom;
40162306a36Sopenharmony_ci	int err;
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	err = xenbus_scanf(XBT_NIL, dev->otherend,
40462306a36Sopenharmony_ci			   "xdp-headroom", "%hu", &headroom);
40562306a36Sopenharmony_ci	if (err != 1) {
40662306a36Sopenharmony_ci		vif->xdp_headroom = 0;
40762306a36Sopenharmony_ci		return;
40862306a36Sopenharmony_ci	}
40962306a36Sopenharmony_ci	if (headroom > XEN_NETIF_MAX_XDP_HEADROOM)
41062306a36Sopenharmony_ci		headroom = XEN_NETIF_MAX_XDP_HEADROOM;
41162306a36Sopenharmony_ci	vif->xdp_headroom = headroom;
41262306a36Sopenharmony_ci}
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci/*
41562306a36Sopenharmony_ci * Callback received when the frontend's state changes.
41662306a36Sopenharmony_ci */
41762306a36Sopenharmony_cistatic void frontend_changed(struct xenbus_device *dev,
41862306a36Sopenharmony_ci			     enum xenbus_state frontend_state)
41962306a36Sopenharmony_ci{
42062306a36Sopenharmony_ci	struct backend_info *be = dev_get_drvdata(&dev->dev);
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci	pr_debug("%s -> %s\n", dev->otherend, xenbus_strstate(frontend_state));
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	be->frontend_state = frontend_state;
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	switch (frontend_state) {
42762306a36Sopenharmony_ci	case XenbusStateInitialising:
42862306a36Sopenharmony_ci		set_backend_state(be, XenbusStateInitWait);
42962306a36Sopenharmony_ci		break;
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci	case XenbusStateInitialised:
43262306a36Sopenharmony_ci		break;
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	case XenbusStateConnected:
43562306a36Sopenharmony_ci		set_backend_state(be, XenbusStateConnected);
43662306a36Sopenharmony_ci		break;
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	case XenbusStateReconfiguring:
43962306a36Sopenharmony_ci		read_xenbus_frontend_xdp(be, dev);
44062306a36Sopenharmony_ci		xenbus_switch_state(dev, XenbusStateReconfigured);
44162306a36Sopenharmony_ci		break;
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci	case XenbusStateClosing:
44462306a36Sopenharmony_ci		set_backend_state(be, XenbusStateClosing);
44562306a36Sopenharmony_ci		break;
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ci	case XenbusStateClosed:
44862306a36Sopenharmony_ci		set_backend_state(be, XenbusStateClosed);
44962306a36Sopenharmony_ci		if (xenbus_dev_is_online(dev))
45062306a36Sopenharmony_ci			break;
45162306a36Sopenharmony_ci		fallthrough;	/* if not online */
45262306a36Sopenharmony_ci	case XenbusStateUnknown:
45362306a36Sopenharmony_ci		set_backend_state(be, XenbusStateClosed);
45462306a36Sopenharmony_ci		device_unregister(&dev->dev);
45562306a36Sopenharmony_ci		break;
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci	default:
45862306a36Sopenharmony_ci		xenbus_dev_fatal(dev, -EINVAL, "saw state %d at frontend",
45962306a36Sopenharmony_ci				 frontend_state);
46062306a36Sopenharmony_ci		break;
46162306a36Sopenharmony_ci	}
46262306a36Sopenharmony_ci}
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_cistatic void xen_net_read_rate(struct xenbus_device *dev,
46662306a36Sopenharmony_ci			      unsigned long *bytes, unsigned long *usec)
46762306a36Sopenharmony_ci{
46862306a36Sopenharmony_ci	char *s, *e;
46962306a36Sopenharmony_ci	unsigned long b, u;
47062306a36Sopenharmony_ci	char *ratestr;
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci	/* Default to unlimited bandwidth. */
47362306a36Sopenharmony_ci	*bytes = ~0UL;
47462306a36Sopenharmony_ci	*usec = 0;
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci	ratestr = xenbus_read(XBT_NIL, dev->nodename, "rate", NULL);
47762306a36Sopenharmony_ci	if (IS_ERR(ratestr))
47862306a36Sopenharmony_ci		return;
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	s = ratestr;
48162306a36Sopenharmony_ci	b = simple_strtoul(s, &e, 10);
48262306a36Sopenharmony_ci	if ((s == e) || (*e != ','))
48362306a36Sopenharmony_ci		goto fail;
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci	s = e + 1;
48662306a36Sopenharmony_ci	u = simple_strtoul(s, &e, 10);
48762306a36Sopenharmony_ci	if ((s == e) || (*e != '\0'))
48862306a36Sopenharmony_ci		goto fail;
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	*bytes = b;
49162306a36Sopenharmony_ci	*usec = u;
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_ci	kfree(ratestr);
49462306a36Sopenharmony_ci	return;
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci fail:
49762306a36Sopenharmony_ci	pr_warn("Failed to parse network rate limit. Traffic unlimited.\n");
49862306a36Sopenharmony_ci	kfree(ratestr);
49962306a36Sopenharmony_ci}
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_cistatic int xen_net_read_mac(struct xenbus_device *dev, u8 mac[])
50262306a36Sopenharmony_ci{
50362306a36Sopenharmony_ci	char *s, *e, *macstr;
50462306a36Sopenharmony_ci	int i;
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci	macstr = s = xenbus_read(XBT_NIL, dev->nodename, "mac", NULL);
50762306a36Sopenharmony_ci	if (IS_ERR(macstr))
50862306a36Sopenharmony_ci		return PTR_ERR(macstr);
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci	for (i = 0; i < ETH_ALEN; i++) {
51162306a36Sopenharmony_ci		mac[i] = simple_strtoul(s, &e, 16);
51262306a36Sopenharmony_ci		if ((s == e) || (*e != ((i == ETH_ALEN-1) ? '\0' : ':'))) {
51362306a36Sopenharmony_ci			kfree(macstr);
51462306a36Sopenharmony_ci			return -ENOENT;
51562306a36Sopenharmony_ci		}
51662306a36Sopenharmony_ci		s = e+1;
51762306a36Sopenharmony_ci	}
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci	kfree(macstr);
52062306a36Sopenharmony_ci	return 0;
52162306a36Sopenharmony_ci}
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_cistatic void xen_net_rate_changed(struct xenbus_watch *watch,
52462306a36Sopenharmony_ci				 const char *path, const char *token)
52562306a36Sopenharmony_ci{
52662306a36Sopenharmony_ci	struct xenvif *vif = container_of(watch, struct xenvif, credit_watch);
52762306a36Sopenharmony_ci	struct xenbus_device *dev = xenvif_to_xenbus_device(vif);
52862306a36Sopenharmony_ci	unsigned long   credit_bytes;
52962306a36Sopenharmony_ci	unsigned long   credit_usec;
53062306a36Sopenharmony_ci	unsigned int queue_index;
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ci	xen_net_read_rate(dev, &credit_bytes, &credit_usec);
53362306a36Sopenharmony_ci	for (queue_index = 0; queue_index < vif->num_queues; queue_index++) {
53462306a36Sopenharmony_ci		struct xenvif_queue *queue = &vif->queues[queue_index];
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci		queue->credit_bytes = credit_bytes;
53762306a36Sopenharmony_ci		queue->credit_usec = credit_usec;
53862306a36Sopenharmony_ci		if (!mod_timer_pending(&queue->credit_timeout, jiffies) &&
53962306a36Sopenharmony_ci			queue->remaining_credit > queue->credit_bytes) {
54062306a36Sopenharmony_ci			queue->remaining_credit = queue->credit_bytes;
54162306a36Sopenharmony_ci		}
54262306a36Sopenharmony_ci	}
54362306a36Sopenharmony_ci}
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_cistatic int xen_register_credit_watch(struct xenbus_device *dev,
54662306a36Sopenharmony_ci				     struct xenvif *vif)
54762306a36Sopenharmony_ci{
54862306a36Sopenharmony_ci	int err = 0;
54962306a36Sopenharmony_ci	char *node;
55062306a36Sopenharmony_ci	unsigned maxlen = strlen(dev->nodename) + sizeof("/rate");
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci	if (vif->credit_watch.node)
55362306a36Sopenharmony_ci		return -EADDRINUSE;
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci	node = kmalloc(maxlen, GFP_KERNEL);
55662306a36Sopenharmony_ci	if (!node)
55762306a36Sopenharmony_ci		return -ENOMEM;
55862306a36Sopenharmony_ci	snprintf(node, maxlen, "%s/rate", dev->nodename);
55962306a36Sopenharmony_ci	vif->credit_watch.node = node;
56062306a36Sopenharmony_ci	vif->credit_watch.will_handle = NULL;
56162306a36Sopenharmony_ci	vif->credit_watch.callback = xen_net_rate_changed;
56262306a36Sopenharmony_ci	err = register_xenbus_watch(&vif->credit_watch);
56362306a36Sopenharmony_ci	if (err) {
56462306a36Sopenharmony_ci		pr_err("Failed to set watcher %s\n", vif->credit_watch.node);
56562306a36Sopenharmony_ci		kfree(node);
56662306a36Sopenharmony_ci		vif->credit_watch.node = NULL;
56762306a36Sopenharmony_ci		vif->credit_watch.will_handle = NULL;
56862306a36Sopenharmony_ci		vif->credit_watch.callback = NULL;
56962306a36Sopenharmony_ci	}
57062306a36Sopenharmony_ci	return err;
57162306a36Sopenharmony_ci}
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_cistatic void xen_unregister_credit_watch(struct xenvif *vif)
57462306a36Sopenharmony_ci{
57562306a36Sopenharmony_ci	if (vif->credit_watch.node) {
57662306a36Sopenharmony_ci		unregister_xenbus_watch(&vif->credit_watch);
57762306a36Sopenharmony_ci		kfree(vif->credit_watch.node);
57862306a36Sopenharmony_ci		vif->credit_watch.node = NULL;
57962306a36Sopenharmony_ci	}
58062306a36Sopenharmony_ci}
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_cistatic void xen_mcast_ctrl_changed(struct xenbus_watch *watch,
58362306a36Sopenharmony_ci				   const char *path, const char *token)
58462306a36Sopenharmony_ci{
58562306a36Sopenharmony_ci	struct xenvif *vif = container_of(watch, struct xenvif,
58662306a36Sopenharmony_ci					  mcast_ctrl_watch);
58762306a36Sopenharmony_ci	struct xenbus_device *dev = xenvif_to_xenbus_device(vif);
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_ci	vif->multicast_control = !!xenbus_read_unsigned(dev->otherend,
59062306a36Sopenharmony_ci					"request-multicast-control", 0);
59162306a36Sopenharmony_ci}
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_cistatic int xen_register_mcast_ctrl_watch(struct xenbus_device *dev,
59462306a36Sopenharmony_ci					 struct xenvif *vif)
59562306a36Sopenharmony_ci{
59662306a36Sopenharmony_ci	int err = 0;
59762306a36Sopenharmony_ci	char *node;
59862306a36Sopenharmony_ci	unsigned maxlen = strlen(dev->otherend) +
59962306a36Sopenharmony_ci		sizeof("/request-multicast-control");
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci	if (vif->mcast_ctrl_watch.node) {
60262306a36Sopenharmony_ci		pr_err_ratelimited("Watch is already registered\n");
60362306a36Sopenharmony_ci		return -EADDRINUSE;
60462306a36Sopenharmony_ci	}
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ci	node = kmalloc(maxlen, GFP_KERNEL);
60762306a36Sopenharmony_ci	if (!node) {
60862306a36Sopenharmony_ci		pr_err("Failed to allocate memory for watch\n");
60962306a36Sopenharmony_ci		return -ENOMEM;
61062306a36Sopenharmony_ci	}
61162306a36Sopenharmony_ci	snprintf(node, maxlen, "%s/request-multicast-control",
61262306a36Sopenharmony_ci		 dev->otherend);
61362306a36Sopenharmony_ci	vif->mcast_ctrl_watch.node = node;
61462306a36Sopenharmony_ci	vif->mcast_ctrl_watch.will_handle = NULL;
61562306a36Sopenharmony_ci	vif->mcast_ctrl_watch.callback = xen_mcast_ctrl_changed;
61662306a36Sopenharmony_ci	err = register_xenbus_watch(&vif->mcast_ctrl_watch);
61762306a36Sopenharmony_ci	if (err) {
61862306a36Sopenharmony_ci		pr_err("Failed to set watcher %s\n",
61962306a36Sopenharmony_ci		       vif->mcast_ctrl_watch.node);
62062306a36Sopenharmony_ci		kfree(node);
62162306a36Sopenharmony_ci		vif->mcast_ctrl_watch.node = NULL;
62262306a36Sopenharmony_ci		vif->mcast_ctrl_watch.will_handle = NULL;
62362306a36Sopenharmony_ci		vif->mcast_ctrl_watch.callback = NULL;
62462306a36Sopenharmony_ci	}
62562306a36Sopenharmony_ci	return err;
62662306a36Sopenharmony_ci}
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_cistatic void xen_unregister_mcast_ctrl_watch(struct xenvif *vif)
62962306a36Sopenharmony_ci{
63062306a36Sopenharmony_ci	if (vif->mcast_ctrl_watch.node) {
63162306a36Sopenharmony_ci		unregister_xenbus_watch(&vif->mcast_ctrl_watch);
63262306a36Sopenharmony_ci		kfree(vif->mcast_ctrl_watch.node);
63362306a36Sopenharmony_ci		vif->mcast_ctrl_watch.node = NULL;
63462306a36Sopenharmony_ci	}
63562306a36Sopenharmony_ci}
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_cistatic void xen_register_watchers(struct xenbus_device *dev,
63862306a36Sopenharmony_ci				  struct xenvif *vif)
63962306a36Sopenharmony_ci{
64062306a36Sopenharmony_ci	xen_register_credit_watch(dev, vif);
64162306a36Sopenharmony_ci	xen_register_mcast_ctrl_watch(dev, vif);
64262306a36Sopenharmony_ci}
64362306a36Sopenharmony_ci
64462306a36Sopenharmony_cistatic void xen_unregister_watchers(struct xenvif *vif)
64562306a36Sopenharmony_ci{
64662306a36Sopenharmony_ci	xen_unregister_mcast_ctrl_watch(vif);
64762306a36Sopenharmony_ci	xen_unregister_credit_watch(vif);
64862306a36Sopenharmony_ci}
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_cistatic void unregister_hotplug_status_watch(struct backend_info *be)
65162306a36Sopenharmony_ci{
65262306a36Sopenharmony_ci	if (be->have_hotplug_status_watch) {
65362306a36Sopenharmony_ci		unregister_xenbus_watch(&be->hotplug_status_watch);
65462306a36Sopenharmony_ci		kfree(be->hotplug_status_watch.node);
65562306a36Sopenharmony_ci	}
65662306a36Sopenharmony_ci	be->have_hotplug_status_watch = 0;
65762306a36Sopenharmony_ci}
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_cistatic void hotplug_status_changed(struct xenbus_watch *watch,
66062306a36Sopenharmony_ci				   const char *path,
66162306a36Sopenharmony_ci				   const char *token)
66262306a36Sopenharmony_ci{
66362306a36Sopenharmony_ci	struct backend_info *be = container_of(watch,
66462306a36Sopenharmony_ci					       struct backend_info,
66562306a36Sopenharmony_ci					       hotplug_status_watch);
66662306a36Sopenharmony_ci	char *str;
66762306a36Sopenharmony_ci	unsigned int len;
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ci	str = xenbus_read(XBT_NIL, be->dev->nodename, "hotplug-status", &len);
67062306a36Sopenharmony_ci	if (IS_ERR(str))
67162306a36Sopenharmony_ci		return;
67262306a36Sopenharmony_ci	if (len == sizeof("connected")-1 && !memcmp(str, "connected", len)) {
67362306a36Sopenharmony_ci		/* Complete any pending state change */
67462306a36Sopenharmony_ci		xenbus_switch_state(be->dev, be->state);
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci		/* Not interested in this watch anymore. */
67762306a36Sopenharmony_ci		unregister_hotplug_status_watch(be);
67862306a36Sopenharmony_ci	}
67962306a36Sopenharmony_ci	kfree(str);
68062306a36Sopenharmony_ci}
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_cistatic int connect_ctrl_ring(struct backend_info *be)
68362306a36Sopenharmony_ci{
68462306a36Sopenharmony_ci	struct xenbus_device *dev = be->dev;
68562306a36Sopenharmony_ci	struct xenvif *vif = be->vif;
68662306a36Sopenharmony_ci	unsigned int val;
68762306a36Sopenharmony_ci	grant_ref_t ring_ref;
68862306a36Sopenharmony_ci	unsigned int evtchn;
68962306a36Sopenharmony_ci	int err;
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_ci	err = xenbus_scanf(XBT_NIL, dev->otherend,
69262306a36Sopenharmony_ci			   "ctrl-ring-ref", "%u", &val);
69362306a36Sopenharmony_ci	if (err < 0)
69462306a36Sopenharmony_ci		goto done; /* The frontend does not have a control ring */
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ci	ring_ref = val;
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci	err = xenbus_scanf(XBT_NIL, dev->otherend,
69962306a36Sopenharmony_ci			   "event-channel-ctrl", "%u", &val);
70062306a36Sopenharmony_ci	if (err < 0) {
70162306a36Sopenharmony_ci		xenbus_dev_fatal(dev, err,
70262306a36Sopenharmony_ci				 "reading %s/event-channel-ctrl",
70362306a36Sopenharmony_ci				 dev->otherend);
70462306a36Sopenharmony_ci		goto fail;
70562306a36Sopenharmony_ci	}
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ci	evtchn = val;
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_ci	err = xenvif_connect_ctrl(vif, ring_ref, evtchn);
71062306a36Sopenharmony_ci	if (err) {
71162306a36Sopenharmony_ci		xenbus_dev_fatal(dev, err,
71262306a36Sopenharmony_ci				 "mapping shared-frame %u port %u",
71362306a36Sopenharmony_ci				 ring_ref, evtchn);
71462306a36Sopenharmony_ci		goto fail;
71562306a36Sopenharmony_ci	}
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_cidone:
71862306a36Sopenharmony_ci	return 0;
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_cifail:
72162306a36Sopenharmony_ci	return err;
72262306a36Sopenharmony_ci}
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_cistatic void connect(struct backend_info *be)
72562306a36Sopenharmony_ci{
72662306a36Sopenharmony_ci	int err;
72762306a36Sopenharmony_ci	struct xenbus_device *dev = be->dev;
72862306a36Sopenharmony_ci	unsigned long credit_bytes, credit_usec;
72962306a36Sopenharmony_ci	unsigned int queue_index;
73062306a36Sopenharmony_ci	unsigned int requested_num_queues;
73162306a36Sopenharmony_ci	struct xenvif_queue *queue;
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ci	/* Check whether the frontend requested multiple queues
73462306a36Sopenharmony_ci	 * and read the number requested.
73562306a36Sopenharmony_ci	 */
73662306a36Sopenharmony_ci	requested_num_queues = xenbus_read_unsigned(dev->otherend,
73762306a36Sopenharmony_ci					"multi-queue-num-queues", 1);
73862306a36Sopenharmony_ci	if (requested_num_queues > xenvif_max_queues) {
73962306a36Sopenharmony_ci		/* buggy or malicious guest */
74062306a36Sopenharmony_ci		xenbus_dev_fatal(dev, -EINVAL,
74162306a36Sopenharmony_ci				 "guest requested %u queues, exceeding the maximum of %u.",
74262306a36Sopenharmony_ci				 requested_num_queues, xenvif_max_queues);
74362306a36Sopenharmony_ci		return;
74462306a36Sopenharmony_ci	}
74562306a36Sopenharmony_ci
74662306a36Sopenharmony_ci	err = xen_net_read_mac(dev, be->vif->fe_dev_addr);
74762306a36Sopenharmony_ci	if (err) {
74862306a36Sopenharmony_ci		xenbus_dev_fatal(dev, err, "parsing %s/mac", dev->nodename);
74962306a36Sopenharmony_ci		return;
75062306a36Sopenharmony_ci	}
75162306a36Sopenharmony_ci
75262306a36Sopenharmony_ci	xen_net_read_rate(dev, &credit_bytes, &credit_usec);
75362306a36Sopenharmony_ci	xen_unregister_watchers(be->vif);
75462306a36Sopenharmony_ci	xen_register_watchers(dev, be->vif);
75562306a36Sopenharmony_ci	read_xenbus_vif_flags(be);
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_ci	err = connect_ctrl_ring(be);
75862306a36Sopenharmony_ci	if (err) {
75962306a36Sopenharmony_ci		xenbus_dev_fatal(dev, err, "connecting control ring");
76062306a36Sopenharmony_ci		return;
76162306a36Sopenharmony_ci	}
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_ci	/* Use the number of queues requested by the frontend */
76462306a36Sopenharmony_ci	be->vif->queues = vzalloc(array_size(requested_num_queues,
76562306a36Sopenharmony_ci					     sizeof(struct xenvif_queue)));
76662306a36Sopenharmony_ci	if (!be->vif->queues) {
76762306a36Sopenharmony_ci		xenbus_dev_fatal(dev, -ENOMEM,
76862306a36Sopenharmony_ci				 "allocating queues");
76962306a36Sopenharmony_ci		return;
77062306a36Sopenharmony_ci	}
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_ci	be->vif->num_queues = requested_num_queues;
77362306a36Sopenharmony_ci	be->vif->stalled_queues = requested_num_queues;
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_ci	for (queue_index = 0; queue_index < requested_num_queues; ++queue_index) {
77662306a36Sopenharmony_ci		queue = &be->vif->queues[queue_index];
77762306a36Sopenharmony_ci		queue->vif = be->vif;
77862306a36Sopenharmony_ci		queue->id = queue_index;
77962306a36Sopenharmony_ci		snprintf(queue->name, sizeof(queue->name), "%s-q%u",
78062306a36Sopenharmony_ci				be->vif->dev->name, queue->id);
78162306a36Sopenharmony_ci
78262306a36Sopenharmony_ci		err = xenvif_init_queue(queue);
78362306a36Sopenharmony_ci		if (err) {
78462306a36Sopenharmony_ci			/* xenvif_init_queue() cleans up after itself on
78562306a36Sopenharmony_ci			 * failure, but we need to clean up any previously
78662306a36Sopenharmony_ci			 * initialised queues. Set num_queues to i so that
78762306a36Sopenharmony_ci			 * earlier queues can be destroyed using the regular
78862306a36Sopenharmony_ci			 * disconnect logic.
78962306a36Sopenharmony_ci			 */
79062306a36Sopenharmony_ci			be->vif->num_queues = queue_index;
79162306a36Sopenharmony_ci			goto err;
79262306a36Sopenharmony_ci		}
79362306a36Sopenharmony_ci
79462306a36Sopenharmony_ci		queue->credit_bytes = credit_bytes;
79562306a36Sopenharmony_ci		queue->remaining_credit = credit_bytes;
79662306a36Sopenharmony_ci		queue->credit_usec = credit_usec;
79762306a36Sopenharmony_ci
79862306a36Sopenharmony_ci		err = connect_data_rings(be, queue);
79962306a36Sopenharmony_ci		if (err) {
80062306a36Sopenharmony_ci			/* connect_data_rings() cleans up after itself on
80162306a36Sopenharmony_ci			 * failure, but we need to clean up after
80262306a36Sopenharmony_ci			 * xenvif_init_queue() here, and also clean up any
80362306a36Sopenharmony_ci			 * previously initialised queues.
80462306a36Sopenharmony_ci			 */
80562306a36Sopenharmony_ci			xenvif_deinit_queue(queue);
80662306a36Sopenharmony_ci			be->vif->num_queues = queue_index;
80762306a36Sopenharmony_ci			goto err;
80862306a36Sopenharmony_ci		}
80962306a36Sopenharmony_ci	}
81062306a36Sopenharmony_ci
81162306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS
81262306a36Sopenharmony_ci	xenvif_debugfs_addif(be->vif);
81362306a36Sopenharmony_ci#endif /* CONFIG_DEBUG_FS */
81462306a36Sopenharmony_ci
81562306a36Sopenharmony_ci	/* Initialisation completed, tell core driver the number of
81662306a36Sopenharmony_ci	 * active queues.
81762306a36Sopenharmony_ci	 */
81862306a36Sopenharmony_ci	rtnl_lock();
81962306a36Sopenharmony_ci	netif_set_real_num_tx_queues(be->vif->dev, requested_num_queues);
82062306a36Sopenharmony_ci	netif_set_real_num_rx_queues(be->vif->dev, requested_num_queues);
82162306a36Sopenharmony_ci	rtnl_unlock();
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_ci	xenvif_carrier_on(be->vif);
82462306a36Sopenharmony_ci
82562306a36Sopenharmony_ci	unregister_hotplug_status_watch(be);
82662306a36Sopenharmony_ci	err = xenbus_watch_pathfmt(dev, &be->hotplug_status_watch, NULL,
82762306a36Sopenharmony_ci				   hotplug_status_changed,
82862306a36Sopenharmony_ci				   "%s/%s", dev->nodename, "hotplug-status");
82962306a36Sopenharmony_ci	if (!err)
83062306a36Sopenharmony_ci		be->have_hotplug_status_watch = 1;
83162306a36Sopenharmony_ci
83262306a36Sopenharmony_ci	netif_tx_wake_all_queues(be->vif->dev);
83362306a36Sopenharmony_ci
83462306a36Sopenharmony_ci	return;
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_cierr:
83762306a36Sopenharmony_ci	if (be->vif->num_queues > 0)
83862306a36Sopenharmony_ci		xenvif_disconnect_data(be->vif); /* Clean up existing queues */
83962306a36Sopenharmony_ci	for (queue_index = 0; queue_index < be->vif->num_queues; ++queue_index)
84062306a36Sopenharmony_ci		xenvif_deinit_queue(&be->vif->queues[queue_index]);
84162306a36Sopenharmony_ci	vfree(be->vif->queues);
84262306a36Sopenharmony_ci	be->vif->queues = NULL;
84362306a36Sopenharmony_ci	be->vif->num_queues = 0;
84462306a36Sopenharmony_ci	xenvif_disconnect_ctrl(be->vif);
84562306a36Sopenharmony_ci	return;
84662306a36Sopenharmony_ci}
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_ci
84962306a36Sopenharmony_cistatic int connect_data_rings(struct backend_info *be,
85062306a36Sopenharmony_ci			      struct xenvif_queue *queue)
85162306a36Sopenharmony_ci{
85262306a36Sopenharmony_ci	struct xenbus_device *dev = be->dev;
85362306a36Sopenharmony_ci	unsigned int num_queues = queue->vif->num_queues;
85462306a36Sopenharmony_ci	unsigned long tx_ring_ref, rx_ring_ref;
85562306a36Sopenharmony_ci	unsigned int tx_evtchn, rx_evtchn;
85662306a36Sopenharmony_ci	int err;
85762306a36Sopenharmony_ci	char *xspath;
85862306a36Sopenharmony_ci	size_t xspathsize;
85962306a36Sopenharmony_ci	const size_t xenstore_path_ext_size = 11; /* sufficient for "/queue-NNN" */
86062306a36Sopenharmony_ci
86162306a36Sopenharmony_ci	/* If the frontend requested 1 queue, or we have fallen back
86262306a36Sopenharmony_ci	 * to single queue due to lack of frontend support for multi-
86362306a36Sopenharmony_ci	 * queue, expect the remaining XenStore keys in the toplevel
86462306a36Sopenharmony_ci	 * directory. Otherwise, expect them in a subdirectory called
86562306a36Sopenharmony_ci	 * queue-N.
86662306a36Sopenharmony_ci	 */
86762306a36Sopenharmony_ci	if (num_queues == 1) {
86862306a36Sopenharmony_ci		xspath = kstrdup(dev->otherend, GFP_KERNEL);
86962306a36Sopenharmony_ci		if (!xspath) {
87062306a36Sopenharmony_ci			xenbus_dev_fatal(dev, -ENOMEM,
87162306a36Sopenharmony_ci					 "reading ring references");
87262306a36Sopenharmony_ci			return -ENOMEM;
87362306a36Sopenharmony_ci		}
87462306a36Sopenharmony_ci	} else {
87562306a36Sopenharmony_ci		xspathsize = strlen(dev->otherend) + xenstore_path_ext_size;
87662306a36Sopenharmony_ci		xspath = kzalloc(xspathsize, GFP_KERNEL);
87762306a36Sopenharmony_ci		if (!xspath) {
87862306a36Sopenharmony_ci			xenbus_dev_fatal(dev, -ENOMEM,
87962306a36Sopenharmony_ci					 "reading ring references");
88062306a36Sopenharmony_ci			return -ENOMEM;
88162306a36Sopenharmony_ci		}
88262306a36Sopenharmony_ci		snprintf(xspath, xspathsize, "%s/queue-%u", dev->otherend,
88362306a36Sopenharmony_ci			 queue->id);
88462306a36Sopenharmony_ci	}
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_ci	err = xenbus_gather(XBT_NIL, xspath,
88762306a36Sopenharmony_ci			    "tx-ring-ref", "%lu", &tx_ring_ref,
88862306a36Sopenharmony_ci			    "rx-ring-ref", "%lu", &rx_ring_ref, NULL);
88962306a36Sopenharmony_ci	if (err) {
89062306a36Sopenharmony_ci		xenbus_dev_fatal(dev, err,
89162306a36Sopenharmony_ci				 "reading %s/ring-ref",
89262306a36Sopenharmony_ci				 xspath);
89362306a36Sopenharmony_ci		goto err;
89462306a36Sopenharmony_ci	}
89562306a36Sopenharmony_ci
89662306a36Sopenharmony_ci	/* Try split event channels first, then single event channel. */
89762306a36Sopenharmony_ci	err = xenbus_gather(XBT_NIL, xspath,
89862306a36Sopenharmony_ci			    "event-channel-tx", "%u", &tx_evtchn,
89962306a36Sopenharmony_ci			    "event-channel-rx", "%u", &rx_evtchn, NULL);
90062306a36Sopenharmony_ci	if (err < 0) {
90162306a36Sopenharmony_ci		err = xenbus_scanf(XBT_NIL, xspath,
90262306a36Sopenharmony_ci				   "event-channel", "%u", &tx_evtchn);
90362306a36Sopenharmony_ci		if (err < 0) {
90462306a36Sopenharmony_ci			xenbus_dev_fatal(dev, err,
90562306a36Sopenharmony_ci					 "reading %s/event-channel(-tx/rx)",
90662306a36Sopenharmony_ci					 xspath);
90762306a36Sopenharmony_ci			goto err;
90862306a36Sopenharmony_ci		}
90962306a36Sopenharmony_ci		rx_evtchn = tx_evtchn;
91062306a36Sopenharmony_ci	}
91162306a36Sopenharmony_ci
91262306a36Sopenharmony_ci	/* Map the shared frame, irq etc. */
91362306a36Sopenharmony_ci	err = xenvif_connect_data(queue, tx_ring_ref, rx_ring_ref,
91462306a36Sopenharmony_ci				  tx_evtchn, rx_evtchn);
91562306a36Sopenharmony_ci	if (err) {
91662306a36Sopenharmony_ci		xenbus_dev_fatal(dev, err,
91762306a36Sopenharmony_ci				 "mapping shared-frames %lu/%lu port tx %u rx %u",
91862306a36Sopenharmony_ci				 tx_ring_ref, rx_ring_ref,
91962306a36Sopenharmony_ci				 tx_evtchn, rx_evtchn);
92062306a36Sopenharmony_ci		goto err;
92162306a36Sopenharmony_ci	}
92262306a36Sopenharmony_ci
92362306a36Sopenharmony_ci	err = 0;
92462306a36Sopenharmony_cierr: /* Regular return falls through with err == 0 */
92562306a36Sopenharmony_ci	kfree(xspath);
92662306a36Sopenharmony_ci	return err;
92762306a36Sopenharmony_ci}
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_cistatic int read_xenbus_vif_flags(struct backend_info *be)
93062306a36Sopenharmony_ci{
93162306a36Sopenharmony_ci	struct xenvif *vif = be->vif;
93262306a36Sopenharmony_ci	struct xenbus_device *dev = be->dev;
93362306a36Sopenharmony_ci	unsigned int rx_copy;
93462306a36Sopenharmony_ci	int err;
93562306a36Sopenharmony_ci
93662306a36Sopenharmony_ci	err = xenbus_scanf(XBT_NIL, dev->otherend, "request-rx-copy", "%u",
93762306a36Sopenharmony_ci			   &rx_copy);
93862306a36Sopenharmony_ci	if (err == -ENOENT) {
93962306a36Sopenharmony_ci		err = 0;
94062306a36Sopenharmony_ci		rx_copy = 0;
94162306a36Sopenharmony_ci	}
94262306a36Sopenharmony_ci	if (err < 0) {
94362306a36Sopenharmony_ci		xenbus_dev_fatal(dev, err, "reading %s/request-rx-copy",
94462306a36Sopenharmony_ci				 dev->otherend);
94562306a36Sopenharmony_ci		return err;
94662306a36Sopenharmony_ci	}
94762306a36Sopenharmony_ci	if (!rx_copy)
94862306a36Sopenharmony_ci		return -EOPNOTSUPP;
94962306a36Sopenharmony_ci
95062306a36Sopenharmony_ci	if (!xenbus_read_unsigned(dev->otherend, "feature-rx-notify", 0)) {
95162306a36Sopenharmony_ci		/* - Reduce drain timeout to poll more frequently for
95262306a36Sopenharmony_ci		 *   Rx requests.
95362306a36Sopenharmony_ci		 * - Disable Rx stall detection.
95462306a36Sopenharmony_ci		 */
95562306a36Sopenharmony_ci		be->vif->drain_timeout = msecs_to_jiffies(30);
95662306a36Sopenharmony_ci		be->vif->stall_timeout = 0;
95762306a36Sopenharmony_ci	}
95862306a36Sopenharmony_ci
95962306a36Sopenharmony_ci	vif->can_sg = !!xenbus_read_unsigned(dev->otherend, "feature-sg", 0);
96062306a36Sopenharmony_ci
96162306a36Sopenharmony_ci	vif->gso_mask = 0;
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_ci	if (xenbus_read_unsigned(dev->otherend, "feature-gso-tcpv4", 0))
96462306a36Sopenharmony_ci		vif->gso_mask |= GSO_BIT(TCPV4);
96562306a36Sopenharmony_ci
96662306a36Sopenharmony_ci	if (xenbus_read_unsigned(dev->otherend, "feature-gso-tcpv6", 0))
96762306a36Sopenharmony_ci		vif->gso_mask |= GSO_BIT(TCPV6);
96862306a36Sopenharmony_ci
96962306a36Sopenharmony_ci	vif->ip_csum = !xenbus_read_unsigned(dev->otherend,
97062306a36Sopenharmony_ci					     "feature-no-csum-offload", 0);
97162306a36Sopenharmony_ci
97262306a36Sopenharmony_ci	vif->ipv6_csum = !!xenbus_read_unsigned(dev->otherend,
97362306a36Sopenharmony_ci						"feature-ipv6-csum-offload", 0);
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_ci	read_xenbus_frontend_xdp(be, dev);
97662306a36Sopenharmony_ci
97762306a36Sopenharmony_ci	return 0;
97862306a36Sopenharmony_ci}
97962306a36Sopenharmony_ci
98062306a36Sopenharmony_cistatic void netback_remove(struct xenbus_device *dev)
98162306a36Sopenharmony_ci{
98262306a36Sopenharmony_ci	struct backend_info *be = dev_get_drvdata(&dev->dev);
98362306a36Sopenharmony_ci
98462306a36Sopenharmony_ci	unregister_hotplug_status_watch(be);
98562306a36Sopenharmony_ci	xenbus_rm(XBT_NIL, dev->nodename, "hotplug-status");
98662306a36Sopenharmony_ci	if (be->vif) {
98762306a36Sopenharmony_ci		kobject_uevent(&dev->dev.kobj, KOBJ_OFFLINE);
98862306a36Sopenharmony_ci		backend_disconnect(be);
98962306a36Sopenharmony_ci		xenvif_free(be->vif);
99062306a36Sopenharmony_ci		be->vif = NULL;
99162306a36Sopenharmony_ci	}
99262306a36Sopenharmony_ci	kfree(be->hotplug_script);
99362306a36Sopenharmony_ci	kfree(be);
99462306a36Sopenharmony_ci	dev_set_drvdata(&dev->dev, NULL);
99562306a36Sopenharmony_ci}
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_ci/*
99862306a36Sopenharmony_ci * Entry point to this code when a new device is created.  Allocate the basic
99962306a36Sopenharmony_ci * structures and switch to InitWait.
100062306a36Sopenharmony_ci */
100162306a36Sopenharmony_cistatic int netback_probe(struct xenbus_device *dev,
100262306a36Sopenharmony_ci			 const struct xenbus_device_id *id)
100362306a36Sopenharmony_ci{
100462306a36Sopenharmony_ci	const char *message;
100562306a36Sopenharmony_ci	struct xenbus_transaction xbt;
100662306a36Sopenharmony_ci	int err;
100762306a36Sopenharmony_ci	int sg;
100862306a36Sopenharmony_ci	const char *script;
100962306a36Sopenharmony_ci	struct backend_info *be = kzalloc(sizeof(*be), GFP_KERNEL);
101062306a36Sopenharmony_ci
101162306a36Sopenharmony_ci	if (!be) {
101262306a36Sopenharmony_ci		xenbus_dev_fatal(dev, -ENOMEM,
101362306a36Sopenharmony_ci				 "allocating backend structure");
101462306a36Sopenharmony_ci		return -ENOMEM;
101562306a36Sopenharmony_ci	}
101662306a36Sopenharmony_ci
101762306a36Sopenharmony_ci	be->dev = dev;
101862306a36Sopenharmony_ci	dev_set_drvdata(&dev->dev, be);
101962306a36Sopenharmony_ci
102062306a36Sopenharmony_ci	sg = 1;
102162306a36Sopenharmony_ci
102262306a36Sopenharmony_ci	do {
102362306a36Sopenharmony_ci		err = xenbus_transaction_start(&xbt);
102462306a36Sopenharmony_ci		if (err) {
102562306a36Sopenharmony_ci			xenbus_dev_fatal(dev, err, "starting transaction");
102662306a36Sopenharmony_ci			goto fail;
102762306a36Sopenharmony_ci		}
102862306a36Sopenharmony_ci
102962306a36Sopenharmony_ci		err = xenbus_printf(xbt, dev->nodename, "feature-sg", "%d", sg);
103062306a36Sopenharmony_ci		if (err) {
103162306a36Sopenharmony_ci			message = "writing feature-sg";
103262306a36Sopenharmony_ci			goto abort_transaction;
103362306a36Sopenharmony_ci		}
103462306a36Sopenharmony_ci
103562306a36Sopenharmony_ci		err = xenbus_printf(xbt, dev->nodename, "feature-gso-tcpv4",
103662306a36Sopenharmony_ci				    "%d", sg);
103762306a36Sopenharmony_ci		if (err) {
103862306a36Sopenharmony_ci			message = "writing feature-gso-tcpv4";
103962306a36Sopenharmony_ci			goto abort_transaction;
104062306a36Sopenharmony_ci		}
104162306a36Sopenharmony_ci
104262306a36Sopenharmony_ci		err = xenbus_printf(xbt, dev->nodename, "feature-gso-tcpv6",
104362306a36Sopenharmony_ci				    "%d", sg);
104462306a36Sopenharmony_ci		if (err) {
104562306a36Sopenharmony_ci			message = "writing feature-gso-tcpv6";
104662306a36Sopenharmony_ci			goto abort_transaction;
104762306a36Sopenharmony_ci		}
104862306a36Sopenharmony_ci
104962306a36Sopenharmony_ci		/* We support partial checksum setup for IPv6 packets */
105062306a36Sopenharmony_ci		err = xenbus_printf(xbt, dev->nodename,
105162306a36Sopenharmony_ci				    "feature-ipv6-csum-offload",
105262306a36Sopenharmony_ci				    "%d", 1);
105362306a36Sopenharmony_ci		if (err) {
105462306a36Sopenharmony_ci			message = "writing feature-ipv6-csum-offload";
105562306a36Sopenharmony_ci			goto abort_transaction;
105662306a36Sopenharmony_ci		}
105762306a36Sopenharmony_ci
105862306a36Sopenharmony_ci		/* We support rx-copy path. */
105962306a36Sopenharmony_ci		err = xenbus_printf(xbt, dev->nodename,
106062306a36Sopenharmony_ci				    "feature-rx-copy", "%d", 1);
106162306a36Sopenharmony_ci		if (err) {
106262306a36Sopenharmony_ci			message = "writing feature-rx-copy";
106362306a36Sopenharmony_ci			goto abort_transaction;
106462306a36Sopenharmony_ci		}
106562306a36Sopenharmony_ci
106662306a36Sopenharmony_ci		/* we can adjust a headroom for netfront XDP processing */
106762306a36Sopenharmony_ci		err = xenbus_printf(xbt, dev->nodename,
106862306a36Sopenharmony_ci				    "feature-xdp-headroom", "%d",
106962306a36Sopenharmony_ci				    provides_xdp_headroom);
107062306a36Sopenharmony_ci		if (err) {
107162306a36Sopenharmony_ci			message = "writing feature-xdp-headroom";
107262306a36Sopenharmony_ci			goto abort_transaction;
107362306a36Sopenharmony_ci		}
107462306a36Sopenharmony_ci
107562306a36Sopenharmony_ci		/* We don't support rx-flip path (except old guests who
107662306a36Sopenharmony_ci		 * don't grok this feature flag).
107762306a36Sopenharmony_ci		 */
107862306a36Sopenharmony_ci		err = xenbus_printf(xbt, dev->nodename,
107962306a36Sopenharmony_ci				    "feature-rx-flip", "%d", 0);
108062306a36Sopenharmony_ci		if (err) {
108162306a36Sopenharmony_ci			message = "writing feature-rx-flip";
108262306a36Sopenharmony_ci			goto abort_transaction;
108362306a36Sopenharmony_ci		}
108462306a36Sopenharmony_ci
108562306a36Sopenharmony_ci		/* We support dynamic multicast-control. */
108662306a36Sopenharmony_ci		err = xenbus_printf(xbt, dev->nodename,
108762306a36Sopenharmony_ci				    "feature-multicast-control", "%d", 1);
108862306a36Sopenharmony_ci		if (err) {
108962306a36Sopenharmony_ci			message = "writing feature-multicast-control";
109062306a36Sopenharmony_ci			goto abort_transaction;
109162306a36Sopenharmony_ci		}
109262306a36Sopenharmony_ci
109362306a36Sopenharmony_ci		err = xenbus_printf(xbt, dev->nodename,
109462306a36Sopenharmony_ci				    "feature-dynamic-multicast-control",
109562306a36Sopenharmony_ci				    "%d", 1);
109662306a36Sopenharmony_ci		if (err) {
109762306a36Sopenharmony_ci			message = "writing feature-dynamic-multicast-control";
109862306a36Sopenharmony_ci			goto abort_transaction;
109962306a36Sopenharmony_ci		}
110062306a36Sopenharmony_ci
110162306a36Sopenharmony_ci		err = xenbus_transaction_end(xbt, 0);
110262306a36Sopenharmony_ci	} while (err == -EAGAIN);
110362306a36Sopenharmony_ci
110462306a36Sopenharmony_ci	if (err) {
110562306a36Sopenharmony_ci		xenbus_dev_fatal(dev, err, "completing transaction");
110662306a36Sopenharmony_ci		goto fail;
110762306a36Sopenharmony_ci	}
110862306a36Sopenharmony_ci
110962306a36Sopenharmony_ci	/* Split event channels support, this is optional so it is not
111062306a36Sopenharmony_ci	 * put inside the above loop.
111162306a36Sopenharmony_ci	 */
111262306a36Sopenharmony_ci	err = xenbus_printf(XBT_NIL, dev->nodename,
111362306a36Sopenharmony_ci			    "feature-split-event-channels",
111462306a36Sopenharmony_ci			    "%u", separate_tx_rx_irq);
111562306a36Sopenharmony_ci	if (err)
111662306a36Sopenharmony_ci		pr_debug("Error writing feature-split-event-channels\n");
111762306a36Sopenharmony_ci
111862306a36Sopenharmony_ci	/* Multi-queue support: This is an optional feature. */
111962306a36Sopenharmony_ci	err = xenbus_printf(XBT_NIL, dev->nodename,
112062306a36Sopenharmony_ci			    "multi-queue-max-queues", "%u", xenvif_max_queues);
112162306a36Sopenharmony_ci	if (err)
112262306a36Sopenharmony_ci		pr_debug("Error writing multi-queue-max-queues\n");
112362306a36Sopenharmony_ci
112462306a36Sopenharmony_ci	err = xenbus_printf(XBT_NIL, dev->nodename,
112562306a36Sopenharmony_ci			    "feature-ctrl-ring",
112662306a36Sopenharmony_ci			    "%u", true);
112762306a36Sopenharmony_ci	if (err)
112862306a36Sopenharmony_ci		pr_debug("Error writing feature-ctrl-ring\n");
112962306a36Sopenharmony_ci
113062306a36Sopenharmony_ci	backend_switch_state(be, XenbusStateInitWait);
113162306a36Sopenharmony_ci
113262306a36Sopenharmony_ci	script = xenbus_read(XBT_NIL, dev->nodename, "script", NULL);
113362306a36Sopenharmony_ci	if (IS_ERR(script)) {
113462306a36Sopenharmony_ci		err = PTR_ERR(script);
113562306a36Sopenharmony_ci		xenbus_dev_fatal(dev, err, "reading script");
113662306a36Sopenharmony_ci		goto fail;
113762306a36Sopenharmony_ci	}
113862306a36Sopenharmony_ci
113962306a36Sopenharmony_ci	be->hotplug_script = script;
114062306a36Sopenharmony_ci
114162306a36Sopenharmony_ci	/* This kicks hotplug scripts, so do it immediately. */
114262306a36Sopenharmony_ci	err = backend_create_xenvif(be);
114362306a36Sopenharmony_ci	if (err)
114462306a36Sopenharmony_ci		goto fail;
114562306a36Sopenharmony_ci
114662306a36Sopenharmony_ci	return 0;
114762306a36Sopenharmony_ci
114862306a36Sopenharmony_ciabort_transaction:
114962306a36Sopenharmony_ci	xenbus_transaction_end(xbt, 1);
115062306a36Sopenharmony_ci	xenbus_dev_fatal(dev, err, "%s", message);
115162306a36Sopenharmony_cifail:
115262306a36Sopenharmony_ci	pr_debug("failed\n");
115362306a36Sopenharmony_ci	netback_remove(dev);
115462306a36Sopenharmony_ci	return err;
115562306a36Sopenharmony_ci}
115662306a36Sopenharmony_ci
115762306a36Sopenharmony_cistatic const struct xenbus_device_id netback_ids[] = {
115862306a36Sopenharmony_ci	{ "vif" },
115962306a36Sopenharmony_ci	{ "" }
116062306a36Sopenharmony_ci};
116162306a36Sopenharmony_ci
116262306a36Sopenharmony_cistatic struct xenbus_driver netback_driver = {
116362306a36Sopenharmony_ci	.ids = netback_ids,
116462306a36Sopenharmony_ci	.probe = netback_probe,
116562306a36Sopenharmony_ci	.remove = netback_remove,
116662306a36Sopenharmony_ci	.uevent = netback_uevent,
116762306a36Sopenharmony_ci	.otherend_changed = frontend_changed,
116862306a36Sopenharmony_ci	.allow_rebind = true,
116962306a36Sopenharmony_ci};
117062306a36Sopenharmony_ci
117162306a36Sopenharmony_ciint xenvif_xenbus_init(void)
117262306a36Sopenharmony_ci{
117362306a36Sopenharmony_ci	return xenbus_register_backend(&netback_driver);
117462306a36Sopenharmony_ci}
117562306a36Sopenharmony_ci
117662306a36Sopenharmony_civoid xenvif_xenbus_fini(void)
117762306a36Sopenharmony_ci{
117862306a36Sopenharmony_ci	return xenbus_unregister_driver(&netback_driver);
117962306a36Sopenharmony_ci}
1180