aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum.c36
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum.h18
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c255
3 files changed, 293 insertions, 16 deletions
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
index ecadb15c4907..681afe1a3802 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
@@ -2493,22 +2493,26 @@ static struct mlxsw_config_profile mlxsw_sp_config_profile = {
2493}; 2493};
2494 2494
2495static struct mlxsw_driver mlxsw_sp_driver = { 2495static struct mlxsw_driver mlxsw_sp_driver = {
2496 .kind = MLXSW_DEVICE_KIND_SPECTRUM, 2496 .kind = MLXSW_DEVICE_KIND_SPECTRUM,
2497 .owner = THIS_MODULE, 2497 .owner = THIS_MODULE,
2498 .priv_size = sizeof(struct mlxsw_sp), 2498 .priv_size = sizeof(struct mlxsw_sp),
2499 .init = mlxsw_sp_init, 2499 .init = mlxsw_sp_init,
2500 .fini = mlxsw_sp_fini, 2500 .fini = mlxsw_sp_fini,
2501 .port_split = mlxsw_sp_port_split, 2501 .port_split = mlxsw_sp_port_split,
2502 .port_unsplit = mlxsw_sp_port_unsplit, 2502 .port_unsplit = mlxsw_sp_port_unsplit,
2503 .sb_pool_get = mlxsw_sp_sb_pool_get, 2503 .sb_pool_get = mlxsw_sp_sb_pool_get,
2504 .sb_pool_set = mlxsw_sp_sb_pool_set, 2504 .sb_pool_set = mlxsw_sp_sb_pool_set,
2505 .sb_port_pool_get = mlxsw_sp_sb_port_pool_get, 2505 .sb_port_pool_get = mlxsw_sp_sb_port_pool_get,
2506 .sb_port_pool_set = mlxsw_sp_sb_port_pool_set, 2506 .sb_port_pool_set = mlxsw_sp_sb_port_pool_set,
2507 .sb_tc_pool_bind_get = mlxsw_sp_sb_tc_pool_bind_get, 2507 .sb_tc_pool_bind_get = mlxsw_sp_sb_tc_pool_bind_get,
2508 .sb_tc_pool_bind_set = mlxsw_sp_sb_tc_pool_bind_set, 2508 .sb_tc_pool_bind_set = mlxsw_sp_sb_tc_pool_bind_set,
2509 .txhdr_construct = mlxsw_sp_txhdr_construct, 2509 .sb_occ_snapshot = mlxsw_sp_sb_occ_snapshot,
2510 .txhdr_len = MLXSW_TXHDR_LEN, 2510 .sb_occ_max_clear = mlxsw_sp_sb_occ_max_clear,
2511 .profile = &mlxsw_sp_config_profile, 2511 .sb_occ_port_pool_get = mlxsw_sp_sb_occ_port_pool_get,
2512 .sb_occ_tc_port_bind_get = mlxsw_sp_sb_occ_tc_port_bind_get,
2513 .txhdr_construct = mlxsw_sp_txhdr_construct,
2514 .txhdr_len = MLXSW_TXHDR_LEN,
2515 .profile = &mlxsw_sp_config_profile,
2512}; 2516};
2513 2517
2514static int 2518static int
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
index 6458efa5607e..e2c022d3e2f3 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
@@ -123,15 +123,22 @@ struct mlxsw_sp_sb_pr {
123 u32 size; 123 u32 size;
124}; 124};
125 125
126struct mlxsw_cp_sb_occ {
127 u32 cur;
128 u32 max;
129};
130
126struct mlxsw_sp_sb_cm { 131struct mlxsw_sp_sb_cm {
127 u32 min_buff; 132 u32 min_buff;
128 u32 max_buff; 133 u32 max_buff;
129 u8 pool; 134 u8 pool;
135 struct mlxsw_cp_sb_occ occ;
130}; 136};
131 137
132struct mlxsw_sp_sb_pm { 138struct mlxsw_sp_sb_pm {
133 u32 min_buff; 139 u32 min_buff;
134 u32 max_buff; 140 u32 max_buff;
141 struct mlxsw_cp_sb_occ occ;
135}; 142};
136 143
137#define MLXSW_SP_SB_POOL_COUNT 4 144#define MLXSW_SP_SB_POOL_COUNT 4
@@ -328,6 +335,17 @@ int mlxsw_sp_sb_tc_pool_bind_set(struct mlxsw_core_port *mlxsw_core_port,
328 unsigned int sb_index, u16 tc_index, 335 unsigned int sb_index, u16 tc_index,
329 enum devlink_sb_pool_type pool_type, 336 enum devlink_sb_pool_type pool_type,
330 u16 pool_index, u32 threshold); 337 u16 pool_index, u32 threshold);
338int mlxsw_sp_sb_occ_snapshot(struct mlxsw_core *mlxsw_core,
339 unsigned int sb_index);
340int mlxsw_sp_sb_occ_max_clear(struct mlxsw_core *mlxsw_core,
341 unsigned int sb_index);
342int mlxsw_sp_sb_occ_port_pool_get(struct mlxsw_core_port *mlxsw_core_port,
343 unsigned int sb_index, u16 pool_index,
344 u32 *p_cur, u32 *p_max);
345int mlxsw_sp_sb_occ_tc_port_bind_get(struct mlxsw_core_port *mlxsw_core_port,
346 unsigned int sb_index, u16 tc_index,
347 enum devlink_sb_pool_type pool_type,
348 u32 *p_cur, u32 *p_max);
331 349
332int mlxsw_sp_switchdev_init(struct mlxsw_sp *mlxsw_sp); 350int mlxsw_sp_switchdev_init(struct mlxsw_sp *mlxsw_sp);
333void mlxsw_sp_switchdev_fini(struct mlxsw_sp *mlxsw_sp); 351void mlxsw_sp_switchdev_fini(struct mlxsw_sp *mlxsw_sp);
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c
index 639ba5ae8bbd..f2e073af5dd2 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c
@@ -36,6 +36,7 @@
36#include <linux/types.h> 36#include <linux/types.h>
37#include <linux/dcbnl.h> 37#include <linux/dcbnl.h>
38#include <linux/if_ether.h> 38#include <linux/if_ether.h>
39#include <linux/list.h>
39 40
40#include "spectrum.h" 41#include "spectrum.h"
41#include "core.h" 42#include "core.h"
@@ -125,6 +126,41 @@ static int mlxsw_sp_sb_pm_write(struct mlxsw_sp *mlxsw_sp, u8 local_port,
125 return 0; 126 return 0;
126} 127}
127 128
129static int mlxsw_sp_sb_pm_occ_clear(struct mlxsw_sp *mlxsw_sp, u8 local_port,
130 u8 pool, enum mlxsw_reg_sbxx_dir dir,
131 struct list_head *bulk_list)
132{
133 char sbpm_pl[MLXSW_REG_SBPM_LEN];
134
135 mlxsw_reg_sbpm_pack(sbpm_pl, local_port, pool, dir, true, 0, 0);
136 return mlxsw_reg_trans_query(mlxsw_sp->core, MLXSW_REG(sbpm), sbpm_pl,
137 bulk_list, NULL, 0);
138}
139
140static void mlxsw_sp_sb_pm_occ_query_cb(struct mlxsw_core *mlxsw_core,
141 char *sbpm_pl, size_t sbpm_pl_len,
142 unsigned long cb_priv)
143{
144 struct mlxsw_sp_sb_pm *pm = (struct mlxsw_sp_sb_pm *) cb_priv;
145
146 mlxsw_reg_sbpm_unpack(sbpm_pl, &pm->occ.cur, &pm->occ.max);
147}
148
149static int mlxsw_sp_sb_pm_occ_query(struct mlxsw_sp *mlxsw_sp, u8 local_port,
150 u8 pool, enum mlxsw_reg_sbxx_dir dir,
151 struct list_head *bulk_list)
152{
153 char sbpm_pl[MLXSW_REG_SBPM_LEN];
154 struct mlxsw_sp_sb_pm *pm;
155
156 pm = mlxsw_sp_sb_pm_get(mlxsw_sp, local_port, pool, dir);
157 mlxsw_reg_sbpm_pack(sbpm_pl, local_port, pool, dir, false, 0, 0);
158 return mlxsw_reg_trans_query(mlxsw_sp->core, MLXSW_REG(sbpm), sbpm_pl,
159 bulk_list,
160 mlxsw_sp_sb_pm_occ_query_cb,
161 (unsigned long) pm);
162}
163
128static const u16 mlxsw_sp_pbs[] = { 164static const u16 mlxsw_sp_pbs[] = {
129 2 * MLXSW_SP_BYTES_TO_CELLS(ETH_FRAME_LEN), 165 2 * MLXSW_SP_BYTES_TO_CELLS(ETH_FRAME_LEN),
130 0, 166 0,
@@ -707,3 +743,222 @@ int mlxsw_sp_sb_tc_pool_bind_set(struct mlxsw_core_port *mlxsw_core_port,
707 return mlxsw_sp_sb_cm_write(mlxsw_sp, local_port, pg_buff, dir, 743 return mlxsw_sp_sb_cm_write(mlxsw_sp, local_port, pg_buff, dir,
708 0, max_buff, pool); 744 0, max_buff, pool);
709} 745}
746
747#define MASKED_COUNT_MAX \
748 (MLXSW_REG_SBSR_REC_MAX_COUNT / (MLXSW_SP_SB_TC_COUNT * 2))
749
750struct mlxsw_sp_sb_sr_occ_query_cb_ctx {
751 u8 masked_count;
752 u8 local_port_1;
753};
754
755static void mlxsw_sp_sb_sr_occ_query_cb(struct mlxsw_core *mlxsw_core,
756 char *sbsr_pl, size_t sbsr_pl_len,
757 unsigned long cb_priv)
758{
759 struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
760 struct mlxsw_sp_sb_sr_occ_query_cb_ctx cb_ctx;
761 u8 masked_count;
762 u8 local_port;
763 int rec_index = 0;
764 struct mlxsw_sp_sb_cm *cm;
765 int i;
766
767 memcpy(&cb_ctx, &cb_priv, sizeof(cb_ctx));
768
769 masked_count = 0;
770 for (local_port = cb_ctx.local_port_1;
771 local_port < MLXSW_PORT_MAX_PORTS; local_port++) {
772 if (!mlxsw_sp->ports[local_port])
773 continue;
774 for (i = 0; i < MLXSW_SP_SB_TC_COUNT; i++) {
775 cm = mlxsw_sp_sb_cm_get(mlxsw_sp, local_port, i,
776 MLXSW_REG_SBXX_DIR_INGRESS);
777 mlxsw_reg_sbsr_rec_unpack(sbsr_pl, rec_index++,
778 &cm->occ.cur, &cm->occ.max);
779 }
780 if (++masked_count == cb_ctx.masked_count)
781 break;
782 }
783 masked_count = 0;
784 for (local_port = cb_ctx.local_port_1;
785 local_port < MLXSW_PORT_MAX_PORTS; local_port++) {
786 if (!mlxsw_sp->ports[local_port])
787 continue;
788 for (i = 0; i < MLXSW_SP_SB_TC_COUNT; i++) {
789 cm = mlxsw_sp_sb_cm_get(mlxsw_sp, local_port, i,
790 MLXSW_REG_SBXX_DIR_EGRESS);
791 mlxsw_reg_sbsr_rec_unpack(sbsr_pl, rec_index++,
792 &cm->occ.cur, &cm->occ.max);
793 }
794 if (++masked_count == cb_ctx.masked_count)
795 break;
796 }
797}
798
799int mlxsw_sp_sb_occ_snapshot(struct mlxsw_core *mlxsw_core,
800 unsigned int sb_index)
801{
802 struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
803 struct mlxsw_sp_sb_sr_occ_query_cb_ctx cb_ctx;
804 unsigned long cb_priv;
805 LIST_HEAD(bulk_list);
806 char *sbsr_pl;
807 u8 masked_count;
808 u8 local_port_1;
809 u8 local_port = 0;
810 int i;
811 int err;
812 int err2;
813
814 sbsr_pl = kmalloc(MLXSW_REG_SBSR_LEN, GFP_KERNEL);
815 if (!sbsr_pl)
816 return -ENOMEM;
817
818next_batch:
819 local_port++;
820 local_port_1 = local_port;
821 masked_count = 0;
822 mlxsw_reg_sbsr_pack(sbsr_pl, false);
823 for (i = 0; i < MLXSW_SP_SB_TC_COUNT; i++) {
824 mlxsw_reg_sbsr_pg_buff_mask_set(sbsr_pl, i, 1);
825 mlxsw_reg_sbsr_tclass_mask_set(sbsr_pl, i, 1);
826 }
827 for (; local_port < MLXSW_PORT_MAX_PORTS; local_port++) {
828 if (!mlxsw_sp->ports[local_port])
829 continue;
830 mlxsw_reg_sbsr_ingress_port_mask_set(sbsr_pl, local_port, 1);
831 mlxsw_reg_sbsr_egress_port_mask_set(sbsr_pl, local_port, 1);
832 for (i = 0; i < MLXSW_SP_SB_POOL_COUNT; i++) {
833 err = mlxsw_sp_sb_pm_occ_query(mlxsw_sp, local_port, i,
834 MLXSW_REG_SBXX_DIR_INGRESS,
835 &bulk_list);
836 if (err)
837 goto out;
838 err = mlxsw_sp_sb_pm_occ_query(mlxsw_sp, local_port, i,
839 MLXSW_REG_SBXX_DIR_EGRESS,
840 &bulk_list);
841 if (err)
842 goto out;
843 }
844 if (++masked_count == MASKED_COUNT_MAX)
845 goto do_query;
846 }
847
848do_query:
849 cb_ctx.masked_count = masked_count;
850 cb_ctx.local_port_1 = local_port_1;
851 memcpy(&cb_priv, &cb_ctx, sizeof(cb_ctx));
852 err = mlxsw_reg_trans_query(mlxsw_core, MLXSW_REG(sbsr), sbsr_pl,
853 &bulk_list, mlxsw_sp_sb_sr_occ_query_cb,
854 cb_priv);
855 if (err)
856 goto out;
857 if (local_port < MLXSW_PORT_MAX_PORTS)
858 goto next_batch;
859
860out:
861 err2 = mlxsw_reg_trans_bulk_wait(&bulk_list);
862 if (!err)
863 err = err2;
864 kfree(sbsr_pl);
865 return err;
866}
867
868int mlxsw_sp_sb_occ_max_clear(struct mlxsw_core *mlxsw_core,
869 unsigned int sb_index)
870{
871 struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
872 LIST_HEAD(bulk_list);
873 char *sbsr_pl;
874 unsigned int masked_count;
875 u8 local_port = 0;
876 int i;
877 int err;
878 int err2;
879
880 sbsr_pl = kmalloc(MLXSW_REG_SBSR_LEN, GFP_KERNEL);
881 if (!sbsr_pl)
882 return -ENOMEM;
883
884next_batch:
885 local_port++;
886 masked_count = 0;
887 mlxsw_reg_sbsr_pack(sbsr_pl, true);
888 for (i = 0; i < MLXSW_SP_SB_TC_COUNT; i++) {
889 mlxsw_reg_sbsr_pg_buff_mask_set(sbsr_pl, i, 1);
890 mlxsw_reg_sbsr_tclass_mask_set(sbsr_pl, i, 1);
891 }
892 for (; local_port < MLXSW_PORT_MAX_PORTS; local_port++) {
893 if (!mlxsw_sp->ports[local_port])
894 continue;
895 mlxsw_reg_sbsr_ingress_port_mask_set(sbsr_pl, local_port, 1);
896 mlxsw_reg_sbsr_egress_port_mask_set(sbsr_pl, local_port, 1);
897 for (i = 0; i < MLXSW_SP_SB_POOL_COUNT; i++) {
898 err = mlxsw_sp_sb_pm_occ_clear(mlxsw_sp, local_port, i,
899 MLXSW_REG_SBXX_DIR_INGRESS,
900 &bulk_list);
901 if (err)
902 goto out;
903 err = mlxsw_sp_sb_pm_occ_clear(mlxsw_sp, local_port, i,
904 MLXSW_REG_SBXX_DIR_EGRESS,
905 &bulk_list);
906 if (err)
907 goto out;
908 }
909 if (++masked_count == MASKED_COUNT_MAX)
910 goto do_query;
911 }
912
913do_query:
914 err = mlxsw_reg_trans_query(mlxsw_core, MLXSW_REG(sbsr), sbsr_pl,
915 &bulk_list, NULL, 0);
916 if (err)
917 goto out;
918 if (local_port < MLXSW_PORT_MAX_PORTS)
919 goto next_batch;
920
921out:
922 err2 = mlxsw_reg_trans_bulk_wait(&bulk_list);
923 if (!err)
924 err = err2;
925 kfree(sbsr_pl);
926 return err;
927}
928
929int mlxsw_sp_sb_occ_port_pool_get(struct mlxsw_core_port *mlxsw_core_port,
930 unsigned int sb_index, u16 pool_index,
931 u32 *p_cur, u32 *p_max)
932{
933 struct mlxsw_sp_port *mlxsw_sp_port =
934 mlxsw_core_port_driver_priv(mlxsw_core_port);
935 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
936 u8 local_port = mlxsw_sp_port->local_port;
937 u8 pool = pool_get(pool_index);
938 enum mlxsw_reg_sbxx_dir dir = dir_get(pool_index);
939 struct mlxsw_sp_sb_pm *pm = mlxsw_sp_sb_pm_get(mlxsw_sp, local_port,
940 pool, dir);
941
942 *p_cur = MLXSW_SP_CELLS_TO_BYTES(pm->occ.cur);
943 *p_max = MLXSW_SP_CELLS_TO_BYTES(pm->occ.max);
944 return 0;
945}
946
947int mlxsw_sp_sb_occ_tc_port_bind_get(struct mlxsw_core_port *mlxsw_core_port,
948 unsigned int sb_index, u16 tc_index,
949 enum devlink_sb_pool_type pool_type,
950 u32 *p_cur, u32 *p_max)
951{
952 struct mlxsw_sp_port *mlxsw_sp_port =
953 mlxsw_core_port_driver_priv(mlxsw_core_port);
954 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
955 u8 local_port = mlxsw_sp_port->local_port;
956 u8 pg_buff = tc_index;
957 enum mlxsw_reg_sbxx_dir dir = pool_type;
958 struct mlxsw_sp_sb_cm *cm = mlxsw_sp_sb_cm_get(mlxsw_sp, local_port,
959 pg_buff, dir);
960
961 *p_cur = MLXSW_SP_CELLS_TO_BYTES(cm->occ.cur);
962 *p_max = MLXSW_SP_CELLS_TO_BYTES(cm->occ.max);
963 return 0;
964}