Skip to content

Commit 00e57a6

Browse files
Aviad Krawczykdavem330
Aviad Krawczyk
authored andcommitted
net-next/hinic: Add Tx operation
Add transmit operation for sending data by qp operations. Signed-off-by: Aviad Krawczyk <[email protected]> Signed-off-by: Zhao Chen <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent e2585ea commit 00e57a6

File tree

8 files changed

+799
-4
lines changed

8 files changed

+799
-4
lines changed

drivers/net/ethernet/huawei/hinic/hinic_dev.h

+1
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ struct hinic_dev {
4343
struct hinic_hwdev *hwdev;
4444

4545
u32 msg_enable;
46+
unsigned int tx_weight;
4647
unsigned int rx_weight;
4748

4849
unsigned int flags;

drivers/net/ethernet/huawei/hinic/hinic_hw_dev.c

+46
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@
4040
#define MAX_IRQS(max_qps, num_aeqs, num_ceqs) \
4141
(2 * (max_qps) + (num_aeqs) + (num_ceqs))
4242

43+
#define ADDR_IN_4BYTES(addr) ((addr) >> 2)
44+
4345
enum intr_type {
4446
INTR_MSIX_TYPE,
4547
};
@@ -1000,3 +1002,47 @@ int hinic_hwdev_msix_set(struct hinic_hwdev *hwdev, u16 msix_index,
10001002
lli_timer_cfg, lli_credit_limit,
10011003
resend_timer);
10021004
}
1005+
1006+
/**
1007+
* hinic_hwdev_hw_ci_addr_set - set cons idx addr and attributes in HW for sq
1008+
* @hwdev: the NIC HW device
1009+
* @sq: send queue
1010+
* @pending_limit: the maximum pending update ci events (unit 8)
1011+
* @coalesc_timer: coalesc period for update ci (unit 8 us)
1012+
*
1013+
* Return 0 - Success, negative - Failure
1014+
**/
1015+
int hinic_hwdev_hw_ci_addr_set(struct hinic_hwdev *hwdev, struct hinic_sq *sq,
1016+
u8 pending_limit, u8 coalesc_timer)
1017+
{
1018+
struct hinic_qp *qp = container_of(sq, struct hinic_qp, sq);
1019+
struct hinic_hwif *hwif = hwdev->hwif;
1020+
struct pci_dev *pdev = hwif->pdev;
1021+
struct hinic_pfhwdev *pfhwdev;
1022+
struct hinic_cmd_hw_ci hw_ci;
1023+
1024+
if (!HINIC_IS_PF(hwif) && !HINIC_IS_PPF(hwif)) {
1025+
dev_err(&pdev->dev, "Unsupported PCI Function type\n");
1026+
return -EINVAL;
1027+
}
1028+
1029+
hw_ci.dma_attr_off = 0;
1030+
hw_ci.pending_limit = pending_limit;
1031+
hw_ci.coalesc_timer = coalesc_timer;
1032+
1033+
hw_ci.msix_en = 1;
1034+
hw_ci.msix_entry_idx = sq->msix_entry;
1035+
1036+
hw_ci.func_idx = HINIC_HWIF_FUNC_IDX(hwif);
1037+
1038+
hw_ci.sq_id = qp->q_id;
1039+
1040+
hw_ci.ci_addr = ADDR_IN_4BYTES(sq->hw_ci_dma_addr);
1041+
1042+
pfhwdev = container_of(hwdev, struct hinic_pfhwdev, hwdev);
1043+
return hinic_msg_to_mgmt(&pfhwdev->pf_to_mgmt,
1044+
HINIC_MOD_COMM,
1045+
HINIC_COMM_CMD_SQ_HI_CI_SET,
1046+
&hw_ci, sizeof(hw_ci), NULL,
1047+
NULL, HINIC_MGMT_MSG_SYNC);
1048+
}

drivers/net/ethernet/huawei/hinic/hinic_hw_dev.h

+22
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,25 @@ struct hinic_cmd_base_qpn {
153153
u16 qpn;
154154
};
155155

156+
struct hinic_cmd_hw_ci {
157+
u8 status;
158+
u8 version;
159+
u8 rsvd0[6];
160+
161+
u16 func_idx;
162+
163+
u8 dma_attr_off;
164+
u8 pending_limit;
165+
u8 coalesc_timer;
166+
167+
u8 msix_en;
168+
u16 msix_entry_idx;
169+
170+
u32 sq_id;
171+
u32 rsvd1;
172+
u64 ci_addr;
173+
};
174+
156175
struct hinic_hwdev {
157176
struct hinic_hwif *hwif;
158177
struct msix_entry *msix_entries;
@@ -214,4 +233,7 @@ int hinic_hwdev_msix_set(struct hinic_hwdev *hwdev, u16 msix_index,
214233
u8 lli_timer_cfg, u8 lli_credit_limit,
215234
u8 resend_timer);
216235

236+
int hinic_hwdev_hw_ci_addr_set(struct hinic_hwdev *hwdev, struct hinic_sq *sq,
237+
u8 pending_limit, u8 coalesc_timer);
238+
217239
#endif

drivers/net/ethernet/huawei/hinic/hinic_hw_qp.c

+255-2
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include <linux/sizes.h>
2424
#include <linux/atomic.h>
2525
#include <linux/skbuff.h>
26+
#include <linux/io.h>
2627
#include <asm/barrier.h>
2728
#include <asm/byteorder.h>
2829

@@ -32,6 +33,7 @@
3233
#include "hinic_hw_wq.h"
3334
#include "hinic_hw_qp_ctxt.h"
3435
#include "hinic_hw_qp.h"
36+
#include "hinic_hw_io.h"
3537

3638
#define SQ_DB_OFF SZ_2K
3739

@@ -53,11 +55,27 @@
5355
(((max_rqs) + (max_sqs)) * CTXT_RSVD + \
5456
(max_sqs + (q_id)) * Q_CTXT_SIZE)
5557

56-
#define SIZE_16BYTES(size) (ALIGN(size, 16) >> 4)
57-
#define SIZE_8BYTES(size) (ALIGN(size, 8) >> 3)
58+
#define SIZE_16BYTES(size) (ALIGN(size, 16) >> 4)
59+
#define SIZE_8BYTES(size) (ALIGN(size, 8) >> 3)
60+
#define SECT_SIZE_FROM_8BYTES(size) ((size) << 3)
5861

62+
#define SQ_DB_PI_HI_SHIFT 8
63+
#define SQ_DB_PI_HI(prod_idx) ((prod_idx) >> SQ_DB_PI_HI_SHIFT)
64+
65+
#define SQ_DB_PI_LOW_MASK 0xFF
66+
#define SQ_DB_PI_LOW(prod_idx) ((prod_idx) & SQ_DB_PI_LOW_MASK)
67+
68+
#define SQ_DB_ADDR(sq, pi) ((u64 *)((sq)->db_base) + SQ_DB_PI_LOW(pi))
69+
70+
#define SQ_MASKED_IDX(sq, idx) ((idx) & (sq)->wq->mask)
5971
#define RQ_MASKED_IDX(rq, idx) ((idx) & (rq)->wq->mask)
6072

73+
#define TX_MAX_MSS_DEFAULT 0x3E00
74+
75+
enum sq_wqe_type {
76+
SQ_NORMAL_WQE = 0,
77+
};
78+
6179
enum rq_completion_fmt {
6280
RQ_COMPLETE_SGE = 1
6381
};
@@ -435,6 +453,19 @@ void hinic_clean_rq(struct hinic_rq *rq)
435453
free_rq_skb_arr(rq);
436454
}
437455

456+
/**
457+
* hinic_get_sq_free_wqebbs - return number of free wqebbs for use
458+
* @sq: send queue
459+
*
460+
* Return number of free wqebbs
461+
**/
462+
int hinic_get_sq_free_wqebbs(struct hinic_sq *sq)
463+
{
464+
struct hinic_wq *wq = sq->wq;
465+
466+
return atomic_read(&wq->delta) - 1;
467+
}
468+
438469
/**
439470
* hinic_get_rq_free_wqebbs - return number of free wqebbs for use
440471
* @rq: recv queue
@@ -448,6 +479,228 @@ int hinic_get_rq_free_wqebbs(struct hinic_rq *rq)
448479
return atomic_read(&wq->delta) - 1;
449480
}
450481

482+
static void sq_prepare_ctrl(struct hinic_sq_ctrl *ctrl, u16 prod_idx,
483+
int nr_descs)
484+
{
485+
u32 ctrl_size, task_size, bufdesc_size;
486+
487+
ctrl_size = SIZE_8BYTES(sizeof(struct hinic_sq_ctrl));
488+
task_size = SIZE_8BYTES(sizeof(struct hinic_sq_task));
489+
bufdesc_size = nr_descs * sizeof(struct hinic_sq_bufdesc);
490+
bufdesc_size = SIZE_8BYTES(bufdesc_size);
491+
492+
ctrl->ctrl_info = HINIC_SQ_CTRL_SET(bufdesc_size, BUFDESC_SECT_LEN) |
493+
HINIC_SQ_CTRL_SET(task_size, TASKSECT_LEN) |
494+
HINIC_SQ_CTRL_SET(SQ_NORMAL_WQE, DATA_FORMAT) |
495+
HINIC_SQ_CTRL_SET(ctrl_size, LEN);
496+
497+
ctrl->queue_info = HINIC_SQ_CTRL_SET(TX_MAX_MSS_DEFAULT,
498+
QUEUE_INFO_MSS);
499+
}
500+
501+
static void sq_prepare_task(struct hinic_sq_task *task)
502+
{
503+
task->pkt_info0 =
504+
HINIC_SQ_TASK_INFO0_SET(0, L2HDR_LEN) |
505+
HINIC_SQ_TASK_INFO0_SET(HINIC_L4_OFF_DISABLE, L4_OFFLOAD) |
506+
HINIC_SQ_TASK_INFO0_SET(HINIC_OUTER_L3TYPE_UNKNOWN,
507+
INNER_L3TYPE) |
508+
HINIC_SQ_TASK_INFO0_SET(HINIC_VLAN_OFF_DISABLE,
509+
VLAN_OFFLOAD) |
510+
HINIC_SQ_TASK_INFO0_SET(HINIC_PKT_NOT_PARSED, PARSE_FLAG);
511+
512+
task->pkt_info1 =
513+
HINIC_SQ_TASK_INFO1_SET(HINIC_MEDIA_UNKNOWN, MEDIA_TYPE) |
514+
HINIC_SQ_TASK_INFO1_SET(0, INNER_L4_LEN) |
515+
HINIC_SQ_TASK_INFO1_SET(0, INNER_L3_LEN);
516+
517+
task->pkt_info2 =
518+
HINIC_SQ_TASK_INFO2_SET(0, TUNNEL_L4_LEN) |
519+
HINIC_SQ_TASK_INFO2_SET(0, OUTER_L3_LEN) |
520+
HINIC_SQ_TASK_INFO2_SET(HINIC_TUNNEL_L4TYPE_UNKNOWN,
521+
TUNNEL_L4TYPE) |
522+
HINIC_SQ_TASK_INFO2_SET(HINIC_OUTER_L3TYPE_UNKNOWN,
523+
OUTER_L3TYPE);
524+
525+
task->ufo_v6_identify = 0;
526+
527+
task->pkt_info4 = HINIC_SQ_TASK_INFO4_SET(HINIC_L2TYPE_ETH, L2TYPE);
528+
529+
task->zero_pad = 0;
530+
}
531+
532+
/**
533+
* hinic_sq_prepare_wqe - prepare wqe before insert to the queue
534+
* @sq: send queue
535+
* @prod_idx: pi value
536+
* @sq_wqe: wqe to prepare
537+
* @sges: sges for use by the wqe for send for buf addresses
538+
* @nr_sges: number of sges
539+
**/
540+
void hinic_sq_prepare_wqe(struct hinic_sq *sq, u16 prod_idx,
541+
struct hinic_sq_wqe *sq_wqe, struct hinic_sge *sges,
542+
int nr_sges)
543+
{
544+
int i;
545+
546+
sq_prepare_ctrl(&sq_wqe->ctrl, prod_idx, nr_sges);
547+
548+
sq_prepare_task(&sq_wqe->task);
549+
550+
for (i = 0; i < nr_sges; i++)
551+
sq_wqe->buf_descs[i].sge = sges[i];
552+
}
553+
554+
/**
555+
* sq_prepare_db - prepare doorbell to write
556+
* @sq: send queue
557+
* @prod_idx: pi value for the doorbell
558+
* @cos: cos of the doorbell
559+
*
560+
* Return db value
561+
**/
562+
static u32 sq_prepare_db(struct hinic_sq *sq, u16 prod_idx, unsigned int cos)
563+
{
564+
struct hinic_qp *qp = container_of(sq, struct hinic_qp, sq);
565+
u8 hi_prod_idx = SQ_DB_PI_HI(SQ_MASKED_IDX(sq, prod_idx));
566+
567+
/* Data should be written to HW in Big Endian Format */
568+
return cpu_to_be32(HINIC_SQ_DB_INFO_SET(hi_prod_idx, PI_HI) |
569+
HINIC_SQ_DB_INFO_SET(HINIC_DB_SQ_TYPE, TYPE) |
570+
HINIC_SQ_DB_INFO_SET(HINIC_DATA_PATH, PATH) |
571+
HINIC_SQ_DB_INFO_SET(cos, COS) |
572+
HINIC_SQ_DB_INFO_SET(qp->q_id, QID));
573+
}
574+
575+
/**
576+
* hinic_sq_write_db- write doorbell
577+
* @sq: send queue
578+
* @prod_idx: pi value for the doorbell
579+
* @wqe_size: wqe size
580+
* @cos: cos of the wqe
581+
**/
582+
void hinic_sq_write_db(struct hinic_sq *sq, u16 prod_idx, unsigned int wqe_size,
583+
unsigned int cos)
584+
{
585+
struct hinic_wq *wq = sq->wq;
586+
587+
/* increment prod_idx to the next */
588+
prod_idx += ALIGN(wqe_size, wq->wqebb_size) / wq->wqebb_size;
589+
590+
wmb(); /* Write all before the doorbell */
591+
592+
writel(sq_prepare_db(sq, prod_idx, cos), SQ_DB_ADDR(sq, prod_idx));
593+
}
594+
595+
/**
596+
* hinic_sq_get_wqe - get wqe ptr in the current pi and update the pi
597+
* @sq: sq to get wqe from
598+
* @wqe_size: wqe size
599+
* @prod_idx: returned pi
600+
*
601+
* Return wqe pointer
602+
**/
603+
struct hinic_sq_wqe *hinic_sq_get_wqe(struct hinic_sq *sq,
604+
unsigned int wqe_size, u16 *prod_idx)
605+
{
606+
struct hinic_hw_wqe *hw_wqe = hinic_get_wqe(sq->wq, wqe_size,
607+
prod_idx);
608+
609+
if (IS_ERR(hw_wqe))
610+
return NULL;
611+
612+
return &hw_wqe->sq_wqe;
613+
}
614+
615+
/**
616+
* hinic_sq_write_wqe - write the wqe to the sq
617+
* @sq: send queue
618+
* @prod_idx: pi of the wqe
619+
* @sq_wqe: the wqe to write
620+
* @skb: skb to save
621+
* @wqe_size: the size of the wqe
622+
**/
623+
void hinic_sq_write_wqe(struct hinic_sq *sq, u16 prod_idx,
624+
struct hinic_sq_wqe *sq_wqe,
625+
struct sk_buff *skb, unsigned int wqe_size)
626+
{
627+
struct hinic_hw_wqe *hw_wqe = (struct hinic_hw_wqe *)sq_wqe;
628+
629+
sq->saved_skb[prod_idx] = skb;
630+
631+
/* The data in the HW should be in Big Endian Format */
632+
hinic_cpu_to_be32(sq_wqe, wqe_size);
633+
634+
hinic_write_wqe(sq->wq, hw_wqe, wqe_size);
635+
}
636+
637+
/**
638+
* hinic_sq_read_wqe - read wqe ptr in the current ci and update the ci
639+
* @sq: send queue
640+
* @skb: return skb that was saved
641+
* @wqe_size: the size of the wqe
642+
* @cons_idx: consumer index of the wqe
643+
*
644+
* Return wqe in ci position
645+
**/
646+
struct hinic_sq_wqe *hinic_sq_read_wqe(struct hinic_sq *sq,
647+
struct sk_buff **skb,
648+
unsigned int *wqe_size, u16 *cons_idx)
649+
{
650+
struct hinic_hw_wqe *hw_wqe;
651+
struct hinic_sq_wqe *sq_wqe;
652+
struct hinic_sq_ctrl *ctrl;
653+
unsigned int buf_sect_len;
654+
u32 ctrl_info;
655+
656+
/* read the ctrl section for getting wqe size */
657+
hw_wqe = hinic_read_wqe(sq->wq, sizeof(*ctrl), cons_idx);
658+
if (IS_ERR(hw_wqe))
659+
return NULL;
660+
661+
sq_wqe = &hw_wqe->sq_wqe;
662+
ctrl = &sq_wqe->ctrl;
663+
ctrl_info = be32_to_cpu(ctrl->ctrl_info);
664+
buf_sect_len = HINIC_SQ_CTRL_GET(ctrl_info, BUFDESC_SECT_LEN);
665+
666+
*wqe_size = sizeof(*ctrl) + sizeof(sq_wqe->task);
667+
*wqe_size += SECT_SIZE_FROM_8BYTES(buf_sect_len);
668+
669+
*skb = sq->saved_skb[*cons_idx];
670+
671+
/* using the real wqe size to read wqe again */
672+
hw_wqe = hinic_read_wqe(sq->wq, *wqe_size, cons_idx);
673+
674+
return &hw_wqe->sq_wqe;
675+
}
676+
677+
/**
678+
* hinic_sq_put_wqe - release the ci for new wqes
679+
* @sq: send queue
680+
* @wqe_size: the size of the wqe
681+
**/
682+
void hinic_sq_put_wqe(struct hinic_sq *sq, unsigned int wqe_size)
683+
{
684+
hinic_put_wqe(sq->wq, wqe_size);
685+
}
686+
687+
/**
688+
* hinic_sq_get_sges - get sges from the wqe
689+
* @sq_wqe: wqe to get the sges from its buffer addresses
690+
* @sges: returned sges
691+
* @nr_sges: number sges to return
692+
**/
693+
void hinic_sq_get_sges(struct hinic_sq_wqe *sq_wqe, struct hinic_sge *sges,
694+
int nr_sges)
695+
{
696+
int i;
697+
698+
for (i = 0; i < nr_sges && i < HINIC_MAX_SQ_BUFDESCS; i++) {
699+
sges[i] = sq_wqe->buf_descs[i].sge;
700+
hinic_be32_to_cpu(&sges[i], sizeof(sges[i]));
701+
}
702+
}
703+
451704
/**
452705
* hinic_rq_get_wqe - get wqe ptr in the current pi and update the pi
453706
* @rq: rq to get wqe from

0 commit comments

Comments
 (0)