/*********************************************************** * 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; }
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; }
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; }
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; }