N-sim
Emulation and simulation of
Wireless Sensor Networks



   Home


   Project Page


   Download


   CVS



   Installation


   Configuration


   Plug-ins




 Hosted by
SourceForge.net Logo

/home/brennan/n-sim/OrbisQuartus/server/xen/backend/sdev_if.c

Go to the documentation of this file.
00001 
00012 /*
00013  * Copyright (c) 2004-2005, Keir Fraser
00014  *
00015  * Copyright 2006. Los Alamos National Security, LLC. This material
00016  * was produced under U.S. Government contract DE-AC52-06NA25396 for
00017  * Los Alamos National Laboratory (LANL), which is operated by Los
00018  * Alamos National Security, LLC, for the Department of Energy. The
00019  * U.S. Government has rights to use, reproduce, and distribute this
00020  * software. NEITHER THE GOVERNMENT NOR LOS ALAMOS NATIONAL SECURITY,
00021  * LLC, MAKES ANY WARRANTY, EXPRESS OR IMPLIED, OR ASSUMES ANY LEGAL
00022  * LIABILITY FOR THE USE OF THIS SOFTWARE. If software is modified to
00023  * produce derivative works, such modified software should be clearly
00024  * marked, so as not to confuse it with the version available from LANL.
00025  * Additionally, this program is free software; you can redistribute it
00026  * and/or modify it under the terms of the GNU General Public License as
00027  * published by the Free Software Foundation; either version 2 of the
00028  * License, or (at your option) any later version. Accordingly, this
00029  * program is distributed in the hope it will be useful, but WITHOUT ANY
00030  * WARRANTY; without even the implied warranty of MERCHANTABILITY or
00031  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
00032  * for more details.
00033  ******************************
00034  *
00035  * This program is free software; you can redistribute it and/or
00036  * modify it under the terms of the GNU General Public License version 2
00037  * as published by the Free Software Foundation; or, when distributed
00038  * separately from the Linux kernel or incorporated into other
00039  * software packages, subject to the following license:
00040  * 
00041  * Permission is hereby granted, free of charge, to any person obtaining a copy
00042  * of this source file (the "Software"), to deal in the Software without
00043  * restriction, including without limitation the rights to use, copy, modify,
00044  * merge, publish, distribute, sublicense, and/or sell copies of the Software,
00045  * and to permit persons to whom the Software is furnished to do so, subject to
00046  * the following conditions:
00047  * 
00048  * The above copyright notice and this permission notice shall be included in
00049  * all copies or substantial portions of the Software.
00050  * 
00051  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00052  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00053  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
00054  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00055  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
00056  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
00057  * IN THE SOFTWARE.
00058  *
00059  * You should have received a copy of the GNU General Public License
00060  * along with this program; if not, write to the Free Software
00061  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
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         /* Disable queuing. */
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                  * Initialise a dummy MAC address. We choose the numerically
00146                  * largest non-broadcast address to prevent the address getting
00147                  * stolen by an Ethernet bridge for STP purposes.
00148                  * (FE:FF:FF:FF:FF:FF) 
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         /* Already connected through? */
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(); /* Other CPUs see new state before interface is started. */
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         /* Set the credit limit (reset remaining credit to new limit). */
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                  * Schedule work so that any packets waiting under previous
00338                  * credit limit are dealt with (acts as a replenishment point).
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 }


© 2007, Los Alamos National Security, LLC.