Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ipu-isys: fw init procedures moved to queue. #113

Open
wants to merge 1 commit into
base: iotg_ipu6
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
125 changes: 125 additions & 0 deletions drivers/media/pci/intel/ipu-isys-queue.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <linux/module.h>
#include <linux/string.h>
#include <linux/delay.h>
#include <linux/pm_runtime.h>

#include <media/media-entity.h>
#include <media/videobuf2-dma-contig.h>
Expand Down Expand Up @@ -898,12 +899,93 @@ static int __start_streaming(struct vb2_queue *q, unsigned int count)
return rval;
}

static int isys_fw_open(struct ipu_isys_video *av)
{
struct ipu_isys *isys = av->isys;
struct ipu_bus_device *adev = to_ipu_bus_device(&isys->adev->dev);
struct ipu_device *isp = adev->isp;
int rval;
const struct ipu_isys_internal_pdata *ipdata;

dev_warn(&isys->adev->dev, "%s:%d %s: enter\n",
__func__, __LINE__, av->vdev.name);

mutex_lock(&isys->mutex);

if (isys->reset_needed || isp->flr_done) {
mutex_unlock(&isys->mutex);
dev_warn(&isys->adev->dev, "%s:%d %s: isys power cycle required\n",
__func__, __LINE__, av->vdev.name);
return -EIO;
}
mutex_unlock(&isys->mutex);

rval = pm_runtime_get_sync(&isys->adev->dev);
if (rval < 0) {
pm_runtime_put_noidle(&isys->adev->dev);
return rval;
}

mutex_lock(&isys->mutex);
if (isys->video_opened++) {
/* Already open */
mutex_unlock(&isys->mutex);
dev_warn(&isys->adev->dev, "%s:%d %s: Already open, exit %d\n",
__func__, __LINE__, av->vdev.name, isys->video_opened);
return 0;
}

ipdata = isys->pdata->ipdata;
ipu_configure_spc(adev->isp,
&ipdata->hw_variant,
IPU_CPD_PKG_DIR_ISYS_SERVER_IDX,
isys->pdata->base, isys->pkg_dir,
isys->pkg_dir_dma_addr);

/*
* Buffers could have been left to wrong queue at last closure.
* Move them now back to empty buffer queue.
*/
ipu_cleanup_fw_msg_bufs(isys);

if (isys->fwcom) {
/*
* Something went wrong in previous shutdown. As we are now
* restarting isys we can safely delete old context.
*/
dev_err(&isys->adev->dev, "%s:%d %s Clearing old context\n",
__func__, __LINE__, av->vdev.name);
ipu_fw_isys_cleanup(isys);
}

rval = ipu_fw_isys_init(av->isys, ipdata->num_parallel_streams);
if (rval < 0)
goto out_lib_init;

mutex_unlock(&isys->mutex);

dev_warn(&isys->adev->dev, "%s:%d %s: exit\n",
__func__, __LINE__, av->vdev.name);
return 0;

out_lib_init:
isys->video_opened--;
mutex_unlock(&isys->mutex);
pm_runtime_put(&isys->adev->dev);

return rval;
}

static int start_streaming(struct vb2_queue *q, unsigned int count)
{
struct ipu_isys_queue *aq = vb2_queue_to_ipu_isys_queue(q);
struct ipu_isys_video *av = ipu_isys_queue_to_video(aq);
int rval;

rval = isys_fw_open(av);
if (rval < 0) {
dev_err(&av->isys->adev->dev, "isys_fw_open failed: %d\n", rval);
}
mutex_unlock(&av->mutex);
mutex_lock(&av->isys->reset_mutex);
while (av->isys->in_stop_streaming) {
Expand Down Expand Up @@ -1119,6 +1201,48 @@ static int ipu_isys_reset(struct ipu_isys_video *self_av)
return 0;
}

static int isys_fw_release(struct ipu_isys_video *av)
{
struct ipu_isys *isys = av->isys;
int ret = 0;

dev_warn(&isys->adev->dev, "%s:%d %s: enter\n",
__func__, __LINE__, av->vdev.name);
mutex_lock(&isys->reset_mutex);
while (isys->in_reset) {
mutex_unlock(&isys->reset_mutex);
dev_warn(&isys->adev->dev, "%s:%d %s: wait for reset\n",
__func__, __LINE__, av->vdev.name);
usleep_range(10000, 11000);
mutex_lock(&isys->reset_mutex);
}
mutex_unlock(&isys->reset_mutex);

mutex_lock(&isys->mutex);

if (!--isys->video_opened) {
dev_warn(&isys->adev->dev, "%s:%d %s: close fw\n",
__func__, __LINE__, av->vdev.name);
ipu_fw_isys_close(isys);
// isys->reset_needed = true; // force reset
if (isys->fwcom) {
isys->reset_needed = true;
ret = -EIO;
}
}

mutex_unlock(&isys->mutex);

if (isys->reset_needed)
pm_runtime_put_sync(&isys->adev->dev);
else
pm_runtime_put(&isys->adev->dev);

dev_warn(&isys->adev->dev, "%s:%d %s: exit\n",
__func__, __LINE__, av->vdev.name);
return ret;
}

static void stop_streaming(struct vb2_queue *q)
{
struct ipu_isys_queue *aq = vb2_queue_to_ipu_isys_queue(q);
Expand Down Expand Up @@ -1187,6 +1311,7 @@ static void stop_streaming(struct vb2_queue *q)
av->isys->in_stop_streaming = false;
mutex_unlock(&av->isys->reset_mutex);

isys_fw_release(av);
}

static unsigned int
Expand Down
90 changes: 0 additions & 90 deletions drivers/media/pci/intel/ipu-isys-video.c
Original file line number Diff line number Diff line change
Expand Up @@ -145,26 +145,7 @@ const struct ipu_isys_pixelformat ipu_isys_pfmts_packed[] = {
static int video_open(struct file *file)
{
struct ipu_isys_video *av = video_drvdata(file);
struct ipu_isys *isys = av->isys;
struct ipu_bus_device *adev = to_ipu_bus_device(&isys->adev->dev);
struct ipu_device *isp = adev->isp;
int rval;
const struct ipu_isys_internal_pdata *ipdata;

mutex_lock(&isys->mutex);

if (isys->reset_needed || isp->flr_done) {
mutex_unlock(&isys->mutex);
dev_warn(&isys->adev->dev, "isys power cycle required\n");
return -EIO;
}
mutex_unlock(&isys->mutex);

rval = pm_runtime_get_sync(&isys->adev->dev);
if (rval < 0) {
pm_runtime_put_noidle(&isys->adev->dev);
return rval;
}

rval = v4l2_fh_open(file);
if (rval)
Expand All @@ -180,47 +161,9 @@ static int video_open(struct file *file)
if (rval)
goto out_v4l2_fh_release;

mutex_lock(&isys->mutex);

if (isys->video_opened++) {
/* Already open */
mutex_unlock(&isys->mutex);
return 0;
}

ipdata = isys->pdata->ipdata;
ipu_configure_spc(adev->isp,
&ipdata->hw_variant,
IPU_CPD_PKG_DIR_ISYS_SERVER_IDX,
isys->pdata->base, isys->pkg_dir,
isys->pkg_dir_dma_addr);

/*
* Buffers could have been left to wrong queue at last closure.
* Move them now back to empty buffer queue.
*/
ipu_cleanup_fw_msg_bufs(isys);

if (isys->fwcom) {
/*
* Something went wrong in previous shutdown. As we are now
* restarting isys we can safely delete old context.
*/
dev_err(&isys->adev->dev, "Clearing old context\n");
ipu_fw_isys_cleanup(isys);
}

rval = ipu_fw_isys_init(av->isys, ipdata->num_parallel_streams);
if (rval < 0)
goto out_lib_init;

mutex_unlock(&isys->mutex);

return 0;

out_lib_init:
isys->video_opened--;
mutex_unlock(&isys->mutex);
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 6, 0)
ipu_pipeline_pm_use(&av->vdev.entity, 0);
#elif LINUX_VERSION_CODE < KERNEL_VERSION(5, 9, 0)
Expand All @@ -232,8 +175,6 @@ static int video_open(struct file *file)
out_v4l2_fh_release:
v4l2_fh_release(file);
out_power_down:
pm_runtime_put(&isys->adev->dev);

return rval;
}

Expand All @@ -246,44 +187,13 @@ static int video_release(struct file *file)
av->vdev.name);
vb2_fop_release(file);

mutex_lock(&av->isys->reset_mutex);
while (av->isys->in_reset) {
mutex_unlock(&av->isys->reset_mutex);
dev_dbg(&av->isys->adev->dev, "release: %s: wait for reset\n",
av->vdev.name
);
usleep_range(10000, 11000);
mutex_lock(&av->isys->reset_mutex);
}
mutex_unlock(&av->isys->reset_mutex);

mutex_lock(&av->isys->mutex);

if (!--av->isys->video_opened) {
dev_dbg(&av->isys->adev->dev, "release: %s: close fw\n",
av->vdev.name);
ipu_fw_isys_close(av->isys);
if (av->isys->fwcom) {
av->isys->reset_needed = true;
ret = -EIO;
}
}

mutex_unlock(&av->isys->mutex);

#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 6, 0)
ipu_pipeline_pm_use(&av->vdev.entity, 0);
#elif LINUX_VERSION_CODE < KERNEL_VERSION(5, 9, 0)
v4l2_pipeline_pm_use(&av->vdev.entity, 0);
#else
v4l2_pipeline_pm_put(&av->vdev.entity);
#endif

if (av->isys->reset_needed)
pm_runtime_put_sync(&av->isys->adev->dev);
else
pm_runtime_put(&av->isys->adev->dev);

dev_dbg(&av->isys->adev->dev, "release: %s: exit\n",
av->vdev.name);
return ret;
Expand Down