@@ -569,7 +569,7 @@ mlxcx_cmd_queue_init(mlxcx_t *mlxp)
569569 return (B_FALSE );
570570 }
571571
572- cmd -> mcmd_mask = ( uint32_t )(( 1ULL << cmd -> mcmd_size ) - 1 ) ;
572+ cmd -> mcmd_next = 0 ;
573573
574574 mutex_init (& cmd -> mcmd_lock , NULL , MUTEX_DRIVER , NULL );
575575 cv_init (& cmd -> mcmd_cv , NULL , CV_DRIVER , NULL );
@@ -840,31 +840,34 @@ mlxcx_cmd_copy_output(mlxcx_cmd_ent_t *ent, mlxcx_cmd_t *cmd)
840840}
841841
842842static uint_t
843- mlxcx_cmd_reserve_slot (mlxcx_cmd_queue_t * cmdq )
843+ mlxcx_cmd_reserve_slot (mlxcx_cmd_queue_t * cmdq , mlxcx_cmd_t * cmd )
844844{
845- uint_t slot ;
846-
845+ uint_t i , slot ;
846+ ASSERT ( mutex_owned ( & cmd -> mlcmd_lock ));
847847 mutex_enter (& cmdq -> mcmd_lock );
848- slot = ddi_ffs (cmdq -> mcmd_mask );
849- while (slot == 0 ) {
848+ while (1 ) {
849+ for (i = 0 ; i < MLXCX_CMD_MAX ; ++ i ) {
850+ slot = (cmdq -> mcmd_next + i ) % MLXCX_CMD_MAX ;
851+ if (cmdq -> mcmd_active [slot ] == NULL )
852+ break ;
853+ }
854+ if (cmdq -> mcmd_active [slot ] == NULL ) {
855+ cmdq -> mcmd_active [slot ] = cmd ;
856+ cmdq -> mcmd_next = slot + 1 ;
857+ mutex_exit (& cmdq -> mcmd_lock );
858+ return (slot );
859+ }
850860 cv_wait (& cmdq -> mcmd_cv , & cmdq -> mcmd_lock );
851- slot = ddi_ffs (cmdq -> mcmd_mask );
852861 }
853-
854- cmdq -> mcmd_mask &= ~(1U << -- slot );
855-
856- ASSERT3P (cmdq -> mcmd_active [slot ], = = , NULL );
857-
858- mutex_exit (& cmdq -> mcmd_lock );
859-
860- return (slot );
861862}
862863
863864static void
864- mlxcx_cmd_release_slot (mlxcx_cmd_queue_t * cmdq , uint_t slot )
865+ mlxcx_cmd_release_slot (mlxcx_cmd_queue_t * cmdq , uint_t slot , mlxcx_cmd_t * cmd )
865866{
867+ ASSERT (mutex_owned (& cmd -> mlcmd_lock ));
866868 mutex_enter (& cmdq -> mcmd_lock );
867- cmdq -> mcmd_mask |= 1U << slot ;
869+ ASSERT3P (cmdq -> mcmd_active [slot ], = = , cmd );
870+ cmdq -> mcmd_active [slot ] = NULL ;
868871 cv_broadcast (& cmdq -> mcmd_cv );
869872 mutex_exit (& cmdq -> mcmd_lock );
870873}
@@ -876,6 +879,8 @@ mlxcx_cmd_done(mlxcx_cmd_t *cmd, uint_t slot)
876879 mlxcx_cmd_queue_t * cmdq = & mlxp -> mlx_cmd ;
877880 mlxcx_cmd_ent_t * ent ;
878881
882+ ASSERT (mutex_owned (& cmd -> mlcmd_lock ));
883+
879884 /*
880885 * Command is done. Save relevant data. Once we broadcast on the CV and
881886 * drop the lock, we must not touch it again.
@@ -885,17 +890,16 @@ mlxcx_cmd_done(mlxcx_cmd_t *cmd, uint_t slot)
885890 ent = (mlxcx_cmd_ent_t * )(cmdq -> mcmd_dma .mxdb_va +
886891 (slot << cmdq -> mcmd_stride_l2 ));
887892
888- mutex_enter (& cmd -> mlcmd_lock );
889893 cmd -> mlcmd_status = MLXCX_CMD_STATUS (ent -> mce_status );
890894 if (cmd -> mlcmd_status == 0 )
891895 mlxcx_cmd_copy_output (ent , cmd );
892896
893897 cmd -> mlcmd_state = MLXCX_CMD_S_DONE ;
894898 cv_broadcast (& cmd -> mlcmd_cv );
895- mutex_exit (& cmd -> mlcmd_lock );
896899
897- cmdq -> mcmd_active [slot ] = NULL ;
898- mlxcx_cmd_release_slot (cmdq , slot );
900+ mlxcx_cmd_release_slot (cmdq , slot , cmd );
901+
902+ mutex_exit (& cmd -> mlcmd_lock );
899903}
900904
901905static void
@@ -907,14 +911,14 @@ mlxcx_cmd_taskq(void *arg)
907911 mlxcx_cmd_ent_t * ent ;
908912 uint_t poll , slot ;
909913
910- ASSERT3S (cmd -> mlcmd_op , != , 0 );
914+ mutex_enter (& cmd -> mlcmd_lock );
915+
916+ VERIFY3S (cmd -> mlcmd_op , != , 0 );
911917
912- slot = mlxcx_cmd_reserve_slot (cmdq );
918+ slot = mlxcx_cmd_reserve_slot (cmdq , cmd );
913919 ent = (mlxcx_cmd_ent_t * )(cmdq -> mcmd_dma .mxdb_va +
914920 (slot << cmdq -> mcmd_stride_l2 ));
915921
916- cmdq -> mcmd_active [slot ] = cmd ;
917-
918922 /*
919923 * Command queue is currently ours as we set busy.
920924 */
@@ -924,15 +928,25 @@ mlxcx_cmd_taskq(void *arg)
924928 ent -> mce_out_length = to_be32 (cmd -> mlcmd_outlen );
925929 ent -> mce_token = cmd -> mlcmd_token ;
926930 ent -> mce_sig = 0 ;
927- ent -> mce_status = MLXCX_CMD_HW_OWNED ;
928931 mlxcx_cmd_prep_input (ent , cmd );
929932 mlxcx_cmd_prep_output (ent , cmd );
933+
934+ /*
935+ * Ensure all of the other fields of the entry are written before
936+ * we switch the owner to hardware (the device might start executing
937+ * right away)
938+ */
939+ membar_producer ();
940+ ent -> mce_status = MLXCX_CMD_HW_OWNED ;
941+
930942 MLXCX_DMA_SYNC (cmdq -> mcmd_dma , DDI_DMA_SYNC_FORDEV );
931943
932944 mlxcx_put32 (mlxp , MLXCX_ISS_CMD_DOORBELL , 1 << slot );
933945
934- if (!cmd -> mlcmd_poll )
946+ if (!cmd -> mlcmd_poll ) {
947+ mutex_exit (& cmd -> mlcmd_lock );
935948 return ;
949+ }
936950
937951 for (poll = 0 ; poll < mlxcx_cmd_tries ; poll ++ ) {
938952 delay (drv_usectohz (mlxcx_cmd_delay ));
@@ -947,21 +961,21 @@ mlxcx_cmd_taskq(void *arg)
947961 */
948962
949963 if (poll == mlxcx_cmd_tries ) {
950- mutex_enter (& cmd -> mlcmd_lock );
951964 cmd -> mlcmd_status = MLXCX_CMD_R_TIMEOUT ;
952965 cmd -> mlcmd_state = MLXCX_CMD_S_ERROR ;
953966 cv_broadcast (& cmd -> mlcmd_cv );
967+
968+ mlxcx_cmd_release_slot (cmdq , slot , cmd );
969+
954970 mutex_exit (& cmd -> mlcmd_lock );
955971
956972 mlxcx_fm_ereport (mlxp , DDI_FM_DEVICE_NO_RESPONSE );
957973
958- cmdq -> mcmd_active [slot ] = NULL ;
959- mlxcx_cmd_release_slot (cmdq , slot );
960-
961974 return ;
962975 }
963976
964977 mlxcx_cmd_done (cmd , slot );
978+ /* mlxcx_cmd_done releases mlcmd_lock */
965979}
966980
967981void
@@ -980,10 +994,17 @@ mlxcx_cmd_completion(mlxcx_t *mlxp, mlxcx_eventq_ent_t *ent)
980994 comp_vec &= ~(1U << -- slot );
981995
982996 cmd = cmdq -> mcmd_active [slot ];
997+
998+ /*
999+ * This field is never modified, so we shouldn't need to hold
1000+ * mlcmd_lock before checking it.
1001+ */
9831002 if (cmd -> mlcmd_poll )
9841003 continue ;
9851004
1005+ mutex_enter (& cmd -> mlcmd_lock );
9861006 mlxcx_cmd_done (cmd , slot );
1007+ /* mlxcx_cmd_done releases mlcmd_lock */
9871008 }
9881009}
9891010
0 commit comments