Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'linux-4.7' of git://github.com/skeggsb/linux into drm-fixes

Fixes for two issues reported by KASAN, a display engine hang due to
incorrect BIOS table parsing, and incorrect LTC interrupt handling on
Maxwell which could lead to a never-ending interrupt storm.

* 'linux-4.7' of git://github.com/skeggsb/linux:
drm/nouveau/disp/sor/gm107: training pattern registers are like gm200
drm/nouveau/disp/sor/gf119: both links use the same training register
drm/nouveau/core: swap the order of imem/fb
drm/nouveau/fbcon: fix out-of-bounds memory accesses
drm/nouveau/gr/gf100-: update sm error decoding from gk20a nvgpu headers
drm/nouveau/ltc/gm107-: fix typo in the address of NV_PLTCG_LTC0_LTS0_INTR
drm/nouveau/bios/disp: fix handling of "match any protocol" entries

+122 -68
+1 -1
drivers/gpu/drm/nouveau/include/nvkm/core/device.h
··· 16 16 NVKM_SUBDEV_MC, 17 17 NVKM_SUBDEV_BUS, 18 18 NVKM_SUBDEV_TIMER, 19 + NVKM_SUBDEV_INSTMEM, 19 20 NVKM_SUBDEV_FB, 20 21 NVKM_SUBDEV_LTC, 21 - NVKM_SUBDEV_INSTMEM, 22 22 NVKM_SUBDEV_MMU, 23 23 NVKM_SUBDEV_BAR, 24 24 NVKM_SUBDEV_PMU,
+3 -2
drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/disp.h
··· 25 25 u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_outp *); 26 26 27 27 struct nvbios_ocfg { 28 - u16 match; 28 + u8 proto; 29 + u8 flags; 29 30 u16 clkcmp[2]; 30 31 }; 31 32 ··· 34 33 u8 *ver, u8 *hdr, u8 *cnt, u8 *len); 35 34 u16 nvbios_ocfg_parse(struct nvkm_bios *, u16 outp, u8 idx, 36 35 u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_ocfg *); 37 - u16 nvbios_ocfg_match(struct nvkm_bios *, u16 outp, u16 type, 36 + u16 nvbios_ocfg_match(struct nvkm_bios *, u16 outp, u8 proto, u8 flags, 38 37 u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_ocfg *); 39 38 u16 nvbios_oclk_match(struct nvkm_bios *, u16 cmp, u32 khz); 40 39 #endif
+1
drivers/gpu/drm/nouveau/nouveau_fbcon.c
··· 552 552 if (ret) 553 553 goto fini; 554 554 555 + fbcon->helper.fbdev->pixmap.buf_align = 4; 555 556 return 0; 556 557 557 558 fini:
+2 -5
drivers/gpu/drm/nouveau/nv04_fbcon.c
··· 82 82 uint32_t fg; 83 83 uint32_t bg; 84 84 uint32_t dsize; 85 - uint32_t width; 86 85 uint32_t *data = (uint32_t *)image->data; 87 86 int ret; 88 87 ··· 91 92 ret = RING_SPACE(chan, 8); 92 93 if (ret) 93 94 return ret; 94 - 95 - width = ALIGN(image->width, 8); 96 - dsize = ALIGN(width * image->height, 32) >> 5; 97 95 98 96 if (info->fix.visual == FB_VISUAL_TRUECOLOR || 99 97 info->fix.visual == FB_VISUAL_DIRECTCOLOR) { ··· 107 111 ((image->dx + image->width) & 0xffff)); 108 112 OUT_RING(chan, bg); 109 113 OUT_RING(chan, fg); 110 - OUT_RING(chan, (image->height << 16) | width); 114 + OUT_RING(chan, (image->height << 16) | image->width); 111 115 OUT_RING(chan, (image->height << 16) | image->width); 112 116 OUT_RING(chan, (image->dy << 16) | (image->dx & 0xffff)); 113 117 118 + dsize = ALIGN(image->width * image->height, 32) >> 5; 114 119 while (dsize) { 115 120 int iter_len = dsize > 128 ? 128 : dsize; 116 121
+2 -4
drivers/gpu/drm/nouveau/nv50_fbcon.c
··· 95 95 struct nouveau_fbdev *nfbdev = info->par; 96 96 struct nouveau_drm *drm = nouveau_drm(nfbdev->dev); 97 97 struct nouveau_channel *chan = drm->channel; 98 - uint32_t width, dwords, *data = (uint32_t *)image->data; 98 + uint32_t dwords, *data = (uint32_t *)image->data; 99 99 uint32_t mask = ~(~0 >> (32 - info->var.bits_per_pixel)); 100 100 uint32_t *palette = info->pseudo_palette; 101 101 int ret; ··· 106 106 ret = RING_SPACE(chan, 11); 107 107 if (ret) 108 108 return ret; 109 - 110 - width = ALIGN(image->width, 32); 111 - dwords = (width * image->height) >> 5; 112 109 113 110 BEGIN_NV04(chan, NvSub2D, 0x0814, 2); 114 111 if (info->fix.visual == FB_VISUAL_TRUECOLOR || ··· 125 128 OUT_RING(chan, 0); 126 129 OUT_RING(chan, image->dy); 127 130 131 + dwords = ALIGN(image->width * image->height, 32) >> 5; 128 132 while (dwords) { 129 133 int push = dwords > 2047 ? 2047 : dwords; 130 134
+2 -4
drivers/gpu/drm/nouveau/nvc0_fbcon.c
··· 95 95 struct nouveau_fbdev *nfbdev = info->par; 96 96 struct nouveau_drm *drm = nouveau_drm(nfbdev->dev); 97 97 struct nouveau_channel *chan = drm->channel; 98 - uint32_t width, dwords, *data = (uint32_t *)image->data; 98 + uint32_t dwords, *data = (uint32_t *)image->data; 99 99 uint32_t mask = ~(~0 >> (32 - info->var.bits_per_pixel)); 100 100 uint32_t *palette = info->pseudo_palette; 101 101 int ret; ··· 106 106 ret = RING_SPACE(chan, 11); 107 107 if (ret) 108 108 return ret; 109 - 110 - width = ALIGN(image->width, 32); 111 - dwords = (width * image->height) >> 5; 112 109 113 110 BEGIN_NVC0(chan, NvSub2D, 0x0814, 2); 114 111 if (info->fix.visual == FB_VISUAL_TRUECOLOR || ··· 125 128 OUT_RING (chan, 0); 126 129 OUT_RING (chan, image->dy); 127 130 131 + dwords = ALIGN(image->width * image->height, 32) >> 5; 128 132 while (dwords) { 129 133 int push = dwords > 2047 ? 2047 : dwords; 130 134
+1
drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild
··· 18 18 nvkm-y += nvkm/engine/disp/sornv50.o 19 19 nvkm-y += nvkm/engine/disp/sorg94.o 20 20 nvkm-y += nvkm/engine/disp/sorgf119.o 21 + nvkm-y += nvkm/engine/disp/sorgm107.o 21 22 nvkm-y += nvkm/engine/disp/sorgm200.o 22 23 nvkm-y += nvkm/engine/disp/dport.o 23 24
+5 -8
drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c
··· 76 76 mask |= 0x0001 << or; 77 77 mask |= 0x0100 << head; 78 78 79 + 79 80 list_for_each_entry(outp, &disp->base.outp, head) { 80 81 if ((outp->info.hasht & 0xff) == type && 81 82 (outp->info.hashm & mask) == mask) { ··· 156 155 if (!outp) 157 156 return NULL; 158 157 158 + *conf = (ctrl & 0x00000f00) >> 8; 159 159 switch (outp->info.type) { 160 160 case DCB_OUTPUT_TMDS: 161 - *conf = (ctrl & 0x00000f00) >> 8; 162 161 if (*conf == 5) 163 162 *conf |= 0x0100; 164 163 break; 165 164 case DCB_OUTPUT_LVDS: 166 - *conf = disp->sor.lvdsconf; 165 + *conf |= disp->sor.lvdsconf; 167 166 break; 168 - case DCB_OUTPUT_DP: 169 - *conf = (ctrl & 0x00000f00) >> 8; 170 - break; 171 - case DCB_OUTPUT_ANALOG: 172 167 default: 173 - *conf = 0x00ff; 174 168 break; 175 169 } 176 170 177 - data = nvbios_ocfg_match(bios, data, *conf, &ver, &hdr, &cnt, &len, &info2); 171 + data = nvbios_ocfg_match(bios, data, *conf & 0xff, *conf >> 8, 172 + &ver, &hdr, &cnt, &len, &info2); 178 173 if (data && id < 0xff) { 179 174 data = nvbios_oclk_match(bios, info2.clkcmp[id], pclk); 180 175 if (data) {
+1 -1
drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c
··· 36 36 .outp.internal.crt = nv50_dac_output_new, 37 37 .outp.internal.tmds = nv50_sor_output_new, 38 38 .outp.internal.lvds = nv50_sor_output_new, 39 - .outp.internal.dp = gf119_sor_dp_new, 39 + .outp.internal.dp = gm107_sor_dp_new, 40 40 .dac.nr = 3, 41 41 .dac.power = nv50_dac_power, 42 42 .dac.sense = nv50_dac_sense,
+4 -8
drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c
··· 387 387 if (!outp) 388 388 return NULL; 389 389 390 + *conf = (ctrl & 0x00000f00) >> 8; 390 391 if (outp->info.location == 0) { 391 392 switch (outp->info.type) { 392 393 case DCB_OUTPUT_TMDS: 393 - *conf = (ctrl & 0x00000f00) >> 8; 394 394 if (*conf == 5) 395 395 *conf |= 0x0100; 396 396 break; 397 397 case DCB_OUTPUT_LVDS: 398 - *conf = disp->sor.lvdsconf; 398 + *conf |= disp->sor.lvdsconf; 399 399 break; 400 - case DCB_OUTPUT_DP: 401 - *conf = (ctrl & 0x00000f00) >> 8; 402 - break; 403 - case DCB_OUTPUT_ANALOG: 404 400 default: 405 - *conf = 0x00ff; 406 401 break; 407 402 } 408 403 } else { ··· 405 410 pclk = pclk / 2; 406 411 } 407 412 408 - data = nvbios_ocfg_match(bios, data, *conf, &ver, &hdr, &cnt, &len, &info2); 413 + data = nvbios_ocfg_match(bios, data, *conf & 0xff, *conf >> 8, 414 + &ver, &hdr, &cnt, &len, &info2); 409 415 if (data && id < 0xff) { 410 416 data = nvbios_oclk_match(bios, info2.clkcmp[id], pclk); 411 417 if (data) {
+7 -2
drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.h
··· 62 62 int gf119_sor_dp_new(struct nvkm_disp *, int, struct dcb_output *, 63 63 struct nvkm_output **); 64 64 int gf119_sor_dp_lnk_ctl(struct nvkm_output_dp *, int, int, bool); 65 + int gf119_sor_dp_drv_ctl(struct nvkm_output_dp *, int, int, int, int); 65 66 66 - int gm200_sor_dp_new(struct nvkm_disp *, int, struct dcb_output *, 67 - struct nvkm_output **); 67 + int gm107_sor_dp_new(struct nvkm_disp *, int, struct dcb_output *, 68 + struct nvkm_output **); 69 + int gm107_sor_dp_pattern(struct nvkm_output_dp *, int); 70 + 71 + int gm200_sor_dp_new(struct nvkm_disp *, int, struct dcb_output *, 72 + struct nvkm_output **); 68 73 #endif
+2 -3
drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c
··· 40 40 gf119_sor_dp_pattern(struct nvkm_output_dp *outp, int pattern) 41 41 { 42 42 struct nvkm_device *device = outp->base.disp->engine.subdev.device; 43 - const u32 loff = gf119_sor_loff(outp); 44 - nvkm_mask(device, 0x61c110 + loff, 0x0f0f0f0f, 0x01010101 * pattern); 43 + nvkm_mask(device, 0x61c110, 0x0f0f0f0f, 0x01010101 * pattern); 45 44 return 0; 46 45 } 47 46 ··· 63 64 return 0; 64 65 } 65 66 66 - static int 67 + int 67 68 gf119_sor_dp_drv_ctl(struct nvkm_output_dp *outp, 68 69 int ln, int vs, int pe, int pc) 69 70 {
+53
drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c
··· 1 + /* 2 + * Copyright 2016 Red Hat Inc. 3 + * 4 + * Permission is hereby granted, free of charge, to any person obtaining a 5 + * copy of this software and associated documentation files (the "Software"), 6 + * to deal in the Software without restriction, including without limitation 7 + * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 + * and/or sell copies of the Software, and to permit persons to whom the 9 + * Software is furnished to do so, subject to the following conditions: 10 + * 11 + * The above copyright notice and this permission notice shall be included in 12 + * all copies or substantial portions of the Software. 13 + * 14 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 18 + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19 + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20 + * OTHER DEALINGS IN THE SOFTWARE. 21 + * 22 + * Authors: Ben Skeggs <bskeggs@redhat.com> 23 + */ 24 + #include "nv50.h" 25 + #include "outpdp.h" 26 + 27 + int 28 + gm107_sor_dp_pattern(struct nvkm_output_dp *outp, int pattern) 29 + { 30 + struct nvkm_device *device = outp->base.disp->engine.subdev.device; 31 + const u32 soff = outp->base.or * 0x800; 32 + const u32 data = 0x01010101 * pattern; 33 + if (outp->base.info.sorconf.link & 1) 34 + nvkm_mask(device, 0x61c110 + soff, 0x0f0f0f0f, data); 35 + else 36 + nvkm_mask(device, 0x61c12c + soff, 0x0f0f0f0f, data); 37 + return 0; 38 + } 39 + 40 + static const struct nvkm_output_dp_func 41 + gm107_sor_dp_func = { 42 + .pattern = gm107_sor_dp_pattern, 43 + .lnk_pwr = g94_sor_dp_lnk_pwr, 44 + .lnk_ctl = gf119_sor_dp_lnk_ctl, 45 + .drv_ctl = gf119_sor_dp_drv_ctl, 46 + }; 47 + 48 + int 49 + gm107_sor_dp_new(struct nvkm_disp *disp, int index, 50 + struct dcb_output *dcbE, struct nvkm_output **poutp) 51 + { 52 + return nvkm_output_dp_new_(&gm107_sor_dp_func, disp, index, dcbE, poutp); 53 + }
+1 -14
drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c
··· 57 57 } 58 58 59 59 static int 60 - gm200_sor_dp_pattern(struct nvkm_output_dp *outp, int pattern) 61 - { 62 - struct nvkm_device *device = outp->base.disp->engine.subdev.device; 63 - const u32 soff = gm200_sor_soff(outp); 64 - const u32 data = 0x01010101 * pattern; 65 - if (outp->base.info.sorconf.link & 1) 66 - nvkm_mask(device, 0x61c110 + soff, 0x0f0f0f0f, data); 67 - else 68 - nvkm_mask(device, 0x61c12c + soff, 0x0f0f0f0f, data); 69 - return 0; 70 - } 71 - 72 - static int 73 60 gm200_sor_dp_lnk_pwr(struct nvkm_output_dp *outp, int nr) 74 61 { 75 62 struct nvkm_device *device = outp->base.disp->engine.subdev.device; ··· 116 129 117 130 static const struct nvkm_output_dp_func 118 131 gm200_sor_dp_func = { 119 - .pattern = gm200_sor_dp_pattern, 132 + .pattern = gm107_sor_dp_pattern, 120 133 .lnk_pwr = gm200_sor_dp_lnk_pwr, 121 134 .lnk_ctl = gf119_sor_dp_lnk_ctl, 122 135 .drv_ctl = gm200_sor_dp_drv_ctl,
+28 -9
drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c
··· 949 949 } 950 950 951 951 static const struct nvkm_enum gf100_mp_warp_error[] = { 952 - { 0x00, "NO_ERROR" }, 953 - { 0x01, "STACK_MISMATCH" }, 952 + { 0x01, "STACK_ERROR" }, 953 + { 0x02, "API_STACK_ERROR" }, 954 + { 0x03, "RET_EMPTY_STACK_ERROR" }, 955 + { 0x04, "PC_WRAP" }, 954 956 { 0x05, "MISALIGNED_PC" }, 955 - { 0x08, "MISALIGNED_GPR" }, 956 - { 0x09, "INVALID_OPCODE" }, 957 - { 0x0d, "GPR_OUT_OF_BOUNDS" }, 958 - { 0x0e, "MEM_OUT_OF_BOUNDS" }, 959 - { 0x0f, "UNALIGNED_MEM_ACCESS" }, 957 + { 0x06, "PC_OVERFLOW" }, 958 + { 0x07, "MISALIGNED_IMMC_ADDR" }, 959 + { 0x08, "MISALIGNED_REG" }, 960 + { 0x09, "ILLEGAL_INSTR_ENCODING" }, 961 + { 0x0a, "ILLEGAL_SPH_INSTR_COMBO" }, 962 + { 0x0b, "ILLEGAL_INSTR_PARAM" }, 963 + { 0x0c, "INVALID_CONST_ADDR" }, 964 + { 0x0d, "OOR_REG" }, 965 + { 0x0e, "OOR_ADDR" }, 966 + { 0x0f, "MISALIGNED_ADDR" }, 960 967 { 0x10, "INVALID_ADDR_SPACE" }, 961 - { 0x11, "INVALID_PARAM" }, 968 + { 0x11, "ILLEGAL_INSTR_PARAM2" }, 969 + { 0x12, "INVALID_CONST_ADDR_LDC" }, 970 + { 0x13, "GEOMETRY_SM_ERROR" }, 971 + { 0x14, "DIVERGENT" }, 972 + { 0x15, "WARP_EXIT" }, 962 973 {} 963 974 }; 964 975 965 976 static const struct nvkm_bitfield gf100_mp_global_error[] = { 977 + { 0x00000001, "SM_TO_SM_FAULT" }, 978 + { 0x00000002, "L1_ERROR" }, 966 979 { 0x00000004, "MULTIPLE_WARP_ERRORS" }, 967 - { 0x00000008, "OUT_OF_STACK_SPACE" }, 980 + { 0x00000008, "PHYSICAL_STACK_OVERFLOW" }, 981 + { 0x00000010, "BPT_INT" }, 982 + { 0x00000020, "BPT_PAUSE" }, 983 + { 0x00000040, "SINGLE_STEP_COMPLETE" }, 984 + { 0x20000000, "ECC_SEC_ERROR" }, 985 + { 0x40000000, "ECC_DED_ERROR" }, 986 + { 0x80000000, "TIMEOUT" }, 968 987 {} 969 988 }; 970 989
+5 -3
drivers/gpu/drm/nouveau/nvkm/subdev/bios/disp.c
··· 141 141 { 142 142 u16 data = nvbios_ocfg_entry(bios, outp, idx, ver, hdr, cnt, len); 143 143 if (data) { 144 - info->match = nvbios_rd16(bios, data + 0x00); 144 + info->proto = nvbios_rd08(bios, data + 0x00); 145 + info->flags = nvbios_rd16(bios, data + 0x01); 145 146 info->clkcmp[0] = nvbios_rd16(bios, data + 0x02); 146 147 info->clkcmp[1] = nvbios_rd16(bios, data + 0x04); 147 148 } ··· 150 149 } 151 150 152 151 u16 153 - nvbios_ocfg_match(struct nvkm_bios *bios, u16 outp, u16 type, 152 + nvbios_ocfg_match(struct nvkm_bios *bios, u16 outp, u8 proto, u8 flags, 154 153 u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_ocfg *info) 155 154 { 156 155 u16 data, idx = 0; 157 156 while ((data = nvbios_ocfg_parse(bios, outp, idx++, ver, hdr, cnt, len, info))) { 158 - if (info->match == type) 157 + if ((info->proto == proto || info->proto == 0xff) && 158 + (info->flags == flags)) 159 159 break; 160 160 } 161 161 return data;
+3 -3
drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gm107.c
··· 69 69 } 70 70 71 71 static void 72 - gm107_ltc_lts_isr(struct nvkm_ltc *ltc, int c, int s) 72 + gm107_ltc_intr_lts(struct nvkm_ltc *ltc, int c, int s) 73 73 { 74 74 struct nvkm_subdev *subdev = &ltc->subdev; 75 75 struct nvkm_device *device = subdev->device; 76 - u32 base = 0x140000 + (c * 0x2000) + (s * 0x200); 76 + u32 base = 0x140400 + (c * 0x2000) + (s * 0x200); 77 77 u32 stat = nvkm_rd32(device, base + 0x00c); 78 78 79 79 if (stat) { ··· 92 92 while (mask) { 93 93 u32 s, c = __ffs(mask); 94 94 for (s = 0; s < ltc->lts_nr; s++) 95 - gm107_ltc_lts_isr(ltc, c, s); 95 + gm107_ltc_intr_lts(ltc, c, s); 96 96 mask &= ~(1 << c); 97 97 } 98 98 }
+1 -1
drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gm200.c
··· 46 46 gm200_ltc = { 47 47 .oneinit = gm200_ltc_oneinit, 48 48 .init = gm200_ltc_init, 49 - .intr = gm107_ltc_intr, /*XXX: not validated */ 49 + .intr = gm107_ltc_intr, 50 50 .cbc_clear = gm107_ltc_cbc_clear, 51 51 .cbc_wait = gm107_ltc_cbc_wait, 52 52 .zbc = 16,