1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* Copyright (C) 2023 Intel Corporation */ |
3 | |
4 | #include "idpf.h" |
5 | #include "idpf_lan_pf_regs.h" |
6 | #include "idpf_virtchnl.h" |
7 | |
8 | #define IDPF_PF_ITR_IDX_SPACING 0x4 |
9 | |
10 | /** |
11 | * idpf_ctlq_reg_init - initialize default mailbox registers |
12 | * @cq: pointer to the array of create control queues |
13 | */ |
14 | static void idpf_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 = PF_FW_ATQH; |
25 | ccq->reg.tail = PF_FW_ATQT; |
26 | ccq->reg.len = PF_FW_ATQLEN; |
27 | ccq->reg.bah = PF_FW_ATQBAH; |
28 | ccq->reg.bal = PF_FW_ATQBAL; |
29 | ccq->reg.len_mask = PF_FW_ATQLEN_ATQLEN_M; |
30 | ccq->reg.len_ena_mask = PF_FW_ATQLEN_ATQENABLE_M; |
31 | ccq->reg.head_mask = PF_FW_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 = PF_FW_ARQH; |
36 | ccq->reg.tail = PF_FW_ARQT; |
37 | ccq->reg.len = PF_FW_ARQLEN; |
38 | ccq->reg.bah = PF_FW_ARQBAH; |
39 | ccq->reg.bal = PF_FW_ARQBAL; |
40 | ccq->reg.len_mask = PF_FW_ARQLEN_ARQLEN_M; |
41 | ccq->reg.len_ena_mask = PF_FW_ARQLEN_ARQENABLE_M; |
42 | ccq->reg.head_mask = PF_FW_ARQH_ARQH_M; |
43 | break; |
44 | default: |
45 | break; |
46 | } |
47 | } |
48 | } |
49 | |
50 | /** |
51 | * idpf_mb_intr_reg_init - Initialize mailbox interrupt register |
52 | * @adapter: adapter structure |
53 | */ |
54 | static void idpf_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 = PF_GLINT_DYN_CTL_INTENA_M; |
61 | intr->dyn_ctl_itridx_m = PF_GLINT_DYN_CTL_ITR_INDX_M; |
62 | intr->icr_ena = idpf_get_reg_addr(adapter, PF_INT_DIR_OICR_ENA); |
63 | intr->icr_ena_ctlq_m = PF_INT_DIR_OICR_ENA_M; |
64 | } |
65 | |
66 | /** |
67 | * idpf_intr_reg_init - Initialize interrupt registers |
68 | * @vport: virtual port structure |
69 | */ |
70 | static int idpf_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 = PF_GLINT_DYN_CTL_INTENA_M; |
100 | intr->dyn_ctl_itridx_s = PF_GLINT_DYN_CTL_ITR_INDX_S; |
101 | intr->dyn_ctl_intrvl_s = PF_GLINT_DYN_CTL_INTERVAL_S; |
102 | |
103 | spacing = IDPF_ITR_IDX_SPACING(reg_vals[vec_id].itrn_index_spacing, |
104 | IDPF_PF_ITR_IDX_SPACING); |
105 | rx_itr = PF_GLINT_ITR_ADDR(VIRTCHNL2_ITR_IDX_0, |
106 | reg_vals[vec_id].itrn_reg, |
107 | spacing); |
108 | tx_itr = PF_GLINT_ITR_ADDR(VIRTCHNL2_ITR_IDX_1, |
109 | reg_vals[vec_id].itrn_reg, |
110 | spacing); |
111 | intr->rx_itr = idpf_get_reg_addr(adapter, reg_offset: rx_itr); |
112 | intr->tx_itr = idpf_get_reg_addr(adapter, reg_offset: tx_itr); |
113 | } |
114 | |
115 | free_reg_vals: |
116 | kfree(objp: reg_vals); |
117 | |
118 | return err; |
119 | } |
120 | |
121 | /** |
122 | * idpf_reset_reg_init - Initialize reset registers |
123 | * @adapter: Driver specific private structure |
124 | */ |
125 | static void idpf_reset_reg_init(struct idpf_adapter *adapter) |
126 | { |
127 | adapter->reset_reg.rstat = idpf_get_reg_addr(adapter, PFGEN_RSTAT); |
128 | adapter->reset_reg.rstat_m = PFGEN_RSTAT_PFR_STATE_M; |
129 | } |
130 | |
131 | /** |
132 | * idpf_trigger_reset - trigger reset |
133 | * @adapter: Driver specific private structure |
134 | * @trig_cause: Reason to trigger a reset |
135 | */ |
136 | static void idpf_trigger_reset(struct idpf_adapter *adapter, |
137 | enum idpf_flags __always_unused trig_cause) |
138 | { |
139 | u32 reset_reg; |
140 | |
141 | reset_reg = readl(addr: idpf_get_reg_addr(adapter, PFGEN_CTRL)); |
142 | writel(val: reset_reg | PFGEN_CTRL_PFSWR, |
143 | addr: idpf_get_reg_addr(adapter, PFGEN_CTRL)); |
144 | } |
145 | |
146 | /** |
147 | * idpf_reg_ops_init - Initialize register API function pointers |
148 | * @adapter: Driver specific private structure |
149 | */ |
150 | static void idpf_reg_ops_init(struct idpf_adapter *adapter) |
151 | { |
152 | adapter->dev_ops.reg_ops.ctlq_reg_init = idpf_ctlq_reg_init; |
153 | adapter->dev_ops.reg_ops.intr_reg_init = idpf_intr_reg_init; |
154 | adapter->dev_ops.reg_ops.mb_intr_reg_init = idpf_mb_intr_reg_init; |
155 | adapter->dev_ops.reg_ops.reset_reg_init = idpf_reset_reg_init; |
156 | adapter->dev_ops.reg_ops.trigger_reset = idpf_trigger_reset; |
157 | } |
158 | |
159 | /** |
160 | * idpf_dev_ops_init - Initialize device API function pointers |
161 | * @adapter: Driver specific private structure |
162 | */ |
163 | void idpf_dev_ops_init(struct idpf_adapter *adapter) |
164 | { |
165 | idpf_reg_ops_init(adapter); |
166 | } |
167 | |