summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNogah Frankel <nogahf@mellanox.com>2016-09-16 09:05:38 -0400
committerDavid S. Miller <davem@davemloft.net>2016-09-18 22:33:42 -0400
commitfc1bbb0f1831cc22326c86fb21d88cca44999b3e (patch)
tree9ac04fd87ecd80fd0a46b03b48748ba06c8075d7
parent69ae6ad2ff37911903a90256e216d7e7ae460002 (diff)
mlxsw: spectrum: Implement offload stats ndo and expose HW stats by default
Change the default statistics ndo to return HW statistics (like the one returned by ethtool_ops). The HW stats are collected to a cache by delayed work every 1 sec. Implement the offload stat ndo. Add a function to get SW statistics, to be called from this function. Signed-off-by: Nogah Frankel <nogahf@mellanox.com> Signed-off-by: Jiri Pirko <jiri@mellanox.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum.c129
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum.h5
2 files changed, 127 insertions, 7 deletions
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
index 27bbcaf9cfcd..171f8dd19efa 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
@@ -819,9 +819,9 @@ err_span_port_mtu_update:
819 return err; 819 return err;
820} 820}
821 821
822static struct rtnl_link_stats64 * 822int
823mlxsw_sp_port_get_stats64(struct net_device *dev, 823mlxsw_sp_port_get_sw_stats64(const struct net_device *dev,
824 struct rtnl_link_stats64 *stats) 824 struct rtnl_link_stats64 *stats)
825{ 825{
826 struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); 826 struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
827 struct mlxsw_sp_port_pcpu_stats *p; 827 struct mlxsw_sp_port_pcpu_stats *p;
@@ -848,6 +848,107 @@ mlxsw_sp_port_get_stats64(struct net_device *dev,
848 tx_dropped += p->tx_dropped; 848 tx_dropped += p->tx_dropped;
849 } 849 }
850 stats->tx_dropped = tx_dropped; 850 stats->tx_dropped = tx_dropped;
851 return 0;
852}
853
854bool mlxsw_sp_port_has_offload_stats(int attr_id)
855{
856 switch (attr_id) {
857 case IFLA_OFFLOAD_XSTATS_CPU_HIT:
858 return true;
859 }
860
861 return false;
862}
863
864int mlxsw_sp_port_get_offload_stats(int attr_id, const struct net_device *dev,
865 void *sp)
866{
867 switch (attr_id) {
868 case IFLA_OFFLOAD_XSTATS_CPU_HIT:
869 return mlxsw_sp_port_get_sw_stats64(dev, sp);
870 }
871
872 return -EINVAL;
873}
874
875static int mlxsw_sp_port_get_stats_raw(struct net_device *dev, int grp,
876 int prio, char *ppcnt_pl)
877{
878 struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
879 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
880
881 mlxsw_reg_ppcnt_pack(ppcnt_pl, mlxsw_sp_port->local_port, grp, prio);
882 return mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(ppcnt), ppcnt_pl);
883}
884
885static int mlxsw_sp_port_get_hw_stats(struct net_device *dev,
886 struct rtnl_link_stats64 *stats)
887{
888 char ppcnt_pl[MLXSW_REG_PPCNT_LEN];
889 int err;
890
891 err = mlxsw_sp_port_get_stats_raw(dev, MLXSW_REG_PPCNT_IEEE_8023_CNT,
892 0, ppcnt_pl);
893 if (err)
894 goto out;
895
896 stats->tx_packets =
897 mlxsw_reg_ppcnt_a_frames_transmitted_ok_get(ppcnt_pl);
898 stats->rx_packets =
899 mlxsw_reg_ppcnt_a_frames_received_ok_get(ppcnt_pl);
900 stats->tx_bytes =
901 mlxsw_reg_ppcnt_a_octets_transmitted_ok_get(ppcnt_pl);
902 stats->rx_bytes =
903 mlxsw_reg_ppcnt_a_octets_received_ok_get(ppcnt_pl);
904 stats->multicast =
905 mlxsw_reg_ppcnt_a_multicast_frames_received_ok_get(ppcnt_pl);
906
907 stats->rx_crc_errors =
908 mlxsw_reg_ppcnt_a_frame_check_sequence_errors_get(ppcnt_pl);
909 stats->rx_frame_errors =
910 mlxsw_reg_ppcnt_a_alignment_errors_get(ppcnt_pl);
911
912 stats->rx_length_errors = (
913 mlxsw_reg_ppcnt_a_in_range_length_errors_get(ppcnt_pl) +
914 mlxsw_reg_ppcnt_a_out_of_range_length_field_get(ppcnt_pl) +
915 mlxsw_reg_ppcnt_a_frame_too_long_errors_get(ppcnt_pl));
916
917 stats->rx_errors = (stats->rx_crc_errors +
918 stats->rx_frame_errors + stats->rx_length_errors);
919
920out:
921 return err;
922}
923
924static void update_stats_cache(struct work_struct *work)
925{
926 struct mlxsw_sp_port *mlxsw_sp_port =
927 container_of(work, struct mlxsw_sp_port,
928 hw_stats.update_dw.work);
929
930 if (!netif_carrier_ok(mlxsw_sp_port->dev))
931 goto out;
932
933 mlxsw_sp_port_get_hw_stats(mlxsw_sp_port->dev,
934 mlxsw_sp_port->hw_stats.cache);
935
936out:
937 mlxsw_core_schedule_dw(&mlxsw_sp_port->hw_stats.update_dw,
938 MLXSW_HW_STATS_UPDATE_TIME);
939}
940
941/* Return the stats from a cache that is updated periodically,
942 * as this function might get called in an atomic context.
943 */
944static struct rtnl_link_stats64 *
945mlxsw_sp_port_get_stats64(struct net_device *dev,
946 struct rtnl_link_stats64 *stats)
947{
948 struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
949
950 memcpy(stats, mlxsw_sp_port->hw_stats.cache, sizeof(*stats));
951
851 return stats; 952 return stats;
852} 953}
853 954
@@ -1209,6 +1310,8 @@ static const struct net_device_ops mlxsw_sp_port_netdev_ops = {
1209 .ndo_set_mac_address = mlxsw_sp_port_set_mac_address, 1310 .ndo_set_mac_address = mlxsw_sp_port_set_mac_address,
1210 .ndo_change_mtu = mlxsw_sp_port_change_mtu, 1311 .ndo_change_mtu = mlxsw_sp_port_change_mtu,
1211 .ndo_get_stats64 = mlxsw_sp_port_get_stats64, 1312 .ndo_get_stats64 = mlxsw_sp_port_get_stats64,
1313 .ndo_has_offload_stats = mlxsw_sp_port_has_offload_stats,
1314 .ndo_get_offload_stats = mlxsw_sp_port_get_offload_stats,
1212 .ndo_vlan_rx_add_vid = mlxsw_sp_port_add_vid, 1315 .ndo_vlan_rx_add_vid = mlxsw_sp_port_add_vid,
1213 .ndo_vlan_rx_kill_vid = mlxsw_sp_port_kill_vid, 1316 .ndo_vlan_rx_kill_vid = mlxsw_sp_port_kill_vid,
1214 .ndo_neigh_construct = mlxsw_sp_router_neigh_construct, 1317 .ndo_neigh_construct = mlxsw_sp_router_neigh_construct,
@@ -1547,8 +1650,6 @@ static void __mlxsw_sp_port_get_stats(struct net_device *dev,
1547 enum mlxsw_reg_ppcnt_grp grp, int prio, 1650 enum mlxsw_reg_ppcnt_grp grp, int prio,
1548 u64 *data, int data_index) 1651 u64 *data, int data_index)
1549{ 1652{
1550 struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
1551 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1552 struct mlxsw_sp_port_hw_stats *hw_stats; 1653 struct mlxsw_sp_port_hw_stats *hw_stats;
1553 char ppcnt_pl[MLXSW_REG_PPCNT_LEN]; 1654 char ppcnt_pl[MLXSW_REG_PPCNT_LEN];
1554 int i, len; 1655 int i, len;
@@ -1557,8 +1658,7 @@ static void __mlxsw_sp_port_get_stats(struct net_device *dev,
1557 err = mlxsw_sp_get_hw_stats_by_group(&hw_stats, &len, grp); 1658 err = mlxsw_sp_get_hw_stats_by_group(&hw_stats, &len, grp);
1558 if (err) 1659 if (err)
1559 return; 1660 return;
1560 mlxsw_reg_ppcnt_pack(ppcnt_pl, mlxsw_sp_port->local_port, grp, prio); 1661 mlxsw_sp_port_get_stats_raw(dev, grp, prio, ppcnt_pl);
1561 err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(ppcnt), ppcnt_pl);
1562 for (i = 0; i < len; i++) 1662 for (i = 0; i < len; i++)
1563 data[data_index + i] = !err ? hw_stats[i].getter(ppcnt_pl) : 0; 1663 data[data_index + i] = !err ? hw_stats[i].getter(ppcnt_pl) : 0;
1564} 1664}
@@ -2145,6 +2245,16 @@ static int mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port,
2145 goto err_alloc_stats; 2245 goto err_alloc_stats;
2146 } 2246 }
2147 2247
2248 mlxsw_sp_port->hw_stats.cache =
2249 kzalloc(sizeof(*mlxsw_sp_port->hw_stats.cache), GFP_KERNEL);
2250
2251 if (!mlxsw_sp_port->hw_stats.cache) {
2252 err = -ENOMEM;
2253 goto err_alloc_hw_stats;
2254 }
2255 INIT_DELAYED_WORK(&mlxsw_sp_port->hw_stats.update_dw,
2256 &update_stats_cache);
2257
2148 dev->netdev_ops = &mlxsw_sp_port_netdev_ops; 2258 dev->netdev_ops = &mlxsw_sp_port_netdev_ops;
2149 dev->ethtool_ops = &mlxsw_sp_port_ethtool_ops; 2259 dev->ethtool_ops = &mlxsw_sp_port_ethtool_ops;
2150 2260
@@ -2245,6 +2355,7 @@ static int mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port,
2245 goto err_core_port_init; 2355 goto err_core_port_init;
2246 } 2356 }
2247 2357
2358 mlxsw_core_schedule_dw(&mlxsw_sp_port->hw_stats.update_dw, 0);
2248 return 0; 2359 return 0;
2249 2360
2250err_core_port_init: 2361err_core_port_init:
@@ -2265,6 +2376,8 @@ err_port_system_port_mapping_set:
2265err_dev_addr_init: 2376err_dev_addr_init:
2266 mlxsw_sp_port_swid_set(mlxsw_sp_port, MLXSW_PORT_SWID_DISABLED_PORT); 2377 mlxsw_sp_port_swid_set(mlxsw_sp_port, MLXSW_PORT_SWID_DISABLED_PORT);
2267err_port_swid_set: 2378err_port_swid_set:
2379 kfree(mlxsw_sp_port->hw_stats.cache);
2380err_alloc_hw_stats:
2268 free_percpu(mlxsw_sp_port->pcpu_stats); 2381 free_percpu(mlxsw_sp_port->pcpu_stats);
2269err_alloc_stats: 2382err_alloc_stats:
2270 kfree(mlxsw_sp_port->untagged_vlans); 2383 kfree(mlxsw_sp_port->untagged_vlans);
@@ -2281,6 +2394,7 @@ static void mlxsw_sp_port_remove(struct mlxsw_sp *mlxsw_sp, u8 local_port)
2281 2394
2282 if (!mlxsw_sp_port) 2395 if (!mlxsw_sp_port)
2283 return; 2396 return;
2397 cancel_delayed_work_sync(&mlxsw_sp_port->hw_stats.update_dw);
2284 mlxsw_core_port_fini(&mlxsw_sp_port->core_port); 2398 mlxsw_core_port_fini(&mlxsw_sp_port->core_port);
2285 unregister_netdev(mlxsw_sp_port->dev); /* This calls ndo_stop */ 2399 unregister_netdev(mlxsw_sp_port->dev); /* This calls ndo_stop */
2286 mlxsw_sp->ports[local_port] = NULL; 2400 mlxsw_sp->ports[local_port] = NULL;
@@ -2290,6 +2404,7 @@ static void mlxsw_sp_port_remove(struct mlxsw_sp *mlxsw_sp, u8 local_port)
2290 mlxsw_sp_port_swid_set(mlxsw_sp_port, MLXSW_PORT_SWID_DISABLED_PORT); 2404 mlxsw_sp_port_swid_set(mlxsw_sp_port, MLXSW_PORT_SWID_DISABLED_PORT);
2291 mlxsw_sp_port_module_unmap(mlxsw_sp, mlxsw_sp_port->local_port); 2405 mlxsw_sp_port_module_unmap(mlxsw_sp, mlxsw_sp_port->local_port);
2292 free_percpu(mlxsw_sp_port->pcpu_stats); 2406 free_percpu(mlxsw_sp_port->pcpu_stats);
2407 kfree(mlxsw_sp_port->hw_stats.cache);
2293 kfree(mlxsw_sp_port->untagged_vlans); 2408 kfree(mlxsw_sp_port->untagged_vlans);
2294 kfree(mlxsw_sp_port->active_vlans); 2409 kfree(mlxsw_sp_port->active_vlans);
2295 WARN_ON_ONCE(!list_empty(&mlxsw_sp_port->vports_list)); 2410 WARN_ON_ONCE(!list_empty(&mlxsw_sp_port->vports_list));
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
index 969c250b3048..49f4cafce148 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
@@ -361,6 +361,11 @@ struct mlxsw_sp_port {
361 struct list_head vports_list; 361 struct list_head vports_list;
362 /* TC handles */ 362 /* TC handles */
363 struct list_head mall_tc_list; 363 struct list_head mall_tc_list;
364 struct {
365 #define MLXSW_HW_STATS_UPDATE_TIME HZ
366 struct rtnl_link_stats64 *cache;
367 struct delayed_work update_dw;
368 } hw_stats;
364}; 369};
365 370
366struct mlxsw_sp_port *mlxsw_sp_port_lower_dev_hold(struct net_device *dev); 371struct mlxsw_sp_port *mlxsw_sp_port_lower_dev_hold(struct net_device *dev);