/* * Copyright © 2012 Intel Corporation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * Authors: * Ben Widawsky * */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include "intel_chipset.h" #include "intel_gpu_tools.h" #include "drmtest.h" #define NUM_BANKS 4 #define NUM_SUBBANKS 8 #define NUM_REGS (NUM_BANKS * NUM_SUBBANKS) struct __attribute__ ((__packed__)) l3_log_register { uint32_t row0_enable : 1; uint32_t rsvd2 : 4; uint32_t row0 : 11; uint32_t row1_enable : 1; uint32_t rsvd1 : 4; uint32_t row1 : 11; } l3log[NUM_BANKS][NUM_SUBBANKS]; static void dumpit(void) { int i, j; for (i = 0; i < NUM_BANKS; i++) { for (j = 0; j < NUM_SUBBANKS; j++) { struct l3_log_register *reg = &l3log[i][j]; if (reg->row0_enable) printf("Row %d, Bank %d, Subbank %d is disabled\n", reg->row0, i, j); if (reg->row1_enable) printf("Row %d, Bank %d, Subbank %d is disabled\n", reg->row1, i, j); } } } static int disable_rbs(int row, int bank, int sbank) { struct l3_log_register *reg = &l3log[bank][sbank]; // can't map more than 2 rows if (reg->row0_enable && reg->row1_enable) return -1; // can't remap the same row twice if ((reg->row0_enable && reg->row0 == row) || (reg->row1_enable && reg->row1 == row)) { return -1; } if (reg->row0_enable) { reg->row1 = row; reg->row1_enable = 1; } else { reg->row0 = row; reg->row0_enable = 1; } return 0; } static int do_parse(int argc, char *argv[]) { int row, bank, sbank, i, ret; for (i = 1; i < argc; i++) { ret = sscanf(argv[i], "%d,%d,%d", &row, &bank, &sbank); if (ret != 3) return i; assert(disable_rbs(row, bank, sbank) == 0); } return 0; } int main(int argc, char *argv[]) { const int device = drm_get_card(0); char *path; unsigned int devid; int drm_fd, fd, ret; drm_fd = drm_open_any(); devid = intel_get_drm_devid(drm_fd); ret = asprintf(&path, "/sys/class/drm/card%d/l3_parity", device); assert(ret != -1); fd = open(path, O_RDWR); if (fd == -1 && IS_IVYBRIDGE(devid)) { perror("Opening sysfs"); exit(EXIT_FAILURE); } else if (fd == -1) exit(EXIT_SUCCESS); ret = read(fd, l3log, NUM_REGS * sizeof(uint32_t)); if (ret == -1) { perror("Reading sysfs"); exit(EXIT_FAILURE); } assert(lseek(fd, 0, SEEK_SET) == 0); if (argc == 1) { dumpit(); exit(EXIT_SUCCESS); } else if (!strncmp("-c", argv[1], 2)) { memset(l3log, 0, sizeof(l3log)); } else { ret = do_parse(argc, argv); if (ret != 0) { fprintf(stderr, "Malformed command line at %s\n", argv[ret]); exit(EXIT_FAILURE); } } ret = write(fd, l3log, NUM_REGS * sizeof(uint32_t)); if (ret == -1) { perror("Writing sysfs"); exit(EXIT_FAILURE); } close(fd); exit(EXIT_SUCCESS); }