1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * IOSF-SB MailBox Interface Driver 4 * Copyright (c) 2013, Intel Corporation. 5 * 6 * The IOSF-SB is a fabric bus available on Atom based SOC's that uses a 7 * mailbox interface (MBI) to communicate with multiple devices. This 8 * driver implements access to this interface for those platforms that can 9 * enumerate the device using PCI. 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 /**************** Generic iosf_mbi access helpers ****************/ 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 pcibios_err_to_errno(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 pcibios_err_to_errno(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 /* Access to the GFX unit is handled by GPU code */ 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 /* Access to the GFX unit is handled by GPU code */ 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 /* Access to the GFX unit is handled by GPU code */ 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 /* Read current mdr value */ 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 /* Apply mask */ 169 value &= ~mask; 170 mdr &= mask; 171 value |= mdr; 172 173 /* Write back */ 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 /* Mbi isn't hot-pluggable. No remove routine is provided */ 185 return mbi_pdev; 186 } 187 EXPORT_SYMBOL(iosf_mbi_available); 188 189 /* 190 **************** P-Unit/kernel shared I2C bus arbitration **************** 191 * 192 * Some Bay Trail and Cherry Trail devices have the P-Unit and us (the kernel) 193 * share a single I2C bus to the PMIC. Below are helpers to arbitrate the 194 * accesses between the kernel and the P-Unit. 195 * 196 * See arch/x86/include/asm/iosf_mbi.h for kernel-doc text for each function. 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 /* 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); 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 cpu_latency_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 * This function blocks P-Unit accesses to the PMIC I2C bus, so that kernel 276 * I2C code, such as e.g. a fuel-gauge driver, can access it safely. 277 * 278 * This function may be called by I2C controller code while an I2C driver has 279 * already blocked P-Unit accesses because it wants them blocked over multiple 280 * i2c-transfers, for e.g. read-modify-write of an I2C client register. 281 * 282 * To allow safe PMIC i2c bus accesses this function takes the following steps: 283 * 284 * 1) Some code sends request to the P-Unit which make it access the PMIC 285 * I2C bus. Testing has shown that the P-Unit does not check its internal 286 * PMIC bus semaphore for these requests. Callers of these requests call 287 * iosf_mbi_punit_acquire()/_release() around their P-Unit accesses, these 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. 294 * 295 * 3) Some code makes such P-Unit requests from atomic contexts where it 296 * cannot call iosf_mbi_punit_acquire() as that may sleep. 297 * As the second step we call a notifier chain which allows any code 298 * needing P-Unit resources from atomic context to acquire them before 299 * we take control over the PMIC I2C bus. 300 * 301 * 4) When CPU cores enter C6 or C7 the P-Unit needs to talk to the PMIC 302 * if this happens while the kernel itself is accessing the PMIC I2C bus 303 * the SoC hangs. 304 * As the third step we call cpu_latency_qos_update_request() to disallow the 305 * CPU to enter C6 or C7. 306 * 307 * 5) The P-Unit has a PMIC bus semaphore which we can request to stop 308 * autonomous P-Unit tasks from accessing the PMIC I2C bus while we hold it. 309 * As the fourth and final step we request this semaphore and wait for our 310 * request to be acknowledged. 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 * Disallow the CPU to enter C6 or C7 state, entering these states 338 * requires the P-Unit to talk to the PMIC and if this happens while 339 * we're holding the semaphore, the SoC hangs. 340 */ 341 cpu_latency_qos_update_request(&iosf_mbi_pm_qos, 0); 342 343 /* host driver writes to side band semaphore register */ 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 /* host driver waits for bit 0 to be set in semaphore register */ 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 /* Wait for the bus to go inactive before registering */ 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 /* Wait for the bus to go inactive before unregistering */ 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 /**************** iosf_mbi debug code ****************/ 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 /* mdr */ 491 debugfs_create_x32("mdr", 0660, iosf_dbg, &dbg_mdr); 492 493 /* mcrx */ 494 debugfs_create_x32("mcrx", 0660, iosf_dbg, &dbg_mcrx); 495 496 /* mcr - initiates mailbox transaction */ 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 /* CONFIG_IOSF_MBI_DEBUG */ 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 cpu_latency_qos_add_request(&iosf_mbi_pm_qos, PM_QOS_DEFAULT_VALUE); 551 552 return pci_register_driver(&iosf_mbi_pci_driver); 553 } 554 555 static void __exit iosf_mbi_exit(void) 556 { 557 iosf_debugfs_remove(); 558 559 pci_unregister_driver(&iosf_mbi_pci_driver); 560 pci_dev_put(mbi_pdev); 561 mbi_pdev = NULL; 562 563 cpu_latency_qos_remove_request(&iosf_mbi_pm_qos); 564 } 565 566 module_init(iosf_mbi_init); 567 module_exit(iosf_mbi_exit); 568 569 MODULE_AUTHOR("David E. Box <david.e.box@linux.intel.com>"); 570 MODULE_DESCRIPTION("IOSF Mailbox Interface accessor"); 571 MODULE_LICENSE("GPL v2"); 572
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.