From 703c02342c29c44ca434fc1f0c704e2851bd9532 Mon Sep 17 00:00:00 2001 From: Sven Schnelle Date: Sat, 14 Nov 2015 20:56:21 +0100 Subject: [PATCH] bcwc_pcie: Fix removal of module the IRQ workqueue was called after channel info was freed, which was crashing the kernel sometimes. Also fix the isp powerdown sequence, to stop ISP properly if firmware crashes. --- bcwc_drv.c | 12 ++++++++---- bcwc_isp.c | 22 ++++++++++++++++------ bcwc_isp.h | 1 + 3 files changed, 25 insertions(+), 10 deletions(-) diff --git a/bcwc_drv.c b/bcwc_drv.c index e10c5bf..8a8ee8e 100644 --- a/bcwc_drv.c +++ b/bcwc_drv.c @@ -332,12 +332,16 @@ static void bcwc_pci_remove(struct pci_dev *pdev) struct bcwc_private *dev_priv; dev_priv = pci_get_drvdata(pdev); - bcwc_isp_cmd_stop(dev_priv); - isp_uninit(dev_priv); - bcwc_hw_deinit(dev_priv); if (dev_priv) { - isp_mem_destroy(dev_priv->firmware); + bcwc_isp_cmd_stop(dev_priv); + isp_powerdown(dev_priv); bcwc_irq_disable(dev_priv); + cancel_work_sync(&dev_priv->irq_work); + isp_uninit(dev_priv); + bcwc_hw_deinit(dev_priv); + + isp_mem_destroy(dev_priv->firmware); + bcwc_buffer_exit(dev_priv); pci_disable_msi(pdev); if (dev_priv->s2_io) diff --git a/bcwc_isp.c b/bcwc_isp.c index c0a6bc4..9ac71fd 100644 --- a/bcwc_isp.c +++ b/bcwc_isp.c @@ -348,12 +348,15 @@ static void isp_free_set_file(struct bcwc_private *dev_priv) { isp_mem_destroy(dev_priv->set_file); } -int isp_uninit(struct bcwc_private *dev_priv) + +int isp_powerdown(struct bcwc_private *dev_priv) { int retries; u32 reg; + BCWC_ISP_REG_WRITE(0xf7fbdff9, 0xc3000); bcwc_isp_cmd_powerdown(dev_priv); + for (retries = 0; retries < 1000; retries++) { reg = BCWC_ISP_REG_READ(0xc3000); if (reg == 0x8042006) @@ -363,16 +366,23 @@ int isp_uninit(struct bcwc_private *dev_priv) if (retries >= 1000) { dev_info(&dev_priv->pdev->dev, "deinit failed!\n"); + return -EIO; } + return 0; +} +int isp_uninit(struct bcwc_private *dev_priv) +{ + BCWC_ISP_REG_WRITE(0x00000000, 0x40004); + BCWC_ISP_REG_WRITE(0x00000000, 0x41004); BCWC_ISP_REG_WRITE(0xffffffff, 0xc0008); BCWC_ISP_REG_WRITE(0xffffffff, 0xc000c); BCWC_ISP_REG_WRITE(0xffffffff, 0xc0010); - BCWC_ISP_REG_WRITE(0, 0xc0c04); - BCWC_ISP_REG_WRITE(0xffffffff, 0xc0c0c); - BCWC_ISP_REG_WRITE(0, 0xc0c14); - BCWC_ISP_REG_WRITE(0xffffffff, 0xc0c1c); - BCWC_ISP_REG_WRITE(0xffffffff, 0xc0c24); + BCWC_ISP_REG_WRITE(0x00000000, 0xc1004); + BCWC_ISP_REG_WRITE(0xffffffff, 0xc100c); + BCWC_ISP_REG_WRITE(0xffffffff, 0xc1014); + BCWC_ISP_REG_WRITE(0xffffffff, 0xc101c); + BCWC_ISP_REG_WRITE(0xffffffff, 0xc1024); mdelay(1); BCWC_ISP_REG_WRITE(0, 0xc0000); diff --git a/bcwc_isp.h b/bcwc_isp.h index 58e3335..8408bf2 100644 --- a/bcwc_isp.h +++ b/bcwc_isp.h @@ -572,6 +572,7 @@ extern struct isp_mem_obj *isp_mem_create(struct bcwc_private *dev_priv, extern int isp_mem_destroy(struct isp_mem_obj *obj); extern int bcwc_isp_cmd_start(struct bcwc_private *dev_priv); extern int bcwc_isp_cmd_stop(struct bcwc_private *dev_priv); +extern int isp_powerdown(struct bcwc_private *dev_priv); extern int bcwc_isp_cmd_print_enable(struct bcwc_private *dev_priv, int enable); extern int bcwc_isp_cmd_set_loadfile(struct bcwc_private *dev_priv); extern int bcwc_isp_cmd_channel_info(struct bcwc_private *dev_priv);