s390/qeth: consolidate RX code
authorJulian Wiedmann <jwi@linux.ibm.com>
Mon, 23 Dec 2019 14:22:25 +0000 (15:22 +0100)
committerDavid S. Miller <davem@davemloft.net>
Thu, 26 Dec 2019 23:23:50 +0000 (15:23 -0800)
To reduce the path length and levels of indirection, move the RX
processing from the sub-drivers into the core.

Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/s390/net/qeth_core.h
drivers/s390/net/qeth_core_main.c
drivers/s390/net/qeth_l2_main.c
drivers/s390/net/qeth_l3_main.c

index 6e16b19..4ab3be8 100644 (file)
@@ -728,7 +728,6 @@ struct qeth_osn_info {
 
 struct qeth_discipline {
        const struct device_type *devtype;
-       int (*process_rx_buffer)(struct qeth_card *card, int budget, int *done);
        int (*recover)(void *ptr);
        int (*setup) (struct ccwgroup_device *);
        void (*remove) (struct ccwgroup_device *);
@@ -923,18 +922,6 @@ static inline struct dst_entry *qeth_dst_check_rcu(struct sk_buff *skb, int ipv)
        return dst;
 }
 
-static inline void qeth_rx_csum(struct qeth_card *card, struct sk_buff *skb,
-                               u8 flags)
-{
-       if ((card->dev->features & NETIF_F_RXCSUM) &&
-           (flags & QETH_HDR_EXT_CSUM_TRANSP_REQ)) {
-               skb->ip_summed = CHECKSUM_UNNECESSARY;
-               QETH_CARD_STAT_INC(card, rx_skb_csum);
-       } else {
-               skb->ip_summed = CHECKSUM_NONE;
-       }
-}
-
 static inline void qeth_tx_csum(struct sk_buff *skb, u8 *flags, int ipv)
 {
        *flags |= QETH_HDR_EXT_CSUM_TRANSP_REQ;
@@ -1031,9 +1018,6 @@ struct qeth_cmd_buffer *qeth_get_diag_cmd(struct qeth_card *card,
 void qeth_notify_cmd(struct qeth_cmd_buffer *iob, int reason);
 void qeth_put_cmd(struct qeth_cmd_buffer *iob);
 
-struct sk_buff *qeth_core_get_next_skb(struct qeth_card *,
-               struct qeth_qdio_buffer *, struct qdio_buffer_element **, int *,
-               struct qeth_hdr **);
 void qeth_schedule_recovery(struct qeth_card *);
 int qeth_poll(struct napi_struct *napi, int budget);
 void qeth_clear_ipacmd_list(struct qeth_card *);
index 41f37ce..8e2c058 100644 (file)
@@ -5046,6 +5046,114 @@ out:
 }
 EXPORT_SYMBOL_GPL(qeth_core_hardsetup_card);
 
+#if IS_ENABLED(CONFIG_QETH_L3)
+static void qeth_l3_rebuild_skb(struct qeth_card *card, struct sk_buff *skb,
+                               struct qeth_hdr *hdr)
+{
+       struct af_iucv_trans_hdr *iucv = (struct af_iucv_trans_hdr *) skb->data;
+       struct qeth_hdr_layer3 *l3_hdr = &hdr->hdr.l3;
+       struct net_device *dev = skb->dev;
+
+       if (IS_IQD(card) && iucv->magic == ETH_P_AF_IUCV) {
+               dev_hard_header(skb, dev, ETH_P_AF_IUCV, dev->dev_addr,
+                               "FAKELL", skb->len);
+               return;
+       }
+
+       if (!(l3_hdr->flags & QETH_HDR_PASSTHRU)) {
+               u16 prot = (l3_hdr->flags & QETH_HDR_IPV6) ? ETH_P_IPV6 :
+                                                            ETH_P_IP;
+               unsigned char tg_addr[ETH_ALEN];
+
+               skb_reset_network_header(skb);
+               switch (l3_hdr->flags & QETH_HDR_CAST_MASK) {
+               case QETH_CAST_MULTICAST:
+                       if (prot == ETH_P_IP)
+                               ip_eth_mc_map(ip_hdr(skb)->daddr, tg_addr);
+                       else
+                               ipv6_eth_mc_map(&ipv6_hdr(skb)->daddr, tg_addr);
+                       QETH_CARD_STAT_INC(card, rx_multicast);
+                       break;
+               case QETH_CAST_BROADCAST:
+                       ether_addr_copy(tg_addr, dev->broadcast);
+                       QETH_CARD_STAT_INC(card, rx_multicast);
+                       break;
+               default:
+                       if (card->options.sniffer)
+                               skb->pkt_type = PACKET_OTHERHOST;
+                       ether_addr_copy(tg_addr, dev->dev_addr);
+               }
+
+               if (l3_hdr->ext_flags & QETH_HDR_EXT_SRC_MAC_ADDR)
+                       dev_hard_header(skb, dev, prot, tg_addr,
+                                       &l3_hdr->next_hop.rx.src_mac, skb->len);
+               else
+                       dev_hard_header(skb, dev, prot, tg_addr, "FAKELL",
+                                       skb->len);
+       }
+
+       /* copy VLAN tag from hdr into skb */
+       if (!card->options.sniffer &&
+           (l3_hdr->ext_flags & (QETH_HDR_EXT_VLAN_FRAME |
+                                 QETH_HDR_EXT_INCLUDE_VLAN_TAG))) {
+               u16 tag = (l3_hdr->ext_flags & QETH_HDR_EXT_VLAN_FRAME) ?
+                               l3_hdr->vlan_id :
+                               l3_hdr->next_hop.rx.vlan_id;
+
+               __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), tag);
+       }
+}
+#endif
+
+static void qeth_receive_skb(struct qeth_card *card, struct sk_buff *skb,
+                            struct qeth_hdr *hdr)
+{
+       bool is_cso;
+
+       switch (hdr->hdr.l2.id) {
+       case QETH_HEADER_TYPE_OSN:
+               skb_push(skb, sizeof(*hdr));
+               skb_copy_to_linear_data(skb, hdr, sizeof(*hdr));
+               QETH_CARD_STAT_ADD(card, rx_bytes, skb->len);
+               QETH_CARD_STAT_INC(card, rx_packets);
+
+               card->osn_info.data_cb(skb);
+               return;
+#if IS_ENABLED(CONFIG_QETH_L3)
+       case QETH_HEADER_TYPE_LAYER3:
+               qeth_l3_rebuild_skb(card, skb, hdr);
+               is_cso = hdr->hdr.l3.ext_flags & QETH_HDR_EXT_CSUM_TRANSP_REQ;
+               break;
+#endif
+       case QETH_HEADER_TYPE_LAYER2:
+               is_cso = hdr->hdr.l2.flags[1] & QETH_HDR_EXT_CSUM_TRANSP_REQ;
+               break;
+       default:
+               /* never happens */
+               dev_kfree_skb_any(skb);
+               return;
+       }
+
+       if (is_cso && (card->dev->features & NETIF_F_RXCSUM)) {
+               skb->ip_summed = CHECKSUM_UNNECESSARY;
+               QETH_CARD_STAT_INC(card, rx_skb_csum);
+       } else {
+               skb->ip_summed = CHECKSUM_NONE;
+       }
+
+       skb->protocol = eth_type_trans(skb, skb->dev);
+
+       QETH_CARD_STAT_ADD(card, rx_bytes, skb->len);
+       QETH_CARD_STAT_INC(card, rx_packets);
+       if (skb_is_nonlinear(skb)) {
+               QETH_CARD_STAT_INC(card, rx_sg_skbs);
+               QETH_CARD_STAT_ADD(card, rx_sg_frags,
+                                  skb_shinfo(skb)->nr_frags);
+       }
+
+       napi_gro_receive(&card->napi, skb);
+}
+
 static void qeth_create_skb_frag(struct sk_buff *skb, char *data, int data_len)
 {
        struct page *page = virt_to_page(data);
@@ -5062,10 +5170,10 @@ static inline int qeth_is_last_sbale(struct qdio_buffer_element *sbale)
        return (sbale->eflags & SBAL_EFLAGS_LAST_ENTRY);
 }
 
-struct sk_buff *qeth_core_get_next_skb(struct qeth_card *card,
-               struct qeth_qdio_buffer *qethbuffer,
-               struct qdio_buffer_element **__element, int *__offset,
-               struct qeth_hdr **hdr)
+static int qeth_extract_skb(struct qeth_card *card,
+                           struct qeth_qdio_buffer *qethbuffer,
+                           struct qdio_buffer_element **__element,
+                           int *__offset)
 {
        struct qdio_buffer_element *element = *__element;
        struct qdio_buffer *buffer = qethbuffer->buffer;
@@ -5073,6 +5181,7 @@ struct sk_buff *qeth_core_get_next_skb(struct qeth_card *card,
        int offset = *__offset;
        bool use_rx_sg = false;
        unsigned int headroom;
+       struct qeth_hdr *hdr;
        struct sk_buff *skb;
        int skb_len = 0;
 
@@ -5080,42 +5189,42 @@ next_packet:
        /* qeth_hdr must not cross element boundaries */
        while (element->length < offset + sizeof(struct qeth_hdr)) {
                if (qeth_is_last_sbale(element))
-                       return NULL;
+                       return -ENODATA;
                element++;
                offset = 0;
        }
-       *hdr = element->addr + offset;
 
-       offset += sizeof(struct qeth_hdr);
+       hdr = element->addr + offset;
+       offset += sizeof(*hdr);
        skb = NULL;
 
-       switch ((*hdr)->hdr.l2.id) {
+       switch (hdr->hdr.l2.id) {
        case QETH_HEADER_TYPE_LAYER2:
-               skb_len = (*hdr)->hdr.l2.pkt_length;
+               skb_len = hdr->hdr.l2.pkt_length;
                linear_len = ETH_HLEN;
                headroom = 0;
                break;
        case QETH_HEADER_TYPE_LAYER3:
-               skb_len = (*hdr)->hdr.l3.length;
+               skb_len = hdr->hdr.l3.length;
                if (!IS_LAYER3(card)) {
                        QETH_CARD_STAT_INC(card, rx_dropped_notsupp);
                        goto walk_packet;
                }
 
-               if ((*hdr)->hdr.l3.flags & QETH_HDR_PASSTHRU) {
+               if (hdr->hdr.l3.flags & QETH_HDR_PASSTHRU) {
                        linear_len = ETH_HLEN;
                        headroom = 0;
                        break;
                }
 
-               if ((*hdr)->hdr.l3.flags & QETH_HDR_IPV6)
+               if (hdr->hdr.l3.flags & QETH_HDR_IPV6)
                        linear_len = sizeof(struct ipv6hdr);
                else
                        linear_len = sizeof(struct iphdr);
                headroom = ETH_HLEN;
                break;
        case QETH_HEADER_TYPE_OSN:
-               skb_len = (*hdr)->hdr.osn.pdu_length;
+               skb_len = hdr->hdr.osn.pdu_length;
                if (!IS_OSN(card)) {
                        QETH_CARD_STAT_INC(card, rx_dropped_notsupp);
                        goto walk_packet;
@@ -5125,13 +5234,13 @@ next_packet:
                headroom = sizeof(struct qeth_hdr);
                break;
        default:
-               if ((*hdr)->hdr.l2.id & QETH_HEADER_MASK_INVAL)
+               if (hdr->hdr.l2.id & QETH_HEADER_MASK_INVAL)
                        QETH_CARD_STAT_INC(card, rx_frame_errors);
                else
                        QETH_CARD_STAT_INC(card, rx_dropped_notsupp);
 
                /* Can't determine packet length, drop the whole buffer. */
-               return NULL;
+               return -EPROTONOSUPPORT;
        }
 
        if (skb_len < linear_len) {
@@ -5195,7 +5304,7 @@ walk_packet:
                                        QETH_CARD_STAT_INC(card,
                                                           rx_length_errors);
                                }
-                               return NULL;
+                               return -EMSGSIZE;
                        }
                        element++;
                        offset = 0;
@@ -5208,22 +5317,40 @@ walk_packet:
 
        *__element = element;
        *__offset = offset;
-       if (use_rx_sg) {
-               QETH_CARD_STAT_INC(card, rx_sg_skbs);
-               QETH_CARD_STAT_ADD(card, rx_sg_frags,
-                                  skb_shinfo(skb)->nr_frags);
+
+       qeth_receive_skb(card, skb, hdr);
+       return 0;
+}
+
+static int qeth_extract_skbs(struct qeth_card *card, int budget,
+                            struct qeth_qdio_buffer *buf, bool *done)
+{
+       int work_done = 0;
+
+       WARN_ON_ONCE(!budget);
+       *done = false;
+
+       while (budget) {
+               if (qeth_extract_skb(card, buf, &card->rx.b_element,
+                                    &card->rx.e_offset)) {
+                       *done = true;
+                       break;
+               }
+
+               work_done++;
+               budget--;
        }
-       return skb;
+
+       return work_done;
 }
-EXPORT_SYMBOL_GPL(qeth_core_get_next_skb);
 
 int qeth_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;
+       bool done;
 
        while (1) {
                if (!card->rx.b_count) {
@@ -5246,11 +5373,10 @@ int qeth_poll(struct napi_struct *napi, int budget)
                        if (!(card->rx.qdio_err &&
                            qeth_check_qdio_errors(card, buffer->buffer,
                            card->rx.qdio_err, "qinerr")))
-                               work_done +=
-                                       card->discipline->process_rx_buffer(
-                                               card, new_budget, &done);
+                               work_done += qeth_extract_skbs(card, new_budget,
+                                                              buffer, &done);
                        else
-                               done = 1;
+                               done = true;
 
                        if (done) {
                                QETH_CARD_STAT_INC(card, rx_bufs);
index 8c95e60..69d147c 100644 (file)
@@ -298,45 +298,6 @@ static void qeth_l2_stop_card(struct qeth_card *card)
        card->info.promisc_mode = 0;
 }
 
-static int qeth_l2_process_inbound_buffer(struct qeth_card *card,
-                               int budget, int *done)
-{
-       int work_done = 0;
-       struct sk_buff *skb;
-       struct qeth_hdr *hdr;
-       unsigned int len;
-
-       *done = 0;
-       WARN_ON_ONCE(!budget);
-       while (budget) {
-               skb = qeth_core_get_next_skb(card,
-                       &card->qdio.in_q->bufs[card->rx.b_index],
-                       &card->rx.b_element, &card->rx.e_offset, &hdr);
-               if (!skb) {
-                       *done = 1;
-                       break;
-               }
-
-               if (hdr->hdr.l2.id == QETH_HEADER_TYPE_LAYER2) {
-                       skb->protocol = eth_type_trans(skb, skb->dev);
-                       qeth_rx_csum(card, skb, hdr->hdr.l2.flags[1]);
-                       len = skb->len;
-                       napi_gro_receive(&card->napi, skb);
-               } else {
-                       skb_push(skb, sizeof(*hdr));
-                       skb_copy_to_linear_data(skb, hdr, sizeof(*hdr));
-                       len = skb->len;
-                       card->osn_info.data_cb(skb);
-               }
-
-               work_done++;
-               budget--;
-               QETH_CARD_STAT_INC(card, rx_packets);
-               QETH_CARD_STAT_ADD(card, rx_bytes, len);
-       }
-       return work_done;
-}
-
 static int qeth_l2_request_initial_mac(struct qeth_card *card)
 {
        int rc = 0;
@@ -961,7 +922,6 @@ static int qeth_l2_control_event(struct qeth_card *card,
 
 struct qeth_discipline qeth_l2_discipline = {
        .devtype = &qeth_l2_devtype,
-       .process_rx_buffer = qeth_l2_process_inbound_buffer,
        .recover = qeth_l2_recover,
        .setup = qeth_l2_probe_device,
        .remove = qeth_l2_remove_device,
index 04d7777..8a1535e 100644 (file)
@@ -1164,96 +1164,6 @@ static int qeth_l3_vlan_rx_kill_vid(struct net_device *dev,
        return 0;
 }
 
-static void qeth_l3_rebuild_skb(struct qeth_card *card, struct sk_buff *skb,
-                               struct qeth_hdr *hdr)
-{
-       struct af_iucv_trans_hdr *iucv = (struct af_iucv_trans_hdr *) skb->data;
-       struct net_device *dev = skb->dev;
-
-       if (IS_IQD(card) && iucv->magic == ETH_P_AF_IUCV) {
-               dev_hard_header(skb, dev, ETH_P_AF_IUCV, dev->dev_addr,
-                               "FAKELL", skb->len);
-               return;
-       }
-
-       if (!(hdr->hdr.l3.flags & QETH_HDR_PASSTHRU)) {
-               u16 prot = (hdr->hdr.l3.flags & QETH_HDR_IPV6) ? ETH_P_IPV6 :
-                                                                ETH_P_IP;
-               unsigned char tg_addr[ETH_ALEN];
-
-               skb_reset_network_header(skb);
-               switch (hdr->hdr.l3.flags & QETH_HDR_CAST_MASK) {
-               case QETH_CAST_MULTICAST:
-                       if (prot == ETH_P_IP)
-                               ip_eth_mc_map(ip_hdr(skb)->daddr, tg_addr);
-                       else
-                               ipv6_eth_mc_map(&ipv6_hdr(skb)->daddr, tg_addr);
-                       QETH_CARD_STAT_INC(card, rx_multicast);
-                       break;
-               case QETH_CAST_BROADCAST:
-                       ether_addr_copy(tg_addr, card->dev->broadcast);
-                       QETH_CARD_STAT_INC(card, rx_multicast);
-                       break;
-               default:
-                       if (card->options.sniffer)
-                               skb->pkt_type = PACKET_OTHERHOST;
-                       ether_addr_copy(tg_addr, card->dev->dev_addr);
-               }
-
-               if (hdr->hdr.l3.ext_flags & QETH_HDR_EXT_SRC_MAC_ADDR)
-                       card->dev->header_ops->create(skb, card->dev, prot,
-                               tg_addr, &hdr->hdr.l3.next_hop.rx.src_mac,
-                               skb->len);
-               else
-                       card->dev->header_ops->create(skb, card->dev, prot,
-                               tg_addr, "FAKELL", skb->len);
-       }
-
-       /* copy VLAN tag from hdr into skb */
-       if (!card->options.sniffer &&
-           (hdr->hdr.l3.ext_flags & (QETH_HDR_EXT_VLAN_FRAME |
-                                     QETH_HDR_EXT_INCLUDE_VLAN_TAG))) {
-               u16 tag = (hdr->hdr.l3.ext_flags & QETH_HDR_EXT_VLAN_FRAME) ?
-                               hdr->hdr.l3.vlan_id :
-                               hdr->hdr.l3.next_hop.rx.vlan_id;
-               __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), tag);
-       }
-
-       qeth_rx_csum(card, skb, hdr->hdr.l3.ext_flags);
-}
-
-static int qeth_l3_process_inbound_buffer(struct qeth_card *card,
-                               int budget, int *done)
-{
-       int work_done = 0;
-       struct sk_buff *skb;
-       struct qeth_hdr *hdr;
-
-       *done = 0;
-       WARN_ON_ONCE(!budget);
-       while (budget) {
-               skb = qeth_core_get_next_skb(card,
-                       &card->qdio.in_q->bufs[card->rx.b_index],
-                       &card->rx.b_element, &card->rx.e_offset, &hdr);
-               if (!skb) {
-                       *done = 1;
-                       break;
-               }
-
-               if (hdr->hdr.l3.id == QETH_HEADER_TYPE_LAYER3)
-                       qeth_l3_rebuild_skb(card, skb, hdr);
-
-               skb->protocol = eth_type_trans(skb, skb->dev);
-               QETH_CARD_STAT_INC(card, rx_packets);
-               QETH_CARD_STAT_ADD(card, rx_bytes, skb->len);
-
-               napi_gro_receive(&card->napi, skb);
-               work_done++;
-               budget--;
-       }
-       return work_done;
-}
-
 static void qeth_l3_stop_card(struct qeth_card *card)
 {
        QETH_CARD_TEXT(card, 2, "stopcard");
@@ -2317,7 +2227,6 @@ static int qeth_l3_control_event(struct qeth_card *card,
 
 struct qeth_discipline qeth_l3_discipline = {
        .devtype = &qeth_l3_devtype,
-       .process_rx_buffer = qeth_l3_process_inbound_buffer,
        .recover = qeth_l3_recover,
        .setup = qeth_l3_probe_device,
        .remove = qeth_l3_remove_device,