diff options
author | Erick Reyes <erickreyes@google.com> | 2020-11-06 22:48:15 +0000 |
---|---|---|
committer | Erick Reyes <erickreyes@google.com> | 2020-11-06 22:51:36 +0000 |
commit | 1e983deac73bb1a8751a3ac5a0af0412eb309ca7 (patch) | |
tree | dfcd27dc9ce397cc06ab6e5ed1d989be38a5b75d | |
parent | 087f6adaf5ef59d7345aab63bb7350f6b52bccf7 (diff) | |
download | abrolhos-1e983deac73bb1a8751a3ac5a0af0412eb309ca7.tar.gz |
Merge branch 'whitechapel' into android-gs-pixel-mainline
* whitechapel:
edgetpu: abrolhos: change power down failure handling
edgetpu: remove EDGETPU_CREATE_GROUP_COMPAT_2
edgetpu: abrolhos fetch firmware version numbers
Bug: 172356830
Bug: 172618334
Bug: 170328116
Signed-off-by: Erick Reyes <erickreyes@google.com>
Change-Id: Ie9b7ddec384b8e5f4007ea76418c363701f90c2c
-rw-r--r-- | drivers/edgetpu/Kbuild | 2 | ||||
-rw-r--r-- | drivers/edgetpu/Makefile | 2 | ||||
-rw-r--r-- | drivers/edgetpu/abrolhos-firmware.c | 6 | ||||
-rw-r--r-- | drivers/edgetpu/abrolhos-firmware.h | 18 | ||||
-rw-r--r-- | drivers/edgetpu/abrolhos-iommu.c | 2 | ||||
-rw-r--r-- | drivers/edgetpu/abrolhos-pm.c | 65 | ||||
-rw-r--r-- | drivers/edgetpu/abrolhos/config-tpu-cpu.h | 8 | ||||
-rw-r--r-- | drivers/edgetpu/edgetpu-direct.c | 6 | ||||
-rw-r--r-- | drivers/edgetpu/edgetpu-firmware.c | 6 | ||||
-rw-r--r-- | drivers/edgetpu/edgetpu-firmware.h | 4 | ||||
-rw-r--r-- | drivers/edgetpu/edgetpu-mmu.h | 5 | ||||
-rw-r--r-- | drivers/edgetpu/edgetpu-pm.c | 93 | ||||
-rw-r--r-- | drivers/edgetpu/edgetpu-pm.h | 18 | ||||
-rw-r--r-- | drivers/edgetpu/edgetpu.h | 3 |
14 files changed, 200 insertions, 38 deletions
diff --git a/drivers/edgetpu/Kbuild b/drivers/edgetpu/Kbuild index e3e355a..b364f41 100644 --- a/drivers/edgetpu/Kbuild +++ b/drivers/edgetpu/Kbuild @@ -11,7 +11,7 @@ else endif edgetpu-fw-objs := edgetpu-firmware.o edgetpu-firmware-util.o edgetpu-shared-fw.o -edgetpu-objs := edgetpu-mailbox.o edgetpu-kci.o edgetpu-telemetry.o edgetpu-mapping.o edgetpu-dmabuf.o edgetpu-async.o edgetpu-pm.o edgetpu-iremap-pool.o edgetpu-sw-watchdog.o $(edgetpu-fw-objs) +edgetpu-objs := edgetpu-mailbox.o edgetpu-kci.o edgetpu-telemetry.o edgetpu-mapping.o edgetpu-dmabuf.o edgetpu-async.o edgetpu-iremap-pool.o edgetpu-sw-watchdog.o $(edgetpu-fw-objs) abrolhos-y := abrolhos-device.o abrolhos-device-group.o abrolhos-direct.o abrolhos-core.o abrolhos-platform.o abrolhos-iommu.o abrolhos-firmware.o abrolhos-thermal.o abrolhos-pm.o $(edgetpu-objs) CFLAGS_abrolhos-direct.o := -DCONFIG_ABROLHOS=1 CFLAGS_abrolhos-core.o := -DCONFIG_ABROLHOS=1 diff --git a/drivers/edgetpu/Makefile b/drivers/edgetpu/Makefile index cb0c6db..f57050a 100644 --- a/drivers/edgetpu/Makefile +++ b/drivers/edgetpu/Makefile @@ -14,7 +14,7 @@ else endif edgetpu-fw-objs := edgetpu-firmware-util.o edgetpu-shared-fw.o edgetpu-firmware.o -edgetpu-objs := edgetpu-core.o edgetpu-mailbox.o edgetpu-kci.o edgetpu-device-group.o edgetpu-telemetry.o edgetpu-mapping.o edgetpu-dmabuf.o edgetpu-async.o edgetpu-pm.o edgetpu-iremap-pool.o edgetpu-sw-watchdog.o $(edgetpu-fw-objs) +edgetpu-objs := edgetpu-core.o edgetpu-mailbox.o edgetpu-kci.o edgetpu-device-group.o edgetpu-telemetry.o edgetpu-mapping.o edgetpu-dmabuf.o edgetpu-async.o edgetpu-iremap-pool.o edgetpu-sw-watchdog.o $(edgetpu-fw-objs) abrolhos-objs := abrolhos-device.o abrolhos-firmware.o edgetpu-direct.o abrolhos-platform.o abrolhos-iommu.o abrolhos-thermal.o abrolhos-pm.o $(edgetpu-objs) diff --git a/drivers/edgetpu/abrolhos-firmware.c b/drivers/edgetpu/abrolhos-firmware.c index c6f5e0b..649beb8 100644 --- a/drivers/edgetpu/abrolhos-firmware.c +++ b/drivers/edgetpu/abrolhos-firmware.c @@ -74,6 +74,7 @@ static int abrolhos_firmware_prepare_run(struct edgetpu_firmware *et_fw, struct edgetpu_platform_dev *edgetpu_pdev = container_of(etdev, struct edgetpu_platform_dev, edgetpu_dev); void *image_vaddr, *header_vaddr; + struct abrolhos_image_config *image_config; dma_addr_t header_dma_addr; int ret, tpu_state; @@ -138,6 +139,11 @@ static int abrolhos_firmware_prepare_run(struct edgetpu_firmware *et_fw, goto out_free_gsa; } + /* fetch the firmware versions */ + image_config = fw_buf->vaddr + ABROLHOS_IMAGE_CONFIG_OFFSET; + memcpy(&etdev->fw_version, &image_config->firmware_versions, + sizeof(etdev->fw_version)); + /* Reset KCI mailbox before starting f/w, don't process anything old.*/ edgetpu_mailbox_reset(etdev->kci->mailbox); diff --git a/drivers/edgetpu/abrolhos-firmware.h b/drivers/edgetpu/abrolhos-firmware.h index e0c5d1b..7deb36f 100644 --- a/drivers/edgetpu/abrolhos-firmware.h +++ b/drivers/edgetpu/abrolhos-firmware.h @@ -7,7 +7,23 @@ #ifndef __ABROLHOS_FIRMWARE_H__ #define __ABROLHOS_FIRMWARE_H__ -struct edgetpu_dev; +#include "edgetpu-internal.h" +#include "edgetpu.h" + +/* The offset to the signed firmware header. */ +#define ABROLHOS_HEADER_OFFSET 0x400 +/* The offset to image configuration. */ +#define ABROLHOS_IMAGE_CONFIG_OFFSET (ABROLHOS_HEADER_OFFSET + 0x160) + +/* + * The image configuration attached to the signed firmware. + */ +struct abrolhos_image_config { + __u32 carveout_base; + __u32 firmware_base; + __u32 firmware_size; + struct edgetpu_fw_version firmware_versions; +} __packed; int abrolhos_edgetpu_firmware_create(struct edgetpu_dev *etdev); void abrolhos_edgetpu_firmware_destroy(struct edgetpu_dev *etdev); diff --git a/drivers/edgetpu/abrolhos-iommu.c b/drivers/edgetpu/abrolhos-iommu.c index 0357378..f0dbd09 100644 --- a/drivers/edgetpu/abrolhos-iommu.c +++ b/drivers/edgetpu/abrolhos-iommu.c @@ -524,6 +524,6 @@ void edgetpu_mmu_tpu_unmap(struct edgetpu_dev *etdev, tpu_addr_t tpu_addr, iommu_unmap(domain, tpu_addr, size); } -void edgetpu_mmu_use_dev_dram(struct edgetpu_dev *etdev) +void edgetpu_mmu_use_dev_dram(struct edgetpu_dev *etdev, bool use_dev_dram) { } diff --git a/drivers/edgetpu/abrolhos-pm.c b/drivers/edgetpu/abrolhos-pm.c index e8bbd7a..bfe5242 100644 --- a/drivers/edgetpu/abrolhos-pm.c +++ b/drivers/edgetpu/abrolhos-pm.c @@ -20,6 +20,8 @@ #include "edgetpu-pm.h" #include "edgetpu-telemetry.h" +#include "edgetpu-pm.c" + /* Default power state: the lowest power state that keeps firmware running */ static int power_state = TPU_DEEP_SLEEP_CLOCKS_SLOW; @@ -370,6 +372,8 @@ static int abrolhos_power_up(struct edgetpu_pm *etpm) abrolhos_get_initial_pwr_state(dev)); enum edgetpu_firmware_status firmware_status; + etdev_info(etpm->etdev, "Powering up\n"); + if (ret) return ret; @@ -395,7 +399,8 @@ static int abrolhos_power_up(struct edgetpu_pm *etpm) firmware_status = edgetpu_firmware_status_locked(etdev); if (firmware_status == FW_LOADING) - goto out; + return 0; + /* attempt firmware run */ mutex_lock(&etdev->state_lock); if (etdev->state == ETDEV_STATE_FWLOADING) { @@ -424,26 +429,49 @@ static int abrolhos_power_up(struct edgetpu_pm *etpm) else etdev->state = ETDEV_STATE_GOOD; /* f/w handshake success */ mutex_unlock(&etdev->state_lock); -out: + if (ret) abrolhos_power_down(etpm); return ret; } +static void +abrolhos_pm_shutdown_firmware(struct edgetpu_dev *etdev, + struct edgetpu_platform_dev *edgetpu_pdev) +{ + if (!edgetpu_pchannel_power_down(etdev, false)) + return; + + etdev_warn(etdev, "Firmware shutdown request failed!\n"); + etdev_warn(etdev, "Attempting firmware restart\n"); + + if (!edgetpu_firmware_restart_locked(etdev) && + !edgetpu_pchannel_power_down(etdev, false)) + return; + + etdev_warn(etdev, "Forcing shutdown through power policy\n"); + abrolhos_pwr_policy_set(edgetpu_pdev, TPU_OFF); + pm_runtime_put_sync(etdev->dev); + /* + * TODO: experiment on hardware to verify if this delay + * is needed, what is a good value or an alternative way + * to make sure the power policy request turned the + * device off. + */ + msleep(100); + pm_runtime_get_sync(etdev->dev); + abrolhos_pwr_policy_set(edgetpu_pdev, TPU_ACTIVE_OD); +} + static void abrolhos_power_down(struct edgetpu_pm *etpm) { struct edgetpu_platform_dev *edgetpu_pdev = container_of( etpm->etdev, struct edgetpu_platform_dev, edgetpu_dev); u64 val; int res; - int curr_state; - - curr_state = exynos_acpm_get_rate(TPU_ACPM_DOMAIN, 0); - /* We don't need to do anything if the block is already off */ - if (curr_state == TPU_OFF) - return; + etdev_info(etpm->etdev, "Powering down\n"); if (abrolhos_pwr_state_get(etpm->etdev->dev, &val)) { etdev_warn(etpm->etdev, "Failed to read current power state\n"); @@ -454,26 +482,13 @@ static void abrolhos_power_down(struct edgetpu_pm *etpm) "Device already off, skipping shutdown\n"); return; } + if (etpm->etdev->kci && edgetpu_firmware_status_locked(etpm->etdev) == FW_VALID) { - res = edgetpu_kci_shutdown(etpm->etdev->kci); - if (res) { - etdev_warn(etpm->etdev, - "Firmware shutdown request failed!\n"); - etdev_warn( - etpm->etdev, - "Doing forced shutdown through power policy\n"); - abrolhos_pwr_policy_set(edgetpu_pdev, TPU_OFF); - /* - * TODO: experiment on hardware to verify if this delay - * is needed, what is a good value or an alternative way - * to make sure the power policy request turned the - * device off. - */ - msleep(100); - abrolhos_pwr_policy_set(edgetpu_pdev, TPU_ACTIVE_OD); - } + abrolhos_pm_shutdown_firmware(etpm->etdev, edgetpu_pdev); + cancel_work_sync(&etpm->etdev->kci->work); } + res = gsa_send_tpu_cmd(edgetpu_pdev->gsa_dev, GSA_TPU_SHUTDOWN); if (res < 0) etdev_warn(etpm->etdev, "GSA shutdown request failed (%d)\n", diff --git a/drivers/edgetpu/abrolhos/config-tpu-cpu.h b/drivers/edgetpu/abrolhos/config-tpu-cpu.h index 5e3a53f..6060892 100644 --- a/drivers/edgetpu/abrolhos/config-tpu-cpu.h +++ b/drivers/edgetpu/abrolhos/config-tpu-cpu.h @@ -10,12 +10,18 @@ /* TODO(137684940): Modify the CSR generator tool to output the values. */ #define EDGETPU_REG_RESET_CONTROL 0x90010 +#define CPUPORESET (1 << 1) #define EDGETPU_REG_INSTRUCTION_REMAP_CONTROL 0x90050 #define EDGETPU_REG_INSTRUCTION_REMAP_BASE 0x90058 #define EDGETPU_REG_INSTRUCTION_REMAP_LIMIT 0x90060 #define EDGETPU_REG_INSTRUCTION_REMAP_NEW_BASE 0x90068 #define EDGETPU_REG_INSTRUCTION_REMAP_SECURITY 0x90070 #define EDGETPU_REG_SECURITY 0x90048 - +#define EDGETPU_REG_POWER_CONTROL 0xA0008 +#define PSTATE (1 << 0) +#define PREQ (1 << 1) +#define PDENY (1 << 2) +#define PACCEPT (1 << 3) +#define PACTIVE (1 << 5) #endif /* __ABROLHOS_CONFIG_TPU_CPU_H__ */ diff --git a/drivers/edgetpu/edgetpu-direct.c b/drivers/edgetpu/edgetpu-direct.c index a552e95..e6efe51 100644 --- a/drivers/edgetpu/edgetpu-direct.c +++ b/drivers/edgetpu/edgetpu-direct.c @@ -442,9 +442,8 @@ static bool etdirect_ioctl_check_permissions(struct file *file, uint cmd) static bool etdirect_ioctl_check_group(struct edgetpu_client *client, uint cmd) { /* @client must not belong to any group */ - if (cmd == EDGETPU_CREATE_GROUP || - cmd == EDGETPU_CREATE_GROUP_COMPAT_2 || - cmd == EDGETPU_JOIN_GROUP_COMPAT || cmd == EDGETPU_JOIN_GROUP) + if (cmd == EDGETPU_CREATE_GROUP || cmd == EDGETPU_JOIN_GROUP_COMPAT || + cmd == EDGETPU_JOIN_GROUP) return !client->group; /* Valid for any @client */ @@ -604,7 +603,6 @@ long edgetpu_ioctl(struct file *file, uint cmd, ulong arg) switch (cmd) { case EDGETPU_CREATE_GROUP: - case EDGETPU_CREATE_GROUP_COMPAT_2: ret = edgetpu_ioctl_create_group(client, argp); break; case EDGETPU_JOIN_GROUP: diff --git a/drivers/edgetpu/edgetpu-firmware.c b/drivers/edgetpu/edgetpu-firmware.c index b3b1f4f..7927112 100644 --- a/drivers/edgetpu/edgetpu-firmware.c +++ b/drivers/edgetpu/edgetpu-firmware.c @@ -287,6 +287,12 @@ static int edgetpu_firmware_handshake(struct edgetpu_firmware *et_fw) return 0; } +enum edgetpu_fw_flavor +edgetpu_firmware_get_flavor(struct edgetpu_firmware *et_fw) +{ + return et_fw->p->fw_flavor; +} + int edgetpu_firmware_run_locked(struct edgetpu_firmware *et_fw, const char *name, enum edgetpu_firmware_flags flags) diff --git a/drivers/edgetpu/edgetpu-firmware.h b/drivers/edgetpu/edgetpu-firmware.h index 49b4f76..ea9208b 100644 --- a/drivers/edgetpu/edgetpu-firmware.h +++ b/drivers/edgetpu/edgetpu-firmware.h @@ -194,4 +194,8 @@ int edgetpu_firmware_run_locked(struct edgetpu_firmware *et_fw, const char *name, enum edgetpu_firmware_flags flags); +/* Returns the firmware image flavor loaded on the device. */ +enum edgetpu_fw_flavor +edgetpu_firmware_get_flavor(struct edgetpu_firmware *et_fw); + #endif /* __EDGETPU_FIRMWARE_H__ */ diff --git a/drivers/edgetpu/edgetpu-mmu.h b/drivers/edgetpu/edgetpu-mmu.h index 5226e2e..949f5e5 100644 --- a/drivers/edgetpu/edgetpu-mmu.h +++ b/drivers/edgetpu/edgetpu-mmu.h @@ -208,7 +208,10 @@ void edgetpu_mmu_tpu_unmap(struct edgetpu_dev *etdev, /* * Hints the MMU to use edgetpu_device_dram_alloc() for allocating MMU page * tables. + * + * @use_dev_dram: true = use device DRAM for MMU data structures + * false = use host DRAM for MMU data structures */ -void edgetpu_mmu_use_dev_dram(struct edgetpu_dev *etdev); +void edgetpu_mmu_use_dev_dram(struct edgetpu_dev *etdev, bool use_dev_dram); #endif /* __EDGETPU_MMU_H__ */ diff --git a/drivers/edgetpu/edgetpu-pm.c b/drivers/edgetpu/edgetpu-pm.c index 01d60a4..a62da18 100644 --- a/drivers/edgetpu/edgetpu-pm.c +++ b/drivers/edgetpu/edgetpu-pm.c @@ -5,12 +5,15 @@ * Copyright (C) 2020 Google, Inc. */ +#include <linux/iopoll.h> #include <linux/mutex.h> #include <linux/slab.h> +#include "edgetpu-config.h" #include "edgetpu-device-group.h" #include "edgetpu-firmware.h" #include "edgetpu-internal.h" +#include "edgetpu-kci.h" #include "edgetpu-mailbox.h" #include "edgetpu-pm.h" #include "edgetpu-sw-watchdog.h" @@ -37,6 +40,7 @@ int edgetpu_pm_get(struct edgetpu_pm *etpm) } if (ret) etpm->p->power_up_count--; + etdev_dbg(etpm->etdev, "%s: %d\n", __func__, etpm->p->power_up_count); mutex_unlock(&etpm->p->lock); return ret; } @@ -56,6 +60,7 @@ void edgetpu_pm_put(struct edgetpu_pm *etpm) edgetpu_sw_wdt_stop(etpm->etdev); etpm->p->handlers->power_down(etpm); } + etdev_dbg(etpm->etdev, "%s: %d\n", __func__, etpm->p->power_up_count); mutex_unlock(&etpm->p->lock); } @@ -147,3 +152,91 @@ bool edgetpu_is_powered(struct edgetpu_dev *etdev) return true; return etpm->p->power_up_count; } + +static int pchannel_state_change_request(struct edgetpu_dev *etdev, int state) +{ + int ret; + u32 val; + bool deny = false; + + /* P-channel state change request and handshake. */ + val = edgetpu_dev_read_32(etdev, EDGETPU_REG_POWER_CONTROL); + /* Phase 1: Drive PREQ to 0 */ + if (val & PREQ) { + edgetpu_dev_write_32(etdev, EDGETPU_REG_POWER_CONTROL, + val & ~(PREQ)); + ret = readl_relaxed_poll_timeout( + etdev->regs.mem + EDGETPU_REG_POWER_CONTROL, val, + (val & PACCEPT) == 0, 1, + EDGETPU_PCHANNEL_STATE_CHANGE_TIMEOUT); + if (ret) { + etdev_err(etdev, "p-channel request timeout\n"); + return ret; + } + } + /* Phase 2: Request state */ + edgetpu_dev_write_32(etdev, EDGETPU_REG_POWER_CONTROL, state | PREQ); + + /* don't wait for state accept if STATE RUN */ + if (state == STATE_RUN) + return 0; + + /* Phase 3: R52 acknowledgment */ + ret = readl_relaxed_poll_timeout( + etdev->regs.mem + EDGETPU_REG_POWER_CONTROL, val, + (val & PACCEPT) || (val & PDENY), 1, + EDGETPU_PCHANNEL_STATE_CHANGE_TIMEOUT); + if (val & PDENY) { + edgetpu_dev_write_32(etdev, EDGETPU_REG_POWER_CONTROL, + val & !state); + etdev_err(etdev, "p-channel state change request denied\n"); + deny = true; + } + if (ret) { + etdev_err(etdev, "p-channel state change request timeout\n"); + return ret; + } + /* Phase 4. Drive PREQ to 0 */ + edgetpu_dev_write_32(etdev, EDGETPU_REG_POWER_CONTROL, val & ~(PREQ)); + ret = readl_relaxed_poll_timeout( + etdev->regs.mem + EDGETPU_REG_POWER_CONTROL, val, + ((val & PACCEPT) == 0) && ((val & PDENY) == 0), 1, + EDGETPU_PCHANNEL_STATE_CHANGE_TIMEOUT); + + return deny ? -EACCES : ret; +} + +int edgetpu_pchannel_power_down(struct edgetpu_dev *etdev, bool wait_on_pactive) +{ + int ret; + u32 val; + + etdev_dbg(etdev, "Starting p-channel power down\n"); + edgetpu_sw_wdt_stop(etdev); + ret = edgetpu_kci_shutdown(etdev->kci); + if (ret) { + etdev_err(etdev, "request power down routing failed\n"); + return ret; + } + /* + * wait some time for f/w to execute power down and for TPU CPU to enter + * wfi. + */ + if (!wait_on_pactive) + msleep(200); + else + /* wait for PACTIVE[1] goes low. */ + ret = readl_relaxed_poll_timeout( + etdev->regs.mem + EDGETPU_REG_POWER_CONTROL, val, + (val & PACTIVE) == 0, 1, + EDGETPU_PCHANNEL_STATE_CHANGE_TIMEOUT); + if (ret) + return ret; + ret = pchannel_state_change_request(etdev, STATE_SHUTDOWN); + return ret; +} + +void edgetpu_pchannel_power_up(struct edgetpu_dev *etdev) +{ + pchannel_state_change_request(etdev, STATE_RUN); +} diff --git a/drivers/edgetpu/edgetpu-pm.h b/drivers/edgetpu/edgetpu-pm.h index 82eb154..b7c9b5b 100644 --- a/drivers/edgetpu/edgetpu-pm.h +++ b/drivers/edgetpu/edgetpu-pm.h @@ -10,6 +10,10 @@ #include "edgetpu-internal.h" +#define STATE_SHUTDOWN 1 +#define STATE_RUN 0 +#define EDGETPU_PCHANNEL_STATE_CHANGE_TIMEOUT 15 /* 15us */ + struct edgetpu_pm_private; struct edgetpu_pm; @@ -66,4 +70,18 @@ void edgetpu_pm_shutdown(struct edgetpu_dev *etdev); /* Check if device is powered on. power_up_count is not protected by a lock */ bool edgetpu_is_powered(struct edgetpu_dev *etdev); +/* + * Request run state and deassert CPU reset to TPU CPU on p-channel + * interface. + */ +void edgetpu_pchannel_power_up(struct edgetpu_dev *etdev); + +/* + * Request shutdown state and assert CPU reset to TPU CPU on p-channel + * interface. Set @wait_on_pactive if chip has working PACTIVE implementation, + * false otherwise that will sleep for set amount of time. + */ +int edgetpu_pchannel_power_down(struct edgetpu_dev *etdev, + bool wait_on_pactive); + #endif /* __EDGETPU_PM_H__ */ diff --git a/drivers/edgetpu/edgetpu.h b/drivers/edgetpu/edgetpu.h index cd5c262..b3c9325 100644 --- a/drivers/edgetpu/edgetpu.h +++ b/drivers/edgetpu/edgetpu.h @@ -154,9 +154,6 @@ struct edgetpu_mailbox_attr { #define EDGETPU_CREATE_GROUP \ _IOW(EDGETPU_IOCTL_BASE, 6, struct edgetpu_mailbox_attr) -#define EDGETPU_CREATE_GROUP_COMPAT_2 \ - _IOR(EDGETPU_IOCTL_BASE, 6, struct edgetpu_mailbox_attr) - /* Join the calling fd to the device group of the supplied fd. */ #define EDGETPU_JOIN_GROUP \ _IOW(EDGETPU_IOCTL_BASE, 7, __u32) |