linux/arch/x86/platform/intel/iosf_mbi.c
<<
>>
Prefs
   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
  29static struct pci_dev *mbi_pdev;
  30static DEFINE_SPINLOCK(iosf_mbi_lock);
  31
  32/**************** Generic iosf_mbi access helpers ****************/
  33
  34static 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
  39static 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
  63fail_read:
  64        dev_err(&mbi_pdev->dev, "PCI config access failed with %d\n", result);
  65        return result;
  66}
  67
  68static 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
  92fail_write:
  93        dev_err(&mbi_pdev->dev, "PCI config access failed with %d\n", result);
  94        return result;
  95}
  96
  97int 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}
 118EXPORT_SYMBOL(iosf_mbi_read);
 119
 120int 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}
 141EXPORT_SYMBOL(iosf_mbi_write);
 142
 143int 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}
 180EXPORT_SYMBOL(iosf_mbi_modify);
 181
 182bool iosf_mbi_available(void)
 183{
 184        /* Mbi isn't hot-pluggable. No remove routine is provided */
 185        return mbi_pdev;
 186}
 187EXPORT_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
 205static DEFINE_MUTEX(iosf_mbi_pmic_access_mutex);
 206static BLOCKING_NOTIFIER_HEAD(iosf_mbi_pmic_bus_access_notifier);
 207static DECLARE_WAIT_QUEUE_HEAD(iosf_mbi_pmic_access_waitq);
 208static u32 iosf_mbi_pmic_punit_access_count;
 209static u32 iosf_mbi_pmic_i2c_access_count;
 210static u32 iosf_mbi_sem_address;
 211static unsigned long iosf_mbi_sem_acquired;
 212static struct pm_qos_request iosf_mbi_pm_qos;
 213
 214void 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}
 231EXPORT_SYMBOL(iosf_mbi_punit_acquire);
 232
 233void 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}
 245EXPORT_SYMBOL(iosf_mbi_punit_release);
 246
 247static 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
 262static 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 */
 312int 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");
 368error:
 369        iosf_mbi_reset_semaphore();
 370        if (!iosf_mbi_get_sem(&sem))
 371                dev_err(&mbi_pdev->dev, "P-Unit semaphore: %d\n", sem);
 372success:
 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}
 380EXPORT_SYMBOL(iosf_mbi_block_punit_i2c_access);
 381
 382void 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}
 399EXPORT_SYMBOL(iosf_mbi_unblock_punit_i2c_access);
 400
 401int 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}
 413EXPORT_SYMBOL(iosf_mbi_register_pmic_bus_access_notifier);
 414
 415int 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}
 423EXPORT_SYMBOL(iosf_mbi_unregister_pmic_bus_access_notifier_unlocked);
 424
 425int 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}
 436EXPORT_SYMBOL(iosf_mbi_unregister_pmic_bus_access_notifier);
 437
 438void iosf_mbi_assert_punit_acquired(void)
 439{
 440        WARN_ON(iosf_mbi_pmic_punit_access_count == 0);
 441}
 442EXPORT_SYMBOL(iosf_mbi_assert_punit_acquired);
 443
 444/**************** iosf_mbi debug code ****************/
 445
 446#ifdef CONFIG_IOSF_MBI_DEBUG
 447static u32      dbg_mdr;
 448static u32      dbg_mcr;
 449static u32      dbg_mcrx;
 450
 451static int mcr_get(void *data, u64 *val)
 452{
 453        *val = *(u32 *)data;
 454        return 0;
 455}
 456
 457static 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}
 482DEFINE_SIMPLE_ATTRIBUTE(iosf_mcr_fops, mcr_get, mcr_set , "%llx\n");
 483
 484static struct dentry *iosf_dbg;
 485
 486static 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
 500static void iosf_debugfs_init(void)
 501{
 502        iosf_sideband_debug_init();
 503}
 504
 505static void iosf_debugfs_remove(void)
 506{
 507        debugfs_remove_recursive(iosf_dbg);
 508}
 509#else
 510static inline void iosf_debugfs_init(void) { }
 511static inline void iosf_debugfs_remove(void) { }
 512#endif /* CONFIG_IOSF_MBI_DEBUG */
 513
 514static 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
 531static 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};
 538MODULE_DEVICE_TABLE(pci, iosf_mbi_pci_ids);
 539
 540static 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
 546static 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
 555static 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
 566module_init(iosf_mbi_init);
 567module_exit(iosf_mbi_exit);
 568
 569MODULE_AUTHOR("David E. Box <david.e.box@linux.intel.com>");
 570MODULE_DESCRIPTION("IOSF Mailbox Interface accessor");
 571MODULE_LICENSE("GPL v2");
 572