17
17
#include <linux/debugfs.h>
18
18
#include <linux/capability.h>
19
19
#include <linux/pm_qos.h>
20
+ #include <linux/wait.h>
20
21
21
22
#include <asm/iosf_mbi.h>
22
23
@@ -201,23 +202,45 @@ EXPORT_SYMBOL(iosf_mbi_available);
201
202
#define PUNIT_SEMAPHORE_BIT BIT(0)
202
203
#define PUNIT_SEMAPHORE_ACQUIRE BIT(1)
203
204
204
- static DEFINE_MUTEX (iosf_mbi_punit_mutex );
205
- static DEFINE_MUTEX (iosf_mbi_block_punit_i2c_access_count_mutex );
205
+ static DEFINE_MUTEX (iosf_mbi_pmic_access_mutex );
206
206
static BLOCKING_NOTIFIER_HEAD (iosf_mbi_pmic_bus_access_notifier );
207
- static u32 iosf_mbi_block_punit_i2c_access_count ;
207
+ static DECLARE_WAIT_QUEUE_HEAD (iosf_mbi_pmic_access_waitq );
208
+ static u32 iosf_mbi_pmic_punit_access_count ;
209
+ static u32 iosf_mbi_pmic_i2c_access_count ;
208
210
static u32 iosf_mbi_sem_address ;
209
211
static unsigned long iosf_mbi_sem_acquired ;
210
212
static struct pm_qos_request iosf_mbi_pm_qos ;
211
213
212
214
void iosf_mbi_punit_acquire (void )
213
215
{
214
- mutex_lock (& iosf_mbi_punit_mutex );
216
+ /* Wait for any I2C PMIC accesses from in kernel drivers to finish. */
217
+ mutex_lock (& iosf_mbi_pmic_access_mutex );
218
+ while (iosf_mbi_pmic_i2c_access_count != 0 ) {
219
+ mutex_unlock (& iosf_mbi_pmic_access_mutex );
220
+ wait_event (iosf_mbi_pmic_access_waitq ,
221
+ iosf_mbi_pmic_i2c_access_count == 0 );
222
+ mutex_lock (& iosf_mbi_pmic_access_mutex );
223
+ }
224
+ /*
225
+ * We do not need to do anything to allow the PUNIT to safely access
226
+ * the PMIC, other then block in kernel accesses to the PMIC.
227
+ */
228
+ iosf_mbi_pmic_punit_access_count ++ ;
229
+ mutex_unlock (& iosf_mbi_pmic_access_mutex );
215
230
}
216
231
EXPORT_SYMBOL (iosf_mbi_punit_acquire );
217
232
218
233
void iosf_mbi_punit_release (void )
219
234
{
220
- mutex_unlock (& iosf_mbi_punit_mutex );
235
+ bool do_wakeup ;
236
+
237
+ mutex_lock (& iosf_mbi_pmic_access_mutex );
238
+ iosf_mbi_pmic_punit_access_count -- ;
239
+ do_wakeup = iosf_mbi_pmic_punit_access_count == 0 ;
240
+ mutex_unlock (& iosf_mbi_pmic_access_mutex );
241
+
242
+ if (do_wakeup )
243
+ wake_up (& iosf_mbi_pmic_access_waitq );
221
244
}
222
245
EXPORT_SYMBOL (iosf_mbi_punit_release );
223
246
@@ -256,34 +279,32 @@ static void iosf_mbi_reset_semaphore(void)
256
279
* already blocked P-Unit accesses because it wants them blocked over multiple
257
280
* i2c-transfers, for e.g. read-modify-write of an I2C client register.
258
281
*
259
- * The P-Unit accesses already being blocked is tracked through the
260
- * iosf_mbi_block_punit_i2c_access_count variable which is protected by the
261
- * iosf_mbi_block_punit_i2c_access_count_mutex this mutex is hold for the
262
- * entire duration of the function.
263
- *
264
- * If access is not blocked yet, this function takes the following steps:
282
+ * To allow safe PMIC i2c bus accesses this function takes the following steps:
265
283
*
266
284
* 1) Some code sends request to the P-Unit which make it access the PMIC
267
285
* I2C bus. Testing has shown that the P-Unit does not check its internal
268
286
* PMIC bus semaphore for these requests. Callers of these requests call
269
287
* iosf_mbi_punit_acquire()/_release() around their P-Unit accesses, these
270
- * functions lock/unlock the iosf_mbi_punit_mutex.
271
- * As the first step we lock the iosf_mbi_punit_mutex, to wait for any in
272
- * flight requests to finish and to block any new requests.
288
+ * functions increase/decrease iosf_mbi_pmic_punit_access_count, so first
289
+ * we wait for iosf_mbi_pmic_punit_access_count to become 0.
290
+ *
291
+ * 2) Check iosf_mbi_pmic_i2c_access_count, if access has already
292
+ * been blocked by another caller, we only need to increment
293
+ * iosf_mbi_pmic_i2c_access_count and we can skip the other steps.
273
294
*
274
- * 2 ) Some code makes such P-Unit requests from atomic contexts where it
295
+ * 3 ) Some code makes such P-Unit requests from atomic contexts where it
275
296
* cannot call iosf_mbi_punit_acquire() as that may sleep.
276
297
* As the second step we call a notifier chain which allows any code
277
298
* needing P-Unit resources from atomic context to acquire them before
278
299
* we take control over the PMIC I2C bus.
279
300
*
280
- * 3 ) When CPU cores enter C6 or C7 the P-Unit needs to talk to the PMIC
301
+ * 4 ) When CPU cores enter C6 or C7 the P-Unit needs to talk to the PMIC
281
302
* if this happens while the kernel itself is accessing the PMIC I2C bus
282
303
* the SoC hangs.
283
304
* As the third step we call pm_qos_update_request() to disallow the CPU
284
305
* to enter C6 or C7.
285
306
*
286
- * 4 ) The P-Unit has a PMIC bus semaphore which we can request to stop
307
+ * 5 ) The P-Unit has a PMIC bus semaphore which we can request to stop
287
308
* autonomous P-Unit tasks from accessing the PMIC I2C bus while we hold it.
288
309
* As the fourth and final step we request this semaphore and wait for our
289
310
* request to be acknowledged.
@@ -297,12 +318,18 @@ int iosf_mbi_block_punit_i2c_access(void)
297
318
if (WARN_ON (!mbi_pdev || !iosf_mbi_sem_address ))
298
319
return - ENXIO ;
299
320
300
- mutex_lock (& iosf_mbi_block_punit_i2c_access_count_mutex );
321
+ mutex_lock (& iosf_mbi_pmic_access_mutex );
301
322
302
- if (iosf_mbi_block_punit_i2c_access_count > 0 )
323
+ while (iosf_mbi_pmic_punit_access_count != 0 ) {
324
+ mutex_unlock (& iosf_mbi_pmic_access_mutex );
325
+ wait_event (iosf_mbi_pmic_access_waitq ,
326
+ iosf_mbi_pmic_punit_access_count == 0 );
327
+ mutex_lock (& iosf_mbi_pmic_access_mutex );
328
+ }
329
+
330
+ if (iosf_mbi_pmic_i2c_access_count > 0 )
303
331
goto success ;
304
332
305
- mutex_lock (& iosf_mbi_punit_mutex );
306
333
blocking_notifier_call_chain (& iosf_mbi_pmic_bus_access_notifier ,
307
334
MBI_PMIC_BUS_ACCESS_BEGIN , NULL );
308
335
@@ -330,10 +357,6 @@ int iosf_mbi_block_punit_i2c_access(void)
330
357
iosf_mbi_sem_acquired = jiffies ;
331
358
dev_dbg (& mbi_pdev -> dev , "P-Unit semaphore acquired after %ums\n" ,
332
359
jiffies_to_msecs (jiffies - start ));
333
- /*
334
- * Success, keep iosf_mbi_punit_mutex locked till
335
- * iosf_mbi_unblock_punit_i2c_access() gets called.
336
- */
337
360
goto success ;
338
361
}
339
362
@@ -344,33 +367,34 @@ int iosf_mbi_block_punit_i2c_access(void)
344
367
dev_err (& mbi_pdev -> dev , "Error P-Unit semaphore timed out, resetting\n" );
345
368
error :
346
369
iosf_mbi_reset_semaphore ();
347
- mutex_unlock (& iosf_mbi_punit_mutex );
348
-
349
370
if (!iosf_mbi_get_sem (& sem ))
350
371
dev_err (& mbi_pdev -> dev , "P-Unit semaphore: %d\n" , sem );
351
372
success :
352
373
if (!WARN_ON (ret ))
353
- iosf_mbi_block_punit_i2c_access_count ++ ;
374
+ iosf_mbi_pmic_i2c_access_count ++ ;
354
375
355
- mutex_unlock (& iosf_mbi_block_punit_i2c_access_count_mutex );
376
+ mutex_unlock (& iosf_mbi_pmic_access_mutex );
356
377
357
378
return ret ;
358
379
}
359
380
EXPORT_SYMBOL (iosf_mbi_block_punit_i2c_access );
360
381
361
382
void iosf_mbi_unblock_punit_i2c_access (void )
362
383
{
363
- mutex_lock ( & iosf_mbi_block_punit_i2c_access_count_mutex ) ;
384
+ bool do_wakeup = false ;
364
385
365
- iosf_mbi_block_punit_i2c_access_count -- ;
366
- if (iosf_mbi_block_punit_i2c_access_count == 0 ) {
386
+ mutex_lock (& iosf_mbi_pmic_access_mutex );
387
+ iosf_mbi_pmic_i2c_access_count -- ;
388
+ if (iosf_mbi_pmic_i2c_access_count == 0 ) {
367
389
iosf_mbi_reset_semaphore ();
368
- mutex_unlock (& iosf_mbi_punit_mutex );
369
390
dev_dbg (& mbi_pdev -> dev , "punit semaphore held for %ums\n" ,
370
391
jiffies_to_msecs (jiffies - iosf_mbi_sem_acquired ));
392
+ do_wakeup = true;
371
393
}
394
+ mutex_unlock (& iosf_mbi_pmic_access_mutex );
372
395
373
- mutex_unlock (& iosf_mbi_block_punit_i2c_access_count_mutex );
396
+ if (do_wakeup )
397
+ wake_up (& iosf_mbi_pmic_access_waitq );
374
398
}
375
399
EXPORT_SYMBOL (iosf_mbi_unblock_punit_i2c_access );
376
400
@@ -379,10 +403,10 @@ int iosf_mbi_register_pmic_bus_access_notifier(struct notifier_block *nb)
379
403
int ret ;
380
404
381
405
/* Wait for the bus to go inactive before registering */
382
- mutex_lock ( & iosf_mbi_punit_mutex );
406
+ iosf_mbi_punit_acquire ( );
383
407
ret = blocking_notifier_chain_register (
384
408
& iosf_mbi_pmic_bus_access_notifier , nb );
385
- mutex_unlock ( & iosf_mbi_punit_mutex );
409
+ iosf_mbi_punit_release ( );
386
410
387
411
return ret ;
388
412
}
@@ -403,17 +427,17 @@ int iosf_mbi_unregister_pmic_bus_access_notifier(struct notifier_block *nb)
403
427
int ret ;
404
428
405
429
/* Wait for the bus to go inactive before unregistering */
406
- mutex_lock ( & iosf_mbi_punit_mutex );
430
+ iosf_mbi_punit_acquire ( );
407
431
ret = iosf_mbi_unregister_pmic_bus_access_notifier_unlocked (nb );
408
- mutex_unlock ( & iosf_mbi_punit_mutex );
432
+ iosf_mbi_punit_release ( );
409
433
410
434
return ret ;
411
435
}
412
436
EXPORT_SYMBOL (iosf_mbi_unregister_pmic_bus_access_notifier );
413
437
414
438
void iosf_mbi_assert_punit_acquired (void )
415
439
{
416
- WARN_ON (! mutex_is_locked ( & iosf_mbi_punit_mutex ) );
440
+ WARN_ON (iosf_mbi_pmic_punit_access_count == 0 );
417
441
}
418
442
EXPORT_SYMBOL (iosf_mbi_assert_punit_acquired );
419
443
0 commit comments