diff options
Diffstat (limited to 'gxp-platform.c')
-rw-r--r-- | gxp-platform.c | 2323 |
1 files changed, 20 insertions, 2303 deletions
diff --git a/gxp-platform.c b/gxp-platform.c index 5da0eb2..0f56b9c 100644 --- a/gxp-platform.c +++ b/gxp-platform.c @@ -5,2310 +5,35 @@ * Copyright (C) 2021 Google LLC */ -#if IS_ENABLED(CONFIG_SUBSYSTEM_COREDUMP) -#include <linux/platform_data/sscoredump.h> -#endif - -#include <linux/acpi.h> -#include <linux/cred.h> #include <linux/device.h> -#include <linux/dma-mapping.h> -#include <linux/file.h> -#include <linux/fs.h> -#include <linux/genalloc.h> -#include <linux/kthread.h> -#include <linux/log2.h> -#include <linux/miscdevice.h> -#include <linux/module.h> -#include <linux/of_device.h> +#include <linux/mod_devicetable.h> #include <linux/platform_device.h> -#include <linux/pm_runtime.h> -#include <linux/sched.h> -#include <linux/uaccess.h> -#include <linux/uidgid.h> -#if (IS_ENABLED(CONFIG_GXP_TEST) || IS_ENABLED(CONFIG_ANDROID)) && !IS_ENABLED(CONFIG_GXP_GEM5) -#include <soc/google/tpu-ext.h> -#endif -#include "gxp-client.h" -#include "gxp-config.h" -#include "gxp-debug-dump.h" -#include "gxp-debugfs.h" -#include "gxp-dma.h" -#include "gxp-dmabuf.h" -#include "gxp-domain-pool.h" -#include "gxp-firmware.h" -#include "gxp-firmware-data.h" #include "gxp-internal.h" -#include "gxp-mailbox.h" -#include "gxp-mailbox-driver.h" -#include "gxp-mapping.h" -#include "gxp-notification.h" -#include "gxp-pm.h" -#include "gxp-telemetry.h" -#include "gxp-thermal.h" -#include "gxp-vd.h" -#include "gxp-wakelock.h" -#include "gxp.h" - -static struct gxp_dev *gxp_debug_pointer; - -#define __wait_event_lock_irq_timeout_exclusive(wq_head, condition, lock, \ - timeout, state) \ - ___wait_event(wq_head, ___wait_cond_timeout(condition), state, 1, \ - timeout, spin_unlock_irq(&lock); \ - __ret = schedule_timeout(__ret); spin_lock_irq(&lock)) - -/* - * wait_event_interruptible_lock_irq_timeout() but set the exclusive flag. - */ -#define wait_event_interruptible_lock_irq_timeout_exclusive( \ - wq_head, condition, lock, timeout) \ - ({ \ - long __ret = timeout; \ - if (!___wait_cond_timeout(condition)) \ - __ret = __wait_event_lock_irq_timeout_exclusive( \ - wq_head, condition, lock, timeout, \ - TASK_INTERRUPTIBLE); \ - __ret; \ - }) - -/* Caller needs to hold client->semaphore */ -static bool check_client_has_available_vd(struct gxp_client *client, - char *ioctl_name) -{ - struct gxp_dev *gxp = client->gxp; - - lockdep_assert_held(&client->semaphore); - if (!client->vd) { - dev_err(gxp->dev, - "%s requires the client allocate a VIRTUAL_DEVICE\n", - ioctl_name); - return false; - } - if (client->vd->state == GXP_VD_UNAVAILABLE) { - dev_err(gxp->dev, "Cannot do %s on a broken virtual device\n", - ioctl_name); - return false; - } - return true; -} - -/* Caller needs to hold client->semaphore for reading */ -static bool check_client_has_available_vd_wakelock(struct gxp_client *client, - char *ioctl_name) -{ - struct gxp_dev *gxp = client->gxp; - - lockdep_assert_held_read(&client->semaphore); - if (!client->has_vd_wakelock) { - dev_err(gxp->dev, - "%s requires the client hold a VIRTUAL_DEVICE wakelock\n", - ioctl_name); - return false; - } - if (client->vd->state == GXP_VD_UNAVAILABLE) { - dev_err(gxp->dev, "Cannot do %s on a broken virtual device\n", - ioctl_name); - return false; - } - return true; -} - -#if IS_ENABLED(CONFIG_SUBSYSTEM_COREDUMP) -static struct sscd_platform_data gxp_sscd_pdata; - -static void gxp_sscd_release(struct device *dev) -{ - pr_debug("%s\n", __func__); -} - -static struct platform_device gxp_sscd_dev = { - .name = GXP_DRIVER_NAME, - .driver_override = SSCD_NAME, - .id = -1, - .dev = { - .platform_data = &gxp_sscd_pdata, - .release = gxp_sscd_release, - }, -}; -#endif // CONFIG_SUBSYSTEM_COREDUMP - -/* Mapping from GXP_POWER_STATE_* to enum aur_power_state in gxp-pm.h */ -static const uint aur_state_array[GXP_NUM_POWER_STATES] = { - AUR_OFF, AUR_UUD, AUR_SUD, AUR_UD, AUR_NOM, - AUR_READY, AUR_UUD_PLUS, AUR_SUD_PLUS, AUR_UD_PLUS -}; -/* Mapping from MEMORY_POWER_STATE_* to enum aur_memory_power_state in gxp-pm.h */ -static const uint aur_memory_state_array[MEMORY_POWER_STATE_MAX + 1] = { - AUR_MEM_UNDEFINED, AUR_MEM_MIN, AUR_MEM_VERY_LOW, AUR_MEM_LOW, - AUR_MEM_HIGH, AUR_MEM_VERY_HIGH, AUR_MEM_MAX -}; - -static int gxp_open(struct inode *inode, struct file *file) -{ - struct gxp_client *client; - struct gxp_dev *gxp = container_of(file->private_data, struct gxp_dev, - misc_dev); - int ret = 0; - - /* If this is the first call to open(), request the firmware files */ - ret = gxp_firmware_request_if_needed(gxp); - if (ret) { - dev_err(gxp->dev, - "Failed to request dsp firmware files (ret=%d)\n", ret); - return ret; - } - - client = gxp_client_create(gxp); - if (IS_ERR(client)) - return PTR_ERR(client); - - client->tgid = current->tgid; - client->pid = current->pid; - - file->private_data = client; - - mutex_lock(&gxp->client_list_lock); - list_add(&client->list_entry, &gxp->client_list); - mutex_unlock(&gxp->client_list_lock); - - return ret; -} - -static int gxp_release(struct inode *inode, struct file *file) -{ - struct gxp_client *client = file->private_data; - - /* - * If open failed and no client was created then no clean-up is needed. - */ - if (!client) - return 0; - - if (client->enabled_telemetry_logging) - gxp_telemetry_disable(client->gxp, GXP_TELEMETRY_TYPE_LOGGING); - if (client->enabled_telemetry_tracing) - gxp_telemetry_disable(client->gxp, GXP_TELEMETRY_TYPE_TRACING); - - mutex_lock(&client->gxp->client_list_lock); - list_del(&client->list_entry); - mutex_unlock(&client->gxp->client_list_lock); - - gxp_client_destroy(client); - - return 0; -} - -static inline enum dma_data_direction mapping_flags_to_dma_dir(u32 flags) -{ - switch (flags & 0x3) { - case 0x0: /* 0b00 */ - return DMA_BIDIRECTIONAL; - case 0x1: /* 0b01 */ - return DMA_TO_DEVICE; - case 0x2: /* 0b10 */ - return DMA_FROM_DEVICE; - } - - return DMA_NONE; -} - -static int gxp_map_buffer(struct gxp_client *client, - struct gxp_map_ioctl __user *argp) -{ - struct gxp_dev *gxp = client->gxp; - struct gxp_map_ioctl ibuf; - struct gxp_mapping *map; - int ret = 0; - - if (copy_from_user(&ibuf, argp, sizeof(ibuf))) - return -EFAULT; - - if (ibuf.size == 0 || ibuf.virtual_core_list == 0) - return -EINVAL; - - if (ibuf.host_address % L1_CACHE_BYTES || ibuf.size % L1_CACHE_BYTES) { - dev_err(gxp->dev, - "Mapped buffers must be cache line aligned and padded.\n"); - return -EINVAL; - } - - down_read(&client->semaphore); - - if (!check_client_has_available_vd(client, "GXP_MAP_BUFFER")) { - ret = -ENODEV; - goto out; - } - - /* the list contains un-allocated core bits */ - if (ibuf.virtual_core_list & ~(BIT(client->vd->num_cores) - 1)) { - ret = -EINVAL; - goto out; - } - - map = gxp_mapping_create(gxp, client->vd, ibuf.virtual_core_list, - ibuf.host_address, ibuf.size, - /*gxp_dma_flags=*/0, - mapping_flags_to_dma_dir(ibuf.flags)); - if (IS_ERR(map)) { - ret = PTR_ERR(map); - dev_err(gxp->dev, "Failed to create mapping (ret=%d)\n", ret); - goto out; - } - - ret = gxp_vd_mapping_store(client->vd, map); - if (ret) { - dev_err(gxp->dev, "Failed to store mapping (ret=%d)\n", ret); - goto error_destroy; - } - - ibuf.device_address = map->device_address; - - if (copy_to_user(argp, &ibuf, sizeof(ibuf))) { - ret = -EFAULT; - goto error_remove; - } - - /* - * The virtual device acquired its own reference to the mapping when - * it was stored in the VD's records. Release the reference from - * creating the mapping since this function is done using it. - */ - gxp_mapping_put(map); - -out: - up_read(&client->semaphore); - - return ret; - -error_remove: - gxp_vd_mapping_remove(client->vd, map); -error_destroy: - gxp_mapping_put(map); - up_read(&client->semaphore); - return ret; -} - -static int gxp_unmap_buffer(struct gxp_client *client, - struct gxp_map_ioctl __user *argp) -{ - struct gxp_dev *gxp = client->gxp; - struct gxp_map_ioctl ibuf; - struct gxp_mapping *map; - int ret = 0; - - if (copy_from_user(&ibuf, argp, sizeof(ibuf))) - return -EFAULT; - - down_read(&client->semaphore); - - if (!client->vd) { - dev_err(gxp->dev, - "GXP_UNMAP_BUFFER requires the client allocate a VIRTUAL_DEVICE\n"); - ret = -ENODEV; - goto out; - } - - map = gxp_vd_mapping_search(client->vd, - (dma_addr_t)ibuf.device_address); - if (!map) { - dev_err(gxp->dev, - "Mapping not found for provided device address %#llX\n", - ibuf.device_address); - ret = -EINVAL; - goto out; - } else if (!map->host_address) { - dev_err(gxp->dev, "dma-bufs must be unmapped via GXP_UNMAP_DMABUF\n"); - ret = -EINVAL; - goto out; - } - - WARN_ON(map->host_address != ibuf.host_address); - - gxp_vd_mapping_remove(client->vd, map); - - /* Release the reference from gxp_vd_mapping_search() */ - gxp_mapping_put(map); - -out: - up_read(&client->semaphore); - - return ret; -} - -static int gxp_sync_buffer(struct gxp_client *client, - struct gxp_sync_ioctl __user *argp) -{ - struct gxp_dev *gxp = client->gxp; - struct gxp_sync_ioctl ibuf; - struct gxp_mapping *map; - int ret; - - if (copy_from_user(&ibuf, argp, sizeof(ibuf))) - return -EFAULT; - - down_read(&client->semaphore); - - if (!client->vd) { - dev_err(gxp->dev, - "GXP_SYNC_BUFFER requires the client allocate a VIRTUAL_DEVICE\n"); - ret = -ENODEV; - goto out; - } - - map = gxp_vd_mapping_search(client->vd, - (dma_addr_t)ibuf.device_address); - if (!map) { - dev_err(gxp->dev, - "Mapping not found for provided device address %#llX\n", - ibuf.device_address); - ret = -EINVAL; - goto out; - } - - ret = gxp_mapping_sync(map, ibuf.offset, ibuf.size, - ibuf.flags == GXP_SYNC_FOR_CPU); - - /* Release the reference from gxp_vd_mapping_search() */ - gxp_mapping_put(map); - -out: - up_read(&client->semaphore); - - return ret; -} - -static int -gxp_mailbox_command_compat(struct gxp_client *client, - struct gxp_mailbox_command_compat_ioctl __user *argp) -{ - struct gxp_dev *gxp = client->gxp; - struct gxp_mailbox_command_compat_ioctl ibuf; - struct gxp_command cmd; - struct buffer_descriptor buffer; - int virt_core, phys_core; - int ret = 0; - uint gxp_power_state, memory_power_state; - - if (copy_from_user(&ibuf, argp, sizeof(ibuf))) { - dev_err(gxp->dev, - "Unable to copy ioctl data from user-space\n"); - return -EFAULT; - } - - /* Caller must hold VIRTUAL_DEVICE wakelock */ - down_read(&client->semaphore); - - if (!check_client_has_available_vd_wakelock(client, - "GXP_MAILBOX_COMMAND")) { - ret = -ENODEV; - goto out_unlock_client_semaphore; - } - - down_read(&gxp->vd_semaphore); - - virt_core = ibuf.virtual_core_id; - phys_core = gxp_vd_virt_core_to_phys_core(client->vd, virt_core); - if (phys_core < 0) { - dev_err(gxp->dev, - "Mailbox command failed: Invalid virtual core id (%u)\n", - virt_core); - ret = -EINVAL; - goto out; - } - - if (!gxp_is_fw_running(gxp, phys_core)) { - dev_err(gxp->dev, - "Cannot process mailbox command for core %d when firmware isn't running\n", - phys_core); - ret = -EINVAL; - goto out; - } - - if (gxp->mailbox_mgr == NULL || gxp->mailbox_mgr->mailboxes == NULL || - gxp->mailbox_mgr->mailboxes[phys_core] == NULL) { - dev_err(gxp->dev, "Mailbox not initialized for core %d\n", - phys_core); - ret = -EIO; - goto out; - } - - /* Pack the command structure */ - buffer.address = ibuf.device_address; - buffer.size = ibuf.size; - buffer.flags = ibuf.flags; - /* cmd.seq is assigned by mailbox implementation */ - cmd.code = GXP_MBOX_CODE_DISPATCH; /* All IOCTL commands are dispatch */ - cmd.priority = 0; /* currently unused */ - cmd.buffer_descriptor = buffer; - gxp_power_state = AUR_OFF; - memory_power_state = AUR_MEM_UNDEFINED; - - ret = gxp_mailbox_execute_cmd_async( - gxp->mailbox_mgr->mailboxes[phys_core], &cmd, - &client->vd->mailbox_resp_queues[virt_core].queue, - &client->vd->mailbox_resp_queues[virt_core].lock, - &client->vd->mailbox_resp_queues[virt_core].waitq, - gxp_power_state, memory_power_state, false, - client->mb_eventfds[virt_core]); - if (ret) { - dev_err(gxp->dev, "Failed to enqueue mailbox command (ret=%d)\n", - ret); - goto out; - } - - ibuf.sequence_number = cmd.seq; - if (copy_to_user(argp, &ibuf, sizeof(ibuf))) { - dev_err(gxp->dev, "Failed to copy back sequence number!\n"); - ret = -EFAULT; - goto out; - } - -out: - up_read(&gxp->vd_semaphore); -out_unlock_client_semaphore: - up_read(&client->semaphore); - - return ret; -} - -static int gxp_mailbox_command(struct gxp_client *client, - struct gxp_mailbox_command_ioctl __user *argp) -{ - struct gxp_dev *gxp = client->gxp; - struct gxp_mailbox_command_ioctl ibuf; - struct gxp_command cmd; - struct buffer_descriptor buffer; - int virt_core, phys_core; - int ret = 0; - uint gxp_power_state, memory_power_state; - bool requested_low_clkmux = false; - - if (copy_from_user(&ibuf, argp, sizeof(ibuf))) { - dev_err(gxp->dev, - "Unable to copy ioctl data from user-space\n"); - return -EFAULT; - } - if (ibuf.gxp_power_state == GXP_POWER_STATE_OFF) { - dev_err(gxp->dev, - "GXP_POWER_STATE_OFF is not a valid value when executing a mailbox command\n"); - return -EINVAL; - } - if (ibuf.gxp_power_state < GXP_POWER_STATE_OFF || - ibuf.gxp_power_state >= GXP_NUM_POWER_STATES) { - dev_err(gxp->dev, "Requested power state is invalid\n"); - return -EINVAL; - } - if (ibuf.memory_power_state < MEMORY_POWER_STATE_UNDEFINED || - ibuf.memory_power_state > MEMORY_POWER_STATE_MAX) { - dev_err(gxp->dev, "Requested memory power state is invalid\n"); - return -EINVAL; - } - - if (ibuf.gxp_power_state == GXP_POWER_STATE_READY) { - dev_warn_once( - gxp->dev, - "GXP_POWER_STATE_READY is deprecated, please set GXP_POWER_LOW_FREQ_CLKMUX with GXP_POWER_STATE_UUD state"); - ibuf.gxp_power_state = GXP_POWER_STATE_UUD; - } - - if(ibuf.power_flags & GXP_POWER_NON_AGGRESSOR) - dev_warn_once( - gxp->dev, - "GXP_POWER_NON_AGGRESSOR is deprecated, no operation here"); - - /* Caller must hold VIRTUAL_DEVICE wakelock */ - down_read(&client->semaphore); - - if (!check_client_has_available_vd_wakelock(client, - "GXP_MAILBOX_COMMAND")) { - ret = -ENODEV; - goto out_unlock_client_semaphore; - } - - down_read(&gxp->vd_semaphore); - - virt_core = ibuf.virtual_core_id; - phys_core = gxp_vd_virt_core_to_phys_core(client->vd, virt_core); - if (phys_core < 0) { - dev_err(gxp->dev, - "Mailbox command failed: Invalid virtual core id (%u)\n", - virt_core); - ret = -EINVAL; - goto out; - } - - if (!gxp_is_fw_running(gxp, phys_core)) { - dev_err(gxp->dev, - "Cannot process mailbox command for core %d when firmware isn't running\n", - phys_core); - ret = -EINVAL; - goto out; - } - - if (gxp->mailbox_mgr == NULL || gxp->mailbox_mgr->mailboxes == NULL || - gxp->mailbox_mgr->mailboxes[phys_core] == NULL) { - dev_err(gxp->dev, "Mailbox not initialized for core %d\n", - phys_core); - ret = -EIO; - goto out; - } - - /* Pack the command structure */ - buffer.address = ibuf.device_address; - buffer.size = ibuf.size; - buffer.flags = ibuf.flags; - /* cmd.seq is assigned by mailbox implementation */ - cmd.code = GXP_MBOX_CODE_DISPATCH; /* All IOCTL commands are dispatch */ - cmd.priority = 0; /* currently unused */ - cmd.buffer_descriptor = buffer; - gxp_power_state = aur_state_array[ibuf.gxp_power_state]; - memory_power_state = aur_memory_state_array[ibuf.memory_power_state]; - requested_low_clkmux = (ibuf.power_flags & GXP_POWER_LOW_FREQ_CLKMUX) != 0; - - ret = gxp_mailbox_execute_cmd_async( - gxp->mailbox_mgr->mailboxes[phys_core], &cmd, - &client->vd->mailbox_resp_queues[virt_core].queue, - &client->vd->mailbox_resp_queues[virt_core].lock, - &client->vd->mailbox_resp_queues[virt_core].waitq, - gxp_power_state, memory_power_state, requested_low_clkmux, - client->mb_eventfds[virt_core]); - if (ret) { - dev_err(gxp->dev, "Failed to enqueue mailbox command (ret=%d)\n", - ret); - goto out; - } - - ibuf.sequence_number = cmd.seq; - if (copy_to_user(argp, &ibuf, sizeof(ibuf))) { - dev_err(gxp->dev, "Failed to copy back sequence number!\n"); - ret = -EFAULT; - goto out; - } - -out: - up_read(&gxp->vd_semaphore); -out_unlock_client_semaphore: - up_read(&client->semaphore); - - return ret; -} - -static int gxp_mailbox_response(struct gxp_client *client, - struct gxp_mailbox_response_ioctl __user *argp) -{ - struct gxp_dev *gxp = client->gxp; - struct gxp_mailbox_response_ioctl ibuf; - struct gxp_async_response *resp_ptr; - int virt_core; - int ret = 0; - long timeout; - - if (copy_from_user(&ibuf, argp, sizeof(ibuf))) - return -EFAULT; - - /* Caller must hold VIRTUAL_DEVICE wakelock */ - down_read(&client->semaphore); - - if (!check_client_has_available_vd_wakelock(client, - "GXP_MAILBOX_RESPONSE")) { - ret = -ENODEV; - goto out; - } - - virt_core = ibuf.virtual_core_id; - if (virt_core >= client->vd->num_cores) { - dev_err(gxp->dev, "Mailbox response failed: Invalid virtual core id (%u)\n", - virt_core); - ret = -EINVAL; - goto out; - } - - spin_lock_irq(&client->vd->mailbox_resp_queues[virt_core].lock); - - /* - * The "exclusive" version of wait_event is used since each wake - * corresponds to the addition of exactly one new response to be - * consumed. Therefore, only one waiting response ioctl can ever - * proceed per wake event. - */ - timeout = wait_event_interruptible_lock_irq_timeout_exclusive( - client->vd->mailbox_resp_queues[virt_core].waitq, - !list_empty(&client->vd->mailbox_resp_queues[virt_core].queue), - client->vd->mailbox_resp_queues[virt_core].lock, - msecs_to_jiffies(MAILBOX_TIMEOUT)); - if (timeout <= 0) { - spin_unlock_irq( - &client->vd->mailbox_resp_queues[virt_core].lock); - /* unusual case - this only happens when there is no command pushed */ - ret = timeout ? -ETIMEDOUT : timeout; - goto out; - } - resp_ptr = list_first_entry( - &client->vd->mailbox_resp_queues[virt_core].queue, - struct gxp_async_response, list_entry); - - /* Pop the front of the response list */ - list_del(&(resp_ptr->list_entry)); - - spin_unlock_irq(&client->vd->mailbox_resp_queues[virt_core].lock); - - ibuf.sequence_number = resp_ptr->resp.seq; - switch (resp_ptr->resp.status) { - case GXP_RESP_OK: - ibuf.error_code = GXP_RESPONSE_ERROR_NONE; - /* retval is only valid if status == GXP_RESP_OK */ - ibuf.cmd_retval = resp_ptr->resp.retval; - break; - case GXP_RESP_CANCELLED: - ibuf.error_code = GXP_RESPONSE_ERROR_TIMEOUT; - break; - default: - /* No other status values are valid at this point */ - WARN(true, "Completed response had invalid status %hu", - resp_ptr->resp.status); - ibuf.error_code = GXP_RESPONSE_ERROR_INTERNAL; - break; - } - - /* - * We must be absolutely sure the timeout work has been cancelled - * and/or completed before freeing the `gxp_async_response`. - * There are 3 possible cases when we arrive at this point: - * 1) The response arrived normally and the timeout was cancelled - * 2) The response timedout and its timeout handler finished - * 3) The response handler and timeout handler raced, and the response - * handler "cancelled" the timeout handler while it was already in - * progress. - * - * This call handles case #3, and ensures any in-process timeout - * handler (which may reference the `gxp_async_response`) has - * been able to exit cleanly. - */ - cancel_delayed_work_sync(&resp_ptr->timeout_work); - kfree(resp_ptr); - - if (copy_to_user(argp, &ibuf, sizeof(ibuf))) - ret = -EFAULT; - -out: - up_read(&client->semaphore); - - return ret; -} - -static int gxp_get_specs(struct gxp_client *client, - struct gxp_specs_ioctl __user *argp) -{ - struct gxp_specs_ioctl ibuf = { - .core_count = GXP_NUM_CORES, - .memory_per_core = client->gxp->memory_per_core, - }; - - if (copy_to_user(argp, &ibuf, sizeof(ibuf))) - return -EFAULT; - - return 0; -} - -static int gxp_allocate_vd(struct gxp_client *client, - struct gxp_virtual_device_ioctl __user *argp) -{ - struct gxp_dev *gxp = client->gxp; - struct gxp_virtual_device_ioctl ibuf; - struct gxp_virtual_device *vd; - int ret = 0; - - if (copy_from_user(&ibuf, argp, sizeof(ibuf))) - return -EFAULT; - - if (ibuf.core_count == 0 || ibuf.core_count > GXP_NUM_CORES) { - dev_err(gxp->dev, "Invalid core count (%u)\n", ibuf.core_count); - return -EINVAL; - } - - if (ibuf.memory_per_core > gxp->memory_per_core) { - dev_err(gxp->dev, "Invalid memory-per-core (%u)\n", - ibuf.memory_per_core); - return -EINVAL; - } - - down_write(&client->semaphore); - - if (client->vd) { - dev_err(gxp->dev, "Virtual device was already allocated for client\n"); - ret = -EINVAL; - goto out; - } - - vd = gxp_vd_allocate(gxp, ibuf.core_count); - if (IS_ERR(vd)) { - ret = PTR_ERR(vd); - dev_err(gxp->dev, - "Failed to allocate virtual device for client (%d)\n", - ret); - goto out; - } - - client->vd = vd; - -out: - up_write(&client->semaphore); - - return ret; -} - -static int -gxp_etm_trace_start_command(struct gxp_client *client, - struct gxp_etm_trace_start_ioctl __user *argp) -{ - struct gxp_dev *gxp = client->gxp; - struct gxp_etm_trace_start_ioctl ibuf; - int phys_core; - int ret = 0; - - if (copy_from_user(&ibuf, argp, sizeof(ibuf))) - return -EFAULT; - - ibuf.trace_ram_enable &= ETM_TRACE_LSB_MASK; - ibuf.atb_enable &= ETM_TRACE_LSB_MASK; - - if (!ibuf.trace_ram_enable && !ibuf.atb_enable) - return -EINVAL; - - if (!(ibuf.sync_msg_period == 0 || - (ibuf.sync_msg_period <= ETM_TRACE_SYNC_MSG_PERIOD_MAX && - ibuf.sync_msg_period >= ETM_TRACE_SYNC_MSG_PERIOD_MIN && - is_power_of_2(ibuf.sync_msg_period)))) - return -EINVAL; - - if (ibuf.pc_match_mask_length > ETM_TRACE_PC_MATCH_MASK_LEN_MAX) - return -EINVAL; - - /* Caller must hold VIRTUAL_DEVICE wakelock */ - down_read(&client->semaphore); - - if (!check_client_has_available_vd_wakelock( - client, "GXP_ETM_TRACE_START_COMMAND")) { - ret = -ENODEV; - goto out_unlock_client_semaphore; - } - - down_read(&gxp->vd_semaphore); - - phys_core = - gxp_vd_virt_core_to_phys_core(client->vd, ibuf.virtual_core_id); - if (phys_core < 0) { - dev_err(gxp->dev, "Trace start failed: Invalid virtual core id (%u)\n", - ibuf.virtual_core_id); - ret = -EINVAL; - goto out; - } - - /* - * TODO (b/185260919): Pass the etm trace configuration to system FW - * once communication channel between kernel and system FW is ready - * (b/185819530). - */ - -out: - up_read(&gxp->vd_semaphore); -out_unlock_client_semaphore: - up_read(&client->semaphore); - - return ret; -} - -static int gxp_etm_trace_sw_stop_command(struct gxp_client *client, - __u16 __user *argp) -{ - struct gxp_dev *gxp = client->gxp; - u16 virtual_core_id; - int phys_core; - int ret = 0; - - if (copy_from_user(&virtual_core_id, argp, sizeof(virtual_core_id))) - return -EFAULT; - - /* Caller must hold VIRTUAL_DEVICE wakelock */ - down_read(&client->semaphore); - - if (!check_client_has_available_vd_wakelock( - client, "GXP_ETM_TRACE_SW_STOP_COMMAND")) { - ret = -ENODEV; - goto out_unlock_client_semaphore; - } - - down_read(&gxp->vd_semaphore); - - phys_core = gxp_vd_virt_core_to_phys_core(client->vd, virtual_core_id); - if (phys_core < 0) { - dev_err(gxp->dev, "Trace stop via software trigger failed: Invalid virtual core id (%u)\n", - virtual_core_id); - ret = -EINVAL; - goto out; - } - - /* - * TODO (b/185260919): Pass the etm stop signal to system FW once - * communication channel between kernel and system FW is ready - * (b/185819530). - */ - -out: - up_read(&gxp->vd_semaphore); -out_unlock_client_semaphore: - up_read(&client->semaphore); - - return ret; -} - -static int gxp_etm_trace_cleanup_command(struct gxp_client *client, - __u16 __user *argp) -{ - struct gxp_dev *gxp = client->gxp; - u16 virtual_core_id; - int phys_core; - int ret = 0; - - if (copy_from_user(&virtual_core_id, argp, sizeof(virtual_core_id))) - return -EFAULT; - - /* Caller must hold VIRTUAL_DEVICE wakelock */ - down_read(&client->semaphore); - - if (!check_client_has_available_vd_wakelock( - client, "GXP_ETM_TRACE_CLEANUP_COMMAND")) { - ret = -ENODEV; - goto out_unlock_client_semaphore; - } - - down_read(&gxp->vd_semaphore); - - phys_core = gxp_vd_virt_core_to_phys_core(client->vd, virtual_core_id); - if (phys_core < 0) { - dev_err(gxp->dev, "Trace cleanup failed: Invalid virtual core id (%u)\n", - virtual_core_id); - ret = -EINVAL; - goto out; - } - - /* - * TODO (b/185260919): Pass the etm clean up signal to system FW once - * communication channel between kernel and system FW is ready - * (b/185819530). - */ - -out: - up_read(&gxp->vd_semaphore); -out_unlock_client_semaphore: - up_read(&client->semaphore); - - return ret; -} - -static int -gxp_etm_get_trace_info_command(struct gxp_client *client, - struct gxp_etm_get_trace_info_ioctl __user *argp) -{ - struct gxp_dev *gxp = client->gxp; - struct gxp_etm_get_trace_info_ioctl ibuf; - int phys_core; - u32 *trace_header; - u32 *trace_data; - int ret = 0; - - if (copy_from_user(&ibuf, argp, sizeof(ibuf))) - return -EFAULT; - - if (ibuf.type > 1) - return -EINVAL; - - /* Caller must hold VIRTUAL_DEVICE wakelock */ - down_read(&client->semaphore); - - if (!check_client_has_available_vd_wakelock( - client, "GXP_ETM_GET_TRACE_INFO_COMMAND")) { - ret = -ENODEV; - goto out_unlock_client_semaphore; - } - - down_read(&gxp->vd_semaphore); - - phys_core = gxp_vd_virt_core_to_phys_core(client->vd, ibuf.virtual_core_id); - if (phys_core < 0) { - dev_err(gxp->dev, "Get trace info failed: Invalid virtual core id (%u)\n", - ibuf.virtual_core_id); - ret = -EINVAL; - goto out; - } - - trace_header = kzalloc(GXP_TRACE_HEADER_SIZE, GFP_KERNEL); - if (!trace_header) { - ret = -ENOMEM; - goto out; - } - - trace_data = kzalloc(GXP_TRACE_RAM_SIZE, GFP_KERNEL); - if (!trace_data) { - ret = -ENOMEM; - goto out_free_header; - } - - /* - * TODO (b/185260919): Get trace information from system FW once - * communication channel between kernel and system FW is ready - * (b/185819530). - */ - - if (copy_to_user((void __user *)ibuf.trace_header_addr, trace_header, - GXP_TRACE_HEADER_SIZE)) { - ret = -EFAULT; - goto out_free_data; - } - - if (ibuf.type == 1) { - if (copy_to_user((void __user *)ibuf.trace_data_addr, - trace_data, GXP_TRACE_RAM_SIZE)) { - ret = -EFAULT; - goto out_free_data; - } - } - -out_free_data: - kfree(trace_data); -out_free_header: - kfree(trace_header); - -out: - up_read(&gxp->vd_semaphore); -out_unlock_client_semaphore: - up_read(&client->semaphore); - - return ret; -} - -static int gxp_enable_telemetry(struct gxp_client *client, - __u8 __user *argp) -{ - struct gxp_dev *gxp = client->gxp; - __u8 type; - int ret; - - if (copy_from_user(&type, argp, sizeof(type))) - return -EFAULT; - - if (type != GXP_TELEMETRY_TYPE_LOGGING && - type != GXP_TELEMETRY_TYPE_TRACING) - return -EINVAL; - - ret = gxp_telemetry_enable(gxp, type); - - /* - * Record what telemetry types this client enabled so they can be - * cleaned-up if the client closes without disabling them. - */ - if (!ret && type == GXP_TELEMETRY_TYPE_LOGGING) - client->enabled_telemetry_logging = true; - if (!ret && type == GXP_TELEMETRY_TYPE_TRACING) - client->enabled_telemetry_tracing = true; - - return ret; -} - -static int gxp_disable_telemetry(struct gxp_client *client, __u8 __user *argp) -{ - struct gxp_dev *gxp = client->gxp; - __u8 type; - int ret; - - if (copy_from_user(&type, argp, sizeof(type))) - return -EFAULT; - - if (type != GXP_TELEMETRY_TYPE_LOGGING && - type != GXP_TELEMETRY_TYPE_TRACING) - return -EINVAL; - - ret = gxp_telemetry_disable(gxp, type); - - if (!ret && type == GXP_TELEMETRY_TYPE_LOGGING) - client->enabled_telemetry_logging = false; - if (!ret && type == GXP_TELEMETRY_TYPE_TRACING) - client->enabled_telemetry_tracing = false; - - return ret; -} - -static int gxp_map_tpu_mbx_queue(struct gxp_client *client, - struct gxp_tpu_mbx_queue_ioctl __user *argp) -{ -#if (IS_ENABLED(CONFIG_GXP_TEST) || IS_ENABLED(CONFIG_ANDROID)) && !IS_ENABLED(CONFIG_GXP_GEM5) - struct gxp_dev *gxp = client->gxp; - struct edgetpu_ext_mailbox_info *mbx_info; - struct gxp_tpu_mbx_queue_ioctl ibuf; - struct edgetpu_ext_client_info gxp_tpu_info; - u32 phys_core_list = 0; - u32 virtual_core_list; - u32 core_count; - int ret = 0; - - if (!gxp->tpu_dev.mbx_paddr) { - dev_err(gxp->dev, "%s: TPU is not available for interop\n", - __func__); - return -EINVAL; - } - - if (copy_from_user(&ibuf, argp, sizeof(ibuf))) - return -EFAULT; - - down_write(&client->semaphore); - - if (!check_client_has_available_vd(client, "GXP_MAP_TPU_MBX_QUEUE")) { - ret = -ENODEV; - goto out_unlock_client_semaphore; - } - down_read(&gxp->vd_semaphore); +#include "gxp-common-platform.c" - virtual_core_list = ibuf.virtual_core_list; - core_count = hweight_long(virtual_core_list); - phys_core_list = gxp_vd_virt_core_list_to_phys_core_list( - client->vd, virtual_core_list); - if (!phys_core_list) { - dev_err(gxp->dev, "%s: invalid virtual core list 0x%x\n", - __func__, virtual_core_list); - ret = -EINVAL; - goto out; - } - - mbx_info = - kmalloc(sizeof(struct edgetpu_ext_mailbox_info) + core_count * - sizeof(struct edgetpu_ext_mailbox_descriptor), - GFP_KERNEL); - if (!mbx_info) { - ret = -ENOMEM; - goto out; - } - - if (client->tpu_file) { - dev_err(gxp->dev, "Mappings already exist for TPU mailboxes"); - ret = -EBUSY; - goto out_free; - } - - gxp_tpu_info.tpu_fd = ibuf.tpu_fd; - gxp_tpu_info.mbox_map = phys_core_list; - gxp_tpu_info.attr = (struct edgetpu_mailbox_attr __user *)ibuf.attr_ptr; - ret = edgetpu_ext_driver_cmd(gxp->tpu_dev.dev, - EDGETPU_EXTERNAL_CLIENT_TYPE_DSP, - ALLOCATE_EXTERNAL_MAILBOX, &gxp_tpu_info, - mbx_info); - if (ret) { - dev_err(gxp->dev, "Failed to allocate ext TPU mailboxes %d", - ret); - goto out_free; - } - /* - * If someone is attacking us through this interface - - * it's possible that ibuf.tpu_fd here is already a different file from - * the one passed to edgetpu_ext_driver_cmd() (if the runtime closes the - * FD and opens another file exactly between the TPU driver call above - * and the fget below). - * But the worst consequence of this attack is we fget() ourselves (GXP - * FD), which only leads to memory leak (because the file object has a - * reference to itself). The race is also hard to hit so we don't insist - * on preventing it. - */ - client->tpu_file = fget(ibuf.tpu_fd); - if (!client->tpu_file) { - edgetpu_ext_driver_cmd(gxp->tpu_dev.dev, - EDGETPU_EXTERNAL_CLIENT_TYPE_DSP, - FREE_EXTERNAL_MAILBOX, &gxp_tpu_info, - NULL); - ret = -EINVAL; - goto out_free; - } - /* Align queue size to page size for iommu map. */ - mbx_info->cmdq_size = ALIGN(mbx_info->cmdq_size, PAGE_SIZE); - mbx_info->respq_size = ALIGN(mbx_info->respq_size, PAGE_SIZE); - - ret = gxp_dma_map_tpu_buffer(gxp, client->vd, virtual_core_list, - phys_core_list, mbx_info); - if (ret) { - dev_err(gxp->dev, "Failed to map TPU mailbox buffer %d", ret); - fput(client->tpu_file); - client->tpu_file = NULL; - edgetpu_ext_driver_cmd(gxp->tpu_dev.dev, - EDGETPU_EXTERNAL_CLIENT_TYPE_DSP, - FREE_EXTERNAL_MAILBOX, &gxp_tpu_info, - NULL); - goto out_free; - } - client->mbx_desc.phys_core_list = phys_core_list; - client->mbx_desc.virt_core_list = virtual_core_list; - client->mbx_desc.cmdq_size = mbx_info->cmdq_size; - client->mbx_desc.respq_size = mbx_info->respq_size; - -out_free: - kfree(mbx_info); - -out: - up_read(&gxp->vd_semaphore); -out_unlock_client_semaphore: - up_write(&client->semaphore); - - return ret; -#else - return -ENODEV; -#endif -} - -static int gxp_unmap_tpu_mbx_queue(struct gxp_client *client, - struct gxp_tpu_mbx_queue_ioctl __user *argp) -{ -#if (IS_ENABLED(CONFIG_GXP_TEST) || IS_ENABLED(CONFIG_ANDROID)) && !IS_ENABLED(CONFIG_GXP_GEM5) - struct gxp_dev *gxp = client->gxp; - struct gxp_tpu_mbx_queue_ioctl ibuf; - struct edgetpu_ext_client_info gxp_tpu_info; - int ret = 0; - - if (copy_from_user(&ibuf, argp, sizeof(ibuf))) - return -EFAULT; - - down_write(&client->semaphore); - - if (!client->vd) { - dev_err(gxp->dev, - "GXP_UNMAP_TPU_MBX_QUEUE requires the client allocate a VIRTUAL_DEVICE\n"); - ret = -ENODEV; - goto out; - } - - if (!client->tpu_file) { - dev_err(gxp->dev, "No mappings exist for TPU mailboxes"); - ret = -EINVAL; - goto out; - } - - gxp_dma_unmap_tpu_buffer(gxp, client->vd, client->mbx_desc); - - gxp_tpu_info.tpu_fd = ibuf.tpu_fd; - edgetpu_ext_driver_cmd(gxp->tpu_dev.dev, - EDGETPU_EXTERNAL_CLIENT_TYPE_DSP, - FREE_EXTERNAL_MAILBOX, &gxp_tpu_info, NULL); - fput(client->tpu_file); - client->tpu_file = NULL; - -out: - up_write(&client->semaphore); - - return ret; -#else - return -ENODEV; -#endif -} - -static int gxp_register_telemetry_eventfd( - struct gxp_client *client, - struct gxp_register_telemetry_eventfd_ioctl __user *argp) -{ - struct gxp_dev *gxp = client->gxp; - struct gxp_register_telemetry_eventfd_ioctl ibuf; - - if (copy_from_user(&ibuf, argp, sizeof(ibuf))) - return -EFAULT; - - return gxp_telemetry_register_eventfd(gxp, ibuf.type, ibuf.eventfd); -} - -static int gxp_unregister_telemetry_eventfd( - struct gxp_client *client, - struct gxp_register_telemetry_eventfd_ioctl __user *argp) -{ - struct gxp_dev *gxp = client->gxp; - struct gxp_register_telemetry_eventfd_ioctl ibuf; - - if (copy_from_user(&ibuf, argp, sizeof(ibuf))) - return -EFAULT; - - return gxp_telemetry_unregister_eventfd(gxp, ibuf.type); -} - -static int gxp_read_global_counter(struct gxp_client *client, - __u64 __user *argp) +void gxp_iommu_setup_shareability(struct gxp_dev *gxp) { - struct gxp_dev *gxp = client->gxp; - u32 high_first, high_second, low; - u64 counter_val; - int ret = 0; - - /* Caller must hold BLOCK wakelock */ - down_read(&client->semaphore); - - if (!client->has_block_wakelock) { - dev_err(gxp->dev, - "GXP_READ_GLOBAL_COUNTER requires the client hold a BLOCK wakelock\n"); - ret = -ENODEV; - goto out; - } - - high_first = gxp_read_32(gxp, GXP_REG_GLOBAL_COUNTER_HIGH); - low = gxp_read_32(gxp, GXP_REG_GLOBAL_COUNTER_LOW); - - /* - * Check if the lower 32 bits could have wrapped in-between reading - * the high and low bit registers by validating the higher 32 bits - * haven't changed. - */ - high_second = gxp_read_32(gxp, GXP_REG_GLOBAL_COUNTER_HIGH); - if (high_first != high_second) - low = gxp_read_32(gxp, GXP_REG_GLOBAL_COUNTER_LOW); - - counter_val = ((u64)high_second << 32) | low; - - if (copy_to_user(argp, &counter_val, sizeof(counter_val))) - ret = -EFAULT; - -out: - up_read(&client->semaphore); - - return ret; + /* IO coherency not supported */ } -static int gxp_acquire_wake_lock_compat( - struct gxp_client *client, - struct gxp_acquire_wakelock_compat_ioctl __user *argp) -{ - struct gxp_dev *gxp = client->gxp; - struct gxp_acquire_wakelock_compat_ioctl ibuf; - bool acquired_block_wakelock = false; - int ret = 0; - - if (copy_from_user(&ibuf, argp, sizeof(ibuf))) - return -EFAULT; - - if (ibuf.gxp_power_state == GXP_POWER_STATE_OFF) { - dev_err(gxp->dev, - "GXP_POWER_STATE_OFF is not a valid value when acquiring a wakelock\n"); - return -EINVAL; - } - if (ibuf.gxp_power_state < GXP_POWER_STATE_OFF || - ibuf.gxp_power_state >= GXP_NUM_POWER_STATES) { - dev_err(gxp->dev, "Requested power state is invalid\n"); - return -EINVAL; - } - if ((ibuf.memory_power_state < MEMORY_POWER_STATE_MIN || - ibuf.memory_power_state > MEMORY_POWER_STATE_MAX) && - ibuf.memory_power_state != MEMORY_POWER_STATE_UNDEFINED) { - dev_err(gxp->dev, - "Requested memory power state %d is invalid\n", - ibuf.memory_power_state); - return -EINVAL; - } - - if (ibuf.gxp_power_state == GXP_POWER_STATE_READY) { - dev_warn_once( - gxp->dev, - "GXP_POWER_STATE_READY is deprecated, please set GXP_POWER_LOW_FREQ_CLKMUX with GXP_POWER_STATE_UUD state"); - ibuf.gxp_power_state = GXP_POWER_STATE_UUD; - } - - down_write(&client->semaphore); - if ((ibuf.components_to_wake & WAKELOCK_VIRTUAL_DEVICE) && - (!client->vd)) { - dev_err(gxp->dev, - "Must allocate a virtual device to acquire VIRTUAL_DEVICE wakelock\n"); - ret = -EINVAL; - goto out; - } - - /* Acquire a BLOCK wakelock if requested */ - if (ibuf.components_to_wake & WAKELOCK_BLOCK) { - if (!client->has_block_wakelock) { - ret = gxp_wakelock_acquire(gxp); - acquired_block_wakelock = true; - } - - if (ret) { - dev_err(gxp->dev, - "Failed to acquire BLOCK wakelock for client (ret=%d)\n", - ret); - goto out; - } - - client->has_block_wakelock = true; - - /* - * Update client's TGID/PID in case the process that opened - * /dev/gxp is not the one that called this IOCTL. - */ - client->tgid = current->tgid; - client->pid = current->pid; - } - - /* Acquire a VIRTUAL_DEVICE wakelock if requested */ - if (ibuf.components_to_wake & WAKELOCK_VIRTUAL_DEVICE) { - if (!client->has_block_wakelock) { - dev_err(gxp->dev, - "Must hold BLOCK wakelock to acquire VIRTUAL_DEVICE wakelock\n"); - ret = -EINVAL; - goto out; - - } - - if (client->vd->state == GXP_VD_UNAVAILABLE) { - dev_err(gxp->dev, - "Cannot acquire VIRTUAL_DEVICE wakelock on a broken virtual device\n"); - ret = -ENODEV; - goto out; - } - - if (!client->has_vd_wakelock) { - down_write(&gxp->vd_semaphore); - if (client->vd->state == GXP_VD_OFF) - ret = gxp_vd_start(client->vd); - else - ret = gxp_vd_resume(client->vd); - up_write(&gxp->vd_semaphore); - } - - if (ret) { - dev_err(gxp->dev, - "Failed to acquire VIRTUAL_DEVICE wakelock for client (ret=%d)\n", - ret); - goto err_acquiring_vd_wl; - } - - client->has_vd_wakelock = true; - } - - gxp_pm_update_requested_power_states( - gxp, client->requested_power_state, client->requested_low_clkmux, - aur_state_array[ibuf.gxp_power_state], false, - client->requested_memory_power_state, - aur_memory_state_array[ibuf.memory_power_state]); - client->requested_power_state = aur_state_array[ibuf.gxp_power_state]; - client->requested_low_clkmux = false; - client->requested_memory_power_state = - aur_memory_state_array[ibuf.memory_power_state]; -out: - up_write(&client->semaphore); - - return ret; - -err_acquiring_vd_wl: - /* - * In a single call, if any wakelock acquisition fails, all of them do. - * If the client was acquiring both wakelocks and failed to acquire the - * VIRTUAL_DEVICE wakelock after successfully acquiring the BLOCK - * wakelock, then release it before returning the error code. - */ - if (acquired_block_wakelock) { - gxp_wakelock_release(gxp); - client->has_block_wakelock = false; - } - - up_write(&client->semaphore); - - return ret; -} - -static int gxp_acquire_wake_lock(struct gxp_client *client, - struct gxp_acquire_wakelock_ioctl __user *argp) -{ - struct gxp_dev *gxp = client->gxp; - struct gxp_acquire_wakelock_ioctl ibuf; - bool acquired_block_wakelock = false; - bool requested_low_clkmux = false; - int ret = 0; - - if (copy_from_user(&ibuf, argp, sizeof(ibuf))) - return -EFAULT; - - if (ibuf.gxp_power_state == GXP_POWER_STATE_OFF) { - dev_err(gxp->dev, - "GXP_POWER_STATE_OFF is not a valid value when acquiring a wakelock\n"); - return -EINVAL; - } - if (ibuf.gxp_power_state < GXP_POWER_STATE_OFF || - ibuf.gxp_power_state >= GXP_NUM_POWER_STATES) { - dev_err(gxp->dev, "Requested power state is invalid\n"); - return -EINVAL; - } - if ((ibuf.memory_power_state < MEMORY_POWER_STATE_MIN || - ibuf.memory_power_state > MEMORY_POWER_STATE_MAX) && - ibuf.memory_power_state != MEMORY_POWER_STATE_UNDEFINED) { - dev_err(gxp->dev, - "Requested memory power state %d is invalid\n", - ibuf.memory_power_state); - return -EINVAL; - } - - if (ibuf.gxp_power_state == GXP_POWER_STATE_READY) { - dev_warn_once( - gxp->dev, - "GXP_POWER_STATE_READY is deprecated, please set GXP_POWER_LOW_FREQ_CLKMUX with GXP_POWER_STATE_UUD state"); - ibuf.gxp_power_state = GXP_POWER_STATE_UUD; - } - - if(ibuf.flags & GXP_POWER_NON_AGGRESSOR) - dev_warn_once( - gxp->dev, - "GXP_POWER_NON_AGGRESSOR is deprecated, no operation here"); - - down_write(&client->semaphore); - if ((ibuf.components_to_wake & WAKELOCK_VIRTUAL_DEVICE) && - (!client->vd)) { - dev_err(gxp->dev, - "Must allocate a virtual device to acquire VIRTUAL_DEVICE wakelock\n"); - ret = -EINVAL; - goto out; - } - - /* Acquire a BLOCK wakelock if requested */ - if (ibuf.components_to_wake & WAKELOCK_BLOCK) { - if (!client->has_block_wakelock) { - ret = gxp_wakelock_acquire(gxp); - acquired_block_wakelock = true; - } - - if (ret) { - dev_err(gxp->dev, - "Failed to acquire BLOCK wakelock for client (ret=%d)\n", - ret); - goto out; - } - - client->has_block_wakelock = true; - } - - /* Acquire a VIRTUAL_DEVICE wakelock if requested */ - if (ibuf.components_to_wake & WAKELOCK_VIRTUAL_DEVICE) { - if (!client->has_block_wakelock) { - dev_err(gxp->dev, - "Must hold BLOCK wakelock to acquire VIRTUAL_DEVICE wakelock\n"); - ret = -EINVAL; - goto out; - - } - - if (client->vd->state == GXP_VD_UNAVAILABLE) { - dev_err(gxp->dev, - "Cannot acquire VIRTUAL_DEVICE wakelock on a broken virtual device\n"); - ret = -ENODEV; - goto err_acquiring_vd_wl; - } - - if (!client->has_vd_wakelock) { - down_write(&gxp->vd_semaphore); - if (client->vd->state == GXP_VD_OFF) - ret = gxp_vd_start(client->vd); - else - ret = gxp_vd_resume(client->vd); - up_write(&gxp->vd_semaphore); - } - - if (ret) { - dev_err(gxp->dev, - "Failed to acquire VIRTUAL_DEVICE wakelock for client (ret=%d)\n", - ret); - goto err_acquiring_vd_wl; - } - - client->has_vd_wakelock = true; - } - requested_low_clkmux = (ibuf.flags & GXP_POWER_LOW_FREQ_CLKMUX) != 0; - - gxp_pm_update_requested_power_states( - gxp, client->requested_power_state, client->requested_low_clkmux, - aur_state_array[ibuf.gxp_power_state], requested_low_clkmux, - client->requested_memory_power_state, - aur_memory_state_array[ibuf.memory_power_state]); - client->requested_power_state = aur_state_array[ibuf.gxp_power_state]; - client->requested_low_clkmux = requested_low_clkmux; - client->requested_memory_power_state = - aur_memory_state_array[ibuf.memory_power_state]; -out: - up_write(&client->semaphore); - - return ret; - -err_acquiring_vd_wl: - /* - * In a single call, if any wakelock acquisition fails, all of them do. - * If the client was acquiring both wakelocks and failed to acquire the - * VIRTUAL_DEVICE wakelock after successfully acquiring the BLOCK - * wakelock, then release it before returning the error code. - */ - if (acquired_block_wakelock) { - gxp_wakelock_release(gxp); - client->has_block_wakelock = false; - } - - up_write(&client->semaphore); - - return ret; -} - -static int gxp_release_wake_lock(struct gxp_client *client, __u32 __user *argp) -{ - struct gxp_dev *gxp = client->gxp; - u32 wakelock_components; - int ret = 0; - - if (copy_from_user(&wakelock_components, argp, - sizeof(wakelock_components))) - return -EFAULT; - - down_write(&client->semaphore); - - if (wakelock_components & WAKELOCK_VIRTUAL_DEVICE) { - if (!client->has_vd_wakelock) { - dev_err(gxp->dev, - "Client must hold a VIRTUAL_DEVICE wakelock to release one\n"); - ret = -ENODEV; - goto out; - } - - /* - * Currently VD state will not be GXP_VD_UNAVAILABLE if - * has_vd_wakelock is true. Add this check just in case - * GXP_VD_UNAVAILABLE will occur in more scenarios in the - * future. - */ - if (client->vd->state != GXP_VD_UNAVAILABLE) { - down_write(&gxp->vd_semaphore); - gxp_vd_suspend(client->vd); - up_write(&gxp->vd_semaphore); - } - - client->has_vd_wakelock = false; - } - - if (wakelock_components & WAKELOCK_BLOCK) { - if (client->has_vd_wakelock) { - dev_err(gxp->dev, - "Client cannot release BLOCK wakelock while holding a VD wakelock\n"); - ret = -EBUSY; - goto out; - } - - if (!client->has_block_wakelock) { - dev_err(gxp->dev, - "Client must hold a BLOCK wakelock to release one\n"); - ret = -ENODEV; - goto out; - } - - gxp_wakelock_release(gxp); - /* - * Other clients may still be using the BLK_AUR, check if we need - * to change the power state. - */ - gxp_pm_update_requested_power_states( - gxp, client->requested_power_state, - client->requested_low_clkmux, AUR_OFF, false, - client->requested_memory_power_state, - AUR_MEM_UNDEFINED); - client->requested_power_state = AUR_OFF; - client->requested_memory_power_state = AUR_MEM_UNDEFINED; - client->requested_low_clkmux = false; - client->has_block_wakelock = false; - } - -out: - up_write(&client->semaphore); - - return ret; -} - -static int gxp_map_dmabuf(struct gxp_client *client, - struct gxp_map_dmabuf_ioctl __user *argp) -{ - struct gxp_dev *gxp = client->gxp; - struct gxp_map_dmabuf_ioctl ibuf; - struct gxp_mapping *mapping; - int ret = 0; - - if (copy_from_user(&ibuf, argp, sizeof(ibuf))) - return -EFAULT; - - if (ibuf.virtual_core_list == 0) - return -EINVAL; - - down_read(&client->semaphore); - - if (!check_client_has_available_vd(client, "GXP_MAP_DMABUF")) { - ret = -ENODEV; - goto out_unlock; - } - - mapping = gxp_dmabuf_map(gxp, client->vd, ibuf.virtual_core_list, - ibuf.dmabuf_fd, - /*gxp_dma_flags=*/0, - mapping_flags_to_dma_dir(ibuf.flags)); - if (IS_ERR(mapping)) { - ret = PTR_ERR(mapping); - dev_err(gxp->dev, "Failed to map dma-buf (ret=%d)\n", ret); - goto out_unlock; - } - - ret = gxp_vd_mapping_store(client->vd, mapping); - if (ret) { - dev_err(gxp->dev, - "Failed to store mapping for dma-buf (ret=%d)\n", ret); - goto out_put; - } - - ibuf.device_address = mapping->device_address; - - if (copy_to_user(argp, &ibuf, sizeof(ibuf))) { - /* If the IOCTL fails, the dma-buf must be unmapped */ - gxp_vd_mapping_remove(client->vd, mapping); - ret = -EFAULT; - } - -out_put: - /* - * Release the reference from creating the dmabuf mapping - * If the mapping was not successfully stored in the owning virtual - * device, this will unmap and cleanup the dmabuf. - */ - gxp_mapping_put(mapping); - -out_unlock: - up_read(&client->semaphore); - - return ret; -} - -static int gxp_unmap_dmabuf(struct gxp_client *client, - struct gxp_map_dmabuf_ioctl __user *argp) -{ - struct gxp_dev *gxp = client->gxp; - struct gxp_map_dmabuf_ioctl ibuf; - struct gxp_mapping *mapping; - int ret = 0; - - if (copy_from_user(&ibuf, argp, sizeof(ibuf))) - return -EFAULT; - - down_read(&client->semaphore); - - if (!client->vd) { - dev_err(gxp->dev, - "GXP_UNMAP_DMABUF requires the client allocate a VIRTUAL_DEVICE\n"); - ret = -ENODEV; - goto out; - } - - /* - * Fetch and remove the internal mapping records. - * If host_address is not 0, the provided device_address belongs to a - * non-dma-buf mapping. - */ - mapping = gxp_vd_mapping_search(client->vd, ibuf.device_address); - if (IS_ERR_OR_NULL(mapping) || mapping->host_address) { - dev_warn(gxp->dev, "No dma-buf mapped for given IOVA\n"); - /* - * If the device address belongs to a non-dma-buf mapping, - * release the reference to it obtained via the search. - */ - if (!IS_ERR_OR_NULL(mapping)) - gxp_mapping_put(mapping); - ret = -EINVAL; - goto out; - } - - /* Remove the mapping from its VD, releasing the VD's reference */ - gxp_vd_mapping_remove(client->vd, mapping); - - /* Release the reference from gxp_vd_mapping_search() */ - gxp_mapping_put(mapping); - -out: - up_read(&client->semaphore); - - return ret; -} - -static int gxp_register_mailbox_eventfd( - struct gxp_client *client, - struct gxp_register_mailbox_eventfd_ioctl __user *argp) -{ - struct gxp_register_mailbox_eventfd_ioctl ibuf; - struct gxp_eventfd *eventfd; - int ret = 0; - - if (copy_from_user(&ibuf, argp, sizeof(ibuf))) - return -EFAULT; - - down_write(&client->semaphore); - - if (!check_client_has_available_vd(client, "GXP_REGISTER_MAILBOX_EVENTFD")) { - ret = -ENODEV; - goto out; - } - - if (ibuf.virtual_core_id >= client->vd->num_cores) { - ret = -EINVAL; - goto out; - } - - /* Make sure the provided eventfd is valid */ - eventfd = gxp_eventfd_create(ibuf.eventfd); - if (IS_ERR(eventfd)) { - ret = PTR_ERR(eventfd); - goto out; - } - - /* Set the new eventfd, replacing any existing one */ - if (client->mb_eventfds[ibuf.virtual_core_id]) - gxp_eventfd_put(client->mb_eventfds[ibuf.virtual_core_id]); - - client->mb_eventfds[ibuf.virtual_core_id] = eventfd; - -out: - up_write(&client->semaphore); - - return ret; -} - -static int gxp_unregister_mailbox_eventfd( - struct gxp_client *client, - struct gxp_register_mailbox_eventfd_ioctl __user *argp) -{ - struct gxp_register_mailbox_eventfd_ioctl ibuf; - int ret = 0; - - if (copy_from_user(&ibuf, argp, sizeof(ibuf))) - return -EFAULT; - - down_write(&client->semaphore); - - if (!client->vd) { - dev_err(client->gxp->dev, - "GXP_UNREGISTER_MAILBOX_EVENTFD requires the client allocate a VIRTUAL_DEVICE\n"); - ret = -ENODEV; - goto out; - } - - if (ibuf.virtual_core_id >= client->vd->num_cores) { - ret = -EINVAL; - goto out; - } - - if (client->mb_eventfds[ibuf.virtual_core_id]) - gxp_eventfd_put(client->mb_eventfds[ibuf.virtual_core_id]); - - client->mb_eventfds[ibuf.virtual_core_id] = NULL; - -out: - up_write(&client->semaphore); - - return ret; -} - -static int -gxp_get_interface_version(struct gxp_client *client, - struct gxp_interface_version_ioctl __user *argp) -{ - struct gxp_interface_version_ioctl ibuf; - int ret; - - ibuf.version_major = GXP_INTERFACE_VERSION_MAJOR; - ibuf.version_minor = GXP_INTERFACE_VERSION_MINOR; - memset(ibuf.version_build, 0, GXP_INTERFACE_VERSION_BUILD_BUFFER_SIZE); - ret = snprintf(ibuf.version_build, - GXP_INTERFACE_VERSION_BUILD_BUFFER_SIZE - 1, - GIT_REPO_TAG); - - if (ret < 0 || ret >= GXP_INTERFACE_VERSION_BUILD_BUFFER_SIZE) { - dev_warn( - client->gxp->dev, - "Buffer size insufficient to hold GIT_REPO_TAG (size=%d)\n", - ret); - } - - if (copy_to_user(argp, &ibuf, sizeof(ibuf))) - return -EFAULT; - - return 0; -} - -static int gxp_trigger_debug_dump(struct gxp_client *client, - __u32 __user *argp) -{ - struct gxp_dev *gxp = client->gxp; - int phys_core, i; - u32 core_bits; - int ret = 0; - - if (!uid_eq(current_euid(), GLOBAL_ROOT_UID)) - return -EPERM; - - if (!gxp_debug_dump_is_enabled()) { - dev_err(gxp->dev, "Debug dump functionality is disabled\n"); - return -EINVAL; - } - - if (copy_from_user(&core_bits, argp, sizeof(core_bits))) - return -EFAULT; - - /* Caller must hold VIRTUAL_DEVICE wakelock */ - down_read(&client->semaphore); - - if (!check_client_has_available_vd_wakelock(client, - "GXP_TRIGGER_DEBUG_DUMP")) { - ret = -ENODEV; - goto out_unlock_client_semaphore; - } - - down_read(&gxp->vd_semaphore); - - for (i = 0; i < GXP_NUM_CORES; i++) { - if (!(core_bits & BIT(i))) - continue; - phys_core = gxp_vd_virt_core_to_phys_core(client->vd, i); - if (phys_core < 0) { - dev_err(gxp->dev, - "Trigger debug dump failed: Invalid virtual core id (%u)\n", - i); - ret = -EINVAL; - continue; - } - - if (gxp_is_fw_running(gxp, phys_core)) { - gxp_notification_send(gxp, phys_core, - CORE_NOTIF_GENERATE_DEBUG_DUMP); - } - } - - up_read(&gxp->vd_semaphore); -out_unlock_client_semaphore: - up_read(&client->semaphore); - - return ret; -} - -static long gxp_ioctl(struct file *file, uint cmd, ulong arg) -{ - struct gxp_client *client = file->private_data; - void __user *argp = (void __user *)arg; - long ret; - - switch (cmd) { - case GXP_MAP_BUFFER: - ret = gxp_map_buffer(client, argp); - break; - case GXP_UNMAP_BUFFER: - ret = gxp_unmap_buffer(client, argp); - break; - case GXP_SYNC_BUFFER: - ret = gxp_sync_buffer(client, argp); - break; - case GXP_MAILBOX_COMMAND_COMPAT: - ret = gxp_mailbox_command_compat(client, argp); - break; - case GXP_MAILBOX_RESPONSE: - ret = gxp_mailbox_response(client, argp); - break; - case GXP_GET_SPECS: - ret = gxp_get_specs(client, argp); - break; - case GXP_ALLOCATE_VIRTUAL_DEVICE: - ret = gxp_allocate_vd(client, argp); - break; - case GXP_ETM_TRACE_START_COMMAND: - ret = gxp_etm_trace_start_command(client, argp); - break; - case GXP_ETM_TRACE_SW_STOP_COMMAND: - ret = gxp_etm_trace_sw_stop_command(client, argp); - break; - case GXP_ETM_TRACE_CLEANUP_COMMAND: - ret = gxp_etm_trace_cleanup_command(client, argp); - break; - case GXP_ETM_GET_TRACE_INFO_COMMAND: - ret = gxp_etm_get_trace_info_command(client, argp); - break; - case GXP_ENABLE_TELEMETRY: - ret = gxp_enable_telemetry(client, argp); - break; - case GXP_DISABLE_TELEMETRY: - ret = gxp_disable_telemetry(client, argp); - break; - case GXP_MAP_TPU_MBX_QUEUE: - ret = gxp_map_tpu_mbx_queue(client, argp); - break; - case GXP_UNMAP_TPU_MBX_QUEUE: - ret = gxp_unmap_tpu_mbx_queue(client, argp); - break; - case GXP_REGISTER_TELEMETRY_EVENTFD: - ret = gxp_register_telemetry_eventfd(client, argp); - break; - case GXP_UNREGISTER_TELEMETRY_EVENTFD: - ret = gxp_unregister_telemetry_eventfd(client, argp); - break; - case GXP_READ_GLOBAL_COUNTER: - ret = gxp_read_global_counter(client, argp); - break; - case GXP_ACQUIRE_WAKE_LOCK_COMPAT: - ret = gxp_acquire_wake_lock_compat(client, argp); - break; - case GXP_RELEASE_WAKE_LOCK: - ret = gxp_release_wake_lock(client, argp); - break; - case GXP_MAP_DMABUF: - ret = gxp_map_dmabuf(client, argp); - break; - case GXP_UNMAP_DMABUF: - ret = gxp_unmap_dmabuf(client, argp); - break; - case GXP_MAILBOX_COMMAND: - ret = gxp_mailbox_command(client, argp); - break; - case GXP_REGISTER_MAILBOX_EVENTFD: - ret = gxp_register_mailbox_eventfd(client, argp); - break; - case GXP_UNREGISTER_MAILBOX_EVENTFD: - ret = gxp_unregister_mailbox_eventfd(client, argp); - break; - case GXP_ACQUIRE_WAKE_LOCK: - ret = gxp_acquire_wake_lock(client, argp); - break; - case GXP_GET_INTERFACE_VERSION: - ret = gxp_get_interface_version(client, argp); - break; - case GXP_TRIGGER_DEBUG_DUMP: - ret = gxp_trigger_debug_dump(client, argp); - break; - default: - ret = -ENOTTY; /* unknown command */ - } - - return ret; -} - -static int gxp_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct gxp_client *client = file->private_data; - - if (!client) - return -ENODEV; - - switch (vma->vm_pgoff << PAGE_SHIFT) { - case GXP_MMAP_LOG_BUFFER_OFFSET: - return gxp_telemetry_mmap_buffers(client->gxp, - GXP_TELEMETRY_TYPE_LOGGING, - vma); - case GXP_MMAP_TRACE_BUFFER_OFFSET: - return gxp_telemetry_mmap_buffers(client->gxp, - GXP_TELEMETRY_TYPE_TRACING, - vma); - default: - return -EINVAL; - } -} - -static const struct file_operations gxp_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .mmap = gxp_mmap, - .open = gxp_open, - .release = gxp_release, - .unlocked_ioctl = gxp_ioctl, -}; - static int gxp_platform_probe(struct platform_device *pdev) { - struct device *dev = &pdev->dev; - struct gxp_dev *gxp; - struct resource *r; - phys_addr_t offset, base_addr; - struct device_node *np; - struct platform_device *tpu_pdev; - struct platform_device *gsa_pdev; - int ret; - int __maybe_unused i; - bool __maybe_unused tpu_found; - u64 prop; - - dev_notice(dev, "Probing gxp driver with commit %s\n", GIT_REPO_TAG); + struct gxp_dev *gxp = + devm_kzalloc(&pdev->dev, sizeof(*gxp), GFP_KERNEL); - gxp = devm_kzalloc(dev, sizeof(*gxp), GFP_KERNEL); if (!gxp) return -ENOMEM; - platform_set_drvdata(pdev, gxp); - gxp->dev = dev; - - gxp->misc_dev.minor = MISC_DYNAMIC_MINOR; - gxp->misc_dev.name = "gxp"; - gxp->misc_dev.fops = &gxp_fops; - - gxp_wakelock_init(gxp); - - ret = misc_register(&gxp->misc_dev); - if (ret) { - dev_err(dev, "Failed to register misc device (ret = %d)\n", - ret); - devm_kfree(dev, (void *)gxp); - return ret; - } - - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (IS_ERR_OR_NULL(r)) { - dev_err(dev, "Failed to get memory resource\n"); - ret = -ENODEV; - goto err; - } - - gxp->regs.paddr = r->start; - gxp->regs.size = resource_size(r); - gxp->regs.vaddr = devm_ioremap_resource(dev, r); - if (IS_ERR_OR_NULL(gxp->regs.vaddr)) { - dev_err(dev, "Failed to map registers\n"); - ret = -ENODEV; - goto err; - } - - r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cmu"); - if (!IS_ERR_OR_NULL(r)) { - gxp->cmu.paddr = r->start; - gxp->cmu.size = resource_size(r); - gxp->cmu.vaddr = devm_ioremap_resource(dev, r); - } - /* - * TODO (b/224685748): Remove this block after CMU CSR is supported - * in device tree config. - */ - if (IS_ERR_OR_NULL(r) || IS_ERR_OR_NULL(gxp->cmu.vaddr)) { - gxp->cmu.paddr = gxp->regs.paddr - GXP_CMU_OFFSET; - gxp->cmu.size = GXP_CMU_SIZE; - gxp->cmu.vaddr = devm_ioremap(dev, gxp->cmu.paddr, gxp->cmu.size); - if (IS_ERR_OR_NULL(gxp->cmu.vaddr)) - dev_warn(dev, "Failed to map CMU registers\n"); - } - - ret = gxp_pm_init(gxp); - if (ret) { - dev_err(dev, "Failed to init power management (ret=%d)\n", ret); - goto err; - } - - for (i = 0; i < GXP_NUM_CORES; i++) { - r = platform_get_resource(pdev, IORESOURCE_MEM, i + 1); - if (IS_ERR_OR_NULL(r)) { - dev_err(dev, "Failed to get mailbox%d resource\n", i); - ret = -ENODEV; - goto err_pm_destroy; - } - - gxp->mbx[i].paddr = r->start; - gxp->mbx[i].size = resource_size(r); - gxp->mbx[i].vaddr = devm_ioremap_resource(dev, r); - if (IS_ERR_OR_NULL(gxp->mbx[i].vaddr)) { - dev_err(dev, "Failed to map mailbox%d registers\n", i); - ret = -ENODEV; - goto err_pm_destroy; - } - } - - tpu_found = true; - /* Get TPU device from device tree */ - np = of_parse_phandle(dev->of_node, "tpu-device", 0); - if (IS_ERR_OR_NULL(np)) { - dev_warn(dev, "No tpu-device in device tree\n"); - tpu_found = false; - } - tpu_pdev = of_find_device_by_node(np); - if (!tpu_pdev) { - dev_err(dev, "TPU device not found\n"); - tpu_found = false; - } - /* get tpu mailbox register base */ - ret = of_property_read_u64_index(np, "reg", 0, &base_addr); - of_node_put(np); - if (ret) { - dev_warn(dev, "Unable to get tpu-device base address\n"); - tpu_found = false; - } - /* get gxp-tpu mailbox register offset */ - ret = of_property_read_u64(dev->of_node, "gxp-tpu-mbx-offset", - &offset); - if (ret) { - dev_warn(dev, "Unable to get tpu-device mailbox offset\n"); - tpu_found = false; - } - if (tpu_found) { - gxp->tpu_dev.dev = &tpu_pdev->dev; - get_device(gxp->tpu_dev.dev); - gxp->tpu_dev.mbx_paddr = base_addr + offset; - } else { - dev_warn(dev, "TPU will not be available for interop\n"); - gxp->tpu_dev.mbx_paddr = 0; - } - - ret = gxp_dma_init(gxp); - if (ret) { - dev_err(dev, "Failed to initialize GXP DMA interface\n"); - goto err_put_tpu_dev; - } - - gxp->mailbox_mgr = gxp_mailbox_create_manager(gxp, GXP_NUM_CORES); - if (IS_ERR_OR_NULL(gxp->mailbox_mgr)) { - dev_err(dev, "Failed to create mailbox manager\n"); - ret = -ENOMEM; - goto err_dma_exit; - } - -#if IS_ENABLED(CONFIG_SUBSYSTEM_COREDUMP) - ret = gxp_debug_dump_init(gxp, &gxp_sscd_dev, &gxp_sscd_pdata); -#else - ret = gxp_debug_dump_init(gxp, NULL, NULL); -#endif // !CONFIG_SUBSYSTEM_COREDUMP - if (ret) { - dev_err(dev, "Failed to initialize debug dump\n"); - gxp_debug_dump_exit(gxp); - } - - mutex_init(&gxp->dsp_firmware_lock); - mutex_init(&gxp->pin_user_pages_lock); - - gxp->domain_pool = kmalloc(sizeof(*gxp->domain_pool), GFP_KERNEL); - if (!gxp->domain_pool) { - ret = -ENOMEM; - goto err_debug_dump_exit; - } - ret = gxp_domain_pool_init(gxp, gxp->domain_pool, - GXP_NUM_PREALLOCATED_DOMAINS); - if (ret) { - dev_err(dev, - "Failed to initialize IOMMU domain pool (ret=%d)\n", - ret); - goto err_free_domain_pool; - } - ret = gxp_vd_init(gxp); - if (ret) { - dev_err(dev, - "Failed to initialize virtual device manager (ret=%d)\n", - ret); - goto err_domain_pool_destroy; - } - gxp_dma_init_default_resources(gxp); - - /* Get GSA device from device tree */ - np = of_parse_phandle(dev->of_node, "gsa-device", 0); - if (!np) { - dev_warn( - dev, - "No gsa-device in device tree. Firmware authentication not available\n"); - } else { - gsa_pdev = of_find_device_by_node(np); - if (!gsa_pdev) { - dev_err(dev, "GSA device not found\n"); - of_node_put(np); - ret = -ENODEV; - goto err_vd_destroy; - } - gxp->gsa_dev = get_device(&gsa_pdev->dev); - of_node_put(np); - dev_info( - dev, - "GSA device found, Firmware authentication available\n"); - } - - ret = of_property_read_u64(dev->of_node, "gxp-memory-per-core", - &prop); - if (ret) { - dev_err(dev, "Unable to get memory-per-core from device tree\n"); - gxp->memory_per_core = 0; - } else { - gxp->memory_per_core = (u32)prop; - } - - gxp_fw_data_init(gxp); - gxp_telemetry_init(gxp); - gxp_create_debugfs(gxp); - gxp->thermal_mgr = gxp_thermal_init(gxp); - if (!gxp->thermal_mgr) - dev_err(dev, "Failed to init thermal driver\n"); - dev_dbg(dev, "Probe finished\n"); - - INIT_LIST_HEAD(&gxp->client_list); - mutex_init(&gxp->client_list_lock); - - gxp_debug_pointer = gxp; - - return 0; -err_vd_destroy: - gxp_vd_destroy(gxp); -err_domain_pool_destroy: - gxp_domain_pool_destroy(gxp->domain_pool); -err_free_domain_pool: - kfree(gxp->domain_pool); -err_debug_dump_exit: - gxp_debug_dump_exit(gxp); -err_dma_exit: - gxp_dma_exit(gxp); -err_put_tpu_dev: - put_device(gxp->tpu_dev.dev); -err_pm_destroy: - gxp_pm_destroy(gxp); -err: - misc_deregister(&gxp->misc_dev); - devm_kfree(dev, (void *)gxp); - return ret; + return gxp_common_platform_probe(pdev, gxp); } static int gxp_platform_remove(struct platform_device *pdev) { - struct device *dev = &pdev->dev; - struct gxp_dev *gxp = platform_get_drvdata(pdev); - - gxp_remove_debugfs(gxp); - gxp_fw_data_destroy(gxp); - if (gxp->gsa_dev) - put_device(gxp->gsa_dev); - gxp_vd_destroy(gxp); - gxp_domain_pool_destroy(gxp->domain_pool); - kfree(gxp->domain_pool); - gxp_debug_dump_exit(gxp); - gxp_dma_exit(gxp); - put_device(gxp->tpu_dev.dev); - gxp_pm_destroy(gxp); - misc_deregister(&gxp->misc_dev); - - devm_kfree(dev, (void *)gxp); - - gxp_debug_pointer = NULL; - - return 0; -} - -#if IS_ENABLED(CONFIG_PM_SLEEP) - -static int gxp_platform_suspend(struct device *dev) -{ - struct gxp_dev *gxp = dev_get_drvdata(dev); - - return gxp_wakelock_suspend(gxp); + return gxp_common_platform_remove(pdev); } -static int gxp_platform_resume(struct device *dev) -{ - struct gxp_dev *gxp = dev_get_drvdata(dev); - - return gxp_wakelock_resume(gxp); -} - -static const struct dev_pm_ops gxp_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(gxp_platform_suspend, gxp_platform_resume) -}; - -#endif /* IS_ENABLED(CONFIG_PM_SLEEP) */ - #ifdef CONFIG_OF static const struct of_device_id gxp_of_match[] = { { .compatible = "google,gxp", }, @@ -2317,21 +42,12 @@ static const struct of_device_id gxp_of_match[] = { MODULE_DEVICE_TABLE(of, gxp_of_match); #endif -#ifdef CONFIG_ACPI -static const struct acpi_device_id gxp_acpi_match[] = { - { "CXRP0001", 0 }, - { /* end of list */ }, -}; -MODULE_DEVICE_TABLE(acpi, gxp_acpi_match); -#endif - static struct platform_driver gxp_platform_driver = { .probe = gxp_platform_probe, .remove = gxp_platform_remove, .driver = { .name = GXP_DRIVER_NAME, .of_match_table = of_match_ptr(gxp_of_match), - .acpi_match_table = ACPI_PTR(gxp_acpi_match), #if IS_ENABLED(CONFIG_PM_SLEEP) .pm = &gxp_pm_ops, #endif @@ -2340,23 +56,24 @@ static struct platform_driver gxp_platform_driver = { static int __init gxp_platform_init(void) { -#if IS_ENABLED(CONFIG_SUBSYSTEM_COREDUMP) - /* Registers SSCD platform device */ - if (gxp_debug_dump_is_enabled()) { - if (platform_device_register(&gxp_sscd_dev)) - pr_err("Unable to register SSCD platform device\n"); - } -#endif + gxp_common_platform_reg_sscd(); return platform_driver_register(&gxp_platform_driver); } static void __exit gxp_platform_exit(void) { platform_driver_unregister(&gxp_platform_driver); -#if IS_ENABLED(CONFIG_SUBSYSTEM_COREDUMP) - if (gxp_debug_dump_is_enabled()) - platform_device_unregister(&gxp_sscd_dev); -#endif + gxp_common_platform_unreg_sscd(); +} + +bool gxp_is_direct_mode(struct gxp_dev *gxp) +{ + return true; +} + +enum gxp_chip_revision gxp_get_chip_revision(struct gxp_dev *gxp) +{ + return GXP_CHIP_ANY; } MODULE_DESCRIPTION("Google GXP platform driver"); |