Skip to content

Commit 6a77a15

Browse files
Bharat Bhushandavem330
authored andcommitted
cn10k-ipsec: Process outbound ipsec crypto offload
Prepare and submit crypto hardware (CPT) instruction for outbound ipsec crypto offload. The CPT instruction have authentication offset, IV offset and encapsulation offset in input packet. Also provide SA context pointer which have details about algo, keys, salt etc. Crypto hardware encrypt, authenticate and provide the ESP packet to networking hardware. Signed-off-by: Bharat Bhushan <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent c45211c commit 6a77a15

File tree

7 files changed

+321
-3
lines changed

7 files changed

+321
-3
lines changed

drivers/net/ethernet/marvell/octeontx2/nic/cn10k_ipsec.c

Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,15 @@
77
#include <net/xfrm.h>
88
#include <linux/netdevice.h>
99
#include <linux/bitfield.h>
10+
#include <crypto/aead.h>
11+
#include <crypto/gcm.h>
1012

1113
#include "otx2_common.h"
14+
#include "otx2_struct.h"
1215
#include "cn10k_ipsec.h"
1316

17+
DEFINE_STATIC_KEY_FALSE(cn10k_ipsec_sa_enabled);
18+
1419
static bool is_dev_support_ipsec_offload(struct pci_dev *pdev)
1520
{
1621
return is_dev_cn10ka_b0(pdev) || is_dev_cn10kb(pdev);
@@ -690,6 +695,9 @@ static int cn10k_ipsec_outb_add_state(struct xfrm_state *x,
690695
}
691696

692697
x->xso.offload_handle = (unsigned long)sa_info;
698+
/* Enable static branch when first SA setup */
699+
if (!pf->ipsec.outb_sa_count)
700+
static_branch_enable(&cn10k_ipsec_sa_enabled);
693701
pf->ipsec.outb_sa_count++;
694702
return 0;
695703
}
@@ -749,6 +757,8 @@ static void cn10k_ipsec_sa_wq_handler(struct work_struct *work)
749757
sa_work);
750758
struct otx2_nic *pf = container_of(ipsec, struct otx2_nic, ipsec);
751759

760+
/* Disable static branch when no more SA enabled */
761+
static_branch_disable(&cn10k_ipsec_sa_enabled);
752762
rtnl_lock();
753763
netdev_update_features(pf->netdev);
754764
rtnl_unlock();
@@ -822,3 +832,212 @@ void cn10k_ipsec_clean(struct otx2_nic *pf)
822832
cn10k_outb_cpt_clean(pf);
823833
}
824834
EXPORT_SYMBOL(cn10k_ipsec_clean);
835+
836+
static u16 cn10k_ipsec_get_ip_data_len(struct xfrm_state *x,
837+
struct sk_buff *skb)
838+
{
839+
struct ipv6hdr *ipv6h;
840+
struct iphdr *iph;
841+
u8 *src;
842+
843+
src = (u8 *)skb->data + ETH_HLEN;
844+
845+
if (x->props.family == AF_INET) {
846+
iph = (struct iphdr *)src;
847+
return ntohs(iph->tot_len);
848+
}
849+
850+
ipv6h = (struct ipv6hdr *)src;
851+
return ntohs(ipv6h->payload_len) + sizeof(struct ipv6hdr);
852+
}
853+
854+
/* Prepare CPT and NIX SQE scatter/gather subdescriptor structure.
855+
* SG of NIX and CPT are same in size.
856+
* Layout of a NIX SQE and CPT SG entry:
857+
* -----------------------------
858+
* | CPT Scatter Gather |
859+
* | (SQE SIZE) |
860+
* | |
861+
* -----------------------------
862+
* | NIX SQE |
863+
* | (SQE SIZE) |
864+
* | |
865+
* -----------------------------
866+
*/
867+
bool otx2_sqe_add_sg_ipsec(struct otx2_nic *pfvf, struct otx2_snd_queue *sq,
868+
struct sk_buff *skb, int num_segs, int *offset)
869+
{
870+
struct cpt_sg_s *cpt_sg = NULL;
871+
struct nix_sqe_sg_s *sg = NULL;
872+
u64 dma_addr, *iova = NULL;
873+
u64 *cpt_iova = NULL;
874+
u16 *sg_lens = NULL;
875+
int seg, len;
876+
877+
sq->sg[sq->head].num_segs = 0;
878+
cpt_sg = (struct cpt_sg_s *)(sq->sqe_base - sq->sqe_size);
879+
880+
for (seg = 0; seg < num_segs; seg++) {
881+
if ((seg % MAX_SEGS_PER_SG) == 0) {
882+
sg = (struct nix_sqe_sg_s *)(sq->sqe_base + *offset);
883+
sg->ld_type = NIX_SEND_LDTYPE_LDD;
884+
sg->subdc = NIX_SUBDC_SG;
885+
sg->segs = 0;
886+
sg_lens = (void *)sg;
887+
iova = (void *)sg + sizeof(*sg);
888+
/* Next subdc always starts at a 16byte boundary.
889+
* So if sg->segs is whether 2 or 3, offset += 16bytes.
890+
*/
891+
if ((num_segs - seg) >= (MAX_SEGS_PER_SG - 1))
892+
*offset += sizeof(*sg) + (3 * sizeof(u64));
893+
else
894+
*offset += sizeof(*sg) + sizeof(u64);
895+
896+
cpt_sg += (seg / MAX_SEGS_PER_SG) * 4;
897+
cpt_iova = (void *)cpt_sg + sizeof(*cpt_sg);
898+
}
899+
dma_addr = otx2_dma_map_skb_frag(pfvf, skb, seg, &len);
900+
if (dma_mapping_error(pfvf->dev, dma_addr))
901+
return false;
902+
903+
sg_lens[seg % MAX_SEGS_PER_SG] = len;
904+
sg->segs++;
905+
*iova++ = dma_addr;
906+
*cpt_iova++ = dma_addr;
907+
908+
/* Save DMA mapping info for later unmapping */
909+
sq->sg[sq->head].dma_addr[seg] = dma_addr;
910+
sq->sg[sq->head].size[seg] = len;
911+
sq->sg[sq->head].num_segs++;
912+
913+
*cpt_sg = *(struct cpt_sg_s *)sg;
914+
cpt_sg->rsvd_63_50 = 0;
915+
}
916+
917+
sq->sg[sq->head].skb = (u64)skb;
918+
return true;
919+
}
920+
921+
static u16 cn10k_ipsec_get_param1(u8 iv_offset)
922+
{
923+
u16 param1_val;
924+
925+
/* Set Crypto mode, disable L3/L4 checksum */
926+
param1_val = CN10K_IPSEC_INST_PARAM1_DIS_L4_CSUM |
927+
CN10K_IPSEC_INST_PARAM1_DIS_L3_CSUM;
928+
param1_val |= (u16)iv_offset << CN10K_IPSEC_INST_PARAM1_IV_OFFSET_SHIFT;
929+
return param1_val;
930+
}
931+
932+
bool cn10k_ipsec_transmit(struct otx2_nic *pf, struct netdev_queue *txq,
933+
struct otx2_snd_queue *sq, struct sk_buff *skb,
934+
int num_segs, int size)
935+
{
936+
struct cpt_inst_s inst;
937+
struct cpt_res_s *res;
938+
struct xfrm_state *x;
939+
struct qmem *sa_info;
940+
dma_addr_t dptr_iova;
941+
struct sec_path *sp;
942+
u8 encap_offset;
943+
u8 auth_offset;
944+
u8 gthr_size;
945+
u8 iv_offset;
946+
u16 dlen;
947+
948+
/* Check for IPSEC offload enabled */
949+
if (!(pf->flags & OTX2_FLAG_IPSEC_OFFLOAD_ENABLED))
950+
goto drop;
951+
952+
sp = skb_sec_path(skb);
953+
if (unlikely(!sp->len))
954+
goto drop;
955+
956+
x = xfrm_input_state(skb);
957+
if (unlikely(!x))
958+
goto drop;
959+
960+
if (x->props.mode != XFRM_MODE_TRANSPORT &&
961+
x->props.mode != XFRM_MODE_TUNNEL)
962+
goto drop;
963+
964+
dlen = cn10k_ipsec_get_ip_data_len(x, skb);
965+
if (dlen == 0 && netif_msg_tx_err(pf)) {
966+
netdev_err(pf->netdev, "Invalid IP header, ip-length zero\n");
967+
goto drop;
968+
}
969+
970+
/* Check for valid SA context */
971+
sa_info = (struct qmem *)x->xso.offload_handle;
972+
if (!sa_info)
973+
goto drop;
974+
975+
memset(&inst, 0, sizeof(struct cpt_inst_s));
976+
977+
/* Get authentication offset */
978+
if (x->props.family == AF_INET)
979+
auth_offset = sizeof(struct iphdr);
980+
else
981+
auth_offset = sizeof(struct ipv6hdr);
982+
983+
/* IV offset is after ESP header */
984+
iv_offset = auth_offset + sizeof(struct ip_esp_hdr);
985+
/* Encap will start after IV */
986+
encap_offset = iv_offset + GCM_RFC4106_IV_SIZE;
987+
988+
/* CPT Instruction word-1 */
989+
res = (struct cpt_res_s *)(sq->cpt_resp->base + (64 * sq->head));
990+
res->compcode = 0;
991+
inst.res_addr = sq->cpt_resp->iova + (64 * sq->head);
992+
993+
/* CPT Instruction word-2 */
994+
inst.rvu_pf_func = pf->pcifunc;
995+
996+
/* CPT Instruction word-3:
997+
* Set QORD to force CPT_RES_S write completion
998+
*/
999+
inst.qord = 1;
1000+
1001+
/* CPT Instruction word-4 */
1002+
/* inst.dlen should not include ICV length */
1003+
inst.dlen = dlen + ETH_HLEN - (x->aead->alg_icv_len / 8);
1004+
inst.opcode_major = CN10K_IPSEC_MAJOR_OP_OUTB_IPSEC;
1005+
inst.param1 = cn10k_ipsec_get_param1(iv_offset);
1006+
1007+
inst.param2 = encap_offset <<
1008+
CN10K_IPSEC_INST_PARAM2_ENC_DATA_OFFSET_SHIFT;
1009+
inst.param2 |= (u16)auth_offset <<
1010+
CN10K_IPSEC_INST_PARAM2_AUTH_DATA_OFFSET_SHIFT;
1011+
1012+
/* CPT Instruction word-5 */
1013+
gthr_size = num_segs / MAX_SEGS_PER_SG;
1014+
gthr_size = (num_segs % MAX_SEGS_PER_SG) ? gthr_size + 1 : gthr_size;
1015+
1016+
gthr_size &= 0xF;
1017+
dptr_iova = (sq->sqe_ring->iova + (sq->head * (sq->sqe_size * 2)));
1018+
inst.dptr = dptr_iova | ((u64)gthr_size << 60);
1019+
1020+
/* CPT Instruction word-6 */
1021+
inst.rptr = inst.dptr;
1022+
1023+
/* CPT Instruction word-7 */
1024+
inst.cptr = sa_info->iova;
1025+
inst.ctx_val = 1;
1026+
inst.egrp = CN10K_DEF_CPT_IPSEC_EGRP;
1027+
1028+
/* CPT Instruction word-0 */
1029+
inst.nixtxl = (size / 16) - 1;
1030+
inst.dat_offset = ETH_HLEN;
1031+
inst.nixtx_offset = sq->sqe_size;
1032+
1033+
netdev_tx_sent_queue(txq, skb->len);
1034+
1035+
/* Finally Flush the CPT instruction */
1036+
sq->head++;
1037+
sq->head &= (sq->sqe_cnt - 1);
1038+
cn10k_cpt_inst_flush(pf, &inst, sizeof(struct cpt_inst_s));
1039+
return true;
1040+
drop:
1041+
dev_kfree_skb_any(skb);
1042+
return false;
1043+
}

drivers/net/ethernet/marvell/octeontx2/nic/cn10k_ipsec.h

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99

1010
#include <linux/types.h>
1111

12+
DECLARE_STATIC_KEY_FALSE(cn10k_ipsec_sa_enabled);
13+
1214
/* CPT instruction size in bytes */
1315
#define CN10K_CPT_INST_SIZE 64
1416

@@ -53,6 +55,7 @@
5355
/* IPSEC Instruction opcodes */
5456
#define CN10K_IPSEC_MAJOR_OP_WRITE_SA 0x01UL
5557
#define CN10K_IPSEC_MINOR_OP_WRITE_SA 0x09UL
58+
#define CN10K_IPSEC_MAJOR_OP_OUTB_IPSEC 0x2AUL
5659

5760
enum cn10k_cpt_comp_e {
5861
CN10K_CPT_COMP_E_NOTDONE = 0x00,
@@ -143,6 +146,16 @@ struct cn10k_tx_sa_s {
143146
u64 hw_ctx[6]; /* W31 - W36 */
144147
};
145148

149+
/* CPT instruction parameter-1 */
150+
#define CN10K_IPSEC_INST_PARAM1_DIS_L4_CSUM 0x1
151+
#define CN10K_IPSEC_INST_PARAM1_DIS_L3_CSUM 0x2
152+
#define CN10K_IPSEC_INST_PARAM1_CRYPTO_MODE 0x20
153+
#define CN10K_IPSEC_INST_PARAM1_IV_OFFSET_SHIFT 8
154+
155+
/* CPT instruction parameter-2 */
156+
#define CN10K_IPSEC_INST_PARAM2_ENC_DATA_OFFSET_SHIFT 0
157+
#define CN10K_IPSEC_INST_PARAM2_AUTH_DATA_OFFSET_SHIFT 8
158+
146159
/* CPT Instruction Structure */
147160
struct cpt_inst_s {
148161
u64 nixtxl : 3; /* W0 */
@@ -182,6 +195,15 @@ struct cpt_res_s {
182195
u64 esn; /* W1 */
183196
};
184197

198+
/* CPT SG structure */
199+
struct cpt_sg_s {
200+
u64 seg1_size : 16;
201+
u64 seg2_size : 16;
202+
u64 seg3_size : 16;
203+
u64 segs : 2;
204+
u64 rsvd_63_50 : 14;
205+
};
206+
185207
/* CPT LF_INPROG Register */
186208
#define CPT_LF_INPROG_INFLIGHT GENMASK_ULL(8, 0)
187209
#define CPT_LF_INPROG_GRB_CNT GENMASK_ULL(39, 32)
@@ -204,6 +226,11 @@ struct cpt_res_s {
204226
int cn10k_ipsec_init(struct net_device *netdev);
205227
void cn10k_ipsec_clean(struct otx2_nic *pf);
206228
int cn10k_ipsec_ethtool_init(struct net_device *netdev, bool enable);
229+
bool otx2_sqe_add_sg_ipsec(struct otx2_nic *pfvf, struct otx2_snd_queue *sq,
230+
struct sk_buff *skb, int num_segs, int *offset);
231+
bool cn10k_ipsec_transmit(struct otx2_nic *pf, struct netdev_queue *txq,
232+
struct otx2_snd_queue *sq, struct sk_buff *skb,
233+
int num_segs, int size);
207234
#else
208235
static inline __maybe_unused int cn10k_ipsec_init(struct net_device *netdev)
209236
{
@@ -219,5 +246,20 @@ int cn10k_ipsec_ethtool_init(struct net_device *netdev, bool enable)
219246
{
220247
return 0;
221248
}
249+
250+
static inline bool __maybe_unused
251+
otx2_sqe_add_sg_ipsec(struct otx2_nic *pfvf, struct otx2_snd_queue *sq,
252+
struct sk_buff *skb, int num_segs, int *offset)
253+
{
254+
return true;
255+
}
256+
257+
static inline bool __maybe_unused
258+
cn10k_ipsec_transmit(struct otx2_nic *pf, struct netdev_queue *txq,
259+
struct otx2_snd_queue *sq, struct sk_buff *skb,
260+
int num_segs, int size)
261+
{
262+
return true;
263+
}
222264
#endif
223265
#endif // CN10K_IPSEC_H

drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -970,6 +970,29 @@ int otx2_sq_init(struct otx2_nic *pfvf, u16 qidx, u16 sqb_aura)
970970
if (err)
971971
return err;
972972

973+
/* Allocate memory for NIX SQE (which includes NIX SG) and CPT SG.
974+
* SG of NIX and CPT are same in size. Allocate memory for CPT SG
975+
* same as NIX SQE for base address alignment.
976+
* Layout of a NIX SQE and CPT SG entry:
977+
* -----------------------------
978+
* | CPT Scatter Gather |
979+
* | (SQE SIZE) |
980+
* | |
981+
* -----------------------------
982+
* | NIX SQE |
983+
* | (SQE SIZE) |
984+
* | |
985+
* -----------------------------
986+
*/
987+
err = qmem_alloc(pfvf->dev, &sq->sqe_ring, qset->sqe_cnt,
988+
sq->sqe_size * 2);
989+
if (err)
990+
return err;
991+
992+
err = qmem_alloc(pfvf->dev, &sq->cpt_resp, qset->sqe_cnt, 64);
993+
if (err)
994+
return err;
995+
973996
if (qidx < pfvf->hw.tx_queues) {
974997
err = qmem_alloc(pfvf->dev, &sq->tso_hdrs, qset->sqe_cnt,
975998
TSO_HEADER_SIZE);

drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,9 @@
5757
#define NIX_PF_PFC_PRIO_MAX 8
5858
#endif
5959

60+
/* Number of segments per SG structure */
61+
#define MAX_SEGS_PER_SG 3
62+
6063
enum arua_mapped_qtypes {
6164
AURA_NIX_RQ,
6265
AURA_NIX_SQ,

drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1485,6 +1485,8 @@ static void otx2_free_sq_res(struct otx2_nic *pf)
14851485
if (!sq->sqe)
14861486
continue;
14871487
qmem_free(pf->dev, sq->sqe);
1488+
qmem_free(pf->dev, sq->sqe_ring);
1489+
qmem_free(pf->dev, sq->cpt_resp);
14881490
qmem_free(pf->dev, sq->tso_hdrs);
14891491
kfree(sq->sg);
14901492
kfree(sq->sqb_ptrs);

0 commit comments

Comments
 (0)