]>
Commit | Line | Data |
---|---|---|
97bde5c4 DV |
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 | #include "hw_atl/hw_atl_a0.h" | |
17 | #include "hw_atl/hw_atl_b0.h" | |
18 | ||
19 | #include <linux/netdevice.h> | |
20 | #include <linux/module.h> | |
21 | ||
22 | static const struct pci_device_id aq_pci_tbl[] = { | |
23 | { PCI_VDEVICE(AQUANTIA, HW_ATL_DEVICE_ID_0001), }, | |
24 | { PCI_VDEVICE(AQUANTIA, HW_ATL_DEVICE_ID_D100), }, | |
25 | { PCI_VDEVICE(AQUANTIA, HW_ATL_DEVICE_ID_D107), }, | |
26 | { PCI_VDEVICE(AQUANTIA, HW_ATL_DEVICE_ID_D108), }, | |
27 | { PCI_VDEVICE(AQUANTIA, HW_ATL_DEVICE_ID_D109), }, | |
28 | {} | |
29 | }; | |
30 | ||
31 | MODULE_DEVICE_TABLE(pci, aq_pci_tbl); | |
32 | ||
33 | MODULE_LICENSE("GPL v2"); | |
34 | MODULE_VERSION(AQ_CFG_DRV_VERSION); | |
35 | MODULE_AUTHOR(AQ_CFG_DRV_AUTHOR); | |
36 | MODULE_DESCRIPTION(AQ_CFG_DRV_DESC); | |
37 | ||
38 | static struct aq_hw_ops *aq_pci_probe_get_hw_ops_by_id(struct pci_dev *pdev) | |
39 | { | |
40 | struct aq_hw_ops *ops = NULL; | |
41 | ||
42 | ops = hw_atl_a0_get_ops_by_id(pdev); | |
43 | if (!ops) | |
44 | ops = hw_atl_b0_get_ops_by_id(pdev); | |
45 | ||
46 | return ops; | |
47 | } | |
48 | ||
49 | static int aq_ndev_open(struct net_device *ndev) | |
50 | { | |
51 | struct aq_nic_s *aq_nic = NULL; | |
52 | int err = 0; | |
53 | ||
54 | aq_nic = aq_nic_alloc_hot(ndev); | |
55 | if (!aq_nic) { | |
56 | err = -ENOMEM; | |
57 | goto err_exit; | |
58 | } | |
59 | err = aq_nic_init(aq_nic); | |
60 | if (err < 0) | |
61 | goto err_exit; | |
62 | err = aq_nic_start(aq_nic); | |
63 | if (err < 0) | |
64 | goto err_exit; | |
65 | ||
66 | err_exit: | |
67 | if (err < 0) | |
68 | aq_nic_deinit(aq_nic); | |
69 | return err; | |
70 | } | |
71 | ||
72 | static int aq_ndev_close(struct net_device *ndev) | |
73 | { | |
74 | int err = 0; | |
75 | struct aq_nic_s *aq_nic = netdev_priv(ndev); | |
76 | ||
77 | err = aq_nic_stop(aq_nic); | |
78 | if (err < 0) | |
79 | goto err_exit; | |
80 | aq_nic_deinit(aq_nic); | |
81 | aq_nic_free_hot_resources(aq_nic); | |
82 | ||
83 | err_exit: | |
84 | return err; | |
85 | } | |
86 | ||
87 | static int aq_ndev_start_xmit(struct sk_buff *skb, struct net_device *ndev) | |
88 | { | |
89 | struct aq_nic_s *aq_nic = netdev_priv(ndev); | |
97bde5c4 | 90 | |
362f37b2 | 91 | return aq_nic_xmit(aq_nic, skb); |
97bde5c4 DV |
92 | } |
93 | ||
94 | static int aq_ndev_change_mtu(struct net_device *ndev, int new_mtu) | |
95 | { | |
96 | struct aq_nic_s *aq_nic = netdev_priv(ndev); | |
5513e164 | 97 | int err = aq_nic_set_mtu(aq_nic, new_mtu + ETH_HLEN); |
97bde5c4 | 98 | |
97bde5c4 DV |
99 | if (err < 0) |
100 | goto err_exit; | |
bc9ab923 | 101 | ndev->mtu = new_mtu; |
97bde5c4 DV |
102 | |
103 | if (netif_running(ndev)) { | |
104 | aq_ndev_close(ndev); | |
105 | aq_ndev_open(ndev); | |
106 | } | |
107 | ||
108 | err_exit: | |
109 | return err; | |
110 | } | |
111 | ||
112 | static int aq_ndev_set_features(struct net_device *ndev, | |
113 | netdev_features_t features) | |
114 | { | |
115 | struct aq_nic_s *aq_nic = netdev_priv(ndev); | |
116 | struct aq_nic_cfg_s *aq_cfg = aq_nic_get_cfg(aq_nic); | |
117 | bool is_lro = false; | |
118 | ||
119 | if (aq_cfg->hw_features & NETIF_F_LRO) { | |
120 | is_lro = features & NETIF_F_LRO; | |
121 | ||
122 | if (aq_cfg->is_lro != is_lro) { | |
123 | aq_cfg->is_lro = is_lro; | |
124 | ||
125 | if (netif_running(ndev)) { | |
126 | aq_ndev_close(ndev); | |
127 | aq_ndev_open(ndev); | |
128 | } | |
129 | } | |
130 | } | |
131 | ||
132 | return 0; | |
133 | } | |
134 | ||
135 | static int aq_ndev_set_mac_address(struct net_device *ndev, void *addr) | |
136 | { | |
137 | struct aq_nic_s *aq_nic = netdev_priv(ndev); | |
138 | int err = 0; | |
139 | ||
140 | err = eth_mac_addr(ndev, addr); | |
141 | if (err < 0) | |
142 | goto err_exit; | |
143 | err = aq_nic_set_mac(aq_nic, ndev); | |
144 | if (err < 0) | |
145 | goto err_exit; | |
146 | ||
147 | err_exit: | |
148 | return err; | |
149 | } | |
150 | ||
151 | static void aq_ndev_set_multicast_settings(struct net_device *ndev) | |
152 | { | |
153 | struct aq_nic_s *aq_nic = netdev_priv(ndev); | |
154 | int err = 0; | |
155 | ||
156 | err = aq_nic_set_packet_filter(aq_nic, ndev->flags); | |
157 | if (err < 0) | |
158 | goto err_exit; | |
159 | ||
160 | if (netdev_mc_count(ndev)) { | |
161 | err = aq_nic_set_multicast_list(aq_nic, ndev); | |
162 | if (err < 0) | |
163 | goto err_exit; | |
164 | } | |
165 | ||
166 | err_exit:; | |
167 | } | |
168 | ||
169 | static const struct net_device_ops aq_ndev_ops = { | |
170 | .ndo_open = aq_ndev_open, | |
171 | .ndo_stop = aq_ndev_close, | |
172 | .ndo_start_xmit = aq_ndev_start_xmit, | |
173 | .ndo_set_rx_mode = aq_ndev_set_multicast_settings, | |
174 | .ndo_change_mtu = aq_ndev_change_mtu, | |
175 | .ndo_set_mac_address = aq_ndev_set_mac_address, | |
176 | .ndo_set_features = aq_ndev_set_features | |
177 | }; | |
178 | ||
179 | static int aq_pci_probe(struct pci_dev *pdev, | |
180 | const struct pci_device_id *pci_id) | |
181 | { | |
182 | struct aq_hw_ops *aq_hw_ops = NULL; | |
183 | struct aq_pci_func_s *aq_pci_func = NULL; | |
184 | int err = 0; | |
185 | ||
186 | err = pci_enable_device(pdev); | |
187 | if (err < 0) | |
188 | goto err_exit; | |
189 | aq_hw_ops = aq_pci_probe_get_hw_ops_by_id(pdev); | |
190 | aq_pci_func = aq_pci_func_alloc(aq_hw_ops, pdev, | |
191 | &aq_ndev_ops, &aq_ethtool_ops); | |
192 | if (!aq_pci_func) { | |
193 | err = -ENOMEM; | |
194 | goto err_exit; | |
195 | } | |
196 | err = aq_pci_func_init(aq_pci_func); | |
197 | if (err < 0) | |
198 | goto err_exit; | |
199 | ||
200 | err_exit: | |
201 | if (err < 0) { | |
202 | if (aq_pci_func) | |
203 | aq_pci_func_free(aq_pci_func); | |
204 | } | |
205 | return err; | |
206 | } | |
207 | ||
208 | static void aq_pci_remove(struct pci_dev *pdev) | |
209 | { | |
210 | struct aq_pci_func_s *aq_pci_func = pci_get_drvdata(pdev); | |
211 | ||
212 | aq_pci_func_deinit(aq_pci_func); | |
213 | aq_pci_func_free(aq_pci_func); | |
214 | } | |
215 | ||
216 | static int aq_pci_suspend(struct pci_dev *pdev, pm_message_t pm_msg) | |
217 | { | |
218 | struct aq_pci_func_s *aq_pci_func = pci_get_drvdata(pdev); | |
219 | ||
220 | return aq_pci_func_change_pm_state(aq_pci_func, &pm_msg); | |
221 | } | |
222 | ||
223 | static int aq_pci_resume(struct pci_dev *pdev) | |
224 | { | |
225 | struct aq_pci_func_s *aq_pci_func = pci_get_drvdata(pdev); | |
226 | pm_message_t pm_msg = PMSG_RESTORE; | |
227 | ||
228 | return aq_pci_func_change_pm_state(aq_pci_func, &pm_msg); | |
229 | } | |
230 | ||
231 | static struct pci_driver aq_pci_ops = { | |
232 | .name = AQ_CFG_DRV_NAME, | |
233 | .id_table = aq_pci_tbl, | |
234 | .probe = aq_pci_probe, | |
235 | .remove = aq_pci_remove, | |
236 | .suspend = aq_pci_suspend, | |
237 | .resume = aq_pci_resume, | |
238 | }; | |
239 | ||
14861e9d | 240 | module_pci_driver(aq_pci_ops); |