static int hns3_lp_setup(struct net_device *ndev, enum hnae3_loop loop, bool en) { struct hnae3_handle *h = hns3_get_handle(ndev); bool vlan_filter_enable; int ret; if (!h->ae_algo->ops->set_loopback || !h->ae_algo->ops->set_promisc_mode) return -EOPNOTSUPP; switch (loop) { case HNAE3_LOOP_SERIAL_SERDES: case HNAE3_LOOP_PARALLEL_SERDES: case HNAE3_LOOP_APP: ret = h->ae_algo->ops->set_loopback(h, loop, en); break; default: ret = -ENOTSUPP; break; } if (ret) return ret; if (en) { h->ae_algo->ops->set_promisc_mode(h, true, true); } else { /* recover promisc mode before loopback test */ hns3_update_promisc_mode(ndev, h->netdev_flags); vlan_filter_enable = ndev->flags & IFF_PROMISC ? false : true; hns3_enable_vlan_filter(ndev, vlan_filter_enable); } return ret; }
static int hns3_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd, u32 *rule_locs) { struct hnae3_handle *h = hns3_get_handle(netdev); if (!h->ae_algo || !h->ae_algo->ops) return -EOPNOTSUPP; switch (cmd->cmd) { case ETHTOOL_GRXRINGS: cmd->data = h->kinfo.num_tqps; return 0; case ETHTOOL_GRXFH: if (h->ae_algo->ops->get_rss_tuple) return h->ae_algo->ops->get_rss_tuple(h, cmd); return -EOPNOTSUPP; case ETHTOOL_GRXCLSRLCNT: if (h->ae_algo->ops->get_fd_rule_cnt) return h->ae_algo->ops->get_fd_rule_cnt(h, cmd); return -EOPNOTSUPP; case ETHTOOL_GRXCLSRULE: if (h->ae_algo->ops->get_fd_rule_info) return h->ae_algo->ops->get_fd_rule_info(h, cmd); return -EOPNOTSUPP; case ETHTOOL_GRXCLSRLALL: if (h->ae_algo->ops->get_fd_all_rules) return h->ae_algo->ops->get_fd_all_rules(h, cmd, rule_locs); return -EOPNOTSUPP; default: return -EOPNOTSUPP; } }
static int hns3_lp_setup(struct net_device *ndev, enum hnae3_loop loop, bool en) { struct hnae3_handle *h = hns3_get_handle(ndev); int ret; if (!h->ae_algo->ops->set_loopback || !h->ae_algo->ops->set_promisc_mode) return -EOPNOTSUPP; switch (loop) { case HNAE3_MAC_INTER_LOOP_SERDES: case HNAE3_MAC_INTER_LOOP_MAC: ret = h->ae_algo->ops->set_loopback(h, loop, en); break; default: ret = -ENOTSUPP; break; } if (ret) return ret; h->ae_algo->ops->set_promisc_mode(h, en, en); return ret; }
static void hns3_get_channels(struct net_device *netdev, struct ethtool_channels *ch) { struct hnae3_handle *h = hns3_get_handle(netdev); if (h->ae_algo->ops->get_channels) h->ae_algo->ops->get_channels(h, ch); }
static u32 hns3_get_link(struct net_device *netdev) { struct hnae3_handle *h = hns3_get_handle(netdev); if (h->ae_algo && h->ae_algo->ops && h->ae_algo->ops->get_status) return h->ae_algo->ops->get_status(h); else return 0; }
/* return 0 if successful, otherwise fail */ static u8 hns3_dcbnl_setdcbx(struct net_device *ndev, u8 mode) { struct hnae3_handle *h = hns3_get_handle(ndev); if (h->kinfo.dcb_ops->setdcbx) return h->kinfo.dcb_ops->setdcbx(h, mode); return 1; }
void hns3_ethtool_set_ops(struct net_device *netdev) { struct hnae3_handle *h = hns3_get_handle(netdev); if (h->flags & HNAE3_SUPPORT_VF) netdev->ethtool_ops = &hns3vf_ethtool_ops; else netdev->ethtool_ops = &hns3_ethtool_ops; }
static void hns3_get_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *param) { struct hnae3_handle *h = hns3_get_handle(netdev); if (h->ae_algo && h->ae_algo->ops && h->ae_algo->ops->get_pauseparam) h->ae_algo->ops->get_pauseparam(h, ¶m->autoneg, ¶m->rx_pause, ¶m->tx_pause); }
static int hns3_get_regs_len(struct net_device *netdev) { struct hnae3_handle *h = hns3_get_handle(netdev); if (!h->ae_algo->ops->get_regs_len) return -EOPNOTSUPP; return h->ae_algo->ops->get_regs_len(h); }
/* DCBX configuration */ static u8 hns3_dcbnl_getdcbx(struct net_device *ndev) { struct hnae3_handle *h = hns3_get_handle(ndev); if (h->kinfo.dcb_ops->getdcbx) return h->kinfo.dcb_ops->getdcbx(h); return 0; }
static int hns3_get_rss(struct net_device *netdev, u32 *indir, u8 *key, u8 *hfunc) { struct hnae3_handle *h = hns3_get_handle(netdev); if (!h->ae_algo || !h->ae_algo->ops || !h->ae_algo->ops->get_rss) return -EOPNOTSUPP; return h->ae_algo->ops->get_rss(h, indir, key, hfunc); }
static int hns3_dcbnl_ieee_setets(struct net_device *ndev, struct ieee_ets *ets) { struct hnae3_handle *h = hns3_get_handle(ndev); if (h->kinfo.dcb_ops->ieee_setets) return h->kinfo.dcb_ops->ieee_setets(h, ets); return -EOPNOTSUPP; }
static int hns3_dcbnl_ieee_setpfc(struct net_device *ndev, struct ieee_pfc *pfc) { struct hnae3_handle *h = hns3_get_handle(ndev); if (h->kinfo.dcb_ops->ieee_setpfc) return h->kinfo.dcb_ops->ieee_setpfc(h, pfc); return -EOPNOTSUPP; }
static int hns3_set_phys_id(struct net_device *netdev, enum ethtool_phys_id_state state) { struct hnae3_handle *h = hns3_get_handle(netdev); if (!h->ae_algo || !h->ae_algo->ops || !h->ae_algo->ops->set_led_id) return -EOPNOTSUPP; return h->ae_algo->ops->set_led_id(h, state); }
static void hns3_get_regs(struct net_device *netdev, struct ethtool_regs *cmd, void *data) { struct hnae3_handle *h = hns3_get_handle(netdev); if (!h->ae_algo->ops->get_regs) return; h->ae_algo->ops->get_regs(h, &cmd->version, data); }
static u32 hns3_get_rss_indir_size(struct net_device *netdev) { struct hnae3_handle *h = hns3_get_handle(netdev); if (!h->ae_algo || !h->ae_algo->ops || !h->ae_algo->ops->get_rss_indir_size) return 0; return h->ae_algo->ops->get_rss_indir_size(h); }
static int hns3_set_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *param) { struct hnae3_handle *h = hns3_get_handle(netdev); if (h->ae_algo->ops->set_pauseparam) return h->ae_algo->ops->set_pauseparam(h, param->autoneg, param->rx_pause, param->tx_pause); return -EOPNOTSUPP; }
static int hns3_lp_up(struct net_device *ndev, enum hnae3_loop loop_mode) { struct hnae3_handle *h = hns3_get_handle(ndev); int ret; ret = hns3_nic_reset_all_ring(h); if (ret) return ret; ret = hns3_lp_setup(ndev, loop_mode, true); usleep_range(10000, 20000); return ret; }
static int hns3_get_link_ksettings(struct net_device *netdev, struct ethtool_link_ksettings *cmd) { struct hnae3_handle *h = hns3_get_handle(netdev); const struct hnae3_ae_ops *ops; u8 media_type; u8 link_stat; if (!h->ae_algo || !h->ae_algo->ops) return -EOPNOTSUPP; ops = h->ae_algo->ops; if (ops->get_media_type) ops->get_media_type(h, &media_type); else return -EOPNOTSUPP; switch (media_type) { case HNAE3_MEDIA_TYPE_NONE: cmd->base.port = PORT_NONE; hns3_get_ksettings(h, cmd); break; case HNAE3_MEDIA_TYPE_FIBER: cmd->base.port = PORT_FIBRE; hns3_get_ksettings(h, cmd); break; case HNAE3_MEDIA_TYPE_COPPER: cmd->base.port = PORT_TP; if (!netdev->phydev) hns3_get_ksettings(h, cmd); else phy_ethtool_ksettings_get(netdev->phydev, cmd); break; default: netdev_warn(netdev, "Unknown media type"); return 0; } /* mdio_support */ cmd->base.mdio_support = ETH_MDIO_SUPPORTS_C22; link_stat = hns3_get_link(netdev); if (!link_stat) { cmd->base.speed = SPEED_UNKNOWN; cmd->base.duplex = DUPLEX_UNKNOWN; } return 0; }
static int hns3_set_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd) { struct hnae3_handle *h = hns3_get_handle(netdev); if (!h->ae_algo || !h->ae_algo->ops || !h->ae_algo->ops->set_rss_tuple) return -EOPNOTSUPP; switch (cmd->cmd) { case ETHTOOL_SRXFH: return h->ae_algo->ops->set_rss_tuple(h, cmd); default: return -EOPNOTSUPP; } }
static int hns3_lp_down(struct net_device *ndev, enum hnae3_loop loop_mode) { struct hnae3_handle *h = hns3_get_handle(ndev); int ret; if (!h->ae_algo->ops->stop) return -EOPNOTSUPP; ret = hns3_lp_setup(ndev, loop_mode, false); if (ret) { netdev_err(ndev, "lb_setup return error: %d\n", ret); return ret; } h->ae_algo->ops->stop(h); usleep_range(10000, 20000); return 0; }
/* hns3_get_stats - get detail statistics. * @netdev: net device * @stats: statistics info. * @data: statistics data. */ static void hns3_get_stats(struct net_device *netdev, struct ethtool_stats *stats, u64 *data) { struct hnae3_handle *h = hns3_get_handle(netdev); u64 *p = data; if (!h->ae_algo->ops->get_stats || !h->ae_algo->ops->update_stats) { netdev_err(netdev, "could not get any statistics\n"); return; } h->ae_algo->ops->update_stats(h, &netdev->stats); /* get per-queue stats */ p = hns3_get_stats_tqps(h, p); /* get MAC & other misc hardware stats */ h->ae_algo->ops->get_stats(h, p); }
static void hns3_get_strings(struct net_device *netdev, u32 stringset, u8 *data) { struct hnae3_handle *h = hns3_get_handle(netdev); const struct hnae3_ae_ops *ops = h->ae_algo->ops; char *buff = (char *)data; if (!ops->get_strings) return; switch (stringset) { case ETH_SS_STATS: buff = hns3_get_strings_tqps(h, buff); h->ae_algo->ops->get_strings(h, stringset, (u8 *)buff); break; case ETH_SS_TEST: ops->get_strings(h, stringset, data); break; } }
static int hns3_get_sset_count(struct net_device *netdev, int stringset) { struct hnae3_handle *h = hns3_get_handle(netdev); const struct hnae3_ae_ops *ops = h->ae_algo->ops; if (!ops->get_sset_count) return -EOPNOTSUPP; switch (stringset) { case ETH_SS_STATS: return ((HNS3_TQP_STATS_COUNT * h->kinfo.num_tqps) + ops->get_sset_count(h, stringset)); case ETH_SS_TEST: return ops->get_sset_count(h, stringset); } return 0; }
static int hns3_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *cmd) { struct hnae3_handle *h = hns3_get_handle(netdev); u16 queue_num = h->kinfo.num_tqps; int ret; int i; ret = hns3_check_coalesce_para(netdev, cmd); if (ret) return ret; h->kinfo.int_rl_setting = hns3_rl_round_down(cmd->rx_coalesce_usecs_high); for (i = 0; i < queue_num; i++) hns3_set_coalesce_per_queue(netdev, cmd, i); return 0; }
static int hns3_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd, u32 *rule_locs) { struct hnae3_handle *h = hns3_get_handle(netdev); if (!h->ae_algo || !h->ae_algo->ops || !h->ae_algo->ops->get_rss_tuple) return -EOPNOTSUPP; switch (cmd->cmd) { case ETHTOOL_GRXRINGS: cmd->data = h->kinfo.rss_size; break; case ETHTOOL_GRXFH: return h->ae_algo->ops->get_rss_tuple(h, cmd); default: return -EOPNOTSUPP; } return 0; }
static int hns3_set_rss(struct net_device *netdev, const u32 *indir, const u8 *key, const u8 hfunc) { struct hnae3_handle *h = hns3_get_handle(netdev); if (!h->ae_algo || !h->ae_algo->ops || !h->ae_algo->ops->set_rss) return -EOPNOTSUPP; /* currently we only support Toeplitz hash */ if ((hfunc != ETH_RSS_HASH_NO_CHANGE) && (hfunc != ETH_RSS_HASH_TOP)) { netdev_err(netdev, "hash func not supported (only Toeplitz hash)\n"); return -EOPNOTSUPP; } if (!indir) { netdev_err(netdev, "set rss failed for indir is empty\n"); return -EOPNOTSUPP; } return h->ae_algo->ops->set_rss(h, indir, key, hfunc); }
static int hns3_set_rss(struct net_device *netdev, const u32 *indir, const u8 *key, const u8 hfunc) { struct hnae3_handle *h = hns3_get_handle(netdev); if (!h->ae_algo || !h->ae_algo->ops || !h->ae_algo->ops->set_rss) return -EOPNOTSUPP; if ((h->pdev->revision == 0x20 && hfunc != ETH_RSS_HASH_TOP) || (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP && hfunc != ETH_RSS_HASH_XOR)) { netdev_err(netdev, "hash func not supported\n"); return -EOPNOTSUPP; } if (!indir) { netdev_err(netdev, "set rss failed for indir is empty\n"); return -EOPNOTSUPP; } return h->ae_algo->ops->set_rss(h, indir, key, hfunc); }
static int hns3_set_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd) { struct hnae3_handle *h = hns3_get_handle(netdev); if (!h->ae_algo || !h->ae_algo->ops) return -EOPNOTSUPP; switch (cmd->cmd) { case ETHTOOL_SRXFH: if (h->ae_algo->ops->set_rss_tuple) return h->ae_algo->ops->set_rss_tuple(h, cmd); return -EOPNOTSUPP; case ETHTOOL_SRXCLSRLINS: if (h->ae_algo->ops->add_fd_entry) return h->ae_algo->ops->add_fd_entry(h, cmd); return -EOPNOTSUPP; case ETHTOOL_SRXCLSRLDEL: if (h->ae_algo->ops->del_fd_entry) return h->ae_algo->ops->del_fd_entry(h, cmd); return -EOPNOTSUPP; default: return -EOPNOTSUPP; } }
static int hns3_lp_up(struct net_device *ndev, enum hnae3_loop loop_mode) { struct hnae3_handle *h = hns3_get_handle(ndev); int ret; if (!h->ae_algo->ops->start) return -EOPNOTSUPP; ret = hns3_nic_reset_all_ring(h); if (ret) return ret; ret = h->ae_algo->ops->start(h); if (ret) { netdev_err(ndev, "hns3_lb_up ae start return error: %d\n", ret); return ret; } ret = hns3_lp_setup(ndev, loop_mode, true); usleep_range(10000, 20000); return ret; }