175a6faf6SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
24378b882SIgor Russkikh /* Atlantic Network Driver
34378b882SIgor Russkikh *
44378b882SIgor Russkikh * Copyright (C) 2014-2019 aQuantia Corporation
54378b882SIgor Russkikh * Copyright (C) 2019-2020 Marvell International Ltd.
697bde5c4SDavid VomLehn */
797bde5c4SDavid VomLehn
897bde5c4SDavid VomLehn /* File aq_main.c: Main file for aQuantia Linux driver. */
997bde5c4SDavid VomLehn
1097bde5c4SDavid VomLehn #include "aq_main.h"
1197bde5c4SDavid VomLehn #include "aq_nic.h"
1297bde5c4SDavid VomLehn #include "aq_pci_func.h"
1397bde5c4SDavid VomLehn #include "aq_ethtool.h"
1404a18399SEgor Pomozov #include "aq_ptp.h"
158d0bcb01SDmitry Bogdanov #include "aq_filters.h"
16a83fe6b6SDmitry Bezrukov #include "aq_hw_utils.h"
170d14657fSTaehee Yoo #include "aq_vec.h"
1897bde5c4SDavid VomLehn
1997bde5c4SDavid VomLehn #include <linux/netdevice.h>
2097bde5c4SDavid VomLehn #include <linux/module.h>
2104a18399SEgor Pomozov #include <linux/ip.h>
2204a18399SEgor Pomozov #include <linux/udp.h>
23a83fe6b6SDmitry Bezrukov #include <net/pkt_cls.h>
24*9adafe2bSVladimir Oltean #include <net/pkt_sched.h>
250d14657fSTaehee Yoo #include <linux/filter.h>
2697bde5c4SDavid VomLehn
2797bde5c4SDavid VomLehn MODULE_LICENSE("GPL v2");
2897bde5c4SDavid VomLehn MODULE_AUTHOR(AQ_CFG_DRV_AUTHOR);
2997bde5c4SDavid VomLehn MODULE_DESCRIPTION(AQ_CFG_DRV_DESC);
3097bde5c4SDavid VomLehn
310d14657fSTaehee Yoo DEFINE_STATIC_KEY_FALSE(aq_xdp_locking_key);
320d14657fSTaehee Yoo EXPORT_SYMBOL(aq_xdp_locking_key);
330d14657fSTaehee Yoo
3444bec4b3SYueHaibing static const char aq_ndev_driver_name[] = AQ_CFG_DRV_NAME;
3558608082SNikita Danilov
365b97b0d1SIgor Russkikh static const struct net_device_ops aq_ndev_ops;
375b97b0d1SIgor Russkikh
3858608082SNikita Danilov static struct workqueue_struct *aq_ndev_wq;
3958608082SNikita Danilov
aq_ndev_schedule_work(struct work_struct * work)4058608082SNikita Danilov void aq_ndev_schedule_work(struct work_struct *work)
4158608082SNikita Danilov {
4258608082SNikita Danilov queue_work(aq_ndev_wq, work);
4358608082SNikita Danilov }
4458608082SNikita Danilov
aq_ndev_alloc(void)455b97b0d1SIgor Russkikh struct net_device *aq_ndev_alloc(void)
4697bde5c4SDavid VomLehn {
475b97b0d1SIgor Russkikh struct net_device *ndev = NULL;
485b97b0d1SIgor Russkikh struct aq_nic_s *aq_nic = NULL;
4997bde5c4SDavid VomLehn
50a83fe6b6SDmitry Bezrukov ndev = alloc_etherdev_mq(sizeof(struct aq_nic_s), AQ_HW_QUEUES_MAX);
515b97b0d1SIgor Russkikh if (!ndev)
525b97b0d1SIgor Russkikh return NULL;
5397bde5c4SDavid VomLehn
545b97b0d1SIgor Russkikh aq_nic = netdev_priv(ndev);
555b97b0d1SIgor Russkikh aq_nic->ndev = ndev;
565b97b0d1SIgor Russkikh ndev->netdev_ops = &aq_ndev_ops;
575b97b0d1SIgor Russkikh ndev->ethtool_ops = &aq_ethtool_ops;
585b97b0d1SIgor Russkikh
595b97b0d1SIgor Russkikh return ndev;
6097bde5c4SDavid VomLehn }
6197bde5c4SDavid VomLehn
aq_ndev_open(struct net_device * ndev)622a838911SIzabela Bakollari int aq_ndev_open(struct net_device *ndev)
6397bde5c4SDavid VomLehn {
6423ee07adSIgor Russkikh struct aq_nic_s *aq_nic = netdev_priv(ndev);
657b0c342fSNikita Danilov int err = 0;
6697bde5c4SDavid VomLehn
6797bde5c4SDavid VomLehn err = aq_nic_init(aq_nic);
6897bde5c4SDavid VomLehn if (err < 0)
6997bde5c4SDavid VomLehn goto err_exit;
708d0bcb01SDmitry Bogdanov
718d0bcb01SDmitry Bogdanov err = aq_reapply_rxnfc_all_rules(aq_nic);
728d0bcb01SDmitry Bogdanov if (err < 0)
738d0bcb01SDmitry Bogdanov goto err_exit;
748d0bcb01SDmitry Bogdanov
75c2ef057eSDmitry Bogdanov err = aq_filters_vlans_update(aq_nic);
76c2ef057eSDmitry Bogdanov if (err < 0)
77c2ef057eSDmitry Bogdanov goto err_exit;
78c2ef057eSDmitry Bogdanov
7997bde5c4SDavid VomLehn err = aq_nic_start(aq_nic);
808a28af7aSNathan Rossi if (err < 0) {
818a28af7aSNathan Rossi aq_nic_stop(aq_nic);
8297bde5c4SDavid VomLehn goto err_exit;
838a28af7aSNathan Rossi }
8497bde5c4SDavid VomLehn
8597bde5c4SDavid VomLehn err_exit:
8697bde5c4SDavid VomLehn if (err < 0)
87837c6378SNikita Danilov aq_nic_deinit(aq_nic, true);
887b0c342fSNikita Danilov
8997bde5c4SDavid VomLehn return err;
9097bde5c4SDavid VomLehn }
9197bde5c4SDavid VomLehn
aq_ndev_close(struct net_device * ndev)922a838911SIzabela Bakollari int aq_ndev_close(struct net_device *ndev)
9397bde5c4SDavid VomLehn {
9497bde5c4SDavid VomLehn struct aq_nic_s *aq_nic = netdev_priv(ndev);
957b0c342fSNikita Danilov int err = 0;
9697bde5c4SDavid VomLehn
9797bde5c4SDavid VomLehn err = aq_nic_stop(aq_nic);
98837c6378SNikita Danilov aq_nic_deinit(aq_nic, true);
9997bde5c4SDavid VomLehn
10097bde5c4SDavid VomLehn return err;
10197bde5c4SDavid VomLehn }
10297bde5c4SDavid VomLehn
aq_ndev_start_xmit(struct sk_buff * skb,struct net_device * ndev)10392c5e115SLuc Van Oostenryck static netdev_tx_t aq_ndev_start_xmit(struct sk_buff *skb, struct net_device *ndev)
10497bde5c4SDavid VomLehn {
10597bde5c4SDavid VomLehn struct aq_nic_s *aq_nic = netdev_priv(ndev);
10697bde5c4SDavid VomLehn
1074378b882SIgor Russkikh #if IS_REACHABLE(CONFIG_PTP_1588_CLOCK)
10804a18399SEgor Pomozov if (unlikely(aq_utils_obj_test(&aq_nic->flags, AQ_NIC_PTP_DPATH_UP))) {
10904a18399SEgor Pomozov /* Hardware adds the Timestamp for PTPv2 802.AS1
11004a18399SEgor Pomozov * and PTPv2 IPv4 UDP.
11104a18399SEgor Pomozov * We have to push even general 320 port messages to the ptp
11204a18399SEgor Pomozov * queue explicitly. This is a limitation of current firmware
11304a18399SEgor Pomozov * and hardware PTP design of the chip. Otherwise ptp stream
11404a18399SEgor Pomozov * will fail to sync
11504a18399SEgor Pomozov */
11604a18399SEgor Pomozov if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) ||
11704a18399SEgor Pomozov unlikely((ip_hdr(skb)->version == 4) &&
11804a18399SEgor Pomozov (ip_hdr(skb)->protocol == IPPROTO_UDP) &&
11904a18399SEgor Pomozov ((udp_hdr(skb)->dest == htons(319)) ||
12004a18399SEgor Pomozov (udp_hdr(skb)->dest == htons(320)))) ||
12104a18399SEgor Pomozov unlikely(eth_hdr(skb)->h_proto == htons(ETH_P_1588)))
12204a18399SEgor Pomozov return aq_ptp_xmit(aq_nic, skb);
12304a18399SEgor Pomozov }
1244378b882SIgor Russkikh #endif
12504a18399SEgor Pomozov
12604a18399SEgor Pomozov skb_tx_timestamp(skb);
127362f37b2SPavel Belous return aq_nic_xmit(aq_nic, skb);
12897bde5c4SDavid VomLehn }
12997bde5c4SDavid VomLehn
aq_ndev_change_mtu(struct net_device * ndev,int new_mtu)13097bde5c4SDavid VomLehn static int aq_ndev_change_mtu(struct net_device *ndev, int new_mtu)
13197bde5c4SDavid VomLehn {
1320d14657fSTaehee Yoo int new_frame_size = new_mtu + ETH_HLEN + ETH_FCS_LEN;
13397bde5c4SDavid VomLehn struct aq_nic_s *aq_nic = netdev_priv(ndev);
1340d14657fSTaehee Yoo struct bpf_prog *prog;
1357b0c342fSNikita Danilov int err;
1367b0c342fSNikita Danilov
1370d14657fSTaehee Yoo prog = READ_ONCE(aq_nic->xdp_prog);
1380d14657fSTaehee Yoo if (prog && !prog->aux->xdp_has_frags &&
1390d14657fSTaehee Yoo new_frame_size > AQ_CFG_RX_FRAME_MAX) {
1400d14657fSTaehee Yoo netdev_err(ndev, "Illegal MTU %d for XDP prog without frags\n",
1410d14657fSTaehee Yoo ndev->mtu);
1420d14657fSTaehee Yoo return -EOPNOTSUPP;
1430d14657fSTaehee Yoo }
1440d14657fSTaehee Yoo
1457b0c342fSNikita Danilov err = aq_nic_set_mtu(aq_nic, new_mtu + ETH_HLEN);
14697bde5c4SDavid VomLehn
14797bde5c4SDavid VomLehn if (err < 0)
14897bde5c4SDavid VomLehn goto err_exit;
149bc9ab923SDavid Arcari ndev->mtu = new_mtu;
15097bde5c4SDavid VomLehn
15197bde5c4SDavid VomLehn err_exit:
15297bde5c4SDavid VomLehn return err;
15397bde5c4SDavid VomLehn }
15497bde5c4SDavid VomLehn
aq_ndev_set_features(struct net_device * ndev,netdev_features_t features)15597bde5c4SDavid VomLehn static int aq_ndev_set_features(struct net_device *ndev,
15697bde5c4SDavid VomLehn netdev_features_t features)
15797bde5c4SDavid VomLehn {
15804f207fbSIgor Russkikh bool is_vlan_tx_insert = !!(features & NETIF_F_HW_VLAN_CTAG_TX);
1597b0c342fSNikita Danilov bool is_vlan_rx_strip = !!(features & NETIF_F_HW_VLAN_CTAG_RX);
16097bde5c4SDavid VomLehn struct aq_nic_s *aq_nic = netdev_priv(ndev);
16104f207fbSIgor Russkikh bool need_ndev_restart = false;
16204f207fbSIgor Russkikh struct aq_nic_cfg_s *aq_cfg;
16397bde5c4SDavid VomLehn bool is_lro = false;
164bbb67a44SDmitry Bogdanov int err = 0;
16597bde5c4SDavid VomLehn
16604f207fbSIgor Russkikh aq_cfg = aq_nic_get_cfg(aq_nic);
16704f207fbSIgor Russkikh
1688d0bcb01SDmitry Bogdanov if (!(features & NETIF_F_NTUPLE)) {
1698d0bcb01SDmitry Bogdanov if (aq_nic->ndev->features & NETIF_F_NTUPLE) {
1708d0bcb01SDmitry Bogdanov err = aq_clear_rxnfc_all_rules(aq_nic);
1718d0bcb01SDmitry Bogdanov if (unlikely(err))
1728d0bcb01SDmitry Bogdanov goto err_exit;
1738d0bcb01SDmitry Bogdanov }
1748d0bcb01SDmitry Bogdanov }
1757975d2afSDmitry Bogdanov if (!(features & NETIF_F_HW_VLAN_CTAG_FILTER)) {
1767975d2afSDmitry Bogdanov if (aq_nic->ndev->features & NETIF_F_HW_VLAN_CTAG_FILTER) {
1777975d2afSDmitry Bogdanov err = aq_filters_vlan_offload_off(aq_nic);
1787975d2afSDmitry Bogdanov if (unlikely(err))
1797975d2afSDmitry Bogdanov goto err_exit;
1807975d2afSDmitry Bogdanov }
1817975d2afSDmitry Bogdanov }
1828d0bcb01SDmitry Bogdanov
183bbb67a44SDmitry Bogdanov aq_cfg->features = features;
184bbb67a44SDmitry Bogdanov
185bbb67a44SDmitry Bogdanov if (aq_cfg->aq_hw_caps->hw_features & NETIF_F_LRO) {
18697bde5c4SDavid VomLehn is_lro = features & NETIF_F_LRO;
18797bde5c4SDavid VomLehn
18897bde5c4SDavid VomLehn if (aq_cfg->is_lro != is_lro) {
18997bde5c4SDavid VomLehn aq_cfg->is_lro = is_lro;
19004f207fbSIgor Russkikh need_ndev_restart = true;
19104f207fbSIgor Russkikh }
19204f207fbSIgor Russkikh }
19397bde5c4SDavid VomLehn
19404f207fbSIgor Russkikh if ((aq_nic->ndev->features ^ features) & NETIF_F_RXCSUM) {
19504f207fbSIgor Russkikh err = aq_nic->aq_hw_ops->hw_set_offload(aq_nic->aq_hw,
19604f207fbSIgor Russkikh aq_cfg);
19704f207fbSIgor Russkikh
19804f207fbSIgor Russkikh if (unlikely(err))
19904f207fbSIgor Russkikh goto err_exit;
20004f207fbSIgor Russkikh }
20104f207fbSIgor Russkikh
20204f207fbSIgor Russkikh if (aq_cfg->is_vlan_rx_strip != is_vlan_rx_strip) {
20304f207fbSIgor Russkikh aq_cfg->is_vlan_rx_strip = is_vlan_rx_strip;
20404f207fbSIgor Russkikh need_ndev_restart = true;
20504f207fbSIgor Russkikh }
20604f207fbSIgor Russkikh if (aq_cfg->is_vlan_tx_insert != is_vlan_tx_insert) {
20704f207fbSIgor Russkikh aq_cfg->is_vlan_tx_insert = is_vlan_tx_insert;
20804f207fbSIgor Russkikh need_ndev_restart = true;
20904f207fbSIgor Russkikh }
21004f207fbSIgor Russkikh
21104f207fbSIgor Russkikh if (need_ndev_restart && netif_running(ndev)) {
21297bde5c4SDavid VomLehn aq_ndev_close(ndev);
21397bde5c4SDavid VomLehn aq_ndev_open(ndev);
21497bde5c4SDavid VomLehn }
21597bde5c4SDavid VomLehn
2168d0bcb01SDmitry Bogdanov err_exit:
217bbb67a44SDmitry Bogdanov return err;
21897bde5c4SDavid VomLehn }
21997bde5c4SDavid VomLehn
aq_ndev_fix_features(struct net_device * ndev,netdev_features_t features)2200d14657fSTaehee Yoo static netdev_features_t aq_ndev_fix_features(struct net_device *ndev,
2210d14657fSTaehee Yoo netdev_features_t features)
2220d14657fSTaehee Yoo {
2230d14657fSTaehee Yoo struct aq_nic_s *aq_nic = netdev_priv(ndev);
2240d14657fSTaehee Yoo struct bpf_prog *prog;
2250d14657fSTaehee Yoo
2260d14657fSTaehee Yoo if (!(features & NETIF_F_RXCSUM))
2270d14657fSTaehee Yoo features &= ~NETIF_F_LRO;
2280d14657fSTaehee Yoo
2290d14657fSTaehee Yoo prog = READ_ONCE(aq_nic->xdp_prog);
2300d14657fSTaehee Yoo if (prog && !prog->aux->xdp_has_frags &&
2310d14657fSTaehee Yoo aq_nic->xdp_prog && features & NETIF_F_LRO) {
2320d14657fSTaehee Yoo netdev_err(ndev, "LRO is not supported with single buffer XDP, disabling\n");
2330d14657fSTaehee Yoo features &= ~NETIF_F_LRO;
2340d14657fSTaehee Yoo }
2350d14657fSTaehee Yoo
2360d14657fSTaehee Yoo return features;
2370d14657fSTaehee Yoo }
2380d14657fSTaehee Yoo
aq_ndev_set_mac_address(struct net_device * ndev,void * addr)23997bde5c4SDavid VomLehn static int aq_ndev_set_mac_address(struct net_device *ndev, void *addr)
24097bde5c4SDavid VomLehn {
24197bde5c4SDavid VomLehn struct aq_nic_s *aq_nic = netdev_priv(ndev);
24297bde5c4SDavid VomLehn int err = 0;
24397bde5c4SDavid VomLehn
24497bde5c4SDavid VomLehn err = eth_mac_addr(ndev, addr);
24597bde5c4SDavid VomLehn if (err < 0)
24697bde5c4SDavid VomLehn goto err_exit;
24797bde5c4SDavid VomLehn err = aq_nic_set_mac(aq_nic, ndev);
24897bde5c4SDavid VomLehn if (err < 0)
24997bde5c4SDavid VomLehn goto err_exit;
25097bde5c4SDavid VomLehn
25197bde5c4SDavid VomLehn err_exit:
25297bde5c4SDavid VomLehn return err;
25397bde5c4SDavid VomLehn }
25497bde5c4SDavid VomLehn
aq_ndev_set_multicast_settings(struct net_device * ndev)25597bde5c4SDavid VomLehn static void aq_ndev_set_multicast_settings(struct net_device *ndev)
25697bde5c4SDavid VomLehn {
25797bde5c4SDavid VomLehn struct aq_nic_s *aq_nic = netdev_priv(ndev);
25897bde5c4SDavid VomLehn
2599f051db5SDmitry Bogdanov (void)aq_nic_set_multicast_list(aq_nic, ndev);
26097bde5c4SDavid VomLehn }
26197bde5c4SDavid VomLehn
2624378b882SIgor Russkikh #if IS_REACHABLE(CONFIG_PTP_1588_CLOCK)
aq_ndev_config_hwtstamp(struct aq_nic_s * aq_nic,struct hwtstamp_config * config)2637db3d07aSEgor Pomozov static int aq_ndev_config_hwtstamp(struct aq_nic_s *aq_nic,
2647db3d07aSEgor Pomozov struct hwtstamp_config *config)
2657db3d07aSEgor Pomozov {
2667db3d07aSEgor Pomozov switch (config->tx_type) {
2677db3d07aSEgor Pomozov case HWTSTAMP_TX_OFF:
2687db3d07aSEgor Pomozov case HWTSTAMP_TX_ON:
2697db3d07aSEgor Pomozov break;
2707db3d07aSEgor Pomozov default:
2717db3d07aSEgor Pomozov return -ERANGE;
2727db3d07aSEgor Pomozov }
2737db3d07aSEgor Pomozov
2747db3d07aSEgor Pomozov switch (config->rx_filter) {
2757db3d07aSEgor Pomozov case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
2767db3d07aSEgor Pomozov case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
2777db3d07aSEgor Pomozov case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
2787db3d07aSEgor Pomozov case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
2797db3d07aSEgor Pomozov case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
2807db3d07aSEgor Pomozov case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
2817db3d07aSEgor Pomozov case HWTSTAMP_FILTER_PTP_V2_SYNC:
2827db3d07aSEgor Pomozov case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
2837db3d07aSEgor Pomozov config->rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
2847db3d07aSEgor Pomozov break;
2857db3d07aSEgor Pomozov case HWTSTAMP_FILTER_PTP_V2_EVENT:
2867db3d07aSEgor Pomozov case HWTSTAMP_FILTER_NONE:
2877db3d07aSEgor Pomozov break;
2887db3d07aSEgor Pomozov default:
2897db3d07aSEgor Pomozov return -ERANGE;
2907db3d07aSEgor Pomozov }
2917db3d07aSEgor Pomozov
2927db3d07aSEgor Pomozov return aq_ptp_hwtstamp_config_set(aq_nic->aq_ptp, config);
2937db3d07aSEgor Pomozov }
2944378b882SIgor Russkikh #endif
2957db3d07aSEgor Pomozov
aq_ndev_hwtstamp_set(struct aq_nic_s * aq_nic,struct ifreq * ifr)2967db3d07aSEgor Pomozov static int aq_ndev_hwtstamp_set(struct aq_nic_s *aq_nic, struct ifreq *ifr)
2977db3d07aSEgor Pomozov {
2987db3d07aSEgor Pomozov struct hwtstamp_config config;
2994378b882SIgor Russkikh #if IS_REACHABLE(CONFIG_PTP_1588_CLOCK)
3007db3d07aSEgor Pomozov int ret_val;
3014378b882SIgor Russkikh #endif
3027db3d07aSEgor Pomozov
3037db3d07aSEgor Pomozov if (!aq_nic->aq_ptp)
3047db3d07aSEgor Pomozov return -EOPNOTSUPP;
3057db3d07aSEgor Pomozov
3067db3d07aSEgor Pomozov if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
3077db3d07aSEgor Pomozov return -EFAULT;
3084378b882SIgor Russkikh #if IS_REACHABLE(CONFIG_PTP_1588_CLOCK)
3097db3d07aSEgor Pomozov ret_val = aq_ndev_config_hwtstamp(aq_nic, &config);
3107db3d07aSEgor Pomozov if (ret_val)
3117db3d07aSEgor Pomozov return ret_val;
3124378b882SIgor Russkikh #endif
3137db3d07aSEgor Pomozov
3147db3d07aSEgor Pomozov return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ?
3157db3d07aSEgor Pomozov -EFAULT : 0;
3167db3d07aSEgor Pomozov }
3177db3d07aSEgor Pomozov
3184378b882SIgor Russkikh #if IS_REACHABLE(CONFIG_PTP_1588_CLOCK)
aq_ndev_hwtstamp_get(struct aq_nic_s * aq_nic,struct ifreq * ifr)3197db3d07aSEgor Pomozov static int aq_ndev_hwtstamp_get(struct aq_nic_s *aq_nic, struct ifreq *ifr)
3207db3d07aSEgor Pomozov {
3217db3d07aSEgor Pomozov struct hwtstamp_config config;
3227db3d07aSEgor Pomozov
3237db3d07aSEgor Pomozov if (!aq_nic->aq_ptp)
3247db3d07aSEgor Pomozov return -EOPNOTSUPP;
3257db3d07aSEgor Pomozov
3267db3d07aSEgor Pomozov aq_ptp_hwtstamp_config_get(aq_nic->aq_ptp, &config);
3277db3d07aSEgor Pomozov return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ?
3287db3d07aSEgor Pomozov -EFAULT : 0;
3297db3d07aSEgor Pomozov }
3304378b882SIgor Russkikh #endif
3317db3d07aSEgor Pomozov
aq_ndev_ioctl(struct net_device * netdev,struct ifreq * ifr,int cmd)3327db3d07aSEgor Pomozov static int aq_ndev_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
3337db3d07aSEgor Pomozov {
3347db3d07aSEgor Pomozov struct aq_nic_s *aq_nic = netdev_priv(netdev);
3357db3d07aSEgor Pomozov
3367db3d07aSEgor Pomozov switch (cmd) {
3377db3d07aSEgor Pomozov case SIOCSHWTSTAMP:
3387db3d07aSEgor Pomozov return aq_ndev_hwtstamp_set(aq_nic, ifr);
3397db3d07aSEgor Pomozov
3404378b882SIgor Russkikh #if IS_REACHABLE(CONFIG_PTP_1588_CLOCK)
3417db3d07aSEgor Pomozov case SIOCGHWTSTAMP:
3427db3d07aSEgor Pomozov return aq_ndev_hwtstamp_get(aq_nic, ifr);
3434378b882SIgor Russkikh #endif
3447db3d07aSEgor Pomozov }
3457db3d07aSEgor Pomozov
3467db3d07aSEgor Pomozov return -EOPNOTSUPP;
3477db3d07aSEgor Pomozov }
3487db3d07aSEgor Pomozov
aq_ndo_vlan_rx_add_vid(struct net_device * ndev,__be16 proto,u16 vid)3497975d2afSDmitry Bogdanov static int aq_ndo_vlan_rx_add_vid(struct net_device *ndev, __be16 proto,
3507975d2afSDmitry Bogdanov u16 vid)
3517975d2afSDmitry Bogdanov {
3527975d2afSDmitry Bogdanov struct aq_nic_s *aq_nic = netdev_priv(ndev);
3537975d2afSDmitry Bogdanov
3547975d2afSDmitry Bogdanov if (!aq_nic->aq_hw_ops->hw_filter_vlan_set)
3557975d2afSDmitry Bogdanov return -EOPNOTSUPP;
3567975d2afSDmitry Bogdanov
3577975d2afSDmitry Bogdanov set_bit(vid, aq_nic->active_vlans);
3587975d2afSDmitry Bogdanov
3597975d2afSDmitry Bogdanov return aq_filters_vlans_update(aq_nic);
3607975d2afSDmitry Bogdanov }
3617975d2afSDmitry Bogdanov
aq_ndo_vlan_rx_kill_vid(struct net_device * ndev,__be16 proto,u16 vid)3627975d2afSDmitry Bogdanov static int aq_ndo_vlan_rx_kill_vid(struct net_device *ndev, __be16 proto,
3637975d2afSDmitry Bogdanov u16 vid)
3647975d2afSDmitry Bogdanov {
3657975d2afSDmitry Bogdanov struct aq_nic_s *aq_nic = netdev_priv(ndev);
3667975d2afSDmitry Bogdanov
3677975d2afSDmitry Bogdanov if (!aq_nic->aq_hw_ops->hw_filter_vlan_set)
3687975d2afSDmitry Bogdanov return -EOPNOTSUPP;
3697975d2afSDmitry Bogdanov
3707975d2afSDmitry Bogdanov clear_bit(vid, aq_nic->active_vlans);
3717975d2afSDmitry Bogdanov
3727975d2afSDmitry Bogdanov if (-ENOENT == aq_del_fvlan_by_vlan(aq_nic, vid))
3737975d2afSDmitry Bogdanov return aq_filters_vlans_update(aq_nic);
3747975d2afSDmitry Bogdanov
3757975d2afSDmitry Bogdanov return 0;
3767975d2afSDmitry Bogdanov }
3777975d2afSDmitry Bogdanov
aq_validate_mqprio_opt(struct aq_nic_s * self,struct tc_mqprio_qopt_offload * mqprio,const unsigned int num_tc)378a83fe6b6SDmitry Bezrukov static int aq_validate_mqprio_opt(struct aq_nic_s *self,
3797327699fSMark Starovoytov struct tc_mqprio_qopt_offload *mqprio,
380a83fe6b6SDmitry Bezrukov const unsigned int num_tc)
381a83fe6b6SDmitry Bezrukov {
3827327699fSMark Starovoytov const bool has_min_rate = !!(mqprio->flags & TC_MQPRIO_F_MIN_RATE);
38314ef766bSMark Starovoytov struct aq_nic_cfg_s *aq_nic_cfg = aq_nic_get_cfg(self);
38414ef766bSMark Starovoytov const unsigned int tcs_max = min_t(u8, aq_nic_cfg->aq_hw_caps->tcs_max,
38514ef766bSMark Starovoytov AQ_CFG_TCS_MAX);
3867327699fSMark Starovoytov
38714ef766bSMark Starovoytov if (num_tc > tcs_max) {
388a83fe6b6SDmitry Bezrukov netdev_err(self->ndev, "Too many TCs requested\n");
389a83fe6b6SDmitry Bezrukov return -EOPNOTSUPP;
390a83fe6b6SDmitry Bezrukov }
391a83fe6b6SDmitry Bezrukov
392a83fe6b6SDmitry Bezrukov if (num_tc != 0 && !is_power_of_2(num_tc)) {
393a83fe6b6SDmitry Bezrukov netdev_err(self->ndev, "TC count should be power of 2\n");
394a83fe6b6SDmitry Bezrukov return -EOPNOTSUPP;
395a83fe6b6SDmitry Bezrukov }
396a83fe6b6SDmitry Bezrukov
3972deac71aSMark Starovoytov if (has_min_rate && !ATL_HW_IS_CHIP_FEATURE(self->aq_hw, ANTIGUA)) {
3982deac71aSMark Starovoytov netdev_err(self->ndev, "Min tx rate is not supported\n");
3997327699fSMark Starovoytov return -EOPNOTSUPP;
4007327699fSMark Starovoytov }
4017327699fSMark Starovoytov
402a83fe6b6SDmitry Bezrukov return 0;
403a83fe6b6SDmitry Bezrukov }
404a83fe6b6SDmitry Bezrukov
aq_ndo_setup_tc(struct net_device * dev,enum tc_setup_type type,void * type_data)405a83fe6b6SDmitry Bezrukov static int aq_ndo_setup_tc(struct net_device *dev, enum tc_setup_type type,
406a83fe6b6SDmitry Bezrukov void *type_data)
407a83fe6b6SDmitry Bezrukov {
4087327699fSMark Starovoytov struct tc_mqprio_qopt_offload *mqprio = type_data;
409a83fe6b6SDmitry Bezrukov struct aq_nic_s *aq_nic = netdev_priv(dev);
4102deac71aSMark Starovoytov bool has_min_rate;
4112deac71aSMark Starovoytov bool has_max_rate;
412a83fe6b6SDmitry Bezrukov int err;
4137327699fSMark Starovoytov int i;
414a83fe6b6SDmitry Bezrukov
415a83fe6b6SDmitry Bezrukov if (type != TC_SETUP_QDISC_MQPRIO)
416a83fe6b6SDmitry Bezrukov return -EOPNOTSUPP;
417a83fe6b6SDmitry Bezrukov
4182deac71aSMark Starovoytov has_min_rate = !!(mqprio->flags & TC_MQPRIO_F_MIN_RATE);
4192deac71aSMark Starovoytov has_max_rate = !!(mqprio->flags & TC_MQPRIO_F_MAX_RATE);
4202deac71aSMark Starovoytov
4217327699fSMark Starovoytov err = aq_validate_mqprio_opt(aq_nic, mqprio, mqprio->qopt.num_tc);
422a83fe6b6SDmitry Bezrukov if (err)
423a83fe6b6SDmitry Bezrukov return err;
424a83fe6b6SDmitry Bezrukov
4257327699fSMark Starovoytov for (i = 0; i < mqprio->qopt.num_tc; i++) {
4262deac71aSMark Starovoytov if (has_max_rate) {
4277327699fSMark Starovoytov u64 max_rate = mqprio->max_rate[i];
4287327699fSMark Starovoytov
4297327699fSMark Starovoytov do_div(max_rate, AQ_MBPS_DIVISOR);
4307327699fSMark Starovoytov aq_nic_setup_tc_max_rate(aq_nic, i, (u32)max_rate);
4317327699fSMark Starovoytov }
4322deac71aSMark Starovoytov
4332deac71aSMark Starovoytov if (has_min_rate) {
4342deac71aSMark Starovoytov u64 min_rate = mqprio->min_rate[i];
4352deac71aSMark Starovoytov
4362deac71aSMark Starovoytov do_div(min_rate, AQ_MBPS_DIVISOR);
4372deac71aSMark Starovoytov aq_nic_setup_tc_min_rate(aq_nic, i, (u32)min_rate);
4382deac71aSMark Starovoytov }
4397327699fSMark Starovoytov }
4407327699fSMark Starovoytov
4417327699fSMark Starovoytov return aq_nic_setup_tc_mqprio(aq_nic, mqprio->qopt.num_tc,
4427327699fSMark Starovoytov mqprio->qopt.prio_tc_map);
443a83fe6b6SDmitry Bezrukov }
444a83fe6b6SDmitry Bezrukov
aq_xdp_setup(struct net_device * ndev,struct bpf_prog * prog,struct netlink_ext_ack * extack)4450d14657fSTaehee Yoo static int aq_xdp_setup(struct net_device *ndev, struct bpf_prog *prog,
4460d14657fSTaehee Yoo struct netlink_ext_ack *extack)
4470d14657fSTaehee Yoo {
4480d14657fSTaehee Yoo bool need_update, running = netif_running(ndev);
4490d14657fSTaehee Yoo struct aq_nic_s *aq_nic = netdev_priv(ndev);
4500d14657fSTaehee Yoo struct bpf_prog *old_prog;
4510d14657fSTaehee Yoo
4520d14657fSTaehee Yoo if (prog && !prog->aux->xdp_has_frags) {
4530d14657fSTaehee Yoo if (ndev->mtu > AQ_CFG_RX_FRAME_MAX) {
4540d14657fSTaehee Yoo NL_SET_ERR_MSG_MOD(extack,
4550d14657fSTaehee Yoo "prog does not support XDP frags");
4560d14657fSTaehee Yoo return -EOPNOTSUPP;
4570d14657fSTaehee Yoo }
4580d14657fSTaehee Yoo
4590d14657fSTaehee Yoo if (prog && ndev->features & NETIF_F_LRO) {
4600d14657fSTaehee Yoo netdev_err(ndev,
4610d14657fSTaehee Yoo "LRO is not supported with single buffer XDP, disabling\n");
4620d14657fSTaehee Yoo ndev->features &= ~NETIF_F_LRO;
4630d14657fSTaehee Yoo }
4640d14657fSTaehee Yoo }
4650d14657fSTaehee Yoo
4660d14657fSTaehee Yoo need_update = !!aq_nic->xdp_prog != !!prog;
4670d14657fSTaehee Yoo if (running && need_update)
4680d14657fSTaehee Yoo aq_ndev_close(ndev);
4690d14657fSTaehee Yoo
4700d14657fSTaehee Yoo old_prog = xchg(&aq_nic->xdp_prog, prog);
4710d14657fSTaehee Yoo if (old_prog)
4720d14657fSTaehee Yoo bpf_prog_put(old_prog);
4730d14657fSTaehee Yoo
4740d14657fSTaehee Yoo if (!old_prog && prog)
4750d14657fSTaehee Yoo static_branch_inc(&aq_xdp_locking_key);
4760d14657fSTaehee Yoo else if (old_prog && !prog)
4770d14657fSTaehee Yoo static_branch_dec(&aq_xdp_locking_key);
4780d14657fSTaehee Yoo
4790d14657fSTaehee Yoo if (running && need_update)
4800d14657fSTaehee Yoo return aq_ndev_open(ndev);
4810d14657fSTaehee Yoo
4820d14657fSTaehee Yoo return 0;
4830d14657fSTaehee Yoo }
4840d14657fSTaehee Yoo
aq_xdp(struct net_device * dev,struct netdev_bpf * xdp)4850d14657fSTaehee Yoo static int aq_xdp(struct net_device *dev, struct netdev_bpf *xdp)
4860d14657fSTaehee Yoo {
4870d14657fSTaehee Yoo switch (xdp->command) {
4880d14657fSTaehee Yoo case XDP_SETUP_PROG:
4890d14657fSTaehee Yoo return aq_xdp_setup(dev, xdp->prog, xdp->extack);
4900d14657fSTaehee Yoo default:
4910d14657fSTaehee Yoo return -EINVAL;
4920d14657fSTaehee Yoo }
4930d14657fSTaehee Yoo }
4940d14657fSTaehee Yoo
49597bde5c4SDavid VomLehn static const struct net_device_ops aq_ndev_ops = {
49697bde5c4SDavid VomLehn .ndo_open = aq_ndev_open,
49797bde5c4SDavid VomLehn .ndo_stop = aq_ndev_close,
49897bde5c4SDavid VomLehn .ndo_start_xmit = aq_ndev_start_xmit,
49997bde5c4SDavid VomLehn .ndo_set_rx_mode = aq_ndev_set_multicast_settings,
50097bde5c4SDavid VomLehn .ndo_change_mtu = aq_ndev_change_mtu,
50197bde5c4SDavid VomLehn .ndo_set_mac_address = aq_ndev_set_mac_address,
5027975d2afSDmitry Bogdanov .ndo_set_features = aq_ndev_set_features,
5030d14657fSTaehee Yoo .ndo_fix_features = aq_ndev_fix_features,
504a7605370SArnd Bergmann .ndo_eth_ioctl = aq_ndev_ioctl,
5057975d2afSDmitry Bogdanov .ndo_vlan_rx_add_vid = aq_ndo_vlan_rx_add_vid,
5067975d2afSDmitry Bogdanov .ndo_vlan_rx_kill_vid = aq_ndo_vlan_rx_kill_vid,
507a83fe6b6SDmitry Bezrukov .ndo_setup_tc = aq_ndo_setup_tc,
5080d14657fSTaehee Yoo .ndo_bpf = aq_xdp,
50945638f01STaehee Yoo .ndo_xdp_xmit = aq_xdp_xmit,
51097bde5c4SDavid VomLehn };
51158608082SNikita Danilov
aq_ndev_init_module(void)51258608082SNikita Danilov static int __init aq_ndev_init_module(void)
51358608082SNikita Danilov {
51458608082SNikita Danilov int ret;
51558608082SNikita Danilov
51658608082SNikita Danilov aq_ndev_wq = create_singlethread_workqueue(aq_ndev_driver_name);
51758608082SNikita Danilov if (!aq_ndev_wq) {
51858608082SNikita Danilov pr_err("Failed to create workqueue\n");
51958608082SNikita Danilov return -ENOMEM;
52058608082SNikita Danilov }
52158608082SNikita Danilov
52258608082SNikita Danilov ret = aq_pci_func_register_driver();
52358608082SNikita Danilov if (ret) {
52458608082SNikita Danilov destroy_workqueue(aq_ndev_wq);
52558608082SNikita Danilov return ret;
52658608082SNikita Danilov }
52758608082SNikita Danilov
52858608082SNikita Danilov return 0;
52958608082SNikita Danilov }
53058608082SNikita Danilov
aq_ndev_exit_module(void)53158608082SNikita Danilov static void __exit aq_ndev_exit_module(void)
53258608082SNikita Danilov {
53358608082SNikita Danilov aq_pci_func_unregister_driver();
53458608082SNikita Danilov
53558608082SNikita Danilov if (aq_ndev_wq) {
53658608082SNikita Danilov destroy_workqueue(aq_ndev_wq);
53758608082SNikita Danilov aq_ndev_wq = NULL;
53858608082SNikita Danilov }
53958608082SNikita Danilov }
54058608082SNikita Danilov
54158608082SNikita Danilov module_init(aq_ndev_init_module);
54258608082SNikita Danilov module_exit(aq_ndev_exit_module);
543