Skip to content

Commit 2196819

Browse files
sstabelliniBoris Ostrovsky
authored andcommitted
xen/pvcalls: connect to the backend
Implement the probe function for the pvcalls frontend. Read the supported versions, max-page-order and function-calls nodes from xenstore. Only one frontend<->backend connection is supported at any given time for a guest. Store the active frontend device to a static pointer. Introduce a stub functions for the event handler. Signed-off-by: Stefano Stabellini <[email protected]> Reviewed-by: Boris Ostrovsky <[email protected]> CC: [email protected] CC: [email protected] Signed-off-by: Boris Ostrovsky <[email protected]>
1 parent aa7ba37 commit 2196819

File tree

1 file changed

+132
-0
lines changed

1 file changed

+132
-0
lines changed

drivers/xen/pvcalls-front.c

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,12 +104,144 @@ static int pvcalls_front_remove(struct xenbus_device *dev)
104104
static int pvcalls_front_probe(struct xenbus_device *dev,
105105
const struct xenbus_device_id *id)
106106
{
107+
int ret = -ENOMEM, evtchn, i;
108+
unsigned int max_page_order, function_calls, len;
109+
char *versions;
110+
grant_ref_t gref_head = 0;
111+
struct xenbus_transaction xbt;
112+
struct pvcalls_bedata *bedata = NULL;
113+
struct xen_pvcalls_sring *sring;
114+
115+
if (pvcalls_front_dev != NULL) {
116+
dev_err(&dev->dev, "only one PV Calls connection supported\n");
117+
return -EINVAL;
118+
}
119+
120+
versions = xenbus_read(XBT_NIL, dev->otherend, "versions", &len);
121+
if (!len)
122+
return -EINVAL;
123+
if (strcmp(versions, "1")) {
124+
kfree(versions);
125+
return -EINVAL;
126+
}
127+
kfree(versions);
128+
max_page_order = xenbus_read_unsigned(dev->otherend,
129+
"max-page-order", 0);
130+
if (max_page_order < PVCALLS_RING_ORDER)
131+
return -ENODEV;
132+
function_calls = xenbus_read_unsigned(dev->otherend,
133+
"function-calls", 0);
134+
/* See XENBUS_FUNCTIONS_CALLS in pvcalls.h */
135+
if (function_calls != 1)
136+
return -ENODEV;
137+
pr_info("%s max-page-order is %u\n", __func__, max_page_order);
138+
139+
bedata = kzalloc(sizeof(struct pvcalls_bedata), GFP_KERNEL);
140+
if (!bedata)
141+
return -ENOMEM;
142+
143+
dev_set_drvdata(&dev->dev, bedata);
144+
pvcalls_front_dev = dev;
145+
init_waitqueue_head(&bedata->inflight_req);
146+
INIT_LIST_HEAD(&bedata->socket_mappings);
147+
spin_lock_init(&bedata->socket_lock);
148+
bedata->irq = -1;
149+
bedata->ref = -1;
150+
151+
for (i = 0; i < PVCALLS_NR_RSP_PER_RING; i++)
152+
bedata->rsp[i].req_id = PVCALLS_INVALID_ID;
153+
154+
sring = (struct xen_pvcalls_sring *) __get_free_page(GFP_KERNEL |
155+
__GFP_ZERO);
156+
if (!sring)
157+
goto error;
158+
SHARED_RING_INIT(sring);
159+
FRONT_RING_INIT(&bedata->ring, sring, XEN_PAGE_SIZE);
160+
161+
ret = xenbus_alloc_evtchn(dev, &evtchn);
162+
if (ret)
163+
goto error;
164+
165+
bedata->irq = bind_evtchn_to_irqhandler(evtchn,
166+
pvcalls_front_event_handler,
167+
0, "pvcalls-frontend", dev);
168+
if (bedata->irq < 0) {
169+
ret = bedata->irq;
170+
goto error;
171+
}
172+
173+
ret = gnttab_alloc_grant_references(1, &gref_head);
174+
if (ret < 0)
175+
goto error;
176+
bedata->ref = gnttab_claim_grant_reference(&gref_head);
177+
if (bedata->ref < 0) {
178+
ret = bedata->ref;
179+
goto error;
180+
}
181+
gnttab_grant_foreign_access_ref(bedata->ref, dev->otherend_id,
182+
virt_to_gfn((void *)sring), 0);
183+
184+
again:
185+
ret = xenbus_transaction_start(&xbt);
186+
if (ret) {
187+
xenbus_dev_fatal(dev, ret, "starting transaction");
188+
goto error;
189+
}
190+
ret = xenbus_printf(xbt, dev->nodename, "version", "%u", 1);
191+
if (ret)
192+
goto error_xenbus;
193+
ret = xenbus_printf(xbt, dev->nodename, "ring-ref", "%d", bedata->ref);
194+
if (ret)
195+
goto error_xenbus;
196+
ret = xenbus_printf(xbt, dev->nodename, "port", "%u",
197+
evtchn);
198+
if (ret)
199+
goto error_xenbus;
200+
ret = xenbus_transaction_end(xbt, 0);
201+
if (ret) {
202+
if (ret == -EAGAIN)
203+
goto again;
204+
xenbus_dev_fatal(dev, ret, "completing transaction");
205+
goto error;
206+
}
207+
xenbus_switch_state(dev, XenbusStateInitialised);
208+
107209
return 0;
210+
211+
error_xenbus:
212+
xenbus_transaction_end(xbt, 1);
213+
xenbus_dev_fatal(dev, ret, "writing xenstore");
214+
error:
215+
pvcalls_front_remove(dev);
216+
return ret;
108217
}
109218

110219
static void pvcalls_front_changed(struct xenbus_device *dev,
111220
enum xenbus_state backend_state)
112221
{
222+
switch (backend_state) {
223+
case XenbusStateReconfiguring:
224+
case XenbusStateReconfigured:
225+
case XenbusStateInitialising:
226+
case XenbusStateInitialised:
227+
case XenbusStateUnknown:
228+
break;
229+
230+
case XenbusStateInitWait:
231+
break;
232+
233+
case XenbusStateConnected:
234+
xenbus_switch_state(dev, XenbusStateConnected);
235+
break;
236+
237+
case XenbusStateClosed:
238+
if (dev->state == XenbusStateClosed)
239+
break;
240+
/* Missed the backend's CLOSING state -- fallthrough */
241+
case XenbusStateClosing:
242+
xenbus_frontend_closed(dev);
243+
break;
244+
}
113245
}
114246

115247
static struct xenbus_driver pvcalls_front_driver = {

0 commit comments

Comments
 (0)