/drivers/gpu/mali/mali/linux/mali_kernel_sysfs.c
C | 1281 lines | 1025 code | 207 blank | 49 comment | 174 complexity | 8c9ab4aaae4dd787c42c781b0d146995 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.0, AGPL-1.0
1/** 2 * Copyright (C) 2011-2012 ARM Limited. All rights reserved. 3 * 4 * This program is free software and is provided to you under the terms of the GNU General Public License version 2 5 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. 6 * 7 * A copy of the licence is included with the program, and can also be obtained from Free Software 8 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 9 */ 10 11 12/** 13 * @file mali_kernel_sysfs.c 14 * Implementation of some sysfs data exports 15 */ 16 17#include <linux/kernel.h> 18#include <linux/fs.h> 19#include <linux/device.h> 20#include <linux/version.h> 21#include <linux/module.h> 22#include "mali_kernel_license.h" 23#include "mali_kernel_common.h" 24#include "mali_kernel_linux.h" 25#include "mali_ukk.h" 26 27#if MALI_LICENSE_IS_GPL 28 29#include <linux/seq_file.h> 30#include <linux/debugfs.h> 31#include <asm/uaccess.h> 32#include <linux/module.h> 33#include "mali_kernel_sysfs.h" 34#if MALI_INTERNAL_TIMELINE_PROFILING_ENABLED 35#include <linux/slab.h> 36#include "mali_osk_profiling.h" 37#endif 38#include "mali_pm.h" 39#include "mali_cluster.h" 40#include "mali_group.h" 41#include "mali_gp.h" 42#include "mali_pp.h" 43#include "mali_l2_cache.h" 44#include "mali_hw_core.h" 45#include "mali_kernel_core.h" 46#include "mali_user_settings_db.h" 47#include "mali_device_pause_resume.h" 48 49#define POWER_BUFFER_SIZE 3 50 51static struct dentry *mali_debugfs_dir = NULL; 52 53typedef enum 54{ 55 _MALI_DEVICE_SUSPEND, 56 _MALI_DEVICE_RESUME, 57 _MALI_DEVICE_DVFS_PAUSE, 58 _MALI_DEVICE_DVFS_RESUME, 59 _MALI_MAX_EVENTS 60} _mali_device_debug_power_events; 61 62static const char* const mali_power_events[_MALI_MAX_EVENTS] = { 63 [_MALI_DEVICE_SUSPEND] = "suspend", 64 [_MALI_DEVICE_RESUME] = "resume", 65 [_MALI_DEVICE_DVFS_PAUSE] = "dvfs_pause", 66 [_MALI_DEVICE_DVFS_RESUME] = "dvfs_resume", 67}; 68 69static u32 virtual_power_status_register=0; 70static char pwr_buf[POWER_BUFFER_SIZE]; 71 72static int open_copy_private_data(struct inode *inode, struct file *filp) 73{ 74 filp->private_data = inode->i_private; 75 return 0; 76} 77 78static ssize_t gp_gpx_counter_srcx_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *gpos, u32 src_id) 79{ 80 char buf[64]; 81 int r; 82 u32 val; 83 struct mali_gp_core *gp_core = (struct mali_gp_core *)filp->private_data; 84 85 if (0 == src_id) 86 { 87 val = mali_gp_core_get_counter_src0(gp_core); 88 } 89 else 90 { 91 val = mali_gp_core_get_counter_src1(gp_core); 92 } 93 94 if (MALI_HW_CORE_NO_COUNTER == val) 95 { 96 r = sprintf(buf, "-1\n"); 97 } 98 else 99 { 100 r = sprintf(buf, "%u\n", val); 101 } 102 return simple_read_from_buffer(ubuf, cnt, gpos, buf, r); 103} 104 105static ssize_t gp_gpx_counter_srcx_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *gpos, u32 src_id) 106{ 107 struct mali_gp_core *gp_core = (struct mali_gp_core *)filp->private_data; 108 char buf[64]; 109 long val; 110 int ret; 111 112 if (cnt >= sizeof(buf)) 113 { 114 return -EINVAL; 115 } 116 117 if (copy_from_user(&buf, ubuf, cnt)) 118 { 119 return -EFAULT; 120 } 121 122 buf[cnt] = 0; 123 124 ret = strict_strtol(buf, 10, &val); 125 if (ret < 0) 126 { 127 return ret; 128 } 129 130 if (val < 0) 131 { 132 /* any negative input will disable counter */ 133 val = MALI_HW_CORE_NO_COUNTER; 134 } 135 136 if (0 == src_id) 137 { 138 if (MALI_TRUE != mali_gp_core_set_counter_src0(gp_core, (u32)val)) 139 { 140 return 0; 141 } 142 } 143 else 144 { 145 if (MALI_TRUE != mali_gp_core_set_counter_src1(gp_core, (u32)val)) 146 { 147 return 0; 148 } 149 } 150 151 *gpos += cnt; 152 return cnt; 153} 154 155static ssize_t gp_all_counter_srcx_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *gpos, u32 src_id) 156{ 157 char buf[64]; 158 long val; 159 int ret; 160 u32 ci; 161 struct mali_cluster *cluster; 162 163 if (cnt >= sizeof(buf)) 164 { 165 return -EINVAL; 166 } 167 168 if (copy_from_user(&buf, ubuf, cnt)) 169 { 170 return -EFAULT; 171 } 172 173 buf[cnt] = 0; 174 175 ret = strict_strtol(buf, 10, &val); 176 if (ret < 0) 177 { 178 return ret; 179 } 180 181 if (val < 0) 182 { 183 /* any negative input will disable counter */ 184 val = MALI_HW_CORE_NO_COUNTER; 185 } 186 187 ci = 0; 188 cluster = mali_cluster_get_global_cluster(ci); 189 while (NULL != cluster) 190 { 191 u32 gi = 0; 192 struct mali_group *group = mali_cluster_get_group(cluster, gi); 193 while (NULL != group) 194 { 195 struct mali_gp_core *gp_core = mali_group_get_gp_core(group); 196 if (NULL != gp_core) 197 { 198 if (0 == src_id) 199 { 200 if (MALI_TRUE != mali_gp_core_set_counter_src0(gp_core, (u32)val)) 201 { 202 return 0; 203 } 204 } 205 else 206 { 207 if (MALI_TRUE != mali_gp_core_set_counter_src1(gp_core, (u32)val)) 208 { 209 return 0; 210 } 211 } 212 } 213 214 /* try next group */ 215 gi++; 216 group = mali_cluster_get_group(cluster, gi); 217 } 218 219 /* try next cluster */ 220 ci++; 221 cluster = mali_cluster_get_global_cluster(ci); 222 } 223 224 *gpos += cnt; 225 return cnt; 226} 227 228static ssize_t gp_gpx_counter_src0_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *gpos) 229{ 230 return gp_gpx_counter_srcx_read(filp, ubuf, cnt, gpos, 0); 231} 232 233static ssize_t gp_gpx_counter_src1_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *gpos) 234{ 235 return gp_gpx_counter_srcx_read(filp, ubuf, cnt, gpos, 1); 236} 237 238static ssize_t gp_gpx_counter_src0_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *gpos) 239{ 240 return gp_gpx_counter_srcx_write(filp, ubuf, cnt, gpos, 0); 241} 242 243static ssize_t gp_gpx_counter_src1_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *gpos) 244{ 245 return gp_gpx_counter_srcx_write(filp, ubuf, cnt, gpos, 1); 246} 247 248static ssize_t gp_all_counter_src0_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *gpos) 249{ 250 return gp_all_counter_srcx_write(filp, ubuf, cnt, gpos, 0); 251} 252 253static ssize_t gp_all_counter_src1_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *gpos) 254{ 255 return gp_all_counter_srcx_write(filp, ubuf, cnt, gpos, 1); 256} 257 258static const struct file_operations gp_gpx_counter_src0_fops = { 259 .owner = THIS_MODULE, 260 .open = open_copy_private_data, 261 .read = gp_gpx_counter_src0_read, 262 .write = gp_gpx_counter_src0_write, 263}; 264 265static const struct file_operations gp_gpx_counter_src1_fops = { 266 .owner = THIS_MODULE, 267 .open = open_copy_private_data, 268 .read = gp_gpx_counter_src1_read, 269 .write = gp_gpx_counter_src1_write, 270}; 271 272static const struct file_operations gp_all_counter_src0_fops = { 273 .owner = THIS_MODULE, 274 .write = gp_all_counter_src0_write, 275}; 276 277static const struct file_operations gp_all_counter_src1_fops = { 278 .owner = THIS_MODULE, 279 .write = gp_all_counter_src1_write, 280}; 281 282static ssize_t pp_ppx_counter_srcx_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos, u32 src_id) 283{ 284 char buf[64]; 285 int r; 286 u32 val; 287 struct mali_pp_core *pp_core = (struct mali_pp_core *)filp->private_data; 288 289 if (0 == src_id) 290 { 291 val = mali_pp_core_get_counter_src0(pp_core); 292 } 293 else 294 { 295 val = mali_pp_core_get_counter_src1(pp_core); 296 } 297 298 if (MALI_HW_CORE_NO_COUNTER == val) 299 { 300 r = sprintf(buf, "-1\n"); 301 } 302 else 303 { 304 r = sprintf(buf, "%u\n", val); 305 } 306 return simple_read_from_buffer(ubuf, cnt, ppos, buf, r); 307} 308 309static ssize_t pp_ppx_counter_srcx_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos, u32 src_id) 310{ 311 struct mali_pp_core *pp_core = (struct mali_pp_core *)filp->private_data; 312 char buf[64]; 313 long val; 314 int ret; 315 316 if (cnt >= sizeof(buf)) 317 { 318 return -EINVAL; 319 } 320 321 if (copy_from_user(&buf, ubuf, cnt)) 322 { 323 return -EFAULT; 324 } 325 326 buf[cnt] = 0; 327 328 ret = strict_strtol(buf, 10, &val); 329 if (ret < 0) 330 { 331 return ret; 332 } 333 334 if (val < 0) 335 { 336 /* any negative input will disable counter */ 337 val = MALI_HW_CORE_NO_COUNTER; 338 } 339 340 if (0 == src_id) 341 { 342 if (MALI_TRUE != mali_pp_core_set_counter_src0(pp_core, (u32)val)) 343 { 344 return 0; 345 } 346 } 347 else 348 { 349 if (MALI_TRUE != mali_pp_core_set_counter_src1(pp_core, (u32)val)) 350 { 351 return 0; 352 } 353 } 354 355 *ppos += cnt; 356 return cnt; 357} 358 359static ssize_t pp_all_counter_srcx_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos, u32 src_id) 360{ 361 char buf[64]; 362 long val; 363 int ret; 364 u32 ci; 365 struct mali_cluster *cluster; 366 367 if (cnt >= sizeof(buf)) 368 { 369 return -EINVAL; 370 } 371 372 if (copy_from_user(&buf, ubuf, cnt)) 373 { 374 return -EFAULT; 375 } 376 377 buf[cnt] = 0; 378 379 ret = strict_strtol(buf, 10, &val); 380 if (ret < 0) 381 { 382 return ret; 383 } 384 385 if (val < 0) 386 { 387 /* any negative input will disable counter */ 388 val = MALI_HW_CORE_NO_COUNTER; 389 } 390 391 ci = 0; 392 cluster = mali_cluster_get_global_cluster(ci); 393 while (NULL != cluster) 394 { 395 u32 gi = 0; 396 struct mali_group *group = mali_cluster_get_group(cluster, gi); 397 while (NULL != group) 398 { 399 struct mali_pp_core *pp_core = mali_group_get_pp_core(group); 400 if (NULL != pp_core) 401 { 402 if (0 == src_id) 403 { 404 if (MALI_TRUE != mali_pp_core_set_counter_src0(pp_core, (u32)val)) 405 { 406 return 0; 407 } 408 } 409 else 410 { 411 if (MALI_TRUE != mali_pp_core_set_counter_src1(pp_core, (u32)val)) 412 { 413 return 0; 414 } 415 } 416 } 417 418 /* try next group */ 419 gi++; 420 group = mali_cluster_get_group(cluster, gi); 421 } 422 423 /* try next cluster */ 424 ci++; 425 cluster = mali_cluster_get_global_cluster(ci); 426 } 427 428 *ppos += cnt; 429 return cnt; 430} 431 432static ssize_t pp_ppx_counter_src0_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos) 433{ 434 return pp_ppx_counter_srcx_read(filp, ubuf, cnt, ppos, 0); 435} 436 437static ssize_t pp_ppx_counter_src1_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos) 438{ 439 return pp_ppx_counter_srcx_read(filp, ubuf, cnt, ppos, 1); 440} 441 442static ssize_t pp_ppx_counter_src0_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos) 443{ 444 return pp_ppx_counter_srcx_write(filp, ubuf, cnt, ppos, 0); 445} 446 447static ssize_t pp_ppx_counter_src1_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos) 448{ 449 return pp_ppx_counter_srcx_write(filp, ubuf, cnt, ppos, 1); 450} 451 452static ssize_t pp_all_counter_src0_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos) 453{ 454 return pp_all_counter_srcx_write(filp, ubuf, cnt, ppos, 0); 455} 456 457static ssize_t pp_all_counter_src1_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos) 458{ 459 return pp_all_counter_srcx_write(filp, ubuf, cnt, ppos, 1); 460} 461 462static const struct file_operations pp_ppx_counter_src0_fops = { 463 .owner = THIS_MODULE, 464 .open = open_copy_private_data, 465 .read = pp_ppx_counter_src0_read, 466 .write = pp_ppx_counter_src0_write, 467}; 468 469static const struct file_operations pp_ppx_counter_src1_fops = { 470 .owner = THIS_MODULE, 471 .open = open_copy_private_data, 472 .read = pp_ppx_counter_src1_read, 473 .write = pp_ppx_counter_src1_write, 474}; 475 476static const struct file_operations pp_all_counter_src0_fops = { 477 .owner = THIS_MODULE, 478 .write = pp_all_counter_src0_write, 479}; 480 481static const struct file_operations pp_all_counter_src1_fops = { 482 .owner = THIS_MODULE, 483 .write = pp_all_counter_src1_write, 484}; 485 486 487 488 489 490 491static ssize_t l2_l2x_counter_srcx_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos, u32 src_id) 492{ 493 char buf[64]; 494 int r; 495 u32 val; 496 struct mali_l2_cache_core *l2_core = (struct mali_l2_cache_core *)filp->private_data; 497 498 if (0 == src_id) 499 { 500 val = mali_l2_cache_core_get_counter_src0(l2_core); 501 } 502 else 503 { 504 val = mali_l2_cache_core_get_counter_src1(l2_core); 505 } 506 507 if (MALI_HW_CORE_NO_COUNTER == val) 508 { 509 r = sprintf(buf, "-1\n"); 510 } 511 else 512 { 513 r = sprintf(buf, "%u\n", val); 514 } 515 return simple_read_from_buffer(ubuf, cnt, ppos, buf, r); 516} 517 518static ssize_t l2_l2x_counter_srcx_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos, u32 src_id) 519{ 520 struct mali_l2_cache_core *l2_core = (struct mali_l2_cache_core *)filp->private_data; 521 char buf[64]; 522 long val; 523 int ret; 524 525 if (cnt >= sizeof(buf)) 526 { 527 return -EINVAL; 528 } 529 530 if (copy_from_user(&buf, ubuf, cnt)) 531 { 532 return -EFAULT; 533 } 534 535 buf[cnt] = 0; 536 537 ret = strict_strtol(buf, 10, &val); 538 if (ret < 0) 539 { 540 return ret; 541 } 542 543 if (val < 0) 544 { 545 /* any negative input will disable counter */ 546 val = MALI_HW_CORE_NO_COUNTER; 547 } 548 549 if (0 == src_id) 550 { 551 if (MALI_TRUE != mali_l2_cache_core_set_counter_src0(l2_core, (u32)val)) 552 { 553 return 0; 554 } 555 } 556 else 557 { 558 if (MALI_TRUE != mali_l2_cache_core_set_counter_src1(l2_core, (u32)val)) 559 { 560 return 0; 561 } 562 } 563 564 *ppos += cnt; 565 return cnt; 566} 567 568static ssize_t l2_all_counter_srcx_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos, u32 src_id) 569{ 570 char buf[64]; 571 long val; 572 int ret; 573 u32 l2_id; 574 struct mali_l2_cache_core *l2_cache; 575 576 if (cnt >= sizeof(buf)) 577 { 578 return -EINVAL; 579 } 580 581 if (copy_from_user(&buf, ubuf, cnt)) 582 { 583 return -EFAULT; 584 } 585 586 buf[cnt] = 0; 587 588 ret = strict_strtol(buf, 10, &val); 589 if (ret < 0) 590 { 591 return ret; 592 } 593 594 if (val < 0) 595 { 596 /* any negative input will disable counter */ 597 val = MALI_HW_CORE_NO_COUNTER; 598 } 599 600 l2_id = 0; 601 l2_cache = mali_l2_cache_core_get_glob_l2_core(l2_id); 602 while (NULL != l2_cache) 603 { 604 if (0 == src_id) 605 { 606 if (MALI_TRUE != mali_l2_cache_core_set_counter_src0(l2_cache, (u32)val)) 607 { 608 return 0; 609 } 610 } 611 else 612 { 613 if (MALI_TRUE != mali_l2_cache_core_set_counter_src1(l2_cache, (u32)val)) 614 { 615 return 0; 616 } 617 } 618 619 /* try next L2 */ 620 l2_id++; 621 l2_cache = mali_l2_cache_core_get_glob_l2_core(l2_id); 622 } 623 624 *ppos += cnt; 625 return cnt; 626} 627 628static ssize_t l2_l2x_counter_src0_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos) 629{ 630 return l2_l2x_counter_srcx_read(filp, ubuf, cnt, ppos, 0); 631} 632 633static ssize_t l2_l2x_counter_src1_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos) 634{ 635 return l2_l2x_counter_srcx_read(filp, ubuf, cnt, ppos, 1); 636} 637 638static ssize_t l2_l2x_counter_src0_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos) 639{ 640 return l2_l2x_counter_srcx_write(filp, ubuf, cnt, ppos, 0); 641} 642 643static ssize_t l2_l2x_counter_src1_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos) 644{ 645 return l2_l2x_counter_srcx_write(filp, ubuf, cnt, ppos, 1); 646} 647 648static ssize_t l2_all_counter_src0_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos) 649{ 650 return l2_all_counter_srcx_write(filp, ubuf, cnt, ppos, 0); 651} 652 653static ssize_t l2_all_counter_src1_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos) 654{ 655 return l2_all_counter_srcx_write(filp, ubuf, cnt, ppos, 1); 656} 657 658static const struct file_operations l2_l2x_counter_src0_fops = { 659 .owner = THIS_MODULE, 660 .open = open_copy_private_data, 661 .read = l2_l2x_counter_src0_read, 662 .write = l2_l2x_counter_src0_write, 663}; 664 665static const struct file_operations l2_l2x_counter_src1_fops = { 666 .owner = THIS_MODULE, 667 .open = open_copy_private_data, 668 .read = l2_l2x_counter_src1_read, 669 .write = l2_l2x_counter_src1_write, 670}; 671 672static const struct file_operations l2_all_counter_src0_fops = { 673 .owner = THIS_MODULE, 674 .write = l2_all_counter_src0_write, 675}; 676 677static const struct file_operations l2_all_counter_src1_fops = { 678 .owner = THIS_MODULE, 679 .write = l2_all_counter_src1_write, 680}; 681 682static ssize_t power_events_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos) 683{ 684 685 memset(pwr_buf,0,POWER_BUFFER_SIZE); 686 virtual_power_status_register = 0; 687 if (!strncmp(ubuf,mali_power_events[_MALI_DEVICE_SUSPEND],strlen(mali_power_events[_MALI_DEVICE_SUSPEND]))) 688 { 689 mali_pm_os_suspend(); 690 /* @@@@ assuming currently suspend is successful later on to tune as per previous*/ 691 virtual_power_status_register =1; 692 693 } 694 else if (!strncmp(ubuf,mali_power_events[_MALI_DEVICE_RESUME],strlen(mali_power_events[_MALI_DEVICE_RESUME]))) 695 { 696 mali_pm_os_resume(); 697 698 /* @@@@ assuming currently resume is successful later on to tune as per previous */ 699 virtual_power_status_register = 1; 700 } 701 else if (!strncmp(ubuf,mali_power_events[_MALI_DEVICE_DVFS_PAUSE],strlen(mali_power_events[_MALI_DEVICE_DVFS_PAUSE]))) 702 { 703 mali_bool power_on; 704 mali_dev_pause(&power_on); 705 if (!power_on) 706 { 707 virtual_power_status_register = 2; 708 mali_dev_resume(); 709 } 710 else 711 { 712 /* @@@@ assuming currently resume is successful later on to tune as per previous */ 713 virtual_power_status_register =1; 714 } 715 } 716 else if (!strncmp(ubuf,mali_power_events[_MALI_DEVICE_DVFS_RESUME],strlen(mali_power_events[_MALI_DEVICE_DVFS_RESUME]))) 717 { 718 mali_dev_resume(); 719 /* @@@@ assuming currently resume is successful later on to tune as per previous */ 720 virtual_power_status_register = 1; 721 722 } 723 *ppos += cnt; 724 sprintf(pwr_buf, "%d",virtual_power_status_register); 725 return cnt; 726} 727 728static ssize_t power_events_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos) 729{ 730 return simple_read_from_buffer(ubuf, cnt, ppos, pwr_buf, POWER_BUFFER_SIZE); 731} 732 733static loff_t power_events_seek(struct file *file, loff_t offset, int orig) 734{ 735 file->f_pos = offset; 736 return 0; 737} 738 739static const struct file_operations power_events_fops = { 740 .owner = THIS_MODULE, 741 .read = power_events_read, 742 .write = power_events_write, 743 .llseek = power_events_seek, 744}; 745 746 747#if MALI_STATE_TRACKING 748static int mali_seq_internal_state_show(struct seq_file *seq_file, void *v) 749{ 750 u32 len = 0; 751 u32 size; 752 char *buf; 753 754 size = seq_get_buf(seq_file, &buf); 755 756 if(!size) 757 { 758 return -ENOMEM; 759 } 760 761 /* Create the internal state dump. */ 762 len = snprintf(buf+len, size-len, "Mali device driver %s\n", SVN_REV_STRING); 763 len += snprintf(buf+len, size-len, "License: %s\n\n", MALI_KERNEL_LINUX_LICENSE); 764 765 len += _mali_kernel_core_dump_state(buf + len, size - len); 766 767 seq_commit(seq_file, len); 768 769 return 0; 770} 771 772static int mali_seq_internal_state_open(struct inode *inode, struct file *file) 773{ 774 return single_open(file, mali_seq_internal_state_show, NULL); 775} 776 777static const struct file_operations mali_seq_internal_state_fops = { 778 .owner = THIS_MODULE, 779 .open = mali_seq_internal_state_open, 780 .read = seq_read, 781 .llseek = seq_lseek, 782 .release = single_release, 783}; 784#endif /* MALI_STATE_TRACKING */ 785 786 787#if MALI_INTERNAL_TIMELINE_PROFILING_ENABLED 788static ssize_t profiling_record_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos) 789{ 790 char buf[64]; 791 int r; 792 793 r = sprintf(buf, "%u\n", _mali_osk_profiling_is_recording() ? 1 : 0); 794 return simple_read_from_buffer(ubuf, cnt, ppos, buf, r); 795} 796 797static ssize_t profiling_record_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos) 798{ 799 char buf[64]; 800 unsigned long val; 801 int ret; 802 803 if (cnt >= sizeof(buf)) 804 { 805 return -EINVAL; 806 } 807 808 if (copy_from_user(&buf, ubuf, cnt)) 809 { 810 return -EFAULT; 811 } 812 813 buf[cnt] = 0; 814 815 ret = strict_strtoul(buf, 10, &val); 816 if (ret < 0) 817 { 818 return ret; 819 } 820 821 if (val != 0) 822 { 823 u32 limit = MALI_PROFILING_MAX_BUFFER_ENTRIES; /* This can be made configurable at a later stage if we need to */ 824 825 /* check if we are already recording */ 826 if (MALI_TRUE == _mali_osk_profiling_is_recording()) 827 { 828 MALI_DEBUG_PRINT(3, ("Recording of profiling events already in progress\n")); 829 return -EFAULT; 830 } 831 832 /* check if we need to clear out an old recording first */ 833 if (MALI_TRUE == _mali_osk_profiling_have_recording()) 834 { 835 if (_MALI_OSK_ERR_OK != _mali_osk_profiling_clear()) 836 { 837 MALI_DEBUG_PRINT(3, ("Failed to clear existing recording of profiling events\n")); 838 return -EFAULT; 839 } 840 } 841 842 /* start recording profiling data */ 843 if (_MALI_OSK_ERR_OK != _mali_osk_profiling_start(&limit)) 844 { 845 MALI_DEBUG_PRINT(3, ("Failed to start recording of profiling events\n")); 846 return -EFAULT; 847 } 848 849 MALI_DEBUG_PRINT(3, ("Profiling recording started (max %u events)\n", limit)); 850 } 851 else 852 { 853 /* stop recording profiling data */ 854 u32 count = 0; 855 if (_MALI_OSK_ERR_OK != _mali_osk_profiling_stop(&count)) 856 { 857 MALI_DEBUG_PRINT(2, ("Failed to stop recording of profiling events\n")); 858 return -EFAULT; 859 } 860 861 MALI_DEBUG_PRINT(2, ("Profiling recording stopped (recorded %u events)\n", count)); 862 } 863 864 *ppos += cnt; 865 return cnt; 866} 867 868static const struct file_operations profiling_record_fops = { 869 .owner = THIS_MODULE, 870 .read = profiling_record_read, 871 .write = profiling_record_write, 872}; 873 874static void *profiling_events_start(struct seq_file *s, loff_t *pos) 875{ 876 loff_t *spos; 877 878 /* check if we have data avaiable */ 879 if (MALI_TRUE != _mali_osk_profiling_have_recording()) 880 { 881 return NULL; 882 } 883 884 spos = kmalloc(sizeof(loff_t), GFP_KERNEL); 885 if (NULL == spos) 886 { 887 return NULL; 888 } 889 890 *spos = *pos; 891 return spos; 892} 893 894static void *profiling_events_next(struct seq_file *s, void *v, loff_t *pos) 895{ 896 loff_t *spos = v; 897 898 /* check if we have data avaiable */ 899 if (MALI_TRUE != _mali_osk_profiling_have_recording()) 900 { 901 return NULL; 902 } 903 904 /* check if the next entry actually is avaiable */ 905 if (_mali_osk_profiling_get_count() <= (u32)(*spos + 1)) 906 { 907 return NULL; 908 } 909 910 *pos = ++*spos; 911 return spos; 912} 913 914static void profiling_events_stop(struct seq_file *s, void *v) 915{ 916 kfree(v); 917} 918 919static int profiling_events_show(struct seq_file *seq_file, void *v) 920{ 921 loff_t *spos = v; 922 u32 index; 923 u64 timestamp; 924 u32 event_id; 925 u32 data[5]; 926 927 index = (u32)*spos; 928 929 /* Retrieve all events */ 930 if (_MALI_OSK_ERR_OK == _mali_osk_profiling_get_event(index, ×tamp, &event_id, data)) 931 { 932 seq_printf(seq_file, "%llu %u %u %u %u %u %u\n", timestamp, event_id, data[0], data[1], data[2], data[3], data[4]); 933 return 0; 934 } 935 936 return 0; 937} 938 939static const struct seq_operations profiling_events_seq_ops = { 940 .start = profiling_events_start, 941 .next = profiling_events_next, 942 .stop = profiling_events_stop, 943 .show = profiling_events_show 944}; 945 946static int profiling_events_open(struct inode *inode, struct file *file) 947{ 948 return seq_open(file, &profiling_events_seq_ops); 949} 950 951static const struct file_operations profiling_events_fops = { 952 .owner = THIS_MODULE, 953 .open = profiling_events_open, 954 .read = seq_read, 955 .llseek = seq_lseek, 956 .release = seq_release, 957}; 958#endif 959 960static ssize_t memory_used_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos) 961{ 962 char buf[64]; 963 size_t r; 964 u32 mem = _mali_ukk_report_memory_usage(); 965 966 r = snprintf(buf, 64, "%u\n", mem); 967 return simple_read_from_buffer(ubuf, cnt, ppos, buf, r); 968} 969 970static const struct file_operations memory_usage_fops = { 971 .owner = THIS_MODULE, 972 .read = memory_used_read, 973}; 974 975 976static ssize_t user_settings_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos) 977{ 978 unsigned long val; 979 int ret; 980 _mali_uk_user_setting_t setting; 981 char buf[32]; 982 983 cnt = min(cnt, sizeof(buf) - 1); 984 if (copy_from_user(buf, ubuf, cnt)) 985 { 986 return -EFAULT; 987 } 988 buf[cnt] = '\0'; 989 990 ret = strict_strtoul(buf, 10, &val); 991 if (0 != ret) 992 { 993 return ret; 994 } 995 996 /* Update setting */ 997 setting = (_mali_uk_user_setting_t)(filp->private_data); 998 mali_set_user_setting(setting, val); 999 1000 *ppos += cnt; 1001 return cnt; 1002} 1003 1004static ssize_t user_settings_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos) 1005{ 1006 char buf[64]; 1007 size_t r; 1008 u32 value; 1009 _mali_uk_user_setting_t setting; 1010 1011 setting = (_mali_uk_user_setting_t)(filp->private_data); 1012 value = mali_get_user_setting(setting); 1013 1014 r = snprintf(buf, 64, "%u\n", value); 1015 return simple_read_from_buffer(ubuf, cnt, ppos, buf, r); 1016} 1017 1018static const struct file_operations user_settings_fops = { 1019 .owner = THIS_MODULE, 1020 .open = open_copy_private_data, 1021 .read = user_settings_read, 1022 .write = user_settings_write, 1023}; 1024 1025static int mali_sysfs_user_settings_register(void) 1026{ 1027 struct dentry *mali_user_settings_dir = debugfs_create_dir("userspace_settings", mali_debugfs_dir); 1028 1029 if (mali_user_settings_dir != NULL) 1030 { 1031 int i; 1032 for (i = 0; i < _MALI_UK_USER_SETTING_MAX; i++) 1033 { 1034 debugfs_create_file(_mali_uk_user_setting_descriptions[i], 0600, mali_user_settings_dir, (void*)i, &user_settings_fops); 1035 } 1036 } 1037 1038 return 0; 1039} 1040 1041int mali_sysfs_register(struct mali_dev *device, dev_t dev, const char *mali_dev_name) 1042{ 1043 int err = 0; 1044 struct device * mdev; 1045 1046 device->mali_class = class_create(THIS_MODULE, mali_dev_name); 1047 if (IS_ERR(device->mali_class)) 1048 { 1049 err = PTR_ERR(device->mali_class); 1050 goto init_class_err; 1051 } 1052 mdev = device_create(device->mali_class, NULL, dev, NULL, mali_dev_name); 1053 if (IS_ERR(mdev)) 1054 { 1055 err = PTR_ERR(mdev); 1056 goto init_mdev_err; 1057 } 1058 1059 mali_debugfs_dir = debugfs_create_dir(mali_dev_name, NULL); 1060 if(ERR_PTR(-ENODEV) == mali_debugfs_dir) 1061 { 1062 /* Debugfs not supported. */ 1063 mali_debugfs_dir = NULL; 1064 } 1065 else 1066 { 1067 if(NULL != mali_debugfs_dir) 1068 { 1069 /* Debugfs directory created successfully; create files now */ 1070 struct dentry *mali_power_dir; 1071 struct dentry *mali_gp_dir; 1072 struct dentry *mali_pp_dir; 1073 struct dentry *mali_l2_dir; 1074#if MALI_INTERNAL_TIMELINE_PROFILING_ENABLED 1075 struct dentry *mali_profiling_dir; 1076#endif 1077 1078 mali_power_dir = debugfs_create_dir("power", mali_debugfs_dir); 1079 if (mali_power_dir != NULL) 1080 { 1081 debugfs_create_file("power_events", 0400, mali_power_dir, NULL, &power_events_fops); 1082 } 1083 1084 mali_gp_dir = debugfs_create_dir("gp", mali_debugfs_dir); 1085 if (mali_gp_dir != NULL) 1086 { 1087 struct dentry *mali_gp_all_dir; 1088 u32 ci; 1089 struct mali_cluster *cluster; 1090 1091 mali_gp_all_dir = debugfs_create_dir("all", mali_gp_dir); 1092 if (mali_gp_all_dir != NULL) 1093 { 1094 debugfs_create_file("counter_src0", 0400, mali_gp_all_dir, NULL, &gp_all_counter_src0_fops); 1095 debugfs_create_file("counter_src1", 0400, mali_gp_all_dir, NULL, &gp_all_counter_src1_fops); 1096 } 1097 1098 ci = 0; 1099 cluster = mali_cluster_get_global_cluster(ci); 1100 while (NULL != cluster) 1101 { 1102 u32 gi = 0; 1103 struct mali_group *group = mali_cluster_get_group(cluster, gi); 1104 while (NULL != group) 1105 { 1106 struct mali_gp_core *gp_core = mali_group_get_gp_core(group); 1107 if (NULL != gp_core) 1108 { 1109 struct dentry *mali_gp_gpx_dir; 1110 mali_gp_gpx_dir = debugfs_create_dir("gp0", mali_gp_dir); 1111 if (NULL != mali_gp_gpx_dir) 1112 { 1113 debugfs_create_file("counter_src0", 0600, mali_gp_gpx_dir, gp_core, &gp_gpx_counter_src0_fops); 1114 debugfs_create_file("counter_src1", 0600, mali_gp_gpx_dir, gp_core, &gp_gpx_counter_src1_fops); 1115 } 1116 break; /* no need to look for any other GP cores */ 1117 } 1118 1119 /* try next group */ 1120 gi++; 1121 group = mali_cluster_get_group(cluster, gi); 1122 } 1123 1124 /* try next cluster */ 1125 ci++; 1126 cluster = mali_cluster_get_global_cluster(ci); 1127 } 1128 } 1129 1130 mali_pp_dir = debugfs_create_dir("pp", mali_debugfs_dir); 1131 if (mali_pp_dir != NULL) 1132 { 1133 struct dentry *mali_pp_all_dir; 1134 u32 ci; 1135 struct mali_cluster *cluster; 1136 1137 mali_pp_all_dir = debugfs_create_dir("all", mali_pp_dir); 1138 if (mali_pp_all_dir != NULL) 1139 { 1140 debugfs_create_file("counter_src0", 0400, mali_pp_all_dir, NULL, &pp_all_counter_src0_fops); 1141 debugfs_create_file("counter_src1", 0400, mali_pp_all_dir, NULL, &pp_all_counter_src1_fops); 1142 } 1143 1144 ci = 0; 1145 cluster = mali_cluster_get_global_cluster(ci); 1146 while (NULL != cluster) 1147 { 1148 u32 gi = 0; 1149 struct mali_group *group = mali_cluster_get_group(cluster, gi); 1150 while (NULL != group) 1151 { 1152 struct mali_pp_core *pp_core = mali_group_get_pp_core(group); 1153 if (NULL != pp_core) 1154 { 1155 char buf[16]; 1156 struct dentry *mali_pp_ppx_dir; 1157 _mali_osk_snprintf(buf, sizeof(buf), "pp%u", mali_pp_core_get_id(pp_core)); 1158 mali_pp_ppx_dir = debugfs_create_dir(buf, mali_pp_dir); 1159 if (NULL != mali_pp_ppx_dir) 1160 { 1161 debugfs_create_file("counter_src0", 0600, mali_pp_ppx_dir, pp_core, &pp_ppx_counter_src0_fops); 1162 debugfs_create_file("counter_src1", 0600, mali_pp_ppx_dir, pp_core, &pp_ppx_counter_src1_fops); 1163 } 1164 } 1165 1166 /* try next group */ 1167 gi++; 1168 group = mali_cluster_get_group(cluster, gi); 1169 } 1170 1171 /* try next cluster */ 1172 ci++; 1173 cluster = mali_cluster_get_global_cluster(ci); 1174 } 1175 } 1176 1177 mali_l2_dir = debugfs_create_dir("l2", mali_debugfs_dir); 1178 if (mali_l2_dir != NULL) 1179 { 1180 struct dentry *mali_l2_all_dir; 1181 u32 l2_id; 1182 struct mali_l2_cache_core *l2_cache; 1183 1184 mali_l2_all_dir = debugfs_create_dir("all", mali_l2_dir); 1185 if (mali_l2_all_dir != NULL) 1186 { 1187 debugfs_create_file("counter_src0", 0400, mali_l2_all_dir, NULL, &l2_all_counter_src0_fops); 1188 debugfs_create_file("counter_src1", 0400, mali_l2_all_dir, NULL, &l2_all_counter_src1_fops); 1189 } 1190 1191 l2_id = 0; 1192 l2_cache = mali_l2_cache_core_get_glob_l2_core(l2_id); 1193 while (NULL != l2_cache) 1194 { 1195 char buf[16]; 1196 struct dentry *mali_l2_l2x_dir; 1197 _mali_osk_snprintf(buf, sizeof(buf), "l2%u", l2_id); 1198 mali_l2_l2x_dir = debugfs_create_dir(buf, mali_l2_dir); 1199 if (NULL != mali_l2_l2x_dir) 1200 { 1201 debugfs_create_file("counter_src0", 0600, mali_l2_l2x_dir, l2_cache, &l2_l2x_counter_src0_fops); 1202 debugfs_create_file("counter_src1", 0600, mali_l2_l2x_dir, l2_cache, &l2_l2x_counter_src1_fops); 1203 } 1204 1205 /* try next L2 */ 1206 l2_id++; 1207 l2_cache = mali_l2_cache_core_get_glob_l2_core(l2_id); 1208 } 1209 } 1210 1211 debugfs_create_file("memory_usage", 0400, mali_debugfs_dir, NULL, &memory_usage_fops); 1212 1213#if MALI_INTERNAL_TIMELINE_PROFILING_ENABLED 1214 mali_profiling_dir = debugfs_create_dir("profiling", mali_debugfs_dir); 1215 if (mali_profiling_dir != NULL) 1216 { 1217 struct dentry *mali_profiling_proc_dir = debugfs_create_dir("proc", mali_profiling_dir); 1218 if (mali_profiling_proc_dir != NULL) 1219 { 1220 struct dentry *mali_profiling_proc_default_dir = debugfs_create_dir("default", mali_profiling_proc_dir); 1221 if (mali_profiling_proc_default_dir != NULL) 1222 { 1223 debugfs_create_file("enable", 0600, mali_profiling_proc_default_dir, (void*)_MALI_UK_USER_SETTING_SW_EVENTS_ENABLE, &user_settings_fops); 1224 } 1225 } 1226 debugfs_create_file("record", 0600, mali_profiling_dir, NULL, &profiling_record_fops); 1227 debugfs_create_file("events", 0400, mali_profiling_dir, NULL, &profiling_events_fops); 1228 } 1229#endif 1230 1231#if MALI_STATE_TRACKING 1232 debugfs_create_file("state_dump", 0400, mali_debugfs_dir, NULL, &mali_seq_internal_state_fops); 1233#endif 1234 1235 if (mali_sysfs_user_settings_register()) 1236 { 1237 /* Failed to create the debugfs entries for the user settings DB. */ 1238 MALI_DEBUG_PRINT(2, ("Failed to create user setting debugfs files. Ignoring...\n")); 1239 } 1240 } 1241 } 1242 1243 /* Success! */ 1244 return 0; 1245 1246 /* Error handling */ 1247init_mdev_err: 1248 class_destroy(device->mali_class); 1249init_class_err: 1250 1251 return err; 1252} 1253 1254int mali_sysfs_unregister(struct mali_dev *device, dev_t dev, const char *mali_dev_name) 1255{ 1256 if(NULL != mali_debugfs_dir) 1257 { 1258 debugfs_remove_recursive(mali_debugfs_dir); 1259 } 1260 device_destroy(device->mali_class, dev); 1261 class_destroy(device->mali_class); 1262 1263 return 0; 1264} 1265 1266#else 1267 1268/* Dummy implementations for non-GPL */ 1269 1270int mali_sysfs_register(struct mali_dev *device, dev_t dev, const char *mali_dev_name) 1271{ 1272 return 0; 1273} 1274 1275int mali_sysfs_unregister(struct mali_dev *device, dev_t dev, const char *mali_dev_name) 1276{ 1277 return 0; 1278} 1279 1280 1281#endif