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

Merge branch 'cxgb4-chcr-ktls-tx-ofld-support-on-T6-adapter'



Rohit Maheshwari says:

====================
cxgb4/chcr: ktls tx ofld support on T6 adapter

This series of patches add support for kernel tls offload in Tx direction,
over Chelsio T6 NICs. SKBs marked as decrypted will be treated as tls plain
text packets and then offloaded to encrypt using network device (chelsio T6
adapter).

This series is broken down as follows:

Patch 1 defines a new macro and registers tls_dev_add and tls_dev_del
callbacks. When tls_dev_add gets called we send a connection request to
our hardware and to make HW understand about tls offload. Its a partial
connection setup and only ipv4 part is done.

Patch 2 handles the HW response of the connection request and then we
request to update TCB and handle it's HW response as well. Also we save
crypto key locally. Only supporting TLS_CIPHER_AES_GCM_128_KEY_SIZE.

Patch 3 handles tls marked skbs (decrypted bit set) and sends it to ULD for
crypto handling. This code has a minimal portion of tx handler, to handle
only one complete record per skb.

Patch 4 hanldes partial end part of records. Also added logic to handle
multiple records in one single skb. It also adds support to send out tcp
option(/s) if exists in skb. If a record is partial but has end part of a
record, we'll fetch complete record and then only send it to HW to generate
HASH on complete record.

Patch 5 handles partial first or middle part of record, it uses AES_CTR to
encrypt the partial record. If we are trying to send middle record, it's
start should be 16 byte aligned, so we'll fetch few earlier bytes from the
record and then send it to HW for encryption.

Patch 6 enables ipv6 support and also includes ktls startistics.

v1->v2:
- mark tcb state to close in tls_dev_del.
- u_ctx is now picked from adapter structure.
- clear atid in case of failure.
- corrected ULP_CRYPTO_KTLS_INLINE value.
- optimized tcb update using control queue.
- state machine handling when earlier states received.
- chcr_write_cpl_set_tcb_ulp  function is shifted to patch3.
- un-necessary updating left variable.

v2->v3:
- add empty line after variable declaration.
- local variable declaration in reverse christmas tree ordering.

v3->v4:
- replaced kfree_skb with dev_kfree_skb_any.
- corrected error message reported by kbuild test robot <lkp@intel.com>
- mss calculation logic.
- correct place for Alloc skb check.
- Replaced atomic_t with atomic64_t
- added few more statistics counters.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 9d2e4e16 62370a4f
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -42,3 +42,14 @@ config CRYPTO_DEV_CHELSIO_TLS

	  To compile this driver as a module, choose M here: the module
	  will be called chtls.

config CHELSIO_TLS_DEVICE
	bool "Chelsio Inline KTLS Offload"
	depends on CHELSIO_T4
	depends on TLS_DEVICE
	select CRYPTO_DEV_CHELSIO
	default y
	help
	  This flag enables support for kernel tls offload over Chelsio T6
	  crypto accelerator. CONFIG_CHELSIO_TLS_DEVICE flag can be enabled
	  only if CONFIG_TLS and CONFIG_TLS_DEVICE flags are enabled.
+3 −0
Original line number Diff line number Diff line
@@ -3,5 +3,8 @@ ccflags-y := -I $(srctree)/drivers/net/ethernet/chelsio/cxgb4

obj-$(CONFIG_CRYPTO_DEV_CHELSIO) += chcr.o
chcr-objs :=  chcr_core.o chcr_algo.o
#ifdef CONFIG_CHELSIO_TLS_DEVICE
chcr-objs += chcr_ktls.o
#endif
chcr-$(CONFIG_CHELSIO_IPSEC_INLINE) += chcr_ipsec.o
obj-$(CONFIG_CRYPTO_DEV_CHELSIO_TLS) += chtls/
+135 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0-only */
/* Copyright (C) 2020 Chelsio Communications.  All rights reserved. */

#ifndef __CHCR_COMMON_H__
#define __CHCR_COMMON_H__

#include "cxgb4.h"

#define CHCR_MAX_SALT                      4
#define CHCR_KEYCTX_MAC_KEY_SIZE_128       0
#define CHCR_KEYCTX_CIPHER_KEY_SIZE_128    0
#define CHCR_SCMD_CIPHER_MODE_AES_GCM      2
#define CHCR_SCMD_CIPHER_MODE_AES_CTR      3
#define CHCR_CPL_TX_SEC_PDU_LEN_64BIT      2
#define CHCR_SCMD_SEQ_NO_CTRL_64BIT        3
#define CHCR_SCMD_PROTO_VERSION_TLS        0
#define CHCR_SCMD_PROTO_VERSION_GENERIC    4
#define CHCR_SCMD_AUTH_MODE_GHASH          4
#define AES_BLOCK_LEN                      16

enum chcr_state {
	CHCR_INIT = 0,
	CHCR_ATTACH,
	CHCR_DETACH,
};

struct chcr_dev {
	spinlock_t lock_chcr_dev; /* chcr dev structure lock */
	enum chcr_state state;
	atomic_t inflight;
	int wqretry;
	struct delayed_work detach_work;
	struct completion detach_comp;
	unsigned char tx_channel_id;
};

struct uld_ctx {
	struct list_head entry;
	struct cxgb4_lld_info lldi;
	struct chcr_dev dev;
};

struct ktls_key_ctx {
	__be32 ctx_hdr;
	u8 salt[CHCR_MAX_SALT];
	__be64 iv_to_auth;
	unsigned char key[TLS_CIPHER_AES_GCM_128_KEY_SIZE +
			  TLS_CIPHER_AES_GCM_256_TAG_SIZE];
};

/* Crypto key context */
#define KEY_CONTEXT_CTX_LEN_S           24
#define KEY_CONTEXT_CTX_LEN_V(x)        ((x) << KEY_CONTEXT_CTX_LEN_S)

#define KEY_CONTEXT_SALT_PRESENT_S      10
#define KEY_CONTEXT_SALT_PRESENT_V(x)   ((x) << KEY_CONTEXT_SALT_PRESENT_S)
#define KEY_CONTEXT_SALT_PRESENT_F      KEY_CONTEXT_SALT_PRESENT_V(1U)

#define KEY_CONTEXT_VALID_S     0
#define KEY_CONTEXT_VALID_V(x)  ((x) << KEY_CONTEXT_VALID_S)
#define KEY_CONTEXT_VALID_F     KEY_CONTEXT_VALID_V(1U)

#define KEY_CONTEXT_CK_SIZE_S           6
#define KEY_CONTEXT_CK_SIZE_V(x)        ((x) << KEY_CONTEXT_CK_SIZE_S)

#define KEY_CONTEXT_MK_SIZE_S           2
#define KEY_CONTEXT_MK_SIZE_V(x)        ((x) << KEY_CONTEXT_MK_SIZE_S)

#define KEY_CONTEXT_OPAD_PRESENT_S      11
#define KEY_CONTEXT_OPAD_PRESENT_V(x)   ((x) << KEY_CONTEXT_OPAD_PRESENT_S)
#define KEY_CONTEXT_OPAD_PRESENT_F      KEY_CONTEXT_OPAD_PRESENT_V(1U)

#define FILL_KEY_CTX_HDR(ck_size, mk_size, ctx_len) \
		htonl(KEY_CONTEXT_MK_SIZE_V(mk_size) | \
		      KEY_CONTEXT_CK_SIZE_V(ck_size) | \
		      KEY_CONTEXT_VALID_F | \
		      KEY_CONTEXT_SALT_PRESENT_F | \
		      KEY_CONTEXT_CTX_LEN_V((ctx_len)))

struct uld_ctx *assign_chcr_device(void);

static inline void *chcr_copy_to_txd(const void *src, const struct sge_txq *q,
				     void *pos, int length)
{
	int left = (void *)q->stat - pos;
	u64 *p;

	if (likely(length <= left)) {
		memcpy(pos, src, length);
		pos += length;
	} else {
		memcpy(pos, src, left);
		memcpy(q->desc, src + left, length - left);
		pos = (void *)q->desc + (length - left);
	}
	/* 0-pad to multiple of 16 */
	p = PTR_ALIGN(pos, 8);
	if ((uintptr_t)p & 8) {
		*p = 0;
		return p + 1;
	}
	return p;
}

static inline unsigned int chcr_txq_avail(const struct sge_txq *q)
{
	return q->size - 1 - q->in_use;
}

static inline void chcr_txq_advance(struct sge_txq *q, unsigned int n)
{
	q->in_use += n;
	q->pidx += n;
	if (q->pidx >= q->size)
		q->pidx -= q->size;
}

static inline void chcr_eth_txq_stop(struct sge_eth_txq *q)
{
	netif_tx_stop_queue(q->txq);
	q->q.stops++;
}

static inline unsigned int chcr_sgl_len(unsigned int n)
{
	n--;
	return (3 * n) / 2 + (n & 1) + 2;
}

static inline unsigned int chcr_flits_to_desc(unsigned int n)
{
	WARN_ON(n > SGE_MAX_WR_LEN / 8);
	return DIV_ROUND_UP(n, 8);
}
#endif /* __CHCR_COMMON_H__ */
+39 −12
Original line number Diff line number Diff line
@@ -28,13 +28,17 @@

static struct chcr_driver_data drv_data;

typedef int (*chcr_handler_func)(struct chcr_dev *dev, unsigned char *input);
static int cpl_fw6_pld_handler(struct chcr_dev *dev, unsigned char *input);
typedef int (*chcr_handler_func)(struct adapter *adap, unsigned char *input);
static int cpl_fw6_pld_handler(struct adapter *adap, unsigned char *input);
static void *chcr_uld_add(const struct cxgb4_lld_info *lld);
static int chcr_uld_state_change(void *handle, enum cxgb4_state state);

static chcr_handler_func work_handlers[NUM_CPL_CMDS] = {
	[CPL_FW6_PLD] = cpl_fw6_pld_handler,
#ifdef CONFIG_CHELSIO_TLS_DEVICE
	[CPL_ACT_OPEN_RPL] = chcr_ktls_cpl_act_open_rpl,
	[CPL_SET_TCB_RPL] = chcr_ktls_cpl_set_tcb_rpl,
#endif
};

static struct cxgb4_uld_info chcr_uld_info = {
@@ -45,9 +49,9 @@ static struct cxgb4_uld_info chcr_uld_info = {
	.add = chcr_uld_add,
	.state_change = chcr_uld_state_change,
	.rx_handler = chcr_uld_rx_handler,
#ifdef CONFIG_CHELSIO_IPSEC_INLINE
#if defined(CONFIG_CHELSIO_IPSEC_INLINE) || defined(CONFIG_CHELSIO_TLS_DEVICE)
	.tx_handler = chcr_uld_tx_handler,
#endif /* CONFIG_CHELSIO_IPSEC_INLINE */
#endif /* CONFIG_CHELSIO_IPSEC_INLINE || CONFIG_CHELSIO_TLS_DEVICE */
};

static void detach_work_fn(struct work_struct *work)
@@ -150,14 +154,13 @@ static int chcr_dev_move(struct uld_ctx *u_ctx)
	return 0;
}

static int cpl_fw6_pld_handler(struct chcr_dev *dev,
static int cpl_fw6_pld_handler(struct adapter *adap,
			       unsigned char *input)
{
	struct crypto_async_request *req;
	struct cpl_fw6_pld *fw6_pld;
	u32 ack_err_status = 0;
	int error_status = 0;
	struct adapter *adap = padap(dev);

	fw6_pld = (struct cpl_fw6_pld *)input;
	req = (struct crypto_async_request *)(uintptr_t)be64_to_cpu(
@@ -205,6 +208,11 @@ static void *chcr_uld_add(const struct cxgb4_lld_info *lld)
	if (lld->crypto & ULP_CRYPTO_IPSEC_INLINE)
		chcr_add_xfrmops(lld);
#endif /* CONFIG_CHELSIO_IPSEC_INLINE */

#ifdef CONFIG_CHELSIO_TLS_DEVICE
	if (lld->ulp_crypto & ULP_CRYPTO_KTLS_INLINE)
		chcr_enable_ktls(padap(&u_ctx->dev));
#endif
out:
	return u_ctx;
}
@@ -214,26 +222,37 @@ int chcr_uld_rx_handler(void *handle, const __be64 *rsp,
{
	struct uld_ctx *u_ctx = (struct uld_ctx *)handle;
	struct chcr_dev *dev = &u_ctx->dev;
	struct adapter *adap = padap(dev);
	const struct cpl_fw6_pld *rpl = (struct cpl_fw6_pld *)rsp;

	if (rpl->opcode != CPL_FW6_PLD) {
		pr_err("Unsupported opcode\n");
	if (!work_handlers[rpl->opcode]) {
		pr_err("Unsupported opcode %d received\n", rpl->opcode);
		return 0;
	}

	if (!pgl)
		work_handlers[rpl->opcode](dev, (unsigned char *)&rsp[1]);
		work_handlers[rpl->opcode](adap, (unsigned char *)&rsp[1]);
	else
		work_handlers[rpl->opcode](dev, pgl->va);
		work_handlers[rpl->opcode](adap, pgl->va);
	return 0;
}

#ifdef CONFIG_CHELSIO_IPSEC_INLINE
#if defined(CONFIG_CHELSIO_IPSEC_INLINE) || defined(CONFIG_CHELSIO_TLS_DEVICE)
int chcr_uld_tx_handler(struct sk_buff *skb, struct net_device *dev)
{
	/* In case if skb's decrypted bit is set, it's nic tls packet, else it's
	 * ipsec packet.
	 */
#ifdef CONFIG_CHELSIO_TLS_DEVICE
	if (skb->decrypted)
		return chcr_ktls_xmit(skb, dev);
#endif
#ifdef CONFIG_CHELSIO_IPSEC_INLINE
	return chcr_ipsec_xmit(skb, dev);
#endif
	return 0;
}
#endif /* CONFIG_CHELSIO_IPSEC_INLINE */
#endif /* CONFIG_CHELSIO_IPSEC_INLINE || CONFIG_CHELSIO_TLS_DEVICE */

static void chcr_detach_device(struct uld_ctx *u_ctx)
{
@@ -304,12 +323,20 @@ static void __exit chcr_crypto_exit(void)
	list_for_each_entry_safe(u_ctx, tmp, &drv_data.act_dev, entry) {
		adap = padap(&u_ctx->dev);
		memset(&adap->chcr_stats, 0, sizeof(adap->chcr_stats));
#ifdef CONFIG_CHELSIO_TLS_DEVICE
		if (u_ctx->lldi.ulp_crypto & ULP_CRYPTO_KTLS_INLINE)
			chcr_disable_ktls(adap);
#endif
		list_del(&u_ctx->entry);
		kfree(u_ctx);
	}
	list_for_each_entry_safe(u_ctx, tmp, &drv_data.inact_dev, entry) {
		adap = padap(&u_ctx->dev);
		memset(&adap->chcr_stats, 0, sizeof(adap->chcr_stats));
#ifdef CONFIG_CHELSIO_TLS_DEVICE
		if (u_ctx->lldi.ulp_crypto & ULP_CRYPTO_KTLS_INLINE)
			chcr_disable_ktls(adap);
#endif
		list_del(&u_ctx->entry);
		kfree(u_ctx);
	}
+7 −0
Original line number Diff line number Diff line
@@ -222,4 +222,11 @@ int chcr_handle_resp(struct crypto_async_request *req, unsigned char *input,
		     int err);
int chcr_ipsec_xmit(struct sk_buff *skb, struct net_device *dev);
void chcr_add_xfrmops(const struct cxgb4_lld_info *lld);
#ifdef CONFIG_CHELSIO_TLS_DEVICE
void chcr_enable_ktls(struct adapter *adap);
void chcr_disable_ktls(struct adapter *adap);
int chcr_ktls_cpl_act_open_rpl(struct adapter *adap, unsigned char *input);
int chcr_ktls_cpl_set_tcb_rpl(struct adapter *adap, unsigned char *input);
int chcr_ktls_xmit(struct sk_buff *skb, struct net_device *dev);
#endif
#endif /* __CHCR_CORE_H__ */
Loading