慢慢的的将理论的东西与实际相结合了,这个问题很奇怪,手机不到几分钟,就会报这样的错误,问题其实根本就跟这个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.