File Index
Files and directories
Sign in
FILE

hinic3_hw_cfg.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/ethernet/huawei/hinic3/hinic3_hw_cfg.c C
  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
 13static 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
 22static 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
 33static 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
 47static 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
 72static 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
100static 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
128int 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
155err_free_irq_info:
156	kfree(cfg_mgmt->irq_info.irq);
157	cfg_mgmt->irq_info.irq = NULL;
158err_free_cfg_mgmt:
159	kfree(cfg_mgmt);
160
161	return err;
162}
163
164void 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
174int 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
199void 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
217int hinic3_init_capability(struct hinic3_hwdev *hwdev)
218{
219	return get_cap_from_fw(hwdev, HINIC3_FUNC_TYPE_VF);
220}
221
222bool 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
228u16 hinic3_func_max_qnum(struct hinic3_hwdev *hwdev)
229{
230	return hwdev->cfg_mgmt->cap.nic_svc_cap.max_sqs;
231}
232
233u8 hinic3_physical_port_id(struct hinic3_hwdev *hwdev)
234{
235	return hwdev->cfg_mgmt->cap.port_id;
236}
~/ Read-only file preview.