xref: /openbmc/linux/net/9p/trans_virtio.c (revision b530cc794024be227876a089e66fb17b7b512763)
1*b530cc79SEric Van Hensbergen /*
2*b530cc79SEric Van Hensbergen  * The Guest 9p transport driver
3*b530cc79SEric Van Hensbergen  *
4*b530cc79SEric Van Hensbergen  * This is a trivial pipe-based transport driver based on the lguest console
5*b530cc79SEric Van Hensbergen  * code: we use lguest's DMA mechanism to send bytes out, and register a
6*b530cc79SEric Van Hensbergen  * DMA buffer to receive bytes in.  It is assumed to be present and available
7*b530cc79SEric Van Hensbergen  * from the very beginning of boot.
8*b530cc79SEric Van Hensbergen  *
9*b530cc79SEric Van Hensbergen  * This may be have been done by just instaniating another HVC console,
10*b530cc79SEric Van Hensbergen  * but HVC's blocksize of 16 bytes is annoying and painful to performance.
11*b530cc79SEric Van Hensbergen  *
12*b530cc79SEric Van Hensbergen  * A more efficient transport could be built based on the virtio block driver
13*b530cc79SEric Van Hensbergen  * but it requires some changes in the 9p transport model (which are in
14*b530cc79SEric Van Hensbergen  * progress)
15*b530cc79SEric Van Hensbergen  *
16*b530cc79SEric Van Hensbergen  */
17*b530cc79SEric Van Hensbergen /*
18*b530cc79SEric Van Hensbergen  *  Copyright (C) 2007 Eric Van Hensbergen, IBM Corporation
19*b530cc79SEric Van Hensbergen  *
20*b530cc79SEric Van Hensbergen  *  Based on virtio console driver
21*b530cc79SEric Van Hensbergen  *  Copyright (C) 2006, 2007 Rusty Russell, IBM Corporation
22*b530cc79SEric Van Hensbergen  *
23*b530cc79SEric Van Hensbergen  *  This program is free software; you can redistribute it and/or modify
24*b530cc79SEric Van Hensbergen  *  it under the terms of the GNU General Public License version 2
25*b530cc79SEric Van Hensbergen  *  as published by the Free Software Foundation.
26*b530cc79SEric Van Hensbergen  *
27*b530cc79SEric Van Hensbergen  *  This program is distributed in the hope that it will be useful,
28*b530cc79SEric Van Hensbergen  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
29*b530cc79SEric Van Hensbergen  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
30*b530cc79SEric Van Hensbergen  *  GNU General Public License for more details.
31*b530cc79SEric Van Hensbergen  *
32*b530cc79SEric Van Hensbergen  *  You should have received a copy of the GNU General Public License
33*b530cc79SEric Van Hensbergen  *  along with this program; if not, write to:
34*b530cc79SEric Van Hensbergen  *  Free Software Foundation
35*b530cc79SEric Van Hensbergen  *  51 Franklin Street, Fifth Floor
36*b530cc79SEric Van Hensbergen  *  Boston, MA  02111-1301  USA
37*b530cc79SEric Van Hensbergen  *
38*b530cc79SEric Van Hensbergen  */
39*b530cc79SEric Van Hensbergen 
40*b530cc79SEric Van Hensbergen #include <linux/in.h>
41*b530cc79SEric Van Hensbergen #include <linux/module.h>
42*b530cc79SEric Van Hensbergen #include <linux/net.h>
43*b530cc79SEric Van Hensbergen #include <linux/ipv6.h>
44*b530cc79SEric Van Hensbergen #include <linux/errno.h>
45*b530cc79SEric Van Hensbergen #include <linux/kernel.h>
46*b530cc79SEric Van Hensbergen #include <linux/un.h>
47*b530cc79SEric Van Hensbergen #include <linux/uaccess.h>
48*b530cc79SEric Van Hensbergen #include <linux/inet.h>
49*b530cc79SEric Van Hensbergen #include <linux/idr.h>
50*b530cc79SEric Van Hensbergen #include <linux/file.h>
51*b530cc79SEric Van Hensbergen #include <net/9p/9p.h>
52*b530cc79SEric Van Hensbergen #include <linux/parser.h>
53*b530cc79SEric Van Hensbergen #include <net/9p/transport.h>
54*b530cc79SEric Van Hensbergen #include <linux/scatterlist.h>
55*b530cc79SEric Van Hensbergen #include <linux/virtio.h>
56*b530cc79SEric Van Hensbergen #include <linux/virtio_9p.h>
57*b530cc79SEric Van Hensbergen 
58*b530cc79SEric Van Hensbergen /* a single mutex to manage channel initialization and attachment */
59*b530cc79SEric Van Hensbergen static DECLARE_MUTEX(virtio_9p_lock);
60*b530cc79SEric Van Hensbergen /* global which tracks highest initialized channel */
61*b530cc79SEric Van Hensbergen static int chan_index;
62*b530cc79SEric Van Hensbergen 
63*b530cc79SEric Van Hensbergen /* We keep all per-channel information in a structure.
64*b530cc79SEric Van Hensbergen  * This structure is allocated within the devices dev->mem space.
65*b530cc79SEric Van Hensbergen  * A pointer to the structure will get put in the transport private.
66*b530cc79SEric Van Hensbergen  */
67*b530cc79SEric Van Hensbergen static struct virtio_chan {
68*b530cc79SEric Van Hensbergen 	bool initialized;		/* channel is initialized */
69*b530cc79SEric Van Hensbergen 	bool inuse;			/* channel is in use */
70*b530cc79SEric Van Hensbergen 
71*b530cc79SEric Van Hensbergen 	struct virtqueue *in_vq, *out_vq;
72*b530cc79SEric Van Hensbergen 	struct virtio_device *vdev;
73*b530cc79SEric Van Hensbergen 
74*b530cc79SEric Van Hensbergen 	/* This is our input buffer, and how much data is left in it. */
75*b530cc79SEric Van Hensbergen 	unsigned int in_len;
76*b530cc79SEric Van Hensbergen 	char *in, *inbuf;
77*b530cc79SEric Van Hensbergen 
78*b530cc79SEric Van Hensbergen 	wait_queue_head_t wq;		/* waitq for buffer */
79*b530cc79SEric Van Hensbergen } channels[MAX_9P_CHAN];
80*b530cc79SEric Van Hensbergen 
81*b530cc79SEric Van Hensbergen /* How many bytes left in this page. */
82*b530cc79SEric Van Hensbergen static unsigned int rest_of_page(void *data)
83*b530cc79SEric Van Hensbergen {
84*b530cc79SEric Van Hensbergen 	return PAGE_SIZE - ((unsigned long)data % PAGE_SIZE);
85*b530cc79SEric Van Hensbergen }
86*b530cc79SEric Van Hensbergen 
87*b530cc79SEric Van Hensbergen static int p9_virtio_write(struct p9_trans *trans, void *buf, int count)
88*b530cc79SEric Van Hensbergen {
89*b530cc79SEric Van Hensbergen 	struct virtio_chan *chan = (struct virtio_chan *) trans->priv;
90*b530cc79SEric Van Hensbergen 	struct virtqueue *out_vq = chan->out_vq;
91*b530cc79SEric Van Hensbergen 	struct scatterlist sg[1];
92*b530cc79SEric Van Hensbergen 	unsigned int len;
93*b530cc79SEric Van Hensbergen 
94*b530cc79SEric Van Hensbergen 	P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio write (%d)\n", count);
95*b530cc79SEric Van Hensbergen 
96*b530cc79SEric Van Hensbergen 	/* keep it simple - make sure we don't overflow a page */
97*b530cc79SEric Van Hensbergen 	if (rest_of_page(buf) < count)
98*b530cc79SEric Van Hensbergen 		count = rest_of_page(buf);
99*b530cc79SEric Van Hensbergen 
100*b530cc79SEric Van Hensbergen 	sg_init_one(sg, buf, count);
101*b530cc79SEric Van Hensbergen 
102*b530cc79SEric Van Hensbergen 	/* add_buf wants a token to identify this buffer: we hand it any
103*b530cc79SEric Van Hensbergen 	 * non-NULL pointer, since there's only ever one buffer. */
104*b530cc79SEric Van Hensbergen 	if (out_vq->vq_ops->add_buf(out_vq, sg, 1, 0, (void *)1) == 0) {
105*b530cc79SEric Van Hensbergen 		/* Tell Host to go! */
106*b530cc79SEric Van Hensbergen 		out_vq->vq_ops->kick(out_vq);
107*b530cc79SEric Van Hensbergen 		/* Chill out until it's done with the buffer. */
108*b530cc79SEric Van Hensbergen 		while (!out_vq->vq_ops->get_buf(out_vq, &len))
109*b530cc79SEric Van Hensbergen 			cpu_relax();
110*b530cc79SEric Van Hensbergen 	}
111*b530cc79SEric Van Hensbergen 
112*b530cc79SEric Van Hensbergen 	P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio wrote (%d)\n", count);
113*b530cc79SEric Van Hensbergen 
114*b530cc79SEric Van Hensbergen 	/* We're expected to return the amount of data we wrote: all of it. */
115*b530cc79SEric Van Hensbergen 	return count;
116*b530cc79SEric Van Hensbergen }
117*b530cc79SEric Van Hensbergen 
118*b530cc79SEric Van Hensbergen /* Create a scatter-gather list representing our input buffer and put it in the
119*b530cc79SEric Van Hensbergen  * queue. */
120*b530cc79SEric Van Hensbergen static void add_inbuf(struct virtio_chan *chan)
121*b530cc79SEric Van Hensbergen {
122*b530cc79SEric Van Hensbergen 	struct scatterlist sg[1];
123*b530cc79SEric Van Hensbergen 
124*b530cc79SEric Van Hensbergen 	sg_init_one(sg, chan->inbuf, PAGE_SIZE);
125*b530cc79SEric Van Hensbergen 
126*b530cc79SEric Van Hensbergen 	/* We should always be able to add one buffer to an empty queue. */
127*b530cc79SEric Van Hensbergen 	if (chan->in_vq->vq_ops->add_buf(chan->in_vq, sg, 0, 1, chan->inbuf))
128*b530cc79SEric Van Hensbergen 		BUG();
129*b530cc79SEric Van Hensbergen 	chan->in_vq->vq_ops->kick(chan->in_vq);
130*b530cc79SEric Van Hensbergen }
131*b530cc79SEric Van Hensbergen 
132*b530cc79SEric Van Hensbergen static int p9_virtio_read(struct p9_trans *trans, void *buf, int count)
133*b530cc79SEric Van Hensbergen {
134*b530cc79SEric Van Hensbergen 	struct virtio_chan *chan = (struct virtio_chan *) trans->priv;
135*b530cc79SEric Van Hensbergen 	struct virtqueue *in_vq = chan->in_vq;
136*b530cc79SEric Van Hensbergen 
137*b530cc79SEric Van Hensbergen 	P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio read (%d)\n", count);
138*b530cc79SEric Van Hensbergen 
139*b530cc79SEric Van Hensbergen 	/* If we don't have an input queue yet, we can't get input. */
140*b530cc79SEric Van Hensbergen 	BUG_ON(!in_vq);
141*b530cc79SEric Van Hensbergen 
142*b530cc79SEric Van Hensbergen 	/* No buffer?  Try to get one. */
143*b530cc79SEric Van Hensbergen 	if (!chan->in_len) {
144*b530cc79SEric Van Hensbergen 		chan->in = in_vq->vq_ops->get_buf(in_vq, &chan->in_len);
145*b530cc79SEric Van Hensbergen 		if (!chan->in)
146*b530cc79SEric Van Hensbergen 			return 0;
147*b530cc79SEric Van Hensbergen 	}
148*b530cc79SEric Van Hensbergen 
149*b530cc79SEric Van Hensbergen 	/* You want more than we have to give?  Well, try wanting less! */
150*b530cc79SEric Van Hensbergen 	if (chan->in_len < count)
151*b530cc79SEric Van Hensbergen 		count = chan->in_len;
152*b530cc79SEric Van Hensbergen 
153*b530cc79SEric Van Hensbergen 	/* Copy across to their buffer and increment offset. */
154*b530cc79SEric Van Hensbergen 	memcpy(buf, chan->in, count);
155*b530cc79SEric Van Hensbergen 	chan->in += count;
156*b530cc79SEric Van Hensbergen 	chan->in_len -= count;
157*b530cc79SEric Van Hensbergen 
158*b530cc79SEric Van Hensbergen 	/* Finished?  Re-register buffer so Host will use it again. */
159*b530cc79SEric Van Hensbergen 	if (chan->in_len == 0)
160*b530cc79SEric Van Hensbergen 		add_inbuf(chan);
161*b530cc79SEric Van Hensbergen 
162*b530cc79SEric Van Hensbergen 	P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio finished read (%d)\n",
163*b530cc79SEric Van Hensbergen 									count);
164*b530cc79SEric Van Hensbergen 
165*b530cc79SEric Van Hensbergen 	return count;
166*b530cc79SEric Van Hensbergen }
167*b530cc79SEric Van Hensbergen 
168*b530cc79SEric Van Hensbergen /* The poll function is used by 9p transports to determine if there
169*b530cc79SEric Van Hensbergen  * is there is activity available on a particular channel.  In our case
170*b530cc79SEric Van Hensbergen  * we use it to wait for a callback from the input routines.
171*b530cc79SEric Van Hensbergen  */
172*b530cc79SEric Van Hensbergen static unsigned int
173*b530cc79SEric Van Hensbergen p9_virtio_poll(struct p9_trans *trans, struct poll_table_struct *pt)
174*b530cc79SEric Van Hensbergen {
175*b530cc79SEric Van Hensbergen 	struct virtio_chan *chan = (struct virtio_chan *)trans->priv;
176*b530cc79SEric Van Hensbergen 	struct virtqueue *in_vq = chan->in_vq;
177*b530cc79SEric Van Hensbergen 	int ret = POLLOUT; /* we can always handle more output */
178*b530cc79SEric Van Hensbergen 
179*b530cc79SEric Van Hensbergen 	poll_wait(NULL, &chan->wq, pt);
180*b530cc79SEric Van Hensbergen 
181*b530cc79SEric Van Hensbergen 	/* No buffer?  Try to get one. */
182*b530cc79SEric Van Hensbergen 	if (!chan->in_len)
183*b530cc79SEric Van Hensbergen 		chan->in = in_vq->vq_ops->get_buf(in_vq, &chan->in_len);
184*b530cc79SEric Van Hensbergen 
185*b530cc79SEric Van Hensbergen 	if (chan->in_len)
186*b530cc79SEric Van Hensbergen 		ret |= POLLIN;
187*b530cc79SEric Van Hensbergen 
188*b530cc79SEric Van Hensbergen 	return ret;
189*b530cc79SEric Van Hensbergen }
190*b530cc79SEric Van Hensbergen 
191*b530cc79SEric Van Hensbergen static void p9_virtio_close(struct p9_trans *trans)
192*b530cc79SEric Van Hensbergen {
193*b530cc79SEric Van Hensbergen 	struct virtio_chan *chan = trans->priv;
194*b530cc79SEric Van Hensbergen 
195*b530cc79SEric Van Hensbergen 	down(&virtio_9p_lock);
196*b530cc79SEric Van Hensbergen 	chan->inuse = false;
197*b530cc79SEric Van Hensbergen 	up(&virtio_9p_lock);
198*b530cc79SEric Van Hensbergen 
199*b530cc79SEric Van Hensbergen 	kfree(trans);
200*b530cc79SEric Van Hensbergen }
201*b530cc79SEric Van Hensbergen 
202*b530cc79SEric Van Hensbergen static bool p9_virtio_intr(struct virtqueue *q)
203*b530cc79SEric Van Hensbergen {
204*b530cc79SEric Van Hensbergen 	struct virtio_chan *chan = q->vdev->priv;
205*b530cc79SEric Van Hensbergen 
206*b530cc79SEric Van Hensbergen 	P9_DPRINTK(P9_DEBUG_TRANS, "9p poll_wakeup: %p\n", &chan->wq);
207*b530cc79SEric Van Hensbergen 	wake_up_interruptible(&chan->wq);
208*b530cc79SEric Van Hensbergen 
209*b530cc79SEric Van Hensbergen 	return true;
210*b530cc79SEric Van Hensbergen }
211*b530cc79SEric Van Hensbergen 
212*b530cc79SEric Van Hensbergen static int p9_virtio_probe(struct virtio_device *dev)
213*b530cc79SEric Van Hensbergen {
214*b530cc79SEric Van Hensbergen 	int err;
215*b530cc79SEric Van Hensbergen 	struct virtio_chan *chan;
216*b530cc79SEric Van Hensbergen 	int index;
217*b530cc79SEric Van Hensbergen 
218*b530cc79SEric Van Hensbergen 	down(&virtio_9p_lock);
219*b530cc79SEric Van Hensbergen 	index = chan_index++;
220*b530cc79SEric Van Hensbergen 	chan = &channels[index];
221*b530cc79SEric Van Hensbergen 	up(&virtio_9p_lock);
222*b530cc79SEric Van Hensbergen 
223*b530cc79SEric Van Hensbergen 	if (chan_index > MAX_9P_CHAN) {
224*b530cc79SEric Van Hensbergen 		printk(KERN_ERR "9p: virtio: Maximum channels exceeded\n");
225*b530cc79SEric Van Hensbergen 		BUG();
226*b530cc79SEric Van Hensbergen 	}
227*b530cc79SEric Van Hensbergen 
228*b530cc79SEric Van Hensbergen 	chan->vdev = dev;
229*b530cc79SEric Van Hensbergen 
230*b530cc79SEric Van Hensbergen 	/* This is the scratch page we use to receive console input */
231*b530cc79SEric Van Hensbergen 	chan->inbuf = kmalloc(PAGE_SIZE, GFP_KERNEL);
232*b530cc79SEric Van Hensbergen 	if (!chan->inbuf) {
233*b530cc79SEric Van Hensbergen 		err = -ENOMEM;
234*b530cc79SEric Van Hensbergen 		goto fail;
235*b530cc79SEric Van Hensbergen 	}
236*b530cc79SEric Van Hensbergen 
237*b530cc79SEric Van Hensbergen 	/* Find the input queue. */
238*b530cc79SEric Van Hensbergen 	dev->priv = chan;
239*b530cc79SEric Van Hensbergen 	chan->in_vq = dev->config->find_vq(dev, p9_virtio_intr);
240*b530cc79SEric Van Hensbergen 	if (IS_ERR(chan->in_vq)) {
241*b530cc79SEric Van Hensbergen 		err = PTR_ERR(chan->in_vq);
242*b530cc79SEric Van Hensbergen 		goto free;
243*b530cc79SEric Van Hensbergen 	}
244*b530cc79SEric Van Hensbergen 
245*b530cc79SEric Van Hensbergen 	chan->out_vq = dev->config->find_vq(dev, NULL);
246*b530cc79SEric Van Hensbergen 	if (IS_ERR(chan->out_vq)) {
247*b530cc79SEric Van Hensbergen 		err = PTR_ERR(chan->out_vq);
248*b530cc79SEric Van Hensbergen 		goto free_in_vq;
249*b530cc79SEric Van Hensbergen 	}
250*b530cc79SEric Van Hensbergen 
251*b530cc79SEric Van Hensbergen 	init_waitqueue_head(&chan->wq);
252*b530cc79SEric Van Hensbergen 
253*b530cc79SEric Van Hensbergen 	/* Register the input buffer the first time. */
254*b530cc79SEric Van Hensbergen 	add_inbuf(chan);
255*b530cc79SEric Van Hensbergen 	chan->inuse = false;
256*b530cc79SEric Van Hensbergen 	chan->initialized = true;
257*b530cc79SEric Van Hensbergen 
258*b530cc79SEric Van Hensbergen 	return 0;
259*b530cc79SEric Van Hensbergen 
260*b530cc79SEric Van Hensbergen free_in_vq:
261*b530cc79SEric Van Hensbergen 	dev->config->del_vq(chan->in_vq);
262*b530cc79SEric Van Hensbergen free:
263*b530cc79SEric Van Hensbergen 	kfree(chan->inbuf);
264*b530cc79SEric Van Hensbergen fail:
265*b530cc79SEric Van Hensbergen 	down(&virtio_9p_lock);
266*b530cc79SEric Van Hensbergen 	chan_index--;
267*b530cc79SEric Van Hensbergen 	up(&virtio_9p_lock);
268*b530cc79SEric Van Hensbergen 	return err;
269*b530cc79SEric Van Hensbergen }
270*b530cc79SEric Van Hensbergen 
271*b530cc79SEric Van Hensbergen /* This sets up a transport channel for 9p communication.  Right now
272*b530cc79SEric Van Hensbergen  * we only match the first available channel, but eventually we couldlook up
273*b530cc79SEric Van Hensbergen  * alternate channels by matching devname versus a virtio_config entry.
274*b530cc79SEric Van Hensbergen  * We use a simple reference count mechanism to ensure that only a single
275*b530cc79SEric Van Hensbergen  * mount has a channel open at a time. */
276*b530cc79SEric Van Hensbergen static struct p9_trans *p9_virtio_create(const char *devname, char *args)
277*b530cc79SEric Van Hensbergen {
278*b530cc79SEric Van Hensbergen 	struct p9_trans *trans;
279*b530cc79SEric Van Hensbergen 	int index = 0;
280*b530cc79SEric Van Hensbergen 	struct virtio_chan *chan = channels;
281*b530cc79SEric Van Hensbergen 
282*b530cc79SEric Van Hensbergen 	down(&virtio_9p_lock);
283*b530cc79SEric Van Hensbergen 	while (index < MAX_9P_CHAN) {
284*b530cc79SEric Van Hensbergen 		if (chan->initialized && !chan->inuse) {
285*b530cc79SEric Van Hensbergen 			chan->inuse = true;
286*b530cc79SEric Van Hensbergen 			break;
287*b530cc79SEric Van Hensbergen 		} else {
288*b530cc79SEric Van Hensbergen 			index++;
289*b530cc79SEric Van Hensbergen 			chan = &channels[index];
290*b530cc79SEric Van Hensbergen 		}
291*b530cc79SEric Van Hensbergen 	}
292*b530cc79SEric Van Hensbergen 	up(&virtio_9p_lock);
293*b530cc79SEric Van Hensbergen 
294*b530cc79SEric Van Hensbergen 	if (index >= MAX_9P_CHAN) {
295*b530cc79SEric Van Hensbergen 		printk(KERN_ERR "9p: virtio: couldn't find a free channel\n");
296*b530cc79SEric Van Hensbergen 		return NULL;
297*b530cc79SEric Van Hensbergen 	}
298*b530cc79SEric Van Hensbergen 
299*b530cc79SEric Van Hensbergen 	trans = kmalloc(sizeof(struct p9_trans), GFP_KERNEL);
300*b530cc79SEric Van Hensbergen 	if (!trans) {
301*b530cc79SEric Van Hensbergen 		printk(KERN_ERR "9p: couldn't allocate transport\n");
302*b530cc79SEric Van Hensbergen 		return ERR_PTR(-ENOMEM);
303*b530cc79SEric Van Hensbergen 	}
304*b530cc79SEric Van Hensbergen 
305*b530cc79SEric Van Hensbergen 	trans->write = p9_virtio_write;
306*b530cc79SEric Van Hensbergen 	trans->read = p9_virtio_read;
307*b530cc79SEric Van Hensbergen 	trans->close = p9_virtio_close;
308*b530cc79SEric Van Hensbergen 	trans->poll = p9_virtio_poll;
309*b530cc79SEric Van Hensbergen 	trans->priv = chan;
310*b530cc79SEric Van Hensbergen 
311*b530cc79SEric Van Hensbergen 	return trans;
312*b530cc79SEric Van Hensbergen }
313*b530cc79SEric Van Hensbergen 
314*b530cc79SEric Van Hensbergen #define VIRTIO_ID_9P 9
315*b530cc79SEric Van Hensbergen 
316*b530cc79SEric Van Hensbergen static struct virtio_device_id id_table[] = {
317*b530cc79SEric Van Hensbergen 	{ VIRTIO_ID_9P, VIRTIO_DEV_ANY_ID },
318*b530cc79SEric Van Hensbergen 	{ 0 },
319*b530cc79SEric Van Hensbergen };
320*b530cc79SEric Van Hensbergen 
321*b530cc79SEric Van Hensbergen /* The standard "struct lguest_driver": */
322*b530cc79SEric Van Hensbergen static struct virtio_driver p9_virtio_drv = {
323*b530cc79SEric Van Hensbergen 	.driver.name = 	KBUILD_MODNAME,
324*b530cc79SEric Van Hensbergen 	.driver.owner = THIS_MODULE,
325*b530cc79SEric Van Hensbergen 	.id_table =	id_table,
326*b530cc79SEric Van Hensbergen 	.probe = 	p9_virtio_probe,
327*b530cc79SEric Van Hensbergen };
328*b530cc79SEric Van Hensbergen 
329*b530cc79SEric Van Hensbergen static struct p9_trans_module p9_virtio_trans = {
330*b530cc79SEric Van Hensbergen 	.name = "virtio",
331*b530cc79SEric Van Hensbergen 	.create = p9_virtio_create,
332*b530cc79SEric Van Hensbergen 	.maxsize = PAGE_SIZE,
333*b530cc79SEric Van Hensbergen 	.def = 0,
334*b530cc79SEric Van Hensbergen };
335*b530cc79SEric Van Hensbergen 
336*b530cc79SEric Van Hensbergen /* The standard init function */
337*b530cc79SEric Van Hensbergen static int __init p9_virtio_init(void)
338*b530cc79SEric Van Hensbergen {
339*b530cc79SEric Van Hensbergen 	int count;
340*b530cc79SEric Van Hensbergen 
341*b530cc79SEric Van Hensbergen 	for (count = 0; count < MAX_9P_CHAN; count++)
342*b530cc79SEric Van Hensbergen 		channels[count].initialized = false;
343*b530cc79SEric Van Hensbergen 
344*b530cc79SEric Van Hensbergen 	v9fs_register_trans(&p9_virtio_trans);
345*b530cc79SEric Van Hensbergen 	return register_virtio_driver(&p9_virtio_drv);
346*b530cc79SEric Van Hensbergen }
347*b530cc79SEric Van Hensbergen 
348*b530cc79SEric Van Hensbergen module_init(p9_virtio_init);
349*b530cc79SEric Van Hensbergen 
350*b530cc79SEric Van Hensbergen MODULE_DEVICE_TABLE(virtio, id_table);
351*b530cc79SEric Van Hensbergen MODULE_AUTHOR("Eric Van Hensbergen <ericvh@gmail.com>");
352*b530cc79SEric Van Hensbergen MODULE_DESCRIPTION("Virtio 9p Transport");
353*b530cc79SEric Van Hensbergen MODULE_LICENSE("GPL");
354