3030/* Used by client hardware to identify a fixed telemetry entry*/
3131#define TELEM_CLIENT_FIXED_BLOCK_GUID 0x10000000
3232
33+ #define NUM_BYTES_QWORD (v ) ((v) << 3)
34+ #define SAMPLE_ID_OFFSET (v ) ((v) << 3)
35+
36+ #define NUM_BYTES_DWORD (v ) ((v) << 2)
37+ #define SAMPLE_ID_OFFSET32 (v ) ((v) << 2)
38+
39+ /* Protects access to the xarray of telemetry endpoint handles */
40+ static DEFINE_MUTEX (ep_lock );
41+
3342enum telem_type {
3443 TELEM_TYPE_PUNIT = 0 ,
3544 TELEM_TYPE_CRASHLOG ,
@@ -84,21 +93,195 @@ static int pmt_telem_header_decode(struct intel_pmt_entry *entry,
8493 return 0 ;
8594}
8695
96+ static int pmt_telem_add_endpoint (struct intel_pmt_entry * entry ,
97+ struct pci_dev * pdev )
98+ {
99+ struct telem_endpoint * ep ;
100+
101+ /* Endpoint lifetimes are managed by kref, not devres */
102+ entry -> ep = kzalloc (sizeof (* (entry -> ep )), GFP_KERNEL );
103+ if (!entry -> ep )
104+ return - ENOMEM ;
105+
106+ ep = entry -> ep ;
107+ ep -> pcidev = pdev ;
108+ ep -> header .access_type = entry -> header .access_type ;
109+ ep -> header .guid = entry -> header .guid ;
110+ ep -> header .base_offset = entry -> header .base_offset ;
111+ ep -> header .size = entry -> header .size ;
112+ ep -> base = entry -> base ;
113+ ep -> present = true;
114+
115+ kref_init (& ep -> kref );
116+
117+ return 0 ;
118+ }
119+
87120static DEFINE_XARRAY_ALLOC (telem_array );
88121static struct intel_pmt_namespace pmt_telem_ns = {
89122 .name = "telem" ,
90123 .xa = & telem_array ,
91124 .pmt_header_decode = pmt_telem_header_decode ,
125+ .pmt_add_endpoint = pmt_telem_add_endpoint ,
92126};
93127
128+ /* Called when all users unregister and the device is removed */
129+ static void pmt_telem_ep_release (struct kref * kref )
130+ {
131+ struct telem_endpoint * ep ;
132+
133+ ep = container_of (kref , struct telem_endpoint , kref );
134+ kfree (ep );
135+ }
136+
137+ unsigned long pmt_telem_get_next_endpoint (unsigned long start )
138+ {
139+ struct intel_pmt_entry * entry ;
140+ unsigned long found_idx ;
141+
142+ mutex_lock (& ep_lock );
143+ xa_for_each_start (& telem_array , found_idx , entry , start ) {
144+ /*
145+ * Return first found index after start.
146+ * 0 is not valid id.
147+ */
148+ if (found_idx > start )
149+ break ;
150+ }
151+ mutex_unlock (& ep_lock );
152+
153+ return found_idx == start ? 0 : found_idx ;
154+ }
155+ EXPORT_SYMBOL_NS_GPL (pmt_telem_get_next_endpoint , INTEL_PMT_TELEMETRY );
156+
157+ struct telem_endpoint * pmt_telem_register_endpoint (int devid )
158+ {
159+ struct intel_pmt_entry * entry ;
160+ unsigned long index = devid ;
161+
162+ mutex_lock (& ep_lock );
163+ entry = xa_find (& telem_array , & index , index , XA_PRESENT );
164+ if (!entry ) {
165+ mutex_unlock (& ep_lock );
166+ return ERR_PTR (- ENXIO );
167+ }
168+
169+ kref_get (& entry -> ep -> kref );
170+ mutex_unlock (& ep_lock );
171+
172+ return entry -> ep ;
173+ }
174+ EXPORT_SYMBOL_NS_GPL (pmt_telem_register_endpoint , INTEL_PMT_TELEMETRY );
175+
176+ void pmt_telem_unregister_endpoint (struct telem_endpoint * ep )
177+ {
178+ kref_put (& ep -> kref , pmt_telem_ep_release );
179+ }
180+ EXPORT_SYMBOL_NS_GPL (pmt_telem_unregister_endpoint , INTEL_PMT_TELEMETRY );
181+
182+ int pmt_telem_get_endpoint_info (int devid , struct telem_endpoint_info * info )
183+ {
184+ struct intel_pmt_entry * entry ;
185+ unsigned long index = devid ;
186+ int err = 0 ;
187+
188+ if (!info )
189+ return - EINVAL ;
190+
191+ mutex_lock (& ep_lock );
192+ entry = xa_find (& telem_array , & index , index , XA_PRESENT );
193+ if (!entry ) {
194+ err = - ENXIO ;
195+ goto unlock ;
196+ }
197+
198+ info -> pdev = entry -> ep -> pcidev ;
199+ info -> header = entry -> ep -> header ;
200+
201+ unlock :
202+ mutex_unlock (& ep_lock );
203+ return err ;
204+
205+ }
206+ EXPORT_SYMBOL_NS_GPL (pmt_telem_get_endpoint_info , INTEL_PMT_TELEMETRY );
207+
208+ int pmt_telem_read (struct telem_endpoint * ep , u32 id , u64 * data , u32 count )
209+ {
210+ u32 offset , size ;
211+
212+ if (!ep -> present )
213+ return - ENODEV ;
214+
215+ offset = SAMPLE_ID_OFFSET (id );
216+ size = ep -> header .size ;
217+
218+ if (offset + NUM_BYTES_QWORD (count ) > size )
219+ return - EINVAL ;
220+
221+ memcpy_fromio (data , ep -> base + offset , NUM_BYTES_QWORD (count ));
222+
223+ return ep -> present ? 0 : - EPIPE ;
224+ }
225+ EXPORT_SYMBOL_NS_GPL (pmt_telem_read , INTEL_PMT_TELEMETRY );
226+
227+ int pmt_telem_read32 (struct telem_endpoint * ep , u32 id , u32 * data , u32 count )
228+ {
229+ u32 offset , size ;
230+
231+ if (!ep -> present )
232+ return - ENODEV ;
233+
234+ offset = SAMPLE_ID_OFFSET32 (id );
235+ size = ep -> header .size ;
236+
237+ if (offset + NUM_BYTES_DWORD (count ) > size )
238+ return - EINVAL ;
239+
240+ memcpy_fromio (data , ep -> base + offset , NUM_BYTES_DWORD (count ));
241+
242+ return ep -> present ? 0 : - EPIPE ;
243+ }
244+ EXPORT_SYMBOL_NS_GPL (pmt_telem_read32 , INTEL_PMT_TELEMETRY );
245+
246+ struct telem_endpoint *
247+ pmt_telem_find_and_register_endpoint (struct pci_dev * pcidev , u32 guid , u16 pos )
248+ {
249+ int devid = 0 ;
250+ int inst = 0 ;
251+ int err = 0 ;
252+
253+ while ((devid = pmt_telem_get_next_endpoint (devid ))) {
254+ struct telem_endpoint_info ep_info ;
255+
256+ err = pmt_telem_get_endpoint_info (devid , & ep_info );
257+ if (err )
258+ return ERR_PTR (err );
259+
260+ if (ep_info .header .guid == guid && ep_info .pdev == pcidev ) {
261+ if (inst == pos )
262+ return pmt_telem_register_endpoint (devid );
263+ ++ inst ;
264+ }
265+ }
266+
267+ return ERR_PTR (- ENXIO );
268+ }
269+ EXPORT_SYMBOL_NS_GPL (pmt_telem_find_and_register_endpoint , INTEL_PMT_TELEMETRY );
270+
94271static void pmt_telem_remove (struct auxiliary_device * auxdev )
95272{
96273 struct pmt_telem_priv * priv = auxiliary_get_drvdata (auxdev );
97274 int i ;
98275
99- for (i = 0 ; i < priv -> num_entries ; i ++ )
100- intel_pmt_dev_destroy (& priv -> entry [i ], & pmt_telem_ns );
101- }
276+ mutex_lock (& ep_lock );
277+ for (i = 0 ; i < priv -> num_entries ; i ++ ) {
278+ struct intel_pmt_entry * entry = & priv -> entry [i ];
279+
280+ kref_put (& entry -> ep -> kref , pmt_telem_ep_release );
281+ intel_pmt_dev_destroy (entry , & pmt_telem_ns );
282+ }
283+ mutex_unlock (& ep_lock );
284+ };
102285
103286static int pmt_telem_probe (struct auxiliary_device * auxdev , const struct auxiliary_device_id * id )
104287{
@@ -117,7 +300,9 @@ static int pmt_telem_probe(struct auxiliary_device *auxdev, const struct auxilia
117300 for (i = 0 ; i < intel_vsec_dev -> num_resources ; i ++ ) {
118301 struct intel_pmt_entry * entry = & priv -> entry [priv -> num_entries ];
119302
303+ mutex_lock (& ep_lock );
120304 ret = intel_pmt_dev_create (entry , & pmt_telem_ns , intel_vsec_dev , i );
305+ mutex_unlock (& ep_lock );
121306 if (ret < 0 )
122307 goto abort_probe ;
123308 if (ret )
0 commit comments