diff options
author | Dan Williams <dan.j.williams@intel.com> | 2017-05-05 02:38:43 -0400 |
---|---|---|
committer | Dan Williams <dan.j.williams@intel.com> | 2017-05-05 02:38:43 -0400 |
commit | 736163671bcb163fc82600b46c83dfa89d532d95 (patch) | |
tree | 0639dc9d9fa180450b4e8fbda706eaae5f1876da /drivers | |
parent | d5483feda85a8f39ee2e940e279547c686aac30c (diff) | |
parent | 1ef97fe4f8abd3317d5c3c860f990e02c2633959 (diff) |
Merge branch 'for-4.12/dax' into libnvdimm-for-next
Diffstat (limited to 'drivers')
69 files changed, 3880 insertions, 1439 deletions
diff --git a/drivers/Makefile b/drivers/Makefile index 2eced9afba53..0442e982cf35 100644 --- a/drivers/Makefile +++ b/drivers/Makefile | |||
@@ -71,7 +71,7 @@ obj-$(CONFIG_PARPORT) += parport/ | |||
71 | obj-$(CONFIG_NVM) += lightnvm/ | 71 | obj-$(CONFIG_NVM) += lightnvm/ |
72 | obj-y += base/ block/ misc/ mfd/ nfc/ | 72 | obj-y += base/ block/ misc/ mfd/ nfc/ |
73 | obj-$(CONFIG_LIBNVDIMM) += nvdimm/ | 73 | obj-$(CONFIG_LIBNVDIMM) += nvdimm/ |
74 | obj-$(CONFIG_DEV_DAX) += dax/ | 74 | obj-$(CONFIG_DAX) += dax/ |
75 | obj-$(CONFIG_DMA_SHARED_BUFFER) += dma-buf/ | 75 | obj-$(CONFIG_DMA_SHARED_BUFFER) += dma-buf/ |
76 | obj-$(CONFIG_NUBUS) += nubus/ | 76 | obj-$(CONFIG_NUBUS) += nubus/ |
77 | obj-y += macintosh/ | 77 | obj-y += macintosh/ |
diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c index 891bd49ada0b..656acb5d7166 100644 --- a/drivers/acpi/nfit/core.c +++ b/drivers/acpi/nfit/core.c | |||
@@ -1849,8 +1849,7 @@ static int acpi_nfit_blk_single_io(struct nfit_blk *nfit_blk, | |||
1849 | mmio_flush_range((void __force *) | 1849 | mmio_flush_range((void __force *) |
1850 | mmio->addr.aperture + offset, c); | 1850 | mmio->addr.aperture + offset, c); |
1851 | 1851 | ||
1852 | memcpy_from_pmem(iobuf + copied, | 1852 | memcpy(iobuf + copied, mmio->addr.aperture + offset, c); |
1853 | mmio->addr.aperture + offset, c); | ||
1854 | } | 1853 | } |
1855 | 1854 | ||
1856 | copied += c; | 1855 | copied += c; |
diff --git a/drivers/android/Kconfig b/drivers/android/Kconfig index a82fc022d34b..832e885349b1 100644 --- a/drivers/android/Kconfig +++ b/drivers/android/Kconfig | |||
@@ -22,7 +22,7 @@ config ANDROID_BINDER_IPC | |||
22 | config ANDROID_BINDER_DEVICES | 22 | config ANDROID_BINDER_DEVICES |
23 | string "Android Binder devices" | 23 | string "Android Binder devices" |
24 | depends on ANDROID_BINDER_IPC | 24 | depends on ANDROID_BINDER_IPC |
25 | default "binder" | 25 | default "binder,hwbinder" |
26 | ---help--- | 26 | ---help--- |
27 | Default value for the binder.devices parameter. | 27 | Default value for the binder.devices parameter. |
28 | 28 | ||
diff --git a/drivers/auxdisplay/Kconfig b/drivers/auxdisplay/Kconfig index 8a8e403644d6..c317dc515617 100644 --- a/drivers/auxdisplay/Kconfig +++ b/drivers/auxdisplay/Kconfig | |||
@@ -13,8 +13,22 @@ menuconfig AUXDISPLAY | |||
13 | 13 | ||
14 | If you say N, all options in this submenu will be skipped and disabled. | 14 | If you say N, all options in this submenu will be skipped and disabled. |
15 | 15 | ||
16 | config CHARLCD | ||
17 | tristate "Character LCD core support" if COMPILE_TEST | ||
18 | |||
16 | if AUXDISPLAY | 19 | if AUXDISPLAY |
17 | 20 | ||
21 | config HD44780 | ||
22 | tristate "HD44780 Character LCD support" | ||
23 | depends on GPIOLIB || COMPILE_TEST | ||
24 | select CHARLCD | ||
25 | ---help--- | ||
26 | Enable support for Character LCDs using a HD44780 controller. | ||
27 | The LCD is accessible through the /dev/lcd char device (10, 156). | ||
28 | This code can either be compiled as a module, or linked into the | ||
29 | kernel and started at boot. | ||
30 | If you don't understand what all this is about, say N. | ||
31 | |||
18 | config KS0108 | 32 | config KS0108 |
19 | tristate "KS0108 LCD Controller" | 33 | tristate "KS0108 LCD Controller" |
20 | depends on PARPORT_PC | 34 | depends on PARPORT_PC |
diff --git a/drivers/auxdisplay/Makefile b/drivers/auxdisplay/Makefile index cb3dd847713b..fcefa686be0f 100644 --- a/drivers/auxdisplay/Makefile +++ b/drivers/auxdisplay/Makefile | |||
@@ -2,7 +2,9 @@ | |||
2 | # Makefile for the kernel auxiliary displays device drivers. | 2 | # Makefile for the kernel auxiliary displays device drivers. |
3 | # | 3 | # |
4 | 4 | ||
5 | obj-$(CONFIG_CHARLCD) += charlcd.o | ||
5 | obj-$(CONFIG_KS0108) += ks0108.o | 6 | obj-$(CONFIG_KS0108) += ks0108.o |
6 | obj-$(CONFIG_CFAG12864B) += cfag12864b.o cfag12864bfb.o | 7 | obj-$(CONFIG_CFAG12864B) += cfag12864b.o cfag12864bfb.o |
7 | obj-$(CONFIG_IMG_ASCII_LCD) += img-ascii-lcd.o | 8 | obj-$(CONFIG_IMG_ASCII_LCD) += img-ascii-lcd.o |
9 | obj-$(CONFIG_HD44780) += hd44780.o | ||
8 | obj-$(CONFIG_HT16K33) += ht16k33.o | 10 | obj-$(CONFIG_HT16K33) += ht16k33.o |
diff --git a/drivers/auxdisplay/charlcd.c b/drivers/auxdisplay/charlcd.c new file mode 100644 index 000000000000..cfeb049a01ef --- /dev/null +++ b/drivers/auxdisplay/charlcd.c | |||
@@ -0,0 +1,818 @@ | |||
1 | /* | ||
2 | * Character LCD driver for Linux | ||
3 | * | ||
4 | * Copyright (C) 2000-2008, Willy Tarreau <w@1wt.eu> | ||
5 | * Copyright (C) 2016-2017 Glider bvba | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License | ||
9 | * as published by the Free Software Foundation; either version | ||
10 | * 2 of the License, or (at your option) any later version. | ||
11 | */ | ||
12 | |||
13 | #include <linux/atomic.h> | ||
14 | #include <linux/delay.h> | ||
15 | #include <linux/fs.h> | ||
16 | #include <linux/miscdevice.h> | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/notifier.h> | ||
19 | #include <linux/reboot.h> | ||
20 | #include <linux/slab.h> | ||
21 | #include <linux/uaccess.h> | ||
22 | #include <linux/workqueue.h> | ||
23 | |||
24 | #include <generated/utsrelease.h> | ||
25 | |||
26 | #include <misc/charlcd.h> | ||
27 | |||
28 | #define LCD_MINOR 156 | ||
29 | |||
30 | #define DEFAULT_LCD_BWIDTH 40 | ||
31 | #define DEFAULT_LCD_HWIDTH 64 | ||
32 | |||
33 | /* Keep the backlight on this many seconds for each flash */ | ||
34 | #define LCD_BL_TEMPO_PERIOD 4 | ||
35 | |||
36 | #define LCD_FLAG_B 0x0004 /* Blink on */ | ||
37 | #define LCD_FLAG_C 0x0008 /* Cursor on */ | ||
38 | #define LCD_FLAG_D 0x0010 /* Display on */ | ||
39 | #define LCD_FLAG_F 0x0020 /* Large font mode */ | ||
40 | #define LCD_FLAG_N 0x0040 /* 2-rows mode */ | ||
41 | #define LCD_FLAG_L 0x0080 /* Backlight enabled */ | ||
42 | |||
43 | /* LCD commands */ | ||
44 | #define LCD_CMD_DISPLAY_CLEAR 0x01 /* Clear entire display */ | ||
45 | |||
46 | #define LCD_CMD_ENTRY_MODE 0x04 /* Set entry mode */ | ||
47 | #define LCD_CMD_CURSOR_INC 0x02 /* Increment cursor */ | ||
48 | |||
49 | #define LCD_CMD_DISPLAY_CTRL 0x08 /* Display control */ | ||
50 | #define LCD_CMD_DISPLAY_ON 0x04 /* Set display on */ | ||
51 | #define LCD_CMD_CURSOR_ON 0x02 /* Set cursor on */ | ||
52 | #define LCD_CMD_BLINK_ON 0x01 /* Set blink on */ | ||
53 | |||
54 | #define LCD_CMD_SHIFT 0x10 /* Shift cursor/display */ | ||
55 | #define LCD_CMD_DISPLAY_SHIFT 0x08 /* Shift display instead of cursor */ | ||
56 | #define LCD_CMD_SHIFT_RIGHT 0x04 /* Shift display/cursor to the right */ | ||
57 | |||
58 | #define LCD_CMD_FUNCTION_SET 0x20 /* Set function */ | ||
59 | #define LCD_CMD_DATA_LEN_8BITS 0x10 /* Set data length to 8 bits */ | ||
60 | #define LCD_CMD_TWO_LINES 0x08 /* Set to two display lines */ | ||
61 | #define LCD_CMD_FONT_5X10_DOTS 0x04 /* Set char font to 5x10 dots */ | ||
62 | |||
63 | #define LCD_CMD_SET_CGRAM_ADDR 0x40 /* Set char generator RAM address */ | ||
64 | |||
65 | #define LCD_CMD_SET_DDRAM_ADDR 0x80 /* Set display data RAM address */ | ||
66 | |||
67 | #define LCD_ESCAPE_LEN 24 /* Max chars for LCD escape command */ | ||
68 | #define LCD_ESCAPE_CHAR 27 /* Use char 27 for escape command */ | ||
69 | |||
70 | struct charlcd_priv { | ||
71 | struct charlcd lcd; | ||
72 | |||
73 | struct delayed_work bl_work; | ||
74 | struct mutex bl_tempo_lock; /* Protects access to bl_tempo */ | ||
75 | bool bl_tempo; | ||
76 | |||
77 | bool must_clear; | ||
78 | |||
79 | /* contains the LCD config state */ | ||
80 | unsigned long int flags; | ||
81 | |||
82 | /* Contains the LCD X and Y offset */ | ||
83 | struct { | ||
84 | unsigned long int x; | ||
85 | unsigned long int y; | ||
86 | } addr; | ||
87 | |||
88 | /* Current escape sequence and it's length or -1 if outside */ | ||
89 | struct { | ||
90 | char buf[LCD_ESCAPE_LEN + 1]; | ||
91 | int len; | ||
92 | } esc_seq; | ||
93 | |||
94 | unsigned long long drvdata[0]; | ||
95 | }; | ||
96 | |||
97 | #define to_priv(p) container_of(p, struct charlcd_priv, lcd) | ||
98 | |||
99 | /* Device single-open policy control */ | ||
100 | static atomic_t charlcd_available = ATOMIC_INIT(1); | ||
101 | |||
102 | /* sleeps that many milliseconds with a reschedule */ | ||
103 | static void long_sleep(int ms) | ||
104 | { | ||
105 | if (in_interrupt()) | ||
106 | mdelay(ms); | ||
107 | else | ||
108 | schedule_timeout_interruptible(msecs_to_jiffies(ms)); | ||
109 | } | ||
110 | |||
111 | /* turn the backlight on or off */ | ||
112 | static void charlcd_backlight(struct charlcd *lcd, int on) | ||
113 | { | ||
114 | struct charlcd_priv *priv = to_priv(lcd); | ||
115 | |||
116 | if (!lcd->ops->backlight) | ||
117 | return; | ||
118 | |||
119 | mutex_lock(&priv->bl_tempo_lock); | ||
120 | if (!priv->bl_tempo) | ||
121 | lcd->ops->backlight(lcd, on); | ||
122 | mutex_unlock(&priv->bl_tempo_lock); | ||
123 | } | ||
124 | |||
125 | static void charlcd_bl_off(struct work_struct *work) | ||
126 | { | ||
127 | struct delayed_work *dwork = to_delayed_work(work); | ||
128 | struct charlcd_priv *priv = | ||
129 | container_of(dwork, struct charlcd_priv, bl_work); | ||
130 | |||
131 | mutex_lock(&priv->bl_tempo_lock); | ||
132 | if (priv->bl_tempo) { | ||
133 | priv->bl_tempo = false; | ||
134 | if (!(priv->flags & LCD_FLAG_L)) | ||
135 | priv->lcd.ops->backlight(&priv->lcd, 0); | ||
136 | } | ||
137 | mutex_unlock(&priv->bl_tempo_lock); | ||
138 | } | ||
139 | |||
140 | /* turn the backlight on for a little while */ | ||
141 | void charlcd_poke(struct charlcd *lcd) | ||
142 | { | ||
143 | struct charlcd_priv *priv = to_priv(lcd); | ||
144 | |||
145 | if (!lcd->ops->backlight) | ||
146 | return; | ||
147 | |||
148 | cancel_delayed_work_sync(&priv->bl_work); | ||
149 | |||
150 | mutex_lock(&priv->bl_tempo_lock); | ||
151 | if (!priv->bl_tempo && !(priv->flags & LCD_FLAG_L)) | ||
152 | lcd->ops->backlight(lcd, 1); | ||
153 | priv->bl_tempo = true; | ||
154 | schedule_delayed_work(&priv->bl_work, LCD_BL_TEMPO_PERIOD * HZ); | ||
155 | mutex_unlock(&priv->bl_tempo_lock); | ||
156 | } | ||
157 | EXPORT_SYMBOL_GPL(charlcd_poke); | ||
158 | |||
159 | static void charlcd_gotoxy(struct charlcd *lcd) | ||
160 | { | ||
161 | struct charlcd_priv *priv = to_priv(lcd); | ||
162 | unsigned int addr; | ||
163 | |||
164 | /* | ||
165 | * we force the cursor to stay at the end of the | ||
166 | * line if it wants to go farther | ||
167 | */ | ||
168 | addr = priv->addr.x < lcd->bwidth ? priv->addr.x & (lcd->hwidth - 1) | ||
169 | : lcd->bwidth - 1; | ||
170 | if (priv->addr.y & 1) | ||
171 | addr += lcd->hwidth; | ||
172 | if (priv->addr.y & 2) | ||
173 | addr += lcd->bwidth; | ||
174 | lcd->ops->write_cmd(lcd, LCD_CMD_SET_DDRAM_ADDR | addr); | ||
175 | } | ||
176 | |||
177 | static void charlcd_home(struct charlcd *lcd) | ||
178 | { | ||
179 | struct charlcd_priv *priv = to_priv(lcd); | ||
180 | |||
181 | priv->addr.x = 0; | ||
182 | priv->addr.y = 0; | ||
183 | charlcd_gotoxy(lcd); | ||
184 | } | ||
185 | |||
186 | static void charlcd_print(struct charlcd *lcd, char c) | ||
187 | { | ||
188 | struct charlcd_priv *priv = to_priv(lcd); | ||
189 | |||
190 | if (priv->addr.x < lcd->bwidth) { | ||
191 | if (lcd->char_conv) | ||
192 | c = lcd->char_conv[(unsigned char)c]; | ||
193 | lcd->ops->write_data(lcd, c); | ||
194 | priv->addr.x++; | ||
195 | } | ||
196 | /* prevents the cursor from wrapping onto the next line */ | ||
197 | if (priv->addr.x == lcd->bwidth) | ||
198 | charlcd_gotoxy(lcd); | ||
199 | } | ||
200 | |||
201 | static void charlcd_clear_fast(struct charlcd *lcd) | ||
202 | { | ||
203 | int pos; | ||
204 | |||
205 | charlcd_home(lcd); | ||
206 | |||
207 | if (lcd->ops->clear_fast) | ||
208 | lcd->ops->clear_fast(lcd); | ||
209 | else | ||
210 | for (pos = 0; pos < min(2, lcd->height) * lcd->hwidth; pos++) | ||
211 | lcd->ops->write_data(lcd, ' '); | ||
212 | |||
213 | charlcd_home(lcd); | ||
214 | } | ||
215 | |||
216 | /* clears the display and resets X/Y */ | ||
217 | static void charlcd_clear_display(struct charlcd *lcd) | ||
218 | { | ||
219 | struct charlcd_priv *priv = to_priv(lcd); | ||
220 | |||
221 | lcd->ops->write_cmd(lcd, LCD_CMD_DISPLAY_CLEAR); | ||
222 | priv->addr.x = 0; | ||
223 | priv->addr.y = 0; | ||
224 | /* we must wait a few milliseconds (15) */ | ||
225 | long_sleep(15); | ||
226 | } | ||
227 | |||
228 | static int charlcd_init_display(struct charlcd *lcd) | ||
229 | { | ||
230 | void (*write_cmd_raw)(struct charlcd *lcd, int cmd); | ||
231 | struct charlcd_priv *priv = to_priv(lcd); | ||
232 | u8 init; | ||
233 | |||
234 | if (lcd->ifwidth != 4 && lcd->ifwidth != 8) | ||
235 | return -EINVAL; | ||
236 | |||
237 | priv->flags = ((lcd->height > 1) ? LCD_FLAG_N : 0) | LCD_FLAG_D | | ||
238 | LCD_FLAG_C | LCD_FLAG_B; | ||
239 | |||
240 | long_sleep(20); /* wait 20 ms after power-up for the paranoid */ | ||
241 | |||
242 | /* | ||
243 | * 8-bit mode, 1 line, small fonts; let's do it 3 times, to make sure | ||
244 | * the LCD is in 8-bit mode afterwards | ||
245 | */ | ||
246 | init = LCD_CMD_FUNCTION_SET | LCD_CMD_DATA_LEN_8BITS; | ||
247 | if (lcd->ifwidth == 4) { | ||
248 | init >>= 4; | ||
249 | write_cmd_raw = lcd->ops->write_cmd_raw4; | ||
250 | } else { | ||
251 | write_cmd_raw = lcd->ops->write_cmd; | ||
252 | } | ||
253 | write_cmd_raw(lcd, init); | ||
254 | long_sleep(10); | ||
255 | write_cmd_raw(lcd, init); | ||
256 | long_sleep(10); | ||
257 | write_cmd_raw(lcd, init); | ||
258 | long_sleep(10); | ||
259 | |||
260 | if (lcd->ifwidth == 4) { | ||
261 | /* Switch to 4-bit mode, 1 line, small fonts */ | ||
262 | lcd->ops->write_cmd_raw4(lcd, LCD_CMD_FUNCTION_SET >> 4); | ||
263 | long_sleep(10); | ||
264 | } | ||
265 | |||
266 | /* set font height and lines number */ | ||
267 | lcd->ops->write_cmd(lcd, | ||
268 | LCD_CMD_FUNCTION_SET | | ||
269 | ((lcd->ifwidth == 8) ? LCD_CMD_DATA_LEN_8BITS : 0) | | ||
270 | ((priv->flags & LCD_FLAG_F) ? LCD_CMD_FONT_5X10_DOTS : 0) | | ||
271 | ((priv->flags & LCD_FLAG_N) ? LCD_CMD_TWO_LINES : 0)); | ||
272 | long_sleep(10); | ||
273 | |||
274 | /* display off, cursor off, blink off */ | ||
275 | lcd->ops->write_cmd(lcd, LCD_CMD_DISPLAY_CTRL); | ||
276 | long_sleep(10); | ||
277 | |||
278 | lcd->ops->write_cmd(lcd, | ||
279 | LCD_CMD_DISPLAY_CTRL | /* set display mode */ | ||
280 | ((priv->flags & LCD_FLAG_D) ? LCD_CMD_DISPLAY_ON : 0) | | ||
281 | ((priv->flags & LCD_FLAG_C) ? LCD_CMD_CURSOR_ON : 0) | | ||
282 | ((priv->flags & LCD_FLAG_B) ? LCD_CMD_BLINK_ON : 0)); | ||
283 | |||
284 | charlcd_backlight(lcd, (priv->flags & LCD_FLAG_L) ? 1 : 0); | ||
285 | |||
286 | long_sleep(10); | ||
287 | |||
288 | /* entry mode set : increment, cursor shifting */ | ||
289 | lcd->ops->write_cmd(lcd, LCD_CMD_ENTRY_MODE | LCD_CMD_CURSOR_INC); | ||
290 | |||
291 | charlcd_clear_display(lcd); | ||
292 | return 0; | ||
293 | } | ||
294 | |||
295 | /* | ||
296 | * These are the file operation function for user access to /dev/lcd | ||
297 | * This function can also be called from inside the kernel, by | ||
298 | * setting file and ppos to NULL. | ||
299 | * | ||
300 | */ | ||
301 | |||
302 | static inline int handle_lcd_special_code(struct charlcd *lcd) | ||
303 | { | ||
304 | struct charlcd_priv *priv = to_priv(lcd); | ||
305 | |||
306 | /* LCD special codes */ | ||
307 | |||
308 | int processed = 0; | ||
309 | |||
310 | char *esc = priv->esc_seq.buf + 2; | ||
311 | int oldflags = priv->flags; | ||
312 | |||
313 | /* check for display mode flags */ | ||
314 | switch (*esc) { | ||
315 | case 'D': /* Display ON */ | ||
316 | priv->flags |= LCD_FLAG_D; | ||
317 | processed = 1; | ||
318 | break; | ||
319 | case 'd': /* Display OFF */ | ||
320 | priv->flags &= ~LCD_FLAG_D; | ||
321 | processed = 1; | ||
322 | break; | ||
323 | case 'C': /* Cursor ON */ | ||
324 | priv->flags |= LCD_FLAG_C; | ||
325 | processed = 1; | ||
326 | break; | ||
327 | case 'c': /* Cursor OFF */ | ||
328 | priv->flags &= ~LCD_FLAG_C; | ||
329 | processed = 1; | ||
330 | break; | ||
331 | case 'B': /* Blink ON */ | ||
332 | priv->flags |= LCD_FLAG_B; | ||
333 | processed = 1; | ||
334 | break; | ||
335 | case 'b': /* Blink OFF */ | ||
336 | priv->flags &= ~LCD_FLAG_B; | ||
337 | processed = 1; | ||
338 | break; | ||
339 | case '+': /* Back light ON */ | ||
340 | priv->flags |= LCD_FLAG_L; | ||
341 | processed = 1; | ||
342 | break; | ||
343 | case '-': /* Back light OFF */ | ||
344 | priv->flags &= ~LCD_FLAG_L; | ||
345 | processed = 1; | ||
346 | break; | ||
347 | case '*': /* Flash back light */ | ||
348 | charlcd_poke(lcd); | ||
349 | processed = 1; | ||
350 | break; | ||
351 | case 'f': /* Small Font */ | ||
352 | priv->flags &= ~LCD_FLAG_F; | ||
353 | processed = 1; | ||
354 | break; | ||
355 | case 'F': /* Large Font */ | ||
356 | priv->flags |= LCD_FLAG_F; | ||
357 | processed = 1; | ||
358 | break; | ||
359 | case 'n': /* One Line */ | ||
360 | priv->flags &= ~LCD_FLAG_N; | ||
361 | processed = 1; | ||
362 | break; | ||
363 | case 'N': /* Two Lines */ | ||
364 | priv->flags |= LCD_FLAG_N; | ||
365 | break; | ||
366 | case 'l': /* Shift Cursor Left */ | ||
367 | if (priv->addr.x > 0) { | ||
368 | /* back one char if not at end of line */ | ||
369 | if (priv->addr.x < lcd->bwidth) | ||
370 | lcd->ops->write_cmd(lcd, LCD_CMD_SHIFT); | ||
371 | priv->addr.x--; | ||
372 | } | ||
373 | processed = 1; | ||
374 | break; | ||
375 | case 'r': /* shift cursor right */ | ||
376 | if (priv->addr.x < lcd->width) { | ||
377 | /* allow the cursor to pass the end of the line */ | ||
378 | if (priv->addr.x < (lcd->bwidth - 1)) | ||
379 | lcd->ops->write_cmd(lcd, | ||
380 | LCD_CMD_SHIFT | LCD_CMD_SHIFT_RIGHT); | ||
381 | priv->addr.x++; | ||
382 | } | ||
383 | processed = 1; | ||
384 | break; | ||
385 | case 'L': /* shift display left */ | ||
386 | lcd->ops->write_cmd(lcd, LCD_CMD_SHIFT | LCD_CMD_DISPLAY_SHIFT); | ||
387 | processed = 1; | ||
388 | break; | ||
389 | case 'R': /* shift display right */ | ||
390 | lcd->ops->write_cmd(lcd, | ||
391 | LCD_CMD_SHIFT | LCD_CMD_DISPLAY_SHIFT | | ||
392 | LCD_CMD_SHIFT_RIGHT); | ||
393 | processed = 1; | ||
394 | break; | ||
395 | case 'k': { /* kill end of line */ | ||
396 | int x; | ||
397 | |||
398 | for (x = priv->addr.x; x < lcd->bwidth; x++) | ||
399 | lcd->ops->write_data(lcd, ' '); | ||
400 | |||
401 | /* restore cursor position */ | ||
402 | charlcd_gotoxy(lcd); | ||
403 | processed = 1; | ||
404 | break; | ||
405 | } | ||
406 | case 'I': /* reinitialize display */ | ||
407 | charlcd_init_display(lcd); | ||
408 | processed = 1; | ||
409 | break; | ||
410 | case 'G': { | ||
411 | /* Generator : LGcxxxxx...xx; must have <c> between '0' | ||
412 | * and '7', representing the numerical ASCII code of the | ||
413 | * redefined character, and <xx...xx> a sequence of 16 | ||
414 | * hex digits representing 8 bytes for each character. | ||
415 | * Most LCDs will only use 5 lower bits of the 7 first | ||
416 | * bytes. | ||
417 | */ | ||
418 | |||
419 | unsigned char cgbytes[8]; | ||
420 | unsigned char cgaddr; | ||
421 | int cgoffset; | ||
422 | int shift; | ||
423 | char value; | ||
424 | int addr; | ||
425 | |||
426 | if (!strchr(esc, ';')) | ||
427 | break; | ||
428 | |||
429 | esc++; | ||
430 | |||
431 | cgaddr = *(esc++) - '0'; | ||
432 | if (cgaddr > 7) { | ||
433 | processed = 1; | ||
434 | break; | ||
435 | } | ||
436 | |||
437 | cgoffset = 0; | ||
438 | shift = 0; | ||
439 | value = 0; | ||
440 | while (*esc && cgoffset < 8) { | ||
441 | shift ^= 4; | ||
442 | if (*esc >= '0' && *esc <= '9') { | ||
443 | value |= (*esc - '0') << shift; | ||
444 | } else if (*esc >= 'A' && *esc <= 'Z') { | ||
445 | value |= (*esc - 'A' + 10) << shift; | ||
446 | } else if (*esc >= 'a' && *esc <= 'z') { | ||
447 | value |= (*esc - 'a' + 10) << shift; | ||
448 | } else { | ||
449 | esc++; | ||
450 | continue; | ||
451 | } | ||
452 | |||
453 | if (shift == 0) { | ||
454 | cgbytes[cgoffset++] = value; | ||
455 | value = 0; | ||
456 | } | ||
457 | |||
458 | esc++; | ||
459 | } | ||
460 | |||
461 | lcd->ops->write_cmd(lcd, LCD_CMD_SET_CGRAM_ADDR | (cgaddr * 8)); | ||
462 | for (addr = 0; addr < cgoffset; addr++) | ||
463 | lcd->ops->write_data(lcd, cgbytes[addr]); | ||
464 | |||
465 | /* ensures that we stop writing to CGRAM */ | ||
466 | charlcd_gotoxy(lcd); | ||
467 | processed = 1; | ||
468 | break; | ||
469 | } | ||
470 | case 'x': /* gotoxy : LxXXX[yYYY]; */ | ||
471 | case 'y': /* gotoxy : LyYYY[xXXX]; */ | ||
472 | if (!strchr(esc, ';')) | ||
473 | break; | ||
474 | |||
475 | while (*esc) { | ||
476 | if (*esc == 'x') { | ||
477 | esc++; | ||
478 | if (kstrtoul(esc, 10, &priv->addr.x) < 0) | ||
479 | break; | ||
480 | } else if (*esc == 'y') { | ||
481 | esc++; | ||
482 | if (kstrtoul(esc, 10, &priv->addr.y) < 0) | ||
483 | break; | ||
484 | } else { | ||
485 | break; | ||
486 | } | ||
487 | } | ||
488 | |||
489 | charlcd_gotoxy(lcd); | ||
490 | processed = 1; | ||
491 | break; | ||
492 | } | ||
493 | |||
494 | /* TODO: This indent party here got ugly, clean it! */ | ||
495 | /* Check whether one flag was changed */ | ||
496 | if (oldflags == priv->flags) | ||
497 | return processed; | ||
498 | |||
499 | /* check whether one of B,C,D flags were changed */ | ||
500 | if ((oldflags ^ priv->flags) & | ||
501 | (LCD_FLAG_B | LCD_FLAG_C | LCD_FLAG_D)) | ||
502 | /* set display mode */ | ||
503 | lcd->ops->write_cmd(lcd, | ||
504 | LCD_CMD_DISPLAY_CTRL | | ||
505 | ((priv->flags & LCD_FLAG_D) ? LCD_CMD_DISPLAY_ON : 0) | | ||
506 | ((priv->flags & LCD_FLAG_C) ? LCD_CMD_CURSOR_ON : 0) | | ||
507 | ((priv->flags & LCD_FLAG_B) ? LCD_CMD_BLINK_ON : 0)); | ||
508 | /* check whether one of F,N flags was changed */ | ||
509 | else if ((oldflags ^ priv->flags) & (LCD_FLAG_F | LCD_FLAG_N)) | ||
510 | lcd->ops->write_cmd(lcd, | ||
511 | LCD_CMD_FUNCTION_SET | | ||
512 | ((lcd->ifwidth == 8) ? LCD_CMD_DATA_LEN_8BITS : 0) | | ||
513 | ((priv->flags & LCD_FLAG_F) ? LCD_CMD_FONT_5X10_DOTS : 0) | | ||
514 | ((priv->flags & LCD_FLAG_N) ? LCD_CMD_TWO_LINES : 0)); | ||
515 | /* check whether L flag was changed */ | ||
516 | else if ((oldflags ^ priv->flags) & LCD_FLAG_L) | ||
517 | charlcd_backlight(lcd, !!(priv->flags & LCD_FLAG_L)); | ||
518 | |||
519 | return processed; | ||
520 | } | ||
521 | |||
522 | static void charlcd_write_char(struct charlcd *lcd, char c) | ||
523 | { | ||
524 | struct charlcd_priv *priv = to_priv(lcd); | ||
525 | |||
526 | /* first, we'll test if we're in escape mode */ | ||
527 | if ((c != '\n') && priv->esc_seq.len >= 0) { | ||
528 | /* yes, let's add this char to the buffer */ | ||
529 | priv->esc_seq.buf[priv->esc_seq.len++] = c; | ||
530 | priv->esc_seq.buf[priv->esc_seq.len] = 0; | ||
531 | } else { | ||
532 | /* aborts any previous escape sequence */ | ||
533 | priv->esc_seq.len = -1; | ||
534 | |||
535 | switch (c) { | ||
536 | case LCD_ESCAPE_CHAR: | ||
537 | /* start of an escape sequence */ | ||
538 | priv->esc_seq.len = 0; | ||
539 | priv->esc_seq.buf[priv->esc_seq.len] = 0; | ||
540 | break; | ||
541 | case '\b': | ||
542 | /* go back one char and clear it */ | ||
543 | if (priv->addr.x > 0) { | ||
544 | /* | ||
545 | * check if we're not at the | ||
546 | * end of the line | ||
547 | */ | ||
548 | if (priv->addr.x < lcd->bwidth) | ||
549 | /* back one char */ | ||
550 | lcd->ops->write_cmd(lcd, LCD_CMD_SHIFT); | ||
551 | priv->addr.x--; | ||
552 | } | ||
553 | /* replace with a space */ | ||
554 | lcd->ops->write_data(lcd, ' '); | ||
555 | /* back one char again */ | ||
556 | lcd->ops->write_cmd(lcd, LCD_CMD_SHIFT); | ||
557 | break; | ||
558 | case '\014': | ||
559 | /* quickly clear the display */ | ||
560 | charlcd_clear_fast(lcd); | ||
561 | break; | ||
562 | case '\n': | ||
563 | /* | ||
564 | * flush the remainder of the current line and | ||
565 | * go to the beginning of the next line | ||
566 | */ | ||
567 | for (; priv->addr.x < lcd->bwidth; priv->addr.x++) | ||
568 | lcd->ops->write_data(lcd, ' '); | ||
569 | priv->addr.x = 0; | ||
570 | priv->addr.y = (priv->addr.y + 1) % lcd->height; | ||
571 | charlcd_gotoxy(lcd); | ||
572 | break; | ||
573 | case '\r': | ||
574 | /* go to the beginning of the same line */ | ||
575 | priv->addr.x = 0; | ||
576 | charlcd_gotoxy(lcd); | ||
577 | break; | ||
578 | case '\t': | ||
579 | /* print a space instead of the tab */ | ||
580 | charlcd_print(lcd, ' '); | ||
581 | break; | ||
582 | default: | ||
583 | /* simply print this char */ | ||
584 | charlcd_print(lcd, c); | ||
585 | break; | ||
586 | } | ||
587 | } | ||
588 | |||
589 | /* | ||
590 | * now we'll see if we're in an escape mode and if the current | ||
591 | * escape sequence can be understood. | ||
592 | */ | ||
593 | if (priv->esc_seq.len >= 2) { | ||
594 | int processed = 0; | ||
595 | |||
596 | if (!strcmp(priv->esc_seq.buf, "[2J")) { | ||
597 | /* clear the display */ | ||
598 | charlcd_clear_fast(lcd); | ||
599 | processed = 1; | ||
600 | } else if (!strcmp(priv->esc_seq.buf, "[H")) { | ||
601 | /* cursor to home */ | ||
602 | charlcd_home(lcd); | ||
603 | processed = 1; | ||
604 | } | ||
605 | /* codes starting with ^[[L */ | ||
606 | else if ((priv->esc_seq.len >= 3) && | ||
607 | (priv->esc_seq.buf[0] == '[') && | ||
608 | (priv->esc_seq.buf[1] == 'L')) { | ||
609 | processed = handle_lcd_special_code(lcd); | ||
610 | } | ||
611 | |||
612 | /* LCD special escape codes */ | ||
613 | /* | ||
614 | * flush the escape sequence if it's been processed | ||
615 | * or if it is getting too long. | ||
616 | */ | ||
617 | if (processed || (priv->esc_seq.len >= LCD_ESCAPE_LEN)) | ||
618 | priv->esc_seq.len = -1; | ||
619 | } /* escape codes */ | ||
620 | } | ||
621 | |||
622 | static struct charlcd *the_charlcd; | ||
623 | |||
624 | static ssize_t charlcd_write(struct file *file, const char __user *buf, | ||
625 | size_t count, loff_t *ppos) | ||
626 | { | ||
627 | const char __user *tmp = buf; | ||
628 | char c; | ||
629 | |||
630 | for (; count-- > 0; (*ppos)++, tmp++) { | ||
631 | if (!in_interrupt() && (((count + 1) & 0x1f) == 0)) | ||
632 | /* | ||
633 | * let's be a little nice with other processes | ||
634 | * that need some CPU | ||
635 | */ | ||
636 | schedule(); | ||
637 | |||
638 | if (get_user(c, tmp)) | ||
639 | return -EFAULT; | ||
640 | |||
641 | charlcd_write_char(the_charlcd, c); | ||
642 | } | ||
643 | |||
644 | return tmp - buf; | ||
645 | } | ||
646 | |||
647 | static int charlcd_open(struct inode *inode, struct file *file) | ||
648 | { | ||
649 | struct charlcd_priv *priv = to_priv(the_charlcd); | ||
650 | |||
651 | if (!atomic_dec_and_test(&charlcd_available)) | ||
652 | return -EBUSY; /* open only once at a time */ | ||
653 | |||
654 | if (file->f_mode & FMODE_READ) /* device is write-only */ | ||
655 | return -EPERM; | ||
656 | |||
657 | if (priv->must_clear) { | ||
658 | charlcd_clear_display(&priv->lcd); | ||
659 | priv->must_clear = false; | ||
660 | } | ||
661 | return nonseekable_open(inode, file); | ||
662 | } | ||
663 | |||
664 | static int charlcd_release(struct inode *inode, struct file *file) | ||
665 | { | ||
666 | atomic_inc(&charlcd_available); | ||
667 | return 0; | ||
668 | } | ||
669 | |||
670 | static const struct file_operations charlcd_fops = { | ||
671 | .write = charlcd_write, | ||
672 | .open = charlcd_open, | ||
673 | .release = charlcd_release, | ||
674 | .llseek = no_llseek, | ||
675 | }; | ||
676 | |||
677 | static struct miscdevice charlcd_dev = { | ||
678 | .minor = LCD_MINOR, | ||
679 | .name = "lcd", | ||
680 | .fops = &charlcd_fops, | ||
681 | }; | ||
682 | |||
683 | static void charlcd_puts(struct charlcd *lcd, const char *s) | ||
684 | { | ||
685 | const char *tmp = s; | ||
686 | int count = strlen(s); | ||
687 | |||
688 | for (; count-- > 0; tmp++) { | ||
689 | if (!in_interrupt() && (((count + 1) & 0x1f) == 0)) | ||
690 | /* | ||
691 | * let's be a little nice with other processes | ||
692 | * that need some CPU | ||
693 | */ | ||
694 | schedule(); | ||
695 | |||
696 | charlcd_write_char(lcd, *tmp); | ||
697 | } | ||
698 | } | ||
699 | |||
700 | /* initialize the LCD driver */ | ||
701 | static int charlcd_init(struct charlcd *lcd) | ||
702 | { | ||
703 | struct charlcd_priv *priv = to_priv(lcd); | ||
704 | int ret; | ||
705 | |||
706 | if (lcd->ops->backlight) { | ||
707 | mutex_init(&priv->bl_tempo_lock); | ||
708 | INIT_DELAYED_WORK(&priv->bl_work, charlcd_bl_off); | ||
709 | } | ||
710 | |||
711 | /* | ||
712 | * before this line, we must NOT send anything to the display. | ||
713 | * Since charlcd_init_display() needs to write data, we have to | ||
714 | * enable mark the LCD initialized just before. | ||
715 | */ | ||
716 | ret = charlcd_init_display(lcd); | ||
717 | if (ret) | ||
718 | return ret; | ||
719 | |||
720 | /* display a short message */ | ||
721 | #ifdef CONFIG_PANEL_CHANGE_MESSAGE | ||
722 | #ifdef CONFIG_PANEL_BOOT_MESSAGE | ||
723 | charlcd_puts(lcd, "\x1b[Lc\x1b[Lb\x1b[L*" CONFIG_PANEL_BOOT_MESSAGE); | ||
724 | #endif | ||
725 | #else | ||
726 | charlcd_puts(lcd, "\x1b[Lc\x1b[Lb\x1b[L*Linux-" UTS_RELEASE "\n"); | ||
727 | #endif | ||
728 | /* clear the display on the next device opening */ | ||
729 | priv->must_clear = true; | ||
730 | charlcd_home(lcd); | ||
731 | return 0; | ||
732 | } | ||
733 | |||
734 | struct charlcd *charlcd_alloc(unsigned int drvdata_size) | ||
735 | { | ||
736 | struct charlcd_priv *priv; | ||
737 | struct charlcd *lcd; | ||
738 | |||
739 | priv = kzalloc(sizeof(*priv) + drvdata_size, GFP_KERNEL); | ||
740 | if (!priv) | ||
741 | return NULL; | ||
742 | |||
743 | priv->esc_seq.len = -1; | ||
744 | |||
745 | lcd = &priv->lcd; | ||
746 | lcd->ifwidth = 8; | ||
747 | lcd->bwidth = DEFAULT_LCD_BWIDTH; | ||
748 | lcd->hwidth = DEFAULT_LCD_HWIDTH; | ||
749 | lcd->drvdata = priv->drvdata; | ||
750 | |||
751 | return lcd; | ||
752 | } | ||
753 | EXPORT_SYMBOL_GPL(charlcd_alloc); | ||
754 | |||
755 | static int panel_notify_sys(struct notifier_block *this, unsigned long code, | ||
756 | void *unused) | ||
757 | { | ||
758 | struct charlcd *lcd = the_charlcd; | ||
759 | |||
760 | switch (code) { | ||
761 | case SYS_DOWN: | ||
762 | charlcd_puts(lcd, | ||
763 | "\x0cReloading\nSystem...\x1b[Lc\x1b[Lb\x1b[L+"); | ||
764 | break; | ||
765 | case SYS_HALT: | ||
766 | charlcd_puts(lcd, "\x0cSystem Halted.\x1b[Lc\x1b[Lb\x1b[L+"); | ||
767 | break; | ||
768 | case SYS_POWER_OFF: | ||
769 | charlcd_puts(lcd, "\x0cPower off.\x1b[Lc\x1b[Lb\x1b[L+"); | ||
770 | break; | ||
771 | default: | ||
772 | break; | ||
773 | } | ||
774 | return NOTIFY_DONE; | ||
775 | } | ||
776 | |||
777 | static struct notifier_block panel_notifier = { | ||
778 | panel_notify_sys, | ||
779 | NULL, | ||
780 | 0 | ||
781 | }; | ||
782 | |||
783 | int charlcd_register(struct charlcd *lcd) | ||
784 | { | ||
785 | int ret; | ||
786 | |||
787 | ret = charlcd_init(lcd); | ||
788 | if (ret) | ||
789 | return ret; | ||
790 | |||
791 | ret = misc_register(&charlcd_dev); | ||
792 | if (ret) | ||
793 | return ret; | ||
794 | |||
795 | the_charlcd = lcd; | ||
796 | register_reboot_notifier(&panel_notifier); | ||
797 | return 0; | ||
798 | } | ||
799 | EXPORT_SYMBOL_GPL(charlcd_register); | ||
800 | |||
801 | int charlcd_unregister(struct charlcd *lcd) | ||
802 | { | ||
803 | struct charlcd_priv *priv = to_priv(lcd); | ||
804 | |||
805 | unregister_reboot_notifier(&panel_notifier); | ||
806 | charlcd_puts(lcd, "\x0cLCD driver unloaded.\x1b[Lc\x1b[Lb\x1b[L-"); | ||
807 | misc_deregister(&charlcd_dev); | ||
808 | the_charlcd = NULL; | ||
809 | if (lcd->ops->backlight) { | ||
810 | cancel_delayed_work_sync(&priv->bl_work); | ||
811 | priv->lcd.ops->backlight(&priv->lcd, 0); | ||
812 | } | ||
813 | |||
814 | return 0; | ||
815 | } | ||
816 | EXPORT_SYMBOL_GPL(charlcd_unregister); | ||
817 | |||
818 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/auxdisplay/hd44780.c b/drivers/auxdisplay/hd44780.c new file mode 100644 index 000000000000..1665ac6ef9ff --- /dev/null +++ b/drivers/auxdisplay/hd44780.c | |||
@@ -0,0 +1,325 @@ | |||
1 | /* | ||
2 | * HD44780 Character LCD driver for Linux | ||
3 | * | ||
4 | * Copyright (C) 2000-2008, Willy Tarreau <w@1wt.eu> | ||
5 | * Copyright (C) 2016-2017 Glider bvba | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License | ||
9 | * as published by the Free Software Foundation; either version | ||
10 | * 2 of the License, or (at your option) any later version. | ||
11 | */ | ||
12 | |||
13 | #include <linux/delay.h> | ||
14 | #include <linux/gpio/consumer.h> | ||
15 | #include <linux/module.h> | ||
16 | #include <linux/platform_device.h> | ||
17 | #include <linux/property.h> | ||
18 | #include <linux/slab.h> | ||
19 | |||
20 | #include <misc/charlcd.h> | ||
21 | |||
22 | |||
23 | enum hd44780_pin { | ||
24 | /* Order does matter due to writing to GPIO array subsets! */ | ||
25 | PIN_DATA0, /* Optional */ | ||
26 | PIN_DATA1, /* Optional */ | ||
27 | PIN_DATA2, /* Optional */ | ||
28 | PIN_DATA3, /* Optional */ | ||
29 | PIN_DATA4, | ||
30 | PIN_DATA5, | ||
31 | PIN_DATA6, | ||
32 | PIN_DATA7, | ||
33 | PIN_CTRL_RS, | ||
34 | PIN_CTRL_RW, /* Optional */ | ||
35 | PIN_CTRL_E, | ||
36 | PIN_CTRL_BL, /* Optional */ | ||
37 | PIN_NUM | ||
38 | }; | ||
39 | |||
40 | struct hd44780 { | ||
41 | struct gpio_desc *pins[PIN_NUM]; | ||
42 | }; | ||
43 | |||
44 | static void hd44780_backlight(struct charlcd *lcd, int on) | ||
45 | { | ||
46 | struct hd44780 *hd = lcd->drvdata; | ||
47 | |||
48 | if (hd->pins[PIN_CTRL_BL]) | ||
49 | gpiod_set_value_cansleep(hd->pins[PIN_CTRL_BL], on); | ||
50 | } | ||
51 | |||
52 | static void hd44780_strobe_gpio(struct hd44780 *hd) | ||
53 | { | ||
54 | /* Maintain the data during 20 us before the strobe */ | ||
55 | udelay(20); | ||
56 | |||
57 | gpiod_set_value_cansleep(hd->pins[PIN_CTRL_E], 1); | ||
58 | |||
59 | /* Maintain the strobe during 40 us */ | ||
60 | udelay(40); | ||
61 | |||
62 | gpiod_set_value_cansleep(hd->pins[PIN_CTRL_E], 0); | ||
63 | } | ||
64 | |||
65 | /* write to an LCD panel register in 8 bit GPIO mode */ | ||
66 | static void hd44780_write_gpio8(struct hd44780 *hd, u8 val, unsigned int rs) | ||
67 | { | ||
68 | int values[10]; /* for DATA[0-7], RS, RW */ | ||
69 | unsigned int i, n; | ||
70 | |||
71 | for (i = 0; i < 8; i++) | ||
72 | values[PIN_DATA0 + i] = !!(val & BIT(i)); | ||
73 | values[PIN_CTRL_RS] = rs; | ||
74 | n = 9; | ||
75 | if (hd->pins[PIN_CTRL_RW]) { | ||
76 | values[PIN_CTRL_RW] = 0; | ||
77 | n++; | ||
78 | } | ||
79 | |||
80 | /* Present the data to the port */ | ||
81 | gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA0], values); | ||
82 | |||
83 | hd44780_strobe_gpio(hd); | ||
84 | } | ||
85 | |||
86 | /* write to an LCD panel register in 4 bit GPIO mode */ | ||
87 | static void hd44780_write_gpio4(struct hd44780 *hd, u8 val, unsigned int rs) | ||
88 | { | ||
89 | int values[10]; /* for DATA[0-7], RS, RW, but DATA[0-3] is unused */ | ||
90 | unsigned int i, n; | ||
91 | |||
92 | /* High nibble + RS, RW */ | ||
93 | for (i = 4; i < 8; i++) | ||
94 | values[PIN_DATA0 + i] = !!(val & BIT(i)); | ||
95 | values[PIN_CTRL_RS] = rs; | ||
96 | n = 5; | ||
97 | if (hd->pins[PIN_CTRL_RW]) { | ||
98 | values[PIN_CTRL_RW] = 0; | ||
99 | n++; | ||
100 | } | ||
101 | |||
102 | /* Present the data to the port */ | ||
103 | gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA4], | ||
104 | &values[PIN_DATA4]); | ||
105 | |||
106 | hd44780_strobe_gpio(hd); | ||
107 | |||
108 | /* Low nibble */ | ||
109 | for (i = 0; i < 4; i++) | ||
110 | values[PIN_DATA4 + i] = !!(val & BIT(i)); | ||
111 | |||
112 | /* Present the data to the port */ | ||
113 | gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA4], | ||
114 | &values[PIN_DATA4]); | ||
115 | |||
116 | hd44780_strobe_gpio(hd); | ||
117 | } | ||
118 | |||
119 | /* Send a command to the LCD panel in 8 bit GPIO mode */ | ||
120 | static void hd44780_write_cmd_gpio8(struct charlcd *lcd, int cmd) | ||
121 | { | ||
122 | struct hd44780 *hd = lcd->drvdata; | ||
123 | |||
124 | hd44780_write_gpio8(hd, cmd, 0); | ||
125 | |||
126 | /* The shortest command takes at least 120 us */ | ||
127 | udelay(120); | ||
128 | } | ||
129 | |||
130 | /* Send data to the LCD panel in 8 bit GPIO mode */ | ||
131 | static void hd44780_write_data_gpio8(struct charlcd *lcd, int data) | ||
132 | { | ||
133 | struct hd44780 *hd = lcd->drvdata; | ||
134 | |||
135 | hd44780_write_gpio8(hd, data, 1); | ||
136 | |||
137 | /* The shortest data takes at least 45 us */ | ||
138 | udelay(45); | ||
139 | } | ||
140 | |||
141 | static const struct charlcd_ops hd44780_ops_gpio8 = { | ||
142 | .write_cmd = hd44780_write_cmd_gpio8, | ||
143 | .write_data = hd44780_write_data_gpio8, | ||
144 | .backlight = hd44780_backlight, | ||
145 | }; | ||
146 | |||
147 | /* Send a command to the LCD panel in 4 bit GPIO mode */ | ||
148 | static void hd44780_write_cmd_gpio4(struct charlcd *lcd, int cmd) | ||
149 | { | ||
150 | struct hd44780 *hd = lcd->drvdata; | ||
151 | |||
152 | hd44780_write_gpio4(hd, cmd, 0); | ||
153 | |||
154 | /* The shortest command takes at least 120 us */ | ||
155 | udelay(120); | ||
156 | } | ||
157 | |||
158 | /* Send 4-bits of a command to the LCD panel in raw 4 bit GPIO mode */ | ||
159 | static void hd44780_write_cmd_raw_gpio4(struct charlcd *lcd, int cmd) | ||
160 | { | ||
161 | int values[10]; /* for DATA[0-7], RS, RW, but DATA[0-3] is unused */ | ||
162 | struct hd44780 *hd = lcd->drvdata; | ||
163 | unsigned int i, n; | ||
164 | |||
165 | /* Command nibble + RS, RW */ | ||
166 | for (i = 0; i < 4; i++) | ||
167 | values[PIN_DATA4 + i] = !!(cmd & BIT(i)); | ||
168 | values[PIN_CTRL_RS] = 0; | ||
169 | n = 5; | ||
170 | if (hd->pins[PIN_CTRL_RW]) { | ||
171 | values[PIN_CTRL_RW] = 0; | ||
172 | n++; | ||
173 | } | ||
174 | |||
175 | /* Present the data to the port */ | ||
176 | gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA4], | ||
177 | &values[PIN_DATA4]); | ||
178 | |||
179 | hd44780_strobe_gpio(hd); | ||
180 | } | ||
181 | |||
182 | /* Send data to the LCD panel in 4 bit GPIO mode */ | ||
183 | static void hd44780_write_data_gpio4(struct charlcd *lcd, int data) | ||
184 | { | ||
185 | struct hd44780 *hd = lcd->drvdata; | ||
186 | |||
187 | hd44780_write_gpio4(hd, data, 1); | ||
188 | |||
189 | /* The shortest data takes at least 45 us */ | ||
190 | udelay(45); | ||
191 | } | ||
192 | |||
193 | static const struct charlcd_ops hd44780_ops_gpio4 = { | ||
194 | .write_cmd = hd44780_write_cmd_gpio4, | ||
195 | .write_cmd_raw4 = hd44780_write_cmd_raw_gpio4, | ||
196 | .write_data = hd44780_write_data_gpio4, | ||
197 | .backlight = hd44780_backlight, | ||
198 | }; | ||
199 | |||
200 | static int hd44780_probe(struct platform_device *pdev) | ||
201 | { | ||
202 | struct device *dev = &pdev->dev; | ||
203 | unsigned int i, base; | ||
204 | struct charlcd *lcd; | ||
205 | struct hd44780 *hd; | ||
206 | int ifwidth, ret; | ||
207 | |||
208 | /* Required pins */ | ||
209 | ifwidth = gpiod_count(dev, "data"); | ||
210 | if (ifwidth < 0) | ||
211 | return ifwidth; | ||
212 | |||
213 | switch (ifwidth) { | ||
214 | case 4: | ||
215 | base = PIN_DATA4; | ||
216 | break; | ||
217 | case 8: | ||
218 | base = PIN_DATA0; | ||
219 | break; | ||
220 | default: | ||
221 | return -EINVAL; | ||
222 | } | ||
223 | |||
224 | lcd = charlcd_alloc(sizeof(struct hd44780)); | ||
225 | if (!lcd) | ||
226 | return -ENOMEM; | ||
227 | |||
228 | hd = lcd->drvdata; | ||
229 | |||
230 | for (i = 0; i < ifwidth; i++) { | ||
231 | hd->pins[base + i] = devm_gpiod_get_index(dev, "data", i, | ||
232 | GPIOD_OUT_LOW); | ||
233 | if (IS_ERR(hd->pins[base + i])) { | ||
234 | ret = PTR_ERR(hd->pins[base + i]); | ||
235 | goto fail; | ||
236 | } | ||
237 | } | ||
238 | |||
239 | hd->pins[PIN_CTRL_E] = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW); | ||
240 | if (IS_ERR(hd->pins[PIN_CTRL_E])) { | ||
241 | ret = PTR_ERR(hd->pins[PIN_CTRL_E]); | ||
242 | goto fail; | ||
243 | } | ||
244 | |||
245 | hd->pins[PIN_CTRL_RS] = devm_gpiod_get(dev, "rs", GPIOD_OUT_HIGH); | ||
246 | if (IS_ERR(hd->pins[PIN_CTRL_RS])) { | ||
247 | ret = PTR_ERR(hd->pins[PIN_CTRL_RS]); | ||
248 | goto fail; | ||
249 | } | ||
250 | |||
251 | /* Optional pins */ | ||
252 | hd->pins[PIN_CTRL_RW] = devm_gpiod_get_optional(dev, "rw", | ||
253 | GPIOD_OUT_LOW); | ||
254 | if (IS_ERR(hd->pins[PIN_CTRL_RW])) { | ||
255 | ret = PTR_ERR(hd->pins[PIN_CTRL_RW]); | ||
256 | goto fail; | ||
257 | } | ||
258 | |||
259 | hd->pins[PIN_CTRL_BL] = devm_gpiod_get_optional(dev, "backlight", | ||
260 | GPIOD_OUT_LOW); | ||
261 | if (IS_ERR(hd->pins[PIN_CTRL_BL])) { | ||
262 | ret = PTR_ERR(hd->pins[PIN_CTRL_BL]); | ||
263 | goto fail; | ||
264 | } | ||
265 | |||
266 | /* Required properties */ | ||
267 | ret = device_property_read_u32(dev, "display-height", &lcd->height); | ||
268 | if (ret) | ||
269 | goto fail; | ||
270 | ret = device_property_read_u32(dev, "display-width", &lcd->width); | ||
271 | if (ret) | ||
272 | goto fail; | ||
273 | |||
274 | /* | ||
275 | * On displays with more than two rows, the internal buffer width is | ||
276 | * usually equal to the display width | ||
277 | */ | ||
278 | if (lcd->height > 2) | ||
279 | lcd->bwidth = lcd->width; | ||
280 | |||
281 | /* Optional properties */ | ||
282 | device_property_read_u32(dev, "internal-buffer-width", &lcd->bwidth); | ||
283 | |||
284 | lcd->ifwidth = ifwidth; | ||
285 | lcd->ops = ifwidth == 8 ? &hd44780_ops_gpio8 : &hd44780_ops_gpio4; | ||
286 | |||
287 | ret = charlcd_register(lcd); | ||
288 | if (ret) | ||
289 | goto fail; | ||
290 | |||
291 | platform_set_drvdata(pdev, lcd); | ||
292 | return 0; | ||
293 | |||
294 | fail: | ||
295 | kfree(lcd); | ||
296 | return ret; | ||
297 | } | ||
298 | |||
299 | static int hd44780_remove(struct platform_device *pdev) | ||
300 | { | ||
301 | struct charlcd *lcd = platform_get_drvdata(pdev); | ||
302 | |||
303 | charlcd_unregister(lcd); | ||
304 | return 0; | ||
305 | } | ||
306 | |||
307 | static const struct of_device_id hd44780_of_match[] = { | ||
308 | { .compatible = "hit,hd44780" }, | ||
309 | { /* sentinel */ } | ||
310 | }; | ||
311 | MODULE_DEVICE_TABLE(of, hd44780_of_match); | ||
312 | |||
313 | static struct platform_driver hd44780_driver = { | ||
314 | .probe = hd44780_probe, | ||
315 | .remove = hd44780_remove, | ||
316 | .driver = { | ||
317 | .name = "hd44780", | ||
318 | .of_match_table = hd44780_of_match, | ||
319 | }, | ||
320 | }; | ||
321 | |||
322 | module_platform_driver(hd44780_driver); | ||
323 | MODULE_DESCRIPTION("HD44780 Character LCD driver"); | ||
324 | MODULE_AUTHOR("Geert Uytterhoeven <geert@linux-m68k.org>"); | ||
325 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index f744de7a0f9b..e66956fc2c88 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig | |||
@@ -339,6 +339,7 @@ config BLK_DEV_SX8 | |||
339 | 339 | ||
340 | config BLK_DEV_RAM | 340 | config BLK_DEV_RAM |
341 | tristate "RAM block device support" | 341 | tristate "RAM block device support" |
342 | select DAX if BLK_DEV_RAM_DAX | ||
342 | ---help--- | 343 | ---help--- |
343 | Saying Y here will allow you to use a portion of your RAM memory as | 344 | Saying Y here will allow you to use a portion of your RAM memory as |
344 | a block device, so that you can make file systems on it, read and | 345 | a block device, so that you can make file systems on it, read and |
diff --git a/drivers/block/brd.c b/drivers/block/brd.c index 3adc32a3153b..ec00c01b8dc3 100644 --- a/drivers/block/brd.c +++ b/drivers/block/brd.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/slab.h> | 21 | #include <linux/slab.h> |
22 | #ifdef CONFIG_BLK_DEV_RAM_DAX | 22 | #ifdef CONFIG_BLK_DEV_RAM_DAX |
23 | #include <linux/pfn_t.h> | 23 | #include <linux/pfn_t.h> |
24 | #include <linux/dax.h> | ||
24 | #endif | 25 | #endif |
25 | 26 | ||
26 | #include <linux/uaccess.h> | 27 | #include <linux/uaccess.h> |
@@ -41,6 +42,9 @@ struct brd_device { | |||
41 | 42 | ||
42 | struct request_queue *brd_queue; | 43 | struct request_queue *brd_queue; |
43 | struct gendisk *brd_disk; | 44 | struct gendisk *brd_disk; |
45 | #ifdef CONFIG_BLK_DEV_RAM_DAX | ||
46 | struct dax_device *dax_dev; | ||
47 | #endif | ||
44 | struct list_head brd_list; | 48 | struct list_head brd_list; |
45 | 49 | ||
46 | /* | 50 | /* |
@@ -375,30 +379,38 @@ static int brd_rw_page(struct block_device *bdev, sector_t sector, | |||
375 | } | 379 | } |
376 | 380 | ||
377 | #ifdef CONFIG_BLK_DEV_RAM_DAX | 381 | #ifdef CONFIG_BLK_DEV_RAM_DAX |
378 | static long brd_direct_access(struct block_device *bdev, sector_t sector, | 382 | static long __brd_direct_access(struct brd_device *brd, pgoff_t pgoff, |
379 | void **kaddr, pfn_t *pfn, long size) | 383 | long nr_pages, void **kaddr, pfn_t *pfn) |
380 | { | 384 | { |
381 | struct brd_device *brd = bdev->bd_disk->private_data; | ||
382 | struct page *page; | 385 | struct page *page; |
383 | 386 | ||
384 | if (!brd) | 387 | if (!brd) |
385 | return -ENODEV; | 388 | return -ENODEV; |
386 | page = brd_insert_page(brd, sector); | 389 | page = brd_insert_page(brd, PFN_PHYS(pgoff) / 512); |
387 | if (!page) | 390 | if (!page) |
388 | return -ENOSPC; | 391 | return -ENOSPC; |
389 | *kaddr = page_address(page); | 392 | *kaddr = page_address(page); |
390 | *pfn = page_to_pfn_t(page); | 393 | *pfn = page_to_pfn_t(page); |
391 | 394 | ||
392 | return PAGE_SIZE; | 395 | return 1; |
393 | } | 396 | } |
394 | #else | 397 | |
395 | #define brd_direct_access NULL | 398 | static long brd_dax_direct_access(struct dax_device *dax_dev, |
399 | pgoff_t pgoff, long nr_pages, void **kaddr, pfn_t *pfn) | ||
400 | { | ||
401 | struct brd_device *brd = dax_get_private(dax_dev); | ||
402 | |||
403 | return __brd_direct_access(brd, pgoff, nr_pages, kaddr, pfn); | ||
404 | } | ||
405 | |||
406 | static const struct dax_operations brd_dax_ops = { | ||
407 | .direct_access = brd_dax_direct_access, | ||
408 | }; | ||
396 | #endif | 409 | #endif |
397 | 410 | ||
398 | static const struct block_device_operations brd_fops = { | 411 | static const struct block_device_operations brd_fops = { |
399 | .owner = THIS_MODULE, | 412 | .owner = THIS_MODULE, |
400 | .rw_page = brd_rw_page, | 413 | .rw_page = brd_rw_page, |
401 | .direct_access = brd_direct_access, | ||
402 | }; | 414 | }; |
403 | 415 | ||
404 | /* | 416 | /* |
@@ -469,9 +481,6 @@ static struct brd_device *brd_alloc(int i) | |||
469 | blk_queue_max_discard_sectors(brd->brd_queue, UINT_MAX); | 481 | blk_queue_max_discard_sectors(brd->brd_queue, UINT_MAX); |
470 | brd->brd_queue->limits.discard_zeroes_data = 1; | 482 | brd->brd_queue->limits.discard_zeroes_data = 1; |
471 | queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, brd->brd_queue); | 483 | queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, brd->brd_queue); |
472 | #ifdef CONFIG_BLK_DEV_RAM_DAX | ||
473 | queue_flag_set_unlocked(QUEUE_FLAG_DAX, brd->brd_queue); | ||
474 | #endif | ||
475 | disk = brd->brd_disk = alloc_disk(max_part); | 484 | disk = brd->brd_disk = alloc_disk(max_part); |
476 | if (!disk) | 485 | if (!disk) |
477 | goto out_free_queue; | 486 | goto out_free_queue; |
@@ -484,8 +493,21 @@ static struct brd_device *brd_alloc(int i) | |||
484 | sprintf(disk->disk_name, "ram%d", i); | 493 | sprintf(disk->disk_name, "ram%d", i); |
485 | set_capacity(disk, rd_size * 2); | 494 | set_capacity(disk, rd_size * 2); |
486 | 495 | ||
496 | #ifdef CONFIG_BLK_DEV_RAM_DAX | ||
497 | queue_flag_set_unlocked(QUEUE_FLAG_DAX, brd->brd_queue); | ||
498 | brd->dax_dev = alloc_dax(brd, disk->disk_name, &brd_dax_ops); | ||
499 | if (!brd->dax_dev) | ||
500 | goto out_free_inode; | ||
501 | #endif | ||
502 | |||
503 | |||
487 | return brd; | 504 | return brd; |
488 | 505 | ||
506 | #ifdef CONFIG_BLK_DEV_RAM_DAX | ||
507 | out_free_inode: | ||
508 | kill_dax(brd->dax_dev); | ||
509 | put_dax(brd->dax_dev); | ||
510 | #endif | ||
489 | out_free_queue: | 511 | out_free_queue: |
490 | blk_cleanup_queue(brd->brd_queue); | 512 | blk_cleanup_queue(brd->brd_queue); |
491 | out_free_dev: | 513 | out_free_dev: |
@@ -525,6 +547,10 @@ out: | |||
525 | static void brd_del_one(struct brd_device *brd) | 547 | static void brd_del_one(struct brd_device *brd) |
526 | { | 548 | { |
527 | list_del(&brd->brd_list); | 549 | list_del(&brd->brd_list); |
550 | #ifdef CONFIG_BLK_DEV_RAM_DAX | ||
551 | kill_dax(brd->dax_dev); | ||
552 | put_dax(brd->dax_dev); | ||
553 | #endif | ||
528 | del_gendisk(brd->brd_disk); | 554 | del_gendisk(brd->brd_disk); |
529 | brd_free(brd); | 555 | brd_free(brd); |
530 | } | 556 | } |
diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c index 8bdc38d81adf..b941e6d59fd6 100644 --- a/drivers/char/hpet.c +++ b/drivers/char/hpet.c | |||
@@ -575,7 +575,7 @@ static inline unsigned long hpet_time_div(struct hpets *hpets, | |||
575 | } | 575 | } |
576 | 576 | ||
577 | static int | 577 | static int |
578 | hpet_ioctl_common(struct hpet_dev *devp, int cmd, unsigned long arg, | 578 | hpet_ioctl_common(struct hpet_dev *devp, unsigned int cmd, unsigned long arg, |
579 | struct hpet_info *info) | 579 | struct hpet_info *info) |
580 | { | 580 | { |
581 | struct hpet_timer __iomem *timer; | 581 | struct hpet_timer __iomem *timer; |
diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index e9b7e0b3cabe..c6f760b3d9d7 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c | |||
@@ -2302,7 +2302,7 @@ static int __init init(void) | |||
2302 | 2302 | ||
2303 | pdrvdata.debugfs_dir = debugfs_create_dir("virtio-ports", NULL); | 2303 | pdrvdata.debugfs_dir = debugfs_create_dir("virtio-ports", NULL); |
2304 | if (!pdrvdata.debugfs_dir) | 2304 | if (!pdrvdata.debugfs_dir) |
2305 | pr_warning("Error creating debugfs dir for virtio-ports\n"); | 2305 | pr_warn("Error creating debugfs dir for virtio-ports\n"); |
2306 | INIT_LIST_HEAD(&pdrvdata.consoles); | 2306 | INIT_LIST_HEAD(&pdrvdata.consoles); |
2307 | INIT_LIST_HEAD(&pdrvdata.portdevs); | 2307 | INIT_LIST_HEAD(&pdrvdata.portdevs); |
2308 | 2308 | ||
diff --git a/drivers/dax/Kconfig b/drivers/dax/Kconfig index 9e95bf94eb13..b7053eafd88e 100644 --- a/drivers/dax/Kconfig +++ b/drivers/dax/Kconfig | |||
@@ -1,8 +1,13 @@ | |||
1 | menuconfig DEV_DAX | 1 | menuconfig DAX |
2 | tristate "DAX: direct access to differentiated memory" | 2 | tristate "DAX: direct access to differentiated memory" |
3 | select SRCU | ||
3 | default m if NVDIMM_DAX | 4 | default m if NVDIMM_DAX |
5 | |||
6 | if DAX | ||
7 | |||
8 | config DEV_DAX | ||
9 | tristate "Device DAX: direct access mapping device" | ||
4 | depends on TRANSPARENT_HUGEPAGE | 10 | depends on TRANSPARENT_HUGEPAGE |
5 | select SRCU | ||
6 | help | 11 | help |
7 | Support raw access to differentiated (persistence, bandwidth, | 12 | Support raw access to differentiated (persistence, bandwidth, |
8 | latency...) memory via an mmap(2) capable character | 13 | latency...) memory via an mmap(2) capable character |
@@ -11,7 +16,6 @@ menuconfig DEV_DAX | |||
11 | baseline memory pool. Mappings of a /dev/daxX.Y device impose | 16 | baseline memory pool. Mappings of a /dev/daxX.Y device impose |
12 | restrictions that make the mapping behavior deterministic. | 17 | restrictions that make the mapping behavior deterministic. |
13 | 18 | ||
14 | if DEV_DAX | ||
15 | 19 | ||
16 | config DEV_DAX_PMEM | 20 | config DEV_DAX_PMEM |
17 | tristate "PMEM DAX: direct access to persistent memory" | 21 | tristate "PMEM DAX: direct access to persistent memory" |
diff --git a/drivers/dax/Makefile b/drivers/dax/Makefile index 27c54e38478a..dc7422530462 100644 --- a/drivers/dax/Makefile +++ b/drivers/dax/Makefile | |||
@@ -1,4 +1,7 @@ | |||
1 | obj-$(CONFIG_DEV_DAX) += dax.o | 1 | obj-$(CONFIG_DAX) += dax.o |
2 | obj-$(CONFIG_DEV_DAX) += device_dax.o | ||
2 | obj-$(CONFIG_DEV_DAX_PMEM) += dax_pmem.o | 3 | obj-$(CONFIG_DEV_DAX_PMEM) += dax_pmem.o |
3 | 4 | ||
5 | dax-y := super.o | ||
4 | dax_pmem-y := pmem.o | 6 | dax_pmem-y := pmem.o |
7 | device_dax-y := device.o | ||
diff --git a/drivers/dax/dax-private.h b/drivers/dax/dax-private.h index b1cd7a8e5ab9..b6fc4f04636d 100644 --- a/drivers/dax/dax-private.h +++ b/drivers/dax/dax-private.h | |||
@@ -38,22 +38,18 @@ struct dax_region { | |||
38 | }; | 38 | }; |
39 | 39 | ||
40 | /** | 40 | /** |
41 | * struct dax_dev - subdivision of a dax region | 41 | * struct dev_dax - instance data for a subdivision of a dax region |
42 | * @region - parent region | 42 | * @region - parent region |
43 | * @inode - inode | 43 | * @dax_dev - core dax functionality |
44 | * @dev - device backing the character device | 44 | * @dev - device core |
45 | * @cdev - core chardev data | ||
46 | * @alive - !alive + srcu grace period == no new mappings can be established | ||
47 | * @id - child id in the region | 45 | * @id - child id in the region |
48 | * @num_resources - number of physical address extents in this device | 46 | * @num_resources - number of physical address extents in this device |
49 | * @res - array of physical address ranges | 47 | * @res - array of physical address ranges |
50 | */ | 48 | */ |
51 | struct dax_dev { | 49 | struct dev_dax { |
52 | struct dax_region *region; | 50 | struct dax_region *region; |
53 | struct inode *inode; | 51 | struct dax_device *dax_dev; |
54 | struct device dev; | 52 | struct device dev; |
55 | struct cdev cdev; | ||
56 | bool alive; | ||
57 | int id; | 53 | int id; |
58 | int num_resources; | 54 | int num_resources; |
59 | struct resource res[0]; | 55 | struct resource res[0]; |
diff --git a/drivers/dax/dax.h b/drivers/dax/dax.h index ddd829ab58c0..f9e5feea742c 100644 --- a/drivers/dax/dax.h +++ b/drivers/dax/dax.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright(c) 2016 Intel Corporation. All rights reserved. | 2 | * Copyright(c) 2016 - 2017 Intel Corporation. All rights reserved. |
3 | * | 3 | * |
4 | * This program is free software; you can redistribute it and/or modify | 4 | * This program is free software; you can redistribute it and/or modify |
5 | * it under the terms of version 2 of the GNU General Public License as | 5 | * it under the terms of version 2 of the GNU General Public License as |
@@ -12,14 +12,7 @@ | |||
12 | */ | 12 | */ |
13 | #ifndef __DAX_H__ | 13 | #ifndef __DAX_H__ |
14 | #define __DAX_H__ | 14 | #define __DAX_H__ |
15 | struct device; | 15 | struct dax_device; |
16 | struct dax_dev; | 16 | struct dax_device *inode_dax(struct inode *inode); |
17 | struct resource; | 17 | struct inode *dax_inode(struct dax_device *dax_dev); |
18 | struct dax_region; | ||
19 | void dax_region_put(struct dax_region *dax_region); | ||
20 | struct dax_region *alloc_dax_region(struct device *parent, | ||
21 | int region_id, struct resource *res, unsigned int align, | ||
22 | void *addr, unsigned long flags); | ||
23 | struct dax_dev *devm_create_dax_dev(struct dax_region *dax_region, | ||
24 | struct resource *res, int count); | ||
25 | #endif /* __DAX_H__ */ | 18 | #endif /* __DAX_H__ */ |
diff --git a/drivers/dax/device-dax.h b/drivers/dax/device-dax.h new file mode 100644 index 000000000000..fdcd9769ffde --- /dev/null +++ b/drivers/dax/device-dax.h | |||
@@ -0,0 +1,25 @@ | |||
1 | /* | ||
2 | * Copyright(c) 2016 Intel Corporation. All rights reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of version 2 of the GNU General Public License as | ||
6 | * published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, but | ||
9 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
11 | * General Public License for more details. | ||
12 | */ | ||
13 | #ifndef __DEVICE_DAX_H__ | ||
14 | #define __DEVICE_DAX_H__ | ||
15 | struct device; | ||
16 | struct dev_dax; | ||
17 | struct resource; | ||
18 | struct dax_region; | ||
19 | void dax_region_put(struct dax_region *dax_region); | ||
20 | struct dax_region *alloc_dax_region(struct device *parent, | ||
21 | int region_id, struct resource *res, unsigned int align, | ||
22 | void *addr, unsigned long flags); | ||
23 | struct dev_dax *devm_create_dev_dax(struct dax_region *dax_region, | ||
24 | struct resource *res, int count); | ||
25 | #endif /* __DEVICE_DAX_H__ */ | ||
diff --git a/drivers/dax/dax.c b/drivers/dax/device.c index 5e8302d3a89c..006e657dfcb9 100644 --- a/drivers/dax/dax.c +++ b/drivers/dax/device.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright(c) 2016 Intel Corporation. All rights reserved. | 2 | * Copyright(c) 2016 - 2017 Intel Corporation. All rights reserved. |
3 | * | 3 | * |
4 | * This program is free software; you can redistribute it and/or modify | 4 | * This program is free software; you can redistribute it and/or modify |
5 | * it under the terms of version 2 of the GNU General Public License as | 5 | * it under the terms of version 2 of the GNU General Public License as |
@@ -13,10 +13,7 @@ | |||
13 | #include <linux/pagemap.h> | 13 | #include <linux/pagemap.h> |
14 | #include <linux/module.h> | 14 | #include <linux/module.h> |
15 | #include <linux/device.h> | 15 | #include <linux/device.h> |
16 | #include <linux/magic.h> | ||
17 | #include <linux/mount.h> | ||
18 | #include <linux/pfn_t.h> | 16 | #include <linux/pfn_t.h> |
19 | #include <linux/hash.h> | ||
20 | #include <linux/cdev.h> | 17 | #include <linux/cdev.h> |
21 | #include <linux/slab.h> | 18 | #include <linux/slab.h> |
22 | #include <linux/dax.h> | 19 | #include <linux/dax.h> |
@@ -25,16 +22,7 @@ | |||
25 | #include "dax-private.h" | 22 | #include "dax-private.h" |
26 | #include "dax.h" | 23 | #include "dax.h" |
27 | 24 | ||
28 | static dev_t dax_devt; | ||
29 | DEFINE_STATIC_SRCU(dax_srcu); | ||
30 | static struct class *dax_class; | 25 | static struct class *dax_class; |
31 | static DEFINE_IDA(dax_minor_ida); | ||
32 | static int nr_dax = CONFIG_NR_DEV_DAX; | ||
33 | module_param(nr_dax, int, S_IRUGO); | ||
34 | static struct vfsmount *dax_mnt; | ||
35 | static struct kmem_cache *dax_cache __read_mostly; | ||
36 | static struct super_block *dax_superblock __read_mostly; | ||
37 | MODULE_PARM_DESC(nr_dax, "max number of device-dax instances"); | ||
38 | 26 | ||
39 | /* | 27 | /* |
40 | * Rely on the fact that drvdata is set before the attributes are | 28 | * Rely on the fact that drvdata is set before the attributes are |
@@ -87,117 +75,6 @@ static const struct attribute_group *dax_region_attribute_groups[] = { | |||
87 | NULL, | 75 | NULL, |
88 | }; | 76 | }; |
89 | 77 | ||
90 | static struct inode *dax_alloc_inode(struct super_block *sb) | ||
91 | { | ||
92 | return kmem_cache_alloc(dax_cache, GFP_KERNEL); | ||
93 | } | ||
94 | |||
95 | static void dax_i_callback(struct rcu_head *head) | ||
96 | { | ||
97 | struct inode *inode = container_of(head, struct inode, i_rcu); | ||
98 | |||
99 | kmem_cache_free(dax_cache, inode); | ||
100 | } | ||
101 | |||
102 | static void dax_destroy_inode(struct inode *inode) | ||
103 | { | ||
104 | call_rcu(&inode->i_rcu, dax_i_callback); | ||
105 | } | ||
106 | |||
107 | static const struct super_operations dax_sops = { | ||
108 | .statfs = simple_statfs, | ||
109 | .alloc_inode = dax_alloc_inode, | ||
110 | .destroy_inode = dax_destroy_inode, | ||
111 | .drop_inode = generic_delete_inode, | ||
112 | }; | ||
113 | |||
114 | static struct dentry *dax_mount(struct file_system_type *fs_type, | ||
115 | int flags, const char *dev_name, void *data) | ||
116 | { | ||
117 | return mount_pseudo(fs_type, "dax:", &dax_sops, NULL, DAXFS_MAGIC); | ||
118 | } | ||
119 | |||
120 | static struct file_system_type dax_type = { | ||
121 | .name = "dax", | ||
122 | .mount = dax_mount, | ||
123 | .kill_sb = kill_anon_super, | ||
124 | }; | ||
125 | |||
126 | static int dax_test(struct inode *inode, void *data) | ||
127 | { | ||
128 | return inode->i_cdev == data; | ||
129 | } | ||
130 | |||
131 | static int dax_set(struct inode *inode, void *data) | ||
132 | { | ||
133 | inode->i_cdev = data; | ||
134 | return 0; | ||
135 | } | ||
136 | |||
137 | static struct inode *dax_inode_get(struct cdev *cdev, dev_t devt) | ||
138 | { | ||
139 | struct inode *inode; | ||
140 | |||
141 | inode = iget5_locked(dax_superblock, hash_32(devt + DAXFS_MAGIC, 31), | ||
142 | dax_test, dax_set, cdev); | ||
143 | |||
144 | if (!inode) | ||
145 | return NULL; | ||
146 | |||
147 | if (inode->i_state & I_NEW) { | ||
148 | inode->i_mode = S_IFCHR; | ||
149 | inode->i_flags = S_DAX; | ||
150 | inode->i_rdev = devt; | ||
151 | mapping_set_gfp_mask(&inode->i_data, GFP_USER); | ||
152 | unlock_new_inode(inode); | ||
153 | } | ||
154 | return inode; | ||
155 | } | ||
156 | |||
157 | static void init_once(void *inode) | ||
158 | { | ||
159 | inode_init_once(inode); | ||
160 | } | ||
161 | |||
162 | static int dax_inode_init(void) | ||
163 | { | ||
164 | int rc; | ||
165 | |||
166 | dax_cache = kmem_cache_create("dax_cache", sizeof(struct inode), 0, | ||
167 | (SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT| | ||
168 | SLAB_MEM_SPREAD|SLAB_ACCOUNT), | ||
169 | init_once); | ||
170 | if (!dax_cache) | ||
171 | return -ENOMEM; | ||
172 | |||
173 | rc = register_filesystem(&dax_type); | ||
174 | if (rc) | ||
175 | goto err_register_fs; | ||
176 | |||
177 | dax_mnt = kern_mount(&dax_type); | ||
178 | if (IS_ERR(dax_mnt)) { | ||
179 | rc = PTR_ERR(dax_mnt); | ||
180 | goto err_mount; | ||
181 | } | ||
182 | dax_superblock = dax_mnt->mnt_sb; | ||
183 | |||
184 | return 0; | ||
185 | |||
186 | err_mount: | ||
187 | unregister_filesystem(&dax_type); | ||
188 | err_register_fs: | ||
189 | kmem_cache_destroy(dax_cache); | ||
190 | |||
191 | return rc; | ||
192 | } | ||
193 | |||
194 | static void dax_inode_exit(void) | ||
195 | { | ||
196 | kern_unmount(dax_mnt); | ||
197 | unregister_filesystem(&dax_type); | ||
198 | kmem_cache_destroy(dax_cache); | ||
199 | } | ||
200 | |||
201 | static void dax_region_free(struct kref *kref) | 78 | static void dax_region_free(struct kref *kref) |
202 | { | 79 | { |
203 | struct dax_region *dax_region; | 80 | struct dax_region *dax_region; |
@@ -266,47 +143,47 @@ struct dax_region *alloc_dax_region(struct device *parent, int region_id, | |||
266 | } | 143 | } |
267 | EXPORT_SYMBOL_GPL(alloc_dax_region); | 144 | EXPORT_SYMBOL_GPL(alloc_dax_region); |
268 | 145 | ||
269 | static struct dax_dev *to_dax_dev(struct device *dev) | 146 | static struct dev_dax *to_dev_dax(struct device *dev) |
270 | { | 147 | { |
271 | return container_of(dev, struct dax_dev, dev); | 148 | return container_of(dev, struct dev_dax, dev); |
272 | } | 149 | } |
273 | 150 | ||
274 | static ssize_t size_show(struct device *dev, | 151 | static ssize_t size_show(struct device *dev, |
275 | struct device_attribute *attr, char *buf) | 152 | struct device_attribute *attr, char *buf) |
276 | { | 153 | { |
277 | struct dax_dev *dax_dev = to_dax_dev(dev); | 154 | struct dev_dax *dev_dax = to_dev_dax(dev); |
278 | unsigned long long size = 0; | 155 | unsigned long long size = 0; |
279 | int i; | 156 | int i; |
280 | 157 | ||
281 | for (i = 0; i < dax_dev->num_resources; i++) | 158 | for (i = 0; i < dev_dax->num_resources; i++) |
282 | size += resource_size(&dax_dev->res[i]); | 159 | size += resource_size(&dev_dax->res[i]); |
283 | 160 | ||
284 | return sprintf(buf, "%llu\n", size); | 161 | return sprintf(buf, "%llu\n", size); |
285 | } | 162 | } |
286 | static DEVICE_ATTR_RO(size); | 163 | static DEVICE_ATTR_RO(size); |
287 | 164 | ||
288 | static struct attribute *dax_device_attributes[] = { | 165 | static struct attribute *dev_dax_attributes[] = { |
289 | &dev_attr_size.attr, | 166 | &dev_attr_size.attr, |
290 | NULL, | 167 | NULL, |
291 | }; | 168 | }; |
292 | 169 | ||
293 | static const struct attribute_group dax_device_attribute_group = { | 170 | static const struct attribute_group dev_dax_attribute_group = { |
294 | .attrs = dax_device_attributes, | 171 | .attrs = dev_dax_attributes, |
295 | }; | 172 | }; |
296 | 173 | ||
297 | static const struct attribute_group *dax_attribute_groups[] = { | 174 | static const struct attribute_group *dax_attribute_groups[] = { |
298 | &dax_device_attribute_group, | 175 | &dev_dax_attribute_group, |
299 | NULL, | 176 | NULL, |
300 | }; | 177 | }; |
301 | 178 | ||
302 | static int check_vma(struct dax_dev *dax_dev, struct vm_area_struct *vma, | 179 | static int check_vma(struct dev_dax *dev_dax, struct vm_area_struct *vma, |
303 | const char *func) | 180 | const char *func) |
304 | { | 181 | { |
305 | struct dax_region *dax_region = dax_dev->region; | 182 | struct dax_region *dax_region = dev_dax->region; |
306 | struct device *dev = &dax_dev->dev; | 183 | struct device *dev = &dev_dax->dev; |
307 | unsigned long mask; | 184 | unsigned long mask; |
308 | 185 | ||
309 | if (!dax_dev->alive) | 186 | if (!dax_alive(dev_dax->dax_dev)) |
310 | return -ENXIO; | 187 | return -ENXIO; |
311 | 188 | ||
312 | /* prevent private mappings from being established */ | 189 | /* prevent private mappings from being established */ |
@@ -341,23 +218,23 @@ static int check_vma(struct dax_dev *dax_dev, struct vm_area_struct *vma, | |||
341 | } | 218 | } |
342 | 219 | ||
343 | /* see "strong" declaration in tools/testing/nvdimm/dax-dev.c */ | 220 | /* see "strong" declaration in tools/testing/nvdimm/dax-dev.c */ |
344 | __weak phys_addr_t dax_pgoff_to_phys(struct dax_dev *dax_dev, pgoff_t pgoff, | 221 | __weak phys_addr_t dax_pgoff_to_phys(struct dev_dax *dev_dax, pgoff_t pgoff, |
345 | unsigned long size) | 222 | unsigned long size) |
346 | { | 223 | { |
347 | struct resource *res; | 224 | struct resource *res; |
348 | phys_addr_t phys; | 225 | phys_addr_t phys; |
349 | int i; | 226 | int i; |
350 | 227 | ||
351 | for (i = 0; i < dax_dev->num_resources; i++) { | 228 | for (i = 0; i < dev_dax->num_resources; i++) { |
352 | res = &dax_dev->res[i]; | 229 | res = &dev_dax->res[i]; |
353 | phys = pgoff * PAGE_SIZE + res->start; | 230 | phys = pgoff * PAGE_SIZE + res->start; |
354 | if (phys >= res->start && phys <= res->end) | 231 | if (phys >= res->start && phys <= res->end) |
355 | break; | 232 | break; |
356 | pgoff -= PHYS_PFN(resource_size(res)); | 233 | pgoff -= PHYS_PFN(resource_size(res)); |
357 | } | 234 | } |
358 | 235 | ||
359 | if (i < dax_dev->num_resources) { | 236 | if (i < dev_dax->num_resources) { |
360 | res = &dax_dev->res[i]; | 237 | res = &dev_dax->res[i]; |
361 | if (phys + size - 1 <= res->end) | 238 | if (phys + size - 1 <= res->end) |
362 | return phys; | 239 | return phys; |
363 | } | 240 | } |
@@ -365,28 +242,29 @@ __weak phys_addr_t dax_pgoff_to_phys(struct dax_dev *dax_dev, pgoff_t pgoff, | |||
365 | return -1; | 242 | return -1; |
366 | } | 243 | } |
367 | 244 | ||
368 | static int __dax_dev_pte_fault(struct dax_dev *dax_dev, struct vm_fault *vmf) | 245 | static int __dev_dax_pte_fault(struct dev_dax *dev_dax, struct vm_fault *vmf) |
369 | { | 246 | { |
370 | struct device *dev = &dax_dev->dev; | 247 | struct device *dev = &dev_dax->dev; |
371 | struct dax_region *dax_region; | 248 | struct dax_region *dax_region; |
372 | int rc = VM_FAULT_SIGBUS; | 249 | int rc = VM_FAULT_SIGBUS; |
373 | phys_addr_t phys; | 250 | phys_addr_t phys; |
374 | pfn_t pfn; | 251 | pfn_t pfn; |
375 | unsigned int fault_size = PAGE_SIZE; | 252 | unsigned int fault_size = PAGE_SIZE; |
376 | 253 | ||
377 | if (check_vma(dax_dev, vmf->vma, __func__)) | 254 | if (check_vma(dev_dax, vmf->vma, __func__)) |
378 | return VM_FAULT_SIGBUS; | 255 | return VM_FAULT_SIGBUS; |
379 | 256 | ||
380 | dax_region = dax_dev->region; | 257 | dax_region = dev_dax->region; |
381 | if (dax_region->align > PAGE_SIZE) { | 258 | if (dax_region->align > PAGE_SIZE) { |
382 | dev_dbg(dev, "%s: alignment > fault size\n", __func__); | 259 | dev_dbg(dev, "%s: alignment (%#x) > fault size (%#x)\n", |
260 | __func__, dax_region->align, fault_size); | ||
383 | return VM_FAULT_SIGBUS; | 261 | return VM_FAULT_SIGBUS; |
384 | } | 262 | } |
385 | 263 | ||
386 | if (fault_size != dax_region->align) | 264 | if (fault_size != dax_region->align) |
387 | return VM_FAULT_SIGBUS; | 265 | return VM_FAULT_SIGBUS; |
388 | 266 | ||
389 | phys = dax_pgoff_to_phys(dax_dev, vmf->pgoff, PAGE_SIZE); | 267 | phys = dax_pgoff_to_phys(dev_dax, vmf->pgoff, PAGE_SIZE); |
390 | if (phys == -1) { | 268 | if (phys == -1) { |
391 | dev_dbg(dev, "%s: pgoff_to_phys(%#lx) failed\n", __func__, | 269 | dev_dbg(dev, "%s: pgoff_to_phys(%#lx) failed\n", __func__, |
392 | vmf->pgoff); | 270 | vmf->pgoff); |
@@ -405,28 +283,29 @@ static int __dax_dev_pte_fault(struct dax_dev *dax_dev, struct vm_fault *vmf) | |||
405 | return VM_FAULT_NOPAGE; | 283 | return VM_FAULT_NOPAGE; |
406 | } | 284 | } |
407 | 285 | ||
408 | static int __dax_dev_pmd_fault(struct dax_dev *dax_dev, struct vm_fault *vmf) | 286 | static int __dev_dax_pmd_fault(struct dev_dax *dev_dax, struct vm_fault *vmf) |
409 | { | 287 | { |
410 | unsigned long pmd_addr = vmf->address & PMD_MASK; | 288 | unsigned long pmd_addr = vmf->address & PMD_MASK; |
411 | struct device *dev = &dax_dev->dev; | 289 | struct device *dev = &dev_dax->dev; |
412 | struct dax_region *dax_region; | 290 | struct dax_region *dax_region; |
413 | phys_addr_t phys; | 291 | phys_addr_t phys; |
414 | pgoff_t pgoff; | 292 | pgoff_t pgoff; |
415 | pfn_t pfn; | 293 | pfn_t pfn; |
416 | unsigned int fault_size = PMD_SIZE; | 294 | unsigned int fault_size = PMD_SIZE; |
417 | 295 | ||
418 | if (check_vma(dax_dev, vmf->vma, __func__)) | 296 | if (check_vma(dev_dax, vmf->vma, __func__)) |
419 | return VM_FAULT_SIGBUS; | 297 | return VM_FAULT_SIGBUS; |
420 | 298 | ||
421 | dax_region = dax_dev->region; | 299 | dax_region = dev_dax->region; |
422 | if (dax_region->align > PMD_SIZE) { | 300 | if (dax_region->align > PMD_SIZE) { |
423 | dev_dbg(dev, "%s: alignment > fault size\n", __func__); | 301 | dev_dbg(dev, "%s: alignment (%#x) > fault size (%#x)\n", |
302 | __func__, dax_region->align, fault_size); | ||
424 | return VM_FAULT_SIGBUS; | 303 | return VM_FAULT_SIGBUS; |
425 | } | 304 | } |
426 | 305 | ||
427 | /* dax pmd mappings require pfn_t_devmap() */ | 306 | /* dax pmd mappings require pfn_t_devmap() */ |
428 | if ((dax_region->pfn_flags & (PFN_DEV|PFN_MAP)) != (PFN_DEV|PFN_MAP)) { | 307 | if ((dax_region->pfn_flags & (PFN_DEV|PFN_MAP)) != (PFN_DEV|PFN_MAP)) { |
429 | dev_dbg(dev, "%s: alignment > fault size\n", __func__); | 308 | dev_dbg(dev, "%s: region lacks devmap flags\n", __func__); |
430 | return VM_FAULT_SIGBUS; | 309 | return VM_FAULT_SIGBUS; |
431 | } | 310 | } |
432 | 311 | ||
@@ -441,7 +320,7 @@ static int __dax_dev_pmd_fault(struct dax_dev *dax_dev, struct vm_fault *vmf) | |||
441 | return VM_FAULT_SIGBUS; | 320 | return VM_FAULT_SIGBUS; |
442 | 321 | ||
443 | pgoff = linear_page_index(vmf->vma, pmd_addr); | 322 | pgoff = linear_page_index(vmf->vma, pmd_addr); |
444 | phys = dax_pgoff_to_phys(dax_dev, pgoff, PMD_SIZE); | 323 | phys = dax_pgoff_to_phys(dev_dax, pgoff, PMD_SIZE); |
445 | if (phys == -1) { | 324 | if (phys == -1) { |
446 | dev_dbg(dev, "%s: pgoff_to_phys(%#lx) failed\n", __func__, | 325 | dev_dbg(dev, "%s: pgoff_to_phys(%#lx) failed\n", __func__, |
447 | pgoff); | 326 | pgoff); |
@@ -455,10 +334,10 @@ static int __dax_dev_pmd_fault(struct dax_dev *dax_dev, struct vm_fault *vmf) | |||
455 | } | 334 | } |
456 | 335 | ||
457 | #ifdef CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD | 336 | #ifdef CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD |
458 | static int __dax_dev_pud_fault(struct dax_dev *dax_dev, struct vm_fault *vmf) | 337 | static int __dev_dax_pud_fault(struct dev_dax *dev_dax, struct vm_fault *vmf) |
459 | { | 338 | { |
460 | unsigned long pud_addr = vmf->address & PUD_MASK; | 339 | unsigned long pud_addr = vmf->address & PUD_MASK; |
461 | struct device *dev = &dax_dev->dev; | 340 | struct device *dev = &dev_dax->dev; |
462 | struct dax_region *dax_region; | 341 | struct dax_region *dax_region; |
463 | phys_addr_t phys; | 342 | phys_addr_t phys; |
464 | pgoff_t pgoff; | 343 | pgoff_t pgoff; |
@@ -466,18 +345,19 @@ static int __dax_dev_pud_fault(struct dax_dev *dax_dev, struct vm_fault *vmf) | |||
466 | unsigned int fault_size = PUD_SIZE; | 345 | unsigned int fault_size = PUD_SIZE; |
467 | 346 | ||
468 | 347 | ||
469 | if (check_vma(dax_dev, vmf->vma, __func__)) | 348 | if (check_vma(dev_dax, vmf->vma, __func__)) |
470 | return VM_FAULT_SIGBUS; | 349 | return VM_FAULT_SIGBUS; |
471 | 350 | ||
472 | dax_region = dax_dev->region; | 351 | dax_region = dev_dax->region; |
473 | if (dax_region->align > PUD_SIZE) { | 352 | if (dax_region->align > PUD_SIZE) { |
474 | dev_dbg(dev, "%s: alignment > fault size\n", __func__); | 353 | dev_dbg(dev, "%s: alignment (%#x) > fault size (%#x)\n", |
354 | __func__, dax_region->align, fault_size); | ||
475 | return VM_FAULT_SIGBUS; | 355 | return VM_FAULT_SIGBUS; |
476 | } | 356 | } |
477 | 357 | ||
478 | /* dax pud mappings require pfn_t_devmap() */ | 358 | /* dax pud mappings require pfn_t_devmap() */ |
479 | if ((dax_region->pfn_flags & (PFN_DEV|PFN_MAP)) != (PFN_DEV|PFN_MAP)) { | 359 | if ((dax_region->pfn_flags & (PFN_DEV|PFN_MAP)) != (PFN_DEV|PFN_MAP)) { |
480 | dev_dbg(dev, "%s: alignment > fault size\n", __func__); | 360 | dev_dbg(dev, "%s: region lacks devmap flags\n", __func__); |
481 | return VM_FAULT_SIGBUS; | 361 | return VM_FAULT_SIGBUS; |
482 | } | 362 | } |
483 | 363 | ||
@@ -492,7 +372,7 @@ static int __dax_dev_pud_fault(struct dax_dev *dax_dev, struct vm_fault *vmf) | |||
492 | return VM_FAULT_SIGBUS; | 372 | return VM_FAULT_SIGBUS; |
493 | 373 | ||
494 | pgoff = linear_page_index(vmf->vma, pud_addr); | 374 | pgoff = linear_page_index(vmf->vma, pud_addr); |
495 | phys = dax_pgoff_to_phys(dax_dev, pgoff, PUD_SIZE); | 375 | phys = dax_pgoff_to_phys(dev_dax, pgoff, PUD_SIZE); |
496 | if (phys == -1) { | 376 | if (phys == -1) { |
497 | dev_dbg(dev, "%s: pgoff_to_phys(%#lx) failed\n", __func__, | 377 | dev_dbg(dev, "%s: pgoff_to_phys(%#lx) failed\n", __func__, |
498 | pgoff); | 378 | pgoff); |
@@ -505,65 +385,71 @@ static int __dax_dev_pud_fault(struct dax_dev *dax_dev, struct vm_fault *vmf) | |||
505 | vmf->flags & FAULT_FLAG_WRITE); | 385 | vmf->flags & FAULT_FLAG_WRITE); |
506 | } | 386 | } |
507 | #else | 387 | #else |
508 | static int __dax_dev_pud_fault(struct dax_dev *dax_dev, struct vm_fault *vmf) | 388 | static int __dev_dax_pud_fault(struct dev_dax *dev_dax, struct vm_fault *vmf) |
509 | { | 389 | { |
510 | return VM_FAULT_FALLBACK; | 390 | return VM_FAULT_FALLBACK; |
511 | } | 391 | } |
512 | #endif /* !CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD */ | 392 | #endif /* !CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD */ |
513 | 393 | ||
514 | static int dax_dev_huge_fault(struct vm_fault *vmf, | 394 | static int dev_dax_huge_fault(struct vm_fault *vmf, |
515 | enum page_entry_size pe_size) | 395 | enum page_entry_size pe_size) |
516 | { | 396 | { |
517 | int rc, id; | 397 | int rc, id; |
518 | struct file *filp = vmf->vma->vm_file; | 398 | struct file *filp = vmf->vma->vm_file; |
519 | struct dax_dev *dax_dev = filp->private_data; | 399 | struct dev_dax *dev_dax = filp->private_data; |
520 | 400 | ||
521 | dev_dbg(&dax_dev->dev, "%s: %s: %s (%#lx - %#lx)\n", __func__, | 401 | dev_dbg(&dev_dax->dev, "%s: %s: %s (%#lx - %#lx) size = %d\n", __func__, |
522 | current->comm, (vmf->flags & FAULT_FLAG_WRITE) | 402 | current->comm, (vmf->flags & FAULT_FLAG_WRITE) |
523 | ? "write" : "read", | 403 | ? "write" : "read", |
524 | vmf->vma->vm_start, vmf->vma->vm_end); | 404 | vmf->vma->vm_start, vmf->vma->vm_end, pe_size); |
525 | 405 | ||
526 | id = srcu_read_lock(&dax_srcu); | 406 | id = dax_read_lock(); |
527 | switch (pe_size) { | 407 | switch (pe_size) { |
528 | case PE_SIZE_PTE: | 408 | case PE_SIZE_PTE: |
529 | rc = __dax_dev_pte_fault(dax_dev, vmf); | 409 | rc = __dev_dax_pte_fault(dev_dax, vmf); |
530 | break; | 410 | break; |
531 | case PE_SIZE_PMD: | 411 | case PE_SIZE_PMD: |
532 | rc = __dax_dev_pmd_fault(dax_dev, vmf); | 412 | rc = __dev_dax_pmd_fault(dev_dax, vmf); |
533 | break; | 413 | break; |
534 | case PE_SIZE_PUD: | 414 | case PE_SIZE_PUD: |
535 | rc = __dax_dev_pud_fault(dax_dev, vmf); | 415 | rc = __dev_dax_pud_fault(dev_dax, vmf); |
536 | break; | 416 | break; |
537 | default: | 417 | default: |
538 | return VM_FAULT_FALLBACK; | 418 | rc = VM_FAULT_SIGBUS; |
539 | } | 419 | } |
540 | srcu_read_unlock(&dax_srcu, id); | 420 | dax_read_unlock(id); |
541 | 421 | ||
542 | return rc; | 422 | return rc; |
543 | } | 423 | } |
544 | 424 | ||
545 | static int dax_dev_fault(struct vm_fault *vmf) | 425 | static int dev_dax_fault(struct vm_fault *vmf) |
546 | { | 426 | { |
547 | return dax_dev_huge_fault(vmf, PE_SIZE_PTE); | 427 | return dev_dax_huge_fault(vmf, PE_SIZE_PTE); |
548 | } | 428 | } |
549 | 429 | ||
550 | static const struct vm_operations_struct dax_dev_vm_ops = { | 430 | static const struct vm_operations_struct dax_vm_ops = { |
551 | .fault = dax_dev_fault, | 431 | .fault = dev_dax_fault, |
552 | .huge_fault = dax_dev_huge_fault, | 432 | .huge_fault = dev_dax_huge_fault, |
553 | }; | 433 | }; |
554 | 434 | ||
555 | static int dax_mmap(struct file *filp, struct vm_area_struct *vma) | 435 | static int dax_mmap(struct file *filp, struct vm_area_struct *vma) |
556 | { | 436 | { |
557 | struct dax_dev *dax_dev = filp->private_data; | 437 | struct dev_dax *dev_dax = filp->private_data; |
558 | int rc; | 438 | int rc, id; |
559 | 439 | ||
560 | dev_dbg(&dax_dev->dev, "%s\n", __func__); | 440 | dev_dbg(&dev_dax->dev, "%s\n", __func__); |
561 | 441 | ||
562 | rc = check_vma(dax_dev, vma, __func__); | 442 | /* |
443 | * We lock to check dax_dev liveness and will re-check at | ||
444 | * fault time. | ||
445 | */ | ||
446 | id = dax_read_lock(); | ||
447 | rc = check_vma(dev_dax, vma, __func__); | ||
448 | dax_read_unlock(id); | ||
563 | if (rc) | 449 | if (rc) |
564 | return rc; | 450 | return rc; |
565 | 451 | ||
566 | vma->vm_ops = &dax_dev_vm_ops; | 452 | vma->vm_ops = &dax_vm_ops; |
567 | vma->vm_flags |= VM_MIXEDMAP | VM_HUGEPAGE; | 453 | vma->vm_flags |= VM_MIXEDMAP | VM_HUGEPAGE; |
568 | return 0; | 454 | return 0; |
569 | } | 455 | } |
@@ -574,13 +460,13 @@ static unsigned long dax_get_unmapped_area(struct file *filp, | |||
574 | unsigned long flags) | 460 | unsigned long flags) |
575 | { | 461 | { |
576 | unsigned long off, off_end, off_align, len_align, addr_align, align; | 462 | unsigned long off, off_end, off_align, len_align, addr_align, align; |
577 | struct dax_dev *dax_dev = filp ? filp->private_data : NULL; | 463 | struct dev_dax *dev_dax = filp ? filp->private_data : NULL; |
578 | struct dax_region *dax_region; | 464 | struct dax_region *dax_region; |
579 | 465 | ||
580 | if (!dax_dev || addr) | 466 | if (!dev_dax || addr) |
581 | goto out; | 467 | goto out; |
582 | 468 | ||
583 | dax_region = dax_dev->region; | 469 | dax_region = dev_dax->region; |
584 | align = dax_region->align; | 470 | align = dax_region->align; |
585 | off = pgoff << PAGE_SHIFT; | 471 | off = pgoff << PAGE_SHIFT; |
586 | off_end = off + len; | 472 | off_end = off + len; |
@@ -605,14 +491,15 @@ static unsigned long dax_get_unmapped_area(struct file *filp, | |||
605 | 491 | ||
606 | static int dax_open(struct inode *inode, struct file *filp) | 492 | static int dax_open(struct inode *inode, struct file *filp) |
607 | { | 493 | { |
608 | struct dax_dev *dax_dev; | 494 | struct dax_device *dax_dev = inode_dax(inode); |
495 | struct inode *__dax_inode = dax_inode(dax_dev); | ||
496 | struct dev_dax *dev_dax = dax_get_private(dax_dev); | ||
609 | 497 | ||
610 | dax_dev = container_of(inode->i_cdev, struct dax_dev, cdev); | 498 | dev_dbg(&dev_dax->dev, "%s\n", __func__); |
611 | dev_dbg(&dax_dev->dev, "%s\n", __func__); | 499 | inode->i_mapping = __dax_inode->i_mapping; |
612 | inode->i_mapping = dax_dev->inode->i_mapping; | 500 | inode->i_mapping->host = __dax_inode; |
613 | inode->i_mapping->host = dax_dev->inode; | ||
614 | filp->f_mapping = inode->i_mapping; | 501 | filp->f_mapping = inode->i_mapping; |
615 | filp->private_data = dax_dev; | 502 | filp->private_data = dev_dax; |
616 | inode->i_flags = S_DAX; | 503 | inode->i_flags = S_DAX; |
617 | 504 | ||
618 | return 0; | 505 | return 0; |
@@ -620,9 +507,9 @@ static int dax_open(struct inode *inode, struct file *filp) | |||
620 | 507 | ||
621 | static int dax_release(struct inode *inode, struct file *filp) | 508 | static int dax_release(struct inode *inode, struct file *filp) |
622 | { | 509 | { |
623 | struct dax_dev *dax_dev = filp->private_data; | 510 | struct dev_dax *dev_dax = filp->private_data; |
624 | 511 | ||
625 | dev_dbg(&dax_dev->dev, "%s\n", __func__); | 512 | dev_dbg(&dev_dax->dev, "%s\n", __func__); |
626 | return 0; | 513 | return 0; |
627 | } | 514 | } |
628 | 515 | ||
@@ -635,51 +522,54 @@ static const struct file_operations dax_fops = { | |||
635 | .mmap = dax_mmap, | 522 | .mmap = dax_mmap, |
636 | }; | 523 | }; |
637 | 524 | ||
638 | static void dax_dev_release(struct device *dev) | 525 | static void dev_dax_release(struct device *dev) |
639 | { | 526 | { |
640 | struct dax_dev *dax_dev = to_dax_dev(dev); | 527 | struct dev_dax *dev_dax = to_dev_dax(dev); |
641 | struct dax_region *dax_region = dax_dev->region; | 528 | struct dax_region *dax_region = dev_dax->region; |
529 | struct dax_device *dax_dev = dev_dax->dax_dev; | ||
642 | 530 | ||
643 | ida_simple_remove(&dax_region->ida, dax_dev->id); | 531 | ida_simple_remove(&dax_region->ida, dev_dax->id); |
644 | ida_simple_remove(&dax_minor_ida, MINOR(dev->devt)); | ||
645 | dax_region_put(dax_region); | 532 | dax_region_put(dax_region); |
646 | iput(dax_dev->inode); | 533 | put_dax(dax_dev); |
647 | kfree(dax_dev); | 534 | kfree(dev_dax); |
535 | } | ||
536 | |||
537 | static void kill_dev_dax(struct dev_dax *dev_dax) | ||
538 | { | ||
539 | struct dax_device *dax_dev = dev_dax->dax_dev; | ||
540 | struct inode *inode = dax_inode(dax_dev); | ||
541 | |||
542 | kill_dax(dax_dev); | ||
543 | unmap_mapping_range(inode->i_mapping, 0, 0, 1); | ||
648 | } | 544 | } |
649 | 545 | ||
650 | static void unregister_dax_dev(void *dev) | 546 | static void unregister_dev_dax(void *dev) |
651 | { | 547 | { |
652 | struct dax_dev *dax_dev = to_dax_dev(dev); | 548 | struct dev_dax *dev_dax = to_dev_dax(dev); |
653 | struct cdev *cdev = &dax_dev->cdev; | 549 | struct dax_device *dax_dev = dev_dax->dax_dev; |
550 | struct inode *inode = dax_inode(dax_dev); | ||
551 | struct cdev *cdev = inode->i_cdev; | ||
654 | 552 | ||
655 | dev_dbg(dev, "%s\n", __func__); | 553 | dev_dbg(dev, "%s\n", __func__); |
656 | 554 | ||
657 | /* | 555 | kill_dev_dax(dev_dax); |
658 | * Note, rcu is not protecting the liveness of dax_dev, rcu is | 556 | cdev_device_del(cdev, dev); |
659 | * ensuring that any fault handlers that might have seen | 557 | put_device(dev); |
660 | * dax_dev->alive == true, have completed. Any fault handlers | ||
661 | * that start after synchronize_srcu() has started will abort | ||
662 | * upon seeing dax_dev->alive == false. | ||
663 | */ | ||
664 | dax_dev->alive = false; | ||
665 | synchronize_srcu(&dax_srcu); | ||
666 | unmap_mapping_range(dax_dev->inode->i_mapping, 0, 0, 1); | ||
667 | cdev_del(cdev); | ||
668 | device_unregister(dev); | ||
669 | } | 558 | } |
670 | 559 | ||
671 | struct dax_dev *devm_create_dax_dev(struct dax_region *dax_region, | 560 | struct dev_dax *devm_create_dev_dax(struct dax_region *dax_region, |
672 | struct resource *res, int count) | 561 | struct resource *res, int count) |
673 | { | 562 | { |
674 | struct device *parent = dax_region->dev; | 563 | struct device *parent = dax_region->dev; |
675 | struct dax_dev *dax_dev; | 564 | struct dax_device *dax_dev; |
676 | int rc = 0, minor, i; | 565 | struct dev_dax *dev_dax; |
566 | struct inode *inode; | ||
677 | struct device *dev; | 567 | struct device *dev; |
678 | struct cdev *cdev; | 568 | struct cdev *cdev; |
679 | dev_t dev_t; | 569 | int rc = 0, i; |
680 | 570 | ||
681 | dax_dev = kzalloc(sizeof(*dax_dev) + sizeof(*res) * count, GFP_KERNEL); | 571 | dev_dax = kzalloc(sizeof(*dev_dax) + sizeof(*res) * count, GFP_KERNEL); |
682 | if (!dax_dev) | 572 | if (!dev_dax) |
683 | return ERR_PTR(-ENOMEM); | 573 | return ERR_PTR(-ENOMEM); |
684 | 574 | ||
685 | for (i = 0; i < count; i++) { | 575 | for (i = 0; i < count; i++) { |
@@ -689,115 +579,79 @@ struct dax_dev *devm_create_dax_dev(struct dax_region *dax_region, | |||
689 | rc = -EINVAL; | 579 | rc = -EINVAL; |
690 | break; | 580 | break; |
691 | } | 581 | } |
692 | dax_dev->res[i].start = res[i].start; | 582 | dev_dax->res[i].start = res[i].start; |
693 | dax_dev->res[i].end = res[i].end; | 583 | dev_dax->res[i].end = res[i].end; |
694 | } | 584 | } |
695 | 585 | ||
696 | if (i < count) | 586 | if (i < count) |
697 | goto err_id; | 587 | goto err_id; |
698 | 588 | ||
699 | dax_dev->id = ida_simple_get(&dax_region->ida, 0, 0, GFP_KERNEL); | 589 | dev_dax->id = ida_simple_get(&dax_region->ida, 0, 0, GFP_KERNEL); |
700 | if (dax_dev->id < 0) { | 590 | if (dev_dax->id < 0) { |
701 | rc = dax_dev->id; | 591 | rc = dev_dax->id; |
702 | goto err_id; | 592 | goto err_id; |
703 | } | 593 | } |
704 | 594 | ||
705 | minor = ida_simple_get(&dax_minor_ida, 0, 0, GFP_KERNEL); | 595 | /* |
706 | if (minor < 0) { | 596 | * No 'host' or dax_operations since there is no access to this |
707 | rc = minor; | 597 | * device outside of mmap of the resulting character device. |
708 | goto err_minor; | 598 | */ |
709 | } | 599 | dax_dev = alloc_dax(dev_dax, NULL, NULL); |
710 | 600 | if (!dax_dev) | |
711 | dev_t = MKDEV(MAJOR(dax_devt), minor); | 601 | goto err_dax; |
712 | dev = &dax_dev->dev; | ||
713 | dax_dev->inode = dax_inode_get(&dax_dev->cdev, dev_t); | ||
714 | if (!dax_dev->inode) { | ||
715 | rc = -ENOMEM; | ||
716 | goto err_inode; | ||
717 | } | ||
718 | 602 | ||
719 | /* device_initialize() so cdev can reference kobj parent */ | 603 | /* from here on we're committed to teardown via dax_dev_release() */ |
604 | dev = &dev_dax->dev; | ||
720 | device_initialize(dev); | 605 | device_initialize(dev); |
721 | 606 | ||
722 | cdev = &dax_dev->cdev; | 607 | inode = dax_inode(dax_dev); |
608 | cdev = inode->i_cdev; | ||
723 | cdev_init(cdev, &dax_fops); | 609 | cdev_init(cdev, &dax_fops); |
724 | cdev->owner = parent->driver->owner; | 610 | cdev->owner = parent->driver->owner; |
725 | cdev->kobj.parent = &dev->kobj; | ||
726 | rc = cdev_add(&dax_dev->cdev, dev_t, 1); | ||
727 | if (rc) | ||
728 | goto err_cdev; | ||
729 | 611 | ||
730 | /* from here on we're committed to teardown via dax_dev_release() */ | 612 | dev_dax->num_resources = count; |
731 | dax_dev->num_resources = count; | 613 | dev_dax->dax_dev = dax_dev; |
732 | dax_dev->alive = true; | 614 | dev_dax->region = dax_region; |
733 | dax_dev->region = dax_region; | ||
734 | kref_get(&dax_region->kref); | 615 | kref_get(&dax_region->kref); |
735 | 616 | ||
736 | dev->devt = dev_t; | 617 | dev->devt = inode->i_rdev; |
737 | dev->class = dax_class; | 618 | dev->class = dax_class; |
738 | dev->parent = parent; | 619 | dev->parent = parent; |
739 | dev->groups = dax_attribute_groups; | 620 | dev->groups = dax_attribute_groups; |
740 | dev->release = dax_dev_release; | 621 | dev->release = dev_dax_release; |
741 | dev_set_name(dev, "dax%d.%d", dax_region->id, dax_dev->id); | 622 | dev_set_name(dev, "dax%d.%d", dax_region->id, dev_dax->id); |
742 | rc = device_add(dev); | 623 | |
624 | rc = cdev_device_add(cdev, dev); | ||
743 | if (rc) { | 625 | if (rc) { |
626 | kill_dev_dax(dev_dax); | ||
744 | put_device(dev); | 627 | put_device(dev); |
745 | return ERR_PTR(rc); | 628 | return ERR_PTR(rc); |
746 | } | 629 | } |
747 | 630 | ||
748 | rc = devm_add_action_or_reset(dax_region->dev, unregister_dax_dev, dev); | 631 | rc = devm_add_action_or_reset(dax_region->dev, unregister_dev_dax, dev); |
749 | if (rc) | 632 | if (rc) |
750 | return ERR_PTR(rc); | 633 | return ERR_PTR(rc); |
751 | 634 | ||
752 | return dax_dev; | 635 | return dev_dax; |
753 | 636 | ||
754 | err_cdev: | 637 | err_dax: |
755 | iput(dax_dev->inode); | 638 | ida_simple_remove(&dax_region->ida, dev_dax->id); |
756 | err_inode: | ||
757 | ida_simple_remove(&dax_minor_ida, minor); | ||
758 | err_minor: | ||
759 | ida_simple_remove(&dax_region->ida, dax_dev->id); | ||
760 | err_id: | 639 | err_id: |
761 | kfree(dax_dev); | 640 | kfree(dev_dax); |
762 | 641 | ||
763 | return ERR_PTR(rc); | 642 | return ERR_PTR(rc); |
764 | } | 643 | } |
765 | EXPORT_SYMBOL_GPL(devm_create_dax_dev); | 644 | EXPORT_SYMBOL_GPL(devm_create_dev_dax); |
766 | 645 | ||
767 | static int __init dax_init(void) | 646 | static int __init dax_init(void) |
768 | { | 647 | { |
769 | int rc; | ||
770 | |||
771 | rc = dax_inode_init(); | ||
772 | if (rc) | ||
773 | return rc; | ||
774 | |||
775 | nr_dax = max(nr_dax, 256); | ||
776 | rc = alloc_chrdev_region(&dax_devt, 0, nr_dax, "dax"); | ||
777 | if (rc) | ||
778 | goto err_chrdev; | ||
779 | |||
780 | dax_class = class_create(THIS_MODULE, "dax"); | 648 | dax_class = class_create(THIS_MODULE, "dax"); |
781 | if (IS_ERR(dax_class)) { | 649 | return PTR_ERR_OR_ZERO(dax_class); |
782 | rc = PTR_ERR(dax_class); | ||
783 | goto err_class; | ||
784 | } | ||
785 | |||
786 | return 0; | ||
787 | |||
788 | err_class: | ||
789 | unregister_chrdev_region(dax_devt, nr_dax); | ||
790 | err_chrdev: | ||
791 | dax_inode_exit(); | ||
792 | return rc; | ||
793 | } | 650 | } |
794 | 651 | ||
795 | static void __exit dax_exit(void) | 652 | static void __exit dax_exit(void) |
796 | { | 653 | { |
797 | class_destroy(dax_class); | 654 | class_destroy(dax_class); |
798 | unregister_chrdev_region(dax_devt, nr_dax); | ||
799 | ida_destroy(&dax_minor_ida); | ||
800 | dax_inode_exit(); | ||
801 | } | 655 | } |
802 | 656 | ||
803 | MODULE_AUTHOR("Intel Corporation"); | 657 | MODULE_AUTHOR("Intel Corporation"); |
diff --git a/drivers/dax/pmem.c b/drivers/dax/pmem.c index 033f49b31fdc..d4ca19bd74eb 100644 --- a/drivers/dax/pmem.c +++ b/drivers/dax/pmem.c | |||
@@ -16,7 +16,7 @@ | |||
16 | #include <linux/pfn_t.h> | 16 | #include <linux/pfn_t.h> |
17 | #include "../nvdimm/pfn.h" | 17 | #include "../nvdimm/pfn.h" |
18 | #include "../nvdimm/nd.h" | 18 | #include "../nvdimm/nd.h" |
19 | #include "dax.h" | 19 | #include "device-dax.h" |
20 | 20 | ||
21 | struct dax_pmem { | 21 | struct dax_pmem { |
22 | struct device *dev; | 22 | struct device *dev; |
@@ -61,8 +61,8 @@ static int dax_pmem_probe(struct device *dev) | |||
61 | int rc; | 61 | int rc; |
62 | void *addr; | 62 | void *addr; |
63 | struct resource res; | 63 | struct resource res; |
64 | struct dax_dev *dax_dev; | ||
65 | struct nd_pfn_sb *pfn_sb; | 64 | struct nd_pfn_sb *pfn_sb; |
65 | struct dev_dax *dev_dax; | ||
66 | struct dax_pmem *dax_pmem; | 66 | struct dax_pmem *dax_pmem; |
67 | struct nd_region *nd_region; | 67 | struct nd_region *nd_region; |
68 | struct nd_namespace_io *nsio; | 68 | struct nd_namespace_io *nsio; |
@@ -130,12 +130,12 @@ static int dax_pmem_probe(struct device *dev) | |||
130 | return -ENOMEM; | 130 | return -ENOMEM; |
131 | 131 | ||
132 | /* TODO: support for subdividing a dax region... */ | 132 | /* TODO: support for subdividing a dax region... */ |
133 | dax_dev = devm_create_dax_dev(dax_region, &res, 1); | 133 | dev_dax = devm_create_dev_dax(dax_region, &res, 1); |
134 | 134 | ||
135 | /* child dax_dev instances now own the lifetime of the dax_region */ | 135 | /* child dev_dax instances now own the lifetime of the dax_region */ |
136 | dax_region_put(dax_region); | 136 | dax_region_put(dax_region); |
137 | 137 | ||
138 | return PTR_ERR_OR_ZERO(dax_dev); | 138 | return PTR_ERR_OR_ZERO(dev_dax); |
139 | } | 139 | } |
140 | 140 | ||
141 | static struct nd_device_driver dax_pmem_driver = { | 141 | static struct nd_device_driver dax_pmem_driver = { |
diff --git a/drivers/dax/super.c b/drivers/dax/super.c new file mode 100644 index 000000000000..465dcd7317d5 --- /dev/null +++ b/drivers/dax/super.c | |||
@@ -0,0 +1,425 @@ | |||
1 | /* | ||
2 | * Copyright(c) 2017 Intel Corporation. All rights reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of version 2 of the GNU General Public License as | ||
6 | * published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, but | ||
9 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
11 | * General Public License for more details. | ||
12 | */ | ||
13 | #include <linux/pagemap.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/mount.h> | ||
16 | #include <linux/magic.h> | ||
17 | #include <linux/cdev.h> | ||
18 | #include <linux/hash.h> | ||
19 | #include <linux/slab.h> | ||
20 | #include <linux/dax.h> | ||
21 | #include <linux/fs.h> | ||
22 | |||
23 | static int nr_dax = CONFIG_NR_DEV_DAX; | ||
24 | module_param(nr_dax, int, S_IRUGO); | ||
25 | MODULE_PARM_DESC(nr_dax, "max number of dax device instances"); | ||
26 | |||
27 | static dev_t dax_devt; | ||
28 | DEFINE_STATIC_SRCU(dax_srcu); | ||
29 | static struct vfsmount *dax_mnt; | ||
30 | static DEFINE_IDA(dax_minor_ida); | ||
31 | static struct kmem_cache *dax_cache __read_mostly; | ||
32 | static struct super_block *dax_superblock __read_mostly; | ||
33 | |||
34 | #define DAX_HASH_SIZE (PAGE_SIZE / sizeof(struct hlist_head)) | ||
35 | static struct hlist_head dax_host_list[DAX_HASH_SIZE]; | ||
36 | static DEFINE_SPINLOCK(dax_host_lock); | ||
37 | |||
38 | int dax_read_lock(void) | ||
39 | { | ||
40 | return srcu_read_lock(&dax_srcu); | ||
41 | } | ||
42 | EXPORT_SYMBOL_GPL(dax_read_lock); | ||
43 | |||
44 | void dax_read_unlock(int id) | ||
45 | { | ||
46 | srcu_read_unlock(&dax_srcu, id); | ||
47 | } | ||
48 | EXPORT_SYMBOL_GPL(dax_read_unlock); | ||
49 | |||
50 | /** | ||
51 | * struct dax_device - anchor object for dax services | ||
52 | * @inode: core vfs | ||
53 | * @cdev: optional character interface for "device dax" | ||
54 | * @host: optional name for lookups where the device path is not available | ||
55 | * @private: dax driver private data | ||
56 | * @alive: !alive + rcu grace period == no new operations / mappings | ||
57 | */ | ||
58 | struct dax_device { | ||
59 | struct hlist_node list; | ||
60 | struct inode inode; | ||
61 | struct cdev cdev; | ||
62 | const char *host; | ||
63 | void *private; | ||
64 | bool alive; | ||
65 | const struct dax_operations *ops; | ||
66 | }; | ||
67 | |||
68 | /** | ||
69 | * dax_direct_access() - translate a device pgoff to an absolute pfn | ||
70 | * @dax_dev: a dax_device instance representing the logical memory range | ||
71 | * @pgoff: offset in pages from the start of the device to translate | ||
72 | * @nr_pages: number of consecutive pages caller can handle relative to @pfn | ||
73 | * @kaddr: output parameter that returns a virtual address mapping of pfn | ||
74 | * @pfn: output parameter that returns an absolute pfn translation of @pgoff | ||
75 | * | ||
76 | * Return: negative errno if an error occurs, otherwise the number of | ||
77 | * pages accessible at the device relative @pgoff. | ||
78 | */ | ||
79 | long dax_direct_access(struct dax_device *dax_dev, pgoff_t pgoff, long nr_pages, | ||
80 | void **kaddr, pfn_t *pfn) | ||
81 | { | ||
82 | long avail; | ||
83 | |||
84 | /* | ||
85 | * The device driver is allowed to sleep, in order to make the | ||
86 | * memory directly accessible. | ||
87 | */ | ||
88 | might_sleep(); | ||
89 | |||
90 | if (!dax_dev) | ||
91 | return -EOPNOTSUPP; | ||
92 | |||
93 | if (!dax_alive(dax_dev)) | ||
94 | return -ENXIO; | ||
95 | |||
96 | if (nr_pages < 0) | ||
97 | return nr_pages; | ||
98 | |||
99 | avail = dax_dev->ops->direct_access(dax_dev, pgoff, nr_pages, | ||
100 | kaddr, pfn); | ||
101 | if (!avail) | ||
102 | return -ERANGE; | ||
103 | return min(avail, nr_pages); | ||
104 | } | ||
105 | EXPORT_SYMBOL_GPL(dax_direct_access); | ||
106 | |||
107 | bool dax_alive(struct dax_device *dax_dev) | ||
108 | { | ||
109 | lockdep_assert_held(&dax_srcu); | ||
110 | return dax_dev->alive; | ||
111 | } | ||
112 | EXPORT_SYMBOL_GPL(dax_alive); | ||
113 | |||
114 | static int dax_host_hash(const char *host) | ||
115 | { | ||
116 | return hashlen_hash(hashlen_string("DAX", host)) % DAX_HASH_SIZE; | ||
117 | } | ||
118 | |||
119 | /* | ||
120 | * Note, rcu is not protecting the liveness of dax_dev, rcu is ensuring | ||
121 | * that any fault handlers or operations that might have seen | ||
122 | * dax_alive(), have completed. Any operations that start after | ||
123 | * synchronize_srcu() has run will abort upon seeing !dax_alive(). | ||
124 | */ | ||
125 | void kill_dax(struct dax_device *dax_dev) | ||
126 | { | ||
127 | if (!dax_dev) | ||
128 | return; | ||
129 | |||
130 | dax_dev->alive = false; | ||
131 | |||
132 | synchronize_srcu(&dax_srcu); | ||
133 | |||
134 | spin_lock(&dax_host_lock); | ||
135 | hlist_del_init(&dax_dev->list); | ||
136 | spin_unlock(&dax_host_lock); | ||
137 | |||
138 | dax_dev->private = NULL; | ||
139 | } | ||
140 | EXPORT_SYMBOL_GPL(kill_dax); | ||
141 | |||
142 | static struct inode *dax_alloc_inode(struct super_block *sb) | ||
143 | { | ||
144 | struct dax_device *dax_dev; | ||
145 | |||
146 | dax_dev = kmem_cache_alloc(dax_cache, GFP_KERNEL); | ||
147 | return &dax_dev->inode; | ||
148 | } | ||
149 | |||
150 | static struct dax_device *to_dax_dev(struct inode *inode) | ||
151 | { | ||
152 | return container_of(inode, struct dax_device, inode); | ||
153 | } | ||
154 | |||
155 | static void dax_i_callback(struct rcu_head *head) | ||
156 | { | ||
157 | struct inode *inode = container_of(head, struct inode, i_rcu); | ||
158 | struct dax_device *dax_dev = to_dax_dev(inode); | ||
159 | |||
160 | kfree(dax_dev->host); | ||
161 | dax_dev->host = NULL; | ||
162 | ida_simple_remove(&dax_minor_ida, MINOR(inode->i_rdev)); | ||
163 | kmem_cache_free(dax_cache, dax_dev); | ||
164 | } | ||
165 | |||
166 | static void dax_destroy_inode(struct inode *inode) | ||
167 | { | ||
168 | struct dax_device *dax_dev = to_dax_dev(inode); | ||
169 | |||
170 | WARN_ONCE(dax_dev->alive, | ||
171 | "kill_dax() must be called before final iput()\n"); | ||
172 | call_rcu(&inode->i_rcu, dax_i_callback); | ||
173 | } | ||
174 | |||
175 | static const struct super_operations dax_sops = { | ||
176 | .statfs = simple_statfs, | ||
177 | .alloc_inode = dax_alloc_inode, | ||
178 | .destroy_inode = dax_destroy_inode, | ||
179 | .drop_inode = generic_delete_inode, | ||
180 | }; | ||
181 | |||
182 | static struct dentry *dax_mount(struct file_system_type *fs_type, | ||
183 | int flags, const char *dev_name, void *data) | ||
184 | { | ||
185 | return mount_pseudo(fs_type, "dax:", &dax_sops, NULL, DAXFS_MAGIC); | ||
186 | } | ||
187 | |||
188 | static struct file_system_type dax_fs_type = { | ||
189 | .name = "dax", | ||
190 | .mount = dax_mount, | ||
191 | .kill_sb = kill_anon_super, | ||
192 | }; | ||
193 | |||
194 | static int dax_test(struct inode *inode, void *data) | ||
195 | { | ||
196 | dev_t devt = *(dev_t *) data; | ||
197 | |||
198 | return inode->i_rdev == devt; | ||
199 | } | ||
200 | |||
201 | static int dax_set(struct inode *inode, void *data) | ||
202 | { | ||
203 | dev_t devt = *(dev_t *) data; | ||
204 | |||
205 | inode->i_rdev = devt; | ||
206 | return 0; | ||
207 | } | ||
208 | |||
209 | static struct dax_device *dax_dev_get(dev_t devt) | ||
210 | { | ||
211 | struct dax_device *dax_dev; | ||
212 | struct inode *inode; | ||
213 | |||
214 | inode = iget5_locked(dax_superblock, hash_32(devt + DAXFS_MAGIC, 31), | ||
215 | dax_test, dax_set, &devt); | ||
216 | |||
217 | if (!inode) | ||
218 | return NULL; | ||
219 | |||
220 | dax_dev = to_dax_dev(inode); | ||
221 | if (inode->i_state & I_NEW) { | ||
222 | dax_dev->alive = true; | ||
223 | inode->i_cdev = &dax_dev->cdev; | ||
224 | inode->i_mode = S_IFCHR; | ||
225 | inode->i_flags = S_DAX; | ||
226 | mapping_set_gfp_mask(&inode->i_data, GFP_USER); | ||
227 | unlock_new_inode(inode); | ||
228 | } | ||
229 | |||
230 | return dax_dev; | ||
231 | } | ||
232 | |||
233 | static void dax_add_host(struct dax_device *dax_dev, const char *host) | ||
234 | { | ||
235 | int hash; | ||
236 | |||
237 | /* | ||
238 | * Unconditionally init dax_dev since it's coming from a | ||
239 | * non-zeroed slab cache | ||
240 | */ | ||
241 | INIT_HLIST_NODE(&dax_dev->list); | ||
242 | dax_dev->host = host; | ||
243 | if (!host) | ||
244 | return; | ||
245 | |||
246 | hash = dax_host_hash(host); | ||
247 | spin_lock(&dax_host_lock); | ||
248 | hlist_add_head(&dax_dev->list, &dax_host_list[hash]); | ||
249 | spin_unlock(&dax_host_lock); | ||
250 | } | ||
251 | |||
252 | struct dax_device *alloc_dax(void *private, const char *__host, | ||
253 | const struct dax_operations *ops) | ||
254 | { | ||
255 | struct dax_device *dax_dev; | ||
256 | const char *host; | ||
257 | dev_t devt; | ||
258 | int minor; | ||
259 | |||
260 | host = kstrdup(__host, GFP_KERNEL); | ||
261 | if (__host && !host) | ||
262 | return NULL; | ||
263 | |||
264 | minor = ida_simple_get(&dax_minor_ida, 0, nr_dax, GFP_KERNEL); | ||
265 | if (minor < 0) | ||
266 | goto err_minor; | ||
267 | |||
268 | devt = MKDEV(MAJOR(dax_devt), minor); | ||
269 | dax_dev = dax_dev_get(devt); | ||
270 | if (!dax_dev) | ||
271 | goto err_dev; | ||
272 | |||
273 | dax_add_host(dax_dev, host); | ||
274 | dax_dev->ops = ops; | ||
275 | dax_dev->private = private; | ||
276 | return dax_dev; | ||
277 | |||
278 | err_dev: | ||
279 | ida_simple_remove(&dax_minor_ida, minor); | ||
280 | err_minor: | ||
281 | kfree(host); | ||
282 | return NULL; | ||
283 | } | ||
284 | EXPORT_SYMBOL_GPL(alloc_dax); | ||
285 | |||
286 | void put_dax(struct dax_device *dax_dev) | ||
287 | { | ||
288 | if (!dax_dev) | ||
289 | return; | ||
290 | iput(&dax_dev->inode); | ||
291 | } | ||
292 | EXPORT_SYMBOL_GPL(put_dax); | ||
293 | |||
294 | /** | ||
295 | * dax_get_by_host() - temporary lookup mechanism for filesystem-dax | ||
296 | * @host: alternate name for the device registered by a dax driver | ||
297 | */ | ||
298 | struct dax_device *dax_get_by_host(const char *host) | ||
299 | { | ||
300 | struct dax_device *dax_dev, *found = NULL; | ||
301 | int hash, id; | ||
302 | |||
303 | if (!host) | ||
304 | return NULL; | ||
305 | |||
306 | hash = dax_host_hash(host); | ||
307 | |||
308 | id = dax_read_lock(); | ||
309 | spin_lock(&dax_host_lock); | ||
310 | hlist_for_each_entry(dax_dev, &dax_host_list[hash], list) { | ||
311 | if (!dax_alive(dax_dev) | ||
312 | || strcmp(host, dax_dev->host) != 0) | ||
313 | continue; | ||
314 | |||
315 | if (igrab(&dax_dev->inode)) | ||
316 | found = dax_dev; | ||
317 | break; | ||
318 | } | ||
319 | spin_unlock(&dax_host_lock); | ||
320 | dax_read_unlock(id); | ||
321 | |||
322 | return found; | ||
323 | } | ||
324 | EXPORT_SYMBOL_GPL(dax_get_by_host); | ||
325 | |||
326 | /** | ||
327 | * inode_dax: convert a public inode into its dax_dev | ||
328 | * @inode: An inode with i_cdev pointing to a dax_dev | ||
329 | * | ||
330 | * Note this is not equivalent to to_dax_dev() which is for private | ||
331 | * internal use where we know the inode filesystem type == dax_fs_type. | ||
332 | */ | ||
333 | struct dax_device *inode_dax(struct inode *inode) | ||
334 | { | ||
335 | struct cdev *cdev = inode->i_cdev; | ||
336 | |||
337 | return container_of(cdev, struct dax_device, cdev); | ||
338 | } | ||
339 | EXPORT_SYMBOL_GPL(inode_dax); | ||
340 | |||
341 | struct inode *dax_inode(struct dax_device *dax_dev) | ||
342 | { | ||
343 | return &dax_dev->inode; | ||
344 | } | ||
345 | EXPORT_SYMBOL_GPL(dax_inode); | ||
346 | |||
347 | void *dax_get_private(struct dax_device *dax_dev) | ||
348 | { | ||
349 | return dax_dev->private; | ||
350 | } | ||
351 | EXPORT_SYMBOL_GPL(dax_get_private); | ||
352 | |||
353 | static void init_once(void *_dax_dev) | ||
354 | { | ||
355 | struct dax_device *dax_dev = _dax_dev; | ||
356 | struct inode *inode = &dax_dev->inode; | ||
357 | |||
358 | inode_init_once(inode); | ||
359 | } | ||
360 | |||
361 | static int __dax_fs_init(void) | ||
362 | { | ||
363 | int rc; | ||
364 | |||
365 | dax_cache = kmem_cache_create("dax_cache", sizeof(struct dax_device), 0, | ||
366 | (SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT| | ||
367 | SLAB_MEM_SPREAD|SLAB_ACCOUNT), | ||
368 | init_once); | ||
369 | if (!dax_cache) | ||
370 | return -ENOMEM; | ||
371 | |||
372 | rc = register_filesystem(&dax_fs_type); | ||
373 | if (rc) | ||
374 | goto err_register_fs; | ||
375 | |||
376 | dax_mnt = kern_mount(&dax_fs_type); | ||
377 | if (IS_ERR(dax_mnt)) { | ||
378 | rc = PTR_ERR(dax_mnt); | ||
379 | goto err_mount; | ||
380 | } | ||
381 | dax_superblock = dax_mnt->mnt_sb; | ||
382 | |||
383 | return 0; | ||
384 | |||
385 | err_mount: | ||
386 | unregister_filesystem(&dax_fs_type); | ||
387 | err_register_fs: | ||
388 | kmem_cache_destroy(dax_cache); | ||
389 | |||
390 | return rc; | ||
391 | } | ||
392 | |||
393 | static void __dax_fs_exit(void) | ||
394 | { | ||
395 | kern_unmount(dax_mnt); | ||
396 | unregister_filesystem(&dax_fs_type); | ||
397 | kmem_cache_destroy(dax_cache); | ||
398 | } | ||
399 | |||
400 | static int __init dax_fs_init(void) | ||
401 | { | ||
402 | int rc; | ||
403 | |||
404 | rc = __dax_fs_init(); | ||
405 | if (rc) | ||
406 | return rc; | ||
407 | |||
408 | nr_dax = max(nr_dax, 256); | ||
409 | rc = alloc_chrdev_region(&dax_devt, 0, nr_dax, "dax"); | ||
410 | if (rc) | ||
411 | __dax_fs_exit(); | ||
412 | return rc; | ||
413 | } | ||
414 | |||
415 | static void __exit dax_fs_exit(void) | ||
416 | { | ||
417 | unregister_chrdev_region(dax_devt, nr_dax); | ||
418 | ida_destroy(&dax_minor_ida); | ||
419 | __dax_fs_exit(); | ||
420 | } | ||
421 | |||
422 | MODULE_AUTHOR("Intel Corporation"); | ||
423 | MODULE_LICENSE("GPL v2"); | ||
424 | subsys_initcall(dax_fs_init); | ||
425 | module_exit(dax_fs_exit); | ||
diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig index ce861a2853a4..dee470f9113f 100644 --- a/drivers/fpga/Kconfig +++ b/drivers/fpga/Kconfig | |||
@@ -20,6 +20,12 @@ config FPGA_REGION | |||
20 | FPGA Regions allow loading FPGA images under control of | 20 | FPGA Regions allow loading FPGA images under control of |
21 | the Device Tree. | 21 | the Device Tree. |
22 | 22 | ||
23 | config FPGA_MGR_ICE40_SPI | ||
24 | tristate "Lattice iCE40 SPI" | ||
25 | depends on OF && SPI | ||
26 | help | ||
27 | FPGA manager driver support for Lattice iCE40 FPGAs over SPI. | ||
28 | |||
23 | config FPGA_MGR_SOCFPGA | 29 | config FPGA_MGR_SOCFPGA |
24 | tristate "Altera SOCFPGA FPGA Manager" | 30 | tristate "Altera SOCFPGA FPGA Manager" |
25 | depends on ARCH_SOCFPGA || COMPILE_TEST | 31 | depends on ARCH_SOCFPGA || COMPILE_TEST |
@@ -33,6 +39,13 @@ config FPGA_MGR_SOCFPGA_A10 | |||
33 | help | 39 | help |
34 | FPGA manager driver support for Altera Arria10 SoCFPGA. | 40 | FPGA manager driver support for Altera Arria10 SoCFPGA. |
35 | 41 | ||
42 | config FPGA_MGR_TS73XX | ||
43 | tristate "Technologic Systems TS-73xx SBC FPGA Manager" | ||
44 | depends on ARCH_EP93XX && MACH_TS72XX | ||
45 | help | ||
46 | FPGA manager driver support for the Altera Cyclone II FPGA | ||
47 | present on the TS-73xx SBC boards. | ||
48 | |||
36 | config FPGA_MGR_ZYNQ_FPGA | 49 | config FPGA_MGR_ZYNQ_FPGA |
37 | tristate "Xilinx Zynq FPGA" | 50 | tristate "Xilinx Zynq FPGA" |
38 | depends on ARCH_ZYNQ || COMPILE_TEST | 51 | depends on ARCH_ZYNQ || COMPILE_TEST |
diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile index 8df07bcf42a6..a5ee3ffe8b18 100644 --- a/drivers/fpga/Makefile +++ b/drivers/fpga/Makefile | |||
@@ -6,8 +6,10 @@ | |||
6 | obj-$(CONFIG_FPGA) += fpga-mgr.o | 6 | obj-$(CONFIG_FPGA) += fpga-mgr.o |
7 | 7 | ||
8 | # FPGA Manager Drivers | 8 | # FPGA Manager Drivers |
9 | obj-$(CONFIG_FPGA_MGR_ICE40_SPI) += ice40-spi.o | ||
9 | obj-$(CONFIG_FPGA_MGR_SOCFPGA) += socfpga.o | 10 | obj-$(CONFIG_FPGA_MGR_SOCFPGA) += socfpga.o |
10 | obj-$(CONFIG_FPGA_MGR_SOCFPGA_A10) += socfpga-a10.o | 11 | obj-$(CONFIG_FPGA_MGR_SOCFPGA_A10) += socfpga-a10.o |
12 | obj-$(CONFIG_FPGA_MGR_TS73XX) += ts73xx-fpga.o | ||
11 | obj-$(CONFIG_FPGA_MGR_ZYNQ_FPGA) += zynq-fpga.o | 13 | obj-$(CONFIG_FPGA_MGR_ZYNQ_FPGA) += zynq-fpga.o |
12 | 14 | ||
13 | # FPGA Bridge Drivers | 15 | # FPGA Bridge Drivers |
diff --git a/drivers/fpga/fpga-bridge.c b/drivers/fpga/fpga-bridge.c index 33ee83e6373c..9651aa56244a 100644 --- a/drivers/fpga/fpga-bridge.c +++ b/drivers/fpga/fpga-bridge.c | |||
@@ -27,7 +27,7 @@ static DEFINE_IDA(fpga_bridge_ida); | |||
27 | static struct class *fpga_bridge_class; | 27 | static struct class *fpga_bridge_class; |
28 | 28 | ||
29 | /* Lock for adding/removing bridges to linked lists*/ | 29 | /* Lock for adding/removing bridges to linked lists*/ |
30 | spinlock_t bridge_list_lock; | 30 | static spinlock_t bridge_list_lock; |
31 | 31 | ||
32 | static int fpga_bridge_of_node_match(struct device *dev, const void *data) | 32 | static int fpga_bridge_of_node_match(struct device *dev, const void *data) |
33 | { | 33 | { |
@@ -146,11 +146,9 @@ EXPORT_SYMBOL_GPL(fpga_bridge_put); | |||
146 | int fpga_bridges_enable(struct list_head *bridge_list) | 146 | int fpga_bridges_enable(struct list_head *bridge_list) |
147 | { | 147 | { |
148 | struct fpga_bridge *bridge; | 148 | struct fpga_bridge *bridge; |
149 | struct list_head *node; | ||
150 | int ret; | 149 | int ret; |
151 | 150 | ||
152 | list_for_each(node, bridge_list) { | 151 | list_for_each_entry(bridge, bridge_list, node) { |
153 | bridge = list_entry(node, struct fpga_bridge, node); | ||
154 | ret = fpga_bridge_enable(bridge); | 152 | ret = fpga_bridge_enable(bridge); |
155 | if (ret) | 153 | if (ret) |
156 | return ret; | 154 | return ret; |
@@ -172,11 +170,9 @@ EXPORT_SYMBOL_GPL(fpga_bridges_enable); | |||
172 | int fpga_bridges_disable(struct list_head *bridge_list) | 170 | int fpga_bridges_disable(struct list_head *bridge_list) |
173 | { | 171 | { |
174 | struct fpga_bridge *bridge; | 172 | struct fpga_bridge *bridge; |
175 | struct list_head *node; | ||
176 | int ret; | 173 | int ret; |
177 | 174 | ||
178 | list_for_each(node, bridge_list) { | 175 | list_for_each_entry(bridge, bridge_list, node) { |
179 | bridge = list_entry(node, struct fpga_bridge, node); | ||
180 | ret = fpga_bridge_disable(bridge); | 176 | ret = fpga_bridge_disable(bridge); |
181 | if (ret) | 177 | if (ret) |
182 | return ret; | 178 | return ret; |
@@ -196,13 +192,10 @@ EXPORT_SYMBOL_GPL(fpga_bridges_disable); | |||
196 | */ | 192 | */ |
197 | void fpga_bridges_put(struct list_head *bridge_list) | 193 | void fpga_bridges_put(struct list_head *bridge_list) |
198 | { | 194 | { |
199 | struct fpga_bridge *bridge; | 195 | struct fpga_bridge *bridge, *next; |
200 | struct list_head *node, *next; | ||
201 | unsigned long flags; | 196 | unsigned long flags; |
202 | 197 | ||
203 | list_for_each_safe(node, next, bridge_list) { | 198 | list_for_each_entry_safe(bridge, next, bridge_list, node) { |
204 | bridge = list_entry(node, struct fpga_bridge, node); | ||
205 | |||
206 | fpga_bridge_put(bridge); | 199 | fpga_bridge_put(bridge); |
207 | 200 | ||
208 | spin_lock_irqsave(&bridge_list_lock, flags); | 201 | spin_lock_irqsave(&bridge_list_lock, flags); |
diff --git a/drivers/fpga/fpga-mgr.c b/drivers/fpga/fpga-mgr.c index 86d2cb203533..188ffefa3cc3 100644 --- a/drivers/fpga/fpga-mgr.c +++ b/drivers/fpga/fpga-mgr.c | |||
@@ -361,7 +361,7 @@ static struct attribute *fpga_mgr_attrs[] = { | |||
361 | }; | 361 | }; |
362 | ATTRIBUTE_GROUPS(fpga_mgr); | 362 | ATTRIBUTE_GROUPS(fpga_mgr); |
363 | 363 | ||
364 | struct fpga_manager *__fpga_mgr_get(struct device *dev) | 364 | static struct fpga_manager *__fpga_mgr_get(struct device *dev) |
365 | { | 365 | { |
366 | struct fpga_manager *mgr; | 366 | struct fpga_manager *mgr; |
367 | int ret = -ENODEV; | 367 | int ret = -ENODEV; |
diff --git a/drivers/fpga/fpga-region.c b/drivers/fpga/fpga-region.c index 3222fdbad75a..2fe2a52c66ca 100644 --- a/drivers/fpga/fpga-region.c +++ b/drivers/fpga/fpga-region.c | |||
@@ -337,8 +337,9 @@ static int child_regions_with_firmware(struct device_node *overlay) | |||
337 | * The overlay must add either firmware-name or external-fpga-config property | 337 | * The overlay must add either firmware-name or external-fpga-config property |
338 | * to the FPGA Region. | 338 | * to the FPGA Region. |
339 | * | 339 | * |
340 | * firmware-name : program the FPGA | 340 | * firmware-name : program the FPGA |
341 | * external-fpga-config : FPGA is already programmed | 341 | * external-fpga-config : FPGA is already programmed |
342 | * encrypted-fpga-config : FPGA bitstream is encrypted | ||
342 | * | 343 | * |
343 | * The overlay can add other FPGA regions, but child FPGA regions cannot have a | 344 | * The overlay can add other FPGA regions, but child FPGA regions cannot have a |
344 | * firmware-name property since those regions don't exist yet. | 345 | * firmware-name property since those regions don't exist yet. |
@@ -373,6 +374,9 @@ static int fpga_region_notify_pre_apply(struct fpga_region *region, | |||
373 | if (of_property_read_bool(nd->overlay, "external-fpga-config")) | 374 | if (of_property_read_bool(nd->overlay, "external-fpga-config")) |
374 | info->flags |= FPGA_MGR_EXTERNAL_CONFIG; | 375 | info->flags |= FPGA_MGR_EXTERNAL_CONFIG; |
375 | 376 | ||
377 | if (of_property_read_bool(nd->overlay, "encrypted-fpga-config")) | ||
378 | info->flags |= FPGA_MGR_ENCRYPTED_BITSTREAM; | ||
379 | |||
376 | of_property_read_string(nd->overlay, "firmware-name", &firmware_name); | 380 | of_property_read_string(nd->overlay, "firmware-name", &firmware_name); |
377 | 381 | ||
378 | of_property_read_u32(nd->overlay, "region-unfreeze-timeout-us", | 382 | of_property_read_u32(nd->overlay, "region-unfreeze-timeout-us", |
diff --git a/drivers/fpga/ice40-spi.c b/drivers/fpga/ice40-spi.c new file mode 100644 index 000000000000..7fca82023062 --- /dev/null +++ b/drivers/fpga/ice40-spi.c | |||
@@ -0,0 +1,207 @@ | |||
1 | /* | ||
2 | * FPGA Manager Driver for Lattice iCE40. | ||
3 | * | ||
4 | * Copyright (c) 2016 Joel Holdsworth | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; version 2 of the License. | ||
9 | * | ||
10 | * This driver adds support to the FPGA manager for configuring the SRAM of | ||
11 | * Lattice iCE40 FPGAs through slave SPI. | ||
12 | */ | ||
13 | |||
14 | #include <linux/fpga/fpga-mgr.h> | ||
15 | #include <linux/gpio/consumer.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/of_gpio.h> | ||
18 | #include <linux/spi/spi.h> | ||
19 | #include <linux/stringify.h> | ||
20 | |||
21 | #define ICE40_SPI_MAX_SPEED 25000000 /* Hz */ | ||
22 | #define ICE40_SPI_MIN_SPEED 1000000 /* Hz */ | ||
23 | |||
24 | #define ICE40_SPI_RESET_DELAY 1 /* us (>200ns) */ | ||
25 | #define ICE40_SPI_HOUSEKEEPING_DELAY 1200 /* us */ | ||
26 | |||
27 | #define ICE40_SPI_NUM_ACTIVATION_BYTES DIV_ROUND_UP(49, 8) | ||
28 | |||
29 | struct ice40_fpga_priv { | ||
30 | struct spi_device *dev; | ||
31 | struct gpio_desc *reset; | ||
32 | struct gpio_desc *cdone; | ||
33 | }; | ||
34 | |||
35 | static enum fpga_mgr_states ice40_fpga_ops_state(struct fpga_manager *mgr) | ||
36 | { | ||
37 | struct ice40_fpga_priv *priv = mgr->priv; | ||
38 | |||
39 | return gpiod_get_value(priv->cdone) ? FPGA_MGR_STATE_OPERATING : | ||
40 | FPGA_MGR_STATE_UNKNOWN; | ||
41 | } | ||
42 | |||
43 | static int ice40_fpga_ops_write_init(struct fpga_manager *mgr, | ||
44 | struct fpga_image_info *info, | ||
45 | const char *buf, size_t count) | ||
46 | { | ||
47 | struct ice40_fpga_priv *priv = mgr->priv; | ||
48 | struct spi_device *dev = priv->dev; | ||
49 | struct spi_message message; | ||
50 | struct spi_transfer assert_cs_then_reset_delay = { | ||
51 | .cs_change = 1, | ||
52 | .delay_usecs = ICE40_SPI_RESET_DELAY | ||
53 | }; | ||
54 | struct spi_transfer housekeeping_delay_then_release_cs = { | ||
55 | .delay_usecs = ICE40_SPI_HOUSEKEEPING_DELAY | ||
56 | }; | ||
57 | int ret; | ||
58 | |||
59 | if ((info->flags & FPGA_MGR_PARTIAL_RECONFIG)) { | ||
60 | dev_err(&dev->dev, | ||
61 | "Partial reconfiguration is not supported\n"); | ||
62 | return -ENOTSUPP; | ||
63 | } | ||
64 | |||
65 | /* Lock the bus, assert CRESET_B and SS_B and delay >200ns */ | ||
66 | spi_bus_lock(dev->master); | ||
67 | |||
68 | gpiod_set_value(priv->reset, 1); | ||
69 | |||
70 | spi_message_init(&message); | ||
71 | spi_message_add_tail(&assert_cs_then_reset_delay, &message); | ||
72 | ret = spi_sync_locked(dev, &message); | ||
73 | |||
74 | /* Come out of reset */ | ||
75 | gpiod_set_value(priv->reset, 0); | ||
76 | |||
77 | /* Abort if the chip-select failed */ | ||
78 | if (ret) | ||
79 | goto fail; | ||
80 | |||
81 | /* Check CDONE is de-asserted i.e. the FPGA is reset */ | ||
82 | if (gpiod_get_value(priv->cdone)) { | ||
83 | dev_err(&dev->dev, "Device reset failed, CDONE is asserted\n"); | ||
84 | ret = -EIO; | ||
85 | goto fail; | ||
86 | } | ||
87 | |||
88 | /* Wait for the housekeeping to complete, and release SS_B */ | ||
89 | spi_message_init(&message); | ||
90 | spi_message_add_tail(&housekeeping_delay_then_release_cs, &message); | ||
91 | ret = spi_sync_locked(dev, &message); | ||
92 | |||
93 | fail: | ||
94 | spi_bus_unlock(dev->master); | ||
95 | |||
96 | return ret; | ||
97 | } | ||
98 | |||
99 | static int ice40_fpga_ops_write(struct fpga_manager *mgr, | ||
100 | const char *buf, size_t count) | ||
101 | { | ||
102 | struct ice40_fpga_priv *priv = mgr->priv; | ||
103 | |||
104 | return spi_write(priv->dev, buf, count); | ||
105 | } | ||
106 | |||
107 | static int ice40_fpga_ops_write_complete(struct fpga_manager *mgr, | ||
108 | struct fpga_image_info *info) | ||
109 | { | ||
110 | struct ice40_fpga_priv *priv = mgr->priv; | ||
111 | struct spi_device *dev = priv->dev; | ||
112 | const u8 padding[ICE40_SPI_NUM_ACTIVATION_BYTES] = {0}; | ||
113 | |||
114 | /* Check CDONE is asserted */ | ||
115 | if (!gpiod_get_value(priv->cdone)) { | ||
116 | dev_err(&dev->dev, | ||
117 | "CDONE was not asserted after firmware transfer\n"); | ||
118 | return -EIO; | ||
119 | } | ||
120 | |||
121 | /* Send of zero-padding to activate the firmware */ | ||
122 | return spi_write(dev, padding, sizeof(padding)); | ||
123 | } | ||
124 | |||
125 | static const struct fpga_manager_ops ice40_fpga_ops = { | ||
126 | .state = ice40_fpga_ops_state, | ||
127 | .write_init = ice40_fpga_ops_write_init, | ||
128 | .write = ice40_fpga_ops_write, | ||
129 | .write_complete = ice40_fpga_ops_write_complete, | ||
130 | }; | ||
131 | |||
132 | static int ice40_fpga_probe(struct spi_device *spi) | ||
133 | { | ||
134 | struct device *dev = &spi->dev; | ||
135 | struct ice40_fpga_priv *priv; | ||
136 | int ret; | ||
137 | |||
138 | priv = devm_kzalloc(&spi->dev, sizeof(*priv), GFP_KERNEL); | ||
139 | if (!priv) | ||
140 | return -ENOMEM; | ||
141 | |||
142 | priv->dev = spi; | ||
143 | |||
144 | /* Check board setup data. */ | ||
145 | if (spi->max_speed_hz > ICE40_SPI_MAX_SPEED) { | ||
146 | dev_err(dev, "SPI speed is too high, maximum speed is " | ||
147 | __stringify(ICE40_SPI_MAX_SPEED) "\n"); | ||
148 | return -EINVAL; | ||
149 | } | ||
150 | |||
151 | if (spi->max_speed_hz < ICE40_SPI_MIN_SPEED) { | ||
152 | dev_err(dev, "SPI speed is too low, minimum speed is " | ||
153 | __stringify(ICE40_SPI_MIN_SPEED) "\n"); | ||
154 | return -EINVAL; | ||
155 | } | ||
156 | |||
157 | if (spi->mode & SPI_CPHA) { | ||
158 | dev_err(dev, "Bad SPI mode, CPHA not supported\n"); | ||
159 | return -EINVAL; | ||
160 | } | ||
161 | |||
162 | /* Set up the GPIOs */ | ||
163 | priv->cdone = devm_gpiod_get(dev, "cdone", GPIOD_IN); | ||
164 | if (IS_ERR(priv->cdone)) { | ||
165 | ret = PTR_ERR(priv->cdone); | ||
166 | dev_err(dev, "Failed to get CDONE GPIO: %d\n", ret); | ||
167 | return ret; | ||
168 | } | ||
169 | |||
170 | priv->reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); | ||
171 | if (IS_ERR(priv->reset)) { | ||
172 | ret = PTR_ERR(priv->reset); | ||
173 | dev_err(dev, "Failed to get CRESET_B GPIO: %d\n", ret); | ||
174 | return ret; | ||
175 | } | ||
176 | |||
177 | /* Register with the FPGA manager */ | ||
178 | return fpga_mgr_register(dev, "Lattice iCE40 FPGA Manager", | ||
179 | &ice40_fpga_ops, priv); | ||
180 | } | ||
181 | |||
182 | static int ice40_fpga_remove(struct spi_device *spi) | ||
183 | { | ||
184 | fpga_mgr_unregister(&spi->dev); | ||
185 | return 0; | ||
186 | } | ||
187 | |||
188 | static const struct of_device_id ice40_fpga_of_match[] = { | ||
189 | { .compatible = "lattice,ice40-fpga-mgr", }, | ||
190 | {}, | ||
191 | }; | ||
192 | MODULE_DEVICE_TABLE(of, ice40_fpga_of_match); | ||
193 | |||
194 | static struct spi_driver ice40_fpga_driver = { | ||
195 | .probe = ice40_fpga_probe, | ||
196 | .remove = ice40_fpga_remove, | ||
197 | .driver = { | ||
198 | .name = "ice40spi", | ||
199 | .of_match_table = of_match_ptr(ice40_fpga_of_match), | ||
200 | }, | ||
201 | }; | ||
202 | |||
203 | module_spi_driver(ice40_fpga_driver); | ||
204 | |||
205 | MODULE_AUTHOR("Joel Holdsworth <joel@airwebreathe.org.uk>"); | ||
206 | MODULE_DESCRIPTION("Lattice iCE40 FPGA Manager"); | ||
207 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/fpga/ts73xx-fpga.c b/drivers/fpga/ts73xx-fpga.c new file mode 100644 index 000000000000..f6a96b42e2ca --- /dev/null +++ b/drivers/fpga/ts73xx-fpga.c | |||
@@ -0,0 +1,156 @@ | |||
1 | /* | ||
2 | * Technologic Systems TS-73xx SBC FPGA loader | ||
3 | * | ||
4 | * Copyright (C) 2016 Florian Fainelli <f.fainelli@gmail.com> | ||
5 | * | ||
6 | * FPGA Manager Driver for the on-board Altera Cyclone II FPGA found on | ||
7 | * TS-7300, heavily based on load_fpga.c in their vendor tree. | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; version 2 of the License. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | */ | ||
18 | |||
19 | #include <linux/delay.h> | ||
20 | #include <linux/io.h> | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/platform_device.h> | ||
23 | #include <linux/string.h> | ||
24 | #include <linux/iopoll.h> | ||
25 | #include <linux/fpga/fpga-mgr.h> | ||
26 | |||
27 | #define TS73XX_FPGA_DATA_REG 0 | ||
28 | #define TS73XX_FPGA_CONFIG_REG 1 | ||
29 | |||
30 | #define TS73XX_FPGA_WRITE_DONE 0x1 | ||
31 | #define TS73XX_FPGA_WRITE_DONE_TIMEOUT 1000 /* us */ | ||
32 | #define TS73XX_FPGA_RESET 0x2 | ||
33 | #define TS73XX_FPGA_RESET_LOW_DELAY 30 /* us */ | ||
34 | #define TS73XX_FPGA_RESET_HIGH_DELAY 80 /* us */ | ||
35 | #define TS73XX_FPGA_LOAD_OK 0x4 | ||
36 | #define TS73XX_FPGA_CONFIG_LOAD 0x8 | ||
37 | |||
38 | struct ts73xx_fpga_priv { | ||
39 | void __iomem *io_base; | ||
40 | struct device *dev; | ||
41 | }; | ||
42 | |||
43 | static enum fpga_mgr_states ts73xx_fpga_state(struct fpga_manager *mgr) | ||
44 | { | ||
45 | return FPGA_MGR_STATE_UNKNOWN; | ||
46 | } | ||
47 | |||
48 | static int ts73xx_fpga_write_init(struct fpga_manager *mgr, | ||
49 | struct fpga_image_info *info, | ||
50 | const char *buf, size_t count) | ||
51 | { | ||
52 | struct ts73xx_fpga_priv *priv = mgr->priv; | ||
53 | |||
54 | /* Reset the FPGA */ | ||
55 | writeb(0, priv->io_base + TS73XX_FPGA_CONFIG_REG); | ||
56 | udelay(TS73XX_FPGA_RESET_LOW_DELAY); | ||
57 | writeb(TS73XX_FPGA_RESET, priv->io_base + TS73XX_FPGA_CONFIG_REG); | ||
58 | udelay(TS73XX_FPGA_RESET_HIGH_DELAY); | ||
59 | |||
60 | return 0; | ||
61 | } | ||
62 | |||
63 | static int ts73xx_fpga_write(struct fpga_manager *mgr, const char *buf, | ||
64 | size_t count) | ||
65 | { | ||
66 | struct ts73xx_fpga_priv *priv = mgr->priv; | ||
67 | size_t i = 0; | ||
68 | int ret; | ||
69 | u8 reg; | ||
70 | |||
71 | while (count--) { | ||
72 | ret = readb_poll_timeout(priv->io_base + TS73XX_FPGA_CONFIG_REG, | ||
73 | reg, !(reg & TS73XX_FPGA_WRITE_DONE), | ||
74 | 1, TS73XX_FPGA_WRITE_DONE_TIMEOUT); | ||
75 | if (ret < 0) | ||
76 | return ret; | ||
77 | |||
78 | writeb(buf[i], priv->io_base + TS73XX_FPGA_DATA_REG); | ||
79 | i++; | ||
80 | } | ||
81 | |||
82 | return 0; | ||
83 | } | ||
84 | |||
85 | static int ts73xx_fpga_write_complete(struct fpga_manager *mgr, | ||
86 | struct fpga_image_info *info) | ||
87 | { | ||
88 | struct ts73xx_fpga_priv *priv = mgr->priv; | ||
89 | u8 reg; | ||
90 | |||
91 | usleep_range(1000, 2000); | ||
92 | reg = readb(priv->io_base + TS73XX_FPGA_CONFIG_REG); | ||
93 | reg |= TS73XX_FPGA_CONFIG_LOAD; | ||
94 | writeb(reg, priv->io_base + TS73XX_FPGA_CONFIG_REG); | ||
95 | |||
96 | usleep_range(1000, 2000); | ||
97 | reg = readb(priv->io_base + TS73XX_FPGA_CONFIG_REG); | ||
98 | reg &= ~TS73XX_FPGA_CONFIG_LOAD; | ||
99 | writeb(reg, priv->io_base + TS73XX_FPGA_CONFIG_REG); | ||
100 | |||
101 | reg = readb(priv->io_base + TS73XX_FPGA_CONFIG_REG); | ||
102 | if ((reg & TS73XX_FPGA_LOAD_OK) != TS73XX_FPGA_LOAD_OK) | ||
103 | return -ETIMEDOUT; | ||
104 | |||
105 | return 0; | ||
106 | } | ||
107 | |||
108 | static const struct fpga_manager_ops ts73xx_fpga_ops = { | ||
109 | .state = ts73xx_fpga_state, | ||
110 | .write_init = ts73xx_fpga_write_init, | ||
111 | .write = ts73xx_fpga_write, | ||
112 | .write_complete = ts73xx_fpga_write_complete, | ||
113 | }; | ||
114 | |||
115 | static int ts73xx_fpga_probe(struct platform_device *pdev) | ||
116 | { | ||
117 | struct device *kdev = &pdev->dev; | ||
118 | struct ts73xx_fpga_priv *priv; | ||
119 | struct resource *res; | ||
120 | |||
121 | priv = devm_kzalloc(kdev, sizeof(*priv), GFP_KERNEL); | ||
122 | if (!priv) | ||
123 | return -ENOMEM; | ||
124 | |||
125 | priv->dev = kdev; | ||
126 | |||
127 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
128 | priv->io_base = devm_ioremap_resource(kdev, res); | ||
129 | if (IS_ERR(priv->io_base)) { | ||
130 | dev_err(kdev, "unable to remap registers\n"); | ||
131 | return PTR_ERR(priv->io_base); | ||
132 | } | ||
133 | |||
134 | return fpga_mgr_register(kdev, "TS-73xx FPGA Manager", | ||
135 | &ts73xx_fpga_ops, priv); | ||
136 | } | ||
137 | |||
138 | static int ts73xx_fpga_remove(struct platform_device *pdev) | ||
139 | { | ||
140 | fpga_mgr_unregister(&pdev->dev); | ||
141 | |||
142 | return 0; | ||
143 | } | ||
144 | |||
145 | static struct platform_driver ts73xx_fpga_driver = { | ||
146 | .driver = { | ||
147 | .name = "ts73xx-fpga-mgr", | ||
148 | }, | ||
149 | .probe = ts73xx_fpga_probe, | ||
150 | .remove = ts73xx_fpga_remove, | ||
151 | }; | ||
152 | module_platform_driver(ts73xx_fpga_driver); | ||
153 | |||
154 | MODULE_AUTHOR("Florian Fainelli <f.fainelli@gmail.com>"); | ||
155 | MODULE_DESCRIPTION("TS-73xx FPGA Manager driver"); | ||
156 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/fpga/zynq-fpga.c b/drivers/fpga/zynq-fpga.c index 34cb98139442..70b15b303471 100644 --- a/drivers/fpga/zynq-fpga.c +++ b/drivers/fpga/zynq-fpga.c | |||
@@ -72,6 +72,10 @@ | |||
72 | #define CTRL_PCAP_PR_MASK BIT(27) | 72 | #define CTRL_PCAP_PR_MASK BIT(27) |
73 | /* Enable PCAP */ | 73 | /* Enable PCAP */ |
74 | #define CTRL_PCAP_MODE_MASK BIT(26) | 74 | #define CTRL_PCAP_MODE_MASK BIT(26) |
75 | /* Lower rate to allow decrypt on the fly */ | ||
76 | #define CTRL_PCAP_RATE_EN_MASK BIT(25) | ||
77 | /* System booted in secure mode */ | ||
78 | #define CTRL_SEC_EN_MASK BIT(7) | ||
75 | 79 | ||
76 | /* Miscellaneous Control Register bit definitions */ | 80 | /* Miscellaneous Control Register bit definitions */ |
77 | /* Internal PCAP loopback */ | 81 | /* Internal PCAP loopback */ |
@@ -266,6 +270,17 @@ static int zynq_fpga_ops_write_init(struct fpga_manager *mgr, | |||
266 | if (err) | 270 | if (err) |
267 | return err; | 271 | return err; |
268 | 272 | ||
273 | /* check if bitstream is encrypted & and system's still secure */ | ||
274 | if (info->flags & FPGA_MGR_ENCRYPTED_BITSTREAM) { | ||
275 | ctrl = zynq_fpga_read(priv, CTRL_OFFSET); | ||
276 | if (!(ctrl & CTRL_SEC_EN_MASK)) { | ||
277 | dev_err(&mgr->dev, | ||
278 | "System not secure, can't use crypted bitstreams\n"); | ||
279 | err = -EINVAL; | ||
280 | goto out_err; | ||
281 | } | ||
282 | } | ||
283 | |||
269 | /* don't globally reset PL if we're doing partial reconfig */ | 284 | /* don't globally reset PL if we're doing partial reconfig */ |
270 | if (!(info->flags & FPGA_MGR_PARTIAL_RECONFIG)) { | 285 | if (!(info->flags & FPGA_MGR_PARTIAL_RECONFIG)) { |
271 | if (!zynq_fpga_has_sync(buf, count)) { | 286 | if (!zynq_fpga_has_sync(buf, count)) { |
@@ -337,12 +352,19 @@ static int zynq_fpga_ops_write_init(struct fpga_manager *mgr, | |||
337 | 352 | ||
338 | /* set configuration register with following options: | 353 | /* set configuration register with following options: |
339 | * - enable PCAP interface | 354 | * - enable PCAP interface |
340 | * - set throughput for maximum speed | 355 | * - set throughput for maximum speed (if bistream not crypted) |
341 | * - set CPU in user mode | 356 | * - set CPU in user mode |
342 | */ | 357 | */ |
343 | ctrl = zynq_fpga_read(priv, CTRL_OFFSET); | 358 | ctrl = zynq_fpga_read(priv, CTRL_OFFSET); |
344 | zynq_fpga_write(priv, CTRL_OFFSET, | 359 | if (info->flags & FPGA_MGR_ENCRYPTED_BITSTREAM) |
345 | (CTRL_PCAP_PR_MASK | CTRL_PCAP_MODE_MASK | ctrl)); | 360 | zynq_fpga_write(priv, CTRL_OFFSET, |
361 | (CTRL_PCAP_PR_MASK | CTRL_PCAP_MODE_MASK | ||
362 | | CTRL_PCAP_RATE_EN_MASK | ctrl)); | ||
363 | else | ||
364 | zynq_fpga_write(priv, CTRL_OFFSET, | ||
365 | (CTRL_PCAP_PR_MASK | CTRL_PCAP_MODE_MASK | ||
366 | | ctrl)); | ||
367 | |||
346 | 368 | ||
347 | /* We expect that the command queue is empty right now. */ | 369 | /* We expect that the command queue is empty right now. */ |
348 | status = zynq_fpga_read(priv, STATUS_OFFSET); | 370 | status = zynq_fpga_read(priv, STATUS_OFFSET); |
diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c index 321b8833fa6f..736ac76d2a6a 100644 --- a/drivers/hv/channel.c +++ b/drivers/hv/channel.c | |||
@@ -333,7 +333,7 @@ static int create_gpadl_header(void *kbuffer, u32 size, | |||
333 | * Gpadl is u32 and we are using a pointer which could | 333 | * Gpadl is u32 and we are using a pointer which could |
334 | * be 64-bit | 334 | * be 64-bit |
335 | * This is governed by the guest/host protocol and | 335 | * This is governed by the guest/host protocol and |
336 | * so the hypervisor gurantees that this is ok. | 336 | * so the hypervisor guarantees that this is ok. |
337 | */ | 337 | */ |
338 | for (i = 0; i < pfncurr; i++) | 338 | for (i = 0; i < pfncurr; i++) |
339 | gpadl_body->pfn[i] = slow_virt_to_phys( | 339 | gpadl_body->pfn[i] = slow_virt_to_phys( |
@@ -380,7 +380,7 @@ nomem: | |||
380 | } | 380 | } |
381 | 381 | ||
382 | /* | 382 | /* |
383 | * vmbus_establish_gpadl - Estabish a GPADL for the specified buffer | 383 | * vmbus_establish_gpadl - Establish a GPADL for the specified buffer |
384 | * | 384 | * |
385 | * @channel: a channel | 385 | * @channel: a channel |
386 | * @kbuffer: from kmalloc or vmalloc | 386 | * @kbuffer: from kmalloc or vmalloc |
@@ -731,7 +731,7 @@ int vmbus_sendpacket_pagebuffer_ctl(struct vmbus_channel *channel, | |||
731 | /* Setup the descriptor */ | 731 | /* Setup the descriptor */ |
732 | desc.type = VM_PKT_DATA_USING_GPA_DIRECT; | 732 | desc.type = VM_PKT_DATA_USING_GPA_DIRECT; |
733 | desc.flags = flags; | 733 | desc.flags = flags; |
734 | desc.dataoffset8 = descsize >> 3; /* in 8-bytes grandularity */ | 734 | desc.dataoffset8 = descsize >> 3; /* in 8-bytes granularity */ |
735 | desc.length8 = (u16)(packetlen_aligned >> 3); | 735 | desc.length8 = (u16)(packetlen_aligned >> 3); |
736 | desc.transactionid = requestid; | 736 | desc.transactionid = requestid; |
737 | desc.rangecount = pagecount; | 737 | desc.rangecount = pagecount; |
@@ -792,7 +792,7 @@ int vmbus_sendpacket_mpb_desc(struct vmbus_channel *channel, | |||
792 | /* Setup the descriptor */ | 792 | /* Setup the descriptor */ |
793 | desc->type = VM_PKT_DATA_USING_GPA_DIRECT; | 793 | desc->type = VM_PKT_DATA_USING_GPA_DIRECT; |
794 | desc->flags = VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED; | 794 | desc->flags = VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED; |
795 | desc->dataoffset8 = desc_size >> 3; /* in 8-bytes grandularity */ | 795 | desc->dataoffset8 = desc_size >> 3; /* in 8-bytes granularity */ |
796 | desc->length8 = (u16)(packetlen_aligned >> 3); | 796 | desc->length8 = (u16)(packetlen_aligned >> 3); |
797 | desc->transactionid = requestid; | 797 | desc->transactionid = requestid; |
798 | desc->rangecount = 1; | 798 | desc->rangecount = 1; |
@@ -842,7 +842,7 @@ int vmbus_sendpacket_multipagebuffer(struct vmbus_channel *channel, | |||
842 | /* Setup the descriptor */ | 842 | /* Setup the descriptor */ |
843 | desc.type = VM_PKT_DATA_USING_GPA_DIRECT; | 843 | desc.type = VM_PKT_DATA_USING_GPA_DIRECT; |
844 | desc.flags = VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED; | 844 | desc.flags = VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED; |
845 | desc.dataoffset8 = descsize >> 3; /* in 8-bytes grandularity */ | 845 | desc.dataoffset8 = descsize >> 3; /* in 8-bytes granularity */ |
846 | desc.length8 = (u16)(packetlen_aligned >> 3); | 846 | desc.length8 = (u16)(packetlen_aligned >> 3); |
847 | desc.transactionid = requestid; | 847 | desc.transactionid = requestid; |
848 | desc.rangecount = 1; | 848 | desc.rangecount = 1; |
diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c index fbcb06352308..735f9363f2e4 100644 --- a/drivers/hv/channel_mgmt.c +++ b/drivers/hv/channel_mgmt.c | |||
@@ -1080,30 +1080,30 @@ static void vmbus_onversion_response( | |||
1080 | } | 1080 | } |
1081 | 1081 | ||
1082 | /* Channel message dispatch table */ | 1082 | /* Channel message dispatch table */ |
1083 | struct vmbus_channel_message_table_entry | 1083 | const struct vmbus_channel_message_table_entry |
1084 | channel_message_table[CHANNELMSG_COUNT] = { | 1084 | channel_message_table[CHANNELMSG_COUNT] = { |
1085 | {CHANNELMSG_INVALID, 0, NULL}, | 1085 | { CHANNELMSG_INVALID, 0, NULL }, |
1086 | {CHANNELMSG_OFFERCHANNEL, 0, vmbus_onoffer}, | 1086 | { CHANNELMSG_OFFERCHANNEL, 0, vmbus_onoffer }, |
1087 | {CHANNELMSG_RESCIND_CHANNELOFFER, 0, vmbus_onoffer_rescind}, | 1087 | { CHANNELMSG_RESCIND_CHANNELOFFER, 0, vmbus_onoffer_rescind }, |
1088 | {CHANNELMSG_REQUESTOFFERS, 0, NULL}, | 1088 | { CHANNELMSG_REQUESTOFFERS, 0, NULL }, |
1089 | {CHANNELMSG_ALLOFFERS_DELIVERED, 1, vmbus_onoffers_delivered}, | 1089 | { CHANNELMSG_ALLOFFERS_DELIVERED, 1, vmbus_onoffers_delivered }, |
1090 | {CHANNELMSG_OPENCHANNEL, 0, NULL}, | 1090 | { CHANNELMSG_OPENCHANNEL, 0, NULL }, |
1091 | {CHANNELMSG_OPENCHANNEL_RESULT, 1, vmbus_onopen_result}, | 1091 | { CHANNELMSG_OPENCHANNEL_RESULT, 1, vmbus_onopen_result }, |
1092 | {CHANNELMSG_CLOSECHANNEL, 0, NULL}, | 1092 | { CHANNELMSG_CLOSECHANNEL, 0, NULL }, |
1093 | {CHANNELMSG_GPADL_HEADER, 0, NULL}, | 1093 | { CHANNELMSG_GPADL_HEADER, 0, NULL }, |
1094 | {CHANNELMSG_GPADL_BODY, 0, NULL}, | 1094 | { CHANNELMSG_GPADL_BODY, 0, NULL }, |
1095 | {CHANNELMSG_GPADL_CREATED, 1, vmbus_ongpadl_created}, | 1095 | { CHANNELMSG_GPADL_CREATED, 1, vmbus_ongpadl_created }, |
1096 | {CHANNELMSG_GPADL_TEARDOWN, 0, NULL}, | 1096 | { CHANNELMSG_GPADL_TEARDOWN, 0, NULL }, |
1097 | {CHANNELMSG_GPADL_TORNDOWN, 1, vmbus_ongpadl_torndown}, | 1097 | { CHANNELMSG_GPADL_TORNDOWN, 1, vmbus_ongpadl_torndown }, |
1098 | {CHANNELMSG_RELID_RELEASED, 0, NULL}, | 1098 | { CHANNELMSG_RELID_RELEASED, 0, NULL }, |
1099 | {CHANNELMSG_INITIATE_CONTACT, 0, NULL}, | 1099 | { CHANNELMSG_INITIATE_CONTACT, 0, NULL }, |
1100 | {CHANNELMSG_VERSION_RESPONSE, 1, vmbus_onversion_response}, | 1100 | { CHANNELMSG_VERSION_RESPONSE, 1, vmbus_onversion_response }, |
1101 | {CHANNELMSG_UNLOAD, 0, NULL}, | 1101 | { CHANNELMSG_UNLOAD, 0, NULL }, |
1102 | {CHANNELMSG_UNLOAD_RESPONSE, 1, vmbus_unload_response}, | 1102 | { CHANNELMSG_UNLOAD_RESPONSE, 1, vmbus_unload_response }, |
1103 | {CHANNELMSG_18, 0, NULL}, | 1103 | { CHANNELMSG_18, 0, NULL }, |
1104 | {CHANNELMSG_19, 0, NULL}, | 1104 | { CHANNELMSG_19, 0, NULL }, |
1105 | {CHANNELMSG_20, 0, NULL}, | 1105 | { CHANNELMSG_20, 0, NULL }, |
1106 | {CHANNELMSG_TL_CONNECT_REQUEST, 0, NULL}, | 1106 | { CHANNELMSG_TL_CONNECT_REQUEST, 0, NULL }, |
1107 | }; | 1107 | }; |
1108 | 1108 | ||
1109 | /* | 1109 | /* |
diff --git a/drivers/hv/connection.c b/drivers/hv/connection.c index a8366fec1458..fce27fb141cc 100644 --- a/drivers/hv/connection.c +++ b/drivers/hv/connection.c | |||
@@ -296,44 +296,47 @@ struct vmbus_channel *relid2channel(u32 relid) | |||
296 | 296 | ||
297 | /* | 297 | /* |
298 | * vmbus_on_event - Process a channel event notification | 298 | * vmbus_on_event - Process a channel event notification |
299 | * | ||
300 | * For batched channels (default) optimize host to guest signaling | ||
301 | * by ensuring: | ||
302 | * 1. While reading the channel, we disable interrupts from host. | ||
303 | * 2. Ensure that we process all posted messages from the host | ||
304 | * before returning from this callback. | ||
305 | * 3. Once we return, enable signaling from the host. Once this | ||
306 | * state is set we check to see if additional packets are | ||
307 | * available to read. In this case we repeat the process. | ||
308 | * If this tasklet has been running for a long time | ||
309 | * then reschedule ourselves. | ||
299 | */ | 310 | */ |
300 | void vmbus_on_event(unsigned long data) | 311 | void vmbus_on_event(unsigned long data) |
301 | { | 312 | { |
302 | struct vmbus_channel *channel = (void *) data; | 313 | struct vmbus_channel *channel = (void *) data; |
303 | void (*callback_fn)(void *); | 314 | unsigned long time_limit = jiffies + 2; |
304 | 315 | ||
305 | /* | 316 | do { |
306 | * A channel once created is persistent even when there | 317 | void (*callback_fn)(void *); |
307 | * is no driver handling the device. An unloading driver | 318 | |
308 | * sets the onchannel_callback to NULL on the same CPU | 319 | /* A channel once created is persistent even when |
309 | * as where this interrupt is handled (in an interrupt context). | 320 | * there is no driver handling the device. An |
310 | * Thus, checking and invoking the driver specific callback takes | 321 | * unloading driver sets the onchannel_callback to NULL. |
311 | * care of orderly unloading of the driver. | ||
312 | */ | ||
313 | callback_fn = READ_ONCE(channel->onchannel_callback); | ||
314 | if (unlikely(callback_fn == NULL)) | ||
315 | return; | ||
316 | |||
317 | (*callback_fn)(channel->channel_callback_context); | ||
318 | |||
319 | if (channel->callback_mode == HV_CALL_BATCHED) { | ||
320 | /* | ||
321 | * This callback reads the messages sent by the host. | ||
322 | * We can optimize host to guest signaling by ensuring: | ||
323 | * 1. While reading the channel, we disable interrupts from | ||
324 | * host. | ||
325 | * 2. Ensure that we process all posted messages from the host | ||
326 | * before returning from this callback. | ||
327 | * 3. Once we return, enable signaling from the host. Once this | ||
328 | * state is set we check to see if additional packets are | ||
329 | * available to read. In this case we repeat the process. | ||
330 | */ | 322 | */ |
331 | if (hv_end_read(&channel->inbound) != 0) { | 323 | callback_fn = READ_ONCE(channel->onchannel_callback); |
332 | hv_begin_read(&channel->inbound); | 324 | if (unlikely(callback_fn == NULL)) |
325 | return; | ||
333 | 326 | ||
334 | tasklet_schedule(&channel->callback_event); | 327 | (*callback_fn)(channel->channel_callback_context); |
335 | } | 328 | |
336 | } | 329 | if (channel->callback_mode != HV_CALL_BATCHED) |
330 | return; | ||
331 | |||
332 | if (likely(hv_end_read(&channel->inbound) == 0)) | ||
333 | return; | ||
334 | |||
335 | hv_begin_read(&channel->inbound); | ||
336 | } while (likely(time_before(jiffies, time_limit))); | ||
337 | |||
338 | /* The time limit (2 jiffies) has been reached */ | ||
339 | tasklet_schedule(&channel->callback_event); | ||
337 | } | 340 | } |
338 | 341 | ||
339 | /* | 342 | /* |
diff --git a/drivers/hv/hv.c b/drivers/hv/hv.c index 665a64f1611e..12e7baecb84e 100644 --- a/drivers/hv/hv.c +++ b/drivers/hv/hv.c | |||
@@ -254,7 +254,10 @@ int hv_synic_init(unsigned int cpu) | |||
254 | shared_sint.as_uint64 = 0; | 254 | shared_sint.as_uint64 = 0; |
255 | shared_sint.vector = HYPERVISOR_CALLBACK_VECTOR; | 255 | shared_sint.vector = HYPERVISOR_CALLBACK_VECTOR; |
256 | shared_sint.masked = false; | 256 | shared_sint.masked = false; |
257 | shared_sint.auto_eoi = true; | 257 | if (ms_hyperv.hints & HV_X64_DEPRECATING_AEOI_RECOMMENDED) |
258 | shared_sint.auto_eoi = false; | ||
259 | else | ||
260 | shared_sint.auto_eoi = true; | ||
258 | 261 | ||
259 | hv_set_synint_state(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, | 262 | hv_set_synint_state(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, |
260 | shared_sint.as_uint64); | 263 | shared_sint.as_uint64); |
diff --git a/drivers/hv/hv_balloon.c b/drivers/hv/hv_balloon.c index 5fd03e59cee5..f5728deff893 100644 --- a/drivers/hv/hv_balloon.c +++ b/drivers/hv/hv_balloon.c | |||
@@ -722,8 +722,6 @@ static void hv_mem_hot_add(unsigned long start, unsigned long size, | |||
722 | 5*HZ); | 722 | 5*HZ); |
723 | post_status(&dm_device); | 723 | post_status(&dm_device); |
724 | } | 724 | } |
725 | |||
726 | return; | ||
727 | } | 725 | } |
728 | 726 | ||
729 | static void hv_online_page(struct page *pg) | 727 | static void hv_online_page(struct page *pg) |
diff --git a/drivers/hv/hv_fcopy.c b/drivers/hv/hv_fcopy.c index a5596a642ed0..daa75bd41f86 100644 --- a/drivers/hv/hv_fcopy.c +++ b/drivers/hv/hv_fcopy.c | |||
@@ -186,8 +186,6 @@ static void fcopy_send_data(struct work_struct *dummy) | |||
186 | } | 186 | } |
187 | } | 187 | } |
188 | kfree(smsg_out); | 188 | kfree(smsg_out); |
189 | |||
190 | return; | ||
191 | } | 189 | } |
192 | 190 | ||
193 | /* | 191 | /* |
diff --git a/drivers/hv/hv_kvp.c b/drivers/hv/hv_kvp.c index a1adfe2cfb34..e99ff2ddad40 100644 --- a/drivers/hv/hv_kvp.c +++ b/drivers/hv/hv_kvp.c | |||
@@ -69,7 +69,7 @@ static const int fw_versions[] = { | |||
69 | * | 69 | * |
70 | * While the request/response protocol is guaranteed by the host, we further | 70 | * While the request/response protocol is guaranteed by the host, we further |
71 | * ensure this by serializing packet processing in this driver - we do not | 71 | * ensure this by serializing packet processing in this driver - we do not |
72 | * read additional packets from the VMBUs until the current packet is fully | 72 | * read additional packets from the VMBUS until the current packet is fully |
73 | * handled. | 73 | * handled. |
74 | */ | 74 | */ |
75 | 75 | ||
@@ -397,7 +397,7 @@ kvp_send_key(struct work_struct *dummy) | |||
397 | * the max lengths specified. We will however, reserve room | 397 | * the max lengths specified. We will however, reserve room |
398 | * for the string terminating character - in the utf16s_utf8s() | 398 | * for the string terminating character - in the utf16s_utf8s() |
399 | * function we limit the size of the buffer where the converted | 399 | * function we limit the size of the buffer where the converted |
400 | * string is placed to HV_KVP_EXCHANGE_MAX_*_SIZE -1 to gaurantee | 400 | * string is placed to HV_KVP_EXCHANGE_MAX_*_SIZE -1 to guarantee |
401 | * that the strings can be properly terminated! | 401 | * that the strings can be properly terminated! |
402 | */ | 402 | */ |
403 | 403 | ||
@@ -483,8 +483,6 @@ kvp_send_key(struct work_struct *dummy) | |||
483 | } | 483 | } |
484 | 484 | ||
485 | kfree(message); | 485 | kfree(message); |
486 | |||
487 | return; | ||
488 | } | 486 | } |
489 | 487 | ||
490 | /* | 488 | /* |
@@ -533,7 +531,7 @@ kvp_respond_to_host(struct hv_kvp_msg *msg_to_host, int error) | |||
533 | */ | 531 | */ |
534 | if (error) { | 532 | if (error) { |
535 | /* | 533 | /* |
536 | * Something failed or we have timedout; | 534 | * Something failed or we have timed out; |
537 | * terminate the current host-side iteration. | 535 | * terminate the current host-side iteration. |
538 | */ | 536 | */ |
539 | goto response_done; | 537 | goto response_done; |
@@ -607,8 +605,8 @@ response_done: | |||
607 | * This callback is invoked when we get a KVP message from the host. | 605 | * This callback is invoked when we get a KVP message from the host. |
608 | * The host ensures that only one KVP transaction can be active at a time. | 606 | * The host ensures that only one KVP transaction can be active at a time. |
609 | * KVP implementation in Linux needs to forward the key to a user-mde | 607 | * KVP implementation in Linux needs to forward the key to a user-mde |
610 | * component to retrive the corresponding value. Consequently, we cannot | 608 | * component to retrieve the corresponding value. Consequently, we cannot |
611 | * respond to the host in the conext of this callback. Since the host | 609 | * respond to the host in the context of this callback. Since the host |
612 | * guarantees that at most only one transaction can be active at a time, | 610 | * guarantees that at most only one transaction can be active at a time, |
613 | * we stash away the transaction state in a set of global variables. | 611 | * we stash away the transaction state in a set of global variables. |
614 | */ | 612 | */ |
diff --git a/drivers/hv/hv_snapshot.c b/drivers/hv/hv_snapshot.c index e659d1b94a57..6831efd73394 100644 --- a/drivers/hv/hv_snapshot.c +++ b/drivers/hv/hv_snapshot.c | |||
@@ -212,8 +212,6 @@ static void vss_send_op(void) | |||
212 | } | 212 | } |
213 | 213 | ||
214 | kfree(vss_msg); | 214 | kfree(vss_msg); |
215 | |||
216 | return; | ||
217 | } | 215 | } |
218 | 216 | ||
219 | static void vss_handle_request(struct work_struct *dummy) | 217 | static void vss_handle_request(struct work_struct *dummy) |
diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h index 884f83bba1ab..6113e915c50e 100644 --- a/drivers/hv/hyperv_vmbus.h +++ b/drivers/hv/hyperv_vmbus.h | |||
@@ -218,8 +218,8 @@ struct hv_per_cpu_context { | |||
218 | 218 | ||
219 | struct hv_context { | 219 | struct hv_context { |
220 | /* We only support running on top of Hyper-V | 220 | /* We only support running on top of Hyper-V |
221 | * So at this point this really can only contain the Hyper-V ID | 221 | * So at this point this really can only contain the Hyper-V ID |
222 | */ | 222 | */ |
223 | u64 guestid; | 223 | u64 guestid; |
224 | 224 | ||
225 | void *tsc_page; | 225 | void *tsc_page; |
@@ -248,14 +248,6 @@ struct hv_context { | |||
248 | 248 | ||
249 | extern struct hv_context hv_context; | 249 | extern struct hv_context hv_context; |
250 | 250 | ||
251 | struct hv_ring_buffer_debug_info { | ||
252 | u32 current_interrupt_mask; | ||
253 | u32 current_read_index; | ||
254 | u32 current_write_index; | ||
255 | u32 bytes_avail_toread; | ||
256 | u32 bytes_avail_towrite; | ||
257 | }; | ||
258 | |||
259 | /* Hv Interface */ | 251 | /* Hv Interface */ |
260 | 252 | ||
261 | extern int hv_init(void); | 253 | extern int hv_init(void); |
@@ -289,9 +281,6 @@ int hv_ringbuffer_read(struct vmbus_channel *channel, | |||
289 | void *buffer, u32 buflen, u32 *buffer_actual_len, | 281 | void *buffer, u32 buflen, u32 *buffer_actual_len, |
290 | u64 *requestid, bool raw); | 282 | u64 *requestid, bool raw); |
291 | 283 | ||
292 | void hv_ringbuffer_get_debuginfo(const struct hv_ring_buffer_info *ring_info, | ||
293 | struct hv_ring_buffer_debug_info *debug_info); | ||
294 | |||
295 | /* | 284 | /* |
296 | * Maximum channels is determined by the size of the interrupt page | 285 | * Maximum channels is determined by the size of the interrupt page |
297 | * which is PAGE_SIZE. 1/2 of PAGE_SIZE is for send endpoint interrupt | 286 | * which is PAGE_SIZE. 1/2 of PAGE_SIZE is for send endpoint interrupt |
@@ -376,7 +365,7 @@ struct vmbus_channel_message_table_entry { | |||
376 | void (*message_handler)(struct vmbus_channel_message_header *msg); | 365 | void (*message_handler)(struct vmbus_channel_message_header *msg); |
377 | }; | 366 | }; |
378 | 367 | ||
379 | extern struct vmbus_channel_message_table_entry | 368 | extern const struct vmbus_channel_message_table_entry |
380 | channel_message_table[CHANNELMSG_COUNT]; | 369 | channel_message_table[CHANNELMSG_COUNT]; |
381 | 370 | ||
382 | 371 | ||
@@ -403,17 +392,17 @@ int vmbus_post_msg(void *buffer, size_t buflen, bool can_sleep); | |||
403 | void vmbus_on_event(unsigned long data); | 392 | void vmbus_on_event(unsigned long data); |
404 | void vmbus_on_msg_dpc(unsigned long data); | 393 | void vmbus_on_msg_dpc(unsigned long data); |
405 | 394 | ||
406 | int hv_kvp_init(struct hv_util_service *); | 395 | int hv_kvp_init(struct hv_util_service *srv); |
407 | void hv_kvp_deinit(void); | 396 | void hv_kvp_deinit(void); |
408 | void hv_kvp_onchannelcallback(void *); | 397 | void hv_kvp_onchannelcallback(void *context); |
409 | 398 | ||
410 | int hv_vss_init(struct hv_util_service *); | 399 | int hv_vss_init(struct hv_util_service *srv); |
411 | void hv_vss_deinit(void); | 400 | void hv_vss_deinit(void); |
412 | void hv_vss_onchannelcallback(void *); | 401 | void hv_vss_onchannelcallback(void *context); |
413 | 402 | ||
414 | int hv_fcopy_init(struct hv_util_service *); | 403 | int hv_fcopy_init(struct hv_util_service *srv); |
415 | void hv_fcopy_deinit(void); | 404 | void hv_fcopy_deinit(void); |
416 | void hv_fcopy_onchannelcallback(void *); | 405 | void hv_fcopy_onchannelcallback(void *context); |
417 | void vmbus_initiate_unload(bool crash); | 406 | void vmbus_initiate_unload(bool crash); |
418 | 407 | ||
419 | static inline void hv_poll_channel(struct vmbus_channel *channel, | 408 | static inline void hv_poll_channel(struct vmbus_channel *channel, |
diff --git a/drivers/hv/ring_buffer.c b/drivers/hv/ring_buffer.c index 87799e81af97..cfacca566e3f 100644 --- a/drivers/hv/ring_buffer.c +++ b/drivers/hv/ring_buffer.c | |||
@@ -73,8 +73,6 @@ static void hv_signal_on_write(u32 old_write, struct vmbus_channel *channel) | |||
73 | */ | 73 | */ |
74 | if (old_write == READ_ONCE(rbi->ring_buffer->read_index)) | 74 | if (old_write == READ_ONCE(rbi->ring_buffer->read_index)) |
75 | vmbus_setevent(channel); | 75 | vmbus_setevent(channel); |
76 | |||
77 | return; | ||
78 | } | 76 | } |
79 | 77 | ||
80 | /* Get the next write location for the specified ring buffer. */ | 78 | /* Get the next write location for the specified ring buffer. */ |
@@ -208,6 +206,7 @@ void hv_ringbuffer_get_debuginfo(const struct hv_ring_buffer_info *ring_info, | |||
208 | ring_info->ring_buffer->interrupt_mask; | 206 | ring_info->ring_buffer->interrupt_mask; |
209 | } | 207 | } |
210 | } | 208 | } |
209 | EXPORT_SYMBOL_GPL(hv_ringbuffer_get_debuginfo); | ||
211 | 210 | ||
212 | /* Initialize the ring buffer. */ | 211 | /* Initialize the ring buffer. */ |
213 | int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info, | 212 | int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info, |
@@ -267,14 +266,13 @@ void hv_ringbuffer_cleanup(struct hv_ring_buffer_info *ring_info) | |||
267 | int hv_ringbuffer_write(struct vmbus_channel *channel, | 266 | int hv_ringbuffer_write(struct vmbus_channel *channel, |
268 | const struct kvec *kv_list, u32 kv_count) | 267 | const struct kvec *kv_list, u32 kv_count) |
269 | { | 268 | { |
270 | int i = 0; | 269 | int i; |
271 | u32 bytes_avail_towrite; | 270 | u32 bytes_avail_towrite; |
272 | u32 totalbytes_towrite = 0; | 271 | u32 totalbytes_towrite = sizeof(u64); |
273 | |||
274 | u32 next_write_location; | 272 | u32 next_write_location; |
275 | u32 old_write; | 273 | u32 old_write; |
276 | u64 prev_indices = 0; | 274 | u64 prev_indices; |
277 | unsigned long flags = 0; | 275 | unsigned long flags; |
278 | struct hv_ring_buffer_info *outring_info = &channel->outbound; | 276 | struct hv_ring_buffer_info *outring_info = &channel->outbound; |
279 | 277 | ||
280 | if (channel->rescind) | 278 | if (channel->rescind) |
@@ -283,8 +281,6 @@ int hv_ringbuffer_write(struct vmbus_channel *channel, | |||
283 | for (i = 0; i < kv_count; i++) | 281 | for (i = 0; i < kv_count; i++) |
284 | totalbytes_towrite += kv_list[i].iov_len; | 282 | totalbytes_towrite += kv_list[i].iov_len; |
285 | 283 | ||
286 | totalbytes_towrite += sizeof(u64); | ||
287 | |||
288 | spin_lock_irqsave(&outring_info->ring_lock, flags); | 284 | spin_lock_irqsave(&outring_info->ring_lock, flags); |
289 | 285 | ||
290 | bytes_avail_towrite = hv_get_bytes_to_write(outring_info); | 286 | bytes_avail_towrite = hv_get_bytes_to_write(outring_info); |
@@ -341,18 +337,16 @@ int hv_ringbuffer_read(struct vmbus_channel *channel, | |||
341 | u64 *requestid, bool raw) | 337 | u64 *requestid, bool raw) |
342 | { | 338 | { |
343 | u32 bytes_avail_toread; | 339 | u32 bytes_avail_toread; |
344 | u32 next_read_location = 0; | 340 | u32 next_read_location; |
345 | u64 prev_indices = 0; | 341 | u64 prev_indices = 0; |
346 | struct vmpacket_descriptor desc; | 342 | struct vmpacket_descriptor desc; |
347 | u32 offset; | 343 | u32 offset; |
348 | u32 packetlen; | 344 | u32 packetlen; |
349 | int ret = 0; | ||
350 | struct hv_ring_buffer_info *inring_info = &channel->inbound; | 345 | struct hv_ring_buffer_info *inring_info = &channel->inbound; |
351 | 346 | ||
352 | if (buflen <= 0) | 347 | if (buflen <= 0) |
353 | return -EINVAL; | 348 | return -EINVAL; |
354 | 349 | ||
355 | |||
356 | *buffer_actual_len = 0; | 350 | *buffer_actual_len = 0; |
357 | *requestid = 0; | 351 | *requestid = 0; |
358 | 352 | ||
@@ -363,7 +357,7 @@ int hv_ringbuffer_read(struct vmbus_channel *channel, | |||
363 | * No error is set when there is even no header, drivers are | 357 | * No error is set when there is even no header, drivers are |
364 | * supposed to analyze buffer_actual_len. | 358 | * supposed to analyze buffer_actual_len. |
365 | */ | 359 | */ |
366 | return ret; | 360 | return 0; |
367 | } | 361 | } |
368 | 362 | ||
369 | init_cached_read_index(channel); | 363 | init_cached_read_index(channel); |
@@ -408,5 +402,5 @@ int hv_ringbuffer_read(struct vmbus_channel *channel, | |||
408 | 402 | ||
409 | hv_signal_on_read(channel); | 403 | hv_signal_on_read(channel); |
410 | 404 | ||
411 | return ret; | 405 | return 0; |
412 | } | 406 | } |
diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c index 8370b9dc6037..0087b49095eb 100644 --- a/drivers/hv/vmbus_drv.c +++ b/drivers/hv/vmbus_drv.c | |||
@@ -787,8 +787,6 @@ static void vmbus_shutdown(struct device *child_device) | |||
787 | 787 | ||
788 | if (drv->shutdown) | 788 | if (drv->shutdown) |
789 | drv->shutdown(dev); | 789 | drv->shutdown(dev); |
790 | |||
791 | return; | ||
792 | } | 790 | } |
793 | 791 | ||
794 | 792 | ||
@@ -855,7 +853,7 @@ void vmbus_on_msg_dpc(unsigned long data) | |||
855 | struct hv_message *msg = (struct hv_message *)page_addr + | 853 | struct hv_message *msg = (struct hv_message *)page_addr + |
856 | VMBUS_MESSAGE_SINT; | 854 | VMBUS_MESSAGE_SINT; |
857 | struct vmbus_channel_message_header *hdr; | 855 | struct vmbus_channel_message_header *hdr; |
858 | struct vmbus_channel_message_table_entry *entry; | 856 | const struct vmbus_channel_message_table_entry *entry; |
859 | struct onmessage_work_context *ctx; | 857 | struct onmessage_work_context *ctx; |
860 | u32 message_type = msg->header.message_type; | 858 | u32 message_type = msg->header.message_type; |
861 | 859 | ||
diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig index b7767da50c26..1de8372d9459 100644 --- a/drivers/md/Kconfig +++ b/drivers/md/Kconfig | |||
@@ -200,6 +200,7 @@ config BLK_DEV_DM_BUILTIN | |||
200 | config BLK_DEV_DM | 200 | config BLK_DEV_DM |
201 | tristate "Device mapper support" | 201 | tristate "Device mapper support" |
202 | select BLK_DEV_DM_BUILTIN | 202 | select BLK_DEV_DM_BUILTIN |
203 | select DAX | ||
203 | ---help--- | 204 | ---help--- |
204 | Device-mapper is a low level volume manager. It works by allowing | 205 | Device-mapper is a low level volume manager. It works by allowing |
205 | people to specify mappings for ranges of logical sectors. Various | 206 | people to specify mappings for ranges of logical sectors. Various |
diff --git a/drivers/md/dm-core.h b/drivers/md/dm-core.h index 136fda3ff9e5..538630190f66 100644 --- a/drivers/md/dm-core.h +++ b/drivers/md/dm-core.h | |||
@@ -58,6 +58,7 @@ struct mapped_device { | |||
58 | struct target_type *immutable_target_type; | 58 | struct target_type *immutable_target_type; |
59 | 59 | ||
60 | struct gendisk *disk; | 60 | struct gendisk *disk; |
61 | struct dax_device *dax_dev; | ||
61 | char name[16]; | 62 | char name[16]; |
62 | 63 | ||
63 | void *interface_ptr; | 64 | void *interface_ptr; |
diff --git a/drivers/md/dm-linear.c b/drivers/md/dm-linear.c index 4788b0b989a9..c5a52f4dae81 100644 --- a/drivers/md/dm-linear.c +++ b/drivers/md/dm-linear.c | |||
@@ -9,6 +9,7 @@ | |||
9 | #include <linux/init.h> | 9 | #include <linux/init.h> |
10 | #include <linux/blkdev.h> | 10 | #include <linux/blkdev.h> |
11 | #include <linux/bio.h> | 11 | #include <linux/bio.h> |
12 | #include <linux/dax.h> | ||
12 | #include <linux/slab.h> | 13 | #include <linux/slab.h> |
13 | #include <linux/device-mapper.h> | 14 | #include <linux/device-mapper.h> |
14 | 15 | ||
@@ -141,22 +142,20 @@ static int linear_iterate_devices(struct dm_target *ti, | |||
141 | return fn(ti, lc->dev, lc->start, ti->len, data); | 142 | return fn(ti, lc->dev, lc->start, ti->len, data); |
142 | } | 143 | } |
143 | 144 | ||
144 | static long linear_direct_access(struct dm_target *ti, sector_t sector, | 145 | static long linear_dax_direct_access(struct dm_target *ti, pgoff_t pgoff, |
145 | void **kaddr, pfn_t *pfn, long size) | 146 | long nr_pages, void **kaddr, pfn_t *pfn) |
146 | { | 147 | { |
148 | long ret; | ||
147 | struct linear_c *lc = ti->private; | 149 | struct linear_c *lc = ti->private; |
148 | struct block_device *bdev = lc->dev->bdev; | 150 | struct block_device *bdev = lc->dev->bdev; |
149 | struct blk_dax_ctl dax = { | 151 | struct dax_device *dax_dev = lc->dev->dax_dev; |
150 | .sector = linear_map_sector(ti, sector), | 152 | sector_t dev_sector, sector = pgoff * PAGE_SECTORS; |
151 | .size = size, | 153 | |
152 | }; | 154 | dev_sector = linear_map_sector(ti, sector); |
153 | long ret; | 155 | ret = bdev_dax_pgoff(bdev, dev_sector, nr_pages * PAGE_SIZE, &pgoff); |
154 | 156 | if (ret) | |
155 | ret = bdev_direct_access(bdev, &dax); | 157 | return ret; |
156 | *kaddr = dax.addr; | 158 | return dax_direct_access(dax_dev, pgoff, nr_pages, kaddr, pfn); |
157 | *pfn = dax.pfn; | ||
158 | |||
159 | return ret; | ||
160 | } | 159 | } |
161 | 160 | ||
162 | static struct target_type linear_target = { | 161 | static struct target_type linear_target = { |
@@ -169,7 +168,7 @@ static struct target_type linear_target = { | |||
169 | .status = linear_status, | 168 | .status = linear_status, |
170 | .prepare_ioctl = linear_prepare_ioctl, | 169 | .prepare_ioctl = linear_prepare_ioctl, |
171 | .iterate_devices = linear_iterate_devices, | 170 | .iterate_devices = linear_iterate_devices, |
172 | .direct_access = linear_direct_access, | 171 | .direct_access = linear_dax_direct_access, |
173 | }; | 172 | }; |
174 | 173 | ||
175 | int __init dm_linear_init(void) | 174 | int __init dm_linear_init(void) |
diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c index c65feeada864..e152d9817c81 100644 --- a/drivers/md/dm-snap.c +++ b/drivers/md/dm-snap.c | |||
@@ -2302,8 +2302,8 @@ static int origin_map(struct dm_target *ti, struct bio *bio) | |||
2302 | return do_origin(o->dev, bio); | 2302 | return do_origin(o->dev, bio); |
2303 | } | 2303 | } |
2304 | 2304 | ||
2305 | static long origin_direct_access(struct dm_target *ti, sector_t sector, | 2305 | static long origin_dax_direct_access(struct dm_target *ti, pgoff_t pgoff, |
2306 | void **kaddr, pfn_t *pfn, long size) | 2306 | long nr_pages, void **kaddr, pfn_t *pfn) |
2307 | { | 2307 | { |
2308 | DMWARN("device does not support dax."); | 2308 | DMWARN("device does not support dax."); |
2309 | return -EIO; | 2309 | return -EIO; |
@@ -2368,7 +2368,7 @@ static struct target_type origin_target = { | |||
2368 | .postsuspend = origin_postsuspend, | 2368 | .postsuspend = origin_postsuspend, |
2369 | .status = origin_status, | 2369 | .status = origin_status, |
2370 | .iterate_devices = origin_iterate_devices, | 2370 | .iterate_devices = origin_iterate_devices, |
2371 | .direct_access = origin_direct_access, | 2371 | .direct_access = origin_dax_direct_access, |
2372 | }; | 2372 | }; |
2373 | 2373 | ||
2374 | static struct target_type snapshot_target = { | 2374 | static struct target_type snapshot_target = { |
diff --git a/drivers/md/dm-stripe.c b/drivers/md/dm-stripe.c index 28193a57bf47..cb4b1e9e16ab 100644 --- a/drivers/md/dm-stripe.c +++ b/drivers/md/dm-stripe.c | |||
@@ -11,6 +11,7 @@ | |||
11 | #include <linux/init.h> | 11 | #include <linux/init.h> |
12 | #include <linux/blkdev.h> | 12 | #include <linux/blkdev.h> |
13 | #include <linux/bio.h> | 13 | #include <linux/bio.h> |
14 | #include <linux/dax.h> | ||
14 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
15 | #include <linux/log2.h> | 16 | #include <linux/log2.h> |
16 | 17 | ||
@@ -308,27 +309,25 @@ static int stripe_map(struct dm_target *ti, struct bio *bio) | |||
308 | return DM_MAPIO_REMAPPED; | 309 | return DM_MAPIO_REMAPPED; |
309 | } | 310 | } |
310 | 311 | ||
311 | static long stripe_direct_access(struct dm_target *ti, sector_t sector, | 312 | static long stripe_dax_direct_access(struct dm_target *ti, pgoff_t pgoff, |
312 | void **kaddr, pfn_t *pfn, long size) | 313 | long nr_pages, void **kaddr, pfn_t *pfn) |
313 | { | 314 | { |
315 | sector_t dev_sector, sector = pgoff * PAGE_SECTORS; | ||
314 | struct stripe_c *sc = ti->private; | 316 | struct stripe_c *sc = ti->private; |
315 | uint32_t stripe; | 317 | struct dax_device *dax_dev; |
316 | struct block_device *bdev; | 318 | struct block_device *bdev; |
317 | struct blk_dax_ctl dax = { | 319 | uint32_t stripe; |
318 | .size = size, | ||
319 | }; | ||
320 | long ret; | 320 | long ret; |
321 | 321 | ||
322 | stripe_map_sector(sc, sector, &stripe, &dax.sector); | 322 | stripe_map_sector(sc, sector, &stripe, &dev_sector); |
323 | 323 | dev_sector += sc->stripe[stripe].physical_start; | |
324 | dax.sector += sc->stripe[stripe].physical_start; | 324 | dax_dev = sc->stripe[stripe].dev->dax_dev; |
325 | bdev = sc->stripe[stripe].dev->bdev; | 325 | bdev = sc->stripe[stripe].dev->bdev; |
326 | 326 | ||
327 | ret = bdev_direct_access(bdev, &dax); | 327 | ret = bdev_dax_pgoff(bdev, dev_sector, nr_pages * PAGE_SIZE, &pgoff); |
328 | *kaddr = dax.addr; | 328 | if (ret) |
329 | *pfn = dax.pfn; | 329 | return ret; |
330 | 330 | return dax_direct_access(dax_dev, pgoff, nr_pages, kaddr, pfn); | |
331 | return ret; | ||
332 | } | 331 | } |
333 | 332 | ||
334 | /* | 333 | /* |
@@ -448,7 +447,7 @@ static struct target_type stripe_target = { | |||
448 | .status = stripe_status, | 447 | .status = stripe_status, |
449 | .iterate_devices = stripe_iterate_devices, | 448 | .iterate_devices = stripe_iterate_devices, |
450 | .io_hints = stripe_io_hints, | 449 | .io_hints = stripe_io_hints, |
451 | .direct_access = stripe_direct_access, | 450 | .direct_access = stripe_dax_direct_access, |
452 | }; | 451 | }; |
453 | 452 | ||
454 | int __init dm_stripe_init(void) | 453 | int __init dm_stripe_init(void) |
diff --git a/drivers/md/dm-target.c b/drivers/md/dm-target.c index 43d3445b121d..6a7968f93f3c 100644 --- a/drivers/md/dm-target.c +++ b/drivers/md/dm-target.c | |||
@@ -142,8 +142,8 @@ static void io_err_release_clone_rq(struct request *clone) | |||
142 | { | 142 | { |
143 | } | 143 | } |
144 | 144 | ||
145 | static long io_err_direct_access(struct dm_target *ti, sector_t sector, | 145 | static long io_err_dax_direct_access(struct dm_target *ti, pgoff_t pgoff, |
146 | void **kaddr, pfn_t *pfn, long size) | 146 | long nr_pages, void **kaddr, pfn_t *pfn) |
147 | { | 147 | { |
148 | return -EIO; | 148 | return -EIO; |
149 | } | 149 | } |
@@ -157,7 +157,7 @@ static struct target_type error_target = { | |||
157 | .map = io_err_map, | 157 | .map = io_err_map, |
158 | .clone_and_map_rq = io_err_clone_and_map_rq, | 158 | .clone_and_map_rq = io_err_clone_and_map_rq, |
159 | .release_clone_rq = io_err_release_clone_rq, | 159 | .release_clone_rq = io_err_release_clone_rq, |
160 | .direct_access = io_err_direct_access, | 160 | .direct_access = io_err_dax_direct_access, |
161 | }; | 161 | }; |
162 | 162 | ||
163 | int __init dm_target_init(void) | 163 | int __init dm_target_init(void) |
diff --git a/drivers/md/dm.c b/drivers/md/dm.c index dfb75979e455..79d5f5fd823e 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/blkpg.h> | 16 | #include <linux/blkpg.h> |
17 | #include <linux/bio.h> | 17 | #include <linux/bio.h> |
18 | #include <linux/mempool.h> | 18 | #include <linux/mempool.h> |
19 | #include <linux/dax.h> | ||
19 | #include <linux/slab.h> | 20 | #include <linux/slab.h> |
20 | #include <linux/idr.h> | 21 | #include <linux/idr.h> |
21 | #include <linux/hdreg.h> | 22 | #include <linux/hdreg.h> |
@@ -629,6 +630,7 @@ static int open_table_device(struct table_device *td, dev_t dev, | |||
629 | } | 630 | } |
630 | 631 | ||
631 | td->dm_dev.bdev = bdev; | 632 | td->dm_dev.bdev = bdev; |
633 | td->dm_dev.dax_dev = dax_get_by_host(bdev->bd_disk->disk_name); | ||
632 | return 0; | 634 | return 0; |
633 | } | 635 | } |
634 | 636 | ||
@@ -642,7 +644,9 @@ static void close_table_device(struct table_device *td, struct mapped_device *md | |||
642 | 644 | ||
643 | bd_unlink_disk_holder(td->dm_dev.bdev, dm_disk(md)); | 645 | bd_unlink_disk_holder(td->dm_dev.bdev, dm_disk(md)); |
644 | blkdev_put(td->dm_dev.bdev, td->dm_dev.mode | FMODE_EXCL); | 646 | blkdev_put(td->dm_dev.bdev, td->dm_dev.mode | FMODE_EXCL); |
647 | put_dax(td->dm_dev.dax_dev); | ||
645 | td->dm_dev.bdev = NULL; | 648 | td->dm_dev.bdev = NULL; |
649 | td->dm_dev.dax_dev = NULL; | ||
646 | } | 650 | } |
647 | 651 | ||
648 | static struct table_device *find_table_device(struct list_head *l, dev_t dev, | 652 | static struct table_device *find_table_device(struct list_head *l, dev_t dev, |
@@ -908,31 +912,49 @@ int dm_set_target_max_io_len(struct dm_target *ti, sector_t len) | |||
908 | } | 912 | } |
909 | EXPORT_SYMBOL_GPL(dm_set_target_max_io_len); | 913 | EXPORT_SYMBOL_GPL(dm_set_target_max_io_len); |
910 | 914 | ||
911 | static long dm_blk_direct_access(struct block_device *bdev, sector_t sector, | 915 | static struct dm_target *dm_dax_get_live_target(struct mapped_device *md, |
912 | void **kaddr, pfn_t *pfn, long size) | 916 | sector_t sector, int *srcu_idx) |
913 | { | 917 | { |
914 | struct mapped_device *md = bdev->bd_disk->private_data; | ||
915 | struct dm_table *map; | 918 | struct dm_table *map; |
916 | struct dm_target *ti; | 919 | struct dm_target *ti; |
917 | int srcu_idx; | ||
918 | long len, ret = -EIO; | ||
919 | 920 | ||
920 | map = dm_get_live_table(md, &srcu_idx); | 921 | map = dm_get_live_table(md, srcu_idx); |
921 | if (!map) | 922 | if (!map) |
922 | goto out; | 923 | return NULL; |
923 | 924 | ||
924 | ti = dm_table_find_target(map, sector); | 925 | ti = dm_table_find_target(map, sector); |
925 | if (!dm_target_is_valid(ti)) | 926 | if (!dm_target_is_valid(ti)) |
926 | goto out; | 927 | return NULL; |
928 | |||
929 | return ti; | ||
930 | } | ||
931 | |||
932 | static long dm_dax_direct_access(struct dax_device *dax_dev, pgoff_t pgoff, | ||
933 | long nr_pages, void **kaddr, pfn_t *pfn) | ||
934 | { | ||
935 | struct mapped_device *md = dax_get_private(dax_dev); | ||
936 | sector_t sector = pgoff * PAGE_SECTORS; | ||
937 | struct dm_target *ti; | ||
938 | long len, ret = -EIO; | ||
939 | int srcu_idx; | ||
927 | 940 | ||
928 | len = max_io_len(sector, ti) << SECTOR_SHIFT; | 941 | ti = dm_dax_get_live_target(md, sector, &srcu_idx); |
929 | size = min(len, size); | ||
930 | 942 | ||
943 | if (!ti) | ||
944 | goto out; | ||
945 | if (!ti->type->direct_access) | ||
946 | goto out; | ||
947 | len = max_io_len(sector, ti) / PAGE_SECTORS; | ||
948 | if (len < 1) | ||
949 | goto out; | ||
950 | nr_pages = min(len, nr_pages); | ||
931 | if (ti->type->direct_access) | 951 | if (ti->type->direct_access) |
932 | ret = ti->type->direct_access(ti, sector, kaddr, pfn, size); | 952 | ret = ti->type->direct_access(ti, pgoff, nr_pages, kaddr, pfn); |
933 | out: | 953 | |
954 | out: | ||
934 | dm_put_live_table(md, srcu_idx); | 955 | dm_put_live_table(md, srcu_idx); |
935 | return min(ret, size); | 956 | |
957 | return ret; | ||
936 | } | 958 | } |
937 | 959 | ||
938 | /* | 960 | /* |
@@ -1437,6 +1459,7 @@ static int next_free_minor(int *minor) | |||
1437 | } | 1459 | } |
1438 | 1460 | ||
1439 | static const struct block_device_operations dm_blk_dops; | 1461 | static const struct block_device_operations dm_blk_dops; |
1462 | static const struct dax_operations dm_dax_ops; | ||
1440 | 1463 | ||
1441 | static void dm_wq_work(struct work_struct *work); | 1464 | static void dm_wq_work(struct work_struct *work); |
1442 | 1465 | ||
@@ -1483,6 +1506,12 @@ static void cleanup_mapped_device(struct mapped_device *md) | |||
1483 | if (md->bs) | 1506 | if (md->bs) |
1484 | bioset_free(md->bs); | 1507 | bioset_free(md->bs); |
1485 | 1508 | ||
1509 | if (md->dax_dev) { | ||
1510 | kill_dax(md->dax_dev); | ||
1511 | put_dax(md->dax_dev); | ||
1512 | md->dax_dev = NULL; | ||
1513 | } | ||
1514 | |||
1486 | if (md->disk) { | 1515 | if (md->disk) { |
1487 | spin_lock(&_minor_lock); | 1516 | spin_lock(&_minor_lock); |
1488 | md->disk->private_data = NULL; | 1517 | md->disk->private_data = NULL; |
@@ -1510,6 +1539,7 @@ static void cleanup_mapped_device(struct mapped_device *md) | |||
1510 | static struct mapped_device *alloc_dev(int minor) | 1539 | static struct mapped_device *alloc_dev(int minor) |
1511 | { | 1540 | { |
1512 | int r, numa_node_id = dm_get_numa_node(); | 1541 | int r, numa_node_id = dm_get_numa_node(); |
1542 | struct dax_device *dax_dev; | ||
1513 | struct mapped_device *md; | 1543 | struct mapped_device *md; |
1514 | void *old_md; | 1544 | void *old_md; |
1515 | 1545 | ||
@@ -1574,6 +1604,12 @@ static struct mapped_device *alloc_dev(int minor) | |||
1574 | md->disk->queue = md->queue; | 1604 | md->disk->queue = md->queue; |
1575 | md->disk->private_data = md; | 1605 | md->disk->private_data = md; |
1576 | sprintf(md->disk->disk_name, "dm-%d", minor); | 1606 | sprintf(md->disk->disk_name, "dm-%d", minor); |
1607 | |||
1608 | dax_dev = alloc_dax(md, md->disk->disk_name, &dm_dax_ops); | ||
1609 | if (!dax_dev) | ||
1610 | goto bad; | ||
1611 | md->dax_dev = dax_dev; | ||
1612 | |||
1577 | add_disk(md->disk); | 1613 | add_disk(md->disk); |
1578 | format_dev_t(md->name, MKDEV(_major, minor)); | 1614 | format_dev_t(md->name, MKDEV(_major, minor)); |
1579 | 1615 | ||
@@ -2775,12 +2811,15 @@ static const struct block_device_operations dm_blk_dops = { | |||
2775 | .open = dm_blk_open, | 2811 | .open = dm_blk_open, |
2776 | .release = dm_blk_close, | 2812 | .release = dm_blk_close, |
2777 | .ioctl = dm_blk_ioctl, | 2813 | .ioctl = dm_blk_ioctl, |
2778 | .direct_access = dm_blk_direct_access, | ||
2779 | .getgeo = dm_blk_getgeo, | 2814 | .getgeo = dm_blk_getgeo, |
2780 | .pr_ops = &dm_pr_ops, | 2815 | .pr_ops = &dm_pr_ops, |
2781 | .owner = THIS_MODULE | 2816 | .owner = THIS_MODULE |
2782 | }; | 2817 | }; |
2783 | 2818 | ||
2819 | static const struct dax_operations dm_dax_ops = { | ||
2820 | .direct_access = dm_dax_direct_access, | ||
2821 | }; | ||
2822 | |||
2784 | /* | 2823 | /* |
2785 | * module hooks | 2824 | * module hooks |
2786 | */ | 2825 | */ |
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index c290990d73ed..fb933b0b9297 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig | |||
@@ -495,6 +495,7 @@ config VEXPRESS_SYSCFG | |||
495 | config PANEL | 495 | config PANEL |
496 | tristate "Parallel port LCD/Keypad Panel support" | 496 | tristate "Parallel port LCD/Keypad Panel support" |
497 | depends on PARPORT | 497 | depends on PARPORT |
498 | select CHARLCD | ||
498 | ---help--- | 499 | ---help--- |
499 | Say Y here if you have an HD44780 or KS-0074 LCD connected to your | 500 | Say Y here if you have an HD44780 or KS-0074 LCD connected to your |
500 | parallel port. This driver also features 4 and 6-key keypads. The LCD | 501 | parallel port. This driver also features 4 and 6-key keypads. The LCD |
@@ -771,6 +772,14 @@ config PANEL_BOOT_MESSAGE | |||
771 | 772 | ||
772 | endif # PANEL | 773 | endif # PANEL |
773 | 774 | ||
775 | config ASPEED_LPC_CTRL | ||
776 | depends on (ARCH_ASPEED || COMPILE_TEST) && REGMAP && MFD_SYSCON | ||
777 | tristate "Aspeed ast2400/2500 HOST LPC to BMC bridge control" | ||
778 | ---help--- | ||
779 | Control Aspeed ast2400/2500 HOST LPC to BMC mappings through | ||
780 | ioctl()s, the driver also provides a read/write interface to a BMC ram | ||
781 | region where the host LPC read/write region can be buffered. | ||
782 | |||
774 | source "drivers/misc/c2port/Kconfig" | 783 | source "drivers/misc/c2port/Kconfig" |
775 | source "drivers/misc/eeprom/Kconfig" | 784 | source "drivers/misc/eeprom/Kconfig" |
776 | source "drivers/misc/cb710/Kconfig" | 785 | source "drivers/misc/cb710/Kconfig" |
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 7a3ea89339b4..4925ea8e1952 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile | |||
@@ -54,6 +54,7 @@ obj-$(CONFIG_ECHO) += echo/ | |||
54 | obj-$(CONFIG_VEXPRESS_SYSCFG) += vexpress-syscfg.o | 54 | obj-$(CONFIG_VEXPRESS_SYSCFG) += vexpress-syscfg.o |
55 | obj-$(CONFIG_CXL_BASE) += cxl/ | 55 | obj-$(CONFIG_CXL_BASE) += cxl/ |
56 | obj-$(CONFIG_PANEL) += panel.o | 56 | obj-$(CONFIG_PANEL) += panel.o |
57 | obj-$(CONFIG_ASPEED_LPC_CTRL) += aspeed-lpc-ctrl.o | ||
57 | 58 | ||
58 | lkdtm-$(CONFIG_LKDTM) += lkdtm_core.o | 59 | lkdtm-$(CONFIG_LKDTM) += lkdtm_core.o |
59 | lkdtm-$(CONFIG_LKDTM) += lkdtm_bugs.o | 60 | lkdtm-$(CONFIG_LKDTM) += lkdtm_bugs.o |
diff --git a/drivers/misc/aspeed-lpc-ctrl.c b/drivers/misc/aspeed-lpc-ctrl.c new file mode 100644 index 000000000000..f6acbe1d9378 --- /dev/null +++ b/drivers/misc/aspeed-lpc-ctrl.c | |||
@@ -0,0 +1,267 @@ | |||
1 | /* | ||
2 | * Copyright 2017 IBM Corporation | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public License | ||
6 | * as published by the Free Software Foundation; either version | ||
7 | * 2 of the License, or (at your option) any later version. | ||
8 | */ | ||
9 | |||
10 | #include <linux/mfd/syscon.h> | ||
11 | #include <linux/miscdevice.h> | ||
12 | #include <linux/mm.h> | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/of_address.h> | ||
15 | #include <linux/platform_device.h> | ||
16 | #include <linux/poll.h> | ||
17 | #include <linux/regmap.h> | ||
18 | |||
19 | #include <linux/aspeed-lpc-ctrl.h> | ||
20 | |||
21 | #define DEVICE_NAME "aspeed-lpc-ctrl" | ||
22 | |||
23 | #define HICR7 0x8 | ||
24 | #define HICR8 0xc | ||
25 | |||
26 | struct aspeed_lpc_ctrl { | ||
27 | struct miscdevice miscdev; | ||
28 | struct regmap *regmap; | ||
29 | phys_addr_t mem_base; | ||
30 | resource_size_t mem_size; | ||
31 | u32 pnor_size; | ||
32 | u32 pnor_base; | ||
33 | }; | ||
34 | |||
35 | static struct aspeed_lpc_ctrl *file_aspeed_lpc_ctrl(struct file *file) | ||
36 | { | ||
37 | return container_of(file->private_data, struct aspeed_lpc_ctrl, | ||
38 | miscdev); | ||
39 | } | ||
40 | |||
41 | static int aspeed_lpc_ctrl_mmap(struct file *file, struct vm_area_struct *vma) | ||
42 | { | ||
43 | struct aspeed_lpc_ctrl *lpc_ctrl = file_aspeed_lpc_ctrl(file); | ||
44 | unsigned long vsize = vma->vm_end - vma->vm_start; | ||
45 | pgprot_t prot = vma->vm_page_prot; | ||
46 | |||
47 | if (vma->vm_pgoff + vsize > lpc_ctrl->mem_base + lpc_ctrl->mem_size) | ||
48 | return -EINVAL; | ||
49 | |||
50 | /* ast2400/2500 AHB accesses are not cache coherent */ | ||
51 | prot = pgprot_dmacoherent(prot); | ||
52 | |||
53 | if (remap_pfn_range(vma, vma->vm_start, | ||
54 | (lpc_ctrl->mem_base >> PAGE_SHIFT) + vma->vm_pgoff, | ||
55 | vsize, prot)) | ||
56 | return -EAGAIN; | ||
57 | |||
58 | return 0; | ||
59 | } | ||
60 | |||
61 | static long aspeed_lpc_ctrl_ioctl(struct file *file, unsigned int cmd, | ||
62 | unsigned long param) | ||
63 | { | ||
64 | struct aspeed_lpc_ctrl *lpc_ctrl = file_aspeed_lpc_ctrl(file); | ||
65 | void __user *p = (void __user *)param; | ||
66 | struct aspeed_lpc_ctrl_mapping map; | ||
67 | u32 addr; | ||
68 | u32 size; | ||
69 | long rc; | ||
70 | |||
71 | if (copy_from_user(&map, p, sizeof(map))) | ||
72 | return -EFAULT; | ||
73 | |||
74 | if (map.flags != 0) | ||
75 | return -EINVAL; | ||
76 | |||
77 | switch (cmd) { | ||
78 | case ASPEED_LPC_CTRL_IOCTL_GET_SIZE: | ||
79 | /* The flash windows don't report their size */ | ||
80 | if (map.window_type != ASPEED_LPC_CTRL_WINDOW_MEMORY) | ||
81 | return -EINVAL; | ||
82 | |||
83 | /* Support more than one window id in the future */ | ||
84 | if (map.window_id != 0) | ||
85 | return -EINVAL; | ||
86 | |||
87 | map.size = lpc_ctrl->mem_size; | ||
88 | |||
89 | return copy_to_user(p, &map, sizeof(map)) ? -EFAULT : 0; | ||
90 | case ASPEED_LPC_CTRL_IOCTL_MAP: | ||
91 | |||
92 | /* | ||
93 | * The top half of HICR7 is the MSB of the BMC address of the | ||
94 | * mapping. | ||
95 | * The bottom half of HICR7 is the MSB of the HOST LPC | ||
96 | * firmware space address of the mapping. | ||
97 | * | ||
98 | * The 1 bits in the top of half of HICR8 represent the bits | ||
99 | * (in the requested address) that should be ignored and | ||
100 | * replaced with those from the top half of HICR7. | ||
101 | * The 1 bits in the bottom half of HICR8 represent the bits | ||
102 | * (in the requested address) that should be kept and pass | ||
103 | * into the BMC address space. | ||
104 | */ | ||
105 | |||
106 | /* | ||
107 | * It doesn't make sense to talk about a size or offset with | ||
108 | * low 16 bits set. Both HICR7 and HICR8 talk about the top 16 | ||
109 | * bits of addresses and sizes. | ||
110 | */ | ||
111 | |||
112 | if ((map.size & 0x0000ffff) || (map.offset & 0x0000ffff)) | ||
113 | return -EINVAL; | ||
114 | |||
115 | /* | ||
116 | * Because of the way the masks work in HICR8 offset has to | ||
117 | * be a multiple of size. | ||
118 | */ | ||
119 | if (map.offset & (map.size - 1)) | ||
120 | return -EINVAL; | ||
121 | |||
122 | if (map.window_type == ASPEED_LPC_CTRL_WINDOW_FLASH) { | ||
123 | addr = lpc_ctrl->pnor_base; | ||
124 | size = lpc_ctrl->pnor_size; | ||
125 | } else if (map.window_type == ASPEED_LPC_CTRL_WINDOW_MEMORY) { | ||
126 | addr = lpc_ctrl->mem_base; | ||
127 | size = lpc_ctrl->mem_size; | ||
128 | } else { | ||
129 | return -EINVAL; | ||
130 | } | ||
131 | |||
132 | /* Check overflow first! */ | ||
133 | if (map.offset + map.size < map.offset || | ||
134 | map.offset + map.size > size) | ||
135 | return -EINVAL; | ||
136 | |||
137 | if (map.size == 0 || map.size > size) | ||
138 | return -EINVAL; | ||
139 | |||
140 | addr += map.offset; | ||
141 | |||
142 | /* | ||
143 | * addr (host lpc address) is safe regardless of values. This | ||
144 | * simply changes the address the host has to request on its | ||
145 | * side of the LPC bus. This cannot impact the hosts own | ||
146 | * memory space by surprise as LPC specific accessors are | ||
147 | * required. The only strange thing that could be done is | ||
148 | * setting the lower 16 bits but the shift takes care of that. | ||
149 | */ | ||
150 | |||
151 | rc = regmap_write(lpc_ctrl->regmap, HICR7, | ||
152 | (addr | (map.addr >> 16))); | ||
153 | if (rc) | ||
154 | return rc; | ||
155 | |||
156 | return regmap_write(lpc_ctrl->regmap, HICR8, | ||
157 | (~(map.size - 1)) | ((map.size >> 16) - 1)); | ||
158 | } | ||
159 | |||
160 | return -EINVAL; | ||
161 | } | ||
162 | |||
163 | static const struct file_operations aspeed_lpc_ctrl_fops = { | ||
164 | .owner = THIS_MODULE, | ||
165 | .mmap = aspeed_lpc_ctrl_mmap, | ||
166 | .unlocked_ioctl = aspeed_lpc_ctrl_ioctl, | ||
167 | }; | ||
168 | |||
169 | static int aspeed_lpc_ctrl_probe(struct platform_device *pdev) | ||
170 | { | ||
171 | struct aspeed_lpc_ctrl *lpc_ctrl; | ||
172 | struct device_node *node; | ||
173 | struct resource resm; | ||
174 | struct device *dev; | ||
175 | int rc; | ||
176 | |||
177 | dev = &pdev->dev; | ||
178 | |||
179 | lpc_ctrl = devm_kzalloc(dev, sizeof(*lpc_ctrl), GFP_KERNEL); | ||
180 | if (!lpc_ctrl) | ||
181 | return -ENOMEM; | ||
182 | |||
183 | node = of_parse_phandle(dev->of_node, "flash", 0); | ||
184 | if (!node) { | ||
185 | dev_err(dev, "Didn't find host pnor flash node\n"); | ||
186 | return -ENODEV; | ||
187 | } | ||
188 | |||
189 | rc = of_address_to_resource(node, 1, &resm); | ||
190 | of_node_put(node); | ||
191 | if (rc) { | ||
192 | dev_err(dev, "Couldn't address to resource for flash\n"); | ||
193 | return rc; | ||
194 | } | ||
195 | |||
196 | lpc_ctrl->pnor_size = resource_size(&resm); | ||
197 | lpc_ctrl->pnor_base = resm.start; | ||
198 | |||
199 | dev_set_drvdata(&pdev->dev, lpc_ctrl); | ||
200 | |||
201 | node = of_parse_phandle(dev->of_node, "memory-region", 0); | ||
202 | if (!node) { | ||
203 | dev_err(dev, "Didn't find reserved memory\n"); | ||
204 | return -EINVAL; | ||
205 | } | ||
206 | |||
207 | rc = of_address_to_resource(node, 0, &resm); | ||
208 | of_node_put(node); | ||
209 | if (rc) { | ||
210 | dev_err(dev, "Couldn't address to resource for reserved memory\n"); | ||
211 | return -ENOMEM; | ||
212 | } | ||
213 | |||
214 | lpc_ctrl->mem_size = resource_size(&resm); | ||
215 | lpc_ctrl->mem_base = resm.start; | ||
216 | |||
217 | lpc_ctrl->regmap = syscon_node_to_regmap( | ||
218 | pdev->dev.parent->of_node); | ||
219 | if (IS_ERR(lpc_ctrl->regmap)) { | ||
220 | dev_err(dev, "Couldn't get regmap\n"); | ||
221 | return -ENODEV; | ||
222 | } | ||
223 | |||
224 | lpc_ctrl->miscdev.minor = MISC_DYNAMIC_MINOR; | ||
225 | lpc_ctrl->miscdev.name = DEVICE_NAME; | ||
226 | lpc_ctrl->miscdev.fops = &aspeed_lpc_ctrl_fops; | ||
227 | lpc_ctrl->miscdev.parent = dev; | ||
228 | rc = misc_register(&lpc_ctrl->miscdev); | ||
229 | if (rc) | ||
230 | dev_err(dev, "Unable to register device\n"); | ||
231 | else | ||
232 | dev_info(dev, "Loaded at 0x%08x (0x%08x)\n", | ||
233 | lpc_ctrl->mem_base, lpc_ctrl->mem_size); | ||
234 | |||
235 | return rc; | ||
236 | } | ||
237 | |||
238 | static int aspeed_lpc_ctrl_remove(struct platform_device *pdev) | ||
239 | { | ||
240 | struct aspeed_lpc_ctrl *lpc_ctrl = dev_get_drvdata(&pdev->dev); | ||
241 | |||
242 | misc_deregister(&lpc_ctrl->miscdev); | ||
243 | |||
244 | return 0; | ||
245 | } | ||
246 | |||
247 | static const struct of_device_id aspeed_lpc_ctrl_match[] = { | ||
248 | { .compatible = "aspeed,ast2400-lpc-ctrl" }, | ||
249 | { .compatible = "aspeed,ast2500-lpc-ctrl" }, | ||
250 | { }, | ||
251 | }; | ||
252 | |||
253 | static struct platform_driver aspeed_lpc_ctrl_driver = { | ||
254 | .driver = { | ||
255 | .name = DEVICE_NAME, | ||
256 | .of_match_table = aspeed_lpc_ctrl_match, | ||
257 | }, | ||
258 | .probe = aspeed_lpc_ctrl_probe, | ||
259 | .remove = aspeed_lpc_ctrl_remove, | ||
260 | }; | ||
261 | |||
262 | module_platform_driver(aspeed_lpc_ctrl_driver); | ||
263 | |||
264 | MODULE_DEVICE_TABLE(of, aspeed_lpc_ctrl_match); | ||
265 | MODULE_LICENSE("GPL"); | ||
266 | MODULE_AUTHOR("Cyril Bur <cyrilbur@gmail.com>"); | ||
267 | MODULE_DESCRIPTION("Control for aspeed 2400/2500 LPC HOST to BMC mappings"); | ||
diff --git a/drivers/misc/panel.c b/drivers/misc/panel.c index ef2ece0f26af..e0c014c2356f 100644 --- a/drivers/misc/panel.c +++ b/drivers/misc/panel.c | |||
@@ -1,6 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * Front panel driver for Linux | 2 | * Front panel driver for Linux |
3 | * Copyright (C) 2000-2008, Willy Tarreau <w@1wt.eu> | 3 | * Copyright (C) 2000-2008, Willy Tarreau <w@1wt.eu> |
4 | * Copyright (C) 2016-2017 Glider bvba | ||
4 | * | 5 | * |
5 | * This program is free software; you can redistribute it and/or | 6 | * This program is free software; you can redistribute it and/or |
6 | * modify it under the terms of the GNU General Public License | 7 | * modify it under the terms of the GNU General Public License |
@@ -54,15 +55,12 @@ | |||
54 | #include <linux/ctype.h> | 55 | #include <linux/ctype.h> |
55 | #include <linux/parport.h> | 56 | #include <linux/parport.h> |
56 | #include <linux/list.h> | 57 | #include <linux/list.h> |
57 | #include <linux/notifier.h> | ||
58 | #include <linux/reboot.h> | ||
59 | #include <linux/workqueue.h> | ||
60 | #include <generated/utsrelease.h> | ||
61 | 58 | ||
62 | #include <linux/io.h> | 59 | #include <linux/io.h> |
63 | #include <linux/uaccess.h> | 60 | #include <linux/uaccess.h> |
64 | 61 | ||
65 | #define LCD_MINOR 156 | 62 | #include <misc/charlcd.h> |
63 | |||
66 | #define KEYPAD_MINOR 185 | 64 | #define KEYPAD_MINOR 185 |
67 | 65 | ||
68 | #define LCD_MAXBYTES 256 /* max burst write */ | 66 | #define LCD_MAXBYTES 256 /* max burst write */ |
@@ -76,9 +74,6 @@ | |||
76 | /* a key repeats this times INPUT_POLL_TIME */ | 74 | /* a key repeats this times INPUT_POLL_TIME */ |
77 | #define KEYPAD_REP_DELAY (2) | 75 | #define KEYPAD_REP_DELAY (2) |
78 | 76 | ||
79 | /* keep the light on this many seconds for each flash */ | ||
80 | #define FLASH_LIGHT_TEMPO (4) | ||
81 | |||
82 | /* converts an r_str() input to an active high, bits string : 000BAOSE */ | 77 | /* converts an r_str() input to an active high, bits string : 000BAOSE */ |
83 | #define PNL_PINPUT(a) ((((unsigned char)(a)) ^ 0x7F) >> 3) | 78 | #define PNL_PINPUT(a) ((((unsigned char)(a)) ^ 0x7F) >> 3) |
84 | 79 | ||
@@ -120,40 +115,6 @@ | |||
120 | #define PIN_SELECP 17 | 115 | #define PIN_SELECP 17 |
121 | #define PIN_NOT_SET 127 | 116 | #define PIN_NOT_SET 127 |
122 | 117 | ||
123 | #define LCD_FLAG_B 0x0004 /* blink on */ | ||
124 | #define LCD_FLAG_C 0x0008 /* cursor on */ | ||
125 | #define LCD_FLAG_D 0x0010 /* display on */ | ||
126 | #define LCD_FLAG_F 0x0020 /* large font mode */ | ||
127 | #define LCD_FLAG_N 0x0040 /* 2-rows mode */ | ||
128 | #define LCD_FLAG_L 0x0080 /* backlight enabled */ | ||
129 | |||
130 | /* LCD commands */ | ||
131 | #define LCD_CMD_DISPLAY_CLEAR 0x01 /* Clear entire display */ | ||
132 | |||
133 | #define LCD_CMD_ENTRY_MODE 0x04 /* Set entry mode */ | ||
134 | #define LCD_CMD_CURSOR_INC 0x02 /* Increment cursor */ | ||
135 | |||
136 | #define LCD_CMD_DISPLAY_CTRL 0x08 /* Display control */ | ||
137 | #define LCD_CMD_DISPLAY_ON 0x04 /* Set display on */ | ||
138 | #define LCD_CMD_CURSOR_ON 0x02 /* Set cursor on */ | ||
139 | #define LCD_CMD_BLINK_ON 0x01 /* Set blink on */ | ||
140 | |||
141 | #define LCD_CMD_SHIFT 0x10 /* Shift cursor/display */ | ||
142 | #define LCD_CMD_DISPLAY_SHIFT 0x08 /* Shift display instead of cursor */ | ||
143 | #define LCD_CMD_SHIFT_RIGHT 0x04 /* Shift display/cursor to the right */ | ||
144 | |||
145 | #define LCD_CMD_FUNCTION_SET 0x20 /* Set function */ | ||
146 | #define LCD_CMD_DATA_LEN_8BITS 0x10 /* Set data length to 8 bits */ | ||
147 | #define LCD_CMD_TWO_LINES 0x08 /* Set to two display lines */ | ||
148 | #define LCD_CMD_FONT_5X10_DOTS 0x04 /* Set char font to 5x10 dots */ | ||
149 | |||
150 | #define LCD_CMD_SET_CGRAM_ADDR 0x40 /* Set char generator RAM address */ | ||
151 | |||
152 | #define LCD_CMD_SET_DDRAM_ADDR 0x80 /* Set display data RAM address */ | ||
153 | |||
154 | #define LCD_ESCAPE_LEN 24 /* max chars for LCD escape command */ | ||
155 | #define LCD_ESCAPE_CHAR 27 /* use char 27 for escape command */ | ||
156 | |||
157 | #define NOT_SET -1 | 118 | #define NOT_SET -1 |
158 | 119 | ||
159 | /* macros to simplify use of the parallel port */ | 120 | /* macros to simplify use of the parallel port */ |
@@ -245,19 +206,10 @@ static wait_queue_head_t keypad_read_wait; | |||
245 | static struct { | 206 | static struct { |
246 | bool enabled; | 207 | bool enabled; |
247 | bool initialized; | 208 | bool initialized; |
248 | bool must_clear; | ||
249 | 209 | ||
250 | int height; | ||
251 | int width; | ||
252 | int bwidth; | ||
253 | int hwidth; | ||
254 | int charset; | 210 | int charset; |
255 | int proto; | 211 | int proto; |
256 | 212 | ||
257 | struct delayed_work bl_work; | ||
258 | struct mutex bl_tempo_lock; /* Protects access to bl_tempo */ | ||
259 | bool bl_tempo; | ||
260 | |||
261 | /* TODO: use union here? */ | 213 | /* TODO: use union here? */ |
262 | struct { | 214 | struct { |
263 | int e; | 215 | int e; |
@@ -268,20 +220,7 @@ static struct { | |||
268 | int bl; | 220 | int bl; |
269 | } pins; | 221 | } pins; |
270 | 222 | ||
271 | /* contains the LCD config state */ | 223 | struct charlcd *charlcd; |
272 | unsigned long int flags; | ||
273 | |||
274 | /* Contains the LCD X and Y offset */ | ||
275 | struct { | ||
276 | unsigned long int x; | ||
277 | unsigned long int y; | ||
278 | } addr; | ||
279 | |||
280 | /* Current escape sequence and it's length or -1 if outside */ | ||
281 | struct { | ||
282 | char buf[LCD_ESCAPE_LEN + 1]; | ||
283 | int len; | ||
284 | } esc_seq; | ||
285 | } lcd; | 224 | } lcd; |
286 | 225 | ||
287 | /* Needed only for init */ | 226 | /* Needed only for init */ |
@@ -464,17 +403,12 @@ static unsigned char lcd_bits[LCD_PORTS][LCD_BITS][BIT_STATES]; | |||
464 | /* global variables */ | 403 | /* global variables */ |
465 | 404 | ||
466 | /* Device single-open policy control */ | 405 | /* Device single-open policy control */ |
467 | static atomic_t lcd_available = ATOMIC_INIT(1); | ||
468 | static atomic_t keypad_available = ATOMIC_INIT(1); | 406 | static atomic_t keypad_available = ATOMIC_INIT(1); |
469 | 407 | ||
470 | static struct pardevice *pprt; | 408 | static struct pardevice *pprt; |
471 | 409 | ||
472 | static int keypad_initialized; | 410 | static int keypad_initialized; |
473 | 411 | ||
474 | static void (*lcd_write_cmd)(int); | ||
475 | static void (*lcd_write_data)(int); | ||
476 | static void (*lcd_clear_fast)(void); | ||
477 | |||
478 | static DEFINE_SPINLOCK(pprt_lock); | 412 | static DEFINE_SPINLOCK(pprt_lock); |
479 | static struct timer_list scan_timer; | 413 | static struct timer_list scan_timer; |
480 | 414 | ||
@@ -574,8 +508,6 @@ static int keypad_enabled = NOT_SET; | |||
574 | module_param(keypad_enabled, int, 0000); | 508 | module_param(keypad_enabled, int, 0000); |
575 | MODULE_PARM_DESC(keypad_enabled, "Deprecated option, use keypad_type instead"); | 509 | MODULE_PARM_DESC(keypad_enabled, "Deprecated option, use keypad_type instead"); |
576 | 510 | ||
577 | static const unsigned char *lcd_char_conv; | ||
578 | |||
579 | /* for some LCD drivers (ks0074) we need a charset conversion table. */ | 511 | /* for some LCD drivers (ks0074) we need a charset conversion table. */ |
580 | static const unsigned char lcd_char_conv_ks0074[256] = { | 512 | static const unsigned char lcd_char_conv_ks0074[256] = { |
581 | /* 0|8 1|9 2|A 3|B 4|C 5|D 6|E 7|F */ | 513 | /* 0|8 1|9 2|A 3|B 4|C 5|D 6|E 7|F */ |
@@ -752,15 +684,6 @@ static void pin_to_bits(int pin, unsigned char *d_val, unsigned char *c_val) | |||
752 | } | 684 | } |
753 | } | 685 | } |
754 | 686 | ||
755 | /* sleeps that many milliseconds with a reschedule */ | ||
756 | static void long_sleep(int ms) | ||
757 | { | ||
758 | if (in_interrupt()) | ||
759 | mdelay(ms); | ||
760 | else | ||
761 | schedule_timeout_interruptible(msecs_to_jiffies(ms)); | ||
762 | } | ||
763 | |||
764 | /* | 687 | /* |
765 | * send a serial byte to the LCD panel. The caller is responsible for locking | 688 | * send a serial byte to the LCD panel. The caller is responsible for locking |
766 | * if needed. | 689 | * if needed. |
@@ -792,8 +715,11 @@ static void lcd_send_serial(int byte) | |||
792 | } | 715 | } |
793 | 716 | ||
794 | /* turn the backlight on or off */ | 717 | /* turn the backlight on or off */ |
795 | static void __lcd_backlight(int on) | 718 | static void lcd_backlight(struct charlcd *charlcd, int on) |
796 | { | 719 | { |
720 | if (lcd.pins.bl == PIN_NONE) | ||
721 | return; | ||
722 | |||
797 | /* The backlight is activated by setting the AUTOFEED line to +5V */ | 723 | /* The backlight is activated by setting the AUTOFEED line to +5V */ |
798 | spin_lock_irq(&pprt_lock); | 724 | spin_lock_irq(&pprt_lock); |
799 | if (on) | 725 | if (on) |
@@ -804,46 +730,8 @@ static void __lcd_backlight(int on) | |||
804 | spin_unlock_irq(&pprt_lock); | 730 | spin_unlock_irq(&pprt_lock); |
805 | } | 731 | } |
806 | 732 | ||
807 | static void lcd_backlight(int on) | ||
808 | { | ||
809 | if (lcd.pins.bl == PIN_NONE) | ||
810 | return; | ||
811 | |||
812 | mutex_lock(&lcd.bl_tempo_lock); | ||
813 | if (!lcd.bl_tempo) | ||
814 | __lcd_backlight(on); | ||
815 | mutex_unlock(&lcd.bl_tempo_lock); | ||
816 | } | ||
817 | |||
818 | static void lcd_bl_off(struct work_struct *work) | ||
819 | { | ||
820 | mutex_lock(&lcd.bl_tempo_lock); | ||
821 | if (lcd.bl_tempo) { | ||
822 | lcd.bl_tempo = false; | ||
823 | if (!(lcd.flags & LCD_FLAG_L)) | ||
824 | __lcd_backlight(0); | ||
825 | } | ||
826 | mutex_unlock(&lcd.bl_tempo_lock); | ||
827 | } | ||
828 | |||
829 | /* turn the backlight on for a little while */ | ||
830 | static void lcd_poke(void) | ||
831 | { | ||
832 | if (lcd.pins.bl == PIN_NONE) | ||
833 | return; | ||
834 | |||
835 | cancel_delayed_work_sync(&lcd.bl_work); | ||
836 | |||
837 | mutex_lock(&lcd.bl_tempo_lock); | ||
838 | if (!lcd.bl_tempo && !(lcd.flags & LCD_FLAG_L)) | ||
839 | __lcd_backlight(1); | ||
840 | lcd.bl_tempo = true; | ||
841 | schedule_delayed_work(&lcd.bl_work, FLASH_LIGHT_TEMPO * HZ); | ||
842 | mutex_unlock(&lcd.bl_tempo_lock); | ||
843 | } | ||
844 | |||
845 | /* send a command to the LCD panel in serial mode */ | 733 | /* send a command to the LCD panel in serial mode */ |
846 | static void lcd_write_cmd_s(int cmd) | 734 | static void lcd_write_cmd_s(struct charlcd *charlcd, int cmd) |
847 | { | 735 | { |
848 | spin_lock_irq(&pprt_lock); | 736 | spin_lock_irq(&pprt_lock); |
849 | lcd_send_serial(0x1F); /* R/W=W, RS=0 */ | 737 | lcd_send_serial(0x1F); /* R/W=W, RS=0 */ |
@@ -854,7 +742,7 @@ static void lcd_write_cmd_s(int cmd) | |||
854 | } | 742 | } |
855 | 743 | ||
856 | /* send data to the LCD panel in serial mode */ | 744 | /* send data to the LCD panel in serial mode */ |
857 | static void lcd_write_data_s(int data) | 745 | static void lcd_write_data_s(struct charlcd *charlcd, int data) |
858 | { | 746 | { |
859 | spin_lock_irq(&pprt_lock); | 747 | spin_lock_irq(&pprt_lock); |
860 | lcd_send_serial(0x5F); /* R/W=W, RS=1 */ | 748 | lcd_send_serial(0x5F); /* R/W=W, RS=1 */ |
@@ -865,7 +753,7 @@ static void lcd_write_data_s(int data) | |||
865 | } | 753 | } |
866 | 754 | ||
867 | /* send a command to the LCD panel in 8 bits parallel mode */ | 755 | /* send a command to the LCD panel in 8 bits parallel mode */ |
868 | static void lcd_write_cmd_p8(int cmd) | 756 | static void lcd_write_cmd_p8(struct charlcd *charlcd, int cmd) |
869 | { | 757 | { |
870 | spin_lock_irq(&pprt_lock); | 758 | spin_lock_irq(&pprt_lock); |
871 | /* present the data to the data port */ | 759 | /* present the data to the data port */ |
@@ -887,7 +775,7 @@ static void lcd_write_cmd_p8(int cmd) | |||
887 | } | 775 | } |
888 | 776 | ||
889 | /* send data to the LCD panel in 8 bits parallel mode */ | 777 | /* send data to the LCD panel in 8 bits parallel mode */ |
890 | static void lcd_write_data_p8(int data) | 778 | static void lcd_write_data_p8(struct charlcd *charlcd, int data) |
891 | { | 779 | { |
892 | spin_lock_irq(&pprt_lock); | 780 | spin_lock_irq(&pprt_lock); |
893 | /* present the data to the data port */ | 781 | /* present the data to the data port */ |
@@ -909,7 +797,7 @@ static void lcd_write_data_p8(int data) | |||
909 | } | 797 | } |
910 | 798 | ||
911 | /* send a command to the TI LCD panel */ | 799 | /* send a command to the TI LCD panel */ |
912 | static void lcd_write_cmd_tilcd(int cmd) | 800 | static void lcd_write_cmd_tilcd(struct charlcd *charlcd, int cmd) |
913 | { | 801 | { |
914 | spin_lock_irq(&pprt_lock); | 802 | spin_lock_irq(&pprt_lock); |
915 | /* present the data to the control port */ | 803 | /* present the data to the control port */ |
@@ -919,7 +807,7 @@ static void lcd_write_cmd_tilcd(int cmd) | |||
919 | } | 807 | } |
920 | 808 | ||
921 | /* send data to the TI LCD panel */ | 809 | /* send data to the TI LCD panel */ |
922 | static void lcd_write_data_tilcd(int data) | 810 | static void lcd_write_data_tilcd(struct charlcd *charlcd, int data) |
923 | { | 811 | { |
924 | spin_lock_irq(&pprt_lock); | 812 | spin_lock_irq(&pprt_lock); |
925 | /* present the data to the data port */ | 813 | /* present the data to the data port */ |
@@ -928,47 +816,13 @@ static void lcd_write_data_tilcd(int data) | |||
928 | spin_unlock_irq(&pprt_lock); | 816 | spin_unlock_irq(&pprt_lock); |
929 | } | 817 | } |
930 | 818 | ||
931 | static void lcd_gotoxy(void) | ||
932 | { | ||
933 | lcd_write_cmd(LCD_CMD_SET_DDRAM_ADDR | ||
934 | | (lcd.addr.y ? lcd.hwidth : 0) | ||
935 | /* | ||
936 | * we force the cursor to stay at the end of the | ||
937 | * line if it wants to go farther | ||
938 | */ | ||
939 | | ((lcd.addr.x < lcd.bwidth) ? lcd.addr.x & | ||
940 | (lcd.hwidth - 1) : lcd.bwidth - 1)); | ||
941 | } | ||
942 | |||
943 | static void lcd_home(void) | ||
944 | { | ||
945 | lcd.addr.x = 0; | ||
946 | lcd.addr.y = 0; | ||
947 | lcd_gotoxy(); | ||
948 | } | ||
949 | |||
950 | static void lcd_print(char c) | ||
951 | { | ||
952 | if (lcd.addr.x < lcd.bwidth) { | ||
953 | if (lcd_char_conv) | ||
954 | c = lcd_char_conv[(unsigned char)c]; | ||
955 | lcd_write_data(c); | ||
956 | lcd.addr.x++; | ||
957 | } | ||
958 | /* prevents the cursor from wrapping onto the next line */ | ||
959 | if (lcd.addr.x == lcd.bwidth) | ||
960 | lcd_gotoxy(); | ||
961 | } | ||
962 | |||
963 | /* fills the display with spaces and resets X/Y */ | 819 | /* fills the display with spaces and resets X/Y */ |
964 | static void lcd_clear_fast_s(void) | 820 | static void lcd_clear_fast_s(struct charlcd *charlcd) |
965 | { | 821 | { |
966 | int pos; | 822 | int pos; |
967 | 823 | ||
968 | lcd_home(); | ||
969 | |||
970 | spin_lock_irq(&pprt_lock); | 824 | spin_lock_irq(&pprt_lock); |
971 | for (pos = 0; pos < lcd.height * lcd.hwidth; pos++) { | 825 | for (pos = 0; pos < charlcd->height * charlcd->hwidth; pos++) { |
972 | lcd_send_serial(0x5F); /* R/W=W, RS=1 */ | 826 | lcd_send_serial(0x5F); /* R/W=W, RS=1 */ |
973 | lcd_send_serial(' ' & 0x0F); | 827 | lcd_send_serial(' ' & 0x0F); |
974 | lcd_send_serial((' ' >> 4) & 0x0F); | 828 | lcd_send_serial((' ' >> 4) & 0x0F); |
@@ -976,19 +830,15 @@ static void lcd_clear_fast_s(void) | |||
976 | udelay(40); | 830 | udelay(40); |
977 | } | 831 | } |
978 | spin_unlock_irq(&pprt_lock); | 832 | spin_unlock_irq(&pprt_lock); |
979 | |||
980 | lcd_home(); | ||
981 | } | 833 | } |
982 | 834 | ||
983 | /* fills the display with spaces and resets X/Y */ | 835 | /* fills the display with spaces and resets X/Y */ |
984 | static void lcd_clear_fast_p8(void) | 836 | static void lcd_clear_fast_p8(struct charlcd *charlcd) |
985 | { | 837 | { |
986 | int pos; | 838 | int pos; |
987 | 839 | ||
988 | lcd_home(); | ||
989 | |||
990 | spin_lock_irq(&pprt_lock); | 840 | spin_lock_irq(&pprt_lock); |
991 | for (pos = 0; pos < lcd.height * lcd.hwidth; pos++) { | 841 | for (pos = 0; pos < charlcd->height * charlcd->hwidth; pos++) { |
992 | /* present the data to the data port */ | 842 | /* present the data to the data port */ |
993 | w_dtr(pprt, ' '); | 843 | w_dtr(pprt, ' '); |
994 | 844 | ||
@@ -1010,488 +860,62 @@ static void lcd_clear_fast_p8(void) | |||
1010 | udelay(45); | 860 | udelay(45); |
1011 | } | 861 | } |
1012 | spin_unlock_irq(&pprt_lock); | 862 | spin_unlock_irq(&pprt_lock); |
1013 | |||
1014 | lcd_home(); | ||
1015 | } | 863 | } |
1016 | 864 | ||
1017 | /* fills the display with spaces and resets X/Y */ | 865 | /* fills the display with spaces and resets X/Y */ |
1018 | static void lcd_clear_fast_tilcd(void) | 866 | static void lcd_clear_fast_tilcd(struct charlcd *charlcd) |
1019 | { | 867 | { |
1020 | int pos; | 868 | int pos; |
1021 | 869 | ||
1022 | lcd_home(); | ||
1023 | |||
1024 | spin_lock_irq(&pprt_lock); | 870 | spin_lock_irq(&pprt_lock); |
1025 | for (pos = 0; pos < lcd.height * lcd.hwidth; pos++) { | 871 | for (pos = 0; pos < charlcd->height * charlcd->hwidth; pos++) { |
1026 | /* present the data to the data port */ | 872 | /* present the data to the data port */ |
1027 | w_dtr(pprt, ' '); | 873 | w_dtr(pprt, ' '); |
1028 | udelay(60); | 874 | udelay(60); |
1029 | } | 875 | } |
1030 | 876 | ||
1031 | spin_unlock_irq(&pprt_lock); | 877 | spin_unlock_irq(&pprt_lock); |
1032 | |||
1033 | lcd_home(); | ||
1034 | } | ||
1035 | |||
1036 | /* clears the display and resets X/Y */ | ||
1037 | static void lcd_clear_display(void) | ||
1038 | { | ||
1039 | lcd_write_cmd(LCD_CMD_DISPLAY_CLEAR); | ||
1040 | lcd.addr.x = 0; | ||
1041 | lcd.addr.y = 0; | ||
1042 | /* we must wait a few milliseconds (15) */ | ||
1043 | long_sleep(15); | ||
1044 | } | 878 | } |
1045 | 879 | ||
1046 | static void lcd_init_display(void) | 880 | static struct charlcd_ops charlcd_serial_ops = { |
1047 | { | 881 | .write_cmd = lcd_write_cmd_s, |
1048 | lcd.flags = ((lcd.height > 1) ? LCD_FLAG_N : 0) | 882 | .write_data = lcd_write_data_s, |
1049 | | LCD_FLAG_D | LCD_FLAG_C | LCD_FLAG_B; | 883 | .clear_fast = lcd_clear_fast_s, |
1050 | 884 | .backlight = lcd_backlight, | |
1051 | long_sleep(20); /* wait 20 ms after power-up for the paranoid */ | 885 | }; |
1052 | |||
1053 | /* 8bits, 1 line, small fonts; let's do it 3 times */ | ||
1054 | lcd_write_cmd(LCD_CMD_FUNCTION_SET | LCD_CMD_DATA_LEN_8BITS); | ||
1055 | long_sleep(10); | ||
1056 | lcd_write_cmd(LCD_CMD_FUNCTION_SET | LCD_CMD_DATA_LEN_8BITS); | ||
1057 | long_sleep(10); | ||
1058 | lcd_write_cmd(LCD_CMD_FUNCTION_SET | LCD_CMD_DATA_LEN_8BITS); | ||
1059 | long_sleep(10); | ||
1060 | |||
1061 | /* set font height and lines number */ | ||
1062 | lcd_write_cmd(LCD_CMD_FUNCTION_SET | LCD_CMD_DATA_LEN_8BITS | ||
1063 | | ((lcd.flags & LCD_FLAG_F) ? LCD_CMD_FONT_5X10_DOTS : 0) | ||
1064 | | ((lcd.flags & LCD_FLAG_N) ? LCD_CMD_TWO_LINES : 0) | ||
1065 | ); | ||
1066 | long_sleep(10); | ||
1067 | |||
1068 | /* display off, cursor off, blink off */ | ||
1069 | lcd_write_cmd(LCD_CMD_DISPLAY_CTRL); | ||
1070 | long_sleep(10); | ||
1071 | |||
1072 | lcd_write_cmd(LCD_CMD_DISPLAY_CTRL /* set display mode */ | ||
1073 | | ((lcd.flags & LCD_FLAG_D) ? LCD_CMD_DISPLAY_ON : 0) | ||
1074 | | ((lcd.flags & LCD_FLAG_C) ? LCD_CMD_CURSOR_ON : 0) | ||
1075 | | ((lcd.flags & LCD_FLAG_B) ? LCD_CMD_BLINK_ON : 0) | ||
1076 | ); | ||
1077 | |||
1078 | lcd_backlight((lcd.flags & LCD_FLAG_L) ? 1 : 0); | ||
1079 | |||
1080 | long_sleep(10); | ||
1081 | |||
1082 | /* entry mode set : increment, cursor shifting */ | ||
1083 | lcd_write_cmd(LCD_CMD_ENTRY_MODE | LCD_CMD_CURSOR_INC); | ||
1084 | 886 | ||
1085 | lcd_clear_display(); | 887 | static struct charlcd_ops charlcd_parallel_ops = { |
1086 | } | 888 | .write_cmd = lcd_write_cmd_p8, |
889 | .write_data = lcd_write_data_p8, | ||
890 | .clear_fast = lcd_clear_fast_p8, | ||
891 | .backlight = lcd_backlight, | ||
892 | }; | ||
1087 | 893 | ||
1088 | /* | 894 | static struct charlcd_ops charlcd_tilcd_ops = { |
1089 | * These are the file operation function for user access to /dev/lcd | 895 | .write_cmd = lcd_write_cmd_tilcd, |
1090 | * This function can also be called from inside the kernel, by | 896 | .write_data = lcd_write_data_tilcd, |
1091 | * setting file and ppos to NULL. | 897 | .clear_fast = lcd_clear_fast_tilcd, |
1092 | * | 898 | .backlight = lcd_backlight, |
1093 | */ | 899 | }; |
1094 | 900 | ||
1095 | static inline int handle_lcd_special_code(void) | 901 | /* initialize the LCD driver */ |
902 | static void lcd_init(void) | ||
1096 | { | 903 | { |
1097 | /* LCD special codes */ | 904 | struct charlcd *charlcd; |
1098 | |||
1099 | int processed = 0; | ||
1100 | 905 | ||
1101 | char *esc = lcd.esc_seq.buf + 2; | 906 | charlcd = charlcd_alloc(0); |
1102 | int oldflags = lcd.flags; | 907 | if (!charlcd) |
1103 | 908 | return; | |
1104 | /* check for display mode flags */ | ||
1105 | switch (*esc) { | ||
1106 | case 'D': /* Display ON */ | ||
1107 | lcd.flags |= LCD_FLAG_D; | ||
1108 | processed = 1; | ||
1109 | break; | ||
1110 | case 'd': /* Display OFF */ | ||
1111 | lcd.flags &= ~LCD_FLAG_D; | ||
1112 | processed = 1; | ||
1113 | break; | ||
1114 | case 'C': /* Cursor ON */ | ||
1115 | lcd.flags |= LCD_FLAG_C; | ||
1116 | processed = 1; | ||
1117 | break; | ||
1118 | case 'c': /* Cursor OFF */ | ||
1119 | lcd.flags &= ~LCD_FLAG_C; | ||
1120 | processed = 1; | ||
1121 | break; | ||
1122 | case 'B': /* Blink ON */ | ||
1123 | lcd.flags |= LCD_FLAG_B; | ||
1124 | processed = 1; | ||
1125 | break; | ||
1126 | case 'b': /* Blink OFF */ | ||
1127 | lcd.flags &= ~LCD_FLAG_B; | ||
1128 | processed = 1; | ||
1129 | break; | ||
1130 | case '+': /* Back light ON */ | ||
1131 | lcd.flags |= LCD_FLAG_L; | ||
1132 | processed = 1; | ||
1133 | break; | ||
1134 | case '-': /* Back light OFF */ | ||
1135 | lcd.flags &= ~LCD_FLAG_L; | ||
1136 | processed = 1; | ||
1137 | break; | ||
1138 | case '*': | ||
1139 | /* flash back light */ | ||
1140 | lcd_poke(); | ||
1141 | processed = 1; | ||
1142 | break; | ||
1143 | case 'f': /* Small Font */ | ||
1144 | lcd.flags &= ~LCD_FLAG_F; | ||
1145 | processed = 1; | ||
1146 | break; | ||
1147 | case 'F': /* Large Font */ | ||
1148 | lcd.flags |= LCD_FLAG_F; | ||
1149 | processed = 1; | ||
1150 | break; | ||
1151 | case 'n': /* One Line */ | ||
1152 | lcd.flags &= ~LCD_FLAG_N; | ||
1153 | processed = 1; | ||
1154 | break; | ||
1155 | case 'N': /* Two Lines */ | ||
1156 | lcd.flags |= LCD_FLAG_N; | ||
1157 | break; | ||
1158 | case 'l': /* Shift Cursor Left */ | ||
1159 | if (lcd.addr.x > 0) { | ||
1160 | /* back one char if not at end of line */ | ||
1161 | if (lcd.addr.x < lcd.bwidth) | ||
1162 | lcd_write_cmd(LCD_CMD_SHIFT); | ||
1163 | lcd.addr.x--; | ||
1164 | } | ||
1165 | processed = 1; | ||
1166 | break; | ||
1167 | case 'r': /* shift cursor right */ | ||
1168 | if (lcd.addr.x < lcd.width) { | ||
1169 | /* allow the cursor to pass the end of the line */ | ||
1170 | if (lcd.addr.x < (lcd.bwidth - 1)) | ||
1171 | lcd_write_cmd(LCD_CMD_SHIFT | | ||
1172 | LCD_CMD_SHIFT_RIGHT); | ||
1173 | lcd.addr.x++; | ||
1174 | } | ||
1175 | processed = 1; | ||
1176 | break; | ||
1177 | case 'L': /* shift display left */ | ||
1178 | lcd_write_cmd(LCD_CMD_SHIFT | LCD_CMD_DISPLAY_SHIFT); | ||
1179 | processed = 1; | ||
1180 | break; | ||
1181 | case 'R': /* shift display right */ | ||
1182 | lcd_write_cmd(LCD_CMD_SHIFT | LCD_CMD_DISPLAY_SHIFT | | ||
1183 | LCD_CMD_SHIFT_RIGHT); | ||
1184 | processed = 1; | ||
1185 | break; | ||
1186 | case 'k': { /* kill end of line */ | ||
1187 | int x; | ||
1188 | |||
1189 | for (x = lcd.addr.x; x < lcd.bwidth; x++) | ||
1190 | lcd_write_data(' '); | ||
1191 | |||
1192 | /* restore cursor position */ | ||
1193 | lcd_gotoxy(); | ||
1194 | processed = 1; | ||
1195 | break; | ||
1196 | } | ||
1197 | case 'I': /* reinitialize display */ | ||
1198 | lcd_init_display(); | ||
1199 | processed = 1; | ||
1200 | break; | ||
1201 | case 'G': { | ||
1202 | /* Generator : LGcxxxxx...xx; must have <c> between '0' | ||
1203 | * and '7', representing the numerical ASCII code of the | ||
1204 | * redefined character, and <xx...xx> a sequence of 16 | ||
1205 | * hex digits representing 8 bytes for each character. | ||
1206 | * Most LCDs will only use 5 lower bits of the 7 first | ||
1207 | * bytes. | ||
1208 | */ | ||
1209 | |||
1210 | unsigned char cgbytes[8]; | ||
1211 | unsigned char cgaddr; | ||
1212 | int cgoffset; | ||
1213 | int shift; | ||
1214 | char value; | ||
1215 | int addr; | ||
1216 | |||
1217 | if (!strchr(esc, ';')) | ||
1218 | break; | ||
1219 | |||
1220 | esc++; | ||
1221 | |||
1222 | cgaddr = *(esc++) - '0'; | ||
1223 | if (cgaddr > 7) { | ||
1224 | processed = 1; | ||
1225 | break; | ||
1226 | } | ||
1227 | |||
1228 | cgoffset = 0; | ||
1229 | shift = 0; | ||
1230 | value = 0; | ||
1231 | while (*esc && cgoffset < 8) { | ||
1232 | shift ^= 4; | ||
1233 | if (*esc >= '0' && *esc <= '9') { | ||
1234 | value |= (*esc - '0') << shift; | ||
1235 | } else if (*esc >= 'A' && *esc <= 'Z') { | ||
1236 | value |= (*esc - 'A' + 10) << shift; | ||
1237 | } else if (*esc >= 'a' && *esc <= 'z') { | ||
1238 | value |= (*esc - 'a' + 10) << shift; | ||
1239 | } else { | ||
1240 | esc++; | ||
1241 | continue; | ||
1242 | } | ||
1243 | |||
1244 | if (shift == 0) { | ||
1245 | cgbytes[cgoffset++] = value; | ||
1246 | value = 0; | ||
1247 | } | ||
1248 | |||
1249 | esc++; | ||
1250 | } | ||
1251 | |||
1252 | lcd_write_cmd(LCD_CMD_SET_CGRAM_ADDR | (cgaddr * 8)); | ||
1253 | for (addr = 0; addr < cgoffset; addr++) | ||
1254 | lcd_write_data(cgbytes[addr]); | ||
1255 | |||
1256 | /* ensures that we stop writing to CGRAM */ | ||
1257 | lcd_gotoxy(); | ||
1258 | processed = 1; | ||
1259 | break; | ||
1260 | } | ||
1261 | case 'x': /* gotoxy : LxXXX[yYYY]; */ | ||
1262 | case 'y': /* gotoxy : LyYYY[xXXX]; */ | ||
1263 | if (!strchr(esc, ';')) | ||
1264 | break; | ||
1265 | |||
1266 | while (*esc) { | ||
1267 | if (*esc == 'x') { | ||
1268 | esc++; | ||
1269 | if (kstrtoul(esc, 10, &lcd.addr.x) < 0) | ||
1270 | break; | ||
1271 | } else if (*esc == 'y') { | ||
1272 | esc++; | ||
1273 | if (kstrtoul(esc, 10, &lcd.addr.y) < 0) | ||
1274 | break; | ||
1275 | } else { | ||
1276 | break; | ||
1277 | } | ||
1278 | } | ||
1279 | |||
1280 | lcd_gotoxy(); | ||
1281 | processed = 1; | ||
1282 | break; | ||
1283 | } | ||
1284 | |||
1285 | /* TODO: This indent party here got ugly, clean it! */ | ||
1286 | /* Check whether one flag was changed */ | ||
1287 | if (oldflags != lcd.flags) { | ||
1288 | /* check whether one of B,C,D flags were changed */ | ||
1289 | if ((oldflags ^ lcd.flags) & | ||
1290 | (LCD_FLAG_B | LCD_FLAG_C | LCD_FLAG_D)) | ||
1291 | /* set display mode */ | ||
1292 | lcd_write_cmd(LCD_CMD_DISPLAY_CTRL | ||
1293 | | ((lcd.flags & LCD_FLAG_D) | ||
1294 | ? LCD_CMD_DISPLAY_ON : 0) | ||
1295 | | ((lcd.flags & LCD_FLAG_C) | ||
1296 | ? LCD_CMD_CURSOR_ON : 0) | ||
1297 | | ((lcd.flags & LCD_FLAG_B) | ||
1298 | ? LCD_CMD_BLINK_ON : 0)); | ||
1299 | /* check whether one of F,N flags was changed */ | ||
1300 | else if ((oldflags ^ lcd.flags) & (LCD_FLAG_F | LCD_FLAG_N)) | ||
1301 | lcd_write_cmd(LCD_CMD_FUNCTION_SET | ||
1302 | | LCD_CMD_DATA_LEN_8BITS | ||
1303 | | ((lcd.flags & LCD_FLAG_F) | ||
1304 | ? LCD_CMD_FONT_5X10_DOTS | ||
1305 | : 0) | ||
1306 | | ((lcd.flags & LCD_FLAG_N) | ||
1307 | ? LCD_CMD_TWO_LINES | ||
1308 | : 0)); | ||
1309 | /* check whether L flag was changed */ | ||
1310 | else if ((oldflags ^ lcd.flags) & (LCD_FLAG_L)) | ||
1311 | lcd_backlight(!!(lcd.flags & LCD_FLAG_L)); | ||
1312 | } | ||
1313 | |||
1314 | return processed; | ||
1315 | } | ||
1316 | |||
1317 | static void lcd_write_char(char c) | ||
1318 | { | ||
1319 | /* first, we'll test if we're in escape mode */ | ||
1320 | if ((c != '\n') && lcd.esc_seq.len >= 0) { | ||
1321 | /* yes, let's add this char to the buffer */ | ||
1322 | lcd.esc_seq.buf[lcd.esc_seq.len++] = c; | ||
1323 | lcd.esc_seq.buf[lcd.esc_seq.len] = 0; | ||
1324 | } else { | ||
1325 | /* aborts any previous escape sequence */ | ||
1326 | lcd.esc_seq.len = -1; | ||
1327 | |||
1328 | switch (c) { | ||
1329 | case LCD_ESCAPE_CHAR: | ||
1330 | /* start of an escape sequence */ | ||
1331 | lcd.esc_seq.len = 0; | ||
1332 | lcd.esc_seq.buf[lcd.esc_seq.len] = 0; | ||
1333 | break; | ||
1334 | case '\b': | ||
1335 | /* go back one char and clear it */ | ||
1336 | if (lcd.addr.x > 0) { | ||
1337 | /* | ||
1338 | * check if we're not at the | ||
1339 | * end of the line | ||
1340 | */ | ||
1341 | if (lcd.addr.x < lcd.bwidth) | ||
1342 | /* back one char */ | ||
1343 | lcd_write_cmd(LCD_CMD_SHIFT); | ||
1344 | lcd.addr.x--; | ||
1345 | } | ||
1346 | /* replace with a space */ | ||
1347 | lcd_write_data(' '); | ||
1348 | /* back one char again */ | ||
1349 | lcd_write_cmd(LCD_CMD_SHIFT); | ||
1350 | break; | ||
1351 | case '\014': | ||
1352 | /* quickly clear the display */ | ||
1353 | lcd_clear_fast(); | ||
1354 | break; | ||
1355 | case '\n': | ||
1356 | /* | ||
1357 | * flush the remainder of the current line and | ||
1358 | * go to the beginning of the next line | ||
1359 | */ | ||
1360 | for (; lcd.addr.x < lcd.bwidth; lcd.addr.x++) | ||
1361 | lcd_write_data(' '); | ||
1362 | lcd.addr.x = 0; | ||
1363 | lcd.addr.y = (lcd.addr.y + 1) % lcd.height; | ||
1364 | lcd_gotoxy(); | ||
1365 | break; | ||
1366 | case '\r': | ||
1367 | /* go to the beginning of the same line */ | ||
1368 | lcd.addr.x = 0; | ||
1369 | lcd_gotoxy(); | ||
1370 | break; | ||
1371 | case '\t': | ||
1372 | /* print a space instead of the tab */ | ||
1373 | lcd_print(' '); | ||
1374 | break; | ||
1375 | default: | ||
1376 | /* simply print this char */ | ||
1377 | lcd_print(c); | ||
1378 | break; | ||
1379 | } | ||
1380 | } | ||
1381 | 909 | ||
1382 | /* | 910 | /* |
1383 | * now we'll see if we're in an escape mode and if the current | 911 | * Init lcd struct with load-time values to preserve exact |
1384 | * escape sequence can be understood. | 912 | * current functionality (at least for now). |
1385 | */ | 913 | */ |
1386 | if (lcd.esc_seq.len >= 2) { | 914 | charlcd->height = lcd_height; |
1387 | int processed = 0; | 915 | charlcd->width = lcd_width; |
1388 | 916 | charlcd->bwidth = lcd_bwidth; | |
1389 | if (!strcmp(lcd.esc_seq.buf, "[2J")) { | 917 | charlcd->hwidth = lcd_hwidth; |
1390 | /* clear the display */ | ||
1391 | lcd_clear_fast(); | ||
1392 | processed = 1; | ||
1393 | } else if (!strcmp(lcd.esc_seq.buf, "[H")) { | ||
1394 | /* cursor to home */ | ||
1395 | lcd_home(); | ||
1396 | processed = 1; | ||
1397 | } | ||
1398 | /* codes starting with ^[[L */ | ||
1399 | else if ((lcd.esc_seq.len >= 3) && | ||
1400 | (lcd.esc_seq.buf[0] == '[') && | ||
1401 | (lcd.esc_seq.buf[1] == 'L')) { | ||
1402 | processed = handle_lcd_special_code(); | ||
1403 | } | ||
1404 | |||
1405 | /* LCD special escape codes */ | ||
1406 | /* | ||
1407 | * flush the escape sequence if it's been processed | ||
1408 | * or if it is getting too long. | ||
1409 | */ | ||
1410 | if (processed || (lcd.esc_seq.len >= LCD_ESCAPE_LEN)) | ||
1411 | lcd.esc_seq.len = -1; | ||
1412 | } /* escape codes */ | ||
1413 | } | ||
1414 | 918 | ||
1415 | static ssize_t lcd_write(struct file *file, | ||
1416 | const char __user *buf, size_t count, loff_t *ppos) | ||
1417 | { | ||
1418 | const char __user *tmp = buf; | ||
1419 | char c; | ||
1420 | |||
1421 | for (; count-- > 0; (*ppos)++, tmp++) { | ||
1422 | if (!in_interrupt() && (((count + 1) & 0x1f) == 0)) | ||
1423 | /* | ||
1424 | * let's be a little nice with other processes | ||
1425 | * that need some CPU | ||
1426 | */ | ||
1427 | schedule(); | ||
1428 | |||
1429 | if (get_user(c, tmp)) | ||
1430 | return -EFAULT; | ||
1431 | |||
1432 | lcd_write_char(c); | ||
1433 | } | ||
1434 | |||
1435 | return tmp - buf; | ||
1436 | } | ||
1437 | |||
1438 | static int lcd_open(struct inode *inode, struct file *file) | ||
1439 | { | ||
1440 | if (!atomic_dec_and_test(&lcd_available)) | ||
1441 | return -EBUSY; /* open only once at a time */ | ||
1442 | |||
1443 | if (file->f_mode & FMODE_READ) /* device is write-only */ | ||
1444 | return -EPERM; | ||
1445 | |||
1446 | if (lcd.must_clear) { | ||
1447 | lcd_clear_display(); | ||
1448 | lcd.must_clear = false; | ||
1449 | } | ||
1450 | return nonseekable_open(inode, file); | ||
1451 | } | ||
1452 | |||
1453 | static int lcd_release(struct inode *inode, struct file *file) | ||
1454 | { | ||
1455 | atomic_inc(&lcd_available); | ||
1456 | return 0; | ||
1457 | } | ||
1458 | |||
1459 | static const struct file_operations lcd_fops = { | ||
1460 | .write = lcd_write, | ||
1461 | .open = lcd_open, | ||
1462 | .release = lcd_release, | ||
1463 | .llseek = no_llseek, | ||
1464 | }; | ||
1465 | |||
1466 | static struct miscdevice lcd_dev = { | ||
1467 | .minor = LCD_MINOR, | ||
1468 | .name = "lcd", | ||
1469 | .fops = &lcd_fops, | ||
1470 | }; | ||
1471 | |||
1472 | /* public function usable from the kernel for any purpose */ | ||
1473 | static void panel_lcd_print(const char *s) | ||
1474 | { | ||
1475 | const char *tmp = s; | ||
1476 | int count = strlen(s); | ||
1477 | |||
1478 | if (lcd.enabled && lcd.initialized) { | ||
1479 | for (; count-- > 0; tmp++) { | ||
1480 | if (!in_interrupt() && (((count + 1) & 0x1f) == 0)) | ||
1481 | /* | ||
1482 | * let's be a little nice with other processes | ||
1483 | * that need some CPU | ||
1484 | */ | ||
1485 | schedule(); | ||
1486 | |||
1487 | lcd_write_char(*tmp); | ||
1488 | } | ||
1489 | } | ||
1490 | } | ||
1491 | |||
1492 | /* initialize the LCD driver */ | ||
1493 | static void lcd_init(void) | ||
1494 | { | ||
1495 | switch (selected_lcd_type) { | 919 | switch (selected_lcd_type) { |
1496 | case LCD_TYPE_OLD: | 920 | case LCD_TYPE_OLD: |
1497 | /* parallel mode, 8 bits */ | 921 | /* parallel mode, 8 bits */ |
@@ -1500,10 +924,10 @@ static void lcd_init(void) | |||
1500 | lcd.pins.e = PIN_STROBE; | 924 | lcd.pins.e = PIN_STROBE; |
1501 | lcd.pins.rs = PIN_AUTOLF; | 925 | lcd.pins.rs = PIN_AUTOLF; |
1502 | 926 | ||
1503 | lcd.width = 40; | 927 | charlcd->width = 40; |
1504 | lcd.bwidth = 40; | 928 | charlcd->bwidth = 40; |
1505 | lcd.hwidth = 64; | 929 | charlcd->hwidth = 64; |
1506 | lcd.height = 2; | 930 | charlcd->height = 2; |
1507 | break; | 931 | break; |
1508 | case LCD_TYPE_KS0074: | 932 | case LCD_TYPE_KS0074: |
1509 | /* serial mode, ks0074 */ | 933 | /* serial mode, ks0074 */ |
@@ -1513,10 +937,10 @@ static void lcd_init(void) | |||
1513 | lcd.pins.cl = PIN_STROBE; | 937 | lcd.pins.cl = PIN_STROBE; |
1514 | lcd.pins.da = PIN_D0; | 938 | lcd.pins.da = PIN_D0; |
1515 | 939 | ||
1516 | lcd.width = 16; | 940 | charlcd->width = 16; |
1517 | lcd.bwidth = 40; | 941 | charlcd->bwidth = 40; |
1518 | lcd.hwidth = 16; | 942 | charlcd->hwidth = 16; |
1519 | lcd.height = 2; | 943 | charlcd->height = 2; |
1520 | break; | 944 | break; |
1521 | case LCD_TYPE_NEXCOM: | 945 | case LCD_TYPE_NEXCOM: |
1522 | /* parallel mode, 8 bits, generic */ | 946 | /* parallel mode, 8 bits, generic */ |
@@ -1526,10 +950,10 @@ static void lcd_init(void) | |||
1526 | lcd.pins.rs = PIN_SELECP; | 950 | lcd.pins.rs = PIN_SELECP; |
1527 | lcd.pins.rw = PIN_INITP; | 951 | lcd.pins.rw = PIN_INITP; |
1528 | 952 | ||
1529 | lcd.width = 16; | 953 | charlcd->width = 16; |
1530 | lcd.bwidth = 40; | 954 | charlcd->bwidth = 40; |
1531 | lcd.hwidth = 64; | 955 | charlcd->hwidth = 64; |
1532 | lcd.height = 2; | 956 | charlcd->height = 2; |
1533 | break; | 957 | break; |
1534 | case LCD_TYPE_CUSTOM: | 958 | case LCD_TYPE_CUSTOM: |
1535 | /* customer-defined */ | 959 | /* customer-defined */ |
@@ -1545,22 +969,22 @@ static void lcd_init(void) | |||
1545 | lcd.pins.e = PIN_STROBE; | 969 | lcd.pins.e = PIN_STROBE; |
1546 | lcd.pins.rs = PIN_SELECP; | 970 | lcd.pins.rs = PIN_SELECP; |
1547 | 971 | ||
1548 | lcd.width = 16; | 972 | charlcd->width = 16; |
1549 | lcd.bwidth = 40; | 973 | charlcd->bwidth = 40; |
1550 | lcd.hwidth = 64; | 974 | charlcd->hwidth = 64; |
1551 | lcd.height = 2; | 975 | charlcd->height = 2; |
1552 | break; | 976 | break; |
1553 | } | 977 | } |
1554 | 978 | ||
1555 | /* Overwrite with module params set on loading */ | 979 | /* Overwrite with module params set on loading */ |
1556 | if (lcd_height != NOT_SET) | 980 | if (lcd_height != NOT_SET) |
1557 | lcd.height = lcd_height; | 981 | charlcd->height = lcd_height; |
1558 | if (lcd_width != NOT_SET) | 982 | if (lcd_width != NOT_SET) |
1559 | lcd.width = lcd_width; | 983 | charlcd->width = lcd_width; |
1560 | if (lcd_bwidth != NOT_SET) | 984 | if (lcd_bwidth != NOT_SET) |
1561 | lcd.bwidth = lcd_bwidth; | 985 | charlcd->bwidth = lcd_bwidth; |
1562 | if (lcd_hwidth != NOT_SET) | 986 | if (lcd_hwidth != NOT_SET) |
1563 | lcd.hwidth = lcd_hwidth; | 987 | charlcd->hwidth = lcd_hwidth; |
1564 | if (lcd_charset != NOT_SET) | 988 | if (lcd_charset != NOT_SET) |
1565 | lcd.charset = lcd_charset; | 989 | lcd.charset = lcd_charset; |
1566 | if (lcd_proto != NOT_SET) | 990 | if (lcd_proto != NOT_SET) |
@@ -1579,19 +1003,17 @@ static void lcd_init(void) | |||
1579 | lcd.pins.bl = lcd_bl_pin; | 1003 | lcd.pins.bl = lcd_bl_pin; |
1580 | 1004 | ||
1581 | /* this is used to catch wrong and default values */ | 1005 | /* this is used to catch wrong and default values */ |
1582 | if (lcd.width <= 0) | 1006 | if (charlcd->width <= 0) |
1583 | lcd.width = DEFAULT_LCD_WIDTH; | 1007 | charlcd->width = DEFAULT_LCD_WIDTH; |
1584 | if (lcd.bwidth <= 0) | 1008 | if (charlcd->bwidth <= 0) |
1585 | lcd.bwidth = DEFAULT_LCD_BWIDTH; | 1009 | charlcd->bwidth = DEFAULT_LCD_BWIDTH; |
1586 | if (lcd.hwidth <= 0) | 1010 | if (charlcd->hwidth <= 0) |
1587 | lcd.hwidth = DEFAULT_LCD_HWIDTH; | 1011 | charlcd->hwidth = DEFAULT_LCD_HWIDTH; |
1588 | if (lcd.height <= 0) | 1012 | if (charlcd->height <= 0) |
1589 | lcd.height = DEFAULT_LCD_HEIGHT; | 1013 | charlcd->height = DEFAULT_LCD_HEIGHT; |
1590 | 1014 | ||
1591 | if (lcd.proto == LCD_PROTO_SERIAL) { /* SERIAL */ | 1015 | if (lcd.proto == LCD_PROTO_SERIAL) { /* SERIAL */ |
1592 | lcd_write_cmd = lcd_write_cmd_s; | 1016 | charlcd->ops = &charlcd_serial_ops; |
1593 | lcd_write_data = lcd_write_data_s; | ||
1594 | lcd_clear_fast = lcd_clear_fast_s; | ||
1595 | 1017 | ||
1596 | if (lcd.pins.cl == PIN_NOT_SET) | 1018 | if (lcd.pins.cl == PIN_NOT_SET) |
1597 | lcd.pins.cl = DEFAULT_LCD_PIN_SCL; | 1019 | lcd.pins.cl = DEFAULT_LCD_PIN_SCL; |
@@ -1599,9 +1021,7 @@ static void lcd_init(void) | |||
1599 | lcd.pins.da = DEFAULT_LCD_PIN_SDA; | 1021 | lcd.pins.da = DEFAULT_LCD_PIN_SDA; |
1600 | 1022 | ||
1601 | } else if (lcd.proto == LCD_PROTO_PARALLEL) { /* PARALLEL */ | 1023 | } else if (lcd.proto == LCD_PROTO_PARALLEL) { /* PARALLEL */ |
1602 | lcd_write_cmd = lcd_write_cmd_p8; | 1024 | charlcd->ops = &charlcd_parallel_ops; |
1603 | lcd_write_data = lcd_write_data_p8; | ||
1604 | lcd_clear_fast = lcd_clear_fast_p8; | ||
1605 | 1025 | ||
1606 | if (lcd.pins.e == PIN_NOT_SET) | 1026 | if (lcd.pins.e == PIN_NOT_SET) |
1607 | lcd.pins.e = DEFAULT_LCD_PIN_E; | 1027 | lcd.pins.e = DEFAULT_LCD_PIN_E; |
@@ -1610,9 +1030,7 @@ static void lcd_init(void) | |||
1610 | if (lcd.pins.rw == PIN_NOT_SET) | 1030 | if (lcd.pins.rw == PIN_NOT_SET) |
1611 | lcd.pins.rw = DEFAULT_LCD_PIN_RW; | 1031 | lcd.pins.rw = DEFAULT_LCD_PIN_RW; |
1612 | } else { | 1032 | } else { |
1613 | lcd_write_cmd = lcd_write_cmd_tilcd; | 1033 | charlcd->ops = &charlcd_tilcd_ops; |
1614 | lcd_write_data = lcd_write_data_tilcd; | ||
1615 | lcd_clear_fast = lcd_clear_fast_tilcd; | ||
1616 | } | 1034 | } |
1617 | 1035 | ||
1618 | if (lcd.pins.bl == PIN_NOT_SET) | 1036 | if (lcd.pins.bl == PIN_NOT_SET) |
@@ -1635,14 +1053,9 @@ static void lcd_init(void) | |||
1635 | lcd.charset = DEFAULT_LCD_CHARSET; | 1053 | lcd.charset = DEFAULT_LCD_CHARSET; |
1636 | 1054 | ||
1637 | if (lcd.charset == LCD_CHARSET_KS0074) | 1055 | if (lcd.charset == LCD_CHARSET_KS0074) |
1638 | lcd_char_conv = lcd_char_conv_ks0074; | 1056 | charlcd->char_conv = lcd_char_conv_ks0074; |
1639 | else | 1057 | else |
1640 | lcd_char_conv = NULL; | 1058 | charlcd->char_conv = NULL; |
1641 | |||
1642 | if (lcd.pins.bl != PIN_NONE) { | ||
1643 | mutex_init(&lcd.bl_tempo_lock); | ||
1644 | INIT_DELAYED_WORK(&lcd.bl_work, lcd_bl_off); | ||
1645 | } | ||
1646 | 1059 | ||
1647 | pin_to_bits(lcd.pins.e, lcd_bits[LCD_PORT_D][LCD_BIT_E], | 1060 | pin_to_bits(lcd.pins.e, lcd_bits[LCD_PORT_D][LCD_BIT_E], |
1648 | lcd_bits[LCD_PORT_C][LCD_BIT_E]); | 1061 | lcd_bits[LCD_PORT_C][LCD_BIT_E]); |
@@ -1657,25 +1070,8 @@ static void lcd_init(void) | |||
1657 | pin_to_bits(lcd.pins.da, lcd_bits[LCD_PORT_D][LCD_BIT_DA], | 1070 | pin_to_bits(lcd.pins.da, lcd_bits[LCD_PORT_D][LCD_BIT_DA], |
1658 | lcd_bits[LCD_PORT_C][LCD_BIT_DA]); | 1071 | lcd_bits[LCD_PORT_C][LCD_BIT_DA]); |
1659 | 1072 | ||
1660 | /* | 1073 | lcd.charlcd = charlcd; |
1661 | * before this line, we must NOT send anything to the display. | ||
1662 | * Since lcd_init_display() needs to write data, we have to | ||
1663 | * enable mark the LCD initialized just before. | ||
1664 | */ | ||
1665 | lcd.initialized = true; | 1074 | lcd.initialized = true; |
1666 | lcd_init_display(); | ||
1667 | |||
1668 | /* display a short message */ | ||
1669 | #ifdef CONFIG_PANEL_CHANGE_MESSAGE | ||
1670 | #ifdef CONFIG_PANEL_BOOT_MESSAGE | ||
1671 | panel_lcd_print("\x1b[Lc\x1b[Lb\x1b[L*" CONFIG_PANEL_BOOT_MESSAGE); | ||
1672 | #endif | ||
1673 | #else | ||
1674 | panel_lcd_print("\x1b[Lc\x1b[Lb\x1b[L*Linux-" UTS_RELEASE); | ||
1675 | #endif | ||
1676 | /* clear the display on the next device opening */ | ||
1677 | lcd.must_clear = true; | ||
1678 | lcd_home(); | ||
1679 | } | 1075 | } |
1680 | 1076 | ||
1681 | /* | 1077 | /* |
@@ -2011,7 +1407,7 @@ static void panel_scan_timer(void) | |||
2011 | } | 1407 | } |
2012 | 1408 | ||
2013 | if (keypressed && lcd.enabled && lcd.initialized) | 1409 | if (keypressed && lcd.enabled && lcd.initialized) |
2014 | lcd_poke(); | 1410 | charlcd_poke(lcd.charlcd); |
2015 | 1411 | ||
2016 | mod_timer(&scan_timer, jiffies + INPUT_POLL_TIME); | 1412 | mod_timer(&scan_timer, jiffies + INPUT_POLL_TIME); |
2017 | } | 1413 | } |
@@ -2175,35 +1571,6 @@ static void keypad_init(void) | |||
2175 | /* device initialization */ | 1571 | /* device initialization */ |
2176 | /**************************************************/ | 1572 | /**************************************************/ |
2177 | 1573 | ||
2178 | static int panel_notify_sys(struct notifier_block *this, unsigned long code, | ||
2179 | void *unused) | ||
2180 | { | ||
2181 | if (lcd.enabled && lcd.initialized) { | ||
2182 | switch (code) { | ||
2183 | case SYS_DOWN: | ||
2184 | panel_lcd_print | ||
2185 | ("\x0cReloading\nSystem...\x1b[Lc\x1b[Lb\x1b[L+"); | ||
2186 | break; | ||
2187 | case SYS_HALT: | ||
2188 | panel_lcd_print | ||
2189 | ("\x0cSystem Halted.\x1b[Lc\x1b[Lb\x1b[L+"); | ||
2190 | break; | ||
2191 | case SYS_POWER_OFF: | ||
2192 | panel_lcd_print("\x0cPower off.\x1b[Lc\x1b[Lb\x1b[L+"); | ||
2193 | break; | ||
2194 | default: | ||
2195 | break; | ||
2196 | } | ||
2197 | } | ||
2198 | return NOTIFY_DONE; | ||
2199 | } | ||
2200 | |||
2201 | static struct notifier_block panel_notifier = { | ||
2202 | panel_notify_sys, | ||
2203 | NULL, | ||
2204 | 0 | ||
2205 | }; | ||
2206 | |||
2207 | static void panel_attach(struct parport *port) | 1574 | static void panel_attach(struct parport *port) |
2208 | { | 1575 | { |
2209 | struct pardev_cb panel_cb; | 1576 | struct pardev_cb panel_cb; |
@@ -2239,7 +1606,7 @@ static void panel_attach(struct parport *port) | |||
2239 | */ | 1606 | */ |
2240 | if (lcd.enabled) { | 1607 | if (lcd.enabled) { |
2241 | lcd_init(); | 1608 | lcd_init(); |
2242 | if (misc_register(&lcd_dev)) | 1609 | if (!lcd.charlcd || charlcd_register(lcd.charlcd)) |
2243 | goto err_unreg_device; | 1610 | goto err_unreg_device; |
2244 | } | 1611 | } |
2245 | 1612 | ||
@@ -2248,13 +1615,14 @@ static void panel_attach(struct parport *port) | |||
2248 | if (misc_register(&keypad_dev)) | 1615 | if (misc_register(&keypad_dev)) |
2249 | goto err_lcd_unreg; | 1616 | goto err_lcd_unreg; |
2250 | } | 1617 | } |
2251 | register_reboot_notifier(&panel_notifier); | ||
2252 | return; | 1618 | return; |
2253 | 1619 | ||
2254 | err_lcd_unreg: | 1620 | err_lcd_unreg: |
2255 | if (lcd.enabled) | 1621 | if (lcd.enabled) |
2256 | misc_deregister(&lcd_dev); | 1622 | charlcd_unregister(lcd.charlcd); |
2257 | err_unreg_device: | 1623 | err_unreg_device: |
1624 | kfree(lcd.charlcd); | ||
1625 | lcd.charlcd = NULL; | ||
2258 | parport_unregister_device(pprt); | 1626 | parport_unregister_device(pprt); |
2259 | pprt = NULL; | 1627 | pprt = NULL; |
2260 | } | 1628 | } |
@@ -2278,20 +1646,16 @@ static void panel_detach(struct parport *port) | |||
2278 | } | 1646 | } |
2279 | 1647 | ||
2280 | if (lcd.enabled) { | 1648 | if (lcd.enabled) { |
2281 | panel_lcd_print("\x0cLCD driver unloaded.\x1b[Lc\x1b[Lb\x1b[L-"); | 1649 | charlcd_unregister(lcd.charlcd); |
2282 | misc_deregister(&lcd_dev); | ||
2283 | if (lcd.pins.bl != PIN_NONE) { | ||
2284 | cancel_delayed_work_sync(&lcd.bl_work); | ||
2285 | __lcd_backlight(0); | ||
2286 | } | ||
2287 | lcd.initialized = false; | 1650 | lcd.initialized = false; |
1651 | kfree(lcd.charlcd); | ||
1652 | lcd.charlcd = NULL; | ||
2288 | } | 1653 | } |
2289 | 1654 | ||
2290 | /* TODO: free all input signals */ | 1655 | /* TODO: free all input signals */ |
2291 | parport_release(pprt); | 1656 | parport_release(pprt); |
2292 | parport_unregister_device(pprt); | 1657 | parport_unregister_device(pprt); |
2293 | pprt = NULL; | 1658 | pprt = NULL; |
2294 | unregister_reboot_notifier(&panel_notifier); | ||
2295 | } | 1659 | } |
2296 | 1660 | ||
2297 | static struct parport_driver panel_driver = { | 1661 | static struct parport_driver panel_driver = { |
@@ -2369,10 +1733,6 @@ static int __init panel_init_module(void) | |||
2369 | * Init lcd struct with load-time values to preserve exact | 1733 | * Init lcd struct with load-time values to preserve exact |
2370 | * current functionality (at least for now). | 1734 | * current functionality (at least for now). |
2371 | */ | 1735 | */ |
2372 | lcd.height = lcd_height; | ||
2373 | lcd.width = lcd_width; | ||
2374 | lcd.bwidth = lcd_bwidth; | ||
2375 | lcd.hwidth = lcd_hwidth; | ||
2376 | lcd.charset = lcd_charset; | 1736 | lcd.charset = lcd_charset; |
2377 | lcd.proto = lcd_proto; | 1737 | lcd.proto = lcd_proto; |
2378 | lcd.pins.e = lcd_e_pin; | 1738 | lcd.pins.e = lcd_e_pin; |
@@ -2381,9 +1741,6 @@ static int __init panel_init_module(void) | |||
2381 | lcd.pins.cl = lcd_cl_pin; | 1741 | lcd.pins.cl = lcd_cl_pin; |
2382 | lcd.pins.da = lcd_da_pin; | 1742 | lcd.pins.da = lcd_da_pin; |
2383 | lcd.pins.bl = lcd_bl_pin; | 1743 | lcd.pins.bl = lcd_bl_pin; |
2384 | |||
2385 | /* Leave it for now, just in case */ | ||
2386 | lcd.esc_seq.len = -1; | ||
2387 | } | 1744 | } |
2388 | 1745 | ||
2389 | switch (selected_keypad_type) { | 1746 | switch (selected_keypad_type) { |
diff --git a/drivers/nvdimm/Kconfig b/drivers/nvdimm/Kconfig index 59e750183b7f..5bdd499b5f4f 100644 --- a/drivers/nvdimm/Kconfig +++ b/drivers/nvdimm/Kconfig | |||
@@ -20,6 +20,7 @@ if LIBNVDIMM | |||
20 | config BLK_DEV_PMEM | 20 | config BLK_DEV_PMEM |
21 | tristate "PMEM: Persistent memory block device support" | 21 | tristate "PMEM: Persistent memory block device support" |
22 | default LIBNVDIMM | 22 | default LIBNVDIMM |
23 | select DAX | ||
23 | select ND_BTT if BTT | 24 | select ND_BTT if BTT |
24 | select ND_PFN if NVDIMM_PFN | 25 | select ND_PFN if NVDIMM_PFN |
25 | help | 26 | help |
diff --git a/drivers/nvdimm/claim.c b/drivers/nvdimm/claim.c index 6945e35058bf..93d128da1c92 100644 --- a/drivers/nvdimm/claim.c +++ b/drivers/nvdimm/claim.c | |||
@@ -246,7 +246,7 @@ static int nsio_rw_bytes(struct nd_namespace_common *ndns, | |||
246 | if (rw == READ) { | 246 | if (rw == READ) { |
247 | if (unlikely(is_bad_pmem(&nsio->bb, sector, sz_align))) | 247 | if (unlikely(is_bad_pmem(&nsio->bb, sector, sz_align))) |
248 | return -EIO; | 248 | return -EIO; |
249 | return memcpy_from_pmem(buf, nsio->addr + offset, size); | 249 | return memcpy_mcsafe(buf, nsio->addr + offset, size); |
250 | } | 250 | } |
251 | 251 | ||
252 | if (unlikely(is_bad_pmem(&nsio->bb, sector, sz_align))) { | 252 | if (unlikely(is_bad_pmem(&nsio->bb, sector, sz_align))) { |
diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c index 0fc18262a2bc..58db813e7b7b 100644 --- a/drivers/nvdimm/pmem.c +++ b/drivers/nvdimm/pmem.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <linux/pfn_t.h> | 28 | #include <linux/pfn_t.h> |
29 | #include <linux/slab.h> | 29 | #include <linux/slab.h> |
30 | #include <linux/pmem.h> | 30 | #include <linux/pmem.h> |
31 | #include <linux/dax.h> | ||
31 | #include <linux/nd.h> | 32 | #include <linux/nd.h> |
32 | #include "pmem.h" | 33 | #include "pmem.h" |
33 | #include "pfn.h" | 34 | #include "pfn.h" |
@@ -88,7 +89,7 @@ static int read_pmem(struct page *page, unsigned int off, | |||
88 | int rc; | 89 | int rc; |
89 | void *mem = kmap_atomic(page); | 90 | void *mem = kmap_atomic(page); |
90 | 91 | ||
91 | rc = memcpy_from_pmem(mem + off, pmem_addr, len); | 92 | rc = memcpy_mcsafe(mem + off, pmem_addr, len); |
92 | kunmap_atomic(mem); | 93 | kunmap_atomic(mem); |
93 | if (rc) | 94 | if (rc) |
94 | return -EIO; | 95 | return -EIO; |
@@ -199,13 +200,13 @@ static int pmem_rw_page(struct block_device *bdev, sector_t sector, | |||
199 | } | 200 | } |
200 | 201 | ||
201 | /* see "strong" declaration in tools/testing/nvdimm/pmem-dax.c */ | 202 | /* see "strong" declaration in tools/testing/nvdimm/pmem-dax.c */ |
202 | __weak long pmem_direct_access(struct block_device *bdev, sector_t sector, | 203 | __weak long __pmem_direct_access(struct pmem_device *pmem, pgoff_t pgoff, |
203 | void **kaddr, pfn_t *pfn, long size) | 204 | long nr_pages, void **kaddr, pfn_t *pfn) |
204 | { | 205 | { |
205 | struct pmem_device *pmem = bdev->bd_queue->queuedata; | 206 | resource_size_t offset = PFN_PHYS(pgoff) + pmem->data_offset; |
206 | resource_size_t offset = sector * 512 + pmem->data_offset; | ||
207 | 207 | ||
208 | if (unlikely(is_bad_pmem(&pmem->bb, sector, size))) | 208 | if (unlikely(is_bad_pmem(&pmem->bb, PFN_PHYS(pgoff) / 512, |
209 | PFN_PHYS(nr_pages)))) | ||
209 | return -EIO; | 210 | return -EIO; |
210 | *kaddr = pmem->virt_addr + offset; | 211 | *kaddr = pmem->virt_addr + offset; |
211 | *pfn = phys_to_pfn_t(pmem->phys_addr + offset, pmem->pfn_flags); | 212 | *pfn = phys_to_pfn_t(pmem->phys_addr + offset, pmem->pfn_flags); |
@@ -215,26 +216,41 @@ __weak long pmem_direct_access(struct block_device *bdev, sector_t sector, | |||
215 | * requested range. | 216 | * requested range. |
216 | */ | 217 | */ |
217 | if (unlikely(pmem->bb.count)) | 218 | if (unlikely(pmem->bb.count)) |
218 | return size; | 219 | return nr_pages; |
219 | return pmem->size - pmem->pfn_pad - offset; | 220 | return PHYS_PFN(pmem->size - pmem->pfn_pad - offset); |
220 | } | 221 | } |
221 | 222 | ||
222 | static const struct block_device_operations pmem_fops = { | 223 | static const struct block_device_operations pmem_fops = { |
223 | .owner = THIS_MODULE, | 224 | .owner = THIS_MODULE, |
224 | .rw_page = pmem_rw_page, | 225 | .rw_page = pmem_rw_page, |
225 | .direct_access = pmem_direct_access, | ||
226 | .revalidate_disk = nvdimm_revalidate_disk, | 226 | .revalidate_disk = nvdimm_revalidate_disk, |
227 | }; | 227 | }; |
228 | 228 | ||
229 | static long pmem_dax_direct_access(struct dax_device *dax_dev, | ||
230 | pgoff_t pgoff, long nr_pages, void **kaddr, pfn_t *pfn) | ||
231 | { | ||
232 | struct pmem_device *pmem = dax_get_private(dax_dev); | ||
233 | |||
234 | return __pmem_direct_access(pmem, pgoff, nr_pages, kaddr, pfn); | ||
235 | } | ||
236 | |||
237 | static const struct dax_operations pmem_dax_ops = { | ||
238 | .direct_access = pmem_dax_direct_access, | ||
239 | }; | ||
240 | |||
229 | static void pmem_release_queue(void *q) | 241 | static void pmem_release_queue(void *q) |
230 | { | 242 | { |
231 | blk_cleanup_queue(q); | 243 | blk_cleanup_queue(q); |
232 | } | 244 | } |
233 | 245 | ||
234 | static void pmem_release_disk(void *disk) | 246 | static void pmem_release_disk(void *__pmem) |
235 | { | 247 | { |
236 | del_gendisk(disk); | 248 | struct pmem_device *pmem = __pmem; |
237 | put_disk(disk); | 249 | |
250 | kill_dax(pmem->dax_dev); | ||
251 | put_dax(pmem->dax_dev); | ||
252 | del_gendisk(pmem->disk); | ||
253 | put_disk(pmem->disk); | ||
238 | } | 254 | } |
239 | 255 | ||
240 | static int pmem_attach_disk(struct device *dev, | 256 | static int pmem_attach_disk(struct device *dev, |
@@ -245,6 +261,7 @@ static int pmem_attach_disk(struct device *dev, | |||
245 | struct vmem_altmap __altmap, *altmap = NULL; | 261 | struct vmem_altmap __altmap, *altmap = NULL; |
246 | struct resource *res = &nsio->res; | 262 | struct resource *res = &nsio->res; |
247 | struct nd_pfn *nd_pfn = NULL; | 263 | struct nd_pfn *nd_pfn = NULL; |
264 | struct dax_device *dax_dev; | ||
248 | int nid = dev_to_node(dev); | 265 | int nid = dev_to_node(dev); |
249 | struct nd_pfn_sb *pfn_sb; | 266 | struct nd_pfn_sb *pfn_sb; |
250 | struct pmem_device *pmem; | 267 | struct pmem_device *pmem; |
@@ -325,6 +342,7 @@ static int pmem_attach_disk(struct device *dev, | |||
325 | disk = alloc_disk_node(0, nid); | 342 | disk = alloc_disk_node(0, nid); |
326 | if (!disk) | 343 | if (!disk) |
327 | return -ENOMEM; | 344 | return -ENOMEM; |
345 | pmem->disk = disk; | ||
328 | 346 | ||
329 | disk->fops = &pmem_fops; | 347 | disk->fops = &pmem_fops; |
330 | disk->queue = q; | 348 | disk->queue = q; |
@@ -336,9 +354,16 @@ static int pmem_attach_disk(struct device *dev, | |||
336 | return -ENOMEM; | 354 | return -ENOMEM; |
337 | nvdimm_badblocks_populate(nd_region, &pmem->bb, res); | 355 | nvdimm_badblocks_populate(nd_region, &pmem->bb, res); |
338 | disk->bb = &pmem->bb; | 356 | disk->bb = &pmem->bb; |
339 | device_add_disk(dev, disk); | ||
340 | 357 | ||
341 | if (devm_add_action_or_reset(dev, pmem_release_disk, disk)) | 358 | dax_dev = alloc_dax(pmem, disk->disk_name, &pmem_dax_ops); |
359 | if (!dax_dev) { | ||
360 | put_disk(disk); | ||
361 | return -ENOMEM; | ||
362 | } | ||
363 | pmem->dax_dev = dax_dev; | ||
364 | |||
365 | device_add_disk(dev, disk); | ||
366 | if (devm_add_action_or_reset(dev, pmem_release_disk, pmem)) | ||
342 | return -ENOMEM; | 367 | return -ENOMEM; |
343 | 368 | ||
344 | revalidate_disk(disk); | 369 | revalidate_disk(disk); |
diff --git a/drivers/nvdimm/pmem.h b/drivers/nvdimm/pmem.h index b4ee4f71b4a1..7f4dbd72a90a 100644 --- a/drivers/nvdimm/pmem.h +++ b/drivers/nvdimm/pmem.h | |||
@@ -5,8 +5,6 @@ | |||
5 | #include <linux/pfn_t.h> | 5 | #include <linux/pfn_t.h> |
6 | #include <linux/fs.h> | 6 | #include <linux/fs.h> |
7 | 7 | ||
8 | long pmem_direct_access(struct block_device *bdev, sector_t sector, | ||
9 | void **kaddr, pfn_t *pfn, long size); | ||
10 | /* this definition is in it's own header for tools/testing/nvdimm to consume */ | 8 | /* this definition is in it's own header for tools/testing/nvdimm to consume */ |
11 | struct pmem_device { | 9 | struct pmem_device { |
12 | /* One contiguous memory region per device */ | 10 | /* One contiguous memory region per device */ |
@@ -20,5 +18,10 @@ struct pmem_device { | |||
20 | /* trim size when namespace capacity has been section aligned */ | 18 | /* trim size when namespace capacity has been section aligned */ |
21 | u32 pfn_pad; | 19 | u32 pfn_pad; |
22 | struct badblocks bb; | 20 | struct badblocks bb; |
21 | struct dax_device *dax_dev; | ||
22 | struct gendisk *disk; | ||
23 | }; | 23 | }; |
24 | |||
25 | long __pmem_direct_access(struct pmem_device *pmem, pgoff_t pgoff, | ||
26 | long nr_pages, void **kaddr, pfn_t *pfn); | ||
24 | #endif /* __NVDIMM_PMEM_H__ */ | 27 | #endif /* __NVDIMM_PMEM_H__ */ |
diff --git a/drivers/pps/pps.c b/drivers/pps/pps.c index 2f07cd615665..6eb0db37dd88 100644 --- a/drivers/pps/pps.c +++ b/drivers/pps/pps.c | |||
@@ -64,6 +64,43 @@ static int pps_cdev_fasync(int fd, struct file *file, int on) | |||
64 | return fasync_helper(fd, file, on, &pps->async_queue); | 64 | return fasync_helper(fd, file, on, &pps->async_queue); |
65 | } | 65 | } |
66 | 66 | ||
67 | static int pps_cdev_pps_fetch(struct pps_device *pps, struct pps_fdata *fdata) | ||
68 | { | ||
69 | unsigned int ev = pps->last_ev; | ||
70 | int err = 0; | ||
71 | |||
72 | /* Manage the timeout */ | ||
73 | if (fdata->timeout.flags & PPS_TIME_INVALID) | ||
74 | err = wait_event_interruptible(pps->queue, | ||
75 | ev != pps->last_ev); | ||
76 | else { | ||
77 | unsigned long ticks; | ||
78 | |||
79 | dev_dbg(pps->dev, "timeout %lld.%09d\n", | ||
80 | (long long) fdata->timeout.sec, | ||
81 | fdata->timeout.nsec); | ||
82 | ticks = fdata->timeout.sec * HZ; | ||
83 | ticks += fdata->timeout.nsec / (NSEC_PER_SEC / HZ); | ||
84 | |||
85 | if (ticks != 0) { | ||
86 | err = wait_event_interruptible_timeout( | ||
87 | pps->queue, | ||
88 | ev != pps->last_ev, | ||
89 | ticks); | ||
90 | if (err == 0) | ||
91 | return -ETIMEDOUT; | ||
92 | } | ||
93 | } | ||
94 | |||
95 | /* Check for pending signals */ | ||
96 | if (err == -ERESTARTSYS) { | ||
97 | dev_dbg(pps->dev, "pending signal caught\n"); | ||
98 | return -EINTR; | ||
99 | } | ||
100 | |||
101 | return 0; | ||
102 | } | ||
103 | |||
67 | static long pps_cdev_ioctl(struct file *file, | 104 | static long pps_cdev_ioctl(struct file *file, |
68 | unsigned int cmd, unsigned long arg) | 105 | unsigned int cmd, unsigned long arg) |
69 | { | 106 | { |
@@ -144,7 +181,6 @@ static long pps_cdev_ioctl(struct file *file, | |||
144 | 181 | ||
145 | case PPS_FETCH: { | 182 | case PPS_FETCH: { |
146 | struct pps_fdata fdata; | 183 | struct pps_fdata fdata; |
147 | unsigned int ev; | ||
148 | 184 | ||
149 | dev_dbg(pps->dev, "PPS_FETCH\n"); | 185 | dev_dbg(pps->dev, "PPS_FETCH\n"); |
150 | 186 | ||
@@ -152,36 +188,9 @@ static long pps_cdev_ioctl(struct file *file, | |||
152 | if (err) | 188 | if (err) |
153 | return -EFAULT; | 189 | return -EFAULT; |
154 | 190 | ||
155 | ev = pps->last_ev; | 191 | err = pps_cdev_pps_fetch(pps, &fdata); |
156 | 192 | if (err) | |
157 | /* Manage the timeout */ | 193 | return err; |
158 | if (fdata.timeout.flags & PPS_TIME_INVALID) | ||
159 | err = wait_event_interruptible(pps->queue, | ||
160 | ev != pps->last_ev); | ||
161 | else { | ||
162 | unsigned long ticks; | ||
163 | |||
164 | dev_dbg(pps->dev, "timeout %lld.%09d\n", | ||
165 | (long long) fdata.timeout.sec, | ||
166 | fdata.timeout.nsec); | ||
167 | ticks = fdata.timeout.sec * HZ; | ||
168 | ticks += fdata.timeout.nsec / (NSEC_PER_SEC / HZ); | ||
169 | |||
170 | if (ticks != 0) { | ||
171 | err = wait_event_interruptible_timeout( | ||
172 | pps->queue, | ||
173 | ev != pps->last_ev, | ||
174 | ticks); | ||
175 | if (err == 0) | ||
176 | return -ETIMEDOUT; | ||
177 | } | ||
178 | } | ||
179 | |||
180 | /* Check for pending signals */ | ||
181 | if (err == -ERESTARTSYS) { | ||
182 | dev_dbg(pps->dev, "pending signal caught\n"); | ||
183 | return -EINTR; | ||
184 | } | ||
185 | 194 | ||
186 | /* Return the fetched timestamp */ | 195 | /* Return the fetched timestamp */ |
187 | spin_lock_irq(&pps->lock); | 196 | spin_lock_irq(&pps->lock); |
@@ -242,6 +251,57 @@ static long pps_cdev_ioctl(struct file *file, | |||
242 | return 0; | 251 | return 0; |
243 | } | 252 | } |
244 | 253 | ||
254 | #ifdef CONFIG_COMPAT | ||
255 | static long pps_cdev_compat_ioctl(struct file *file, | ||
256 | unsigned int cmd, unsigned long arg) | ||
257 | { | ||
258 | struct pps_device *pps = file->private_data; | ||
259 | void __user *uarg = (void __user *) arg; | ||
260 | |||
261 | cmd = _IOC(_IOC_DIR(cmd), _IOC_TYPE(cmd), _IOC_NR(cmd), sizeof(void *)); | ||
262 | |||
263 | if (cmd == PPS_FETCH) { | ||
264 | struct pps_fdata_compat compat; | ||
265 | struct pps_fdata fdata; | ||
266 | int err; | ||
267 | |||
268 | dev_dbg(pps->dev, "PPS_FETCH\n"); | ||
269 | |||
270 | err = copy_from_user(&compat, uarg, sizeof(struct pps_fdata_compat)); | ||
271 | if (err) | ||
272 | return -EFAULT; | ||
273 | |||
274 | memcpy(&fdata.timeout, &compat.timeout, | ||
275 | sizeof(struct pps_ktime_compat)); | ||
276 | |||
277 | err = pps_cdev_pps_fetch(pps, &fdata); | ||
278 | if (err) | ||
279 | return err; | ||
280 | |||
281 | /* Return the fetched timestamp */ | ||
282 | spin_lock_irq(&pps->lock); | ||
283 | |||
284 | compat.info.assert_sequence = pps->assert_sequence; | ||
285 | compat.info.clear_sequence = pps->clear_sequence; | ||
286 | compat.info.current_mode = pps->current_mode; | ||
287 | |||
288 | memcpy(&compat.info.assert_tu, &pps->assert_tu, | ||
289 | sizeof(struct pps_ktime_compat)); | ||
290 | memcpy(&compat.info.clear_tu, &pps->clear_tu, | ||
291 | sizeof(struct pps_ktime_compat)); | ||
292 | |||
293 | spin_unlock_irq(&pps->lock); | ||
294 | |||
295 | return copy_to_user(uarg, &compat, | ||
296 | sizeof(struct pps_fdata_compat)) ? -EFAULT : 0; | ||
297 | } | ||
298 | |||
299 | return pps_cdev_ioctl(file, cmd, arg); | ||
300 | } | ||
301 | #else | ||
302 | #define pps_cdev_compat_ioctl NULL | ||
303 | #endif | ||
304 | |||
245 | static int pps_cdev_open(struct inode *inode, struct file *file) | 305 | static int pps_cdev_open(struct inode *inode, struct file *file) |
246 | { | 306 | { |
247 | struct pps_device *pps = container_of(inode->i_cdev, | 307 | struct pps_device *pps = container_of(inode->i_cdev, |
@@ -268,6 +328,7 @@ static const struct file_operations pps_cdev_fops = { | |||
268 | .llseek = no_llseek, | 328 | .llseek = no_llseek, |
269 | .poll = pps_cdev_poll, | 329 | .poll = pps_cdev_poll, |
270 | .fasync = pps_cdev_fasync, | 330 | .fasync = pps_cdev_fasync, |
331 | .compat_ioctl = pps_cdev_compat_ioctl, | ||
271 | .unlocked_ioctl = pps_cdev_ioctl, | 332 | .unlocked_ioctl = pps_cdev_ioctl, |
272 | .open = pps_cdev_open, | 333 | .open = pps_cdev_open, |
273 | .release = pps_cdev_release, | 334 | .release = pps_cdev_release, |
diff --git a/drivers/rapidio/rio-sysfs.c b/drivers/rapidio/rio-sysfs.c index eda41563d06d..73e4b407f162 100644 --- a/drivers/rapidio/rio-sysfs.c +++ b/drivers/rapidio/rio-sysfs.c | |||
@@ -108,15 +108,11 @@ static struct attribute *rio_dev_attrs[] = { | |||
108 | &dev_attr_lprev.attr, | 108 | &dev_attr_lprev.attr, |
109 | &dev_attr_destid.attr, | 109 | &dev_attr_destid.attr, |
110 | &dev_attr_modalias.attr, | 110 | &dev_attr_modalias.attr, |
111 | NULL, | ||
112 | }; | ||
113 | 111 | ||
114 | static const struct attribute_group rio_dev_group = { | 112 | /* Switch-only attributes */ |
115 | .attrs = rio_dev_attrs, | 113 | &dev_attr_routes.attr, |
116 | }; | 114 | &dev_attr_lnext.attr, |
117 | 115 | &dev_attr_hopcount.attr, | |
118 | const struct attribute_group *rio_dev_groups[] = { | ||
119 | &rio_dev_group, | ||
120 | NULL, | 116 | NULL, |
121 | }; | 117 | }; |
122 | 118 | ||
@@ -259,46 +255,40 @@ static struct bin_attribute rio_config_attr = { | |||
259 | .write = rio_write_config, | 255 | .write = rio_write_config, |
260 | }; | 256 | }; |
261 | 257 | ||
262 | /** | 258 | static struct bin_attribute *rio_dev_bin_attrs[] = { |
263 | * rio_create_sysfs_dev_files - create RIO specific sysfs files | 259 | &rio_config_attr, |
264 | * @rdev: device whose entries should be created | 260 | NULL, |
265 | * | 261 | }; |
266 | * Create files when @rdev is added to sysfs. | ||
267 | */ | ||
268 | int rio_create_sysfs_dev_files(struct rio_dev *rdev) | ||
269 | { | ||
270 | int err = 0; | ||
271 | |||
272 | err = device_create_bin_file(&rdev->dev, &rio_config_attr); | ||
273 | 262 | ||
274 | if (!err && (rdev->pef & RIO_PEF_SWITCH)) { | 263 | static umode_t rio_dev_is_attr_visible(struct kobject *kobj, |
275 | err |= device_create_file(&rdev->dev, &dev_attr_routes); | 264 | struct attribute *attr, int n) |
276 | err |= device_create_file(&rdev->dev, &dev_attr_lnext); | 265 | { |
277 | err |= device_create_file(&rdev->dev, &dev_attr_hopcount); | 266 | struct rio_dev *rdev = to_rio_dev(kobj_to_dev(kobj)); |
267 | umode_t mode = attr->mode; | ||
268 | |||
269 | if (!(rdev->pef & RIO_PEF_SWITCH) && | ||
270 | (attr == &dev_attr_routes.attr || | ||
271 | attr == &dev_attr_lnext.attr || | ||
272 | attr == &dev_attr_hopcount.attr)) { | ||
273 | /* | ||
274 | * Hide switch-specific attributes for a non-switch device. | ||
275 | */ | ||
276 | mode = 0; | ||
278 | } | 277 | } |
279 | 278 | ||
280 | if (err) | 279 | return mode; |
281 | pr_warning("RIO: Failed to create attribute file(s) for %s\n", | ||
282 | rio_name(rdev)); | ||
283 | |||
284 | return err; | ||
285 | } | 280 | } |
286 | 281 | ||
287 | /** | 282 | static const struct attribute_group rio_dev_group = { |
288 | * rio_remove_sysfs_dev_files - cleanup RIO specific sysfs files | 283 | .attrs = rio_dev_attrs, |
289 | * @rdev: device whose entries we should free | 284 | .is_visible = rio_dev_is_attr_visible, |
290 | * | 285 | .bin_attrs = rio_dev_bin_attrs, |
291 | * Cleanup when @rdev is removed from sysfs. | 286 | }; |
292 | */ | 287 | |
293 | void rio_remove_sysfs_dev_files(struct rio_dev *rdev) | 288 | const struct attribute_group *rio_dev_groups[] = { |
294 | { | 289 | &rio_dev_group, |
295 | device_remove_bin_file(&rdev->dev, &rio_config_attr); | 290 | NULL, |
296 | if (rdev->pef & RIO_PEF_SWITCH) { | 291 | }; |
297 | device_remove_file(&rdev->dev, &dev_attr_routes); | ||
298 | device_remove_file(&rdev->dev, &dev_attr_lnext); | ||
299 | device_remove_file(&rdev->dev, &dev_attr_hopcount); | ||
300 | } | ||
301 | } | ||
302 | 292 | ||
303 | static ssize_t bus_scan_store(struct bus_type *bus, const char *buf, | 293 | static ssize_t bus_scan_store(struct bus_type *bus, const char *buf, |
304 | size_t count) | 294 | size_t count) |
diff --git a/drivers/rapidio/rio.c b/drivers/rapidio/rio.c index 37042858c2db..38d949405618 100644 --- a/drivers/rapidio/rio.c +++ b/drivers/rapidio/rio.c | |||
@@ -192,8 +192,6 @@ int rio_add_device(struct rio_dev *rdev) | |||
192 | } | 192 | } |
193 | spin_unlock(&rio_global_list_lock); | 193 | spin_unlock(&rio_global_list_lock); |
194 | 194 | ||
195 | rio_create_sysfs_dev_files(rdev); | ||
196 | |||
197 | return 0; | 195 | return 0; |
198 | } | 196 | } |
199 | EXPORT_SYMBOL_GPL(rio_add_device); | 197 | EXPORT_SYMBOL_GPL(rio_add_device); |
@@ -220,7 +218,6 @@ void rio_del_device(struct rio_dev *rdev, enum rio_device_state state) | |||
220 | } | 218 | } |
221 | } | 219 | } |
222 | spin_unlock(&rio_global_list_lock); | 220 | spin_unlock(&rio_global_list_lock); |
223 | rio_remove_sysfs_dev_files(rdev); | ||
224 | device_unregister(&rdev->dev); | 221 | device_unregister(&rdev->dev); |
225 | } | 222 | } |
226 | EXPORT_SYMBOL_GPL(rio_del_device); | 223 | EXPORT_SYMBOL_GPL(rio_del_device); |
diff --git a/drivers/rapidio/rio.h b/drivers/rapidio/rio.h index 9796b3fee70d..b2abf8576397 100644 --- a/drivers/rapidio/rio.h +++ b/drivers/rapidio/rio.h | |||
@@ -27,8 +27,6 @@ extern u32 rio_mport_get_efb(struct rio_mport *port, int local, u16 destid, | |||
27 | u8 hopcount, u32 from); | 27 | u8 hopcount, u32 from); |
28 | extern int rio_mport_chk_dev_access(struct rio_mport *mport, u16 destid, | 28 | extern int rio_mport_chk_dev_access(struct rio_mport *mport, u16 destid, |
29 | u8 hopcount); | 29 | u8 hopcount); |
30 | extern int rio_create_sysfs_dev_files(struct rio_dev *rdev); | ||
31 | extern void rio_remove_sysfs_dev_files(struct rio_dev *rdev); | ||
32 | extern int rio_lock_device(struct rio_mport *port, u16 destid, | 30 | extern int rio_lock_device(struct rio_mport *port, u16 destid, |
33 | u8 hopcount, int wait_ms); | 31 | u8 hopcount, int wait_ms); |
34 | extern int rio_unlock_device(struct rio_mport *port, u16 destid, u8 hopcount); | 32 | extern int rio_unlock_device(struct rio_mport *port, u16 destid, u8 hopcount); |
diff --git a/drivers/s390/block/Kconfig b/drivers/s390/block/Kconfig index 4a3b62326183..0acb8c2f9475 100644 --- a/drivers/s390/block/Kconfig +++ b/drivers/s390/block/Kconfig | |||
@@ -14,6 +14,7 @@ config BLK_DEV_XPRAM | |||
14 | 14 | ||
15 | config DCSSBLK | 15 | config DCSSBLK |
16 | def_tristate m | 16 | def_tristate m |
17 | select DAX | ||
17 | prompt "DCSSBLK support" | 18 | prompt "DCSSBLK support" |
18 | depends on S390 && BLOCK | 19 | depends on S390 && BLOCK |
19 | help | 20 | help |
diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c index 415d10a67b7a..36e5280af3e4 100644 --- a/drivers/s390/block/dcssblk.c +++ b/drivers/s390/block/dcssblk.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/interrupt.h> | 18 | #include <linux/interrupt.h> |
19 | #include <linux/platform_device.h> | 19 | #include <linux/platform_device.h> |
20 | #include <linux/pfn_t.h> | 20 | #include <linux/pfn_t.h> |
21 | #include <linux/dax.h> | ||
21 | #include <asm/extmem.h> | 22 | #include <asm/extmem.h> |
22 | #include <asm/io.h> | 23 | #include <asm/io.h> |
23 | 24 | ||
@@ -30,8 +31,8 @@ static int dcssblk_open(struct block_device *bdev, fmode_t mode); | |||
30 | static void dcssblk_release(struct gendisk *disk, fmode_t mode); | 31 | static void dcssblk_release(struct gendisk *disk, fmode_t mode); |
31 | static blk_qc_t dcssblk_make_request(struct request_queue *q, | 32 | static blk_qc_t dcssblk_make_request(struct request_queue *q, |
32 | struct bio *bio); | 33 | struct bio *bio); |
33 | static long dcssblk_direct_access(struct block_device *bdev, sector_t secnum, | 34 | static long dcssblk_dax_direct_access(struct dax_device *dax_dev, pgoff_t pgoff, |
34 | void **kaddr, pfn_t *pfn, long size); | 35 | long nr_pages, void **kaddr, pfn_t *pfn); |
35 | 36 | ||
36 | static char dcssblk_segments[DCSSBLK_PARM_LEN] = "\0"; | 37 | static char dcssblk_segments[DCSSBLK_PARM_LEN] = "\0"; |
37 | 38 | ||
@@ -40,7 +41,10 @@ static const struct block_device_operations dcssblk_devops = { | |||
40 | .owner = THIS_MODULE, | 41 | .owner = THIS_MODULE, |
41 | .open = dcssblk_open, | 42 | .open = dcssblk_open, |
42 | .release = dcssblk_release, | 43 | .release = dcssblk_release, |
43 | .direct_access = dcssblk_direct_access, | 44 | }; |
45 | |||
46 | static const struct dax_operations dcssblk_dax_ops = { | ||
47 | .direct_access = dcssblk_dax_direct_access, | ||
44 | }; | 48 | }; |
45 | 49 | ||
46 | struct dcssblk_dev_info { | 50 | struct dcssblk_dev_info { |
@@ -57,6 +61,7 @@ struct dcssblk_dev_info { | |||
57 | struct request_queue *dcssblk_queue; | 61 | struct request_queue *dcssblk_queue; |
58 | int num_of_segments; | 62 | int num_of_segments; |
59 | struct list_head seg_list; | 63 | struct list_head seg_list; |
64 | struct dax_device *dax_dev; | ||
60 | }; | 65 | }; |
61 | 66 | ||
62 | struct segment_info { | 67 | struct segment_info { |
@@ -389,6 +394,8 @@ removeseg: | |||
389 | } | 394 | } |
390 | list_del(&dev_info->lh); | 395 | list_del(&dev_info->lh); |
391 | 396 | ||
397 | kill_dax(dev_info->dax_dev); | ||
398 | put_dax(dev_info->dax_dev); | ||
392 | del_gendisk(dev_info->gd); | 399 | del_gendisk(dev_info->gd); |
393 | blk_cleanup_queue(dev_info->dcssblk_queue); | 400 | blk_cleanup_queue(dev_info->dcssblk_queue); |
394 | dev_info->gd->queue = NULL; | 401 | dev_info->gd->queue = NULL; |
@@ -654,6 +661,13 @@ dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char | |||
654 | if (rc) | 661 | if (rc) |
655 | goto put_dev; | 662 | goto put_dev; |
656 | 663 | ||
664 | dev_info->dax_dev = alloc_dax(dev_info, dev_info->gd->disk_name, | ||
665 | &dcssblk_dax_ops); | ||
666 | if (!dev_info->dax_dev) { | ||
667 | rc = -ENOMEM; | ||
668 | goto put_dev; | ||
669 | } | ||
670 | |||
657 | get_device(&dev_info->dev); | 671 | get_device(&dev_info->dev); |
658 | device_add_disk(&dev_info->dev, dev_info->gd); | 672 | device_add_disk(&dev_info->dev, dev_info->gd); |
659 | 673 | ||
@@ -752,6 +766,8 @@ dcssblk_remove_store(struct device *dev, struct device_attribute *attr, const ch | |||
752 | } | 766 | } |
753 | 767 | ||
754 | list_del(&dev_info->lh); | 768 | list_del(&dev_info->lh); |
769 | kill_dax(dev_info->dax_dev); | ||
770 | put_dax(dev_info->dax_dev); | ||
755 | del_gendisk(dev_info->gd); | 771 | del_gendisk(dev_info->gd); |
756 | blk_cleanup_queue(dev_info->dcssblk_queue); | 772 | blk_cleanup_queue(dev_info->dcssblk_queue); |
757 | dev_info->gd->queue = NULL; | 773 | dev_info->gd->queue = NULL; |
@@ -883,21 +899,26 @@ fail: | |||
883 | } | 899 | } |
884 | 900 | ||
885 | static long | 901 | static long |
886 | dcssblk_direct_access (struct block_device *bdev, sector_t secnum, | 902 | __dcssblk_direct_access(struct dcssblk_dev_info *dev_info, pgoff_t pgoff, |
887 | void **kaddr, pfn_t *pfn, long size) | 903 | long nr_pages, void **kaddr, pfn_t *pfn) |
888 | { | 904 | { |
889 | struct dcssblk_dev_info *dev_info; | 905 | resource_size_t offset = pgoff * PAGE_SIZE; |
890 | unsigned long offset, dev_sz; | 906 | unsigned long dev_sz; |
891 | 907 | ||
892 | dev_info = bdev->bd_disk->private_data; | ||
893 | if (!dev_info) | ||
894 | return -ENODEV; | ||
895 | dev_sz = dev_info->end - dev_info->start + 1; | 908 | dev_sz = dev_info->end - dev_info->start + 1; |
896 | offset = secnum * 512; | ||
897 | *kaddr = (void *) dev_info->start + offset; | 909 | *kaddr = (void *) dev_info->start + offset; |
898 | *pfn = __pfn_to_pfn_t(PFN_DOWN(dev_info->start + offset), PFN_DEV); | 910 | *pfn = __pfn_to_pfn_t(PFN_DOWN(dev_info->start + offset), PFN_DEV); |
899 | 911 | ||
900 | return dev_sz - offset; | 912 | return (dev_sz - offset) / PAGE_SIZE; |
913 | } | ||
914 | |||
915 | static long | ||
916 | dcssblk_dax_direct_access(struct dax_device *dax_dev, pgoff_t pgoff, | ||
917 | long nr_pages, void **kaddr, pfn_t *pfn) | ||
918 | { | ||
919 | struct dcssblk_dev_info *dev_info = dax_get_private(dax_dev); | ||
920 | |||
921 | return __dcssblk_direct_access(dev_info, pgoff, nr_pages, kaddr, pfn); | ||
901 | } | 922 | } |
902 | 923 | ||
903 | static void | 924 | static void |
diff --git a/drivers/vme/vme.c b/drivers/vme/vme.c index 0035cf79760a..6a3ead42aba8 100644 --- a/drivers/vme/vme.c +++ b/drivers/vme/vme.c | |||
@@ -76,9 +76,16 @@ static struct vme_bridge *find_bridge(struct vme_resource *resource) | |||
76 | } | 76 | } |
77 | } | 77 | } |
78 | 78 | ||
79 | /* | 79 | /** |
80 | * vme_free_consistent - Allocate contiguous memory. | ||
81 | * @resource: Pointer to VME resource. | ||
82 | * @size: Size of allocation required. | ||
83 | * @dma: Pointer to variable to store physical address of allocation. | ||
84 | * | ||
80 | * Allocate a contiguous block of memory for use by the driver. This is used to | 85 | * Allocate a contiguous block of memory for use by the driver. This is used to |
81 | * create the buffers for the slave windows. | 86 | * create the buffers for the slave windows. |
87 | * | ||
88 | * Return: Virtual address of allocation on success, NULL on failure. | ||
82 | */ | 89 | */ |
83 | void *vme_alloc_consistent(struct vme_resource *resource, size_t size, | 90 | void *vme_alloc_consistent(struct vme_resource *resource, size_t size, |
84 | dma_addr_t *dma) | 91 | dma_addr_t *dma) |
@@ -111,8 +118,14 @@ void *vme_alloc_consistent(struct vme_resource *resource, size_t size, | |||
111 | } | 118 | } |
112 | EXPORT_SYMBOL(vme_alloc_consistent); | 119 | EXPORT_SYMBOL(vme_alloc_consistent); |
113 | 120 | ||
114 | /* | 121 | /** |
115 | * Free previously allocated contiguous block of memory. | 122 | * vme_free_consistent - Free previously allocated memory. |
123 | * @resource: Pointer to VME resource. | ||
124 | * @size: Size of allocation to free. | ||
125 | * @vaddr: Virtual address of allocation. | ||
126 | * @dma: Physical address of allocation. | ||
127 | * | ||
128 | * Free previously allocated block of contiguous memory. | ||
116 | */ | 129 | */ |
117 | void vme_free_consistent(struct vme_resource *resource, size_t size, | 130 | void vme_free_consistent(struct vme_resource *resource, size_t size, |
118 | void *vaddr, dma_addr_t dma) | 131 | void *vaddr, dma_addr_t dma) |
@@ -145,6 +158,16 @@ void vme_free_consistent(struct vme_resource *resource, size_t size, | |||
145 | } | 158 | } |
146 | EXPORT_SYMBOL(vme_free_consistent); | 159 | EXPORT_SYMBOL(vme_free_consistent); |
147 | 160 | ||
161 | /** | ||
162 | * vme_get_size - Helper function returning size of a VME window | ||
163 | * @resource: Pointer to VME slave or master resource. | ||
164 | * | ||
165 | * Determine the size of the VME window provided. This is a helper | ||
166 | * function, wrappering the call to vme_master_get or vme_slave_get | ||
167 | * depending on the type of window resource handed to it. | ||
168 | * | ||
169 | * Return: Size of the window on success, zero on failure. | ||
170 | */ | ||
148 | size_t vme_get_size(struct vme_resource *resource) | 171 | size_t vme_get_size(struct vme_resource *resource) |
149 | { | 172 | { |
150 | int enabled, retval; | 173 | int enabled, retval; |
@@ -259,9 +282,16 @@ static u32 vme_get_aspace(int am) | |||
259 | return 0; | 282 | return 0; |
260 | } | 283 | } |
261 | 284 | ||
262 | /* | 285 | /** |
263 | * Request a slave image with specific attributes, return some unique | 286 | * vme_slave_request - Request a VME slave window resource. |
264 | * identifier. | 287 | * @vdev: Pointer to VME device struct vme_dev assigned to driver instance. |
288 | * @address: Required VME address space. | ||
289 | * @cycle: Required VME data transfer cycle type. | ||
290 | * | ||
291 | * Request use of a VME window resource capable of being set for the requested | ||
292 | * address space and data transfer cycle. | ||
293 | * | ||
294 | * Return: Pointer to VME resource on success, NULL on failure. | ||
265 | */ | 295 | */ |
266 | struct vme_resource *vme_slave_request(struct vme_dev *vdev, u32 address, | 296 | struct vme_resource *vme_slave_request(struct vme_dev *vdev, u32 address, |
267 | u32 cycle) | 297 | u32 cycle) |
@@ -327,6 +357,23 @@ err_bus: | |||
327 | } | 357 | } |
328 | EXPORT_SYMBOL(vme_slave_request); | 358 | EXPORT_SYMBOL(vme_slave_request); |
329 | 359 | ||
360 | /** | ||
361 | * vme_slave_set - Set VME slave window configuration. | ||
362 | * @resource: Pointer to VME slave resource. | ||
363 | * @enabled: State to which the window should be configured. | ||
364 | * @vme_base: Base address for the window. | ||
365 | * @size: Size of the VME window. | ||
366 | * @buf_base: Based address of buffer used to provide VME slave window storage. | ||
367 | * @aspace: VME address space for the VME window. | ||
368 | * @cycle: VME data transfer cycle type for the VME window. | ||
369 | * | ||
370 | * Set configuration for provided VME slave window. | ||
371 | * | ||
372 | * Return: Zero on success, -EINVAL if operation is not supported on this | ||
373 | * device, if an invalid resource has been provided or invalid | ||
374 | * attributes are provided. Hardware specific errors may also be | ||
375 | * returned. | ||
376 | */ | ||
330 | int vme_slave_set(struct vme_resource *resource, int enabled, | 377 | int vme_slave_set(struct vme_resource *resource, int enabled, |
331 | unsigned long long vme_base, unsigned long long size, | 378 | unsigned long long vme_base, unsigned long long size, |
332 | dma_addr_t buf_base, u32 aspace, u32 cycle) | 379 | dma_addr_t buf_base, u32 aspace, u32 cycle) |
@@ -362,6 +409,21 @@ int vme_slave_set(struct vme_resource *resource, int enabled, | |||
362 | } | 409 | } |
363 | EXPORT_SYMBOL(vme_slave_set); | 410 | EXPORT_SYMBOL(vme_slave_set); |
364 | 411 | ||
412 | /** | ||
413 | * vme_slave_get - Retrieve VME slave window configuration. | ||
414 | * @resource: Pointer to VME slave resource. | ||
415 | * @enabled: Pointer to variable for storing state. | ||
416 | * @vme_base: Pointer to variable for storing window base address. | ||
417 | * @size: Pointer to variable for storing window size. | ||
418 | * @buf_base: Pointer to variable for storing slave buffer base address. | ||
419 | * @aspace: Pointer to variable for storing VME address space. | ||
420 | * @cycle: Pointer to variable for storing VME data transfer cycle type. | ||
421 | * | ||
422 | * Return configuration for provided VME slave window. | ||
423 | * | ||
424 | * Return: Zero on success, -EINVAL if operation is not supported on this | ||
425 | * device or if an invalid resource has been provided. | ||
426 | */ | ||
365 | int vme_slave_get(struct vme_resource *resource, int *enabled, | 427 | int vme_slave_get(struct vme_resource *resource, int *enabled, |
366 | unsigned long long *vme_base, unsigned long long *size, | 428 | unsigned long long *vme_base, unsigned long long *size, |
367 | dma_addr_t *buf_base, u32 *aspace, u32 *cycle) | 429 | dma_addr_t *buf_base, u32 *aspace, u32 *cycle) |
@@ -386,6 +448,12 @@ int vme_slave_get(struct vme_resource *resource, int *enabled, | |||
386 | } | 448 | } |
387 | EXPORT_SYMBOL(vme_slave_get); | 449 | EXPORT_SYMBOL(vme_slave_get); |
388 | 450 | ||
451 | /** | ||
452 | * vme_slave_free - Free VME slave window | ||
453 | * @resource: Pointer to VME slave resource. | ||
454 | * | ||
455 | * Free the provided slave resource so that it may be reallocated. | ||
456 | */ | ||
389 | void vme_slave_free(struct vme_resource *resource) | 457 | void vme_slave_free(struct vme_resource *resource) |
390 | { | 458 | { |
391 | struct vme_slave_resource *slave_image; | 459 | struct vme_slave_resource *slave_image; |
@@ -415,9 +483,17 @@ void vme_slave_free(struct vme_resource *resource) | |||
415 | } | 483 | } |
416 | EXPORT_SYMBOL(vme_slave_free); | 484 | EXPORT_SYMBOL(vme_slave_free); |
417 | 485 | ||
418 | /* | 486 | /** |
419 | * Request a master image with specific attributes, return some unique | 487 | * vme_master_request - Request a VME master window resource. |
420 | * identifier. | 488 | * @vdev: Pointer to VME device struct vme_dev assigned to driver instance. |
489 | * @address: Required VME address space. | ||
490 | * @cycle: Required VME data transfer cycle type. | ||
491 | * @dwidth: Required VME data transfer width. | ||
492 | * | ||
493 | * Request use of a VME window resource capable of being set for the requested | ||
494 | * address space, data transfer cycle and width. | ||
495 | * | ||
496 | * Return: Pointer to VME resource on success, NULL on failure. | ||
421 | */ | 497 | */ |
422 | struct vme_resource *vme_master_request(struct vme_dev *vdev, u32 address, | 498 | struct vme_resource *vme_master_request(struct vme_dev *vdev, u32 address, |
423 | u32 cycle, u32 dwidth) | 499 | u32 cycle, u32 dwidth) |
@@ -486,6 +562,23 @@ err_bus: | |||
486 | } | 562 | } |
487 | EXPORT_SYMBOL(vme_master_request); | 563 | EXPORT_SYMBOL(vme_master_request); |
488 | 564 | ||
565 | /** | ||
566 | * vme_master_set - Set VME master window configuration. | ||
567 | * @resource: Pointer to VME master resource. | ||
568 | * @enabled: State to which the window should be configured. | ||
569 | * @vme_base: Base address for the window. | ||
570 | * @size: Size of the VME window. | ||
571 | * @aspace: VME address space for the VME window. | ||
572 | * @cycle: VME data transfer cycle type for the VME window. | ||
573 | * @dwidth: VME data transfer width for the VME window. | ||
574 | * | ||
575 | * Set configuration for provided VME master window. | ||
576 | * | ||
577 | * Return: Zero on success, -EINVAL if operation is not supported on this | ||
578 | * device, if an invalid resource has been provided or invalid | ||
579 | * attributes are provided. Hardware specific errors may also be | ||
580 | * returned. | ||
581 | */ | ||
489 | int vme_master_set(struct vme_resource *resource, int enabled, | 582 | int vme_master_set(struct vme_resource *resource, int enabled, |
490 | unsigned long long vme_base, unsigned long long size, u32 aspace, | 583 | unsigned long long vme_base, unsigned long long size, u32 aspace, |
491 | u32 cycle, u32 dwidth) | 584 | u32 cycle, u32 dwidth) |
@@ -522,6 +615,21 @@ int vme_master_set(struct vme_resource *resource, int enabled, | |||
522 | } | 615 | } |
523 | EXPORT_SYMBOL(vme_master_set); | 616 | EXPORT_SYMBOL(vme_master_set); |
524 | 617 | ||
618 | /** | ||
619 | * vme_master_get - Retrieve VME master window configuration. | ||
620 | * @resource: Pointer to VME master resource. | ||
621 | * @enabled: Pointer to variable for storing state. | ||
622 | * @vme_base: Pointer to variable for storing window base address. | ||
623 | * @size: Pointer to variable for storing window size. | ||
624 | * @aspace: Pointer to variable for storing VME address space. | ||
625 | * @cycle: Pointer to variable for storing VME data transfer cycle type. | ||
626 | * @dwidth: Pointer to variable for storing VME data transfer width. | ||
627 | * | ||
628 | * Return configuration for provided VME master window. | ||
629 | * | ||
630 | * Return: Zero on success, -EINVAL if operation is not supported on this | ||
631 | * device or if an invalid resource has been provided. | ||
632 | */ | ||
525 | int vme_master_get(struct vme_resource *resource, int *enabled, | 633 | int vme_master_get(struct vme_resource *resource, int *enabled, |
526 | unsigned long long *vme_base, unsigned long long *size, u32 *aspace, | 634 | unsigned long long *vme_base, unsigned long long *size, u32 *aspace, |
527 | u32 *cycle, u32 *dwidth) | 635 | u32 *cycle, u32 *dwidth) |
@@ -546,8 +654,20 @@ int vme_master_get(struct vme_resource *resource, int *enabled, | |||
546 | } | 654 | } |
547 | EXPORT_SYMBOL(vme_master_get); | 655 | EXPORT_SYMBOL(vme_master_get); |
548 | 656 | ||
549 | /* | 657 | /** |
550 | * Read data out of VME space into a buffer. | 658 | * vme_master_write - Read data from VME space into a buffer. |
659 | * @resource: Pointer to VME master resource. | ||
660 | * @buf: Pointer to buffer where data should be transferred. | ||
661 | * @count: Number of bytes to transfer. | ||
662 | * @offset: Offset into VME master window at which to start transfer. | ||
663 | * | ||
664 | * Perform read of count bytes of data from location on VME bus which maps into | ||
665 | * the VME master window at offset to buf. | ||
666 | * | ||
667 | * Return: Number of bytes read, -EINVAL if resource is not a VME master | ||
668 | * resource or read operation is not supported. -EFAULT returned if | ||
669 | * invalid offset is provided. Hardware specific errors may also be | ||
670 | * returned. | ||
551 | */ | 671 | */ |
552 | ssize_t vme_master_read(struct vme_resource *resource, void *buf, size_t count, | 672 | ssize_t vme_master_read(struct vme_resource *resource, void *buf, size_t count, |
553 | loff_t offset) | 673 | loff_t offset) |
@@ -583,8 +703,20 @@ ssize_t vme_master_read(struct vme_resource *resource, void *buf, size_t count, | |||
583 | } | 703 | } |
584 | EXPORT_SYMBOL(vme_master_read); | 704 | EXPORT_SYMBOL(vme_master_read); |
585 | 705 | ||
586 | /* | 706 | /** |
587 | * Write data out to VME space from a buffer. | 707 | * vme_master_write - Write data out to VME space from a buffer. |
708 | * @resource: Pointer to VME master resource. | ||
709 | * @buf: Pointer to buffer holding data to transfer. | ||
710 | * @count: Number of bytes to transfer. | ||
711 | * @offset: Offset into VME master window at which to start transfer. | ||
712 | * | ||
713 | * Perform write of count bytes of data from buf to location on VME bus which | ||
714 | * maps into the VME master window at offset. | ||
715 | * | ||
716 | * Return: Number of bytes written, -EINVAL if resource is not a VME master | ||
717 | * resource or write operation is not supported. -EFAULT returned if | ||
718 | * invalid offset is provided. Hardware specific errors may also be | ||
719 | * returned. | ||
588 | */ | 720 | */ |
589 | ssize_t vme_master_write(struct vme_resource *resource, void *buf, | 721 | ssize_t vme_master_write(struct vme_resource *resource, void *buf, |
590 | size_t count, loff_t offset) | 722 | size_t count, loff_t offset) |
@@ -619,8 +751,24 @@ ssize_t vme_master_write(struct vme_resource *resource, void *buf, | |||
619 | } | 751 | } |
620 | EXPORT_SYMBOL(vme_master_write); | 752 | EXPORT_SYMBOL(vme_master_write); |
621 | 753 | ||
622 | /* | 754 | /** |
623 | * Perform RMW cycle to provided location. | 755 | * vme_master_rmw - Perform read-modify-write cycle. |
756 | * @resource: Pointer to VME master resource. | ||
757 | * @mask: Bits to be compared and swapped in operation. | ||
758 | * @compare: Bits to be compared with data read from offset. | ||
759 | * @swap: Bits to be swapped in data read from offset. | ||
760 | * @offset: Offset into VME master window at which to perform operation. | ||
761 | * | ||
762 | * Perform read-modify-write cycle on provided location: | ||
763 | * - Location on VME bus is read. | ||
764 | * - Bits selected by mask are compared with compare. | ||
765 | * - Where a selected bit matches that in compare and are selected in swap, | ||
766 | * the bit is swapped. | ||
767 | * - Result written back to location on VME bus. | ||
768 | * | ||
769 | * Return: Bytes written on success, -EINVAL if resource is not a VME master | ||
770 | * resource or RMW operation is not supported. Hardware specific | ||
771 | * errors may also be returned. | ||
624 | */ | 772 | */ |
625 | unsigned int vme_master_rmw(struct vme_resource *resource, unsigned int mask, | 773 | unsigned int vme_master_rmw(struct vme_resource *resource, unsigned int mask, |
626 | unsigned int compare, unsigned int swap, loff_t offset) | 774 | unsigned int compare, unsigned int swap, loff_t offset) |
@@ -644,6 +792,17 @@ unsigned int vme_master_rmw(struct vme_resource *resource, unsigned int mask, | |||
644 | } | 792 | } |
645 | EXPORT_SYMBOL(vme_master_rmw); | 793 | EXPORT_SYMBOL(vme_master_rmw); |
646 | 794 | ||
795 | /** | ||
796 | * vme_master_mmap - Mmap region of VME master window. | ||
797 | * @resource: Pointer to VME master resource. | ||
798 | * @vma: Pointer to definition of user mapping. | ||
799 | * | ||
800 | * Memory map a region of the VME master window into user space. | ||
801 | * | ||
802 | * Return: Zero on success, -EINVAL if resource is not a VME master | ||
803 | * resource or -EFAULT if map exceeds window size. Other generic mmap | ||
804 | * errors may also be returned. | ||
805 | */ | ||
647 | int vme_master_mmap(struct vme_resource *resource, struct vm_area_struct *vma) | 806 | int vme_master_mmap(struct vme_resource *resource, struct vm_area_struct *vma) |
648 | { | 807 | { |
649 | struct vme_master_resource *image; | 808 | struct vme_master_resource *image; |
@@ -670,6 +829,12 @@ int vme_master_mmap(struct vme_resource *resource, struct vm_area_struct *vma) | |||
670 | } | 829 | } |
671 | EXPORT_SYMBOL(vme_master_mmap); | 830 | EXPORT_SYMBOL(vme_master_mmap); |
672 | 831 | ||
832 | /** | ||
833 | * vme_master_free - Free VME master window | ||
834 | * @resource: Pointer to VME master resource. | ||
835 | * | ||
836 | * Free the provided master resource so that it may be reallocated. | ||
837 | */ | ||
673 | void vme_master_free(struct vme_resource *resource) | 838 | void vme_master_free(struct vme_resource *resource) |
674 | { | 839 | { |
675 | struct vme_master_resource *master_image; | 840 | struct vme_master_resource *master_image; |
@@ -699,9 +864,15 @@ void vme_master_free(struct vme_resource *resource) | |||
699 | } | 864 | } |
700 | EXPORT_SYMBOL(vme_master_free); | 865 | EXPORT_SYMBOL(vme_master_free); |
701 | 866 | ||
702 | /* | 867 | /** |
703 | * Request a DMA controller with specific attributes, return some unique | 868 | * vme_dma_request - Request a DMA controller. |
704 | * identifier. | 869 | * @vdev: Pointer to VME device struct vme_dev assigned to driver instance. |
870 | * @route: Required src/destination combination. | ||
871 | * | ||
872 | * Request a VME DMA controller with capability to perform transfers bewteen | ||
873 | * requested source/destination combination. | ||
874 | * | ||
875 | * Return: Pointer to VME DMA resource on success, NULL on failure. | ||
705 | */ | 876 | */ |
706 | struct vme_resource *vme_dma_request(struct vme_dev *vdev, u32 route) | 877 | struct vme_resource *vme_dma_request(struct vme_dev *vdev, u32 route) |
707 | { | 878 | { |
@@ -768,8 +939,15 @@ err_bus: | |||
768 | } | 939 | } |
769 | EXPORT_SYMBOL(vme_dma_request); | 940 | EXPORT_SYMBOL(vme_dma_request); |
770 | 941 | ||
771 | /* | 942 | /** |
772 | * Start new list | 943 | * vme_new_dma_list - Create new VME DMA list. |
944 | * @resource: Pointer to VME DMA resource. | ||
945 | * | ||
946 | * Create a new VME DMA list. It is the responsibility of the user to free | ||
947 | * the list once it is no longer required with vme_dma_list_free(). | ||
948 | * | ||
949 | * Return: Pointer to new VME DMA list, NULL on allocation failure or invalid | ||
950 | * VME DMA resource. | ||
773 | */ | 951 | */ |
774 | struct vme_dma_list *vme_new_dma_list(struct vme_resource *resource) | 952 | struct vme_dma_list *vme_new_dma_list(struct vme_resource *resource) |
775 | { | 953 | { |
@@ -796,8 +974,16 @@ struct vme_dma_list *vme_new_dma_list(struct vme_resource *resource) | |||
796 | } | 974 | } |
797 | EXPORT_SYMBOL(vme_new_dma_list); | 975 | EXPORT_SYMBOL(vme_new_dma_list); |
798 | 976 | ||
799 | /* | 977 | /** |
800 | * Create "Pattern" type attributes | 978 | * vme_dma_pattern_attribute - Create "Pattern" type VME DMA list attribute. |
979 | * @pattern: Value to use used as pattern | ||
980 | * @type: Type of pattern to be written. | ||
981 | * | ||
982 | * Create VME DMA list attribute for pattern generation. It is the | ||
983 | * responsibility of the user to free used attributes using | ||
984 | * vme_dma_free_attribute(). | ||
985 | * | ||
986 | * Return: Pointer to VME DMA attribute, NULL on failure. | ||
801 | */ | 987 | */ |
802 | struct vme_dma_attr *vme_dma_pattern_attribute(u32 pattern, u32 type) | 988 | struct vme_dma_attr *vme_dma_pattern_attribute(u32 pattern, u32 type) |
803 | { | 989 | { |
@@ -831,8 +1017,15 @@ err_attr: | |||
831 | } | 1017 | } |
832 | EXPORT_SYMBOL(vme_dma_pattern_attribute); | 1018 | EXPORT_SYMBOL(vme_dma_pattern_attribute); |
833 | 1019 | ||
834 | /* | 1020 | /** |
835 | * Create "PCI" type attributes | 1021 | * vme_dma_pci_attribute - Create "PCI" type VME DMA list attribute. |
1022 | * @address: PCI base address for DMA transfer. | ||
1023 | * | ||
1024 | * Create VME DMA list attribute pointing to a location on PCI for DMA | ||
1025 | * transfers. It is the responsibility of the user to free used attributes | ||
1026 | * using vme_dma_free_attribute(). | ||
1027 | * | ||
1028 | * Return: Pointer to VME DMA attribute, NULL on failure. | ||
836 | */ | 1029 | */ |
837 | struct vme_dma_attr *vme_dma_pci_attribute(dma_addr_t address) | 1030 | struct vme_dma_attr *vme_dma_pci_attribute(dma_addr_t address) |
838 | { | 1031 | { |
@@ -869,8 +1062,18 @@ err_attr: | |||
869 | } | 1062 | } |
870 | EXPORT_SYMBOL(vme_dma_pci_attribute); | 1063 | EXPORT_SYMBOL(vme_dma_pci_attribute); |
871 | 1064 | ||
872 | /* | 1065 | /** |
873 | * Create "VME" type attributes | 1066 | * vme_dma_vme_attribute - Create "VME" type VME DMA list attribute. |
1067 | * @address: VME base address for DMA transfer. | ||
1068 | * @aspace: VME address space to use for DMA transfer. | ||
1069 | * @cycle: VME bus cycle to use for DMA transfer. | ||
1070 | * @dwidth: VME data width to use for DMA transfer. | ||
1071 | * | ||
1072 | * Create VME DMA list attribute pointing to a location on the VME bus for DMA | ||
1073 | * transfers. It is the responsibility of the user to free used attributes | ||
1074 | * using vme_dma_free_attribute(). | ||
1075 | * | ||
1076 | * Return: Pointer to VME DMA attribute, NULL on failure. | ||
874 | */ | 1077 | */ |
875 | struct vme_dma_attr *vme_dma_vme_attribute(unsigned long long address, | 1078 | struct vme_dma_attr *vme_dma_vme_attribute(unsigned long long address, |
876 | u32 aspace, u32 cycle, u32 dwidth) | 1079 | u32 aspace, u32 cycle, u32 dwidth) |
@@ -908,8 +1111,12 @@ err_attr: | |||
908 | } | 1111 | } |
909 | EXPORT_SYMBOL(vme_dma_vme_attribute); | 1112 | EXPORT_SYMBOL(vme_dma_vme_attribute); |
910 | 1113 | ||
911 | /* | 1114 | /** |
912 | * Free attribute | 1115 | * vme_dma_free_attribute - Free DMA list attribute. |
1116 | * @attributes: Pointer to DMA list attribute. | ||
1117 | * | ||
1118 | * Free VME DMA list attribute. VME DMA list attributes can be safely freed | ||
1119 | * once vme_dma_list_add() has returned. | ||
913 | */ | 1120 | */ |
914 | void vme_dma_free_attribute(struct vme_dma_attr *attributes) | 1121 | void vme_dma_free_attribute(struct vme_dma_attr *attributes) |
915 | { | 1122 | { |
@@ -918,6 +1125,23 @@ void vme_dma_free_attribute(struct vme_dma_attr *attributes) | |||
918 | } | 1125 | } |
919 | EXPORT_SYMBOL(vme_dma_free_attribute); | 1126 | EXPORT_SYMBOL(vme_dma_free_attribute); |
920 | 1127 | ||
1128 | /** | ||
1129 | * vme_dma_list_add - Add enty to a VME DMA list. | ||
1130 | * @list: Pointer to VME list. | ||
1131 | * @src: Pointer to DMA list attribute to use as source. | ||
1132 | * @dest: Pointer to DMA list attribute to use as destination. | ||
1133 | * @count: Number of bytes to transfer. | ||
1134 | * | ||
1135 | * Add an entry to the provided VME DMA list. Entry requires pointers to source | ||
1136 | * and destination DMA attributes and a count. | ||
1137 | * | ||
1138 | * Please note, the attributes supported as source and destinations for | ||
1139 | * transfers are hardware dependent. | ||
1140 | * | ||
1141 | * Return: Zero on success, -EINVAL if operation is not supported on this | ||
1142 | * device or if the link list has already been submitted for execution. | ||
1143 | * Hardware specific errors also possible. | ||
1144 | */ | ||
921 | int vme_dma_list_add(struct vme_dma_list *list, struct vme_dma_attr *src, | 1145 | int vme_dma_list_add(struct vme_dma_list *list, struct vme_dma_attr *src, |
922 | struct vme_dma_attr *dest, size_t count) | 1146 | struct vme_dma_attr *dest, size_t count) |
923 | { | 1147 | { |
@@ -942,6 +1166,16 @@ int vme_dma_list_add(struct vme_dma_list *list, struct vme_dma_attr *src, | |||
942 | } | 1166 | } |
943 | EXPORT_SYMBOL(vme_dma_list_add); | 1167 | EXPORT_SYMBOL(vme_dma_list_add); |
944 | 1168 | ||
1169 | /** | ||
1170 | * vme_dma_list_exec - Queue a VME DMA list for execution. | ||
1171 | * @list: Pointer to VME list. | ||
1172 | * | ||
1173 | * Queue the provided VME DMA list for execution. The call will return once the | ||
1174 | * list has been executed. | ||
1175 | * | ||
1176 | * Return: Zero on success, -EINVAL if operation is not supported on this | ||
1177 | * device. Hardware specific errors also possible. | ||
1178 | */ | ||
945 | int vme_dma_list_exec(struct vme_dma_list *list) | 1179 | int vme_dma_list_exec(struct vme_dma_list *list) |
946 | { | 1180 | { |
947 | struct vme_bridge *bridge = list->parent->parent; | 1181 | struct vme_bridge *bridge = list->parent->parent; |
@@ -962,6 +1196,15 @@ int vme_dma_list_exec(struct vme_dma_list *list) | |||
962 | } | 1196 | } |
963 | EXPORT_SYMBOL(vme_dma_list_exec); | 1197 | EXPORT_SYMBOL(vme_dma_list_exec); |
964 | 1198 | ||
1199 | /** | ||
1200 | * vme_dma_list_free - Free a VME DMA list. | ||
1201 | * @list: Pointer to VME list. | ||
1202 | * | ||
1203 | * Free the provided DMA list and all its entries. | ||
1204 | * | ||
1205 | * Return: Zero on success, -EINVAL on invalid VME resource, -EBUSY if resource | ||
1206 | * is still in use. Hardware specific errors also possible. | ||
1207 | */ | ||
965 | int vme_dma_list_free(struct vme_dma_list *list) | 1208 | int vme_dma_list_free(struct vme_dma_list *list) |
966 | { | 1209 | { |
967 | struct vme_bridge *bridge = list->parent->parent; | 1210 | struct vme_bridge *bridge = list->parent->parent; |
@@ -994,6 +1237,15 @@ int vme_dma_list_free(struct vme_dma_list *list) | |||
994 | } | 1237 | } |
995 | EXPORT_SYMBOL(vme_dma_list_free); | 1238 | EXPORT_SYMBOL(vme_dma_list_free); |
996 | 1239 | ||
1240 | /** | ||
1241 | * vme_dma_free - Free a VME DMA resource. | ||
1242 | * @resource: Pointer to VME DMA resource. | ||
1243 | * | ||
1244 | * Free the provided DMA resource so that it may be reallocated. | ||
1245 | * | ||
1246 | * Return: Zero on success, -EINVAL on invalid VME resource, -EBUSY if resource | ||
1247 | * is still active. | ||
1248 | */ | ||
997 | int vme_dma_free(struct vme_resource *resource) | 1249 | int vme_dma_free(struct vme_resource *resource) |
998 | { | 1250 | { |
999 | struct vme_dma_resource *ctrlr; | 1251 | struct vme_dma_resource *ctrlr; |
@@ -1099,6 +1351,22 @@ void vme_irq_handler(struct vme_bridge *bridge, int level, int statid) | |||
1099 | } | 1351 | } |
1100 | EXPORT_SYMBOL(vme_irq_handler); | 1352 | EXPORT_SYMBOL(vme_irq_handler); |
1101 | 1353 | ||
1354 | /** | ||
1355 | * vme_irq_request - Request a specific VME interrupt. | ||
1356 | * @vdev: Pointer to VME device struct vme_dev assigned to driver instance. | ||
1357 | * @level: Interrupt priority being requested. | ||
1358 | * @statid: Interrupt vector being requested. | ||
1359 | * @callback: Pointer to callback function called when VME interrupt/vector | ||
1360 | * received. | ||
1361 | * @priv_data: Generic pointer that will be passed to the callback function. | ||
1362 | * | ||
1363 | * Request callback to be attached as a handler for VME interrupts with provided | ||
1364 | * level and statid. | ||
1365 | * | ||
1366 | * Return: Zero on success, -EINVAL on invalid vme device, level or if the | ||
1367 | * function is not supported, -EBUSY if the level/statid combination is | ||
1368 | * already in use. Hardware specific errors also possible. | ||
1369 | */ | ||
1102 | int vme_irq_request(struct vme_dev *vdev, int level, int statid, | 1370 | int vme_irq_request(struct vme_dev *vdev, int level, int statid, |
1103 | void (*callback)(int, int, void *), | 1371 | void (*callback)(int, int, void *), |
1104 | void *priv_data) | 1372 | void *priv_data) |
@@ -1142,6 +1410,14 @@ int vme_irq_request(struct vme_dev *vdev, int level, int statid, | |||
1142 | } | 1410 | } |
1143 | EXPORT_SYMBOL(vme_irq_request); | 1411 | EXPORT_SYMBOL(vme_irq_request); |
1144 | 1412 | ||
1413 | /** | ||
1414 | * vme_irq_free - Free a VME interrupt. | ||
1415 | * @vdev: Pointer to VME device struct vme_dev assigned to driver instance. | ||
1416 | * @level: Interrupt priority of interrupt being freed. | ||
1417 | * @statid: Interrupt vector of interrupt being freed. | ||
1418 | * | ||
1419 | * Remove previously attached callback from VME interrupt priority/vector. | ||
1420 | */ | ||
1145 | void vme_irq_free(struct vme_dev *vdev, int level, int statid) | 1421 | void vme_irq_free(struct vme_dev *vdev, int level, int statid) |
1146 | { | 1422 | { |
1147 | struct vme_bridge *bridge; | 1423 | struct vme_bridge *bridge; |
@@ -1177,6 +1453,18 @@ void vme_irq_free(struct vme_dev *vdev, int level, int statid) | |||
1177 | } | 1453 | } |
1178 | EXPORT_SYMBOL(vme_irq_free); | 1454 | EXPORT_SYMBOL(vme_irq_free); |
1179 | 1455 | ||
1456 | /** | ||
1457 | * vme_irq_generate - Generate VME interrupt. | ||
1458 | * @vdev: Pointer to VME device struct vme_dev assigned to driver instance. | ||
1459 | * @level: Interrupt priority at which to assert the interrupt. | ||
1460 | * @statid: Interrupt vector to associate with the interrupt. | ||
1461 | * | ||
1462 | * Generate a VME interrupt of the provided level and with the provided | ||
1463 | * statid. | ||
1464 | * | ||
1465 | * Return: Zero on success, -EINVAL on invalid vme device, level or if the | ||
1466 | * function is not supported. Hardware specific errors also possible. | ||
1467 | */ | ||
1180 | int vme_irq_generate(struct vme_dev *vdev, int level, int statid) | 1468 | int vme_irq_generate(struct vme_dev *vdev, int level, int statid) |
1181 | { | 1469 | { |
1182 | struct vme_bridge *bridge; | 1470 | struct vme_bridge *bridge; |
@@ -1201,8 +1489,15 @@ int vme_irq_generate(struct vme_dev *vdev, int level, int statid) | |||
1201 | } | 1489 | } |
1202 | EXPORT_SYMBOL(vme_irq_generate); | 1490 | EXPORT_SYMBOL(vme_irq_generate); |
1203 | 1491 | ||
1204 | /* | 1492 | /** |
1205 | * Request the location monitor, return resource or NULL | 1493 | * vme_lm_request - Request a VME location monitor |
1494 | * @vdev: Pointer to VME device struct vme_dev assigned to driver instance. | ||
1495 | * | ||
1496 | * Allocate a location monitor resource to the driver. A location monitor | ||
1497 | * allows the driver to monitor accesses to a contiguous number of | ||
1498 | * addresses on the VME bus. | ||
1499 | * | ||
1500 | * Return: Pointer to a VME resource on success or NULL on failure. | ||
1206 | */ | 1501 | */ |
1207 | struct vme_resource *vme_lm_request(struct vme_dev *vdev) | 1502 | struct vme_resource *vme_lm_request(struct vme_dev *vdev) |
1208 | { | 1503 | { |
@@ -1218,7 +1513,7 @@ struct vme_resource *vme_lm_request(struct vme_dev *vdev) | |||
1218 | goto err_bus; | 1513 | goto err_bus; |
1219 | } | 1514 | } |
1220 | 1515 | ||
1221 | /* Loop through DMA resources */ | 1516 | /* Loop through LM resources */ |
1222 | list_for_each(lm_pos, &bridge->lm_resources) { | 1517 | list_for_each(lm_pos, &bridge->lm_resources) { |
1223 | lm = list_entry(lm_pos, | 1518 | lm = list_entry(lm_pos, |
1224 | struct vme_lm_resource, list); | 1519 | struct vme_lm_resource, list); |
@@ -1264,6 +1559,17 @@ err_bus: | |||
1264 | } | 1559 | } |
1265 | EXPORT_SYMBOL(vme_lm_request); | 1560 | EXPORT_SYMBOL(vme_lm_request); |
1266 | 1561 | ||
1562 | /** | ||
1563 | * vme_lm_count - Determine number of VME Addresses monitored | ||
1564 | * @resource: Pointer to VME location monitor resource. | ||
1565 | * | ||
1566 | * The number of contiguous addresses monitored is hardware dependent. | ||
1567 | * Return the number of contiguous addresses monitored by the | ||
1568 | * location monitor. | ||
1569 | * | ||
1570 | * Return: Count of addresses monitored or -EINVAL when provided with an | ||
1571 | * invalid location monitor resource. | ||
1572 | */ | ||
1267 | int vme_lm_count(struct vme_resource *resource) | 1573 | int vme_lm_count(struct vme_resource *resource) |
1268 | { | 1574 | { |
1269 | struct vme_lm_resource *lm; | 1575 | struct vme_lm_resource *lm; |
@@ -1279,6 +1585,20 @@ int vme_lm_count(struct vme_resource *resource) | |||
1279 | } | 1585 | } |
1280 | EXPORT_SYMBOL(vme_lm_count); | 1586 | EXPORT_SYMBOL(vme_lm_count); |
1281 | 1587 | ||
1588 | /** | ||
1589 | * vme_lm_set - Configure location monitor | ||
1590 | * @resource: Pointer to VME location monitor resource. | ||
1591 | * @lm_base: Base address to monitor. | ||
1592 | * @aspace: VME address space to monitor. | ||
1593 | * @cycle: VME bus cycle type to monitor. | ||
1594 | * | ||
1595 | * Set the base address, address space and cycle type of accesses to be | ||
1596 | * monitored by the location monitor. | ||
1597 | * | ||
1598 | * Return: Zero on success, -EINVAL when provided with an invalid location | ||
1599 | * monitor resource or function is not supported. Hardware specific | ||
1600 | * errors may also be returned. | ||
1601 | */ | ||
1282 | int vme_lm_set(struct vme_resource *resource, unsigned long long lm_base, | 1602 | int vme_lm_set(struct vme_resource *resource, unsigned long long lm_base, |
1283 | u32 aspace, u32 cycle) | 1603 | u32 aspace, u32 cycle) |
1284 | { | 1604 | { |
@@ -1301,6 +1621,20 @@ int vme_lm_set(struct vme_resource *resource, unsigned long long lm_base, | |||
1301 | } | 1621 | } |
1302 | EXPORT_SYMBOL(vme_lm_set); | 1622 | EXPORT_SYMBOL(vme_lm_set); |
1303 | 1623 | ||
1624 | /** | ||
1625 | * vme_lm_get - Retrieve location monitor settings | ||
1626 | * @resource: Pointer to VME location monitor resource. | ||
1627 | * @lm_base: Pointer used to output the base address monitored. | ||
1628 | * @aspace: Pointer used to output the address space monitored. | ||
1629 | * @cycle: Pointer used to output the VME bus cycle type monitored. | ||
1630 | * | ||
1631 | * Retrieve the base address, address space and cycle type of accesses to | ||
1632 | * be monitored by the location monitor. | ||
1633 | * | ||
1634 | * Return: Zero on success, -EINVAL when provided with an invalid location | ||
1635 | * monitor resource or function is not supported. Hardware specific | ||
1636 | * errors may also be returned. | ||
1637 | */ | ||
1304 | int vme_lm_get(struct vme_resource *resource, unsigned long long *lm_base, | 1638 | int vme_lm_get(struct vme_resource *resource, unsigned long long *lm_base, |
1305 | u32 *aspace, u32 *cycle) | 1639 | u32 *aspace, u32 *cycle) |
1306 | { | 1640 | { |
@@ -1323,6 +1657,21 @@ int vme_lm_get(struct vme_resource *resource, unsigned long long *lm_base, | |||
1323 | } | 1657 | } |
1324 | EXPORT_SYMBOL(vme_lm_get); | 1658 | EXPORT_SYMBOL(vme_lm_get); |
1325 | 1659 | ||
1660 | /** | ||
1661 | * vme_lm_attach - Provide callback for location monitor address | ||
1662 | * @resource: Pointer to VME location monitor resource. | ||
1663 | * @monitor: Offset to which callback should be attached. | ||
1664 | * @callback: Pointer to callback function called when triggered. | ||
1665 | * @data: Generic pointer that will be passed to the callback function. | ||
1666 | * | ||
1667 | * Attach a callback to the specificed offset into the location monitors | ||
1668 | * monitored addresses. A generic pointer is provided to allow data to be | ||
1669 | * passed to the callback when called. | ||
1670 | * | ||
1671 | * Return: Zero on success, -EINVAL when provided with an invalid location | ||
1672 | * monitor resource or function is not supported. Hardware specific | ||
1673 | * errors may also be returned. | ||
1674 | */ | ||
1326 | int vme_lm_attach(struct vme_resource *resource, int monitor, | 1675 | int vme_lm_attach(struct vme_resource *resource, int monitor, |
1327 | void (*callback)(void *), void *data) | 1676 | void (*callback)(void *), void *data) |
1328 | { | 1677 | { |
@@ -1345,6 +1694,18 @@ int vme_lm_attach(struct vme_resource *resource, int monitor, | |||
1345 | } | 1694 | } |
1346 | EXPORT_SYMBOL(vme_lm_attach); | 1695 | EXPORT_SYMBOL(vme_lm_attach); |
1347 | 1696 | ||
1697 | /** | ||
1698 | * vme_lm_detach - Remove callback for location monitor address | ||
1699 | * @resource: Pointer to VME location monitor resource. | ||
1700 | * @monitor: Offset to which callback should be removed. | ||
1701 | * | ||
1702 | * Remove the callback associated with the specificed offset into the | ||
1703 | * location monitors monitored addresses. | ||
1704 | * | ||
1705 | * Return: Zero on success, -EINVAL when provided with an invalid location | ||
1706 | * monitor resource or function is not supported. Hardware specific | ||
1707 | * errors may also be returned. | ||
1708 | */ | ||
1348 | int vme_lm_detach(struct vme_resource *resource, int monitor) | 1709 | int vme_lm_detach(struct vme_resource *resource, int monitor) |
1349 | { | 1710 | { |
1350 | struct vme_bridge *bridge = find_bridge(resource); | 1711 | struct vme_bridge *bridge = find_bridge(resource); |
@@ -1366,6 +1727,18 @@ int vme_lm_detach(struct vme_resource *resource, int monitor) | |||
1366 | } | 1727 | } |
1367 | EXPORT_SYMBOL(vme_lm_detach); | 1728 | EXPORT_SYMBOL(vme_lm_detach); |
1368 | 1729 | ||
1730 | /** | ||
1731 | * vme_lm_free - Free allocated VME location monitor | ||
1732 | * @resource: Pointer to VME location monitor resource. | ||
1733 | * | ||
1734 | * Free allocation of a VME location monitor. | ||
1735 | * | ||
1736 | * WARNING: This function currently expects that any callbacks that have | ||
1737 | * been attached to the location monitor have been removed. | ||
1738 | * | ||
1739 | * Return: Zero on success, -EINVAL when provided with an invalid location | ||
1740 | * monitor resource. | ||
1741 | */ | ||
1369 | void vme_lm_free(struct vme_resource *resource) | 1742 | void vme_lm_free(struct vme_resource *resource) |
1370 | { | 1743 | { |
1371 | struct vme_lm_resource *lm; | 1744 | struct vme_lm_resource *lm; |
@@ -1392,6 +1765,16 @@ void vme_lm_free(struct vme_resource *resource) | |||
1392 | } | 1765 | } |
1393 | EXPORT_SYMBOL(vme_lm_free); | 1766 | EXPORT_SYMBOL(vme_lm_free); |
1394 | 1767 | ||
1768 | /** | ||
1769 | * vme_slot_num - Retrieve slot ID | ||
1770 | * @vdev: Pointer to VME device struct vme_dev assigned to driver instance. | ||
1771 | * | ||
1772 | * Retrieve the slot ID associated with the provided VME device. | ||
1773 | * | ||
1774 | * Return: The slot ID on success, -EINVAL if VME bridge cannot be determined | ||
1775 | * or the function is not supported. Hardware specific errors may also | ||
1776 | * be returned. | ||
1777 | */ | ||
1395 | int vme_slot_num(struct vme_dev *vdev) | 1778 | int vme_slot_num(struct vme_dev *vdev) |
1396 | { | 1779 | { |
1397 | struct vme_bridge *bridge; | 1780 | struct vme_bridge *bridge; |
@@ -1411,6 +1794,15 @@ int vme_slot_num(struct vme_dev *vdev) | |||
1411 | } | 1794 | } |
1412 | EXPORT_SYMBOL(vme_slot_num); | 1795 | EXPORT_SYMBOL(vme_slot_num); |
1413 | 1796 | ||
1797 | /** | ||
1798 | * vme_bus_num - Retrieve bus number | ||
1799 | * @vdev: Pointer to VME device struct vme_dev assigned to driver instance. | ||
1800 | * | ||
1801 | * Retrieve the bus enumeration associated with the provided VME device. | ||
1802 | * | ||
1803 | * Return: The bus number on success, -EINVAL if VME bridge cannot be | ||
1804 | * determined. | ||
1805 | */ | ||
1414 | int vme_bus_num(struct vme_dev *vdev) | 1806 | int vme_bus_num(struct vme_dev *vdev) |
1415 | { | 1807 | { |
1416 | struct vme_bridge *bridge; | 1808 | struct vme_bridge *bridge; |
@@ -1556,6 +1948,15 @@ static int __vme_register_driver(struct vme_driver *drv, unsigned int ndevs) | |||
1556 | return err; | 1948 | return err; |
1557 | } | 1949 | } |
1558 | 1950 | ||
1951 | /** | ||
1952 | * vme_register_driver - Register a VME driver | ||
1953 | * @drv: Pointer to VME driver structure to register. | ||
1954 | * @ndevs: Maximum number of devices to allow to be enumerated. | ||
1955 | * | ||
1956 | * Register a VME device driver with the VME subsystem. | ||
1957 | * | ||
1958 | * Return: Zero on success, error value on registration failure. | ||
1959 | */ | ||
1559 | int vme_register_driver(struct vme_driver *drv, unsigned int ndevs) | 1960 | int vme_register_driver(struct vme_driver *drv, unsigned int ndevs) |
1560 | { | 1961 | { |
1561 | int err; | 1962 | int err; |
@@ -1576,6 +1977,12 @@ int vme_register_driver(struct vme_driver *drv, unsigned int ndevs) | |||
1576 | } | 1977 | } |
1577 | EXPORT_SYMBOL(vme_register_driver); | 1978 | EXPORT_SYMBOL(vme_register_driver); |
1578 | 1979 | ||
1980 | /** | ||
1981 | * vme_unregister_driver - Unregister a VME driver | ||
1982 | * @drv: Pointer to VME driver structure to unregister. | ||
1983 | * | ||
1984 | * Unregister a VME device driver from the VME subsystem. | ||
1985 | */ | ||
1579 | void vme_unregister_driver(struct vme_driver *drv) | 1986 | void vme_unregister_driver(struct vme_driver *drv) |
1580 | { | 1987 | { |
1581 | struct vme_dev *dev, *dev_tmp; | 1988 | struct vme_dev *dev, *dev_tmp; |
diff --git a/drivers/w1/slaves/Kconfig b/drivers/w1/slaves/Kconfig index 0ef9f2663dbd..fb68465908f2 100644 --- a/drivers/w1/slaves/Kconfig +++ b/drivers/w1/slaves/Kconfig | |||
@@ -86,6 +86,12 @@ config W1_SLAVE_DS2433_CRC | |||
86 | Each block has 30 bytes of data and a two byte CRC16. | 86 | Each block has 30 bytes of data and a two byte CRC16. |
87 | Full block writes are only allowed if the CRC is valid. | 87 | Full block writes are only allowed if the CRC is valid. |
88 | 88 | ||
89 | config W1_SLAVE_DS2438 | ||
90 | tristate "DS2438 Smart Battery Monitor 0x26 family support" | ||
91 | help | ||
92 | Say Y here if you want to use a 1-wire | ||
93 | DS2438 Smart Battery Monitor device support | ||
94 | |||
89 | config W1_SLAVE_DS2760 | 95 | config W1_SLAVE_DS2760 |
90 | tristate "Dallas 2760 battery monitor chip (HP iPAQ & others)" | 96 | tristate "Dallas 2760 battery monitor chip (HP iPAQ & others)" |
91 | help | 97 | help |
diff --git a/drivers/w1/slaves/Makefile b/drivers/w1/slaves/Makefile index b4a358955ef9..54c63e420302 100644 --- a/drivers/w1/slaves/Makefile +++ b/drivers/w1/slaves/Makefile | |||
@@ -11,6 +11,7 @@ obj-$(CONFIG_W1_SLAVE_DS2406) += w1_ds2406.o | |||
11 | obj-$(CONFIG_W1_SLAVE_DS2423) += w1_ds2423.o | 11 | obj-$(CONFIG_W1_SLAVE_DS2423) += w1_ds2423.o |
12 | obj-$(CONFIG_W1_SLAVE_DS2431) += w1_ds2431.o | 12 | obj-$(CONFIG_W1_SLAVE_DS2431) += w1_ds2431.o |
13 | obj-$(CONFIG_W1_SLAVE_DS2433) += w1_ds2433.o | 13 | obj-$(CONFIG_W1_SLAVE_DS2433) += w1_ds2433.o |
14 | obj-$(CONFIG_W1_SLAVE_DS2438) += w1_ds2438.o | ||
14 | obj-$(CONFIG_W1_SLAVE_DS2760) += w1_ds2760.o | 15 | obj-$(CONFIG_W1_SLAVE_DS2760) += w1_ds2760.o |
15 | obj-$(CONFIG_W1_SLAVE_DS2780) += w1_ds2780.o | 16 | obj-$(CONFIG_W1_SLAVE_DS2780) += w1_ds2780.o |
16 | obj-$(CONFIG_W1_SLAVE_DS2781) += w1_ds2781.o | 17 | obj-$(CONFIG_W1_SLAVE_DS2781) += w1_ds2781.o |
diff --git a/drivers/w1/slaves/w1_ds2438.c b/drivers/w1/slaves/w1_ds2438.c new file mode 100644 index 000000000000..5ededb4965e1 --- /dev/null +++ b/drivers/w1/slaves/w1_ds2438.c | |||
@@ -0,0 +1,390 @@ | |||
1 | /* | ||
2 | * 1-Wire implementation for the ds2438 chip | ||
3 | * | ||
4 | * Copyright (c) 2017 Mariusz Bialonczyk <manio@skyboo.net> | ||
5 | * | ||
6 | * This source code is licensed under the GNU General Public License, | ||
7 | * Version 2. See the file COPYING for more details. | ||
8 | */ | ||
9 | |||
10 | #include <linux/kernel.h> | ||
11 | #include <linux/module.h> | ||
12 | #include <linux/device.h> | ||
13 | #include <linux/types.h> | ||
14 | #include <linux/delay.h> | ||
15 | |||
16 | #include "../w1.h" | ||
17 | #include "../w1_family.h" | ||
18 | |||
19 | #define W1_DS2438_RETRIES 3 | ||
20 | |||
21 | /* Memory commands */ | ||
22 | #define W1_DS2438_READ_SCRATCH 0xBE | ||
23 | #define W1_DS2438_WRITE_SCRATCH 0x4E | ||
24 | #define W1_DS2438_COPY_SCRATCH 0x48 | ||
25 | #define W1_DS2438_RECALL_MEMORY 0xB8 | ||
26 | /* Register commands */ | ||
27 | #define W1_DS2438_CONVERT_TEMP 0x44 | ||
28 | #define W1_DS2438_CONVERT_VOLTAGE 0xB4 | ||
29 | |||
30 | #define DS2438_PAGE_SIZE 8 | ||
31 | #define DS2438_ADC_INPUT_VAD 0 | ||
32 | #define DS2438_ADC_INPUT_VDD 1 | ||
33 | #define DS2438_MAX_CONVERSION_TIME 10 /* ms */ | ||
34 | |||
35 | /* Page #0 definitions */ | ||
36 | #define DS2438_STATUS_REG 0x00 /* Status/Configuration Register */ | ||
37 | #define DS2438_STATUS_IAD (1 << 0) /* Current A/D Control Bit */ | ||
38 | #define DS2438_STATUS_CA (1 << 1) /* Current Accumulator Configuration */ | ||
39 | #define DS2438_STATUS_EE (1 << 2) /* Current Accumulator Shadow Selector bit */ | ||
40 | #define DS2438_STATUS_AD (1 << 3) /* Voltage A/D Input Select Bit */ | ||
41 | #define DS2438_STATUS_TB (1 << 4) /* Temperature Busy Flag */ | ||
42 | #define DS2438_STATUS_NVB (1 << 5) /* Nonvolatile Memory Busy Flag */ | ||
43 | #define DS2438_STATUS_ADB (1 << 6) /* A/D Converter Busy Flag */ | ||
44 | |||
45 | #define DS2438_TEMP_LSB 0x01 | ||
46 | #define DS2438_TEMP_MSB 0x02 | ||
47 | #define DS2438_VOLTAGE_LSB 0x03 | ||
48 | #define DS2438_VOLTAGE_MSB 0x04 | ||
49 | #define DS2438_CURRENT_LSB 0x05 | ||
50 | #define DS2438_CURRENT_MSB 0x06 | ||
51 | #define DS2438_THRESHOLD 0x07 | ||
52 | |||
53 | int w1_ds2438_get_page(struct w1_slave *sl, int pageno, u8 *buf) | ||
54 | { | ||
55 | unsigned int retries = W1_DS2438_RETRIES; | ||
56 | u8 w1_buf[2]; | ||
57 | u8 crc; | ||
58 | size_t count; | ||
59 | |||
60 | while (retries--) { | ||
61 | crc = 0; | ||
62 | |||
63 | if (w1_reset_select_slave(sl)) | ||
64 | continue; | ||
65 | w1_buf[0] = W1_DS2438_RECALL_MEMORY; | ||
66 | w1_buf[1] = 0x00; | ||
67 | w1_write_block(sl->master, w1_buf, 2); | ||
68 | |||
69 | if (w1_reset_select_slave(sl)) | ||
70 | continue; | ||
71 | w1_buf[0] = W1_DS2438_READ_SCRATCH; | ||
72 | w1_buf[1] = 0x00; | ||
73 | w1_write_block(sl->master, w1_buf, 2); | ||
74 | |||
75 | count = w1_read_block(sl->master, buf, DS2438_PAGE_SIZE + 1); | ||
76 | if (count == DS2438_PAGE_SIZE + 1) { | ||
77 | crc = w1_calc_crc8(buf, DS2438_PAGE_SIZE); | ||
78 | |||
79 | /* check for correct CRC */ | ||
80 | if ((u8)buf[DS2438_PAGE_SIZE] == crc) | ||
81 | return 0; | ||
82 | } | ||
83 | } | ||
84 | return -1; | ||
85 | } | ||
86 | |||
87 | int w1_ds2438_get_temperature(struct w1_slave *sl, int16_t *temperature) | ||
88 | { | ||
89 | unsigned int retries = W1_DS2438_RETRIES; | ||
90 | u8 w1_buf[DS2438_PAGE_SIZE + 1 /*for CRC*/]; | ||
91 | unsigned int tm = DS2438_MAX_CONVERSION_TIME; | ||
92 | unsigned long sleep_rem; | ||
93 | int ret; | ||
94 | |||
95 | mutex_lock(&sl->master->bus_mutex); | ||
96 | |||
97 | while (retries--) { | ||
98 | if (w1_reset_select_slave(sl)) | ||
99 | continue; | ||
100 | w1_write_8(sl->master, W1_DS2438_CONVERT_TEMP); | ||
101 | |||
102 | mutex_unlock(&sl->master->bus_mutex); | ||
103 | sleep_rem = msleep_interruptible(tm); | ||
104 | if (sleep_rem != 0) { | ||
105 | ret = -1; | ||
106 | goto post_unlock; | ||
107 | } | ||
108 | |||
109 | if (mutex_lock_interruptible(&sl->master->bus_mutex) != 0) { | ||
110 | ret = -1; | ||
111 | goto post_unlock; | ||
112 | } | ||
113 | |||
114 | break; | ||
115 | } | ||
116 | |||
117 | if (w1_ds2438_get_page(sl, 0, w1_buf) == 0) { | ||
118 | *temperature = (((int16_t) w1_buf[DS2438_TEMP_MSB]) << 8) | ((uint16_t) w1_buf[DS2438_TEMP_LSB]); | ||
119 | ret = 0; | ||
120 | } else | ||
121 | ret = -1; | ||
122 | |||
123 | mutex_unlock(&sl->master->bus_mutex); | ||
124 | |||
125 | post_unlock: | ||
126 | return ret; | ||
127 | } | ||
128 | |||
129 | int w1_ds2438_change_config_bit(struct w1_slave *sl, u8 mask, u8 value) | ||
130 | { | ||
131 | unsigned int retries = W1_DS2438_RETRIES; | ||
132 | u8 w1_buf[3]; | ||
133 | u8 status; | ||
134 | int perform_write = 0; | ||
135 | |||
136 | while (retries--) { | ||
137 | if (w1_reset_select_slave(sl)) | ||
138 | continue; | ||
139 | w1_buf[0] = W1_DS2438_RECALL_MEMORY; | ||
140 | w1_buf[1] = 0x00; | ||
141 | w1_write_block(sl->master, w1_buf, 2); | ||
142 | |||
143 | if (w1_reset_select_slave(sl)) | ||
144 | continue; | ||
145 | w1_buf[0] = W1_DS2438_READ_SCRATCH; | ||
146 | w1_buf[1] = 0x00; | ||
147 | w1_write_block(sl->master, w1_buf, 2); | ||
148 | |||
149 | /* reading one byte of result */ | ||
150 | status = w1_read_8(sl->master); | ||
151 | |||
152 | /* if bit0=1, set a value to a mask for easy compare */ | ||
153 | if (value) | ||
154 | value = mask; | ||
155 | |||
156 | if ((status & mask) == value) | ||
157 | return 0; /* already set as requested */ | ||
158 | else { | ||
159 | /* changing bit */ | ||
160 | status ^= mask; | ||
161 | perform_write = 1; | ||
162 | } | ||
163 | break; | ||
164 | } | ||
165 | |||
166 | if (perform_write) { | ||
167 | retries = W1_DS2438_RETRIES; | ||
168 | while (retries--) { | ||
169 | if (w1_reset_select_slave(sl)) | ||
170 | continue; | ||
171 | w1_buf[0] = W1_DS2438_WRITE_SCRATCH; | ||
172 | w1_buf[1] = 0x00; | ||
173 | w1_buf[2] = status; | ||
174 | w1_write_block(sl->master, w1_buf, 3); | ||
175 | |||
176 | if (w1_reset_select_slave(sl)) | ||
177 | continue; | ||
178 | w1_buf[0] = W1_DS2438_COPY_SCRATCH; | ||
179 | w1_buf[1] = 0x00; | ||
180 | w1_write_block(sl->master, w1_buf, 2); | ||
181 | |||
182 | return 0; | ||
183 | } | ||
184 | } | ||
185 | return -1; | ||
186 | } | ||
187 | |||
188 | uint16_t w1_ds2438_get_voltage(struct w1_slave *sl, int adc_input, uint16_t *voltage) | ||
189 | { | ||
190 | unsigned int retries = W1_DS2438_RETRIES; | ||
191 | u8 w1_buf[DS2438_PAGE_SIZE + 1 /*for CRC*/]; | ||
192 | unsigned int tm = DS2438_MAX_CONVERSION_TIME; | ||
193 | unsigned long sleep_rem; | ||
194 | int ret; | ||
195 | |||
196 | mutex_lock(&sl->master->bus_mutex); | ||
197 | |||
198 | if (w1_ds2438_change_config_bit(sl, DS2438_STATUS_AD, adc_input)) { | ||
199 | ret = -1; | ||
200 | goto pre_unlock; | ||
201 | } | ||
202 | |||
203 | while (retries--) { | ||
204 | if (w1_reset_select_slave(sl)) | ||
205 | continue; | ||
206 | w1_write_8(sl->master, W1_DS2438_CONVERT_VOLTAGE); | ||
207 | |||
208 | mutex_unlock(&sl->master->bus_mutex); | ||
209 | sleep_rem = msleep_interruptible(tm); | ||
210 | if (sleep_rem != 0) { | ||
211 | ret = -1; | ||
212 | goto post_unlock; | ||
213 | } | ||
214 | |||
215 | if (mutex_lock_interruptible(&sl->master->bus_mutex) != 0) { | ||
216 | ret = -1; | ||
217 | goto post_unlock; | ||
218 | } | ||
219 | |||
220 | break; | ||
221 | } | ||
222 | |||
223 | if (w1_ds2438_get_page(sl, 0, w1_buf) == 0) { | ||
224 | *voltage = (((uint16_t) w1_buf[DS2438_VOLTAGE_MSB]) << 8) | ((uint16_t) w1_buf[DS2438_VOLTAGE_LSB]); | ||
225 | ret = 0; | ||
226 | } else | ||
227 | ret = -1; | ||
228 | |||
229 | pre_unlock: | ||
230 | mutex_unlock(&sl->master->bus_mutex); | ||
231 | |||
232 | post_unlock: | ||
233 | return ret; | ||
234 | } | ||
235 | |||
236 | static ssize_t iad_write(struct file *filp, struct kobject *kobj, | ||
237 | struct bin_attribute *bin_attr, char *buf, | ||
238 | loff_t off, size_t count) | ||
239 | { | ||
240 | struct w1_slave *sl = kobj_to_w1_slave(kobj); | ||
241 | int ret; | ||
242 | |||
243 | if (count != 1 || off != 0) | ||
244 | return -EFAULT; | ||
245 | |||
246 | mutex_lock(&sl->master->bus_mutex); | ||
247 | |||
248 | if (w1_ds2438_change_config_bit(sl, DS2438_STATUS_IAD, *buf & 0x01) == 0) | ||
249 | ret = 1; | ||
250 | else | ||
251 | ret = -EIO; | ||
252 | |||
253 | mutex_unlock(&sl->master->bus_mutex); | ||
254 | |||
255 | return ret; | ||
256 | } | ||
257 | |||
258 | static ssize_t page0_read(struct file *filp, struct kobject *kobj, | ||
259 | struct bin_attribute *bin_attr, char *buf, | ||
260 | loff_t off, size_t count) | ||
261 | { | ||
262 | struct w1_slave *sl = kobj_to_w1_slave(kobj); | ||
263 | int ret; | ||
264 | u8 w1_buf[DS2438_PAGE_SIZE + 1 /*for CRC*/]; | ||
265 | |||
266 | if (off != 0) | ||
267 | return 0; | ||
268 | if (!buf) | ||
269 | return -EINVAL; | ||
270 | |||
271 | mutex_lock(&sl->master->bus_mutex); | ||
272 | |||
273 | if (w1_ds2438_get_page(sl, 0, w1_buf) == 0) { | ||
274 | memcpy(buf, &w1_buf, DS2438_PAGE_SIZE); | ||
275 | ret = DS2438_PAGE_SIZE; | ||
276 | } else | ||
277 | ret = -EIO; | ||
278 | |||
279 | mutex_unlock(&sl->master->bus_mutex); | ||
280 | |||
281 | return ret; | ||
282 | } | ||
283 | |||
284 | static ssize_t temperature_read(struct file *filp, struct kobject *kobj, | ||
285 | struct bin_attribute *bin_attr, char *buf, | ||
286 | loff_t off, size_t count) | ||
287 | { | ||
288 | struct w1_slave *sl = kobj_to_w1_slave(kobj); | ||
289 | int ret; | ||
290 | ssize_t c = PAGE_SIZE; | ||
291 | int16_t temp; | ||
292 | |||
293 | if (off != 0) | ||
294 | return 0; | ||
295 | if (!buf) | ||
296 | return -EINVAL; | ||
297 | |||
298 | if (w1_ds2438_get_temperature(sl, &temp) == 0) { | ||
299 | c -= snprintf(buf + PAGE_SIZE - c, c, "%d\n", temp); | ||
300 | ret = PAGE_SIZE - c; | ||
301 | } else | ||
302 | ret = -EIO; | ||
303 | |||
304 | return ret; | ||
305 | } | ||
306 | |||
307 | static ssize_t vad_read(struct file *filp, struct kobject *kobj, | ||
308 | struct bin_attribute *bin_attr, char *buf, | ||
309 | loff_t off, size_t count) | ||
310 | { | ||
311 | struct w1_slave *sl = kobj_to_w1_slave(kobj); | ||
312 | int ret; | ||
313 | ssize_t c = PAGE_SIZE; | ||
314 | uint16_t voltage; | ||
315 | |||
316 | if (off != 0) | ||
317 | return 0; | ||
318 | if (!buf) | ||
319 | return -EINVAL; | ||
320 | |||
321 | if (w1_ds2438_get_voltage(sl, DS2438_ADC_INPUT_VAD, &voltage) == 0) { | ||
322 | c -= snprintf(buf + PAGE_SIZE - c, c, "%d\n", voltage); | ||
323 | ret = PAGE_SIZE - c; | ||
324 | } else | ||
325 | ret = -EIO; | ||
326 | |||
327 | return ret; | ||
328 | } | ||
329 | |||
330 | static ssize_t vdd_read(struct file *filp, struct kobject *kobj, | ||
331 | struct bin_attribute *bin_attr, char *buf, | ||
332 | loff_t off, size_t count) | ||
333 | { | ||
334 | struct w1_slave *sl = kobj_to_w1_slave(kobj); | ||
335 | int ret; | ||
336 | ssize_t c = PAGE_SIZE; | ||
337 | uint16_t voltage; | ||
338 | |||
339 | if (off != 0) | ||
340 | return 0; | ||
341 | if (!buf) | ||
342 | return -EINVAL; | ||
343 | |||
344 | if (w1_ds2438_get_voltage(sl, DS2438_ADC_INPUT_VDD, &voltage) == 0) { | ||
345 | c -= snprintf(buf + PAGE_SIZE - c, c, "%d\n", voltage); | ||
346 | ret = PAGE_SIZE - c; | ||
347 | } else | ||
348 | ret = -EIO; | ||
349 | |||
350 | return ret; | ||
351 | } | ||
352 | |||
353 | static BIN_ATTR(iad, S_IRUGO | S_IWUSR | S_IWGRP, NULL, iad_write, 1); | ||
354 | static BIN_ATTR_RO(page0, DS2438_PAGE_SIZE); | ||
355 | static BIN_ATTR_RO(temperature, 0/* real length varies */); | ||
356 | static BIN_ATTR_RO(vad, 0/* real length varies */); | ||
357 | static BIN_ATTR_RO(vdd, 0/* real length varies */); | ||
358 | |||
359 | static struct bin_attribute *w1_ds2438_bin_attrs[] = { | ||
360 | &bin_attr_iad, | ||
361 | &bin_attr_page0, | ||
362 | &bin_attr_temperature, | ||
363 | &bin_attr_vad, | ||
364 | &bin_attr_vdd, | ||
365 | NULL, | ||
366 | }; | ||
367 | |||
368 | static const struct attribute_group w1_ds2438_group = { | ||
369 | .bin_attrs = w1_ds2438_bin_attrs, | ||
370 | }; | ||
371 | |||
372 | static const struct attribute_group *w1_ds2438_groups[] = { | ||
373 | &w1_ds2438_group, | ||
374 | NULL, | ||
375 | }; | ||
376 | |||
377 | static struct w1_family_ops w1_ds2438_fops = { | ||
378 | .groups = w1_ds2438_groups, | ||
379 | }; | ||
380 | |||
381 | static struct w1_family w1_ds2438_family = { | ||
382 | .fid = W1_FAMILY_DS2438, | ||
383 | .fops = &w1_ds2438_fops, | ||
384 | }; | ||
385 | module_w1_family(w1_ds2438_family); | ||
386 | |||
387 | MODULE_LICENSE("GPL"); | ||
388 | MODULE_AUTHOR("Mariusz Bialonczyk <manio@skyboo.net>"); | ||
389 | MODULE_DESCRIPTION("1-wire driver for Maxim/Dallas DS2438 Smart Battery Monitor"); | ||
390 | MODULE_ALIAS("w1-family-" __stringify(W1_FAMILY_DS2438)); | ||
diff --git a/drivers/w1/slaves/w1_ds2760.h b/drivers/w1/slaves/w1_ds2760.h index 58e774141568..24168c94eeae 100644 --- a/drivers/w1/slaves/w1_ds2760.h +++ b/drivers/w1/slaves/w1_ds2760.h | |||
@@ -24,11 +24,13 @@ | |||
24 | #define DS2760_DATA_SIZE 0x40 | 24 | #define DS2760_DATA_SIZE 0x40 |
25 | 25 | ||
26 | #define DS2760_PROTECTION_REG 0x00 | 26 | #define DS2760_PROTECTION_REG 0x00 |
27 | |||
27 | #define DS2760_STATUS_REG 0x01 | 28 | #define DS2760_STATUS_REG 0x01 |
28 | #define DS2760_STATUS_IE (1 << 2) | 29 | #define DS2760_STATUS_IE (1 << 2) |
29 | #define DS2760_STATUS_SWEN (1 << 3) | 30 | #define DS2760_STATUS_SWEN (1 << 3) |
30 | #define DS2760_STATUS_RNAOP (1 << 4) | 31 | #define DS2760_STATUS_RNAOP (1 << 4) |
31 | #define DS2760_STATUS_PMOD (1 << 5) | 32 | #define DS2760_STATUS_PMOD (1 << 5) |
33 | |||
32 | #define DS2760_EEPROM_REG 0x07 | 34 | #define DS2760_EEPROM_REG 0x07 |
33 | #define DS2760_SPECIAL_FEATURE_REG 0x08 | 35 | #define DS2760_SPECIAL_FEATURE_REG 0x08 |
34 | #define DS2760_VOLTAGE_MSB 0x0c | 36 | #define DS2760_VOLTAGE_MSB 0x0c |
diff --git a/drivers/w1/w1_family.h b/drivers/w1/w1_family.h index c4a6b257a367..869a3ff87d29 100644 --- a/drivers/w1/w1_family.h +++ b/drivers/w1/w1_family.h | |||
@@ -29,6 +29,7 @@ | |||
29 | #define W1_COUNTER_DS2423 0x1D | 29 | #define W1_COUNTER_DS2423 0x1D |
30 | #define W1_THERM_DS1822 0x22 | 30 | #define W1_THERM_DS1822 0x22 |
31 | #define W1_EEPROM_DS2433 0x23 | 31 | #define W1_EEPROM_DS2433 0x23 |
32 | #define W1_FAMILY_DS2438 0x26 | ||
32 | #define W1_THERM_DS18B20 0x28 | 33 | #define W1_THERM_DS18B20 0x28 |
33 | #define W1_FAMILY_DS2408 0x29 | 34 | #define W1_FAMILY_DS2408 0x29 |
34 | #define W1_EEPROM_DS2431 0x2D | 35 | #define W1_EEPROM_DS2431 0x2D |
diff --git a/drivers/zorro/zorro-driver.c b/drivers/zorro/zorro-driver.c index eacae1434b73..fa23b7366b98 100644 --- a/drivers/zorro/zorro-driver.c +++ b/drivers/zorro/zorro-driver.c | |||
@@ -14,6 +14,8 @@ | |||
14 | #include <linux/module.h> | 14 | #include <linux/module.h> |
15 | #include <linux/zorro.h> | 15 | #include <linux/zorro.h> |
16 | 16 | ||
17 | #include "zorro.h" | ||
18 | |||
17 | 19 | ||
18 | /** | 20 | /** |
19 | * zorro_match_device - Tell if a Zorro device structure has a matching | 21 | * zorro_match_device - Tell if a Zorro device structure has a matching |
@@ -161,12 +163,13 @@ static int zorro_uevent(struct device *dev, struct kobj_uevent_env *env) | |||
161 | } | 163 | } |
162 | 164 | ||
163 | struct bus_type zorro_bus_type = { | 165 | struct bus_type zorro_bus_type = { |
164 | .name = "zorro", | 166 | .name = "zorro", |
165 | .dev_name = "zorro", | 167 | .dev_name = "zorro", |
166 | .match = zorro_bus_match, | 168 | .dev_groups = zorro_device_attribute_groups, |
167 | .uevent = zorro_uevent, | 169 | .match = zorro_bus_match, |
168 | .probe = zorro_device_probe, | 170 | .uevent = zorro_uevent, |
169 | .remove = zorro_device_remove, | 171 | .probe = zorro_device_probe, |
172 | .remove = zorro_device_remove, | ||
170 | }; | 173 | }; |
171 | EXPORT_SYMBOL(zorro_bus_type); | 174 | EXPORT_SYMBOL(zorro_bus_type); |
172 | 175 | ||
diff --git a/drivers/zorro/zorro-sysfs.c b/drivers/zorro/zorro-sysfs.c index 9282dbf5abdb..3d34dba9bb2d 100644 --- a/drivers/zorro/zorro-sysfs.c +++ b/drivers/zorro/zorro-sysfs.c | |||
@@ -23,33 +23,33 @@ | |||
23 | 23 | ||
24 | /* show configuration fields */ | 24 | /* show configuration fields */ |
25 | #define zorro_config_attr(name, field, format_string) \ | 25 | #define zorro_config_attr(name, field, format_string) \ |
26 | static ssize_t \ | 26 | static ssize_t name##_show(struct device *dev, \ |
27 | show_##name(struct device *dev, struct device_attribute *attr, char *buf) \ | 27 | struct device_attribute *attr, char *buf) \ |
28 | { \ | 28 | { \ |
29 | struct zorro_dev *z; \ | 29 | struct zorro_dev *z; \ |
30 | \ | 30 | \ |
31 | z = to_zorro_dev(dev); \ | 31 | z = to_zorro_dev(dev); \ |
32 | return sprintf(buf, format_string, z->field); \ | 32 | return sprintf(buf, format_string, z->field); \ |
33 | } \ | 33 | } \ |
34 | static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL); | 34 | static DEVICE_ATTR_RO(name); |
35 | 35 | ||
36 | zorro_config_attr(id, id, "0x%08x\n"); | 36 | zorro_config_attr(id, id, "0x%08x\n"); |
37 | zorro_config_attr(type, rom.er_Type, "0x%02x\n"); | 37 | zorro_config_attr(type, rom.er_Type, "0x%02x\n"); |
38 | zorro_config_attr(slotaddr, slotaddr, "0x%04x\n"); | 38 | zorro_config_attr(slotaddr, slotaddr, "0x%04x\n"); |
39 | zorro_config_attr(slotsize, slotsize, "0x%04x\n"); | 39 | zorro_config_attr(slotsize, slotsize, "0x%04x\n"); |
40 | 40 | ||
41 | static ssize_t | 41 | static ssize_t serial_show(struct device *dev, struct device_attribute *attr, |
42 | show_serial(struct device *dev, struct device_attribute *attr, char *buf) | 42 | char *buf) |
43 | { | 43 | { |
44 | struct zorro_dev *z; | 44 | struct zorro_dev *z; |
45 | 45 | ||
46 | z = to_zorro_dev(dev); | 46 | z = to_zorro_dev(dev); |
47 | return sprintf(buf, "0x%08x\n", be32_to_cpu(z->rom.er_SerialNumber)); | 47 | return sprintf(buf, "0x%08x\n", be32_to_cpu(z->rom.er_SerialNumber)); |
48 | } | 48 | } |
49 | static DEVICE_ATTR_RO(serial); | ||
49 | 50 | ||
50 | static DEVICE_ATTR(serial, S_IRUGO, show_serial, NULL); | 51 | static ssize_t resource_show(struct device *dev, struct device_attribute *attr, |
51 | 52 | char *buf) | |
52 | static ssize_t zorro_show_resource(struct device *dev, struct device_attribute *attr, char *buf) | ||
53 | { | 53 | { |
54 | struct zorro_dev *z = to_zorro_dev(dev); | 54 | struct zorro_dev *z = to_zorro_dev(dev); |
55 | 55 | ||
@@ -58,8 +58,27 @@ static ssize_t zorro_show_resource(struct device *dev, struct device_attribute * | |||
58 | (unsigned long)zorro_resource_end(z), | 58 | (unsigned long)zorro_resource_end(z), |
59 | zorro_resource_flags(z)); | 59 | zorro_resource_flags(z)); |
60 | } | 60 | } |
61 | static DEVICE_ATTR_RO(resource); | ||
62 | |||
63 | static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, | ||
64 | char *buf) | ||
65 | { | ||
66 | struct zorro_dev *z = to_zorro_dev(dev); | ||
61 | 67 | ||
62 | static DEVICE_ATTR(resource, S_IRUGO, zorro_show_resource, NULL); | 68 | return sprintf(buf, ZORRO_DEVICE_MODALIAS_FMT "\n", z->id); |
69 | } | ||
70 | static DEVICE_ATTR_RO(modalias); | ||
71 | |||
72 | static struct attribute *zorro_device_attrs[] = { | ||
73 | &dev_attr_id.attr, | ||
74 | &dev_attr_type.attr, | ||
75 | &dev_attr_serial.attr, | ||
76 | &dev_attr_slotaddr.attr, | ||
77 | &dev_attr_slotsize.attr, | ||
78 | &dev_attr_resource.attr, | ||
79 | &dev_attr_modalias.attr, | ||
80 | NULL | ||
81 | }; | ||
63 | 82 | ||
64 | static ssize_t zorro_read_config(struct file *filp, struct kobject *kobj, | 83 | static ssize_t zorro_read_config(struct file *filp, struct kobject *kobj, |
65 | struct bin_attribute *bin_attr, | 84 | struct bin_attribute *bin_attr, |
@@ -88,32 +107,17 @@ static struct bin_attribute zorro_config_attr = { | |||
88 | .read = zorro_read_config, | 107 | .read = zorro_read_config, |
89 | }; | 108 | }; |
90 | 109 | ||
91 | static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, | 110 | static struct bin_attribute *zorro_device_bin_attrs[] = { |
92 | char *buf) | 111 | &zorro_config_attr, |
93 | { | 112 | NULL |
94 | struct zorro_dev *z = to_zorro_dev(dev); | 113 | }; |
95 | |||
96 | return sprintf(buf, ZORRO_DEVICE_MODALIAS_FMT "\n", z->id); | ||
97 | } | ||
98 | |||
99 | static DEVICE_ATTR(modalias, S_IRUGO, modalias_show, NULL); | ||
100 | 114 | ||
101 | int zorro_create_sysfs_dev_files(struct zorro_dev *z) | 115 | static const struct attribute_group zorro_device_attr_group = { |
102 | { | 116 | .attrs = zorro_device_attrs, |
103 | struct device *dev = &z->dev; | 117 | .bin_attrs = zorro_device_bin_attrs, |
104 | int error; | 118 | }; |
105 | |||
106 | /* current configuration's attributes */ | ||
107 | if ((error = device_create_file(dev, &dev_attr_id)) || | ||
108 | (error = device_create_file(dev, &dev_attr_type)) || | ||
109 | (error = device_create_file(dev, &dev_attr_serial)) || | ||
110 | (error = device_create_file(dev, &dev_attr_slotaddr)) || | ||
111 | (error = device_create_file(dev, &dev_attr_slotsize)) || | ||
112 | (error = device_create_file(dev, &dev_attr_resource)) || | ||
113 | (error = device_create_file(dev, &dev_attr_modalias)) || | ||
114 | (error = sysfs_create_bin_file(&dev->kobj, &zorro_config_attr))) | ||
115 | return error; | ||
116 | |||
117 | return 0; | ||
118 | } | ||
119 | 119 | ||
120 | const struct attribute_group *zorro_device_attribute_groups[] = { | ||
121 | &zorro_device_attr_group, | ||
122 | NULL | ||
123 | }; | ||
diff --git a/drivers/zorro/zorro.c b/drivers/zorro/zorro.c index d295d9878dff..cc1b1ac57d61 100644 --- a/drivers/zorro/zorro.c +++ b/drivers/zorro/zorro.c | |||
@@ -197,9 +197,6 @@ static int __init amiga_zorro_probe(struct platform_device *pdev) | |||
197 | put_device(&z->dev); | 197 | put_device(&z->dev); |
198 | continue; | 198 | continue; |
199 | } | 199 | } |
200 | error = zorro_create_sysfs_dev_files(z); | ||
201 | if (error) | ||
202 | dev_err(&z->dev, "Error creating sysfs files\n"); | ||
203 | } | 200 | } |
204 | 201 | ||
205 | /* Mark all available Zorro II memory */ | 202 | /* Mark all available Zorro II memory */ |
diff --git a/drivers/zorro/zorro.h b/drivers/zorro/zorro.h index 34119fb4e560..4f805c01cfbc 100644 --- a/drivers/zorro/zorro.h +++ b/drivers/zorro/zorro.h | |||
@@ -5,5 +5,4 @@ extern void zorro_name_device(struct zorro_dev *z); | |||
5 | static inline void zorro_name_device(struct zorro_dev *dev) { } | 5 | static inline void zorro_name_device(struct zorro_dev *dev) { } |
6 | #endif | 6 | #endif |
7 | 7 | ||
8 | extern int zorro_create_sysfs_dev_files(struct zorro_dev *z); | 8 | extern const struct attribute_group *zorro_device_attribute_groups[]; |
9 | |||