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");