Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b60f699e authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'net-qualcomm-rmnet-Enable-csum-offloads'



Subash Abhinov Kasiviswanathan says:

====================
net: qualcomm: rmnet: Enable csum offloads

This series introduces the MAPv4 packet format for checksum
offload plus some other minor changes.

Patches 1-3 are cleanups.

Patch 4 renames the ingress format to data format so that all data
formats can be configured using this going forward.

Patch 5 uses the pacing helper to improve TCP transmit performance.

Patch 6-9 defines the the MAPv4 for checksum offload for RX and TX.
A new header and trailer format are used as part of MAPv4.
For RX checksum offload, only the 1's complement of the IP payload
portion is computed by hardware. The meta data from RX header is
used to verify the checksum field in the packet. Note that the
IP packet and its field itself is not modified by hardware.
This gives metadata to help with the RX checksum. For TX, the
required metadata is filled up so hardware can compute the
checksum.

Patch 10 enables GSO on rmnet devices

v1->v2: Fix sparse errors reported by kbuild test robot

v2->v3: Update the commit message for Patch 5 based on Eric's comments
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents f66faae2 0c9214d5
Loading
Loading
Loading
Loading
+5 −5
Original line number Diff line number Diff line
@@ -143,7 +143,7 @@ static int rmnet_newlink(struct net *src_net, struct net_device *dev,
			 struct nlattr *tb[], struct nlattr *data[],
			 struct netlink_ext_ack *extack)
{
	int ingress_format = RMNET_INGRESS_FORMAT_DEAGGREGATION;
	u32 data_format = RMNET_INGRESS_FORMAT_DEAGGREGATION;
	struct net_device *real_dev;
	int mode = RMNET_EPMODE_VND;
	struct rmnet_endpoint *ep;
@@ -185,11 +185,11 @@ static int rmnet_newlink(struct net *src_net, struct net_device *dev,
		struct ifla_vlan_flags *flags;

		flags = nla_data(data[IFLA_VLAN_FLAGS]);
		ingress_format = flags->flags & flags->mask;
		data_format = flags->flags & flags->mask;
	}

	netdev_dbg(dev, "data format [ingress 0x%08X]\n", ingress_format);
	port->ingress_data_format = ingress_format;
	netdev_dbg(dev, "data format [0x%08X]\n", data_format);
	port->data_format = data_format;

	return 0;

@@ -353,7 +353,7 @@ static int rmnet_changelink(struct net_device *dev, struct nlattr *tb[],
		struct ifla_vlan_flags *flags;

		flags = nla_data(data[IFLA_VLAN_FLAGS]);
		port->ingress_data_format = flags->flags & flags->mask;
		port->data_format = flags->flags & flags->mask;
	}

	return 0;
+1 −1
Original line number Diff line number Diff line
@@ -32,7 +32,7 @@ struct rmnet_endpoint {
 */
struct rmnet_port {
	struct net_device *dev;
	u32 ingress_data_format;
	u32 data_format;
	u8 nr_rmnet_devs;
	u8 rmnet_mode;
	struct hlist_head muxed_ep[RMNET_MAX_LOGICAL_EP];
+25 −11
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@
#include <linux/netdevice.h>
#include <linux/netdev_features.h>
#include <linux/if_arp.h>
#include <net/sock.h>
#include "rmnet_private.h"
#include "rmnet_config.h"
#include "rmnet_vnd.h"
@@ -65,19 +66,19 @@ __rmnet_map_ingress_handler(struct sk_buff *skb,
			    struct rmnet_port *port)
{
	struct rmnet_endpoint *ep;
	u16 len, pad;
	u8 mux_id;
	u16 len;

	if (RMNET_MAP_GET_CD_BIT(skb)) {
		if (port->ingress_data_format
		    & RMNET_INGRESS_FORMAT_MAP_COMMANDS)
		if (port->data_format & RMNET_INGRESS_FORMAT_MAP_COMMANDS)
			return rmnet_map_command(skb, port);

		goto free_skb;
	}

	mux_id = RMNET_MAP_GET_MUX_ID(skb);
	len = RMNET_MAP_GET_LENGTH(skb) - RMNET_MAP_GET_PAD(skb);
	pad = RMNET_MAP_GET_PAD(skb);
	len = RMNET_MAP_GET_LENGTH(skb) - pad;

	if (mux_id >= RMNET_MAX_LOGICAL_EP)
		goto free_skb;
@@ -90,8 +91,14 @@ __rmnet_map_ingress_handler(struct sk_buff *skb,

	/* Subtract MAP header */
	skb_pull(skb, sizeof(struct rmnet_map_header));
	skb_trim(skb, len);
	rmnet_set_skb_proto(skb);

	if (port->data_format & RMNET_INGRESS_FORMAT_MAP_CKSUMV4) {
		if (!rmnet_map_checksum_downlink_packet(skb, len + pad))
			skb->ip_summed = CHECKSUM_UNNECESSARY;
	}

	skb_trim(skb, len);
	rmnet_deliver_skb(skb);
	return;

@@ -114,8 +121,8 @@ rmnet_map_ingress_handler(struct sk_buff *skb,
		skb_push(skb, ETH_HLEN);
	}

	if (port->ingress_data_format & RMNET_INGRESS_FORMAT_DEAGGREGATION) {
		while ((skbn = rmnet_map_deaggregate(skb)) != NULL)
	if (port->data_format & RMNET_INGRESS_FORMAT_DEAGGREGATION) {
		while ((skbn = rmnet_map_deaggregate(skb, port)) != NULL)
			__rmnet_map_ingress_handler(skbn, port);

		consume_skb(skb);
@@ -134,18 +141,23 @@ static int rmnet_map_egress_handler(struct sk_buff *skb,
	additional_header_len = 0;
	required_headroom = sizeof(struct rmnet_map_header);

	if (port->data_format & RMNET_EGRESS_FORMAT_MAP_CKSUMV4) {
		additional_header_len = sizeof(struct rmnet_map_ul_csum_header);
		required_headroom += additional_header_len;
	}

	if (skb_headroom(skb) < required_headroom) {
		if (pskb_expand_head(skb, required_headroom, 0, GFP_KERNEL))
			goto fail;
	}

	if (port->data_format & RMNET_EGRESS_FORMAT_MAP_CKSUMV4)
		rmnet_map_checksum_uplink_packet(skb, orig_dev);

	map_header = rmnet_map_add_map_header(skb, additional_header_len, 0);
	if (!map_header)
		goto fail;

	if (mux_id == 0xff)
		map_header->mux_id = 0;
	else
	map_header->mux_id = mux_id;

	skb->protocol = htons(ETH_P_MAP);
@@ -208,6 +220,8 @@ void rmnet_egress_handler(struct sk_buff *skb)
	struct rmnet_priv *priv;
	u8 mux_id;

	sk_pacing_shift_update(skb->sk, 8);

	orig_dev = skb->dev;
	priv = netdev_priv(orig_dev);
	skb->dev = priv->real_dev;
+21 −2
Original line number Diff line number Diff line
@@ -47,6 +47,22 @@ struct rmnet_map_header {
	u16 pkt_len;
}  __aligned(1);

struct rmnet_map_dl_csum_trailer {
	u8  reserved1;
	u8  valid:1;
	u8  reserved2:7;
	u16 csum_start_offset;
	u16 csum_length;
	__be16 csum_value;
} __aligned(1);

struct rmnet_map_ul_csum_header {
	__be16 csum_start_offset;
	u16 csum_insert_offset:14;
	u16 udp_ip4_ind:1;
	u16 csum_enabled:1;
} __aligned(1);

#define RMNET_MAP_GET_MUX_ID(Y) (((struct rmnet_map_header *) \
				 (Y)->data)->mux_id)
#define RMNET_MAP_GET_CD_BIT(Y) (((struct rmnet_map_header *) \
@@ -67,10 +83,13 @@ struct rmnet_map_header {
#define RMNET_MAP_NO_PAD_BYTES        0
#define RMNET_MAP_ADD_PAD_BYTES       1

u8 rmnet_map_demultiplex(struct sk_buff *skb);
struct sk_buff *rmnet_map_deaggregate(struct sk_buff *skb);
struct sk_buff *rmnet_map_deaggregate(struct sk_buff *skb,
				      struct rmnet_port *port);
struct rmnet_map_header *rmnet_map_add_map_header(struct sk_buff *skb,
						  int hdrlen, int pad);
void rmnet_map_command(struct sk_buff *skb, struct rmnet_port *port);
int rmnet_map_checksum_downlink_packet(struct sk_buff *skb, u16 len);
void rmnet_map_checksum_uplink_packet(struct sk_buff *skb,
				      struct net_device *orig_dev);

#endif /* _RMNET_MAP_H_ */
+15 −2
Original line number Diff line number Diff line
@@ -58,11 +58,24 @@ static u8 rmnet_map_do_flow_control(struct sk_buff *skb,
}

static void rmnet_map_send_ack(struct sk_buff *skb,
			       unsigned char type)
			       unsigned char type,
			       struct rmnet_port *port)
{
	struct rmnet_map_control_command *cmd;
	int xmit_status;

	if (port->data_format & RMNET_INGRESS_FORMAT_MAP_CKSUMV4) {
		if (skb->len < sizeof(struct rmnet_map_header) +
		    RMNET_MAP_GET_LENGTH(skb) +
		    sizeof(struct rmnet_map_dl_csum_trailer)) {
			kfree_skb(skb);
			return;
		}

		skb_trim(skb, skb->len -
			 sizeof(struct rmnet_map_dl_csum_trailer));
	}

	skb->protocol = htons(ETH_P_MAP);

	cmd = RMNET_MAP_GET_CMD_START(skb);
@@ -100,5 +113,5 @@ void rmnet_map_command(struct sk_buff *skb, struct rmnet_port *port)
		break;
	}
	if (rc == RMNET_MAP_COMMAND_ACK)
		rmnet_map_send_ack(skb, rc);
		rmnet_map_send_ack(skb, rc, port);
}
Loading