1 /*
2  * aQuantia Corporation Network Driver
3  * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved
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 
10 /* File aq_main.c: Main file for aQuantia Linux driver. */
11 
12 #include "aq_main.h"
13 #include "aq_nic.h"
14 #include "aq_pci_func.h"
15 #include "aq_ethtool.h"
16 
17 #include <linux/netdevice.h>
18 #include <linux/module.h>
19 
20 MODULE_LICENSE("GPL v2");
21 MODULE_VERSION(AQ_CFG_DRV_VERSION);
22 MODULE_AUTHOR(AQ_CFG_DRV_AUTHOR);
23 MODULE_DESCRIPTION(AQ_CFG_DRV_DESC);
24 
25 static const struct net_device_ops aq_ndev_ops;
26 
27 struct net_device *aq_ndev_alloc(void)
28 {
29 	struct net_device *ndev = NULL;
30 	struct aq_nic_s *aq_nic = NULL;
31 
32 	ndev = alloc_etherdev_mq(sizeof(struct aq_nic_s), AQ_CFG_VECS_MAX);
33 	if (!ndev)
34 		return NULL;
35 
36 	aq_nic = netdev_priv(ndev);
37 	aq_nic->ndev = ndev;
38 	ndev->netdev_ops = &aq_ndev_ops;
39 	ndev->ethtool_ops = &aq_ethtool_ops;
40 
41 	return ndev;
42 }
43 
44 static int aq_ndev_open(struct net_device *ndev)
45 {
46 	int err = 0;
47 	struct aq_nic_s *aq_nic = netdev_priv(ndev);
48 
49 	err = aq_nic_init(aq_nic);
50 	if (err < 0)
51 		goto err_exit;
52 	err = aq_nic_start(aq_nic);
53 	if (err < 0)
54 		goto err_exit;
55 
56 err_exit:
57 	if (err < 0)
58 		aq_nic_deinit(aq_nic);
59 	return err;
60 }
61 
62 static int aq_ndev_close(struct net_device *ndev)
63 {
64 	int err = 0;
65 	struct aq_nic_s *aq_nic = netdev_priv(ndev);
66 
67 	err = aq_nic_stop(aq_nic);
68 	if (err < 0)
69 		goto err_exit;
70 	aq_nic_deinit(aq_nic);
71 
72 err_exit:
73 	return err;
74 }
75 
76 static int aq_ndev_start_xmit(struct sk_buff *skb, struct net_device *ndev)
77 {
78 	struct aq_nic_s *aq_nic = netdev_priv(ndev);
79 
80 	return aq_nic_xmit(aq_nic, skb);
81 }
82 
83 static int aq_ndev_change_mtu(struct net_device *ndev, int new_mtu)
84 {
85 	struct aq_nic_s *aq_nic = netdev_priv(ndev);
86 	int err = aq_nic_set_mtu(aq_nic, new_mtu + ETH_HLEN);
87 
88 	if (err < 0)
89 		goto err_exit;
90 	ndev->mtu = new_mtu;
91 
92 err_exit:
93 	return err;
94 }
95 
96 static int aq_ndev_set_features(struct net_device *ndev,
97 				netdev_features_t features)
98 {
99 	struct aq_nic_s *aq_nic = netdev_priv(ndev);
100 	struct aq_nic_cfg_s *aq_cfg = aq_nic_get_cfg(aq_nic);
101 	bool is_lro = false;
102 
103 	if (aq_cfg->hw_features & NETIF_F_LRO) {
104 		is_lro = features & NETIF_F_LRO;
105 
106 		if (aq_cfg->is_lro != is_lro) {
107 			aq_cfg->is_lro = is_lro;
108 
109 			if (netif_running(ndev)) {
110 				aq_ndev_close(ndev);
111 				aq_ndev_open(ndev);
112 			}
113 		}
114 	}
115 
116 	return 0;
117 }
118 
119 static int aq_ndev_set_mac_address(struct net_device *ndev, void *addr)
120 {
121 	struct aq_nic_s *aq_nic = netdev_priv(ndev);
122 	int err = 0;
123 
124 	err = eth_mac_addr(ndev, addr);
125 	if (err < 0)
126 		goto err_exit;
127 	err = aq_nic_set_mac(aq_nic, ndev);
128 	if (err < 0)
129 		goto err_exit;
130 
131 err_exit:
132 	return err;
133 }
134 
135 static void aq_ndev_set_multicast_settings(struct net_device *ndev)
136 {
137 	struct aq_nic_s *aq_nic = netdev_priv(ndev);
138 	int err = 0;
139 
140 	err = aq_nic_set_packet_filter(aq_nic, ndev->flags);
141 	if (err < 0)
142 		return;
143 
144 	if (netdev_mc_count(ndev)) {
145 		err = aq_nic_set_multicast_list(aq_nic, ndev);
146 		if (err < 0)
147 			return;
148 	}
149 }
150 
151 static const struct net_device_ops aq_ndev_ops = {
152 	.ndo_open = aq_ndev_open,
153 	.ndo_stop = aq_ndev_close,
154 	.ndo_start_xmit = aq_ndev_start_xmit,
155 	.ndo_set_rx_mode = aq_ndev_set_multicast_settings,
156 	.ndo_change_mtu = aq_ndev_change_mtu,
157 	.ndo_set_mac_address = aq_ndev_set_mac_address,
158 	.ndo_set_features = aq_ndev_set_features
159 };
160