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