]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blame - releases/4.4.181/fbdev-sm712fb-fix-crashes-during-framebuffer-writes-by-correctly-mapping-vram.patch
Linux 4.4.181
[thirdparty/kernel/stable-queue.git] / releases / 4.4.181 / fbdev-sm712fb-fix-crashes-during-framebuffer-writes-by-correctly-mapping-vram.patch
CommitLineData
53722911
GKH
1From 9e0e59993df0601cddb95c4f6c61aa3d5e753c00 Mon Sep 17 00:00:00 2001
2From: Yifeng Li <tomli@tomli.me>
3Date: Mon, 1 Apr 2019 17:46:59 +0200
4Subject: fbdev: sm712fb: fix crashes during framebuffer writes by correctly mapping VRAM
5
6From: Yifeng Li <tomli@tomli.me>
7
8commit 9e0e59993df0601cddb95c4f6c61aa3d5e753c00 upstream.
9
10On a Thinkpad s30 (Pentium III / i440MX, Lynx3DM), running fbtest or X
11will crash the machine instantly, because the VRAM/framebuffer is not
12mapped correctly.
13
14On SM712, the framebuffer starts at the beginning of address space, but
15SM720's framebuffer starts at the 1 MiB offset from the beginning. However,
16sm712fb fails to take this into account, as a result, writing to the
17framebuffer will destroy all the registers and kill the system immediately.
18Another problem is the driver assumes 8 MiB of VRAM for SM720, but some
19SM720 system, such as this IBM Thinkpad, only has 4 MiB of VRAM.
20
21Fix this problem by removing the hardcoded VRAM size, adding a function to
22query the amount of VRAM from register MCR76 on SM720, and adding proper
23framebuffer offset.
24
25Please note that the memory map may have additional problems on Big-Endian
26system, which is not available for testing by myself. But I highly suspect
27that the original code is also broken on Big-Endian machines for SM720, so
28at least we are not making the problem worse. More, the driver also assumed
29SM710/SM712 has 4 MiB of VRAM, but it has a 2 MiB version as well, and used
30in earlier laptops, such as IBM Thinkpad 240X, the driver would probably
31crash on them. I've never seen one of those machines and cannot fix it, but
32I have documented these problems in the comments.
33
34Signed-off-by: Yifeng Li <tomli@tomli.me>
35Tested-by: Sudip Mukherjee <sudipm.mukherjee@gmail.com>
36Cc: Teddy Wang <teddy.wang@siliconmotion.com>
37Cc: <stable@vger.kernel.org> # v4.4+
38Signed-off-by: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
39Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
40
41---
42 drivers/video/fbdev/sm712.h | 5 ----
43 drivers/video/fbdev/sm712fb.c | 48 ++++++++++++++++++++++++++++++++++++++----
44 2 files changed, 44 insertions(+), 9 deletions(-)
45
46--- a/drivers/video/fbdev/sm712.h
47+++ b/drivers/video/fbdev/sm712.h
48@@ -19,11 +19,6 @@
49 #define SCREEN_Y_RES 600
50 #define SCREEN_BPP 16
51
52-/*Assume SM712 graphics chip has 4MB VRAM */
53-#define SM712_VIDEOMEMORYSIZE 0x00400000
54-/*Assume SM722 graphics chip has 8MB VRAM */
55-#define SM722_VIDEOMEMORYSIZE 0x00800000
56-
57 #define dac_reg (0x3c8)
58 #define dac_val (0x3c9)
59
60--- a/drivers/video/fbdev/sm712fb.c
61+++ b/drivers/video/fbdev/sm712fb.c
62@@ -1328,6 +1328,11 @@ static int smtc_map_smem(struct smtcfb_i
63 {
64 sfb->fb->fix.smem_start = pci_resource_start(pdev, 0);
65
66+ if (sfb->chip_id == 0x720)
67+ /* on SM720, the framebuffer starts at the 1 MB offset */
68+ sfb->fb->fix.smem_start += 0x00200000;
69+
70+ /* XXX: is it safe for SM720 on Big-Endian? */
71 if (sfb->fb->var.bits_per_pixel == 32)
72 sfb->fb->fix.smem_start += big_addr;
73
74@@ -1365,12 +1370,45 @@ static inline void sm7xx_init_hw(void)
75 outb_p(0x11, 0x3c5);
76 }
77
78+static u_long sm7xx_vram_probe(struct smtcfb_info *sfb)
79+{
80+ u8 vram;
81+
82+ switch (sfb->chip_id) {
83+ case 0x710:
84+ case 0x712:
85+ /*
86+ * Assume SM712 graphics chip has 4MB VRAM.
87+ *
88+ * FIXME: SM712 can have 2MB VRAM, which is used on earlier
89+ * laptops, such as IBM Thinkpad 240X. This driver would
90+ * probably crash on those machines. If anyone gets one of
91+ * those and is willing to help, run "git blame" and send me
92+ * an E-mail.
93+ */
94+ return 0x00400000;
95+ case 0x720:
96+ outb_p(0x76, 0x3c4);
97+ vram = inb_p(0x3c5) >> 6;
98+
99+ if (vram == 0x00)
100+ return 0x00800000; /* 8 MB */
101+ else if (vram == 0x01)
102+ return 0x01000000; /* 16 MB */
103+ else if (vram == 0x02)
104+ return 0x00400000; /* illegal, fallback to 4 MB */
105+ else if (vram == 0x03)
106+ return 0x00400000; /* 4 MB */
107+ }
108+ return 0; /* unknown hardware */
109+}
110+
111 static int smtcfb_pci_probe(struct pci_dev *pdev,
112 const struct pci_device_id *ent)
113 {
114 struct smtcfb_info *sfb;
115 struct fb_info *info;
116- u_long smem_size = 0x00800000; /* default 8MB */
117+ u_long smem_size;
118 int err;
119 unsigned long mmio_base;
120
121@@ -1427,12 +1465,15 @@ static int smtcfb_pci_probe(struct pci_d
122 mmio_base = pci_resource_start(pdev, 0);
123 pci_read_config_byte(pdev, PCI_REVISION_ID, &sfb->chip_rev_id);
124
125+ smem_size = sm7xx_vram_probe(sfb);
126+ dev_info(&pdev->dev, "%lu MiB of VRAM detected.\n",
127+ smem_size / 1048576);
128+
129 switch (sfb->chip_id) {
130 case 0x710:
131 case 0x712:
132 sfb->fb->fix.mmio_start = mmio_base + 0x00400000;
133 sfb->fb->fix.mmio_len = 0x00400000;
134- smem_size = SM712_VIDEOMEMORYSIZE;
135 sfb->lfb = ioremap(mmio_base, mmio_addr);
136 if (!sfb->lfb) {
137 dev_err(&pdev->dev,
138@@ -1464,8 +1505,7 @@ static int smtcfb_pci_probe(struct pci_d
139 case 0x720:
140 sfb->fb->fix.mmio_start = mmio_base;
141 sfb->fb->fix.mmio_len = 0x00200000;
142- smem_size = SM722_VIDEOMEMORYSIZE;
143- sfb->dp_regs = ioremap(mmio_base, 0x00a00000);
144+ sfb->dp_regs = ioremap(mmio_base, 0x00200000 + smem_size);
145 sfb->lfb = sfb->dp_regs + 0x00200000;
146 sfb->mmio = (smtc_regbaseaddress =
147 sfb->dp_regs + 0x000c0000);