IPANIC at (sep_pci_suspend+0x1e/0x80)

慢慢的的将理论的东西与实际相结合了,这个问题很奇怪,手机不到几分钟,就会报这样的错误,问题其实根本就跟这个sep_pci_suspend函数关系并不是很大,主要是因为在probe函数中,没有初始化好函数,

drivers/staging/sep/sep_main.c中:

/**
 *sep_probe - probe a matching PCI device
 *@pdev:    pci_device
 *@ent:    pci_device_id
 *
 *Attempt to set up and configure a SEP device that has been
 *discovered by the PCI layer. Allocates all required resources.
 */
static int __devinit sep_probe(struct pci_dev *pdev,
    const struct pci_device_id *ent)
{
    int error = 0;
    struct sep_device *sep = NULL;

    /* Used for telling the sep our new shared memory physical address */
    struct sep_msg_shared_mem_addr_to_sep *shm_to_sep = NULL;
    struct sep_msg_shared_mem_addr_from_sep *shm_from_sep = NULL;

    if (sep_dev != NULL) {
        dev_dbg(&pdev->dev, "only one SEP supported.\n");
        return -EBUSY;
    }

    /* Enable the device */
    error = pci_enable_device(pdev);
    if (error) {
        dev_warn(&pdev->dev, "error enabling pci device\n");
        goto end_function;
    }

    /* Allocate the sep_device structure for this device */
    sep_dev = kzalloc(sizeof(struct sep_device), GFP_ATOMIC);
    if (sep_dev == NULL) {
        dev_warn(&pdev->dev,
            "can't kmalloc the sep_device structure\n");
        error = -ENOMEM;
        goto end_function_disable_device;
    }

    /*
     * We're going to use another variable for actually
     * working with the device; this way, if we have
     * multiple devices in the future, it would be easier
     * to make appropriate changes
     */
    sep = sep_dev;

    sep->pdev = pci_dev_get(pdev);

    init_waitqueue_head(&sep->event_transactions);
    init_waitqueue_head(&sep->event_interrupt);
    spin_lock_init(&sep->snd_rply_lck);
    spin_lock_init(&sep->sep_queue_lock);
    sema_init(&sep->sep_doublebuf, SEP_DOUBLEBUF_USERS_LIMIT);

    INIT_LIST_HEAD(&sep->sep_queue_status);

    dev_dbg(&sep->pdev->dev,
        "sep probe: PCI obtained, device being prepared\n");
    dev_dbg(&sep->pdev->dev, "revision is %d\n", sep->pdev->revision);

    /* Set up our register area */
    sep->reg_physical_addr = pci_resource_start(sep->pdev, 0);
    if (!sep->reg_physical_addr) {
        dev_warn(&sep->pdev->dev, "Error getting register start\n");
        error = -ENODEV;
        goto end_function_free_sep_dev;
    }

    sep->reg_physical_end = pci_resource_end(sep->pdev, 0);
    if (!sep->reg_physical_end) {
        dev_warn(&sep->pdev->dev, "Error getting register end\n");
        error = -ENODEV;
        goto end_function_free_sep_dev;
    }

    sep->reg_addr = ioremap_nocache(sep->reg_physical_addr,
        (size_t)(sep->reg_physical_end - sep->reg_physical_addr + 1));
    if (!sep->reg_addr) {
        dev_warn(&sep->pdev->dev, "Error getting register virtual\n");
        error = -ENODEV;
        goto end_function_free_sep_dev;
    }

    dev_dbg(&sep->pdev->dev,
        "Register area start %llx end %llx virtual %p\n",
        (unsigned long long)sep->reg_physical_addr,
        (unsigned long long)sep->reg_physical_end,
        sep->reg_addr);

    /* Allocate the shared area */
    sep->shared_size = SEP_DRIVER_MESSAGE_SHARED_AREA_SIZE_IN_BYTES +
        SYNCHRONIC_DMA_TABLES_AREA_SIZE_BYTES +
        SEP_DRIVER_DATA_POOL_SHARED_AREA_SIZE_IN_BYTES +
        SEP_DRIVER_STATIC_AREA_SIZE_IN_BYTES +
        SEP_DRIVER_SYSTEM_DATA_MEMORY_SIZE_IN_BYTES;

    if (sep_map_and_alloc_shared_area(sep)) {
        error = -ENOMEM;
        /* Allocation failed */
        goto end_function_error;
    }

    /* Clear ICR register */
    sep_write_reg(sep, HW_HOST_ICR_REG_ADDR, 0xFFFFFFFF);

    /* Set the IMR register - open only GPR 2 */
    sep_write_reg(sep, HW_HOST_IMR_REG_ADDR, (~(0x1 << 13)));

    /* Initialize send/receive counters */
    sep->send_ct = sep->reply_ct = 0;

    /* Get the interrupt line */
    error = request_irq(pdev->irq, sep_inthandler, IRQF_SHARED,
        "sep_driver", sep);

    if (error)
        goto end_function_deallocate_sep_shared_area;

    /* The new chip requires a shared area reconfigure */
    error = sep_reconfig_shared_area(sep);
    if (error)
        goto end_function_free_irq;

    /* Create the rpmb workqueue */
    sep->rpmb_workqueue = create_workqueue(DRVNAME "-ewq");
    if (unlikely(!sep->rpmb_workqueue)) {
        dev_err(&sep->pdev->dev, "Unable to create rpmb workqueue");
        error = -EFAULT;
        goto end_function_free_irq;
    }
    INIT_WORK(&sep->rpmb_work, rpmb_process_request);

    sep->in_use = 1;

    /**
     * Now we need to tell the sep the newly acqured shared
     * memory physical address.
     * This also serves the purpose of informing the sep that
     * we are in post-os boot; ie; that it's the os that is
     * now using the sep and no longer the scu. This is required
     * for the RPMB functionality.
     */

    /* First set the outgoing and incomming message pointers */
    dev_dbg(&sep->pdev->dev, "Sending shared phys to sep\n");

    shm_to_sep = (struct sep_msg_shared_mem_addr_to_sep *)
        (sep->shared_addr +
        SEP_DRIVER_MESSAGE_AREA_OFFSET_IN_BYTES);

    shm_from_sep = (struct sep_msg_shared_mem_addr_from_sep *)
        (sep->shared_addr +
        SEP_DRIVER_MESSAGE_AREA_OFFSET_IN_BYTES);

    /* fill in the outgoing meessage to the sep */

    shm_to_sep->token = SEP_START_MSG_TOKEN;
    shm_to_sep->command = DX_SEP_HOST_SEP_SEP_DRIVER_LOADED_OP_CODE;
    shm_to_sep->shared_phys = (u32)sep->shared_bus;
    shm_to_sep->crc = 0;
    shm_to_sep->size = 7;

    /* Now send this command */
    error = sep_send_command_handler(sep);

    /* Now wait for sep */
    wait_event_timeout(sep->event_interrupt,
        (test_bit(SEP_WORKING_LOCK_BIT,
            &sep->in_use_flags) == 0),
        (WAIT_TIME * HZ));
     error = -1;
    /* see if the sep got the message okay */
    if (shm_from_sep->token != SEP_START_MSG_TOKEN) {
        dev_dbg(&sep->pdev->dev, "shm_from_sep->token incorrect\n");
        goto end_function_free_workqueue;
    }

    if (shm_from_sep->command !=
        DX_SEP_HOST_SEP_SEP_DRIVER_LOADED_OP_CODE) {

        dev_dbg(&sep->pdev->dev, "shm_from_sep->command incorrect\n");
        goto end_function_free_workqueue;
    }

    if (shm_from_sep->result != 0) {
        dev_dbg(&sep->pdev->dev, "shm_from_sep->result incorrect\n");
        dev_dbg(&sep->pdev->dev, "got %x instead of %x\n",
            shm_from_sep->result, 0);
        goto end_function_free_workqueue;
    }

    /* clear the lock bit */
    clear_bit(SEP_WORKING_LOCK_BIT, &sep->in_use_flags);

    dev_dbg(&sep->pdev->dev, "Done sending shared phys to sep\n");

    /* Finally magic up the device nodes */
    /* Register driver with the fs */
    error = sep_register_driver_with_fs(sep);

    if (error) {
        dev_dbg(&sep->pdev->dev, "error registering dev file\n");
        goto end_function_free_workqueue;
    }

    sep->in_use = 0; /* through touching the device */
#ifdef SEP_ENABLE_RUNTIME_PM
    pm_runtime_put_noidle(&sep->pdev->dev);
    pm_runtime_allow(&sep->pdev->dev);
    pm_runtime_set_autosuspend_delay(&sep->pdev->dev,
        SUSPEND_DELAY);
    pm_runtime_use_autosuspend(&sep->pdev->dev);
    pm_runtime_mark_last_busy(&sep->pdev->dev);
    sep->power_save_setup = 1;
#endif
    /* register kernel crypto driver */
#if defined(CONFIG_ENABLE_SEP_KERNEL_CRYPTO)
    error = sep_crypto_setup();
    if (error) {
        dev_dbg(&sep->pdev->dev, "crypto setup fail\n");
        goto end_function_free_workqueue;
    }
#endif
    goto end_function;

end_function_free_workqueue:
    destroy_workqueue(sep->rpmb_workqueue);

end_function_free_irq:
    free_irq(pdev->irq, sep);

end_function_deallocate_sep_shared_area:
    /* De-allocate shared area */
    sep_unmap_and_free_shared_area(sep);

end_function_error:
    iounmap(sep->reg_addr);

end_function_free_sep_dev:
    pci_dev_put(sep_dev->pdev);
    kfree(sep_dev);
    sep_dev = NULL;

end_function_disable_device:
    pci_disable_device(pdev);

end_function:
    return error;
}

/**
 * sep_remove -    handles removing device from pci subsystem
 * @pdev:    pointer to pci device
 *
 * This function will handle removing our sep device from pci subsystem on exit
 * or unloading this module. It should free up all used resources, and unmap if
 * any memory regions mapped.
 */
static void sep_remove(struct pci_dev *pdev)
{
    struct sep_device *sep = sep_dev;

    /* Destroy rpmb workqueue */
    destroy_workqueue(sep->rpmb_workqueue);

    /* Unregister from fs */
    misc_deregister(&sep->miscdev_sep);

    /* Unregister from kernel crypto */
    sep_crypto_takedown();

    /* Free the irq */
    free_irq(sep->pdev->irq, sep);

    /* Free the shared area  */
    sep_unmap_and_free_shared_area(sep_dev);
    iounmap((void *) sep_dev->reg_addr);

#ifdef SEP_ENABLE_RUNTIME_PM
    if (sep->in_use) {
        sep->in_use = 0;
        pm_runtime_forbid(&sep->pdev->dev);
        pm_runtime_get_noresume(&sep->pdev->dev);
    }
#endif
    pci_dev_put(sep_dev->pdev);
    kfree(sep_dev);
    sep_dev = NULL;

}

是不是感觉这种逻辑很奇怪,看看解决人是怎么说的:

if sep_probe probe failed, we should return a erro number instead zero.otherwise the pci core will binder the driver and call driver's callback function like sep_pci_suspend, in this function, it'll access no exist memory and cause ipanic.


呵呵,做点笔记,以后自己留着看,without the patch,error =0 if(!shm_from_sep->result != 0) and sep_probe rollback,but sep_probe still returns error = 0;we need returns -1 when sep_probe rollback,so pci framework wouldn't bind the driver to device.then ,at s3,sep driver's callback wouldn't be called.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值