static void isp_stat_buf_insert_magic(struct ispstat *stat, struct ispstat_buffer *buf) { const u32 buf_size = IS_H3A_AF(stat) ? stat->buf_size + AF_EXTRA_DATA : stat->buf_size; isp_stat_buf_sync_magic_for_cpu(stat, buf, buf_size, DMA_FROM_DEVICE); memset(buf->virt_addr, MAGIC_NUM, MAGIC_SIZE); memset(buf->virt_addr + buf_size, MAGIC_NUM, MAGIC_SIZE); isp_stat_buf_sync_magic_for_device(stat, buf, buf_size, DMA_BIDIRECTIONAL); }
static void isp_stat_buf_insert_magic(struct ispstat *stat, struct ispstat_buffer *buf) { const u32 buf_size = IS_H3A_AF(stat) ? stat->buf_size + AF_EXTRA_DATA : stat->buf_size; isp_stat_buf_sync_magic_for_cpu(stat, buf, buf_size, DMA_FROM_DEVICE); /* * Inserting MAGIC_NUM at the beginning and end of the buffer. * buf->buf_size is set only after the buffer is queued. For now the * right buf_size for the current configuration is pointed by * stat->buf_size. */ memset(buf->virt_addr, MAGIC_NUM, MAGIC_SIZE); memset(buf->virt_addr + buf_size, MAGIC_NUM, MAGIC_SIZE); isp_stat_buf_sync_magic_for_device(stat, buf, buf_size, DMA_BIDIRECTIONAL); }
static int isp_stat_buf_check_magic(struct ispstat *stat, struct ispstat_buffer *buf) { const u32 buf_size = IS_H3A_AF(stat) ? buf->buf_size + AF_EXTRA_DATA : buf->buf_size; u8 *w; u8 *end; int ret = -EINVAL; isp_stat_buf_sync_magic_for_cpu(stat, buf, buf_size, DMA_FROM_DEVICE); /* Checking initial magic numbers. They shouldn't be here anymore. */ for (w = buf->virt_addr, end = w + MAGIC_SIZE; w < end; w++) if (likely(*w != MAGIC_NUM)) ret = 0; if (ret) { dev_dbg(stat->isp->dev, "%s: beginning magic check does not match.\n", stat->subdev.name); return ret; } /* Checking magic numbers at the end. They must be still here. */ for (w = buf->virt_addr + buf_size, end = w + MAGIC_SIZE; w < end; w++) { if (unlikely(*w != MAGIC_NUM)) { dev_dbg(stat->isp->dev, "%s: ending magic check does not match.\n", stat->subdev.name); return -EINVAL; } } isp_stat_buf_sync_magic_for_device(stat, buf, buf_size, DMA_FROM_DEVICE); return 0; }
static int isp_stat_buf_check_magic(struct ispstat *stat, struct ispstat_buffer *buf) { const u32 buf_size = IS_H3A_AF(stat) ? buf->buf_size + AF_EXTRA_DATA : buf->buf_size; u8 *w; u8 *end; int ret = -EINVAL; isp_stat_buf_sync_magic_for_cpu(stat, buf, buf_size, DMA_FROM_DEVICE); for (w = buf->virt_addr, end = w + MAGIC_SIZE; w < end; w++) if (likely(*w != MAGIC_NUM)) ret = 0; if (ret) { dev_dbg(stat->isp->dev, "%s: beginning magic check does not " "match.\n", stat->subdev.name); return ret; } for (w = buf->virt_addr + buf_size, end = w + MAGIC_SIZE; w < end; w++) { if (unlikely(*w != MAGIC_NUM)) { dev_dbg(stat->isp->dev, "%s: endding magic check does " "not match.\n", stat->subdev.name); return -EINVAL; } } isp_stat_buf_sync_magic_for_device(stat, buf, buf_size, DMA_FROM_DEVICE); return 0; }
/* * omap3isp_stat_config - Receives new statistic engine configuration. * @new_conf: Pointer to config structure. * * Returns 0 if successful, -EINVAL if new_conf pointer is NULL, -ENOMEM if * was unable to allocate memory for the buffer, or other errors if parameters * are invalid. */ int omap3isp_stat_config(struct ispstat *stat, void *new_conf) { int ret; unsigned long irqflags; struct ispstat_generic_config *user_cfg = new_conf; u32 buf_size = user_cfg->buf_size; if (!new_conf) { dev_dbg(stat->isp->dev, "%s: configuration is NULL\n", stat->subdev.name); return -EINVAL; } mutex_lock(&stat->ioctl_lock); dev_dbg(stat->isp->dev, "%s: configuring module with buffer " "size=0x%08lx\n", stat->subdev.name, (unsigned long)buf_size); ret = stat->ops->validate_params(stat, new_conf); if (ret) { mutex_unlock(&stat->ioctl_lock); dev_dbg(stat->isp->dev, "%s: configuration values are " "invalid.\n", stat->subdev.name); return ret; } if (buf_size != user_cfg->buf_size) dev_dbg(stat->isp->dev, "%s: driver has corrected buffer size " "request to 0x%08lx\n", stat->subdev.name, (unsigned long)user_cfg->buf_size); /* * Hack: H3A modules may need a doubled buffer size to avoid access * to a invalid memory address after a SBL overflow. * The buffer size is always PAGE_ALIGNED. * Hack 2: MAGIC_SIZE is added to buf_size so a magic word can be * inserted at the end to data integrity check purpose. * Hack 3: AF module writes one paxel data more than it should, so * the buffer allocation must consider it to avoid invalid memory * access. * Hack 4: H3A need to allocate extra space for the recover state. */ if (IS_H3A(stat)) { buf_size = user_cfg->buf_size * 2 + MAGIC_SIZE; if (IS_H3A_AF(stat)) /* * Adding one extra paxel data size for each recover * buffer + 2 regular ones. */ buf_size += AF_EXTRA_DATA * (NUM_H3A_RECOVER_BUFS + 2); if (stat->recover_priv) { struct ispstat_generic_config *recover_cfg = stat->recover_priv; buf_size += recover_cfg->buf_size * NUM_H3A_RECOVER_BUFS; } buf_size = PAGE_ALIGN(buf_size); } else { /* Histogram */ buf_size = PAGE_ALIGN(user_cfg->buf_size + MAGIC_SIZE); } ret = isp_stat_bufs_alloc(stat, buf_size); if (ret) { mutex_unlock(&stat->ioctl_lock); return ret; } spin_lock_irqsave(&stat->isp->stat_lock, irqflags); stat->ops->set_params(stat, new_conf); spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags); /* * Returning the right future config_counter for this setup, so * userspace can *know* when it has been applied. */ user_cfg->config_counter = stat->config_counter + stat->inc_config; /* Module has a valid configuration. */ stat->configured = 1; dev_dbg(stat->isp->dev, "%s: module has been successfully " "configured.\n", stat->subdev.name); mutex_unlock(&stat->ioctl_lock); return 0; }
int omap3isp_stat_config(struct ispstat *stat, void *new_conf) { int ret; unsigned long irqflags; struct ispstat_generic_config *user_cfg = new_conf; u32 buf_size = user_cfg->buf_size; if (!new_conf) { dev_dbg(stat->isp->dev, "%s: configuration is NULL\n", stat->subdev.name); return -EINVAL; } mutex_lock(&stat->ioctl_lock); dev_dbg(stat->isp->dev, "%s: configuring module with buffer " "size=0x%08lx\n", stat->subdev.name, (unsigned long)buf_size); ret = stat->ops->validate_params(stat, new_conf); if (ret) { mutex_unlock(&stat->ioctl_lock); dev_dbg(stat->isp->dev, "%s: configuration values are " "invalid.\n", stat->subdev.name); return ret; } if (buf_size != user_cfg->buf_size) dev_dbg(stat->isp->dev, "%s: driver has corrected buffer size " "request to 0x%08lx\n", stat->subdev.name, (unsigned long)user_cfg->buf_size); if (IS_H3A(stat)) { buf_size = user_cfg->buf_size * 2 + MAGIC_SIZE; if (IS_H3A_AF(stat)) buf_size += AF_EXTRA_DATA * (NUM_H3A_RECOVER_BUFS + 2); if (stat->recover_priv) { struct ispstat_generic_config *recover_cfg = stat->recover_priv; buf_size += recover_cfg->buf_size * NUM_H3A_RECOVER_BUFS; } buf_size = PAGE_ALIGN(buf_size); } else { buf_size = PAGE_ALIGN(user_cfg->buf_size + MAGIC_SIZE); } ret = isp_stat_bufs_alloc(stat, buf_size); if (ret) { mutex_unlock(&stat->ioctl_lock); return ret; } spin_lock_irqsave(&stat->isp->stat_lock, irqflags); stat->ops->set_params(stat, new_conf); spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags); user_cfg->config_counter = stat->config_counter + stat->inc_config; stat->configured = 1; dev_dbg(stat->isp->dev, "%s: module has been successfully " "configured.\n", stat->subdev.name); mutex_unlock(&stat->ioctl_lock); return 0; }