]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - drivers/s390/net/qeth_l3_main.c
vlan: Rename VLAN_GROUP_ARRAY_LEN to VLAN_N_VID.
[net-next-2.6.git] / drivers / s390 / net / qeth_l3_main.c
index e22ae248f613eea825eaf8fe48f02bbd078f9818..74d1401a5d5e37065ba722914cf8549ad8718d9c 100644 (file)
@@ -103,12 +103,7 @@ int qeth_l3_string_to_ipaddr4(const char *buf, __u8 *addr)
 
 void qeth_l3_ipaddr6_to_string(const __u8 *addr, char *buf)
 {
-       sprintf(buf, "%02x%02x:%02x%02x:%02x%02x:%02x%02x"
-                    ":%02x%02x:%02x%02x:%02x%02x:%02x%02x",
-                    addr[0], addr[1], addr[2], addr[3],
-                    addr[4], addr[5], addr[6], addr[7],
-                    addr[8], addr[9], addr[10], addr[11],
-                    addr[12], addr[13], addr[14], addr[15]);
+       sprintf(buf, "%pI6", addr);
 }
 
 int qeth_l3_string_to_ipaddr6(const char *buf, __u8 *addr)
@@ -1825,7 +1820,7 @@ static void qeth_l3_add_vlan_mc(struct qeth_card *card)
                return;
 
        vg = card->vlangrp;
-       for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {
+       for (i = 0; i < VLAN_N_VID; i++) {
                struct net_device *netdev = vlan_group_get_device(vg, i);
                if (netdev == NULL ||
                    !(netdev->flags & IFF_UP))
@@ -1888,7 +1883,7 @@ static void qeth_l3_add_vlan_mc6(struct qeth_card *card)
                return;
 
        vg = card->vlangrp;
-       for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {
+       for (i = 0; i < VLAN_N_VID; i++) {
                struct net_device *netdev = vlan_group_get_device(vg, i);
                if (netdev == NULL ||
                    !(netdev->flags & IFF_UP))
@@ -2018,13 +2013,14 @@ static void qeth_l3_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
        qeth_l3_set_multicast_list(card->dev);
 }
 
-static inline __u16 qeth_l3_rebuild_skb(struct qeth_card *card,
-                       struct sk_buff *skb, struct qeth_hdr *hdr)
+static inline int qeth_l3_rebuild_skb(struct qeth_card *card,
+                       struct sk_buff *skb, struct qeth_hdr *hdr,
+                       unsigned short *vlan_id)
 {
-       unsigned short vlan_id = 0;
        __be16 prot;
        struct iphdr *ip_hdr;
        unsigned char tg_addr[MAX_ADDR_LEN];
+       int is_vlan = 0;
 
        if (!(hdr->hdr.l3.flags & QETH_HDR_PASSTHRU)) {
                prot = htons((hdr->hdr.l3.flags & QETH_HDR_IPV6)? ETH_P_IPV6 :
@@ -2087,8 +2083,9 @@ static inline __u16 qeth_l3_rebuild_skb(struct qeth_card *card,
 
        if (hdr->hdr.l3.ext_flags &
            (QETH_HDR_EXT_VLAN_FRAME | QETH_HDR_EXT_INCLUDE_VLAN_TAG)) {
-               vlan_id = (hdr->hdr.l3.ext_flags & QETH_HDR_EXT_VLAN_FRAME)?
+               *vlan_id = (hdr->hdr.l3.ext_flags & QETH_HDR_EXT_VLAN_FRAME) ?
                 hdr->hdr.l3.vlan_id : *((u16 *)&hdr->hdr.l3.dest_addr[12]);
+               is_vlan = 1;
        }
 
        switch (card->options.checksum_type) {
@@ -2109,54 +2106,44 @@ static inline __u16 qeth_l3_rebuild_skb(struct qeth_card *card,
                        skb->ip_summed = CHECKSUM_NONE;
        }
 
-       return vlan_id;
+       return is_vlan;
 }
 
-static void qeth_l3_process_inbound_buffer(struct qeth_card *card,
-                           struct qeth_qdio_buffer *buf, int index)
+static int qeth_l3_process_inbound_buffer(struct qeth_card *card,
+                               int budget, int *done)
 {
-       struct qdio_buffer_element *element;
+       int work_done = 0;
        struct sk_buff *skb;
        struct qeth_hdr *hdr;
-       int offset;
        __u16 vlan_tag = 0;
+       int is_vlan;
        unsigned int len;
-       /* get first element of current buffer */
-       element = (struct qdio_buffer_element *)&buf->buffer->element[0];
-       offset = 0;
-       if (card->options.performance_stats)
-               card->perf_stats.bufs_rec++;
-       while ((skb = qeth_core_get_next_skb(card, buf->buffer, &element,
-                                      &offset, &hdr))) {
-               skb->dev = card->dev;
-               /* is device UP ? */
-               if (!(card->dev->flags & IFF_UP)) {
-                       dev_kfree_skb_any(skb);
-                       continue;
-               }
 
+       *done = 0;
+       BUG_ON(!budget);
+       while (budget) {
+               skb = qeth_core_get_next_skb(card,
+                       card->qdio.in_q->bufs[card->rx.b_index].buffer,
+                       &card->rx.b_element, &card->rx.e_offset, &hdr);
+               if (!skb) {
+                       *done = 1;
+                       break;
+               }
+               skb->dev = card->dev;
                switch (hdr->hdr.l3.id) {
                case QETH_HEADER_TYPE_LAYER3:
-                       vlan_tag = qeth_l3_rebuild_skb(card, skb, hdr);
+                       is_vlan = qeth_l3_rebuild_skb(card, skb, hdr,
+                                                     &vlan_tag);
                        len = skb->len;
-                       if (vlan_tag && !card->options.sniffer)
-                               if (card->vlangrp)
-                                       vlan_hwaccel_rx(skb, card->vlangrp,
-                                               vlan_tag);
-                               else {
-                                       dev_kfree_skb_any(skb);
-                                       continue;
-                               }
+                       if (is_vlan && !card->options.sniffer)
+                               vlan_gro_receive(&card->napi, card->vlangrp,
+                                       vlan_tag, skb);
                        else
-                               netif_rx(skb);
+                               napi_gro_receive(&card->napi, skb);
                        break;
                case QETH_HEADER_TYPE_LAYER2: /* for HiperSockets sniffer */
                        skb->pkt_type = PACKET_HOST;
                        skb->protocol = eth_type_trans(skb, skb->dev);
-                       if (card->options.checksum_type == NO_CHECKSUMMING)
-                               skb->ip_summed = CHECKSUM_UNNECESSARY;
-                       else
-                               skb->ip_summed = CHECKSUM_NONE;
                        len = skb->len;
                        netif_receive_skb(skb);
                        break;
@@ -2166,10 +2153,87 @@ static void qeth_l3_process_inbound_buffer(struct qeth_card *card,
                        QETH_DBF_HEX(CTRL, 3, hdr, QETH_DBF_CTRL_LEN);
                        continue;
                }
-
+               work_done++;
+               budget--;
                card->stats.rx_packets++;
                card->stats.rx_bytes += len;
        }
+       return work_done;
+}
+
+static int qeth_l3_poll(struct napi_struct *napi, int budget)
+{
+       struct qeth_card *card = container_of(napi, struct qeth_card, napi);
+       int work_done = 0;
+       struct qeth_qdio_buffer *buffer;
+       int done;
+       int new_budget = budget;
+
+       if (card->options.performance_stats) {
+               card->perf_stats.inbound_cnt++;
+               card->perf_stats.inbound_start_time = qeth_get_micros();
+       }
+
+       while (1) {
+               if (!card->rx.b_count) {
+                       card->rx.qdio_err = 0;
+                       card->rx.b_count = qdio_get_next_buffers(
+                               card->data.ccwdev, 0, &card->rx.b_index,
+                               &card->rx.qdio_err);
+                       if (card->rx.b_count <= 0) {
+                               card->rx.b_count = 0;
+                               break;
+                       }
+                       card->rx.b_element =
+                               &card->qdio.in_q->bufs[card->rx.b_index]
+                               .buffer->element[0];
+                       card->rx.e_offset = 0;
+               }
+
+               while (card->rx.b_count) {
+                       buffer = &card->qdio.in_q->bufs[card->rx.b_index];
+                       if (!(card->rx.qdio_err &&
+                           qeth_check_qdio_errors(card, buffer->buffer,
+                           card->rx.qdio_err, "qinerr")))
+                               work_done += qeth_l3_process_inbound_buffer(
+                                       card, new_budget, &done);
+                       else
+                               done = 1;
+
+                       if (done) {
+                               if (card->options.performance_stats)
+                                       card->perf_stats.bufs_rec++;
+                               qeth_put_buffer_pool_entry(card,
+                                       buffer->pool_entry);
+                               qeth_queue_input_buffer(card, card->rx.b_index);
+                               card->rx.b_count--;
+                               if (card->rx.b_count) {
+                                       card->rx.b_index =
+                                               (card->rx.b_index + 1) %
+                                               QDIO_MAX_BUFFERS_PER_Q;
+                                       card->rx.b_element =
+                                               &card->qdio.in_q
+                                               ->bufs[card->rx.b_index]
+                                               .buffer->element[0];
+                                       card->rx.e_offset = 0;
+                               }
+                       }
+
+                       if (work_done >= budget)
+                               goto out;
+                       else
+                               new_budget = budget - work_done;
+               }
+       }
+
+       napi_complete(napi);
+       if (qdio_start_irq(card->data.ccwdev, 0))
+               napi_schedule(&card->napi);
+out:
+       if (card->options.performance_stats)
+               card->perf_stats.inbound_time += qeth_get_micros() -
+                       card->perf_stats.inbound_start_time;
+       return work_done;
 }
 
 static int qeth_l3_verify_vlan_dev(struct net_device *dev,
@@ -2183,7 +2247,7 @@ static int qeth_l3_verify_vlan_dev(struct net_device *dev,
        if (!vg)
                return rc;
 
-       for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {
+       for (i = 0; i < VLAN_N_VID; i++) {
                if (vlan_group_get_device(vg, i) == dev) {
                        rc = QETH_VLAN_CARD;
                        break;
@@ -3103,6 +3167,7 @@ tx_drop:
 static int qeth_l3_open(struct net_device *dev)
 {
        struct qeth_card *card = dev->ml_priv;
+       int rc = 0;
 
        QETH_CARD_TEXT(card, 4, "qethopen");
        if (card->state != CARD_STATE_SOFTSETUP)
@@ -3113,7 +3178,12 @@ static int qeth_l3_open(struct net_device *dev)
 
        if (!card->lan_online && netif_carrier_ok(dev))
                netif_carrier_off(dev);
-       return 0;
+       if (qdio_stop_irq(card->data.ccwdev, 0) >= 0) {
+               napi_enable(&card->napi);
+               napi_schedule(&card->napi);
+       } else
+               rc = -EIO;
+       return rc;
 }
 
 static int qeth_l3_stop(struct net_device *dev)
@@ -3122,8 +3192,10 @@ static int qeth_l3_stop(struct net_device *dev)
 
        QETH_CARD_TEXT(card, 4, "qethstop");
        netif_tx_disable(dev);
-       if (card->state == CARD_STATE_UP)
+       if (card->state == CARD_STATE_UP) {
                card->state = CARD_STATE_SOFTSETUP;
+               napi_disable(&card->napi);
+       }
        return 0;
 }
 
@@ -3293,57 +3365,19 @@ static int qeth_l3_setup_netdev(struct qeth_card *card)
        card->dev->gso_max_size = 15 * PAGE_SIZE;
 
        SET_NETDEV_DEV(card->dev, &card->gdev->dev);
+       netif_napi_add(card->dev, &card->napi, qeth_l3_poll, QETH_NAPI_WEIGHT);
        return register_netdev(card->dev);
 }
 
-static void qeth_l3_qdio_input_handler(struct ccw_device *ccwdev,
-               unsigned int qdio_err, unsigned int queue, int first_element,
-               int count, unsigned long card_ptr)
-{
-       struct net_device *net_dev;
-       struct qeth_card *card;
-       struct qeth_qdio_buffer *buffer;
-       int index;
-       int i;
-
-       card = (struct qeth_card *) card_ptr;
-       net_dev = card->dev;
-       if (card->options.performance_stats) {
-               card->perf_stats.inbound_cnt++;
-               card->perf_stats.inbound_start_time = qeth_get_micros();
-       }
-       if (qdio_err & QDIO_ERROR_ACTIVATE_CHECK_CONDITION) {
-               QETH_CARD_TEXT(card, 1, "qdinchk");
-               QETH_CARD_TEXT_(card, 1, "%04X%04X",
-                               first_element, count);
-               QETH_CARD_TEXT_(card, 1, "%04X", queue);
-               qeth_schedule_recovery(card);
-               return;
-       }
-       for (i = first_element; i < (first_element + count); ++i) {
-               index = i % QDIO_MAX_BUFFERS_PER_Q;
-               buffer = &card->qdio.in_q->bufs[index];
-               if (!(qdio_err &&
-                     qeth_check_qdio_errors(card, buffer->buffer,
-                                            qdio_err, "qinerr")))
-                       qeth_l3_process_inbound_buffer(card, buffer, index);
-               /* clear buffer and give back to hardware */
-               qeth_put_buffer_pool_entry(card, buffer->pool_entry);
-               qeth_queue_input_buffer(card, index);
-       }
-       if (card->options.performance_stats)
-               card->perf_stats.inbound_time += qeth_get_micros() -
-                       card->perf_stats.inbound_start_time;
-}
-
 static int qeth_l3_probe_device(struct ccwgroup_device *gdev)
 {
        struct qeth_card *card = dev_get_drvdata(&gdev->dev);
 
        qeth_l3_create_device_attributes(&gdev->dev);
        card->options.layer2 = 0;
+       card->discipline.start_poll = qeth_qdio_start_poll;
        card->discipline.input_handler = (qdio_handler_t *)
-               qeth_l3_qdio_input_handler;
+               qeth_qdio_input_handler;
        card->discipline.output_handler = (qdio_handler_t *)
                qeth_qdio_output_handler;
        card->discipline.recover = qeth_l3_recover;
@@ -3402,6 +3436,7 @@ static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode)
        }
 
        card->state = CARD_STATE_HARDSETUP;
+       memset(&card->rx, 0, sizeof(struct qeth_rx));
        qeth_print_status_message(card);
 
        /* softsetup */
@@ -3538,9 +3573,6 @@ static int qeth_l3_recover(void *ptr)
        card->use_hard_stop = 1;
        __qeth_l3_set_offline(card->gdev, 1);
        rc = __qeth_l3_set_online(card->gdev, 1);
-       /* don't run another scheduled recovery */
-       qeth_clear_thread_start_bit(card, QETH_RECOVER_THREAD);
-       qeth_clear_thread_running_bit(card, QETH_RECOVER_THREAD);
        if (!rc)
                dev_info(&card->gdev->dev,
                        "Device successfully recovered!\n");
@@ -3551,6 +3583,8 @@ static int qeth_l3_recover(void *ptr)
                dev_warn(&card->gdev->dev, "The qeth device driver "
                        "failed to recover an error on the device\n");
        }
+       qeth_clear_thread_start_bit(card, QETH_RECOVER_THREAD);
+       qeth_clear_thread_running_bit(card, QETH_RECOVER_THREAD);
        return 0;
 }