1 /*
2  * Huawei HiNIC PCI Express Linux driver
3  * Copyright(c) 2017 Huawei Technologies Co., Ltd
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms and conditions of the GNU General Public License,
7  * version 2, as published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * for more details.
13  *
14  */
15 
16 #include <linux/types.h>
17 #include <linux/netdevice.h>
18 #include <linux/etherdevice.h>
19 #include <linux/if_vlan.h>
20 #include <linux/pci.h>
21 #include <linux/device.h>
22 #include <linux/errno.h>
23 
24 #include "hinic_hw_if.h"
25 #include "hinic_hw_dev.h"
26 #include "hinic_port.h"
27 #include "hinic_dev.h"
28 
29 #define HINIC_MIN_MTU_SIZE              256
30 #define HINIC_MAX_JUMBO_FRAME_SIZE      15872
31 
32 enum mac_op {
33 	MAC_DEL,
34 	MAC_SET,
35 };
36 
37 /**
38  * change_mac - change(add or delete) mac address
39  * @nic_dev: nic device
40  * @addr: mac address
41  * @vlan_id: vlan number to set with the mac
42  * @op: add or delete the mac
43  *
44  * Return 0 - Success, negative - Failure
45  **/
46 static int change_mac(struct hinic_dev *nic_dev, const u8 *addr,
47 		      u16 vlan_id, enum mac_op op)
48 {
49 	struct net_device *netdev = nic_dev->netdev;
50 	struct hinic_hwdev *hwdev = nic_dev->hwdev;
51 	struct hinic_port_mac_cmd port_mac_cmd;
52 	struct hinic_hwif *hwif = hwdev->hwif;
53 	struct pci_dev *pdev = hwif->pdev;
54 	enum hinic_port_cmd cmd;
55 	u16 out_size;
56 	int err;
57 
58 	if (vlan_id >= VLAN_N_VID) {
59 		netif_err(nic_dev, drv, netdev, "Invalid VLAN number\n");
60 		return -EINVAL;
61 	}
62 
63 	if (op == MAC_SET)
64 		cmd = HINIC_PORT_CMD_SET_MAC;
65 	else
66 		cmd = HINIC_PORT_CMD_DEL_MAC;
67 
68 	port_mac_cmd.func_idx = HINIC_HWIF_FUNC_IDX(hwif);
69 	port_mac_cmd.vlan_id = vlan_id;
70 	memcpy(port_mac_cmd.mac, addr, ETH_ALEN);
71 
72 	err = hinic_port_msg_cmd(hwdev, cmd, &port_mac_cmd,
73 				 sizeof(port_mac_cmd),
74 				 &port_mac_cmd, &out_size);
75 	if (err || (out_size != sizeof(port_mac_cmd)) || port_mac_cmd.status) {
76 		dev_err(&pdev->dev, "Failed to change MAC, ret = %d\n",
77 			port_mac_cmd.status);
78 		return -EFAULT;
79 	}
80 
81 	return 0;
82 }
83 
84 /**
85  * hinic_port_add_mac - add mac address
86  * @nic_dev: nic device
87  * @addr: mac address
88  * @vlan_id: vlan number to set with the mac
89  *
90  * Return 0 - Success, negative - Failure
91  **/
92 int hinic_port_add_mac(struct hinic_dev *nic_dev,
93 		       const u8 *addr, u16 vlan_id)
94 {
95 	return change_mac(nic_dev, addr, vlan_id, MAC_SET);
96 }
97 
98 /**
99  * hinic_port_del_mac - remove mac address
100  * @nic_dev: nic device
101  * @addr: mac address
102  * @vlan_id: vlan number that is connected to the mac
103  *
104  * Return 0 - Success, negative - Failure
105  **/
106 int hinic_port_del_mac(struct hinic_dev *nic_dev, const u8 *addr,
107 		       u16 vlan_id)
108 {
109 	return change_mac(nic_dev, addr, vlan_id, MAC_DEL);
110 }
111 
112 /**
113  * hinic_port_get_mac - get the mac address of the nic device
114  * @nic_dev: nic device
115  * @addr: returned mac address
116  *
117  * Return 0 - Success, negative - Failure
118  **/
119 int hinic_port_get_mac(struct hinic_dev *nic_dev, u8 *addr)
120 {
121 	struct hinic_hwdev *hwdev = nic_dev->hwdev;
122 	struct hinic_port_mac_cmd port_mac_cmd;
123 	struct hinic_hwif *hwif = hwdev->hwif;
124 	struct pci_dev *pdev = hwif->pdev;
125 	u16 out_size;
126 	int err;
127 
128 	port_mac_cmd.func_idx = HINIC_HWIF_FUNC_IDX(hwif);
129 
130 	err = hinic_port_msg_cmd(hwdev, HINIC_PORT_CMD_GET_MAC,
131 				 &port_mac_cmd, sizeof(port_mac_cmd),
132 				 &port_mac_cmd, &out_size);
133 	if (err || (out_size != sizeof(port_mac_cmd)) || port_mac_cmd.status) {
134 		dev_err(&pdev->dev, "Failed to get mac, ret = %d\n",
135 			port_mac_cmd.status);
136 		return -EFAULT;
137 	}
138 
139 	memcpy(addr, port_mac_cmd.mac, ETH_ALEN);
140 	return 0;
141 }
142 
143 /**
144  * hinic_port_set_mtu - set mtu
145  * @nic_dev: nic device
146  * @new_mtu: new mtu
147  *
148  * Return 0 - Success, negative - Failure
149  **/
150 int hinic_port_set_mtu(struct hinic_dev *nic_dev, int new_mtu)
151 {
152 	struct net_device *netdev = nic_dev->netdev;
153 	struct hinic_hwdev *hwdev = nic_dev->hwdev;
154 	struct hinic_port_mtu_cmd port_mtu_cmd;
155 	struct hinic_hwif *hwif = hwdev->hwif;
156 	struct pci_dev *pdev = hwif->pdev;
157 	int err, max_frame;
158 	u16 out_size;
159 
160 	if (new_mtu < HINIC_MIN_MTU_SIZE) {
161 		netif_err(nic_dev, drv, netdev, "mtu < MIN MTU size");
162 		return -EINVAL;
163 	}
164 
165 	max_frame = new_mtu + ETH_HLEN + ETH_FCS_LEN;
166 	if (max_frame > HINIC_MAX_JUMBO_FRAME_SIZE) {
167 		netif_err(nic_dev, drv, netdev, "mtu > MAX MTU size");
168 		return -EINVAL;
169 	}
170 
171 	port_mtu_cmd.func_idx = HINIC_HWIF_FUNC_IDX(hwif);
172 	port_mtu_cmd.mtu = new_mtu;
173 
174 	err = hinic_port_msg_cmd(hwdev, HINIC_PORT_CMD_CHANGE_MTU,
175 				 &port_mtu_cmd, sizeof(port_mtu_cmd),
176 				 &port_mtu_cmd, &out_size);
177 	if (err || (out_size != sizeof(port_mtu_cmd)) || port_mtu_cmd.status) {
178 		dev_err(&pdev->dev, "Failed to set mtu, ret = %d\n",
179 			port_mtu_cmd.status);
180 		return -EFAULT;
181 	}
182 
183 	return 0;
184 }
185 
186 /**
187  * hinic_port_add_vlan - add vlan to the nic device
188  * @nic_dev: nic device
189  * @vlan_id: the vlan number to add
190  *
191  * Return 0 - Success, negative - Failure
192  **/
193 int hinic_port_add_vlan(struct hinic_dev *nic_dev, u16 vlan_id)
194 {
195 	struct hinic_hwdev *hwdev = nic_dev->hwdev;
196 	struct hinic_port_vlan_cmd port_vlan_cmd;
197 
198 	port_vlan_cmd.func_idx = HINIC_HWIF_FUNC_IDX(hwdev->hwif);
199 	port_vlan_cmd.vlan_id = vlan_id;
200 
201 	return hinic_port_msg_cmd(hwdev, HINIC_PORT_CMD_ADD_VLAN,
202 				  &port_vlan_cmd, sizeof(port_vlan_cmd),
203 				  NULL, NULL);
204 }
205 
206 /**
207  * hinic_port_del_vlan - delete vlan from the nic device
208  * @nic_dev: nic device
209  * @vlan_id: the vlan number to delete
210  *
211  * Return 0 - Success, negative - Failure
212  **/
213 int hinic_port_del_vlan(struct hinic_dev *nic_dev, u16 vlan_id)
214 {
215 	struct hinic_hwdev *hwdev = nic_dev->hwdev;
216 	struct hinic_port_vlan_cmd port_vlan_cmd;
217 
218 	port_vlan_cmd.func_idx = HINIC_HWIF_FUNC_IDX(hwdev->hwif);
219 	port_vlan_cmd.vlan_id = vlan_id;
220 
221 	return hinic_port_msg_cmd(hwdev, HINIC_PORT_CMD_DEL_VLAN,
222 				 &port_vlan_cmd, sizeof(port_vlan_cmd),
223 				 NULL, NULL);
224 }
225 
226 /**
227  * hinic_port_set_rx_mode - set rx mode in the nic device
228  * @nic_dev: nic device
229  * @rx_mode: the rx mode to set
230  *
231  * Return 0 - Success, negative - Failure
232  **/
233 int hinic_port_set_rx_mode(struct hinic_dev *nic_dev, u32 rx_mode)
234 {
235 	struct hinic_hwdev *hwdev = nic_dev->hwdev;
236 	struct hinic_port_rx_mode_cmd rx_mode_cmd;
237 
238 	rx_mode_cmd.func_idx = HINIC_HWIF_FUNC_IDX(hwdev->hwif);
239 	rx_mode_cmd.rx_mode = rx_mode;
240 
241 	return hinic_port_msg_cmd(hwdev, HINIC_PORT_CMD_SET_RX_MODE,
242 				  &rx_mode_cmd, sizeof(rx_mode_cmd),
243 				  NULL, NULL);
244 }
245 
246 /**
247  * hinic_port_link_state - get the link state
248  * @nic_dev: nic device
249  * @link_state: the returned link state
250  *
251  * Return 0 - Success, negative - Failure
252  **/
253 int hinic_port_link_state(struct hinic_dev *nic_dev,
254 			  enum hinic_port_link_state *link_state)
255 {
256 	struct hinic_hwdev *hwdev = nic_dev->hwdev;
257 	struct hinic_hwif *hwif = hwdev->hwif;
258 	struct hinic_port_link_cmd link_cmd;
259 	struct pci_dev *pdev = hwif->pdev;
260 	u16 out_size;
261 	int err;
262 
263 	if (!HINIC_IS_PF(hwif) && !HINIC_IS_PPF(hwif)) {
264 		dev_err(&pdev->dev, "unsupported PCI Function type\n");
265 		return -EINVAL;
266 	}
267 
268 	link_cmd.func_idx = HINIC_HWIF_FUNC_IDX(hwif);
269 
270 	err = hinic_port_msg_cmd(hwdev, HINIC_PORT_CMD_GET_LINK_STATE,
271 				 &link_cmd, sizeof(link_cmd),
272 				 &link_cmd, &out_size);
273 	if (err || (out_size != sizeof(link_cmd)) || link_cmd.status) {
274 		dev_err(&pdev->dev, "Failed to get link state, ret = %d\n",
275 			link_cmd.status);
276 		return -EINVAL;
277 	}
278 
279 	*link_state = link_cmd.state;
280 	return 0;
281 }
282 
283 /**
284  * hinic_port_set_state - set port state
285  * @nic_dev: nic device
286  * @state: the state to set
287  *
288  * Return 0 - Success, negative - Failure
289  **/
290 int hinic_port_set_state(struct hinic_dev *nic_dev, enum hinic_port_state state)
291 {
292 	struct hinic_hwdev *hwdev = nic_dev->hwdev;
293 	struct hinic_port_state_cmd port_state;
294 	struct hinic_hwif *hwif = hwdev->hwif;
295 	struct pci_dev *pdev = hwif->pdev;
296 	u16 out_size;
297 	int err;
298 
299 	if (!HINIC_IS_PF(hwif) && !HINIC_IS_PPF(hwif)) {
300 		dev_err(&pdev->dev, "unsupported PCI Function type\n");
301 		return -EINVAL;
302 	}
303 
304 	port_state.state = state;
305 
306 	err = hinic_port_msg_cmd(hwdev, HINIC_PORT_CMD_SET_PORT_STATE,
307 				 &port_state, sizeof(port_state),
308 				 &port_state, &out_size);
309 	if (err || (out_size != sizeof(port_state)) || port_state.status) {
310 		dev_err(&pdev->dev, "Failed to set port state, ret = %d\n",
311 			port_state.status);
312 		return -EFAULT;
313 	}
314 
315 	return 0;
316 }
317 
318 /**
319  * hinic_port_set_func_state- set func device state
320  * @nic_dev: nic device
321  * @state: the state to set
322  *
323  * Return 0 - Success, negative - Failure
324  **/
325 int hinic_port_set_func_state(struct hinic_dev *nic_dev,
326 			      enum hinic_func_port_state state)
327 {
328 	struct hinic_port_func_state_cmd func_state;
329 	struct hinic_hwdev *hwdev = nic_dev->hwdev;
330 	struct hinic_hwif *hwif = hwdev->hwif;
331 	struct pci_dev *pdev = hwif->pdev;
332 	u16 out_size;
333 	int err;
334 
335 	func_state.func_idx = HINIC_HWIF_FUNC_IDX(hwif);
336 	func_state.state = state;
337 
338 	err = hinic_port_msg_cmd(hwdev, HINIC_PORT_CMD_SET_FUNC_STATE,
339 				 &func_state, sizeof(func_state),
340 				 &func_state, &out_size);
341 	if (err || (out_size != sizeof(func_state)) || func_state.status) {
342 		dev_err(&pdev->dev, "Failed to set port func state, ret = %d\n",
343 			func_state.status);
344 		return -EFAULT;
345 	}
346 
347 	return 0;
348 }
349 
350 /**
351  * hinic_port_get_cap - get port capabilities
352  * @nic_dev: nic device
353  * @port_cap: returned port capabilities
354  *
355  * Return 0 - Success, negative - Failure
356  **/
357 int hinic_port_get_cap(struct hinic_dev *nic_dev,
358 		       struct hinic_port_cap *port_cap)
359 {
360 	struct hinic_hwdev *hwdev = nic_dev->hwdev;
361 	struct hinic_hwif *hwif = hwdev->hwif;
362 	struct pci_dev *pdev = hwif->pdev;
363 	u16 out_size;
364 	int err;
365 
366 	port_cap->func_idx = HINIC_HWIF_FUNC_IDX(hwif);
367 
368 	err = hinic_port_msg_cmd(hwdev, HINIC_PORT_CMD_GET_CAP,
369 				 port_cap, sizeof(*port_cap),
370 				 port_cap, &out_size);
371 	if (err || (out_size != sizeof(*port_cap)) || port_cap->status) {
372 		dev_err(&pdev->dev,
373 			"Failed to get port capabilities, ret = %d\n",
374 			port_cap->status);
375 		return -EINVAL;
376 	}
377 
378 	return 0;
379 }
380