@@ -144,6 +144,14 @@ static void arm_smmu_v3_test_ste_expect_transition(
144144 KUNIT_EXPECT_MEMEQ (test , target -> data , cur_copy .data , sizeof (cur_copy ));
145145}
146146
147+ static void arm_smmu_v3_test_ste_expect_non_hitless_transition (
148+ struct kunit * test , const struct arm_smmu_ste * cur ,
149+ const struct arm_smmu_ste * target , unsigned int num_syncs_expected )
150+ {
151+ arm_smmu_v3_test_ste_expect_transition (test , cur , target ,
152+ num_syncs_expected , false);
153+ }
154+
147155static void arm_smmu_v3_test_ste_expect_hitless_transition (
148156 struct kunit * test , const struct arm_smmu_ste * cur ,
149157 const struct arm_smmu_ste * target , unsigned int num_syncs_expected )
@@ -155,6 +163,7 @@ static void arm_smmu_v3_test_ste_expect_hitless_transition(
155163static const dma_addr_t fake_cdtab_dma_addr = 0xF0F0F0F0F0F0 ;
156164
157165static void arm_smmu_test_make_cdtable_ste (struct arm_smmu_ste * ste ,
166+ unsigned int s1dss ,
158167 const dma_addr_t dma_addr )
159168{
160169 struct arm_smmu_master master = {
@@ -164,7 +173,7 @@ static void arm_smmu_test_make_cdtable_ste(struct arm_smmu_ste *ste,
164173 .smmu = & smmu ,
165174 };
166175
167- arm_smmu_make_cdtable_ste (ste , & master , true, STRTAB_STE_1_S1DSS_SSID0 );
176+ arm_smmu_make_cdtable_ste (ste , & master , true, s1dss );
168177}
169178
170179static void arm_smmu_v3_write_ste_test_bypass_to_abort (struct kunit * test )
@@ -194,7 +203,8 @@ static void arm_smmu_v3_write_ste_test_cdtable_to_abort(struct kunit *test)
194203{
195204 struct arm_smmu_ste ste ;
196205
197- arm_smmu_test_make_cdtable_ste (& ste , fake_cdtab_dma_addr );
206+ arm_smmu_test_make_cdtable_ste (& ste , STRTAB_STE_1_S1DSS_SSID0 ,
207+ fake_cdtab_dma_addr );
198208 arm_smmu_v3_test_ste_expect_hitless_transition (test , & ste , & abort_ste ,
199209 NUM_EXPECTED_SYNCS (2 ));
200210}
@@ -203,7 +213,8 @@ static void arm_smmu_v3_write_ste_test_abort_to_cdtable(struct kunit *test)
203213{
204214 struct arm_smmu_ste ste ;
205215
206- arm_smmu_test_make_cdtable_ste (& ste , fake_cdtab_dma_addr );
216+ arm_smmu_test_make_cdtable_ste (& ste , STRTAB_STE_1_S1DSS_SSID0 ,
217+ fake_cdtab_dma_addr );
207218 arm_smmu_v3_test_ste_expect_hitless_transition (test , & abort_ste , & ste ,
208219 NUM_EXPECTED_SYNCS (2 ));
209220}
@@ -212,7 +223,8 @@ static void arm_smmu_v3_write_ste_test_cdtable_to_bypass(struct kunit *test)
212223{
213224 struct arm_smmu_ste ste ;
214225
215- arm_smmu_test_make_cdtable_ste (& ste , fake_cdtab_dma_addr );
226+ arm_smmu_test_make_cdtable_ste (& ste , STRTAB_STE_1_S1DSS_SSID0 ,
227+ fake_cdtab_dma_addr );
216228 arm_smmu_v3_test_ste_expect_hitless_transition (test , & ste , & bypass_ste ,
217229 NUM_EXPECTED_SYNCS (3 ));
218230}
@@ -221,11 +233,54 @@ static void arm_smmu_v3_write_ste_test_bypass_to_cdtable(struct kunit *test)
221233{
222234 struct arm_smmu_ste ste ;
223235
224- arm_smmu_test_make_cdtable_ste (& ste , fake_cdtab_dma_addr );
236+ arm_smmu_test_make_cdtable_ste (& ste , STRTAB_STE_1_S1DSS_SSID0 ,
237+ fake_cdtab_dma_addr );
225238 arm_smmu_v3_test_ste_expect_hitless_transition (test , & bypass_ste , & ste ,
226239 NUM_EXPECTED_SYNCS (3 ));
227240}
228241
242+ static void arm_smmu_v3_write_ste_test_cdtable_s1dss_change (struct kunit * test )
243+ {
244+ struct arm_smmu_ste ste ;
245+ struct arm_smmu_ste s1dss_bypass ;
246+
247+ arm_smmu_test_make_cdtable_ste (& ste , STRTAB_STE_1_S1DSS_SSID0 ,
248+ fake_cdtab_dma_addr );
249+ arm_smmu_test_make_cdtable_ste (& s1dss_bypass , STRTAB_STE_1_S1DSS_BYPASS ,
250+ fake_cdtab_dma_addr );
251+
252+ /*
253+ * Flipping s1dss on a CD table STE only involves changes to the second
254+ * qword of an STE and can be done in a single write.
255+ */
256+ arm_smmu_v3_test_ste_expect_hitless_transition (
257+ test , & ste , & s1dss_bypass , NUM_EXPECTED_SYNCS (1 ));
258+ arm_smmu_v3_test_ste_expect_hitless_transition (
259+ test , & s1dss_bypass , & ste , NUM_EXPECTED_SYNCS (1 ));
260+ }
261+
262+ static void
263+ arm_smmu_v3_write_ste_test_s1dssbypass_to_stebypass (struct kunit * test )
264+ {
265+ struct arm_smmu_ste s1dss_bypass ;
266+
267+ arm_smmu_test_make_cdtable_ste (& s1dss_bypass , STRTAB_STE_1_S1DSS_BYPASS ,
268+ fake_cdtab_dma_addr );
269+ arm_smmu_v3_test_ste_expect_hitless_transition (
270+ test , & s1dss_bypass , & bypass_ste , NUM_EXPECTED_SYNCS (2 ));
271+ }
272+
273+ static void
274+ arm_smmu_v3_write_ste_test_stebypass_to_s1dssbypass (struct kunit * test )
275+ {
276+ struct arm_smmu_ste s1dss_bypass ;
277+
278+ arm_smmu_test_make_cdtable_ste (& s1dss_bypass , STRTAB_STE_1_S1DSS_BYPASS ,
279+ fake_cdtab_dma_addr );
280+ arm_smmu_v3_test_ste_expect_hitless_transition (
281+ test , & bypass_ste , & s1dss_bypass , NUM_EXPECTED_SYNCS (2 ));
282+ }
283+
229284static void arm_smmu_test_make_s2_ste (struct arm_smmu_ste * ste ,
230285 bool ats_enabled )
231286{
@@ -285,6 +340,48 @@ static void arm_smmu_v3_write_ste_test_bypass_to_s2(struct kunit *test)
285340 NUM_EXPECTED_SYNCS (2 ));
286341}
287342
343+ static void arm_smmu_v3_write_ste_test_s1_to_s2 (struct kunit * test )
344+ {
345+ struct arm_smmu_ste s1_ste ;
346+ struct arm_smmu_ste s2_ste ;
347+
348+ arm_smmu_test_make_cdtable_ste (& s1_ste , STRTAB_STE_1_S1DSS_SSID0 ,
349+ fake_cdtab_dma_addr );
350+ arm_smmu_test_make_s2_ste (& s2_ste , true);
351+ arm_smmu_v3_test_ste_expect_hitless_transition (test , & s1_ste , & s2_ste ,
352+ NUM_EXPECTED_SYNCS (3 ));
353+ }
354+
355+ static void arm_smmu_v3_write_ste_test_s2_to_s1 (struct kunit * test )
356+ {
357+ struct arm_smmu_ste s1_ste ;
358+ struct arm_smmu_ste s2_ste ;
359+
360+ arm_smmu_test_make_cdtable_ste (& s1_ste , STRTAB_STE_1_S1DSS_SSID0 ,
361+ fake_cdtab_dma_addr );
362+ arm_smmu_test_make_s2_ste (& s2_ste , true);
363+ arm_smmu_v3_test_ste_expect_hitless_transition (test , & s2_ste , & s1_ste ,
364+ NUM_EXPECTED_SYNCS (3 ));
365+ }
366+
367+ static void arm_smmu_v3_write_ste_test_non_hitless (struct kunit * test )
368+ {
369+ struct arm_smmu_ste ste ;
370+ struct arm_smmu_ste ste_2 ;
371+
372+ /*
373+ * Although no flow resembles this in practice, one way to force an STE
374+ * update to be non-hitless is to change its CD table pointer as well as
375+ * s1 dss field in the same update.
376+ */
377+ arm_smmu_test_make_cdtable_ste (& ste , STRTAB_STE_1_S1DSS_SSID0 ,
378+ fake_cdtab_dma_addr );
379+ arm_smmu_test_make_cdtable_ste (& ste_2 , STRTAB_STE_1_S1DSS_BYPASS ,
380+ 0x4B4B4b4B4B );
381+ arm_smmu_v3_test_ste_expect_non_hitless_transition (
382+ test , & ste , & ste_2 , NUM_EXPECTED_SYNCS (3 ));
383+ }
384+
288385static void arm_smmu_v3_test_cd_expect_transition (
289386 struct kunit * test , const struct arm_smmu_cd * cur ,
290387 const struct arm_smmu_cd * target , unsigned int num_syncs_expected ,
@@ -438,10 +535,16 @@ static struct kunit_case arm_smmu_v3_test_cases[] = {
438535 KUNIT_CASE (arm_smmu_v3_write_ste_test_abort_to_cdtable ),
439536 KUNIT_CASE (arm_smmu_v3_write_ste_test_cdtable_to_bypass ),
440537 KUNIT_CASE (arm_smmu_v3_write_ste_test_bypass_to_cdtable ),
538+ KUNIT_CASE (arm_smmu_v3_write_ste_test_cdtable_s1dss_change ),
539+ KUNIT_CASE (arm_smmu_v3_write_ste_test_s1dssbypass_to_stebypass ),
540+ KUNIT_CASE (arm_smmu_v3_write_ste_test_stebypass_to_s1dssbypass ),
441541 KUNIT_CASE (arm_smmu_v3_write_ste_test_s2_to_abort ),
442542 KUNIT_CASE (arm_smmu_v3_write_ste_test_abort_to_s2 ),
443543 KUNIT_CASE (arm_smmu_v3_write_ste_test_s2_to_bypass ),
444544 KUNIT_CASE (arm_smmu_v3_write_ste_test_bypass_to_s2 ),
545+ KUNIT_CASE (arm_smmu_v3_write_ste_test_s1_to_s2 ),
546+ KUNIT_CASE (arm_smmu_v3_write_ste_test_s2_to_s1 ),
547+ KUNIT_CASE (arm_smmu_v3_write_ste_test_non_hitless ),
445548 KUNIT_CASE (arm_smmu_v3_write_cd_test_s1_clear ),
446549 KUNIT_CASE (arm_smmu_v3_write_cd_test_s1_change_asid ),
447550 KUNIT_CASE (arm_smmu_v3_write_cd_test_sva_clear ),
0 commit comments