Merge to Fedora kernel-2.6.18-1.2255_FC5-vs2.0.2.2-rc9 patched with stable patch...
[linux-2.6.git] / drivers / xen / netfront / netfront.c
index 8e5f622..5dc55e8 100644 (file)
@@ -141,7 +141,6 @@ struct netfront_info {
        spinlock_t   tx_lock;
        spinlock_t   rx_lock;
 
-       unsigned int handle;
        unsigned int evtchn, irq;
        unsigned int copying_receiver;
 
@@ -230,9 +229,8 @@ static inline grant_ref_t xennet_get_rx_ref(struct netfront_info *np,
 #define WPRINTK(fmt, args...)                          \
        printk(KERN_WARNING "netfront: " fmt, ##args)
 
-static int talk_to_backend(struct xenbus_device *, struct netfront_info *);
 static int setup_device(struct xenbus_device *, struct netfront_info *);
-static struct net_device *create_netdev(int, int, struct xenbus_device *);
+static struct net_device *create_netdev(struct xenbus_device *);
 
 static void netfront_closing(struct xenbus_device *);
 
@@ -242,7 +240,7 @@ static int open_netdev(struct netfront_info *);
 static void close_netdev(struct netfront_info *);
 static void netif_free(struct netfront_info *);
 
-static void network_connect(struct net_device *);
+static int network_connect(struct net_device *);
 static void network_tx_buf_gc(struct net_device *);
 static void network_alloc_rx_buffers(struct net_device *);
 static int send_fake_arp(struct net_device *);
@@ -265,8 +263,7 @@ static inline int xennet_can_sg(struct net_device *dev)
 /**
  * Entry point to this code when a new device is created.  Allocate the basic
  * structures and the ring buffers for communication with the backend, and
- * inform the backend of the appropriate details for those.  Switch to
- * Connected state.
+ * inform the backend of the appropriate details for those.
  */
 static int __devinit netfront_probe(struct xenbus_device *dev,
                                    const struct xenbus_device_id *id)
@@ -274,32 +271,8 @@ static int __devinit netfront_probe(struct xenbus_device *dev,
        int err;
        struct net_device *netdev;
        struct netfront_info *info;
-       unsigned int handle, feature_rx_copy, feature_rx_flip, use_copy;
 
-       err = xenbus_scanf(XBT_NIL, dev->nodename, "handle", "%u", &handle);
-       if (err != 1) {
-               xenbus_dev_fatal(dev, err, "reading handle");
-               return err;
-       }
-
-       err = xenbus_scanf(XBT_NIL, dev->otherend, "feature-rx-copy", "%u",
-                          &feature_rx_copy);
-       if (err != 1)
-               feature_rx_copy = 0;
-       err = xenbus_scanf(XBT_NIL, dev->otherend, "feature-rx-flip", "%u",
-                          &feature_rx_flip);
-       if (err != 1)
-               feature_rx_flip = 1;
-
-       /*
-        * Copy packets on receive path if:
-        *  (a) This was requested by user, and the backend supports it; or
-        *  (b) Flipping was requested, but this is unsupported by the backend.
-        */
-       use_copy = (MODPARM_rx_copy && feature_rx_copy) ||
-               (MODPARM_rx_flip && !feature_rx_flip);
-
-       netdev = create_netdev(handle, use_copy, dev);
+       netdev = create_netdev(dev);
        if (IS_ERR(netdev)) {
                err = PTR_ERR(netdev);
                xenbus_dev_fatal(dev, err, "creating netdev");
@@ -309,23 +282,13 @@ static int __devinit netfront_probe(struct xenbus_device *dev,
        info = netdev_priv(netdev);
        dev->dev.driver_data = info;
 
-       err = talk_to_backend(dev, info);
-       if (err)
-               goto fail_backend;
-
        err = open_netdev(info);
        if (err)
-               goto fail_open;
-
-       IPRINTK("Created netdev %s with %sing receive path.\n",
-               netdev->name, info->copying_receiver ? "copy" : "flipp");
+               goto fail;
 
        return 0;
 
- fail_open:
-       xennet_sysfs_delif(info->netdev);
-       unregister_netdev(netdev);
- fail_backend:
+ fail:
        free_netdev(netdev);
        dev->dev.driver_data = NULL;
        return err;
@@ -345,7 +308,7 @@ static int netfront_resume(struct xenbus_device *dev)
        DPRINTK("%s\n", dev->nodename);
 
        netif_disconnect_backend(info);
-       return talk_to_backend(dev, info);
+       return 0;
 }
 
 static int xen_net_read_mac(struct xenbus_device *dev, u8 mac[])
@@ -456,7 +419,7 @@ again:
        xenbus_transaction_end(xbt, 1);
        xenbus_dev_fatal(dev, err, "%s", message);
  destroy_ring:
-       netif_free(info);
+       netif_disconnect_backend(info);
  out:
        return err;
 }
@@ -546,7 +509,10 @@ static void backend_changed(struct xenbus_device *dev,
                break;
 
        case XenbusStateInitWait:
-               network_connect(netdev);
+               if (network_connect(netdev) != 0) {
+                       netif_free(np);
+                       break;
+               }
                xenbus_switch_state(dev, XenbusStateConnected);
                (void)send_fake_arp(netdev);
                break;
@@ -1120,6 +1086,7 @@ static int xennet_get_responses(struct netfront_info *np,
                        if (net_ratelimit())
                                WPRINTK("rx->offset: %x, size: %u\n",
                                        rx->offset, rx->status);
+                       xennet_move_rx_slot(np, skb, ref);
                        err = -EINVAL;
                        goto next;
                }
@@ -1130,7 +1097,8 @@ static int xennet_get_responses(struct netfront_info *np,
                 * situation to the system controller to reboot the backed.
                 */
                if (ref == GRANT_INVALID_REF) {
-                       WPRINTK("Bad rx response id %d.\n", rx->id);
+                       if (net_ratelimit())
+                               WPRINTK("Bad rx response id %d.\n", rx->id);
                        err = -EINVAL;
                        goto next;
                }
@@ -1202,6 +1170,9 @@ next:
                err = -E2BIG;
        }
 
+       if (unlikely(err))
+               np->rx.rsp_cons = cons + frags;
+
        *pages_flipped_p = pages_flipped;
 
        return err;
@@ -1306,9 +1277,9 @@ static int netif_poll(struct net_device *dev, int *pbudget)
        rp = np->rx.sring->rsp_prod;
        rmb(); /* Ensure we see queued responses up to 'rp'. */
 
-       for (i = np->rx.rsp_cons, work_done = 0;
-            (i != rp) && (work_done < budget);
-            np->rx.rsp_cons = ++i, work_done++) {
+       i = np->rx.rsp_cons;
+       work_done = 0;
+       while ((i != rp) && (work_done < budget)) {
                memcpy(rx, RING_GET_RESPONSE(&np->rx, i), sizeof(*rx));
                memset(extras, 0, sizeof(extras));
 
@@ -1316,12 +1287,11 @@ static int netif_poll(struct net_device *dev, int *pbudget)
                                           &pages_flipped);
 
                if (unlikely(err)) {
-err:
-                       i = np->rx.rsp_cons + skb_queue_len(&tmpq) - 1;
-                       work_done--;
+err:   
                        while ((skb = __skb_dequeue(&tmpq)))
                                __skb_queue_tail(&errq, skb);
                        np->stats.rx_errors++;
+                       i = np->rx.rsp_cons;
                        continue;
                }
 
@@ -1333,6 +1303,7 @@ err:
 
                        if (unlikely(xennet_set_skb_gso(skb, gso))) {
                                __skb_queue_head(&tmpq, skb);
+                               np->rx.rsp_cons += skb_queue_len(&tmpq);
                                goto err;
                        }
                }
@@ -1396,6 +1367,9 @@ err:
                np->stats.rx_bytes += skb->len;
 
                __skb_queue_tail(&rxq, skb);
+
+               np->rx.rsp_cons = ++i;
+               work_done++;
        }
 
        if (pages_flipped) {
@@ -1643,16 +1617,41 @@ static void xennet_set_features(struct net_device *dev)
                xennet_set_tso(dev, 1);
 }
 
-static void network_connect(struct net_device *dev)
+static int network_connect(struct net_device *dev)
 {
        struct netfront_info *np = netdev_priv(dev);
-       int i, requeue_idx;
+       int i, requeue_idx, err;
        struct sk_buff *skb;
        grant_ref_t ref;
        netif_rx_request_t *req;
+       unsigned int feature_rx_copy, feature_rx_flip;
+
+       err = xenbus_scanf(XBT_NIL, np->xbdev->otherend,
+                          "feature-rx-copy", "%u", &feature_rx_copy);
+       if (err != 1)
+               feature_rx_copy = 0;
+       err = xenbus_scanf(XBT_NIL, np->xbdev->otherend,
+                          "feature-rx-flip", "%u", &feature_rx_flip);
+       if (err != 1)
+               feature_rx_flip = 1;
+
+       /*
+        * Copy packets on receive path if:
+        *  (a) This was requested by user, and the backend supports it; or
+        *  (b) Flipping was requested, but this is unsupported by the backend.
+        */
+       np->copying_receiver = ((MODPARM_rx_copy && feature_rx_copy) ||
+                               (MODPARM_rx_flip && !feature_rx_flip));
+
+       err = talk_to_backend(np->xbdev, np);
+       if (err)
+               return err;
 
        xennet_set_features(dev);
 
+       IPRINTK("device %s has %sing receive path.\n",
+               dev->name, np->copying_receiver ? "copy" : "flipp");
+
        spin_lock_irq(&np->tx_lock);
        spin_lock(&np->rx_lock);
 
@@ -1708,6 +1707,8 @@ static void network_connect(struct net_device *dev)
 
        spin_unlock(&np->rx_lock);
        spin_unlock_irq(&np->tx_lock);
+
+       return 0;
 }
 
 static void netif_uninit(struct net_device *dev)
@@ -1873,8 +1874,7 @@ static void network_set_multicast_list(struct net_device *dev)
 {
 }
 
-static struct net_device * __devinit
-create_netdev(int handle, int copying_receiver, struct xenbus_device *dev)
+static struct net_device * __devinit create_netdev(struct xenbus_device *dev)
 {
        int i, err = 0;
        struct net_device *netdev = NULL;
@@ -1888,9 +1888,7 @@ create_netdev(int handle, int copying_receiver, struct xenbus_device *dev)
        }
 
        np                   = netdev_priv(netdev);
-       np->handle           = handle;
        np->xbdev            = dev;
-       np->copying_receiver = copying_receiver;
 
        netif_carrier_off(netdev);
 
@@ -2021,10 +2019,12 @@ static int open_netdev(struct netfront_info *info)
 
        err = xennet_sysfs_addif(info->netdev);
        if (err) {
-               /* This can be non-fatal: it only means no tuning parameters */
+               unregister_netdev(info->netdev);
                printk(KERN_WARNING "%s: add sysfs failed err=%d\n",
                       __FUNCTION__, err);
+               return err;
        }
+
        return 0;
 }