1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* Copyright (C) 2023 Intel Corporation */ |
3 | |
4 | #include "idpf.h" |
5 | #include "idpf_lan_vf_regs.h" |
6 | #include "idpf_virtchnl.h" |
7 | |
8 | #define IDPF_VF_ITR_IDX_SPACING 0x40 |
9 | |
10 | /** |
11 | * idpf_vf_ctlq_reg_init - initialize default mailbox registers |
12 | * @cq: pointer to the array of create control queues |
13 | */ |
14 | static void idpf_vf_ctlq_reg_init(struct idpf_ctlq_create_info *cq) |
15 | { |
16 | int i; |
17 | |
18 | for (i = 0; i < IDPF_NUM_DFLT_MBX_Q; i++) { |
19 | struct idpf_ctlq_create_info *ccq = cq + i; |
20 | |
21 | switch (ccq->type) { |
22 | case IDPF_CTLQ_TYPE_MAILBOX_TX: |
23 | /* set head and tail registers in our local struct */ |
24 | ccq->reg.head = VF_ATQH; |
25 | ccq->reg.tail = VF_ATQT; |
26 | ccq->reg.len = VF_ATQLEN; |
27 | ccq->reg.bah = VF_ATQBAH; |
28 | ccq->reg.bal = VF_ATQBAL; |
29 | ccq->reg.len_mask = VF_ATQLEN_ATQLEN_M; |
30 | ccq->reg.len_ena_mask = VF_ATQLEN_ATQENABLE_M; |
31 | ccq->reg.head_mask = VF_ATQH_ATQH_M; |
32 | break; |
33 | case IDPF_CTLQ_TYPE_MAILBOX_RX: |
34 | /* set head and tail registers in our local struct */ |
35 | ccq->reg.head = VF_ARQH; |
36 | ccq->reg.tail = VF_ARQT; |
37 | ccq->reg.len = VF_ARQLEN; |
38 | ccq->reg.bah = VF_ARQBAH; |
39 | ccq->reg.bal = VF_ARQBAL; |
40 | ccq->reg.len_mask = VF_ARQLEN_ARQLEN_M; |
41 | ccq->reg.len_ena_mask = VF_ARQLEN_ARQENABLE_M; |
42 | ccq->reg.head_mask = VF_ARQH_ARQH_M; |
43 | break; |
44 | default: |
45 | break; |
46 | } |
47 | } |
48 | } |
49 | |
50 | /** |
51 | * idpf_vf_mb_intr_reg_init - Initialize the mailbox register |
52 | * @adapter: adapter structure |
53 | */ |
54 | static void idpf_vf_mb_intr_reg_init(struct idpf_adapter *adapter) |
55 | { |
56 | struct idpf_intr_reg *intr = &adapter->mb_vector.intr_reg; |
57 | u32 dyn_ctl = le32_to_cpu(adapter->caps.mailbox_dyn_ctl); |
58 | |
59 | intr->dyn_ctl = idpf_get_reg_addr(adapter, reg_offset: dyn_ctl); |
60 | intr->dyn_ctl_intena_m = VF_INT_DYN_CTL0_INTENA_M; |
61 | intr->dyn_ctl_itridx_m = VF_INT_DYN_CTL0_ITR_INDX_M; |
62 | intr->icr_ena = idpf_get_reg_addr(adapter, VF_INT_ICR0_ENA1); |
63 | intr->icr_ena_ctlq_m = VF_INT_ICR0_ENA1_ADMINQ_M; |
64 | } |
65 | |
66 | /** |
67 | * idpf_vf_intr_reg_init - Initialize interrupt registers |
68 | * @vport: virtual port structure |
69 | */ |
70 | static int idpf_vf_intr_reg_init(struct idpf_vport *vport) |
71 | { |
72 | struct idpf_adapter *adapter = vport->adapter; |
73 | int num_vecs = vport->num_q_vectors; |
74 | struct idpf_vec_regs *reg_vals; |
75 | int num_regs, i, err = 0; |
76 | u32 rx_itr, tx_itr; |
77 | u16 total_vecs; |
78 | |
79 | total_vecs = idpf_get_reserved_vecs(adapter: vport->adapter); |
80 | reg_vals = kcalloc(n: total_vecs, size: sizeof(struct idpf_vec_regs), |
81 | GFP_KERNEL); |
82 | if (!reg_vals) |
83 | return -ENOMEM; |
84 | |
85 | num_regs = idpf_get_reg_intr_vecs(vport, reg_vals); |
86 | if (num_regs < num_vecs) { |
87 | err = -EINVAL; |
88 | goto free_reg_vals; |
89 | } |
90 | |
91 | for (i = 0; i < num_vecs; i++) { |
92 | struct idpf_q_vector *q_vector = &vport->q_vectors[i]; |
93 | u16 vec_id = vport->q_vector_idxs[i] - IDPF_MBX_Q_VEC; |
94 | struct idpf_intr_reg *intr = &q_vector->intr_reg; |
95 | u32 spacing; |
96 | |
97 | intr->dyn_ctl = idpf_get_reg_addr(adapter, |
98 | reg_offset: reg_vals[vec_id].dyn_ctl_reg); |
99 | intr->dyn_ctl_intena_m = VF_INT_DYN_CTLN_INTENA_M; |
100 | intr->dyn_ctl_itridx_s = VF_INT_DYN_CTLN_ITR_INDX_S; |
101 | |
102 | spacing = IDPF_ITR_IDX_SPACING(reg_vals[vec_id].itrn_index_spacing, |
103 | IDPF_VF_ITR_IDX_SPACING); |
104 | rx_itr = VF_INT_ITRN_ADDR(VIRTCHNL2_ITR_IDX_0, |
105 | reg_vals[vec_id].itrn_reg, |
106 | spacing); |
107 | tx_itr = VF_INT_ITRN_ADDR(VIRTCHNL2_ITR_IDX_1, |
108 | reg_vals[vec_id].itrn_reg, |
109 | spacing); |
110 | intr->rx_itr = idpf_get_reg_addr(adapter, reg_offset: rx_itr); |
111 | intr->tx_itr = idpf_get_reg_addr(adapter, reg_offset: tx_itr); |
112 | } |
113 | |
114 | free_reg_vals: |
115 | kfree(objp: reg_vals); |
116 | |
117 | return err; |
118 | } |
119 | |
120 | /** |
121 | * idpf_vf_reset_reg_init - Initialize reset registers |
122 | * @adapter: Driver specific private structure |
123 | */ |
124 | static void idpf_vf_reset_reg_init(struct idpf_adapter *adapter) |
125 | { |
126 | adapter->reset_reg.rstat = idpf_get_reg_addr(adapter, VFGEN_RSTAT); |
127 | adapter->reset_reg.rstat_m = VFGEN_RSTAT_VFR_STATE_M; |
128 | } |
129 | |
130 | /** |
131 | * idpf_vf_trigger_reset - trigger reset |
132 | * @adapter: Driver specific private structure |
133 | * @trig_cause: Reason to trigger a reset |
134 | */ |
135 | static void idpf_vf_trigger_reset(struct idpf_adapter *adapter, |
136 | enum idpf_flags trig_cause) |
137 | { |
138 | /* Do not send VIRTCHNL2_OP_RESET_VF message on driver unload */ |
139 | if (trig_cause == IDPF_HR_FUNC_RESET && |
140 | !test_bit(IDPF_REMOVE_IN_PROG, adapter->flags)) |
141 | idpf_send_mb_msg(adapter, op: VIRTCHNL2_OP_RESET_VF, msg_size: 0, NULL, cookie: 0); |
142 | } |
143 | |
144 | /** |
145 | * idpf_vf_reg_ops_init - Initialize register API function pointers |
146 | * @adapter: Driver specific private structure |
147 | */ |
148 | static void idpf_vf_reg_ops_init(struct idpf_adapter *adapter) |
149 | { |
150 | adapter->dev_ops.reg_ops.ctlq_reg_init = idpf_vf_ctlq_reg_init; |
151 | adapter->dev_ops.reg_ops.intr_reg_init = idpf_vf_intr_reg_init; |
152 | adapter->dev_ops.reg_ops.mb_intr_reg_init = idpf_vf_mb_intr_reg_init; |
153 | adapter->dev_ops.reg_ops.reset_reg_init = idpf_vf_reset_reg_init; |
154 | adapter->dev_ops.reg_ops.trigger_reset = idpf_vf_trigger_reset; |
155 | } |
156 | |
157 | /** |
158 | * idpf_vf_dev_ops_init - Initialize device API function pointers |
159 | * @adapter: Driver specific private structure |
160 | */ |
161 | void idpf_vf_dev_ops_init(struct idpf_adapter *adapter) |
162 | { |
163 | idpf_vf_reg_ops_init(adapter); |
164 | } |
165 | |