@@ -42,8 +42,19 @@ enum arm_smmu_msi_index {
4242 ARM_SMMU_MAX_MSIS ,
4343};
4444
45- static void arm_smmu_sync_ste_for_sid (struct arm_smmu_device * smmu ,
46- ioasid_t sid );
45+ struct arm_smmu_entry_writer_ops ;
46+ struct arm_smmu_entry_writer {
47+ const struct arm_smmu_entry_writer_ops * ops ;
48+ struct arm_smmu_master * master ;
49+ };
50+
51+ struct arm_smmu_entry_writer_ops {
52+ void (* get_used )(const __le64 * entry , __le64 * used );
53+ void (* sync )(struct arm_smmu_entry_writer * writer );
54+ };
55+
56+ #define NUM_ENTRY_QWORDS 8
57+ static_assert (sizeof (struct arm_smmu_ste ) == NUM_ENTRY_QWORDS * sizeof (u64 ));
4758
4859static phys_addr_t arm_smmu_msi_cfg [ARM_SMMU_MAX_MSIS ][3 ] = {
4960 [EVTQ_MSI_INDEX ] = {
@@ -972,43 +983,42 @@ void arm_smmu_tlb_inv_asid(struct arm_smmu_device *smmu, u16 asid)
972983 * would be nice if this was complete according to the spec, but minimally it
973984 * has to capture the bits this driver uses.
974985 */
975- static void arm_smmu_get_ste_used (const struct arm_smmu_ste * ent ,
976- struct arm_smmu_ste * used_bits )
986+ static void arm_smmu_get_ste_used (const __le64 * ent , __le64 * used_bits )
977987{
978- unsigned int cfg = FIELD_GET (STRTAB_STE_0_CFG , le64_to_cpu (ent -> data [0 ]));
988+ unsigned int cfg = FIELD_GET (STRTAB_STE_0_CFG , le64_to_cpu (ent [0 ]));
979989
980- used_bits -> data [0 ] = cpu_to_le64 (STRTAB_STE_0_V );
981- if (!(ent -> data [0 ] & cpu_to_le64 (STRTAB_STE_0_V )))
990+ used_bits [0 ] = cpu_to_le64 (STRTAB_STE_0_V );
991+ if (!(ent [0 ] & cpu_to_le64 (STRTAB_STE_0_V )))
982992 return ;
983993
984- used_bits -> data [0 ] |= cpu_to_le64 (STRTAB_STE_0_CFG );
994+ used_bits [0 ] |= cpu_to_le64 (STRTAB_STE_0_CFG );
985995
986996 /* S1 translates */
987997 if (cfg & BIT (0 )) {
988- used_bits -> data [0 ] |= cpu_to_le64 (STRTAB_STE_0_S1FMT |
989- STRTAB_STE_0_S1CTXPTR_MASK |
990- STRTAB_STE_0_S1CDMAX );
991- used_bits -> data [1 ] |=
998+ used_bits [0 ] |= cpu_to_le64 (STRTAB_STE_0_S1FMT |
999+ STRTAB_STE_0_S1CTXPTR_MASK |
1000+ STRTAB_STE_0_S1CDMAX );
1001+ used_bits [1 ] |=
9921002 cpu_to_le64 (STRTAB_STE_1_S1DSS | STRTAB_STE_1_S1CIR |
9931003 STRTAB_STE_1_S1COR | STRTAB_STE_1_S1CSH |
9941004 STRTAB_STE_1_S1STALLD | STRTAB_STE_1_STRW |
9951005 STRTAB_STE_1_EATS );
996- used_bits -> data [2 ] |= cpu_to_le64 (STRTAB_STE_2_S2VMID );
1006+ used_bits [2 ] |= cpu_to_le64 (STRTAB_STE_2_S2VMID );
9971007 }
9981008
9991009 /* S2 translates */
10001010 if (cfg & BIT (1 )) {
1001- used_bits -> data [1 ] |=
1011+ used_bits [1 ] |=
10021012 cpu_to_le64 (STRTAB_STE_1_EATS | STRTAB_STE_1_SHCFG );
1003- used_bits -> data [2 ] |=
1013+ used_bits [2 ] |=
10041014 cpu_to_le64 (STRTAB_STE_2_S2VMID | STRTAB_STE_2_VTCR |
10051015 STRTAB_STE_2_S2AA64 | STRTAB_STE_2_S2ENDI |
10061016 STRTAB_STE_2_S2PTW | STRTAB_STE_2_S2R );
1007- used_bits -> data [3 ] |= cpu_to_le64 (STRTAB_STE_3_S2TTB_MASK );
1017+ used_bits [3 ] |= cpu_to_le64 (STRTAB_STE_3_S2TTB_MASK );
10081018 }
10091019
10101020 if (cfg == STRTAB_STE_0_CFG_BYPASS )
1011- used_bits -> data [1 ] |= cpu_to_le64 (STRTAB_STE_1_SHCFG );
1021+ used_bits [1 ] |= cpu_to_le64 (STRTAB_STE_1_SHCFG );
10121022}
10131023
10141024/*
@@ -1017,57 +1027,55 @@ static void arm_smmu_get_ste_used(const struct arm_smmu_ste *ent,
10171027 * unused_update is an intermediate value of entry that has unused bits set to
10181028 * their new values.
10191029 */
1020- static u8 arm_smmu_entry_qword_diff (const struct arm_smmu_ste * entry ,
1021- const struct arm_smmu_ste * target ,
1022- struct arm_smmu_ste * unused_update )
1030+ static u8 arm_smmu_entry_qword_diff (struct arm_smmu_entry_writer * writer ,
1031+ const __le64 * entry , const __le64 * target ,
1032+ __le64 * unused_update )
10231033{
1024- struct arm_smmu_ste target_used = {};
1025- struct arm_smmu_ste cur_used = {};
1034+ __le64 target_used [ NUM_ENTRY_QWORDS ] = {};
1035+ __le64 cur_used [ NUM_ENTRY_QWORDS ] = {};
10261036 u8 used_qword_diff = 0 ;
10271037 unsigned int i ;
10281038
1029- arm_smmu_get_ste_used (entry , & cur_used );
1030- arm_smmu_get_ste_used (target , & target_used );
1039+ writer -> ops -> get_used (entry , cur_used );
1040+ writer -> ops -> get_used (target , target_used );
10311041
1032- for (i = 0 ; i != ARRAY_SIZE ( target_used . data ) ; i ++ ) {
1042+ for (i = 0 ; i != NUM_ENTRY_QWORDS ; i ++ ) {
10331043 /*
10341044 * Check that masks are up to date, the make functions are not
10351045 * allowed to set a bit to 1 if the used function doesn't say it
10361046 * is used.
10371047 */
1038- WARN_ON_ONCE (target -> data [i ] & ~target_used . data [i ]);
1048+ WARN_ON_ONCE (target [i ] & ~target_used [i ]);
10391049
10401050 /* Bits can change because they are not currently being used */
1041- unused_update -> data [i ] = (entry -> data [i ] & cur_used . data [i ]) |
1042- (target -> data [i ] & ~cur_used . data [i ]);
1051+ unused_update [i ] = (entry [i ] & cur_used [i ]) |
1052+ (target [i ] & ~cur_used [i ]);
10431053 /*
10441054 * Each bit indicates that a used bit in a qword needs to be
10451055 * changed after unused_update is applied.
10461056 */
1047- if ((unused_update -> data [i ] & target_used .data [i ]) !=
1048- target -> data [i ])
1057+ if ((unused_update [i ] & target_used [i ]) != target [i ])
10491058 used_qword_diff |= 1 << i ;
10501059 }
10511060 return used_qword_diff ;
10521061}
10531062
1054- static bool entry_set (struct arm_smmu_device * smmu , ioasid_t sid ,
1055- struct arm_smmu_ste * entry ,
1056- const struct arm_smmu_ste * target , unsigned int start ,
1063+ static bool entry_set (struct arm_smmu_entry_writer * writer , __le64 * entry ,
1064+ const __le64 * target , unsigned int start ,
10571065 unsigned int len )
10581066{
10591067 bool changed = false;
10601068 unsigned int i ;
10611069
10621070 for (i = start ; len != 0 ; len -- , i ++ ) {
1063- if (entry -> data [i ] != target -> data [i ]) {
1064- WRITE_ONCE (entry -> data [i ], target -> data [i ]);
1071+ if (entry [i ] != target [i ]) {
1072+ WRITE_ONCE (entry [i ], target [i ]);
10651073 changed = true;
10661074 }
10671075 }
10681076
10691077 if (changed )
1070- arm_smmu_sync_ste_for_sid ( smmu , sid );
1078+ writer -> ops -> sync ( writer );
10711079 return changed ;
10721080}
10731081
@@ -1097,24 +1105,21 @@ static bool entry_set(struct arm_smmu_device *smmu, ioasid_t sid,
10971105 * V=0 process. This relies on the IGNORED behavior described in the
10981106 * specification.
10991107 */
1100- static void arm_smmu_write_ste (struct arm_smmu_master * master , u32 sid ,
1101- struct arm_smmu_ste * entry ,
1102- const struct arm_smmu_ste * target )
1108+ static void arm_smmu_write_entry (struct arm_smmu_entry_writer * writer ,
1109+ __le64 * entry , const __le64 * target )
11031110{
1104- unsigned int num_entry_qwords = ARRAY_SIZE (target -> data );
1105- struct arm_smmu_device * smmu = master -> smmu ;
1106- struct arm_smmu_ste unused_update ;
1111+ __le64 unused_update [NUM_ENTRY_QWORDS ];
11071112 u8 used_qword_diff ;
11081113
11091114 used_qword_diff =
1110- arm_smmu_entry_qword_diff (entry , target , & unused_update );
1115+ arm_smmu_entry_qword_diff (writer , entry , target , unused_update );
11111116 if (hweight8 (used_qword_diff ) == 1 ) {
11121117 /*
11131118 * Only one qword needs its used bits to be changed. This is a
1114- * hitless update, update all bits the current STE is ignoring
1115- * to their new values, then update a single "critical qword" to
1116- * change the STE and finally 0 out any bits that are now unused
1117- * in the target configuration.
1119+ * hitless update, update all bits the current STE/CD is
1120+ * ignoring to their new values, then update a single "critical
1121+ * qword" to change the STE/CD and finally 0 out any bits that
1122+ * are now unused in the target configuration.
11181123 */
11191124 unsigned int critical_qword_index = ffs (used_qword_diff ) - 1 ;
11201125
@@ -1123,41 +1128,29 @@ static void arm_smmu_write_ste(struct arm_smmu_master *master, u32 sid,
11231128 * writing it in the next step anyways. This can save a sync
11241129 * when the only change is in that qword.
11251130 */
1126- unused_update . data [critical_qword_index ] =
1127- entry -> data [critical_qword_index ];
1128- entry_set (smmu , sid , entry , & unused_update , 0 , num_entry_qwords );
1129- entry_set (smmu , sid , entry , target , critical_qword_index , 1 );
1130- entry_set (smmu , sid , entry , target , 0 , num_entry_qwords );
1131+ unused_update [critical_qword_index ] =
1132+ entry [critical_qword_index ];
1133+ entry_set (writer , entry , unused_update , 0 , NUM_ENTRY_QWORDS );
1134+ entry_set (writer , entry , target , critical_qword_index , 1 );
1135+ entry_set (writer , entry , target , 0 , NUM_ENTRY_QWORDS );
11311136 } else if (used_qword_diff ) {
11321137 /*
11331138 * At least two qwords need their inuse bits to be changed. This
11341139 * requires a breaking update, zero the V bit, write all qwords
11351140 * but 0, then set qword 0
11361141 */
1137- unused_update .data [0 ] = entry -> data [0 ] &
1138- cpu_to_le64 (~STRTAB_STE_0_V );
1139- entry_set (smmu , sid , entry , & unused_update , 0 , 1 );
1140- entry_set (smmu , sid , entry , target , 1 , num_entry_qwords - 1 );
1141- entry_set (smmu , sid , entry , target , 0 , 1 );
1142+ unused_update [0 ] = 0 ;
1143+ entry_set (writer , entry , unused_update , 0 , 1 );
1144+ entry_set (writer , entry , target , 1 , NUM_ENTRY_QWORDS - 1 );
1145+ entry_set (writer , entry , target , 0 , 1 );
11421146 } else {
11431147 /*
11441148 * No inuse bit changed. Sanity check that all unused bits are 0
11451149 * in the entry. The target was already sanity checked by
11461150 * compute_qword_diff().
11471151 */
11481152 WARN_ON_ONCE (
1149- entry_set (smmu , sid , entry , target , 0 , num_entry_qwords ));
1150- }
1151-
1152- /* It's likely that we'll want to use the new STE soon */
1153- if (!(smmu -> options & ARM_SMMU_OPT_SKIP_PREFETCH )) {
1154- struct arm_smmu_cmdq_ent
1155- prefetch_cmd = { .opcode = CMDQ_OP_PREFETCH_CFG ,
1156- .prefetch = {
1157- .sid = sid ,
1158- } };
1159-
1160- arm_smmu_cmdq_issue_cmd (smmu , & prefetch_cmd );
1153+ entry_set (writer , entry , target , 0 , NUM_ENTRY_QWORDS ));
11611154 }
11621155}
11631156
@@ -1430,17 +1423,56 @@ arm_smmu_write_strtab_l1_desc(__le64 *dst, struct arm_smmu_strtab_l1_desc *desc)
14301423 WRITE_ONCE (* dst , cpu_to_le64 (val ));
14311424}
14321425
1433- static void arm_smmu_sync_ste_for_sid (struct arm_smmu_device * smmu , u32 sid )
1426+ struct arm_smmu_ste_writer {
1427+ struct arm_smmu_entry_writer writer ;
1428+ u32 sid ;
1429+ };
1430+
1431+ static void arm_smmu_ste_writer_sync_entry (struct arm_smmu_entry_writer * writer )
14341432{
1433+ struct arm_smmu_ste_writer * ste_writer =
1434+ container_of (writer , struct arm_smmu_ste_writer , writer );
14351435 struct arm_smmu_cmdq_ent cmd = {
14361436 .opcode = CMDQ_OP_CFGI_STE ,
14371437 .cfgi = {
1438- .sid = sid ,
1438+ .sid = ste_writer -> sid ,
14391439 .leaf = true,
14401440 },
14411441 };
14421442
1443- arm_smmu_cmdq_issue_cmd_with_sync (smmu , & cmd );
1443+ arm_smmu_cmdq_issue_cmd_with_sync (writer -> master -> smmu , & cmd );
1444+ }
1445+
1446+ static const struct arm_smmu_entry_writer_ops arm_smmu_ste_writer_ops = {
1447+ .sync = arm_smmu_ste_writer_sync_entry ,
1448+ .get_used = arm_smmu_get_ste_used ,
1449+ };
1450+
1451+ static void arm_smmu_write_ste (struct arm_smmu_master * master , u32 sid ,
1452+ struct arm_smmu_ste * ste ,
1453+ const struct arm_smmu_ste * target )
1454+ {
1455+ struct arm_smmu_device * smmu = master -> smmu ;
1456+ struct arm_smmu_ste_writer ste_writer = {
1457+ .writer = {
1458+ .ops = & arm_smmu_ste_writer_ops ,
1459+ .master = master ,
1460+ },
1461+ .sid = sid ,
1462+ };
1463+
1464+ arm_smmu_write_entry (& ste_writer .writer , ste -> data , target -> data );
1465+
1466+ /* It's likely that we'll want to use the new STE soon */
1467+ if (!(smmu -> options & ARM_SMMU_OPT_SKIP_PREFETCH )) {
1468+ struct arm_smmu_cmdq_ent
1469+ prefetch_cmd = { .opcode = CMDQ_OP_PREFETCH_CFG ,
1470+ .prefetch = {
1471+ .sid = sid ,
1472+ } };
1473+
1474+ arm_smmu_cmdq_issue_cmd (smmu , & prefetch_cmd );
1475+ }
14441476}
14451477
14461478static void arm_smmu_make_abort_ste (struct arm_smmu_ste * target )
0 commit comments