00001
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065 #include "sdev.h"
00066
00067 static void __sdev_up(sdev_t *sdev)
00068 {
00069 struct net_device *dev = sdev->dev;
00070 spin_lock_bh(&dev->xmit_lock);
00071 sdev->active = 1;
00072 spin_unlock_bh(&dev->xmit_lock);
00073 enable_irq(sdev->irq);
00074 sdev_schedule_work(sdev);
00075 }
00076
00077 static void __sdev_down(sdev_t *sdev)
00078 {
00079 struct net_device *dev = sdev->dev;
00080 disable_irq(sdev->irq);
00081 spin_lock_bh(&dev->xmit_lock);
00082 sdev->active = 0;
00083 spin_unlock_bh(&dev->xmit_lock);
00084 sdev_deschedule_work(sdev);
00085 }
00086
00087 static int net_open(struct net_device *dev)
00088 {
00089 sdev_t *sdev = netdev_priv(dev);
00090 if (sdev->status == CONNECTED)
00091 __sdev_up(sdev);
00092 netif_start_queue(dev);
00093 return 0;
00094 }
00095
00096 static int net_close(struct net_device *dev)
00097 {
00098 sdev_t *sdev = netdev_priv(dev);
00099 netif_stop_queue(dev);
00100 if (sdev->status == CONNECTED)
00101 __sdev_down(sdev);
00102 return 0;
00103 }
00104
00105 sdev_t *alloc_sdev(domid_t domid, unsigned int handle, u8 be_mac[ETH_ALEN])
00106 {
00107 int err = 0, i;
00108 struct net_device *dev;
00109 sdev_t *sdev;
00110 char name[IFNAMSIZ] = {};
00111
00112 snprintf(name, IFNAMSIZ - 1, "vwif%u.%u", domid, handle);
00113 dev = alloc_netdev(sizeof(sdev_t), name, ether_setup);
00114 if (dev == NULL) {
00115 DPRINTK("Could not create sdev: out of memory\n");
00116 return ERR_PTR(-ENOMEM);
00117 }
00118
00119 sdev = netdev_priv(dev);
00120 memset(sdev, 0, sizeof(*sdev));
00121 sdev->domid = domid;
00122 sdev->handle = handle;
00123 sdev->status = DISCONNECTED;
00124 atomic_set(&sdev->refcnt, 0);
00125 sdev->dev = dev;
00126
00127 sdev->credit_bytes = sdev->remaining_credit = ~0UL;
00128 sdev->credit_usec = 0UL;
00129 init_timer(&sdev->credit_timeout);
00130
00131 dev->hard_start_xmit = sdev_be_start_xmit;
00132 dev->get_stats = sdev_be_get_stats;
00133 dev->open = net_open;
00134 dev->stop = net_close;
00135 dev->features = NETIF_F_NO_CSUM;
00136
00137
00138 dev->tx_queue_len = 0;
00139
00140 for (i = 0; i < ETH_ALEN; i++)
00141 if (be_mac[i] != 0)
00142 break;
00143 if (i == ETH_ALEN) {
00144
00145
00146
00147
00148
00149
00150 memset(dev->dev_addr, 0xFF, ETH_ALEN);
00151 dev->dev_addr[0] &= ~0x01;
00152 } else
00153 memcpy(dev->dev_addr, be_mac, ETH_ALEN);
00154
00155 rtnl_lock();
00156 err = register_netdevice(dev);
00157 rtnl_unlock();
00158 if (err) {
00159 DPRINTK("Could not register new net device %s: err=%d\n",
00160 dev->name, err);
00161 free_netdev(dev);
00162 return ERR_PTR(err);
00163 }
00164
00165 DPRINTK("Successfully created sdev\n");
00166 return sdev;
00167 }
00168
00169 static int map_frontend_pages(
00170 sdev_t *sdev, grant_ref_t tx_ring_ref, grant_ref_t rx_ring_ref)
00171 {
00172 struct gnttab_map_grant_ref op;
00173 int ret;
00174
00175 op.host_addr = (unsigned long)sdev->tx_comms_area->addr;
00176 op.flags = GNTMAP_host_map;
00177 op.ref = tx_ring_ref;
00178 op.dom = sdev->domid;
00179
00180 lock_vm_area(sdev->tx_comms_area);
00181 ret = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1);
00182 unlock_vm_area(sdev->tx_comms_area);
00183 BUG_ON(ret);
00184
00185 if (op.status) {
00186 DPRINTK(" Gnttab failure mapping tx_ring_ref!\n");
00187 return op.status;
00188 }
00189
00190 sdev->tx_shmem_ref = tx_ring_ref;
00191 sdev->tx_shmem_handle = op.handle;
00192
00193 op.host_addr = (unsigned long)sdev->rx_comms_area->addr;
00194 op.flags = GNTMAP_host_map;
00195 op.ref = rx_ring_ref;
00196 op.dom = sdev->domid;
00197
00198 lock_vm_area(sdev->rx_comms_area);
00199 ret = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1);
00200 unlock_vm_area(sdev->rx_comms_area);
00201 BUG_ON(ret);
00202
00203 if (op.status) {
00204 DPRINTK(" Gnttab failure mapping rx_ring_ref!\n");
00205 return op.status;
00206 }
00207
00208 sdev->rx_shmem_ref = rx_ring_ref;
00209 sdev->rx_shmem_handle = op.handle;
00210
00211 return 0;
00212 }
00213
00214 static void unmap_frontend_pages(sdev_t *sdev)
00215 {
00216 struct gnttab_unmap_grant_ref op;
00217 int ret;
00218
00219 op.host_addr = (unsigned long)sdev->tx_comms_area->addr;
00220 op.handle = sdev->tx_shmem_handle;
00221 op.dev_bus_addr = 0;
00222
00223 lock_vm_area(sdev->tx_comms_area);
00224 ret = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1);
00225 unlock_vm_area(sdev->tx_comms_area);
00226 BUG_ON(ret);
00227
00228 op.host_addr = (unsigned long)sdev->rx_comms_area->addr;
00229 op.handle = sdev->rx_shmem_handle;
00230 op.dev_bus_addr = 0;
00231
00232 lock_vm_area(sdev->rx_comms_area);
00233 ret = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1);
00234 unlock_vm_area(sdev->rx_comms_area);
00235 BUG_ON(ret);
00236 }
00237
00238 int sdev_map(sdev_t *sdev, unsigned long tx_ring_ref,
00239 unsigned long rx_ring_ref, unsigned int evtchn)
00240 {
00241 int err = -ENOMEM;
00242 netif_tx_sring_t *txs;
00243 netif_rx_sring_t *rxs;
00244 evtchn_op_t op = {
00245 .cmd = EVTCHNOP_bind_interdomain,
00246 .u.bind_interdomain.remote_dom = sdev->domid,
00247 .u.bind_interdomain.remote_port = evtchn };
00248
00249
00250 if (sdev->irq)
00251 return 0;
00252
00253 sdev->tx_comms_area = alloc_vm_area(PAGE_SIZE);
00254 if (sdev->tx_comms_area == NULL)
00255 return -ENOMEM;
00256 sdev->rx_comms_area = alloc_vm_area(PAGE_SIZE);
00257 if (sdev->rx_comms_area == NULL)
00258 goto err_rx;
00259
00260 err = map_frontend_pages(sdev, tx_ring_ref, rx_ring_ref);
00261 if (err)
00262 goto err_map;
00263
00264 err = HYPERVISOR_event_channel_op(&op);
00265 if (err)
00266 goto err_hypervisor;
00267
00268 sdev->evtchn = op.u.bind_interdomain.local_port;
00269
00270 sdev->irq = bind_evtchn_to_irqhandler(
00271 sdev->evtchn, sdev_be_int, 0, sdev->dev->name, sdev);
00272 disable_irq(sdev->irq);
00273
00274 txs = (netif_tx_sring_t *)sdev->tx_comms_area->addr;
00275 BACK_RING_INIT(&sdev->tx, txs, PAGE_SIZE);
00276
00277 rxs = (netif_rx_sring_t *)
00278 ((char *)sdev->rx_comms_area->addr);
00279 BACK_RING_INIT(&sdev->rx, rxs, PAGE_SIZE);
00280
00281 sdev->rx_req_cons_peek = 0;
00282
00283 sdev_get(sdev);
00284 wmb();
00285
00286 rtnl_lock();
00287 sdev->status = CONNECTED;
00288 wmb();
00289 if (netif_running(sdev->dev))
00290 __sdev_up(sdev);
00291 rtnl_unlock();
00292
00293 return 0;
00294 err_hypervisor:
00295 unmap_frontend_pages(sdev);
00296 err_map:
00297 free_vm_area(sdev->rx_comms_area);
00298 err_rx:
00299 free_vm_area(sdev->tx_comms_area);
00300 return err;
00301 }
00302
00303 static void free_sdev_callback(void *arg)
00304 {
00305 sdev_t *sdev = (sdev_t *)arg;
00306
00307 if (sdev->irq)
00308 unbind_from_irqhandler(sdev->irq, sdev);
00309
00310 unregister_netdev(sdev->dev);
00311
00312 if (sdev->tx.sring) {
00313 unmap_frontend_pages(sdev);
00314 free_vm_area(sdev->tx_comms_area);
00315 free_vm_area(sdev->rx_comms_area);
00316 }
00317
00318 free_netdev(sdev->dev);
00319 }
00320
00321 void free_sdev(sdev_t *sdev)
00322 {
00323 INIT_WORK(&sdev->free_work, free_sdev_callback, (void *)sdev);
00324 schedule_work(&sdev->free_work);
00325 }
00326
00327 void sdev_creditlimit(sdev_t *sdev)
00328 {
00329 #if 0
00330
00331 sdev->credit_bytes = creditlimit->credit_bytes;
00332 sdev->remaining_credit = creditlimit->credit_bytes;
00333 sdev->credit_usec = creditlimit->period_usec;
00334
00335 if (sdev->status == CONNECTED) {
00336
00337
00338
00339
00340 sdev->credit_timeout.expires = jiffies;
00341 sdev_schedule_work(sdev);
00342 }
00343 #endif
00344 }
00345
00346 void sdev_disconnect(sdev_t *sdev)
00347 {
00348 switch (sdev->status) {
00349 case CONNECTED:
00350 rtnl_lock();
00351 sdev->status = DISCONNECTING;
00352 wmb();
00353 if (netif_running(sdev->dev))
00354 __sdev_down(sdev);
00355 rtnl_unlock();
00356 sdev_put(sdev);
00357 break;
00358 case DISCONNECTED:
00359 BUG_ON(atomic_read(&sdev->refcnt) != 0);
00360 free_sdev(sdev);
00361 break;
00362 default:
00363 BUG();
00364 }
00365 }