@@ -2049,50 +2049,81 @@ int of_find_last_cache_level(unsigned int cpu)
20492049 return cache_level ;
20502050}
20512051
2052+ /*
2053+ * Some DTs have an iommu-map targeting a 2-cell IOMMU node while
2054+ * specifying only 1 cell. Fortunately they all consist of value '1'
2055+ * as the 2nd cell entry with the same target, so check for that pattern.
2056+ *
2057+ * Example:
2058+ * IOMMU node:
2059+ * #iommu-cells = <2>;
2060+ *
2061+ * Device node:
2062+ * iommu-map = <0x0000 &smmu 0x0000 0x1>,
2063+ * <0x0100 &smmu 0x0100 0x1>;
2064+ */
2065+ static bool of_check_bad_map (const __be32 * map , int len )
2066+ {
2067+ __be32 phandle = map [1 ];
2068+
2069+ if (len % 4 )
2070+ return false;
2071+ for (int i = 0 ; i < len ; i += 4 ) {
2072+ if (map [i + 1 ] != phandle || map [i + 3 ] != cpu_to_be32 (1 ))
2073+ return false;
2074+ }
2075+ return true;
2076+ }
2077+
20522078/**
20532079 * of_map_id - Translate an ID through a downstream mapping.
20542080 * @np: root complex device node.
20552081 * @id: device ID to map.
20562082 * @map_name: property name of the map to use.
2083+ * @cells_name: property name of target specifier cells.
20572084 * @map_mask_name: optional property name of the mask to use.
2058- * @target: optional pointer to a target device node.
2059- * @id_out: optional pointer to receive the translated ID.
2085+ * @filter_np: optional device node to filter matches by, or NULL to match any.
2086+ * If non-NULL, only map entries targeting this node will be matched.
2087+ * @arg: pointer to a &struct of_phandle_args for the result. On success,
2088+ * @arg->args_count will be set to the number of output specifier cells
2089+ * as defined by @cells_name in the target node, and
2090+ * @arg->args[0..args_count-1] will contain the translated output
2091+ * specifier values. If a map entry was matched, @arg->np will be set
2092+ * to the target node with a reference held that the caller must release
2093+ * with of_node_put().
20602094 *
20612095 * Given a device ID, look up the appropriate implementation-defined
20622096 * platform ID and/or the target device which receives transactions on that
2063- * ID, as per the "iommu-map" and "msi-map" bindings. Either of @target or
2064- * @id_out may be NULL if only the other is required. If @target points to
2065- * a non-NULL device node pointer, only entries targeting that node will be
2066- * matched; if it points to a NULL value, it will receive the device node of
2067- * the first matching target phandle, with a reference held.
2097+ * ID, as per the "iommu-map" and "msi-map" bindings.
20682098 *
20692099 * Return: 0 on success or a standard error code on failure.
20702100 */
20712101int of_map_id (const struct device_node * np , u32 id ,
2072- const char * map_name , const char * map_mask_name ,
2073- struct device_node * * target , u32 * id_out )
2102+ const char * map_name , const char * cells_name ,
2103+ const char * map_mask_name ,
2104+ const struct device_node * filter_np , struct of_phandle_args * arg )
20742105{
20752106 u32 map_mask , masked_id ;
2076- int map_len ;
2107+ int map_bytes , map_len , offset = 0 ;
2108+ bool bad_map = false;
20772109 const __be32 * map = NULL ;
20782110
2079- if (!np || !map_name || (! target && ! id_out ) )
2111+ if (!np || !map_name || ! arg )
20802112 return - EINVAL ;
20812113
2082- map = of_get_property (np , map_name , & map_len );
2114+ map = of_get_property (np , map_name , & map_bytes );
20832115 if (!map ) {
2084- if (target )
2116+ if (filter_np )
20852117 return - ENODEV ;
20862118 /* Otherwise, no map implies no translation */
2087- * id_out = id ;
2119+ arg -> args [0 ] = id ;
2120+ arg -> args_count = 1 ;
20882121 return 0 ;
20892122 }
20902123
2091- if (!map_len || map_len % (4 * sizeof (* map ))) {
2092- pr_err ("%pOF: Error: Bad %s length: %d\n" , np ,
2093- map_name , map_len );
2094- return - EINVAL ;
2095- }
2124+ if (map_bytes % sizeof (* map ))
2125+ goto err_map_len ;
2126+ map_len = map_bytes / sizeof (* map );
20962127
20972128 /* The default is to select all bits. */
20982129 map_mask = 0xffffffff ;
@@ -2105,52 +2136,148 @@ int of_map_id(const struct device_node *np, u32 id,
21052136 of_property_read_u32 (np , map_mask_name , & map_mask );
21062137
21072138 masked_id = map_mask & id ;
2108- for ( ; map_len > 0 ; map_len -= 4 * sizeof (* map ), map += 4 ) {
2139+
2140+ while (offset < map_len ) {
21092141 struct device_node * phandle_node ;
2110- u32 id_base = be32_to_cpup (map + 0 );
2111- u32 phandle = be32_to_cpup (map + 1 );
2112- u32 out_base = be32_to_cpup (map + 2 );
2113- u32 id_len = be32_to_cpup (map + 3 );
2142+ u32 id_base , phandle , id_len , id_off , cells = 0 ;
2143+ const __be32 * out_base ;
2144+
2145+ if (map_len - offset < 2 )
2146+ goto err_map_len ;
2147+
2148+ id_base = be32_to_cpup (map + offset );
21142149
21152150 if (id_base & ~map_mask ) {
2116- pr_err ("%pOF: Invalid %s translation - %s-mask (0x%x) ignores id-base (0x%x)\n" ,
2117- np , map_name , map_name ,
2118- map_mask , id_base );
2151+ pr_err ("%pOF: Invalid %s translation - %s (0x%x) ignores id-base (0x%x)\n" ,
2152+ np , map_name , map_mask_name , map_mask , id_base );
21192153 return - EFAULT ;
21202154 }
21212155
2122- if (masked_id < id_base || masked_id >= id_base + id_len )
2123- continue ;
2124-
2156+ phandle = be32_to_cpup (map + offset + 1 );
21252157 phandle_node = of_find_node_by_phandle (phandle );
21262158 if (!phandle_node )
21272159 return - ENODEV ;
21282160
2129- if (target ) {
2130- if (* target )
2131- of_node_put (phandle_node );
2132- else
2133- * target = phandle_node ;
2161+ if (bad_map ) {
2162+ cells = 1 ;
2163+ } else if (of_property_read_u32 (phandle_node , cells_name , & cells )) {
2164+ pr_err ("%pOF: missing %s property\n" , phandle_node , cells_name );
2165+ of_node_put (phandle_node );
2166+ return - EINVAL ;
2167+ }
21342168
2135- if (* target != phandle_node )
2136- continue ;
2169+ if (map_len - offset < 3 + cells ) {
2170+ of_node_put (phandle_node );
2171+ goto err_map_len ;
21372172 }
21382173
2139- if (id_out )
2140- * id_out = masked_id - id_base + out_base ;
2174+ if (offset == 0 && cells == 2 ) {
2175+ bad_map = of_check_bad_map (map , map_len );
2176+ if (bad_map ) {
2177+ pr_warn_once ("%pOF: %s mismatches target %s, assuming extra cell of 0\n" ,
2178+ np , map_name , cells_name );
2179+ cells = 1 ;
2180+ }
2181+ }
2182+
2183+ out_base = map + offset + 2 ;
2184+ offset += 3 + cells ;
2185+
2186+ id_len = be32_to_cpup (map + offset - 1 );
2187+ if (id_len > 1 && cells > 1 ) {
2188+ /*
2189+ * With 1 output cell we reasonably assume its value
2190+ * has a linear relationship to the input; with more,
2191+ * we'd need help from the provider to know what to do.
2192+ */
2193+ pr_err ("%pOF: Unsupported %s - cannot handle %d-ID range with %d-cell output specifier\n" ,
2194+ np , map_name , id_len , cells );
2195+ of_node_put (phandle_node );
2196+ return - EINVAL ;
2197+ }
2198+ id_off = masked_id - id_base ;
2199+ if (masked_id < id_base || id_off >= id_len ) {
2200+ of_node_put (phandle_node );
2201+ continue ;
2202+ }
2203+
2204+ if (filter_np && filter_np != phandle_node ) {
2205+ of_node_put (phandle_node );
2206+ continue ;
2207+ }
2208+
2209+ arg -> np = phandle_node ;
2210+ for (int i = 0 ; i < cells ; i ++ )
2211+ arg -> args [i ] = id_off + be32_to_cpu (out_base [i ]);
2212+ arg -> args_count = cells ;
21412213
21422214 pr_debug ("%pOF: %s, using mask %08x, id-base: %08x, out-base: %08x, length: %08x, id: %08x -> %08x\n" ,
2143- np , map_name , map_mask , id_base , out_base ,
2144- id_len , id , masked_id - id_base + out_base );
2215+ np , map_name , map_mask , id_base , be32_to_cpup ( out_base ) ,
2216+ id_len , id , id_off + be32_to_cpup ( out_base ) );
21452217 return 0 ;
21462218 }
21472219
21482220 pr_info ("%pOF: no %s translation for id 0x%x on %pOF\n" , np , map_name ,
2149- id , target && * target ? * target : NULL );
2221+ id , filter_np );
21502222
21512223 /* Bypasses translation */
2152- if ( id_out )
2153- * id_out = id ;
2224+ arg -> args [ 0 ] = id ;
2225+ arg -> args_count = 1 ;
21542226 return 0 ;
2227+
2228+ err_map_len :
2229+ pr_err ("%pOF: Error: Bad %s length: %d\n" , np , map_name , map_bytes );
2230+ return - EINVAL ;
21552231}
21562232EXPORT_SYMBOL_GPL (of_map_id );
2233+
2234+ /**
2235+ * of_map_iommu_id - Translate an ID using "iommu-map" bindings.
2236+ * @np: root complex device node.
2237+ * @id: Requester ID of the device (e.g. PCI RID/BDF or a platform
2238+ * stream/device ID) used as the lookup key in the iommu-map table.
2239+ * @arg: pointer to a &struct of_phandle_args for the result. On success,
2240+ * @arg->args_count will be set to the number of output specifier cells
2241+ * and @arg->args[0..args_count-1] will contain the translated output
2242+ * specifier values. If a map entry was matched, @arg->np holds a
2243+ * reference to the target node that the caller must release with
2244+ * of_node_put().
2245+ *
2246+ * Convenience wrapper around of_map_id() using "iommu-map", "#iommu-cells",
2247+ * and "iommu-map-mask".
2248+ *
2249+ * Return: 0 on success or a standard error code on failure.
2250+ */
2251+ int of_map_iommu_id (const struct device_node * np , u32 id ,
2252+ struct of_phandle_args * arg )
2253+ {
2254+ return of_map_id (np , id , "iommu-map" , "#iommu-cells" , "iommu-map-mask" , NULL , arg );
2255+ }
2256+ EXPORT_SYMBOL_GPL (of_map_iommu_id );
2257+
2258+ /**
2259+ * of_map_msi_id - Translate an ID using "msi-map" bindings.
2260+ * @np: root complex device node.
2261+ * @id: Requester ID of the device (e.g. PCI RID/BDF or a platform
2262+ * stream/device ID) used as the lookup key in the msi-map table.
2263+ * @filter_np: optional MSI controller node to filter matches by, or NULL
2264+ * to match any. If non-NULL, only map entries targeting this node will
2265+ * be matched.
2266+ * @arg: pointer to a &struct of_phandle_args for the result. On success,
2267+ * @arg->args_count will be set to the number of output specifier cells
2268+ * and @arg->args[0..args_count-1] will contain the translated output
2269+ * specifier values. If a map entry was matched, @arg->np holds a
2270+ * reference to the target node that the caller must release with
2271+ * of_node_put().
2272+ *
2273+ * Convenience wrapper around of_map_id() using "msi-map", "#msi-cells",
2274+ * and "msi-map-mask".
2275+ *
2276+ * Return: 0 on success or a standard error code on failure.
2277+ */
2278+ int of_map_msi_id (const struct device_node * np , u32 id ,
2279+ const struct device_node * filter_np , struct of_phandle_args * arg )
2280+ {
2281+ return of_map_id (np , id , "msi-map" , "#msi-cells" , "msi-map-mask" , filter_np , arg );
2282+ }
2283+ EXPORT_SYMBOL_GPL (of_map_msi_id );
0 commit comments