fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / drivers / s390 / net / qeth_main.c
index 5613b45..d2efa5f 100644 (file)
@@ -471,7 +471,7 @@ qeth_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
            channel->state == CH_STATE_UP)
                qeth_issue_next_read(card);
 
-       tasklet_schedule(&channel->irq_tasklet);
+       qeth_irq_tasklet((unsigned long)channel);
        return;
 out:
        wake_up(&card->wait_q);
@@ -950,40 +950,6 @@ qeth_do_run_thread(struct qeth_card *card, unsigned long thread)
        return rc;
 }
 
-static int
-qeth_register_ip_addresses(void *ptr)
-{
-       struct qeth_card *card;
-
-       card = (struct qeth_card *) ptr;
-       daemonize("qeth_reg_ip");
-       QETH_DBF_TEXT(trace,4,"regipth1");
-       if (!qeth_do_run_thread(card, QETH_SET_IP_THREAD))
-               return 0;
-       QETH_DBF_TEXT(trace,4,"regipth2");
-       qeth_set_ip_addr_list(card);
-       qeth_clear_thread_running_bit(card, QETH_SET_IP_THREAD);
-       return 0;
-}
-
-/*
- * Drive the SET_PROMISC_MODE thread
- */
-static int
-qeth_set_promisc_mode(void *ptr)
-{
-       struct qeth_card *card = (struct qeth_card *) ptr;
-
-       daemonize("qeth_setprm");
-       QETH_DBF_TEXT(trace,4,"setprm1");
-       if (!qeth_do_run_thread(card, QETH_SET_PROMISC_MODE_THREAD))
-               return 0;
-       QETH_DBF_TEXT(trace,4,"setprm2");
-       qeth_setadp_promisc_mode(card);
-       qeth_clear_thread_running_bit(card, QETH_SET_PROMISC_MODE_THREAD);
-       return 0;
-}
-
 static int
 qeth_recover(void *ptr)
 {
@@ -1039,18 +1005,14 @@ qeth_do_start_thread(struct qeth_card *card, unsigned long thread)
 }
 
 static void
-qeth_start_kernel_thread(struct qeth_card *card)
+qeth_start_kernel_thread(struct work_struct *work)
 {
+       struct qeth_card *card = container_of(work, struct qeth_card, kernel_thread_starter);
        QETH_DBF_TEXT(trace , 2, "strthrd");
 
        if (card->read.state != CH_STATE_UP &&
            card->write.state != CH_STATE_UP)
                return;
-
-       if (qeth_do_start_thread(card, QETH_SET_IP_THREAD))
-               kernel_thread(qeth_register_ip_addresses, (void *)card,SIGCHLD);
-       if (qeth_do_start_thread(card, QETH_SET_PROMISC_MODE_THREAD))
-               kernel_thread(qeth_set_promisc_mode, (void *)card, SIGCHLD);
        if (qeth_do_start_thread(card, QETH_RECOVER_THREAD))
                kernel_thread(qeth_recover, (void *) card, SIGCHLD);
 }
@@ -1073,7 +1035,7 @@ qeth_set_intial_options(struct qeth_card *card)
                card->options.layer2 = 1;
        else
                card->options.layer2 = 0;
-       card->options.performance_stats = 1;
+       card->options.performance_stats = 0;
 }
 
 /**
@@ -1103,8 +1065,7 @@ qeth_setup_card(struct qeth_card *card)
        card->thread_start_mask = 0;
        card->thread_allowed_mask = 0;
        card->thread_running_mask = 0;
-       INIT_WORK(&card->kernel_thread_starter,
-                 (void *)qeth_start_kernel_thread,card);
+       INIT_WORK(&card->kernel_thread_starter, qeth_start_kernel_thread);
        INIT_LIST_HEAD(&card->ip_list);
        card->ip_tbd_list = kmalloc(sizeof(struct list_head), GFP_KERNEL);
        if (!card->ip_tbd_list) {
@@ -1613,8 +1574,6 @@ qeth_issue_next_read(struct qeth_card *card)
                return -ENOMEM;
        }
        qeth_setup_ccw(&card->read, iob->data, QETH_BUFSIZE);
-       wait_event(card->wait_q,
-                  atomic_cmpxchg(&card->read.irq_pending, 0, 1) == 0);
        QETH_DBF_TEXT(trace, 6, "noirqpnd");
        rc = ccw_device_start(card->read.ccwdev, &card->read.ccw,
                              (addr_t) iob, 0, 0);
@@ -1635,6 +1594,7 @@ qeth_alloc_reply(struct qeth_card *card)
        reply = kzalloc(sizeof(struct qeth_reply), GFP_ATOMIC);
        if (reply){
                atomic_set(&reply->refcnt, 1);
+               atomic_set(&reply->received, 0);
                reply->card = card;
        };
        return reply;
@@ -1655,31 +1615,6 @@ qeth_put_reply(struct qeth_reply *reply)
                kfree(reply);
 }
 
-static void
-qeth_cmd_timeout(unsigned long data)
-{
-       struct qeth_reply *reply, *list_reply, *r;
-       unsigned long flags;
-
-       reply = (struct qeth_reply *) data;
-       spin_lock_irqsave(&reply->card->lock, flags);
-       list_for_each_entry_safe(list_reply, r,
-                                &reply->card->cmd_waiter_list, list) {
-               if (reply == list_reply){
-                       qeth_get_reply(reply);
-                       list_del_init(&reply->list);
-                       spin_unlock_irqrestore(&reply->card->lock, flags);
-                       reply->rc = -ETIME;
-                       reply->received = 1;
-                       wake_up(&reply->wait_q);
-                       qeth_put_reply(reply);
-                       return;
-               }
-       }
-       spin_unlock_irqrestore(&reply->card->lock, flags);
-}
-
-
 static struct qeth_ipa_cmd *
 qeth_check_ipa_data(struct qeth_card *card, struct qeth_cmd_buffer *iob)
 {
@@ -1745,7 +1680,7 @@ qeth_clear_ipacmd_list(struct qeth_card *card)
        list_for_each_entry_safe(reply, r, &card->cmd_waiter_list, list) {
                qeth_get_reply(reply);
                reply->rc = -EIO;
-               reply->received = 1;
+               atomic_inc(&reply->received);
                list_del_init(&reply->list);
                wake_up(&reply->wait_q);
                qeth_put_reply(reply);
@@ -1814,7 +1749,7 @@ qeth_send_control_data_cb(struct qeth_channel *channel,
                                              &card->cmd_waiter_list);
                                spin_unlock_irqrestore(&card->lock, flags);
                        } else {
-                               reply->received = 1;
+                               atomic_inc(&reply->received);
                                wake_up(&reply->wait_q);
                        }
                        qeth_put_reply(reply);
@@ -1858,7 +1793,7 @@ qeth_send_control_data(struct qeth_card *card, int len,
        int rc;
        unsigned long flags;
        struct qeth_reply *reply = NULL;
-       struct timer_list timer;
+       unsigned long timeout;
 
        QETH_DBF_TEXT(trace, 2, "sendctl");
 
@@ -1873,21 +1808,20 @@ qeth_send_control_data(struct qeth_card *card, int len,
                reply->seqno = QETH_IDX_COMMAND_SEQNO;
        else
                reply->seqno = card->seqno.ipa++;
-       init_timer(&timer);
-       timer.function = qeth_cmd_timeout;
-       timer.data = (unsigned long) reply;
        init_waitqueue_head(&reply->wait_q);
        spin_lock_irqsave(&card->lock, flags);
        list_add_tail(&reply->list, &card->cmd_waiter_list);
        spin_unlock_irqrestore(&card->lock, flags);
        QETH_DBF_HEX(control, 2, iob->data, QETH_DBF_CONTROL_LEN);
-       wait_event(card->wait_q,
-                  atomic_cmpxchg(&card->write.irq_pending, 0, 1) == 0);
+
+       while (atomic_cmpxchg(&card->write.irq_pending, 0, 1)) ;
        qeth_prepare_control_data(card, len, iob);
+
        if (IS_IPA(iob->data))
-               timer.expires = jiffies + QETH_IPA_TIMEOUT;
+               timeout = jiffies + QETH_IPA_TIMEOUT;
        else
-               timer.expires = jiffies + QETH_TIMEOUT;
+               timeout = jiffies + QETH_TIMEOUT;
+
        QETH_DBF_TEXT(trace, 6, "noirqpnd");
        spin_lock_irqsave(get_ccwdev_lock(card->write.ccwdev), flags);
        rc = ccw_device_start(card->write.ccwdev, &card->write.ccw,
@@ -1906,9 +1840,16 @@ qeth_send_control_data(struct qeth_card *card, int len,
                wake_up(&card->wait_q);
                return rc;
        }
-       add_timer(&timer);
-       wait_event(reply->wait_q, reply->received);
-       del_timer_sync(&timer);
+       while (!atomic_read(&reply->received)) {
+               if (time_after(jiffies, timeout)) {
+                       spin_lock_irqsave(&reply->card->lock, flags);
+                       list_del_init(&reply->list);
+                       spin_unlock_irqrestore(&reply->card->lock, flags);
+                       reply->rc = -ETIME;
+                       atomic_inc(&reply->received);
+                       wake_up(&reply->wait_q);
+               }
+       };
        rc = reply->rc;
        qeth_put_reply(reply);
        return rc;
@@ -2466,32 +2407,17 @@ qeth_rebuild_skb_fake_ll(struct qeth_card *card, struct sk_buff *skb,
                qeth_rebuild_skb_fake_ll_eth(card, skb, hdr);
 }
 
-static inline __u16
+static inline void
 qeth_layer2_rebuild_skb(struct qeth_card *card, struct sk_buff *skb,
                        struct qeth_hdr *hdr)
 {
-       unsigned short vlan_id = 0;
-#ifdef CONFIG_QETH_VLAN
-       struct vlan_hdr *vhdr;
-#endif
-
        skb->pkt_type = PACKET_HOST;
        skb->protocol = qeth_type_trans(skb, skb->dev);
        if (card->options.checksum_type == NO_CHECKSUMMING)
                skb->ip_summed = CHECKSUM_UNNECESSARY;
        else
                skb->ip_summed = CHECKSUM_NONE;
-#ifdef CONFIG_QETH_VLAN
-       if (hdr->hdr.l2.flags[2] & (QETH_LAYER2_FLAG_VLAN)) {
-               vhdr = (struct vlan_hdr *) skb->data;
-               skb->protocol =
-                       __constant_htons(vhdr->h_vlan_encapsulated_proto);
-               vlan_id = hdr->hdr.l2.vlan_id;
-               skb_pull(skb, VLAN_HLEN);
-       }
-#endif
        *((__u32 *)skb->cb) = ++card->seqno.pkt_seqno;
-       return vlan_id;
 }
 
 static inline __u16
@@ -2560,7 +2486,6 @@ qeth_process_inbound_buffer(struct qeth_card *card,
        int offset;
        int rxrc;
        __u16 vlan_tag = 0;
-       __u16 *vlan_addr;
 
        /* get first element of current buffer */
        element = (struct qdio_buffer_element *)&buf->buffer->element[0];
@@ -2571,7 +2496,7 @@ qeth_process_inbound_buffer(struct qeth_card *card,
                                       &offset, &hdr))) {
                skb->dev = card->dev;
                if (hdr->hdr.l2.id == QETH_HEADER_TYPE_LAYER2)
-                       vlan_tag = qeth_layer2_rebuild_skb(card, skb, hdr);
+                       qeth_layer2_rebuild_skb(card, skb, hdr);
                else if (hdr->hdr.l3.id == QETH_HEADER_TYPE_LAYER3)
                        vlan_tag = qeth_rebuild_skb(card, skb, hdr);
                else { /*in case of OSN*/
@@ -2982,7 +2907,7 @@ qeth_check_outbound_queue(struct qeth_qdio_out_q *queue)
         */
        if ((atomic_read(&queue->used_buffers) <= QETH_LOW_WATERMARK_PACK) ||
            !atomic_read(&queue->set_pci_flags_count)){
-               if (atomic_swap(&queue->state, QETH_OUT_Q_LOCKED_FLUSH) ==
+               if (atomic_xchg(&queue->state, QETH_OUT_Q_LOCKED_FLUSH) ==
                                QETH_OUT_Q_UNLOCKED) {
                        /*
                         * If we get in here, there was no action in
@@ -3245,7 +3170,7 @@ qeth_free_qdio_buffers(struct qeth_card *card)
        int i, j;
 
        QETH_DBF_TEXT(trace, 2, "freeqdbf");
-       if (atomic_swap(&card->qdio.state, QETH_QDIO_UNINITIALIZED) ==
+       if (atomic_xchg(&card->qdio.state, QETH_QDIO_UNINITIALIZED) ==
                QETH_QDIO_UNINITIALIZED)
                return;
        kfree(card->qdio.in_q);
@@ -3968,13 +3893,22 @@ static inline struct sk_buff *
 qeth_prepare_skb(struct qeth_card *card, struct sk_buff *skb,
                 struct qeth_hdr **hdr, int ipv)
 {
-       struct sk_buff *new_skb;
+       struct sk_buff *new_skb, *new_skb2;
        
        QETH_DBF_TEXT(trace, 6, "prepskb");
-
-        new_skb = qeth_realloc_headroom(card, skb, sizeof(struct qeth_hdr));
-               if (new_skb == NULL)
+       new_skb = skb;
+       new_skb = qeth_pskb_unshare(skb, GFP_ATOMIC);
+       if (!new_skb)
+               return NULL;
+       new_skb2 = qeth_realloc_headroom(card, new_skb,
+                                        sizeof(struct qeth_hdr));
+       if (!new_skb2) {
+               __qeth_free_new_skb(skb, new_skb);
                return NULL;
+       }
+       if (new_skb != skb)
+               __qeth_free_new_skb(new_skb2, new_skb);
+       new_skb = new_skb2;
        *hdr = __qeth_prepare_skb(card, new_skb, ipv);
        if (*hdr == NULL) {
                __qeth_free_new_skb(skb, new_skb);
@@ -4366,7 +4300,7 @@ out:
        if (flush_count)
                qeth_flush_buffers(queue, 0, start_index, flush_count);
        else if (!atomic_read(&queue->set_pci_flags_count))
-               atomic_swap(&queue->state, QETH_OUT_Q_LOCKED_FLUSH);
+               atomic_xchg(&queue->state, QETH_OUT_Q_LOCKED_FLUSH);
        /*
         * queue->state will go from LOCKED -> UNLOCKED or from
         * LOCKED_FLUSH -> LOCKED if output_handler wanted to 'notify' us
@@ -4844,9 +4778,11 @@ qeth_arp_query(struct qeth_card *card, char __user *udata)
                           "(0x%x/%d)\n",
                           QETH_CARD_IFNAME(card), qeth_arp_get_error_cause(&rc),
                           tmp, tmp);
-               copy_to_user(udata, qinfo.udata, 4);
+               if (copy_to_user(udata, qinfo.udata, 4))
+                       rc = -EFAULT;
        } else {
-               copy_to_user(udata, qinfo.udata, qinfo.udata_len);
+               if (copy_to_user(udata, qinfo.udata, qinfo.udata_len))
+                       rc = -EFAULT;
        }
        kfree(qinfo.udata);
        return rc;
@@ -4992,8 +4928,10 @@ qeth_snmp_command(struct qeth_card *card, char __user *udata)
        if (rc)
                PRINT_WARN("SNMP command failed on %s: (0x%x)\n",
                           QETH_CARD_IFNAME(card), rc);
-        else
-               copy_to_user(udata, qinfo.udata, qinfo.udata_len);
+       else {
+               if (copy_to_user(udata, qinfo.udata, qinfo.udata_len))
+                       rc = -EFAULT;
+       }
 
        kfree(ureq);
        kfree(qinfo.udata);
@@ -5544,12 +5482,10 @@ qeth_set_multicast_list(struct net_device *dev)
        qeth_add_multicast_ipv6(card);
 #endif
 out:
-       if (qeth_set_thread_start_bit(card, QETH_SET_IP_THREAD) == 0)
-               schedule_work(&card->kernel_thread_starter);
+       qeth_set_ip_addr_list(card);
        if (!qeth_adp_supported(card, IPA_SETADP_SET_PROMISC_MODE))
                return;
-       if (qeth_set_thread_start_bit(card, QETH_SET_PROMISC_MODE_THREAD)==0)
-               schedule_work(&card->kernel_thread_starter);
+       qeth_setadp_promisc_mode(card);
 }
 
 static int
@@ -6350,6 +6286,42 @@ static struct ethtool_ops qeth_ethtool_ops = {
        .set_tso     = qeth_ethtool_set_tso,
 };
 
+static int
+qeth_hard_header_parse(struct sk_buff *skb, unsigned char *haddr)
+{
+       struct qeth_card *card;
+       struct ethhdr *eth;
+
+       card = qeth_get_card_from_dev(skb->dev);
+       if (card->options.layer2)
+               goto haveheader;
+#ifdef CONFIG_QETH_IPV6
+       /* cause of the manipulated arp constructor and the ARP
+          flag for OSAE devices we have some nasty exceptions */
+       if (card->info.type == QETH_CARD_TYPE_OSAE) {
+               if (!card->options.fake_ll) {
+                       if ((skb->pkt_type==PACKET_OUTGOING) &&
+                           (skb->protocol==ETH_P_IPV6))
+                               goto haveheader;
+                       else
+                               return 0;
+               } else {
+                       if ((skb->pkt_type==PACKET_OUTGOING) &&
+                           (skb->protocol==ETH_P_IP))
+                               return 0;
+                       else
+                               goto haveheader;
+               }
+       }
+#endif
+       if (!card->options.fake_ll)
+               return 0;
+haveheader:
+       eth = eth_hdr(skb);
+       memcpy(haddr, eth->h_source, ETH_ALEN);
+       return ETH_ALEN;
+}
+
 static int
 qeth_netdev_init(struct net_device *dev)
 {
@@ -6388,7 +6360,10 @@ qeth_netdev_init(struct net_device *dev)
        if (card->options.fake_ll &&
                (qeth_get_netdev_flags(card) & IFF_NOARP))
                        dev->hard_header = qeth_fake_header;
-       dev->hard_header_parse = NULL;
+       if (dev->type == ARPHRD_IEEE802_TR)
+               dev->hard_header_parse = NULL;
+       else
+               dev->hard_header_parse = qeth_hard_header_parse;
        dev->set_mac_address = qeth_layer2_set_mac_address;
        dev->flags |= qeth_get_netdev_flags(card);
        if ((card->options.fake_broadcast) ||
@@ -8067,7 +8042,7 @@ qeth_arp_constructor(struct neighbour *neigh)
        neigh->parms = neigh_parms_clone(parms);
        rcu_read_unlock();
 
-       neigh->type = inet_addr_type(*(u32 *) neigh->primary_key);
+       neigh->type = inet_addr_type(*(__be32 *) neigh->primary_key);
        neigh->nud_state = NUD_NOARP;
        neigh->ops = arp_direct_ops;
        neigh->output = neigh->ops->queue_xmit;
@@ -8235,8 +8210,7 @@ qeth_add_vipa(struct qeth_card *card, enum qeth_prot_versions proto,
        }
        if (!qeth_add_ip(card, ipaddr))
                kfree(ipaddr);
-       if (qeth_set_thread_start_bit(card, QETH_SET_IP_THREAD) == 0)
-               schedule_work(&card->kernel_thread_starter);
+       qeth_set_ip_addr_list(card);
        return rc;
 }
 
@@ -8264,8 +8238,7 @@ qeth_del_vipa(struct qeth_card *card, enum qeth_prot_versions proto,
                return;
        if (!qeth_delete_ip(card, ipaddr))
                kfree(ipaddr);
-       if (qeth_set_thread_start_bit(card, QETH_SET_IP_THREAD) == 0)
-               schedule_work(&card->kernel_thread_starter);
+       qeth_set_ip_addr_list(card);
 }
 
 /*
@@ -8308,8 +8281,7 @@ qeth_add_rxip(struct qeth_card *card, enum qeth_prot_versions proto,
        }
        if (!qeth_add_ip(card, ipaddr))
                kfree(ipaddr);
-       if (qeth_set_thread_start_bit(card, QETH_SET_IP_THREAD) == 0)
-               schedule_work(&card->kernel_thread_starter);
+       qeth_set_ip_addr_list(card);
        return 0;
 }
 
@@ -8337,8 +8309,7 @@ qeth_del_rxip(struct qeth_card *card, enum qeth_prot_versions proto,
                return;
        if (!qeth_delete_ip(card, ipaddr))
                kfree(ipaddr);
-       if (qeth_set_thread_start_bit(card, QETH_SET_IP_THREAD) == 0)
-               schedule_work(&card->kernel_thread_starter);
+       qeth_set_ip_addr_list(card);
 }
 
 /**
@@ -8380,8 +8351,7 @@ qeth_ip_event(struct notifier_block *this,
        default:
                break;
        }
-       if (qeth_set_thread_start_bit(card, QETH_SET_IP_THREAD) == 0)
-               schedule_work(&card->kernel_thread_starter);
+       qeth_set_ip_addr_list(card);
 out:
        return NOTIFY_DONE;
 }
@@ -8433,8 +8403,7 @@ qeth_ip6_event(struct notifier_block *this,
        default:
                break;
        }
-       if (qeth_set_thread_start_bit(card, QETH_SET_IP_THREAD) == 0)
-               schedule_work(&card->kernel_thread_starter);
+       qeth_set_ip_addr_list(card);
 out:
        return NOTIFY_DONE;
 }