]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
ibmvnic: Reduce memcpys in tx descriptor generation
authorNick Child <nnac123@linux.ibm.com>
Wed, 7 Aug 2024 21:18:05 +0000 (16:18 -0500)
committerJakub Kicinski <kuba@kernel.org>
Sat, 10 Aug 2024 05:09:18 +0000 (22:09 -0700)
Previously when creating the header descriptors, the driver would:
1. allocate a temporary buffer on the stack (in build_hdr_descs_arr)
2. memcpy the header info into the temporary buffer (in build_hdr_data)
3. memcpy the temp buffer into a local variable (in create_hdr_descs)
4. copy the local variable into the return buffer (in create_hdr_descs)

Since, there is no opportunity for errors during this process, the temp
buffer is not needed and work can be done on the return buffer directly.

Repurpose build_hdr_data() to only calculate the header lengths. Rename
it to get_hdr_lens().
Edit create_hdr_descs() to read from the skb directly and copy directly
into the returned useful buffer.

The process now involves less memory and write operations while
also being more readable.

Signed-off-by: Nick Child <nnac123@linux.ibm.com>
Link: https://patch.msgid.link/20240807211809.1259563-4-nnac123@linux.ibm.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/ethernet/ibm/ibmvnic.c

index 7d552d4bbe15f26ceeab5691ad3b8a6ec916e442..58a517ecbda391a028c699dfc91a8bd70969a5bc 100644 (file)
@@ -2140,56 +2140,49 @@ static int ibmvnic_close(struct net_device *netdev)
 }
 
 /**
- * build_hdr_data - creates L2/L3/L4 header data buffer
+ * get_hdr_lens - fills list of L2/L3/L4 hdr lens
  * @hdr_field: bitfield determining needed headers
  * @skb: socket buffer
- * @hdr_len: array of header lengths
- * @hdr_data: buffer to write the header to
+ * @hdr_len: array of header lengths to be filled
  *
  * Reads hdr_field to determine which headers are needed by firmware.
  * Builds a buffer containing these headers.  Saves individual header
  * lengths and total buffer length to be used to build descriptors.
+ *
+ * Return: total len of all headers
  */
-static int build_hdr_data(u8 hdr_field, struct sk_buff *skb,
-                         int *hdr_len, u8 *hdr_data)
+static int get_hdr_lens(u8 hdr_field, struct sk_buff *skb,
+                       int *hdr_len)
 {
        int len = 0;
-       u8 *hdr;
-
 
-       if (skb->protocol == htons(ETH_P_IP)) {
-               if (ip_hdr(skb)->protocol == IPPROTO_TCP)
-                       hdr_len[2] = tcp_hdrlen(skb);
-               else if (ip_hdr(skb)->protocol == IPPROTO_UDP)
-                       hdr_len[2] = sizeof(struct udphdr);
-       } else if (skb->protocol == htons(ETH_P_IPV6)) {
-               if (ipv6_hdr(skb)->nexthdr == IPPROTO_TCP)
-                       hdr_len[2] = tcp_hdrlen(skb);
-               else if (ipv6_hdr(skb)->nexthdr == IPPROTO_UDP)
-                       hdr_len[2] = sizeof(struct udphdr);
-       }
 
        if ((hdr_field >> 6) & 1) {
                hdr_len[0] = skb_mac_header_len(skb);
-               hdr = skb_mac_header(skb);
-               memcpy(hdr_data, hdr, hdr_len[0]);
                len += hdr_len[0];
        }
 
        if ((hdr_field >> 5) & 1) {
                hdr_len[1] = skb_network_header_len(skb);
-               hdr = skb_network_header(skb);
-               memcpy(hdr_data + len, hdr, hdr_len[1]);
                len += hdr_len[1];
        }
 
-       if ((hdr_field >> 4) & 1) {
-               hdr = skb_transport_header(skb);
-               memcpy(hdr_data + len, hdr, hdr_len[2]);
-               len += hdr_len[2];
+       if (!((hdr_field >> 4) & 1))
+               return len;
+
+       if (skb->protocol == htons(ETH_P_IP)) {
+               if (ip_hdr(skb)->protocol == IPPROTO_TCP)
+                       hdr_len[2] = tcp_hdrlen(skb);
+               else if (ip_hdr(skb)->protocol == IPPROTO_UDP)
+                       hdr_len[2] = sizeof(struct udphdr);
+       } else if (skb->protocol == htons(ETH_P_IPV6)) {
+               if (ipv6_hdr(skb)->nexthdr == IPPROTO_TCP)
+                       hdr_len[2] = tcp_hdrlen(skb);
+               else if (ipv6_hdr(skb)->nexthdr == IPPROTO_UDP)
+                       hdr_len[2] = sizeof(struct udphdr);
        }
 
-       return len;
+       return len + hdr_len[2];
 }
 
 /**
@@ -2202,12 +2195,14 @@ static int build_hdr_data(u8 hdr_field, struct sk_buff *skb,
  *
  * Creates header and, if needed, header extension descriptors and
  * places them in a descriptor array, scrq_arr
+ *
+ * Return: Number of header descs
  */
 
 static int create_hdr_descs(u8 hdr_field, u8 *hdr_data, int len, int *hdr_len,
                            union sub_crq *scrq_arr)
 {
-       union sub_crq hdr_desc;
+       union sub_crq *hdr_desc;
        int tmp_len = len;
        int num_descs = 0;
        u8 *data, *cur;
@@ -2216,28 +2211,26 @@ static int create_hdr_descs(u8 hdr_field, u8 *hdr_data, int len, int *hdr_len,
        while (tmp_len > 0) {
                cur = hdr_data + len - tmp_len;
 
-               memset(&hdr_desc, 0, sizeof(hdr_desc));
-               if (cur != hdr_data) {
-                       data = hdr_desc.hdr_ext.data;
+               hdr_desc = &scrq_arr[num_descs];
+               if (num_descs) {
+                       data = hdr_desc->hdr_ext.data;
                        tmp = tmp_len > 29 ? 29 : tmp_len;
-                       hdr_desc.hdr_ext.first = IBMVNIC_CRQ_CMD;
-                       hdr_desc.hdr_ext.type = IBMVNIC_HDR_EXT_DESC;
-                       hdr_desc.hdr_ext.len = tmp;
+                       hdr_desc->hdr_ext.first = IBMVNIC_CRQ_CMD;
+                       hdr_desc->hdr_ext.type = IBMVNIC_HDR_EXT_DESC;
+                       hdr_desc->hdr_ext.len = tmp;
                } else {
-                       data = hdr_desc.hdr.data;
+                       data = hdr_desc->hdr.data;
                        tmp = tmp_len > 24 ? 24 : tmp_len;
-                       hdr_desc.hdr.first = IBMVNIC_CRQ_CMD;
-                       hdr_desc.hdr.type = IBMVNIC_HDR_DESC;
-                       hdr_desc.hdr.len = tmp;
-                       hdr_desc.hdr.l2_len = (u8)hdr_len[0];
-                       hdr_desc.hdr.l3_len = cpu_to_be16((u16)hdr_len[1]);
-                       hdr_desc.hdr.l4_len = (u8)hdr_len[2];
-                       hdr_desc.hdr.flag = hdr_field << 1;
+                       hdr_desc->hdr.first = IBMVNIC_CRQ_CMD;
+                       hdr_desc->hdr.type = IBMVNIC_HDR_DESC;
+                       hdr_desc->hdr.len = tmp;
+                       hdr_desc->hdr.l2_len = (u8)hdr_len[0];
+                       hdr_desc->hdr.l3_len = cpu_to_be16((u16)hdr_len[1]);
+                       hdr_desc->hdr.l4_len = (u8)hdr_len[2];
+                       hdr_desc->hdr.flag = hdr_field << 1;
                }
                memcpy(data, cur, tmp);
                tmp_len -= tmp;
-               *scrq_arr = hdr_desc;
-               scrq_arr++;
                num_descs++;
        }
 
@@ -2260,13 +2253,11 @@ static void build_hdr_descs_arr(struct sk_buff *skb,
                                int *num_entries, u8 hdr_field)
 {
        int hdr_len[3] = {0, 0, 0};
-       u8 hdr_data[140] = {0};
        int tot_len;
 
-       tot_len = build_hdr_data(hdr_field, skb, hdr_len,
-                                hdr_data);
-       *num_entries += create_hdr_descs(hdr_field, hdr_data, tot_len, hdr_len,
-                                        indir_arr + 1);
+       tot_len = get_hdr_lens(hdr_field, skb, hdr_len);
+       *num_entries += create_hdr_descs(hdr_field, skb_mac_header(skb),
+                                        tot_len, hdr_len, indir_arr + 1);
 }
 
 static int ibmvnic_xmit_workarounds(struct sk_buff *skb,