diff options
-rw-r--r-- | drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 36 | ||||
-rw-r--r-- | drivers/net/ethernet/mellanox/mlxsw/spectrum.h | 18 | ||||
-rw-r--r-- | drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c | 255 |
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 | ||
2495 | static struct mlxsw_driver mlxsw_sp_driver = { | 2495 | static 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 | ||
2514 | static int | 2518 | static 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 | ||
126 | struct mlxsw_cp_sb_occ { | ||
127 | u32 cur; | ||
128 | u32 max; | ||
129 | }; | ||
130 | |||
126 | struct mlxsw_sp_sb_cm { | 131 | struct 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 | ||
132 | struct mlxsw_sp_sb_pm { | 138 | struct 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); |
338 | int mlxsw_sp_sb_occ_snapshot(struct mlxsw_core *mlxsw_core, | ||
339 | unsigned int sb_index); | ||
340 | int mlxsw_sp_sb_occ_max_clear(struct mlxsw_core *mlxsw_core, | ||
341 | unsigned int sb_index); | ||
342 | int 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); | ||
345 | int 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 | ||
332 | int mlxsw_sp_switchdev_init(struct mlxsw_sp *mlxsw_sp); | 350 | int mlxsw_sp_switchdev_init(struct mlxsw_sp *mlxsw_sp); |
333 | void mlxsw_sp_switchdev_fini(struct mlxsw_sp *mlxsw_sp); | 351 | void 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 | ||
129 | static 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 | |||
140 | static 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 | |||
149 | static 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 | |||
128 | static const u16 mlxsw_sp_pbs[] = { | 164 | static 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 | |||
750 | struct mlxsw_sp_sb_sr_occ_query_cb_ctx { | ||
751 | u8 masked_count; | ||
752 | u8 local_port_1; | ||
753 | }; | ||
754 | |||
755 | static 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 | |||
799 | int 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 | |||
818 | next_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 | |||
848 | do_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 | |||
860 | out: | ||
861 | err2 = mlxsw_reg_trans_bulk_wait(&bulk_list); | ||
862 | if (!err) | ||
863 | err = err2; | ||
864 | kfree(sbsr_pl); | ||
865 | return err; | ||
866 | } | ||
867 | |||
868 | int 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 | |||
884 | next_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 | |||
913 | do_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 | |||
921 | out: | ||
922 | err2 = mlxsw_reg_trans_bulk_wait(&bulk_list); | ||
923 | if (!err) | ||
924 | err = err2; | ||
925 | kfree(sbsr_pl); | ||
926 | return err; | ||
927 | } | ||
928 | |||
929 | int 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 | |||
947 | int 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 | } | ||