xref: /linux/drivers/net/ethernet/huawei/hinic3/hinic3_hw_cfg.c (revision 55a42f78ffd386e01a5404419f8c5ded7db70a21)
1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.
3 
4 #include <linux/device.h>
5 
6 #include "hinic3_hw_cfg.h"
7 #include "hinic3_hwdev.h"
8 #include "hinic3_hwif.h"
9 #include "hinic3_mbox.h"
10 
11 #define HINIC3_CFG_MAX_QP  256
12 
13 static void hinic3_parse_pub_res_cap(struct hinic3_hwdev *hwdev,
14 				     struct hinic3_dev_cap *cap,
15 				     const struct cfg_cmd_dev_cap *dev_cap,
16 				     enum hinic3_func_type type)
17 {
18 	cap->port_id = dev_cap->port_id;
19 	cap->supp_svcs_bitmap = dev_cap->svc_cap_en;
20 }
21 
22 static void hinic3_parse_l2nic_res_cap(struct hinic3_hwdev *hwdev,
23 				       struct hinic3_dev_cap *cap,
24 				       const struct cfg_cmd_dev_cap *dev_cap,
25 				       enum hinic3_func_type type)
26 {
27 	struct hinic3_nic_service_cap *nic_svc_cap = &cap->nic_svc_cap;
28 
29 	nic_svc_cap->max_sqs = min(dev_cap->nic_max_sq_id + 1,
30 				   HINIC3_CFG_MAX_QP);
31 }
32 
33 static void hinic3_parse_dev_cap(struct hinic3_hwdev *hwdev,
34 				 const struct cfg_cmd_dev_cap *dev_cap,
35 				 enum hinic3_func_type type)
36 {
37 	struct hinic3_dev_cap *cap = &hwdev->cfg_mgmt->cap;
38 
39 	/* Public resource */
40 	hinic3_parse_pub_res_cap(hwdev, cap, dev_cap, type);
41 
42 	/* L2 NIC resource */
43 	if (hinic3_support_nic(hwdev))
44 		hinic3_parse_l2nic_res_cap(hwdev, cap, dev_cap, type);
45 }
46 
47 static int get_cap_from_fw(struct hinic3_hwdev *hwdev,
48 			   enum hinic3_func_type type)
49 {
50 	struct mgmt_msg_params msg_params = {};
51 	struct cfg_cmd_dev_cap dev_cap = {};
52 	int err;
53 
54 	dev_cap.func_id = hinic3_global_func_id(hwdev);
55 
56 	mgmt_msg_params_init_default(&msg_params, &dev_cap, sizeof(dev_cap));
57 
58 	err = hinic3_send_mbox_to_mgmt(hwdev, MGMT_MOD_CFGM,
59 				       CFG_CMD_GET_DEV_CAP, &msg_params);
60 	if (err || dev_cap.head.status) {
61 		dev_err(hwdev->dev,
62 			"Failed to get capability from FW, err: %d, status: 0x%x\n",
63 			err, dev_cap.head.status);
64 		return -EIO;
65 	}
66 
67 	hinic3_parse_dev_cap(hwdev, &dev_cap, type);
68 
69 	return 0;
70 }
71 
72 static int hinic3_init_irq_info(struct hinic3_hwdev *hwdev)
73 {
74 	struct hinic3_cfg_mgmt_info *cfg_mgmt = hwdev->cfg_mgmt;
75 	struct hinic3_hwif *hwif = hwdev->hwif;
76 	u16 intr_num = hwif->attr.num_irqs;
77 	struct hinic3_irq_info *irq_info;
78 	u16 intr_needed;
79 
80 	intr_needed = hwif->attr.msix_flex_en ? (hwif->attr.num_aeqs +
81 		      hwif->attr.num_ceqs + hwif->attr.num_sq) : intr_num;
82 	if (intr_needed > intr_num) {
83 		dev_warn(hwdev->dev, "Irq num cfg %d is less than the needed irq num %d msix_flex_en %d\n",
84 			 intr_num, intr_needed, hwdev->hwif->attr.msix_flex_en);
85 		intr_needed = intr_num;
86 	}
87 
88 	irq_info = &cfg_mgmt->irq_info;
89 	irq_info->irq = kcalloc(intr_num, sizeof(struct hinic3_irq),
90 				GFP_KERNEL);
91 	if (!irq_info->irq)
92 		return -ENOMEM;
93 
94 	irq_info->num_irq_hw = intr_needed;
95 	mutex_init(&irq_info->irq_mutex);
96 
97 	return 0;
98 }
99 
100 static int hinic3_init_irq_alloc_info(struct hinic3_hwdev *hwdev)
101 {
102 	struct hinic3_cfg_mgmt_info *cfg_mgmt = hwdev->cfg_mgmt;
103 	struct hinic3_irq *irq = cfg_mgmt->irq_info.irq;
104 	u16 nreq = cfg_mgmt->irq_info.num_irq_hw;
105 	struct pci_dev *pdev = hwdev->pdev;
106 	int actual_irq;
107 	u16 i;
108 
109 	actual_irq = pci_alloc_irq_vectors(pdev, 2, nreq, PCI_IRQ_MSIX);
110 	if (actual_irq < 0) {
111 		dev_err(hwdev->dev, "Alloc msix entries with threshold 2 failed. actual_irq: %d\n",
112 			actual_irq);
113 		return -ENOMEM;
114 	}
115 
116 	nreq = actual_irq;
117 	cfg_mgmt->irq_info.num_irq = nreq;
118 
119 	for (i = 0; i < nreq; ++i) {
120 		irq[i].msix_entry_idx = i;
121 		irq[i].irq_id = pci_irq_vector(pdev, i);
122 		irq[i].allocated = false;
123 	}
124 
125 	return 0;
126 }
127 
128 int hinic3_init_cfg_mgmt(struct hinic3_hwdev *hwdev)
129 {
130 	struct hinic3_cfg_mgmt_info *cfg_mgmt;
131 	int err;
132 
133 	cfg_mgmt = kzalloc(sizeof(*cfg_mgmt), GFP_KERNEL);
134 	if (!cfg_mgmt)
135 		return -ENOMEM;
136 
137 	hwdev->cfg_mgmt = cfg_mgmt;
138 
139 	err = hinic3_init_irq_info(hwdev);
140 	if (err) {
141 		dev_err(hwdev->dev, "Failed to init hinic3_irq_mgmt_info, err: %d\n",
142 			err);
143 		goto err_free_cfg_mgmt;
144 	}
145 
146 	err = hinic3_init_irq_alloc_info(hwdev);
147 	if (err) {
148 		dev_err(hwdev->dev, "Failed to init hinic3_irq_info, err: %d\n",
149 			err);
150 		goto err_free_irq_info;
151 	}
152 
153 	return 0;
154 
155 err_free_irq_info:
156 	kfree(cfg_mgmt->irq_info.irq);
157 	cfg_mgmt->irq_info.irq = NULL;
158 err_free_cfg_mgmt:
159 	kfree(cfg_mgmt);
160 
161 	return err;
162 }
163 
164 void hinic3_free_cfg_mgmt(struct hinic3_hwdev *hwdev)
165 {
166 	struct hinic3_cfg_mgmt_info *cfg_mgmt = hwdev->cfg_mgmt;
167 
168 	pci_free_irq_vectors(hwdev->pdev);
169 	kfree(cfg_mgmt->irq_info.irq);
170 	cfg_mgmt->irq_info.irq = NULL;
171 	kfree(cfg_mgmt);
172 }
173 
174 int hinic3_alloc_irqs(struct hinic3_hwdev *hwdev, u16 num,
175 		      struct msix_entry *alloc_arr, u16 *act_num)
176 {
177 	struct hinic3_irq_info *irq_info;
178 	struct hinic3_irq *curr;
179 	u16 i, found = 0;
180 
181 	irq_info = &hwdev->cfg_mgmt->irq_info;
182 	mutex_lock(&irq_info->irq_mutex);
183 	for (i = 0; i < irq_info->num_irq && found < num; i++) {
184 		curr = irq_info->irq + i;
185 		if (curr->allocated)
186 			continue;
187 		curr->allocated = true;
188 		alloc_arr[found].vector = curr->irq_id;
189 		alloc_arr[found].entry = curr->msix_entry_idx;
190 		found++;
191 	}
192 	mutex_unlock(&irq_info->irq_mutex);
193 
194 	*act_num = found;
195 
196 	return found == 0 ? -ENOMEM : 0;
197 }
198 
199 void hinic3_free_irq(struct hinic3_hwdev *hwdev, u32 irq_id)
200 {
201 	struct hinic3_irq_info *irq_info;
202 	struct hinic3_irq *curr;
203 	u16 i;
204 
205 	irq_info = &hwdev->cfg_mgmt->irq_info;
206 	mutex_lock(&irq_info->irq_mutex);
207 	for (i = 0; i < irq_info->num_irq; i++) {
208 		curr = irq_info->irq + i;
209 		if (curr->irq_id == irq_id) {
210 			curr->allocated = false;
211 			break;
212 		}
213 	}
214 	mutex_unlock(&irq_info->irq_mutex);
215 }
216 
217 int hinic3_init_capability(struct hinic3_hwdev *hwdev)
218 {
219 	return get_cap_from_fw(hwdev, HINIC3_FUNC_TYPE_VF);
220 }
221 
222 bool hinic3_support_nic(struct hinic3_hwdev *hwdev)
223 {
224 	return hwdev->cfg_mgmt->cap.supp_svcs_bitmap &
225 	       BIT(HINIC3_SERVICE_T_NIC);
226 }
227 
228 u16 hinic3_func_max_qnum(struct hinic3_hwdev *hwdev)
229 {
230 	return hwdev->cfg_mgmt->cap.nic_svc_cap.max_sqs;
231 }
232 
233 u8 hinic3_physical_port_id(struct hinic3_hwdev *hwdev)
234 {
235 	return hwdev->cfg_mgmt->cap.port_id;
236 }
237