162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/* Atlantic Network Driver
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Copyright (C) 2014-2019 aQuantia Corporation
562306a36Sopenharmony_ci * Copyright (C) 2019-2020 Marvell International Ltd.
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci/* File aq_main.c: Main file for aQuantia Linux driver. */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include "aq_main.h"
1162306a36Sopenharmony_ci#include "aq_nic.h"
1262306a36Sopenharmony_ci#include "aq_pci_func.h"
1362306a36Sopenharmony_ci#include "aq_ethtool.h"
1462306a36Sopenharmony_ci#include "aq_ptp.h"
1562306a36Sopenharmony_ci#include "aq_filters.h"
1662306a36Sopenharmony_ci#include "aq_hw_utils.h"
1762306a36Sopenharmony_ci#include "aq_vec.h"
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci#include <linux/netdevice.h>
2062306a36Sopenharmony_ci#include <linux/module.h>
2162306a36Sopenharmony_ci#include <linux/ip.h>
2262306a36Sopenharmony_ci#include <linux/udp.h>
2362306a36Sopenharmony_ci#include <net/pkt_cls.h>
2462306a36Sopenharmony_ci#include <net/pkt_sched.h>
2562306a36Sopenharmony_ci#include <linux/filter.h>
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
2862306a36Sopenharmony_ciMODULE_AUTHOR(AQ_CFG_DRV_AUTHOR);
2962306a36Sopenharmony_ciMODULE_DESCRIPTION(AQ_CFG_DRV_DESC);
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ciDEFINE_STATIC_KEY_FALSE(aq_xdp_locking_key);
3262306a36Sopenharmony_ciEXPORT_SYMBOL(aq_xdp_locking_key);
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_cistatic const char aq_ndev_driver_name[] = AQ_CFG_DRV_NAME;
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_cistatic const struct net_device_ops aq_ndev_ops;
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_cistatic struct workqueue_struct *aq_ndev_wq;
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_civoid aq_ndev_schedule_work(struct work_struct *work)
4162306a36Sopenharmony_ci{
4262306a36Sopenharmony_ci	queue_work(aq_ndev_wq, work);
4362306a36Sopenharmony_ci}
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_cistruct net_device *aq_ndev_alloc(void)
4662306a36Sopenharmony_ci{
4762306a36Sopenharmony_ci	struct net_device *ndev = NULL;
4862306a36Sopenharmony_ci	struct aq_nic_s *aq_nic = NULL;
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci	ndev = alloc_etherdev_mq(sizeof(struct aq_nic_s), AQ_HW_QUEUES_MAX);
5162306a36Sopenharmony_ci	if (!ndev)
5262306a36Sopenharmony_ci		return NULL;
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	aq_nic = netdev_priv(ndev);
5562306a36Sopenharmony_ci	aq_nic->ndev = ndev;
5662306a36Sopenharmony_ci	ndev->netdev_ops = &aq_ndev_ops;
5762306a36Sopenharmony_ci	ndev->ethtool_ops = &aq_ethtool_ops;
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	return ndev;
6062306a36Sopenharmony_ci}
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ciint aq_ndev_open(struct net_device *ndev)
6362306a36Sopenharmony_ci{
6462306a36Sopenharmony_ci	struct aq_nic_s *aq_nic = netdev_priv(ndev);
6562306a36Sopenharmony_ci	int err = 0;
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	err = aq_nic_init(aq_nic);
6862306a36Sopenharmony_ci	if (err < 0)
6962306a36Sopenharmony_ci		goto err_exit;
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	err = aq_reapply_rxnfc_all_rules(aq_nic);
7262306a36Sopenharmony_ci	if (err < 0)
7362306a36Sopenharmony_ci		goto err_exit;
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	err = aq_filters_vlans_update(aq_nic);
7662306a36Sopenharmony_ci	if (err < 0)
7762306a36Sopenharmony_ci		goto err_exit;
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	err = aq_nic_start(aq_nic);
8062306a36Sopenharmony_ci	if (err < 0) {
8162306a36Sopenharmony_ci		aq_nic_stop(aq_nic);
8262306a36Sopenharmony_ci		goto err_exit;
8362306a36Sopenharmony_ci	}
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_cierr_exit:
8662306a36Sopenharmony_ci	if (err < 0)
8762306a36Sopenharmony_ci		aq_nic_deinit(aq_nic, true);
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	return err;
9062306a36Sopenharmony_ci}
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ciint aq_ndev_close(struct net_device *ndev)
9362306a36Sopenharmony_ci{
9462306a36Sopenharmony_ci	struct aq_nic_s *aq_nic = netdev_priv(ndev);
9562306a36Sopenharmony_ci	int err = 0;
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	err = aq_nic_stop(aq_nic);
9862306a36Sopenharmony_ci	aq_nic_deinit(aq_nic, true);
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	return err;
10162306a36Sopenharmony_ci}
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_cistatic netdev_tx_t aq_ndev_start_xmit(struct sk_buff *skb, struct net_device *ndev)
10462306a36Sopenharmony_ci{
10562306a36Sopenharmony_ci	struct aq_nic_s *aq_nic = netdev_priv(ndev);
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci#if IS_REACHABLE(CONFIG_PTP_1588_CLOCK)
10862306a36Sopenharmony_ci	if (unlikely(aq_utils_obj_test(&aq_nic->flags, AQ_NIC_PTP_DPATH_UP))) {
10962306a36Sopenharmony_ci		/* Hardware adds the Timestamp for PTPv2 802.AS1
11062306a36Sopenharmony_ci		 * and PTPv2 IPv4 UDP.
11162306a36Sopenharmony_ci		 * We have to push even general 320 port messages to the ptp
11262306a36Sopenharmony_ci		 * queue explicitly. This is a limitation of current firmware
11362306a36Sopenharmony_ci		 * and hardware PTP design of the chip. Otherwise ptp stream
11462306a36Sopenharmony_ci		 * will fail to sync
11562306a36Sopenharmony_ci		 */
11662306a36Sopenharmony_ci		if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) ||
11762306a36Sopenharmony_ci		    unlikely((ip_hdr(skb)->version == 4) &&
11862306a36Sopenharmony_ci			     (ip_hdr(skb)->protocol == IPPROTO_UDP) &&
11962306a36Sopenharmony_ci			     ((udp_hdr(skb)->dest == htons(319)) ||
12062306a36Sopenharmony_ci			      (udp_hdr(skb)->dest == htons(320)))) ||
12162306a36Sopenharmony_ci		    unlikely(eth_hdr(skb)->h_proto == htons(ETH_P_1588)))
12262306a36Sopenharmony_ci			return aq_ptp_xmit(aq_nic, skb);
12362306a36Sopenharmony_ci	}
12462306a36Sopenharmony_ci#endif
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	skb_tx_timestamp(skb);
12762306a36Sopenharmony_ci	return aq_nic_xmit(aq_nic, skb);
12862306a36Sopenharmony_ci}
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_cistatic int aq_ndev_change_mtu(struct net_device *ndev, int new_mtu)
13162306a36Sopenharmony_ci{
13262306a36Sopenharmony_ci	int new_frame_size = new_mtu + ETH_HLEN + ETH_FCS_LEN;
13362306a36Sopenharmony_ci	struct aq_nic_s *aq_nic = netdev_priv(ndev);
13462306a36Sopenharmony_ci	struct bpf_prog *prog;
13562306a36Sopenharmony_ci	int err;
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	prog = READ_ONCE(aq_nic->xdp_prog);
13862306a36Sopenharmony_ci	if (prog && !prog->aux->xdp_has_frags &&
13962306a36Sopenharmony_ci	    new_frame_size > AQ_CFG_RX_FRAME_MAX) {
14062306a36Sopenharmony_ci		netdev_err(ndev, "Illegal MTU %d for XDP prog without frags\n",
14162306a36Sopenharmony_ci			   ndev->mtu);
14262306a36Sopenharmony_ci		return -EOPNOTSUPP;
14362306a36Sopenharmony_ci	}
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	err = aq_nic_set_mtu(aq_nic, new_mtu + ETH_HLEN);
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	if (err < 0)
14862306a36Sopenharmony_ci		goto err_exit;
14962306a36Sopenharmony_ci	ndev->mtu = new_mtu;
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_cierr_exit:
15262306a36Sopenharmony_ci	return err;
15362306a36Sopenharmony_ci}
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_cistatic int aq_ndev_set_features(struct net_device *ndev,
15662306a36Sopenharmony_ci				netdev_features_t features)
15762306a36Sopenharmony_ci{
15862306a36Sopenharmony_ci	bool is_vlan_tx_insert = !!(features & NETIF_F_HW_VLAN_CTAG_TX);
15962306a36Sopenharmony_ci	bool is_vlan_rx_strip = !!(features & NETIF_F_HW_VLAN_CTAG_RX);
16062306a36Sopenharmony_ci	struct aq_nic_s *aq_nic = netdev_priv(ndev);
16162306a36Sopenharmony_ci	bool need_ndev_restart = false;
16262306a36Sopenharmony_ci	struct aq_nic_cfg_s *aq_cfg;
16362306a36Sopenharmony_ci	bool is_lro = false;
16462306a36Sopenharmony_ci	int err = 0;
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	aq_cfg = aq_nic_get_cfg(aq_nic);
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	if (!(features & NETIF_F_NTUPLE)) {
16962306a36Sopenharmony_ci		if (aq_nic->ndev->features & NETIF_F_NTUPLE) {
17062306a36Sopenharmony_ci			err = aq_clear_rxnfc_all_rules(aq_nic);
17162306a36Sopenharmony_ci			if (unlikely(err))
17262306a36Sopenharmony_ci				goto err_exit;
17362306a36Sopenharmony_ci		}
17462306a36Sopenharmony_ci	}
17562306a36Sopenharmony_ci	if (!(features & NETIF_F_HW_VLAN_CTAG_FILTER)) {
17662306a36Sopenharmony_ci		if (aq_nic->ndev->features & NETIF_F_HW_VLAN_CTAG_FILTER) {
17762306a36Sopenharmony_ci			err = aq_filters_vlan_offload_off(aq_nic);
17862306a36Sopenharmony_ci			if (unlikely(err))
17962306a36Sopenharmony_ci				goto err_exit;
18062306a36Sopenharmony_ci		}
18162306a36Sopenharmony_ci	}
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	aq_cfg->features = features;
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	if (aq_cfg->aq_hw_caps->hw_features & NETIF_F_LRO) {
18662306a36Sopenharmony_ci		is_lro = features & NETIF_F_LRO;
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci		if (aq_cfg->is_lro != is_lro) {
18962306a36Sopenharmony_ci			aq_cfg->is_lro = is_lro;
19062306a36Sopenharmony_ci			need_ndev_restart = true;
19162306a36Sopenharmony_ci		}
19262306a36Sopenharmony_ci	}
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci	if ((aq_nic->ndev->features ^ features) & NETIF_F_RXCSUM) {
19562306a36Sopenharmony_ci		err = aq_nic->aq_hw_ops->hw_set_offload(aq_nic->aq_hw,
19662306a36Sopenharmony_ci							aq_cfg);
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci		if (unlikely(err))
19962306a36Sopenharmony_ci			goto err_exit;
20062306a36Sopenharmony_ci	}
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	if (aq_cfg->is_vlan_rx_strip != is_vlan_rx_strip) {
20362306a36Sopenharmony_ci		aq_cfg->is_vlan_rx_strip = is_vlan_rx_strip;
20462306a36Sopenharmony_ci		need_ndev_restart = true;
20562306a36Sopenharmony_ci	}
20662306a36Sopenharmony_ci	if (aq_cfg->is_vlan_tx_insert != is_vlan_tx_insert) {
20762306a36Sopenharmony_ci		aq_cfg->is_vlan_tx_insert = is_vlan_tx_insert;
20862306a36Sopenharmony_ci		need_ndev_restart = true;
20962306a36Sopenharmony_ci	}
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	if (need_ndev_restart && netif_running(ndev)) {
21262306a36Sopenharmony_ci		aq_ndev_close(ndev);
21362306a36Sopenharmony_ci		aq_ndev_open(ndev);
21462306a36Sopenharmony_ci	}
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_cierr_exit:
21762306a36Sopenharmony_ci	return err;
21862306a36Sopenharmony_ci}
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_cistatic netdev_features_t aq_ndev_fix_features(struct net_device *ndev,
22162306a36Sopenharmony_ci					      netdev_features_t features)
22262306a36Sopenharmony_ci{
22362306a36Sopenharmony_ci	struct aq_nic_s *aq_nic = netdev_priv(ndev);
22462306a36Sopenharmony_ci	struct bpf_prog *prog;
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	if (!(features & NETIF_F_RXCSUM))
22762306a36Sopenharmony_ci		features &= ~NETIF_F_LRO;
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	prog = READ_ONCE(aq_nic->xdp_prog);
23062306a36Sopenharmony_ci	if (prog && !prog->aux->xdp_has_frags &&
23162306a36Sopenharmony_ci	    aq_nic->xdp_prog && features & NETIF_F_LRO) {
23262306a36Sopenharmony_ci		netdev_err(ndev, "LRO is not supported with single buffer XDP, disabling\n");
23362306a36Sopenharmony_ci		features &= ~NETIF_F_LRO;
23462306a36Sopenharmony_ci	}
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	return features;
23762306a36Sopenharmony_ci}
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_cistatic int aq_ndev_set_mac_address(struct net_device *ndev, void *addr)
24062306a36Sopenharmony_ci{
24162306a36Sopenharmony_ci	struct aq_nic_s *aq_nic = netdev_priv(ndev);
24262306a36Sopenharmony_ci	int err = 0;
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	err = eth_mac_addr(ndev, addr);
24562306a36Sopenharmony_ci	if (err < 0)
24662306a36Sopenharmony_ci		goto err_exit;
24762306a36Sopenharmony_ci	err = aq_nic_set_mac(aq_nic, ndev);
24862306a36Sopenharmony_ci	if (err < 0)
24962306a36Sopenharmony_ci		goto err_exit;
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_cierr_exit:
25262306a36Sopenharmony_ci	return err;
25362306a36Sopenharmony_ci}
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_cistatic void aq_ndev_set_multicast_settings(struct net_device *ndev)
25662306a36Sopenharmony_ci{
25762306a36Sopenharmony_ci	struct aq_nic_s *aq_nic = netdev_priv(ndev);
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	(void)aq_nic_set_multicast_list(aq_nic, ndev);
26062306a36Sopenharmony_ci}
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci#if IS_REACHABLE(CONFIG_PTP_1588_CLOCK)
26362306a36Sopenharmony_cistatic int aq_ndev_config_hwtstamp(struct aq_nic_s *aq_nic,
26462306a36Sopenharmony_ci				   struct hwtstamp_config *config)
26562306a36Sopenharmony_ci{
26662306a36Sopenharmony_ci	switch (config->tx_type) {
26762306a36Sopenharmony_ci	case HWTSTAMP_TX_OFF:
26862306a36Sopenharmony_ci	case HWTSTAMP_TX_ON:
26962306a36Sopenharmony_ci		break;
27062306a36Sopenharmony_ci	default:
27162306a36Sopenharmony_ci		return -ERANGE;
27262306a36Sopenharmony_ci	}
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	switch (config->rx_filter) {
27562306a36Sopenharmony_ci	case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
27662306a36Sopenharmony_ci	case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
27762306a36Sopenharmony_ci	case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
27862306a36Sopenharmony_ci	case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
27962306a36Sopenharmony_ci	case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
28062306a36Sopenharmony_ci	case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
28162306a36Sopenharmony_ci	case HWTSTAMP_FILTER_PTP_V2_SYNC:
28262306a36Sopenharmony_ci	case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
28362306a36Sopenharmony_ci		config->rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
28462306a36Sopenharmony_ci		break;
28562306a36Sopenharmony_ci	case HWTSTAMP_FILTER_PTP_V2_EVENT:
28662306a36Sopenharmony_ci	case HWTSTAMP_FILTER_NONE:
28762306a36Sopenharmony_ci		break;
28862306a36Sopenharmony_ci	default:
28962306a36Sopenharmony_ci		return -ERANGE;
29062306a36Sopenharmony_ci	}
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	return aq_ptp_hwtstamp_config_set(aq_nic->aq_ptp, config);
29362306a36Sopenharmony_ci}
29462306a36Sopenharmony_ci#endif
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_cistatic int aq_ndev_hwtstamp_set(struct aq_nic_s *aq_nic, struct ifreq *ifr)
29762306a36Sopenharmony_ci{
29862306a36Sopenharmony_ci	struct hwtstamp_config config;
29962306a36Sopenharmony_ci#if IS_REACHABLE(CONFIG_PTP_1588_CLOCK)
30062306a36Sopenharmony_ci	int ret_val;
30162306a36Sopenharmony_ci#endif
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	if (!aq_nic->aq_ptp)
30462306a36Sopenharmony_ci		return -EOPNOTSUPP;
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
30762306a36Sopenharmony_ci		return -EFAULT;
30862306a36Sopenharmony_ci#if IS_REACHABLE(CONFIG_PTP_1588_CLOCK)
30962306a36Sopenharmony_ci	ret_val = aq_ndev_config_hwtstamp(aq_nic, &config);
31062306a36Sopenharmony_ci	if (ret_val)
31162306a36Sopenharmony_ci		return ret_val;
31262306a36Sopenharmony_ci#endif
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ?
31562306a36Sopenharmony_ci	       -EFAULT : 0;
31662306a36Sopenharmony_ci}
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci#if IS_REACHABLE(CONFIG_PTP_1588_CLOCK)
31962306a36Sopenharmony_cistatic int aq_ndev_hwtstamp_get(struct aq_nic_s *aq_nic, struct ifreq *ifr)
32062306a36Sopenharmony_ci{
32162306a36Sopenharmony_ci	struct hwtstamp_config config;
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	if (!aq_nic->aq_ptp)
32462306a36Sopenharmony_ci		return -EOPNOTSUPP;
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci	aq_ptp_hwtstamp_config_get(aq_nic->aq_ptp, &config);
32762306a36Sopenharmony_ci	return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ?
32862306a36Sopenharmony_ci	       -EFAULT : 0;
32962306a36Sopenharmony_ci}
33062306a36Sopenharmony_ci#endif
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_cistatic int aq_ndev_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
33362306a36Sopenharmony_ci{
33462306a36Sopenharmony_ci	struct aq_nic_s *aq_nic = netdev_priv(netdev);
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	switch (cmd) {
33762306a36Sopenharmony_ci	case SIOCSHWTSTAMP:
33862306a36Sopenharmony_ci		return aq_ndev_hwtstamp_set(aq_nic, ifr);
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci#if IS_REACHABLE(CONFIG_PTP_1588_CLOCK)
34162306a36Sopenharmony_ci	case SIOCGHWTSTAMP:
34262306a36Sopenharmony_ci		return aq_ndev_hwtstamp_get(aq_nic, ifr);
34362306a36Sopenharmony_ci#endif
34462306a36Sopenharmony_ci	}
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	return -EOPNOTSUPP;
34762306a36Sopenharmony_ci}
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_cistatic int aq_ndo_vlan_rx_add_vid(struct net_device *ndev, __be16 proto,
35062306a36Sopenharmony_ci				  u16 vid)
35162306a36Sopenharmony_ci{
35262306a36Sopenharmony_ci	struct aq_nic_s *aq_nic = netdev_priv(ndev);
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	if (!aq_nic->aq_hw_ops->hw_filter_vlan_set)
35562306a36Sopenharmony_ci		return -EOPNOTSUPP;
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci	set_bit(vid, aq_nic->active_vlans);
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	return aq_filters_vlans_update(aq_nic);
36062306a36Sopenharmony_ci}
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_cistatic int aq_ndo_vlan_rx_kill_vid(struct net_device *ndev, __be16 proto,
36362306a36Sopenharmony_ci				   u16 vid)
36462306a36Sopenharmony_ci{
36562306a36Sopenharmony_ci	struct aq_nic_s *aq_nic = netdev_priv(ndev);
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	if (!aq_nic->aq_hw_ops->hw_filter_vlan_set)
36862306a36Sopenharmony_ci		return -EOPNOTSUPP;
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	clear_bit(vid, aq_nic->active_vlans);
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	if (-ENOENT == aq_del_fvlan_by_vlan(aq_nic, vid))
37362306a36Sopenharmony_ci		return aq_filters_vlans_update(aq_nic);
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	return 0;
37662306a36Sopenharmony_ci}
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_cistatic int aq_validate_mqprio_opt(struct aq_nic_s *self,
37962306a36Sopenharmony_ci				  struct tc_mqprio_qopt_offload *mqprio,
38062306a36Sopenharmony_ci				  const unsigned int num_tc)
38162306a36Sopenharmony_ci{
38262306a36Sopenharmony_ci	const bool has_min_rate = !!(mqprio->flags & TC_MQPRIO_F_MIN_RATE);
38362306a36Sopenharmony_ci	struct aq_nic_cfg_s *aq_nic_cfg = aq_nic_get_cfg(self);
38462306a36Sopenharmony_ci	const unsigned int tcs_max = min_t(u8, aq_nic_cfg->aq_hw_caps->tcs_max,
38562306a36Sopenharmony_ci					   AQ_CFG_TCS_MAX);
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	if (num_tc > tcs_max) {
38862306a36Sopenharmony_ci		netdev_err(self->ndev, "Too many TCs requested\n");
38962306a36Sopenharmony_ci		return -EOPNOTSUPP;
39062306a36Sopenharmony_ci	}
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci	if (num_tc != 0 && !is_power_of_2(num_tc)) {
39362306a36Sopenharmony_ci		netdev_err(self->ndev, "TC count should be power of 2\n");
39462306a36Sopenharmony_ci		return -EOPNOTSUPP;
39562306a36Sopenharmony_ci	}
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci	if (has_min_rate && !ATL_HW_IS_CHIP_FEATURE(self->aq_hw, ANTIGUA)) {
39862306a36Sopenharmony_ci		netdev_err(self->ndev, "Min tx rate is not supported\n");
39962306a36Sopenharmony_ci		return -EOPNOTSUPP;
40062306a36Sopenharmony_ci	}
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	return 0;
40362306a36Sopenharmony_ci}
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_cistatic int aq_ndo_setup_tc(struct net_device *dev, enum tc_setup_type type,
40662306a36Sopenharmony_ci			   void *type_data)
40762306a36Sopenharmony_ci{
40862306a36Sopenharmony_ci	struct tc_mqprio_qopt_offload *mqprio = type_data;
40962306a36Sopenharmony_ci	struct aq_nic_s *aq_nic = netdev_priv(dev);
41062306a36Sopenharmony_ci	bool has_min_rate;
41162306a36Sopenharmony_ci	bool has_max_rate;
41262306a36Sopenharmony_ci	int err;
41362306a36Sopenharmony_ci	int i;
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci	if (type != TC_SETUP_QDISC_MQPRIO)
41662306a36Sopenharmony_ci		return -EOPNOTSUPP;
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci	has_min_rate = !!(mqprio->flags & TC_MQPRIO_F_MIN_RATE);
41962306a36Sopenharmony_ci	has_max_rate = !!(mqprio->flags & TC_MQPRIO_F_MAX_RATE);
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	err = aq_validate_mqprio_opt(aq_nic, mqprio, mqprio->qopt.num_tc);
42262306a36Sopenharmony_ci	if (err)
42362306a36Sopenharmony_ci		return err;
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci	for (i = 0; i < mqprio->qopt.num_tc; i++) {
42662306a36Sopenharmony_ci		if (has_max_rate) {
42762306a36Sopenharmony_ci			u64 max_rate = mqprio->max_rate[i];
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci			do_div(max_rate, AQ_MBPS_DIVISOR);
43062306a36Sopenharmony_ci			aq_nic_setup_tc_max_rate(aq_nic, i, (u32)max_rate);
43162306a36Sopenharmony_ci		}
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci		if (has_min_rate) {
43462306a36Sopenharmony_ci			u64 min_rate = mqprio->min_rate[i];
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci			do_div(min_rate, AQ_MBPS_DIVISOR);
43762306a36Sopenharmony_ci			aq_nic_setup_tc_min_rate(aq_nic, i, (u32)min_rate);
43862306a36Sopenharmony_ci		}
43962306a36Sopenharmony_ci	}
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci	return aq_nic_setup_tc_mqprio(aq_nic, mqprio->qopt.num_tc,
44262306a36Sopenharmony_ci				      mqprio->qopt.prio_tc_map);
44362306a36Sopenharmony_ci}
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_cistatic int aq_xdp_setup(struct net_device *ndev, struct bpf_prog *prog,
44662306a36Sopenharmony_ci			struct netlink_ext_ack *extack)
44762306a36Sopenharmony_ci{
44862306a36Sopenharmony_ci	bool need_update, running = netif_running(ndev);
44962306a36Sopenharmony_ci	struct aq_nic_s *aq_nic = netdev_priv(ndev);
45062306a36Sopenharmony_ci	struct bpf_prog *old_prog;
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci	if (prog && !prog->aux->xdp_has_frags) {
45362306a36Sopenharmony_ci		if (ndev->mtu > AQ_CFG_RX_FRAME_MAX) {
45462306a36Sopenharmony_ci			NL_SET_ERR_MSG_MOD(extack,
45562306a36Sopenharmony_ci					   "prog does not support XDP frags");
45662306a36Sopenharmony_ci			return -EOPNOTSUPP;
45762306a36Sopenharmony_ci		}
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci		if (prog && ndev->features & NETIF_F_LRO) {
46062306a36Sopenharmony_ci			netdev_err(ndev,
46162306a36Sopenharmony_ci				   "LRO is not supported with single buffer XDP, disabling\n");
46262306a36Sopenharmony_ci			ndev->features &= ~NETIF_F_LRO;
46362306a36Sopenharmony_ci		}
46462306a36Sopenharmony_ci	}
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	need_update = !!aq_nic->xdp_prog != !!prog;
46762306a36Sopenharmony_ci	if (running && need_update)
46862306a36Sopenharmony_ci		aq_ndev_close(ndev);
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci	old_prog = xchg(&aq_nic->xdp_prog, prog);
47162306a36Sopenharmony_ci	if (old_prog)
47262306a36Sopenharmony_ci		bpf_prog_put(old_prog);
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci	if (!old_prog && prog)
47562306a36Sopenharmony_ci		static_branch_inc(&aq_xdp_locking_key);
47662306a36Sopenharmony_ci	else if (old_prog && !prog)
47762306a36Sopenharmony_ci		static_branch_dec(&aq_xdp_locking_key);
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci	if (running && need_update)
48062306a36Sopenharmony_ci		return aq_ndev_open(ndev);
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci	return 0;
48362306a36Sopenharmony_ci}
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_cistatic int aq_xdp(struct net_device *dev, struct netdev_bpf *xdp)
48662306a36Sopenharmony_ci{
48762306a36Sopenharmony_ci	switch (xdp->command) {
48862306a36Sopenharmony_ci	case XDP_SETUP_PROG:
48962306a36Sopenharmony_ci		return aq_xdp_setup(dev, xdp->prog, xdp->extack);
49062306a36Sopenharmony_ci	default:
49162306a36Sopenharmony_ci		return -EINVAL;
49262306a36Sopenharmony_ci	}
49362306a36Sopenharmony_ci}
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_cistatic const struct net_device_ops aq_ndev_ops = {
49662306a36Sopenharmony_ci	.ndo_open = aq_ndev_open,
49762306a36Sopenharmony_ci	.ndo_stop = aq_ndev_close,
49862306a36Sopenharmony_ci	.ndo_start_xmit = aq_ndev_start_xmit,
49962306a36Sopenharmony_ci	.ndo_set_rx_mode = aq_ndev_set_multicast_settings,
50062306a36Sopenharmony_ci	.ndo_change_mtu = aq_ndev_change_mtu,
50162306a36Sopenharmony_ci	.ndo_set_mac_address = aq_ndev_set_mac_address,
50262306a36Sopenharmony_ci	.ndo_set_features = aq_ndev_set_features,
50362306a36Sopenharmony_ci	.ndo_fix_features = aq_ndev_fix_features,
50462306a36Sopenharmony_ci	.ndo_eth_ioctl = aq_ndev_ioctl,
50562306a36Sopenharmony_ci	.ndo_vlan_rx_add_vid = aq_ndo_vlan_rx_add_vid,
50662306a36Sopenharmony_ci	.ndo_vlan_rx_kill_vid = aq_ndo_vlan_rx_kill_vid,
50762306a36Sopenharmony_ci	.ndo_setup_tc = aq_ndo_setup_tc,
50862306a36Sopenharmony_ci	.ndo_bpf = aq_xdp,
50962306a36Sopenharmony_ci	.ndo_xdp_xmit = aq_xdp_xmit,
51062306a36Sopenharmony_ci};
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_cistatic int __init aq_ndev_init_module(void)
51362306a36Sopenharmony_ci{
51462306a36Sopenharmony_ci	int ret;
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci	aq_ndev_wq = create_singlethread_workqueue(aq_ndev_driver_name);
51762306a36Sopenharmony_ci	if (!aq_ndev_wq) {
51862306a36Sopenharmony_ci		pr_err("Failed to create workqueue\n");
51962306a36Sopenharmony_ci		return -ENOMEM;
52062306a36Sopenharmony_ci	}
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci	ret = aq_pci_func_register_driver();
52362306a36Sopenharmony_ci	if (ret) {
52462306a36Sopenharmony_ci		destroy_workqueue(aq_ndev_wq);
52562306a36Sopenharmony_ci		return ret;
52662306a36Sopenharmony_ci	}
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci	return 0;
52962306a36Sopenharmony_ci}
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_cistatic void __exit aq_ndev_exit_module(void)
53262306a36Sopenharmony_ci{
53362306a36Sopenharmony_ci	aq_pci_func_unregister_driver();
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci	if (aq_ndev_wq) {
53662306a36Sopenharmony_ci		destroy_workqueue(aq_ndev_wq);
53762306a36Sopenharmony_ci		aq_ndev_wq = NULL;
53862306a36Sopenharmony_ci	}
53962306a36Sopenharmony_ci}
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_cimodule_init(aq_ndev_init_module);
54262306a36Sopenharmony_cimodule_exit(aq_ndev_exit_module);
543