Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * IOSF-SB MailBox Interface Driver
0004  * Copyright (c) 2013, Intel Corporation.
0005  *
0006  * The IOSF-SB is a fabric bus available on Atom based SOC's that uses a
0007  * mailbox interface (MBI) to communicate with multiple devices. This
0008  * driver implements access to this interface for those platforms that can
0009  * enumerate the device using PCI.
0010  */
0011 
0012 #include <linux/delay.h>
0013 #include <linux/module.h>
0014 #include <linux/init.h>
0015 #include <linux/spinlock.h>
0016 #include <linux/pci.h>
0017 #include <linux/debugfs.h>
0018 #include <linux/capability.h>
0019 #include <linux/pm_qos.h>
0020 #include <linux/wait.h>
0021 
0022 #include <asm/iosf_mbi.h>
0023 
0024 #define PCI_DEVICE_ID_INTEL_BAYTRAIL        0x0F00
0025 #define PCI_DEVICE_ID_INTEL_BRASWELL        0x2280
0026 #define PCI_DEVICE_ID_INTEL_QUARK_X1000     0x0958
0027 #define PCI_DEVICE_ID_INTEL_TANGIER     0x1170
0028 
0029 static struct pci_dev *mbi_pdev;
0030 static DEFINE_SPINLOCK(iosf_mbi_lock);
0031 
0032 /**************** Generic iosf_mbi access helpers ****************/
0033 
0034 static inline u32 iosf_mbi_form_mcr(u8 op, u8 port, u8 offset)
0035 {
0036     return (op << 24) | (port << 16) | (offset << 8) | MBI_ENABLE;
0037 }
0038 
0039 static int iosf_mbi_pci_read_mdr(u32 mcrx, u32 mcr, u32 *mdr)
0040 {
0041     int result;
0042 
0043     if (!mbi_pdev)
0044         return -ENODEV;
0045 
0046     if (mcrx) {
0047         result = pci_write_config_dword(mbi_pdev, MBI_MCRX_OFFSET,
0048                         mcrx);
0049         if (result < 0)
0050             goto fail_read;
0051     }
0052 
0053     result = pci_write_config_dword(mbi_pdev, MBI_MCR_OFFSET, mcr);
0054     if (result < 0)
0055         goto fail_read;
0056 
0057     result = pci_read_config_dword(mbi_pdev, MBI_MDR_OFFSET, mdr);
0058     if (result < 0)
0059         goto fail_read;
0060 
0061     return 0;
0062 
0063 fail_read:
0064     dev_err(&mbi_pdev->dev, "PCI config access failed with %d\n", result);
0065     return result;
0066 }
0067 
0068 static int iosf_mbi_pci_write_mdr(u32 mcrx, u32 mcr, u32 mdr)
0069 {
0070     int result;
0071 
0072     if (!mbi_pdev)
0073         return -ENODEV;
0074 
0075     result = pci_write_config_dword(mbi_pdev, MBI_MDR_OFFSET, mdr);
0076     if (result < 0)
0077         goto fail_write;
0078 
0079     if (mcrx) {
0080         result = pci_write_config_dword(mbi_pdev, MBI_MCRX_OFFSET,
0081                         mcrx);
0082         if (result < 0)
0083             goto fail_write;
0084     }
0085 
0086     result = pci_write_config_dword(mbi_pdev, MBI_MCR_OFFSET, mcr);
0087     if (result < 0)
0088         goto fail_write;
0089 
0090     return 0;
0091 
0092 fail_write:
0093     dev_err(&mbi_pdev->dev, "PCI config access failed with %d\n", result);
0094     return result;
0095 }
0096 
0097 int iosf_mbi_read(u8 port, u8 opcode, u32 offset, u32 *mdr)
0098 {
0099     u32 mcr, mcrx;
0100     unsigned long flags;
0101     int ret;
0102 
0103     /* Access to the GFX unit is handled by GPU code */
0104     if (port == BT_MBI_UNIT_GFX) {
0105         WARN_ON(1);
0106         return -EPERM;
0107     }
0108 
0109     mcr = iosf_mbi_form_mcr(opcode, port, offset & MBI_MASK_LO);
0110     mcrx = offset & MBI_MASK_HI;
0111 
0112     spin_lock_irqsave(&iosf_mbi_lock, flags);
0113     ret = iosf_mbi_pci_read_mdr(mcrx, mcr, mdr);
0114     spin_unlock_irqrestore(&iosf_mbi_lock, flags);
0115 
0116     return ret;
0117 }
0118 EXPORT_SYMBOL(iosf_mbi_read);
0119 
0120 int iosf_mbi_write(u8 port, u8 opcode, u32 offset, u32 mdr)
0121 {
0122     u32 mcr, mcrx;
0123     unsigned long flags;
0124     int ret;
0125 
0126     /* Access to the GFX unit is handled by GPU code */
0127     if (port == BT_MBI_UNIT_GFX) {
0128         WARN_ON(1);
0129         return -EPERM;
0130     }
0131 
0132     mcr = iosf_mbi_form_mcr(opcode, port, offset & MBI_MASK_LO);
0133     mcrx = offset & MBI_MASK_HI;
0134 
0135     spin_lock_irqsave(&iosf_mbi_lock, flags);
0136     ret = iosf_mbi_pci_write_mdr(mcrx, mcr, mdr);
0137     spin_unlock_irqrestore(&iosf_mbi_lock, flags);
0138 
0139     return ret;
0140 }
0141 EXPORT_SYMBOL(iosf_mbi_write);
0142 
0143 int iosf_mbi_modify(u8 port, u8 opcode, u32 offset, u32 mdr, u32 mask)
0144 {
0145     u32 mcr, mcrx;
0146     u32 value;
0147     unsigned long flags;
0148     int ret;
0149 
0150     /* Access to the GFX unit is handled by GPU code */
0151     if (port == BT_MBI_UNIT_GFX) {
0152         WARN_ON(1);
0153         return -EPERM;
0154     }
0155 
0156     mcr = iosf_mbi_form_mcr(opcode, port, offset & MBI_MASK_LO);
0157     mcrx = offset & MBI_MASK_HI;
0158 
0159     spin_lock_irqsave(&iosf_mbi_lock, flags);
0160 
0161     /* Read current mdr value */
0162     ret = iosf_mbi_pci_read_mdr(mcrx, mcr & MBI_RD_MASK, &value);
0163     if (ret < 0) {
0164         spin_unlock_irqrestore(&iosf_mbi_lock, flags);
0165         return ret;
0166     }
0167 
0168     /* Apply mask */
0169     value &= ~mask;
0170     mdr &= mask;
0171     value |= mdr;
0172 
0173     /* Write back */
0174     ret = iosf_mbi_pci_write_mdr(mcrx, mcr | MBI_WR_MASK, value);
0175 
0176     spin_unlock_irqrestore(&iosf_mbi_lock, flags);
0177 
0178     return ret;
0179 }
0180 EXPORT_SYMBOL(iosf_mbi_modify);
0181 
0182 bool iosf_mbi_available(void)
0183 {
0184     /* Mbi isn't hot-pluggable. No remove routine is provided */
0185     return mbi_pdev;
0186 }
0187 EXPORT_SYMBOL(iosf_mbi_available);
0188 
0189 /*
0190  **************** P-Unit/kernel shared I2C bus arbitration ****************
0191  *
0192  * Some Bay Trail and Cherry Trail devices have the P-Unit and us (the kernel)
0193  * share a single I2C bus to the PMIC. Below are helpers to arbitrate the
0194  * accesses between the kernel and the P-Unit.
0195  *
0196  * See arch/x86/include/asm/iosf_mbi.h for kernel-doc text for each function.
0197  */
0198 
0199 #define SEMAPHORE_TIMEOUT       500
0200 #define PUNIT_SEMAPHORE_BYT     0x7
0201 #define PUNIT_SEMAPHORE_CHT     0x10e
0202 #define PUNIT_SEMAPHORE_BIT     BIT(0)
0203 #define PUNIT_SEMAPHORE_ACQUIRE     BIT(1)
0204 
0205 static DEFINE_MUTEX(iosf_mbi_pmic_access_mutex);
0206 static BLOCKING_NOTIFIER_HEAD(iosf_mbi_pmic_bus_access_notifier);
0207 static DECLARE_WAIT_QUEUE_HEAD(iosf_mbi_pmic_access_waitq);
0208 static u32 iosf_mbi_pmic_punit_access_count;
0209 static u32 iosf_mbi_pmic_i2c_access_count;
0210 static u32 iosf_mbi_sem_address;
0211 static unsigned long iosf_mbi_sem_acquired;
0212 static struct pm_qos_request iosf_mbi_pm_qos;
0213 
0214 void iosf_mbi_punit_acquire(void)
0215 {
0216     /* Wait for any I2C PMIC accesses from in kernel drivers to finish. */
0217     mutex_lock(&iosf_mbi_pmic_access_mutex);
0218     while (iosf_mbi_pmic_i2c_access_count != 0) {
0219         mutex_unlock(&iosf_mbi_pmic_access_mutex);
0220         wait_event(iosf_mbi_pmic_access_waitq,
0221                iosf_mbi_pmic_i2c_access_count == 0);
0222         mutex_lock(&iosf_mbi_pmic_access_mutex);
0223     }
0224     /*
0225      * We do not need to do anything to allow the PUNIT to safely access
0226      * the PMIC, other then block in kernel accesses to the PMIC.
0227      */
0228     iosf_mbi_pmic_punit_access_count++;
0229     mutex_unlock(&iosf_mbi_pmic_access_mutex);
0230 }
0231 EXPORT_SYMBOL(iosf_mbi_punit_acquire);
0232 
0233 void iosf_mbi_punit_release(void)
0234 {
0235     bool do_wakeup;
0236 
0237     mutex_lock(&iosf_mbi_pmic_access_mutex);
0238     iosf_mbi_pmic_punit_access_count--;
0239     do_wakeup = iosf_mbi_pmic_punit_access_count == 0;
0240     mutex_unlock(&iosf_mbi_pmic_access_mutex);
0241 
0242     if (do_wakeup)
0243         wake_up(&iosf_mbi_pmic_access_waitq);
0244 }
0245 EXPORT_SYMBOL(iosf_mbi_punit_release);
0246 
0247 static int iosf_mbi_get_sem(u32 *sem)
0248 {
0249     int ret;
0250 
0251     ret = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ,
0252                 iosf_mbi_sem_address, sem);
0253     if (ret) {
0254         dev_err(&mbi_pdev->dev, "Error P-Unit semaphore read failed\n");
0255         return ret;
0256     }
0257 
0258     *sem &= PUNIT_SEMAPHORE_BIT;
0259     return 0;
0260 }
0261 
0262 static void iosf_mbi_reset_semaphore(void)
0263 {
0264     if (iosf_mbi_modify(BT_MBI_UNIT_PMC, MBI_REG_READ,
0265                 iosf_mbi_sem_address, 0, PUNIT_SEMAPHORE_BIT))
0266         dev_err(&mbi_pdev->dev, "Error P-Unit semaphore reset failed\n");
0267 
0268     cpu_latency_qos_update_request(&iosf_mbi_pm_qos, PM_QOS_DEFAULT_VALUE);
0269 
0270     blocking_notifier_call_chain(&iosf_mbi_pmic_bus_access_notifier,
0271                      MBI_PMIC_BUS_ACCESS_END, NULL);
0272 }
0273 
0274 /*
0275  * This function blocks P-Unit accesses to the PMIC I2C bus, so that kernel
0276  * I2C code, such as e.g. a fuel-gauge driver, can access it safely.
0277  *
0278  * This function may be called by I2C controller code while an I2C driver has
0279  * already blocked P-Unit accesses because it wants them blocked over multiple
0280  * i2c-transfers, for e.g. read-modify-write of an I2C client register.
0281  *
0282  * To allow safe PMIC i2c bus accesses this function takes the following steps:
0283  *
0284  * 1) Some code sends request to the P-Unit which make it access the PMIC
0285  *    I2C bus. Testing has shown that the P-Unit does not check its internal
0286  *    PMIC bus semaphore for these requests. Callers of these requests call
0287  *    iosf_mbi_punit_acquire()/_release() around their P-Unit accesses, these
0288  *    functions increase/decrease iosf_mbi_pmic_punit_access_count, so first
0289  *    we wait for iosf_mbi_pmic_punit_access_count to become 0.
0290  *
0291  * 2) Check iosf_mbi_pmic_i2c_access_count, if access has already
0292  *    been blocked by another caller, we only need to increment
0293  *    iosf_mbi_pmic_i2c_access_count and we can skip the other steps.
0294  *
0295  * 3) Some code makes such P-Unit requests from atomic contexts where it
0296  *    cannot call iosf_mbi_punit_acquire() as that may sleep.
0297  *    As the second step we call a notifier chain which allows any code
0298  *    needing P-Unit resources from atomic context to acquire them before
0299  *    we take control over the PMIC I2C bus.
0300  *
0301  * 4) When CPU cores enter C6 or C7 the P-Unit needs to talk to the PMIC
0302  *    if this happens while the kernel itself is accessing the PMIC I2C bus
0303  *    the SoC hangs.
0304  *    As the third step we call cpu_latency_qos_update_request() to disallow the
0305  *    CPU to enter C6 or C7.
0306  *
0307  * 5) The P-Unit has a PMIC bus semaphore which we can request to stop
0308  *    autonomous P-Unit tasks from accessing the PMIC I2C bus while we hold it.
0309  *    As the fourth and final step we request this semaphore and wait for our
0310  *    request to be acknowledged.
0311  */
0312 int iosf_mbi_block_punit_i2c_access(void)
0313 {
0314     unsigned long start, end;
0315     int ret = 0;
0316     u32 sem;
0317 
0318     if (WARN_ON(!mbi_pdev || !iosf_mbi_sem_address))
0319         return -ENXIO;
0320 
0321     mutex_lock(&iosf_mbi_pmic_access_mutex);
0322 
0323     while (iosf_mbi_pmic_punit_access_count != 0) {
0324         mutex_unlock(&iosf_mbi_pmic_access_mutex);
0325         wait_event(iosf_mbi_pmic_access_waitq,
0326                iosf_mbi_pmic_punit_access_count == 0);
0327         mutex_lock(&iosf_mbi_pmic_access_mutex);
0328     }
0329 
0330     if (iosf_mbi_pmic_i2c_access_count > 0)
0331         goto success;
0332 
0333     blocking_notifier_call_chain(&iosf_mbi_pmic_bus_access_notifier,
0334                      MBI_PMIC_BUS_ACCESS_BEGIN, NULL);
0335 
0336     /*
0337      * Disallow the CPU to enter C6 or C7 state, entering these states
0338      * requires the P-Unit to talk to the PMIC and if this happens while
0339      * we're holding the semaphore, the SoC hangs.
0340      */
0341     cpu_latency_qos_update_request(&iosf_mbi_pm_qos, 0);
0342 
0343     /* host driver writes to side band semaphore register */
0344     ret = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE,
0345                  iosf_mbi_sem_address, PUNIT_SEMAPHORE_ACQUIRE);
0346     if (ret) {
0347         dev_err(&mbi_pdev->dev, "Error P-Unit semaphore request failed\n");
0348         goto error;
0349     }
0350 
0351     /* host driver waits for bit 0 to be set in semaphore register */
0352     start = jiffies;
0353     end = start + msecs_to_jiffies(SEMAPHORE_TIMEOUT);
0354     do {
0355         ret = iosf_mbi_get_sem(&sem);
0356         if (!ret && sem) {
0357             iosf_mbi_sem_acquired = jiffies;
0358             dev_dbg(&mbi_pdev->dev, "P-Unit semaphore acquired after %ums\n",
0359                 jiffies_to_msecs(jiffies - start));
0360             goto success;
0361         }
0362 
0363         usleep_range(1000, 2000);
0364     } while (time_before(jiffies, end));
0365 
0366     ret = -ETIMEDOUT;
0367     dev_err(&mbi_pdev->dev, "Error P-Unit semaphore timed out, resetting\n");
0368 error:
0369     iosf_mbi_reset_semaphore();
0370     if (!iosf_mbi_get_sem(&sem))
0371         dev_err(&mbi_pdev->dev, "P-Unit semaphore: %d\n", sem);
0372 success:
0373     if (!WARN_ON(ret))
0374         iosf_mbi_pmic_i2c_access_count++;
0375 
0376     mutex_unlock(&iosf_mbi_pmic_access_mutex);
0377 
0378     return ret;
0379 }
0380 EXPORT_SYMBOL(iosf_mbi_block_punit_i2c_access);
0381 
0382 void iosf_mbi_unblock_punit_i2c_access(void)
0383 {
0384     bool do_wakeup = false;
0385 
0386     mutex_lock(&iosf_mbi_pmic_access_mutex);
0387     iosf_mbi_pmic_i2c_access_count--;
0388     if (iosf_mbi_pmic_i2c_access_count == 0) {
0389         iosf_mbi_reset_semaphore();
0390         dev_dbg(&mbi_pdev->dev, "punit semaphore held for %ums\n",
0391             jiffies_to_msecs(jiffies - iosf_mbi_sem_acquired));
0392         do_wakeup = true;
0393     }
0394     mutex_unlock(&iosf_mbi_pmic_access_mutex);
0395 
0396     if (do_wakeup)
0397         wake_up(&iosf_mbi_pmic_access_waitq);
0398 }
0399 EXPORT_SYMBOL(iosf_mbi_unblock_punit_i2c_access);
0400 
0401 int iosf_mbi_register_pmic_bus_access_notifier(struct notifier_block *nb)
0402 {
0403     int ret;
0404 
0405     /* Wait for the bus to go inactive before registering */
0406     iosf_mbi_punit_acquire();
0407     ret = blocking_notifier_chain_register(
0408                 &iosf_mbi_pmic_bus_access_notifier, nb);
0409     iosf_mbi_punit_release();
0410 
0411     return ret;
0412 }
0413 EXPORT_SYMBOL(iosf_mbi_register_pmic_bus_access_notifier);
0414 
0415 int iosf_mbi_unregister_pmic_bus_access_notifier_unlocked(
0416     struct notifier_block *nb)
0417 {
0418     iosf_mbi_assert_punit_acquired();
0419 
0420     return blocking_notifier_chain_unregister(
0421                 &iosf_mbi_pmic_bus_access_notifier, nb);
0422 }
0423 EXPORT_SYMBOL(iosf_mbi_unregister_pmic_bus_access_notifier_unlocked);
0424 
0425 int iosf_mbi_unregister_pmic_bus_access_notifier(struct notifier_block *nb)
0426 {
0427     int ret;
0428 
0429     /* Wait for the bus to go inactive before unregistering */
0430     iosf_mbi_punit_acquire();
0431     ret = iosf_mbi_unregister_pmic_bus_access_notifier_unlocked(nb);
0432     iosf_mbi_punit_release();
0433 
0434     return ret;
0435 }
0436 EXPORT_SYMBOL(iosf_mbi_unregister_pmic_bus_access_notifier);
0437 
0438 void iosf_mbi_assert_punit_acquired(void)
0439 {
0440     WARN_ON(iosf_mbi_pmic_punit_access_count == 0);
0441 }
0442 EXPORT_SYMBOL(iosf_mbi_assert_punit_acquired);
0443 
0444 /**************** iosf_mbi debug code ****************/
0445 
0446 #ifdef CONFIG_IOSF_MBI_DEBUG
0447 static u32  dbg_mdr;
0448 static u32  dbg_mcr;
0449 static u32  dbg_mcrx;
0450 
0451 static int mcr_get(void *data, u64 *val)
0452 {
0453     *val = *(u32 *)data;
0454     return 0;
0455 }
0456 
0457 static int mcr_set(void *data, u64 val)
0458 {
0459     u8 command = ((u32)val & 0xFF000000) >> 24,
0460        port    = ((u32)val & 0x00FF0000) >> 16,
0461        offset  = ((u32)val & 0x0000FF00) >> 8;
0462     int err;
0463 
0464     *(u32 *)data = val;
0465 
0466     if (!capable(CAP_SYS_RAWIO))
0467         return -EACCES;
0468 
0469     if (command & 1u)
0470         err = iosf_mbi_write(port,
0471                    command,
0472                    dbg_mcrx | offset,
0473                    dbg_mdr);
0474     else
0475         err = iosf_mbi_read(port,
0476                   command,
0477                   dbg_mcrx | offset,
0478                   &dbg_mdr);
0479 
0480     return err;
0481 }
0482 DEFINE_SIMPLE_ATTRIBUTE(iosf_mcr_fops, mcr_get, mcr_set , "%llx\n");
0483 
0484 static struct dentry *iosf_dbg;
0485 
0486 static void iosf_sideband_debug_init(void)
0487 {
0488     iosf_dbg = debugfs_create_dir("iosf_sb", NULL);
0489 
0490     /* mdr */
0491     debugfs_create_x32("mdr", 0660, iosf_dbg, &dbg_mdr);
0492 
0493     /* mcrx */
0494     debugfs_create_x32("mcrx", 0660, iosf_dbg, &dbg_mcrx);
0495 
0496     /* mcr - initiates mailbox transaction */
0497     debugfs_create_file("mcr", 0660, iosf_dbg, &dbg_mcr, &iosf_mcr_fops);
0498 }
0499 
0500 static void iosf_debugfs_init(void)
0501 {
0502     iosf_sideband_debug_init();
0503 }
0504 
0505 static void iosf_debugfs_remove(void)
0506 {
0507     debugfs_remove_recursive(iosf_dbg);
0508 }
0509 #else
0510 static inline void iosf_debugfs_init(void) { }
0511 static inline void iosf_debugfs_remove(void) { }
0512 #endif /* CONFIG_IOSF_MBI_DEBUG */
0513 
0514 static int iosf_mbi_probe(struct pci_dev *pdev,
0515               const struct pci_device_id *dev_id)
0516 {
0517     int ret;
0518 
0519     ret = pci_enable_device(pdev);
0520     if (ret < 0) {
0521         dev_err(&pdev->dev, "error: could not enable device\n");
0522         return ret;
0523     }
0524 
0525     mbi_pdev = pci_dev_get(pdev);
0526     iosf_mbi_sem_address = dev_id->driver_data;
0527 
0528     return 0;
0529 }
0530 
0531 static const struct pci_device_id iosf_mbi_pci_ids[] = {
0532     { PCI_DEVICE_DATA(INTEL, BAYTRAIL, PUNIT_SEMAPHORE_BYT) },
0533     { PCI_DEVICE_DATA(INTEL, BRASWELL, PUNIT_SEMAPHORE_CHT) },
0534     { PCI_DEVICE_DATA(INTEL, QUARK_X1000, 0) },
0535     { PCI_DEVICE_DATA(INTEL, TANGIER, 0) },
0536     { 0, },
0537 };
0538 MODULE_DEVICE_TABLE(pci, iosf_mbi_pci_ids);
0539 
0540 static struct pci_driver iosf_mbi_pci_driver = {
0541     .name       = "iosf_mbi_pci",
0542     .probe      = iosf_mbi_probe,
0543     .id_table   = iosf_mbi_pci_ids,
0544 };
0545 
0546 static int __init iosf_mbi_init(void)
0547 {
0548     iosf_debugfs_init();
0549 
0550     cpu_latency_qos_add_request(&iosf_mbi_pm_qos, PM_QOS_DEFAULT_VALUE);
0551 
0552     return pci_register_driver(&iosf_mbi_pci_driver);
0553 }
0554 
0555 static void __exit iosf_mbi_exit(void)
0556 {
0557     iosf_debugfs_remove();
0558 
0559     pci_unregister_driver(&iosf_mbi_pci_driver);
0560     pci_dev_put(mbi_pdev);
0561     mbi_pdev = NULL;
0562 
0563     cpu_latency_qos_remove_request(&iosf_mbi_pm_qos);
0564 }
0565 
0566 module_init(iosf_mbi_init);
0567 module_exit(iosf_mbi_exit);
0568 
0569 MODULE_AUTHOR("David E. Box <david.e.box@linux.intel.com>");
0570 MODULE_DESCRIPTION("IOSF Mailbox Interface accessor");
0571 MODULE_LICENSE("GPL v2");