1 // SPDX-License-Identifier: GPL-2.0+
2 /* Copyright (c) 2021 Hisilicon Limited. */
3 
4 #include <net/devlink.h>
5 
6 #include "hclge_devlink.h"
7 
8 static int hclge_devlink_info_get(struct devlink *devlink,
9 				  struct devlink_info_req *req,
10 				  struct netlink_ext_ack *extack)
11 {
12 #define	HCLGE_DEVLINK_FW_STRING_LEN	32
13 	struct hclge_devlink_priv *priv = devlink_priv(devlink);
14 	char version_str[HCLGE_DEVLINK_FW_STRING_LEN];
15 	struct hclge_dev *hdev = priv->hdev;
16 	int ret;
17 
18 	ret = devlink_info_driver_name_put(req, KBUILD_MODNAME);
19 	if (ret)
20 		return ret;
21 
22 	snprintf(version_str, sizeof(version_str), "%lu.%lu.%lu.%lu",
23 		 hnae3_get_field(hdev->fw_version, HNAE3_FW_VERSION_BYTE3_MASK,
24 				 HNAE3_FW_VERSION_BYTE3_SHIFT),
25 		 hnae3_get_field(hdev->fw_version, HNAE3_FW_VERSION_BYTE2_MASK,
26 				 HNAE3_FW_VERSION_BYTE2_SHIFT),
27 		 hnae3_get_field(hdev->fw_version, HNAE3_FW_VERSION_BYTE1_MASK,
28 				 HNAE3_FW_VERSION_BYTE1_SHIFT),
29 		 hnae3_get_field(hdev->fw_version, HNAE3_FW_VERSION_BYTE0_MASK,
30 				 HNAE3_FW_VERSION_BYTE0_SHIFT));
31 
32 	return devlink_info_version_running_put(req,
33 						DEVLINK_INFO_VERSION_GENERIC_FW,
34 						version_str);
35 }
36 
37 static int hclge_devlink_reload_down(struct devlink *devlink, bool netns_change,
38 				     enum devlink_reload_action action,
39 				     enum devlink_reload_limit limit,
40 				     struct netlink_ext_ack *extack)
41 {
42 	struct hclge_devlink_priv *priv = devlink_priv(devlink);
43 	struct hclge_dev *hdev = priv->hdev;
44 	struct hnae3_handle *h = &hdev->vport->nic;
45 	struct pci_dev *pdev = hdev->pdev;
46 	int ret;
47 
48 	if (test_bit(HCLGE_STATE_RST_HANDLING, &hdev->state)) {
49 		dev_err(&pdev->dev, "reset is handling\n");
50 		return -EBUSY;
51 	}
52 
53 	switch (action) {
54 	case DEVLINK_RELOAD_ACTION_DRIVER_REINIT:
55 		rtnl_lock();
56 		ret = hdev->nic_client->ops->reset_notify(h, HNAE3_DOWN_CLIENT);
57 		if (ret) {
58 			rtnl_unlock();
59 			return ret;
60 		}
61 
62 		ret = hdev->nic_client->ops->reset_notify(h,
63 							  HNAE3_UNINIT_CLIENT);
64 		rtnl_unlock();
65 		return ret;
66 	default:
67 		return -EOPNOTSUPP;
68 	}
69 }
70 
71 static int hclge_devlink_reload_up(struct devlink *devlink,
72 				   enum devlink_reload_action action,
73 				   enum devlink_reload_limit limit,
74 				   u32 *actions_performed,
75 				   struct netlink_ext_ack *extack)
76 {
77 	struct hclge_devlink_priv *priv = devlink_priv(devlink);
78 	struct hclge_dev *hdev = priv->hdev;
79 	struct hnae3_handle *h = &hdev->vport->nic;
80 	int ret;
81 
82 	*actions_performed = BIT(action);
83 	switch (action) {
84 	case DEVLINK_RELOAD_ACTION_DRIVER_REINIT:
85 		rtnl_lock();
86 		ret = hdev->nic_client->ops->reset_notify(h, HNAE3_INIT_CLIENT);
87 		if (ret) {
88 			rtnl_unlock();
89 			return ret;
90 		}
91 
92 		ret = hdev->nic_client->ops->reset_notify(h, HNAE3_UP_CLIENT);
93 		rtnl_unlock();
94 		return ret;
95 	default:
96 		return -EOPNOTSUPP;
97 	}
98 }
99 
100 static const struct devlink_ops hclge_devlink_ops = {
101 	.info_get = hclge_devlink_info_get,
102 	.reload_actions = BIT(DEVLINK_RELOAD_ACTION_DRIVER_REINIT),
103 	.reload_down = hclge_devlink_reload_down,
104 	.reload_up = hclge_devlink_reload_up,
105 };
106 
107 int hclge_devlink_init(struct hclge_dev *hdev)
108 {
109 	struct pci_dev *pdev = hdev->pdev;
110 	struct hclge_devlink_priv *priv;
111 	struct devlink *devlink;
112 	int ret;
113 
114 	devlink = devlink_alloc(&hclge_devlink_ops,
115 				sizeof(struct hclge_devlink_priv), &pdev->dev);
116 	if (!devlink)
117 		return -ENOMEM;
118 
119 	priv = devlink_priv(devlink);
120 	priv->hdev = hdev;
121 	hdev->devlink = devlink;
122 
123 	ret = devlink_register(devlink);
124 	if (ret) {
125 		dev_err(&pdev->dev, "failed to register devlink, ret = %d\n",
126 			ret);
127 		goto out_reg_fail;
128 	}
129 
130 	devlink_reload_enable(devlink);
131 
132 	return 0;
133 
134 out_reg_fail:
135 	devlink_free(devlink);
136 	return ret;
137 }
138 
139 void hclge_devlink_uninit(struct hclge_dev *hdev)
140 {
141 	struct devlink *devlink = hdev->devlink;
142 
143 	devlink_reload_disable(devlink);
144 
145 	devlink_unregister(devlink);
146 
147 	devlink_free(devlink);
148 }
149