Commit d95f749a authored by Nick Child's avatar Nick Child Committed by Jakub Kicinski

ibmvnic: Reduce memcpys in tx descriptor generation

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: default avatarNick Child <nnac123@linux.ibm.com>
Link: https://patch.msgid.link/20240807211809.1259563-4-nnac123@linux.ibm.comSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent b41b45ec
...@@ -2140,56 +2140,49 @@ static int ibmvnic_close(struct net_device *netdev) ...@@ -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 * @hdr_field: bitfield determining needed headers
* @skb: socket buffer * @skb: socket buffer
* @hdr_len: array of header lengths * @hdr_len: array of header lengths to be filled
* @hdr_data: buffer to write the header to
* *
* Reads hdr_field to determine which headers are needed by firmware. * Reads hdr_field to determine which headers are needed by firmware.
* Builds a buffer containing these headers. Saves individual header * Builds a buffer containing these headers. Saves individual header
* lengths and total buffer length to be used to build descriptors. * 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, static int get_hdr_lens(u8 hdr_field, struct sk_buff *skb,
int *hdr_len, u8 *hdr_data) int *hdr_len)
{ {
int len = 0; 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) { if ((hdr_field >> 6) & 1) {
hdr_len[0] = skb_mac_header_len(skb); hdr_len[0] = skb_mac_header_len(skb);
hdr = skb_mac_header(skb);
memcpy(hdr_data, hdr, hdr_len[0]);
len += hdr_len[0]; len += hdr_len[0];
} }
if ((hdr_field >> 5) & 1) { if ((hdr_field >> 5) & 1) {
hdr_len[1] = skb_network_header_len(skb); 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]; len += hdr_len[1];
} }
if ((hdr_field >> 4) & 1) { if (!((hdr_field >> 4) & 1))
hdr = skb_transport_header(skb); return len;
memcpy(hdr_data + len, hdr, hdr_len[2]);
len += hdr_len[2]; 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, ...@@ -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 * Creates header and, if needed, header extension descriptors and
* places them in a descriptor array, scrq_arr * 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, static int create_hdr_descs(u8 hdr_field, u8 *hdr_data, int len, int *hdr_len,
union sub_crq *scrq_arr) union sub_crq *scrq_arr)
{ {
union sub_crq hdr_desc; union sub_crq *hdr_desc;
int tmp_len = len; int tmp_len = len;
int num_descs = 0; int num_descs = 0;
u8 *data, *cur; u8 *data, *cur;
...@@ -2216,28 +2211,26 @@ static int create_hdr_descs(u8 hdr_field, u8 *hdr_data, int len, int *hdr_len, ...@@ -2216,28 +2211,26 @@ static int create_hdr_descs(u8 hdr_field, u8 *hdr_data, int len, int *hdr_len,
while (tmp_len > 0) { while (tmp_len > 0) {
cur = hdr_data + len - tmp_len; cur = hdr_data + len - tmp_len;
memset(&hdr_desc, 0, sizeof(hdr_desc)); hdr_desc = &scrq_arr[num_descs];
if (cur != hdr_data) { if (num_descs) {
data = hdr_desc.hdr_ext.data; data = hdr_desc->hdr_ext.data;
tmp = tmp_len > 29 ? 29 : tmp_len; tmp = tmp_len > 29 ? 29 : tmp_len;
hdr_desc.hdr_ext.first = IBMVNIC_CRQ_CMD; hdr_desc->hdr_ext.first = IBMVNIC_CRQ_CMD;
hdr_desc.hdr_ext.type = IBMVNIC_HDR_EXT_DESC; hdr_desc->hdr_ext.type = IBMVNIC_HDR_EXT_DESC;
hdr_desc.hdr_ext.len = tmp; hdr_desc->hdr_ext.len = tmp;
} else { } else {
data = hdr_desc.hdr.data; data = hdr_desc->hdr.data;
tmp = tmp_len > 24 ? 24 : tmp_len; tmp = tmp_len > 24 ? 24 : tmp_len;
hdr_desc.hdr.first = IBMVNIC_CRQ_CMD; hdr_desc->hdr.first = IBMVNIC_CRQ_CMD;
hdr_desc.hdr.type = IBMVNIC_HDR_DESC; hdr_desc->hdr.type = IBMVNIC_HDR_DESC;
hdr_desc.hdr.len = tmp; hdr_desc->hdr.len = tmp;
hdr_desc.hdr.l2_len = (u8)hdr_len[0]; hdr_desc->hdr.l2_len = (u8)hdr_len[0];
hdr_desc.hdr.l3_len = cpu_to_be16((u16)hdr_len[1]); hdr_desc->hdr.l3_len = cpu_to_be16((u16)hdr_len[1]);
hdr_desc.hdr.l4_len = (u8)hdr_len[2]; hdr_desc->hdr.l4_len = (u8)hdr_len[2];
hdr_desc.hdr.flag = hdr_field << 1; hdr_desc->hdr.flag = hdr_field << 1;
} }
memcpy(data, cur, tmp); memcpy(data, cur, tmp);
tmp_len -= tmp; tmp_len -= tmp;
*scrq_arr = hdr_desc;
scrq_arr++;
num_descs++; num_descs++;
} }
...@@ -2260,13 +2253,11 @@ static void build_hdr_descs_arr(struct sk_buff *skb, ...@@ -2260,13 +2253,11 @@ static void build_hdr_descs_arr(struct sk_buff *skb,
int *num_entries, u8 hdr_field) int *num_entries, u8 hdr_field)
{ {
int hdr_len[3] = {0, 0, 0}; int hdr_len[3] = {0, 0, 0};
u8 hdr_data[140] = {0};
int tot_len; int tot_len;
tot_len = build_hdr_data(hdr_field, skb, hdr_len, tot_len = get_hdr_lens(hdr_field, skb, hdr_len);
hdr_data); *num_entries += create_hdr_descs(hdr_field, skb_mac_header(skb),
*num_entries += create_hdr_descs(hdr_field, hdr_data, tot_len, hdr_len, tot_len, hdr_len, indir_arr + 1);
indir_arr + 1);
} }
static int ibmvnic_xmit_workarounds(struct sk_buff *skb, static int ibmvnic_xmit_workarounds(struct sk_buff *skb,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment