This source file includes following definitions.
- iosf_mbi_form_mcr
- iosf_mbi_pci_read_mdr
- iosf_mbi_pci_write_mdr
- iosf_mbi_read
- iosf_mbi_write
- iosf_mbi_modify
- iosf_mbi_available
- iosf_mbi_punit_acquire
- iosf_mbi_punit_release
- iosf_mbi_get_sem
- iosf_mbi_reset_semaphore
- iosf_mbi_block_punit_i2c_access
- iosf_mbi_unblock_punit_i2c_access
- iosf_mbi_register_pmic_bus_access_notifier
- iosf_mbi_unregister_pmic_bus_access_notifier_unlocked
- iosf_mbi_unregister_pmic_bus_access_notifier
- iosf_mbi_assert_punit_acquired
- mcr_get
- mcr_set
- iosf_sideband_debug_init
- iosf_debugfs_init
- iosf_debugfs_remove
- iosf_debugfs_init
- iosf_debugfs_remove
- iosf_mbi_probe
- iosf_mbi_init
- iosf_mbi_exit
1
2
3
4
5
6
7
8
9
10
11
12 #include <linux/delay.h>
13 #include <linux/module.h>
14 #include <linux/init.h>
15 #include <linux/spinlock.h>
16 #include <linux/pci.h>
17 #include <linux/debugfs.h>
18 #include <linux/capability.h>
19 #include <linux/pm_qos.h>
20 #include <linux/wait.h>
21
22 #include <asm/iosf_mbi.h>
23
24 #define PCI_DEVICE_ID_INTEL_BAYTRAIL 0x0F00
25 #define PCI_DEVICE_ID_INTEL_BRASWELL 0x2280
26 #define PCI_DEVICE_ID_INTEL_QUARK_X1000 0x0958
27 #define PCI_DEVICE_ID_INTEL_TANGIER 0x1170
28
29 static struct pci_dev *mbi_pdev;
30 static DEFINE_SPINLOCK(iosf_mbi_lock);
31
32
33
34 static inline u32 iosf_mbi_form_mcr(u8 op, u8 port, u8 offset)
35 {
36 return (op << 24) | (port << 16) | (offset << 8) | MBI_ENABLE;
37 }
38
39 static int iosf_mbi_pci_read_mdr(u32 mcrx, u32 mcr, u32 *mdr)
40 {
41 int result;
42
43 if (!mbi_pdev)
44 return -ENODEV;
45
46 if (mcrx) {
47 result = pci_write_config_dword(mbi_pdev, MBI_MCRX_OFFSET,
48 mcrx);
49 if (result < 0)
50 goto fail_read;
51 }
52
53 result = pci_write_config_dword(mbi_pdev, MBI_MCR_OFFSET, mcr);
54 if (result < 0)
55 goto fail_read;
56
57 result = pci_read_config_dword(mbi_pdev, MBI_MDR_OFFSET, mdr);
58 if (result < 0)
59 goto fail_read;
60
61 return 0;
62
63 fail_read:
64 dev_err(&mbi_pdev->dev, "PCI config access failed with %d\n", result);
65 return result;
66 }
67
68 static int iosf_mbi_pci_write_mdr(u32 mcrx, u32 mcr, u32 mdr)
69 {
70 int result;
71
72 if (!mbi_pdev)
73 return -ENODEV;
74
75 result = pci_write_config_dword(mbi_pdev, MBI_MDR_OFFSET, mdr);
76 if (result < 0)
77 goto fail_write;
78
79 if (mcrx) {
80 result = pci_write_config_dword(mbi_pdev, MBI_MCRX_OFFSET,
81 mcrx);
82 if (result < 0)
83 goto fail_write;
84 }
85
86 result = pci_write_config_dword(mbi_pdev, MBI_MCR_OFFSET, mcr);
87 if (result < 0)
88 goto fail_write;
89
90 return 0;
91
92 fail_write:
93 dev_err(&mbi_pdev->dev, "PCI config access failed with %d\n", result);
94 return result;
95 }
96
97 int iosf_mbi_read(u8 port, u8 opcode, u32 offset, u32 *mdr)
98 {
99 u32 mcr, mcrx;
100 unsigned long flags;
101 int ret;
102
103
104 if (port == BT_MBI_UNIT_GFX) {
105 WARN_ON(1);
106 return -EPERM;
107 }
108
109 mcr = iosf_mbi_form_mcr(opcode, port, offset & MBI_MASK_LO);
110 mcrx = offset & MBI_MASK_HI;
111
112 spin_lock_irqsave(&iosf_mbi_lock, flags);
113 ret = iosf_mbi_pci_read_mdr(mcrx, mcr, mdr);
114 spin_unlock_irqrestore(&iosf_mbi_lock, flags);
115
116 return ret;
117 }
118 EXPORT_SYMBOL(iosf_mbi_read);
119
120 int iosf_mbi_write(u8 port, u8 opcode, u32 offset, u32 mdr)
121 {
122 u32 mcr, mcrx;
123 unsigned long flags;
124 int ret;
125
126
127 if (port == BT_MBI_UNIT_GFX) {
128 WARN_ON(1);
129 return -EPERM;
130 }
131
132 mcr = iosf_mbi_form_mcr(opcode, port, offset & MBI_MASK_LO);
133 mcrx = offset & MBI_MASK_HI;
134
135 spin_lock_irqsave(&iosf_mbi_lock, flags);
136 ret = iosf_mbi_pci_write_mdr(mcrx, mcr, mdr);
137 spin_unlock_irqrestore(&iosf_mbi_lock, flags);
138
139 return ret;
140 }
141 EXPORT_SYMBOL(iosf_mbi_write);
142
143 int iosf_mbi_modify(u8 port, u8 opcode, u32 offset, u32 mdr, u32 mask)
144 {
145 u32 mcr, mcrx;
146 u32 value;
147 unsigned long flags;
148 int ret;
149
150
151 if (port == BT_MBI_UNIT_GFX) {
152 WARN_ON(1);
153 return -EPERM;
154 }
155
156 mcr = iosf_mbi_form_mcr(opcode, port, offset & MBI_MASK_LO);
157 mcrx = offset & MBI_MASK_HI;
158
159 spin_lock_irqsave(&iosf_mbi_lock, flags);
160
161
162 ret = iosf_mbi_pci_read_mdr(mcrx, mcr & MBI_RD_MASK, &value);
163 if (ret < 0) {
164 spin_unlock_irqrestore(&iosf_mbi_lock, flags);
165 return ret;
166 }
167
168
169 value &= ~mask;
170 mdr &= mask;
171 value |= mdr;
172
173
174 ret = iosf_mbi_pci_write_mdr(mcrx, mcr | MBI_WR_MASK, value);
175
176 spin_unlock_irqrestore(&iosf_mbi_lock, flags);
177
178 return ret;
179 }
180 EXPORT_SYMBOL(iosf_mbi_modify);
181
182 bool iosf_mbi_available(void)
183 {
184
185 return mbi_pdev;
186 }
187 EXPORT_SYMBOL(iosf_mbi_available);
188
189
190
191
192
193
194
195
196
197
198
199 #define SEMAPHORE_TIMEOUT 500
200 #define PUNIT_SEMAPHORE_BYT 0x7
201 #define PUNIT_SEMAPHORE_CHT 0x10e
202 #define PUNIT_SEMAPHORE_BIT BIT(0)
203 #define PUNIT_SEMAPHORE_ACQUIRE BIT(1)
204
205 static DEFINE_MUTEX(iosf_mbi_pmic_access_mutex);
206 static BLOCKING_NOTIFIER_HEAD(iosf_mbi_pmic_bus_access_notifier);
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;
210 static u32 iosf_mbi_sem_address;
211 static unsigned long iosf_mbi_sem_acquired;
212 static struct pm_qos_request iosf_mbi_pm_qos;
213
214 void iosf_mbi_punit_acquire(void)
215 {
216
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
226
227
228 iosf_mbi_pmic_punit_access_count++;
229 mutex_unlock(&iosf_mbi_pmic_access_mutex);
230 }
231 EXPORT_SYMBOL(iosf_mbi_punit_acquire);
232
233 void iosf_mbi_punit_release(void)
234 {
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);
244 }
245 EXPORT_SYMBOL(iosf_mbi_punit_release);
246
247 static int iosf_mbi_get_sem(u32 *sem)
248 {
249 int ret;
250
251 ret = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ,
252 iosf_mbi_sem_address, sem);
253 if (ret) {
254 dev_err(&mbi_pdev->dev, "Error P-Unit semaphore read failed\n");
255 return ret;
256 }
257
258 *sem &= PUNIT_SEMAPHORE_BIT;
259 return 0;
260 }
261
262 static void iosf_mbi_reset_semaphore(void)
263 {
264 if (iosf_mbi_modify(BT_MBI_UNIT_PMC, MBI_REG_READ,
265 iosf_mbi_sem_address, 0, PUNIT_SEMAPHORE_BIT))
266 dev_err(&mbi_pdev->dev, "Error P-Unit semaphore reset failed\n");
267
268 pm_qos_update_request(&iosf_mbi_pm_qos, PM_QOS_DEFAULT_VALUE);
269
270 blocking_notifier_call_chain(&iosf_mbi_pmic_bus_access_notifier,
271 MBI_PMIC_BUS_ACCESS_END, NULL);
272 }
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312 int iosf_mbi_block_punit_i2c_access(void)
313 {
314 unsigned long start, end;
315 int ret = 0;
316 u32 sem;
317
318 if (WARN_ON(!mbi_pdev || !iosf_mbi_sem_address))
319 return -ENXIO;
320
321 mutex_lock(&iosf_mbi_pmic_access_mutex);
322
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)
331 goto success;
332
333 blocking_notifier_call_chain(&iosf_mbi_pmic_bus_access_notifier,
334 MBI_PMIC_BUS_ACCESS_BEGIN, NULL);
335
336
337
338
339
340
341 pm_qos_update_request(&iosf_mbi_pm_qos, 0);
342
343
344 ret = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE,
345 iosf_mbi_sem_address, PUNIT_SEMAPHORE_ACQUIRE);
346 if (ret) {
347 dev_err(&mbi_pdev->dev, "Error P-Unit semaphore request failed\n");
348 goto error;
349 }
350
351
352 start = jiffies;
353 end = start + msecs_to_jiffies(SEMAPHORE_TIMEOUT);
354 do {
355 ret = iosf_mbi_get_sem(&sem);
356 if (!ret && sem) {
357 iosf_mbi_sem_acquired = jiffies;
358 dev_dbg(&mbi_pdev->dev, "P-Unit semaphore acquired after %ums\n",
359 jiffies_to_msecs(jiffies - start));
360 goto success;
361 }
362
363 usleep_range(1000, 2000);
364 } while (time_before(jiffies, end));
365
366 ret = -ETIMEDOUT;
367 dev_err(&mbi_pdev->dev, "Error P-Unit semaphore timed out, resetting\n");
368 error:
369 iosf_mbi_reset_semaphore();
370 if (!iosf_mbi_get_sem(&sem))
371 dev_err(&mbi_pdev->dev, "P-Unit semaphore: %d\n", sem);
372 success:
373 if (!WARN_ON(ret))
374 iosf_mbi_pmic_i2c_access_count++;
375
376 mutex_unlock(&iosf_mbi_pmic_access_mutex);
377
378 return ret;
379 }
380 EXPORT_SYMBOL(iosf_mbi_block_punit_i2c_access);
381
382 void iosf_mbi_unblock_punit_i2c_access(void)
383 {
384 bool do_wakeup = false;
385
386 mutex_lock(&iosf_mbi_pmic_access_mutex);
387 iosf_mbi_pmic_i2c_access_count--;
388 if (iosf_mbi_pmic_i2c_access_count == 0) {
389 iosf_mbi_reset_semaphore();
390 dev_dbg(&mbi_pdev->dev, "punit semaphore held for %ums\n",
391 jiffies_to_msecs(jiffies - iosf_mbi_sem_acquired));
392 do_wakeup = true;
393 }
394 mutex_unlock(&iosf_mbi_pmic_access_mutex);
395
396 if (do_wakeup)
397 wake_up(&iosf_mbi_pmic_access_waitq);
398 }
399 EXPORT_SYMBOL(iosf_mbi_unblock_punit_i2c_access);
400
401 int iosf_mbi_register_pmic_bus_access_notifier(struct notifier_block *nb)
402 {
403 int ret;
404
405
406 iosf_mbi_punit_acquire();
407 ret = blocking_notifier_chain_register(
408 &iosf_mbi_pmic_bus_access_notifier, nb);
409 iosf_mbi_punit_release();
410
411 return ret;
412 }
413 EXPORT_SYMBOL(iosf_mbi_register_pmic_bus_access_notifier);
414
415 int iosf_mbi_unregister_pmic_bus_access_notifier_unlocked(
416 struct notifier_block *nb)
417 {
418 iosf_mbi_assert_punit_acquired();
419
420 return blocking_notifier_chain_unregister(
421 &iosf_mbi_pmic_bus_access_notifier, nb);
422 }
423 EXPORT_SYMBOL(iosf_mbi_unregister_pmic_bus_access_notifier_unlocked);
424
425 int iosf_mbi_unregister_pmic_bus_access_notifier(struct notifier_block *nb)
426 {
427 int ret;
428
429
430 iosf_mbi_punit_acquire();
431 ret = iosf_mbi_unregister_pmic_bus_access_notifier_unlocked(nb);
432 iosf_mbi_punit_release();
433
434 return ret;
435 }
436 EXPORT_SYMBOL(iosf_mbi_unregister_pmic_bus_access_notifier);
437
438 void iosf_mbi_assert_punit_acquired(void)
439 {
440 WARN_ON(iosf_mbi_pmic_punit_access_count == 0);
441 }
442 EXPORT_SYMBOL(iosf_mbi_assert_punit_acquired);
443
444
445
446 #ifdef CONFIG_IOSF_MBI_DEBUG
447 static u32 dbg_mdr;
448 static u32 dbg_mcr;
449 static u32 dbg_mcrx;
450
451 static int mcr_get(void *data, u64 *val)
452 {
453 *val = *(u32 *)data;
454 return 0;
455 }
456
457 static int mcr_set(void *data, u64 val)
458 {
459 u8 command = ((u32)val & 0xFF000000) >> 24,
460 port = ((u32)val & 0x00FF0000) >> 16,
461 offset = ((u32)val & 0x0000FF00) >> 8;
462 int err;
463
464 *(u32 *)data = val;
465
466 if (!capable(CAP_SYS_RAWIO))
467 return -EACCES;
468
469 if (command & 1u)
470 err = iosf_mbi_write(port,
471 command,
472 dbg_mcrx | offset,
473 dbg_mdr);
474 else
475 err = iosf_mbi_read(port,
476 command,
477 dbg_mcrx | offset,
478 &dbg_mdr);
479
480 return err;
481 }
482 DEFINE_SIMPLE_ATTRIBUTE(iosf_mcr_fops, mcr_get, mcr_set , "%llx\n");
483
484 static struct dentry *iosf_dbg;
485
486 static void iosf_sideband_debug_init(void)
487 {
488 iosf_dbg = debugfs_create_dir("iosf_sb", NULL);
489
490
491 debugfs_create_x32("mdr", 0660, iosf_dbg, &dbg_mdr);
492
493
494 debugfs_create_x32("mcrx", 0660, iosf_dbg, &dbg_mcrx);
495
496
497 debugfs_create_file("mcr", 0660, iosf_dbg, &dbg_mcr, &iosf_mcr_fops);
498 }
499
500 static void iosf_debugfs_init(void)
501 {
502 iosf_sideband_debug_init();
503 }
504
505 static void iosf_debugfs_remove(void)
506 {
507 debugfs_remove_recursive(iosf_dbg);
508 }
509 #else
510 static inline void iosf_debugfs_init(void) { }
511 static inline void iosf_debugfs_remove(void) { }
512 #endif
513
514 static int iosf_mbi_probe(struct pci_dev *pdev,
515 const struct pci_device_id *dev_id)
516 {
517 int ret;
518
519 ret = pci_enable_device(pdev);
520 if (ret < 0) {
521 dev_err(&pdev->dev, "error: could not enable device\n");
522 return ret;
523 }
524
525 mbi_pdev = pci_dev_get(pdev);
526 iosf_mbi_sem_address = dev_id->driver_data;
527
528 return 0;
529 }
530
531 static const struct pci_device_id iosf_mbi_pci_ids[] = {
532 { PCI_DEVICE_DATA(INTEL, BAYTRAIL, PUNIT_SEMAPHORE_BYT) },
533 { PCI_DEVICE_DATA(INTEL, BRASWELL, PUNIT_SEMAPHORE_CHT) },
534 { PCI_DEVICE_DATA(INTEL, QUARK_X1000, 0) },
535 { PCI_DEVICE_DATA(INTEL, TANGIER, 0) },
536 { 0, },
537 };
538 MODULE_DEVICE_TABLE(pci, iosf_mbi_pci_ids);
539
540 static struct pci_driver iosf_mbi_pci_driver = {
541 .name = "iosf_mbi_pci",
542 .probe = iosf_mbi_probe,
543 .id_table = iosf_mbi_pci_ids,
544 };
545
546 static int __init iosf_mbi_init(void)
547 {
548 iosf_debugfs_init();
549
550 pm_qos_add_request(&iosf_mbi_pm_qos, PM_QOS_CPU_DMA_LATENCY,
551 PM_QOS_DEFAULT_VALUE);
552
553 return pci_register_driver(&iosf_mbi_pci_driver);
554 }
555
556 static void __exit iosf_mbi_exit(void)
557 {
558 iosf_debugfs_remove();
559
560 pci_unregister_driver(&iosf_mbi_pci_driver);
561 pci_dev_put(mbi_pdev);
562 mbi_pdev = NULL;
563
564 pm_qos_remove_request(&iosf_mbi_pm_qos);
565 }
566
567 module_init(iosf_mbi_init);
568 module_exit(iosf_mbi_exit);
569
570 MODULE_AUTHOR("David E. Box <david.e.box@linux.intel.com>");
571 MODULE_DESCRIPTION("IOSF Mailbox Interface accessor");
572 MODULE_LICENSE("GPL v2");