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
aq_ndev_alloc(void)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
aq_ndev_open(struct net_device * ndev)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
aq_ndev_close(struct net_device * ndev)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
aq_ndev_start_xmit(struct sk_buff * skb,struct net_device * ndev)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
aq_ndev_change_mtu(struct net_device * ndev,int new_mtu)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
aq_ndev_set_features(struct net_device * ndev,netdev_features_t features)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
aq_ndev_set_mac_address(struct net_device * ndev,void * addr)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
aq_ndev_set_multicast_settings(struct net_device * ndev)135 static void aq_ndev_set_multicast_settings(struct net_device *ndev)
136 {
137 struct aq_nic_s *aq_nic = netdev_priv(ndev);
138
139 aq_nic_set_packet_filter(aq_nic, ndev->flags);
140
141 aq_nic_set_multicast_list(aq_nic, ndev);
142 }
143
144 static const struct net_device_ops aq_ndev_ops = {
145 .ndo_open = aq_ndev_open,
146 .ndo_stop = aq_ndev_close,
147 .ndo_start_xmit = aq_ndev_start_xmit,
148 .ndo_set_rx_mode = aq_ndev_set_multicast_settings,
149 .ndo_change_mtu = aq_ndev_change_mtu,
150 .ndo_set_mac_address = aq_ndev_set_mac_address,
151 .ndo_set_features = aq_ndev_set_features
152 };
153