Pull style into test branch
[powerpc.git] / net / atm / lec.c
index c5d1f9e..3fc0abe 100644 (file)
@@ -204,9 +204,9 @@ static unsigned char *get_tr_dst(unsigned char *packet, unsigned char *rdesc)
        memset(rdesc, 0, ETH_ALEN);
        /* offset 4 comes from LAN destination field in LE control frames */
        if (trh->rcf & htons((uint16_t) TR_RCF_DIR_BIT))
-               memcpy(&rdesc[4], &trh->rseg[num_rdsc - 2], sizeof(uint16_t));
+               memcpy(&rdesc[4], &trh->rseg[num_rdsc - 2], sizeof(__be16));
        else {
-               memcpy(&rdesc[4], &trh->rseg[1], sizeof(uint16_t));
+               memcpy(&rdesc[4], &trh->rseg[1], sizeof(__be16));
                rdesc[5] = ((ntohs(trh->rseg[0]) & 0x000f) | (rdesc[5] & 0xf0));
        }
 
@@ -396,7 +396,7 @@ static int lec_start_xmit(struct sk_buff *skb, struct net_device *dev)
                        priv->stats.tx_dropped++;
                        dev_kfree_skb(skb);
                }
-               return 0;
+               goto out;
        }
 #if DUMP_PACKETS > 0
        printk("%s:sending to vpi:%d vci:%d\n", dev->name, vcc->vpi, vcc->vci);
@@ -428,6 +428,9 @@ static int lec_start_xmit(struct sk_buff *skb, struct net_device *dev)
                        netif_wake_queue(dev);
        }
 
+out:
+       if (entry)
+               lec_arp_put(entry);
        dev->trans_start = jiffies;
        return 0;
 }
@@ -772,7 +775,7 @@ static void lec_push(struct atm_vcc *vcc, struct sk_buff *skb)
                unsigned char *src, *dst;
 
                atm_return(vcc, skb->truesize);
-               if (*(uint16_t *) skb->data == htons(priv->lecid) ||
+               if (*(__be16 *) skb->data == htons(priv->lecid) ||
                    !priv->lecd || !(dev->flags & IFF_UP)) {
                        /*
                         * Probably looping back, or if lecd is missing,
@@ -1318,11 +1321,10 @@ static int lane2_resolve(struct net_device *dev, u8 *dst_mac, int force,
                if (table == NULL)
                        return -1;
 
-               *tlvs = kmalloc(table->sizeoftlvs, GFP_ATOMIC);
+               *tlvs = kmemdup(table->tlvs, table->sizeoftlvs, GFP_ATOMIC);
                if (*tlvs == NULL)
                        return -1;
 
-               memcpy(*tlvs, table->tlvs, table->sizeoftlvs);
                *sizeoftlvs = table->sizeoftlvs;
 
                return 0;
@@ -1361,11 +1363,10 @@ static int lane2_associate_req(struct net_device *dev, u8 *lan_dst,
 
        kfree(priv->tlvs);      /* NULL if there was no previous association */
 
-       priv->tlvs = kmalloc(sizeoftlvs, GFP_KERNEL);
+       priv->tlvs = kmemdup(tlvs, sizeoftlvs, GFP_KERNEL);
        if (priv->tlvs == NULL)
                return (0);
        priv->sizeoftlvs = sizeoftlvs;
-       memcpy(priv->tlvs, tlvs, sizeoftlvs);
 
        skb = alloc_skb(sizeoftlvs, GFP_ATOMIC);
        if (skb == NULL)
@@ -1406,12 +1407,10 @@ static void lane2_associate_ind(struct net_device *dev, u8 *mac_addr,
 
        kfree(entry->tlvs);
 
-       entry->tlvs = kmalloc(sizeoftlvs, GFP_KERNEL);
+       entry->tlvs = kmemdup(tlvs, sizeoftlvs, GFP_KERNEL);
        if (entry->tlvs == NULL)
                return;
-
        entry->sizeoftlvs = sizeoftlvs;
-       memcpy(entry->tlvs, tlvs, sizeoftlvs);
 #endif
 #if 0
        printk("lec.c: lane2_associate_ind()\n");
@@ -1455,7 +1454,7 @@ static void lane2_associate_ind(struct net_device *dev, u8 *mac_addr,
 
 #define LEC_ARP_REFRESH_INTERVAL (3*HZ)
 
-static void lec_arp_check_expire(void *data);
+static void lec_arp_check_expire(struct work_struct *work);
 static void lec_arp_expire_arp(unsigned long data);
 
 /* 
@@ -1478,7 +1477,7 @@ static void lec_arp_init(struct lec_priv *priv)
         INIT_HLIST_HEAD(&priv->lec_no_forward);
         INIT_HLIST_HEAD(&priv->mcast_fwds);
        spin_lock_init(&priv->lec_arp_lock);
-       INIT_WORK(&priv->lec_arp_work, lec_arp_check_expire, priv);
+       INIT_DELAYED_WORK(&priv->lec_arp_work, lec_arp_check_expire);
        schedule_delayed_work(&priv->lec_arp_work, LEC_ARP_REFRESH_INTERVAL);
 }
 
@@ -1876,10 +1875,11 @@ static void lec_arp_expire_vcc(unsigned long data)
  *       to ESI_FORWARD_DIRECT. This causes the flush period to end
  *       regardless of the progress of the flush protocol.
  */
-static void lec_arp_check_expire(void *data)
+static void lec_arp_check_expire(struct work_struct *work)
 {
        unsigned long flags;
-       struct lec_priv *priv = data;
+       struct lec_priv *priv =
+               container_of(work, struct lec_priv, lec_arp_work.work);
        struct hlist_node *node, *next;
        struct lec_arp_table *entry;
        unsigned long now;
@@ -1888,6 +1888,7 @@ static void lec_arp_check_expire(void *data)
 
        DPRINTK("lec_arp_check_expire %p\n", priv);
        now = jiffies;
+restart:
        spin_lock_irqsave(&priv->lec_arp_lock, flags);
        for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
                hlist_for_each_entry_safe(entry, node, next, &priv->lec_arp_tables[i], next) {
@@ -1927,14 +1928,16 @@ static void lec_arp_check_expire(void *data)
                                    time_after_eq(now, entry->timestamp +
                                                  priv->path_switching_delay)) {
                                        struct sk_buff *skb;
+                                       struct atm_vcc *vcc = entry->vcc;
 
-                                       while ((skb =
-                                               skb_dequeue(&entry->tx_wait)) !=
-                                              NULL)
-                                               lec_send(entry->vcc, skb,
-                                                        entry->priv);
+                                       lec_arp_hold(entry);
+                                       spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
+                                       while ((skb = skb_dequeue(&entry->tx_wait)) != NULL)
+                                               lec_send(vcc, skb, entry->priv);
                                        entry->last_used = jiffies;
                                        entry->status = ESI_FORWARD_DIRECT;
+                                       lec_arp_put(entry);
+                                       goto restart;
                                }
                        }
                }
@@ -1977,6 +1980,7 @@ static struct atm_vcc *lec_arp_resolve(struct lec_priv *priv,
                if (entry->status == ESI_FORWARD_DIRECT) {
                        /* Connection Ok */
                        entry->last_used = jiffies;
+                       lec_arp_hold(entry);
                        *ret_entry = entry;
                        found = entry->vcc;
                        goto out;
@@ -2007,6 +2011,7 @@ static struct atm_vcc *lec_arp_resolve(struct lec_priv *priv,
                 * or BUS flood limit was reached for an entry which is
                 * in ESI_ARP_PENDING or ESI_VC_PENDING state.
                 */
+               lec_arp_hold(entry);
                *ret_entry = entry;
                DPRINTK("lec: entry->status %d entry->vcc %p\n", entry->status,
                        entry->vcc);
@@ -2335,18 +2340,24 @@ static void lec_flush_complete(struct lec_priv *priv, unsigned long tran_id)
        int i;
 
        DPRINTK("LEC:lec_flush_complete %lx\n", tran_id);
+restart:
        spin_lock_irqsave(&priv->lec_arp_lock, flags);
        for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
                hlist_for_each_entry(entry, node, &priv->lec_arp_tables[i], next) {
                        if (entry->flush_tran_id == tran_id
                            && entry->status == ESI_FLUSH_PENDING) {
                                struct sk_buff *skb;
+                               struct atm_vcc *vcc = entry->vcc;
 
-                               while ((skb =
-                                       skb_dequeue(&entry->tx_wait)) != NULL)
-                                       lec_send(entry->vcc, skb, entry->priv);
+                               lec_arp_hold(entry);
+                               spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
+                               while ((skb = skb_dequeue(&entry->tx_wait)) != NULL)
+                                       lec_send(vcc, skb, entry->priv);
+                               entry->last_used = jiffies;
                                entry->status = ESI_FORWARD_DIRECT;
+                               lec_arp_put(entry);
                                DPRINTK("LEC_ARP: Flushed\n");
+                               goto restart;
                        }
                }
        }