version 1.33.4.4, 2011/05/31 03:04:25 |
version 1.34, 2010/04/05 07:19:32 |
|
|
* |
* |
*/ |
*/ |
|
|
#include <sys/cdefs.h> |
|
__KERNEL_RCSID(0, "$NetBSD$"); |
|
|
|
#include "opt_xen.h" |
#include "opt_xen.h" |
|
|
#include <sys/types.h> |
#include <sys/types.h> |
Line 245 xennetback_xenbus_create(struct xenbus_d |
|
Line 242 xennetback_xenbus_create(struct xenbus_d |
|
|
|
if ((err = xenbus_read_ul(NULL, xbusd->xbusd_path, |
if ((err = xenbus_read_ul(NULL, xbusd->xbusd_path, |
"frontend-id", &domid, 10)) != 0) { |
"frontend-id", &domid, 10)) != 0) { |
aprint_error("xvif: can't read %s/frontend-id: %d\n", |
aprint_error("xvif: can' read %s/frontend-id: %d\n", |
xbusd->xbusd_path, err); |
xbusd->xbusd_path, err); |
return err; |
return err; |
} |
} |
if ((err = xenbus_read_ul(NULL, xbusd->xbusd_path, |
if ((err = xenbus_read_ul(NULL, xbusd->xbusd_path, |
"handle", &handle, 10)) != 0) { |
"handle", &handle, 10)) != 0) { |
aprint_error("xvif: can't read %s/handle: %d\n", |
aprint_error("xvif: can' read %s/handle: %d\n", |
xbusd->xbusd_path, err); |
xbusd->xbusd_path, err); |
return err; |
return err; |
} |
} |
Line 274 xennetback_xenbus_create(struct xenbus_d |
|
Line 271 xennetback_xenbus_create(struct xenbus_d |
|
|
|
ifp = &xneti->xni_if; |
ifp = &xneti->xni_if; |
ifp->if_softc = xneti; |
ifp->if_softc = xneti; |
snprintf(ifp->if_xname, IFNAMSIZ, "xvif%di%d", |
|
(int)domid, (int)handle); |
|
|
|
/* read mac address */ |
/* read mac address */ |
if ((err = xenbus_read(NULL, xbusd->xbusd_path, "mac", NULL, &val))) { |
if ((err = xenbus_read(NULL, xbusd->xbusd_path, "mac", NULL, &val))) { |
aprint_error_ifnet(ifp, "can't read %s/mac: %d\n", |
aprint_error("xvif: can' read %s/mac: %d\n", |
xbusd->xbusd_path, err); |
xbusd->xbusd_path, err); |
goto fail; |
goto fail; |
} |
} |
for (i = 0, p = val; i < 6; i++) { |
for (i = 0, p = val; i < 6; i++) { |
xneti->xni_enaddr[i] = strtoul(p, &e, 16); |
xneti->xni_enaddr[i] = strtoul(p, &e, 16); |
if ((e[0] == '\0' && i != 5) && e[0] != ':') { |
if ((e[0] == '\0' && i != 5) && e[0] != ':') { |
aprint_error_ifnet(ifp, |
aprint_error("xvif: %s is not a valid mac address\n", |
"%s is not a valid mac address\n", val); |
val); |
err = EINVAL; |
err = EINVAL; |
goto fail; |
goto fail; |
} |
} |
Line 298 xennetback_xenbus_create(struct xenbus_d |
|
Line 293 xennetback_xenbus_create(struct xenbus_d |
|
/* we can't use the same MAC addr as our guest */ |
/* we can't use the same MAC addr as our guest */ |
xneti->xni_enaddr[3]++; |
xneti->xni_enaddr[3]++; |
/* create pseudo-interface */ |
/* create pseudo-interface */ |
|
snprintf(xneti->xni_if.if_xname, IFNAMSIZ, "xvif%d.%d", |
|
(int)domid, (int)handle); |
aprint_verbose_ifnet(ifp, "Ethernet address %s\n", |
aprint_verbose_ifnet(ifp, "Ethernet address %s\n", |
ether_sprintf(xneti->xni_enaddr)); |
ether_sprintf(xneti->xni_enaddr)); |
ifp->if_flags = |
ifp->if_flags = |
Line 322 xennetback_xenbus_create(struct xenbus_d |
|
Line 319 xennetback_xenbus_create(struct xenbus_d |
|
do { |
do { |
xbt = xenbus_transaction_start(); |
xbt = xenbus_transaction_start(); |
if (xbt == NULL) { |
if (xbt == NULL) { |
aprint_error_ifnet(ifp, |
printf("xbdback %s: can't start transaction\n", |
"%s: can't start transaction\n", |
|
xbusd->xbusd_path); |
xbusd->xbusd_path); |
goto fail; |
goto fail; |
} |
} |
err = xenbus_printf(xbt, xbusd->xbusd_path, |
err = xenbus_printf(xbt, xbusd->xbusd_path, |
"vifname", "%s", ifp->if_xname); |
|
if (err) { |
|
aprint_error_ifnet(ifp, |
|
"failed to write %s/vifname: %d\n", |
|
xbusd->xbusd_path, err); |
|
goto abort_xbt; |
|
} |
|
err = xenbus_printf(xbt, xbusd->xbusd_path, |
|
"feature-rx-copy", "%d", 1); |
"feature-rx-copy", "%d", 1); |
if (err) { |
if (err) { |
aprint_error_ifnet(ifp, |
printf("xbdback: failed to write %s/feature-rx-copy: " |
"failed to write %s/feature-rx-copy: %d\n", |
"%d\n", xbusd->xbusd_path, err); |
xbusd->xbusd_path, err); |
|
goto abort_xbt; |
goto abort_xbt; |
} |
} |
err = xenbus_printf(xbt, xbusd->xbusd_path, |
err = xenbus_printf(xbt, xbusd->xbusd_path, |
"feature-rx-flip", "%d", 1); |
"feature-rx-flip", "%d", 1); |
if (err) { |
if (err) { |
aprint_error_ifnet(ifp, |
printf("xbdback: failed to write %s/feature-rx-flip: " |
"failed to write %s/feature-rx-flip: %d\n", |
"%d\n", xbusd->xbusd_path, err); |
xbusd->xbusd_path, err); |
|
goto abort_xbt; |
goto abort_xbt; |
} |
} |
} while ((err = xenbus_transaction_end(xbt, 0)) == EAGAIN); |
} while ((err = xenbus_transaction_end(xbt, 0)) == EAGAIN); |
if (err) { |
if (err) { |
aprint_error_ifnet(ifp, |
printf("xbdback %s: can't end transaction: %d\n", |
"%s: can't end transaction: %d\n", |
|
xbusd->xbusd_path, err); |
xbusd->xbusd_path, err); |
} |
} |
|
|
err = xenbus_switch_state(xbusd, NULL, XenbusStateInitWait); |
err = xenbus_switch_state(xbusd, NULL, XenbusStateInitWait); |
if (err) { |
if (err) { |
aprint_error_ifnet(ifp, |
printf("failed to switch state on %s: %d\n", |
"failed to switch state on %s: %d\n", |
|
xbusd->xbusd_path, err); |
xbusd->xbusd_path, err); |
goto fail; |
goto fail; |
} |
} |
Line 427 xennetback_xenbus_destroy(void *arg) |
|
Line 411 xennetback_xenbus_destroy(void *arg) |
|
return 0; |
return 0; |
} |
} |
|
|
static int |
static void |
xennetback_connect(struct xnetback_instance *xneti) |
xennetback_frontend_changed(void *arg, XenbusState new_state) |
{ |
{ |
|
struct xnetback_instance *xneti = arg; |
|
struct xenbus_device *xbusd = xneti->xni_xbusd; |
int err; |
int err; |
netif_tx_sring_t *tx_ring; |
netif_tx_sring_t *tx_ring; |
netif_rx_sring_t *rx_ring; |
netif_rx_sring_t *rx_ring; |
struct gnttab_map_grant_ref op; |
struct gnttab_map_grant_ref op; |
struct gnttab_unmap_grant_ref uop; |
|
evtchn_op_t evop; |
evtchn_op_t evop; |
u_long tx_ring_ref, rx_ring_ref; |
u_long tx_ring_ref, rx_ring_ref; |
u_long revtchn, rx_copy; |
u_long revtchn, rx_copy; |
struct xenbus_device *xbusd = xneti->xni_xbusd; |
|
|
|
/* read comunication informations */ |
|
err = xenbus_read_ul(NULL, xbusd->xbusd_otherend, |
|
"tx-ring-ref", &tx_ring_ref, 10); |
|
if (err) { |
|
xenbus_dev_fatal(xbusd, err, "reading %s/tx-ring-ref", |
|
xbusd->xbusd_otherend); |
|
return -1; |
|
} |
|
err = xenbus_read_ul(NULL, xbusd->xbusd_otherend, |
|
"rx-ring-ref", &rx_ring_ref, 10); |
|
if (err) { |
|
xenbus_dev_fatal(xbusd, err, "reading %s/rx-ring-ref", |
|
xbusd->xbusd_otherend); |
|
return -1; |
|
} |
|
err = xenbus_read_ul(NULL, xbusd->xbusd_otherend, |
|
"event-channel", &revtchn, 10); |
|
if (err) { |
|
xenbus_dev_fatal(xbusd, err, "reading %s/event-channel", |
|
xbusd->xbusd_otherend); |
|
return -1; |
|
} |
|
err = xenbus_read_ul(NULL, xbusd->xbusd_otherend, |
|
"request-rx-copy", &rx_copy, 10); |
|
if (err == ENOENT) |
|
rx_copy = 0; |
|
else if (err) { |
|
xenbus_dev_fatal(xbusd, err, "reading %s/request-rx-copy", |
|
xbusd->xbusd_otherend); |
|
return -1; |
|
} |
|
|
|
if (rx_copy) |
|
xneti->xni_softintr = softint_establish(SOFTINT_NET, |
|
xennetback_ifsoftstart_copy, xneti); |
|
else |
|
xneti->xni_softintr = softint_establish(SOFTINT_NET, |
|
xennetback_ifsoftstart_transfer, xneti); |
|
|
|
if (xneti->xni_softintr == NULL) { |
|
err = ENOMEM; |
|
xenbus_dev_fatal(xbusd, ENOMEM, |
|
"can't allocate softint", xbusd->xbusd_otherend); |
|
return -1; |
|
} |
|
|
|
/* allocate VA space and map rings */ |
|
xneti->xni_tx_ring_va = uvm_km_alloc(kernel_map, PAGE_SIZE, 0, |
|
UVM_KMF_VAONLY); |
|
if (xneti->xni_tx_ring_va == 0) { |
|
xenbus_dev_fatal(xbusd, ENOMEM, |
|
"can't get VA for TX ring", xbusd->xbusd_otherend); |
|
goto err1; |
|
} |
|
tx_ring = (void *)xneti->xni_tx_ring_va; |
|
|
|
xneti->xni_rx_ring_va = uvm_km_alloc(kernel_map, PAGE_SIZE, 0, |
|
UVM_KMF_VAONLY); |
|
if (xneti->xni_rx_ring_va == 0) { |
|
xenbus_dev_fatal(xbusd, ENOMEM, |
|
"can't get VA for RX ring", xbusd->xbusd_otherend); |
|
goto err1; |
|
} |
|
rx_ring = (void *)xneti->xni_rx_ring_va; |
|
|
|
op.host_addr = xneti->xni_tx_ring_va; |
|
op.flags = GNTMAP_host_map; |
|
op.ref = tx_ring_ref; |
|
op.dom = xneti->xni_domid; |
|
err = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1); |
|
if (err || op.status) { |
|
aprint_error_ifnet(&xneti->xni_if, |
|
"can't map TX grant ref: err %d status %d\n", |
|
err, op.status); |
|
goto err2; |
|
} |
|
xneti->xni_tx_ring_handle = op.handle; |
|
BACK_RING_INIT(&xneti->xni_txring, tx_ring, PAGE_SIZE); |
|
|
|
op.host_addr = xneti->xni_rx_ring_va; |
|
op.flags = GNTMAP_host_map; |
|
op.ref = rx_ring_ref; |
|
op.dom = xneti->xni_domid; |
|
err = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1); |
|
if (err || op.status) { |
|
aprint_error_ifnet(&xneti->xni_if, |
|
"can't map RX grant ref: err %d status %d\n", |
|
err, op.status); |
|
goto err2; |
|
} |
|
xneti->xni_rx_ring_handle = op.handle; |
|
BACK_RING_INIT(&xneti->xni_rxring, rx_ring, PAGE_SIZE); |
|
|
|
evop.cmd = EVTCHNOP_bind_interdomain; |
|
evop.u.bind_interdomain.remote_dom = xneti->xni_domid; |
|
evop.u.bind_interdomain.remote_port = revtchn; |
|
err = HYPERVISOR_event_channel_op(&evop); |
|
if (err) { |
|
aprint_error_ifnet(&xneti->xni_if, |
|
"can't get event channel: %d\n", err); |
|
goto err2; |
|
} |
|
xneti->xni_evtchn = evop.u.bind_interdomain.local_port; |
|
xen_wmb(); |
|
xneti->xni_status = CONNECTED; |
|
xen_wmb(); |
|
|
|
event_set_handler(xneti->xni_evtchn, xennetback_evthandler, |
|
xneti, IPL_NET, xneti->xni_if.if_xname); |
|
xennetback_ifinit(&xneti->xni_if); |
|
hypervisor_enable_event(xneti->xni_evtchn); |
|
hypervisor_notify_via_evtchn(xneti->xni_evtchn); |
|
return 0; |
|
|
|
err2: |
|
/* unmap rings */ |
|
if (xneti->xni_tx_ring_handle != 0) { |
|
uop.host_addr = xneti->xni_tx_ring_va; |
|
uop.handle = xneti->xni_tx_ring_handle; |
|
uop.dev_bus_addr = 0; |
|
err = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, |
|
&uop, 1); |
|
if (err) |
|
aprint_error_ifnet(&xneti->xni_if, |
|
"unmap_grant_ref failed: %d\n", err); |
|
} |
|
|
|
if (xneti->xni_rx_ring_handle != 0) { |
|
uop.host_addr = xneti->xni_rx_ring_va; |
|
uop.handle = xneti->xni_rx_ring_handle; |
|
uop.dev_bus_addr = 0; |
|
err = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, |
|
&uop, 1); |
|
if (err) |
|
aprint_error_ifnet(&xneti->xni_if, |
|
"unmap_grant_ref failed: %d\n", err); |
|
} |
|
|
|
err1: |
|
/* free rings VA space */ |
|
if (xneti->xni_rx_ring_va != 0) |
|
uvm_km_free(kernel_map, xneti->xni_rx_ring_va, |
|
PAGE_SIZE, UVM_KMF_VAONLY); |
|
|
|
if (xneti->xni_tx_ring_va != 0) |
|
uvm_km_free(kernel_map, xneti->xni_tx_ring_va, |
|
PAGE_SIZE, UVM_KMF_VAONLY); |
|
|
|
softint_disestablish(xneti->xni_softintr); |
|
return -1; |
|
|
|
} |
|
|
|
static void |
|
xennetback_frontend_changed(void *arg, XenbusState new_state) |
|
{ |
|
struct xnetback_instance *xneti = arg; |
|
struct xenbus_device *xbusd = xneti->xni_xbusd; |
|
|
|
XENPRINTF(("%s: new state %d\n", xneti->xni_if.if_xname, new_state)); |
XENPRINTF(("%s: new state %d\n", xneti->xni_if.if_xname, new_state)); |
switch(new_state) { |
switch(new_state) { |
Line 606 xennetback_frontend_changed(void *arg, X |
|
Line 431 xennetback_frontend_changed(void *arg, X |
|
break; |
break; |
|
|
case XenbusStateConnected: |
case XenbusStateConnected: |
if (xneti->xni_status == CONNECTED) |
/* read comunication informations */ |
|
err = xenbus_read_ul(NULL, xbusd->xbusd_otherend, |
|
"tx-ring-ref", &tx_ring_ref, 10); |
|
if (err) { |
|
xenbus_dev_fatal(xbusd, err, "reading %s/tx-ring-ref", |
|
xbusd->xbusd_otherend); |
|
break; |
|
} |
|
err = xenbus_read_ul(NULL, xbusd->xbusd_otherend, |
|
"rx-ring-ref", &rx_ring_ref, 10); |
|
if (err) { |
|
xenbus_dev_fatal(xbusd, err, "reading %s/rx-ring-ref", |
|
xbusd->xbusd_otherend); |
|
break; |
|
} |
|
err = xenbus_read_ul(NULL, xbusd->xbusd_otherend, |
|
"event-channel", &revtchn, 10); |
|
if (err) { |
|
xenbus_dev_fatal(xbusd, err, "reading %s/event-channel", |
|
xbusd->xbusd_otherend); |
|
break; |
|
} |
|
err = xenbus_read_ul(NULL, xbusd->xbusd_otherend, |
|
"request-rx-copy", &rx_copy, 10); |
|
if (err == ENOENT) |
|
rx_copy = 0; |
|
else if (err) { |
|
xenbus_dev_fatal(xbusd, err, "reading %s/request-rx-copy", |
|
xbusd->xbusd_otherend); |
|
break; |
|
} |
|
|
|
if (rx_copy) |
|
xneti->xni_softintr = softint_establish(SOFTINT_NET, |
|
xennetback_ifsoftstart_copy, xneti); |
|
else |
|
xneti->xni_softintr = softint_establish(SOFTINT_NET, |
|
xennetback_ifsoftstart_transfer, xneti); |
|
if (xneti->xni_softintr == NULL) { |
|
err = ENOMEM; |
|
xenbus_dev_fatal(xbusd, ENOMEM, |
|
"can't allocate softint", xbusd->xbusd_otherend); |
break; |
break; |
if (xennetback_connect(xneti) == 0) |
} |
xenbus_switch_state(xbusd, NULL, XenbusStateConnected); |
|
|
/* allocate VA space and map rings */ |
|
xneti->xni_tx_ring_va = uvm_km_alloc(kernel_map, PAGE_SIZE, 0, |
|
UVM_KMF_VAONLY); |
|
if (xneti->xni_tx_ring_va == 0) { |
|
xenbus_dev_fatal(xbusd, ENOMEM, |
|
"can't get VA for tx ring", xbusd->xbusd_otherend); |
|
break; |
|
} |
|
tx_ring = (void *)xneti->xni_tx_ring_va; |
|
xneti->xni_rx_ring_va = uvm_km_alloc(kernel_map, PAGE_SIZE, 0, |
|
UVM_KMF_VAONLY); |
|
if (xneti->xni_rx_ring_va == 0) { |
|
xenbus_dev_fatal(xbusd, ENOMEM, |
|
"can't get VA for rx ring", xbusd->xbusd_otherend); |
|
goto err1; |
|
} |
|
rx_ring = (void *)xneti->xni_rx_ring_va; |
|
op.host_addr = xneti->xni_tx_ring_va; |
|
op.flags = GNTMAP_host_map; |
|
op.ref = tx_ring_ref; |
|
op.dom = xneti->xni_domid; |
|
err = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1); |
|
if (err || op.status) { |
|
printf("%s: can't map TX grant ref: %d/%d\n", |
|
xneti->xni_if.if_xname, err, op.status); |
|
goto err2; |
|
} |
|
xneti->xni_tx_ring_handle = op.handle; |
|
|
|
op.host_addr = xneti->xni_rx_ring_va; |
|
op.flags = GNTMAP_host_map; |
|
op.ref = rx_ring_ref; |
|
op.dom = xneti->xni_domid; |
|
err = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1); |
|
if (err || op.status) { |
|
printf("%s: can't map RX grant ref: %d/%d\n", |
|
xneti->xni_if.if_xname, err, op.status); |
|
goto err2; |
|
} |
|
xneti->xni_rx_ring_handle = op.handle; |
|
BACK_RING_INIT(&xneti->xni_txring, tx_ring, PAGE_SIZE); |
|
BACK_RING_INIT(&xneti->xni_rxring, rx_ring, PAGE_SIZE); |
|
evop.cmd = EVTCHNOP_bind_interdomain; |
|
evop.u.bind_interdomain.remote_dom = xneti->xni_domid; |
|
evop.u.bind_interdomain.remote_port = revtchn; |
|
err = HYPERVISOR_event_channel_op(&evop); |
|
if (err) { |
|
printf("%s: can't get event channel: %d\n", |
|
xneti->xni_if.if_xname, err); |
|
goto err2; |
|
} |
|
xneti->xni_evtchn = evop.u.bind_interdomain.local_port; |
|
xen_wmb(); |
|
xneti->xni_status = CONNECTED; |
|
xenbus_switch_state(xbusd, NULL, XenbusStateConnected); |
|
xen_wmb(); |
|
event_set_handler(xneti->xni_evtchn, xennetback_evthandler, |
|
xneti, IPL_NET, xneti->xni_if.if_xname); |
|
xennetback_ifinit(&xneti->xni_if); |
|
hypervisor_enable_event(xneti->xni_evtchn); |
|
hypervisor_notify_via_evtchn(xneti->xni_evtchn); |
break; |
break; |
|
|
case XenbusStateClosing: |
case XenbusStateClosing: |
Line 630 xennetback_frontend_changed(void *arg, X |
|
Line 557 xennetback_frontend_changed(void *arg, X |
|
break; |
break; |
} |
} |
return; |
return; |
|
err2: |
|
uvm_km_free(kernel_map, xneti->xni_rx_ring_va, |
|
PAGE_SIZE, UVM_KMF_VAONLY); |
|
err1: |
|
uvm_km_free(kernel_map, xneti->xni_tx_ring_va, |
|
PAGE_SIZE, UVM_KMF_VAONLY); |
} |
} |
|
|
/* lookup a xneti based on domain id and interface handle */ |
/* lookup a xneti based on domain id and interface handle */ |