Example #1
0
/***********************************************************
 * Name: vchi_service_release
 *
 * Arguments: const VCHI_SERVICE_HANDLE_T handle
 *
 * Description: Routine to decrement refcount on a service
 *
 * Returns: void
 *
 ***********************************************************/
int32_t vchi_service_release(const VCHI_SERVICE_HANDLE_T handle)
{
	int32_t ret = -1;

	struct shim_service *service = (struct shim_service *)handle;
	if (service)
		ret = vchiq_status_to_vchi(
			vchiq_release_service(service->handle));
	return ret;
}
Example #2
0
static MMAL_STATUS_T mmal_vc_release_internal(MMAL_CLIENT_T *client)
{
   MMAL_STATUS_T status = MMAL_SUCCESS;
   vcos_mutex_lock(&client->lock);
   if(--client->usecount == 0)
   {
      if(vchiq_release_service(client->service) != VCHIQ_SUCCESS)
      {
         client->usecount++;
         status = MMAL_EIO;
      }
   }
   vcos_mutex_unlock(&client->lock);
   return status;
}
Example #3
0
static int vc_watchdog_proc_write(
	struct file *file,
	const char __user *buffer,
	unsigned long count,
	void *data)
{
	char *command;
	char kbuf[PROC_WRITE_BUF_SIZE + 1];

	(void)file;

	memset(kbuf, 0, PROC_WRITE_BUF_SIZE + 1);
	if (count >= PROC_WRITE_BUF_SIZE)
		count = PROC_WRITE_BUF_SIZE;

	if (copy_from_user(kbuf, buffer, count) != 0)
		return -EFAULT;
	kbuf[count - 1] = 0;

	command = kbuf;

	if (strncmp("enable", command, strlen("enable")) == 0) {
		LOG_INFO("%s: Enabling VC watchdog", __func__);
		atomic_set(&vc_wdog_state->wdog_enabled, 1);
		complete_all(&vc_wdog_state->wdog_disable_blocker);
	} else if (strncmp("disable", command, strlen("disable")) == 0) {
		LOG_INFO("%s: Disabling VC watchdog", __func__);
		atomic_set(&vc_wdog_state->wdog_enabled, 0);
		init_completion(&vc_wdog_state->wdog_disable_blocker);
	} else if (strncmp("ping", command, strlen("ping")) == 0) {
		unsigned long msg = WDOG_PING_MSG;
		VCHIQ_ELEMENT_T elem = {
			.data = (void *)&msg,
			.size = sizeof(msg)
		};
		long rc = 0;
		/* on-demand ping of videocore.  Wake VC up to do this. */
		LOG_INFO("%s: Pinging VC...", __func__);
		vchiq_use_service(vc_wdog_state->service_handle);

		if (mutex_lock_interruptible(&vc_wdog_state->wdog_ping_mutex)
									!= 0) {
			LOG_ERR("%s: Interrupted waiting for watchdog",
				__func__);
		} else {
			/* ping vc... */
			vchiq_queue_message(vc_wdog_state->service_handle,
				&elem, 1);

			/* ...and wait for the response with a timeout */
			rc = wait_for_completion_interruptible_timeout(
				&vc_wdog_state->wdog_ping_response,
				msecs_to_jiffies(VC_PING_RESPONSE_TIMEOUT_MS));

			if (rc == 0)
				LOG_ERR("%s VideoCore ping timed out!!",
					__func__);
			else if (rc < 0)
				LOG_ERR("%s: Interrupted waiting for ping",
					__func__);
			else
				LOG_INFO("%s: Ping response received",
					__func__);
		}
		mutex_unlock(&vc_wdog_state->wdog_ping_mutex);

		vchiq_release_service(vc_wdog_state->service_handle);
	}

	return count;
}
Example #4
0
static int
vc_watchdog_thread_func(void *v)
{
	while (1) {
		long rc;
		unsigned long msg = WDOG_PING_MSG;
		VCHIQ_ELEMENT_T elem = {
			.data = (void *)&msg,
			.size = sizeof(msg)
		};
		int time_remaining =
			msecs_to_jiffies(WATCHDOG_PING_RATE_MS);

		LOG_DBG("%s: waiting on disable blocker...", __func__);
		if (wait_for_completion_interruptible(
				&vc_wdog_state->wdog_disable_blocker) != 0) {
			flush_signals(current);
			continue;
		}

		LOG_DBG("%s: Waiting for VC to be awake...", __func__);
		/* Ensure we only ping videocore when it's awake. Call use
		 * service in a mode which will not initiate a wakeup */
		vchiq_use_service_no_resume(vc_wdog_state->service_handle);

		if (!atomic_read(&vc_wdog_state->wdog_enabled)) {
			vchiq_release_service(vc_wdog_state->service_handle);
			LOG_DBG("%s: VC watchdog disabled", __func__);
			continue;
		}

		if (mutex_lock_interruptible(&vc_wdog_state->wdog_ping_mutex)
				!= 0) {
			vchiq_release_service(vc_wdog_state->service_handle);
			LOG_DBG("%s: Interrupted waiting for ping", __func__);
			continue;
		}

		LOG_DBG("%s: Pinging videocore", __func__);
		/* ping vc... */
		vchiq_queue_message(vc_wdog_state->service_handle, &elem, 1);

		LOG_DBG("%s: Waiting for ping response", __func__);
		/* ...and wait for the response with a timeout */
		rc = wait_for_completion_interruptible_timeout(
			&vc_wdog_state->wdog_ping_response,
			msecs_to_jiffies(VC_PING_RESPONSE_TIMEOUT_MS));

		if (rc == 0) {
			/* Timed out... BANG! */
			vc_wdog_state->failed_pings++;
			LOG_ERR("%s VideoCore Watchdog timed out!! (%d)",
				__func__, vc_wdog_state->failed_pings);
			if (vc_wdog_state->failed_pings >=
						WATCHDOG_NO_RESPONSE_COUNT)
			BUG();
		} else if (rc < 0)
			LOG_ERR("%s: Interrupted waiting for ping", __func__);
		else {
			LOG_DBG("%s: Ping response received", __func__);
			vc_wdog_state->failed_pings = 0;
		}

		mutex_unlock(&vc_wdog_state->wdog_ping_mutex);

		vchiq_release_service(vc_wdog_state->service_handle);

		LOG_DBG("%s: waiting before pinging again...", __func__);
		/* delay before running again */
		do {
			set_current_state(TASK_INTERRUPTIBLE);
			time_remaining = schedule_timeout(time_remaining);
			if (time_remaining) {
				LOG_ERR("%s interrupted", __func__);
				flush_signals(current);
			}
		} while (time_remaining > 0);
	}

	return 0;
}

static void vc_watchdog_connected_init(void)
{
	int ret = 0;
	VCHIQ_SERVICE_PARAMS_T vchiq_params = {
		.fourcc      = VCHIQ_MAKE_FOURCC('W', 'D', 'O', 'G'),
		.callback    = vc_watchdog_vchiq_callback,
		.version     = VC_WDOG_VERSION,
		.version_min = VC_WDOG_VERSION_MIN
	};

	LOG_INFO("%s: start", __func__);

	/* Initialize and create a VCHIQ connection */
	ret = vchiq_initialise(&vc_wdog_state->initialise_instance);
	if (ret != 0) {
		LOG_ERR("%s: failed to initialise VCHIQ instance (ret=%d)",
				__func__, ret);
		ret = -EIO;
		goto out;
	}
	ret = vchiq_connect(vc_wdog_state->initialise_instance);
	if (ret != 0) {
		LOG_ERR("%s: failed to connect VCHIQ instance (ret=%d)",
				__func__, ret);
		ret = -EIO;
		goto out;
	}

	ret = vchiq_open_service(vc_wdog_state->initialise_instance,
			&vchiq_params, &vc_wdog_state->service_handle);
	if (ret != 0 || (vc_wdog_state->service_handle == 0)) {
		LOG_ERR("%s: failed to add WDOG service: error %d",
				__func__, ret);
		ret = -EPERM;
		goto out;
	}

	vchiq_release_service(vc_wdog_state->service_handle);

	init_completion(&vc_wdog_state->wdog_ping_response);
	mutex_init(&vc_wdog_state->wdog_ping_mutex);
	init_completion(&vc_wdog_state->wdog_disable_blocker);

#ifdef ENABLE_VC_WATCHDOG
	complete_all(&vc_wdog_state->wdog_disable_blocker);
	atomic_set(&vc_wdog_state->wdog_enabled, 1);
#else
	atomic_set(&vc_wdog_state->wdog_enabled, 0);
#endif

	vc_wdog_state->wdog_thread = kthread_create(
		&vc_watchdog_thread_func, NULL, "vc-watchdog");
	if (vc_wdog_state->wdog_thread == NULL)
		LOG_ERR("FATAL: couldn't create thread vc-watchdog");
	else
		wake_up_process(vc_wdog_state->wdog_thread);

out:
	LOG_INFO("%s: end (ret=%d)", __func__, ret);
}

static int vc_watchdog_probe(struct platform_device *p_dev)
{
	int ret = 0;
	LOG_INFO("%s: start", __func__);
	vc_wdog_state = kzalloc(sizeof(struct vc_watchdog_state), GFP_KERNEL);
	if (!vc_wdog_state) {
		ret = -ENOMEM;
		goto exit;
	}

	vc_wdog_state->p_dev = p_dev;

	vc_wdog_state->proc_entry = create_proc_entry(DRIVER_NAME, 0444, NULL);
	if (vc_wdog_state->proc_entry == NULL) {
		ret = -EFAULT;
		goto out_efault;
	}
	vc_wdog_state->proc_entry->data = (void *)vc_wdog_state;
	vc_wdog_state->proc_entry->write_proc = vc_watchdog_proc_write;

	vchiq_add_connected_callback(vc_watchdog_connected_init);

	goto exit;

out_efault:
	kfree(vc_wdog_state);
	vc_wdog_state = NULL;
exit:
	LOG_INFO("%s: end, ret=%d", __func__, ret);
	return ret;
}