diff options
Diffstat (limited to 'drivers/gpu/msm')
| -rw-r--r-- | drivers/gpu/msm/adreno-gpulist.h | 22 | ||||
| -rw-r--r-- | drivers/gpu/msm/adreno.c | 15 | ||||
| -rw-r--r-- | drivers/gpu/msm/adreno.h | 6 | ||||
| -rw-r--r-- | drivers/gpu/msm/adreno_a5xx.c | 6 | ||||
| -rw-r--r-- | drivers/gpu/msm/kgsl.h | 15 | ||||
| -rw-r--r-- | drivers/gpu/msm/kgsl_device.h | 4 | ||||
| -rw-r--r-- | drivers/gpu/msm/kgsl_pwrctrl.c | 349 | ||||
| -rw-r--r-- | drivers/gpu/msm/kgsl_pwrctrl.h | 2 | ||||
| -rw-r--r-- | drivers/gpu/msm/kgsl_pwrscale.c | 8 | ||||
| -rw-r--r-- | drivers/gpu/msm/kgsl_snapshot.c | 38 |
10 files changed, 420 insertions, 45 deletions
diff --git a/drivers/gpu/msm/adreno-gpulist.h b/drivers/gpu/msm/adreno-gpulist.h index a3b25b3d8dd1..3615be45b6d9 100644 --- a/drivers/gpu/msm/adreno-gpulist.h +++ b/drivers/gpu/msm/adreno-gpulist.h @@ -244,6 +244,28 @@ static const struct adreno_gpu_core adreno_gpulist[] = { .core = 5, .major = 4, .minor = 0, + .patchid = 0, + .features = ADRENO_PREEMPTION | ADRENO_64BIT | + ADRENO_CONTENT_PROTECTION | + ADRENO_GPMU | ADRENO_SPTP_PC, + .pm4fw_name = "a530_pm4.fw", + .pfpfw_name = "a530_pfp.fw", + .zap_name = "a540_zap", + .gpudev = &adreno_a5xx_gpudev, + .gmem_size = SZ_1M, + .num_protected_regs = 0x20, + .busy_mask = 0xFFFFFFFE, + .gpmufw_name = "a540_gpmu.fw2", + .gpmu_major = 3, + .gpmu_minor = 0, + .gpmu_tsens = 0x000C000D, + .max_power = 5448, + }, + { + .gpurev = ADRENO_REV_A540, + .core = 5, + .major = 4, + .minor = 0, .patchid = ANY_ID, .features = ADRENO_PREEMPTION | ADRENO_64BIT | ADRENO_CONTENT_PROTECTION | diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c index 498386903936..1356835d0e93 100644 --- a/drivers/gpu/msm/adreno.c +++ b/drivers/gpu/msm/adreno.c @@ -2799,6 +2799,18 @@ static void adreno_regulator_disable_poll(struct kgsl_device *device) adreno_iommu_sync(device, false); } +static void adreno_gpu_model(struct kgsl_device *device, char *str, + size_t bufsz) +{ + struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + + snprintf(str, bufsz, "Adreno%d%d%dv%d", + ADRENO_CHIPID_CORE(adreno_dev->chipid), + ADRENO_CHIPID_MAJOR(adreno_dev->chipid), + ADRENO_CHIPID_MINOR(adreno_dev->chipid), + ADRENO_CHIPID_PATCH(adreno_dev->chipid) + 1); +} + static const struct kgsl_functable adreno_functable = { /* Mandatory functions */ .regread = adreno_regread, @@ -2835,7 +2847,8 @@ static const struct kgsl_functable adreno_functable = { .regulator_disable = adreno_regulator_disable, .pwrlevel_change_settings = adreno_pwrlevel_change_settings, .regulator_disable_poll = adreno_regulator_disable_poll, - .clk_set_options = adreno_clk_set_options + .clk_set_options = adreno_clk_set_options, + .gpu_model = adreno_gpu_model, }; static struct platform_driver adreno_platform_driver = { diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h index 286f7d63c8fe..d4858f3f818e 100644 --- a/drivers/gpu/msm/adreno.h +++ b/drivers/gpu/msm/adreno.h @@ -1015,6 +1015,12 @@ static inline int adreno_is_a540v1(struct adreno_device *adreno_dev) (ADRENO_CHIPID_PATCH(adreno_dev->chipid) == 0); } +static inline int adreno_is_a540v2(struct adreno_device *adreno_dev) +{ + return (ADRENO_GPUREV(adreno_dev) == ADRENO_REV_A540) && + (ADRENO_CHIPID_PATCH(adreno_dev->chipid) == 1); +} + /* * adreno_checkreg_off() - Checks the validity of a register enum * @adreno_dev: Pointer to adreno device diff --git a/drivers/gpu/msm/adreno_a5xx.c b/drivers/gpu/msm/adreno_a5xx.c index 1782d1d54946..8ac058a7c5b0 100644 --- a/drivers/gpu/msm/adreno_a5xx.c +++ b/drivers/gpu/msm/adreno_a5xx.c @@ -2147,9 +2147,11 @@ static int _me_init_ucode_workarounds(struct adreno_device *adreno_dev) case ADRENO_REV_A540: /* * WFI after every direct-render 3D mode draw and - * WFI after every 2D Mode 3 draw. + * WFI after every 2D Mode 3 draw. This is needed + * only on a540v1. */ - return 0x0000000A; + if (adreno_is_a540v1(adreno_dev)) + return 0x0000000A; default: return 0x00000000; /* No ucode workarounds enabled */ } diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h index 25f5de6ce645..7ac84b777051 100644 --- a/drivers/gpu/msm/kgsl.h +++ b/drivers/gpu/msm/kgsl.h @@ -579,4 +579,19 @@ static inline void __user *to_user_ptr(uint64_t address) return (void __user *)(uintptr_t)address; } +static inline void kgsl_gpu_sysfs_add_link(struct kobject *dst, + struct kobject *src, const char *src_name, + const char *dst_name) +{ + struct kernfs_node *old; + + if (dst == NULL || src == NULL) + return; + + old = sysfs_get_dirent(src->sd, src_name); + if (IS_ERR_OR_NULL(old)) + return; + + kernfs_create_link(dst->sd, dst_name, old); +} #endif /* __KGSL_H */ diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h index 0df6dd8628a5..24511a4de6f1 100644 --- a/drivers/gpu/msm/kgsl_device.h +++ b/drivers/gpu/msm/kgsl_device.h @@ -167,6 +167,8 @@ struct kgsl_functable { void (*regulator_disable_poll)(struct kgsl_device *device); void (*clk_set_options)(struct kgsl_device *device, const char *name, struct clk *clk); + void (*gpu_model)(struct kgsl_device *device, char *str, + size_t bufsz); }; struct kgsl_ioctl { @@ -261,6 +263,7 @@ struct kgsl_device { struct kgsl_snapshot *snapshot; u32 snapshot_faultcount; /* Total number of faults since boot */ + bool force_panic; /* Force panic after snapshot dump */ struct kobject snapshot_kobj; struct kobject ppd_kobj; @@ -281,6 +284,7 @@ struct kgsl_device { /* Number of active contexts seen globally for this device */ int active_context_count; + struct kobject *gpu_sysfs_kobj; }; #define KGSL_MMU_DEVICE(_mmu) \ diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c index 0fcc0c3b0d49..d71c6a63f2d3 100644 --- a/drivers/gpu/msm/kgsl_pwrctrl.c +++ b/drivers/gpu/msm/kgsl_pwrctrl.c @@ -21,6 +21,7 @@ #include <linux/delay.h> #include <linux/msm_adreno_devfreq.h> #include <linux/of_device.h> +#include <linux/thermal.h> #include "kgsl.h" #include "kgsl_pwrscale.h" @@ -590,22 +591,10 @@ static ssize_t kgsl_pwrctrl_max_pwrlevel_show(struct device *dev, return snprintf(buf, PAGE_SIZE, "%u\n", pwr->max_pwrlevel); } -static ssize_t kgsl_pwrctrl_min_pwrlevel_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ struct kgsl_device *device = kgsl_device_from_dev(dev); - struct kgsl_pwrctrl *pwr; - int ret; - unsigned int level = 0; - - if (device == NULL) - return 0; - - pwr = &device->pwrctrl; - - ret = kgsl_sysfs_store(buf, &level); - if (ret) - return ret; +static void kgsl_pwrctrl_min_pwrlevel_set(struct kgsl_device *device, + int level) +{ + struct kgsl_pwrctrl *pwr = &device->pwrctrl; mutex_lock(&device->mutex); if (level > pwr->num_pwrlevels - 2) @@ -621,6 +610,24 @@ static ssize_t kgsl_pwrctrl_min_pwrlevel_store(struct device *dev, kgsl_pwrctrl_pwrlevel_change(device, pwr->active_pwrlevel); mutex_unlock(&device->mutex); +} + +static ssize_t kgsl_pwrctrl_min_pwrlevel_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct kgsl_device *device = kgsl_device_from_dev(dev); + int ret; + unsigned int level = 0; + + if (device == NULL) + return 0; + + ret = kgsl_sysfs_store(buf, &level); + if (ret) + return ret; + + kgsl_pwrctrl_min_pwrlevel_set(device, level); return count; } @@ -664,24 +671,13 @@ static int _get_nearest_pwrlevel(struct kgsl_pwrctrl *pwr, unsigned int clock) return -ERANGE; } -static ssize_t kgsl_pwrctrl_max_gpuclk_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +static void kgsl_pwrctrl_max_clock_set(struct kgsl_device *device, int val) { - struct kgsl_device *device = kgsl_device_from_dev(dev); struct kgsl_pwrctrl *pwr; - unsigned int val = 0; - int level, ret; - - if (device == NULL) - return 0; + int level; pwr = &device->pwrctrl; - ret = kgsl_sysfs_store(buf, &val); - if (ret) - return ret; - mutex_lock(&device->mutex); level = _get_nearest_pwrlevel(pwr, val); /* If the requested power level is not supported by hw, try cycling */ @@ -715,21 +711,37 @@ static ssize_t kgsl_pwrctrl_max_gpuclk_store(struct device *dev, if (pwr->sysfs_pwr_limit) kgsl_pwr_limits_set_freq(pwr->sysfs_pwr_limit, pwr->pwrlevels[level].gpu_freq); - return count; + return; err: mutex_unlock(&device->mutex); - return count; } -static ssize_t kgsl_pwrctrl_max_gpuclk_show(struct device *dev, - struct device_attribute *attr, - char *buf) +static ssize_t kgsl_pwrctrl_max_gpuclk_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { - struct kgsl_device *device = kgsl_device_from_dev(dev); + unsigned int val = 0; + int ret; + + if (device == NULL) + return 0; + + ret = kgsl_sysfs_store(buf, &val); + if (ret) + return ret; + + kgsl_pwrctrl_max_clock_set(device, val); + + return count; +} + +static unsigned int kgsl_pwrctrl_max_clock_get(struct kgsl_device *device) +{ struct kgsl_pwrctrl *pwr; unsigned int freq; + if (device == NULL) return 0; pwr = &device->pwrctrl; @@ -743,7 +755,17 @@ static ssize_t kgsl_pwrctrl_max_gpuclk_show(struct device *dev, (TH_HZ - pwr->thermal_timeout) * (hfreq / TH_HZ); } - return snprintf(buf, PAGE_SIZE, "%d\n", freq); + return freq; +} + +static ssize_t kgsl_pwrctrl_max_gpuclk_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct kgsl_device *device = kgsl_device_from_dev(dev); + + return snprintf(buf, PAGE_SIZE, "%d\n", + kgsl_pwrctrl_max_clock_get(device)); } static ssize_t kgsl_pwrctrl_gpuclk_store(struct device *dev, @@ -903,9 +925,14 @@ static ssize_t kgsl_pwrctrl_gpu_available_frequencies_show( if (device == NULL) return 0; pwr = &device->pwrctrl; - for (index = 0; index < pwr->num_pwrlevels - 1; index++) - num_chars += snprintf(buf + num_chars, PAGE_SIZE, "%d ", - pwr->pwrlevels[index].gpu_freq); + for (index = 0; index < pwr->num_pwrlevels - 1; index++) { + num_chars += scnprintf(buf + num_chars, + PAGE_SIZE - num_chars - 1, + "%d ", pwr->pwrlevels[index].gpu_freq); + /* One space for trailing null and another for the newline */ + if (num_chars >= PAGE_SIZE - 2) + break; + } buf[num_chars++] = '\n'; return num_chars; } @@ -1171,6 +1198,195 @@ static ssize_t kgsl_popp_show(struct device *dev, test_bit(POPP_ON, &device->pwrscale.popp_state)); } +static ssize_t kgsl_pwrctrl_gpu_model_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct kgsl_device *device = kgsl_device_from_dev(dev); + char model_str[32] = {0}; + + if (device == NULL) + return 0; + + device->ftbl->gpu_model(device, model_str, sizeof(model_str)); + + return snprintf(buf, PAGE_SIZE, "%s\n", model_str); +} + +static ssize_t kgsl_pwrctrl_gpu_busy_percentage_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int ret; + struct kgsl_device *device = kgsl_device_from_dev(dev); + struct kgsl_clk_stats *stats; + unsigned int busy_percent = 0; + + if (device == NULL) + return 0; + stats = &device->pwrctrl.clk_stats; + + if (stats->total_old != 0) + busy_percent = (stats->busy_old * 100) / stats->total_old; + + ret = snprintf(buf, PAGE_SIZE, "%d %%\n", busy_percent); + + /* Reset the stats if GPU is OFF */ + if (!test_bit(KGSL_PWRFLAGS_AXI_ON, &device->pwrctrl.power_flags)) { + stats->busy_old = 0; + stats->total_old = 0; + } + return ret; +} + +static ssize_t kgsl_pwrctrl_min_clock_mhz_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct kgsl_device *device = kgsl_device_from_dev(dev); + struct kgsl_pwrctrl *pwr; + + if (device == NULL) + return 0; + pwr = &device->pwrctrl; + + return snprintf(buf, PAGE_SIZE, "%d\n", + pwr->pwrlevels[pwr->min_pwrlevel].gpu_freq / 1000000); +} + +static ssize_t kgsl_pwrctrl_min_clock_mhz_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct kgsl_device *device = kgsl_device_from_dev(dev); + int level, ret; + unsigned int freq; + struct kgsl_pwrctrl *pwr; + + if (device == NULL) + return 0; + + pwr = &device->pwrctrl; + + ret = kgsl_sysfs_store(buf, &freq); + if (ret) + return ret; + + freq *= 1000000; + level = _get_nearest_pwrlevel(pwr, freq); + + if (level >= 0) + kgsl_pwrctrl_min_pwrlevel_set(device, level); + + return count; +} + +static ssize_t kgsl_pwrctrl_max_clock_mhz_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct kgsl_device *device = kgsl_device_from_dev(dev); + unsigned int freq; + + if (device == NULL) + return 0; + + freq = kgsl_pwrctrl_max_clock_get(device); + + return snprintf(buf, PAGE_SIZE, "%d\n", freq / 1000000); +} + +static ssize_t kgsl_pwrctrl_max_clock_mhz_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct kgsl_device *device = kgsl_device_from_dev(dev); + unsigned int val = 0; + int ret; + + if (device == NULL) + return 0; + + ret = kgsl_sysfs_store(buf, &val); + if (ret) + return ret; + + val *= 1000000; + kgsl_pwrctrl_max_clock_set(device, val); + + return count; +} + +static ssize_t kgsl_pwrctrl_clock_mhz_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct kgsl_device *device = kgsl_device_from_dev(dev); + + if (device == NULL) + return 0; + + return snprintf(buf, PAGE_SIZE, "%ld\n", + kgsl_pwrctrl_active_freq(&device->pwrctrl) / 1000000); +} + +static ssize_t kgsl_pwrctrl_freq_table_mhz_show( + struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct kgsl_device *device = kgsl_device_from_dev(dev); + struct kgsl_pwrctrl *pwr; + int index, num_chars = 0; + + if (device == NULL) + return 0; + + pwr = &device->pwrctrl; + for (index = 0; index < pwr->num_pwrlevels - 1; index++) { + num_chars += scnprintf(buf + num_chars, + PAGE_SIZE - num_chars - 1, + "%d ", pwr->pwrlevels[index].gpu_freq / 1000000); + /* One space for trailing null and another for the newline */ + if (num_chars >= PAGE_SIZE - 2) + break; + } + + buf[num_chars++] = '\n'; + + return num_chars; +} + +static ssize_t kgsl_pwrctrl_temp_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct kgsl_device *device = kgsl_device_from_dev(dev); + struct kgsl_pwrctrl *pwr; + int ret, id = 0, temperature = 0; + + if (device == NULL) + goto done; + + pwr = &device->pwrctrl; + + if (!pwr->tsens_name) + goto done; + + id = sensor_get_id((char *)pwr->tsens_name); + if (id < 0) + goto done; + + ret = sensor_get_temp(id, &temperature); + if (ret) + goto done; + + return snprintf(buf, PAGE_SIZE, "%d\n", + temperature); +done: + return 0; +} + static DEVICE_ATTR(gpuclk, 0644, kgsl_pwrctrl_gpuclk_show, kgsl_pwrctrl_gpuclk_store); static DEVICE_ATTR(max_gpuclk, 0644, kgsl_pwrctrl_max_gpuclk_show, @@ -1222,6 +1438,17 @@ static DEVICE_ATTR(popp, 0644, kgsl_popp_show, kgsl_popp_store); static DEVICE_ATTR(force_no_nap, 0644, kgsl_pwrctrl_force_no_nap_show, kgsl_pwrctrl_force_no_nap_store); +static DEVICE_ATTR(gpu_model, 0444, kgsl_pwrctrl_gpu_model_show, NULL); +static DEVICE_ATTR(gpu_busy_percentage, 0444, + kgsl_pwrctrl_gpu_busy_percentage_show, NULL); +static DEVICE_ATTR(min_clock_mhz, 0644, kgsl_pwrctrl_min_clock_mhz_show, + kgsl_pwrctrl_min_clock_mhz_store); +static DEVICE_ATTR(max_clock_mhz, 0644, kgsl_pwrctrl_max_clock_mhz_show, + kgsl_pwrctrl_max_clock_mhz_store); +static DEVICE_ATTR(clock_mhz, 0444, kgsl_pwrctrl_clock_mhz_show, NULL); +static DEVICE_ATTR(freq_table_mhz, 0444, + kgsl_pwrctrl_freq_table_mhz_show, NULL); +static DEVICE_ATTR(temp, 0444, kgsl_pwrctrl_temp_show, NULL); static const struct device_attribute *pwrctrl_attr_list[] = { &dev_attr_gpuclk, @@ -1243,12 +1470,50 @@ static const struct device_attribute *pwrctrl_attr_list[] = { &dev_attr_bus_split, &dev_attr_default_pwrlevel, &dev_attr_popp, + &dev_attr_gpu_model, + &dev_attr_gpu_busy_percentage, + &dev_attr_min_clock_mhz, + &dev_attr_max_clock_mhz, + &dev_attr_clock_mhz, + &dev_attr_freq_table_mhz, + &dev_attr_temp, NULL }; +struct sysfs_link { + const char *src; + const char *dst; +}; + +static struct sysfs_link link_names[] = { + { "gpu_model", "gpu_model",}, + { "gpu_busy_percentage", "gpu_busy",}, + { "min_clock_mhz", "gpu_min_clock",}, + { "max_clock_mhz", "gpu_max_clock",}, + { "clock_mhz", "gpu_clock",}, + { "freq_table_mhz", "gpu_freq_table",}, + { "temp", "gpu_tmu",}, +}; + int kgsl_pwrctrl_init_sysfs(struct kgsl_device *device) { - return kgsl_create_device_sysfs_files(device->dev, pwrctrl_attr_list); + int i, ret; + + ret = kgsl_create_device_sysfs_files(device->dev, pwrctrl_attr_list); + if (ret) + return ret; + + device->gpu_sysfs_kobj = kobject_create_and_add("gpu", kernel_kobj); + if (IS_ERR_OR_NULL(device->gpu_sysfs_kobj)) + return (device->gpu_sysfs_kobj == NULL) ? + -ENOMEM : PTR_ERR(device->gpu_sysfs_kobj); + + for (i = 0; i < ARRAY_SIZE(link_names); i++) + kgsl_gpu_sysfs_add_link(device->gpu_sysfs_kobj, + &device->dev->kobj, link_names[i].src, + link_names[i].dst); + + return 0; } void kgsl_pwrctrl_uninit_sysfs(struct kgsl_device *device) @@ -1860,6 +2125,10 @@ int kgsl_pwrctrl_init(struct kgsl_device *device) kgsl_pwrctrl_vbif_init(); + /* temperature sensor name */ + of_property_read_string(pdev->dev.of_node, "qcom,tsens-name", + &pwr->tsens_name); + return result; } diff --git a/drivers/gpu/msm/kgsl_pwrctrl.h b/drivers/gpu/msm/kgsl_pwrctrl.h index ae21a274fada..2de42d87bcbe 100644 --- a/drivers/gpu/msm/kgsl_pwrctrl.h +++ b/drivers/gpu/msm/kgsl_pwrctrl.h @@ -152,6 +152,7 @@ struct kgsl_regulator { * @sysfs_pwr_limit - pointer to the sysfs limits node * isense_clk_indx - index of isense clock, 0 if no isense * isense_clk_on_level - isense clock rate is XO rate below this level. + * tsens_name - pointer to temperature sensor name of GPU temperature sensor */ struct kgsl_pwrctrl { @@ -204,6 +205,7 @@ struct kgsl_pwrctrl { struct kgsl_pwr_limit *sysfs_pwr_limit; unsigned int gpu_bimc_int_clk_freq; bool gpu_bimc_interface_enabled; + const char *tsens_name; }; int kgsl_pwrctrl_init(struct kgsl_device *device); diff --git a/drivers/gpu/msm/kgsl_pwrscale.c b/drivers/gpu/msm/kgsl_pwrscale.c index d90aec42f30a..01d3b74c16fd 100644 --- a/drivers/gpu/msm/kgsl_pwrscale.c +++ b/drivers/gpu/msm/kgsl_pwrscale.c @@ -910,6 +910,14 @@ int kgsl_pwrscale_init(struct device *dev, const char *governor) pwrscale->history[i].type = i; } + /* Add links to the devfreq sysfs nodes */ + kgsl_gpu_sysfs_add_link(device->gpu_sysfs_kobj, + &pwrscale->devfreqptr->dev.kobj, "governor", + "gpu_governor"); + kgsl_gpu_sysfs_add_link(device->gpu_sysfs_kobj, + &pwrscale->devfreqptr->dev.kobj, + "available_governors", "gpu_available_governor"); + return 0; } EXPORT_SYMBOL(kgsl_pwrscale_init); diff --git a/drivers/gpu/msm/kgsl_snapshot.c b/drivers/gpu/msm/kgsl_snapshot.c index 2c9f17f9e7a4..a2e4a909062f 100644 --- a/drivers/gpu/msm/kgsl_snapshot.c +++ b/drivers/gpu/msm/kgsl_snapshot.c @@ -810,6 +810,29 @@ static ssize_t faultcount_store(struct kgsl_device *device, const char *buf, return count; } +/* Show the force_panic request status */ +static ssize_t force_panic_show(struct kgsl_device *device, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", device->force_panic); +} + +/* Store the panic request value to force_panic */ +static ssize_t force_panic_store(struct kgsl_device *device, const char *buf, + size_t count) +{ + unsigned int val = 0; + int ret; + + if (device && count > 0) + device->force_panic = 0; + + ret = kgsl_sysfs_store(buf, &val); + + if (!ret && device) + device->force_panic = (bool)val; + + return (ssize_t) ret < 0 ? ret : count; +} /* Show the timestamp of the last collected snapshot */ static ssize_t timestamp_show(struct kgsl_device *device, char *buf) { @@ -835,6 +858,7 @@ struct kgsl_snapshot_attribute attr_##_name = { \ static SNAPSHOT_ATTR(timestamp, 0444, timestamp_show, NULL); static SNAPSHOT_ATTR(faultcount, 0644, faultcount_show, faultcount_store); +static SNAPSHOT_ATTR(force_panic, 0644, force_panic_show, force_panic_store); static ssize_t snapshot_sysfs_show(struct kobject *kobj, struct attribute *attr, char *buf) @@ -914,6 +938,7 @@ int kgsl_device_snapshot_init(struct kgsl_device *device) device->snapshot = NULL; device->snapshot_faultcount = 0; + device->force_panic = 0; ret = kobject_init_and_add(&device->snapshot_kobj, &ktype_snapshot, &device->dev->kobj, "snapshot"); @@ -929,7 +954,11 @@ int kgsl_device_snapshot_init(struct kgsl_device *device) goto done; ret = sysfs_create_file(&device->snapshot_kobj, &attr_faultcount.attr); + if (ret) + goto done; + ret = sysfs_create_file(&device->snapshot_kobj, + &attr_force_panic.attr); done: return ret; } @@ -954,6 +983,7 @@ void kgsl_device_snapshot_close(struct kgsl_device *device) device->snapshot_memory.ptr = NULL; device->snapshot_memory.size = 0; device->snapshot_faultcount = 0; + device->force_panic = 0; } EXPORT_SYMBOL(kgsl_device_snapshot_close); @@ -1032,6 +1062,7 @@ void kgsl_snapshot_save_frozen_objs(struct work_struct *work) { struct kgsl_snapshot *snapshot = container_of(work, struct kgsl_snapshot, work); + struct kgsl_device *device = kgsl_get_device(KGSL_DEVICE_3D0); struct kgsl_snapshot_object *obj, *tmp; size_t size = 0; void *ptr; @@ -1073,12 +1104,15 @@ done: snapshot->process = NULL; if (snapshot->ib1base && !snapshot->ib1dumped) - pr_warn("kgsl: snapshot: Active IB1:%016llx not dumped\n", + KGSL_DRV_ERR(device, + "snapshot: Active IB1:%016llx not dumped\n", snapshot->ib1base); else if (snapshot->ib2base && !snapshot->ib2dumped) - pr_warn("kgsl: snapshot: Active IB2:%016llx not dumped\n", + KGSL_DRV_ERR(device, + "snapshot: Active IB2:%016llx not dumped\n", snapshot->ib2base); complete_all(&snapshot->dump_gate); + BUG_ON(device->force_panic); return; } |
