3333#include <linux/processor.h>
3434#include <linux/refcount.h>
3535#include <linux/slab.h>
36+ #include <linux/xarray.h>
3637
3738#include "common.h"
3839#include "notify.h"
4445
4546static DEFINE_IDA (scmi_id );
4647
47- static DEFINE_IDR (scmi_protocols );
48- static DEFINE_SPINLOCK (protocol_lock );
48+ static DEFINE_XARRAY (scmi_protocols );
4949
5050/* List of all SCMI devices active in system */
5151static LIST_HEAD (scmi_list );
@@ -194,33 +194,141 @@ struct scmi_info {
194194#define bus_nb_to_scmi_info (nb ) container_of(nb, struct scmi_info, bus_nb)
195195#define req_nb_to_scmi_info (nb ) container_of(nb, struct scmi_info, dev_req_nb)
196196
197- static const struct scmi_protocol * scmi_protocol_get (int protocol_id )
197+ static unsigned long
198+ scmi_vendor_protocol_signature (unsigned int protocol_id , char * vendor_id ,
199+ char * sub_vendor_id , u32 impl_ver )
198200{
199- const struct scmi_protocol * proto ;
201+ char * signature , * p ;
202+ unsigned long hash = 0 ;
200203
201- proto = idr_find (& scmi_protocols , protocol_id );
204+ /* vendor_id/sub_vendor_id guaranteed <= SCMI_SHORT_NAME_MAX_SIZE */
205+ signature = kasprintf (GFP_KERNEL , "%02X|%s|%s|0x%08X" , protocol_id ,
206+ vendor_id ?: "" , sub_vendor_id ?: "" , impl_ver );
207+ if (!signature )
208+ return 0 ;
209+
210+ p = signature ;
211+ while (* p )
212+ hash = partial_name_hash (tolower (* p ++ ), hash );
213+ hash = end_name_hash (hash );
214+
215+ kfree (signature );
216+
217+ return hash ;
218+ }
219+
220+ static unsigned long
221+ scmi_protocol_key_calculate (int protocol_id , char * vendor_id ,
222+ char * sub_vendor_id , u32 impl_ver )
223+ {
224+ if (protocol_id < SCMI_PROTOCOL_VENDOR_BASE )
225+ return protocol_id ;
226+ else
227+ return scmi_vendor_protocol_signature (protocol_id , vendor_id ,
228+ sub_vendor_id , impl_ver );
229+ }
230+
231+ static const struct scmi_protocol *
232+ __scmi_vendor_protocol_lookup (int protocol_id , char * vendor_id ,
233+ char * sub_vendor_id , u32 impl_ver )
234+ {
235+ unsigned long key ;
236+ struct scmi_protocol * proto = NULL ;
237+
238+ key = scmi_protocol_key_calculate (protocol_id , vendor_id ,
239+ sub_vendor_id , impl_ver );
240+ if (key )
241+ proto = xa_load (& scmi_protocols , key );
242+
243+ return proto ;
244+ }
245+
246+ static const struct scmi_protocol *
247+ scmi_vendor_protocol_lookup (int protocol_id , char * vendor_id ,
248+ char * sub_vendor_id , u32 impl_ver )
249+ {
250+ const struct scmi_protocol * proto = NULL ;
251+
252+ /* Searching for closest match ...*/
253+ proto = __scmi_vendor_protocol_lookup (protocol_id , vendor_id ,
254+ sub_vendor_id , impl_ver );
255+ if (proto )
256+ return proto ;
257+
258+ /* Any match just on vendor/sub_vendor ? */
259+ if (impl_ver ) {
260+ proto = __scmi_vendor_protocol_lookup (protocol_id , vendor_id ,
261+ sub_vendor_id , 0 );
262+ if (proto )
263+ return proto ;
264+ }
265+
266+ /* Any match just on the vendor ? */
267+ if (sub_vendor_id )
268+ proto = __scmi_vendor_protocol_lookup (protocol_id , vendor_id ,
269+ NULL , 0 );
270+ return proto ;
271+ }
272+
273+ static const struct scmi_protocol *
274+ scmi_protocol_get (int protocol_id , struct scmi_revision_info * version )
275+ {
276+ const struct scmi_protocol * proto = NULL ;
277+
278+ if (protocol_id < SCMI_PROTOCOL_VENDOR_BASE )
279+ proto = xa_load (& scmi_protocols , protocol_id );
280+ else
281+ proto = scmi_vendor_protocol_lookup (protocol_id ,
282+ version -> vendor_id ,
283+ version -> sub_vendor_id ,
284+ version -> impl_ver );
202285 if (!proto || !try_module_get (proto -> owner )) {
203286 pr_warn ("SCMI Protocol 0x%x not found!\n" , protocol_id );
204287 return NULL ;
205288 }
206289
207290 pr_debug ("Found SCMI Protocol 0x%x\n" , protocol_id );
208291
292+ if (protocol_id >= SCMI_PROTOCOL_VENDOR_BASE )
293+ pr_info ("Loaded SCMI Vendor Protocol 0x%x - %s %s %X\n" ,
294+ protocol_id , proto -> vendor_id ?: "" ,
295+ proto -> sub_vendor_id ?: "" , proto -> impl_ver );
296+
209297 return proto ;
210298}
211299
212- static void scmi_protocol_put (int protocol_id )
300+ static void scmi_protocol_put (const struct scmi_protocol * proto )
213301{
214- const struct scmi_protocol * proto ;
215-
216- proto = idr_find (& scmi_protocols , protocol_id );
217302 if (proto )
218303 module_put (proto -> owner );
219304}
220305
306+ static int scmi_vendor_protocol_check (const struct scmi_protocol * proto )
307+ {
308+ if (!proto -> vendor_id ) {
309+ pr_err ("missing vendor_id for protocol 0x%x\n" , proto -> id );
310+ return - EINVAL ;
311+ }
312+
313+ if (strlen (proto -> vendor_id ) >= SCMI_SHORT_NAME_MAX_SIZE ) {
314+ pr_err ("malformed vendor_id for protocol 0x%x\n" , proto -> id );
315+ return - EINVAL ;
316+ }
317+
318+ if (proto -> sub_vendor_id &&
319+ strlen (proto -> sub_vendor_id ) >= SCMI_SHORT_NAME_MAX_SIZE ) {
320+ pr_err ("malformed sub_vendor_id for protocol 0x%x\n" ,
321+ proto -> id );
322+ return - EINVAL ;
323+ }
324+
325+ return 0 ;
326+ }
327+
221328int scmi_protocol_register (const struct scmi_protocol * proto )
222329{
223330 int ret ;
331+ unsigned long key ;
224332
225333 if (!proto ) {
226334 pr_err ("invalid protocol\n" );
@@ -232,12 +340,23 @@ int scmi_protocol_register(const struct scmi_protocol *proto)
232340 return - EINVAL ;
233341 }
234342
235- spin_lock (& protocol_lock );
236- ret = idr_alloc (& scmi_protocols , (void * )proto ,
237- proto -> id , proto -> id + 1 , GFP_ATOMIC );
238- spin_unlock (& protocol_lock );
239- if (ret != proto -> id ) {
240- pr_err ("unable to allocate SCMI idr slot for 0x%x - err %d\n" ,
343+ if (proto -> id >= SCMI_PROTOCOL_VENDOR_BASE &&
344+ scmi_vendor_protocol_check (proto ))
345+ return - EINVAL ;
346+
347+ /*
348+ * Calculate a protocol key to register this protocol with the core;
349+ * key value 0 is considered invalid.
350+ */
351+ key = scmi_protocol_key_calculate (proto -> id , proto -> vendor_id ,
352+ proto -> sub_vendor_id ,
353+ proto -> impl_ver );
354+ if (!key )
355+ return - EINVAL ;
356+
357+ ret = xa_insert (& scmi_protocols , key , (void * )proto , GFP_KERNEL );
358+ if (ret ) {
359+ pr_err ("unable to allocate SCMI protocol slot for 0x%x - err %d\n" ,
241360 proto -> id , ret );
242361 return ret ;
243362 }
@@ -250,9 +369,15 @@ EXPORT_SYMBOL_GPL(scmi_protocol_register);
250369
251370void scmi_protocol_unregister (const struct scmi_protocol * proto )
252371{
253- spin_lock (& protocol_lock );
254- idr_remove (& scmi_protocols , proto -> id );
255- spin_unlock (& protocol_lock );
372+ unsigned long key ;
373+
374+ key = scmi_protocol_key_calculate (proto -> id , proto -> vendor_id ,
375+ proto -> sub_vendor_id ,
376+ proto -> impl_ver );
377+ if (!key )
378+ return ;
379+
380+ xa_erase (& scmi_protocols , key );
256381
257382 pr_debug ("Unregistered SCMI Protocol 0x%x\n" , proto -> id );
258383}
@@ -1940,7 +2065,7 @@ scmi_alloc_init_protocol_instance(struct scmi_info *info,
19402065 /* Protocol specific devres group */
19412066 gid = devres_open_group (handle -> dev , NULL , GFP_KERNEL );
19422067 if (!gid ) {
1943- scmi_protocol_put (proto -> id );
2068+ scmi_protocol_put (proto );
19442069 goto out ;
19452070 }
19462071
@@ -2004,7 +2129,7 @@ scmi_alloc_init_protocol_instance(struct scmi_info *info,
20042129
20052130clean :
20062131 /* Take care to put the protocol module's owner before releasing all */
2007- scmi_protocol_put (proto -> id );
2132+ scmi_protocol_put (proto );
20082133 devres_release_group (handle -> dev , gid );
20092134out :
20102135 return ERR_PTR (ret );
@@ -2038,7 +2163,7 @@ scmi_get_protocol_instance(const struct scmi_handle *handle, u8 protocol_id)
20382163 const struct scmi_protocol * proto ;
20392164
20402165 /* Fails if protocol not registered on bus */
2041- proto = scmi_protocol_get (protocol_id );
2166+ proto = scmi_protocol_get (protocol_id , & info -> version );
20422167 if (proto )
20432168 pi = scmi_alloc_init_protocol_instance (info , proto );
20442169 else
@@ -2093,7 +2218,7 @@ void scmi_protocol_release(const struct scmi_handle *handle, u8 protocol_id)
20932218
20942219 idr_remove (& info -> protocols , protocol_id );
20952220
2096- scmi_protocol_put (protocol_id );
2221+ scmi_protocol_put (pi -> proto );
20972222
20982223 devres_release_group (handle -> dev , gid );
20992224 dev_dbg (handle -> dev , "De-Initialized protocol: 0x%X\n" ,
0 commit comments