diff options
Diffstat (limited to 'drivers')
149 files changed, 7866 insertions, 6462 deletions
diff --git a/drivers/Makefile b/drivers/Makefile index 3c5170310bd0..fc2d744a4e4a 100644 --- a/drivers/Makefile +++ b/drivers/Makefile | |||
@@ -74,4 +74,5 @@ obj-$(CONFIG_SGI_SN) += sn/ | |||
74 | obj-y += firmware/ | 74 | obj-y += firmware/ |
75 | obj-$(CONFIG_CRYPTO) += crypto/ | 75 | obj-$(CONFIG_CRYPTO) += crypto/ |
76 | obj-$(CONFIG_SUPERH) += sh/ | 76 | obj-$(CONFIG_SUPERH) += sh/ |
77 | obj-$(CONFIG_GENERIC_TIME) += clocksource/ | ||
77 | obj-$(CONFIG_DMA_ENGINE) += dma/ | 78 | obj-$(CONFIG_DMA_ENGINE) += dma/ |
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 3b97a5eae9e8..8a74bf3efd8e 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c | |||
@@ -206,11 +206,11 @@ acpi_processor_power_activate(struct acpi_processor *pr, | |||
206 | 206 | ||
207 | static void acpi_safe_halt(void) | 207 | static void acpi_safe_halt(void) |
208 | { | 208 | { |
209 | clear_thread_flag(TIF_POLLING_NRFLAG); | 209 | current_thread_info()->status &= ~TS_POLLING; |
210 | smp_mb__after_clear_bit(); | 210 | smp_mb__after_clear_bit(); |
211 | if (!need_resched()) | 211 | if (!need_resched()) |
212 | safe_halt(); | 212 | safe_halt(); |
213 | set_thread_flag(TIF_POLLING_NRFLAG); | 213 | current_thread_info()->status |= TS_POLLING; |
214 | } | 214 | } |
215 | 215 | ||
216 | static atomic_t c3_cpu_count; | 216 | static atomic_t c3_cpu_count; |
@@ -330,10 +330,10 @@ static void acpi_processor_idle(void) | |||
330 | * Invoke the current Cx state to put the processor to sleep. | 330 | * Invoke the current Cx state to put the processor to sleep. |
331 | */ | 331 | */ |
332 | if (cx->type == ACPI_STATE_C2 || cx->type == ACPI_STATE_C3) { | 332 | if (cx->type == ACPI_STATE_C2 || cx->type == ACPI_STATE_C3) { |
333 | clear_thread_flag(TIF_POLLING_NRFLAG); | 333 | current_thread_info()->status &= ~TS_POLLING; |
334 | smp_mb__after_clear_bit(); | 334 | smp_mb__after_clear_bit(); |
335 | if (need_resched()) { | 335 | if (need_resched()) { |
336 | set_thread_flag(TIF_POLLING_NRFLAG); | 336 | current_thread_info()->status |= TS_POLLING; |
337 | local_irq_enable(); | 337 | local_irq_enable(); |
338 | return; | 338 | return; |
339 | } | 339 | } |
@@ -369,9 +369,14 @@ static void acpi_processor_idle(void) | |||
369 | t2 = inl(acpi_fadt.xpm_tmr_blk.address); | 369 | t2 = inl(acpi_fadt.xpm_tmr_blk.address); |
370 | /* Get end time (ticks) */ | 370 | /* Get end time (ticks) */ |
371 | t2 = inl(acpi_fadt.xpm_tmr_blk.address); | 371 | t2 = inl(acpi_fadt.xpm_tmr_blk.address); |
372 | |||
373 | #ifdef CONFIG_GENERIC_TIME | ||
374 | /* TSC halts in C2, so notify users */ | ||
375 | mark_tsc_unstable(); | ||
376 | #endif | ||
372 | /* Re-enable interrupts */ | 377 | /* Re-enable interrupts */ |
373 | local_irq_enable(); | 378 | local_irq_enable(); |
374 | set_thread_flag(TIF_POLLING_NRFLAG); | 379 | current_thread_info()->status |= TS_POLLING; |
375 | /* Compute time (ticks) that we were actually asleep */ | 380 | /* Compute time (ticks) that we were actually asleep */ |
376 | sleep_ticks = | 381 | sleep_ticks = |
377 | ticks_elapsed(t1, t2) - cx->latency_ticks - C2_OVERHEAD; | 382 | ticks_elapsed(t1, t2) - cx->latency_ticks - C2_OVERHEAD; |
@@ -409,9 +414,13 @@ static void acpi_processor_idle(void) | |||
409 | ACPI_MTX_DO_NOT_LOCK); | 414 | ACPI_MTX_DO_NOT_LOCK); |
410 | } | 415 | } |
411 | 416 | ||
417 | #ifdef CONFIG_GENERIC_TIME | ||
418 | /* TSC halts in C3, so notify users */ | ||
419 | mark_tsc_unstable(); | ||
420 | #endif | ||
412 | /* Re-enable interrupts */ | 421 | /* Re-enable interrupts */ |
413 | local_irq_enable(); | 422 | local_irq_enable(); |
414 | set_thread_flag(TIF_POLLING_NRFLAG); | 423 | current_thread_info()->status |= TS_POLLING; |
415 | /* Compute time (ticks) that we were actually asleep */ | 424 | /* Compute time (ticks) that we were actually asleep */ |
416 | sleep_ticks = | 425 | sleep_ticks = |
417 | ticks_elapsed(t1, t2) - cx->latency_ticks - C3_OVERHEAD; | 426 | ticks_elapsed(t1, t2) - cx->latency_ticks - C3_OVERHEAD; |
diff --git a/drivers/base/power/resume.c b/drivers/base/power/resume.c index 520679ce53a8..826093ef4c7e 100644 --- a/drivers/base/power/resume.c +++ b/drivers/base/power/resume.c | |||
@@ -53,8 +53,7 @@ void dpm_resume(void) | |||
53 | struct device * dev = to_device(entry); | 53 | struct device * dev = to_device(entry); |
54 | 54 | ||
55 | get_device(dev); | 55 | get_device(dev); |
56 | list_del_init(entry); | 56 | list_move_tail(entry, &dpm_active); |
57 | list_add_tail(entry, &dpm_active); | ||
58 | 57 | ||
59 | up(&dpm_list_sem); | 58 | up(&dpm_list_sem); |
60 | if (!dev->power.prev_state.event) | 59 | if (!dev->power.prev_state.event) |
@@ -101,8 +100,7 @@ void dpm_power_up(void) | |||
101 | struct device * dev = to_device(entry); | 100 | struct device * dev = to_device(entry); |
102 | 101 | ||
103 | get_device(dev); | 102 | get_device(dev); |
104 | list_del_init(entry); | 103 | list_move_tail(entry, &dpm_active); |
105 | list_add_tail(entry, &dpm_active); | ||
106 | resume_device(dev); | 104 | resume_device(dev); |
107 | put_device(dev); | 105 | put_device(dev); |
108 | } | 106 | } |
diff --git a/drivers/base/power/suspend.c b/drivers/base/power/suspend.c index 1a1fe43a3057..69509e02f703 100644 --- a/drivers/base/power/suspend.c +++ b/drivers/base/power/suspend.c | |||
@@ -116,12 +116,10 @@ int device_suspend(pm_message_t state) | |||
116 | /* Check if the device got removed */ | 116 | /* Check if the device got removed */ |
117 | if (!list_empty(&dev->power.entry)) { | 117 | if (!list_empty(&dev->power.entry)) { |
118 | /* Move it to the dpm_off or dpm_off_irq list */ | 118 | /* Move it to the dpm_off or dpm_off_irq list */ |
119 | if (!error) { | 119 | if (!error) |
120 | list_del(&dev->power.entry); | 120 | list_move(&dev->power.entry, &dpm_off); |
121 | list_add(&dev->power.entry, &dpm_off); | 121 | else if (error == -EAGAIN) { |
122 | } else if (error == -EAGAIN) { | 122 | list_move(&dev->power.entry, &dpm_off_irq); |
123 | list_del(&dev->power.entry); | ||
124 | list_add(&dev->power.entry, &dpm_off_irq); | ||
125 | error = 0; | 123 | error = 0; |
126 | } | 124 | } |
127 | } | 125 | } |
@@ -139,8 +137,7 @@ int device_suspend(pm_message_t state) | |||
139 | */ | 137 | */ |
140 | while (!list_empty(&dpm_off_irq)) { | 138 | while (!list_empty(&dpm_off_irq)) { |
141 | struct list_head * entry = dpm_off_irq.next; | 139 | struct list_head * entry = dpm_off_irq.next; |
142 | list_del(entry); | 140 | list_move(entry, &dpm_off); |
143 | list_add(entry, &dpm_off); | ||
144 | } | 141 | } |
145 | dpm_resume(); | 142 | dpm_resume(); |
146 | } | 143 | } |
diff --git a/drivers/bluetooth/dtl1_cs.c b/drivers/bluetooth/dtl1_cs.c index a71a240611e0..ed8dca84ff69 100644 --- a/drivers/bluetooth/dtl1_cs.c +++ b/drivers/bluetooth/dtl1_cs.c | |||
@@ -423,6 +423,9 @@ static int dtl1_hci_send_frame(struct sk_buff *skb) | |||
423 | nsh.len = skb->len; | 423 | nsh.len = skb->len; |
424 | 424 | ||
425 | s = bt_skb_alloc(NSHL + skb->len + 1, GFP_ATOMIC); | 425 | s = bt_skb_alloc(NSHL + skb->len + 1, GFP_ATOMIC); |
426 | if (!s) | ||
427 | return -ENOMEM; | ||
428 | |||
426 | skb_reserve(s, NSHL); | 429 | skb_reserve(s, NSHL); |
427 | memcpy(skb_put(s, skb->len), skb->data, skb->len); | 430 | memcpy(skb_put(s, skb->len), skb->data, skb->len); |
428 | if (skb->len & 0x0001) | 431 | if (skb->len & 0x0001) |
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 63f28d169b36..3610c5729553 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig | |||
@@ -62,6 +62,23 @@ config HW_CONSOLE | |||
62 | depends on VT && !S390 && !UML | 62 | depends on VT && !S390 && !UML |
63 | default y | 63 | default y |
64 | 64 | ||
65 | config VT_HW_CONSOLE_BINDING | ||
66 | bool "Support for binding and unbinding console drivers" | ||
67 | depends on HW_CONSOLE | ||
68 | default n | ||
69 | ---help--- | ||
70 | The virtual terminal is the device that interacts with the physical | ||
71 | terminal through console drivers. On these systems, at least one | ||
72 | console driver is loaded. In other configurations, additional console | ||
73 | drivers may be enabled, such as the framebuffer console. If more than | ||
74 | 1 console driver is enabled, setting this to 'y' will allow you to | ||
75 | select the console driver that will serve as the backend for the | ||
76 | virtual terminals. | ||
77 | |||
78 | See <file:Documentation/console/console.txt> for more | ||
79 | information. For framebuffer console users, please refer to | ||
80 | <file:Documentation/fb/fbcon.txt>. | ||
81 | |||
65 | config SERIAL_NONSTANDARD | 82 | config SERIAL_NONSTANDARD |
66 | bool "Non-standard serial port support" | 83 | bool "Non-standard serial port support" |
67 | ---help--- | 84 | ---help--- |
@@ -670,20 +687,7 @@ config NWFLASH | |||
670 | 687 | ||
671 | If you're not sure, say N. | 688 | If you're not sure, say N. |
672 | 689 | ||
673 | config HW_RANDOM | 690 | source "drivers/char/hw_random/Kconfig" |
674 | tristate "Intel/AMD/VIA HW Random Number Generator support" | ||
675 | depends on (X86 || IA64) && PCI | ||
676 | ---help--- | ||
677 | This driver provides kernel-side support for the Random Number | ||
678 | Generator hardware found on Intel i8xx-based motherboards, | ||
679 | AMD 76x-based motherboards, and Via Nehemiah CPUs. | ||
680 | |||
681 | Provides a character driver, used to read() entropy data. | ||
682 | |||
683 | To compile this driver as a module, choose M here: the | ||
684 | module will be called hw_random. | ||
685 | |||
686 | If unsure, say N. | ||
687 | 691 | ||
688 | config NVRAM | 692 | config NVRAM |
689 | tristate "/dev/nvram support" | 693 | tristate "/dev/nvram support" |
diff --git a/drivers/char/Makefile b/drivers/char/Makefile index fb919bfb2824..524105597ea7 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile | |||
@@ -75,7 +75,7 @@ endif | |||
75 | obj-$(CONFIG_TOSHIBA) += toshiba.o | 75 | obj-$(CONFIG_TOSHIBA) += toshiba.o |
76 | obj-$(CONFIG_I8K) += i8k.o | 76 | obj-$(CONFIG_I8K) += i8k.o |
77 | obj-$(CONFIG_DS1620) += ds1620.o | 77 | obj-$(CONFIG_DS1620) += ds1620.o |
78 | obj-$(CONFIG_HW_RANDOM) += hw_random.o | 78 | obj-$(CONFIG_HW_RANDOM) += hw_random/ |
79 | obj-$(CONFIG_FTAPE) += ftape/ | 79 | obj-$(CONFIG_FTAPE) += ftape/ |
80 | obj-$(CONFIG_COBALT_LCD) += lcd.o | 80 | obj-$(CONFIG_COBALT_LCD) += lcd.o |
81 | obj-$(CONFIG_PPDEV) += ppdev.o | 81 | obj-$(CONFIG_PPDEV) += ppdev.o |
diff --git a/drivers/char/agp/Kconfig b/drivers/char/agp/Kconfig index 46685a540772..9826a399fa02 100644 --- a/drivers/char/agp/Kconfig +++ b/drivers/char/agp/Kconfig | |||
@@ -55,9 +55,9 @@ config AGP_AMD | |||
55 | X on AMD Irongate, 761, and 762 chipsets. | 55 | X on AMD Irongate, 761, and 762 chipsets. |
56 | 56 | ||
57 | config AGP_AMD64 | 57 | config AGP_AMD64 |
58 | tristate "AMD Opteron/Athlon64 on-CPU GART support" if !GART_IOMMU | 58 | tristate "AMD Opteron/Athlon64 on-CPU GART support" if !IOMMU |
59 | depends on AGP && X86 | 59 | depends on AGP && X86 |
60 | default y if GART_IOMMU | 60 | default y if IOMMU |
61 | help | 61 | help |
62 | This option gives you AGP support for the GLX component of | 62 | This option gives you AGP support for the GLX component of |
63 | X using the on-CPU northbridge of the AMD Athlon64/Opteron CPUs. | 63 | X using the on-CPU northbridge of the AMD Athlon64/Opteron CPUs. |
diff --git a/drivers/char/agp/amd64-agp.c b/drivers/char/agp/amd64-agp.c index ac3c33a2e37d..f690ee8cb732 100644 --- a/drivers/char/agp/amd64-agp.c +++ b/drivers/char/agp/amd64-agp.c | |||
@@ -15,11 +15,9 @@ | |||
15 | #include <linux/agp_backend.h> | 15 | #include <linux/agp_backend.h> |
16 | #include <linux/mmzone.h> | 16 | #include <linux/mmzone.h> |
17 | #include <asm/page.h> /* PAGE_SIZE */ | 17 | #include <asm/page.h> /* PAGE_SIZE */ |
18 | #include <asm/k8.h> | ||
18 | #include "agp.h" | 19 | #include "agp.h" |
19 | 20 | ||
20 | /* Will need to be increased if AMD64 ever goes >8-way. */ | ||
21 | #define MAX_HAMMER_GARTS 8 | ||
22 | |||
23 | /* PTE bits. */ | 21 | /* PTE bits. */ |
24 | #define GPTE_VALID 1 | 22 | #define GPTE_VALID 1 |
25 | #define GPTE_COHERENT 2 | 23 | #define GPTE_COHERENT 2 |
@@ -53,28 +51,12 @@ | |||
53 | #define ULI_X86_64_HTT_FEA_REG 0x50 | 51 | #define ULI_X86_64_HTT_FEA_REG 0x50 |
54 | #define ULI_X86_64_ENU_SCR_REG 0x54 | 52 | #define ULI_X86_64_ENU_SCR_REG 0x54 |
55 | 53 | ||
56 | static int nr_garts; | ||
57 | static struct pci_dev * hammers[MAX_HAMMER_GARTS]; | ||
58 | |||
59 | static struct resource *aperture_resource; | 54 | static struct resource *aperture_resource; |
60 | static int __initdata agp_try_unsupported = 1; | 55 | static int __initdata agp_try_unsupported = 1; |
61 | 56 | ||
62 | #define for_each_nb() for(gart_iterator=0;gart_iterator<nr_garts;gart_iterator++) | ||
63 | |||
64 | static void flush_amd64_tlb(struct pci_dev *dev) | ||
65 | { | ||
66 | u32 tmp; | ||
67 | |||
68 | pci_read_config_dword (dev, AMD64_GARTCACHECTL, &tmp); | ||
69 | tmp |= INVGART; | ||
70 | pci_write_config_dword (dev, AMD64_GARTCACHECTL, tmp); | ||
71 | } | ||
72 | |||
73 | static void amd64_tlbflush(struct agp_memory *temp) | 57 | static void amd64_tlbflush(struct agp_memory *temp) |
74 | { | 58 | { |
75 | int gart_iterator; | 59 | k8_flush_garts(); |
76 | for_each_nb() | ||
77 | flush_amd64_tlb(hammers[gart_iterator]); | ||
78 | } | 60 | } |
79 | 61 | ||
80 | static int amd64_insert_memory(struct agp_memory *mem, off_t pg_start, int type) | 62 | static int amd64_insert_memory(struct agp_memory *mem, off_t pg_start, int type) |
@@ -153,7 +135,7 @@ static int amd64_fetch_size(void) | |||
153 | u32 temp; | 135 | u32 temp; |
154 | struct aper_size_info_32 *values; | 136 | struct aper_size_info_32 *values; |
155 | 137 | ||
156 | dev = hammers[0]; | 138 | dev = k8_northbridges[0]; |
157 | if (dev==NULL) | 139 | if (dev==NULL) |
158 | return 0; | 140 | return 0; |
159 | 141 | ||
@@ -201,9 +183,6 @@ static u64 amd64_configure (struct pci_dev *hammer, u64 gatt_table) | |||
201 | tmp &= ~(DISGARTCPU | DISGARTIO); | 183 | tmp &= ~(DISGARTCPU | DISGARTIO); |
202 | pci_write_config_dword(hammer, AMD64_GARTAPERTURECTL, tmp); | 184 | pci_write_config_dword(hammer, AMD64_GARTAPERTURECTL, tmp); |
203 | 185 | ||
204 | /* keep CPU's coherent. */ | ||
205 | flush_amd64_tlb (hammer); | ||
206 | |||
207 | return aper_base; | 186 | return aper_base; |
208 | } | 187 | } |
209 | 188 | ||
@@ -222,13 +201,14 @@ static struct aper_size_info_32 amd_8151_sizes[7] = | |||
222 | static int amd_8151_configure(void) | 201 | static int amd_8151_configure(void) |
223 | { | 202 | { |
224 | unsigned long gatt_bus = virt_to_gart(agp_bridge->gatt_table_real); | 203 | unsigned long gatt_bus = virt_to_gart(agp_bridge->gatt_table_real); |
225 | int gart_iterator; | 204 | int i; |
226 | 205 | ||
227 | /* Configure AGP regs in each x86-64 host bridge. */ | 206 | /* Configure AGP regs in each x86-64 host bridge. */ |
228 | for_each_nb() { | 207 | for (i = 0; i < num_k8_northbridges; i++) { |
229 | agp_bridge->gart_bus_addr = | 208 | agp_bridge->gart_bus_addr = |
230 | amd64_configure(hammers[gart_iterator],gatt_bus); | 209 | amd64_configure(k8_northbridges[i], gatt_bus); |
231 | } | 210 | } |
211 | k8_flush_garts(); | ||
232 | return 0; | 212 | return 0; |
233 | } | 213 | } |
234 | 214 | ||
@@ -236,12 +216,13 @@ static int amd_8151_configure(void) | |||
236 | static void amd64_cleanup(void) | 216 | static void amd64_cleanup(void) |
237 | { | 217 | { |
238 | u32 tmp; | 218 | u32 tmp; |
239 | int gart_iterator; | 219 | int i; |
240 | for_each_nb() { | 220 | for (i = 0; i < num_k8_northbridges; i++) { |
221 | struct pci_dev *dev = k8_northbridges[i]; | ||
241 | /* disable gart translation */ | 222 | /* disable gart translation */ |
242 | pci_read_config_dword (hammers[gart_iterator], AMD64_GARTAPERTURECTL, &tmp); | 223 | pci_read_config_dword (dev, AMD64_GARTAPERTURECTL, &tmp); |
243 | tmp &= ~AMD64_GARTEN; | 224 | tmp &= ~AMD64_GARTEN; |
244 | pci_write_config_dword (hammers[gart_iterator], AMD64_GARTAPERTURECTL, tmp); | 225 | pci_write_config_dword (dev, AMD64_GARTAPERTURECTL, tmp); |
245 | } | 226 | } |
246 | } | 227 | } |
247 | 228 | ||
@@ -311,7 +292,7 @@ static int __devinit aperture_valid(u64 aper, u32 size) | |||
311 | /* | 292 | /* |
312 | * W*s centric BIOS sometimes only set up the aperture in the AGP | 293 | * W*s centric BIOS sometimes only set up the aperture in the AGP |
313 | * bridge, not the northbridge. On AMD64 this is handled early | 294 | * bridge, not the northbridge. On AMD64 this is handled early |
314 | * in aperture.c, but when GART_IOMMU is not enabled or we run | 295 | * in aperture.c, but when IOMMU is not enabled or we run |
315 | * on a 32bit kernel this needs to be redone. | 296 | * on a 32bit kernel this needs to be redone. |
316 | * Unfortunately it is impossible to fix the aperture here because it's too late | 297 | * Unfortunately it is impossible to fix the aperture here because it's too late |
317 | * to allocate that much memory. But at least error out cleanly instead of | 298 | * to allocate that much memory. But at least error out cleanly instead of |
@@ -361,17 +342,15 @@ static __devinit int fix_northbridge(struct pci_dev *nb, struct pci_dev *agp, | |||
361 | 342 | ||
362 | static __devinit int cache_nbs (struct pci_dev *pdev, u32 cap_ptr) | 343 | static __devinit int cache_nbs (struct pci_dev *pdev, u32 cap_ptr) |
363 | { | 344 | { |
364 | struct pci_dev *loop_dev = NULL; | 345 | int i; |
365 | int i = 0; | 346 | |
366 | 347 | if (cache_k8_northbridges() < 0) | |
367 | /* cache pci_devs of northbridges. */ | 348 | return -ENODEV; |
368 | while ((loop_dev = pci_get_device(PCI_VENDOR_ID_AMD, 0x1103, loop_dev)) | 349 | |
369 | != NULL) { | 350 | i = 0; |
370 | if (i == MAX_HAMMER_GARTS) { | 351 | for (i = 0; i < num_k8_northbridges; i++) { |
371 | printk(KERN_ERR PFX "Too many northbridges for AGP\n"); | 352 | struct pci_dev *dev = k8_northbridges[i]; |
372 | return -1; | 353 | if (fix_northbridge(dev, pdev, cap_ptr) < 0) { |
373 | } | ||
374 | if (fix_northbridge(loop_dev, pdev, cap_ptr) < 0) { | ||
375 | printk(KERN_ERR PFX "No usable aperture found.\n"); | 354 | printk(KERN_ERR PFX "No usable aperture found.\n"); |
376 | #ifdef __x86_64__ | 355 | #ifdef __x86_64__ |
377 | /* should port this to i386 */ | 356 | /* should port this to i386 */ |
@@ -379,10 +358,8 @@ static __devinit int cache_nbs (struct pci_dev *pdev, u32 cap_ptr) | |||
379 | #endif | 358 | #endif |
380 | return -1; | 359 | return -1; |
381 | } | 360 | } |
382 | hammers[i++] = loop_dev; | ||
383 | } | 361 | } |
384 | nr_garts = i; | 362 | return 0; |
385 | return i == 0 ? -1 : 0; | ||
386 | } | 363 | } |
387 | 364 | ||
388 | /* Handle AMD 8151 quirks */ | 365 | /* Handle AMD 8151 quirks */ |
@@ -450,7 +427,7 @@ static int __devinit uli_agp_init(struct pci_dev *pdev) | |||
450 | } | 427 | } |
451 | 428 | ||
452 | /* shadow x86-64 registers into ULi registers */ | 429 | /* shadow x86-64 registers into ULi registers */ |
453 | pci_read_config_dword (hammers[0], AMD64_GARTAPERTUREBASE, &httfea); | 430 | pci_read_config_dword (k8_northbridges[0], AMD64_GARTAPERTUREBASE, &httfea); |
454 | 431 | ||
455 | /* if x86-64 aperture base is beyond 4G, exit here */ | 432 | /* if x86-64 aperture base is beyond 4G, exit here */ |
456 | if ((httfea & 0x7fff) >> (32 - 25)) | 433 | if ((httfea & 0x7fff) >> (32 - 25)) |
@@ -513,7 +490,7 @@ static int __devinit nforce3_agp_init(struct pci_dev *pdev) | |||
513 | pci_write_config_dword(dev1, NVIDIA_X86_64_1_APSIZE, tmp); | 490 | pci_write_config_dword(dev1, NVIDIA_X86_64_1_APSIZE, tmp); |
514 | 491 | ||
515 | /* shadow x86-64 registers into NVIDIA registers */ | 492 | /* shadow x86-64 registers into NVIDIA registers */ |
516 | pci_read_config_dword (hammers[0], AMD64_GARTAPERTUREBASE, &apbase); | 493 | pci_read_config_dword (k8_northbridges[0], AMD64_GARTAPERTUREBASE, &apbase); |
517 | 494 | ||
518 | /* if x86-64 aperture base is beyond 4G, exit here */ | 495 | /* if x86-64 aperture base is beyond 4G, exit here */ |
519 | if ( (apbase & 0x7fff) >> (32 - 25) ) { | 496 | if ( (apbase & 0x7fff) >> (32 - 25) ) { |
@@ -754,10 +731,6 @@ static struct pci_driver agp_amd64_pci_driver = { | |||
754 | int __init agp_amd64_init(void) | 731 | int __init agp_amd64_init(void) |
755 | { | 732 | { |
756 | int err = 0; | 733 | int err = 0; |
757 | static struct pci_device_id amd64nb[] = { | ||
758 | { PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x1103) }, | ||
759 | { }, | ||
760 | }; | ||
761 | 734 | ||
762 | if (agp_off) | 735 | if (agp_off) |
763 | return -EINVAL; | 736 | return -EINVAL; |
@@ -774,7 +747,7 @@ int __init agp_amd64_init(void) | |||
774 | } | 747 | } |
775 | 748 | ||
776 | /* First check that we have at least one AMD64 NB */ | 749 | /* First check that we have at least one AMD64 NB */ |
777 | if (!pci_dev_present(amd64nb)) | 750 | if (!pci_dev_present(k8_nb_ids)) |
778 | return -ENODEV; | 751 | return -ENODEV; |
779 | 752 | ||
780 | /* Look for any AGP bridge */ | 753 | /* Look for any AGP bridge */ |
@@ -802,7 +775,7 @@ static void __exit agp_amd64_cleanup(void) | |||
802 | 775 | ||
803 | /* On AMD64 the PCI driver needs to initialize this driver early | 776 | /* On AMD64 the PCI driver needs to initialize this driver early |
804 | for the IOMMU, so it has to be called via a backdoor. */ | 777 | for the IOMMU, so it has to be called via a backdoor. */ |
805 | #ifndef CONFIG_GART_IOMMU | 778 | #ifndef CONFIG_IOMMU |
806 | module_init(agp_amd64_init); | 779 | module_init(agp_amd64_init); |
807 | module_exit(agp_amd64_cleanup); | 780 | module_exit(agp_amd64_cleanup); |
808 | #endif | 781 | #endif |
diff --git a/drivers/char/hangcheck-timer.c b/drivers/char/hangcheck-timer.c index ac626418b329..d69f2ad9a67d 100644 --- a/drivers/char/hangcheck-timer.c +++ b/drivers/char/hangcheck-timer.c | |||
@@ -117,12 +117,12 @@ __setup("hcheck_reboot", hangcheck_parse_reboot); | |||
117 | __setup("hcheck_dump_tasks", hangcheck_parse_dump_tasks); | 117 | __setup("hcheck_dump_tasks", hangcheck_parse_dump_tasks); |
118 | #endif /* not MODULE */ | 118 | #endif /* not MODULE */ |
119 | 119 | ||
120 | #if defined(CONFIG_X86) || defined(CONFIG_S390) | 120 | #if defined(CONFIG_X86_64) || defined(CONFIG_S390) |
121 | # define HAVE_MONOTONIC | 121 | # define HAVE_MONOTONIC |
122 | # define TIMER_FREQ 1000000000ULL | 122 | # define TIMER_FREQ 1000000000ULL |
123 | #elif defined(CONFIG_IA64) | 123 | #elif defined(CONFIG_IA64) |
124 | # define TIMER_FREQ ((unsigned long long)local_cpu_data->itc_freq) | 124 | # define TIMER_FREQ ((unsigned long long)local_cpu_data->itc_freq) |
125 | #elif defined(CONFIG_PPC64) | 125 | #else |
126 | # define TIMER_FREQ (HZ*loops_per_jiffy) | 126 | # define TIMER_FREQ (HZ*loops_per_jiffy) |
127 | #endif | 127 | #endif |
128 | 128 | ||
diff --git a/drivers/char/hw_random.c b/drivers/char/hw_random.c deleted file mode 100644 index 29dc87e59020..000000000000 --- a/drivers/char/hw_random.c +++ /dev/null | |||
@@ -1,698 +0,0 @@ | |||
1 | /* | ||
2 | Added support for the AMD Geode LX RNG | ||
3 | (c) Copyright 2004-2005 Advanced Micro Devices, Inc. | ||
4 | |||
5 | derived from | ||
6 | |||
7 | Hardware driver for the Intel/AMD/VIA Random Number Generators (RNG) | ||
8 | (c) Copyright 2003 Red Hat Inc <jgarzik@redhat.com> | ||
9 | |||
10 | derived from | ||
11 | |||
12 | Hardware driver for the AMD 768 Random Number Generator (RNG) | ||
13 | (c) Copyright 2001 Red Hat Inc <alan@redhat.com> | ||
14 | |||
15 | derived from | ||
16 | |||
17 | Hardware driver for Intel i810 Random Number Generator (RNG) | ||
18 | Copyright 2000,2001 Jeff Garzik <jgarzik@pobox.com> | ||
19 | Copyright 2000,2001 Philipp Rumpf <prumpf@mandrakesoft.com> | ||
20 | |||
21 | Please read Documentation/hw_random.txt for details on use. | ||
22 | |||
23 | ---------------------------------------------------------- | ||
24 | This software may be used and distributed according to the terms | ||
25 | of the GNU General Public License, incorporated herein by reference. | ||
26 | |||
27 | */ | ||
28 | |||
29 | |||
30 | #include <linux/module.h> | ||
31 | #include <linux/kernel.h> | ||
32 | #include <linux/fs.h> | ||
33 | #include <linux/init.h> | ||
34 | #include <linux/pci.h> | ||
35 | #include <linux/interrupt.h> | ||
36 | #include <linux/spinlock.h> | ||
37 | #include <linux/random.h> | ||
38 | #include <linux/miscdevice.h> | ||
39 | #include <linux/smp_lock.h> | ||
40 | #include <linux/mm.h> | ||
41 | #include <linux/delay.h> | ||
42 | |||
43 | #ifdef __i386__ | ||
44 | #include <asm/msr.h> | ||
45 | #include <asm/cpufeature.h> | ||
46 | #endif | ||
47 | |||
48 | #include <asm/io.h> | ||
49 | #include <asm/uaccess.h> | ||
50 | |||
51 | |||
52 | /* | ||
53 | * core module and version information | ||
54 | */ | ||
55 | #define RNG_VERSION "1.0.0" | ||
56 | #define RNG_MODULE_NAME "hw_random" | ||
57 | #define RNG_DRIVER_NAME RNG_MODULE_NAME " hardware driver " RNG_VERSION | ||
58 | #define PFX RNG_MODULE_NAME ": " | ||
59 | |||
60 | |||
61 | /* | ||
62 | * debugging macros | ||
63 | */ | ||
64 | |||
65 | /* pr_debug() collapses to a no-op if DEBUG is not defined */ | ||
66 | #define DPRINTK(fmt, args...) pr_debug(PFX "%s: " fmt, __FUNCTION__ , ## args) | ||
67 | |||
68 | |||
69 | #undef RNG_NDEBUG /* define to enable lightweight runtime checks */ | ||
70 | #ifdef RNG_NDEBUG | ||
71 | #define assert(expr) \ | ||
72 | if(!(expr)) { \ | ||
73 | printk(KERN_DEBUG PFX "Assertion failed! %s,%s,%s," \ | ||
74 | "line=%d\n", #expr, __FILE__, __FUNCTION__, __LINE__); \ | ||
75 | } | ||
76 | #else | ||
77 | #define assert(expr) | ||
78 | #endif | ||
79 | |||
80 | #define RNG_MISCDEV_MINOR 183 /* official */ | ||
81 | |||
82 | static int rng_dev_open (struct inode *inode, struct file *filp); | ||
83 | static ssize_t rng_dev_read (struct file *filp, char __user *buf, size_t size, | ||
84 | loff_t * offp); | ||
85 | |||
86 | static int __init intel_init (struct pci_dev *dev); | ||
87 | static void intel_cleanup(void); | ||
88 | static unsigned int intel_data_present (void); | ||
89 | static u32 intel_data_read (void); | ||
90 | |||
91 | static int __init amd_init (struct pci_dev *dev); | ||
92 | static void amd_cleanup(void); | ||
93 | static unsigned int amd_data_present (void); | ||
94 | static u32 amd_data_read (void); | ||
95 | |||
96 | #ifdef __i386__ | ||
97 | static int __init via_init(struct pci_dev *dev); | ||
98 | static void via_cleanup(void); | ||
99 | static unsigned int via_data_present (void); | ||
100 | static u32 via_data_read (void); | ||
101 | #endif | ||
102 | |||
103 | static int __init geode_init(struct pci_dev *dev); | ||
104 | static void geode_cleanup(void); | ||
105 | static unsigned int geode_data_present (void); | ||
106 | static u32 geode_data_read (void); | ||
107 | |||
108 | struct rng_operations { | ||
109 | int (*init) (struct pci_dev *dev); | ||
110 | void (*cleanup) (void); | ||
111 | unsigned int (*data_present) (void); | ||
112 | u32 (*data_read) (void); | ||
113 | unsigned int n_bytes; /* number of bytes per ->data_read */ | ||
114 | }; | ||
115 | static struct rng_operations *rng_ops; | ||
116 | |||
117 | static struct file_operations rng_chrdev_ops = { | ||
118 | .owner = THIS_MODULE, | ||
119 | .open = rng_dev_open, | ||
120 | .read = rng_dev_read, | ||
121 | }; | ||
122 | |||
123 | |||
124 | static struct miscdevice rng_miscdev = { | ||
125 | RNG_MISCDEV_MINOR, | ||
126 | RNG_MODULE_NAME, | ||
127 | &rng_chrdev_ops, | ||
128 | }; | ||
129 | |||
130 | enum { | ||
131 | rng_hw_none, | ||
132 | rng_hw_intel, | ||
133 | rng_hw_amd, | ||
134 | #ifdef __i386__ | ||
135 | rng_hw_via, | ||
136 | #endif | ||
137 | rng_hw_geode, | ||
138 | }; | ||
139 | |||
140 | static struct rng_operations rng_vendor_ops[] = { | ||
141 | /* rng_hw_none */ | ||
142 | { }, | ||
143 | |||
144 | /* rng_hw_intel */ | ||
145 | { intel_init, intel_cleanup, intel_data_present, | ||
146 | intel_data_read, 1 }, | ||
147 | |||
148 | /* rng_hw_amd */ | ||
149 | { amd_init, amd_cleanup, amd_data_present, amd_data_read, 4 }, | ||
150 | |||
151 | #ifdef __i386__ | ||
152 | /* rng_hw_via */ | ||
153 | { via_init, via_cleanup, via_data_present, via_data_read, 1 }, | ||
154 | #endif | ||
155 | |||
156 | /* rng_hw_geode */ | ||
157 | { geode_init, geode_cleanup, geode_data_present, geode_data_read, 4 } | ||
158 | }; | ||
159 | |||
160 | /* | ||
161 | * Data for PCI driver interface | ||
162 | * | ||
163 | * This data only exists for exporting the supported | ||
164 | * PCI ids via MODULE_DEVICE_TABLE. We do not actually | ||
165 | * register a pci_driver, because someone else might one day | ||
166 | * want to register another driver on the same PCI id. | ||
167 | */ | ||
168 | static struct pci_device_id rng_pci_tbl[] = { | ||
169 | { 0x1022, 0x7443, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_amd }, | ||
170 | { 0x1022, 0x746b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_amd }, | ||
171 | |||
172 | { 0x8086, 0x2418, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel }, | ||
173 | { 0x8086, 0x2428, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel }, | ||
174 | { 0x8086, 0x2430, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel }, | ||
175 | { 0x8086, 0x2448, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel }, | ||
176 | { 0x8086, 0x244e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel }, | ||
177 | { 0x8086, 0x245e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel }, | ||
178 | |||
179 | { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LX_AES, | ||
180 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_geode }, | ||
181 | |||
182 | { 0, }, /* terminate list */ | ||
183 | }; | ||
184 | MODULE_DEVICE_TABLE (pci, rng_pci_tbl); | ||
185 | |||
186 | |||
187 | /*********************************************************************** | ||
188 | * | ||
189 | * Intel RNG operations | ||
190 | * | ||
191 | */ | ||
192 | |||
193 | /* | ||
194 | * RNG registers (offsets from rng_mem) | ||
195 | */ | ||
196 | #define INTEL_RNG_HW_STATUS 0 | ||
197 | #define INTEL_RNG_PRESENT 0x40 | ||
198 | #define INTEL_RNG_ENABLED 0x01 | ||
199 | #define INTEL_RNG_STATUS 1 | ||
200 | #define INTEL_RNG_DATA_PRESENT 0x01 | ||
201 | #define INTEL_RNG_DATA 2 | ||
202 | |||
203 | /* | ||
204 | * Magic address at which Intel PCI bridges locate the RNG | ||
205 | */ | ||
206 | #define INTEL_RNG_ADDR 0xFFBC015F | ||
207 | #define INTEL_RNG_ADDR_LEN 3 | ||
208 | |||
209 | /* token to our ioremap'd RNG register area */ | ||
210 | static void __iomem *rng_mem; | ||
211 | |||
212 | static inline u8 intel_hwstatus (void) | ||
213 | { | ||
214 | assert (rng_mem != NULL); | ||
215 | return readb (rng_mem + INTEL_RNG_HW_STATUS); | ||
216 | } | ||
217 | |||
218 | static inline u8 intel_hwstatus_set (u8 hw_status) | ||
219 | { | ||
220 | assert (rng_mem != NULL); | ||
221 | writeb (hw_status, rng_mem + INTEL_RNG_HW_STATUS); | ||
222 | return intel_hwstatus (); | ||
223 | } | ||
224 | |||
225 | static unsigned int intel_data_present(void) | ||
226 | { | ||
227 | assert (rng_mem != NULL); | ||
228 | |||
229 | return (readb (rng_mem + INTEL_RNG_STATUS) & INTEL_RNG_DATA_PRESENT) ? | ||
230 | 1 : 0; | ||
231 | } | ||
232 | |||
233 | static u32 intel_data_read(void) | ||
234 | { | ||
235 | assert (rng_mem != NULL); | ||
236 | |||
237 | return readb (rng_mem + INTEL_RNG_DATA); | ||
238 | } | ||
239 | |||
240 | static int __init intel_init (struct pci_dev *dev) | ||
241 | { | ||
242 | int rc; | ||
243 | u8 hw_status; | ||
244 | |||
245 | DPRINTK ("ENTER\n"); | ||
246 | |||
247 | rng_mem = ioremap (INTEL_RNG_ADDR, INTEL_RNG_ADDR_LEN); | ||
248 | if (rng_mem == NULL) { | ||
249 | printk (KERN_ERR PFX "cannot ioremap RNG Memory\n"); | ||
250 | rc = -EBUSY; | ||
251 | goto err_out; | ||
252 | } | ||
253 | |||
254 | /* Check for Intel 82802 */ | ||
255 | hw_status = intel_hwstatus (); | ||
256 | if ((hw_status & INTEL_RNG_PRESENT) == 0) { | ||
257 | printk (KERN_ERR PFX "RNG not detected\n"); | ||
258 | rc = -ENODEV; | ||
259 | goto err_out_free_map; | ||
260 | } | ||
261 | |||
262 | /* turn RNG h/w on, if it's off */ | ||
263 | if ((hw_status & INTEL_RNG_ENABLED) == 0) | ||
264 | hw_status = intel_hwstatus_set (hw_status | INTEL_RNG_ENABLED); | ||
265 | if ((hw_status & INTEL_RNG_ENABLED) == 0) { | ||
266 | printk (KERN_ERR PFX "cannot enable RNG, aborting\n"); | ||
267 | rc = -EIO; | ||
268 | goto err_out_free_map; | ||
269 | } | ||
270 | |||
271 | DPRINTK ("EXIT, returning 0\n"); | ||
272 | return 0; | ||
273 | |||
274 | err_out_free_map: | ||
275 | iounmap (rng_mem); | ||
276 | rng_mem = NULL; | ||
277 | err_out: | ||
278 | DPRINTK ("EXIT, returning %d\n", rc); | ||
279 | return rc; | ||
280 | } | ||
281 | |||
282 | static void intel_cleanup(void) | ||
283 | { | ||
284 | u8 hw_status; | ||
285 | |||
286 | hw_status = intel_hwstatus (); | ||
287 | if (hw_status & INTEL_RNG_ENABLED) | ||
288 | intel_hwstatus_set (hw_status & ~INTEL_RNG_ENABLED); | ||
289 | else | ||
290 | printk(KERN_WARNING PFX "unusual: RNG already disabled\n"); | ||
291 | iounmap(rng_mem); | ||
292 | rng_mem = NULL; | ||
293 | } | ||
294 | |||
295 | /*********************************************************************** | ||
296 | * | ||
297 | * AMD RNG operations | ||
298 | * | ||
299 | */ | ||
300 | |||
301 | static u32 pmbase; /* PMxx I/O base */ | ||
302 | static struct pci_dev *amd_dev; | ||
303 | |||
304 | static unsigned int amd_data_present (void) | ||
305 | { | ||
306 | return inl(pmbase + 0xF4) & 1; | ||
307 | } | ||
308 | |||
309 | |||
310 | static u32 amd_data_read (void) | ||
311 | { | ||
312 | return inl(pmbase + 0xF0); | ||
313 | } | ||
314 | |||
315 | static int __init amd_init (struct pci_dev *dev) | ||
316 | { | ||
317 | int rc; | ||
318 | u8 rnen; | ||
319 | |||
320 | DPRINTK ("ENTER\n"); | ||
321 | |||
322 | pci_read_config_dword(dev, 0x58, &pmbase); | ||
323 | |||
324 | pmbase &= 0x0000FF00; | ||
325 | |||
326 | if (pmbase == 0) | ||
327 | { | ||
328 | printk (KERN_ERR PFX "power management base not set\n"); | ||
329 | rc = -EIO; | ||
330 | goto err_out; | ||
331 | } | ||
332 | |||
333 | pci_read_config_byte(dev, 0x40, &rnen); | ||
334 | rnen |= (1 << 7); /* RNG on */ | ||
335 | pci_write_config_byte(dev, 0x40, rnen); | ||
336 | |||
337 | pci_read_config_byte(dev, 0x41, &rnen); | ||
338 | rnen |= (1 << 7); /* PMIO enable */ | ||
339 | pci_write_config_byte(dev, 0x41, rnen); | ||
340 | |||
341 | pr_info( PFX "AMD768 system management I/O registers at 0x%X.\n", | ||
342 | pmbase); | ||
343 | |||
344 | amd_dev = dev; | ||
345 | |||
346 | DPRINTK ("EXIT, returning 0\n"); | ||
347 | return 0; | ||
348 | |||
349 | err_out: | ||
350 | DPRINTK ("EXIT, returning %d\n", rc); | ||
351 | return rc; | ||
352 | } | ||
353 | |||
354 | static void amd_cleanup(void) | ||
355 | { | ||
356 | u8 rnen; | ||
357 | |||
358 | pci_read_config_byte(amd_dev, 0x40, &rnen); | ||
359 | rnen &= ~(1 << 7); /* RNG off */ | ||
360 | pci_write_config_byte(amd_dev, 0x40, rnen); | ||
361 | |||
362 | /* FIXME: twiddle pmio, also? */ | ||
363 | } | ||
364 | |||
365 | #ifdef __i386__ | ||
366 | /*********************************************************************** | ||
367 | * | ||
368 | * VIA RNG operations | ||
369 | * | ||
370 | */ | ||
371 | |||
372 | enum { | ||
373 | VIA_STRFILT_CNT_SHIFT = 16, | ||
374 | VIA_STRFILT_FAIL = (1 << 15), | ||
375 | VIA_STRFILT_ENABLE = (1 << 14), | ||
376 | VIA_RAWBITS_ENABLE = (1 << 13), | ||
377 | VIA_RNG_ENABLE = (1 << 6), | ||
378 | VIA_XSTORE_CNT_MASK = 0x0F, | ||
379 | |||
380 | VIA_RNG_CHUNK_8 = 0x00, /* 64 rand bits, 64 stored bits */ | ||
381 | VIA_RNG_CHUNK_4 = 0x01, /* 32 rand bits, 32 stored bits */ | ||
382 | VIA_RNG_CHUNK_4_MASK = 0xFFFFFFFF, | ||
383 | VIA_RNG_CHUNK_2 = 0x02, /* 16 rand bits, 32 stored bits */ | ||
384 | VIA_RNG_CHUNK_2_MASK = 0xFFFF, | ||
385 | VIA_RNG_CHUNK_1 = 0x03, /* 8 rand bits, 32 stored bits */ | ||
386 | VIA_RNG_CHUNK_1_MASK = 0xFF, | ||
387 | }; | ||
388 | |||
389 | static u32 via_rng_datum; | ||
390 | |||
391 | /* | ||
392 | * Investigate using the 'rep' prefix to obtain 32 bits of random data | ||
393 | * in one insn. The upside is potentially better performance. The | ||
394 | * downside is that the instruction becomes no longer atomic. Due to | ||
395 | * this, just like familiar issues with /dev/random itself, the worst | ||
396 | * case of a 'rep xstore' could potentially pause a cpu for an | ||
397 | * unreasonably long time. In practice, this condition would likely | ||
398 | * only occur when the hardware is failing. (or so we hope :)) | ||
399 | * | ||
400 | * Another possible performance boost may come from simply buffering | ||
401 | * until we have 4 bytes, thus returning a u32 at a time, | ||
402 | * instead of the current u8-at-a-time. | ||
403 | */ | ||
404 | |||
405 | static inline u32 xstore(u32 *addr, u32 edx_in) | ||
406 | { | ||
407 | u32 eax_out; | ||
408 | |||
409 | asm(".byte 0x0F,0xA7,0xC0 /* xstore %%edi (addr=%0) */" | ||
410 | :"=m"(*addr), "=a"(eax_out) | ||
411 | :"D"(addr), "d"(edx_in)); | ||
412 | |||
413 | return eax_out; | ||
414 | } | ||
415 | |||
416 | static unsigned int via_data_present(void) | ||
417 | { | ||
418 | u32 bytes_out; | ||
419 | |||
420 | /* We choose the recommended 1-byte-per-instruction RNG rate, | ||
421 | * for greater randomness at the expense of speed. Larger | ||
422 | * values 2, 4, or 8 bytes-per-instruction yield greater | ||
423 | * speed at lesser randomness. | ||
424 | * | ||
425 | * If you change this to another VIA_CHUNK_n, you must also | ||
426 | * change the ->n_bytes values in rng_vendor_ops[] tables. | ||
427 | * VIA_CHUNK_8 requires further code changes. | ||
428 | * | ||
429 | * A copy of MSR_VIA_RNG is placed in eax_out when xstore | ||
430 | * completes. | ||
431 | */ | ||
432 | via_rng_datum = 0; /* paranoia, not really necessary */ | ||
433 | bytes_out = xstore(&via_rng_datum, VIA_RNG_CHUNK_1) & VIA_XSTORE_CNT_MASK; | ||
434 | if (bytes_out == 0) | ||
435 | return 0; | ||
436 | |||
437 | return 1; | ||
438 | } | ||
439 | |||
440 | static u32 via_data_read(void) | ||
441 | { | ||
442 | return via_rng_datum; | ||
443 | } | ||
444 | |||
445 | static int __init via_init(struct pci_dev *dev) | ||
446 | { | ||
447 | u32 lo, hi, old_lo; | ||
448 | |||
449 | /* Control the RNG via MSR. Tread lightly and pay very close | ||
450 | * close attention to values written, as the reserved fields | ||
451 | * are documented to be "undefined and unpredictable"; but it | ||
452 | * does not say to write them as zero, so I make a guess that | ||
453 | * we restore the values we find in the register. | ||
454 | */ | ||
455 | rdmsr(MSR_VIA_RNG, lo, hi); | ||
456 | |||
457 | old_lo = lo; | ||
458 | lo &= ~(0x7f << VIA_STRFILT_CNT_SHIFT); | ||
459 | lo &= ~VIA_XSTORE_CNT_MASK; | ||
460 | lo &= ~(VIA_STRFILT_ENABLE | VIA_STRFILT_FAIL | VIA_RAWBITS_ENABLE); | ||
461 | lo |= VIA_RNG_ENABLE; | ||
462 | |||
463 | if (lo != old_lo) | ||
464 | wrmsr(MSR_VIA_RNG, lo, hi); | ||
465 | |||
466 | /* perhaps-unnecessary sanity check; remove after testing if | ||
467 | unneeded */ | ||
468 | rdmsr(MSR_VIA_RNG, lo, hi); | ||
469 | if ((lo & VIA_RNG_ENABLE) == 0) { | ||
470 | printk(KERN_ERR PFX "cannot enable VIA C3 RNG, aborting\n"); | ||
471 | return -ENODEV; | ||
472 | } | ||
473 | |||
474 | return 0; | ||
475 | } | ||
476 | |||
477 | static void via_cleanup(void) | ||
478 | { | ||
479 | /* do nothing */ | ||
480 | } | ||
481 | #endif | ||
482 | |||
483 | /*********************************************************************** | ||
484 | * | ||
485 | * AMD Geode RNG operations | ||
486 | * | ||
487 | */ | ||
488 | |||
489 | static void __iomem *geode_rng_base = NULL; | ||
490 | |||
491 | #define GEODE_RNG_DATA_REG 0x50 | ||
492 | #define GEODE_RNG_STATUS_REG 0x54 | ||
493 | |||
494 | static u32 geode_data_read(void) | ||
495 | { | ||
496 | u32 val; | ||
497 | |||
498 | assert(geode_rng_base != NULL); | ||
499 | val = readl(geode_rng_base + GEODE_RNG_DATA_REG); | ||
500 | return val; | ||
501 | } | ||
502 | |||
503 | static unsigned int geode_data_present(void) | ||
504 | { | ||
505 | u32 val; | ||
506 | |||
507 | assert(geode_rng_base != NULL); | ||
508 | val = readl(geode_rng_base + GEODE_RNG_STATUS_REG); | ||
509 | return val; | ||
510 | } | ||
511 | |||
512 | static void geode_cleanup(void) | ||
513 | { | ||
514 | iounmap(geode_rng_base); | ||
515 | geode_rng_base = NULL; | ||
516 | } | ||
517 | |||
518 | static int geode_init(struct pci_dev *dev) | ||
519 | { | ||
520 | unsigned long rng_base = pci_resource_start(dev, 0); | ||
521 | |||
522 | if (rng_base == 0) | ||
523 | return 1; | ||
524 | |||
525 | geode_rng_base = ioremap(rng_base, 0x58); | ||
526 | |||
527 | if (geode_rng_base == NULL) { | ||
528 | printk(KERN_ERR PFX "Cannot ioremap RNG memory\n"); | ||
529 | return -EBUSY; | ||
530 | } | ||
531 | |||
532 | return 0; | ||
533 | } | ||
534 | |||
535 | /*********************************************************************** | ||
536 | * | ||
537 | * /dev/hwrandom character device handling (major 10, minor 183) | ||
538 | * | ||
539 | */ | ||
540 | |||
541 | static int rng_dev_open (struct inode *inode, struct file *filp) | ||
542 | { | ||
543 | /* enforce read-only access to this chrdev */ | ||
544 | if ((filp->f_mode & FMODE_READ) == 0) | ||
545 | return -EINVAL; | ||
546 | if (filp->f_mode & FMODE_WRITE) | ||
547 | return -EINVAL; | ||
548 | |||
549 | return 0; | ||
550 | } | ||
551 | |||
552 | |||
553 | static ssize_t rng_dev_read (struct file *filp, char __user *buf, size_t size, | ||
554 | loff_t * offp) | ||
555 | { | ||
556 | static DEFINE_SPINLOCK(rng_lock); | ||
557 | unsigned int have_data; | ||
558 | u32 data = 0; | ||
559 | ssize_t ret = 0; | ||
560 | |||
561 | while (size) { | ||
562 | spin_lock(&rng_lock); | ||
563 | |||
564 | have_data = 0; | ||
565 | if (rng_ops->data_present()) { | ||
566 | data = rng_ops->data_read(); | ||
567 | have_data = rng_ops->n_bytes; | ||
568 | } | ||
569 | |||
570 | spin_unlock (&rng_lock); | ||
571 | |||
572 | while (have_data && size) { | ||
573 | if (put_user((u8)data, buf++)) { | ||
574 | ret = ret ? : -EFAULT; | ||
575 | break; | ||
576 | } | ||
577 | size--; | ||
578 | ret++; | ||
579 | have_data--; | ||
580 | data>>=8; | ||
581 | } | ||
582 | |||
583 | if (filp->f_flags & O_NONBLOCK) | ||
584 | return ret ? : -EAGAIN; | ||
585 | |||
586 | if(need_resched()) | ||
587 | schedule_timeout_interruptible(1); | ||
588 | else | ||
589 | udelay(200); /* FIXME: We could poll for 250uS ?? */ | ||
590 | |||
591 | if (signal_pending (current)) | ||
592 | return ret ? : -ERESTARTSYS; | ||
593 | } | ||
594 | return ret; | ||
595 | } | ||
596 | |||
597 | |||
598 | |||
599 | /* | ||
600 | * rng_init_one - look for and attempt to init a single RNG | ||
601 | */ | ||
602 | static int __init rng_init_one (struct pci_dev *dev) | ||
603 | { | ||
604 | int rc; | ||
605 | |||
606 | DPRINTK ("ENTER\n"); | ||
607 | |||
608 | assert(rng_ops != NULL); | ||
609 | |||
610 | rc = rng_ops->init(dev); | ||
611 | if (rc) | ||
612 | goto err_out; | ||
613 | |||
614 | rc = misc_register (&rng_miscdev); | ||
615 | if (rc) { | ||
616 | printk (KERN_ERR PFX "misc device register failed\n"); | ||
617 | goto err_out_cleanup_hw; | ||
618 | } | ||
619 | |||
620 | DPRINTK ("EXIT, returning 0\n"); | ||
621 | return 0; | ||
622 | |||
623 | err_out_cleanup_hw: | ||
624 | rng_ops->cleanup(); | ||
625 | err_out: | ||
626 | DPRINTK ("EXIT, returning %d\n", rc); | ||
627 | return rc; | ||
628 | } | ||
629 | |||
630 | |||
631 | |||
632 | MODULE_AUTHOR("The Linux Kernel team"); | ||
633 | MODULE_DESCRIPTION("H/W Random Number Generator (RNG) driver"); | ||
634 | MODULE_LICENSE("GPL"); | ||
635 | |||
636 | |||
637 | /* | ||
638 | * rng_init - initialize RNG module | ||
639 | */ | ||
640 | static int __init rng_init (void) | ||
641 | { | ||
642 | int rc; | ||
643 | struct pci_dev *pdev = NULL; | ||
644 | const struct pci_device_id *ent; | ||
645 | |||
646 | DPRINTK ("ENTER\n"); | ||
647 | |||
648 | /* Probe for Intel, AMD, Geode RNGs */ | ||
649 | for_each_pci_dev(pdev) { | ||
650 | ent = pci_match_id(rng_pci_tbl, pdev); | ||
651 | if (ent) { | ||
652 | rng_ops = &rng_vendor_ops[ent->driver_data]; | ||
653 | goto match; | ||
654 | } | ||
655 | } | ||
656 | |||
657 | #ifdef __i386__ | ||
658 | /* Probe for VIA RNG */ | ||
659 | if (cpu_has_xstore) { | ||
660 | rng_ops = &rng_vendor_ops[rng_hw_via]; | ||
661 | pdev = NULL; | ||
662 | goto match; | ||
663 | } | ||
664 | #endif | ||
665 | |||
666 | DPRINTK ("EXIT, returning -ENODEV\n"); | ||
667 | return -ENODEV; | ||
668 | |||
669 | match: | ||
670 | rc = rng_init_one (pdev); | ||
671 | if (rc) | ||
672 | return rc; | ||
673 | |||
674 | pr_info( RNG_DRIVER_NAME " loaded\n"); | ||
675 | |||
676 | DPRINTK ("EXIT, returning 0\n"); | ||
677 | return 0; | ||
678 | } | ||
679 | |||
680 | |||
681 | /* | ||
682 | * rng_init - shutdown RNG module | ||
683 | */ | ||
684 | static void __exit rng_cleanup (void) | ||
685 | { | ||
686 | DPRINTK ("ENTER\n"); | ||
687 | |||
688 | misc_deregister (&rng_miscdev); | ||
689 | |||
690 | if (rng_ops->cleanup) | ||
691 | rng_ops->cleanup(); | ||
692 | |||
693 | DPRINTK ("EXIT\n"); | ||
694 | } | ||
695 | |||
696 | |||
697 | module_init (rng_init); | ||
698 | module_exit (rng_cleanup); | ||
diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig new file mode 100644 index 000000000000..9f7635f75178 --- /dev/null +++ b/drivers/char/hw_random/Kconfig | |||
@@ -0,0 +1,90 @@ | |||
1 | # | ||
2 | # Hardware Random Number Generator (RNG) configuration | ||
3 | # | ||
4 | |||
5 | config HW_RANDOM | ||
6 | bool "Hardware Random Number Generator Core support" | ||
7 | default y | ||
8 | ---help--- | ||
9 | Hardware Random Number Generator Core infrastructure. | ||
10 | |||
11 | If unsure, say Y. | ||
12 | |||
13 | config HW_RANDOM_INTEL | ||
14 | tristate "Intel HW Random Number Generator support" | ||
15 | depends on HW_RANDOM && (X86 || IA64) && PCI | ||
16 | default y | ||
17 | ---help--- | ||
18 | This driver provides kernel-side support for the Random Number | ||
19 | Generator hardware found on Intel i8xx-based motherboards. | ||
20 | |||
21 | To compile this driver as a module, choose M here: the | ||
22 | module will be called intel-rng. | ||
23 | |||
24 | If unsure, say Y. | ||
25 | |||
26 | config HW_RANDOM_AMD | ||
27 | tristate "AMD HW Random Number Generator support" | ||
28 | depends on HW_RANDOM && X86 && PCI | ||
29 | default y | ||
30 | ---help--- | ||
31 | This driver provides kernel-side support for the Random Number | ||
32 | Generator hardware found on AMD 76x-based motherboards. | ||
33 | |||
34 | To compile this driver as a module, choose M here: the | ||
35 | module will be called amd-rng. | ||
36 | |||
37 | If unsure, say Y. | ||
38 | |||
39 | config HW_RANDOM_GEODE | ||
40 | tristate "AMD Geode HW Random Number Generator support" | ||
41 | depends on HW_RANDOM && X86 && PCI | ||
42 | default y | ||
43 | ---help--- | ||
44 | This driver provides kernel-side support for the Random Number | ||
45 | Generator hardware found on the AMD Geode LX. | ||
46 | |||
47 | To compile this driver as a module, choose M here: the | ||
48 | module will be called geode-rng. | ||
49 | |||
50 | If unsure, say Y. | ||
51 | |||
52 | config HW_RANDOM_VIA | ||
53 | tristate "VIA HW Random Number Generator support" | ||
54 | depends on HW_RANDOM && X86_32 | ||
55 | default y | ||
56 | ---help--- | ||
57 | This driver provides kernel-side support for the Random Number | ||
58 | Generator hardware found on VIA based motherboards. | ||
59 | |||
60 | To compile this driver as a module, choose M here: the | ||
61 | module will be called via-rng. | ||
62 | |||
63 | If unsure, say Y. | ||
64 | |||
65 | config HW_RANDOM_IXP4XX | ||
66 | tristate "Intel IXP4xx NPU HW Random Number Generator support" | ||
67 | depends on HW_RANDOM && ARCH_IXP4XX | ||
68 | default y | ||
69 | ---help--- | ||
70 | This driver provides kernel-side support for the Random | ||
71 | Number Generator hardware found on the Intel IXP4xx NPU. | ||
72 | |||
73 | To compile this driver as a module, choose M here: the | ||
74 | module will be called ixp4xx-rng. | ||
75 | |||
76 | If unsure, say Y. | ||
77 | |||
78 | config HW_RANDOM_OMAP | ||
79 | tristate "OMAP Random Number Generator support" | ||
80 | depends on HW_RANDOM && (ARCH_OMAP16XX || ARCH_OMAP24XX) | ||
81 | default y | ||
82 | ---help--- | ||
83 | This driver provides kernel-side support for the Random Number | ||
84 | Generator hardware found on OMAP16xx and OMAP24xx multimedia | ||
85 | processors. | ||
86 | |||
87 | To compile this driver as a module, choose M here: the | ||
88 | module will be called omap-rng. | ||
89 | |||
90 | If unsure, say Y. | ||
diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile new file mode 100644 index 000000000000..e263ae96f940 --- /dev/null +++ b/drivers/char/hw_random/Makefile | |||
@@ -0,0 +1,11 @@ | |||
1 | # | ||
2 | # Makefile for HW Random Number Generator (RNG) device drivers. | ||
3 | # | ||
4 | |||
5 | obj-$(CONFIG_HW_RANDOM) += core.o | ||
6 | obj-$(CONFIG_HW_RANDOM_INTEL) += intel-rng.o | ||
7 | obj-$(CONFIG_HW_RANDOM_AMD) += amd-rng.o | ||
8 | obj-$(CONFIG_HW_RANDOM_GEODE) += geode-rng.o | ||
9 | obj-$(CONFIG_HW_RANDOM_VIA) += via-rng.o | ||
10 | obj-$(CONFIG_HW_RANDOM_IXP4XX) += ixp4xx-rng.o | ||
11 | obj-$(CONFIG_HW_RANDOM_OMAP) += omap-rng.o | ||
diff --git a/drivers/char/hw_random/amd-rng.c b/drivers/char/hw_random/amd-rng.c new file mode 100644 index 000000000000..71e4e0f3fd54 --- /dev/null +++ b/drivers/char/hw_random/amd-rng.c | |||
@@ -0,0 +1,152 @@ | |||
1 | /* | ||
2 | * RNG driver for AMD RNGs | ||
3 | * | ||
4 | * Copyright 2005 (c) MontaVista Software, Inc. | ||
5 | * | ||
6 | * with the majority of the code coming from: | ||
7 | * | ||
8 | * Hardware driver for the Intel/AMD/VIA Random Number Generators (RNG) | ||
9 | * (c) Copyright 2003 Red Hat Inc <jgarzik@redhat.com> | ||
10 | * | ||
11 | * derived from | ||
12 | * | ||
13 | * Hardware driver for the AMD 768 Random Number Generator (RNG) | ||
14 | * (c) Copyright 2001 Red Hat Inc <alan@redhat.com> | ||
15 | * | ||
16 | * derived from | ||
17 | * | ||
18 | * Hardware driver for Intel i810 Random Number Generator (RNG) | ||
19 | * Copyright 2000,2001 Jeff Garzik <jgarzik@pobox.com> | ||
20 | * Copyright 2000,2001 Philipp Rumpf <prumpf@mandrakesoft.com> | ||
21 | * | ||
22 | * This file is licensed under the terms of the GNU General Public | ||
23 | * License version 2. This program is licensed "as is" without any | ||
24 | * warranty of any kind, whether express or implied. | ||
25 | */ | ||
26 | |||
27 | #include <linux/module.h> | ||
28 | #include <linux/kernel.h> | ||
29 | #include <linux/pci.h> | ||
30 | #include <linux/hw_random.h> | ||
31 | #include <asm/io.h> | ||
32 | |||
33 | |||
34 | #define PFX KBUILD_MODNAME ": " | ||
35 | |||
36 | |||
37 | /* | ||
38 | * Data for PCI driver interface | ||
39 | * | ||
40 | * This data only exists for exporting the supported | ||
41 | * PCI ids via MODULE_DEVICE_TABLE. We do not actually | ||
42 | * register a pci_driver, because someone else might one day | ||
43 | * want to register another driver on the same PCI id. | ||
44 | */ | ||
45 | static const struct pci_device_id pci_tbl[] = { | ||
46 | { 0x1022, 0x7443, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, | ||
47 | { 0x1022, 0x746b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, | ||
48 | { 0, }, /* terminate list */ | ||
49 | }; | ||
50 | MODULE_DEVICE_TABLE(pci, pci_tbl); | ||
51 | |||
52 | static struct pci_dev *amd_pdev; | ||
53 | |||
54 | |||
55 | static int amd_rng_data_present(struct hwrng *rng) | ||
56 | { | ||
57 | u32 pmbase = (u32)rng->priv; | ||
58 | |||
59 | return !!(inl(pmbase + 0xF4) & 1); | ||
60 | } | ||
61 | |||
62 | static int amd_rng_data_read(struct hwrng *rng, u32 *data) | ||
63 | { | ||
64 | u32 pmbase = (u32)rng->priv; | ||
65 | |||
66 | *data = inl(pmbase + 0xF0); | ||
67 | |||
68 | return 4; | ||
69 | } | ||
70 | |||
71 | static int amd_rng_init(struct hwrng *rng) | ||
72 | { | ||
73 | u8 rnen; | ||
74 | |||
75 | pci_read_config_byte(amd_pdev, 0x40, &rnen); | ||
76 | rnen |= (1 << 7); /* RNG on */ | ||
77 | pci_write_config_byte(amd_pdev, 0x40, rnen); | ||
78 | |||
79 | pci_read_config_byte(amd_pdev, 0x41, &rnen); | ||
80 | rnen |= (1 << 7); /* PMIO enable */ | ||
81 | pci_write_config_byte(amd_pdev, 0x41, rnen); | ||
82 | |||
83 | return 0; | ||
84 | } | ||
85 | |||
86 | static void amd_rng_cleanup(struct hwrng *rng) | ||
87 | { | ||
88 | u8 rnen; | ||
89 | |||
90 | pci_read_config_byte(amd_pdev, 0x40, &rnen); | ||
91 | rnen &= ~(1 << 7); /* RNG off */ | ||
92 | pci_write_config_byte(amd_pdev, 0x40, rnen); | ||
93 | } | ||
94 | |||
95 | |||
96 | static struct hwrng amd_rng = { | ||
97 | .name = "amd", | ||
98 | .init = amd_rng_init, | ||
99 | .cleanup = amd_rng_cleanup, | ||
100 | .data_present = amd_rng_data_present, | ||
101 | .data_read = amd_rng_data_read, | ||
102 | }; | ||
103 | |||
104 | |||
105 | static int __init mod_init(void) | ||
106 | { | ||
107 | int err = -ENODEV; | ||
108 | struct pci_dev *pdev = NULL; | ||
109 | const struct pci_device_id *ent; | ||
110 | u32 pmbase; | ||
111 | |||
112 | for_each_pci_dev(pdev) { | ||
113 | ent = pci_match_id(pci_tbl, pdev); | ||
114 | if (ent) | ||
115 | goto found; | ||
116 | } | ||
117 | /* Device not found. */ | ||
118 | goto out; | ||
119 | |||
120 | found: | ||
121 | err = pci_read_config_dword(pdev, 0x58, &pmbase); | ||
122 | if (err) | ||
123 | goto out; | ||
124 | err = -EIO; | ||
125 | pmbase &= 0x0000FF00; | ||
126 | if (pmbase == 0) | ||
127 | goto out; | ||
128 | amd_rng.priv = (unsigned long)pmbase; | ||
129 | amd_pdev = pdev; | ||
130 | |||
131 | printk(KERN_INFO "AMD768 RNG detected\n"); | ||
132 | err = hwrng_register(&amd_rng); | ||
133 | if (err) { | ||
134 | printk(KERN_ERR PFX "RNG registering failed (%d)\n", | ||
135 | err); | ||
136 | goto out; | ||
137 | } | ||
138 | out: | ||
139 | return err; | ||
140 | } | ||
141 | |||
142 | static void __exit mod_exit(void) | ||
143 | { | ||
144 | hwrng_unregister(&amd_rng); | ||
145 | } | ||
146 | |||
147 | subsys_initcall(mod_init); | ||
148 | module_exit(mod_exit); | ||
149 | |||
150 | MODULE_AUTHOR("The Linux Kernel team"); | ||
151 | MODULE_DESCRIPTION("H/W RNG driver for AMD chipsets"); | ||
152 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c new file mode 100644 index 000000000000..88b026639f10 --- /dev/null +++ b/drivers/char/hw_random/core.c | |||
@@ -0,0 +1,354 @@ | |||
1 | /* | ||
2 | Added support for the AMD Geode LX RNG | ||
3 | (c) Copyright 2004-2005 Advanced Micro Devices, Inc. | ||
4 | |||
5 | derived from | ||
6 | |||
7 | Hardware driver for the Intel/AMD/VIA Random Number Generators (RNG) | ||
8 | (c) Copyright 2003 Red Hat Inc <jgarzik@redhat.com> | ||
9 | |||
10 | derived from | ||
11 | |||
12 | Hardware driver for the AMD 768 Random Number Generator (RNG) | ||
13 | (c) Copyright 2001 Red Hat Inc <alan@redhat.com> | ||
14 | |||
15 | derived from | ||
16 | |||
17 | Hardware driver for Intel i810 Random Number Generator (RNG) | ||
18 | Copyright 2000,2001 Jeff Garzik <jgarzik@pobox.com> | ||
19 | Copyright 2000,2001 Philipp Rumpf <prumpf@mandrakesoft.com> | ||
20 | |||
21 | Added generic RNG API | ||
22 | Copyright 2006 Michael Buesch <mbuesch@freenet.de> | ||
23 | Copyright 2005 (c) MontaVista Software, Inc. | ||
24 | |||
25 | Please read Documentation/hw_random.txt for details on use. | ||
26 | |||
27 | ---------------------------------------------------------- | ||
28 | This software may be used and distributed according to the terms | ||
29 | of the GNU General Public License, incorporated herein by reference. | ||
30 | |||
31 | */ | ||
32 | |||
33 | |||
34 | #include <linux/device.h> | ||
35 | #include <linux/hw_random.h> | ||
36 | #include <linux/module.h> | ||
37 | #include <linux/kernel.h> | ||
38 | #include <linux/fs.h> | ||
39 | #include <linux/init.h> | ||
40 | #include <linux/miscdevice.h> | ||
41 | #include <linux/delay.h> | ||
42 | #include <asm/uaccess.h> | ||
43 | |||
44 | |||
45 | #define RNG_MODULE_NAME "hw_random" | ||
46 | #define PFX RNG_MODULE_NAME ": " | ||
47 | #define RNG_MISCDEV_MINOR 183 /* official */ | ||
48 | |||
49 | |||
50 | static struct hwrng *current_rng; | ||
51 | static LIST_HEAD(rng_list); | ||
52 | static DEFINE_MUTEX(rng_mutex); | ||
53 | |||
54 | |||
55 | static inline int hwrng_init(struct hwrng *rng) | ||
56 | { | ||
57 | if (!rng->init) | ||
58 | return 0; | ||
59 | return rng->init(rng); | ||
60 | } | ||
61 | |||
62 | static inline void hwrng_cleanup(struct hwrng *rng) | ||
63 | { | ||
64 | if (rng && rng->cleanup) | ||
65 | rng->cleanup(rng); | ||
66 | } | ||
67 | |||
68 | static inline int hwrng_data_present(struct hwrng *rng) | ||
69 | { | ||
70 | if (!rng->data_present) | ||
71 | return 1; | ||
72 | return rng->data_present(rng); | ||
73 | } | ||
74 | |||
75 | static inline int hwrng_data_read(struct hwrng *rng, u32 *data) | ||
76 | { | ||
77 | return rng->data_read(rng, data); | ||
78 | } | ||
79 | |||
80 | |||
81 | static int rng_dev_open(struct inode *inode, struct file *filp) | ||
82 | { | ||
83 | /* enforce read-only access to this chrdev */ | ||
84 | if ((filp->f_mode & FMODE_READ) == 0) | ||
85 | return -EINVAL; | ||
86 | if (filp->f_mode & FMODE_WRITE) | ||
87 | return -EINVAL; | ||
88 | return 0; | ||
89 | } | ||
90 | |||
91 | static ssize_t rng_dev_read(struct file *filp, char __user *buf, | ||
92 | size_t size, loff_t *offp) | ||
93 | { | ||
94 | u32 data; | ||
95 | ssize_t ret = 0; | ||
96 | int i, err = 0; | ||
97 | int data_present; | ||
98 | int bytes_read; | ||
99 | |||
100 | while (size) { | ||
101 | err = -ERESTARTSYS; | ||
102 | if (mutex_lock_interruptible(&rng_mutex)) | ||
103 | goto out; | ||
104 | if (!current_rng) { | ||
105 | mutex_unlock(&rng_mutex); | ||
106 | err = -ENODEV; | ||
107 | goto out; | ||
108 | } | ||
109 | if (filp->f_flags & O_NONBLOCK) { | ||
110 | data_present = hwrng_data_present(current_rng); | ||
111 | } else { | ||
112 | /* Some RNG require some time between data_reads to gather | ||
113 | * new entropy. Poll it. | ||
114 | */ | ||
115 | for (i = 0; i < 20; i++) { | ||
116 | data_present = hwrng_data_present(current_rng); | ||
117 | if (data_present) | ||
118 | break; | ||
119 | udelay(10); | ||
120 | } | ||
121 | } | ||
122 | bytes_read = 0; | ||
123 | if (data_present) | ||
124 | bytes_read = hwrng_data_read(current_rng, &data); | ||
125 | mutex_unlock(&rng_mutex); | ||
126 | |||
127 | err = -EAGAIN; | ||
128 | if (!bytes_read && (filp->f_flags & O_NONBLOCK)) | ||
129 | goto out; | ||
130 | |||
131 | err = -EFAULT; | ||
132 | while (bytes_read && size) { | ||
133 | if (put_user((u8)data, buf++)) | ||
134 | goto out; | ||
135 | size--; | ||
136 | ret++; | ||
137 | bytes_read--; | ||
138 | data >>= 8; | ||
139 | } | ||
140 | |||
141 | if (need_resched()) | ||
142 | schedule_timeout_interruptible(1); | ||
143 | err = -ERESTARTSYS; | ||
144 | if (signal_pending(current)) | ||
145 | goto out; | ||
146 | } | ||
147 | out: | ||
148 | return ret ? : err; | ||
149 | } | ||
150 | |||
151 | |||
152 | static struct file_operations rng_chrdev_ops = { | ||
153 | .owner = THIS_MODULE, | ||
154 | .open = rng_dev_open, | ||
155 | .read = rng_dev_read, | ||
156 | }; | ||
157 | |||
158 | static struct miscdevice rng_miscdev = { | ||
159 | .minor = RNG_MISCDEV_MINOR, | ||
160 | .name = RNG_MODULE_NAME, | ||
161 | .fops = &rng_chrdev_ops, | ||
162 | }; | ||
163 | |||
164 | |||
165 | static ssize_t hwrng_attr_current_store(struct class_device *class, | ||
166 | const char *buf, size_t len) | ||
167 | { | ||
168 | int err; | ||
169 | struct hwrng *rng; | ||
170 | |||
171 | err = mutex_lock_interruptible(&rng_mutex); | ||
172 | if (err) | ||
173 | return -ERESTARTSYS; | ||
174 | err = -ENODEV; | ||
175 | list_for_each_entry(rng, &rng_list, list) { | ||
176 | if (strcmp(rng->name, buf) == 0) { | ||
177 | if (rng == current_rng) { | ||
178 | err = 0; | ||
179 | break; | ||
180 | } | ||
181 | err = hwrng_init(rng); | ||
182 | if (err) | ||
183 | break; | ||
184 | hwrng_cleanup(current_rng); | ||
185 | current_rng = rng; | ||
186 | err = 0; | ||
187 | break; | ||
188 | } | ||
189 | } | ||
190 | mutex_unlock(&rng_mutex); | ||
191 | |||
192 | return err ? : len; | ||
193 | } | ||
194 | |||
195 | static ssize_t hwrng_attr_current_show(struct class_device *class, | ||
196 | char *buf) | ||
197 | { | ||
198 | int err; | ||
199 | ssize_t ret; | ||
200 | const char *name = "none"; | ||
201 | |||
202 | err = mutex_lock_interruptible(&rng_mutex); | ||
203 | if (err) | ||
204 | return -ERESTARTSYS; | ||
205 | if (current_rng) | ||
206 | name = current_rng->name; | ||
207 | ret = snprintf(buf, PAGE_SIZE, "%s\n", name); | ||
208 | mutex_unlock(&rng_mutex); | ||
209 | |||
210 | return ret; | ||
211 | } | ||
212 | |||
213 | static ssize_t hwrng_attr_available_show(struct class_device *class, | ||
214 | char *buf) | ||
215 | { | ||
216 | int err; | ||
217 | ssize_t ret = 0; | ||
218 | struct hwrng *rng; | ||
219 | |||
220 | err = mutex_lock_interruptible(&rng_mutex); | ||
221 | if (err) | ||
222 | return -ERESTARTSYS; | ||
223 | buf[0] = '\0'; | ||
224 | list_for_each_entry(rng, &rng_list, list) { | ||
225 | strncat(buf, rng->name, PAGE_SIZE - ret - 1); | ||
226 | ret += strlen(rng->name); | ||
227 | strncat(buf, " ", PAGE_SIZE - ret - 1); | ||
228 | ret++; | ||
229 | } | ||
230 | strncat(buf, "\n", PAGE_SIZE - ret - 1); | ||
231 | ret++; | ||
232 | mutex_unlock(&rng_mutex); | ||
233 | |||
234 | return ret; | ||
235 | } | ||
236 | |||
237 | static CLASS_DEVICE_ATTR(rng_current, S_IRUGO | S_IWUSR, | ||
238 | hwrng_attr_current_show, | ||
239 | hwrng_attr_current_store); | ||
240 | static CLASS_DEVICE_ATTR(rng_available, S_IRUGO, | ||
241 | hwrng_attr_available_show, | ||
242 | NULL); | ||
243 | |||
244 | |||
245 | static void unregister_miscdev(void) | ||
246 | { | ||
247 | class_device_remove_file(rng_miscdev.class, | ||
248 | &class_device_attr_rng_available); | ||
249 | class_device_remove_file(rng_miscdev.class, | ||
250 | &class_device_attr_rng_current); | ||
251 | misc_deregister(&rng_miscdev); | ||
252 | } | ||
253 | |||
254 | static int register_miscdev(void) | ||
255 | { | ||
256 | int err; | ||
257 | |||
258 | err = misc_register(&rng_miscdev); | ||
259 | if (err) | ||
260 | goto out; | ||
261 | err = class_device_create_file(rng_miscdev.class, | ||
262 | &class_device_attr_rng_current); | ||
263 | if (err) | ||
264 | goto err_misc_dereg; | ||
265 | err = class_device_create_file(rng_miscdev.class, | ||
266 | &class_device_attr_rng_available); | ||
267 | if (err) | ||
268 | goto err_remove_current; | ||
269 | out: | ||
270 | return err; | ||
271 | |||
272 | err_remove_current: | ||
273 | class_device_remove_file(rng_miscdev.class, | ||
274 | &class_device_attr_rng_current); | ||
275 | err_misc_dereg: | ||
276 | misc_deregister(&rng_miscdev); | ||
277 | goto out; | ||
278 | } | ||
279 | |||
280 | int hwrng_register(struct hwrng *rng) | ||
281 | { | ||
282 | int must_register_misc; | ||
283 | int err = -EINVAL; | ||
284 | struct hwrng *old_rng, *tmp; | ||
285 | |||
286 | if (rng->name == NULL || | ||
287 | rng->data_read == NULL) | ||
288 | goto out; | ||
289 | |||
290 | mutex_lock(&rng_mutex); | ||
291 | |||
292 | /* Must not register two RNGs with the same name. */ | ||
293 | err = -EEXIST; | ||
294 | list_for_each_entry(tmp, &rng_list, list) { | ||
295 | if (strcmp(tmp->name, rng->name) == 0) | ||
296 | goto out_unlock; | ||
297 | } | ||
298 | |||
299 | must_register_misc = (current_rng == NULL); | ||
300 | old_rng = current_rng; | ||
301 | if (!old_rng) { | ||
302 | err = hwrng_init(rng); | ||
303 | if (err) | ||
304 | goto out_unlock; | ||
305 | current_rng = rng; | ||
306 | } | ||
307 | err = 0; | ||
308 | if (must_register_misc) { | ||
309 | err = register_miscdev(); | ||
310 | if (err) { | ||
311 | if (!old_rng) { | ||
312 | hwrng_cleanup(rng); | ||
313 | current_rng = NULL; | ||
314 | } | ||
315 | goto out_unlock; | ||
316 | } | ||
317 | } | ||
318 | INIT_LIST_HEAD(&rng->list); | ||
319 | list_add_tail(&rng->list, &rng_list); | ||
320 | out_unlock: | ||
321 | mutex_unlock(&rng_mutex); | ||
322 | out: | ||
323 | return err; | ||
324 | } | ||
325 | EXPORT_SYMBOL_GPL(hwrng_register); | ||
326 | |||
327 | void hwrng_unregister(struct hwrng *rng) | ||
328 | { | ||
329 | int err; | ||
330 | |||
331 | mutex_lock(&rng_mutex); | ||
332 | |||
333 | list_del(&rng->list); | ||
334 | if (current_rng == rng) { | ||
335 | hwrng_cleanup(rng); | ||
336 | if (list_empty(&rng_list)) { | ||
337 | current_rng = NULL; | ||
338 | } else { | ||
339 | current_rng = list_entry(rng_list.prev, struct hwrng, list); | ||
340 | err = hwrng_init(current_rng); | ||
341 | if (err) | ||
342 | current_rng = NULL; | ||
343 | } | ||
344 | } | ||
345 | if (list_empty(&rng_list)) | ||
346 | unregister_miscdev(); | ||
347 | |||
348 | mutex_unlock(&rng_mutex); | ||
349 | } | ||
350 | EXPORT_SYMBOL_GPL(hwrng_unregister); | ||
351 | |||
352 | |||
353 | MODULE_DESCRIPTION("H/W Random Number Generator (RNG) driver"); | ||
354 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/char/hw_random/geode-rng.c b/drivers/char/hw_random/geode-rng.c new file mode 100644 index 000000000000..be61f22ee7bb --- /dev/null +++ b/drivers/char/hw_random/geode-rng.c | |||
@@ -0,0 +1,128 @@ | |||
1 | /* | ||
2 | * RNG driver for AMD Geode RNGs | ||
3 | * | ||
4 | * Copyright 2005 (c) MontaVista Software, Inc. | ||
5 | * | ||
6 | * with the majority of the code coming from: | ||
7 | * | ||
8 | * Hardware driver for the Intel/AMD/VIA Random Number Generators (RNG) | ||
9 | * (c) Copyright 2003 Red Hat Inc <jgarzik@redhat.com> | ||
10 | * | ||
11 | * derived from | ||
12 | * | ||
13 | * Hardware driver for the AMD 768 Random Number Generator (RNG) | ||
14 | * (c) Copyright 2001 Red Hat Inc <alan@redhat.com> | ||
15 | * | ||
16 | * derived from | ||
17 | * | ||
18 | * Hardware driver for Intel i810 Random Number Generator (RNG) | ||
19 | * Copyright 2000,2001 Jeff Garzik <jgarzik@pobox.com> | ||
20 | * Copyright 2000,2001 Philipp Rumpf <prumpf@mandrakesoft.com> | ||
21 | * | ||
22 | * This file is licensed under the terms of the GNU General Public | ||
23 | * License version 2. This program is licensed "as is" without any | ||
24 | * warranty of any kind, whether express or implied. | ||
25 | */ | ||
26 | |||
27 | #include <linux/module.h> | ||
28 | #include <linux/kernel.h> | ||
29 | #include <linux/pci.h> | ||
30 | #include <linux/hw_random.h> | ||
31 | #include <asm/io.h> | ||
32 | |||
33 | |||
34 | #define PFX KBUILD_MODNAME ": " | ||
35 | |||
36 | #define GEODE_RNG_DATA_REG 0x50 | ||
37 | #define GEODE_RNG_STATUS_REG 0x54 | ||
38 | |||
39 | /* | ||
40 | * Data for PCI driver interface | ||
41 | * | ||
42 | * This data only exists for exporting the supported | ||
43 | * PCI ids via MODULE_DEVICE_TABLE. We do not actually | ||
44 | * register a pci_driver, because someone else might one day | ||
45 | * want to register another driver on the same PCI id. | ||
46 | */ | ||
47 | static const struct pci_device_id pci_tbl[] = { | ||
48 | { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LX_AES, | ||
49 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, | ||
50 | { 0, }, /* terminate list */ | ||
51 | }; | ||
52 | MODULE_DEVICE_TABLE(pci, pci_tbl); | ||
53 | |||
54 | |||
55 | static int geode_rng_data_read(struct hwrng *rng, u32 *data) | ||
56 | { | ||
57 | void __iomem *mem = (void __iomem *)rng->priv; | ||
58 | |||
59 | *data = readl(mem + GEODE_RNG_DATA_REG); | ||
60 | |||
61 | return 4; | ||
62 | } | ||
63 | |||
64 | static int geode_rng_data_present(struct hwrng *rng) | ||
65 | { | ||
66 | void __iomem *mem = (void __iomem *)rng->priv; | ||
67 | |||
68 | return !!(readl(mem + GEODE_RNG_STATUS_REG)); | ||
69 | } | ||
70 | |||
71 | |||
72 | static struct hwrng geode_rng = { | ||
73 | .name = "geode", | ||
74 | .data_present = geode_rng_data_present, | ||
75 | .data_read = geode_rng_data_read, | ||
76 | }; | ||
77 | |||
78 | |||
79 | static int __init mod_init(void) | ||
80 | { | ||
81 | int err = -ENODEV; | ||
82 | struct pci_dev *pdev = NULL; | ||
83 | const struct pci_device_id *ent; | ||
84 | void __iomem *mem; | ||
85 | unsigned long rng_base; | ||
86 | |||
87 | for_each_pci_dev(pdev) { | ||
88 | ent = pci_match_id(pci_tbl, pdev); | ||
89 | if (ent) | ||
90 | goto found; | ||
91 | } | ||
92 | /* Device not found. */ | ||
93 | goto out; | ||
94 | |||
95 | found: | ||
96 | rng_base = pci_resource_start(pdev, 0); | ||
97 | if (rng_base == 0) | ||
98 | goto out; | ||
99 | err = -ENOMEM; | ||
100 | mem = ioremap(rng_base, 0x58); | ||
101 | if (!mem) | ||
102 | goto out; | ||
103 | geode_rng.priv = (unsigned long)mem; | ||
104 | |||
105 | printk(KERN_INFO "AMD Geode RNG detected\n"); | ||
106 | err = hwrng_register(&geode_rng); | ||
107 | if (err) { | ||
108 | printk(KERN_ERR PFX "RNG registering failed (%d)\n", | ||
109 | err); | ||
110 | goto out; | ||
111 | } | ||
112 | out: | ||
113 | return err; | ||
114 | } | ||
115 | |||
116 | static void __exit mod_exit(void) | ||
117 | { | ||
118 | void __iomem *mem = (void __iomem *)geode_rng.priv; | ||
119 | |||
120 | hwrng_unregister(&geode_rng); | ||
121 | iounmap(mem); | ||
122 | } | ||
123 | |||
124 | subsys_initcall(mod_init); | ||
125 | module_exit(mod_exit); | ||
126 | |||
127 | MODULE_DESCRIPTION("H/W RNG driver for AMD Geode LX CPUs"); | ||
128 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/char/hw_random/intel-rng.c b/drivers/char/hw_random/intel-rng.c new file mode 100644 index 000000000000..6594bd5645f4 --- /dev/null +++ b/drivers/char/hw_random/intel-rng.c | |||
@@ -0,0 +1,189 @@ | |||
1 | /* | ||
2 | * RNG driver for Intel RNGs | ||
3 | * | ||
4 | * Copyright 2005 (c) MontaVista Software, Inc. | ||
5 | * | ||
6 | * with the majority of the code coming from: | ||
7 | * | ||
8 | * Hardware driver for the Intel/AMD/VIA Random Number Generators (RNG) | ||
9 | * (c) Copyright 2003 Red Hat Inc <jgarzik@redhat.com> | ||
10 | * | ||
11 | * derived from | ||
12 | * | ||
13 | * Hardware driver for the AMD 768 Random Number Generator (RNG) | ||
14 | * (c) Copyright 2001 Red Hat Inc <alan@redhat.com> | ||
15 | * | ||
16 | * derived from | ||
17 | * | ||
18 | * Hardware driver for Intel i810 Random Number Generator (RNG) | ||
19 | * Copyright 2000,2001 Jeff Garzik <jgarzik@pobox.com> | ||
20 | * Copyright 2000,2001 Philipp Rumpf <prumpf@mandrakesoft.com> | ||
21 | * | ||
22 | * This file is licensed under the terms of the GNU General Public | ||
23 | * License version 2. This program is licensed "as is" without any | ||
24 | * warranty of any kind, whether express or implied. | ||
25 | */ | ||
26 | |||
27 | #include <linux/module.h> | ||
28 | #include <linux/kernel.h> | ||
29 | #include <linux/pci.h> | ||
30 | #include <linux/hw_random.h> | ||
31 | #include <asm/io.h> | ||
32 | |||
33 | |||
34 | #define PFX KBUILD_MODNAME ": " | ||
35 | |||
36 | /* | ||
37 | * RNG registers | ||
38 | */ | ||
39 | #define INTEL_RNG_HW_STATUS 0 | ||
40 | #define INTEL_RNG_PRESENT 0x40 | ||
41 | #define INTEL_RNG_ENABLED 0x01 | ||
42 | #define INTEL_RNG_STATUS 1 | ||
43 | #define INTEL_RNG_DATA_PRESENT 0x01 | ||
44 | #define INTEL_RNG_DATA 2 | ||
45 | |||
46 | /* | ||
47 | * Magic address at which Intel PCI bridges locate the RNG | ||
48 | */ | ||
49 | #define INTEL_RNG_ADDR 0xFFBC015F | ||
50 | #define INTEL_RNG_ADDR_LEN 3 | ||
51 | |||
52 | /* | ||
53 | * Data for PCI driver interface | ||
54 | * | ||
55 | * This data only exists for exporting the supported | ||
56 | * PCI ids via MODULE_DEVICE_TABLE. We do not actually | ||
57 | * register a pci_driver, because someone else might one day | ||
58 | * want to register another driver on the same PCI id. | ||
59 | */ | ||
60 | static const struct pci_device_id pci_tbl[] = { | ||
61 | { 0x8086, 0x2418, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, | ||
62 | { 0x8086, 0x2428, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, | ||
63 | { 0x8086, 0x2430, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, | ||
64 | { 0x8086, 0x2448, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, | ||
65 | { 0x8086, 0x244e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, | ||
66 | { 0x8086, 0x245e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, | ||
67 | { 0, }, /* terminate list */ | ||
68 | }; | ||
69 | MODULE_DEVICE_TABLE(pci, pci_tbl); | ||
70 | |||
71 | |||
72 | static inline u8 hwstatus_get(void __iomem *mem) | ||
73 | { | ||
74 | return readb(mem + INTEL_RNG_HW_STATUS); | ||
75 | } | ||
76 | |||
77 | static inline u8 hwstatus_set(void __iomem *mem, | ||
78 | u8 hw_status) | ||
79 | { | ||
80 | writeb(hw_status, mem + INTEL_RNG_HW_STATUS); | ||
81 | return hwstatus_get(mem); | ||
82 | } | ||
83 | |||
84 | static int intel_rng_data_present(struct hwrng *rng) | ||
85 | { | ||
86 | void __iomem *mem = (void __iomem *)rng->priv; | ||
87 | |||
88 | return !!(readb(mem + INTEL_RNG_STATUS) & INTEL_RNG_DATA_PRESENT); | ||
89 | } | ||
90 | |||
91 | static int intel_rng_data_read(struct hwrng *rng, u32 *data) | ||
92 | { | ||
93 | void __iomem *mem = (void __iomem *)rng->priv; | ||
94 | |||
95 | *data = readb(mem + INTEL_RNG_DATA); | ||
96 | |||
97 | return 1; | ||
98 | } | ||
99 | |||
100 | static int intel_rng_init(struct hwrng *rng) | ||
101 | { | ||
102 | void __iomem *mem = (void __iomem *)rng->priv; | ||
103 | u8 hw_status; | ||
104 | int err = -EIO; | ||
105 | |||
106 | hw_status = hwstatus_get(mem); | ||
107 | /* turn RNG h/w on, if it's off */ | ||
108 | if ((hw_status & INTEL_RNG_ENABLED) == 0) | ||
109 | hw_status = hwstatus_set(mem, hw_status | INTEL_RNG_ENABLED); | ||
110 | if ((hw_status & INTEL_RNG_ENABLED) == 0) { | ||
111 | printk(KERN_ERR PFX "cannot enable RNG, aborting\n"); | ||
112 | goto out; | ||
113 | } | ||
114 | err = 0; | ||
115 | out: | ||
116 | return err; | ||
117 | } | ||
118 | |||
119 | static void intel_rng_cleanup(struct hwrng *rng) | ||
120 | { | ||
121 | void __iomem *mem = (void __iomem *)rng->priv; | ||
122 | u8 hw_status; | ||
123 | |||
124 | hw_status = hwstatus_get(mem); | ||
125 | if (hw_status & INTEL_RNG_ENABLED) | ||
126 | hwstatus_set(mem, hw_status & ~INTEL_RNG_ENABLED); | ||
127 | else | ||
128 | printk(KERN_WARNING PFX "unusual: RNG already disabled\n"); | ||
129 | } | ||
130 | |||
131 | |||
132 | static struct hwrng intel_rng = { | ||
133 | .name = "intel", | ||
134 | .init = intel_rng_init, | ||
135 | .cleanup = intel_rng_cleanup, | ||
136 | .data_present = intel_rng_data_present, | ||
137 | .data_read = intel_rng_data_read, | ||
138 | }; | ||
139 | |||
140 | |||
141 | static int __init mod_init(void) | ||
142 | { | ||
143 | int err = -ENODEV; | ||
144 | void __iomem *mem; | ||
145 | u8 hw_status; | ||
146 | |||
147 | if (!pci_dev_present(pci_tbl)) | ||
148 | goto out; /* Device not found. */ | ||
149 | |||
150 | err = -ENOMEM; | ||
151 | mem = ioremap(INTEL_RNG_ADDR, INTEL_RNG_ADDR_LEN); | ||
152 | if (!mem) | ||
153 | goto out; | ||
154 | intel_rng.priv = (unsigned long)mem; | ||
155 | |||
156 | /* Check for Intel 82802 */ | ||
157 | err = -ENODEV; | ||
158 | hw_status = hwstatus_get(mem); | ||
159 | if ((hw_status & INTEL_RNG_PRESENT) == 0) | ||
160 | goto err_unmap; | ||
161 | |||
162 | printk(KERN_INFO "Intel 82802 RNG detected\n"); | ||
163 | err = hwrng_register(&intel_rng); | ||
164 | if (err) { | ||
165 | printk(KERN_ERR PFX "RNG registering failed (%d)\n", | ||
166 | err); | ||
167 | goto out; | ||
168 | } | ||
169 | out: | ||
170 | return err; | ||
171 | |||
172 | err_unmap: | ||
173 | iounmap(mem); | ||
174 | goto out; | ||
175 | } | ||
176 | |||
177 | static void __exit mod_exit(void) | ||
178 | { | ||
179 | void __iomem *mem = (void __iomem *)intel_rng.priv; | ||
180 | |||
181 | hwrng_unregister(&intel_rng); | ||
182 | iounmap(mem); | ||
183 | } | ||
184 | |||
185 | subsys_initcall(mod_init); | ||
186 | module_exit(mod_exit); | ||
187 | |||
188 | MODULE_DESCRIPTION("H/W RNG driver for Intel chipsets"); | ||
189 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/char/hw_random/ixp4xx-rng.c b/drivers/char/hw_random/ixp4xx-rng.c new file mode 100644 index 000000000000..ef71022423c9 --- /dev/null +++ b/drivers/char/hw_random/ixp4xx-rng.c | |||
@@ -0,0 +1,73 @@ | |||
1 | /* | ||
2 | * drivers/char/rng/ixp4xx-rng.c | ||
3 | * | ||
4 | * RNG driver for Intel IXP4xx family of NPUs | ||
5 | * | ||
6 | * Author: Deepak Saxena <dsaxena@plexity.net> | ||
7 | * | ||
8 | * Copyright 2005 (c) MontaVista Software, Inc. | ||
9 | * | ||
10 | * Fixes by Michael Buesch | ||
11 | * | ||
12 | * This file is licensed under the terms of the GNU General Public | ||
13 | * License version 2. This program is licensed "as is" without any | ||
14 | * warranty of any kind, whether express or implied. | ||
15 | */ | ||
16 | |||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/config.h> | ||
19 | #include <linux/types.h> | ||
20 | #include <linux/module.h> | ||
21 | #include <linux/moduleparam.h> | ||
22 | #include <linux/init.h> | ||
23 | #include <linux/bitops.h> | ||
24 | #include <linux/hw_random.h> | ||
25 | |||
26 | #include <asm/io.h> | ||
27 | #include <asm/hardware.h> | ||
28 | |||
29 | |||
30 | static int ixp4xx_rng_data_read(struct hwrng *rng, u32 *buffer) | ||
31 | { | ||
32 | void __iomem * rng_base = (void __iomem *)rng->priv; | ||
33 | |||
34 | *buffer = __raw_readl(rng_base); | ||
35 | |||
36 | return 4; | ||
37 | } | ||
38 | |||
39 | static struct hwrng ixp4xx_rng_ops = { | ||
40 | .name = "ixp4xx", | ||
41 | .data_read = ixp4xx_rng_data_read, | ||
42 | }; | ||
43 | |||
44 | static int __init ixp4xx_rng_init(void) | ||
45 | { | ||
46 | void __iomem * rng_base; | ||
47 | int err; | ||
48 | |||
49 | rng_base = ioremap(0x70002100, 4); | ||
50 | if (!rng_base) | ||
51 | return -ENOMEM; | ||
52 | ixp4xx_rng_ops.priv = (unsigned long)rng_base; | ||
53 | err = hwrng_register(&ixp4xx_rng_ops); | ||
54 | if (err) | ||
55 | iounmap(rng_base); | ||
56 | |||
57 | return err; | ||
58 | } | ||
59 | |||
60 | static void __exit ixp4xx_rng_exit(void) | ||
61 | { | ||
62 | void __iomem * rng_base = (void __iomem *)ixp4xx_rng_ops.priv; | ||
63 | |||
64 | hwrng_unregister(&ixp4xx_rng_ops); | ||
65 | iounmap(rng_base); | ||
66 | } | ||
67 | |||
68 | subsys_initcall(ixp4xx_rng_init); | ||
69 | module_exit(ixp4xx_rng_exit); | ||
70 | |||
71 | MODULE_AUTHOR("Deepak Saxena <dsaxena@plexity.net>"); | ||
72 | MODULE_DESCRIPTION("H/W Random Number Generator (RNG) driver for IXP4xx"); | ||
73 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/char/hw_random/omap-rng.c b/drivers/char/hw_random/omap-rng.c new file mode 100644 index 000000000000..819516b35a79 --- /dev/null +++ b/drivers/char/hw_random/omap-rng.c | |||
@@ -0,0 +1,208 @@ | |||
1 | /* | ||
2 | * driver/char/hw_random/omap-rng.c | ||
3 | * | ||
4 | * RNG driver for TI OMAP CPU family | ||
5 | * | ||
6 | * Author: Deepak Saxena <dsaxena@plexity.net> | ||
7 | * | ||
8 | * Copyright 2005 (c) MontaVista Software, Inc. | ||
9 | * | ||
10 | * Mostly based on original driver: | ||
11 | * | ||
12 | * Copyright (C) 2005 Nokia Corporation | ||
13 | * Author: Juha Yrj��<juha.yrjola@nokia.com> | ||
14 | * | ||
15 | * This file is licensed under the terms of the GNU General Public | ||
16 | * License version 2. This program is licensed "as is" without any | ||
17 | * warranty of any kind, whether express or implied. | ||
18 | * | ||
19 | * TODO: | ||
20 | * | ||
21 | * - Make status updated be interrupt driven so we don't poll | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #include <linux/module.h> | ||
26 | #include <linux/init.h> | ||
27 | #include <linux/random.h> | ||
28 | #include <linux/err.h> | ||
29 | #include <linux/device.h> | ||
30 | #include <linux/hw_random.h> | ||
31 | |||
32 | #include <asm/io.h> | ||
33 | #include <asm/hardware/clock.h> | ||
34 | |||
35 | #define RNG_OUT_REG 0x00 /* Output register */ | ||
36 | #define RNG_STAT_REG 0x04 /* Status register | ||
37 | [0] = STAT_BUSY */ | ||
38 | #define RNG_ALARM_REG 0x24 /* Alarm register | ||
39 | [7:0] = ALARM_COUNTER */ | ||
40 | #define RNG_CONFIG_REG 0x28 /* Configuration register | ||
41 | [11:6] = RESET_COUNT | ||
42 | [5:3] = RING2_DELAY | ||
43 | [2:0] = RING1_DELAY */ | ||
44 | #define RNG_REV_REG 0x3c /* Revision register | ||
45 | [7:0] = REV_NB */ | ||
46 | #define RNG_MASK_REG 0x40 /* Mask and reset register | ||
47 | [2] = IT_EN | ||
48 | [1] = SOFTRESET | ||
49 | [0] = AUTOIDLE */ | ||
50 | #define RNG_SYSSTATUS 0x44 /* System status | ||
51 | [0] = RESETDONE */ | ||
52 | |||
53 | static void __iomem *rng_base; | ||
54 | static struct clk *rng_ick; | ||
55 | static struct device *rng_dev; | ||
56 | |||
57 | static u32 omap_rng_read_reg(int reg) | ||
58 | { | ||
59 | return __raw_readl(rng_base + reg); | ||
60 | } | ||
61 | |||
62 | static void omap_rng_write_reg(int reg, u32 val) | ||
63 | { | ||
64 | __raw_writel(val, rng_base + reg); | ||
65 | } | ||
66 | |||
67 | /* REVISIT: Does the status bit really work on 16xx? */ | ||
68 | static int omap_rng_data_present(struct hwrng *rng) | ||
69 | { | ||
70 | return omap_rng_read_reg(RNG_STAT_REG) ? 0 : 1; | ||
71 | } | ||
72 | |||
73 | static int omap_rng_data_read(struct hwrng *rng, u32 *data) | ||
74 | { | ||
75 | *data = omap_rng_read_reg(RNG_OUT_REG); | ||
76 | |||
77 | return 4; | ||
78 | } | ||
79 | |||
80 | static struct hwrng omap_rng_ops = { | ||
81 | .name = "omap", | ||
82 | .data_present = omap_rng_data_present, | ||
83 | .data_read = omap_rng_data_read, | ||
84 | }; | ||
85 | |||
86 | static int __init omap_rng_probe(struct device *dev) | ||
87 | { | ||
88 | struct platform_device *pdev = to_platform_device(dev); | ||
89 | struct resource *res, *mem; | ||
90 | int ret; | ||
91 | |||
92 | /* | ||
93 | * A bit ugly, and it will never actually happen but there can | ||
94 | * be only one RNG and this catches any bork | ||
95 | */ | ||
96 | BUG_ON(rng_dev); | ||
97 | |||
98 | if (cpu_is_omap24xx()) { | ||
99 | rng_ick = clk_get(NULL, "rng_ick"); | ||
100 | if (IS_ERR(rng_ick)) { | ||
101 | dev_err(dev, "Could not get rng_ick\n"); | ||
102 | ret = PTR_ERR(rng_ick); | ||
103 | return ret; | ||
104 | } | ||
105 | else { | ||
106 | clk_use(rng_ick); | ||
107 | } | ||
108 | } | ||
109 | |||
110 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
111 | |||
112 | if (!res) | ||
113 | return -ENOENT; | ||
114 | |||
115 | mem = request_mem_region(res->start, res->end - res->start + 1, | ||
116 | pdev->name); | ||
117 | if (mem == NULL) | ||
118 | return -EBUSY; | ||
119 | |||
120 | dev_set_drvdata(dev, mem); | ||
121 | rng_base = (u32 __iomem *)io_p2v(res->start); | ||
122 | |||
123 | ret = hwrng_register(&omap_rng_ops); | ||
124 | if (ret) { | ||
125 | release_resource(mem); | ||
126 | rng_base = NULL; | ||
127 | return ret; | ||
128 | } | ||
129 | |||
130 | dev_info(dev, "OMAP Random Number Generator ver. %02x\n", | ||
131 | omap_rng_read_reg(RNG_REV_REG)); | ||
132 | omap_rng_write_reg(RNG_MASK_REG, 0x1); | ||
133 | |||
134 | rng_dev = dev; | ||
135 | |||
136 | return 0; | ||
137 | } | ||
138 | |||
139 | static int __exit omap_rng_remove(struct device *dev) | ||
140 | { | ||
141 | struct resource *mem = dev_get_drvdata(dev); | ||
142 | |||
143 | hwrng_unregister(&omap_rng_ops); | ||
144 | |||
145 | omap_rng_write_reg(RNG_MASK_REG, 0x0); | ||
146 | |||
147 | if (cpu_is_omap24xx()) { | ||
148 | clk_unuse(rng_ick); | ||
149 | clk_put(rng_ick); | ||
150 | } | ||
151 | |||
152 | release_resource(mem); | ||
153 | rng_base = NULL; | ||
154 | |||
155 | return 0; | ||
156 | } | ||
157 | |||
158 | #ifdef CONFIG_PM | ||
159 | |||
160 | static int omap_rng_suspend(struct device *dev, pm_message_t message, u32 level) | ||
161 | { | ||
162 | omap_rng_write_reg(RNG_MASK_REG, 0x0); | ||
163 | |||
164 | return 0; | ||
165 | } | ||
166 | |||
167 | static int omap_rng_resume(struct device *dev, pm_message_t message, u32 level) | ||
168 | { | ||
169 | omap_rng_write_reg(RNG_MASK_REG, 0x1); | ||
170 | |||
171 | return 1; | ||
172 | } | ||
173 | |||
174 | #else | ||
175 | |||
176 | #define omap_rng_suspend NULL | ||
177 | #define omap_rng_resume NULL | ||
178 | |||
179 | #endif | ||
180 | |||
181 | |||
182 | static struct device_driver omap_rng_driver = { | ||
183 | .name = "omap_rng", | ||
184 | .bus = &platform_bus_type, | ||
185 | .probe = omap_rng_probe, | ||
186 | .remove = __exit_p(omap_rng_remove), | ||
187 | .suspend = omap_rng_suspend, | ||
188 | .resume = omap_rng_resume | ||
189 | }; | ||
190 | |||
191 | static int __init omap_rng_init(void) | ||
192 | { | ||
193 | if (!cpu_is_omap16xx() && !cpu_is_omap24xx()) | ||
194 | return -ENODEV; | ||
195 | |||
196 | return driver_register(&omap_rng_driver); | ||
197 | } | ||
198 | |||
199 | static void __exit omap_rng_exit(void) | ||
200 | { | ||
201 | driver_unregister(&omap_rng_driver); | ||
202 | } | ||
203 | |||
204 | module_init(omap_rng_init); | ||
205 | module_exit(omap_rng_exit); | ||
206 | |||
207 | MODULE_AUTHOR("Deepak Saxena (and others)"); | ||
208 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/char/hw_random/via-rng.c b/drivers/char/hw_random/via-rng.c new file mode 100644 index 000000000000..0e786b617bb8 --- /dev/null +++ b/drivers/char/hw_random/via-rng.c | |||
@@ -0,0 +1,183 @@ | |||
1 | /* | ||
2 | * RNG driver for VIA RNGs | ||
3 | * | ||
4 | * Copyright 2005 (c) MontaVista Software, Inc. | ||
5 | * | ||
6 | * with the majority of the code coming from: | ||
7 | * | ||
8 | * Hardware driver for the Intel/AMD/VIA Random Number Generators (RNG) | ||
9 | * (c) Copyright 2003 Red Hat Inc <jgarzik@redhat.com> | ||
10 | * | ||
11 | * derived from | ||
12 | * | ||
13 | * Hardware driver for the AMD 768 Random Number Generator (RNG) | ||
14 | * (c) Copyright 2001 Red Hat Inc <alan@redhat.com> | ||
15 | * | ||
16 | * derived from | ||
17 | * | ||
18 | * Hardware driver for Intel i810 Random Number Generator (RNG) | ||
19 | * Copyright 2000,2001 Jeff Garzik <jgarzik@pobox.com> | ||
20 | * Copyright 2000,2001 Philipp Rumpf <prumpf@mandrakesoft.com> | ||
21 | * | ||
22 | * This file is licensed under the terms of the GNU General Public | ||
23 | * License version 2. This program is licensed "as is" without any | ||
24 | * warranty of any kind, whether express or implied. | ||
25 | */ | ||
26 | |||
27 | #include <linux/module.h> | ||
28 | #include <linux/kernel.h> | ||
29 | #include <linux/pci.h> | ||
30 | #include <linux/hw_random.h> | ||
31 | #include <asm/io.h> | ||
32 | #include <asm/msr.h> | ||
33 | #include <asm/cpufeature.h> | ||
34 | |||
35 | |||
36 | #define PFX KBUILD_MODNAME ": " | ||
37 | |||
38 | |||
39 | enum { | ||
40 | VIA_STRFILT_CNT_SHIFT = 16, | ||
41 | VIA_STRFILT_FAIL = (1 << 15), | ||
42 | VIA_STRFILT_ENABLE = (1 << 14), | ||
43 | VIA_RAWBITS_ENABLE = (1 << 13), | ||
44 | VIA_RNG_ENABLE = (1 << 6), | ||
45 | VIA_XSTORE_CNT_MASK = 0x0F, | ||
46 | |||
47 | VIA_RNG_CHUNK_8 = 0x00, /* 64 rand bits, 64 stored bits */ | ||
48 | VIA_RNG_CHUNK_4 = 0x01, /* 32 rand bits, 32 stored bits */ | ||
49 | VIA_RNG_CHUNK_4_MASK = 0xFFFFFFFF, | ||
50 | VIA_RNG_CHUNK_2 = 0x02, /* 16 rand bits, 32 stored bits */ | ||
51 | VIA_RNG_CHUNK_2_MASK = 0xFFFF, | ||
52 | VIA_RNG_CHUNK_1 = 0x03, /* 8 rand bits, 32 stored bits */ | ||
53 | VIA_RNG_CHUNK_1_MASK = 0xFF, | ||
54 | }; | ||
55 | |||
56 | /* | ||
57 | * Investigate using the 'rep' prefix to obtain 32 bits of random data | ||
58 | * in one insn. The upside is potentially better performance. The | ||
59 | * downside is that the instruction becomes no longer atomic. Due to | ||
60 | * this, just like familiar issues with /dev/random itself, the worst | ||
61 | * case of a 'rep xstore' could potentially pause a cpu for an | ||
62 | * unreasonably long time. In practice, this condition would likely | ||
63 | * only occur when the hardware is failing. (or so we hope :)) | ||
64 | * | ||
65 | * Another possible performance boost may come from simply buffering | ||
66 | * until we have 4 bytes, thus returning a u32 at a time, | ||
67 | * instead of the current u8-at-a-time. | ||
68 | */ | ||
69 | |||
70 | static inline u32 xstore(u32 *addr, u32 edx_in) | ||
71 | { | ||
72 | u32 eax_out; | ||
73 | |||
74 | asm(".byte 0x0F,0xA7,0xC0 /* xstore %%edi (addr=%0) */" | ||
75 | :"=m"(*addr), "=a"(eax_out) | ||
76 | :"D"(addr), "d"(edx_in)); | ||
77 | |||
78 | return eax_out; | ||
79 | } | ||
80 | |||
81 | static int via_rng_data_present(struct hwrng *rng) | ||
82 | { | ||
83 | u32 bytes_out; | ||
84 | u32 *via_rng_datum = (u32 *)(&rng->priv); | ||
85 | |||
86 | /* We choose the recommended 1-byte-per-instruction RNG rate, | ||
87 | * for greater randomness at the expense of speed. Larger | ||
88 | * values 2, 4, or 8 bytes-per-instruction yield greater | ||
89 | * speed at lesser randomness. | ||
90 | * | ||
91 | * If you change this to another VIA_CHUNK_n, you must also | ||
92 | * change the ->n_bytes values in rng_vendor_ops[] tables. | ||
93 | * VIA_CHUNK_8 requires further code changes. | ||
94 | * | ||
95 | * A copy of MSR_VIA_RNG is placed in eax_out when xstore | ||
96 | * completes. | ||
97 | */ | ||
98 | |||
99 | *via_rng_datum = 0; /* paranoia, not really necessary */ | ||
100 | bytes_out = xstore(via_rng_datum, VIA_RNG_CHUNK_1); | ||
101 | bytes_out &= VIA_XSTORE_CNT_MASK; | ||
102 | if (bytes_out == 0) | ||
103 | return 0; | ||
104 | return 1; | ||
105 | } | ||
106 | |||
107 | static int via_rng_data_read(struct hwrng *rng, u32 *data) | ||
108 | { | ||
109 | u32 via_rng_datum = (u32)rng->priv; | ||
110 | |||
111 | *data = via_rng_datum; | ||
112 | |||
113 | return 1; | ||
114 | } | ||
115 | |||
116 | static int via_rng_init(struct hwrng *rng) | ||
117 | { | ||
118 | u32 lo, hi, old_lo; | ||
119 | |||
120 | /* Control the RNG via MSR. Tread lightly and pay very close | ||
121 | * close attention to values written, as the reserved fields | ||
122 | * are documented to be "undefined and unpredictable"; but it | ||
123 | * does not say to write them as zero, so I make a guess that | ||
124 | * we restore the values we find in the register. | ||
125 | */ | ||
126 | rdmsr(MSR_VIA_RNG, lo, hi); | ||
127 | |||
128 | old_lo = lo; | ||
129 | lo &= ~(0x7f << VIA_STRFILT_CNT_SHIFT); | ||
130 | lo &= ~VIA_XSTORE_CNT_MASK; | ||
131 | lo &= ~(VIA_STRFILT_ENABLE | VIA_STRFILT_FAIL | VIA_RAWBITS_ENABLE); | ||
132 | lo |= VIA_RNG_ENABLE; | ||
133 | |||
134 | if (lo != old_lo) | ||
135 | wrmsr(MSR_VIA_RNG, lo, hi); | ||
136 | |||
137 | /* perhaps-unnecessary sanity check; remove after testing if | ||
138 | unneeded */ | ||
139 | rdmsr(MSR_VIA_RNG, lo, hi); | ||
140 | if ((lo & VIA_RNG_ENABLE) == 0) { | ||
141 | printk(KERN_ERR PFX "cannot enable VIA C3 RNG, aborting\n"); | ||
142 | return -ENODEV; | ||
143 | } | ||
144 | |||
145 | return 0; | ||
146 | } | ||
147 | |||
148 | |||
149 | static struct hwrng via_rng = { | ||
150 | .name = "via", | ||
151 | .init = via_rng_init, | ||
152 | .data_present = via_rng_data_present, | ||
153 | .data_read = via_rng_data_read, | ||
154 | }; | ||
155 | |||
156 | |||
157 | static int __init mod_init(void) | ||
158 | { | ||
159 | int err; | ||
160 | |||
161 | if (!cpu_has_xstore) | ||
162 | return -ENODEV; | ||
163 | printk(KERN_INFO "VIA RNG detected\n"); | ||
164 | err = hwrng_register(&via_rng); | ||
165 | if (err) { | ||
166 | printk(KERN_ERR PFX "RNG registering failed (%d)\n", | ||
167 | err); | ||
168 | goto out; | ||
169 | } | ||
170 | out: | ||
171 | return err; | ||
172 | } | ||
173 | |||
174 | static void __exit mod_exit(void) | ||
175 | { | ||
176 | hwrng_unregister(&via_rng); | ||
177 | } | ||
178 | |||
179 | subsys_initcall(mod_init); | ||
180 | module_exit(mod_exit); | ||
181 | |||
182 | MODULE_DESCRIPTION("H/W RNG driver for VIA chipsets"); | ||
183 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index 9f2f8fdec69a..23028559dbc4 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c | |||
@@ -936,11 +936,8 @@ int ipmi_set_gets_events(ipmi_user_t user, int val) | |||
936 | 936 | ||
937 | if (val) { | 937 | if (val) { |
938 | /* Deliver any queued events. */ | 938 | /* Deliver any queued events. */ |
939 | list_for_each_entry_safe(msg, msg2, &intf->waiting_events, | 939 | list_for_each_entry_safe(msg, msg2, &intf->waiting_events, link) |
940 | link) { | 940 | list_move_tail(&msg->link, &msgs); |
941 | list_del(&msg->link); | ||
942 | list_add_tail(&msg->link, &msgs); | ||
943 | } | ||
944 | intf->waiting_events_count = 0; | 941 | intf->waiting_events_count = 0; |
945 | } | 942 | } |
946 | 943 | ||
diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c index 6cb85dcbbc83..4bb3d2272604 100644 --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c | |||
@@ -151,6 +151,7 @@ unsigned char kbd_sysrq_xlate[KEY_MAX + 1] = | |||
151 | "230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */ | 151 | "230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */ |
152 | "\r\000/"; /* 0x60 - 0x6f */ | 152 | "\r\000/"; /* 0x60 - 0x6f */ |
153 | static int sysrq_down; | 153 | static int sysrq_down; |
154 | static int sysrq_alt_use; | ||
154 | #endif | 155 | #endif |
155 | static int sysrq_alt; | 156 | static int sysrq_alt; |
156 | 157 | ||
@@ -1145,7 +1146,7 @@ static void kbd_keycode(unsigned int keycode, int down, | |||
1145 | kbd = kbd_table + fg_console; | 1146 | kbd = kbd_table + fg_console; |
1146 | 1147 | ||
1147 | if (keycode == KEY_LEFTALT || keycode == KEY_RIGHTALT) | 1148 | if (keycode == KEY_LEFTALT || keycode == KEY_RIGHTALT) |
1148 | sysrq_alt = down; | 1149 | sysrq_alt = down ? keycode : 0; |
1149 | #ifdef CONFIG_SPARC | 1150 | #ifdef CONFIG_SPARC |
1150 | if (keycode == KEY_STOP) | 1151 | if (keycode == KEY_STOP) |
1151 | sparc_l1_a_state = down; | 1152 | sparc_l1_a_state = down; |
@@ -1165,9 +1166,14 @@ static void kbd_keycode(unsigned int keycode, int down, | |||
1165 | 1166 | ||
1166 | #ifdef CONFIG_MAGIC_SYSRQ /* Handle the SysRq Hack */ | 1167 | #ifdef CONFIG_MAGIC_SYSRQ /* Handle the SysRq Hack */ |
1167 | if (keycode == KEY_SYSRQ && (sysrq_down || (down == 1 && sysrq_alt))) { | 1168 | if (keycode == KEY_SYSRQ && (sysrq_down || (down == 1 && sysrq_alt))) { |
1168 | sysrq_down = down; | 1169 | if (!sysrq_down) { |
1170 | sysrq_down = down; | ||
1171 | sysrq_alt_use = sysrq_alt; | ||
1172 | } | ||
1169 | return; | 1173 | return; |
1170 | } | 1174 | } |
1175 | if (sysrq_down && !down && keycode == sysrq_alt_use) | ||
1176 | sysrq_down = 0; | ||
1171 | if (sysrq_down && down && !rep) { | 1177 | if (sysrq_down && down && !rep) { |
1172 | handle_sysrq(kbd_sysrq_xlate[keycode], regs, tty); | 1178 | handle_sysrq(kbd_sysrq_xlate[keycode], regs, tty); |
1173 | return; | 1179 | return; |
diff --git a/drivers/char/vt.c b/drivers/char/vt.c index 6c94879e0b99..714d95ff2f1e 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c | |||
@@ -98,7 +98,22 @@ | |||
98 | #include <asm/system.h> | 98 | #include <asm/system.h> |
99 | #include <asm/uaccess.h> | 99 | #include <asm/uaccess.h> |
100 | 100 | ||
101 | #define MAX_NR_CON_DRIVER 16 | ||
101 | 102 | ||
103 | #define CON_DRIVER_FLAG_MODULE 1 | ||
104 | #define CON_DRIVER_FLAG_INIT 2 | ||
105 | |||
106 | struct con_driver { | ||
107 | const struct consw *con; | ||
108 | const char *desc; | ||
109 | struct class_device *class_dev; | ||
110 | int node; | ||
111 | int first; | ||
112 | int last; | ||
113 | int flag; | ||
114 | }; | ||
115 | |||
116 | static struct con_driver registered_con_driver[MAX_NR_CON_DRIVER]; | ||
102 | const struct consw *conswitchp; | 117 | const struct consw *conswitchp; |
103 | 118 | ||
104 | /* A bitmap for codes <32. A bit of 1 indicates that the code | 119 | /* A bitmap for codes <32. A bit of 1 indicates that the code |
@@ -2557,7 +2572,7 @@ static int __init con_init(void) | |||
2557 | { | 2572 | { |
2558 | const char *display_desc = NULL; | 2573 | const char *display_desc = NULL; |
2559 | struct vc_data *vc; | 2574 | struct vc_data *vc; |
2560 | unsigned int currcons = 0; | 2575 | unsigned int currcons = 0, i; |
2561 | 2576 | ||
2562 | acquire_console_sem(); | 2577 | acquire_console_sem(); |
2563 | 2578 | ||
@@ -2569,6 +2584,22 @@ static int __init con_init(void) | |||
2569 | return 0; | 2584 | return 0; |
2570 | } | 2585 | } |
2571 | 2586 | ||
2587 | for (i = 0; i < MAX_NR_CON_DRIVER; i++) { | ||
2588 | struct con_driver *con_driver = ®istered_con_driver[i]; | ||
2589 | |||
2590 | if (con_driver->con == NULL) { | ||
2591 | con_driver->con = conswitchp; | ||
2592 | con_driver->desc = display_desc; | ||
2593 | con_driver->flag = CON_DRIVER_FLAG_INIT; | ||
2594 | con_driver->first = 0; | ||
2595 | con_driver->last = MAX_NR_CONSOLES - 1; | ||
2596 | break; | ||
2597 | } | ||
2598 | } | ||
2599 | |||
2600 | for (i = 0; i < MAX_NR_CONSOLES; i++) | ||
2601 | con_driver_map[i] = conswitchp; | ||
2602 | |||
2572 | init_timer(&console_timer); | 2603 | init_timer(&console_timer); |
2573 | console_timer.function = blank_screen_t; | 2604 | console_timer.function = blank_screen_t; |
2574 | if (blankinterval) { | 2605 | if (blankinterval) { |
@@ -2656,38 +2687,53 @@ int __init vty_init(void) | |||
2656 | } | 2687 | } |
2657 | 2688 | ||
2658 | #ifndef VT_SINGLE_DRIVER | 2689 | #ifndef VT_SINGLE_DRIVER |
2690 | #include <linux/device.h> | ||
2659 | 2691 | ||
2660 | /* | 2692 | static struct class *vtconsole_class; |
2661 | * If we support more console drivers, this function is used | ||
2662 | * when a driver wants to take over some existing consoles | ||
2663 | * and become default driver for newly opened ones. | ||
2664 | */ | ||
2665 | 2693 | ||
2666 | int take_over_console(const struct consw *csw, int first, int last, int deflt) | 2694 | static int bind_con_driver(const struct consw *csw, int first, int last, |
2695 | int deflt) | ||
2667 | { | 2696 | { |
2668 | int i, j = -1; | 2697 | struct module *owner = csw->owner; |
2669 | const char *desc; | 2698 | const char *desc = NULL; |
2670 | struct module *owner; | 2699 | struct con_driver *con_driver; |
2700 | int i, j = -1, k = -1, retval = -ENODEV; | ||
2671 | 2701 | ||
2672 | owner = csw->owner; | ||
2673 | if (!try_module_get(owner)) | 2702 | if (!try_module_get(owner)) |
2674 | return -ENODEV; | 2703 | return -ENODEV; |
2675 | 2704 | ||
2676 | acquire_console_sem(); | 2705 | acquire_console_sem(); |
2677 | 2706 | ||
2678 | desc = csw->con_startup(); | 2707 | /* check if driver is registered */ |
2679 | if (!desc) { | 2708 | for (i = 0; i < MAX_NR_CON_DRIVER; i++) { |
2680 | release_console_sem(); | 2709 | con_driver = ®istered_con_driver[i]; |
2681 | module_put(owner); | 2710 | |
2682 | return -ENODEV; | 2711 | if (con_driver->con == csw) { |
2712 | desc = con_driver->desc; | ||
2713 | retval = 0; | ||
2714 | break; | ||
2715 | } | ||
2716 | } | ||
2717 | |||
2718 | if (retval) | ||
2719 | goto err; | ||
2720 | |||
2721 | if (!(con_driver->flag & CON_DRIVER_FLAG_INIT)) { | ||
2722 | csw->con_startup(); | ||
2723 | con_driver->flag |= CON_DRIVER_FLAG_INIT; | ||
2683 | } | 2724 | } |
2725 | |||
2684 | if (deflt) { | 2726 | if (deflt) { |
2685 | if (conswitchp) | 2727 | if (conswitchp) |
2686 | module_put(conswitchp->owner); | 2728 | module_put(conswitchp->owner); |
2729 | |||
2687 | __module_get(owner); | 2730 | __module_get(owner); |
2688 | conswitchp = csw; | 2731 | conswitchp = csw; |
2689 | } | 2732 | } |
2690 | 2733 | ||
2734 | first = max(first, con_driver->first); | ||
2735 | last = min(last, con_driver->last); | ||
2736 | |||
2691 | for (i = first; i <= last; i++) { | 2737 | for (i = first; i <= last; i++) { |
2692 | int old_was_color; | 2738 | int old_was_color; |
2693 | struct vc_data *vc = vc_cons[i].d; | 2739 | struct vc_data *vc = vc_cons[i].d; |
@@ -2701,15 +2747,17 @@ int take_over_console(const struct consw *csw, int first, int last, int deflt) | |||
2701 | continue; | 2747 | continue; |
2702 | 2748 | ||
2703 | j = i; | 2749 | j = i; |
2704 | if (CON_IS_VISIBLE(vc)) | 2750 | |
2751 | if (CON_IS_VISIBLE(vc)) { | ||
2752 | k = i; | ||
2705 | save_screen(vc); | 2753 | save_screen(vc); |
2754 | } | ||
2755 | |||
2706 | old_was_color = vc->vc_can_do_color; | 2756 | old_was_color = vc->vc_can_do_color; |
2707 | vc->vc_sw->con_deinit(vc); | 2757 | vc->vc_sw->con_deinit(vc); |
2708 | vc->vc_origin = (unsigned long)vc->vc_screenbuf; | 2758 | vc->vc_origin = (unsigned long)vc->vc_screenbuf; |
2709 | vc->vc_visible_origin = vc->vc_origin; | ||
2710 | vc->vc_scr_end = vc->vc_origin + vc->vc_screenbuf_size; | ||
2711 | vc->vc_pos = vc->vc_origin + vc->vc_size_row * vc->vc_y + 2 * vc->vc_x; | ||
2712 | visual_init(vc, i, 0); | 2759 | visual_init(vc, i, 0); |
2760 | set_origin(vc); | ||
2713 | update_attr(vc); | 2761 | update_attr(vc); |
2714 | 2762 | ||
2715 | /* If the console changed between mono <-> color, then | 2763 | /* If the console changed between mono <-> color, then |
@@ -2718,36 +2766,506 @@ int take_over_console(const struct consw *csw, int first, int last, int deflt) | |||
2718 | */ | 2766 | */ |
2719 | if (old_was_color != vc->vc_can_do_color) | 2767 | if (old_was_color != vc->vc_can_do_color) |
2720 | clear_buffer_attributes(vc); | 2768 | clear_buffer_attributes(vc); |
2721 | |||
2722 | if (CON_IS_VISIBLE(vc)) | ||
2723 | update_screen(vc); | ||
2724 | } | 2769 | } |
2770 | |||
2725 | printk("Console: switching "); | 2771 | printk("Console: switching "); |
2726 | if (!deflt) | 2772 | if (!deflt) |
2727 | printk("consoles %d-%d ", first+1, last+1); | 2773 | printk("consoles %d-%d ", first+1, last+1); |
2728 | if (j >= 0) | 2774 | if (j >= 0) { |
2775 | struct vc_data *vc = vc_cons[j].d; | ||
2776 | |||
2729 | printk("to %s %s %dx%d\n", | 2777 | printk("to %s %s %dx%d\n", |
2730 | vc_cons[j].d->vc_can_do_color ? "colour" : "mono", | 2778 | vc->vc_can_do_color ? "colour" : "mono", |
2731 | desc, vc_cons[j].d->vc_cols, vc_cons[j].d->vc_rows); | 2779 | desc, vc->vc_cols, vc->vc_rows); |
2732 | else | 2780 | |
2781 | if (k >= 0) { | ||
2782 | vc = vc_cons[k].d; | ||
2783 | update_screen(vc); | ||
2784 | } | ||
2785 | } else | ||
2733 | printk("to %s\n", desc); | 2786 | printk("to %s\n", desc); |
2734 | 2787 | ||
2788 | retval = 0; | ||
2789 | err: | ||
2735 | release_console_sem(); | 2790 | release_console_sem(); |
2791 | module_put(owner); | ||
2792 | return retval; | ||
2793 | }; | ||
2794 | |||
2795 | #ifdef CONFIG_VT_HW_CONSOLE_BINDING | ||
2796 | static int con_is_graphics(const struct consw *csw, int first, int last) | ||
2797 | { | ||
2798 | int i, retval = 0; | ||
2799 | |||
2800 | for (i = first; i <= last; i++) { | ||
2801 | struct vc_data *vc = vc_cons[i].d; | ||
2802 | |||
2803 | if (vc && vc->vc_mode == KD_GRAPHICS) { | ||
2804 | retval = 1; | ||
2805 | break; | ||
2806 | } | ||
2807 | } | ||
2808 | |||
2809 | return retval; | ||
2810 | } | ||
2811 | |||
2812 | static int unbind_con_driver(const struct consw *csw, int first, int last, | ||
2813 | int deflt) | ||
2814 | { | ||
2815 | struct module *owner = csw->owner; | ||
2816 | const struct consw *defcsw = NULL; | ||
2817 | struct con_driver *con_driver = NULL, *con_back = NULL; | ||
2818 | int i, retval = -ENODEV; | ||
2819 | |||
2820 | if (!try_module_get(owner)) | ||
2821 | return -ENODEV; | ||
2822 | |||
2823 | acquire_console_sem(); | ||
2824 | |||
2825 | /* check if driver is registered and if it is unbindable */ | ||
2826 | for (i = 0; i < MAX_NR_CON_DRIVER; i++) { | ||
2827 | con_driver = ®istered_con_driver[i]; | ||
2828 | |||
2829 | if (con_driver->con == csw && | ||
2830 | con_driver->flag & CON_DRIVER_FLAG_MODULE) { | ||
2831 | retval = 0; | ||
2832 | break; | ||
2833 | } | ||
2834 | } | ||
2835 | |||
2836 | if (retval) { | ||
2837 | release_console_sem(); | ||
2838 | goto err; | ||
2839 | } | ||
2840 | |||
2841 | retval = -ENODEV; | ||
2842 | |||
2843 | /* check if backup driver exists */ | ||
2844 | for (i = 0; i < MAX_NR_CON_DRIVER; i++) { | ||
2845 | con_back = ®istered_con_driver[i]; | ||
2846 | |||
2847 | if (con_back->con && | ||
2848 | !(con_back->flag & CON_DRIVER_FLAG_MODULE)) { | ||
2849 | defcsw = con_back->con; | ||
2850 | retval = 0; | ||
2851 | break; | ||
2852 | } | ||
2853 | } | ||
2854 | |||
2855 | if (retval) { | ||
2856 | release_console_sem(); | ||
2857 | goto err; | ||
2858 | } | ||
2859 | |||
2860 | if (!con_is_bound(csw)) { | ||
2861 | release_console_sem(); | ||
2862 | goto err; | ||
2863 | } | ||
2864 | |||
2865 | first = max(first, con_driver->first); | ||
2866 | last = min(last, con_driver->last); | ||
2867 | |||
2868 | for (i = first; i <= last; i++) { | ||
2869 | if (con_driver_map[i] == csw) { | ||
2870 | module_put(csw->owner); | ||
2871 | con_driver_map[i] = NULL; | ||
2872 | } | ||
2873 | } | ||
2874 | |||
2875 | if (!con_is_bound(defcsw)) { | ||
2876 | const struct consw *defconsw = conswitchp; | ||
2877 | |||
2878 | defcsw->con_startup(); | ||
2879 | con_back->flag |= CON_DRIVER_FLAG_INIT; | ||
2880 | /* | ||
2881 | * vgacon may change the default driver to point | ||
2882 | * to dummycon, we restore it here... | ||
2883 | */ | ||
2884 | conswitchp = defconsw; | ||
2885 | } | ||
2886 | |||
2887 | if (!con_is_bound(csw)) | ||
2888 | con_driver->flag &= ~CON_DRIVER_FLAG_INIT; | ||
2736 | 2889 | ||
2890 | release_console_sem(); | ||
2891 | /* ignore return value, binding should not fail */ | ||
2892 | bind_con_driver(defcsw, first, last, deflt); | ||
2893 | err: | ||
2737 | module_put(owner); | 2894 | module_put(owner); |
2895 | return retval; | ||
2896 | |||
2897 | } | ||
2898 | |||
2899 | static int vt_bind(struct con_driver *con) | ||
2900 | { | ||
2901 | const struct consw *defcsw = NULL, *csw = NULL; | ||
2902 | int i, more = 1, first = -1, last = -1, deflt = 0; | ||
2903 | |||
2904 | if (!con->con || !(con->flag & CON_DRIVER_FLAG_MODULE) || | ||
2905 | con_is_graphics(con->con, con->first, con->last)) | ||
2906 | goto err; | ||
2907 | |||
2908 | csw = con->con; | ||
2909 | |||
2910 | for (i = 0; i < MAX_NR_CON_DRIVER; i++) { | ||
2911 | struct con_driver *con = ®istered_con_driver[i]; | ||
2912 | |||
2913 | if (con->con && !(con->flag & CON_DRIVER_FLAG_MODULE)) { | ||
2914 | defcsw = con->con; | ||
2915 | break; | ||
2916 | } | ||
2917 | } | ||
2918 | |||
2919 | if (!defcsw) | ||
2920 | goto err; | ||
2921 | |||
2922 | while (more) { | ||
2923 | more = 0; | ||
2924 | |||
2925 | for (i = con->first; i <= con->last; i++) { | ||
2926 | if (con_driver_map[i] == defcsw) { | ||
2927 | if (first == -1) | ||
2928 | first = i; | ||
2929 | last = i; | ||
2930 | more = 1; | ||
2931 | } else if (first != -1) | ||
2932 | break; | ||
2933 | } | ||
2934 | |||
2935 | if (first == 0 && last == MAX_NR_CONSOLES -1) | ||
2936 | deflt = 1; | ||
2937 | |||
2938 | if (first != -1) | ||
2939 | bind_con_driver(csw, first, last, deflt); | ||
2940 | |||
2941 | first = -1; | ||
2942 | last = -1; | ||
2943 | deflt = 0; | ||
2944 | } | ||
2945 | |||
2946 | err: | ||
2738 | return 0; | 2947 | return 0; |
2739 | } | 2948 | } |
2740 | 2949 | ||
2741 | void give_up_console(const struct consw *csw) | 2950 | static int vt_unbind(struct con_driver *con) |
2951 | { | ||
2952 | const struct consw *csw = NULL; | ||
2953 | int i, more = 1, first = -1, last = -1, deflt = 0; | ||
2954 | |||
2955 | if (!con->con || !(con->flag & CON_DRIVER_FLAG_MODULE) || | ||
2956 | con_is_graphics(con->con, con->first, con->last)) | ||
2957 | goto err; | ||
2958 | |||
2959 | csw = con->con; | ||
2960 | |||
2961 | while (more) { | ||
2962 | more = 0; | ||
2963 | |||
2964 | for (i = con->first; i <= con->last; i++) { | ||
2965 | if (con_driver_map[i] == csw) { | ||
2966 | if (first == -1) | ||
2967 | first = i; | ||
2968 | last = i; | ||
2969 | more = 1; | ||
2970 | } else if (first != -1) | ||
2971 | break; | ||
2972 | } | ||
2973 | |||
2974 | if (first == 0 && last == MAX_NR_CONSOLES -1) | ||
2975 | deflt = 1; | ||
2976 | |||
2977 | if (first != -1) | ||
2978 | unbind_con_driver(csw, first, last, deflt); | ||
2979 | |||
2980 | first = -1; | ||
2981 | last = -1; | ||
2982 | deflt = 0; | ||
2983 | } | ||
2984 | |||
2985 | err: | ||
2986 | return 0; | ||
2987 | } | ||
2988 | #else | ||
2989 | static inline int vt_bind(struct con_driver *con) | ||
2990 | { | ||
2991 | return 0; | ||
2992 | } | ||
2993 | static inline int vt_unbind(struct con_driver *con) | ||
2994 | { | ||
2995 | return 0; | ||
2996 | } | ||
2997 | #endif /* CONFIG_VT_HW_CONSOLE_BINDING */ | ||
2998 | |||
2999 | static ssize_t store_bind(struct class_device *class_device, | ||
3000 | const char *buf, size_t count) | ||
3001 | { | ||
3002 | struct con_driver *con = class_get_devdata(class_device); | ||
3003 | int bind = simple_strtoul(buf, NULL, 0); | ||
3004 | |||
3005 | if (bind) | ||
3006 | vt_bind(con); | ||
3007 | else | ||
3008 | vt_unbind(con); | ||
3009 | |||
3010 | return count; | ||
3011 | } | ||
3012 | |||
3013 | static ssize_t show_bind(struct class_device *class_device, char *buf) | ||
3014 | { | ||
3015 | struct con_driver *con = class_get_devdata(class_device); | ||
3016 | int bind = con_is_bound(con->con); | ||
3017 | |||
3018 | return snprintf(buf, PAGE_SIZE, "%i\n", bind); | ||
3019 | } | ||
3020 | |||
3021 | static ssize_t show_name(struct class_device *class_device, char *buf) | ||
3022 | { | ||
3023 | struct con_driver *con = class_get_devdata(class_device); | ||
3024 | |||
3025 | return snprintf(buf, PAGE_SIZE, "%s %s\n", | ||
3026 | (con->flag & CON_DRIVER_FLAG_MODULE) ? "(M)" : "(S)", | ||
3027 | con->desc); | ||
3028 | |||
3029 | } | ||
3030 | |||
3031 | static struct class_device_attribute class_device_attrs[] = { | ||
3032 | __ATTR(bind, S_IRUGO|S_IWUSR, show_bind, store_bind), | ||
3033 | __ATTR(name, S_IRUGO, show_name, NULL), | ||
3034 | }; | ||
3035 | |||
3036 | static int vtconsole_init_class_device(struct con_driver *con) | ||
3037 | { | ||
3038 | int i; | ||
3039 | |||
3040 | class_set_devdata(con->class_dev, con); | ||
3041 | for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++) | ||
3042 | class_device_create_file(con->class_dev, | ||
3043 | &class_device_attrs[i]); | ||
3044 | |||
3045 | return 0; | ||
3046 | } | ||
3047 | |||
3048 | static void vtconsole_deinit_class_device(struct con_driver *con) | ||
2742 | { | 3049 | { |
2743 | int i; | 3050 | int i; |
2744 | 3051 | ||
2745 | for(i = 0; i < MAX_NR_CONSOLES; i++) | 3052 | for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++) |
3053 | class_device_remove_file(con->class_dev, | ||
3054 | &class_device_attrs[i]); | ||
3055 | } | ||
3056 | |||
3057 | /** | ||
3058 | * con_is_bound - checks if driver is bound to the console | ||
3059 | * @csw: console driver | ||
3060 | * | ||
3061 | * RETURNS: zero if unbound, nonzero if bound | ||
3062 | * | ||
3063 | * Drivers can call this and if zero, they should release | ||
3064 | * all resources allocated on con_startup() | ||
3065 | */ | ||
3066 | int con_is_bound(const struct consw *csw) | ||
3067 | { | ||
3068 | int i, bound = 0; | ||
3069 | |||
3070 | for (i = 0; i < MAX_NR_CONSOLES; i++) { | ||
2746 | if (con_driver_map[i] == csw) { | 3071 | if (con_driver_map[i] == csw) { |
2747 | module_put(csw->owner); | 3072 | bound = 1; |
2748 | con_driver_map[i] = NULL; | 3073 | break; |
3074 | } | ||
3075 | } | ||
3076 | |||
3077 | return bound; | ||
3078 | } | ||
3079 | EXPORT_SYMBOL(con_is_bound); | ||
3080 | |||
3081 | /** | ||
3082 | * register_con_driver - register console driver to console layer | ||
3083 | * @csw: console driver | ||
3084 | * @first: the first console to take over, minimum value is 0 | ||
3085 | * @last: the last console to take over, maximum value is MAX_NR_CONSOLES -1 | ||
3086 | * | ||
3087 | * DESCRIPTION: This function registers a console driver which can later | ||
3088 | * bind to a range of consoles specified by @first and @last. It will | ||
3089 | * also initialize the console driver by calling con_startup(). | ||
3090 | */ | ||
3091 | int register_con_driver(const struct consw *csw, int first, int last) | ||
3092 | { | ||
3093 | struct module *owner = csw->owner; | ||
3094 | struct con_driver *con_driver; | ||
3095 | const char *desc; | ||
3096 | int i, retval = 0; | ||
3097 | |||
3098 | if (!try_module_get(owner)) | ||
3099 | return -ENODEV; | ||
3100 | |||
3101 | acquire_console_sem(); | ||
3102 | |||
3103 | for (i = 0; i < MAX_NR_CON_DRIVER; i++) { | ||
3104 | con_driver = ®istered_con_driver[i]; | ||
3105 | |||
3106 | /* already registered */ | ||
3107 | if (con_driver->con == csw) | ||
3108 | retval = -EINVAL; | ||
3109 | } | ||
3110 | |||
3111 | if (retval) | ||
3112 | goto err; | ||
3113 | |||
3114 | desc = csw->con_startup(); | ||
3115 | |||
3116 | if (!desc) | ||
3117 | goto err; | ||
3118 | |||
3119 | retval = -EINVAL; | ||
3120 | |||
3121 | for (i = 0; i < MAX_NR_CON_DRIVER; i++) { | ||
3122 | con_driver = ®istered_con_driver[i]; | ||
3123 | |||
3124 | if (con_driver->con == NULL) { | ||
3125 | con_driver->con = csw; | ||
3126 | con_driver->desc = desc; | ||
3127 | con_driver->node = i; | ||
3128 | con_driver->flag = CON_DRIVER_FLAG_MODULE | | ||
3129 | CON_DRIVER_FLAG_INIT; | ||
3130 | con_driver->first = first; | ||
3131 | con_driver->last = last; | ||
3132 | retval = 0; | ||
3133 | break; | ||
3134 | } | ||
3135 | } | ||
3136 | |||
3137 | if (retval) | ||
3138 | goto err; | ||
3139 | |||
3140 | con_driver->class_dev = class_device_create(vtconsole_class, NULL, | ||
3141 | MKDEV(0, con_driver->node), | ||
3142 | NULL, "vtcon%i", | ||
3143 | con_driver->node); | ||
3144 | |||
3145 | if (IS_ERR(con_driver->class_dev)) { | ||
3146 | printk(KERN_WARNING "Unable to create class_device for %s; " | ||
3147 | "errno = %ld\n", con_driver->desc, | ||
3148 | PTR_ERR(con_driver->class_dev)); | ||
3149 | con_driver->class_dev = NULL; | ||
3150 | } else { | ||
3151 | vtconsole_init_class_device(con_driver); | ||
3152 | } | ||
3153 | err: | ||
3154 | release_console_sem(); | ||
3155 | module_put(owner); | ||
3156 | return retval; | ||
3157 | } | ||
3158 | EXPORT_SYMBOL(register_con_driver); | ||
3159 | |||
3160 | /** | ||
3161 | * unregister_con_driver - unregister console driver from console layer | ||
3162 | * @csw: console driver | ||
3163 | * | ||
3164 | * DESCRIPTION: All drivers that registers to the console layer must | ||
3165 | * call this function upon exit, or if the console driver is in a state | ||
3166 | * where it won't be able to handle console services, such as the | ||
3167 | * framebuffer console without loaded framebuffer drivers. | ||
3168 | * | ||
3169 | * The driver must unbind first prior to unregistration. | ||
3170 | */ | ||
3171 | int unregister_con_driver(const struct consw *csw) | ||
3172 | { | ||
3173 | int i, retval = -ENODEV; | ||
3174 | |||
3175 | acquire_console_sem(); | ||
3176 | |||
3177 | /* cannot unregister a bound driver */ | ||
3178 | if (con_is_bound(csw)) | ||
3179 | goto err; | ||
3180 | |||
3181 | for (i = 0; i < MAX_NR_CON_DRIVER; i++) { | ||
3182 | struct con_driver *con_driver = ®istered_con_driver[i]; | ||
3183 | |||
3184 | if (con_driver->con == csw && | ||
3185 | con_driver->flag & CON_DRIVER_FLAG_MODULE) { | ||
3186 | vtconsole_deinit_class_device(con_driver); | ||
3187 | class_device_destroy(vtconsole_class, | ||
3188 | MKDEV(0, con_driver->node)); | ||
3189 | con_driver->con = NULL; | ||
3190 | con_driver->desc = NULL; | ||
3191 | con_driver->class_dev = NULL; | ||
3192 | con_driver->node = 0; | ||
3193 | con_driver->flag = 0; | ||
3194 | con_driver->first = 0; | ||
3195 | con_driver->last = 0; | ||
3196 | retval = 0; | ||
3197 | break; | ||
3198 | } | ||
3199 | } | ||
3200 | err: | ||
3201 | release_console_sem(); | ||
3202 | return retval; | ||
3203 | } | ||
3204 | EXPORT_SYMBOL(unregister_con_driver); | ||
3205 | |||
3206 | /* | ||
3207 | * If we support more console drivers, this function is used | ||
3208 | * when a driver wants to take over some existing consoles | ||
3209 | * and become default driver for newly opened ones. | ||
3210 | * | ||
3211 | * take_over_console is basically a register followed by unbind | ||
3212 | */ | ||
3213 | int take_over_console(const struct consw *csw, int first, int last, int deflt) | ||
3214 | { | ||
3215 | int err; | ||
3216 | |||
3217 | err = register_con_driver(csw, first, last); | ||
3218 | |||
3219 | if (!err) | ||
3220 | bind_con_driver(csw, first, last, deflt); | ||
3221 | |||
3222 | return err; | ||
3223 | } | ||
3224 | |||
3225 | /* | ||
3226 | * give_up_console is a wrapper to unregister_con_driver. It will only | ||
3227 | * work if driver is fully unbound. | ||
3228 | */ | ||
3229 | void give_up_console(const struct consw *csw) | ||
3230 | { | ||
3231 | unregister_con_driver(csw); | ||
3232 | } | ||
3233 | |||
3234 | static int __init vtconsole_class_init(void) | ||
3235 | { | ||
3236 | int i; | ||
3237 | |||
3238 | vtconsole_class = class_create(THIS_MODULE, "vtconsole"); | ||
3239 | if (IS_ERR(vtconsole_class)) { | ||
3240 | printk(KERN_WARNING "Unable to create vt console class; " | ||
3241 | "errno = %ld\n", PTR_ERR(vtconsole_class)); | ||
3242 | vtconsole_class = NULL; | ||
3243 | } | ||
3244 | |||
3245 | /* Add system drivers to sysfs */ | ||
3246 | for (i = 0; i < MAX_NR_CON_DRIVER; i++) { | ||
3247 | struct con_driver *con = ®istered_con_driver[i]; | ||
3248 | |||
3249 | if (con->con && !con->class_dev) { | ||
3250 | con->class_dev = | ||
3251 | class_device_create(vtconsole_class, NULL, | ||
3252 | MKDEV(0, con->node), NULL, | ||
3253 | "vtcon%i", con->node); | ||
3254 | |||
3255 | if (IS_ERR(con->class_dev)) { | ||
3256 | printk(KERN_WARNING "Unable to create " | ||
3257 | "class_device for %s; errno = %ld\n", | ||
3258 | con->desc, PTR_ERR(con->class_dev)); | ||
3259 | con->class_dev = NULL; | ||
3260 | } else { | ||
3261 | vtconsole_init_class_device(con); | ||
3262 | } | ||
2749 | } | 3263 | } |
3264 | } | ||
3265 | |||
3266 | return 0; | ||
2750 | } | 3267 | } |
3268 | postcore_initcall(vtconsole_class_init); | ||
2751 | 3269 | ||
2752 | #endif | 3270 | #endif |
2753 | 3271 | ||
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile new file mode 100644 index 000000000000..a52225470225 --- /dev/null +++ b/drivers/clocksource/Makefile | |||
@@ -0,0 +1,3 @@ | |||
1 | obj-$(CONFIG_X86_CYCLONE_TIMER) += cyclone.o | ||
2 | obj-$(CONFIG_X86_PM_TIMER) += acpi_pm.o | ||
3 | obj-$(CONFIG_SCx200HR_TIMER) += scx200_hrt.o | ||
diff --git a/drivers/clocksource/acpi_pm.c b/drivers/clocksource/acpi_pm.c new file mode 100644 index 000000000000..7ad3be8c0f49 --- /dev/null +++ b/drivers/clocksource/acpi_pm.c | |||
@@ -0,0 +1,177 @@ | |||
1 | /* | ||
2 | * linux/drivers/clocksource/acpi_pm.c | ||
3 | * | ||
4 | * This file contains the ACPI PM based clocksource. | ||
5 | * | ||
6 | * This code was largely moved from the i386 timer_pm.c file | ||
7 | * which was (C) Dominik Brodowski <linux@brodo.de> 2003 | ||
8 | * and contained the following comments: | ||
9 | * | ||
10 | * Driver to use the Power Management Timer (PMTMR) available in some | ||
11 | * southbridges as primary timing source for the Linux kernel. | ||
12 | * | ||
13 | * Based on parts of linux/drivers/acpi/hardware/hwtimer.c, timer_pit.c, | ||
14 | * timer_hpet.c, and on Arjan van de Ven's implementation for 2.4. | ||
15 | * | ||
16 | * This file is licensed under the GPL v2. | ||
17 | */ | ||
18 | |||
19 | #include <linux/clocksource.h> | ||
20 | #include <linux/errno.h> | ||
21 | #include <linux/init.h> | ||
22 | #include <linux/pci.h> | ||
23 | #include <asm/io.h> | ||
24 | |||
25 | /* Number of PMTMR ticks expected during calibration run */ | ||
26 | #define PMTMR_TICKS_PER_SEC 3579545 | ||
27 | |||
28 | /* | ||
29 | * The I/O port the PMTMR resides at. | ||
30 | * The location is detected during setup_arch(), | ||
31 | * in arch/i386/acpi/boot.c | ||
32 | */ | ||
33 | u32 pmtmr_ioport __read_mostly; | ||
34 | |||
35 | #define ACPI_PM_MASK CLOCKSOURCE_MASK(24) /* limit it to 24 bits */ | ||
36 | |||
37 | static inline u32 read_pmtmr(void) | ||
38 | { | ||
39 | /* mask the output to 24 bits */ | ||
40 | return inl(pmtmr_ioport) & ACPI_PM_MASK; | ||
41 | } | ||
42 | |||
43 | static cycle_t acpi_pm_read_verified(void) | ||
44 | { | ||
45 | u32 v1 = 0, v2 = 0, v3 = 0; | ||
46 | |||
47 | /* | ||
48 | * It has been reported that because of various broken | ||
49 | * chipsets (ICH4, PIIX4 and PIIX4E) where the ACPI PM clock | ||
50 | * source is not latched, you must read it multiple | ||
51 | * times to ensure a safe value is read: | ||
52 | */ | ||
53 | do { | ||
54 | v1 = read_pmtmr(); | ||
55 | v2 = read_pmtmr(); | ||
56 | v3 = read_pmtmr(); | ||
57 | } while ((v1 > v2 && v1 < v3) || (v2 > v3 && v2 < v1) | ||
58 | || (v3 > v1 && v3 < v2)); | ||
59 | |||
60 | return (cycle_t)v2; | ||
61 | } | ||
62 | |||
63 | static cycle_t acpi_pm_read(void) | ||
64 | { | ||
65 | return (cycle_t)read_pmtmr(); | ||
66 | } | ||
67 | |||
68 | static struct clocksource clocksource_acpi_pm = { | ||
69 | .name = "acpi_pm", | ||
70 | .rating = 200, | ||
71 | .read = acpi_pm_read, | ||
72 | .mask = (cycle_t)ACPI_PM_MASK, | ||
73 | .mult = 0, /*to be caluclated*/ | ||
74 | .shift = 22, | ||
75 | .is_continuous = 1, | ||
76 | }; | ||
77 | |||
78 | |||
79 | #ifdef CONFIG_PCI | ||
80 | static int acpi_pm_good; | ||
81 | static int __init acpi_pm_good_setup(char *__str) | ||
82 | { | ||
83 | acpi_pm_good = 1; | ||
84 | return 1; | ||
85 | } | ||
86 | __setup("acpi_pm_good", acpi_pm_good_setup); | ||
87 | |||
88 | static inline void acpi_pm_need_workaround(void) | ||
89 | { | ||
90 | clocksource_acpi_pm.read = acpi_pm_read_verified; | ||
91 | clocksource_acpi_pm.rating = 110; | ||
92 | } | ||
93 | |||
94 | /* | ||
95 | * PIIX4 Errata: | ||
96 | * | ||
97 | * The power management timer may return improper results when read. | ||
98 | * Although the timer value settles properly after incrementing, | ||
99 | * while incrementing there is a 3 ns window every 69.8 ns where the | ||
100 | * timer value is indeterminate (a 4.2% chance that the data will be | ||
101 | * incorrect when read). As a result, the ACPI free running count up | ||
102 | * timer specification is violated due to erroneous reads. | ||
103 | */ | ||
104 | static void __devinit acpi_pm_check_blacklist(struct pci_dev *dev) | ||
105 | { | ||
106 | u8 rev; | ||
107 | |||
108 | if (acpi_pm_good) | ||
109 | return; | ||
110 | |||
111 | pci_read_config_byte(dev, PCI_REVISION_ID, &rev); | ||
112 | /* the bug has been fixed in PIIX4M */ | ||
113 | if (rev < 3) { | ||
114 | printk(KERN_WARNING "* Found PM-Timer Bug on the chipset." | ||
115 | " Due to workarounds for a bug,\n" | ||
116 | "* this clock source is slow. Consider trying" | ||
117 | " other clock sources\n"); | ||
118 | |||
119 | acpi_pm_need_workaround(); | ||
120 | } | ||
121 | } | ||
122 | DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, | ||
123 | acpi_pm_check_blacklist); | ||
124 | |||
125 | static void __devinit acpi_pm_check_graylist(struct pci_dev *dev) | ||
126 | { | ||
127 | if (acpi_pm_good) | ||
128 | return; | ||
129 | |||
130 | printk(KERN_WARNING "* The chipset may have PM-Timer Bug. Due to" | ||
131 | " workarounds for a bug,\n" | ||
132 | "* this clock source is slow. If you are sure your timer" | ||
133 | " does not have\n" | ||
134 | "* this bug, please use \"acpi_pm_good\" to disable the" | ||
135 | " workaround\n"); | ||
136 | |||
137 | acpi_pm_need_workaround(); | ||
138 | } | ||
139 | DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, | ||
140 | acpi_pm_check_graylist); | ||
141 | #endif | ||
142 | |||
143 | |||
144 | static int __init init_acpi_pm_clocksource(void) | ||
145 | { | ||
146 | u32 value1, value2; | ||
147 | unsigned int i; | ||
148 | |||
149 | if (!pmtmr_ioport) | ||
150 | return -ENODEV; | ||
151 | |||
152 | clocksource_acpi_pm.mult = clocksource_hz2mult(PMTMR_TICKS_PER_SEC, | ||
153 | clocksource_acpi_pm.shift); | ||
154 | |||
155 | /* "verify" this timing source: */ | ||
156 | value1 = read_pmtmr(); | ||
157 | for (i = 0; i < 10000; i++) { | ||
158 | value2 = read_pmtmr(); | ||
159 | if (value2 == value1) | ||
160 | continue; | ||
161 | if (value2 > value1) | ||
162 | goto pm_good; | ||
163 | if ((value2 < value1) && ((value2) < 0xFFF)) | ||
164 | goto pm_good; | ||
165 | printk(KERN_INFO "PM-Timer had inconsistent results:" | ||
166 | " 0x%#x, 0x%#x - aborting.\n", value1, value2); | ||
167 | return -EINVAL; | ||
168 | } | ||
169 | printk(KERN_INFO "PM-Timer had no reasonable result:" | ||
170 | " 0x%#x - aborting.\n", value1); | ||
171 | return -ENODEV; | ||
172 | |||
173 | pm_good: | ||
174 | return clocksource_register(&clocksource_acpi_pm); | ||
175 | } | ||
176 | |||
177 | module_init(init_acpi_pm_clocksource); | ||
diff --git a/drivers/clocksource/cyclone.c b/drivers/clocksource/cyclone.c new file mode 100644 index 000000000000..bf4d3d50d1c4 --- /dev/null +++ b/drivers/clocksource/cyclone.c | |||
@@ -0,0 +1,119 @@ | |||
1 | #include <linux/clocksource.h> | ||
2 | #include <linux/string.h> | ||
3 | #include <linux/errno.h> | ||
4 | #include <linux/timex.h> | ||
5 | #include <linux/init.h> | ||
6 | |||
7 | #include <asm/pgtable.h> | ||
8 | #include <asm/io.h> | ||
9 | |||
10 | #include "mach_timer.h" | ||
11 | |||
12 | #define CYCLONE_CBAR_ADDR 0xFEB00CD0 /* base address ptr */ | ||
13 | #define CYCLONE_PMCC_OFFSET 0x51A0 /* offset to control register */ | ||
14 | #define CYCLONE_MPCS_OFFSET 0x51A8 /* offset to select register */ | ||
15 | #define CYCLONE_MPMC_OFFSET 0x51D0 /* offset to count register */ | ||
16 | #define CYCLONE_TIMER_FREQ 99780000 /* 100Mhz, but not really */ | ||
17 | #define CYCLONE_TIMER_MASK CLOCKSOURCE_MASK(32) /* 32 bit mask */ | ||
18 | |||
19 | int use_cyclone = 0; | ||
20 | static void __iomem *cyclone_ptr; | ||
21 | |||
22 | static cycle_t read_cyclone(void) | ||
23 | { | ||
24 | return (cycle_t)readl(cyclone_ptr); | ||
25 | } | ||
26 | |||
27 | static struct clocksource clocksource_cyclone = { | ||
28 | .name = "cyclone", | ||
29 | .rating = 250, | ||
30 | .read = read_cyclone, | ||
31 | .mask = CYCLONE_TIMER_MASK, | ||
32 | .mult = 10, | ||
33 | .shift = 0, | ||
34 | .is_continuous = 1, | ||
35 | }; | ||
36 | |||
37 | static int __init init_cyclone_clocksource(void) | ||
38 | { | ||
39 | unsigned long base; /* saved value from CBAR */ | ||
40 | unsigned long offset; | ||
41 | u32 __iomem* volatile cyclone_timer; /* Cyclone MPMC0 register */ | ||
42 | u32 __iomem* reg; | ||
43 | int i; | ||
44 | |||
45 | /* make sure we're on a summit box: */ | ||
46 | if (!use_cyclone) | ||
47 | return -ENODEV; | ||
48 | |||
49 | printk(KERN_INFO "Summit chipset: Starting Cyclone Counter.\n"); | ||
50 | |||
51 | /* find base address: */ | ||
52 | offset = CYCLONE_CBAR_ADDR; | ||
53 | reg = ioremap_nocache(offset, sizeof(reg)); | ||
54 | if (!reg) { | ||
55 | printk(KERN_ERR "Summit chipset: Could not find valid CBAR register.\n"); | ||
56 | return -ENODEV; | ||
57 | } | ||
58 | /* even on 64bit systems, this is only 32bits: */ | ||
59 | base = readl(reg); | ||
60 | if (!base) { | ||
61 | printk(KERN_ERR "Summit chipset: Could not find valid CBAR value.\n"); | ||
62 | return -ENODEV; | ||
63 | } | ||
64 | iounmap(reg); | ||
65 | |||
66 | /* setup PMCC: */ | ||
67 | offset = base + CYCLONE_PMCC_OFFSET; | ||
68 | reg = ioremap_nocache(offset, sizeof(reg)); | ||
69 | if (!reg) { | ||
70 | printk(KERN_ERR "Summit chipset: Could not find valid PMCC register.\n"); | ||
71 | return -ENODEV; | ||
72 | } | ||
73 | writel(0x00000001,reg); | ||
74 | iounmap(reg); | ||
75 | |||
76 | /* setup MPCS: */ | ||
77 | offset = base + CYCLONE_MPCS_OFFSET; | ||
78 | reg = ioremap_nocache(offset, sizeof(reg)); | ||
79 | if (!reg) { | ||
80 | printk(KERN_ERR "Summit chipset: Could not find valid MPCS register.\n"); | ||
81 | return -ENODEV; | ||
82 | } | ||
83 | writel(0x00000001,reg); | ||
84 | iounmap(reg); | ||
85 | |||
86 | /* map in cyclone_timer: */ | ||
87 | offset = base + CYCLONE_MPMC_OFFSET; | ||
88 | cyclone_timer = ioremap_nocache(offset, sizeof(u64)); | ||
89 | if (!cyclone_timer) { | ||
90 | printk(KERN_ERR "Summit chipset: Could not find valid MPMC register.\n"); | ||
91 | return -ENODEV; | ||
92 | } | ||
93 | |||
94 | /* quick test to make sure its ticking: */ | ||
95 | for (i = 0; i < 3; i++){ | ||
96 | u32 old = readl(cyclone_timer); | ||
97 | int stall = 100; | ||
98 | |||
99 | while (stall--) | ||
100 | barrier(); | ||
101 | |||
102 | if (readl(cyclone_timer) == old) { | ||
103 | printk(KERN_ERR "Summit chipset: Counter not counting! DISABLED\n"); | ||
104 | iounmap(cyclone_timer); | ||
105 | cyclone_timer = NULL; | ||
106 | return -ENODEV; | ||
107 | } | ||
108 | } | ||
109 | cyclone_ptr = cyclone_timer; | ||
110 | |||
111 | /* sort out mult/shift values: */ | ||
112 | clocksource_cyclone.shift = 22; | ||
113 | clocksource_cyclone.mult = clocksource_hz2mult(CYCLONE_TIMER_FREQ, | ||
114 | clocksource_cyclone.shift); | ||
115 | |||
116 | return clocksource_register(&clocksource_cyclone); | ||
117 | } | ||
118 | |||
119 | module_init(init_cyclone_clocksource); | ||
diff --git a/drivers/clocksource/scx200_hrt.c b/drivers/clocksource/scx200_hrt.c new file mode 100644 index 000000000000..d418b8297211 --- /dev/null +++ b/drivers/clocksource/scx200_hrt.c | |||
@@ -0,0 +1,101 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2006 Jim Cromie | ||
3 | * | ||
4 | * This is a clocksource driver for the Geode SCx200's 1 or 27 MHz | ||
5 | * high-resolution timer. The Geode SC-1100 (at least) has a buggy | ||
6 | * time stamp counter (TSC), which loses time unless 'idle=poll' is | ||
7 | * given as a boot-arg. In its absence, the Generic Timekeeping code | ||
8 | * will detect and de-rate the bad TSC, allowing this timer to take | ||
9 | * over timekeeping duties. | ||
10 | * | ||
11 | * Based on work by John Stultz, and Ted Phelps (in a 2.6.12-rc6 patch) | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or | ||
14 | * modify it under the terms of the GNU General Public License as | ||
15 | * published by the Free Software Foundation; either version 2 of the | ||
16 | * License, or (at your option) any later version. | ||
17 | */ | ||
18 | |||
19 | #include <linux/clocksource.h> | ||
20 | #include <linux/init.h> | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/ioport.h> | ||
23 | #include <linux/scx200.h> | ||
24 | |||
25 | #define NAME "scx200_hrt" | ||
26 | |||
27 | static int mhz27; | ||
28 | module_param(mhz27, int, 0); /* load time only */ | ||
29 | MODULE_PARM_DESC(mhz27, "count at 27.0 MHz (default is 1.0 MHz)"); | ||
30 | |||
31 | static int ppm; | ||
32 | module_param(ppm, int, 0); /* load time only */ | ||
33 | MODULE_PARM_DESC(ppm, "+-adjust to actual XO freq (ppm)"); | ||
34 | |||
35 | /* HiRes Timer configuration register address */ | ||
36 | #define SCx200_TMCNFG_OFFSET (SCx200_TIMER_OFFSET + 5) | ||
37 | |||
38 | /* and config settings */ | ||
39 | #define HR_TMEN (1 << 0) /* timer interrupt enable */ | ||
40 | #define HR_TMCLKSEL (1 << 1) /* 1|0 counts at 27|1 MHz */ | ||
41 | #define HR_TM27MPD (1 << 2) /* 1 turns off input clock (power-down) */ | ||
42 | |||
43 | /* The base timer frequency, * 27 if selected */ | ||
44 | #define HRT_FREQ 1000000 | ||
45 | |||
46 | static cycle_t read_hrt(void) | ||
47 | { | ||
48 | /* Read the timer value */ | ||
49 | return (cycle_t) inl(scx200_cb_base + SCx200_TIMER_OFFSET); | ||
50 | } | ||
51 | |||
52 | #define HRT_SHIFT_1 22 | ||
53 | #define HRT_SHIFT_27 26 | ||
54 | |||
55 | static struct clocksource cs_hrt = { | ||
56 | .name = "scx200_hrt", | ||
57 | .rating = 250, | ||
58 | .read = read_hrt, | ||
59 | .mask = CLOCKSOURCE_MASK(32), | ||
60 | .is_continuous = 1, | ||
61 | /* mult, shift are set based on mhz27 flag */ | ||
62 | }; | ||
63 | |||
64 | static int __init init_hrt_clocksource(void) | ||
65 | { | ||
66 | /* Make sure scx200 has initializedd the configuration block */ | ||
67 | if (!scx200_cb_present()) | ||
68 | return -ENODEV; | ||
69 | |||
70 | /* Reserve the timer's ISA io-region for ourselves */ | ||
71 | if (!request_region(scx200_cb_base + SCx200_TIMER_OFFSET, | ||
72 | SCx200_TIMER_SIZE, | ||
73 | "NatSemi SCx200 High-Resolution Timer")) { | ||
74 | printk(KERN_WARNING NAME ": unable to lock timer region\n"); | ||
75 | return -ENODEV; | ||
76 | } | ||
77 | |||
78 | /* write timer config */ | ||
79 | outb(HR_TMEN | (mhz27) ? HR_TMCLKSEL : 0, | ||
80 | scx200_cb_base + SCx200_TMCNFG_OFFSET); | ||
81 | |||
82 | if (mhz27) { | ||
83 | cs_hrt.shift = HRT_SHIFT_27; | ||
84 | cs_hrt.mult = clocksource_hz2mult((HRT_FREQ + ppm) * 27, | ||
85 | cs_hrt.shift); | ||
86 | } else { | ||
87 | cs_hrt.shift = HRT_SHIFT_1; | ||
88 | cs_hrt.mult = clocksource_hz2mult(HRT_FREQ + ppm, | ||
89 | cs_hrt.shift); | ||
90 | } | ||
91 | printk(KERN_INFO "enabling scx200 high-res timer (%s MHz +%d ppm)\n", | ||
92 | mhz27 ? "27":"1", ppm); | ||
93 | |||
94 | return clocksource_register(&cs_hrt); | ||
95 | } | ||
96 | |||
97 | module_init(init_hrt_clocksource); | ||
98 | |||
99 | MODULE_AUTHOR("Jim Cromie <jim.cromie@gmail.com>"); | ||
100 | MODULE_DESCRIPTION("clocksource on SCx200 HiRes Timer"); | ||
101 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/dma/ioatdma.c b/drivers/dma/ioatdma.c index 0fdf7fbd6495..2801d14a5e42 100644 --- a/drivers/dma/ioatdma.c +++ b/drivers/dma/ioatdma.c | |||
@@ -824,10 +824,9 @@ static int __init ioat_init_module(void) | |||
824 | { | 824 | { |
825 | /* it's currently unsafe to unload this module */ | 825 | /* it's currently unsafe to unload this module */ |
826 | /* if forced, worst case is that rmmod hangs */ | 826 | /* if forced, worst case is that rmmod hangs */ |
827 | if (THIS_MODULE != NULL) | 827 | __unsafe(THIS_MODULE); |
828 | THIS_MODULE->unsafe = 1; | ||
829 | 828 | ||
830 | return pci_module_init(&ioat_pci_drv); | 829 | pci_module_init(&ioat_pci_drv); |
831 | } | 830 | } |
832 | 831 | ||
833 | module_init(ioat_init_module); | 832 | module_init(ioat_init_module); |
diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c index 622a55c72f03..d2428cef1598 100644 --- a/drivers/ide/ide-io.c +++ b/drivers/ide/ide-io.c | |||
@@ -959,7 +959,7 @@ static void ide_check_pm_state(ide_drive_t *drive, struct request *rq) | |||
959 | printk(KERN_WARNING "%s: bus not ready on wakeup\n", drive->name); | 959 | printk(KERN_WARNING "%s: bus not ready on wakeup\n", drive->name); |
960 | SELECT_DRIVE(drive); | 960 | SELECT_DRIVE(drive); |
961 | HWIF(drive)->OUTB(8, HWIF(drive)->io_ports[IDE_CONTROL_OFFSET]); | 961 | HWIF(drive)->OUTB(8, HWIF(drive)->io_ports[IDE_CONTROL_OFFSET]); |
962 | rc = ide_wait_not_busy(HWIF(drive), 10000); | 962 | rc = ide_wait_not_busy(HWIF(drive), 100000); |
963 | if (rc) | 963 | if (rc) |
964 | printk(KERN_WARNING "%s: drive not ready on wakeup\n", drive->name); | 964 | printk(KERN_WARNING "%s: drive not ready on wakeup\n", drive->name); |
965 | } | 965 | } |
diff --git a/drivers/ide/ide-lib.c b/drivers/ide/ide-lib.c index 16a143133f93..7ddb11828731 100644 --- a/drivers/ide/ide-lib.c +++ b/drivers/ide/ide-lib.c | |||
@@ -485,7 +485,7 @@ static u8 ide_dump_ata_status(ide_drive_t *drive, const char *msg, u8 stat) | |||
485 | unsigned long flags; | 485 | unsigned long flags; |
486 | u8 err = 0; | 486 | u8 err = 0; |
487 | 487 | ||
488 | local_irq_set(flags); | 488 | local_irq_save(flags); |
489 | printk("%s: %s: status=0x%02x { ", drive->name, msg, stat); | 489 | printk("%s: %s: status=0x%02x { ", drive->name, msg, stat); |
490 | if (stat & BUSY_STAT) | 490 | if (stat & BUSY_STAT) |
491 | printk("Busy "); | 491 | printk("Busy "); |
@@ -567,7 +567,7 @@ static u8 ide_dump_atapi_status(ide_drive_t *drive, const char *msg, u8 stat) | |||
567 | 567 | ||
568 | status.all = stat; | 568 | status.all = stat; |
569 | error.all = 0; | 569 | error.all = 0; |
570 | local_irq_set(flags); | 570 | local_irq_save(flags); |
571 | printk("%s: %s: status=0x%02x { ", drive->name, msg, stat); | 571 | printk("%s: %s: status=0x%02x { ", drive->name, msg, stat); |
572 | if (status.b.bsy) | 572 | if (status.b.bsy) |
573 | printk("Busy "); | 573 | printk("Busy "); |
diff --git a/drivers/ide/ide-timing.h b/drivers/ide/ide-timing.h index 2fcfac6e967a..c0864b1e9228 100644 --- a/drivers/ide/ide-timing.h +++ b/drivers/ide/ide-timing.h | |||
@@ -220,6 +220,12 @@ static int ide_timing_compute(ide_drive_t *drive, short speed, struct ide_timing | |||
220 | return -EINVAL; | 220 | return -EINVAL; |
221 | 221 | ||
222 | /* | 222 | /* |
223 | * Copy the timing from the table. | ||
224 | */ | ||
225 | |||
226 | *t = *s; | ||
227 | |||
228 | /* | ||
223 | * If the drive is an EIDE drive, it can tell us it needs extended | 229 | * If the drive is an EIDE drive, it can tell us it needs extended |
224 | * PIO/MWDMA cycle timing. | 230 | * PIO/MWDMA cycle timing. |
225 | */ | 231 | */ |
@@ -247,7 +253,7 @@ static int ide_timing_compute(ide_drive_t *drive, short speed, struct ide_timing | |||
247 | * Convert the timing to bus clock counts. | 253 | * Convert the timing to bus clock counts. |
248 | */ | 254 | */ |
249 | 255 | ||
250 | ide_timing_quantize(s, t, T, UT); | 256 | ide_timing_quantize(t, t, T, UT); |
251 | 257 | ||
252 | /* | 258 | /* |
253 | * Even in DMA/UDMA modes we still use PIO access for IDENTIFY, S.M.A.R.T | 259 | * Even in DMA/UDMA modes we still use PIO access for IDENTIFY, S.M.A.R.T |
diff --git a/drivers/ide/pci/pdc202xx_old.c b/drivers/ide/pci/pdc202xx_old.c index 7ce5bf783688..22d17548ecdb 100644 --- a/drivers/ide/pci/pdc202xx_old.c +++ b/drivers/ide/pci/pdc202xx_old.c | |||
@@ -370,7 +370,6 @@ chipset_is_set: | |||
370 | if (!(speed)) { | 370 | if (!(speed)) { |
371 | /* restore original pci-config space */ | 371 | /* restore original pci-config space */ |
372 | pci_write_config_dword(dev, drive_pci, drive_conf); | 372 | pci_write_config_dword(dev, drive_pci, drive_conf); |
373 | hwif->tuneproc(drive, 5); | ||
374 | return 0; | 373 | return 0; |
375 | } | 374 | } |
376 | 375 | ||
@@ -415,8 +414,6 @@ static void pdc202xx_old_ide_dma_start(ide_drive_t *drive) | |||
415 | if (drive->addressing == 1) { | 414 | if (drive->addressing == 1) { |
416 | struct request *rq = HWGROUP(drive)->rq; | 415 | struct request *rq = HWGROUP(drive)->rq; |
417 | ide_hwif_t *hwif = HWIF(drive); | 416 | ide_hwif_t *hwif = HWIF(drive); |
418 | // struct pci_dev *dev = hwif->pci_dev; | ||
419 | // unsgned long high_16 = pci_resource_start(dev, 4); | ||
420 | unsigned long high_16 = hwif->dma_master; | 417 | unsigned long high_16 = hwif->dma_master; |
421 | unsigned long atapi_reg = high_16 + (hwif->channel ? 0x24 : 0x20); | 418 | unsigned long atapi_reg = high_16 + (hwif->channel ? 0x24 : 0x20); |
422 | u32 word_count = 0; | 419 | u32 word_count = 0; |
@@ -436,7 +433,6 @@ static int pdc202xx_old_ide_dma_end(ide_drive_t *drive) | |||
436 | { | 433 | { |
437 | if (drive->addressing == 1) { | 434 | if (drive->addressing == 1) { |
438 | ide_hwif_t *hwif = HWIF(drive); | 435 | ide_hwif_t *hwif = HWIF(drive); |
439 | // unsigned long high_16 = pci_resource_start(hwif->pci_dev, 4); | ||
440 | unsigned long high_16 = hwif->dma_master; | 436 | unsigned long high_16 = hwif->dma_master; |
441 | unsigned long atapi_reg = high_16 + (hwif->channel ? 0x24 : 0x20); | 437 | unsigned long atapi_reg = high_16 + (hwif->channel ? 0x24 : 0x20); |
442 | u8 clock = 0; | 438 | u8 clock = 0; |
@@ -453,8 +449,6 @@ static int pdc202xx_old_ide_dma_end(ide_drive_t *drive) | |||
453 | static int pdc202xx_old_ide_dma_test_irq(ide_drive_t *drive) | 449 | static int pdc202xx_old_ide_dma_test_irq(ide_drive_t *drive) |
454 | { | 450 | { |
455 | ide_hwif_t *hwif = HWIF(drive); | 451 | ide_hwif_t *hwif = HWIF(drive); |
456 | // struct pci_dev *dev = hwif->pci_dev; | ||
457 | // unsigned long high_16 = pci_resource_start(dev, 4); | ||
458 | unsigned long high_16 = hwif->dma_master; | 452 | unsigned long high_16 = hwif->dma_master; |
459 | u8 dma_stat = hwif->INB(hwif->dma_status); | 453 | u8 dma_stat = hwif->INB(hwif->dma_status); |
460 | u8 sc1d = hwif->INB((high_16 + 0x001d)); | 454 | u8 sc1d = hwif->INB((high_16 + 0x001d)); |
@@ -492,12 +486,7 @@ static int pdc202xx_ide_dma_timeout(ide_drive_t *drive) | |||
492 | 486 | ||
493 | static void pdc202xx_reset_host (ide_hwif_t *hwif) | 487 | static void pdc202xx_reset_host (ide_hwif_t *hwif) |
494 | { | 488 | { |
495 | #ifdef CONFIG_BLK_DEV_IDEDMA | ||
496 | // unsigned long high_16 = hwif->dma_base - (8*(hwif->channel)); | ||
497 | unsigned long high_16 = hwif->dma_master; | 489 | unsigned long high_16 = hwif->dma_master; |
498 | #else /* !CONFIG_BLK_DEV_IDEDMA */ | ||
499 | unsigned long high_16 = pci_resource_start(hwif->pci_dev, 4); | ||
500 | #endif /* CONFIG_BLK_DEV_IDEDMA */ | ||
501 | u8 udma_speed_flag = hwif->INB(high_16|0x001f); | 490 | u8 udma_speed_flag = hwif->INB(high_16|0x001f); |
502 | 491 | ||
503 | hwif->OUTB((udma_speed_flag | 0x10), (high_16|0x001f)); | 492 | hwif->OUTB((udma_speed_flag | 0x10), (high_16|0x001f)); |
@@ -550,31 +539,6 @@ static void pdc202xx_reset (ide_drive_t *drive) | |||
550 | #endif | 539 | #endif |
551 | } | 540 | } |
552 | 541 | ||
553 | /* | ||
554 | * Since SUN Cobalt is attempting to do this operation, I should disclose | ||
555 | * this has been a long time ago Thu Jul 27 16:40:57 2000 was the patch date | ||
556 | * HOTSWAP ATA Infrastructure. | ||
557 | */ | ||
558 | static int pdc202xx_tristate (ide_drive_t * drive, int state) | ||
559 | { | ||
560 | ide_hwif_t *hwif = HWIF(drive); | ||
561 | // unsigned long high_16 = hwif->dma_base - (8*(hwif->channel)); | ||
562 | unsigned long high_16 = hwif->dma_master; | ||
563 | u8 sc1f = hwif->INB(high_16|0x001f); | ||
564 | |||
565 | if (!hwif) | ||
566 | return -EINVAL; | ||
567 | |||
568 | // hwif->bus_state = state; | ||
569 | |||
570 | if (state) { | ||
571 | hwif->OUTB(sc1f | 0x08, (high_16|0x001f)); | ||
572 | } else { | ||
573 | hwif->OUTB(sc1f & ~0x08, (high_16|0x001f)); | ||
574 | } | ||
575 | return 0; | ||
576 | } | ||
577 | |||
578 | static unsigned int __devinit init_chipset_pdc202xx(struct pci_dev *dev, const char *name) | 542 | static unsigned int __devinit init_chipset_pdc202xx(struct pci_dev *dev, const char *name) |
579 | { | 543 | { |
580 | if (dev->resource[PCI_ROM_RESOURCE].start) { | 544 | if (dev->resource[PCI_ROM_RESOURCE].start) { |
@@ -624,10 +588,8 @@ static void __devinit init_hwif_pdc202xx(ide_hwif_t *hwif) | |||
624 | hwif->tuneproc = &config_chipset_for_pio; | 588 | hwif->tuneproc = &config_chipset_for_pio; |
625 | hwif->quirkproc = &pdc202xx_quirkproc; | 589 | hwif->quirkproc = &pdc202xx_quirkproc; |
626 | 590 | ||
627 | if (hwif->pci_dev->device != PCI_DEVICE_ID_PROMISE_20246) { | 591 | if (hwif->pci_dev->device != PCI_DEVICE_ID_PROMISE_20246) |
628 | hwif->busproc = &pdc202xx_tristate; | ||
629 | hwif->resetproc = &pdc202xx_reset; | 592 | hwif->resetproc = &pdc202xx_reset; |
630 | } | ||
631 | 593 | ||
632 | hwif->speedproc = &pdc202xx_tune_chipset; | 594 | hwif->speedproc = &pdc202xx_tune_chipset; |
633 | 595 | ||
diff --git a/drivers/ide/pci/piix.c b/drivers/ide/pci/piix.c index e9b83e1a3028..7fac6f57b5d6 100644 --- a/drivers/ide/pci/piix.c +++ b/drivers/ide/pci/piix.c | |||
@@ -222,6 +222,8 @@ static void piix_tune_drive (ide_drive_t *drive, u8 pio) | |||
222 | unsigned long flags; | 222 | unsigned long flags; |
223 | u16 master_data; | 223 | u16 master_data; |
224 | u8 slave_data; | 224 | u8 slave_data; |
225 | static DEFINE_SPINLOCK(tune_lock); | ||
226 | |||
225 | /* ISP RTC */ | 227 | /* ISP RTC */ |
226 | u8 timings[][2] = { { 0, 0 }, | 228 | u8 timings[][2] = { { 0, 0 }, |
227 | { 0, 0 }, | 229 | { 0, 0 }, |
@@ -230,7 +232,13 @@ static void piix_tune_drive (ide_drive_t *drive, u8 pio) | |||
230 | { 2, 3 }, }; | 232 | { 2, 3 }, }; |
231 | 233 | ||
232 | pio = ide_get_best_pio_mode(drive, pio, 5, NULL); | 234 | pio = ide_get_best_pio_mode(drive, pio, 5, NULL); |
233 | spin_lock_irqsave(&ide_lock, flags); | 235 | |
236 | /* | ||
237 | * Master vs slave is synchronized above us but the slave register is | ||
238 | * shared by the two hwifs so the corner case of two slave timeouts in | ||
239 | * parallel must be locked. | ||
240 | */ | ||
241 | spin_lock_irqsave(&tune_lock, flags); | ||
234 | pci_read_config_word(dev, master_port, &master_data); | 242 | pci_read_config_word(dev, master_port, &master_data); |
235 | if (is_slave) { | 243 | if (is_slave) { |
236 | master_data = master_data | 0x4000; | 244 | master_data = master_data | 0x4000; |
@@ -250,7 +258,7 @@ static void piix_tune_drive (ide_drive_t *drive, u8 pio) | |||
250 | pci_write_config_word(dev, master_port, master_data); | 258 | pci_write_config_word(dev, master_port, master_data); |
251 | if (is_slave) | 259 | if (is_slave) |
252 | pci_write_config_byte(dev, slave_port, slave_data); | 260 | pci_write_config_byte(dev, slave_port, slave_data); |
253 | spin_unlock_irqrestore(&ide_lock, flags); | 261 | spin_unlock_irqrestore(&tune_lock, flags); |
254 | } | 262 | } |
255 | 263 | ||
256 | /** | 264 | /** |
diff --git a/drivers/ieee1394/eth1394.c b/drivers/ieee1394/eth1394.c index 5bda15904a08..2d5b57be98c3 100644 --- a/drivers/ieee1394/eth1394.c +++ b/drivers/ieee1394/eth1394.c | |||
@@ -1074,8 +1074,7 @@ static inline int update_partial_datagram(struct list_head *pdgl, struct list_he | |||
1074 | 1074 | ||
1075 | /* Move list entry to beginnig of list so that oldest partial | 1075 | /* Move list entry to beginnig of list so that oldest partial |
1076 | * datagrams percolate to the end of the list */ | 1076 | * datagrams percolate to the end of the list */ |
1077 | list_del(lh); | 1077 | list_move(lh, pdgl); |
1078 | list_add(lh, pdgl); | ||
1079 | 1078 | ||
1080 | return 0; | 1079 | return 0; |
1081 | } | 1080 | } |
diff --git a/drivers/ieee1394/raw1394.c b/drivers/ieee1394/raw1394.c index 20ce539580f1..571ea68c0cf2 100644 --- a/drivers/ieee1394/raw1394.c +++ b/drivers/ieee1394/raw1394.c | |||
@@ -132,8 +132,7 @@ static void free_pending_request(struct pending_request *req) | |||
132 | static void __queue_complete_req(struct pending_request *req) | 132 | static void __queue_complete_req(struct pending_request *req) |
133 | { | 133 | { |
134 | struct file_info *fi = req->file_info; | 134 | struct file_info *fi = req->file_info; |
135 | list_del(&req->list); | 135 | list_move_tail(&req->list, &fi->req_complete); |
136 | list_add_tail(&req->list, &fi->req_complete); | ||
137 | 136 | ||
138 | up(&fi->complete_sem); | 137 | up(&fi->complete_sem); |
139 | wake_up_interruptible(&fi->poll_wait_complete); | 138 | wake_up_interruptible(&fi->poll_wait_complete); |
diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c index b38e02a5db35..5ed4dab52a6f 100644 --- a/drivers/infiniband/core/mad.c +++ b/drivers/infiniband/core/mad.c | |||
@@ -1775,11 +1775,9 @@ ib_find_send_mad(struct ib_mad_agent_private *mad_agent_priv, | |||
1775 | void ib_mark_mad_done(struct ib_mad_send_wr_private *mad_send_wr) | 1775 | void ib_mark_mad_done(struct ib_mad_send_wr_private *mad_send_wr) |
1776 | { | 1776 | { |
1777 | mad_send_wr->timeout = 0; | 1777 | mad_send_wr->timeout = 0; |
1778 | if (mad_send_wr->refcount == 1) { | 1778 | if (mad_send_wr->refcount == 1) |
1779 | list_del(&mad_send_wr->agent_list); | 1779 | list_move_tail(&mad_send_wr->agent_list, |
1780 | list_add_tail(&mad_send_wr->agent_list, | ||
1781 | &mad_send_wr->mad_agent_priv->done_list); | 1780 | &mad_send_wr->mad_agent_priv->done_list); |
1782 | } | ||
1783 | } | 1781 | } |
1784 | 1782 | ||
1785 | static void ib_mad_complete_recv(struct ib_mad_agent_private *mad_agent_priv, | 1783 | static void ib_mad_complete_recv(struct ib_mad_agent_private *mad_agent_priv, |
@@ -2098,8 +2096,7 @@ retry: | |||
2098 | queued_send_wr = container_of(mad_list, | 2096 | queued_send_wr = container_of(mad_list, |
2099 | struct ib_mad_send_wr_private, | 2097 | struct ib_mad_send_wr_private, |
2100 | mad_list); | 2098 | mad_list); |
2101 | list_del(&mad_list->list); | 2099 | list_move_tail(&mad_list->list, &send_queue->list); |
2102 | list_add_tail(&mad_list->list, &send_queue->list); | ||
2103 | } | 2100 | } |
2104 | spin_unlock_irqrestore(&send_queue->lock, flags); | 2101 | spin_unlock_irqrestore(&send_queue->lock, flags); |
2105 | 2102 | ||
diff --git a/drivers/infiniband/core/mad_rmpp.c b/drivers/infiniband/core/mad_rmpp.c index d4704e054e30..ebcd5b181770 100644 --- a/drivers/infiniband/core/mad_rmpp.c +++ b/drivers/infiniband/core/mad_rmpp.c | |||
@@ -665,8 +665,7 @@ static void process_rmpp_ack(struct ib_mad_agent_private *agent, | |||
665 | goto out; | 665 | goto out; |
666 | 666 | ||
667 | mad_send_wr->refcount++; | 667 | mad_send_wr->refcount++; |
668 | list_del(&mad_send_wr->agent_list); | 668 | list_move_tail(&mad_send_wr->agent_list, |
669 | list_add_tail(&mad_send_wr->agent_list, | ||
670 | &mad_send_wr->mad_agent_priv->send_list); | 669 | &mad_send_wr->mad_agent_priv->send_list); |
671 | } | 670 | } |
672 | out: | 671 | out: |
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c index 216471fa01cc..ab40488182b3 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c | |||
@@ -864,8 +864,7 @@ void ipoib_mcast_restart_task(void *dev_ptr) | |||
864 | 864 | ||
865 | if (mcast) { | 865 | if (mcast) { |
866 | /* Destroy the send only entry */ | 866 | /* Destroy the send only entry */ |
867 | list_del(&mcast->list); | 867 | list_move_tail(&mcast->list, &remove_list); |
868 | list_add_tail(&mcast->list, &remove_list); | ||
869 | 868 | ||
870 | rb_replace_node(&mcast->rb_node, | 869 | rb_replace_node(&mcast->rb_node, |
871 | &nmcast->rb_node, | 870 | &nmcast->rb_node, |
@@ -890,8 +889,7 @@ void ipoib_mcast_restart_task(void *dev_ptr) | |||
890 | rb_erase(&mcast->rb_node, &priv->multicast_tree); | 889 | rb_erase(&mcast->rb_node, &priv->multicast_tree); |
891 | 890 | ||
892 | /* Move to the remove list */ | 891 | /* Move to the remove list */ |
893 | list_del(&mcast->list); | 892 | list_move_tail(&mcast->list, &remove_list); |
894 | list_add_tail(&mcast->list, &remove_list); | ||
895 | } | 893 | } |
896 | } | 894 | } |
897 | 895 | ||
diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c index 173c899a1fb4..2e541fa02024 100644 --- a/drivers/isdn/capi/capi.c +++ b/drivers/isdn/capi/capi.c | |||
@@ -87,6 +87,11 @@ struct capincci; | |||
87 | #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE | 87 | #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE |
88 | struct capiminor; | 88 | struct capiminor; |
89 | 89 | ||
90 | struct datahandle_queue { | ||
91 | struct list_head list; | ||
92 | u16 datahandle; | ||
93 | }; | ||
94 | |||
90 | struct capiminor { | 95 | struct capiminor { |
91 | struct list_head list; | 96 | struct list_head list; |
92 | struct capincci *nccip; | 97 | struct capincci *nccip; |
@@ -109,12 +114,9 @@ struct capiminor { | |||
109 | int outbytes; | 114 | int outbytes; |
110 | 115 | ||
111 | /* transmit path */ | 116 | /* transmit path */ |
112 | struct datahandle_queue { | 117 | struct list_head ackqueue; |
113 | struct datahandle_queue *next; | ||
114 | u16 datahandle; | ||
115 | } *ackqueue; | ||
116 | int nack; | 118 | int nack; |
117 | 119 | spinlock_t ackqlock; | |
118 | }; | 120 | }; |
119 | #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ | 121 | #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ |
120 | 122 | ||
@@ -156,48 +158,54 @@ static LIST_HEAD(capiminor_list); | |||
156 | 158 | ||
157 | static int capincci_add_ack(struct capiminor *mp, u16 datahandle) | 159 | static int capincci_add_ack(struct capiminor *mp, u16 datahandle) |
158 | { | 160 | { |
159 | struct datahandle_queue *n, **pp; | 161 | struct datahandle_queue *n; |
162 | unsigned long flags; | ||
160 | 163 | ||
161 | n = kmalloc(sizeof(*n), GFP_ATOMIC); | 164 | n = kmalloc(sizeof(*n), GFP_ATOMIC); |
162 | if (!n) { | 165 | if (unlikely(!n)) { |
163 | printk(KERN_ERR "capi: alloc datahandle failed\n"); | 166 | printk(KERN_ERR "capi: alloc datahandle failed\n"); |
164 | return -1; | 167 | return -1; |
165 | } | 168 | } |
166 | n->next = NULL; | ||
167 | n->datahandle = datahandle; | 169 | n->datahandle = datahandle; |
168 | for (pp = &mp->ackqueue; *pp; pp = &(*pp)->next) ; | 170 | INIT_LIST_HEAD(&n->list); |
169 | *pp = n; | 171 | spin_lock_irqsave(&mp->ackqlock, flags); |
172 | list_add_tail(&n->list, &mp->ackqueue); | ||
170 | mp->nack++; | 173 | mp->nack++; |
174 | spin_unlock_irqrestore(&mp->ackqlock, flags); | ||
171 | return 0; | 175 | return 0; |
172 | } | 176 | } |
173 | 177 | ||
174 | static int capiminor_del_ack(struct capiminor *mp, u16 datahandle) | 178 | static int capiminor_del_ack(struct capiminor *mp, u16 datahandle) |
175 | { | 179 | { |
176 | struct datahandle_queue **pp, *p; | 180 | struct datahandle_queue *p, *tmp; |
181 | unsigned long flags; | ||
177 | 182 | ||
178 | for (pp = &mp->ackqueue; *pp; pp = &(*pp)->next) { | 183 | spin_lock_irqsave(&mp->ackqlock, flags); |
179 | if ((*pp)->datahandle == datahandle) { | 184 | list_for_each_entry_safe(p, tmp, &mp->ackqueue, list) { |
180 | p = *pp; | 185 | if (p->datahandle == datahandle) { |
181 | *pp = (*pp)->next; | 186 | list_del(&p->list); |
182 | kfree(p); | 187 | kfree(p); |
183 | mp->nack--; | 188 | mp->nack--; |
189 | spin_unlock_irqrestore(&mp->ackqlock, flags); | ||
184 | return 0; | 190 | return 0; |
185 | } | 191 | } |
186 | } | 192 | } |
193 | spin_unlock_irqrestore(&mp->ackqlock, flags); | ||
187 | return -1; | 194 | return -1; |
188 | } | 195 | } |
189 | 196 | ||
190 | static void capiminor_del_all_ack(struct capiminor *mp) | 197 | static void capiminor_del_all_ack(struct capiminor *mp) |
191 | { | 198 | { |
192 | struct datahandle_queue **pp, *p; | 199 | struct datahandle_queue *p, *tmp; |
200 | unsigned long flags; | ||
193 | 201 | ||
194 | pp = &mp->ackqueue; | 202 | spin_lock_irqsave(&mp->ackqlock, flags); |
195 | while (*pp) { | 203 | list_for_each_entry_safe(p, tmp, &mp->ackqueue, list) { |
196 | p = *pp; | 204 | list_del(&p->list); |
197 | *pp = (*pp)->next; | ||
198 | kfree(p); | 205 | kfree(p); |
199 | mp->nack--; | 206 | mp->nack--; |
200 | } | 207 | } |
208 | spin_unlock_irqrestore(&mp->ackqlock, flags); | ||
201 | } | 209 | } |
202 | 210 | ||
203 | 211 | ||
@@ -220,6 +228,8 @@ static struct capiminor *capiminor_alloc(struct capi20_appl *ap, u32 ncci) | |||
220 | mp->ncci = ncci; | 228 | mp->ncci = ncci; |
221 | mp->msgid = 0; | 229 | mp->msgid = 0; |
222 | atomic_set(&mp->ttyopencount,0); | 230 | atomic_set(&mp->ttyopencount,0); |
231 | INIT_LIST_HEAD(&mp->ackqueue); | ||
232 | spin_lock_init(&mp->ackqlock); | ||
223 | 233 | ||
224 | skb_queue_head_init(&mp->inqueue); | 234 | skb_queue_head_init(&mp->inqueue); |
225 | skb_queue_head_init(&mp->outqueue); | 235 | skb_queue_head_init(&mp->outqueue); |
diff --git a/drivers/isdn/gigaset/bas-gigaset.c b/drivers/isdn/gigaset/bas-gigaset.c index eb41aba3ddef..8a45715dd4c1 100644 --- a/drivers/isdn/gigaset/bas-gigaset.c +++ b/drivers/isdn/gigaset/bas-gigaset.c | |||
@@ -65,23 +65,22 @@ static struct usb_device_id gigaset_table [] = { | |||
65 | 65 | ||
66 | MODULE_DEVICE_TABLE(usb, gigaset_table); | 66 | MODULE_DEVICE_TABLE(usb, gigaset_table); |
67 | 67 | ||
68 | /*======================= local function prototypes =============================*/ | 68 | /*======================= local function prototypes ==========================*/ |
69 | 69 | ||
70 | /* This function is called if a new device is connected to the USB port. It | 70 | /* function called if a new device belonging to this driver is connected */ |
71 | * checks whether this new device belongs to this driver. | ||
72 | */ | ||
73 | static int gigaset_probe(struct usb_interface *interface, | 71 | static int gigaset_probe(struct usb_interface *interface, |
74 | const struct usb_device_id *id); | 72 | const struct usb_device_id *id); |
75 | 73 | ||
76 | /* Function will be called if the device is unplugged */ | 74 | /* Function will be called if the device is unplugged */ |
77 | static void gigaset_disconnect(struct usb_interface *interface); | 75 | static void gigaset_disconnect(struct usb_interface *interface); |
78 | 76 | ||
79 | static void read_ctrl_callback(struct urb *, struct pt_regs *); | 77 | static int atread_submit(struct cardstate *, int); |
80 | static void stopurbs(struct bas_bc_state *); | 78 | static void stopurbs(struct bas_bc_state *); |
79 | static int req_submit(struct bc_state *, int, int, int); | ||
81 | static int atwrite_submit(struct cardstate *, unsigned char *, int); | 80 | static int atwrite_submit(struct cardstate *, unsigned char *, int); |
82 | static int start_cbsend(struct cardstate *); | 81 | static int start_cbsend(struct cardstate *); |
83 | 82 | ||
84 | /*==============================================================================*/ | 83 | /*============================================================================*/ |
85 | 84 | ||
86 | struct bas_cardstate { | 85 | struct bas_cardstate { |
87 | struct usb_device *udev; /* USB device pointer */ | 86 | struct usb_device *udev; /* USB device pointer */ |
@@ -91,6 +90,7 @@ struct bas_cardstate { | |||
91 | struct urb *urb_ctrl; /* control pipe default URB */ | 90 | struct urb *urb_ctrl; /* control pipe default URB */ |
92 | struct usb_ctrlrequest dr_ctrl; | 91 | struct usb_ctrlrequest dr_ctrl; |
93 | struct timer_list timer_ctrl; /* control request timeout */ | 92 | struct timer_list timer_ctrl; /* control request timeout */ |
93 | int retry_ctrl; | ||
94 | 94 | ||
95 | struct timer_list timer_atrdy; /* AT command ready timeout */ | 95 | struct timer_list timer_atrdy; /* AT command ready timeout */ |
96 | struct urb *urb_cmd_out; /* for sending AT commands */ | 96 | struct urb *urb_cmd_out; /* for sending AT commands */ |
@@ -307,6 +307,7 @@ static int gigaset_set_line_ctrl(struct cardstate *cs, unsigned cflag) | |||
307 | * hang up any existing connection because of an unrecoverable error | 307 | * hang up any existing connection because of an unrecoverable error |
308 | * This function may be called from any context and takes care of scheduling | 308 | * This function may be called from any context and takes care of scheduling |
309 | * the necessary actions for execution outside of interrupt context. | 309 | * the necessary actions for execution outside of interrupt context. |
310 | * cs->lock must not be held. | ||
310 | * argument: | 311 | * argument: |
311 | * B channel control structure | 312 | * B channel control structure |
312 | */ | 313 | */ |
@@ -325,14 +326,17 @@ static inline void error_hangup(struct bc_state *bcs) | |||
325 | 326 | ||
326 | /* error_reset | 327 | /* error_reset |
327 | * reset Gigaset device because of an unrecoverable error | 328 | * reset Gigaset device because of an unrecoverable error |
328 | * This function may be called from any context, and should take care of | 329 | * This function may be called from any context, and takes care of |
329 | * scheduling the necessary actions for execution outside of interrupt context. | 330 | * scheduling the necessary actions for execution outside of interrupt context. |
330 | * Right now, it just generates a kernel message calling for help. | 331 | * cs->lock must not be held. |
331 | * argument: | 332 | * argument: |
332 | * controller state structure | 333 | * controller state structure |
333 | */ | 334 | */ |
334 | static inline void error_reset(struct cardstate *cs) | 335 | static inline void error_reset(struct cardstate *cs) |
335 | { | 336 | { |
337 | /* close AT command channel to recover (ignore errors) */ | ||
338 | req_submit(cs->bcs, HD_CLOSE_ATCHANNEL, 0, BAS_TIMEOUT); | ||
339 | |||
336 | //FIXME try to recover without bothering the user | 340 | //FIXME try to recover without bothering the user |
337 | dev_err(cs->dev, | 341 | dev_err(cs->dev, |
338 | "unrecoverable error - please disconnect Gigaset base to reset\n"); | 342 | "unrecoverable error - please disconnect Gigaset base to reset\n"); |
@@ -403,14 +407,30 @@ static void cmd_in_timeout(unsigned long data) | |||
403 | { | 407 | { |
404 | struct cardstate *cs = (struct cardstate *) data; | 408 | struct cardstate *cs = (struct cardstate *) data; |
405 | struct bas_cardstate *ucs = cs->hw.bas; | 409 | struct bas_cardstate *ucs = cs->hw.bas; |
410 | int rc; | ||
406 | 411 | ||
407 | if (!ucs->rcvbuf_size) { | 412 | if (!ucs->rcvbuf_size) { |
408 | gig_dbg(DEBUG_USBREQ, "%s: no receive in progress", __func__); | 413 | gig_dbg(DEBUG_USBREQ, "%s: no receive in progress", __func__); |
409 | return; | 414 | return; |
410 | } | 415 | } |
411 | 416 | ||
412 | dev_err(cs->dev, "timeout reading AT response\n"); | 417 | if (ucs->retry_cmd_in++ < BAS_RETRY) { |
413 | error_reset(cs); //FIXME retry? | 418 | dev_notice(cs->dev, "control read: timeout, retry %d\n", |
419 | ucs->retry_cmd_in); | ||
420 | rc = atread_submit(cs, BAS_TIMEOUT); | ||
421 | if (rc >= 0 || rc == -ENODEV) | ||
422 | /* resubmitted or disconnected */ | ||
423 | /* - bypass regular exit block */ | ||
424 | return; | ||
425 | } else { | ||
426 | dev_err(cs->dev, | ||
427 | "control read: timeout, giving up after %d tries\n", | ||
428 | ucs->retry_cmd_in); | ||
429 | } | ||
430 | kfree(ucs->rcvbuf); | ||
431 | ucs->rcvbuf = NULL; | ||
432 | ucs->rcvbuf_size = 0; | ||
433 | error_reset(cs); | ||
414 | } | 434 | } |
415 | 435 | ||
416 | /* set/clear bits in base connection state, return previous state | 436 | /* set/clear bits in base connection state, return previous state |
@@ -428,6 +448,96 @@ inline static int update_basstate(struct bas_cardstate *ucs, | |||
428 | return state; | 448 | return state; |
429 | } | 449 | } |
430 | 450 | ||
451 | /* read_ctrl_callback | ||
452 | * USB completion handler for control pipe input | ||
453 | * called by the USB subsystem in interrupt context | ||
454 | * parameter: | ||
455 | * urb USB request block | ||
456 | * urb->context = inbuf structure for controller state | ||
457 | */ | ||
458 | static void read_ctrl_callback(struct urb *urb, struct pt_regs *regs) | ||
459 | { | ||
460 | struct inbuf_t *inbuf = urb->context; | ||
461 | struct cardstate *cs = inbuf->cs; | ||
462 | struct bas_cardstate *ucs = cs->hw.bas; | ||
463 | int have_data = 0; | ||
464 | unsigned numbytes; | ||
465 | int rc; | ||
466 | |||
467 | update_basstate(ucs, 0, BS_ATRDPEND); | ||
468 | |||
469 | if (!ucs->rcvbuf_size) { | ||
470 | dev_warn(cs->dev, "%s: no receive in progress\n", __func__); | ||
471 | return; | ||
472 | } | ||
473 | |||
474 | del_timer(&ucs->timer_cmd_in); | ||
475 | |||
476 | switch (urb->status) { | ||
477 | case 0: /* normal completion */ | ||
478 | numbytes = urb->actual_length; | ||
479 | if (unlikely(numbytes != ucs->rcvbuf_size)) { | ||
480 | dev_warn(cs->dev, | ||
481 | "control read: received %d chars, expected %d\n", | ||
482 | numbytes, ucs->rcvbuf_size); | ||
483 | if (numbytes > ucs->rcvbuf_size) | ||
484 | numbytes = ucs->rcvbuf_size; | ||
485 | } | ||
486 | |||
487 | /* copy received bytes to inbuf */ | ||
488 | have_data = gigaset_fill_inbuf(inbuf, ucs->rcvbuf, numbytes); | ||
489 | |||
490 | if (unlikely(numbytes < ucs->rcvbuf_size)) { | ||
491 | /* incomplete - resubmit for remaining bytes */ | ||
492 | ucs->rcvbuf_size -= numbytes; | ||
493 | ucs->retry_cmd_in = 0; | ||
494 | rc = atread_submit(cs, BAS_TIMEOUT); | ||
495 | if (rc >= 0 || rc == -ENODEV) | ||
496 | /* resubmitted or disconnected */ | ||
497 | /* - bypass regular exit block */ | ||
498 | return; | ||
499 | error_reset(cs); | ||
500 | } | ||
501 | break; | ||
502 | |||
503 | case -ENOENT: /* cancelled */ | ||
504 | case -ECONNRESET: /* cancelled (async) */ | ||
505 | case -EINPROGRESS: /* pending */ | ||
506 | case -ENODEV: /* device removed */ | ||
507 | case -ESHUTDOWN: /* device shut down */ | ||
508 | /* no action necessary */ | ||
509 | gig_dbg(DEBUG_USBREQ, "%s: %s", | ||
510 | __func__, get_usb_statmsg(urb->status)); | ||
511 | break; | ||
512 | |||
513 | default: /* severe trouble */ | ||
514 | dev_warn(cs->dev, "control read: %s\n", | ||
515 | get_usb_statmsg(urb->status)); | ||
516 | if (ucs->retry_cmd_in++ < BAS_RETRY) { | ||
517 | dev_notice(cs->dev, "control read: retry %d\n", | ||
518 | ucs->retry_cmd_in); | ||
519 | rc = atread_submit(cs, BAS_TIMEOUT); | ||
520 | if (rc >= 0 || rc == -ENODEV) | ||
521 | /* resubmitted or disconnected */ | ||
522 | /* - bypass regular exit block */ | ||
523 | return; | ||
524 | } else { | ||
525 | dev_err(cs->dev, | ||
526 | "control read: giving up after %d tries\n", | ||
527 | ucs->retry_cmd_in); | ||
528 | } | ||
529 | error_reset(cs); | ||
530 | } | ||
531 | |||
532 | kfree(ucs->rcvbuf); | ||
533 | ucs->rcvbuf = NULL; | ||
534 | ucs->rcvbuf_size = 0; | ||
535 | if (have_data) { | ||
536 | gig_dbg(DEBUG_INTR, "%s-->BH", __func__); | ||
537 | gigaset_schedule_event(cs); | ||
538 | } | ||
539 | } | ||
540 | |||
431 | /* atread_submit | 541 | /* atread_submit |
432 | * submit an HD_READ_ATMESSAGE command URB and optionally start a timeout | 542 | * submit an HD_READ_ATMESSAGE command URB and optionally start a timeout |
433 | * parameters: | 543 | * parameters: |
@@ -466,7 +576,7 @@ static int atread_submit(struct cardstate *cs, int timeout) | |||
466 | if ((ret = usb_submit_urb(ucs->urb_cmd_in, SLAB_ATOMIC)) != 0) { | 576 | if ((ret = usb_submit_urb(ucs->urb_cmd_in, SLAB_ATOMIC)) != 0) { |
467 | update_basstate(ucs, 0, BS_ATRDPEND); | 577 | update_basstate(ucs, 0, BS_ATRDPEND); |
468 | dev_err(cs->dev, "could not submit HD_READ_ATMESSAGE: %s\n", | 578 | dev_err(cs->dev, "could not submit HD_READ_ATMESSAGE: %s\n", |
469 | get_usb_statmsg(ret)); | 579 | get_usb_rcmsg(ret)); |
470 | return ret; | 580 | return ret; |
471 | } | 581 | } |
472 | 582 | ||
@@ -611,9 +721,12 @@ static void read_int_callback(struct urb *urb, struct pt_regs *regs) | |||
611 | kfree(ucs->rcvbuf); | 721 | kfree(ucs->rcvbuf); |
612 | ucs->rcvbuf = NULL; | 722 | ucs->rcvbuf = NULL; |
613 | ucs->rcvbuf_size = 0; | 723 | ucs->rcvbuf_size = 0; |
614 | if (rc != -ENODEV) | 724 | if (rc != -ENODEV) { |
615 | //FIXME corrective action? | 725 | //FIXME corrective action? |
726 | spin_unlock_irqrestore(&cs->lock, flags); | ||
616 | error_reset(cs); | 727 | error_reset(cs); |
728 | break; | ||
729 | } | ||
617 | } | 730 | } |
618 | spin_unlock_irqrestore(&cs->lock, flags); | 731 | spin_unlock_irqrestore(&cs->lock, flags); |
619 | break; | 732 | break; |
@@ -643,97 +756,6 @@ resubmit: | |||
643 | } | 756 | } |
644 | } | 757 | } |
645 | 758 | ||
646 | /* read_ctrl_callback | ||
647 | * USB completion handler for control pipe input | ||
648 | * called by the USB subsystem in interrupt context | ||
649 | * parameter: | ||
650 | * urb USB request block | ||
651 | * urb->context = inbuf structure for controller state | ||
652 | */ | ||
653 | static void read_ctrl_callback(struct urb *urb, struct pt_regs *regs) | ||
654 | { | ||
655 | struct inbuf_t *inbuf = urb->context; | ||
656 | struct cardstate *cs = inbuf->cs; | ||
657 | struct bas_cardstate *ucs = cs->hw.bas; | ||
658 | int have_data = 0; | ||
659 | unsigned numbytes; | ||
660 | int rc; | ||
661 | |||
662 | update_basstate(ucs, 0, BS_ATRDPEND); | ||
663 | |||
664 | if (!ucs->rcvbuf_size) { | ||
665 | dev_warn(cs->dev, "%s: no receive in progress\n", __func__); | ||
666 | return; | ||
667 | } | ||
668 | |||
669 | del_timer(&ucs->timer_cmd_in); | ||
670 | |||
671 | switch (urb->status) { | ||
672 | case 0: /* normal completion */ | ||
673 | numbytes = urb->actual_length; | ||
674 | if (unlikely(numbytes == 0)) { | ||
675 | dev_warn(cs->dev, | ||
676 | "control read: empty block received\n"); | ||
677 | goto retry; | ||
678 | } | ||
679 | if (unlikely(numbytes != ucs->rcvbuf_size)) { | ||
680 | dev_warn(cs->dev, | ||
681 | "control read: received %d chars, expected %d\n", | ||
682 | numbytes, ucs->rcvbuf_size); | ||
683 | if (numbytes > ucs->rcvbuf_size) | ||
684 | numbytes = ucs->rcvbuf_size; | ||
685 | } | ||
686 | |||
687 | /* copy received bytes to inbuf */ | ||
688 | have_data = gigaset_fill_inbuf(inbuf, ucs->rcvbuf, numbytes); | ||
689 | |||
690 | if (unlikely(numbytes < ucs->rcvbuf_size)) { | ||
691 | /* incomplete - resubmit for remaining bytes */ | ||
692 | ucs->rcvbuf_size -= numbytes; | ||
693 | ucs->retry_cmd_in = 0; | ||
694 | goto retry; | ||
695 | } | ||
696 | break; | ||
697 | |||
698 | case -ENOENT: /* cancelled */ | ||
699 | case -ECONNRESET: /* cancelled (async) */ | ||
700 | case -EINPROGRESS: /* pending */ | ||
701 | case -ENODEV: /* device removed */ | ||
702 | case -ESHUTDOWN: /* device shut down */ | ||
703 | /* no action necessary */ | ||
704 | gig_dbg(DEBUG_USBREQ, "%s: %s", | ||
705 | __func__, get_usb_statmsg(urb->status)); | ||
706 | break; | ||
707 | |||
708 | default: /* severe trouble */ | ||
709 | dev_warn(cs->dev, "control read: %s\n", | ||
710 | get_usb_statmsg(urb->status)); | ||
711 | retry: | ||
712 | if (ucs->retry_cmd_in++ < BAS_RETRY) { | ||
713 | dev_notice(cs->dev, "control read: retry %d\n", | ||
714 | ucs->retry_cmd_in); | ||
715 | rc = atread_submit(cs, BAS_TIMEOUT); | ||
716 | if (rc >= 0 || rc == -ENODEV) | ||
717 | /* resubmitted or disconnected */ | ||
718 | /* - bypass regular exit block */ | ||
719 | return; | ||
720 | } else { | ||
721 | dev_err(cs->dev, | ||
722 | "control read: giving up after %d tries\n", | ||
723 | ucs->retry_cmd_in); | ||
724 | } | ||
725 | error_reset(cs); | ||
726 | } | ||
727 | |||
728 | kfree(ucs->rcvbuf); | ||
729 | ucs->rcvbuf = NULL; | ||
730 | ucs->rcvbuf_size = 0; | ||
731 | if (have_data) { | ||
732 | gig_dbg(DEBUG_INTR, "%s-->BH", __func__); | ||
733 | gigaset_schedule_event(cs); | ||
734 | } | ||
735 | } | ||
736 | |||
737 | /* read_iso_callback | 759 | /* read_iso_callback |
738 | * USB completion handler for B channel isochronous input | 760 | * USB completion handler for B channel isochronous input |
739 | * called by the USB subsystem in interrupt context | 761 | * called by the USB subsystem in interrupt context |
@@ -1378,6 +1400,7 @@ static void req_timeout(unsigned long data) | |||
1378 | case HD_CLOSE_B1CHANNEL: | 1400 | case HD_CLOSE_B1CHANNEL: |
1379 | dev_err(bcs->cs->dev, "timeout closing channel %d\n", | 1401 | dev_err(bcs->cs->dev, "timeout closing channel %d\n", |
1380 | bcs->channel + 1); | 1402 | bcs->channel + 1); |
1403 | error_reset(bcs->cs); | ||
1381 | break; | 1404 | break; |
1382 | 1405 | ||
1383 | default: | 1406 | default: |
@@ -1396,22 +1419,61 @@ static void req_timeout(unsigned long data) | |||
1396 | static void write_ctrl_callback(struct urb *urb, struct pt_regs *regs) | 1419 | static void write_ctrl_callback(struct urb *urb, struct pt_regs *regs) |
1397 | { | 1420 | { |
1398 | struct bas_cardstate *ucs = urb->context; | 1421 | struct bas_cardstate *ucs = urb->context; |
1422 | int rc; | ||
1399 | unsigned long flags; | 1423 | unsigned long flags; |
1400 | 1424 | ||
1401 | spin_lock_irqsave(&ucs->lock, flags); | 1425 | /* check status */ |
1402 | if (urb->status && ucs->pending) { | 1426 | switch (urb->status) { |
1403 | dev_err(&ucs->interface->dev, | 1427 | case 0: /* normal completion */ |
1404 | "control request 0x%02x failed: %s\n", | 1428 | spin_lock_irqsave(&ucs->lock, flags); |
1405 | ucs->pending, get_usb_statmsg(urb->status)); | 1429 | switch (ucs->pending) { |
1406 | del_timer(&ucs->timer_ctrl); | 1430 | case HD_DEVICE_INIT_ACK: /* no reply expected */ |
1407 | ucs->pending = 0; | 1431 | del_timer(&ucs->timer_ctrl); |
1408 | } | 1432 | ucs->pending = 0; |
1409 | /* individual handling of specific request types */ | 1433 | break; |
1410 | switch (ucs->pending) { | 1434 | } |
1411 | case HD_DEVICE_INIT_ACK: /* no reply expected */ | 1435 | spin_unlock_irqrestore(&ucs->lock, flags); |
1412 | ucs->pending = 0; | 1436 | return; |
1437 | |||
1438 | case -ENOENT: /* cancelled */ | ||
1439 | case -ECONNRESET: /* cancelled (async) */ | ||
1440 | case -EINPROGRESS: /* pending */ | ||
1441 | case -ENODEV: /* device removed */ | ||
1442 | case -ESHUTDOWN: /* device shut down */ | ||
1443 | /* ignore silently */ | ||
1444 | gig_dbg(DEBUG_USBREQ, "%s: %s", | ||
1445 | __func__, get_usb_statmsg(urb->status)); | ||
1413 | break; | 1446 | break; |
1447 | |||
1448 | default: /* any failure */ | ||
1449 | if (++ucs->retry_ctrl > BAS_RETRY) { | ||
1450 | dev_err(&ucs->interface->dev, | ||
1451 | "control request 0x%02x failed: %s\n", | ||
1452 | ucs->dr_ctrl.bRequest, | ||
1453 | get_usb_statmsg(urb->status)); | ||
1454 | break; /* give up */ | ||
1455 | } | ||
1456 | dev_notice(&ucs->interface->dev, | ||
1457 | "control request 0x%02x: %s, retry %d\n", | ||
1458 | ucs->dr_ctrl.bRequest, get_usb_statmsg(urb->status), | ||
1459 | ucs->retry_ctrl); | ||
1460 | /* urb->dev is clobbered by USB subsystem */ | ||
1461 | urb->dev = ucs->udev; | ||
1462 | rc = usb_submit_urb(urb, SLAB_ATOMIC); | ||
1463 | if (unlikely(rc)) { | ||
1464 | dev_err(&ucs->interface->dev, | ||
1465 | "could not resubmit request 0x%02x: %s\n", | ||
1466 | ucs->dr_ctrl.bRequest, get_usb_rcmsg(rc)); | ||
1467 | break; | ||
1468 | } | ||
1469 | /* resubmitted */ | ||
1470 | return; | ||
1414 | } | 1471 | } |
1472 | |||
1473 | /* failed, clear pending request */ | ||
1474 | spin_lock_irqsave(&ucs->lock, flags); | ||
1475 | del_timer(&ucs->timer_ctrl); | ||
1476 | ucs->pending = 0; | ||
1415 | spin_unlock_irqrestore(&ucs->lock, flags); | 1477 | spin_unlock_irqrestore(&ucs->lock, flags); |
1416 | } | 1478 | } |
1417 | 1479 | ||
@@ -1455,9 +1517,11 @@ static int req_submit(struct bc_state *bcs, int req, int val, int timeout) | |||
1455 | usb_sndctrlpipe(ucs->udev, 0), | 1517 | usb_sndctrlpipe(ucs->udev, 0), |
1456 | (unsigned char*) &ucs->dr_ctrl, NULL, 0, | 1518 | (unsigned char*) &ucs->dr_ctrl, NULL, 0, |
1457 | write_ctrl_callback, ucs); | 1519 | write_ctrl_callback, ucs); |
1458 | if ((ret = usb_submit_urb(ucs->urb_ctrl, SLAB_ATOMIC)) != 0) { | 1520 | ucs->retry_ctrl = 0; |
1521 | ret = usb_submit_urb(ucs->urb_ctrl, SLAB_ATOMIC); | ||
1522 | if (unlikely(ret)) { | ||
1459 | dev_err(bcs->cs->dev, "could not submit request 0x%02x: %s\n", | 1523 | dev_err(bcs->cs->dev, "could not submit request 0x%02x: %s\n", |
1460 | req, get_usb_statmsg(ret)); | 1524 | req, get_usb_rcmsg(ret)); |
1461 | spin_unlock_irqrestore(&ucs->lock, flags); | 1525 | spin_unlock_irqrestore(&ucs->lock, flags); |
1462 | return ret; | 1526 | return ret; |
1463 | } | 1527 | } |
diff --git a/drivers/isdn/gigaset/ev-layer.c b/drivers/isdn/gigaset/ev-layer.c index 18e05c09b71c..44f02dbd1111 100644 --- a/drivers/isdn/gigaset/ev-layer.c +++ b/drivers/isdn/gigaset/ev-layer.c | |||
@@ -1262,7 +1262,8 @@ static void do_action(int action, struct cardstate *cs, | |||
1262 | break; | 1262 | break; |
1263 | case ACT_HUPMODEM: | 1263 | case ACT_HUPMODEM: |
1264 | /* send "+++" (hangup in unimodem mode) */ | 1264 | /* send "+++" (hangup in unimodem mode) */ |
1265 | cs->ops->write_cmd(cs, "+++", 3, NULL); | 1265 | if (cs->connected) |
1266 | cs->ops->write_cmd(cs, "+++", 3, NULL); | ||
1266 | break; | 1267 | break; |
1267 | case ACT_RING: | 1268 | case ACT_RING: |
1268 | /* get fresh AT state structure for new CID */ | 1269 | /* get fresh AT state structure for new CID */ |
@@ -1294,7 +1295,6 @@ static void do_action(int action, struct cardstate *cs, | |||
1294 | break; | 1295 | break; |
1295 | case ACT_ICALL: | 1296 | case ACT_ICALL: |
1296 | handle_icall(cs, bcs, p_at_state); | 1297 | handle_icall(cs, bcs, p_at_state); |
1297 | at_state = *p_at_state; | ||
1298 | break; | 1298 | break; |
1299 | case ACT_FAILSDOWN: | 1299 | case ACT_FAILSDOWN: |
1300 | dev_warn(cs->dev, "Could not shut down the device.\n"); | 1300 | dev_warn(cs->dev, "Could not shut down the device.\n"); |
@@ -1334,10 +1334,8 @@ static void do_action(int action, struct cardstate *cs, | |||
1334 | */ | 1334 | */ |
1335 | at_state->pending_commands |= PC_DLE0; | 1335 | at_state->pending_commands |= PC_DLE0; |
1336 | atomic_set(&cs->commands_pending, 1); | 1336 | atomic_set(&cs->commands_pending, 1); |
1337 | } else { | 1337 | } else |
1338 | disconnect(p_at_state); | 1338 | disconnect(p_at_state); |
1339 | at_state = *p_at_state; | ||
1340 | } | ||
1341 | break; | 1339 | break; |
1342 | case ACT_FAKEDLE0: | 1340 | case ACT_FAKEDLE0: |
1343 | at_state->int_var[VAR_ZDLE] = 0; | 1341 | at_state->int_var[VAR_ZDLE] = 0; |
@@ -1354,10 +1352,8 @@ static void do_action(int action, struct cardstate *cs, | |||
1354 | at_state->cid = -1; | 1352 | at_state->cid = -1; |
1355 | if (bcs && cs->onechannel) | 1353 | if (bcs && cs->onechannel) |
1356 | at_state->pending_commands |= PC_DLE0; | 1354 | at_state->pending_commands |= PC_DLE0; |
1357 | else { | 1355 | else |
1358 | disconnect(p_at_state); | 1356 | disconnect(p_at_state); |
1359 | at_state = *p_at_state; | ||
1360 | } | ||
1361 | schedule_init(cs, MS_RECOVER); | 1357 | schedule_init(cs, MS_RECOVER); |
1362 | break; | 1358 | break; |
1363 | case ACT_FAILDLE0: | 1359 | case ACT_FAILDLE0: |
@@ -1410,7 +1406,6 @@ static void do_action(int action, struct cardstate *cs, | |||
1410 | 1406 | ||
1411 | case ACT_ABORTACCEPT: /* hangup/error/timeout during ICALL processing */ | 1407 | case ACT_ABORTACCEPT: /* hangup/error/timeout during ICALL processing */ |
1412 | disconnect(p_at_state); | 1408 | disconnect(p_at_state); |
1413 | at_state = *p_at_state; | ||
1414 | break; | 1409 | break; |
1415 | 1410 | ||
1416 | case ACT_ABORTDIAL: /* error/timeout during dial preparation */ | 1411 | case ACT_ABORTDIAL: /* error/timeout during dial preparation */ |
diff --git a/drivers/isdn/hisax/q931.c b/drivers/isdn/hisax/q931.c index abecabf8c271..aacbf0d14b64 100644 --- a/drivers/isdn/hisax/q931.c +++ b/drivers/isdn/hisax/q931.c | |||
@@ -1402,12 +1402,12 @@ dlogframe(struct IsdnCardState *cs, struct sk_buff *skb, int dir) | |||
1402 | } | 1402 | } |
1403 | /* No, locate it in the table */ | 1403 | /* No, locate it in the table */ |
1404 | if (cset == 0) { | 1404 | if (cset == 0) { |
1405 | for (i = 0; i < IESIZE; i++) | 1405 | for (i = 0; i < IESIZE_NI1; i++) |
1406 | if (*buf == ielist_ni1[i].nr) | 1406 | if (*buf == ielist_ni1[i].nr) |
1407 | break; | 1407 | break; |
1408 | 1408 | ||
1409 | /* When not found, give appropriate msg */ | 1409 | /* When not found, give appropriate msg */ |
1410 | if (i != IESIZE) { | 1410 | if (i != IESIZE_NI1) { |
1411 | dp += sprintf(dp, " %s\n", ielist_ni1[i].descr); | 1411 | dp += sprintf(dp, " %s\n", ielist_ni1[i].descr); |
1412 | dp += ielist_ni1[i].f(dp, buf); | 1412 | dp += ielist_ni1[i].f(dp, buf); |
1413 | } else | 1413 | } else |
diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig index ac25a48362ac..bf869ed03eed 100644 --- a/drivers/md/Kconfig +++ b/drivers/md/Kconfig | |||
@@ -90,7 +90,7 @@ config MD_RAID10 | |||
90 | depends on BLK_DEV_MD && EXPERIMENTAL | 90 | depends on BLK_DEV_MD && EXPERIMENTAL |
91 | ---help--- | 91 | ---help--- |
92 | RAID-10 provides a combination of striping (RAID-0) and | 92 | RAID-10 provides a combination of striping (RAID-0) and |
93 | mirroring (RAID-1) with easier configuration and more flexable | 93 | mirroring (RAID-1) with easier configuration and more flexible |
94 | layout. | 94 | layout. |
95 | Unlike RAID-0, but like RAID-1, RAID-10 requires all devices to | 95 | Unlike RAID-0, but like RAID-1, RAID-10 requires all devices to |
96 | be the same size (or at least, only as much as the smallest device | 96 | be the same size (or at least, only as much as the smallest device |
@@ -104,8 +104,8 @@ config MD_RAID10 | |||
104 | 104 | ||
105 | If unsure, say Y. | 105 | If unsure, say Y. |
106 | 106 | ||
107 | config MD_RAID5 | 107 | config MD_RAID456 |
108 | tristate "RAID-4/RAID-5 mode" | 108 | tristate "RAID-4/RAID-5/RAID-6 mode" |
109 | depends on BLK_DEV_MD | 109 | depends on BLK_DEV_MD |
110 | ---help--- | 110 | ---help--- |
111 | A RAID-5 set of N drives with a capacity of C MB per drive provides | 111 | A RAID-5 set of N drives with a capacity of C MB per drive provides |
@@ -116,20 +116,28 @@ config MD_RAID5 | |||
116 | while a RAID-5 set distributes the parity across the drives in one | 116 | while a RAID-5 set distributes the parity across the drives in one |
117 | of the available parity distribution methods. | 117 | of the available parity distribution methods. |
118 | 118 | ||
119 | A RAID-6 set of N drives with a capacity of C MB per drive | ||
120 | provides the capacity of C * (N - 2) MB, and protects | ||
121 | against a failure of any two drives. For a given sector | ||
122 | (row) number, (N - 2) drives contain data sectors, and two | ||
123 | drives contains two independent redundancy syndromes. Like | ||
124 | RAID-5, RAID-6 distributes the syndromes across the drives | ||
125 | in one of the available parity distribution methods. | ||
126 | |||
119 | Information about Software RAID on Linux is contained in the | 127 | Information about Software RAID on Linux is contained in the |
120 | Software-RAID mini-HOWTO, available from | 128 | Software-RAID mini-HOWTO, available from |
121 | <http://www.tldp.org/docs.html#howto>. There you will also | 129 | <http://www.tldp.org/docs.html#howto>. There you will also |
122 | learn where to get the supporting user space utilities raidtools. | 130 | learn where to get the supporting user space utilities raidtools. |
123 | 131 | ||
124 | If you want to use such a RAID-4/RAID-5 set, say Y. To | 132 | If you want to use such a RAID-4/RAID-5/RAID-6 set, say Y. To |
125 | compile this code as a module, choose M here: the module | 133 | compile this code as a module, choose M here: the module |
126 | will be called raid5. | 134 | will be called raid456. |
127 | 135 | ||
128 | If unsure, say Y. | 136 | If unsure, say Y. |
129 | 137 | ||
130 | config MD_RAID5_RESHAPE | 138 | config MD_RAID5_RESHAPE |
131 | bool "Support adding drives to a raid-5 array (experimental)" | 139 | bool "Support adding drives to a raid-5 array (experimental)" |
132 | depends on MD_RAID5 && EXPERIMENTAL | 140 | depends on MD_RAID456 && EXPERIMENTAL |
133 | ---help--- | 141 | ---help--- |
134 | A RAID-5 set can be expanded by adding extra drives. This | 142 | A RAID-5 set can be expanded by adding extra drives. This |
135 | requires "restriping" the array which means (almost) every | 143 | requires "restriping" the array which means (almost) every |
@@ -139,7 +147,7 @@ config MD_RAID5_RESHAPE | |||
139 | is online. However it is still EXPERIMENTAL code. It should | 147 | is online. However it is still EXPERIMENTAL code. It should |
140 | work, but please be sure that you have backups. | 148 | work, but please be sure that you have backups. |
141 | 149 | ||
142 | You will need mdadm verion 2.4.1 or later to use this | 150 | You will need mdadm version 2.4.1 or later to use this |
143 | feature safely. During the early stage of reshape there is | 151 | feature safely. During the early stage of reshape there is |
144 | a critical section where live data is being over-written. A | 152 | a critical section where live data is being over-written. A |
145 | crash during this time needs extra care for recovery. The | 153 | crash during this time needs extra care for recovery. The |
@@ -154,28 +162,6 @@ config MD_RAID5_RESHAPE | |||
154 | There should be enough spares already present to make the new | 162 | There should be enough spares already present to make the new |
155 | array workable. | 163 | array workable. |
156 | 164 | ||
157 | config MD_RAID6 | ||
158 | tristate "RAID-6 mode" | ||
159 | depends on BLK_DEV_MD | ||
160 | ---help--- | ||
161 | A RAID-6 set of N drives with a capacity of C MB per drive | ||
162 | provides the capacity of C * (N - 2) MB, and protects | ||
163 | against a failure of any two drives. For a given sector | ||
164 | (row) number, (N - 2) drives contain data sectors, and two | ||
165 | drives contains two independent redundancy syndromes. Like | ||
166 | RAID-5, RAID-6 distributes the syndromes across the drives | ||
167 | in one of the available parity distribution methods. | ||
168 | |||
169 | RAID-6 requires mdadm-1.5.0 or later, available at: | ||
170 | |||
171 | ftp://ftp.kernel.org/pub/linux/utils/raid/mdadm/ | ||
172 | |||
173 | If you want to use such a RAID-6 set, say Y. To compile | ||
174 | this code as a module, choose M here: the module will be | ||
175 | called raid6. | ||
176 | |||
177 | If unsure, say Y. | ||
178 | |||
179 | config MD_MULTIPATH | 165 | config MD_MULTIPATH |
180 | tristate "Multipath I/O support" | 166 | tristate "Multipath I/O support" |
181 | depends on BLK_DEV_MD | 167 | depends on BLK_DEV_MD |
@@ -235,7 +221,7 @@ config DM_SNAPSHOT | |||
235 | tristate "Snapshot target (EXPERIMENTAL)" | 221 | tristate "Snapshot target (EXPERIMENTAL)" |
236 | depends on BLK_DEV_DM && EXPERIMENTAL | 222 | depends on BLK_DEV_DM && EXPERIMENTAL |
237 | ---help--- | 223 | ---help--- |
238 | Allow volume managers to take writeable snapshots of a device. | 224 | Allow volume managers to take writable snapshots of a device. |
239 | 225 | ||
240 | config DM_MIRROR | 226 | config DM_MIRROR |
241 | tristate "Mirror target (EXPERIMENTAL)" | 227 | tristate "Mirror target (EXPERIMENTAL)" |
diff --git a/drivers/md/Makefile b/drivers/md/Makefile index d3efedf6a6ad..34957a68d921 100644 --- a/drivers/md/Makefile +++ b/drivers/md/Makefile | |||
@@ -8,7 +8,7 @@ dm-multipath-objs := dm-hw-handler.o dm-path-selector.o dm-mpath.o | |||
8 | dm-snapshot-objs := dm-snap.o dm-exception-store.o | 8 | dm-snapshot-objs := dm-snap.o dm-exception-store.o |
9 | dm-mirror-objs := dm-log.o dm-raid1.o | 9 | dm-mirror-objs := dm-log.o dm-raid1.o |
10 | md-mod-objs := md.o bitmap.o | 10 | md-mod-objs := md.o bitmap.o |
11 | raid6-objs := raid6main.o raid6algos.o raid6recov.o raid6tables.o \ | 11 | raid456-objs := raid5.o raid6algos.o raid6recov.o raid6tables.o \ |
12 | raid6int1.o raid6int2.o raid6int4.o \ | 12 | raid6int1.o raid6int2.o raid6int4.o \ |
13 | raid6int8.o raid6int16.o raid6int32.o \ | 13 | raid6int8.o raid6int16.o raid6int32.o \ |
14 | raid6altivec1.o raid6altivec2.o raid6altivec4.o \ | 14 | raid6altivec1.o raid6altivec2.o raid6altivec4.o \ |
@@ -25,8 +25,7 @@ obj-$(CONFIG_MD_LINEAR) += linear.o | |||
25 | obj-$(CONFIG_MD_RAID0) += raid0.o | 25 | obj-$(CONFIG_MD_RAID0) += raid0.o |
26 | obj-$(CONFIG_MD_RAID1) += raid1.o | 26 | obj-$(CONFIG_MD_RAID1) += raid1.o |
27 | obj-$(CONFIG_MD_RAID10) += raid10.o | 27 | obj-$(CONFIG_MD_RAID10) += raid10.o |
28 | obj-$(CONFIG_MD_RAID5) += raid5.o xor.o | 28 | obj-$(CONFIG_MD_RAID456) += raid456.o xor.o |
29 | obj-$(CONFIG_MD_RAID6) += raid6.o xor.o | ||
30 | obj-$(CONFIG_MD_MULTIPATH) += multipath.o | 29 | obj-$(CONFIG_MD_MULTIPATH) += multipath.o |
31 | obj-$(CONFIG_MD_FAULTY) += faulty.o | 30 | obj-$(CONFIG_MD_FAULTY) += faulty.o |
32 | obj-$(CONFIG_BLK_DEV_MD) += md-mod.o | 31 | obj-$(CONFIG_BLK_DEV_MD) += md-mod.o |
diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index f8ffaee20ff8..ebbd2d856256 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c | |||
@@ -7,7 +7,6 @@ | |||
7 | * additions, Copyright (C) 2003-2004, Paul Clements, SteelEye Technology, Inc.: | 7 | * additions, Copyright (C) 2003-2004, Paul Clements, SteelEye Technology, Inc.: |
8 | * - added disk storage for bitmap | 8 | * - added disk storage for bitmap |
9 | * - changes to allow various bitmap chunk sizes | 9 | * - changes to allow various bitmap chunk sizes |
10 | * - added bitmap daemon (to asynchronously clear bitmap bits from disk) | ||
11 | */ | 10 | */ |
12 | 11 | ||
13 | /* | 12 | /* |
@@ -15,9 +14,6 @@ | |||
15 | * | 14 | * |
16 | * flush after percent set rather than just time based. (maybe both). | 15 | * flush after percent set rather than just time based. (maybe both). |
17 | * wait if count gets too high, wake when it drops to half. | 16 | * wait if count gets too high, wake when it drops to half. |
18 | * allow bitmap to be mirrored with superblock (before or after...) | ||
19 | * allow hot-add to re-instate a current device. | ||
20 | * allow hot-add of bitmap after quiessing device | ||
21 | */ | 17 | */ |
22 | 18 | ||
23 | #include <linux/module.h> | 19 | #include <linux/module.h> |
@@ -73,24 +69,6 @@ static inline char * bmname(struct bitmap *bitmap) | |||
73 | 69 | ||
74 | 70 | ||
75 | /* | 71 | /* |
76 | * test if the bitmap is active | ||
77 | */ | ||
78 | int bitmap_active(struct bitmap *bitmap) | ||
79 | { | ||
80 | unsigned long flags; | ||
81 | int res = 0; | ||
82 | |||
83 | if (!bitmap) | ||
84 | return res; | ||
85 | spin_lock_irqsave(&bitmap->lock, flags); | ||
86 | res = bitmap->flags & BITMAP_ACTIVE; | ||
87 | spin_unlock_irqrestore(&bitmap->lock, flags); | ||
88 | return res; | ||
89 | } | ||
90 | |||
91 | #define WRITE_POOL_SIZE 256 | ||
92 | |||
93 | /* | ||
94 | * just a placeholder - calls kmalloc for bitmap pages | 72 | * just a placeholder - calls kmalloc for bitmap pages |
95 | */ | 73 | */ |
96 | static unsigned char *bitmap_alloc_page(struct bitmap *bitmap) | 74 | static unsigned char *bitmap_alloc_page(struct bitmap *bitmap) |
@@ -269,6 +247,8 @@ static struct page *read_sb_page(mddev_t *mddev, long offset, unsigned long inde | |||
269 | 247 | ||
270 | if (sync_page_io(rdev->bdev, target, PAGE_SIZE, page, READ)) { | 248 | if (sync_page_io(rdev->bdev, target, PAGE_SIZE, page, READ)) { |
271 | page->index = index; | 249 | page->index = index; |
250 | attach_page_buffers(page, NULL); /* so that free_buffer will | ||
251 | * quietly no-op */ | ||
272 | return page; | 252 | return page; |
273 | } | 253 | } |
274 | } | 254 | } |
@@ -300,77 +280,132 @@ static int write_sb_page(mddev_t *mddev, long offset, struct page *page, int wai | |||
300 | */ | 280 | */ |
301 | static int write_page(struct bitmap *bitmap, struct page *page, int wait) | 281 | static int write_page(struct bitmap *bitmap, struct page *page, int wait) |
302 | { | 282 | { |
303 | int ret = -ENOMEM; | 283 | struct buffer_head *bh; |
304 | 284 | ||
305 | if (bitmap->file == NULL) | 285 | if (bitmap->file == NULL) |
306 | return write_sb_page(bitmap->mddev, bitmap->offset, page, wait); | 286 | return write_sb_page(bitmap->mddev, bitmap->offset, page, wait); |
307 | 287 | ||
308 | flush_dcache_page(page); /* make sure visible to anyone reading the file */ | 288 | bh = page_buffers(page); |
309 | 289 | ||
310 | if (wait) | 290 | while (bh && bh->b_blocknr) { |
311 | lock_page(page); | 291 | atomic_inc(&bitmap->pending_writes); |
312 | else { | 292 | set_buffer_locked(bh); |
313 | if (TestSetPageLocked(page)) | 293 | set_buffer_mapped(bh); |
314 | return -EAGAIN; /* already locked */ | 294 | submit_bh(WRITE, bh); |
315 | if (PageWriteback(page)) { | 295 | bh = bh->b_this_page; |
316 | unlock_page(page); | ||
317 | return -EAGAIN; | ||
318 | } | ||
319 | } | 296 | } |
320 | 297 | ||
321 | ret = page->mapping->a_ops->prepare_write(bitmap->file, page, 0, PAGE_SIZE); | 298 | if (wait) { |
322 | if (!ret) | 299 | wait_event(bitmap->write_wait, |
323 | ret = page->mapping->a_ops->commit_write(bitmap->file, page, 0, | 300 | atomic_read(&bitmap->pending_writes)==0); |
324 | PAGE_SIZE); | 301 | return (bitmap->flags & BITMAP_WRITE_ERROR) ? -EIO : 0; |
325 | if (ret) { | ||
326 | unlock_page(page); | ||
327 | return ret; | ||
328 | } | 302 | } |
303 | return 0; | ||
304 | } | ||
329 | 305 | ||
330 | set_page_dirty(page); /* force it to be written out */ | 306 | static void end_bitmap_write(struct buffer_head *bh, int uptodate) |
331 | 307 | { | |
332 | if (!wait) { | 308 | struct bitmap *bitmap = bh->b_private; |
333 | /* add to list to be waited for by daemon */ | 309 | unsigned long flags; |
334 | struct page_list *item = mempool_alloc(bitmap->write_pool, GFP_NOIO); | 310 | |
335 | item->page = page; | 311 | if (!uptodate) { |
336 | get_page(page); | 312 | spin_lock_irqsave(&bitmap->lock, flags); |
337 | spin_lock(&bitmap->write_lock); | 313 | bitmap->flags |= BITMAP_WRITE_ERROR; |
338 | list_add(&item->list, &bitmap->complete_pages); | 314 | spin_unlock_irqrestore(&bitmap->lock, flags); |
339 | spin_unlock(&bitmap->write_lock); | 315 | } |
340 | md_wakeup_thread(bitmap->writeback_daemon); | 316 | if (atomic_dec_and_test(&bitmap->pending_writes)) |
317 | wake_up(&bitmap->write_wait); | ||
318 | } | ||
319 | |||
320 | /* copied from buffer.c */ | ||
321 | static void | ||
322 | __clear_page_buffers(struct page *page) | ||
323 | { | ||
324 | ClearPagePrivate(page); | ||
325 | set_page_private(page, 0); | ||
326 | page_cache_release(page); | ||
327 | } | ||
328 | static void free_buffers(struct page *page) | ||
329 | { | ||
330 | struct buffer_head *bh = page_buffers(page); | ||
331 | |||
332 | while (bh) { | ||
333 | struct buffer_head *next = bh->b_this_page; | ||
334 | free_buffer_head(bh); | ||
335 | bh = next; | ||
341 | } | 336 | } |
342 | return write_one_page(page, wait); | 337 | __clear_page_buffers(page); |
338 | put_page(page); | ||
343 | } | 339 | } |
344 | 340 | ||
345 | /* read a page from a file, pinning it into cache, and return bytes_read */ | 341 | /* read a page from a file. |
342 | * We both read the page, and attach buffers to the page to record the | ||
343 | * address of each block (using bmap). These addresses will be used | ||
344 | * to write the block later, completely bypassing the filesystem. | ||
345 | * This usage is similar to how swap files are handled, and allows us | ||
346 | * to write to a file with no concerns of memory allocation failing. | ||
347 | */ | ||
346 | static struct page *read_page(struct file *file, unsigned long index, | 348 | static struct page *read_page(struct file *file, unsigned long index, |
347 | unsigned long *bytes_read) | 349 | struct bitmap *bitmap, |
350 | unsigned long count) | ||
348 | { | 351 | { |
349 | struct inode *inode = file->f_mapping->host; | ||
350 | struct page *page = NULL; | 352 | struct page *page = NULL; |
351 | loff_t isize = i_size_read(inode); | 353 | struct inode *inode = file->f_dentry->d_inode; |
352 | unsigned long end_index = isize >> PAGE_SHIFT; | 354 | struct buffer_head *bh; |
355 | sector_t block; | ||
353 | 356 | ||
354 | PRINTK("read bitmap file (%dB @ %Lu)\n", (int)PAGE_SIZE, | 357 | PRINTK("read bitmap file (%dB @ %Lu)\n", (int)PAGE_SIZE, |
355 | (unsigned long long)index << PAGE_SHIFT); | 358 | (unsigned long long)index << PAGE_SHIFT); |
356 | 359 | ||
357 | page = read_cache_page(inode->i_mapping, index, | 360 | page = alloc_page(GFP_KERNEL); |
358 | (filler_t *)inode->i_mapping->a_ops->readpage, file); | 361 | if (!page) |
362 | page = ERR_PTR(-ENOMEM); | ||
359 | if (IS_ERR(page)) | 363 | if (IS_ERR(page)) |
360 | goto out; | 364 | goto out; |
361 | wait_on_page_locked(page); | 365 | |
362 | if (!PageUptodate(page) || PageError(page)) { | 366 | bh = alloc_page_buffers(page, 1<<inode->i_blkbits, 0); |
367 | if (!bh) { | ||
363 | put_page(page); | 368 | put_page(page); |
364 | page = ERR_PTR(-EIO); | 369 | page = ERR_PTR(-ENOMEM); |
365 | goto out; | 370 | goto out; |
366 | } | 371 | } |
372 | attach_page_buffers(page, bh); | ||
373 | block = index << (PAGE_SHIFT - inode->i_blkbits); | ||
374 | while (bh) { | ||
375 | if (count == 0) | ||
376 | bh->b_blocknr = 0; | ||
377 | else { | ||
378 | bh->b_blocknr = bmap(inode, block); | ||
379 | if (bh->b_blocknr == 0) { | ||
380 | /* Cannot use this file! */ | ||
381 | free_buffers(page); | ||
382 | page = ERR_PTR(-EINVAL); | ||
383 | goto out; | ||
384 | } | ||
385 | bh->b_bdev = inode->i_sb->s_bdev; | ||
386 | if (count < (1<<inode->i_blkbits)) | ||
387 | count = 0; | ||
388 | else | ||
389 | count -= (1<<inode->i_blkbits); | ||
390 | |||
391 | bh->b_end_io = end_bitmap_write; | ||
392 | bh->b_private = bitmap; | ||
393 | atomic_inc(&bitmap->pending_writes); | ||
394 | set_buffer_locked(bh); | ||
395 | set_buffer_mapped(bh); | ||
396 | submit_bh(READ, bh); | ||
397 | } | ||
398 | block++; | ||
399 | bh = bh->b_this_page; | ||
400 | } | ||
401 | page->index = index; | ||
367 | 402 | ||
368 | if (index > end_index) /* we have read beyond EOF */ | 403 | wait_event(bitmap->write_wait, |
369 | *bytes_read = 0; | 404 | atomic_read(&bitmap->pending_writes)==0); |
370 | else if (index == end_index) /* possible short read */ | 405 | if (bitmap->flags & BITMAP_WRITE_ERROR) { |
371 | *bytes_read = isize & ~PAGE_MASK; | 406 | free_buffers(page); |
372 | else | 407 | page = ERR_PTR(-EIO); |
373 | *bytes_read = PAGE_SIZE; /* got a full page */ | 408 | } |
374 | out: | 409 | out: |
375 | if (IS_ERR(page)) | 410 | if (IS_ERR(page)) |
376 | printk(KERN_ALERT "md: bitmap read error: (%dB @ %Lu): %ld\n", | 411 | printk(KERN_ALERT "md: bitmap read error: (%dB @ %Lu): %ld\n", |
@@ -441,16 +476,14 @@ static int bitmap_read_sb(struct bitmap *bitmap) | |||
441 | char *reason = NULL; | 476 | char *reason = NULL; |
442 | bitmap_super_t *sb; | 477 | bitmap_super_t *sb; |
443 | unsigned long chunksize, daemon_sleep, write_behind; | 478 | unsigned long chunksize, daemon_sleep, write_behind; |
444 | unsigned long bytes_read; | ||
445 | unsigned long long events; | 479 | unsigned long long events; |
446 | int err = -EINVAL; | 480 | int err = -EINVAL; |
447 | 481 | ||
448 | /* page 0 is the superblock, read it... */ | 482 | /* page 0 is the superblock, read it... */ |
449 | if (bitmap->file) | 483 | if (bitmap->file) |
450 | bitmap->sb_page = read_page(bitmap->file, 0, &bytes_read); | 484 | bitmap->sb_page = read_page(bitmap->file, 0, bitmap, PAGE_SIZE); |
451 | else { | 485 | else { |
452 | bitmap->sb_page = read_sb_page(bitmap->mddev, bitmap->offset, 0); | 486 | bitmap->sb_page = read_sb_page(bitmap->mddev, bitmap->offset, 0); |
453 | bytes_read = PAGE_SIZE; | ||
454 | } | 487 | } |
455 | if (IS_ERR(bitmap->sb_page)) { | 488 | if (IS_ERR(bitmap->sb_page)) { |
456 | err = PTR_ERR(bitmap->sb_page); | 489 | err = PTR_ERR(bitmap->sb_page); |
@@ -460,13 +493,6 @@ static int bitmap_read_sb(struct bitmap *bitmap) | |||
460 | 493 | ||
461 | sb = (bitmap_super_t *)kmap_atomic(bitmap->sb_page, KM_USER0); | 494 | sb = (bitmap_super_t *)kmap_atomic(bitmap->sb_page, KM_USER0); |
462 | 495 | ||
463 | if (bytes_read < sizeof(*sb)) { /* short read */ | ||
464 | printk(KERN_INFO "%s: bitmap file superblock truncated\n", | ||
465 | bmname(bitmap)); | ||
466 | err = -ENOSPC; | ||
467 | goto out; | ||
468 | } | ||
469 | |||
470 | chunksize = le32_to_cpu(sb->chunksize); | 496 | chunksize = le32_to_cpu(sb->chunksize); |
471 | daemon_sleep = le32_to_cpu(sb->daemon_sleep); | 497 | daemon_sleep = le32_to_cpu(sb->daemon_sleep); |
472 | write_behind = le32_to_cpu(sb->write_behind); | 498 | write_behind = le32_to_cpu(sb->write_behind); |
@@ -550,7 +576,6 @@ static void bitmap_mask_state(struct bitmap *bitmap, enum bitmap_state bits, | |||
550 | spin_unlock_irqrestore(&bitmap->lock, flags); | 576 | spin_unlock_irqrestore(&bitmap->lock, flags); |
551 | return; | 577 | return; |
552 | } | 578 | } |
553 | get_page(bitmap->sb_page); | ||
554 | spin_unlock_irqrestore(&bitmap->lock, flags); | 579 | spin_unlock_irqrestore(&bitmap->lock, flags); |
555 | sb = (bitmap_super_t *)kmap_atomic(bitmap->sb_page, KM_USER0); | 580 | sb = (bitmap_super_t *)kmap_atomic(bitmap->sb_page, KM_USER0); |
556 | switch (op) { | 581 | switch (op) { |
@@ -561,7 +586,6 @@ static void bitmap_mask_state(struct bitmap *bitmap, enum bitmap_state bits, | |||
561 | default: BUG(); | 586 | default: BUG(); |
562 | } | 587 | } |
563 | kunmap_atomic(sb, KM_USER0); | 588 | kunmap_atomic(sb, KM_USER0); |
564 | put_page(bitmap->sb_page); | ||
565 | } | 589 | } |
566 | 590 | ||
567 | /* | 591 | /* |
@@ -614,48 +638,17 @@ static void bitmap_file_unmap(struct bitmap *bitmap) | |||
614 | 638 | ||
615 | while (pages--) | 639 | while (pages--) |
616 | if (map[pages]->index != 0) /* 0 is sb_page, release it below */ | 640 | if (map[pages]->index != 0) /* 0 is sb_page, release it below */ |
617 | put_page(map[pages]); | 641 | free_buffers(map[pages]); |
618 | kfree(map); | 642 | kfree(map); |
619 | kfree(attr); | 643 | kfree(attr); |
620 | 644 | ||
621 | safe_put_page(sb_page); | 645 | if (sb_page) |
622 | } | 646 | free_buffers(sb_page); |
623 | |||
624 | static void bitmap_stop_daemon(struct bitmap *bitmap); | ||
625 | |||
626 | /* dequeue the next item in a page list -- don't call from irq context */ | ||
627 | static struct page_list *dequeue_page(struct bitmap *bitmap) | ||
628 | { | ||
629 | struct page_list *item = NULL; | ||
630 | struct list_head *head = &bitmap->complete_pages; | ||
631 | |||
632 | spin_lock(&bitmap->write_lock); | ||
633 | if (list_empty(head)) | ||
634 | goto out; | ||
635 | item = list_entry(head->prev, struct page_list, list); | ||
636 | list_del(head->prev); | ||
637 | out: | ||
638 | spin_unlock(&bitmap->write_lock); | ||
639 | return item; | ||
640 | } | ||
641 | |||
642 | static void drain_write_queues(struct bitmap *bitmap) | ||
643 | { | ||
644 | struct page_list *item; | ||
645 | |||
646 | while ((item = dequeue_page(bitmap))) { | ||
647 | /* don't bother to wait */ | ||
648 | put_page(item->page); | ||
649 | mempool_free(item, bitmap->write_pool); | ||
650 | } | ||
651 | |||
652 | wake_up(&bitmap->write_wait); | ||
653 | } | 647 | } |
654 | 648 | ||
655 | static void bitmap_file_put(struct bitmap *bitmap) | 649 | static void bitmap_file_put(struct bitmap *bitmap) |
656 | { | 650 | { |
657 | struct file *file; | 651 | struct file *file; |
658 | struct inode *inode; | ||
659 | unsigned long flags; | 652 | unsigned long flags; |
660 | 653 | ||
661 | spin_lock_irqsave(&bitmap->lock, flags); | 654 | spin_lock_irqsave(&bitmap->lock, flags); |
@@ -663,17 +656,14 @@ static void bitmap_file_put(struct bitmap *bitmap) | |||
663 | bitmap->file = NULL; | 656 | bitmap->file = NULL; |
664 | spin_unlock_irqrestore(&bitmap->lock, flags); | 657 | spin_unlock_irqrestore(&bitmap->lock, flags); |
665 | 658 | ||
666 | bitmap_stop_daemon(bitmap); | 659 | if (file) |
667 | 660 | wait_event(bitmap->write_wait, | |
668 | drain_write_queues(bitmap); | 661 | atomic_read(&bitmap->pending_writes)==0); |
669 | |||
670 | bitmap_file_unmap(bitmap); | 662 | bitmap_file_unmap(bitmap); |
671 | 663 | ||
672 | if (file) { | 664 | if (file) { |
673 | inode = file->f_mapping->host; | 665 | struct inode *inode = file->f_dentry->d_inode; |
674 | spin_lock(&inode->i_lock); | 666 | invalidate_inode_pages(inode->i_mapping); |
675 | atomic_set(&inode->i_writecount, 1); /* allow writes again */ | ||
676 | spin_unlock(&inode->i_lock); | ||
677 | fput(file); | 667 | fput(file); |
678 | } | 668 | } |
679 | } | 669 | } |
@@ -708,26 +698,27 @@ static void bitmap_file_kick(struct bitmap *bitmap) | |||
708 | } | 698 | } |
709 | 699 | ||
710 | enum bitmap_page_attr { | 700 | enum bitmap_page_attr { |
711 | BITMAP_PAGE_DIRTY = 1, // there are set bits that need to be synced | 701 | BITMAP_PAGE_DIRTY = 0, // there are set bits that need to be synced |
712 | BITMAP_PAGE_CLEAN = 2, // there are bits that might need to be cleared | 702 | BITMAP_PAGE_CLEAN = 1, // there are bits that might need to be cleared |
713 | BITMAP_PAGE_NEEDWRITE=4, // there are cleared bits that need to be synced | 703 | BITMAP_PAGE_NEEDWRITE=2, // there are cleared bits that need to be synced |
714 | }; | 704 | }; |
715 | 705 | ||
716 | static inline void set_page_attr(struct bitmap *bitmap, struct page *page, | 706 | static inline void set_page_attr(struct bitmap *bitmap, struct page *page, |
717 | enum bitmap_page_attr attr) | 707 | enum bitmap_page_attr attr) |
718 | { | 708 | { |
719 | bitmap->filemap_attr[page->index] |= attr; | 709 | __set_bit((page->index<<2) + attr, bitmap->filemap_attr); |
720 | } | 710 | } |
721 | 711 | ||
722 | static inline void clear_page_attr(struct bitmap *bitmap, struct page *page, | 712 | static inline void clear_page_attr(struct bitmap *bitmap, struct page *page, |
723 | enum bitmap_page_attr attr) | 713 | enum bitmap_page_attr attr) |
724 | { | 714 | { |
725 | bitmap->filemap_attr[page->index] &= ~attr; | 715 | __clear_bit((page->index<<2) + attr, bitmap->filemap_attr); |
726 | } | 716 | } |
727 | 717 | ||
728 | static inline unsigned long get_page_attr(struct bitmap *bitmap, struct page *page) | 718 | static inline unsigned long test_page_attr(struct bitmap *bitmap, struct page *page, |
719 | enum bitmap_page_attr attr) | ||
729 | { | 720 | { |
730 | return bitmap->filemap_attr[page->index]; | 721 | return test_bit((page->index<<2) + attr, bitmap->filemap_attr); |
731 | } | 722 | } |
732 | 723 | ||
733 | /* | 724 | /* |
@@ -751,11 +742,6 @@ static void bitmap_file_set_bit(struct bitmap *bitmap, sector_t block) | |||
751 | page = filemap_get_page(bitmap, chunk); | 742 | page = filemap_get_page(bitmap, chunk); |
752 | bit = file_page_offset(chunk); | 743 | bit = file_page_offset(chunk); |
753 | 744 | ||
754 | |||
755 | /* make sure the page stays cached until it gets written out */ | ||
756 | if (! (get_page_attr(bitmap, page) & BITMAP_PAGE_DIRTY)) | ||
757 | get_page(page); | ||
758 | |||
759 | /* set the bit */ | 745 | /* set the bit */ |
760 | kaddr = kmap_atomic(page, KM_USER0); | 746 | kaddr = kmap_atomic(page, KM_USER0); |
761 | if (bitmap->flags & BITMAP_HOSTENDIAN) | 747 | if (bitmap->flags & BITMAP_HOSTENDIAN) |
@@ -775,7 +761,8 @@ static void bitmap_file_set_bit(struct bitmap *bitmap, sector_t block) | |||
775 | * sync the dirty pages of the bitmap file to disk */ | 761 | * sync the dirty pages of the bitmap file to disk */ |
776 | int bitmap_unplug(struct bitmap *bitmap) | 762 | int bitmap_unplug(struct bitmap *bitmap) |
777 | { | 763 | { |
778 | unsigned long i, attr, flags; | 764 | unsigned long i, flags; |
765 | int dirty, need_write; | ||
779 | struct page *page; | 766 | struct page *page; |
780 | int wait = 0; | 767 | int wait = 0; |
781 | int err; | 768 | int err; |
@@ -792,35 +779,26 @@ int bitmap_unplug(struct bitmap *bitmap) | |||
792 | return 0; | 779 | return 0; |
793 | } | 780 | } |
794 | page = bitmap->filemap[i]; | 781 | page = bitmap->filemap[i]; |
795 | attr = get_page_attr(bitmap, page); | 782 | dirty = test_page_attr(bitmap, page, BITMAP_PAGE_DIRTY); |
783 | need_write = test_page_attr(bitmap, page, BITMAP_PAGE_NEEDWRITE); | ||
796 | clear_page_attr(bitmap, page, BITMAP_PAGE_DIRTY); | 784 | clear_page_attr(bitmap, page, BITMAP_PAGE_DIRTY); |
797 | clear_page_attr(bitmap, page, BITMAP_PAGE_NEEDWRITE); | 785 | clear_page_attr(bitmap, page, BITMAP_PAGE_NEEDWRITE); |
798 | if ((attr & BITMAP_PAGE_DIRTY)) | 786 | if (dirty) |
799 | wait = 1; | 787 | wait = 1; |
800 | spin_unlock_irqrestore(&bitmap->lock, flags); | 788 | spin_unlock_irqrestore(&bitmap->lock, flags); |
801 | 789 | ||
802 | if (attr & (BITMAP_PAGE_DIRTY | BITMAP_PAGE_NEEDWRITE)) { | 790 | if (dirty | need_write) |
803 | err = write_page(bitmap, page, 0); | 791 | err = write_page(bitmap, page, 0); |
804 | if (err == -EAGAIN) { | ||
805 | if (attr & BITMAP_PAGE_DIRTY) | ||
806 | err = write_page(bitmap, page, 1); | ||
807 | else | ||
808 | err = 0; | ||
809 | } | ||
810 | if (err) | ||
811 | return 1; | ||
812 | } | ||
813 | } | 792 | } |
814 | if (wait) { /* if any writes were performed, we need to wait on them */ | 793 | if (wait) { /* if any writes were performed, we need to wait on them */ |
815 | if (bitmap->file) { | 794 | if (bitmap->file) |
816 | spin_lock_irq(&bitmap->write_lock); | 795 | wait_event(bitmap->write_wait, |
817 | wait_event_lock_irq(bitmap->write_wait, | 796 | atomic_read(&bitmap->pending_writes)==0); |
818 | list_empty(&bitmap->complete_pages), bitmap->write_lock, | 797 | else |
819 | wake_up_process(bitmap->writeback_daemon->tsk)); | ||
820 | spin_unlock_irq(&bitmap->write_lock); | ||
821 | } else | ||
822 | md_super_wait(bitmap->mddev); | 798 | md_super_wait(bitmap->mddev); |
823 | } | 799 | } |
800 | if (bitmap->flags & BITMAP_WRITE_ERROR) | ||
801 | bitmap_file_kick(bitmap); | ||
824 | return 0; | 802 | return 0; |
825 | } | 803 | } |
826 | 804 | ||
@@ -842,7 +820,7 @@ static int bitmap_init_from_disk(struct bitmap *bitmap, sector_t start) | |||
842 | struct page *page = NULL, *oldpage = NULL; | 820 | struct page *page = NULL, *oldpage = NULL; |
843 | unsigned long num_pages, bit_cnt = 0; | 821 | unsigned long num_pages, bit_cnt = 0; |
844 | struct file *file; | 822 | struct file *file; |
845 | unsigned long bytes, offset, dummy; | 823 | unsigned long bytes, offset; |
846 | int outofdate; | 824 | int outofdate; |
847 | int ret = -ENOSPC; | 825 | int ret = -ENOSPC; |
848 | void *paddr; | 826 | void *paddr; |
@@ -879,7 +857,12 @@ static int bitmap_init_from_disk(struct bitmap *bitmap, sector_t start) | |||
879 | if (!bitmap->filemap) | 857 | if (!bitmap->filemap) |
880 | goto out; | 858 | goto out; |
881 | 859 | ||
882 | bitmap->filemap_attr = kzalloc(sizeof(long) * num_pages, GFP_KERNEL); | 860 | /* We need 4 bits per page, rounded up to a multiple of sizeof(unsigned long) */ |
861 | bitmap->filemap_attr = kzalloc( | ||
862 | (((num_pages*4/8)+sizeof(unsigned long)-1) | ||
863 | /sizeof(unsigned long)) | ||
864 | *sizeof(unsigned long), | ||
865 | GFP_KERNEL); | ||
883 | if (!bitmap->filemap_attr) | 866 | if (!bitmap->filemap_attr) |
884 | goto out; | 867 | goto out; |
885 | 868 | ||
@@ -890,7 +873,12 @@ static int bitmap_init_from_disk(struct bitmap *bitmap, sector_t start) | |||
890 | index = file_page_index(i); | 873 | index = file_page_index(i); |
891 | bit = file_page_offset(i); | 874 | bit = file_page_offset(i); |
892 | if (index != oldindex) { /* this is a new page, read it in */ | 875 | if (index != oldindex) { /* this is a new page, read it in */ |
876 | int count; | ||
893 | /* unmap the old page, we're done with it */ | 877 | /* unmap the old page, we're done with it */ |
878 | if (index == num_pages-1) | ||
879 | count = bytes - index * PAGE_SIZE; | ||
880 | else | ||
881 | count = PAGE_SIZE; | ||
894 | if (index == 0) { | 882 | if (index == 0) { |
895 | /* | 883 | /* |
896 | * if we're here then the superblock page | 884 | * if we're here then the superblock page |
@@ -900,7 +888,7 @@ static int bitmap_init_from_disk(struct bitmap *bitmap, sector_t start) | |||
900 | page = bitmap->sb_page; | 888 | page = bitmap->sb_page; |
901 | offset = sizeof(bitmap_super_t); | 889 | offset = sizeof(bitmap_super_t); |
902 | } else if (file) { | 890 | } else if (file) { |
903 | page = read_page(file, index, &dummy); | 891 | page = read_page(file, index, bitmap, count); |
904 | offset = 0; | 892 | offset = 0; |
905 | } else { | 893 | } else { |
906 | page = read_sb_page(bitmap->mddev, bitmap->offset, index); | 894 | page = read_sb_page(bitmap->mddev, bitmap->offset, index); |
@@ -971,12 +959,11 @@ void bitmap_write_all(struct bitmap *bitmap) | |||
971 | /* We don't actually write all bitmap blocks here, | 959 | /* We don't actually write all bitmap blocks here, |
972 | * just flag them as needing to be written | 960 | * just flag them as needing to be written |
973 | */ | 961 | */ |
962 | int i; | ||
974 | 963 | ||
975 | unsigned long chunks = bitmap->chunks; | 964 | for (i=0; i < bitmap->file_pages; i++) |
976 | unsigned long bytes = (chunks+7)/8 + sizeof(bitmap_super_t); | 965 | set_page_attr(bitmap, bitmap->filemap[i], |
977 | unsigned long num_pages = (bytes + PAGE_SIZE-1) / PAGE_SIZE; | 966 | BITMAP_PAGE_NEEDWRITE); |
978 | while (num_pages--) | ||
979 | bitmap->filemap_attr[num_pages] |= BITMAP_PAGE_NEEDWRITE; | ||
980 | } | 967 | } |
981 | 968 | ||
982 | 969 | ||
@@ -1007,7 +994,6 @@ int bitmap_daemon_work(struct bitmap *bitmap) | |||
1007 | struct page *page = NULL, *lastpage = NULL; | 994 | struct page *page = NULL, *lastpage = NULL; |
1008 | int err = 0; | 995 | int err = 0; |
1009 | int blocks; | 996 | int blocks; |
1010 | int attr; | ||
1011 | void *paddr; | 997 | void *paddr; |
1012 | 998 | ||
1013 | if (bitmap == NULL) | 999 | if (bitmap == NULL) |
@@ -1029,43 +1015,34 @@ int bitmap_daemon_work(struct bitmap *bitmap) | |||
1029 | 1015 | ||
1030 | if (page != lastpage) { | 1016 | if (page != lastpage) { |
1031 | /* skip this page unless it's marked as needing cleaning */ | 1017 | /* skip this page unless it's marked as needing cleaning */ |
1032 | if (!((attr=get_page_attr(bitmap, page)) & BITMAP_PAGE_CLEAN)) { | 1018 | if (!test_page_attr(bitmap, page, BITMAP_PAGE_CLEAN)) { |
1033 | if (attr & BITMAP_PAGE_NEEDWRITE) { | 1019 | int need_write = test_page_attr(bitmap, page, |
1034 | get_page(page); | 1020 | BITMAP_PAGE_NEEDWRITE); |
1021 | if (need_write) | ||
1035 | clear_page_attr(bitmap, page, BITMAP_PAGE_NEEDWRITE); | 1022 | clear_page_attr(bitmap, page, BITMAP_PAGE_NEEDWRITE); |
1036 | } | 1023 | |
1037 | spin_unlock_irqrestore(&bitmap->lock, flags); | 1024 | spin_unlock_irqrestore(&bitmap->lock, flags); |
1038 | if (attr & BITMAP_PAGE_NEEDWRITE) { | 1025 | if (need_write) { |
1039 | switch (write_page(bitmap, page, 0)) { | 1026 | switch (write_page(bitmap, page, 0)) { |
1040 | case -EAGAIN: | ||
1041 | set_page_attr(bitmap, page, BITMAP_PAGE_NEEDWRITE); | ||
1042 | break; | ||
1043 | case 0: | 1027 | case 0: |
1044 | break; | 1028 | break; |
1045 | default: | 1029 | default: |
1046 | bitmap_file_kick(bitmap); | 1030 | bitmap_file_kick(bitmap); |
1047 | } | 1031 | } |
1048 | put_page(page); | ||
1049 | } | 1032 | } |
1050 | continue; | 1033 | continue; |
1051 | } | 1034 | } |
1052 | 1035 | ||
1053 | /* grab the new page, sync and release the old */ | 1036 | /* grab the new page, sync and release the old */ |
1054 | get_page(page); | ||
1055 | if (lastpage != NULL) { | 1037 | if (lastpage != NULL) { |
1056 | if (get_page_attr(bitmap, lastpage) & BITMAP_PAGE_NEEDWRITE) { | 1038 | if (test_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE)) { |
1057 | clear_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE); | 1039 | clear_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE); |
1058 | spin_unlock_irqrestore(&bitmap->lock, flags); | 1040 | spin_unlock_irqrestore(&bitmap->lock, flags); |
1059 | err = write_page(bitmap, lastpage, 0); | 1041 | err = write_page(bitmap, lastpage, 0); |
1060 | if (err == -EAGAIN) { | ||
1061 | err = 0; | ||
1062 | set_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE); | ||
1063 | } | ||
1064 | } else { | 1042 | } else { |
1065 | set_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE); | 1043 | set_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE); |
1066 | spin_unlock_irqrestore(&bitmap->lock, flags); | 1044 | spin_unlock_irqrestore(&bitmap->lock, flags); |
1067 | } | 1045 | } |
1068 | put_page(lastpage); | ||
1069 | if (err) | 1046 | if (err) |
1070 | bitmap_file_kick(bitmap); | 1047 | bitmap_file_kick(bitmap); |
1071 | } else | 1048 | } else |
@@ -1107,131 +1084,19 @@ int bitmap_daemon_work(struct bitmap *bitmap) | |||
1107 | /* now sync the final page */ | 1084 | /* now sync the final page */ |
1108 | if (lastpage != NULL) { | 1085 | if (lastpage != NULL) { |
1109 | spin_lock_irqsave(&bitmap->lock, flags); | 1086 | spin_lock_irqsave(&bitmap->lock, flags); |
1110 | if (get_page_attr(bitmap, lastpage) &BITMAP_PAGE_NEEDWRITE) { | 1087 | if (test_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE)) { |
1111 | clear_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE); | 1088 | clear_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE); |
1112 | spin_unlock_irqrestore(&bitmap->lock, flags); | 1089 | spin_unlock_irqrestore(&bitmap->lock, flags); |
1113 | err = write_page(bitmap, lastpage, 0); | 1090 | err = write_page(bitmap, lastpage, 0); |
1114 | if (err == -EAGAIN) { | ||
1115 | set_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE); | ||
1116 | err = 0; | ||
1117 | } | ||
1118 | } else { | 1091 | } else { |
1119 | set_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE); | 1092 | set_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE); |
1120 | spin_unlock_irqrestore(&bitmap->lock, flags); | 1093 | spin_unlock_irqrestore(&bitmap->lock, flags); |
1121 | } | 1094 | } |
1122 | |||
1123 | put_page(lastpage); | ||
1124 | } | 1095 | } |
1125 | 1096 | ||
1126 | return err; | 1097 | return err; |
1127 | } | 1098 | } |
1128 | 1099 | ||
1129 | static void daemon_exit(struct bitmap *bitmap, mdk_thread_t **daemon) | ||
1130 | { | ||
1131 | mdk_thread_t *dmn; | ||
1132 | unsigned long flags; | ||
1133 | |||
1134 | /* if no one is waiting on us, we'll free the md thread struct | ||
1135 | * and exit, otherwise we let the waiter clean things up */ | ||
1136 | spin_lock_irqsave(&bitmap->lock, flags); | ||
1137 | if ((dmn = *daemon)) { /* no one is waiting, cleanup and exit */ | ||
1138 | *daemon = NULL; | ||
1139 | spin_unlock_irqrestore(&bitmap->lock, flags); | ||
1140 | kfree(dmn); | ||
1141 | complete_and_exit(NULL, 0); /* do_exit not exported */ | ||
1142 | } | ||
1143 | spin_unlock_irqrestore(&bitmap->lock, flags); | ||
1144 | } | ||
1145 | |||
1146 | static void bitmap_writeback_daemon(mddev_t *mddev) | ||
1147 | { | ||
1148 | struct bitmap *bitmap = mddev->bitmap; | ||
1149 | struct page *page; | ||
1150 | struct page_list *item; | ||
1151 | int err = 0; | ||
1152 | |||
1153 | if (signal_pending(current)) { | ||
1154 | printk(KERN_INFO | ||
1155 | "%s: bitmap writeback daemon got signal, exiting...\n", | ||
1156 | bmname(bitmap)); | ||
1157 | err = -EINTR; | ||
1158 | goto out; | ||
1159 | } | ||
1160 | if (bitmap == NULL) | ||
1161 | /* about to be stopped. */ | ||
1162 | return; | ||
1163 | |||
1164 | PRINTK("%s: bitmap writeback daemon woke up...\n", bmname(bitmap)); | ||
1165 | /* wait on bitmap page writebacks */ | ||
1166 | while ((item = dequeue_page(bitmap))) { | ||
1167 | page = item->page; | ||
1168 | mempool_free(item, bitmap->write_pool); | ||
1169 | PRINTK("wait on page writeback: %p\n", page); | ||
1170 | wait_on_page_writeback(page); | ||
1171 | PRINTK("finished page writeback: %p\n", page); | ||
1172 | |||
1173 | err = PageError(page); | ||
1174 | put_page(page); | ||
1175 | if (err) { | ||
1176 | printk(KERN_WARNING "%s: bitmap file writeback " | ||
1177 | "failed (page %lu): %d\n", | ||
1178 | bmname(bitmap), page->index, err); | ||
1179 | bitmap_file_kick(bitmap); | ||
1180 | goto out; | ||
1181 | } | ||
1182 | } | ||
1183 | out: | ||
1184 | wake_up(&bitmap->write_wait); | ||
1185 | if (err) { | ||
1186 | printk(KERN_INFO "%s: bitmap writeback daemon exiting (%d)\n", | ||
1187 | bmname(bitmap), err); | ||
1188 | daemon_exit(bitmap, &bitmap->writeback_daemon); | ||
1189 | } | ||
1190 | } | ||
1191 | |||
1192 | static mdk_thread_t *bitmap_start_daemon(struct bitmap *bitmap, | ||
1193 | void (*func)(mddev_t *), char *name) | ||
1194 | { | ||
1195 | mdk_thread_t *daemon; | ||
1196 | char namebuf[32]; | ||
1197 | |||
1198 | #ifdef INJECT_FATAL_FAULT_2 | ||
1199 | daemon = NULL; | ||
1200 | #else | ||
1201 | sprintf(namebuf, "%%s_%s", name); | ||
1202 | daemon = md_register_thread(func, bitmap->mddev, namebuf); | ||
1203 | #endif | ||
1204 | if (!daemon) { | ||
1205 | printk(KERN_ERR "%s: failed to start bitmap daemon\n", | ||
1206 | bmname(bitmap)); | ||
1207 | return ERR_PTR(-ECHILD); | ||
1208 | } | ||
1209 | |||
1210 | md_wakeup_thread(daemon); /* start it running */ | ||
1211 | |||
1212 | PRINTK("%s: %s daemon (pid %d) started...\n", | ||
1213 | bmname(bitmap), name, daemon->tsk->pid); | ||
1214 | |||
1215 | return daemon; | ||
1216 | } | ||
1217 | |||
1218 | static void bitmap_stop_daemon(struct bitmap *bitmap) | ||
1219 | { | ||
1220 | /* the daemon can't stop itself... it'll just exit instead... */ | ||
1221 | if (bitmap->writeback_daemon && ! IS_ERR(bitmap->writeback_daemon) && | ||
1222 | current->pid != bitmap->writeback_daemon->tsk->pid) { | ||
1223 | mdk_thread_t *daemon; | ||
1224 | unsigned long flags; | ||
1225 | |||
1226 | spin_lock_irqsave(&bitmap->lock, flags); | ||
1227 | daemon = bitmap->writeback_daemon; | ||
1228 | bitmap->writeback_daemon = NULL; | ||
1229 | spin_unlock_irqrestore(&bitmap->lock, flags); | ||
1230 | if (daemon && ! IS_ERR(daemon)) | ||
1231 | md_unregister_thread(daemon); /* destroy the thread */ | ||
1232 | } | ||
1233 | } | ||
1234 | |||
1235 | static bitmap_counter_t *bitmap_get_counter(struct bitmap *bitmap, | 1100 | static bitmap_counter_t *bitmap_get_counter(struct bitmap *bitmap, |
1236 | sector_t offset, int *blocks, | 1101 | sector_t offset, int *blocks, |
1237 | int create) | 1102 | int create) |
@@ -1500,8 +1365,6 @@ static void bitmap_free(struct bitmap *bitmap) | |||
1500 | 1365 | ||
1501 | /* free all allocated memory */ | 1366 | /* free all allocated memory */ |
1502 | 1367 | ||
1503 | mempool_destroy(bitmap->write_pool); | ||
1504 | |||
1505 | if (bp) /* deallocate the page memory */ | 1368 | if (bp) /* deallocate the page memory */ |
1506 | for (k = 0; k < pages; k++) | 1369 | for (k = 0; k < pages; k++) |
1507 | if (bp[k].map && !bp[k].hijacked) | 1370 | if (bp[k].map && !bp[k].hijacked) |
@@ -1549,20 +1412,20 @@ int bitmap_create(mddev_t *mddev) | |||
1549 | return -ENOMEM; | 1412 | return -ENOMEM; |
1550 | 1413 | ||
1551 | spin_lock_init(&bitmap->lock); | 1414 | spin_lock_init(&bitmap->lock); |
1552 | bitmap->mddev = mddev; | 1415 | atomic_set(&bitmap->pending_writes, 0); |
1553 | |||
1554 | spin_lock_init(&bitmap->write_lock); | ||
1555 | INIT_LIST_HEAD(&bitmap->complete_pages); | ||
1556 | init_waitqueue_head(&bitmap->write_wait); | 1416 | init_waitqueue_head(&bitmap->write_wait); |
1557 | bitmap->write_pool = mempool_create_kmalloc_pool(WRITE_POOL_SIZE, | 1417 | |
1558 | sizeof(struct page_list)); | 1418 | bitmap->mddev = mddev; |
1559 | err = -ENOMEM; | ||
1560 | if (!bitmap->write_pool) | ||
1561 | goto error; | ||
1562 | 1419 | ||
1563 | bitmap->file = file; | 1420 | bitmap->file = file; |
1564 | bitmap->offset = mddev->bitmap_offset; | 1421 | bitmap->offset = mddev->bitmap_offset; |
1565 | if (file) get_file(file); | 1422 | if (file) { |
1423 | get_file(file); | ||
1424 | do_sync_file_range(file, 0, LLONG_MAX, | ||
1425 | SYNC_FILE_RANGE_WAIT_BEFORE | | ||
1426 | SYNC_FILE_RANGE_WRITE | | ||
1427 | SYNC_FILE_RANGE_WAIT_AFTER); | ||
1428 | } | ||
1566 | /* read superblock from bitmap file (this sets bitmap->chunksize) */ | 1429 | /* read superblock from bitmap file (this sets bitmap->chunksize) */ |
1567 | err = bitmap_read_sb(bitmap); | 1430 | err = bitmap_read_sb(bitmap); |
1568 | if (err) | 1431 | if (err) |
@@ -1594,8 +1457,6 @@ int bitmap_create(mddev_t *mddev) | |||
1594 | if (!bitmap->bp) | 1457 | if (!bitmap->bp) |
1595 | goto error; | 1458 | goto error; |
1596 | 1459 | ||
1597 | bitmap->flags |= BITMAP_ACTIVE; | ||
1598 | |||
1599 | /* now that we have some pages available, initialize the in-memory | 1460 | /* now that we have some pages available, initialize the in-memory |
1600 | * bitmap from the on-disk bitmap */ | 1461 | * bitmap from the on-disk bitmap */ |
1601 | start = 0; | 1462 | start = 0; |
@@ -1613,15 +1474,6 @@ int bitmap_create(mddev_t *mddev) | |||
1613 | 1474 | ||
1614 | mddev->bitmap = bitmap; | 1475 | mddev->bitmap = bitmap; |
1615 | 1476 | ||
1616 | if (file) | ||
1617 | /* kick off the bitmap writeback daemon */ | ||
1618 | bitmap->writeback_daemon = | ||
1619 | bitmap_start_daemon(bitmap, | ||
1620 | bitmap_writeback_daemon, | ||
1621 | "bitmap_wb"); | ||
1622 | |||
1623 | if (IS_ERR(bitmap->writeback_daemon)) | ||
1624 | return PTR_ERR(bitmap->writeback_daemon); | ||
1625 | mddev->thread->timeout = bitmap->daemon_sleep * HZ; | 1477 | mddev->thread->timeout = bitmap->daemon_sleep * HZ; |
1626 | 1478 | ||
1627 | return bitmap_update_sb(bitmap); | 1479 | return bitmap_update_sb(bitmap); |
@@ -1638,4 +1490,3 @@ EXPORT_SYMBOL(bitmap_start_sync); | |||
1638 | EXPORT_SYMBOL(bitmap_end_sync); | 1490 | EXPORT_SYMBOL(bitmap_end_sync); |
1639 | EXPORT_SYMBOL(bitmap_unplug); | 1491 | EXPORT_SYMBOL(bitmap_unplug); |
1640 | EXPORT_SYMBOL(bitmap_close_sync); | 1492 | EXPORT_SYMBOL(bitmap_close_sync); |
1641 | EXPORT_SYMBOL(bitmap_daemon_work); | ||
diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index 61a590bb6241..6022ed12a795 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c | |||
@@ -20,7 +20,7 @@ | |||
20 | 20 | ||
21 | #include "dm.h" | 21 | #include "dm.h" |
22 | 22 | ||
23 | #define PFX "crypt: " | 23 | #define DM_MSG_PREFIX "crypt" |
24 | 24 | ||
25 | /* | 25 | /* |
26 | * per bio private data | 26 | * per bio private data |
@@ -125,19 +125,19 @@ static int crypt_iv_essiv_ctr(struct crypt_config *cc, struct dm_target *ti, | |||
125 | u8 *salt; | 125 | u8 *salt; |
126 | 126 | ||
127 | if (opts == NULL) { | 127 | if (opts == NULL) { |
128 | ti->error = PFX "Digest algorithm missing for ESSIV mode"; | 128 | ti->error = "Digest algorithm missing for ESSIV mode"; |
129 | return -EINVAL; | 129 | return -EINVAL; |
130 | } | 130 | } |
131 | 131 | ||
132 | /* Hash the cipher key with the given hash algorithm */ | 132 | /* Hash the cipher key with the given hash algorithm */ |
133 | hash_tfm = crypto_alloc_tfm(opts, CRYPTO_TFM_REQ_MAY_SLEEP); | 133 | hash_tfm = crypto_alloc_tfm(opts, CRYPTO_TFM_REQ_MAY_SLEEP); |
134 | if (hash_tfm == NULL) { | 134 | if (hash_tfm == NULL) { |
135 | ti->error = PFX "Error initializing ESSIV hash"; | 135 | ti->error = "Error initializing ESSIV hash"; |
136 | return -EINVAL; | 136 | return -EINVAL; |
137 | } | 137 | } |
138 | 138 | ||
139 | if (crypto_tfm_alg_type(hash_tfm) != CRYPTO_ALG_TYPE_DIGEST) { | 139 | if (crypto_tfm_alg_type(hash_tfm) != CRYPTO_ALG_TYPE_DIGEST) { |
140 | ti->error = PFX "Expected digest algorithm for ESSIV hash"; | 140 | ti->error = "Expected digest algorithm for ESSIV hash"; |
141 | crypto_free_tfm(hash_tfm); | 141 | crypto_free_tfm(hash_tfm); |
142 | return -EINVAL; | 142 | return -EINVAL; |
143 | } | 143 | } |
@@ -145,7 +145,7 @@ static int crypt_iv_essiv_ctr(struct crypt_config *cc, struct dm_target *ti, | |||
145 | saltsize = crypto_tfm_alg_digestsize(hash_tfm); | 145 | saltsize = crypto_tfm_alg_digestsize(hash_tfm); |
146 | salt = kmalloc(saltsize, GFP_KERNEL); | 146 | salt = kmalloc(saltsize, GFP_KERNEL); |
147 | if (salt == NULL) { | 147 | if (salt == NULL) { |
148 | ti->error = PFX "Error kmallocing salt storage in ESSIV"; | 148 | ti->error = "Error kmallocing salt storage in ESSIV"; |
149 | crypto_free_tfm(hash_tfm); | 149 | crypto_free_tfm(hash_tfm); |
150 | return -ENOMEM; | 150 | return -ENOMEM; |
151 | } | 151 | } |
@@ -159,20 +159,20 @@ static int crypt_iv_essiv_ctr(struct crypt_config *cc, struct dm_target *ti, | |||
159 | CRYPTO_TFM_MODE_ECB | | 159 | CRYPTO_TFM_MODE_ECB | |
160 | CRYPTO_TFM_REQ_MAY_SLEEP); | 160 | CRYPTO_TFM_REQ_MAY_SLEEP); |
161 | if (essiv_tfm == NULL) { | 161 | if (essiv_tfm == NULL) { |
162 | ti->error = PFX "Error allocating crypto tfm for ESSIV"; | 162 | ti->error = "Error allocating crypto tfm for ESSIV"; |
163 | kfree(salt); | 163 | kfree(salt); |
164 | return -EINVAL; | 164 | return -EINVAL; |
165 | } | 165 | } |
166 | if (crypto_tfm_alg_blocksize(essiv_tfm) | 166 | if (crypto_tfm_alg_blocksize(essiv_tfm) |
167 | != crypto_tfm_alg_ivsize(cc->tfm)) { | 167 | != crypto_tfm_alg_ivsize(cc->tfm)) { |
168 | ti->error = PFX "Block size of ESSIV cipher does " | 168 | ti->error = "Block size of ESSIV cipher does " |
169 | "not match IV size of block cipher"; | 169 | "not match IV size of block cipher"; |
170 | crypto_free_tfm(essiv_tfm); | 170 | crypto_free_tfm(essiv_tfm); |
171 | kfree(salt); | 171 | kfree(salt); |
172 | return -EINVAL; | 172 | return -EINVAL; |
173 | } | 173 | } |
174 | if (crypto_cipher_setkey(essiv_tfm, salt, saltsize) < 0) { | 174 | if (crypto_cipher_setkey(essiv_tfm, salt, saltsize) < 0) { |
175 | ti->error = PFX "Failed to set key for ESSIV cipher"; | 175 | ti->error = "Failed to set key for ESSIV cipher"; |
176 | crypto_free_tfm(essiv_tfm); | 176 | crypto_free_tfm(essiv_tfm); |
177 | kfree(salt); | 177 | kfree(salt); |
178 | return -EINVAL; | 178 | return -EINVAL; |
@@ -521,7 +521,7 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
521 | unsigned long long tmpll; | 521 | unsigned long long tmpll; |
522 | 522 | ||
523 | if (argc != 5) { | 523 | if (argc != 5) { |
524 | ti->error = PFX "Not enough arguments"; | 524 | ti->error = "Not enough arguments"; |
525 | return -EINVAL; | 525 | return -EINVAL; |
526 | } | 526 | } |
527 | 527 | ||
@@ -532,21 +532,21 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
532 | ivmode = strsep(&ivopts, ":"); | 532 | ivmode = strsep(&ivopts, ":"); |
533 | 533 | ||
534 | if (tmp) | 534 | if (tmp) |
535 | DMWARN(PFX "Unexpected additional cipher options"); | 535 | DMWARN("Unexpected additional cipher options"); |
536 | 536 | ||
537 | key_size = strlen(argv[1]) >> 1; | 537 | key_size = strlen(argv[1]) >> 1; |
538 | 538 | ||
539 | cc = kmalloc(sizeof(*cc) + key_size * sizeof(u8), GFP_KERNEL); | 539 | cc = kmalloc(sizeof(*cc) + key_size * sizeof(u8), GFP_KERNEL); |
540 | if (cc == NULL) { | 540 | if (cc == NULL) { |
541 | ti->error = | 541 | ti->error = |
542 | PFX "Cannot allocate transparent encryption context"; | 542 | "Cannot allocate transparent encryption context"; |
543 | return -ENOMEM; | 543 | return -ENOMEM; |
544 | } | 544 | } |
545 | 545 | ||
546 | cc->key_size = key_size; | 546 | cc->key_size = key_size; |
547 | if ((!key_size && strcmp(argv[1], "-") != 0) || | 547 | if ((!key_size && strcmp(argv[1], "-") != 0) || |
548 | (key_size && crypt_decode_key(cc->key, argv[1], key_size) < 0)) { | 548 | (key_size && crypt_decode_key(cc->key, argv[1], key_size) < 0)) { |
549 | ti->error = PFX "Error decoding key"; | 549 | ti->error = "Error decoding key"; |
550 | goto bad1; | 550 | goto bad1; |
551 | } | 551 | } |
552 | 552 | ||
@@ -562,22 +562,22 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
562 | else if (strcmp(chainmode, "ecb") == 0) | 562 | else if (strcmp(chainmode, "ecb") == 0) |
563 | crypto_flags = CRYPTO_TFM_MODE_ECB; | 563 | crypto_flags = CRYPTO_TFM_MODE_ECB; |
564 | else { | 564 | else { |
565 | ti->error = PFX "Unknown chaining mode"; | 565 | ti->error = "Unknown chaining mode"; |
566 | goto bad1; | 566 | goto bad1; |
567 | } | 567 | } |
568 | 568 | ||
569 | if (crypto_flags != CRYPTO_TFM_MODE_ECB && !ivmode) { | 569 | if (crypto_flags != CRYPTO_TFM_MODE_ECB && !ivmode) { |
570 | ti->error = PFX "This chaining mode requires an IV mechanism"; | 570 | ti->error = "This chaining mode requires an IV mechanism"; |
571 | goto bad1; | 571 | goto bad1; |
572 | } | 572 | } |
573 | 573 | ||
574 | tfm = crypto_alloc_tfm(cipher, crypto_flags | CRYPTO_TFM_REQ_MAY_SLEEP); | 574 | tfm = crypto_alloc_tfm(cipher, crypto_flags | CRYPTO_TFM_REQ_MAY_SLEEP); |
575 | if (!tfm) { | 575 | if (!tfm) { |
576 | ti->error = PFX "Error allocating crypto tfm"; | 576 | ti->error = "Error allocating crypto tfm"; |
577 | goto bad1; | 577 | goto bad1; |
578 | } | 578 | } |
579 | if (crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER) { | 579 | if (crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER) { |
580 | ti->error = PFX "Expected cipher algorithm"; | 580 | ti->error = "Expected cipher algorithm"; |
581 | goto bad2; | 581 | goto bad2; |
582 | } | 582 | } |
583 | 583 | ||
@@ -595,7 +595,7 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
595 | else if (strcmp(ivmode, "essiv") == 0) | 595 | else if (strcmp(ivmode, "essiv") == 0) |
596 | cc->iv_gen_ops = &crypt_iv_essiv_ops; | 596 | cc->iv_gen_ops = &crypt_iv_essiv_ops; |
597 | else { | 597 | else { |
598 | ti->error = PFX "Invalid IV mode"; | 598 | ti->error = "Invalid IV mode"; |
599 | goto bad2; | 599 | goto bad2; |
600 | } | 600 | } |
601 | 601 | ||
@@ -610,7 +610,7 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
610 | else { | 610 | else { |
611 | cc->iv_size = 0; | 611 | cc->iv_size = 0; |
612 | if (cc->iv_gen_ops) { | 612 | if (cc->iv_gen_ops) { |
613 | DMWARN(PFX "Selected cipher does not support IVs"); | 613 | DMWARN("Selected cipher does not support IVs"); |
614 | if (cc->iv_gen_ops->dtr) | 614 | if (cc->iv_gen_ops->dtr) |
615 | cc->iv_gen_ops->dtr(cc); | 615 | cc->iv_gen_ops->dtr(cc); |
616 | cc->iv_gen_ops = NULL; | 616 | cc->iv_gen_ops = NULL; |
@@ -619,36 +619,36 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
619 | 619 | ||
620 | cc->io_pool = mempool_create_slab_pool(MIN_IOS, _crypt_io_pool); | 620 | cc->io_pool = mempool_create_slab_pool(MIN_IOS, _crypt_io_pool); |
621 | if (!cc->io_pool) { | 621 | if (!cc->io_pool) { |
622 | ti->error = PFX "Cannot allocate crypt io mempool"; | 622 | ti->error = "Cannot allocate crypt io mempool"; |
623 | goto bad3; | 623 | goto bad3; |
624 | } | 624 | } |
625 | 625 | ||
626 | cc->page_pool = mempool_create_page_pool(MIN_POOL_PAGES, 0); | 626 | cc->page_pool = mempool_create_page_pool(MIN_POOL_PAGES, 0); |
627 | if (!cc->page_pool) { | 627 | if (!cc->page_pool) { |
628 | ti->error = PFX "Cannot allocate page mempool"; | 628 | ti->error = "Cannot allocate page mempool"; |
629 | goto bad4; | 629 | goto bad4; |
630 | } | 630 | } |
631 | 631 | ||
632 | if (tfm->crt_cipher.cit_setkey(tfm, cc->key, key_size) < 0) { | 632 | if (tfm->crt_cipher.cit_setkey(tfm, cc->key, key_size) < 0) { |
633 | ti->error = PFX "Error setting key"; | 633 | ti->error = "Error setting key"; |
634 | goto bad5; | 634 | goto bad5; |
635 | } | 635 | } |
636 | 636 | ||
637 | if (sscanf(argv[2], "%llu", &tmpll) != 1) { | 637 | if (sscanf(argv[2], "%llu", &tmpll) != 1) { |
638 | ti->error = PFX "Invalid iv_offset sector"; | 638 | ti->error = "Invalid iv_offset sector"; |
639 | goto bad5; | 639 | goto bad5; |
640 | } | 640 | } |
641 | cc->iv_offset = tmpll; | 641 | cc->iv_offset = tmpll; |
642 | 642 | ||
643 | if (sscanf(argv[4], "%llu", &tmpll) != 1) { | 643 | if (sscanf(argv[4], "%llu", &tmpll) != 1) { |
644 | ti->error = PFX "Invalid device sector"; | 644 | ti->error = "Invalid device sector"; |
645 | goto bad5; | 645 | goto bad5; |
646 | } | 646 | } |
647 | cc->start = tmpll; | 647 | cc->start = tmpll; |
648 | 648 | ||
649 | if (dm_get_device(ti, argv[3], cc->start, ti->len, | 649 | if (dm_get_device(ti, argv[3], cc->start, ti->len, |
650 | dm_table_get_mode(ti->table), &cc->dev)) { | 650 | dm_table_get_mode(ti->table), &cc->dev)) { |
651 | ti->error = PFX "Device lookup failed"; | 651 | ti->error = "Device lookup failed"; |
652 | goto bad5; | 652 | goto bad5; |
653 | } | 653 | } |
654 | 654 | ||
@@ -657,7 +657,7 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
657 | *(ivopts - 1) = ':'; | 657 | *(ivopts - 1) = ':'; |
658 | cc->iv_mode = kmalloc(strlen(ivmode) + 1, GFP_KERNEL); | 658 | cc->iv_mode = kmalloc(strlen(ivmode) + 1, GFP_KERNEL); |
659 | if (!cc->iv_mode) { | 659 | if (!cc->iv_mode) { |
660 | ti->error = PFX "Error kmallocing iv_mode string"; | 660 | ti->error = "Error kmallocing iv_mode string"; |
661 | goto bad5; | 661 | goto bad5; |
662 | } | 662 | } |
663 | strcpy(cc->iv_mode, ivmode); | 663 | strcpy(cc->iv_mode, ivmode); |
@@ -918,13 +918,13 @@ static int __init dm_crypt_init(void) | |||
918 | _kcryptd_workqueue = create_workqueue("kcryptd"); | 918 | _kcryptd_workqueue = create_workqueue("kcryptd"); |
919 | if (!_kcryptd_workqueue) { | 919 | if (!_kcryptd_workqueue) { |
920 | r = -ENOMEM; | 920 | r = -ENOMEM; |
921 | DMERR(PFX "couldn't create kcryptd"); | 921 | DMERR("couldn't create kcryptd"); |
922 | goto bad1; | 922 | goto bad1; |
923 | } | 923 | } |
924 | 924 | ||
925 | r = dm_register_target(&crypt_target); | 925 | r = dm_register_target(&crypt_target); |
926 | if (r < 0) { | 926 | if (r < 0) { |
927 | DMERR(PFX "register failed %d", r); | 927 | DMERR("register failed %d", r); |
928 | goto bad2; | 928 | goto bad2; |
929 | } | 929 | } |
930 | 930 | ||
@@ -942,7 +942,7 @@ static void __exit dm_crypt_exit(void) | |||
942 | int r = dm_unregister_target(&crypt_target); | 942 | int r = dm_unregister_target(&crypt_target); |
943 | 943 | ||
944 | if (r < 0) | 944 | if (r < 0) |
945 | DMERR(PFX "unregister failed %d", r); | 945 | DMERR("unregister failed %d", r); |
946 | 946 | ||
947 | destroy_workqueue(_kcryptd_workqueue); | 947 | destroy_workqueue(_kcryptd_workqueue); |
948 | kmem_cache_destroy(_crypt_io_pool); | 948 | kmem_cache_destroy(_crypt_io_pool); |
diff --git a/drivers/md/dm-emc.c b/drivers/md/dm-emc.c index c7067674dcb7..2a374ccb30dd 100644 --- a/drivers/md/dm-emc.c +++ b/drivers/md/dm-emc.c | |||
@@ -12,6 +12,8 @@ | |||
12 | #include <scsi/scsi.h> | 12 | #include <scsi/scsi.h> |
13 | #include <scsi/scsi_cmnd.h> | 13 | #include <scsi/scsi_cmnd.h> |
14 | 14 | ||
15 | #define DM_MSG_PREFIX "multipath emc" | ||
16 | |||
15 | struct emc_handler { | 17 | struct emc_handler { |
16 | spinlock_t lock; | 18 | spinlock_t lock; |
17 | 19 | ||
@@ -66,7 +68,7 @@ static struct bio *get_failover_bio(struct path *path, unsigned data_size) | |||
66 | 68 | ||
67 | bio = bio_alloc(GFP_ATOMIC, 1); | 69 | bio = bio_alloc(GFP_ATOMIC, 1); |
68 | if (!bio) { | 70 | if (!bio) { |
69 | DMERR("dm-emc: get_failover_bio: bio_alloc() failed."); | 71 | DMERR("get_failover_bio: bio_alloc() failed."); |
70 | return NULL; | 72 | return NULL; |
71 | } | 73 | } |
72 | 74 | ||
@@ -78,13 +80,13 @@ static struct bio *get_failover_bio(struct path *path, unsigned data_size) | |||
78 | 80 | ||
79 | page = alloc_page(GFP_ATOMIC); | 81 | page = alloc_page(GFP_ATOMIC); |
80 | if (!page) { | 82 | if (!page) { |
81 | DMERR("dm-emc: get_failover_bio: alloc_page() failed."); | 83 | DMERR("get_failover_bio: alloc_page() failed."); |
82 | bio_put(bio); | 84 | bio_put(bio); |
83 | return NULL; | 85 | return NULL; |
84 | } | 86 | } |
85 | 87 | ||
86 | if (bio_add_page(bio, page, data_size, 0) != data_size) { | 88 | if (bio_add_page(bio, page, data_size, 0) != data_size) { |
87 | DMERR("dm-emc: get_failover_bio: alloc_page() failed."); | 89 | DMERR("get_failover_bio: alloc_page() failed."); |
88 | __free_page(page); | 90 | __free_page(page); |
89 | bio_put(bio); | 91 | bio_put(bio); |
90 | return NULL; | 92 | return NULL; |
@@ -103,7 +105,7 @@ static struct request *get_failover_req(struct emc_handler *h, | |||
103 | /* FIXME: Figure out why it fails with GFP_ATOMIC. */ | 105 | /* FIXME: Figure out why it fails with GFP_ATOMIC. */ |
104 | rq = blk_get_request(q, WRITE, __GFP_WAIT); | 106 | rq = blk_get_request(q, WRITE, __GFP_WAIT); |
105 | if (!rq) { | 107 | if (!rq) { |
106 | DMERR("dm-emc: get_failover_req: blk_get_request failed"); | 108 | DMERR("get_failover_req: blk_get_request failed"); |
107 | return NULL; | 109 | return NULL; |
108 | } | 110 | } |
109 | 111 | ||
@@ -160,7 +162,7 @@ static struct request *emc_trespass_get(struct emc_handler *h, | |||
160 | 162 | ||
161 | bio = get_failover_bio(path, data_size); | 163 | bio = get_failover_bio(path, data_size); |
162 | if (!bio) { | 164 | if (!bio) { |
163 | DMERR("dm-emc: emc_trespass_get: no bio"); | 165 | DMERR("emc_trespass_get: no bio"); |
164 | return NULL; | 166 | return NULL; |
165 | } | 167 | } |
166 | 168 | ||
@@ -173,7 +175,7 @@ static struct request *emc_trespass_get(struct emc_handler *h, | |||
173 | /* get request for block layer packet command */ | 175 | /* get request for block layer packet command */ |
174 | rq = get_failover_req(h, bio, path); | 176 | rq = get_failover_req(h, bio, path); |
175 | if (!rq) { | 177 | if (!rq) { |
176 | DMERR("dm-emc: emc_trespass_get: no rq"); | 178 | DMERR("emc_trespass_get: no rq"); |
177 | free_bio(bio); | 179 | free_bio(bio); |
178 | return NULL; | 180 | return NULL; |
179 | } | 181 | } |
@@ -200,18 +202,18 @@ static void emc_pg_init(struct hw_handler *hwh, unsigned bypassed, | |||
200 | * initial state passed into us and then get an update here. | 202 | * initial state passed into us and then get an update here. |
201 | */ | 203 | */ |
202 | if (!q) { | 204 | if (!q) { |
203 | DMINFO("dm-emc: emc_pg_init: no queue"); | 205 | DMINFO("emc_pg_init: no queue"); |
204 | goto fail_path; | 206 | goto fail_path; |
205 | } | 207 | } |
206 | 208 | ||
207 | /* FIXME: The request should be pre-allocated. */ | 209 | /* FIXME: The request should be pre-allocated. */ |
208 | rq = emc_trespass_get(hwh->context, path); | 210 | rq = emc_trespass_get(hwh->context, path); |
209 | if (!rq) { | 211 | if (!rq) { |
210 | DMERR("dm-emc: emc_pg_init: no rq"); | 212 | DMERR("emc_pg_init: no rq"); |
211 | goto fail_path; | 213 | goto fail_path; |
212 | } | 214 | } |
213 | 215 | ||
214 | DMINFO("dm-emc: emc_pg_init: sending switch-over command"); | 216 | DMINFO("emc_pg_init: sending switch-over command"); |
215 | elv_add_request(q, rq, ELEVATOR_INSERT_FRONT, 1); | 217 | elv_add_request(q, rq, ELEVATOR_INSERT_FRONT, 1); |
216 | return; | 218 | return; |
217 | 219 | ||
@@ -241,18 +243,18 @@ static int emc_create(struct hw_handler *hwh, unsigned argc, char **argv) | |||
241 | hr = 0; | 243 | hr = 0; |
242 | short_trespass = 0; | 244 | short_trespass = 0; |
243 | } else if (argc != 2) { | 245 | } else if (argc != 2) { |
244 | DMWARN("dm-emc hwhandler: incorrect number of arguments"); | 246 | DMWARN("incorrect number of arguments"); |
245 | return -EINVAL; | 247 | return -EINVAL; |
246 | } else { | 248 | } else { |
247 | if ((sscanf(argv[0], "%u", &short_trespass) != 1) | 249 | if ((sscanf(argv[0], "%u", &short_trespass) != 1) |
248 | || (short_trespass > 1)) { | 250 | || (short_trespass > 1)) { |
249 | DMWARN("dm-emc: invalid trespass mode selected"); | 251 | DMWARN("invalid trespass mode selected"); |
250 | return -EINVAL; | 252 | return -EINVAL; |
251 | } | 253 | } |
252 | 254 | ||
253 | if ((sscanf(argv[1], "%u", &hr) != 1) | 255 | if ((sscanf(argv[1], "%u", &hr) != 1) |
254 | || (hr > 1)) { | 256 | || (hr > 1)) { |
255 | DMWARN("dm-emc: invalid honor reservation flag selected"); | 257 | DMWARN("invalid honor reservation flag selected"); |
256 | return -EINVAL; | 258 | return -EINVAL; |
257 | } | 259 | } |
258 | } | 260 | } |
@@ -264,14 +266,14 @@ static int emc_create(struct hw_handler *hwh, unsigned argc, char **argv) | |||
264 | hwh->context = h; | 266 | hwh->context = h; |
265 | 267 | ||
266 | if ((h->short_trespass = short_trespass)) | 268 | if ((h->short_trespass = short_trespass)) |
267 | DMWARN("dm-emc: short trespass command will be send"); | 269 | DMWARN("short trespass command will be send"); |
268 | else | 270 | else |
269 | DMWARN("dm-emc: long trespass command will be send"); | 271 | DMWARN("long trespass command will be send"); |
270 | 272 | ||
271 | if ((h->hr = hr)) | 273 | if ((h->hr = hr)) |
272 | DMWARN("dm-emc: honor reservation bit will be set"); | 274 | DMWARN("honor reservation bit will be set"); |
273 | else | 275 | else |
274 | DMWARN("dm-emc: honor reservation bit will not be set (default)"); | 276 | DMWARN("honor reservation bit will not be set (default)"); |
275 | 277 | ||
276 | return 0; | 278 | return 0; |
277 | } | 279 | } |
@@ -336,9 +338,9 @@ static int __init dm_emc_init(void) | |||
336 | int r = dm_register_hw_handler(&emc_hwh); | 338 | int r = dm_register_hw_handler(&emc_hwh); |
337 | 339 | ||
338 | if (r < 0) | 340 | if (r < 0) |
339 | DMERR("emc: register failed %d", r); | 341 | DMERR("register failed %d", r); |
340 | 342 | ||
341 | DMINFO("dm-emc version 0.0.3 loaded"); | 343 | DMINFO("version 0.0.3 loaded"); |
342 | 344 | ||
343 | return r; | 345 | return r; |
344 | } | 346 | } |
@@ -348,7 +350,7 @@ static void __exit dm_emc_exit(void) | |||
348 | int r = dm_unregister_hw_handler(&emc_hwh); | 350 | int r = dm_unregister_hw_handler(&emc_hwh); |
349 | 351 | ||
350 | if (r < 0) | 352 | if (r < 0) |
351 | DMERR("emc: unregister failed %d", r); | 353 | DMERR("unregister failed %d", r); |
352 | } | 354 | } |
353 | 355 | ||
354 | module_init(dm_emc_init); | 356 | module_init(dm_emc_init); |
diff --git a/drivers/md/dm-exception-store.c b/drivers/md/dm-exception-store.c index cc07bbebbb16..d12379b5cdb5 100644 --- a/drivers/md/dm-exception-store.c +++ b/drivers/md/dm-exception-store.c | |||
@@ -16,6 +16,8 @@ | |||
16 | #include <linux/vmalloc.h> | 16 | #include <linux/vmalloc.h> |
17 | #include <linux/slab.h> | 17 | #include <linux/slab.h> |
18 | 18 | ||
19 | #define DM_MSG_PREFIX "snapshots" | ||
20 | |||
19 | /*----------------------------------------------------------------- | 21 | /*----------------------------------------------------------------- |
20 | * Persistent snapshots, by persistent we mean that the snapshot | 22 | * Persistent snapshots, by persistent we mean that the snapshot |
21 | * will survive a reboot. | 23 | * will survive a reboot. |
@@ -91,7 +93,6 @@ struct pstore { | |||
91 | struct dm_snapshot *snap; /* up pointer to my snapshot */ | 93 | struct dm_snapshot *snap; /* up pointer to my snapshot */ |
92 | int version; | 94 | int version; |
93 | int valid; | 95 | int valid; |
94 | uint32_t chunk_size; | ||
95 | uint32_t exceptions_per_area; | 96 | uint32_t exceptions_per_area; |
96 | 97 | ||
97 | /* | 98 | /* |
@@ -133,7 +134,7 @@ static int alloc_area(struct pstore *ps) | |||
133 | int r = -ENOMEM; | 134 | int r = -ENOMEM; |
134 | size_t len; | 135 | size_t len; |
135 | 136 | ||
136 | len = ps->chunk_size << SECTOR_SHIFT; | 137 | len = ps->snap->chunk_size << SECTOR_SHIFT; |
137 | 138 | ||
138 | /* | 139 | /* |
139 | * Allocate the chunk_size block of memory that will hold | 140 | * Allocate the chunk_size block of memory that will hold |
@@ -160,8 +161,8 @@ static int chunk_io(struct pstore *ps, uint32_t chunk, int rw) | |||
160 | unsigned long bits; | 161 | unsigned long bits; |
161 | 162 | ||
162 | where.bdev = ps->snap->cow->bdev; | 163 | where.bdev = ps->snap->cow->bdev; |
163 | where.sector = ps->chunk_size * chunk; | 164 | where.sector = ps->snap->chunk_size * chunk; |
164 | where.count = ps->chunk_size; | 165 | where.count = ps->snap->chunk_size; |
165 | 166 | ||
166 | return dm_io_sync_vm(1, &where, rw, ps->area, &bits); | 167 | return dm_io_sync_vm(1, &where, rw, ps->area, &bits); |
167 | } | 168 | } |
@@ -188,7 +189,7 @@ static int area_io(struct pstore *ps, uint32_t area, int rw) | |||
188 | 189 | ||
189 | static int zero_area(struct pstore *ps, uint32_t area) | 190 | static int zero_area(struct pstore *ps, uint32_t area) |
190 | { | 191 | { |
191 | memset(ps->area, 0, ps->chunk_size << SECTOR_SHIFT); | 192 | memset(ps->area, 0, ps->snap->chunk_size << SECTOR_SHIFT); |
192 | return area_io(ps, area, WRITE); | 193 | return area_io(ps, area, WRITE); |
193 | } | 194 | } |
194 | 195 | ||
@@ -196,6 +197,7 @@ static int read_header(struct pstore *ps, int *new_snapshot) | |||
196 | { | 197 | { |
197 | int r; | 198 | int r; |
198 | struct disk_header *dh; | 199 | struct disk_header *dh; |
200 | chunk_t chunk_size; | ||
199 | 201 | ||
200 | r = chunk_io(ps, 0, READ); | 202 | r = chunk_io(ps, 0, READ); |
201 | if (r) | 203 | if (r) |
@@ -210,8 +212,29 @@ static int read_header(struct pstore *ps, int *new_snapshot) | |||
210 | *new_snapshot = 0; | 212 | *new_snapshot = 0; |
211 | ps->valid = le32_to_cpu(dh->valid); | 213 | ps->valid = le32_to_cpu(dh->valid); |
212 | ps->version = le32_to_cpu(dh->version); | 214 | ps->version = le32_to_cpu(dh->version); |
213 | ps->chunk_size = le32_to_cpu(dh->chunk_size); | 215 | chunk_size = le32_to_cpu(dh->chunk_size); |
214 | 216 | if (ps->snap->chunk_size != chunk_size) { | |
217 | DMWARN("chunk size %llu in device metadata overrides " | ||
218 | "table chunk size of %llu.", | ||
219 | (unsigned long long)chunk_size, | ||
220 | (unsigned long long)ps->snap->chunk_size); | ||
221 | |||
222 | /* We had a bogus chunk_size. Fix stuff up. */ | ||
223 | dm_io_put(sectors_to_pages(ps->snap->chunk_size)); | ||
224 | free_area(ps); | ||
225 | |||
226 | ps->snap->chunk_size = chunk_size; | ||
227 | ps->snap->chunk_mask = chunk_size - 1; | ||
228 | ps->snap->chunk_shift = ffs(chunk_size) - 1; | ||
229 | |||
230 | r = alloc_area(ps); | ||
231 | if (r) | ||
232 | return r; | ||
233 | |||
234 | r = dm_io_get(sectors_to_pages(chunk_size)); | ||
235 | if (r) | ||
236 | return r; | ||
237 | } | ||
215 | } else { | 238 | } else { |
216 | DMWARN("Invalid/corrupt snapshot"); | 239 | DMWARN("Invalid/corrupt snapshot"); |
217 | r = -ENXIO; | 240 | r = -ENXIO; |
@@ -224,13 +247,13 @@ static int write_header(struct pstore *ps) | |||
224 | { | 247 | { |
225 | struct disk_header *dh; | 248 | struct disk_header *dh; |
226 | 249 | ||
227 | memset(ps->area, 0, ps->chunk_size << SECTOR_SHIFT); | 250 | memset(ps->area, 0, ps->snap->chunk_size << SECTOR_SHIFT); |
228 | 251 | ||
229 | dh = (struct disk_header *) ps->area; | 252 | dh = (struct disk_header *) ps->area; |
230 | dh->magic = cpu_to_le32(SNAP_MAGIC); | 253 | dh->magic = cpu_to_le32(SNAP_MAGIC); |
231 | dh->valid = cpu_to_le32(ps->valid); | 254 | dh->valid = cpu_to_le32(ps->valid); |
232 | dh->version = cpu_to_le32(ps->version); | 255 | dh->version = cpu_to_le32(ps->version); |
233 | dh->chunk_size = cpu_to_le32(ps->chunk_size); | 256 | dh->chunk_size = cpu_to_le32(ps->snap->chunk_size); |
234 | 257 | ||
235 | return chunk_io(ps, 0, WRITE); | 258 | return chunk_io(ps, 0, WRITE); |
236 | } | 259 | } |
@@ -365,7 +388,7 @@ static void persistent_destroy(struct exception_store *store) | |||
365 | { | 388 | { |
366 | struct pstore *ps = get_info(store); | 389 | struct pstore *ps = get_info(store); |
367 | 390 | ||
368 | dm_io_put(sectors_to_pages(ps->chunk_size)); | 391 | dm_io_put(sectors_to_pages(ps->snap->chunk_size)); |
369 | vfree(ps->callbacks); | 392 | vfree(ps->callbacks); |
370 | free_area(ps); | 393 | free_area(ps); |
371 | kfree(ps); | 394 | kfree(ps); |
@@ -384,6 +407,16 @@ static int persistent_read_metadata(struct exception_store *store) | |||
384 | return r; | 407 | return r; |
385 | 408 | ||
386 | /* | 409 | /* |
410 | * Now we know correct chunk_size, complete the initialisation. | ||
411 | */ | ||
412 | ps->exceptions_per_area = (ps->snap->chunk_size << SECTOR_SHIFT) / | ||
413 | sizeof(struct disk_exception); | ||
414 | ps->callbacks = dm_vcalloc(ps->exceptions_per_area, | ||
415 | sizeof(*ps->callbacks)); | ||
416 | if (!ps->callbacks) | ||
417 | return -ENOMEM; | ||
418 | |||
419 | /* | ||
387 | * Do we need to setup a new snapshot ? | 420 | * Do we need to setup a new snapshot ? |
388 | */ | 421 | */ |
389 | if (new_snapshot) { | 422 | if (new_snapshot) { |
@@ -533,9 +566,6 @@ int dm_create_persistent(struct exception_store *store, uint32_t chunk_size) | |||
533 | ps->snap = store->snap; | 566 | ps->snap = store->snap; |
534 | ps->valid = 1; | 567 | ps->valid = 1; |
535 | ps->version = SNAPSHOT_DISK_VERSION; | 568 | ps->version = SNAPSHOT_DISK_VERSION; |
536 | ps->chunk_size = chunk_size; | ||
537 | ps->exceptions_per_area = (chunk_size << SECTOR_SHIFT) / | ||
538 | sizeof(struct disk_exception); | ||
539 | ps->next_free = 2; /* skipping the header and first area */ | 569 | ps->next_free = 2; /* skipping the header and first area */ |
540 | ps->current_committed = 0; | 570 | ps->current_committed = 0; |
541 | 571 | ||
@@ -543,18 +573,9 @@ int dm_create_persistent(struct exception_store *store, uint32_t chunk_size) | |||
543 | if (r) | 573 | if (r) |
544 | goto bad; | 574 | goto bad; |
545 | 575 | ||
546 | /* | ||
547 | * Allocate space for all the callbacks. | ||
548 | */ | ||
549 | ps->callback_count = 0; | 576 | ps->callback_count = 0; |
550 | atomic_set(&ps->pending_count, 0); | 577 | atomic_set(&ps->pending_count, 0); |
551 | ps->callbacks = dm_vcalloc(ps->exceptions_per_area, | 578 | ps->callbacks = NULL; |
552 | sizeof(*ps->callbacks)); | ||
553 | |||
554 | if (!ps->callbacks) { | ||
555 | r = -ENOMEM; | ||
556 | goto bad; | ||
557 | } | ||
558 | 579 | ||
559 | store->destroy = persistent_destroy; | 580 | store->destroy = persistent_destroy; |
560 | store->read_metadata = persistent_read_metadata; | 581 | store->read_metadata = persistent_read_metadata; |
diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c index 8edd6435414d..3edb3477f987 100644 --- a/drivers/md/dm-ioctl.c +++ b/drivers/md/dm-ioctl.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2001, 2002 Sistina Software (UK) Limited. | 2 | * Copyright (C) 2001, 2002 Sistina Software (UK) Limited. |
3 | * Copyright (C) 2004 - 2005 Red Hat, Inc. All rights reserved. | 3 | * Copyright (C) 2004 - 2006 Red Hat, Inc. All rights reserved. |
4 | * | 4 | * |
5 | * This file is released under the GPL. | 5 | * This file is released under the GPL. |
6 | */ | 6 | */ |
@@ -19,6 +19,7 @@ | |||
19 | 19 | ||
20 | #include <asm/uaccess.h> | 20 | #include <asm/uaccess.h> |
21 | 21 | ||
22 | #define DM_MSG_PREFIX "ioctl" | ||
22 | #define DM_DRIVER_EMAIL "dm-devel@redhat.com" | 23 | #define DM_DRIVER_EMAIL "dm-devel@redhat.com" |
23 | 24 | ||
24 | /*----------------------------------------------------------------- | 25 | /*----------------------------------------------------------------- |
@@ -48,7 +49,7 @@ struct vers_iter { | |||
48 | static struct list_head _name_buckets[NUM_BUCKETS]; | 49 | static struct list_head _name_buckets[NUM_BUCKETS]; |
49 | static struct list_head _uuid_buckets[NUM_BUCKETS]; | 50 | static struct list_head _uuid_buckets[NUM_BUCKETS]; |
50 | 51 | ||
51 | static void dm_hash_remove_all(void); | 52 | static void dm_hash_remove_all(int keep_open_devices); |
52 | 53 | ||
53 | /* | 54 | /* |
54 | * Guards access to both hash tables. | 55 | * Guards access to both hash tables. |
@@ -73,7 +74,7 @@ static int dm_hash_init(void) | |||
73 | 74 | ||
74 | static void dm_hash_exit(void) | 75 | static void dm_hash_exit(void) |
75 | { | 76 | { |
76 | dm_hash_remove_all(); | 77 | dm_hash_remove_all(0); |
77 | devfs_remove(DM_DIR); | 78 | devfs_remove(DM_DIR); |
78 | } | 79 | } |
79 | 80 | ||
@@ -102,8 +103,10 @@ static struct hash_cell *__get_name_cell(const char *str) | |||
102 | unsigned int h = hash_str(str); | 103 | unsigned int h = hash_str(str); |
103 | 104 | ||
104 | list_for_each_entry (hc, _name_buckets + h, name_list) | 105 | list_for_each_entry (hc, _name_buckets + h, name_list) |
105 | if (!strcmp(hc->name, str)) | 106 | if (!strcmp(hc->name, str)) { |
107 | dm_get(hc->md); | ||
106 | return hc; | 108 | return hc; |
109 | } | ||
107 | 110 | ||
108 | return NULL; | 111 | return NULL; |
109 | } | 112 | } |
@@ -114,8 +117,10 @@ static struct hash_cell *__get_uuid_cell(const char *str) | |||
114 | unsigned int h = hash_str(str); | 117 | unsigned int h = hash_str(str); |
115 | 118 | ||
116 | list_for_each_entry (hc, _uuid_buckets + h, uuid_list) | 119 | list_for_each_entry (hc, _uuid_buckets + h, uuid_list) |
117 | if (!strcmp(hc->uuid, str)) | 120 | if (!strcmp(hc->uuid, str)) { |
121 | dm_get(hc->md); | ||
118 | return hc; | 122 | return hc; |
123 | } | ||
119 | 124 | ||
120 | return NULL; | 125 | return NULL; |
121 | } | 126 | } |
@@ -191,7 +196,7 @@ static int unregister_with_devfs(struct hash_cell *hc) | |||
191 | */ | 196 | */ |
192 | static int dm_hash_insert(const char *name, const char *uuid, struct mapped_device *md) | 197 | static int dm_hash_insert(const char *name, const char *uuid, struct mapped_device *md) |
193 | { | 198 | { |
194 | struct hash_cell *cell; | 199 | struct hash_cell *cell, *hc; |
195 | 200 | ||
196 | /* | 201 | /* |
197 | * Allocate the new cells. | 202 | * Allocate the new cells. |
@@ -204,14 +209,19 @@ static int dm_hash_insert(const char *name, const char *uuid, struct mapped_devi | |||
204 | * Insert the cell into both hash tables. | 209 | * Insert the cell into both hash tables. |
205 | */ | 210 | */ |
206 | down_write(&_hash_lock); | 211 | down_write(&_hash_lock); |
207 | if (__get_name_cell(name)) | 212 | hc = __get_name_cell(name); |
213 | if (hc) { | ||
214 | dm_put(hc->md); | ||
208 | goto bad; | 215 | goto bad; |
216 | } | ||
209 | 217 | ||
210 | list_add(&cell->name_list, _name_buckets + hash_str(name)); | 218 | list_add(&cell->name_list, _name_buckets + hash_str(name)); |
211 | 219 | ||
212 | if (uuid) { | 220 | if (uuid) { |
213 | if (__get_uuid_cell(uuid)) { | 221 | hc = __get_uuid_cell(uuid); |
222 | if (hc) { | ||
214 | list_del(&cell->name_list); | 223 | list_del(&cell->name_list); |
224 | dm_put(hc->md); | ||
215 | goto bad; | 225 | goto bad; |
216 | } | 226 | } |
217 | list_add(&cell->uuid_list, _uuid_buckets + hash_str(uuid)); | 227 | list_add(&cell->uuid_list, _uuid_buckets + hash_str(uuid)); |
@@ -251,19 +261,41 @@ static void __hash_remove(struct hash_cell *hc) | |||
251 | free_cell(hc); | 261 | free_cell(hc); |
252 | } | 262 | } |
253 | 263 | ||
254 | static void dm_hash_remove_all(void) | 264 | static void dm_hash_remove_all(int keep_open_devices) |
255 | { | 265 | { |
256 | int i; | 266 | int i, dev_skipped, dev_removed; |
257 | struct hash_cell *hc; | 267 | struct hash_cell *hc; |
258 | struct list_head *tmp, *n; | 268 | struct list_head *tmp, *n; |
259 | 269 | ||
260 | down_write(&_hash_lock); | 270 | down_write(&_hash_lock); |
271 | |||
272 | retry: | ||
273 | dev_skipped = dev_removed = 0; | ||
261 | for (i = 0; i < NUM_BUCKETS; i++) { | 274 | for (i = 0; i < NUM_BUCKETS; i++) { |
262 | list_for_each_safe (tmp, n, _name_buckets + i) { | 275 | list_for_each_safe (tmp, n, _name_buckets + i) { |
263 | hc = list_entry(tmp, struct hash_cell, name_list); | 276 | hc = list_entry(tmp, struct hash_cell, name_list); |
277 | |||
278 | if (keep_open_devices && | ||
279 | dm_lock_for_deletion(hc->md)) { | ||
280 | dev_skipped++; | ||
281 | continue; | ||
282 | } | ||
264 | __hash_remove(hc); | 283 | __hash_remove(hc); |
284 | dev_removed = 1; | ||
265 | } | 285 | } |
266 | } | 286 | } |
287 | |||
288 | /* | ||
289 | * Some mapped devices may be using other mapped devices, so if any | ||
290 | * still exist, repeat until we make no further progress. | ||
291 | */ | ||
292 | if (dev_skipped) { | ||
293 | if (dev_removed) | ||
294 | goto retry; | ||
295 | |||
296 | DMWARN("remove_all left %d open device(s)", dev_skipped); | ||
297 | } | ||
298 | |||
267 | up_write(&_hash_lock); | 299 | up_write(&_hash_lock); |
268 | } | 300 | } |
269 | 301 | ||
@@ -289,6 +321,7 @@ static int dm_hash_rename(const char *old, const char *new) | |||
289 | if (hc) { | 321 | if (hc) { |
290 | DMWARN("asked to rename to an already existing name %s -> %s", | 322 | DMWARN("asked to rename to an already existing name %s -> %s", |
291 | old, new); | 323 | old, new); |
324 | dm_put(hc->md); | ||
292 | up_write(&_hash_lock); | 325 | up_write(&_hash_lock); |
293 | kfree(new_name); | 326 | kfree(new_name); |
294 | return -EBUSY; | 327 | return -EBUSY; |
@@ -328,6 +361,7 @@ static int dm_hash_rename(const char *old, const char *new) | |||
328 | dm_table_put(table); | 361 | dm_table_put(table); |
329 | } | 362 | } |
330 | 363 | ||
364 | dm_put(hc->md); | ||
331 | up_write(&_hash_lock); | 365 | up_write(&_hash_lock); |
332 | kfree(old_name); | 366 | kfree(old_name); |
333 | return 0; | 367 | return 0; |
@@ -344,7 +378,7 @@ typedef int (*ioctl_fn)(struct dm_ioctl *param, size_t param_size); | |||
344 | 378 | ||
345 | static int remove_all(struct dm_ioctl *param, size_t param_size) | 379 | static int remove_all(struct dm_ioctl *param, size_t param_size) |
346 | { | 380 | { |
347 | dm_hash_remove_all(); | 381 | dm_hash_remove_all(1); |
348 | param->data_size = 0; | 382 | param->data_size = 0; |
349 | return 0; | 383 | return 0; |
350 | } | 384 | } |
@@ -524,7 +558,6 @@ static int __dev_status(struct mapped_device *md, struct dm_ioctl *param) | |||
524 | { | 558 | { |
525 | struct gendisk *disk = dm_disk(md); | 559 | struct gendisk *disk = dm_disk(md); |
526 | struct dm_table *table; | 560 | struct dm_table *table; |
527 | struct block_device *bdev; | ||
528 | 561 | ||
529 | param->flags &= ~(DM_SUSPEND_FLAG | DM_READONLY_FLAG | | 562 | param->flags &= ~(DM_SUSPEND_FLAG | DM_READONLY_FLAG | |
530 | DM_ACTIVE_PRESENT_FLAG); | 563 | DM_ACTIVE_PRESENT_FLAG); |
@@ -534,20 +567,12 @@ static int __dev_status(struct mapped_device *md, struct dm_ioctl *param) | |||
534 | 567 | ||
535 | param->dev = huge_encode_dev(MKDEV(disk->major, disk->first_minor)); | 568 | param->dev = huge_encode_dev(MKDEV(disk->major, disk->first_minor)); |
536 | 569 | ||
537 | if (!(param->flags & DM_SKIP_BDGET_FLAG)) { | 570 | /* |
538 | bdev = bdget_disk(disk, 0); | 571 | * Yes, this will be out of date by the time it gets back |
539 | if (!bdev) | 572 | * to userland, but it is still very useful for |
540 | return -ENXIO; | 573 | * debugging. |
541 | 574 | */ | |
542 | /* | 575 | param->open_count = dm_open_count(md); |
543 | * Yes, this will be out of date by the time it gets back | ||
544 | * to userland, but it is still very useful for | ||
545 | * debugging. | ||
546 | */ | ||
547 | param->open_count = bdev->bd_openers; | ||
548 | bdput(bdev); | ||
549 | } else | ||
550 | param->open_count = -1; | ||
551 | 576 | ||
552 | if (disk->policy) | 577 | if (disk->policy) |
553 | param->flags |= DM_READONLY_FLAG; | 578 | param->flags |= DM_READONLY_FLAG; |
@@ -567,7 +592,7 @@ static int __dev_status(struct mapped_device *md, struct dm_ioctl *param) | |||
567 | 592 | ||
568 | static int dev_create(struct dm_ioctl *param, size_t param_size) | 593 | static int dev_create(struct dm_ioctl *param, size_t param_size) |
569 | { | 594 | { |
570 | int r; | 595 | int r, m = DM_ANY_MINOR; |
571 | struct mapped_device *md; | 596 | struct mapped_device *md; |
572 | 597 | ||
573 | r = check_name(param->name); | 598 | r = check_name(param->name); |
@@ -575,10 +600,9 @@ static int dev_create(struct dm_ioctl *param, size_t param_size) | |||
575 | return r; | 600 | return r; |
576 | 601 | ||
577 | if (param->flags & DM_PERSISTENT_DEV_FLAG) | 602 | if (param->flags & DM_PERSISTENT_DEV_FLAG) |
578 | r = dm_create_with_minor(MINOR(huge_decode_dev(param->dev)), &md); | 603 | m = MINOR(huge_decode_dev(param->dev)); |
579 | else | ||
580 | r = dm_create(&md); | ||
581 | 604 | ||
605 | r = dm_create(m, &md); | ||
582 | if (r) | 606 | if (r) |
583 | return r; | 607 | return r; |
584 | 608 | ||
@@ -611,10 +635,8 @@ static struct hash_cell *__find_device_hash_cell(struct dm_ioctl *param) | |||
611 | return __get_name_cell(param->name); | 635 | return __get_name_cell(param->name); |
612 | 636 | ||
613 | md = dm_get_md(huge_decode_dev(param->dev)); | 637 | md = dm_get_md(huge_decode_dev(param->dev)); |
614 | if (md) { | 638 | if (md) |
615 | mdptr = dm_get_mdptr(md); | 639 | mdptr = dm_get_mdptr(md); |
616 | dm_put(md); | ||
617 | } | ||
618 | 640 | ||
619 | return mdptr; | 641 | return mdptr; |
620 | } | 642 | } |
@@ -628,7 +650,6 @@ static struct mapped_device *find_device(struct dm_ioctl *param) | |||
628 | hc = __find_device_hash_cell(param); | 650 | hc = __find_device_hash_cell(param); |
629 | if (hc) { | 651 | if (hc) { |
630 | md = hc->md; | 652 | md = hc->md; |
631 | dm_get(md); | ||
632 | 653 | ||
633 | /* | 654 | /* |
634 | * Sneakily write in both the name and the uuid | 655 | * Sneakily write in both the name and the uuid |
@@ -653,6 +674,8 @@ static struct mapped_device *find_device(struct dm_ioctl *param) | |||
653 | static int dev_remove(struct dm_ioctl *param, size_t param_size) | 674 | static int dev_remove(struct dm_ioctl *param, size_t param_size) |
654 | { | 675 | { |
655 | struct hash_cell *hc; | 676 | struct hash_cell *hc; |
677 | struct mapped_device *md; | ||
678 | int r; | ||
656 | 679 | ||
657 | down_write(&_hash_lock); | 680 | down_write(&_hash_lock); |
658 | hc = __find_device_hash_cell(param); | 681 | hc = __find_device_hash_cell(param); |
@@ -663,8 +686,22 @@ static int dev_remove(struct dm_ioctl *param, size_t param_size) | |||
663 | return -ENXIO; | 686 | return -ENXIO; |
664 | } | 687 | } |
665 | 688 | ||
689 | md = hc->md; | ||
690 | |||
691 | /* | ||
692 | * Ensure the device is not open and nothing further can open it. | ||
693 | */ | ||
694 | r = dm_lock_for_deletion(md); | ||
695 | if (r) { | ||
696 | DMWARN("unable to remove open device %s", hc->name); | ||
697 | up_write(&_hash_lock); | ||
698 | dm_put(md); | ||
699 | return r; | ||
700 | } | ||
701 | |||
666 | __hash_remove(hc); | 702 | __hash_remove(hc); |
667 | up_write(&_hash_lock); | 703 | up_write(&_hash_lock); |
704 | dm_put(md); | ||
668 | param->data_size = 0; | 705 | param->data_size = 0; |
669 | return 0; | 706 | return 0; |
670 | } | 707 | } |
@@ -790,7 +827,6 @@ static int do_resume(struct dm_ioctl *param) | |||
790 | } | 827 | } |
791 | 828 | ||
792 | md = hc->md; | 829 | md = hc->md; |
793 | dm_get(md); | ||
794 | 830 | ||
795 | new_map = hc->new_map; | 831 | new_map = hc->new_map; |
796 | hc->new_map = NULL; | 832 | hc->new_map = NULL; |
@@ -1078,6 +1114,7 @@ static int table_clear(struct dm_ioctl *param, size_t param_size) | |||
1078 | { | 1114 | { |
1079 | int r; | 1115 | int r; |
1080 | struct hash_cell *hc; | 1116 | struct hash_cell *hc; |
1117 | struct mapped_device *md; | ||
1081 | 1118 | ||
1082 | down_write(&_hash_lock); | 1119 | down_write(&_hash_lock); |
1083 | 1120 | ||
@@ -1096,7 +1133,9 @@ static int table_clear(struct dm_ioctl *param, size_t param_size) | |||
1096 | param->flags &= ~DM_INACTIVE_PRESENT_FLAG; | 1133 | param->flags &= ~DM_INACTIVE_PRESENT_FLAG; |
1097 | 1134 | ||
1098 | r = __dev_status(hc->md, param); | 1135 | r = __dev_status(hc->md, param); |
1136 | md = hc->md; | ||
1099 | up_write(&_hash_lock); | 1137 | up_write(&_hash_lock); |
1138 | dm_put(md); | ||
1100 | return r; | 1139 | return r; |
1101 | } | 1140 | } |
1102 | 1141 | ||
diff --git a/drivers/md/dm-linear.c b/drivers/md/dm-linear.c index daf586c0898d..47b3c62bbdb8 100644 --- a/drivers/md/dm-linear.c +++ b/drivers/md/dm-linear.c | |||
@@ -12,6 +12,8 @@ | |||
12 | #include <linux/bio.h> | 12 | #include <linux/bio.h> |
13 | #include <linux/slab.h> | 13 | #include <linux/slab.h> |
14 | 14 | ||
15 | #define DM_MSG_PREFIX "linear" | ||
16 | |||
15 | /* | 17 | /* |
16 | * Linear: maps a linear range of a device. | 18 | * Linear: maps a linear range of a device. |
17 | */ | 19 | */ |
@@ -29,7 +31,7 @@ static int linear_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
29 | unsigned long long tmp; | 31 | unsigned long long tmp; |
30 | 32 | ||
31 | if (argc != 2) { | 33 | if (argc != 2) { |
32 | ti->error = "dm-linear: Invalid argument count"; | 34 | ti->error = "Invalid argument count"; |
33 | return -EINVAL; | 35 | return -EINVAL; |
34 | } | 36 | } |
35 | 37 | ||
@@ -111,7 +113,7 @@ int __init dm_linear_init(void) | |||
111 | int r = dm_register_target(&linear_target); | 113 | int r = dm_register_target(&linear_target); |
112 | 114 | ||
113 | if (r < 0) | 115 | if (r < 0) |
114 | DMERR("linear: register failed %d", r); | 116 | DMERR("register failed %d", r); |
115 | 117 | ||
116 | return r; | 118 | return r; |
117 | } | 119 | } |
@@ -121,5 +123,5 @@ void dm_linear_exit(void) | |||
121 | int r = dm_unregister_target(&linear_target); | 123 | int r = dm_unregister_target(&linear_target); |
122 | 124 | ||
123 | if (r < 0) | 125 | if (r < 0) |
124 | DMERR("linear: unregister failed %d", r); | 126 | DMERR("unregister failed %d", r); |
125 | } | 127 | } |
diff --git a/drivers/md/dm-log.c b/drivers/md/dm-log.c index d73779a42417..64b764bd02cc 100644 --- a/drivers/md/dm-log.c +++ b/drivers/md/dm-log.c | |||
@@ -12,6 +12,8 @@ | |||
12 | #include "dm-log.h" | 12 | #include "dm-log.h" |
13 | #include "dm-io.h" | 13 | #include "dm-io.h" |
14 | 14 | ||
15 | #define DM_MSG_PREFIX "mirror log" | ||
16 | |||
15 | static LIST_HEAD(_log_types); | 17 | static LIST_HEAD(_log_types); |
16 | static DEFINE_SPINLOCK(_lock); | 18 | static DEFINE_SPINLOCK(_lock); |
17 | 19 | ||
@@ -155,8 +157,6 @@ struct log_c { | |||
155 | 157 | ||
156 | struct io_region header_location; | 158 | struct io_region header_location; |
157 | struct log_header *disk_header; | 159 | struct log_header *disk_header; |
158 | |||
159 | struct io_region bits_location; | ||
160 | }; | 160 | }; |
161 | 161 | ||
162 | /* | 162 | /* |
@@ -241,43 +241,21 @@ static inline int write_header(struct log_c *log) | |||
241 | } | 241 | } |
242 | 242 | ||
243 | /*---------------------------------------------------------------- | 243 | /*---------------------------------------------------------------- |
244 | * Bits IO | ||
245 | *--------------------------------------------------------------*/ | ||
246 | static int read_bits(struct log_c *log) | ||
247 | { | ||
248 | int r; | ||
249 | unsigned long ebits; | ||
250 | |||
251 | r = dm_io_sync_vm(1, &log->bits_location, READ, | ||
252 | log->clean_bits, &ebits); | ||
253 | if (r) | ||
254 | return r; | ||
255 | |||
256 | return 0; | ||
257 | } | ||
258 | |||
259 | static int write_bits(struct log_c *log) | ||
260 | { | ||
261 | unsigned long ebits; | ||
262 | return dm_io_sync_vm(1, &log->bits_location, WRITE, | ||
263 | log->clean_bits, &ebits); | ||
264 | } | ||
265 | |||
266 | /*---------------------------------------------------------------- | ||
267 | * core log constructor/destructor | 244 | * core log constructor/destructor |
268 | * | 245 | * |
269 | * argv contains region_size followed optionally by [no]sync | 246 | * argv contains region_size followed optionally by [no]sync |
270 | *--------------------------------------------------------------*/ | 247 | *--------------------------------------------------------------*/ |
271 | #define BYTE_SHIFT 3 | 248 | #define BYTE_SHIFT 3 |
272 | static int core_ctr(struct dirty_log *log, struct dm_target *ti, | 249 | static int create_log_context(struct dirty_log *log, struct dm_target *ti, |
273 | unsigned int argc, char **argv) | 250 | unsigned int argc, char **argv, |
251 | struct dm_dev *dev) | ||
274 | { | 252 | { |
275 | enum sync sync = DEFAULTSYNC; | 253 | enum sync sync = DEFAULTSYNC; |
276 | 254 | ||
277 | struct log_c *lc; | 255 | struct log_c *lc; |
278 | uint32_t region_size; | 256 | uint32_t region_size; |
279 | unsigned int region_count; | 257 | unsigned int region_count; |
280 | size_t bitset_size; | 258 | size_t bitset_size, buf_size; |
281 | 259 | ||
282 | if (argc < 1 || argc > 2) { | 260 | if (argc < 1 || argc > 2) { |
283 | DMWARN("wrong number of arguments to mirror log"); | 261 | DMWARN("wrong number of arguments to mirror log"); |
@@ -319,22 +297,53 @@ static int core_ctr(struct dirty_log *log, struct dm_target *ti, | |||
319 | * Work out how many "unsigned long"s we need to hold the bitset. | 297 | * Work out how many "unsigned long"s we need to hold the bitset. |
320 | */ | 298 | */ |
321 | bitset_size = dm_round_up(region_count, | 299 | bitset_size = dm_round_up(region_count, |
322 | sizeof(unsigned long) << BYTE_SHIFT); | 300 | sizeof(*lc->clean_bits) << BYTE_SHIFT); |
323 | bitset_size >>= BYTE_SHIFT; | 301 | bitset_size >>= BYTE_SHIFT; |
324 | 302 | ||
325 | lc->bitset_uint32_count = bitset_size / 4; | 303 | lc->bitset_uint32_count = bitset_size / sizeof(*lc->clean_bits); |
326 | lc->clean_bits = vmalloc(bitset_size); | 304 | |
327 | if (!lc->clean_bits) { | 305 | /* |
328 | DMWARN("couldn't allocate clean bitset"); | 306 | * Disk log? |
329 | kfree(lc); | 307 | */ |
330 | return -ENOMEM; | 308 | if (!dev) { |
309 | lc->clean_bits = vmalloc(bitset_size); | ||
310 | if (!lc->clean_bits) { | ||
311 | DMWARN("couldn't allocate clean bitset"); | ||
312 | kfree(lc); | ||
313 | return -ENOMEM; | ||
314 | } | ||
315 | lc->disk_header = NULL; | ||
316 | } else { | ||
317 | lc->log_dev = dev; | ||
318 | lc->header_location.bdev = lc->log_dev->bdev; | ||
319 | lc->header_location.sector = 0; | ||
320 | |||
321 | /* | ||
322 | * Buffer holds both header and bitset. | ||
323 | */ | ||
324 | buf_size = dm_round_up((LOG_OFFSET << SECTOR_SHIFT) + | ||
325 | bitset_size, ti->limits.hardsect_size); | ||
326 | lc->header_location.count = buf_size >> SECTOR_SHIFT; | ||
327 | |||
328 | lc->disk_header = vmalloc(buf_size); | ||
329 | if (!lc->disk_header) { | ||
330 | DMWARN("couldn't allocate disk log buffer"); | ||
331 | kfree(lc); | ||
332 | return -ENOMEM; | ||
333 | } | ||
334 | |||
335 | lc->clean_bits = (void *)lc->disk_header + | ||
336 | (LOG_OFFSET << SECTOR_SHIFT); | ||
331 | } | 337 | } |
338 | |||
332 | memset(lc->clean_bits, -1, bitset_size); | 339 | memset(lc->clean_bits, -1, bitset_size); |
333 | 340 | ||
334 | lc->sync_bits = vmalloc(bitset_size); | 341 | lc->sync_bits = vmalloc(bitset_size); |
335 | if (!lc->sync_bits) { | 342 | if (!lc->sync_bits) { |
336 | DMWARN("couldn't allocate sync bitset"); | 343 | DMWARN("couldn't allocate sync bitset"); |
337 | vfree(lc->clean_bits); | 344 | if (!dev) |
345 | vfree(lc->clean_bits); | ||
346 | vfree(lc->disk_header); | ||
338 | kfree(lc); | 347 | kfree(lc); |
339 | return -ENOMEM; | 348 | return -ENOMEM; |
340 | } | 349 | } |
@@ -345,25 +354,40 @@ static int core_ctr(struct dirty_log *log, struct dm_target *ti, | |||
345 | if (!lc->recovering_bits) { | 354 | if (!lc->recovering_bits) { |
346 | DMWARN("couldn't allocate sync bitset"); | 355 | DMWARN("couldn't allocate sync bitset"); |
347 | vfree(lc->sync_bits); | 356 | vfree(lc->sync_bits); |
348 | vfree(lc->clean_bits); | 357 | if (!dev) |
358 | vfree(lc->clean_bits); | ||
359 | vfree(lc->disk_header); | ||
349 | kfree(lc); | 360 | kfree(lc); |
350 | return -ENOMEM; | 361 | return -ENOMEM; |
351 | } | 362 | } |
352 | memset(lc->recovering_bits, 0, bitset_size); | 363 | memset(lc->recovering_bits, 0, bitset_size); |
353 | lc->sync_search = 0; | 364 | lc->sync_search = 0; |
354 | log->context = lc; | 365 | log->context = lc; |
366 | |||
355 | return 0; | 367 | return 0; |
356 | } | 368 | } |
357 | 369 | ||
358 | static void core_dtr(struct dirty_log *log) | 370 | static int core_ctr(struct dirty_log *log, struct dm_target *ti, |
371 | unsigned int argc, char **argv) | ||
372 | { | ||
373 | return create_log_context(log, ti, argc, argv, NULL); | ||
374 | } | ||
375 | |||
376 | static void destroy_log_context(struct log_c *lc) | ||
359 | { | 377 | { |
360 | struct log_c *lc = (struct log_c *) log->context; | ||
361 | vfree(lc->clean_bits); | ||
362 | vfree(lc->sync_bits); | 378 | vfree(lc->sync_bits); |
363 | vfree(lc->recovering_bits); | 379 | vfree(lc->recovering_bits); |
364 | kfree(lc); | 380 | kfree(lc); |
365 | } | 381 | } |
366 | 382 | ||
383 | static void core_dtr(struct dirty_log *log) | ||
384 | { | ||
385 | struct log_c *lc = (struct log_c *) log->context; | ||
386 | |||
387 | vfree(lc->clean_bits); | ||
388 | destroy_log_context(lc); | ||
389 | } | ||
390 | |||
367 | /*---------------------------------------------------------------- | 391 | /*---------------------------------------------------------------- |
368 | * disk log constructor/destructor | 392 | * disk log constructor/destructor |
369 | * | 393 | * |
@@ -373,8 +397,6 @@ static int disk_ctr(struct dirty_log *log, struct dm_target *ti, | |||
373 | unsigned int argc, char **argv) | 397 | unsigned int argc, char **argv) |
374 | { | 398 | { |
375 | int r; | 399 | int r; |
376 | size_t size; | ||
377 | struct log_c *lc; | ||
378 | struct dm_dev *dev; | 400 | struct dm_dev *dev; |
379 | 401 | ||
380 | if (argc < 2 || argc > 3) { | 402 | if (argc < 2 || argc > 3) { |
@@ -387,49 +409,22 @@ static int disk_ctr(struct dirty_log *log, struct dm_target *ti, | |||
387 | if (r) | 409 | if (r) |
388 | return r; | 410 | return r; |
389 | 411 | ||
390 | r = core_ctr(log, ti, argc - 1, argv + 1); | 412 | r = create_log_context(log, ti, argc - 1, argv + 1, dev); |
391 | if (r) { | 413 | if (r) { |
392 | dm_put_device(ti, dev); | 414 | dm_put_device(ti, dev); |
393 | return r; | 415 | return r; |
394 | } | 416 | } |
395 | 417 | ||
396 | lc = (struct log_c *) log->context; | ||
397 | lc->log_dev = dev; | ||
398 | |||
399 | /* setup the disk header fields */ | ||
400 | lc->header_location.bdev = lc->log_dev->bdev; | ||
401 | lc->header_location.sector = 0; | ||
402 | lc->header_location.count = 1; | ||
403 | |||
404 | /* | ||
405 | * We can't read less than this amount, even though we'll | ||
406 | * not be using most of this space. | ||
407 | */ | ||
408 | lc->disk_header = vmalloc(1 << SECTOR_SHIFT); | ||
409 | if (!lc->disk_header) | ||
410 | goto bad; | ||
411 | |||
412 | /* setup the disk bitset fields */ | ||
413 | lc->bits_location.bdev = lc->log_dev->bdev; | ||
414 | lc->bits_location.sector = LOG_OFFSET; | ||
415 | |||
416 | size = dm_round_up(lc->bitset_uint32_count * sizeof(uint32_t), | ||
417 | 1 << SECTOR_SHIFT); | ||
418 | lc->bits_location.count = size >> SECTOR_SHIFT; | ||
419 | return 0; | 418 | return 0; |
420 | |||
421 | bad: | ||
422 | dm_put_device(ti, lc->log_dev); | ||
423 | core_dtr(log); | ||
424 | return -ENOMEM; | ||
425 | } | 419 | } |
426 | 420 | ||
427 | static void disk_dtr(struct dirty_log *log) | 421 | static void disk_dtr(struct dirty_log *log) |
428 | { | 422 | { |
429 | struct log_c *lc = (struct log_c *) log->context; | 423 | struct log_c *lc = (struct log_c *) log->context; |
424 | |||
430 | dm_put_device(lc->ti, lc->log_dev); | 425 | dm_put_device(lc->ti, lc->log_dev); |
431 | vfree(lc->disk_header); | 426 | vfree(lc->disk_header); |
432 | core_dtr(log); | 427 | destroy_log_context(lc); |
433 | } | 428 | } |
434 | 429 | ||
435 | static int count_bits32(uint32_t *addr, unsigned size) | 430 | static int count_bits32(uint32_t *addr, unsigned size) |
@@ -454,12 +449,7 @@ static int disk_resume(struct dirty_log *log) | |||
454 | if (r) | 449 | if (r) |
455 | return r; | 450 | return r; |
456 | 451 | ||
457 | /* read the bits */ | 452 | /* set or clear any new bits -- device has grown */ |
458 | r = read_bits(lc); | ||
459 | if (r) | ||
460 | return r; | ||
461 | |||
462 | /* set or clear any new bits */ | ||
463 | if (lc->sync == NOSYNC) | 453 | if (lc->sync == NOSYNC) |
464 | for (i = lc->header.nr_regions; i < lc->region_count; i++) | 454 | for (i = lc->header.nr_regions; i < lc->region_count; i++) |
465 | /* FIXME: amazingly inefficient */ | 455 | /* FIXME: amazingly inefficient */ |
@@ -469,15 +459,14 @@ static int disk_resume(struct dirty_log *log) | |||
469 | /* FIXME: amazingly inefficient */ | 459 | /* FIXME: amazingly inefficient */ |
470 | log_clear_bit(lc, lc->clean_bits, i); | 460 | log_clear_bit(lc, lc->clean_bits, i); |
471 | 461 | ||
462 | /* clear any old bits -- device has shrunk */ | ||
463 | for (i = lc->region_count; i % (sizeof(*lc->clean_bits) << BYTE_SHIFT); i++) | ||
464 | log_clear_bit(lc, lc->clean_bits, i); | ||
465 | |||
472 | /* copy clean across to sync */ | 466 | /* copy clean across to sync */ |
473 | memcpy(lc->sync_bits, lc->clean_bits, size); | 467 | memcpy(lc->sync_bits, lc->clean_bits, size); |
474 | lc->sync_count = count_bits32(lc->clean_bits, lc->bitset_uint32_count); | 468 | lc->sync_count = count_bits32(lc->clean_bits, lc->bitset_uint32_count); |
475 | 469 | ||
476 | /* write the bits */ | ||
477 | r = write_bits(lc); | ||
478 | if (r) | ||
479 | return r; | ||
480 | |||
481 | /* set the correct number of regions in the header */ | 470 | /* set the correct number of regions in the header */ |
482 | lc->header.nr_regions = lc->region_count; | 471 | lc->header.nr_regions = lc->region_count; |
483 | 472 | ||
@@ -518,7 +507,7 @@ static int disk_flush(struct dirty_log *log) | |||
518 | if (!lc->touched) | 507 | if (!lc->touched) |
519 | return 0; | 508 | return 0; |
520 | 509 | ||
521 | r = write_bits(lc); | 510 | r = write_header(lc); |
522 | if (!r) | 511 | if (!r) |
523 | lc->touched = 0; | 512 | lc->touched = 0; |
524 | 513 | ||
diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c index 1816f30678ed..217615b33223 100644 --- a/drivers/md/dm-mpath.c +++ b/drivers/md/dm-mpath.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/workqueue.h> | 21 | #include <linux/workqueue.h> |
22 | #include <asm/atomic.h> | 22 | #include <asm/atomic.h> |
23 | 23 | ||
24 | #define DM_MSG_PREFIX "multipath" | ||
24 | #define MESG_STR(x) x, sizeof(x) | 25 | #define MESG_STR(x) x, sizeof(x) |
25 | 26 | ||
26 | /* Path properties */ | 27 | /* Path properties */ |
@@ -446,8 +447,6 @@ struct param { | |||
446 | char *error; | 447 | char *error; |
447 | }; | 448 | }; |
448 | 449 | ||
449 | #define ESTR(s) ("dm-multipath: " s) | ||
450 | |||
451 | static int read_param(struct param *param, char *str, unsigned *v, char **error) | 450 | static int read_param(struct param *param, char *str, unsigned *v, char **error) |
452 | { | 451 | { |
453 | if (!str || | 452 | if (!str || |
@@ -495,12 +494,12 @@ static int parse_path_selector(struct arg_set *as, struct priority_group *pg, | |||
495 | unsigned ps_argc; | 494 | unsigned ps_argc; |
496 | 495 | ||
497 | static struct param _params[] = { | 496 | static struct param _params[] = { |
498 | {0, 1024, ESTR("invalid number of path selector args")}, | 497 | {0, 1024, "invalid number of path selector args"}, |
499 | }; | 498 | }; |
500 | 499 | ||
501 | pst = dm_get_path_selector(shift(as)); | 500 | pst = dm_get_path_selector(shift(as)); |
502 | if (!pst) { | 501 | if (!pst) { |
503 | ti->error = ESTR("unknown path selector type"); | 502 | ti->error = "unknown path selector type"; |
504 | return -EINVAL; | 503 | return -EINVAL; |
505 | } | 504 | } |
506 | 505 | ||
@@ -511,7 +510,7 @@ static int parse_path_selector(struct arg_set *as, struct priority_group *pg, | |||
511 | r = pst->create(&pg->ps, ps_argc, as->argv); | 510 | r = pst->create(&pg->ps, ps_argc, as->argv); |
512 | if (r) { | 511 | if (r) { |
513 | dm_put_path_selector(pst); | 512 | dm_put_path_selector(pst); |
514 | ti->error = ESTR("path selector constructor failed"); | 513 | ti->error = "path selector constructor failed"; |
515 | return r; | 514 | return r; |
516 | } | 515 | } |
517 | 516 | ||
@@ -529,7 +528,7 @@ static struct pgpath *parse_path(struct arg_set *as, struct path_selector *ps, | |||
529 | 528 | ||
530 | /* we need at least a path arg */ | 529 | /* we need at least a path arg */ |
531 | if (as->argc < 1) { | 530 | if (as->argc < 1) { |
532 | ti->error = ESTR("no device given"); | 531 | ti->error = "no device given"; |
533 | return NULL; | 532 | return NULL; |
534 | } | 533 | } |
535 | 534 | ||
@@ -540,7 +539,7 @@ static struct pgpath *parse_path(struct arg_set *as, struct path_selector *ps, | |||
540 | r = dm_get_device(ti, shift(as), ti->begin, ti->len, | 539 | r = dm_get_device(ti, shift(as), ti->begin, ti->len, |
541 | dm_table_get_mode(ti->table), &p->path.dev); | 540 | dm_table_get_mode(ti->table), &p->path.dev); |
542 | if (r) { | 541 | if (r) { |
543 | ti->error = ESTR("error getting device"); | 542 | ti->error = "error getting device"; |
544 | goto bad; | 543 | goto bad; |
545 | } | 544 | } |
546 | 545 | ||
@@ -562,8 +561,8 @@ static struct priority_group *parse_priority_group(struct arg_set *as, | |||
562 | struct dm_target *ti) | 561 | struct dm_target *ti) |
563 | { | 562 | { |
564 | static struct param _params[] = { | 563 | static struct param _params[] = { |
565 | {1, 1024, ESTR("invalid number of paths")}, | 564 | {1, 1024, "invalid number of paths"}, |
566 | {0, 1024, ESTR("invalid number of selector args")} | 565 | {0, 1024, "invalid number of selector args"} |
567 | }; | 566 | }; |
568 | 567 | ||
569 | int r; | 568 | int r; |
@@ -572,13 +571,13 @@ static struct priority_group *parse_priority_group(struct arg_set *as, | |||
572 | 571 | ||
573 | if (as->argc < 2) { | 572 | if (as->argc < 2) { |
574 | as->argc = 0; | 573 | as->argc = 0; |
575 | ti->error = ESTR("not enough priority group aruments"); | 574 | ti->error = "not enough priority group aruments"; |
576 | return NULL; | 575 | return NULL; |
577 | } | 576 | } |
578 | 577 | ||
579 | pg = alloc_priority_group(); | 578 | pg = alloc_priority_group(); |
580 | if (!pg) { | 579 | if (!pg) { |
581 | ti->error = ESTR("couldn't allocate priority group"); | 580 | ti->error = "couldn't allocate priority group"; |
582 | return NULL; | 581 | return NULL; |
583 | } | 582 | } |
584 | pg->m = m; | 583 | pg->m = m; |
@@ -633,7 +632,7 @@ static int parse_hw_handler(struct arg_set *as, struct multipath *m, | |||
633 | unsigned hw_argc; | 632 | unsigned hw_argc; |
634 | 633 | ||
635 | static struct param _params[] = { | 634 | static struct param _params[] = { |
636 | {0, 1024, ESTR("invalid number of hardware handler args")}, | 635 | {0, 1024, "invalid number of hardware handler args"}, |
637 | }; | 636 | }; |
638 | 637 | ||
639 | r = read_param(_params, shift(as), &hw_argc, &ti->error); | 638 | r = read_param(_params, shift(as), &hw_argc, &ti->error); |
@@ -645,14 +644,14 @@ static int parse_hw_handler(struct arg_set *as, struct multipath *m, | |||
645 | 644 | ||
646 | hwht = dm_get_hw_handler(shift(as)); | 645 | hwht = dm_get_hw_handler(shift(as)); |
647 | if (!hwht) { | 646 | if (!hwht) { |
648 | ti->error = ESTR("unknown hardware handler type"); | 647 | ti->error = "unknown hardware handler type"; |
649 | return -EINVAL; | 648 | return -EINVAL; |
650 | } | 649 | } |
651 | 650 | ||
652 | r = hwht->create(&m->hw_handler, hw_argc - 1, as->argv); | 651 | r = hwht->create(&m->hw_handler, hw_argc - 1, as->argv); |
653 | if (r) { | 652 | if (r) { |
654 | dm_put_hw_handler(hwht); | 653 | dm_put_hw_handler(hwht); |
655 | ti->error = ESTR("hardware handler constructor failed"); | 654 | ti->error = "hardware handler constructor failed"; |
656 | return r; | 655 | return r; |
657 | } | 656 | } |
658 | 657 | ||
@@ -669,7 +668,7 @@ static int parse_features(struct arg_set *as, struct multipath *m, | |||
669 | unsigned argc; | 668 | unsigned argc; |
670 | 669 | ||
671 | static struct param _params[] = { | 670 | static struct param _params[] = { |
672 | {0, 1, ESTR("invalid number of feature args")}, | 671 | {0, 1, "invalid number of feature args"}, |
673 | }; | 672 | }; |
674 | 673 | ||
675 | r = read_param(_params, shift(as), &argc, &ti->error); | 674 | r = read_param(_params, shift(as), &argc, &ti->error); |
@@ -692,8 +691,8 @@ static int multipath_ctr(struct dm_target *ti, unsigned int argc, | |||
692 | { | 691 | { |
693 | /* target parameters */ | 692 | /* target parameters */ |
694 | static struct param _params[] = { | 693 | static struct param _params[] = { |
695 | {1, 1024, ESTR("invalid number of priority groups")}, | 694 | {1, 1024, "invalid number of priority groups"}, |
696 | {1, 1024, ESTR("invalid initial priority group number")}, | 695 | {1, 1024, "invalid initial priority group number"}, |
697 | }; | 696 | }; |
698 | 697 | ||
699 | int r; | 698 | int r; |
@@ -707,7 +706,7 @@ static int multipath_ctr(struct dm_target *ti, unsigned int argc, | |||
707 | 706 | ||
708 | m = alloc_multipath(); | 707 | m = alloc_multipath(); |
709 | if (!m) { | 708 | if (!m) { |
710 | ti->error = ESTR("can't allocate multipath"); | 709 | ti->error = "can't allocate multipath"; |
711 | return -EINVAL; | 710 | return -EINVAL; |
712 | } | 711 | } |
713 | 712 | ||
@@ -746,7 +745,7 @@ static int multipath_ctr(struct dm_target *ti, unsigned int argc, | |||
746 | } | 745 | } |
747 | 746 | ||
748 | if (pg_count != m->nr_priority_groups) { | 747 | if (pg_count != m->nr_priority_groups) { |
749 | ti->error = ESTR("priority group count mismatch"); | 748 | ti->error = "priority group count mismatch"; |
750 | r = -EINVAL; | 749 | r = -EINVAL; |
751 | goto bad; | 750 | goto bad; |
752 | } | 751 | } |
@@ -807,7 +806,7 @@ static int fail_path(struct pgpath *pgpath) | |||
807 | if (!pgpath->path.is_active) | 806 | if (!pgpath->path.is_active) |
808 | goto out; | 807 | goto out; |
809 | 808 | ||
810 | DMWARN("dm-multipath: Failing path %s.", pgpath->path.dev->name); | 809 | DMWARN("Failing path %s.", pgpath->path.dev->name); |
811 | 810 | ||
812 | pgpath->pg->ps.type->fail_path(&pgpath->pg->ps, &pgpath->path); | 811 | pgpath->pg->ps.type->fail_path(&pgpath->pg->ps, &pgpath->path); |
813 | pgpath->path.is_active = 0; | 812 | pgpath->path.is_active = 0; |
@@ -1250,7 +1249,7 @@ static int multipath_message(struct dm_target *ti, unsigned argc, char **argv) | |||
1250 | r = dm_get_device(ti, argv[1], ti->begin, ti->len, | 1249 | r = dm_get_device(ti, argv[1], ti->begin, ti->len, |
1251 | dm_table_get_mode(ti->table), &dev); | 1250 | dm_table_get_mode(ti->table), &dev); |
1252 | if (r) { | 1251 | if (r) { |
1253 | DMWARN("dm-multipath message: error getting device %s", | 1252 | DMWARN("message: error getting device %s", |
1254 | argv[1]); | 1253 | argv[1]); |
1255 | return -EINVAL; | 1254 | return -EINVAL; |
1256 | } | 1255 | } |
@@ -1309,7 +1308,7 @@ static int __init dm_multipath_init(void) | |||
1309 | return -ENOMEM; | 1308 | return -ENOMEM; |
1310 | } | 1309 | } |
1311 | 1310 | ||
1312 | DMINFO("dm-multipath version %u.%u.%u loaded", | 1311 | DMINFO("version %u.%u.%u loaded", |
1313 | multipath_target.version[0], multipath_target.version[1], | 1312 | multipath_target.version[0], multipath_target.version[1], |
1314 | multipath_target.version[2]); | 1313 | multipath_target.version[2]); |
1315 | 1314 | ||
diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c index d12cf3e5e076..be48cedf986b 100644 --- a/drivers/md/dm-raid1.c +++ b/drivers/md/dm-raid1.c | |||
@@ -20,6 +20,8 @@ | |||
20 | #include <linux/vmalloc.h> | 20 | #include <linux/vmalloc.h> |
21 | #include <linux/workqueue.h> | 21 | #include <linux/workqueue.h> |
22 | 22 | ||
23 | #define DM_MSG_PREFIX "raid1" | ||
24 | |||
23 | static struct workqueue_struct *_kmirrord_wq; | 25 | static struct workqueue_struct *_kmirrord_wq; |
24 | static struct work_struct _kmirrord_work; | 26 | static struct work_struct _kmirrord_work; |
25 | 27 | ||
@@ -106,12 +108,42 @@ struct region { | |||
106 | struct bio_list delayed_bios; | 108 | struct bio_list delayed_bios; |
107 | }; | 109 | }; |
108 | 110 | ||
111 | |||
112 | /*----------------------------------------------------------------- | ||
113 | * Mirror set structures. | ||
114 | *---------------------------------------------------------------*/ | ||
115 | struct mirror { | ||
116 | atomic_t error_count; | ||
117 | struct dm_dev *dev; | ||
118 | sector_t offset; | ||
119 | }; | ||
120 | |||
121 | struct mirror_set { | ||
122 | struct dm_target *ti; | ||
123 | struct list_head list; | ||
124 | struct region_hash rh; | ||
125 | struct kcopyd_client *kcopyd_client; | ||
126 | |||
127 | spinlock_t lock; /* protects the next two lists */ | ||
128 | struct bio_list reads; | ||
129 | struct bio_list writes; | ||
130 | |||
131 | /* recovery */ | ||
132 | region_t nr_regions; | ||
133 | int in_sync; | ||
134 | |||
135 | struct mirror *default_mirror; /* Default mirror */ | ||
136 | |||
137 | unsigned int nr_mirrors; | ||
138 | struct mirror mirror[0]; | ||
139 | }; | ||
140 | |||
109 | /* | 141 | /* |
110 | * Conversion fns | 142 | * Conversion fns |
111 | */ | 143 | */ |
112 | static inline region_t bio_to_region(struct region_hash *rh, struct bio *bio) | 144 | static inline region_t bio_to_region(struct region_hash *rh, struct bio *bio) |
113 | { | 145 | { |
114 | return bio->bi_sector >> rh->region_shift; | 146 | return (bio->bi_sector - rh->ms->ti->begin) >> rh->region_shift; |
115 | } | 147 | } |
116 | 148 | ||
117 | static inline sector_t region_to_sector(struct region_hash *rh, region_t region) | 149 | static inline sector_t region_to_sector(struct region_hash *rh, region_t region) |
@@ -458,11 +490,9 @@ static int __rh_recovery_prepare(struct region_hash *rh) | |||
458 | /* Already quiesced ? */ | 490 | /* Already quiesced ? */ |
459 | if (atomic_read(®->pending)) | 491 | if (atomic_read(®->pending)) |
460 | list_del_init(®->list); | 492 | list_del_init(®->list); |
493 | else | ||
494 | list_move(®->list, &rh->quiesced_regions); | ||
461 | 495 | ||
462 | else { | ||
463 | list_del_init(®->list); | ||
464 | list_add(®->list, &rh->quiesced_regions); | ||
465 | } | ||
466 | spin_unlock_irq(&rh->region_lock); | 496 | spin_unlock_irq(&rh->region_lock); |
467 | 497 | ||
468 | return 1; | 498 | return 1; |
@@ -541,35 +571,6 @@ static void rh_start_recovery(struct region_hash *rh) | |||
541 | wake(); | 571 | wake(); |
542 | } | 572 | } |
543 | 573 | ||
544 | /*----------------------------------------------------------------- | ||
545 | * Mirror set structures. | ||
546 | *---------------------------------------------------------------*/ | ||
547 | struct mirror { | ||
548 | atomic_t error_count; | ||
549 | struct dm_dev *dev; | ||
550 | sector_t offset; | ||
551 | }; | ||
552 | |||
553 | struct mirror_set { | ||
554 | struct dm_target *ti; | ||
555 | struct list_head list; | ||
556 | struct region_hash rh; | ||
557 | struct kcopyd_client *kcopyd_client; | ||
558 | |||
559 | spinlock_t lock; /* protects the next two lists */ | ||
560 | struct bio_list reads; | ||
561 | struct bio_list writes; | ||
562 | |||
563 | /* recovery */ | ||
564 | region_t nr_regions; | ||
565 | int in_sync; | ||
566 | |||
567 | struct mirror *default_mirror; /* Default mirror */ | ||
568 | |||
569 | unsigned int nr_mirrors; | ||
570 | struct mirror mirror[0]; | ||
571 | }; | ||
572 | |||
573 | /* | 574 | /* |
574 | * Every mirror should look like this one. | 575 | * Every mirror should look like this one. |
575 | */ | 576 | */ |
@@ -603,7 +604,7 @@ static void recovery_complete(int read_err, unsigned int write_err, | |||
603 | struct region *reg = (struct region *) context; | 604 | struct region *reg = (struct region *) context; |
604 | 605 | ||
605 | /* FIXME: better error handling */ | 606 | /* FIXME: better error handling */ |
606 | rh_recovery_end(reg, read_err || write_err); | 607 | rh_recovery_end(reg, !(read_err || write_err)); |
607 | } | 608 | } |
608 | 609 | ||
609 | static int recover(struct mirror_set *ms, struct region *reg) | 610 | static int recover(struct mirror_set *ms, struct region *reg) |
@@ -893,7 +894,7 @@ static struct mirror_set *alloc_context(unsigned int nr_mirrors, | |||
893 | 894 | ||
894 | ms = kmalloc(len, GFP_KERNEL); | 895 | ms = kmalloc(len, GFP_KERNEL); |
895 | if (!ms) { | 896 | if (!ms) { |
896 | ti->error = "dm-mirror: Cannot allocate mirror context"; | 897 | ti->error = "Cannot allocate mirror context"; |
897 | return NULL; | 898 | return NULL; |
898 | } | 899 | } |
899 | 900 | ||
@@ -907,7 +908,7 @@ static struct mirror_set *alloc_context(unsigned int nr_mirrors, | |||
907 | ms->default_mirror = &ms->mirror[DEFAULT_MIRROR]; | 908 | ms->default_mirror = &ms->mirror[DEFAULT_MIRROR]; |
908 | 909 | ||
909 | if (rh_init(&ms->rh, ms, dl, region_size, ms->nr_regions)) { | 910 | if (rh_init(&ms->rh, ms, dl, region_size, ms->nr_regions)) { |
910 | ti->error = "dm-mirror: Error creating dirty region hash"; | 911 | ti->error = "Error creating dirty region hash"; |
911 | kfree(ms); | 912 | kfree(ms); |
912 | return NULL; | 913 | return NULL; |
913 | } | 914 | } |
@@ -937,14 +938,14 @@ static int get_mirror(struct mirror_set *ms, struct dm_target *ti, | |||
937 | unsigned long long offset; | 938 | unsigned long long offset; |
938 | 939 | ||
939 | if (sscanf(argv[1], "%llu", &offset) != 1) { | 940 | if (sscanf(argv[1], "%llu", &offset) != 1) { |
940 | ti->error = "dm-mirror: Invalid offset"; | 941 | ti->error = "Invalid offset"; |
941 | return -EINVAL; | 942 | return -EINVAL; |
942 | } | 943 | } |
943 | 944 | ||
944 | if (dm_get_device(ti, argv[0], offset, ti->len, | 945 | if (dm_get_device(ti, argv[0], offset, ti->len, |
945 | dm_table_get_mode(ti->table), | 946 | dm_table_get_mode(ti->table), |
946 | &ms->mirror[mirror].dev)) { | 947 | &ms->mirror[mirror].dev)) { |
947 | ti->error = "dm-mirror: Device lookup failure"; | 948 | ti->error = "Device lookup failure"; |
948 | return -ENXIO; | 949 | return -ENXIO; |
949 | } | 950 | } |
950 | 951 | ||
@@ -981,30 +982,30 @@ static struct dirty_log *create_dirty_log(struct dm_target *ti, | |||
981 | struct dirty_log *dl; | 982 | struct dirty_log *dl; |
982 | 983 | ||
983 | if (argc < 2) { | 984 | if (argc < 2) { |
984 | ti->error = "dm-mirror: Insufficient mirror log arguments"; | 985 | ti->error = "Insufficient mirror log arguments"; |
985 | return NULL; | 986 | return NULL; |
986 | } | 987 | } |
987 | 988 | ||
988 | if (sscanf(argv[1], "%u", ¶m_count) != 1) { | 989 | if (sscanf(argv[1], "%u", ¶m_count) != 1) { |
989 | ti->error = "dm-mirror: Invalid mirror log argument count"; | 990 | ti->error = "Invalid mirror log argument count"; |
990 | return NULL; | 991 | return NULL; |
991 | } | 992 | } |
992 | 993 | ||
993 | *args_used = 2 + param_count; | 994 | *args_used = 2 + param_count; |
994 | 995 | ||
995 | if (argc < *args_used) { | 996 | if (argc < *args_used) { |
996 | ti->error = "dm-mirror: Insufficient mirror log arguments"; | 997 | ti->error = "Insufficient mirror log arguments"; |
997 | return NULL; | 998 | return NULL; |
998 | } | 999 | } |
999 | 1000 | ||
1000 | dl = dm_create_dirty_log(argv[0], ti, param_count, argv + 2); | 1001 | dl = dm_create_dirty_log(argv[0], ti, param_count, argv + 2); |
1001 | if (!dl) { | 1002 | if (!dl) { |
1002 | ti->error = "dm-mirror: Error creating mirror dirty log"; | 1003 | ti->error = "Error creating mirror dirty log"; |
1003 | return NULL; | 1004 | return NULL; |
1004 | } | 1005 | } |
1005 | 1006 | ||
1006 | if (!_check_region_size(ti, dl->type->get_region_size(dl))) { | 1007 | if (!_check_region_size(ti, dl->type->get_region_size(dl))) { |
1007 | ti->error = "dm-mirror: Invalid region size"; | 1008 | ti->error = "Invalid region size"; |
1008 | dm_destroy_dirty_log(dl); | 1009 | dm_destroy_dirty_log(dl); |
1009 | return NULL; | 1010 | return NULL; |
1010 | } | 1011 | } |
@@ -1038,7 +1039,7 @@ static int mirror_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
1038 | 1039 | ||
1039 | if (!argc || sscanf(argv[0], "%u", &nr_mirrors) != 1 || | 1040 | if (!argc || sscanf(argv[0], "%u", &nr_mirrors) != 1 || |
1040 | nr_mirrors < 2 || nr_mirrors > KCOPYD_MAX_REGIONS + 1) { | 1041 | nr_mirrors < 2 || nr_mirrors > KCOPYD_MAX_REGIONS + 1) { |
1041 | ti->error = "dm-mirror: Invalid number of mirrors"; | 1042 | ti->error = "Invalid number of mirrors"; |
1042 | dm_destroy_dirty_log(dl); | 1043 | dm_destroy_dirty_log(dl); |
1043 | return -EINVAL; | 1044 | return -EINVAL; |
1044 | } | 1045 | } |
@@ -1046,7 +1047,7 @@ static int mirror_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
1046 | argv++, argc--; | 1047 | argv++, argc--; |
1047 | 1048 | ||
1048 | if (argc != nr_mirrors * 2) { | 1049 | if (argc != nr_mirrors * 2) { |
1049 | ti->error = "dm-mirror: Wrong number of mirror arguments"; | 1050 | ti->error = "Wrong number of mirror arguments"; |
1050 | dm_destroy_dirty_log(dl); | 1051 | dm_destroy_dirty_log(dl); |
1051 | return -EINVAL; | 1052 | return -EINVAL; |
1052 | } | 1053 | } |
@@ -1115,7 +1116,7 @@ static int mirror_map(struct dm_target *ti, struct bio *bio, | |||
1115 | struct mirror *m; | 1116 | struct mirror *m; |
1116 | struct mirror_set *ms = ti->private; | 1117 | struct mirror_set *ms = ti->private; |
1117 | 1118 | ||
1118 | map_context->ll = bio->bi_sector >> ms->rh.region_shift; | 1119 | map_context->ll = bio_to_region(&ms->rh, bio); |
1119 | 1120 | ||
1120 | if (rw == WRITE) { | 1121 | if (rw == WRITE) { |
1121 | queue_bio(ms, bio, rw); | 1122 | queue_bio(ms, bio, rw); |
@@ -1221,7 +1222,7 @@ static int mirror_status(struct dm_target *ti, status_type_t type, | |||
1221 | 1222 | ||
1222 | static struct target_type mirror_target = { | 1223 | static struct target_type mirror_target = { |
1223 | .name = "mirror", | 1224 | .name = "mirror", |
1224 | .version = {1, 0, 1}, | 1225 | .version = {1, 0, 2}, |
1225 | .module = THIS_MODULE, | 1226 | .module = THIS_MODULE, |
1226 | .ctr = mirror_ctr, | 1227 | .ctr = mirror_ctr, |
1227 | .dtr = mirror_dtr, | 1228 | .dtr = mirror_dtr, |
diff --git a/drivers/md/dm-round-robin.c b/drivers/md/dm-round-robin.c index d0024865a789..c5a16c550122 100644 --- a/drivers/md/dm-round-robin.c +++ b/drivers/md/dm-round-robin.c | |||
@@ -14,6 +14,8 @@ | |||
14 | 14 | ||
15 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
16 | 16 | ||
17 | #define DM_MSG_PREFIX "multipath round-robin" | ||
18 | |||
17 | /*----------------------------------------------------------------- | 19 | /*----------------------------------------------------------------- |
18 | * Path-handling code, paths are held in lists | 20 | * Path-handling code, paths are held in lists |
19 | *---------------------------------------------------------------*/ | 21 | *---------------------------------------------------------------*/ |
@@ -191,9 +193,9 @@ static int __init dm_rr_init(void) | |||
191 | int r = dm_register_path_selector(&rr_ps); | 193 | int r = dm_register_path_selector(&rr_ps); |
192 | 194 | ||
193 | if (r < 0) | 195 | if (r < 0) |
194 | DMERR("round-robin: register failed %d", r); | 196 | DMERR("register failed %d", r); |
195 | 197 | ||
196 | DMINFO("dm-round-robin version 1.0.0 loaded"); | 198 | DMINFO("version 1.0.0 loaded"); |
197 | 199 | ||
198 | return r; | 200 | return r; |
199 | } | 201 | } |
diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c index 08312b46463a..8eea0ddbf5ec 100644 --- a/drivers/md/dm-snap.c +++ b/drivers/md/dm-snap.c | |||
@@ -23,6 +23,8 @@ | |||
23 | #include "dm-bio-list.h" | 23 | #include "dm-bio-list.h" |
24 | #include "kcopyd.h" | 24 | #include "kcopyd.h" |
25 | 25 | ||
26 | #define DM_MSG_PREFIX "snapshots" | ||
27 | |||
26 | /* | 28 | /* |
27 | * The percentage increment we will wake up users at | 29 | * The percentage increment we will wake up users at |
28 | */ | 30 | */ |
@@ -117,7 +119,7 @@ static int init_origin_hash(void) | |||
117 | _origins = kmalloc(ORIGIN_HASH_SIZE * sizeof(struct list_head), | 119 | _origins = kmalloc(ORIGIN_HASH_SIZE * sizeof(struct list_head), |
118 | GFP_KERNEL); | 120 | GFP_KERNEL); |
119 | if (!_origins) { | 121 | if (!_origins) { |
120 | DMERR("Device mapper: Snapshot: unable to allocate memory"); | 122 | DMERR("unable to allocate memory"); |
121 | return -ENOMEM; | 123 | return -ENOMEM; |
122 | } | 124 | } |
123 | 125 | ||
@@ -412,7 +414,7 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
412 | int blocksize; | 414 | int blocksize; |
413 | 415 | ||
414 | if (argc < 4) { | 416 | if (argc < 4) { |
415 | ti->error = "dm-snapshot: requires exactly 4 arguments"; | 417 | ti->error = "requires exactly 4 arguments"; |
416 | r = -EINVAL; | 418 | r = -EINVAL; |
417 | goto bad1; | 419 | goto bad1; |
418 | } | 420 | } |
@@ -530,7 +532,7 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
530 | } | 532 | } |
531 | 533 | ||
532 | ti->private = s; | 534 | ti->private = s; |
533 | ti->split_io = chunk_size; | 535 | ti->split_io = s->chunk_size; |
534 | 536 | ||
535 | return 0; | 537 | return 0; |
536 | 538 | ||
@@ -1127,7 +1129,7 @@ static int origin_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
1127 | struct dm_dev *dev; | 1129 | struct dm_dev *dev; |
1128 | 1130 | ||
1129 | if (argc != 1) { | 1131 | if (argc != 1) { |
1130 | ti->error = "dm-origin: incorrect number of arguments"; | 1132 | ti->error = "origin: incorrect number of arguments"; |
1131 | return -EINVAL; | 1133 | return -EINVAL; |
1132 | } | 1134 | } |
1133 | 1135 | ||
@@ -1204,7 +1206,7 @@ static int origin_status(struct dm_target *ti, status_type_t type, char *result, | |||
1204 | 1206 | ||
1205 | static struct target_type origin_target = { | 1207 | static struct target_type origin_target = { |
1206 | .name = "snapshot-origin", | 1208 | .name = "snapshot-origin", |
1207 | .version = {1, 1, 0}, | 1209 | .version = {1, 4, 0}, |
1208 | .module = THIS_MODULE, | 1210 | .module = THIS_MODULE, |
1209 | .ctr = origin_ctr, | 1211 | .ctr = origin_ctr, |
1210 | .dtr = origin_dtr, | 1212 | .dtr = origin_dtr, |
@@ -1215,7 +1217,7 @@ static struct target_type origin_target = { | |||
1215 | 1217 | ||
1216 | static struct target_type snapshot_target = { | 1218 | static struct target_type snapshot_target = { |
1217 | .name = "snapshot", | 1219 | .name = "snapshot", |
1218 | .version = {1, 1, 0}, | 1220 | .version = {1, 4, 0}, |
1219 | .module = THIS_MODULE, | 1221 | .module = THIS_MODULE, |
1220 | .ctr = snapshot_ctr, | 1222 | .ctr = snapshot_ctr, |
1221 | .dtr = snapshot_dtr, | 1223 | .dtr = snapshot_dtr, |
@@ -1236,7 +1238,7 @@ static int __init dm_snapshot_init(void) | |||
1236 | 1238 | ||
1237 | r = dm_register_target(&origin_target); | 1239 | r = dm_register_target(&origin_target); |
1238 | if (r < 0) { | 1240 | if (r < 0) { |
1239 | DMERR("Device mapper: Origin: register failed %d\n", r); | 1241 | DMERR("Origin target register failed %d", r); |
1240 | goto bad1; | 1242 | goto bad1; |
1241 | } | 1243 | } |
1242 | 1244 | ||
diff --git a/drivers/md/dm-stripe.c b/drivers/md/dm-stripe.c index 08328a8f5a3c..6c29fcecd892 100644 --- a/drivers/md/dm-stripe.c +++ b/drivers/md/dm-stripe.c | |||
@@ -12,6 +12,8 @@ | |||
12 | #include <linux/bio.h> | 12 | #include <linux/bio.h> |
13 | #include <linux/slab.h> | 13 | #include <linux/slab.h> |
14 | 14 | ||
15 | #define DM_MSG_PREFIX "striped" | ||
16 | |||
15 | struct stripe { | 17 | struct stripe { |
16 | struct dm_dev *dev; | 18 | struct dm_dev *dev; |
17 | sector_t physical_start; | 19 | sector_t physical_start; |
@@ -78,19 +80,19 @@ static int stripe_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
78 | unsigned int i; | 80 | unsigned int i; |
79 | 81 | ||
80 | if (argc < 2) { | 82 | if (argc < 2) { |
81 | ti->error = "dm-stripe: Not enough arguments"; | 83 | ti->error = "Not enough arguments"; |
82 | return -EINVAL; | 84 | return -EINVAL; |
83 | } | 85 | } |
84 | 86 | ||
85 | stripes = simple_strtoul(argv[0], &end, 10); | 87 | stripes = simple_strtoul(argv[0], &end, 10); |
86 | if (*end) { | 88 | if (*end) { |
87 | ti->error = "dm-stripe: Invalid stripe count"; | 89 | ti->error = "Invalid stripe count"; |
88 | return -EINVAL; | 90 | return -EINVAL; |
89 | } | 91 | } |
90 | 92 | ||
91 | chunk_size = simple_strtoul(argv[1], &end, 10); | 93 | chunk_size = simple_strtoul(argv[1], &end, 10); |
92 | if (*end) { | 94 | if (*end) { |
93 | ti->error = "dm-stripe: Invalid chunk_size"; | 95 | ti->error = "Invalid chunk_size"; |
94 | return -EINVAL; | 96 | return -EINVAL; |
95 | } | 97 | } |
96 | 98 | ||
@@ -99,19 +101,19 @@ static int stripe_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
99 | */ | 101 | */ |
100 | if (!chunk_size || (chunk_size & (chunk_size - 1)) || | 102 | if (!chunk_size || (chunk_size & (chunk_size - 1)) || |
101 | (chunk_size < (PAGE_SIZE >> SECTOR_SHIFT))) { | 103 | (chunk_size < (PAGE_SIZE >> SECTOR_SHIFT))) { |
102 | ti->error = "dm-stripe: Invalid chunk size"; | 104 | ti->error = "Invalid chunk size"; |
103 | return -EINVAL; | 105 | return -EINVAL; |
104 | } | 106 | } |
105 | 107 | ||
106 | if (ti->len & (chunk_size - 1)) { | 108 | if (ti->len & (chunk_size - 1)) { |
107 | ti->error = "dm-stripe: Target length not divisible by " | 109 | ti->error = "Target length not divisible by " |
108 | "chunk size"; | 110 | "chunk size"; |
109 | return -EINVAL; | 111 | return -EINVAL; |
110 | } | 112 | } |
111 | 113 | ||
112 | width = ti->len; | 114 | width = ti->len; |
113 | if (sector_div(width, stripes)) { | 115 | if (sector_div(width, stripes)) { |
114 | ti->error = "dm-stripe: Target length not divisible by " | 116 | ti->error = "Target length not divisible by " |
115 | "number of stripes"; | 117 | "number of stripes"; |
116 | return -EINVAL; | 118 | return -EINVAL; |
117 | } | 119 | } |
@@ -120,14 +122,14 @@ static int stripe_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
120 | * Do we have enough arguments for that many stripes ? | 122 | * Do we have enough arguments for that many stripes ? |
121 | */ | 123 | */ |
122 | if (argc != (2 + 2 * stripes)) { | 124 | if (argc != (2 + 2 * stripes)) { |
123 | ti->error = "dm-stripe: Not enough destinations " | 125 | ti->error = "Not enough destinations " |
124 | "specified"; | 126 | "specified"; |
125 | return -EINVAL; | 127 | return -EINVAL; |
126 | } | 128 | } |
127 | 129 | ||
128 | sc = alloc_context(stripes); | 130 | sc = alloc_context(stripes); |
129 | if (!sc) { | 131 | if (!sc) { |
130 | ti->error = "dm-stripe: Memory allocation for striped context " | 132 | ti->error = "Memory allocation for striped context " |
131 | "failed"; | 133 | "failed"; |
132 | return -ENOMEM; | 134 | return -ENOMEM; |
133 | } | 135 | } |
@@ -149,8 +151,7 @@ static int stripe_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
149 | 151 | ||
150 | r = get_stripe(ti, sc, i, argv); | 152 | r = get_stripe(ti, sc, i, argv); |
151 | if (r < 0) { | 153 | if (r < 0) { |
152 | ti->error = "dm-stripe: Couldn't parse stripe " | 154 | ti->error = "Couldn't parse stripe destination"; |
153 | "destination"; | ||
154 | while (i--) | 155 | while (i--) |
155 | dm_put_device(ti, sc->stripe[i].dev); | 156 | dm_put_device(ti, sc->stripe[i].dev); |
156 | kfree(sc); | 157 | kfree(sc); |
@@ -227,7 +228,7 @@ int __init dm_stripe_init(void) | |||
227 | 228 | ||
228 | r = dm_register_target(&stripe_target); | 229 | r = dm_register_target(&stripe_target); |
229 | if (r < 0) | 230 | if (r < 0) |
230 | DMWARN("striped target registration failed"); | 231 | DMWARN("target registration failed"); |
231 | 232 | ||
232 | return r; | 233 | return r; |
233 | } | 234 | } |
@@ -235,7 +236,7 @@ int __init dm_stripe_init(void) | |||
235 | void dm_stripe_exit(void) | 236 | void dm_stripe_exit(void) |
236 | { | 237 | { |
237 | if (dm_unregister_target(&stripe_target)) | 238 | if (dm_unregister_target(&stripe_target)) |
238 | DMWARN("striped target unregistration failed"); | 239 | DMWARN("target unregistration failed"); |
239 | 240 | ||
240 | return; | 241 | return; |
241 | } | 242 | } |
diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index 8f56a54cf0ce..75fe9493e6af 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c | |||
@@ -17,6 +17,8 @@ | |||
17 | #include <linux/mutex.h> | 17 | #include <linux/mutex.h> |
18 | #include <asm/atomic.h> | 18 | #include <asm/atomic.h> |
19 | 19 | ||
20 | #define DM_MSG_PREFIX "table" | ||
21 | |||
20 | #define MAX_DEPTH 16 | 22 | #define MAX_DEPTH 16 |
21 | #define NODE_SIZE L1_CACHE_BYTES | 23 | #define NODE_SIZE L1_CACHE_BYTES |
22 | #define KEYS_PER_NODE (NODE_SIZE / sizeof(sector_t)) | 24 | #define KEYS_PER_NODE (NODE_SIZE / sizeof(sector_t)) |
@@ -237,6 +239,44 @@ int dm_table_create(struct dm_table **result, int mode, | |||
237 | return 0; | 239 | return 0; |
238 | } | 240 | } |
239 | 241 | ||
242 | int dm_create_error_table(struct dm_table **result, struct mapped_device *md) | ||
243 | { | ||
244 | struct dm_table *t; | ||
245 | sector_t dev_size = 1; | ||
246 | int r; | ||
247 | |||
248 | /* | ||
249 | * Find current size of device. | ||
250 | * Default to 1 sector if inactive. | ||
251 | */ | ||
252 | t = dm_get_table(md); | ||
253 | if (t) { | ||
254 | dev_size = dm_table_get_size(t); | ||
255 | dm_table_put(t); | ||
256 | } | ||
257 | |||
258 | r = dm_table_create(&t, FMODE_READ, 1, md); | ||
259 | if (r) | ||
260 | return r; | ||
261 | |||
262 | r = dm_table_add_target(t, "error", 0, dev_size, NULL); | ||
263 | if (r) | ||
264 | goto out; | ||
265 | |||
266 | r = dm_table_complete(t); | ||
267 | if (r) | ||
268 | goto out; | ||
269 | |||
270 | *result = t; | ||
271 | |||
272 | out: | ||
273 | if (r) | ||
274 | dm_table_put(t); | ||
275 | |||
276 | return r; | ||
277 | } | ||
278 | EXPORT_SYMBOL_GPL(dm_create_error_table); | ||
279 | |||
240 | static void free_devices(struct list_head *devices) | 280 | static void free_devices(struct list_head *devices) |
241 | { | 281 | { |
242 | struct list_head *tmp, *next; | 282 | struct list_head *tmp, *next; |
@@ -590,6 +630,12 @@ int dm_split_args(int *argc, char ***argvp, char *input) | |||
590 | unsigned array_size = 0; | 630 | unsigned array_size = 0; |
591 | 631 | ||
592 | *argc = 0; | 632 | *argc = 0; |
633 | |||
634 | if (!input) { | ||
635 | *argvp = NULL; | ||
636 | return 0; | ||
637 | } | ||
638 | |||
593 | argv = realloc_argv(&array_size, argv); | 639 | argv = realloc_argv(&array_size, argv); |
594 | if (!argv) | 640 | if (!argv) |
595 | return -ENOMEM; | 641 | return -ENOMEM; |
@@ -671,15 +717,14 @@ int dm_table_add_target(struct dm_table *t, const char *type, | |||
671 | memset(tgt, 0, sizeof(*tgt)); | 717 | memset(tgt, 0, sizeof(*tgt)); |
672 | 718 | ||
673 | if (!len) { | 719 | if (!len) { |
674 | tgt->error = "zero-length target"; | 720 | DMERR("%s: zero-length target", dm_device_name(t->md)); |
675 | DMERR("%s", tgt->error); | ||
676 | return -EINVAL; | 721 | return -EINVAL; |
677 | } | 722 | } |
678 | 723 | ||
679 | tgt->type = dm_get_target_type(type); | 724 | tgt->type = dm_get_target_type(type); |
680 | if (!tgt->type) { | 725 | if (!tgt->type) { |
681 | tgt->error = "unknown target type"; | 726 | DMERR("%s: %s: unknown target type", dm_device_name(t->md), |
682 | DMERR("%s", tgt->error); | 727 | type); |
683 | return -EINVAL; | 728 | return -EINVAL; |
684 | } | 729 | } |
685 | 730 | ||
@@ -716,7 +761,7 @@ int dm_table_add_target(struct dm_table *t, const char *type, | |||
716 | return 0; | 761 | return 0; |
717 | 762 | ||
718 | bad: | 763 | bad: |
719 | DMERR("%s", tgt->error); | 764 | DMERR("%s: %s: %s", dm_device_name(t->md), type, tgt->error); |
720 | dm_put_target_type(tgt->type); | 765 | dm_put_target_type(tgt->type); |
721 | return r; | 766 | return r; |
722 | } | 767 | } |
@@ -802,7 +847,7 @@ sector_t dm_table_get_size(struct dm_table *t) | |||
802 | 847 | ||
803 | struct dm_target *dm_table_get_target(struct dm_table *t, unsigned int index) | 848 | struct dm_target *dm_table_get_target(struct dm_table *t, unsigned int index) |
804 | { | 849 | { |
805 | if (index > t->num_targets) | 850 | if (index >= t->num_targets) |
806 | return NULL; | 851 | return NULL; |
807 | 852 | ||
808 | return t->targets + index; | 853 | return t->targets + index; |
diff --git a/drivers/md/dm-target.c b/drivers/md/dm-target.c index 64fd8e79ea4c..477a041a41cf 100644 --- a/drivers/md/dm-target.c +++ b/drivers/md/dm-target.c | |||
@@ -12,6 +12,8 @@ | |||
12 | #include <linux/bio.h> | 12 | #include <linux/bio.h> |
13 | #include <linux/slab.h> | 13 | #include <linux/slab.h> |
14 | 14 | ||
15 | #define DM_MSG_PREFIX "target" | ||
16 | |||
15 | struct tt_internal { | 17 | struct tt_internal { |
16 | struct target_type tt; | 18 | struct target_type tt; |
17 | 19 | ||
diff --git a/drivers/md/dm-zero.c b/drivers/md/dm-zero.c index 51c0639b2487..ea569f7348d2 100644 --- a/drivers/md/dm-zero.c +++ b/drivers/md/dm-zero.c | |||
@@ -10,13 +10,15 @@ | |||
10 | #include <linux/init.h> | 10 | #include <linux/init.h> |
11 | #include <linux/bio.h> | 11 | #include <linux/bio.h> |
12 | 12 | ||
13 | #define DM_MSG_PREFIX "zero" | ||
14 | |||
13 | /* | 15 | /* |
14 | * Construct a dummy mapping that only returns zeros | 16 | * Construct a dummy mapping that only returns zeros |
15 | */ | 17 | */ |
16 | static int zero_ctr(struct dm_target *ti, unsigned int argc, char **argv) | 18 | static int zero_ctr(struct dm_target *ti, unsigned int argc, char **argv) |
17 | { | 19 | { |
18 | if (argc != 0) { | 20 | if (argc != 0) { |
19 | ti->error = "dm-zero: No arguments required"; | 21 | ti->error = "No arguments required"; |
20 | return -EINVAL; | 22 | return -EINVAL; |
21 | } | 23 | } |
22 | 24 | ||
@@ -60,7 +62,7 @@ static int __init dm_zero_init(void) | |||
60 | int r = dm_register_target(&zero_target); | 62 | int r = dm_register_target(&zero_target); |
61 | 63 | ||
62 | if (r < 0) | 64 | if (r < 0) |
63 | DMERR("zero: register failed %d", r); | 65 | DMERR("register failed %d", r); |
64 | 66 | ||
65 | return r; | 67 | return r; |
66 | } | 68 | } |
@@ -70,7 +72,7 @@ static void __exit dm_zero_exit(void) | |||
70 | int r = dm_unregister_target(&zero_target); | 72 | int r = dm_unregister_target(&zero_target); |
71 | 73 | ||
72 | if (r < 0) | 74 | if (r < 0) |
73 | DMERR("zero: unregister failed %d", r); | 75 | DMERR("unregister failed %d", r); |
74 | } | 76 | } |
75 | 77 | ||
76 | module_init(dm_zero_init) | 78 | module_init(dm_zero_init) |
diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 4d710b7a133b..3ed2e53b9eb6 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2001, 2002 Sistina Software (UK) Limited. | 2 | * Copyright (C) 2001, 2002 Sistina Software (UK) Limited. |
3 | * Copyright (C) 2004 Red Hat, Inc. All rights reserved. | 3 | * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. |
4 | * | 4 | * |
5 | * This file is released under the GPL. | 5 | * This file is released under the GPL. |
6 | */ | 6 | */ |
@@ -21,11 +21,14 @@ | |||
21 | #include <linux/hdreg.h> | 21 | #include <linux/hdreg.h> |
22 | #include <linux/blktrace_api.h> | 22 | #include <linux/blktrace_api.h> |
23 | 23 | ||
24 | #define DM_MSG_PREFIX "core" | ||
25 | |||
24 | static const char *_name = DM_NAME; | 26 | static const char *_name = DM_NAME; |
25 | 27 | ||
26 | static unsigned int major = 0; | 28 | static unsigned int major = 0; |
27 | static unsigned int _major = 0; | 29 | static unsigned int _major = 0; |
28 | 30 | ||
31 | static DEFINE_SPINLOCK(_minor_lock); | ||
29 | /* | 32 | /* |
30 | * One of these is allocated per bio. | 33 | * One of these is allocated per bio. |
31 | */ | 34 | */ |
@@ -49,23 +52,28 @@ struct target_io { | |||
49 | 52 | ||
50 | union map_info *dm_get_mapinfo(struct bio *bio) | 53 | union map_info *dm_get_mapinfo(struct bio *bio) |
51 | { | 54 | { |
52 | if (bio && bio->bi_private) | 55 | if (bio && bio->bi_private) |
53 | return &((struct target_io *)bio->bi_private)->info; | 56 | return &((struct target_io *)bio->bi_private)->info; |
54 | return NULL; | 57 | return NULL; |
55 | } | 58 | } |
56 | 59 | ||
60 | #define MINOR_ALLOCED ((void *)-1) | ||
61 | |||
57 | /* | 62 | /* |
58 | * Bits for the md->flags field. | 63 | * Bits for the md->flags field. |
59 | */ | 64 | */ |
60 | #define DMF_BLOCK_IO 0 | 65 | #define DMF_BLOCK_IO 0 |
61 | #define DMF_SUSPENDED 1 | 66 | #define DMF_SUSPENDED 1 |
62 | #define DMF_FROZEN 2 | 67 | #define DMF_FROZEN 2 |
68 | #define DMF_FREEING 3 | ||
69 | #define DMF_DELETING 4 | ||
63 | 70 | ||
64 | struct mapped_device { | 71 | struct mapped_device { |
65 | struct rw_semaphore io_lock; | 72 | struct rw_semaphore io_lock; |
66 | struct semaphore suspend_lock; | 73 | struct semaphore suspend_lock; |
67 | rwlock_t map_lock; | 74 | rwlock_t map_lock; |
68 | atomic_t holders; | 75 | atomic_t holders; |
76 | atomic_t open_count; | ||
69 | 77 | ||
70 | unsigned long flags; | 78 | unsigned long flags; |
71 | 79 | ||
@@ -218,9 +226,25 @@ static int dm_blk_open(struct inode *inode, struct file *file) | |||
218 | { | 226 | { |
219 | struct mapped_device *md; | 227 | struct mapped_device *md; |
220 | 228 | ||
229 | spin_lock(&_minor_lock); | ||
230 | |||
221 | md = inode->i_bdev->bd_disk->private_data; | 231 | md = inode->i_bdev->bd_disk->private_data; |
232 | if (!md) | ||
233 | goto out; | ||
234 | |||
235 | if (test_bit(DMF_FREEING, &md->flags) || | ||
236 | test_bit(DMF_DELETING, &md->flags)) { | ||
237 | md = NULL; | ||
238 | goto out; | ||
239 | } | ||
240 | |||
222 | dm_get(md); | 241 | dm_get(md); |
223 | return 0; | 242 | atomic_inc(&md->open_count); |
243 | |||
244 | out: | ||
245 | spin_unlock(&_minor_lock); | ||
246 | |||
247 | return md ? 0 : -ENXIO; | ||
224 | } | 248 | } |
225 | 249 | ||
226 | static int dm_blk_close(struct inode *inode, struct file *file) | 250 | static int dm_blk_close(struct inode *inode, struct file *file) |
@@ -228,10 +252,35 @@ static int dm_blk_close(struct inode *inode, struct file *file) | |||
228 | struct mapped_device *md; | 252 | struct mapped_device *md; |
229 | 253 | ||
230 | md = inode->i_bdev->bd_disk->private_data; | 254 | md = inode->i_bdev->bd_disk->private_data; |
255 | atomic_dec(&md->open_count); | ||
231 | dm_put(md); | 256 | dm_put(md); |
232 | return 0; | 257 | return 0; |
233 | } | 258 | } |
234 | 259 | ||
260 | int dm_open_count(struct mapped_device *md) | ||
261 | { | ||
262 | return atomic_read(&md->open_count); | ||
263 | } | ||
264 | |||
265 | /* | ||
266 | * Guarantees nothing is using the device before it's deleted. | ||
267 | */ | ||
268 | int dm_lock_for_deletion(struct mapped_device *md) | ||
269 | { | ||
270 | int r = 0; | ||
271 | |||
272 | spin_lock(&_minor_lock); | ||
273 | |||
274 | if (dm_open_count(md)) | ||
275 | r = -EBUSY; | ||
276 | else | ||
277 | set_bit(DMF_DELETING, &md->flags); | ||
278 | |||
279 | spin_unlock(&_minor_lock); | ||
280 | |||
281 | return r; | ||
282 | } | ||
283 | |||
235 | static int dm_blk_getgeo(struct block_device *bdev, struct hd_geometry *geo) | 284 | static int dm_blk_getgeo(struct block_device *bdev, struct hd_geometry *geo) |
236 | { | 285 | { |
237 | struct mapped_device *md = bdev->bd_disk->private_data; | 286 | struct mapped_device *md = bdev->bd_disk->private_data; |
@@ -456,8 +505,8 @@ static void __map_bio(struct dm_target *ti, struct bio *clone, | |||
456 | if (r > 0) { | 505 | if (r > 0) { |
457 | /* the bio has been remapped so dispatch it */ | 506 | /* the bio has been remapped so dispatch it */ |
458 | 507 | ||
459 | blk_add_trace_remap(bdev_get_queue(clone->bi_bdev), clone, | 508 | blk_add_trace_remap(bdev_get_queue(clone->bi_bdev), clone, |
460 | tio->io->bio->bi_bdev->bd_dev, sector, | 509 | tio->io->bio->bi_bdev->bd_dev, sector, |
461 | clone->bi_sector); | 510 | clone->bi_sector); |
462 | 511 | ||
463 | generic_make_request(clone); | 512 | generic_make_request(clone); |
@@ -744,43 +793,39 @@ static int dm_any_congested(void *congested_data, int bdi_bits) | |||
744 | /*----------------------------------------------------------------- | 793 | /*----------------------------------------------------------------- |
745 | * An IDR is used to keep track of allocated minor numbers. | 794 | * An IDR is used to keep track of allocated minor numbers. |
746 | *---------------------------------------------------------------*/ | 795 | *---------------------------------------------------------------*/ |
747 | static DEFINE_MUTEX(_minor_lock); | ||
748 | static DEFINE_IDR(_minor_idr); | 796 | static DEFINE_IDR(_minor_idr); |
749 | 797 | ||
750 | static void free_minor(unsigned int minor) | 798 | static void free_minor(int minor) |
751 | { | 799 | { |
752 | mutex_lock(&_minor_lock); | 800 | spin_lock(&_minor_lock); |
753 | idr_remove(&_minor_idr, minor); | 801 | idr_remove(&_minor_idr, minor); |
754 | mutex_unlock(&_minor_lock); | 802 | spin_unlock(&_minor_lock); |
755 | } | 803 | } |
756 | 804 | ||
757 | /* | 805 | /* |
758 | * See if the device with a specific minor # is free. | 806 | * See if the device with a specific minor # is free. |
759 | */ | 807 | */ |
760 | static int specific_minor(struct mapped_device *md, unsigned int minor) | 808 | static int specific_minor(struct mapped_device *md, int minor) |
761 | { | 809 | { |
762 | int r, m; | 810 | int r, m; |
763 | 811 | ||
764 | if (minor >= (1 << MINORBITS)) | 812 | if (minor >= (1 << MINORBITS)) |
765 | return -EINVAL; | 813 | return -EINVAL; |
766 | 814 | ||
767 | mutex_lock(&_minor_lock); | 815 | r = idr_pre_get(&_minor_idr, GFP_KERNEL); |
816 | if (!r) | ||
817 | return -ENOMEM; | ||
818 | |||
819 | spin_lock(&_minor_lock); | ||
768 | 820 | ||
769 | if (idr_find(&_minor_idr, minor)) { | 821 | if (idr_find(&_minor_idr, minor)) { |
770 | r = -EBUSY; | 822 | r = -EBUSY; |
771 | goto out; | 823 | goto out; |
772 | } | 824 | } |
773 | 825 | ||
774 | r = idr_pre_get(&_minor_idr, GFP_KERNEL); | 826 | r = idr_get_new_above(&_minor_idr, MINOR_ALLOCED, minor, &m); |
775 | if (!r) { | 827 | if (r) |
776 | r = -ENOMEM; | ||
777 | goto out; | ||
778 | } | ||
779 | |||
780 | r = idr_get_new_above(&_minor_idr, md, minor, &m); | ||
781 | if (r) { | ||
782 | goto out; | 828 | goto out; |
783 | } | ||
784 | 829 | ||
785 | if (m != minor) { | 830 | if (m != minor) { |
786 | idr_remove(&_minor_idr, m); | 831 | idr_remove(&_minor_idr, m); |
@@ -789,24 +834,21 @@ static int specific_minor(struct mapped_device *md, unsigned int minor) | |||
789 | } | 834 | } |
790 | 835 | ||
791 | out: | 836 | out: |
792 | mutex_unlock(&_minor_lock); | 837 | spin_unlock(&_minor_lock); |
793 | return r; | 838 | return r; |
794 | } | 839 | } |
795 | 840 | ||
796 | static int next_free_minor(struct mapped_device *md, unsigned int *minor) | 841 | static int next_free_minor(struct mapped_device *md, int *minor) |
797 | { | 842 | { |
798 | int r; | 843 | int r, m; |
799 | unsigned int m; | ||
800 | |||
801 | mutex_lock(&_minor_lock); | ||
802 | 844 | ||
803 | r = idr_pre_get(&_minor_idr, GFP_KERNEL); | 845 | r = idr_pre_get(&_minor_idr, GFP_KERNEL); |
804 | if (!r) { | 846 | if (!r) |
805 | r = -ENOMEM; | 847 | return -ENOMEM; |
806 | goto out; | 848 | |
807 | } | 849 | spin_lock(&_minor_lock); |
808 | 850 | ||
809 | r = idr_get_new(&_minor_idr, md, &m); | 851 | r = idr_get_new(&_minor_idr, MINOR_ALLOCED, &m); |
810 | if (r) { | 852 | if (r) { |
811 | goto out; | 853 | goto out; |
812 | } | 854 | } |
@@ -820,7 +862,7 @@ static int next_free_minor(struct mapped_device *md, unsigned int *minor) | |||
820 | *minor = m; | 862 | *minor = m; |
821 | 863 | ||
822 | out: | 864 | out: |
823 | mutex_unlock(&_minor_lock); | 865 | spin_unlock(&_minor_lock); |
824 | return r; | 866 | return r; |
825 | } | 867 | } |
826 | 868 | ||
@@ -829,18 +871,25 @@ static struct block_device_operations dm_blk_dops; | |||
829 | /* | 871 | /* |
830 | * Allocate and initialise a blank device with a given minor. | 872 | * Allocate and initialise a blank device with a given minor. |
831 | */ | 873 | */ |
832 | static struct mapped_device *alloc_dev(unsigned int minor, int persistent) | 874 | static struct mapped_device *alloc_dev(int minor) |
833 | { | 875 | { |
834 | int r; | 876 | int r; |
835 | struct mapped_device *md = kmalloc(sizeof(*md), GFP_KERNEL); | 877 | struct mapped_device *md = kmalloc(sizeof(*md), GFP_KERNEL); |
878 | void *old_md; | ||
836 | 879 | ||
837 | if (!md) { | 880 | if (!md) { |
838 | DMWARN("unable to allocate device, out of memory."); | 881 | DMWARN("unable to allocate device, out of memory."); |
839 | return NULL; | 882 | return NULL; |
840 | } | 883 | } |
841 | 884 | ||
885 | if (!try_module_get(THIS_MODULE)) | ||
886 | goto bad0; | ||
887 | |||
842 | /* get a minor number for the dev */ | 888 | /* get a minor number for the dev */ |
843 | r = persistent ? specific_minor(md, minor) : next_free_minor(md, &minor); | 889 | if (minor == DM_ANY_MINOR) |
890 | r = next_free_minor(md, &minor); | ||
891 | else | ||
892 | r = specific_minor(md, minor); | ||
844 | if (r < 0) | 893 | if (r < 0) |
845 | goto bad1; | 894 | goto bad1; |
846 | 895 | ||
@@ -849,6 +898,7 @@ static struct mapped_device *alloc_dev(unsigned int minor, int persistent) | |||
849 | init_MUTEX(&md->suspend_lock); | 898 | init_MUTEX(&md->suspend_lock); |
850 | rwlock_init(&md->map_lock); | 899 | rwlock_init(&md->map_lock); |
851 | atomic_set(&md->holders, 1); | 900 | atomic_set(&md->holders, 1); |
901 | atomic_set(&md->open_count, 0); | ||
852 | atomic_set(&md->event_nr, 0); | 902 | atomic_set(&md->event_nr, 0); |
853 | 903 | ||
854 | md->queue = blk_alloc_queue(GFP_KERNEL); | 904 | md->queue = blk_alloc_queue(GFP_KERNEL); |
@@ -875,6 +925,10 @@ static struct mapped_device *alloc_dev(unsigned int minor, int persistent) | |||
875 | if (!md->disk) | 925 | if (!md->disk) |
876 | goto bad4; | 926 | goto bad4; |
877 | 927 | ||
928 | atomic_set(&md->pending, 0); | ||
929 | init_waitqueue_head(&md->wait); | ||
930 | init_waitqueue_head(&md->eventq); | ||
931 | |||
878 | md->disk->major = _major; | 932 | md->disk->major = _major; |
879 | md->disk->first_minor = minor; | 933 | md->disk->first_minor = minor; |
880 | md->disk->fops = &dm_blk_dops; | 934 | md->disk->fops = &dm_blk_dops; |
@@ -884,9 +938,12 @@ static struct mapped_device *alloc_dev(unsigned int minor, int persistent) | |||
884 | add_disk(md->disk); | 938 | add_disk(md->disk); |
885 | format_dev_t(md->name, MKDEV(_major, minor)); | 939 | format_dev_t(md->name, MKDEV(_major, minor)); |
886 | 940 | ||
887 | atomic_set(&md->pending, 0); | 941 | /* Populate the mapping, nobody knows we exist yet */ |
888 | init_waitqueue_head(&md->wait); | 942 | spin_lock(&_minor_lock); |
889 | init_waitqueue_head(&md->eventq); | 943 | old_md = idr_replace(&_minor_idr, md, minor); |
944 | spin_unlock(&_minor_lock); | ||
945 | |||
946 | BUG_ON(old_md != MINOR_ALLOCED); | ||
890 | 947 | ||
891 | return md; | 948 | return md; |
892 | 949 | ||
@@ -898,13 +955,15 @@ static struct mapped_device *alloc_dev(unsigned int minor, int persistent) | |||
898 | blk_cleanup_queue(md->queue); | 955 | blk_cleanup_queue(md->queue); |
899 | free_minor(minor); | 956 | free_minor(minor); |
900 | bad1: | 957 | bad1: |
958 | module_put(THIS_MODULE); | ||
959 | bad0: | ||
901 | kfree(md); | 960 | kfree(md); |
902 | return NULL; | 961 | return NULL; |
903 | } | 962 | } |
904 | 963 | ||
905 | static void free_dev(struct mapped_device *md) | 964 | static void free_dev(struct mapped_device *md) |
906 | { | 965 | { |
907 | unsigned int minor = md->disk->first_minor; | 966 | int minor = md->disk->first_minor; |
908 | 967 | ||
909 | if (md->suspended_bdev) { | 968 | if (md->suspended_bdev) { |
910 | thaw_bdev(md->suspended_bdev, NULL); | 969 | thaw_bdev(md->suspended_bdev, NULL); |
@@ -914,8 +973,14 @@ static void free_dev(struct mapped_device *md) | |||
914 | mempool_destroy(md->io_pool); | 973 | mempool_destroy(md->io_pool); |
915 | del_gendisk(md->disk); | 974 | del_gendisk(md->disk); |
916 | free_minor(minor); | 975 | free_minor(minor); |
976 | |||
977 | spin_lock(&_minor_lock); | ||
978 | md->disk->private_data = NULL; | ||
979 | spin_unlock(&_minor_lock); | ||
980 | |||
917 | put_disk(md->disk); | 981 | put_disk(md->disk); |
918 | blk_cleanup_queue(md->queue); | 982 | blk_cleanup_queue(md->queue); |
983 | module_put(THIS_MODULE); | ||
919 | kfree(md); | 984 | kfree(md); |
920 | } | 985 | } |
921 | 986 | ||
@@ -984,12 +1049,11 @@ static void __unbind(struct mapped_device *md) | |||
984 | /* | 1049 | /* |
985 | * Constructor for a new device. | 1050 | * Constructor for a new device. |
986 | */ | 1051 | */ |
987 | static int create_aux(unsigned int minor, int persistent, | 1052 | int dm_create(int minor, struct mapped_device **result) |
988 | struct mapped_device **result) | ||
989 | { | 1053 | { |
990 | struct mapped_device *md; | 1054 | struct mapped_device *md; |
991 | 1055 | ||
992 | md = alloc_dev(minor, persistent); | 1056 | md = alloc_dev(minor); |
993 | if (!md) | 1057 | if (!md) |
994 | return -ENXIO; | 1058 | return -ENXIO; |
995 | 1059 | ||
@@ -997,16 +1061,6 @@ static int create_aux(unsigned int minor, int persistent, | |||
997 | return 0; | 1061 | return 0; |
998 | } | 1062 | } |
999 | 1063 | ||
1000 | int dm_create(struct mapped_device **result) | ||
1001 | { | ||
1002 | return create_aux(0, 0, result); | ||
1003 | } | ||
1004 | |||
1005 | int dm_create_with_minor(unsigned int minor, struct mapped_device **result) | ||
1006 | { | ||
1007 | return create_aux(minor, 1, result); | ||
1008 | } | ||
1009 | |||
1010 | static struct mapped_device *dm_find_md(dev_t dev) | 1064 | static struct mapped_device *dm_find_md(dev_t dev) |
1011 | { | 1065 | { |
1012 | struct mapped_device *md; | 1066 | struct mapped_device *md; |
@@ -1015,13 +1069,18 @@ static struct mapped_device *dm_find_md(dev_t dev) | |||
1015 | if (MAJOR(dev) != _major || minor >= (1 << MINORBITS)) | 1069 | if (MAJOR(dev) != _major || minor >= (1 << MINORBITS)) |
1016 | return NULL; | 1070 | return NULL; |
1017 | 1071 | ||
1018 | mutex_lock(&_minor_lock); | 1072 | spin_lock(&_minor_lock); |
1019 | 1073 | ||
1020 | md = idr_find(&_minor_idr, minor); | 1074 | md = idr_find(&_minor_idr, minor); |
1021 | if (!md || (dm_disk(md)->first_minor != minor)) | 1075 | if (md && (md == MINOR_ALLOCED || |
1076 | (dm_disk(md)->first_minor != minor) || | ||
1077 | test_bit(DMF_FREEING, &md->flags))) { | ||
1022 | md = NULL; | 1078 | md = NULL; |
1079 | goto out; | ||
1080 | } | ||
1023 | 1081 | ||
1024 | mutex_unlock(&_minor_lock); | 1082 | out: |
1083 | spin_unlock(&_minor_lock); | ||
1025 | 1084 | ||
1026 | return md; | 1085 | return md; |
1027 | } | 1086 | } |
@@ -1051,12 +1110,23 @@ void dm_get(struct mapped_device *md) | |||
1051 | atomic_inc(&md->holders); | 1110 | atomic_inc(&md->holders); |
1052 | } | 1111 | } |
1053 | 1112 | ||
1113 | const char *dm_device_name(struct mapped_device *md) | ||
1114 | { | ||
1115 | return md->name; | ||
1116 | } | ||
1117 | EXPORT_SYMBOL_GPL(dm_device_name); | ||
1118 | |||
1054 | void dm_put(struct mapped_device *md) | 1119 | void dm_put(struct mapped_device *md) |
1055 | { | 1120 | { |
1056 | struct dm_table *map; | 1121 | struct dm_table *map; |
1057 | 1122 | ||
1058 | if (atomic_dec_and_test(&md->holders)) { | 1123 | BUG_ON(test_bit(DMF_FREEING, &md->flags)); |
1124 | |||
1125 | if (atomic_dec_and_lock(&md->holders, &_minor_lock)) { | ||
1059 | map = dm_get_table(md); | 1126 | map = dm_get_table(md); |
1127 | idr_replace(&_minor_idr, MINOR_ALLOCED, dm_disk(md)->first_minor); | ||
1128 | set_bit(DMF_FREEING, &md->flags); | ||
1129 | spin_unlock(&_minor_lock); | ||
1060 | if (!dm_suspended(md)) { | 1130 | if (!dm_suspended(md)) { |
1061 | dm_table_presuspend_targets(map); | 1131 | dm_table_presuspend_targets(map); |
1062 | dm_table_postsuspend_targets(map); | 1132 | dm_table_postsuspend_targets(map); |
diff --git a/drivers/md/dm.h b/drivers/md/dm.h index fd90bc8f9e45..3c03c0ecab7e 100644 --- a/drivers/md/dm.h +++ b/drivers/md/dm.h | |||
@@ -2,7 +2,7 @@ | |||
2 | * Internal header file for device mapper | 2 | * Internal header file for device mapper |
3 | * | 3 | * |
4 | * Copyright (C) 2001, 2002 Sistina Software | 4 | * Copyright (C) 2001, 2002 Sistina Software |
5 | * Copyright (C) 2004 Red Hat, Inc. All rights reserved. | 5 | * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. |
6 | * | 6 | * |
7 | * This file is released under the LGPL. | 7 | * This file is released under the LGPL. |
8 | */ | 8 | */ |
@@ -17,9 +17,10 @@ | |||
17 | #include <linux/hdreg.h> | 17 | #include <linux/hdreg.h> |
18 | 18 | ||
19 | #define DM_NAME "device-mapper" | 19 | #define DM_NAME "device-mapper" |
20 | #define DMWARN(f, x...) printk(KERN_WARNING DM_NAME ": " f "\n" , ## x) | 20 | |
21 | #define DMERR(f, x...) printk(KERN_ERR DM_NAME ": " f "\n" , ## x) | 21 | #define DMERR(f, arg...) printk(KERN_ERR DM_NAME ": " DM_MSG_PREFIX ": " f "\n", ## arg) |
22 | #define DMINFO(f, x...) printk(KERN_INFO DM_NAME ": " f "\n" , ## x) | 22 | #define DMWARN(f, arg...) printk(KERN_WARNING DM_NAME ": " DM_MSG_PREFIX ": " f "\n", ## arg) |
23 | #define DMINFO(f, arg...) printk(KERN_INFO DM_NAME ": " DM_MSG_PREFIX ": " f "\n", ## arg) | ||
23 | 24 | ||
24 | #define DMEMIT(x...) sz += ((sz >= maxlen) ? \ | 25 | #define DMEMIT(x...) sz += ((sz >= maxlen) ? \ |
25 | 0 : scnprintf(result + sz, maxlen - sz, x)) | 26 | 0 : scnprintf(result + sz, maxlen - sz, x)) |
@@ -39,83 +40,16 @@ struct dm_dev { | |||
39 | }; | 40 | }; |
40 | 41 | ||
41 | struct dm_table; | 42 | struct dm_table; |
42 | struct mapped_device; | ||
43 | |||
44 | /*----------------------------------------------------------------- | ||
45 | * Functions for manipulating a struct mapped_device. | ||
46 | * Drop the reference with dm_put when you finish with the object. | ||
47 | *---------------------------------------------------------------*/ | ||
48 | int dm_create(struct mapped_device **md); | ||
49 | int dm_create_with_minor(unsigned int minor, struct mapped_device **md); | ||
50 | void dm_set_mdptr(struct mapped_device *md, void *ptr); | ||
51 | void *dm_get_mdptr(struct mapped_device *md); | ||
52 | struct mapped_device *dm_get_md(dev_t dev); | ||
53 | |||
54 | /* | ||
55 | * Reference counting for md. | ||
56 | */ | ||
57 | void dm_get(struct mapped_device *md); | ||
58 | void dm_put(struct mapped_device *md); | ||
59 | |||
60 | /* | ||
61 | * A device can still be used while suspended, but I/O is deferred. | ||
62 | */ | ||
63 | int dm_suspend(struct mapped_device *md, int with_lockfs); | ||
64 | int dm_resume(struct mapped_device *md); | ||
65 | |||
66 | /* | ||
67 | * The device must be suspended before calling this method. | ||
68 | */ | ||
69 | int dm_swap_table(struct mapped_device *md, struct dm_table *t); | ||
70 | |||
71 | /* | ||
72 | * Drop a reference on the table when you've finished with the | ||
73 | * result. | ||
74 | */ | ||
75 | struct dm_table *dm_get_table(struct mapped_device *md); | ||
76 | |||
77 | /* | ||
78 | * Event functions. | ||
79 | */ | ||
80 | uint32_t dm_get_event_nr(struct mapped_device *md); | ||
81 | int dm_wait_event(struct mapped_device *md, int event_nr); | ||
82 | |||
83 | /* | ||
84 | * Info functions. | ||
85 | */ | ||
86 | struct gendisk *dm_disk(struct mapped_device *md); | ||
87 | int dm_suspended(struct mapped_device *md); | ||
88 | |||
89 | /* | ||
90 | * Geometry functions. | ||
91 | */ | ||
92 | int dm_get_geometry(struct mapped_device *md, struct hd_geometry *geo); | ||
93 | int dm_set_geometry(struct mapped_device *md, struct hd_geometry *geo); | ||
94 | 43 | ||
95 | /*----------------------------------------------------------------- | 44 | /*----------------------------------------------------------------- |
96 | * Functions for manipulating a table. Tables are also reference | 45 | * Internal table functions. |
97 | * counted. | ||
98 | *---------------------------------------------------------------*/ | 46 | *---------------------------------------------------------------*/ |
99 | int dm_table_create(struct dm_table **result, int mode, | ||
100 | unsigned num_targets, struct mapped_device *md); | ||
101 | |||
102 | void dm_table_get(struct dm_table *t); | ||
103 | void dm_table_put(struct dm_table *t); | ||
104 | |||
105 | int dm_table_add_target(struct dm_table *t, const char *type, | ||
106 | sector_t start, sector_t len, char *params); | ||
107 | int dm_table_complete(struct dm_table *t); | ||
108 | void dm_table_event_callback(struct dm_table *t, | 47 | void dm_table_event_callback(struct dm_table *t, |
109 | void (*fn)(void *), void *context); | 48 | void (*fn)(void *), void *context); |
110 | void dm_table_event(struct dm_table *t); | ||
111 | sector_t dm_table_get_size(struct dm_table *t); | ||
112 | struct dm_target *dm_table_get_target(struct dm_table *t, unsigned int index); | 49 | struct dm_target *dm_table_get_target(struct dm_table *t, unsigned int index); |
113 | struct dm_target *dm_table_find_target(struct dm_table *t, sector_t sector); | 50 | struct dm_target *dm_table_find_target(struct dm_table *t, sector_t sector); |
114 | void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q); | 51 | void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q); |
115 | unsigned int dm_table_get_num_targets(struct dm_table *t); | ||
116 | struct list_head *dm_table_get_devices(struct dm_table *t); | 52 | struct list_head *dm_table_get_devices(struct dm_table *t); |
117 | int dm_table_get_mode(struct dm_table *t); | ||
118 | struct mapped_device *dm_table_get_md(struct dm_table *t); | ||
119 | void dm_table_presuspend_targets(struct dm_table *t); | 53 | void dm_table_presuspend_targets(struct dm_table *t); |
120 | void dm_table_postsuspend_targets(struct dm_table *t); | 54 | void dm_table_postsuspend_targets(struct dm_table *t); |
121 | void dm_table_resume_targets(struct dm_table *t); | 55 | void dm_table_resume_targets(struct dm_table *t); |
@@ -133,7 +67,6 @@ void dm_put_target_type(struct target_type *t); | |||
133 | int dm_target_iterate(void (*iter_func)(struct target_type *tt, | 67 | int dm_target_iterate(void (*iter_func)(struct target_type *tt, |
134 | void *param), void *param); | 68 | void *param), void *param); |
135 | 69 | ||
136 | |||
137 | /*----------------------------------------------------------------- | 70 | /*----------------------------------------------------------------- |
138 | * Useful inlines. | 71 | * Useful inlines. |
139 | *---------------------------------------------------------------*/ | 72 | *---------------------------------------------------------------*/ |
@@ -191,5 +124,7 @@ void dm_stripe_exit(void); | |||
191 | 124 | ||
192 | void *dm_vcalloc(unsigned long nmemb, unsigned long elem_size); | 125 | void *dm_vcalloc(unsigned long nmemb, unsigned long elem_size); |
193 | union map_info *dm_get_mapinfo(struct bio *bio); | 126 | union map_info *dm_get_mapinfo(struct bio *bio); |
127 | int dm_open_count(struct mapped_device *md); | ||
128 | int dm_lock_for_deletion(struct mapped_device *md); | ||
194 | 129 | ||
195 | #endif | 130 | #endif |
diff --git a/drivers/md/kcopyd.c b/drivers/md/kcopyd.c index 72480a48d88b..73ab875fb158 100644 --- a/drivers/md/kcopyd.c +++ b/drivers/md/kcopyd.c | |||
@@ -314,7 +314,7 @@ static void complete_io(unsigned long error, void *context) | |||
314 | 314 | ||
315 | if (error) { | 315 | if (error) { |
316 | if (job->rw == WRITE) | 316 | if (job->rw == WRITE) |
317 | job->write_err &= error; | 317 | job->write_err |= error; |
318 | else | 318 | else |
319 | job->read_err = 1; | 319 | job->read_err = 1; |
320 | 320 | ||
@@ -460,7 +460,7 @@ static void segment_complete(int read_err, | |||
460 | job->read_err = 1; | 460 | job->read_err = 1; |
461 | 461 | ||
462 | if (write_err) | 462 | if (write_err) |
463 | job->write_err &= write_err; | 463 | job->write_err |= write_err; |
464 | 464 | ||
465 | /* | 465 | /* |
466 | * Only dispatch more work if there hasn't been an error. | 466 | * Only dispatch more work if there hasn't been an error. |
diff --git a/drivers/md/linear.c b/drivers/md/linear.c index 777585458c85..ff83c9b5979e 100644 --- a/drivers/md/linear.c +++ b/drivers/md/linear.c | |||
@@ -111,7 +111,7 @@ static int linear_issue_flush(request_queue_t *q, struct gendisk *disk, | |||
111 | return ret; | 111 | return ret; |
112 | } | 112 | } |
113 | 113 | ||
114 | static int linear_run (mddev_t *mddev) | 114 | static linear_conf_t *linear_conf(mddev_t *mddev, int raid_disks) |
115 | { | 115 | { |
116 | linear_conf_t *conf; | 116 | linear_conf_t *conf; |
117 | dev_info_t **table; | 117 | dev_info_t **table; |
@@ -121,20 +121,21 @@ static int linear_run (mddev_t *mddev) | |||
121 | sector_t curr_offset; | 121 | sector_t curr_offset; |
122 | struct list_head *tmp; | 122 | struct list_head *tmp; |
123 | 123 | ||
124 | conf = kzalloc (sizeof (*conf) + mddev->raid_disks*sizeof(dev_info_t), | 124 | conf = kzalloc (sizeof (*conf) + raid_disks*sizeof(dev_info_t), |
125 | GFP_KERNEL); | 125 | GFP_KERNEL); |
126 | if (!conf) | 126 | if (!conf) |
127 | goto out; | 127 | return NULL; |
128 | |||
128 | mddev->private = conf; | 129 | mddev->private = conf; |
129 | 130 | ||
130 | cnt = 0; | 131 | cnt = 0; |
131 | mddev->array_size = 0; | 132 | conf->array_size = 0; |
132 | 133 | ||
133 | ITERATE_RDEV(mddev,rdev,tmp) { | 134 | ITERATE_RDEV(mddev,rdev,tmp) { |
134 | int j = rdev->raid_disk; | 135 | int j = rdev->raid_disk; |
135 | dev_info_t *disk = conf->disks + j; | 136 | dev_info_t *disk = conf->disks + j; |
136 | 137 | ||
137 | if (j < 0 || j > mddev->raid_disks || disk->rdev) { | 138 | if (j < 0 || j > raid_disks || disk->rdev) { |
138 | printk("linear: disk numbering problem. Aborting!\n"); | 139 | printk("linear: disk numbering problem. Aborting!\n"); |
139 | goto out; | 140 | goto out; |
140 | } | 141 | } |
@@ -152,11 +153,11 @@ static int linear_run (mddev_t *mddev) | |||
152 | blk_queue_max_sectors(mddev->queue, PAGE_SIZE>>9); | 153 | blk_queue_max_sectors(mddev->queue, PAGE_SIZE>>9); |
153 | 154 | ||
154 | disk->size = rdev->size; | 155 | disk->size = rdev->size; |
155 | mddev->array_size += rdev->size; | 156 | conf->array_size += rdev->size; |
156 | 157 | ||
157 | cnt++; | 158 | cnt++; |
158 | } | 159 | } |
159 | if (cnt != mddev->raid_disks) { | 160 | if (cnt != raid_disks) { |
160 | printk("linear: not enough drives present. Aborting!\n"); | 161 | printk("linear: not enough drives present. Aborting!\n"); |
161 | goto out; | 162 | goto out; |
162 | } | 163 | } |
@@ -200,7 +201,7 @@ static int linear_run (mddev_t *mddev) | |||
200 | unsigned round; | 201 | unsigned round; |
201 | unsigned long base; | 202 | unsigned long base; |
202 | 203 | ||
203 | sz = mddev->array_size >> conf->preshift; | 204 | sz = conf->array_size >> conf->preshift; |
204 | sz += 1; /* force round-up */ | 205 | sz += 1; /* force round-up */ |
205 | base = conf->hash_spacing >> conf->preshift; | 206 | base = conf->hash_spacing >> conf->preshift; |
206 | round = sector_div(sz, base); | 207 | round = sector_div(sz, base); |
@@ -247,14 +248,56 @@ static int linear_run (mddev_t *mddev) | |||
247 | 248 | ||
248 | BUG_ON(table - conf->hash_table > nb_zone); | 249 | BUG_ON(table - conf->hash_table > nb_zone); |
249 | 250 | ||
251 | return conf; | ||
252 | |||
253 | out: | ||
254 | kfree(conf); | ||
255 | return NULL; | ||
256 | } | ||
257 | |||
258 | static int linear_run (mddev_t *mddev) | ||
259 | { | ||
260 | linear_conf_t *conf; | ||
261 | |||
262 | conf = linear_conf(mddev, mddev->raid_disks); | ||
263 | |||
264 | if (!conf) | ||
265 | return 1; | ||
266 | mddev->private = conf; | ||
267 | mddev->array_size = conf->array_size; | ||
268 | |||
250 | blk_queue_merge_bvec(mddev->queue, linear_mergeable_bvec); | 269 | blk_queue_merge_bvec(mddev->queue, linear_mergeable_bvec); |
251 | mddev->queue->unplug_fn = linear_unplug; | 270 | mddev->queue->unplug_fn = linear_unplug; |
252 | mddev->queue->issue_flush_fn = linear_issue_flush; | 271 | mddev->queue->issue_flush_fn = linear_issue_flush; |
253 | return 0; | 272 | return 0; |
273 | } | ||
254 | 274 | ||
255 | out: | 275 | static int linear_add(mddev_t *mddev, mdk_rdev_t *rdev) |
256 | kfree(conf); | 276 | { |
257 | return 1; | 277 | /* Adding a drive to a linear array allows the array to grow. |
278 | * It is permitted if the new drive has a matching superblock | ||
279 | * already on it, with raid_disk equal to raid_disks. | ||
280 | * It is achieved by creating a new linear_private_data structure | ||
281 | * and swapping it in in-place of the current one. | ||
282 | * The current one is never freed until the array is stopped. | ||
283 | * This avoids races. | ||
284 | */ | ||
285 | linear_conf_t *newconf; | ||
286 | |||
287 | if (rdev->raid_disk != mddev->raid_disks) | ||
288 | return -EINVAL; | ||
289 | |||
290 | newconf = linear_conf(mddev,mddev->raid_disks+1); | ||
291 | |||
292 | if (!newconf) | ||
293 | return -ENOMEM; | ||
294 | |||
295 | newconf->prev = mddev_to_conf(mddev); | ||
296 | mddev->private = newconf; | ||
297 | mddev->raid_disks++; | ||
298 | mddev->array_size = newconf->array_size; | ||
299 | set_capacity(mddev->gendisk, mddev->array_size << 1); | ||
300 | return 0; | ||
258 | } | 301 | } |
259 | 302 | ||
260 | static int linear_stop (mddev_t *mddev) | 303 | static int linear_stop (mddev_t *mddev) |
@@ -262,8 +305,12 @@ static int linear_stop (mddev_t *mddev) | |||
262 | linear_conf_t *conf = mddev_to_conf(mddev); | 305 | linear_conf_t *conf = mddev_to_conf(mddev); |
263 | 306 | ||
264 | blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/ | 307 | blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/ |
265 | kfree(conf->hash_table); | 308 | do { |
266 | kfree(conf); | 309 | linear_conf_t *t = conf->prev; |
310 | kfree(conf->hash_table); | ||
311 | kfree(conf); | ||
312 | conf = t; | ||
313 | } while (conf); | ||
267 | 314 | ||
268 | return 0; | 315 | return 0; |
269 | } | 316 | } |
@@ -360,6 +407,7 @@ static struct mdk_personality linear_personality = | |||
360 | .run = linear_run, | 407 | .run = linear_run, |
361 | .stop = linear_stop, | 408 | .stop = linear_stop, |
362 | .status = linear_status, | 409 | .status = linear_status, |
410 | .hot_add_disk = linear_add, | ||
363 | }; | 411 | }; |
364 | 412 | ||
365 | static int __init linear_init (void) | 413 | static int __init linear_init (void) |
diff --git a/drivers/md/md.c b/drivers/md/md.c index f19b874753a9..306268ec99ff 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c | |||
@@ -44,6 +44,7 @@ | |||
44 | #include <linux/suspend.h> | 44 | #include <linux/suspend.h> |
45 | #include <linux/poll.h> | 45 | #include <linux/poll.h> |
46 | #include <linux/mutex.h> | 46 | #include <linux/mutex.h> |
47 | #include <linux/ctype.h> | ||
47 | 48 | ||
48 | #include <linux/init.h> | 49 | #include <linux/init.h> |
49 | 50 | ||
@@ -72,6 +73,10 @@ static void autostart_arrays (int part); | |||
72 | static LIST_HEAD(pers_list); | 73 | static LIST_HEAD(pers_list); |
73 | static DEFINE_SPINLOCK(pers_lock); | 74 | static DEFINE_SPINLOCK(pers_lock); |
74 | 75 | ||
76 | static void md_print_devices(void); | ||
77 | |||
78 | #define MD_BUG(x...) { printk("md: bug in file %s, line %d\n", __FILE__, __LINE__); md_print_devices(); } | ||
79 | |||
75 | /* | 80 | /* |
76 | * Current RAID-1,4,5 parallel reconstruction 'guaranteed speed limit' | 81 | * Current RAID-1,4,5 parallel reconstruction 'guaranteed speed limit' |
77 | * is 1000 KB/sec, so the extra system load does not show up that much. | 82 | * is 1000 KB/sec, so the extra system load does not show up that much. |
@@ -170,7 +175,7 @@ EXPORT_SYMBOL_GPL(md_new_event); | |||
170 | /* Alternate version that can be called from interrupts | 175 | /* Alternate version that can be called from interrupts |
171 | * when calling sysfs_notify isn't needed. | 176 | * when calling sysfs_notify isn't needed. |
172 | */ | 177 | */ |
173 | void md_new_event_inintr(mddev_t *mddev) | 178 | static void md_new_event_inintr(mddev_t *mddev) |
174 | { | 179 | { |
175 | atomic_inc(&md_event_count); | 180 | atomic_inc(&md_event_count); |
176 | wake_up(&md_event_waiters); | 181 | wake_up(&md_event_waiters); |
@@ -732,6 +737,7 @@ static int super_90_validate(mddev_t *mddev, mdk_rdev_t *rdev) | |||
732 | { | 737 | { |
733 | mdp_disk_t *desc; | 738 | mdp_disk_t *desc; |
734 | mdp_super_t *sb = (mdp_super_t *)page_address(rdev->sb_page); | 739 | mdp_super_t *sb = (mdp_super_t *)page_address(rdev->sb_page); |
740 | __u64 ev1 = md_event(sb); | ||
735 | 741 | ||
736 | rdev->raid_disk = -1; | 742 | rdev->raid_disk = -1; |
737 | rdev->flags = 0; | 743 | rdev->flags = 0; |
@@ -748,7 +754,7 @@ static int super_90_validate(mddev_t *mddev, mdk_rdev_t *rdev) | |||
748 | mddev->layout = sb->layout; | 754 | mddev->layout = sb->layout; |
749 | mddev->raid_disks = sb->raid_disks; | 755 | mddev->raid_disks = sb->raid_disks; |
750 | mddev->size = sb->size; | 756 | mddev->size = sb->size; |
751 | mddev->events = md_event(sb); | 757 | mddev->events = ev1; |
752 | mddev->bitmap_offset = 0; | 758 | mddev->bitmap_offset = 0; |
753 | mddev->default_bitmap_offset = MD_SB_BYTES >> 9; | 759 | mddev->default_bitmap_offset = MD_SB_BYTES >> 9; |
754 | 760 | ||
@@ -797,7 +803,6 @@ static int super_90_validate(mddev_t *mddev, mdk_rdev_t *rdev) | |||
797 | 803 | ||
798 | } else if (mddev->pers == NULL) { | 804 | } else if (mddev->pers == NULL) { |
799 | /* Insist on good event counter while assembling */ | 805 | /* Insist on good event counter while assembling */ |
800 | __u64 ev1 = md_event(sb); | ||
801 | ++ev1; | 806 | ++ev1; |
802 | if (ev1 < mddev->events) | 807 | if (ev1 < mddev->events) |
803 | return -EINVAL; | 808 | return -EINVAL; |
@@ -805,19 +810,21 @@ static int super_90_validate(mddev_t *mddev, mdk_rdev_t *rdev) | |||
805 | /* if adding to array with a bitmap, then we can accept an | 810 | /* if adding to array with a bitmap, then we can accept an |
806 | * older device ... but not too old. | 811 | * older device ... but not too old. |
807 | */ | 812 | */ |
808 | __u64 ev1 = md_event(sb); | ||
809 | if (ev1 < mddev->bitmap->events_cleared) | 813 | if (ev1 < mddev->bitmap->events_cleared) |
810 | return 0; | 814 | return 0; |
811 | } else /* just a hot-add of a new device, leave raid_disk at -1 */ | 815 | } else { |
812 | return 0; | 816 | if (ev1 < mddev->events) |
817 | /* just a hot-add of a new device, leave raid_disk at -1 */ | ||
818 | return 0; | ||
819 | } | ||
813 | 820 | ||
814 | if (mddev->level != LEVEL_MULTIPATH) { | 821 | if (mddev->level != LEVEL_MULTIPATH) { |
815 | desc = sb->disks + rdev->desc_nr; | 822 | desc = sb->disks + rdev->desc_nr; |
816 | 823 | ||
817 | if (desc->state & (1<<MD_DISK_FAULTY)) | 824 | if (desc->state & (1<<MD_DISK_FAULTY)) |
818 | set_bit(Faulty, &rdev->flags); | 825 | set_bit(Faulty, &rdev->flags); |
819 | else if (desc->state & (1<<MD_DISK_SYNC) && | 826 | else if (desc->state & (1<<MD_DISK_SYNC) /* && |
820 | desc->raid_disk < mddev->raid_disks) { | 827 | desc->raid_disk < mddev->raid_disks */) { |
821 | set_bit(In_sync, &rdev->flags); | 828 | set_bit(In_sync, &rdev->flags); |
822 | rdev->raid_disk = desc->raid_disk; | 829 | rdev->raid_disk = desc->raid_disk; |
823 | } | 830 | } |
@@ -1100,6 +1107,7 @@ static int super_1_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version) | |||
1100 | static int super_1_validate(mddev_t *mddev, mdk_rdev_t *rdev) | 1107 | static int super_1_validate(mddev_t *mddev, mdk_rdev_t *rdev) |
1101 | { | 1108 | { |
1102 | struct mdp_superblock_1 *sb = (struct mdp_superblock_1*)page_address(rdev->sb_page); | 1109 | struct mdp_superblock_1 *sb = (struct mdp_superblock_1*)page_address(rdev->sb_page); |
1110 | __u64 ev1 = le64_to_cpu(sb->events); | ||
1103 | 1111 | ||
1104 | rdev->raid_disk = -1; | 1112 | rdev->raid_disk = -1; |
1105 | rdev->flags = 0; | 1113 | rdev->flags = 0; |
@@ -1115,7 +1123,7 @@ static int super_1_validate(mddev_t *mddev, mdk_rdev_t *rdev) | |||
1115 | mddev->layout = le32_to_cpu(sb->layout); | 1123 | mddev->layout = le32_to_cpu(sb->layout); |
1116 | mddev->raid_disks = le32_to_cpu(sb->raid_disks); | 1124 | mddev->raid_disks = le32_to_cpu(sb->raid_disks); |
1117 | mddev->size = le64_to_cpu(sb->size)/2; | 1125 | mddev->size = le64_to_cpu(sb->size)/2; |
1118 | mddev->events = le64_to_cpu(sb->events); | 1126 | mddev->events = ev1; |
1119 | mddev->bitmap_offset = 0; | 1127 | mddev->bitmap_offset = 0; |
1120 | mddev->default_bitmap_offset = 1024 >> 9; | 1128 | mddev->default_bitmap_offset = 1024 >> 9; |
1121 | 1129 | ||
@@ -1149,7 +1157,6 @@ static int super_1_validate(mddev_t *mddev, mdk_rdev_t *rdev) | |||
1149 | 1157 | ||
1150 | } else if (mddev->pers == NULL) { | 1158 | } else if (mddev->pers == NULL) { |
1151 | /* Insist of good event counter while assembling */ | 1159 | /* Insist of good event counter while assembling */ |
1152 | __u64 ev1 = le64_to_cpu(sb->events); | ||
1153 | ++ev1; | 1160 | ++ev1; |
1154 | if (ev1 < mddev->events) | 1161 | if (ev1 < mddev->events) |
1155 | return -EINVAL; | 1162 | return -EINVAL; |
@@ -1157,12 +1164,13 @@ static int super_1_validate(mddev_t *mddev, mdk_rdev_t *rdev) | |||
1157 | /* If adding to array with a bitmap, then we can accept an | 1164 | /* If adding to array with a bitmap, then we can accept an |
1158 | * older device, but not too old. | 1165 | * older device, but not too old. |
1159 | */ | 1166 | */ |
1160 | __u64 ev1 = le64_to_cpu(sb->events); | ||
1161 | if (ev1 < mddev->bitmap->events_cleared) | 1167 | if (ev1 < mddev->bitmap->events_cleared) |
1162 | return 0; | 1168 | return 0; |
1163 | } else /* just a hot-add of a new device, leave raid_disk at -1 */ | 1169 | } else { |
1164 | return 0; | 1170 | if (ev1 < mddev->events) |
1165 | 1171 | /* just a hot-add of a new device, leave raid_disk at -1 */ | |
1172 | return 0; | ||
1173 | } | ||
1166 | if (mddev->level != LEVEL_MULTIPATH) { | 1174 | if (mddev->level != LEVEL_MULTIPATH) { |
1167 | int role; | 1175 | int role; |
1168 | rdev->desc_nr = le32_to_cpu(sb->dev_number); | 1176 | rdev->desc_nr = le32_to_cpu(sb->dev_number); |
@@ -1174,7 +1182,11 @@ static int super_1_validate(mddev_t *mddev, mdk_rdev_t *rdev) | |||
1174 | set_bit(Faulty, &rdev->flags); | 1182 | set_bit(Faulty, &rdev->flags); |
1175 | break; | 1183 | break; |
1176 | default: | 1184 | default: |
1177 | set_bit(In_sync, &rdev->flags); | 1185 | if ((le32_to_cpu(sb->feature_map) & |
1186 | MD_FEATURE_RECOVERY_OFFSET)) | ||
1187 | rdev->recovery_offset = le64_to_cpu(sb->recovery_offset); | ||
1188 | else | ||
1189 | set_bit(In_sync, &rdev->flags); | ||
1178 | rdev->raid_disk = role; | 1190 | rdev->raid_disk = role; |
1179 | break; | 1191 | break; |
1180 | } | 1192 | } |
@@ -1198,6 +1210,7 @@ static void super_1_sync(mddev_t *mddev, mdk_rdev_t *rdev) | |||
1198 | 1210 | ||
1199 | sb->feature_map = 0; | 1211 | sb->feature_map = 0; |
1200 | sb->pad0 = 0; | 1212 | sb->pad0 = 0; |
1213 | sb->recovery_offset = cpu_to_le64(0); | ||
1201 | memset(sb->pad1, 0, sizeof(sb->pad1)); | 1214 | memset(sb->pad1, 0, sizeof(sb->pad1)); |
1202 | memset(sb->pad2, 0, sizeof(sb->pad2)); | 1215 | memset(sb->pad2, 0, sizeof(sb->pad2)); |
1203 | memset(sb->pad3, 0, sizeof(sb->pad3)); | 1216 | memset(sb->pad3, 0, sizeof(sb->pad3)); |
@@ -1218,6 +1231,14 @@ static void super_1_sync(mddev_t *mddev, mdk_rdev_t *rdev) | |||
1218 | sb->bitmap_offset = cpu_to_le32((__u32)mddev->bitmap_offset); | 1231 | sb->bitmap_offset = cpu_to_le32((__u32)mddev->bitmap_offset); |
1219 | sb->feature_map = cpu_to_le32(MD_FEATURE_BITMAP_OFFSET); | 1232 | sb->feature_map = cpu_to_le32(MD_FEATURE_BITMAP_OFFSET); |
1220 | } | 1233 | } |
1234 | |||
1235 | if (rdev->raid_disk >= 0 && | ||
1236 | !test_bit(In_sync, &rdev->flags) && | ||
1237 | rdev->recovery_offset > 0) { | ||
1238 | sb->feature_map |= cpu_to_le32(MD_FEATURE_RECOVERY_OFFSET); | ||
1239 | sb->recovery_offset = cpu_to_le64(rdev->recovery_offset); | ||
1240 | } | ||
1241 | |||
1221 | if (mddev->reshape_position != MaxSector) { | 1242 | if (mddev->reshape_position != MaxSector) { |
1222 | sb->feature_map |= cpu_to_le32(MD_FEATURE_RESHAPE_ACTIVE); | 1243 | sb->feature_map |= cpu_to_le32(MD_FEATURE_RESHAPE_ACTIVE); |
1223 | sb->reshape_position = cpu_to_le64(mddev->reshape_position); | 1244 | sb->reshape_position = cpu_to_le64(mddev->reshape_position); |
@@ -1242,11 +1263,12 @@ static void super_1_sync(mddev_t *mddev, mdk_rdev_t *rdev) | |||
1242 | sb->dev_roles[i] = cpu_to_le16(0xfffe); | 1263 | sb->dev_roles[i] = cpu_to_le16(0xfffe); |
1243 | else if (test_bit(In_sync, &rdev2->flags)) | 1264 | else if (test_bit(In_sync, &rdev2->flags)) |
1244 | sb->dev_roles[i] = cpu_to_le16(rdev2->raid_disk); | 1265 | sb->dev_roles[i] = cpu_to_le16(rdev2->raid_disk); |
1266 | else if (rdev2->raid_disk >= 0 && rdev2->recovery_offset > 0) | ||
1267 | sb->dev_roles[i] = cpu_to_le16(rdev2->raid_disk); | ||
1245 | else | 1268 | else |
1246 | sb->dev_roles[i] = cpu_to_le16(0xffff); | 1269 | sb->dev_roles[i] = cpu_to_le16(0xffff); |
1247 | } | 1270 | } |
1248 | 1271 | ||
1249 | sb->recovery_offset = cpu_to_le64(0); /* not supported yet */ | ||
1250 | sb->sb_csum = calc_sb_1_csum(sb); | 1272 | sb->sb_csum = calc_sb_1_csum(sb); |
1251 | } | 1273 | } |
1252 | 1274 | ||
@@ -1507,7 +1529,7 @@ static void print_rdev(mdk_rdev_t *rdev) | |||
1507 | printk(KERN_INFO "md: no rdev superblock!\n"); | 1529 | printk(KERN_INFO "md: no rdev superblock!\n"); |
1508 | } | 1530 | } |
1509 | 1531 | ||
1510 | void md_print_devices(void) | 1532 | static void md_print_devices(void) |
1511 | { | 1533 | { |
1512 | struct list_head *tmp, *tmp2; | 1534 | struct list_head *tmp, *tmp2; |
1513 | mdk_rdev_t *rdev; | 1535 | mdk_rdev_t *rdev; |
@@ -1536,15 +1558,30 @@ void md_print_devices(void) | |||
1536 | } | 1558 | } |
1537 | 1559 | ||
1538 | 1560 | ||
1539 | static void sync_sbs(mddev_t * mddev) | 1561 | static void sync_sbs(mddev_t * mddev, int nospares) |
1540 | { | 1562 | { |
1563 | /* Update each superblock (in-memory image), but | ||
1564 | * if we are allowed to, skip spares which already | ||
1565 | * have the right event counter, or have one earlier | ||
1566 | * (which would mean they aren't being marked as dirty | ||
1567 | * with the rest of the array) | ||
1568 | */ | ||
1541 | mdk_rdev_t *rdev; | 1569 | mdk_rdev_t *rdev; |
1542 | struct list_head *tmp; | 1570 | struct list_head *tmp; |
1543 | 1571 | ||
1544 | ITERATE_RDEV(mddev,rdev,tmp) { | 1572 | ITERATE_RDEV(mddev,rdev,tmp) { |
1545 | super_types[mddev->major_version]. | 1573 | if (rdev->sb_events == mddev->events || |
1546 | sync_super(mddev, rdev); | 1574 | (nospares && |
1547 | rdev->sb_loaded = 1; | 1575 | rdev->raid_disk < 0 && |
1576 | (rdev->sb_events&1)==0 && | ||
1577 | rdev->sb_events+1 == mddev->events)) { | ||
1578 | /* Don't update this superblock */ | ||
1579 | rdev->sb_loaded = 2; | ||
1580 | } else { | ||
1581 | super_types[mddev->major_version]. | ||
1582 | sync_super(mddev, rdev); | ||
1583 | rdev->sb_loaded = 1; | ||
1584 | } | ||
1548 | } | 1585 | } |
1549 | } | 1586 | } |
1550 | 1587 | ||
@@ -1554,12 +1591,42 @@ void md_update_sb(mddev_t * mddev) | |||
1554 | struct list_head *tmp; | 1591 | struct list_head *tmp; |
1555 | mdk_rdev_t *rdev; | 1592 | mdk_rdev_t *rdev; |
1556 | int sync_req; | 1593 | int sync_req; |
1594 | int nospares = 0; | ||
1557 | 1595 | ||
1558 | repeat: | 1596 | repeat: |
1559 | spin_lock_irq(&mddev->write_lock); | 1597 | spin_lock_irq(&mddev->write_lock); |
1560 | sync_req = mddev->in_sync; | 1598 | sync_req = mddev->in_sync; |
1561 | mddev->utime = get_seconds(); | 1599 | mddev->utime = get_seconds(); |
1562 | mddev->events ++; | 1600 | if (mddev->sb_dirty == 3) |
1601 | /* just a clean<-> dirty transition, possibly leave spares alone, | ||
1602 | * though if events isn't the right even/odd, we will have to do | ||
1603 | * spares after all | ||
1604 | */ | ||
1605 | nospares = 1; | ||
1606 | |||
1607 | /* If this is just a dirty<->clean transition, and the array is clean | ||
1608 | * and 'events' is odd, we can roll back to the previous clean state */ | ||
1609 | if (mddev->sb_dirty == 3 | ||
1610 | && (mddev->in_sync && mddev->recovery_cp == MaxSector) | ||
1611 | && (mddev->events & 1)) | ||
1612 | mddev->events--; | ||
1613 | else { | ||
1614 | /* otherwise we have to go forward and ... */ | ||
1615 | mddev->events ++; | ||
1616 | if (!mddev->in_sync || mddev->recovery_cp != MaxSector) { /* not clean */ | ||
1617 | /* .. if the array isn't clean, insist on an odd 'events' */ | ||
1618 | if ((mddev->events&1)==0) { | ||
1619 | mddev->events++; | ||
1620 | nospares = 0; | ||
1621 | } | ||
1622 | } else { | ||
1623 | /* otherwise insist on an even 'events' (for clean states) */ | ||
1624 | if ((mddev->events&1)) { | ||
1625 | mddev->events++; | ||
1626 | nospares = 0; | ||
1627 | } | ||
1628 | } | ||
1629 | } | ||
1563 | 1630 | ||
1564 | if (!mddev->events) { | 1631 | if (!mddev->events) { |
1565 | /* | 1632 | /* |
@@ -1571,7 +1638,7 @@ repeat: | |||
1571 | mddev->events --; | 1638 | mddev->events --; |
1572 | } | 1639 | } |
1573 | mddev->sb_dirty = 2; | 1640 | mddev->sb_dirty = 2; |
1574 | sync_sbs(mddev); | 1641 | sync_sbs(mddev, nospares); |
1575 | 1642 | ||
1576 | /* | 1643 | /* |
1577 | * do not write anything to disk if using | 1644 | * do not write anything to disk if using |
@@ -1593,6 +1660,8 @@ repeat: | |||
1593 | ITERATE_RDEV(mddev,rdev,tmp) { | 1660 | ITERATE_RDEV(mddev,rdev,tmp) { |
1594 | char b[BDEVNAME_SIZE]; | 1661 | char b[BDEVNAME_SIZE]; |
1595 | dprintk(KERN_INFO "md: "); | 1662 | dprintk(KERN_INFO "md: "); |
1663 | if (rdev->sb_loaded != 1) | ||
1664 | continue; /* no noise on spare devices */ | ||
1596 | if (test_bit(Faulty, &rdev->flags)) | 1665 | if (test_bit(Faulty, &rdev->flags)) |
1597 | dprintk("(skipping faulty "); | 1666 | dprintk("(skipping faulty "); |
1598 | 1667 | ||
@@ -1604,6 +1673,7 @@ repeat: | |||
1604 | dprintk(KERN_INFO "(write) %s's sb offset: %llu\n", | 1673 | dprintk(KERN_INFO "(write) %s's sb offset: %llu\n", |
1605 | bdevname(rdev->bdev,b), | 1674 | bdevname(rdev->bdev,b), |
1606 | (unsigned long long)rdev->sb_offset); | 1675 | (unsigned long long)rdev->sb_offset); |
1676 | rdev->sb_events = mddev->events; | ||
1607 | 1677 | ||
1608 | } else | 1678 | } else |
1609 | dprintk(")\n"); | 1679 | dprintk(")\n"); |
@@ -1667,6 +1737,10 @@ state_show(mdk_rdev_t *rdev, char *page) | |||
1667 | len += sprintf(page+len, "%sin_sync",sep); | 1737 | len += sprintf(page+len, "%sin_sync",sep); |
1668 | sep = ","; | 1738 | sep = ","; |
1669 | } | 1739 | } |
1740 | if (test_bit(WriteMostly, &rdev->flags)) { | ||
1741 | len += sprintf(page+len, "%swrite_mostly",sep); | ||
1742 | sep = ","; | ||
1743 | } | ||
1670 | if (!test_bit(Faulty, &rdev->flags) && | 1744 | if (!test_bit(Faulty, &rdev->flags) && |
1671 | !test_bit(In_sync, &rdev->flags)) { | 1745 | !test_bit(In_sync, &rdev->flags)) { |
1672 | len += sprintf(page+len, "%sspare", sep); | 1746 | len += sprintf(page+len, "%sspare", sep); |
@@ -1675,8 +1749,40 @@ state_show(mdk_rdev_t *rdev, char *page) | |||
1675 | return len+sprintf(page+len, "\n"); | 1749 | return len+sprintf(page+len, "\n"); |
1676 | } | 1750 | } |
1677 | 1751 | ||
1752 | static ssize_t | ||
1753 | state_store(mdk_rdev_t *rdev, const char *buf, size_t len) | ||
1754 | { | ||
1755 | /* can write | ||
1756 | * faulty - simulates and error | ||
1757 | * remove - disconnects the device | ||
1758 | * writemostly - sets write_mostly | ||
1759 | * -writemostly - clears write_mostly | ||
1760 | */ | ||
1761 | int err = -EINVAL; | ||
1762 | if (cmd_match(buf, "faulty") && rdev->mddev->pers) { | ||
1763 | md_error(rdev->mddev, rdev); | ||
1764 | err = 0; | ||
1765 | } else if (cmd_match(buf, "remove")) { | ||
1766 | if (rdev->raid_disk >= 0) | ||
1767 | err = -EBUSY; | ||
1768 | else { | ||
1769 | mddev_t *mddev = rdev->mddev; | ||
1770 | kick_rdev_from_array(rdev); | ||
1771 | md_update_sb(mddev); | ||
1772 | md_new_event(mddev); | ||
1773 | err = 0; | ||
1774 | } | ||
1775 | } else if (cmd_match(buf, "writemostly")) { | ||
1776 | set_bit(WriteMostly, &rdev->flags); | ||
1777 | err = 0; | ||
1778 | } else if (cmd_match(buf, "-writemostly")) { | ||
1779 | clear_bit(WriteMostly, &rdev->flags); | ||
1780 | err = 0; | ||
1781 | } | ||
1782 | return err ? err : len; | ||
1783 | } | ||
1678 | static struct rdev_sysfs_entry | 1784 | static struct rdev_sysfs_entry |
1679 | rdev_state = __ATTR_RO(state); | 1785 | rdev_state = __ATTR(state, 0644, state_show, state_store); |
1680 | 1786 | ||
1681 | static ssize_t | 1787 | static ssize_t |
1682 | super_show(mdk_rdev_t *rdev, char *page) | 1788 | super_show(mdk_rdev_t *rdev, char *page) |
@@ -1873,6 +1979,7 @@ static mdk_rdev_t *md_import_device(dev_t newdev, int super_format, int super_mi | |||
1873 | rdev->desc_nr = -1; | 1979 | rdev->desc_nr = -1; |
1874 | rdev->flags = 0; | 1980 | rdev->flags = 0; |
1875 | rdev->data_offset = 0; | 1981 | rdev->data_offset = 0; |
1982 | rdev->sb_events = 0; | ||
1876 | atomic_set(&rdev->nr_pending, 0); | 1983 | atomic_set(&rdev->nr_pending, 0); |
1877 | atomic_set(&rdev->read_errors, 0); | 1984 | atomic_set(&rdev->read_errors, 0); |
1878 | atomic_set(&rdev->corrected_errors, 0); | 1985 | atomic_set(&rdev->corrected_errors, 0); |
@@ -1978,6 +2085,54 @@ static void analyze_sbs(mddev_t * mddev) | |||
1978 | } | 2085 | } |
1979 | 2086 | ||
1980 | static ssize_t | 2087 | static ssize_t |
2088 | safe_delay_show(mddev_t *mddev, char *page) | ||
2089 | { | ||
2090 | int msec = (mddev->safemode_delay*1000)/HZ; | ||
2091 | return sprintf(page, "%d.%03d\n", msec/1000, msec%1000); | ||
2092 | } | ||
2093 | static ssize_t | ||
2094 | safe_delay_store(mddev_t *mddev, const char *cbuf, size_t len) | ||
2095 | { | ||
2096 | int scale=1; | ||
2097 | int dot=0; | ||
2098 | int i; | ||
2099 | unsigned long msec; | ||
2100 | char buf[30]; | ||
2101 | char *e; | ||
2102 | /* remove a period, and count digits after it */ | ||
2103 | if (len >= sizeof(buf)) | ||
2104 | return -EINVAL; | ||
2105 | strlcpy(buf, cbuf, len); | ||
2106 | buf[len] = 0; | ||
2107 | for (i=0; i<len; i++) { | ||
2108 | if (dot) { | ||
2109 | if (isdigit(buf[i])) { | ||
2110 | buf[i-1] = buf[i]; | ||
2111 | scale *= 10; | ||
2112 | } | ||
2113 | buf[i] = 0; | ||
2114 | } else if (buf[i] == '.') { | ||
2115 | dot=1; | ||
2116 | buf[i] = 0; | ||
2117 | } | ||
2118 | } | ||
2119 | msec = simple_strtoul(buf, &e, 10); | ||
2120 | if (e == buf || (*e && *e != '\n')) | ||
2121 | return -EINVAL; | ||
2122 | msec = (msec * 1000) / scale; | ||
2123 | if (msec == 0) | ||
2124 | mddev->safemode_delay = 0; | ||
2125 | else { | ||
2126 | mddev->safemode_delay = (msec*HZ)/1000; | ||
2127 | if (mddev->safemode_delay == 0) | ||
2128 | mddev->safemode_delay = 1; | ||
2129 | } | ||
2130 | return len; | ||
2131 | } | ||
2132 | static struct md_sysfs_entry md_safe_delay = | ||
2133 | __ATTR(safe_mode_delay, 0644,safe_delay_show, safe_delay_store); | ||
2134 | |||
2135 | static ssize_t | ||
1981 | level_show(mddev_t *mddev, char *page) | 2136 | level_show(mddev_t *mddev, char *page) |
1982 | { | 2137 | { |
1983 | struct mdk_personality *p = mddev->pers; | 2138 | struct mdk_personality *p = mddev->pers; |
@@ -2012,6 +2167,32 @@ level_store(mddev_t *mddev, const char *buf, size_t len) | |||
2012 | static struct md_sysfs_entry md_level = | 2167 | static struct md_sysfs_entry md_level = |
2013 | __ATTR(level, 0644, level_show, level_store); | 2168 | __ATTR(level, 0644, level_show, level_store); |
2014 | 2169 | ||
2170 | |||
2171 | static ssize_t | ||
2172 | layout_show(mddev_t *mddev, char *page) | ||
2173 | { | ||
2174 | /* just a number, not meaningful for all levels */ | ||
2175 | return sprintf(page, "%d\n", mddev->layout); | ||
2176 | } | ||
2177 | |||
2178 | static ssize_t | ||
2179 | layout_store(mddev_t *mddev, const char *buf, size_t len) | ||
2180 | { | ||
2181 | char *e; | ||
2182 | unsigned long n = simple_strtoul(buf, &e, 10); | ||
2183 | if (mddev->pers) | ||
2184 | return -EBUSY; | ||
2185 | |||
2186 | if (!*buf || (*e && *e != '\n')) | ||
2187 | return -EINVAL; | ||
2188 | |||
2189 | mddev->layout = n; | ||
2190 | return len; | ||
2191 | } | ||
2192 | static struct md_sysfs_entry md_layout = | ||
2193 | __ATTR(layout, 0655, layout_show, layout_store); | ||
2194 | |||
2195 | |||
2015 | static ssize_t | 2196 | static ssize_t |
2016 | raid_disks_show(mddev_t *mddev, char *page) | 2197 | raid_disks_show(mddev_t *mddev, char *page) |
2017 | { | 2198 | { |
@@ -2067,6 +2248,200 @@ static struct md_sysfs_entry md_chunk_size = | |||
2067 | __ATTR(chunk_size, 0644, chunk_size_show, chunk_size_store); | 2248 | __ATTR(chunk_size, 0644, chunk_size_show, chunk_size_store); |
2068 | 2249 | ||
2069 | static ssize_t | 2250 | static ssize_t |
2251 | resync_start_show(mddev_t *mddev, char *page) | ||
2252 | { | ||
2253 | return sprintf(page, "%llu\n", (unsigned long long)mddev->recovery_cp); | ||
2254 | } | ||
2255 | |||
2256 | static ssize_t | ||
2257 | resync_start_store(mddev_t *mddev, const char *buf, size_t len) | ||
2258 | { | ||
2259 | /* can only set chunk_size if array is not yet active */ | ||
2260 | char *e; | ||
2261 | unsigned long long n = simple_strtoull(buf, &e, 10); | ||
2262 | |||
2263 | if (mddev->pers) | ||
2264 | return -EBUSY; | ||
2265 | if (!*buf || (*e && *e != '\n')) | ||
2266 | return -EINVAL; | ||
2267 | |||
2268 | mddev->recovery_cp = n; | ||
2269 | return len; | ||
2270 | } | ||
2271 | static struct md_sysfs_entry md_resync_start = | ||
2272 | __ATTR(resync_start, 0644, resync_start_show, resync_start_store); | ||
2273 | |||
2274 | /* | ||
2275 | * The array state can be: | ||
2276 | * | ||
2277 | * clear | ||
2278 | * No devices, no size, no level | ||
2279 | * Equivalent to STOP_ARRAY ioctl | ||
2280 | * inactive | ||
2281 | * May have some settings, but array is not active | ||
2282 | * all IO results in error | ||
2283 | * When written, doesn't tear down array, but just stops it | ||
2284 | * suspended (not supported yet) | ||
2285 | * All IO requests will block. The array can be reconfigured. | ||
2286 | * Writing this, if accepted, will block until array is quiessent | ||
2287 | * readonly | ||
2288 | * no resync can happen. no superblocks get written. | ||
2289 | * write requests fail | ||
2290 | * read-auto | ||
2291 | * like readonly, but behaves like 'clean' on a write request. | ||
2292 | * | ||
2293 | * clean - no pending writes, but otherwise active. | ||
2294 | * When written to inactive array, starts without resync | ||
2295 | * If a write request arrives then | ||
2296 | * if metadata is known, mark 'dirty' and switch to 'active'. | ||
2297 | * if not known, block and switch to write-pending | ||
2298 | * If written to an active array that has pending writes, then fails. | ||
2299 | * active | ||
2300 | * fully active: IO and resync can be happening. | ||
2301 | * When written to inactive array, starts with resync | ||
2302 | * | ||
2303 | * write-pending | ||
2304 | * clean, but writes are blocked waiting for 'active' to be written. | ||
2305 | * | ||
2306 | * active-idle | ||
2307 | * like active, but no writes have been seen for a while (100msec). | ||
2308 | * | ||
2309 | */ | ||
2310 | enum array_state { clear, inactive, suspended, readonly, read_auto, clean, active, | ||
2311 | write_pending, active_idle, bad_word}; | ||
2312 | static char *array_states[] = { | ||
2313 | "clear", "inactive", "suspended", "readonly", "read-auto", "clean", "active", | ||
2314 | "write-pending", "active-idle", NULL }; | ||
2315 | |||
2316 | static int match_word(const char *word, char **list) | ||
2317 | { | ||
2318 | int n; | ||
2319 | for (n=0; list[n]; n++) | ||
2320 | if (cmd_match(word, list[n])) | ||
2321 | break; | ||
2322 | return n; | ||
2323 | } | ||
2324 | |||
2325 | static ssize_t | ||
2326 | array_state_show(mddev_t *mddev, char *page) | ||
2327 | { | ||
2328 | enum array_state st = inactive; | ||
2329 | |||
2330 | if (mddev->pers) | ||
2331 | switch(mddev->ro) { | ||
2332 | case 1: | ||
2333 | st = readonly; | ||
2334 | break; | ||
2335 | case 2: | ||
2336 | st = read_auto; | ||
2337 | break; | ||
2338 | case 0: | ||
2339 | if (mddev->in_sync) | ||
2340 | st = clean; | ||
2341 | else if (mddev->safemode) | ||
2342 | st = active_idle; | ||
2343 | else | ||
2344 | st = active; | ||
2345 | } | ||
2346 | else { | ||
2347 | if (list_empty(&mddev->disks) && | ||
2348 | mddev->raid_disks == 0 && | ||
2349 | mddev->size == 0) | ||
2350 | st = clear; | ||
2351 | else | ||
2352 | st = inactive; | ||
2353 | } | ||
2354 | return sprintf(page, "%s\n", array_states[st]); | ||
2355 | } | ||
2356 | |||
2357 | static int do_md_stop(mddev_t * mddev, int ro); | ||
2358 | static int do_md_run(mddev_t * mddev); | ||
2359 | static int restart_array(mddev_t *mddev); | ||
2360 | |||
2361 | static ssize_t | ||
2362 | array_state_store(mddev_t *mddev, const char *buf, size_t len) | ||
2363 | { | ||
2364 | int err = -EINVAL; | ||
2365 | enum array_state st = match_word(buf, array_states); | ||
2366 | switch(st) { | ||
2367 | case bad_word: | ||
2368 | break; | ||
2369 | case clear: | ||
2370 | /* stopping an active array */ | ||
2371 | if (mddev->pers) { | ||
2372 | if (atomic_read(&mddev->active) > 1) | ||
2373 | return -EBUSY; | ||
2374 | err = do_md_stop(mddev, 0); | ||
2375 | } | ||
2376 | break; | ||
2377 | case inactive: | ||
2378 | /* stopping an active array */ | ||
2379 | if (mddev->pers) { | ||
2380 | if (atomic_read(&mddev->active) > 1) | ||
2381 | return -EBUSY; | ||
2382 | err = do_md_stop(mddev, 2); | ||
2383 | } | ||
2384 | break; | ||
2385 | case suspended: | ||
2386 | break; /* not supported yet */ | ||
2387 | case readonly: | ||
2388 | if (mddev->pers) | ||
2389 | err = do_md_stop(mddev, 1); | ||
2390 | else { | ||
2391 | mddev->ro = 1; | ||
2392 | err = do_md_run(mddev); | ||
2393 | } | ||
2394 | break; | ||
2395 | case read_auto: | ||
2396 | /* stopping an active array */ | ||
2397 | if (mddev->pers) { | ||
2398 | err = do_md_stop(mddev, 1); | ||
2399 | if (err == 0) | ||
2400 | mddev->ro = 2; /* FIXME mark devices writable */ | ||
2401 | } else { | ||
2402 | mddev->ro = 2; | ||
2403 | err = do_md_run(mddev); | ||
2404 | } | ||
2405 | break; | ||
2406 | case clean: | ||
2407 | if (mddev->pers) { | ||
2408 | restart_array(mddev); | ||
2409 | spin_lock_irq(&mddev->write_lock); | ||
2410 | if (atomic_read(&mddev->writes_pending) == 0) { | ||
2411 | mddev->in_sync = 1; | ||
2412 | mddev->sb_dirty = 1; | ||
2413 | } | ||
2414 | spin_unlock_irq(&mddev->write_lock); | ||
2415 | } else { | ||
2416 | mddev->ro = 0; | ||
2417 | mddev->recovery_cp = MaxSector; | ||
2418 | err = do_md_run(mddev); | ||
2419 | } | ||
2420 | break; | ||
2421 | case active: | ||
2422 | if (mddev->pers) { | ||
2423 | restart_array(mddev); | ||
2424 | mddev->sb_dirty = 0; | ||
2425 | wake_up(&mddev->sb_wait); | ||
2426 | err = 0; | ||
2427 | } else { | ||
2428 | mddev->ro = 0; | ||
2429 | err = do_md_run(mddev); | ||
2430 | } | ||
2431 | break; | ||
2432 | case write_pending: | ||
2433 | case active_idle: | ||
2434 | /* these cannot be set */ | ||
2435 | break; | ||
2436 | } | ||
2437 | if (err) | ||
2438 | return err; | ||
2439 | else | ||
2440 | return len; | ||
2441 | } | ||
2442 | static struct md_sysfs_entry md_array_state = __ATTR(array_state, 0644, array_state_show, array_state_store); | ||
2443 | |||
2444 | static ssize_t | ||
2070 | null_show(mddev_t *mddev, char *page) | 2445 | null_show(mddev_t *mddev, char *page) |
2071 | { | 2446 | { |
2072 | return -EINVAL; | 2447 | return -EINVAL; |
@@ -2428,11 +2803,15 @@ __ATTR(suspend_hi, S_IRUGO|S_IWUSR, suspend_hi_show, suspend_hi_store); | |||
2428 | 2803 | ||
2429 | static struct attribute *md_default_attrs[] = { | 2804 | static struct attribute *md_default_attrs[] = { |
2430 | &md_level.attr, | 2805 | &md_level.attr, |
2806 | &md_layout.attr, | ||
2431 | &md_raid_disks.attr, | 2807 | &md_raid_disks.attr, |
2432 | &md_chunk_size.attr, | 2808 | &md_chunk_size.attr, |
2433 | &md_size.attr, | 2809 | &md_size.attr, |
2810 | &md_resync_start.attr, | ||
2434 | &md_metadata.attr, | 2811 | &md_metadata.attr, |
2435 | &md_new_device.attr, | 2812 | &md_new_device.attr, |
2813 | &md_safe_delay.attr, | ||
2814 | &md_array_state.attr, | ||
2436 | NULL, | 2815 | NULL, |
2437 | }; | 2816 | }; |
2438 | 2817 | ||
@@ -2553,8 +2932,6 @@ static struct kobject *md_probe(dev_t dev, int *part, void *data) | |||
2553 | return NULL; | 2932 | return NULL; |
2554 | } | 2933 | } |
2555 | 2934 | ||
2556 | void md_wakeup_thread(mdk_thread_t *thread); | ||
2557 | |||
2558 | static void md_safemode_timeout(unsigned long data) | 2935 | static void md_safemode_timeout(unsigned long data) |
2559 | { | 2936 | { |
2560 | mddev_t *mddev = (mddev_t *) data; | 2937 | mddev_t *mddev = (mddev_t *) data; |
@@ -2708,7 +3085,7 @@ static int do_md_run(mddev_t * mddev) | |||
2708 | mddev->safemode = 0; | 3085 | mddev->safemode = 0; |
2709 | mddev->safemode_timer.function = md_safemode_timeout; | 3086 | mddev->safemode_timer.function = md_safemode_timeout; |
2710 | mddev->safemode_timer.data = (unsigned long) mddev; | 3087 | mddev->safemode_timer.data = (unsigned long) mddev; |
2711 | mddev->safemode_delay = (20 * HZ)/1000 +1; /* 20 msec delay */ | 3088 | mddev->safemode_delay = (200 * HZ)/1000 +1; /* 200 msec delay */ |
2712 | mddev->in_sync = 1; | 3089 | mddev->in_sync = 1; |
2713 | 3090 | ||
2714 | ITERATE_RDEV(mddev,rdev,tmp) | 3091 | ITERATE_RDEV(mddev,rdev,tmp) |
@@ -2736,6 +3113,36 @@ static int do_md_run(mddev_t * mddev) | |||
2736 | mddev->queue->queuedata = mddev; | 3113 | mddev->queue->queuedata = mddev; |
2737 | mddev->queue->make_request_fn = mddev->pers->make_request; | 3114 | mddev->queue->make_request_fn = mddev->pers->make_request; |
2738 | 3115 | ||
3116 | /* If there is a partially-recovered drive we need to | ||
3117 | * start recovery here. If we leave it to md_check_recovery, | ||
3118 | * it will remove the drives and not do the right thing | ||
3119 | */ | ||
3120 | if (mddev->degraded) { | ||
3121 | struct list_head *rtmp; | ||
3122 | int spares = 0; | ||
3123 | ITERATE_RDEV(mddev,rdev,rtmp) | ||
3124 | if (rdev->raid_disk >= 0 && | ||
3125 | !test_bit(In_sync, &rdev->flags) && | ||
3126 | !test_bit(Faulty, &rdev->flags)) | ||
3127 | /* complete an interrupted recovery */ | ||
3128 | spares++; | ||
3129 | if (spares && mddev->pers->sync_request) { | ||
3130 | mddev->recovery = 0; | ||
3131 | set_bit(MD_RECOVERY_RUNNING, &mddev->recovery); | ||
3132 | mddev->sync_thread = md_register_thread(md_do_sync, | ||
3133 | mddev, | ||
3134 | "%s_resync"); | ||
3135 | if (!mddev->sync_thread) { | ||
3136 | printk(KERN_ERR "%s: could not start resync" | ||
3137 | " thread...\n", | ||
3138 | mdname(mddev)); | ||
3139 | /* leave the spares where they are, it shouldn't hurt */ | ||
3140 | mddev->recovery = 0; | ||
3141 | } else | ||
3142 | md_wakeup_thread(mddev->sync_thread); | ||
3143 | } | ||
3144 | } | ||
3145 | |||
2739 | mddev->changed = 1; | 3146 | mddev->changed = 1; |
2740 | md_new_event(mddev); | 3147 | md_new_event(mddev); |
2741 | return 0; | 3148 | return 0; |
@@ -2769,18 +3176,47 @@ static int restart_array(mddev_t *mddev) | |||
2769 | */ | 3176 | */ |
2770 | set_bit(MD_RECOVERY_NEEDED, &mddev->recovery); | 3177 | set_bit(MD_RECOVERY_NEEDED, &mddev->recovery); |
2771 | md_wakeup_thread(mddev->thread); | 3178 | md_wakeup_thread(mddev->thread); |
3179 | md_wakeup_thread(mddev->sync_thread); | ||
2772 | err = 0; | 3180 | err = 0; |
2773 | } else { | 3181 | } else |
2774 | printk(KERN_ERR "md: %s has no personality assigned.\n", | ||
2775 | mdname(mddev)); | ||
2776 | err = -EINVAL; | 3182 | err = -EINVAL; |
2777 | } | ||
2778 | 3183 | ||
2779 | out: | 3184 | out: |
2780 | return err; | 3185 | return err; |
2781 | } | 3186 | } |
2782 | 3187 | ||
2783 | static int do_md_stop(mddev_t * mddev, int ro) | 3188 | /* similar to deny_write_access, but accounts for our holding a reference |
3189 | * to the file ourselves */ | ||
3190 | static int deny_bitmap_write_access(struct file * file) | ||
3191 | { | ||
3192 | struct inode *inode = file->f_mapping->host; | ||
3193 | |||
3194 | spin_lock(&inode->i_lock); | ||
3195 | if (atomic_read(&inode->i_writecount) > 1) { | ||
3196 | spin_unlock(&inode->i_lock); | ||
3197 | return -ETXTBSY; | ||
3198 | } | ||
3199 | atomic_set(&inode->i_writecount, -1); | ||
3200 | spin_unlock(&inode->i_lock); | ||
3201 | |||
3202 | return 0; | ||
3203 | } | ||
3204 | |||
3205 | static void restore_bitmap_write_access(struct file *file) | ||
3206 | { | ||
3207 | struct inode *inode = file->f_mapping->host; | ||
3208 | |||
3209 | spin_lock(&inode->i_lock); | ||
3210 | atomic_set(&inode->i_writecount, 1); | ||
3211 | spin_unlock(&inode->i_lock); | ||
3212 | } | ||
3213 | |||
3214 | /* mode: | ||
3215 | * 0 - completely stop and dis-assemble array | ||
3216 | * 1 - switch to readonly | ||
3217 | * 2 - stop but do not disassemble array | ||
3218 | */ | ||
3219 | static int do_md_stop(mddev_t * mddev, int mode) | ||
2784 | { | 3220 | { |
2785 | int err = 0; | 3221 | int err = 0; |
2786 | struct gendisk *disk = mddev->gendisk; | 3222 | struct gendisk *disk = mddev->gendisk; |
@@ -2792,6 +3228,7 @@ static int do_md_stop(mddev_t * mddev, int ro) | |||
2792 | } | 3228 | } |
2793 | 3229 | ||
2794 | if (mddev->sync_thread) { | 3230 | if (mddev->sync_thread) { |
3231 | set_bit(MD_RECOVERY_FROZEN, &mddev->recovery); | ||
2795 | set_bit(MD_RECOVERY_INTR, &mddev->recovery); | 3232 | set_bit(MD_RECOVERY_INTR, &mddev->recovery); |
2796 | md_unregister_thread(mddev->sync_thread); | 3233 | md_unregister_thread(mddev->sync_thread); |
2797 | mddev->sync_thread = NULL; | 3234 | mddev->sync_thread = NULL; |
@@ -2801,12 +3238,15 @@ static int do_md_stop(mddev_t * mddev, int ro) | |||
2801 | 3238 | ||
2802 | invalidate_partition(disk, 0); | 3239 | invalidate_partition(disk, 0); |
2803 | 3240 | ||
2804 | if (ro) { | 3241 | switch(mode) { |
3242 | case 1: /* readonly */ | ||
2805 | err = -ENXIO; | 3243 | err = -ENXIO; |
2806 | if (mddev->ro==1) | 3244 | if (mddev->ro==1) |
2807 | goto out; | 3245 | goto out; |
2808 | mddev->ro = 1; | 3246 | mddev->ro = 1; |
2809 | } else { | 3247 | break; |
3248 | case 0: /* disassemble */ | ||
3249 | case 2: /* stop */ | ||
2810 | bitmap_flush(mddev); | 3250 | bitmap_flush(mddev); |
2811 | md_super_wait(mddev); | 3251 | md_super_wait(mddev); |
2812 | if (mddev->ro) | 3252 | if (mddev->ro) |
@@ -2821,19 +3261,20 @@ static int do_md_stop(mddev_t * mddev, int ro) | |||
2821 | if (mddev->ro) | 3261 | if (mddev->ro) |
2822 | mddev->ro = 0; | 3262 | mddev->ro = 0; |
2823 | } | 3263 | } |
2824 | if (!mddev->in_sync) { | 3264 | if (!mddev->in_sync || mddev->sb_dirty) { |
2825 | /* mark array as shutdown cleanly */ | 3265 | /* mark array as shutdown cleanly */ |
2826 | mddev->in_sync = 1; | 3266 | mddev->in_sync = 1; |
2827 | md_update_sb(mddev); | 3267 | md_update_sb(mddev); |
2828 | } | 3268 | } |
2829 | if (ro) | 3269 | if (mode == 1) |
2830 | set_disk_ro(disk, 1); | 3270 | set_disk_ro(disk, 1); |
3271 | clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery); | ||
2831 | } | 3272 | } |
2832 | 3273 | ||
2833 | /* | 3274 | /* |
2834 | * Free resources if final stop | 3275 | * Free resources if final stop |
2835 | */ | 3276 | */ |
2836 | if (!ro) { | 3277 | if (mode == 0) { |
2837 | mdk_rdev_t *rdev; | 3278 | mdk_rdev_t *rdev; |
2838 | struct list_head *tmp; | 3279 | struct list_head *tmp; |
2839 | struct gendisk *disk; | 3280 | struct gendisk *disk; |
@@ -2841,7 +3282,7 @@ static int do_md_stop(mddev_t * mddev, int ro) | |||
2841 | 3282 | ||
2842 | bitmap_destroy(mddev); | 3283 | bitmap_destroy(mddev); |
2843 | if (mddev->bitmap_file) { | 3284 | if (mddev->bitmap_file) { |
2844 | atomic_set(&mddev->bitmap_file->f_dentry->d_inode->i_writecount, 1); | 3285 | restore_bitmap_write_access(mddev->bitmap_file); |
2845 | fput(mddev->bitmap_file); | 3286 | fput(mddev->bitmap_file); |
2846 | mddev->bitmap_file = NULL; | 3287 | mddev->bitmap_file = NULL; |
2847 | } | 3288 | } |
@@ -2857,11 +3298,15 @@ static int do_md_stop(mddev_t * mddev, int ro) | |||
2857 | export_array(mddev); | 3298 | export_array(mddev); |
2858 | 3299 | ||
2859 | mddev->array_size = 0; | 3300 | mddev->array_size = 0; |
3301 | mddev->size = 0; | ||
3302 | mddev->raid_disks = 0; | ||
3303 | mddev->recovery_cp = 0; | ||
3304 | |||
2860 | disk = mddev->gendisk; | 3305 | disk = mddev->gendisk; |
2861 | if (disk) | 3306 | if (disk) |
2862 | set_capacity(disk, 0); | 3307 | set_capacity(disk, 0); |
2863 | mddev->changed = 1; | 3308 | mddev->changed = 1; |
2864 | } else | 3309 | } else if (mddev->pers) |
2865 | printk(KERN_INFO "md: %s switched to read-only mode.\n", | 3310 | printk(KERN_INFO "md: %s switched to read-only mode.\n", |
2866 | mdname(mddev)); | 3311 | mdname(mddev)); |
2867 | err = 0; | 3312 | err = 0; |
@@ -3264,6 +3709,17 @@ static int add_new_disk(mddev_t * mddev, mdu_disk_info_t *info) | |||
3264 | 3709 | ||
3265 | rdev->raid_disk = -1; | 3710 | rdev->raid_disk = -1; |
3266 | err = bind_rdev_to_array(rdev, mddev); | 3711 | err = bind_rdev_to_array(rdev, mddev); |
3712 | if (!err && !mddev->pers->hot_remove_disk) { | ||
3713 | /* If there is hot_add_disk but no hot_remove_disk | ||
3714 | * then added disks for geometry changes, | ||
3715 | * and should be added immediately. | ||
3716 | */ | ||
3717 | super_types[mddev->major_version]. | ||
3718 | validate_super(mddev, rdev); | ||
3719 | err = mddev->pers->hot_add_disk(mddev, rdev); | ||
3720 | if (err) | ||
3721 | unbind_rdev_from_array(rdev); | ||
3722 | } | ||
3267 | if (err) | 3723 | if (err) |
3268 | export_rdev(rdev); | 3724 | export_rdev(rdev); |
3269 | 3725 | ||
@@ -3434,23 +3890,6 @@ abort_export: | |||
3434 | return err; | 3890 | return err; |
3435 | } | 3891 | } |
3436 | 3892 | ||
3437 | /* similar to deny_write_access, but accounts for our holding a reference | ||
3438 | * to the file ourselves */ | ||
3439 | static int deny_bitmap_write_access(struct file * file) | ||
3440 | { | ||
3441 | struct inode *inode = file->f_mapping->host; | ||
3442 | |||
3443 | spin_lock(&inode->i_lock); | ||
3444 | if (atomic_read(&inode->i_writecount) > 1) { | ||
3445 | spin_unlock(&inode->i_lock); | ||
3446 | return -ETXTBSY; | ||
3447 | } | ||
3448 | atomic_set(&inode->i_writecount, -1); | ||
3449 | spin_unlock(&inode->i_lock); | ||
3450 | |||
3451 | return 0; | ||
3452 | } | ||
3453 | |||
3454 | static int set_bitmap_file(mddev_t *mddev, int fd) | 3893 | static int set_bitmap_file(mddev_t *mddev, int fd) |
3455 | { | 3894 | { |
3456 | int err; | 3895 | int err; |
@@ -3491,12 +3930,17 @@ static int set_bitmap_file(mddev_t *mddev, int fd) | |||
3491 | mddev->pers->quiesce(mddev, 1); | 3930 | mddev->pers->quiesce(mddev, 1); |
3492 | if (fd >= 0) | 3931 | if (fd >= 0) |
3493 | err = bitmap_create(mddev); | 3932 | err = bitmap_create(mddev); |
3494 | if (fd < 0 || err) | 3933 | if (fd < 0 || err) { |
3495 | bitmap_destroy(mddev); | 3934 | bitmap_destroy(mddev); |
3935 | fd = -1; /* make sure to put the file */ | ||
3936 | } | ||
3496 | mddev->pers->quiesce(mddev, 0); | 3937 | mddev->pers->quiesce(mddev, 0); |
3497 | } else if (fd < 0) { | 3938 | } |
3498 | if (mddev->bitmap_file) | 3939 | if (fd < 0) { |
3940 | if (mddev->bitmap_file) { | ||
3941 | restore_bitmap_write_access(mddev->bitmap_file); | ||
3499 | fput(mddev->bitmap_file); | 3942 | fput(mddev->bitmap_file); |
3943 | } | ||
3500 | mddev->bitmap_file = NULL; | 3944 | mddev->bitmap_file = NULL; |
3501 | } | 3945 | } |
3502 | 3946 | ||
@@ -3977,11 +4421,6 @@ static int md_ioctl(struct inode *inode, struct file *file, | |||
3977 | goto done_unlock; | 4421 | goto done_unlock; |
3978 | 4422 | ||
3979 | default: | 4423 | default: |
3980 | if (_IOC_TYPE(cmd) == MD_MAJOR) | ||
3981 | printk(KERN_WARNING "md: %s(pid %d) used" | ||
3982 | " obsolete MD ioctl, upgrade your" | ||
3983 | " software to use new ictls.\n", | ||
3984 | current->comm, current->pid); | ||
3985 | err = -EINVAL; | 4424 | err = -EINVAL; |
3986 | goto abort_unlock; | 4425 | goto abort_unlock; |
3987 | } | 4426 | } |
@@ -4586,7 +5025,7 @@ void md_write_start(mddev_t *mddev, struct bio *bi) | |||
4586 | spin_lock_irq(&mddev->write_lock); | 5025 | spin_lock_irq(&mddev->write_lock); |
4587 | if (mddev->in_sync) { | 5026 | if (mddev->in_sync) { |
4588 | mddev->in_sync = 0; | 5027 | mddev->in_sync = 0; |
4589 | mddev->sb_dirty = 1; | 5028 | mddev->sb_dirty = 3; |
4590 | md_wakeup_thread(mddev->thread); | 5029 | md_wakeup_thread(mddev->thread); |
4591 | } | 5030 | } |
4592 | spin_unlock_irq(&mddev->write_lock); | 5031 | spin_unlock_irq(&mddev->write_lock); |
@@ -4599,7 +5038,7 @@ void md_write_end(mddev_t *mddev) | |||
4599 | if (atomic_dec_and_test(&mddev->writes_pending)) { | 5038 | if (atomic_dec_and_test(&mddev->writes_pending)) { |
4600 | if (mddev->safemode == 2) | 5039 | if (mddev->safemode == 2) |
4601 | md_wakeup_thread(mddev->thread); | 5040 | md_wakeup_thread(mddev->thread); |
4602 | else | 5041 | else if (mddev->safemode_delay) |
4603 | mod_timer(&mddev->safemode_timer, jiffies + mddev->safemode_delay); | 5042 | mod_timer(&mddev->safemode_timer, jiffies + mddev->safemode_delay); |
4604 | } | 5043 | } |
4605 | } | 5044 | } |
@@ -4620,10 +5059,14 @@ void md_do_sync(mddev_t *mddev) | |||
4620 | struct list_head *tmp; | 5059 | struct list_head *tmp; |
4621 | sector_t last_check; | 5060 | sector_t last_check; |
4622 | int skipped = 0; | 5061 | int skipped = 0; |
5062 | struct list_head *rtmp; | ||
5063 | mdk_rdev_t *rdev; | ||
4623 | 5064 | ||
4624 | /* just incase thread restarts... */ | 5065 | /* just incase thread restarts... */ |
4625 | if (test_bit(MD_RECOVERY_DONE, &mddev->recovery)) | 5066 | if (test_bit(MD_RECOVERY_DONE, &mddev->recovery)) |
4626 | return; | 5067 | return; |
5068 | if (mddev->ro) /* never try to sync a read-only array */ | ||
5069 | return; | ||
4627 | 5070 | ||
4628 | /* we overload curr_resync somewhat here. | 5071 | /* we overload curr_resync somewhat here. |
4629 | * 0 == not engaged in resync at all | 5072 | * 0 == not engaged in resync at all |
@@ -4682,17 +5125,30 @@ void md_do_sync(mddev_t *mddev) | |||
4682 | } | 5125 | } |
4683 | } while (mddev->curr_resync < 2); | 5126 | } while (mddev->curr_resync < 2); |
4684 | 5127 | ||
5128 | j = 0; | ||
4685 | if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) { | 5129 | if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) { |
4686 | /* resync follows the size requested by the personality, | 5130 | /* resync follows the size requested by the personality, |
4687 | * which defaults to physical size, but can be virtual size | 5131 | * which defaults to physical size, but can be virtual size |
4688 | */ | 5132 | */ |
4689 | max_sectors = mddev->resync_max_sectors; | 5133 | max_sectors = mddev->resync_max_sectors; |
4690 | mddev->resync_mismatches = 0; | 5134 | mddev->resync_mismatches = 0; |
5135 | /* we don't use the checkpoint if there's a bitmap */ | ||
5136 | if (!mddev->bitmap && | ||
5137 | !test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery)) | ||
5138 | j = mddev->recovery_cp; | ||
4691 | } else if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery)) | 5139 | } else if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery)) |
4692 | max_sectors = mddev->size << 1; | 5140 | max_sectors = mddev->size << 1; |
4693 | else | 5141 | else { |
4694 | /* recovery follows the physical size of devices */ | 5142 | /* recovery follows the physical size of devices */ |
4695 | max_sectors = mddev->size << 1; | 5143 | max_sectors = mddev->size << 1; |
5144 | j = MaxSector; | ||
5145 | ITERATE_RDEV(mddev,rdev,rtmp) | ||
5146 | if (rdev->raid_disk >= 0 && | ||
5147 | !test_bit(Faulty, &rdev->flags) && | ||
5148 | !test_bit(In_sync, &rdev->flags) && | ||
5149 | rdev->recovery_offset < j) | ||
5150 | j = rdev->recovery_offset; | ||
5151 | } | ||
4696 | 5152 | ||
4697 | printk(KERN_INFO "md: syncing RAID array %s\n", mdname(mddev)); | 5153 | printk(KERN_INFO "md: syncing RAID array %s\n", mdname(mddev)); |
4698 | printk(KERN_INFO "md: minimum _guaranteed_ reconstruction speed:" | 5154 | printk(KERN_INFO "md: minimum _guaranteed_ reconstruction speed:" |
@@ -4702,12 +5158,7 @@ void md_do_sync(mddev_t *mddev) | |||
4702 | speed_max(mddev)); | 5158 | speed_max(mddev)); |
4703 | 5159 | ||
4704 | is_mddev_idle(mddev); /* this also initializes IO event counters */ | 5160 | is_mddev_idle(mddev); /* this also initializes IO event counters */ |
4705 | /* we don't use the checkpoint if there's a bitmap */ | 5161 | |
4706 | if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery) && !mddev->bitmap | ||
4707 | && ! test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery)) | ||
4708 | j = mddev->recovery_cp; | ||
4709 | else | ||
4710 | j = 0; | ||
4711 | io_sectors = 0; | 5162 | io_sectors = 0; |
4712 | for (m = 0; m < SYNC_MARKS; m++) { | 5163 | for (m = 0; m < SYNC_MARKS; m++) { |
4713 | mark[m] = jiffies; | 5164 | mark[m] = jiffies; |
@@ -4828,15 +5279,28 @@ void md_do_sync(mddev_t *mddev) | |||
4828 | if (!test_bit(MD_RECOVERY_ERR, &mddev->recovery) && | 5279 | if (!test_bit(MD_RECOVERY_ERR, &mddev->recovery) && |
4829 | test_bit(MD_RECOVERY_SYNC, &mddev->recovery) && | 5280 | test_bit(MD_RECOVERY_SYNC, &mddev->recovery) && |
4830 | !test_bit(MD_RECOVERY_CHECK, &mddev->recovery) && | 5281 | !test_bit(MD_RECOVERY_CHECK, &mddev->recovery) && |
4831 | mddev->curr_resync > 2 && | 5282 | mddev->curr_resync > 2) { |
4832 | mddev->curr_resync >= mddev->recovery_cp) { | 5283 | if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) { |
4833 | if (test_bit(MD_RECOVERY_INTR, &mddev->recovery)) { | 5284 | if (test_bit(MD_RECOVERY_INTR, &mddev->recovery)) { |
4834 | printk(KERN_INFO | 5285 | if (mddev->curr_resync >= mddev->recovery_cp) { |
4835 | "md: checkpointing recovery of %s.\n", | 5286 | printk(KERN_INFO |
4836 | mdname(mddev)); | 5287 | "md: checkpointing recovery of %s.\n", |
4837 | mddev->recovery_cp = mddev->curr_resync; | 5288 | mdname(mddev)); |
4838 | } else | 5289 | mddev->recovery_cp = mddev->curr_resync; |
4839 | mddev->recovery_cp = MaxSector; | 5290 | } |
5291 | } else | ||
5292 | mddev->recovery_cp = MaxSector; | ||
5293 | } else { | ||
5294 | if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery)) | ||
5295 | mddev->curr_resync = MaxSector; | ||
5296 | ITERATE_RDEV(mddev,rdev,rtmp) | ||
5297 | if (rdev->raid_disk >= 0 && | ||
5298 | !test_bit(Faulty, &rdev->flags) && | ||
5299 | !test_bit(In_sync, &rdev->flags) && | ||
5300 | rdev->recovery_offset < mddev->curr_resync) | ||
5301 | rdev->recovery_offset = mddev->curr_resync; | ||
5302 | mddev->sb_dirty = 1; | ||
5303 | } | ||
4840 | } | 5304 | } |
4841 | 5305 | ||
4842 | skip: | 5306 | skip: |
@@ -4908,7 +5372,7 @@ void md_check_recovery(mddev_t *mddev) | |||
4908 | if (mddev->safemode && !atomic_read(&mddev->writes_pending) && | 5372 | if (mddev->safemode && !atomic_read(&mddev->writes_pending) && |
4909 | !mddev->in_sync && mddev->recovery_cp == MaxSector) { | 5373 | !mddev->in_sync && mddev->recovery_cp == MaxSector) { |
4910 | mddev->in_sync = 1; | 5374 | mddev->in_sync = 1; |
4911 | mddev->sb_dirty = 1; | 5375 | mddev->sb_dirty = 3; |
4912 | } | 5376 | } |
4913 | if (mddev->safemode == 1) | 5377 | if (mddev->safemode == 1) |
4914 | mddev->safemode = 0; | 5378 | mddev->safemode = 0; |
@@ -4957,6 +5421,8 @@ void md_check_recovery(mddev_t *mddev) | |||
4957 | clear_bit(MD_RECOVERY_INTR, &mddev->recovery); | 5421 | clear_bit(MD_RECOVERY_INTR, &mddev->recovery); |
4958 | clear_bit(MD_RECOVERY_DONE, &mddev->recovery); | 5422 | clear_bit(MD_RECOVERY_DONE, &mddev->recovery); |
4959 | 5423 | ||
5424 | if (test_bit(MD_RECOVERY_FROZEN, &mddev->recovery)) | ||
5425 | goto unlock; | ||
4960 | /* no recovery is running. | 5426 | /* no recovery is running. |
4961 | * remove any failed drives, then | 5427 | * remove any failed drives, then |
4962 | * add spares if possible. | 5428 | * add spares if possible. |
@@ -4979,6 +5445,7 @@ void md_check_recovery(mddev_t *mddev) | |||
4979 | ITERATE_RDEV(mddev,rdev,rtmp) | 5445 | ITERATE_RDEV(mddev,rdev,rtmp) |
4980 | if (rdev->raid_disk < 0 | 5446 | if (rdev->raid_disk < 0 |
4981 | && !test_bit(Faulty, &rdev->flags)) { | 5447 | && !test_bit(Faulty, &rdev->flags)) { |
5448 | rdev->recovery_offset = 0; | ||
4982 | if (mddev->pers->hot_add_disk(mddev,rdev)) { | 5449 | if (mddev->pers->hot_add_disk(mddev,rdev)) { |
4983 | char nm[20]; | 5450 | char nm[20]; |
4984 | sprintf(nm, "rd%d", rdev->raid_disk); | 5451 | sprintf(nm, "rd%d", rdev->raid_disk); |
@@ -5216,7 +5683,6 @@ EXPORT_SYMBOL(md_write_end); | |||
5216 | EXPORT_SYMBOL(md_register_thread); | 5683 | EXPORT_SYMBOL(md_register_thread); |
5217 | EXPORT_SYMBOL(md_unregister_thread); | 5684 | EXPORT_SYMBOL(md_unregister_thread); |
5218 | EXPORT_SYMBOL(md_wakeup_thread); | 5685 | EXPORT_SYMBOL(md_wakeup_thread); |
5219 | EXPORT_SYMBOL(md_print_devices); | ||
5220 | EXPORT_SYMBOL(md_check_recovery); | 5686 | EXPORT_SYMBOL(md_check_recovery); |
5221 | MODULE_LICENSE("GPL"); | 5687 | MODULE_LICENSE("GPL"); |
5222 | MODULE_ALIAS("md"); | 5688 | MODULE_ALIAS("md"); |
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 4070eff6f0f8..cead918578a7 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c | |||
@@ -374,26 +374,26 @@ static int raid1_end_write_request(struct bio *bio, unsigned int bytes_done, int | |||
374 | * already. | 374 | * already. |
375 | */ | 375 | */ |
376 | if (atomic_dec_and_test(&r1_bio->remaining)) { | 376 | if (atomic_dec_and_test(&r1_bio->remaining)) { |
377 | if (test_bit(R1BIO_BarrierRetry, &r1_bio->state)) { | 377 | if (test_bit(R1BIO_BarrierRetry, &r1_bio->state)) |
378 | reschedule_retry(r1_bio); | 378 | reschedule_retry(r1_bio); |
379 | goto out; | 379 | else { |
380 | } | 380 | /* it really is the end of this request */ |
381 | /* it really is the end of this request */ | 381 | if (test_bit(R1BIO_BehindIO, &r1_bio->state)) { |
382 | if (test_bit(R1BIO_BehindIO, &r1_bio->state)) { | 382 | /* free extra copy of the data pages */ |
383 | /* free extra copy of the data pages */ | 383 | int i = bio->bi_vcnt; |
384 | int i = bio->bi_vcnt; | 384 | while (i--) |
385 | while (i--) | 385 | safe_put_page(bio->bi_io_vec[i].bv_page); |
386 | safe_put_page(bio->bi_io_vec[i].bv_page); | 386 | } |
387 | /* clear the bitmap if all writes complete successfully */ | ||
388 | bitmap_endwrite(r1_bio->mddev->bitmap, r1_bio->sector, | ||
389 | r1_bio->sectors, | ||
390 | !test_bit(R1BIO_Degraded, &r1_bio->state), | ||
391 | behind); | ||
392 | md_write_end(r1_bio->mddev); | ||
393 | raid_end_bio_io(r1_bio); | ||
387 | } | 394 | } |
388 | /* clear the bitmap if all writes complete successfully */ | ||
389 | bitmap_endwrite(r1_bio->mddev->bitmap, r1_bio->sector, | ||
390 | r1_bio->sectors, | ||
391 | !test_bit(R1BIO_Degraded, &r1_bio->state), | ||
392 | behind); | ||
393 | md_write_end(r1_bio->mddev); | ||
394 | raid_end_bio_io(r1_bio); | ||
395 | } | 395 | } |
396 | out: | 396 | |
397 | if (to_put) | 397 | if (to_put) |
398 | bio_put(to_put); | 398 | bio_put(to_put); |
399 | 399 | ||
@@ -1625,6 +1625,12 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i | |||
1625 | /* before building a request, check if we can skip these blocks.. | 1625 | /* before building a request, check if we can skip these blocks.. |
1626 | * This call the bitmap_start_sync doesn't actually record anything | 1626 | * This call the bitmap_start_sync doesn't actually record anything |
1627 | */ | 1627 | */ |
1628 | if (mddev->bitmap == NULL && | ||
1629 | mddev->recovery_cp == MaxSector && | ||
1630 | conf->fullsync == 0) { | ||
1631 | *skipped = 1; | ||
1632 | return max_sector - sector_nr; | ||
1633 | } | ||
1628 | if (!bitmap_start_sync(mddev->bitmap, sector_nr, &sync_blocks, 1) && | 1634 | if (!bitmap_start_sync(mddev->bitmap, sector_nr, &sync_blocks, 1) && |
1629 | !conf->fullsync && !test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery)) { | 1635 | !conf->fullsync && !test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery)) { |
1630 | /* We can skip this block, and probably several more */ | 1636 | /* We can skip this block, and probably several more */ |
@@ -1888,7 +1894,8 @@ static int run(mddev_t *mddev) | |||
1888 | 1894 | ||
1889 | disk = conf->mirrors + i; | 1895 | disk = conf->mirrors + i; |
1890 | 1896 | ||
1891 | if (!disk->rdev) { | 1897 | if (!disk->rdev || |
1898 | !test_bit(In_sync, &disk->rdev->flags)) { | ||
1892 | disk->head_position = 0; | 1899 | disk->head_position = 0; |
1893 | mddev->degraded++; | 1900 | mddev->degraded++; |
1894 | } | 1901 | } |
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 1440935414e6..7f636283a1ba 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c | |||
@@ -29,6 +29,7 @@ | |||
29 | * raid_disks | 29 | * raid_disks |
30 | * near_copies (stored in low byte of layout) | 30 | * near_copies (stored in low byte of layout) |
31 | * far_copies (stored in second byte of layout) | 31 | * far_copies (stored in second byte of layout) |
32 | * far_offset (stored in bit 16 of layout ) | ||
32 | * | 33 | * |
33 | * The data to be stored is divided into chunks using chunksize. | 34 | * The data to be stored is divided into chunks using chunksize. |
34 | * Each device is divided into far_copies sections. | 35 | * Each device is divided into far_copies sections. |
@@ -36,10 +37,14 @@ | |||
36 | * near_copies copies of each chunk is stored (each on a different drive). | 37 | * near_copies copies of each chunk is stored (each on a different drive). |
37 | * The starting device for each section is offset near_copies from the starting | 38 | * The starting device for each section is offset near_copies from the starting |
38 | * device of the previous section. | 39 | * device of the previous section. |
39 | * Thus there are (near_copies*far_copies) of each chunk, and each is on a different | 40 | * Thus they are (near_copies*far_copies) of each chunk, and each is on a different |
40 | * drive. | 41 | * drive. |
41 | * near_copies and far_copies must be at least one, and their product is at most | 42 | * near_copies and far_copies must be at least one, and their product is at most |
42 | * raid_disks. | 43 | * raid_disks. |
44 | * | ||
45 | * If far_offset is true, then the far_copies are handled a bit differently. | ||
46 | * The copies are still in different stripes, but instead of be very far apart | ||
47 | * on disk, there are adjacent stripes. | ||
43 | */ | 48 | */ |
44 | 49 | ||
45 | /* | 50 | /* |
@@ -357,8 +362,7 @@ static int raid10_end_write_request(struct bio *bio, unsigned int bytes_done, in | |||
357 | * With this layout, and block is never stored twice on the one device. | 362 | * With this layout, and block is never stored twice on the one device. |
358 | * | 363 | * |
359 | * raid10_find_phys finds the sector offset of a given virtual sector | 364 | * raid10_find_phys finds the sector offset of a given virtual sector |
360 | * on each device that it is on. If a block isn't on a device, | 365 | * on each device that it is on. |
361 | * that entry in the array is set to MaxSector. | ||
362 | * | 366 | * |
363 | * raid10_find_virt does the reverse mapping, from a device and a | 367 | * raid10_find_virt does the reverse mapping, from a device and a |
364 | * sector offset to a virtual address | 368 | * sector offset to a virtual address |
@@ -381,6 +385,8 @@ static void raid10_find_phys(conf_t *conf, r10bio_t *r10bio) | |||
381 | chunk *= conf->near_copies; | 385 | chunk *= conf->near_copies; |
382 | stripe = chunk; | 386 | stripe = chunk; |
383 | dev = sector_div(stripe, conf->raid_disks); | 387 | dev = sector_div(stripe, conf->raid_disks); |
388 | if (conf->far_offset) | ||
389 | stripe *= conf->far_copies; | ||
384 | 390 | ||
385 | sector += stripe << conf->chunk_shift; | 391 | sector += stripe << conf->chunk_shift; |
386 | 392 | ||
@@ -414,16 +420,24 @@ static sector_t raid10_find_virt(conf_t *conf, sector_t sector, int dev) | |||
414 | { | 420 | { |
415 | sector_t offset, chunk, vchunk; | 421 | sector_t offset, chunk, vchunk; |
416 | 422 | ||
417 | while (sector > conf->stride) { | ||
418 | sector -= conf->stride; | ||
419 | if (dev < conf->near_copies) | ||
420 | dev += conf->raid_disks - conf->near_copies; | ||
421 | else | ||
422 | dev -= conf->near_copies; | ||
423 | } | ||
424 | |||
425 | offset = sector & conf->chunk_mask; | 423 | offset = sector & conf->chunk_mask; |
426 | chunk = sector >> conf->chunk_shift; | 424 | if (conf->far_offset) { |
425 | int fc; | ||
426 | chunk = sector >> conf->chunk_shift; | ||
427 | fc = sector_div(chunk, conf->far_copies); | ||
428 | dev -= fc * conf->near_copies; | ||
429 | if (dev < 0) | ||
430 | dev += conf->raid_disks; | ||
431 | } else { | ||
432 | while (sector > conf->stride) { | ||
433 | sector -= conf->stride; | ||
434 | if (dev < conf->near_copies) | ||
435 | dev += conf->raid_disks - conf->near_copies; | ||
436 | else | ||
437 | dev -= conf->near_copies; | ||
438 | } | ||
439 | chunk = sector >> conf->chunk_shift; | ||
440 | } | ||
427 | vchunk = chunk * conf->raid_disks + dev; | 441 | vchunk = chunk * conf->raid_disks + dev; |
428 | sector_div(vchunk, conf->near_copies); | 442 | sector_div(vchunk, conf->near_copies); |
429 | return (vchunk << conf->chunk_shift) + offset; | 443 | return (vchunk << conf->chunk_shift) + offset; |
@@ -900,9 +914,12 @@ static void status(struct seq_file *seq, mddev_t *mddev) | |||
900 | seq_printf(seq, " %dK chunks", mddev->chunk_size/1024); | 914 | seq_printf(seq, " %dK chunks", mddev->chunk_size/1024); |
901 | if (conf->near_copies > 1) | 915 | if (conf->near_copies > 1) |
902 | seq_printf(seq, " %d near-copies", conf->near_copies); | 916 | seq_printf(seq, " %d near-copies", conf->near_copies); |
903 | if (conf->far_copies > 1) | 917 | if (conf->far_copies > 1) { |
904 | seq_printf(seq, " %d far-copies", conf->far_copies); | 918 | if (conf->far_offset) |
905 | 919 | seq_printf(seq, " %d offset-copies", conf->far_copies); | |
920 | else | ||
921 | seq_printf(seq, " %d far-copies", conf->far_copies); | ||
922 | } | ||
906 | seq_printf(seq, " [%d/%d] [", conf->raid_disks, | 923 | seq_printf(seq, " [%d/%d] [", conf->raid_disks, |
907 | conf->working_disks); | 924 | conf->working_disks); |
908 | for (i = 0; i < conf->raid_disks; i++) | 925 | for (i = 0; i < conf->raid_disks; i++) |
@@ -1915,7 +1932,7 @@ static int run(mddev_t *mddev) | |||
1915 | mirror_info_t *disk; | 1932 | mirror_info_t *disk; |
1916 | mdk_rdev_t *rdev; | 1933 | mdk_rdev_t *rdev; |
1917 | struct list_head *tmp; | 1934 | struct list_head *tmp; |
1918 | int nc, fc; | 1935 | int nc, fc, fo; |
1919 | sector_t stride, size; | 1936 | sector_t stride, size; |
1920 | 1937 | ||
1921 | if (mddev->chunk_size == 0) { | 1938 | if (mddev->chunk_size == 0) { |
@@ -1925,8 +1942,9 @@ static int run(mddev_t *mddev) | |||
1925 | 1942 | ||
1926 | nc = mddev->layout & 255; | 1943 | nc = mddev->layout & 255; |
1927 | fc = (mddev->layout >> 8) & 255; | 1944 | fc = (mddev->layout >> 8) & 255; |
1945 | fo = mddev->layout & (1<<16); | ||
1928 | if ((nc*fc) <2 || (nc*fc) > mddev->raid_disks || | 1946 | if ((nc*fc) <2 || (nc*fc) > mddev->raid_disks || |
1929 | (mddev->layout >> 16)) { | 1947 | (mddev->layout >> 17)) { |
1930 | printk(KERN_ERR "raid10: %s: unsupported raid10 layout: 0x%8x\n", | 1948 | printk(KERN_ERR "raid10: %s: unsupported raid10 layout: 0x%8x\n", |
1931 | mdname(mddev), mddev->layout); | 1949 | mdname(mddev), mddev->layout); |
1932 | goto out; | 1950 | goto out; |
@@ -1958,12 +1976,16 @@ static int run(mddev_t *mddev) | |||
1958 | conf->near_copies = nc; | 1976 | conf->near_copies = nc; |
1959 | conf->far_copies = fc; | 1977 | conf->far_copies = fc; |
1960 | conf->copies = nc*fc; | 1978 | conf->copies = nc*fc; |
1979 | conf->far_offset = fo; | ||
1961 | conf->chunk_mask = (sector_t)(mddev->chunk_size>>9)-1; | 1980 | conf->chunk_mask = (sector_t)(mddev->chunk_size>>9)-1; |
1962 | conf->chunk_shift = ffz(~mddev->chunk_size) - 9; | 1981 | conf->chunk_shift = ffz(~mddev->chunk_size) - 9; |
1963 | stride = mddev->size >> (conf->chunk_shift-1); | 1982 | if (fo) |
1964 | sector_div(stride, fc); | 1983 | conf->stride = 1 << conf->chunk_shift; |
1965 | conf->stride = stride << conf->chunk_shift; | 1984 | else { |
1966 | 1985 | stride = mddev->size >> (conf->chunk_shift-1); | |
1986 | sector_div(stride, fc); | ||
1987 | conf->stride = stride << conf->chunk_shift; | ||
1988 | } | ||
1967 | conf->r10bio_pool = mempool_create(NR_RAID10_BIOS, r10bio_pool_alloc, | 1989 | conf->r10bio_pool = mempool_create(NR_RAID10_BIOS, r10bio_pool_alloc, |
1968 | r10bio_pool_free, conf); | 1990 | r10bio_pool_free, conf); |
1969 | if (!conf->r10bio_pool) { | 1991 | if (!conf->r10bio_pool) { |
@@ -2015,7 +2037,8 @@ static int run(mddev_t *mddev) | |||
2015 | 2037 | ||
2016 | disk = conf->mirrors + i; | 2038 | disk = conf->mirrors + i; |
2017 | 2039 | ||
2018 | if (!disk->rdev) { | 2040 | if (!disk->rdev || |
2041 | !test_bit(In_sync, &rdev->flags)) { | ||
2019 | disk->head_position = 0; | 2042 | disk->head_position = 0; |
2020 | mddev->degraded++; | 2043 | mddev->degraded++; |
2021 | } | 2044 | } |
@@ -2037,7 +2060,13 @@ static int run(mddev_t *mddev) | |||
2037 | /* | 2060 | /* |
2038 | * Ok, everything is just fine now | 2061 | * Ok, everything is just fine now |
2039 | */ | 2062 | */ |
2040 | size = conf->stride * conf->raid_disks; | 2063 | if (conf->far_offset) { |
2064 | size = mddev->size >> (conf->chunk_shift-1); | ||
2065 | size *= conf->raid_disks; | ||
2066 | size <<= conf->chunk_shift; | ||
2067 | sector_div(size, conf->far_copies); | ||
2068 | } else | ||
2069 | size = conf->stride * conf->raid_disks; | ||
2041 | sector_div(size, conf->near_copies); | 2070 | sector_div(size, conf->near_copies); |
2042 | mddev->array_size = size/2; | 2071 | mddev->array_size = size/2; |
2043 | mddev->resync_max_sectors = size; | 2072 | mddev->resync_max_sectors = size; |
@@ -2050,7 +2079,7 @@ static int run(mddev_t *mddev) | |||
2050 | * maybe... | 2079 | * maybe... |
2051 | */ | 2080 | */ |
2052 | { | 2081 | { |
2053 | int stripe = conf->raid_disks * mddev->chunk_size / PAGE_SIZE; | 2082 | int stripe = conf->raid_disks * (mddev->chunk_size / PAGE_SIZE); |
2054 | stripe /= conf->near_copies; | 2083 | stripe /= conf->near_copies; |
2055 | if (mddev->queue->backing_dev_info.ra_pages < 2* stripe) | 2084 | if (mddev->queue->backing_dev_info.ra_pages < 2* stripe) |
2056 | mddev->queue->backing_dev_info.ra_pages = 2* stripe; | 2085 | mddev->queue->backing_dev_info.ra_pages = 2* stripe; |
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 31843604049c..f920e50ea124 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c | |||
@@ -2,8 +2,11 @@ | |||
2 | * raid5.c : Multiple Devices driver for Linux | 2 | * raid5.c : Multiple Devices driver for Linux |
3 | * Copyright (C) 1996, 1997 Ingo Molnar, Miguel de Icaza, Gadi Oxman | 3 | * Copyright (C) 1996, 1997 Ingo Molnar, Miguel de Icaza, Gadi Oxman |
4 | * Copyright (C) 1999, 2000 Ingo Molnar | 4 | * Copyright (C) 1999, 2000 Ingo Molnar |
5 | * Copyright (C) 2002, 2003 H. Peter Anvin | ||
5 | * | 6 | * |
6 | * RAID-5 management functions. | 7 | * RAID-4/5/6 management functions. |
8 | * Thanks to Penguin Computing for making the RAID-6 development possible | ||
9 | * by donating a test server! | ||
7 | * | 10 | * |
8 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
9 | * it under the terms of the GNU General Public License as published by | 12 | * it under the terms of the GNU General Public License as published by |
@@ -19,11 +22,11 @@ | |||
19 | #include <linux/config.h> | 22 | #include <linux/config.h> |
20 | #include <linux/module.h> | 23 | #include <linux/module.h> |
21 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
22 | #include <linux/raid/raid5.h> | ||
23 | #include <linux/highmem.h> | 25 | #include <linux/highmem.h> |
24 | #include <linux/bitops.h> | 26 | #include <linux/bitops.h> |
25 | #include <linux/kthread.h> | 27 | #include <linux/kthread.h> |
26 | #include <asm/atomic.h> | 28 | #include <asm/atomic.h> |
29 | #include "raid6.h" | ||
27 | 30 | ||
28 | #include <linux/raid/bitmap.h> | 31 | #include <linux/raid/bitmap.h> |
29 | 32 | ||
@@ -68,6 +71,16 @@ | |||
68 | #define __inline__ | 71 | #define __inline__ |
69 | #endif | 72 | #endif |
70 | 73 | ||
74 | #if !RAID6_USE_EMPTY_ZERO_PAGE | ||
75 | /* In .bss so it's zeroed */ | ||
76 | const char raid6_empty_zero_page[PAGE_SIZE] __attribute__((aligned(256))); | ||
77 | #endif | ||
78 | |||
79 | static inline int raid6_next_disk(int disk, int raid_disks) | ||
80 | { | ||
81 | disk++; | ||
82 | return (disk < raid_disks) ? disk : 0; | ||
83 | } | ||
71 | static void print_raid5_conf (raid5_conf_t *conf); | 84 | static void print_raid5_conf (raid5_conf_t *conf); |
72 | 85 | ||
73 | static void __release_stripe(raid5_conf_t *conf, struct stripe_head *sh) | 86 | static void __release_stripe(raid5_conf_t *conf, struct stripe_head *sh) |
@@ -104,7 +117,7 @@ static void release_stripe(struct stripe_head *sh) | |||
104 | { | 117 | { |
105 | raid5_conf_t *conf = sh->raid_conf; | 118 | raid5_conf_t *conf = sh->raid_conf; |
106 | unsigned long flags; | 119 | unsigned long flags; |
107 | 120 | ||
108 | spin_lock_irqsave(&conf->device_lock, flags); | 121 | spin_lock_irqsave(&conf->device_lock, flags); |
109 | __release_stripe(conf, sh); | 122 | __release_stripe(conf, sh); |
110 | spin_unlock_irqrestore(&conf->device_lock, flags); | 123 | spin_unlock_irqrestore(&conf->device_lock, flags); |
@@ -117,7 +130,7 @@ static inline void remove_hash(struct stripe_head *sh) | |||
117 | hlist_del_init(&sh->hash); | 130 | hlist_del_init(&sh->hash); |
118 | } | 131 | } |
119 | 132 | ||
120 | static void insert_hash(raid5_conf_t *conf, struct stripe_head *sh) | 133 | static inline void insert_hash(raid5_conf_t *conf, struct stripe_head *sh) |
121 | { | 134 | { |
122 | struct hlist_head *hp = stripe_hash(conf, sh->sector); | 135 | struct hlist_head *hp = stripe_hash(conf, sh->sector); |
123 | 136 | ||
@@ -190,7 +203,7 @@ static void init_stripe(struct stripe_head *sh, sector_t sector, int pd_idx, int | |||
190 | (unsigned long long)sh->sector); | 203 | (unsigned long long)sh->sector); |
191 | 204 | ||
192 | remove_hash(sh); | 205 | remove_hash(sh); |
193 | 206 | ||
194 | sh->sector = sector; | 207 | sh->sector = sector; |
195 | sh->pd_idx = pd_idx; | 208 | sh->pd_idx = pd_idx; |
196 | sh->state = 0; | 209 | sh->state = 0; |
@@ -269,8 +282,9 @@ static struct stripe_head *get_active_stripe(raid5_conf_t *conf, sector_t sector | |||
269 | } else { | 282 | } else { |
270 | if (!test_bit(STRIPE_HANDLE, &sh->state)) | 283 | if (!test_bit(STRIPE_HANDLE, &sh->state)) |
271 | atomic_inc(&conf->active_stripes); | 284 | atomic_inc(&conf->active_stripes); |
272 | if (!list_empty(&sh->lru)) | 285 | if (list_empty(&sh->lru)) |
273 | list_del_init(&sh->lru); | 286 | BUG(); |
287 | list_del_init(&sh->lru); | ||
274 | } | 288 | } |
275 | } | 289 | } |
276 | } while (sh == NULL); | 290 | } while (sh == NULL); |
@@ -321,10 +335,9 @@ static int grow_stripes(raid5_conf_t *conf, int num) | |||
321 | return 1; | 335 | return 1; |
322 | conf->slab_cache = sc; | 336 | conf->slab_cache = sc; |
323 | conf->pool_size = devs; | 337 | conf->pool_size = devs; |
324 | while (num--) { | 338 | while (num--) |
325 | if (!grow_one_stripe(conf)) | 339 | if (!grow_one_stripe(conf)) |
326 | return 1; | 340 | return 1; |
327 | } | ||
328 | return 0; | 341 | return 0; |
329 | } | 342 | } |
330 | 343 | ||
@@ -631,8 +644,7 @@ static void raid5_build_block (struct stripe_head *sh, int i) | |||
631 | dev->req.bi_private = sh; | 644 | dev->req.bi_private = sh; |
632 | 645 | ||
633 | dev->flags = 0; | 646 | dev->flags = 0; |
634 | if (i != sh->pd_idx) | 647 | dev->sector = compute_blocknr(sh, i); |
635 | dev->sector = compute_blocknr(sh, i); | ||
636 | } | 648 | } |
637 | 649 | ||
638 | static void error(mddev_t *mddev, mdk_rdev_t *rdev) | 650 | static void error(mddev_t *mddev, mdk_rdev_t *rdev) |
@@ -659,7 +671,7 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev) | |||
659 | " Operation continuing on %d devices\n", | 671 | " Operation continuing on %d devices\n", |
660 | bdevname(rdev->bdev,b), conf->working_disks); | 672 | bdevname(rdev->bdev,b), conf->working_disks); |
661 | } | 673 | } |
662 | } | 674 | } |
663 | 675 | ||
664 | /* | 676 | /* |
665 | * Input: a 'big' sector number, | 677 | * Input: a 'big' sector number, |
@@ -697,9 +709,12 @@ static sector_t raid5_compute_sector(sector_t r_sector, unsigned int raid_disks, | |||
697 | /* | 709 | /* |
698 | * Select the parity disk based on the user selected algorithm. | 710 | * Select the parity disk based on the user selected algorithm. |
699 | */ | 711 | */ |
700 | if (conf->level == 4) | 712 | switch(conf->level) { |
713 | case 4: | ||
701 | *pd_idx = data_disks; | 714 | *pd_idx = data_disks; |
702 | else switch (conf->algorithm) { | 715 | break; |
716 | case 5: | ||
717 | switch (conf->algorithm) { | ||
703 | case ALGORITHM_LEFT_ASYMMETRIC: | 718 | case ALGORITHM_LEFT_ASYMMETRIC: |
704 | *pd_idx = data_disks - stripe % raid_disks; | 719 | *pd_idx = data_disks - stripe % raid_disks; |
705 | if (*dd_idx >= *pd_idx) | 720 | if (*dd_idx >= *pd_idx) |
@@ -721,6 +736,39 @@ static sector_t raid5_compute_sector(sector_t r_sector, unsigned int raid_disks, | |||
721 | default: | 736 | default: |
722 | printk(KERN_ERR "raid5: unsupported algorithm %d\n", | 737 | printk(KERN_ERR "raid5: unsupported algorithm %d\n", |
723 | conf->algorithm); | 738 | conf->algorithm); |
739 | } | ||
740 | break; | ||
741 | case 6: | ||
742 | |||
743 | /**** FIX THIS ****/ | ||
744 | switch (conf->algorithm) { | ||
745 | case ALGORITHM_LEFT_ASYMMETRIC: | ||
746 | *pd_idx = raid_disks - 1 - (stripe % raid_disks); | ||
747 | if (*pd_idx == raid_disks-1) | ||
748 | (*dd_idx)++; /* Q D D D P */ | ||
749 | else if (*dd_idx >= *pd_idx) | ||
750 | (*dd_idx) += 2; /* D D P Q D */ | ||
751 | break; | ||
752 | case ALGORITHM_RIGHT_ASYMMETRIC: | ||
753 | *pd_idx = stripe % raid_disks; | ||
754 | if (*pd_idx == raid_disks-1) | ||
755 | (*dd_idx)++; /* Q D D D P */ | ||
756 | else if (*dd_idx >= *pd_idx) | ||
757 | (*dd_idx) += 2; /* D D P Q D */ | ||
758 | break; | ||
759 | case ALGORITHM_LEFT_SYMMETRIC: | ||
760 | *pd_idx = raid_disks - 1 - (stripe % raid_disks); | ||
761 | *dd_idx = (*pd_idx + 2 + *dd_idx) % raid_disks; | ||
762 | break; | ||
763 | case ALGORITHM_RIGHT_SYMMETRIC: | ||
764 | *pd_idx = stripe % raid_disks; | ||
765 | *dd_idx = (*pd_idx + 2 + *dd_idx) % raid_disks; | ||
766 | break; | ||
767 | default: | ||
768 | printk (KERN_CRIT "raid6: unsupported algorithm %d\n", | ||
769 | conf->algorithm); | ||
770 | } | ||
771 | break; | ||
724 | } | 772 | } |
725 | 773 | ||
726 | /* | 774 | /* |
@@ -742,12 +790,17 @@ static sector_t compute_blocknr(struct stripe_head *sh, int i) | |||
742 | int chunk_number, dummy1, dummy2, dd_idx = i; | 790 | int chunk_number, dummy1, dummy2, dd_idx = i; |
743 | sector_t r_sector; | 791 | sector_t r_sector; |
744 | 792 | ||
793 | |||
745 | chunk_offset = sector_div(new_sector, sectors_per_chunk); | 794 | chunk_offset = sector_div(new_sector, sectors_per_chunk); |
746 | stripe = new_sector; | 795 | stripe = new_sector; |
747 | BUG_ON(new_sector != stripe); | 796 | BUG_ON(new_sector != stripe); |
748 | 797 | ||
749 | 798 | if (i == sh->pd_idx) | |
750 | switch (conf->algorithm) { | 799 | return 0; |
800 | switch(conf->level) { | ||
801 | case 4: break; | ||
802 | case 5: | ||
803 | switch (conf->algorithm) { | ||
751 | case ALGORITHM_LEFT_ASYMMETRIC: | 804 | case ALGORITHM_LEFT_ASYMMETRIC: |
752 | case ALGORITHM_RIGHT_ASYMMETRIC: | 805 | case ALGORITHM_RIGHT_ASYMMETRIC: |
753 | if (i > sh->pd_idx) | 806 | if (i > sh->pd_idx) |
@@ -761,7 +814,37 @@ static sector_t compute_blocknr(struct stripe_head *sh, int i) | |||
761 | break; | 814 | break; |
762 | default: | 815 | default: |
763 | printk(KERN_ERR "raid5: unsupported algorithm %d\n", | 816 | printk(KERN_ERR "raid5: unsupported algorithm %d\n", |
817 | conf->algorithm); | ||
818 | } | ||
819 | break; | ||
820 | case 6: | ||
821 | data_disks = raid_disks - 2; | ||
822 | if (i == raid6_next_disk(sh->pd_idx, raid_disks)) | ||
823 | return 0; /* It is the Q disk */ | ||
824 | switch (conf->algorithm) { | ||
825 | case ALGORITHM_LEFT_ASYMMETRIC: | ||
826 | case ALGORITHM_RIGHT_ASYMMETRIC: | ||
827 | if (sh->pd_idx == raid_disks-1) | ||
828 | i--; /* Q D D D P */ | ||
829 | else if (i > sh->pd_idx) | ||
830 | i -= 2; /* D D P Q D */ | ||
831 | break; | ||
832 | case ALGORITHM_LEFT_SYMMETRIC: | ||
833 | case ALGORITHM_RIGHT_SYMMETRIC: | ||
834 | if (sh->pd_idx == raid_disks-1) | ||
835 | i--; /* Q D D D P */ | ||
836 | else { | ||
837 | /* D D P Q D */ | ||
838 | if (i < sh->pd_idx) | ||
839 | i += raid_disks; | ||
840 | i -= (sh->pd_idx + 2); | ||
841 | } | ||
842 | break; | ||
843 | default: | ||
844 | printk (KERN_CRIT "raid6: unsupported algorithm %d\n", | ||
764 | conf->algorithm); | 845 | conf->algorithm); |
846 | } | ||
847 | break; | ||
765 | } | 848 | } |
766 | 849 | ||
767 | chunk_number = stripe * data_disks + i; | 850 | chunk_number = stripe * data_disks + i; |
@@ -778,10 +861,11 @@ static sector_t compute_blocknr(struct stripe_head *sh, int i) | |||
778 | 861 | ||
779 | 862 | ||
780 | /* | 863 | /* |
781 | * Copy data between a page in the stripe cache, and a bio. | 864 | * Copy data between a page in the stripe cache, and one or more bion |
782 | * There are no alignment or size guarantees between the page or the | 865 | * The page could align with the middle of the bio, or there could be |
783 | * bio except that there is some overlap. | 866 | * several bion, each with several bio_vecs, which cover part of the page |
784 | * All iovecs in the bio must be considered. | 867 | * Multiple bion are linked together on bi_next. There may be extras |
868 | * at the end of this list. We ignore them. | ||
785 | */ | 869 | */ |
786 | static void copy_data(int frombio, struct bio *bio, | 870 | static void copy_data(int frombio, struct bio *bio, |
787 | struct page *page, | 871 | struct page *page, |
@@ -810,7 +894,7 @@ static void copy_data(int frombio, struct bio *bio, | |||
810 | if (len > 0 && page_offset + len > STRIPE_SIZE) | 894 | if (len > 0 && page_offset + len > STRIPE_SIZE) |
811 | clen = STRIPE_SIZE - page_offset; | 895 | clen = STRIPE_SIZE - page_offset; |
812 | else clen = len; | 896 | else clen = len; |
813 | 897 | ||
814 | if (clen > 0) { | 898 | if (clen > 0) { |
815 | char *ba = __bio_kmap_atomic(bio, i, KM_USER0); | 899 | char *ba = __bio_kmap_atomic(bio, i, KM_USER0); |
816 | if (frombio) | 900 | if (frombio) |
@@ -862,14 +946,14 @@ static void compute_block(struct stripe_head *sh, int dd_idx) | |||
862 | set_bit(R5_UPTODATE, &sh->dev[dd_idx].flags); | 946 | set_bit(R5_UPTODATE, &sh->dev[dd_idx].flags); |
863 | } | 947 | } |
864 | 948 | ||
865 | static void compute_parity(struct stripe_head *sh, int method) | 949 | static void compute_parity5(struct stripe_head *sh, int method) |
866 | { | 950 | { |
867 | raid5_conf_t *conf = sh->raid_conf; | 951 | raid5_conf_t *conf = sh->raid_conf; |
868 | int i, pd_idx = sh->pd_idx, disks = sh->disks, count; | 952 | int i, pd_idx = sh->pd_idx, disks = sh->disks, count; |
869 | void *ptr[MAX_XOR_BLOCKS]; | 953 | void *ptr[MAX_XOR_BLOCKS]; |
870 | struct bio *chosen; | 954 | struct bio *chosen; |
871 | 955 | ||
872 | PRINTK("compute_parity, stripe %llu, method %d\n", | 956 | PRINTK("compute_parity5, stripe %llu, method %d\n", |
873 | (unsigned long long)sh->sector, method); | 957 | (unsigned long long)sh->sector, method); |
874 | 958 | ||
875 | count = 1; | 959 | count = 1; |
@@ -956,9 +1040,195 @@ static void compute_parity(struct stripe_head *sh, int method) | |||
956 | clear_bit(R5_UPTODATE, &sh->dev[pd_idx].flags); | 1040 | clear_bit(R5_UPTODATE, &sh->dev[pd_idx].flags); |
957 | } | 1041 | } |
958 | 1042 | ||
1043 | static void compute_parity6(struct stripe_head *sh, int method) | ||
1044 | { | ||
1045 | raid6_conf_t *conf = sh->raid_conf; | ||
1046 | int i, pd_idx = sh->pd_idx, qd_idx, d0_idx, disks = conf->raid_disks, count; | ||
1047 | struct bio *chosen; | ||
1048 | /**** FIX THIS: This could be very bad if disks is close to 256 ****/ | ||
1049 | void *ptrs[disks]; | ||
1050 | |||
1051 | qd_idx = raid6_next_disk(pd_idx, disks); | ||
1052 | d0_idx = raid6_next_disk(qd_idx, disks); | ||
1053 | |||
1054 | PRINTK("compute_parity, stripe %llu, method %d\n", | ||
1055 | (unsigned long long)sh->sector, method); | ||
1056 | |||
1057 | switch(method) { | ||
1058 | case READ_MODIFY_WRITE: | ||
1059 | BUG(); /* READ_MODIFY_WRITE N/A for RAID-6 */ | ||
1060 | case RECONSTRUCT_WRITE: | ||
1061 | for (i= disks; i-- ;) | ||
1062 | if ( i != pd_idx && i != qd_idx && sh->dev[i].towrite ) { | ||
1063 | chosen = sh->dev[i].towrite; | ||
1064 | sh->dev[i].towrite = NULL; | ||
1065 | |||
1066 | if (test_and_clear_bit(R5_Overlap, &sh->dev[i].flags)) | ||
1067 | wake_up(&conf->wait_for_overlap); | ||
1068 | |||
1069 | if (sh->dev[i].written) BUG(); | ||
1070 | sh->dev[i].written = chosen; | ||
1071 | } | ||
1072 | break; | ||
1073 | case CHECK_PARITY: | ||
1074 | BUG(); /* Not implemented yet */ | ||
1075 | } | ||
1076 | |||
1077 | for (i = disks; i--;) | ||
1078 | if (sh->dev[i].written) { | ||
1079 | sector_t sector = sh->dev[i].sector; | ||
1080 | struct bio *wbi = sh->dev[i].written; | ||
1081 | while (wbi && wbi->bi_sector < sector + STRIPE_SECTORS) { | ||
1082 | copy_data(1, wbi, sh->dev[i].page, sector); | ||
1083 | wbi = r5_next_bio(wbi, sector); | ||
1084 | } | ||
1085 | |||
1086 | set_bit(R5_LOCKED, &sh->dev[i].flags); | ||
1087 | set_bit(R5_UPTODATE, &sh->dev[i].flags); | ||
1088 | } | ||
1089 | |||
1090 | // switch(method) { | ||
1091 | // case RECONSTRUCT_WRITE: | ||
1092 | // case CHECK_PARITY: | ||
1093 | // case UPDATE_PARITY: | ||
1094 | /* Note that unlike RAID-5, the ordering of the disks matters greatly. */ | ||
1095 | /* FIX: Is this ordering of drives even remotely optimal? */ | ||
1096 | count = 0; | ||
1097 | i = d0_idx; | ||
1098 | do { | ||
1099 | ptrs[count++] = page_address(sh->dev[i].page); | ||
1100 | if (count <= disks-2 && !test_bit(R5_UPTODATE, &sh->dev[i].flags)) | ||
1101 | printk("block %d/%d not uptodate on parity calc\n", i,count); | ||
1102 | i = raid6_next_disk(i, disks); | ||
1103 | } while ( i != d0_idx ); | ||
1104 | // break; | ||
1105 | // } | ||
1106 | |||
1107 | raid6_call.gen_syndrome(disks, STRIPE_SIZE, ptrs); | ||
1108 | |||
1109 | switch(method) { | ||
1110 | case RECONSTRUCT_WRITE: | ||
1111 | set_bit(R5_UPTODATE, &sh->dev[pd_idx].flags); | ||
1112 | set_bit(R5_UPTODATE, &sh->dev[qd_idx].flags); | ||
1113 | set_bit(R5_LOCKED, &sh->dev[pd_idx].flags); | ||
1114 | set_bit(R5_LOCKED, &sh->dev[qd_idx].flags); | ||
1115 | break; | ||
1116 | case UPDATE_PARITY: | ||
1117 | set_bit(R5_UPTODATE, &sh->dev[pd_idx].flags); | ||
1118 | set_bit(R5_UPTODATE, &sh->dev[qd_idx].flags); | ||
1119 | break; | ||
1120 | } | ||
1121 | } | ||
1122 | |||
1123 | |||
1124 | /* Compute one missing block */ | ||
1125 | static void compute_block_1(struct stripe_head *sh, int dd_idx, int nozero) | ||
1126 | { | ||
1127 | raid6_conf_t *conf = sh->raid_conf; | ||
1128 | int i, count, disks = conf->raid_disks; | ||
1129 | void *ptr[MAX_XOR_BLOCKS], *p; | ||
1130 | int pd_idx = sh->pd_idx; | ||
1131 | int qd_idx = raid6_next_disk(pd_idx, disks); | ||
1132 | |||
1133 | PRINTK("compute_block_1, stripe %llu, idx %d\n", | ||
1134 | (unsigned long long)sh->sector, dd_idx); | ||
1135 | |||
1136 | if ( dd_idx == qd_idx ) { | ||
1137 | /* We're actually computing the Q drive */ | ||
1138 | compute_parity6(sh, UPDATE_PARITY); | ||
1139 | } else { | ||
1140 | ptr[0] = page_address(sh->dev[dd_idx].page); | ||
1141 | if (!nozero) memset(ptr[0], 0, STRIPE_SIZE); | ||
1142 | count = 1; | ||
1143 | for (i = disks ; i--; ) { | ||
1144 | if (i == dd_idx || i == qd_idx) | ||
1145 | continue; | ||
1146 | p = page_address(sh->dev[i].page); | ||
1147 | if (test_bit(R5_UPTODATE, &sh->dev[i].flags)) | ||
1148 | ptr[count++] = p; | ||
1149 | else | ||
1150 | printk("compute_block() %d, stripe %llu, %d" | ||
1151 | " not present\n", dd_idx, | ||
1152 | (unsigned long long)sh->sector, i); | ||
1153 | |||
1154 | check_xor(); | ||
1155 | } | ||
1156 | if (count != 1) | ||
1157 | xor_block(count, STRIPE_SIZE, ptr); | ||
1158 | if (!nozero) set_bit(R5_UPTODATE, &sh->dev[dd_idx].flags); | ||
1159 | else clear_bit(R5_UPTODATE, &sh->dev[dd_idx].flags); | ||
1160 | } | ||
1161 | } | ||
1162 | |||
1163 | /* Compute two missing blocks */ | ||
1164 | static void compute_block_2(struct stripe_head *sh, int dd_idx1, int dd_idx2) | ||
1165 | { | ||
1166 | raid6_conf_t *conf = sh->raid_conf; | ||
1167 | int i, count, disks = conf->raid_disks; | ||
1168 | int pd_idx = sh->pd_idx; | ||
1169 | int qd_idx = raid6_next_disk(pd_idx, disks); | ||
1170 | int d0_idx = raid6_next_disk(qd_idx, disks); | ||
1171 | int faila, failb; | ||
1172 | |||
1173 | /* faila and failb are disk numbers relative to d0_idx */ | ||
1174 | /* pd_idx become disks-2 and qd_idx become disks-1 */ | ||
1175 | faila = (dd_idx1 < d0_idx) ? dd_idx1+(disks-d0_idx) : dd_idx1-d0_idx; | ||
1176 | failb = (dd_idx2 < d0_idx) ? dd_idx2+(disks-d0_idx) : dd_idx2-d0_idx; | ||
1177 | |||
1178 | BUG_ON(faila == failb); | ||
1179 | if ( failb < faila ) { int tmp = faila; faila = failb; failb = tmp; } | ||
1180 | |||
1181 | PRINTK("compute_block_2, stripe %llu, idx %d,%d (%d,%d)\n", | ||
1182 | (unsigned long long)sh->sector, dd_idx1, dd_idx2, faila, failb); | ||
1183 | |||
1184 | if ( failb == disks-1 ) { | ||
1185 | /* Q disk is one of the missing disks */ | ||
1186 | if ( faila == disks-2 ) { | ||
1187 | /* Missing P+Q, just recompute */ | ||
1188 | compute_parity6(sh, UPDATE_PARITY); | ||
1189 | return; | ||
1190 | } else { | ||
1191 | /* We're missing D+Q; recompute D from P */ | ||
1192 | compute_block_1(sh, (dd_idx1 == qd_idx) ? dd_idx2 : dd_idx1, 0); | ||
1193 | compute_parity6(sh, UPDATE_PARITY); /* Is this necessary? */ | ||
1194 | return; | ||
1195 | } | ||
1196 | } | ||
1197 | |||
1198 | /* We're missing D+P or D+D; build pointer table */ | ||
1199 | { | ||
1200 | /**** FIX THIS: This could be very bad if disks is close to 256 ****/ | ||
1201 | void *ptrs[disks]; | ||
1202 | |||
1203 | count = 0; | ||
1204 | i = d0_idx; | ||
1205 | do { | ||
1206 | ptrs[count++] = page_address(sh->dev[i].page); | ||
1207 | i = raid6_next_disk(i, disks); | ||
1208 | if (i != dd_idx1 && i != dd_idx2 && | ||
1209 | !test_bit(R5_UPTODATE, &sh->dev[i].flags)) | ||
1210 | printk("compute_2 with missing block %d/%d\n", count, i); | ||
1211 | } while ( i != d0_idx ); | ||
1212 | |||
1213 | if ( failb == disks-2 ) { | ||
1214 | /* We're missing D+P. */ | ||
1215 | raid6_datap_recov(disks, STRIPE_SIZE, faila, ptrs); | ||
1216 | } else { | ||
1217 | /* We're missing D+D. */ | ||
1218 | raid6_2data_recov(disks, STRIPE_SIZE, faila, failb, ptrs); | ||
1219 | } | ||
1220 | |||
1221 | /* Both the above update both missing blocks */ | ||
1222 | set_bit(R5_UPTODATE, &sh->dev[dd_idx1].flags); | ||
1223 | set_bit(R5_UPTODATE, &sh->dev[dd_idx2].flags); | ||
1224 | } | ||
1225 | } | ||
1226 | |||
1227 | |||
1228 | |||
959 | /* | 1229 | /* |
960 | * Each stripe/dev can have one or more bion attached. | 1230 | * Each stripe/dev can have one or more bion attached. |
961 | * toread/towrite point to the first in a chain. | 1231 | * toread/towrite point to the first in a chain. |
962 | * The bi_next chain must be in order. | 1232 | * The bi_next chain must be in order. |
963 | */ | 1233 | */ |
964 | static int add_stripe_bio(struct stripe_head *sh, struct bio *bi, int dd_idx, int forwrite) | 1234 | static int add_stripe_bio(struct stripe_head *sh, struct bio *bi, int dd_idx, int forwrite) |
@@ -1031,6 +1301,13 @@ static int add_stripe_bio(struct stripe_head *sh, struct bio *bi, int dd_idx, in | |||
1031 | 1301 | ||
1032 | static void end_reshape(raid5_conf_t *conf); | 1302 | static void end_reshape(raid5_conf_t *conf); |
1033 | 1303 | ||
1304 | static int page_is_zero(struct page *p) | ||
1305 | { | ||
1306 | char *a = page_address(p); | ||
1307 | return ((*(u32*)a) == 0 && | ||
1308 | memcmp(a, a+4, STRIPE_SIZE-4)==0); | ||
1309 | } | ||
1310 | |||
1034 | static int stripe_to_pdidx(sector_t stripe, raid5_conf_t *conf, int disks) | 1311 | static int stripe_to_pdidx(sector_t stripe, raid5_conf_t *conf, int disks) |
1035 | { | 1312 | { |
1036 | int sectors_per_chunk = conf->chunk_size >> 9; | 1313 | int sectors_per_chunk = conf->chunk_size >> 9; |
@@ -1062,7 +1339,7 @@ static int stripe_to_pdidx(sector_t stripe, raid5_conf_t *conf, int disks) | |||
1062 | * | 1339 | * |
1063 | */ | 1340 | */ |
1064 | 1341 | ||
1065 | static void handle_stripe(struct stripe_head *sh) | 1342 | static void handle_stripe5(struct stripe_head *sh) |
1066 | { | 1343 | { |
1067 | raid5_conf_t *conf = sh->raid_conf; | 1344 | raid5_conf_t *conf = sh->raid_conf; |
1068 | int disks = sh->disks; | 1345 | int disks = sh->disks; |
@@ -1394,7 +1671,7 @@ static void handle_stripe(struct stripe_head *sh) | |||
1394 | if (locked == 0 && (rcw == 0 ||rmw == 0) && | 1671 | if (locked == 0 && (rcw == 0 ||rmw == 0) && |
1395 | !test_bit(STRIPE_BIT_DELAY, &sh->state)) { | 1672 | !test_bit(STRIPE_BIT_DELAY, &sh->state)) { |
1396 | PRINTK("Computing parity...\n"); | 1673 | PRINTK("Computing parity...\n"); |
1397 | compute_parity(sh, rcw==0 ? RECONSTRUCT_WRITE : READ_MODIFY_WRITE); | 1674 | compute_parity5(sh, rcw==0 ? RECONSTRUCT_WRITE : READ_MODIFY_WRITE); |
1398 | /* now every locked buffer is ready to be written */ | 1675 | /* now every locked buffer is ready to be written */ |
1399 | for (i=disks; i--;) | 1676 | for (i=disks; i--;) |
1400 | if (test_bit(R5_LOCKED, &sh->dev[i].flags)) { | 1677 | if (test_bit(R5_LOCKED, &sh->dev[i].flags)) { |
@@ -1421,13 +1698,10 @@ static void handle_stripe(struct stripe_head *sh) | |||
1421 | !test_bit(STRIPE_INSYNC, &sh->state)) { | 1698 | !test_bit(STRIPE_INSYNC, &sh->state)) { |
1422 | set_bit(STRIPE_HANDLE, &sh->state); | 1699 | set_bit(STRIPE_HANDLE, &sh->state); |
1423 | if (failed == 0) { | 1700 | if (failed == 0) { |
1424 | char *pagea; | ||
1425 | BUG_ON(uptodate != disks); | 1701 | BUG_ON(uptodate != disks); |
1426 | compute_parity(sh, CHECK_PARITY); | 1702 | compute_parity5(sh, CHECK_PARITY); |
1427 | uptodate--; | 1703 | uptodate--; |
1428 | pagea = page_address(sh->dev[sh->pd_idx].page); | 1704 | if (page_is_zero(sh->dev[sh->pd_idx].page)) { |
1429 | if ((*(u32*)pagea) == 0 && | ||
1430 | !memcmp(pagea, pagea+4, STRIPE_SIZE-4)) { | ||
1431 | /* parity is correct (on disc, not in buffer any more) */ | 1705 | /* parity is correct (on disc, not in buffer any more) */ |
1432 | set_bit(STRIPE_INSYNC, &sh->state); | 1706 | set_bit(STRIPE_INSYNC, &sh->state); |
1433 | } else { | 1707 | } else { |
@@ -1487,7 +1761,7 @@ static void handle_stripe(struct stripe_head *sh) | |||
1487 | /* Need to write out all blocks after computing parity */ | 1761 | /* Need to write out all blocks after computing parity */ |
1488 | sh->disks = conf->raid_disks; | 1762 | sh->disks = conf->raid_disks; |
1489 | sh->pd_idx = stripe_to_pdidx(sh->sector, conf, conf->raid_disks); | 1763 | sh->pd_idx = stripe_to_pdidx(sh->sector, conf, conf->raid_disks); |
1490 | compute_parity(sh, RECONSTRUCT_WRITE); | 1764 | compute_parity5(sh, RECONSTRUCT_WRITE); |
1491 | for (i= conf->raid_disks; i--;) { | 1765 | for (i= conf->raid_disks; i--;) { |
1492 | set_bit(R5_LOCKED, &sh->dev[i].flags); | 1766 | set_bit(R5_LOCKED, &sh->dev[i].flags); |
1493 | locked++; | 1767 | locked++; |
@@ -1615,6 +1889,569 @@ static void handle_stripe(struct stripe_head *sh) | |||
1615 | } | 1889 | } |
1616 | } | 1890 | } |
1617 | 1891 | ||
1892 | static void handle_stripe6(struct stripe_head *sh, struct page *tmp_page) | ||
1893 | { | ||
1894 | raid6_conf_t *conf = sh->raid_conf; | ||
1895 | int disks = conf->raid_disks; | ||
1896 | struct bio *return_bi= NULL; | ||
1897 | struct bio *bi; | ||
1898 | int i; | ||
1899 | int syncing; | ||
1900 | int locked=0, uptodate=0, to_read=0, to_write=0, failed=0, written=0; | ||
1901 | int non_overwrite = 0; | ||
1902 | int failed_num[2] = {0, 0}; | ||
1903 | struct r5dev *dev, *pdev, *qdev; | ||
1904 | int pd_idx = sh->pd_idx; | ||
1905 | int qd_idx = raid6_next_disk(pd_idx, disks); | ||
1906 | int p_failed, q_failed; | ||
1907 | |||
1908 | PRINTK("handling stripe %llu, state=%#lx cnt=%d, pd_idx=%d, qd_idx=%d\n", | ||
1909 | (unsigned long long)sh->sector, sh->state, atomic_read(&sh->count), | ||
1910 | pd_idx, qd_idx); | ||
1911 | |||
1912 | spin_lock(&sh->lock); | ||
1913 | clear_bit(STRIPE_HANDLE, &sh->state); | ||
1914 | clear_bit(STRIPE_DELAYED, &sh->state); | ||
1915 | |||
1916 | syncing = test_bit(STRIPE_SYNCING, &sh->state); | ||
1917 | /* Now to look around and see what can be done */ | ||
1918 | |||
1919 | rcu_read_lock(); | ||
1920 | for (i=disks; i--; ) { | ||
1921 | mdk_rdev_t *rdev; | ||
1922 | dev = &sh->dev[i]; | ||
1923 | clear_bit(R5_Insync, &dev->flags); | ||
1924 | |||
1925 | PRINTK("check %d: state 0x%lx read %p write %p written %p\n", | ||
1926 | i, dev->flags, dev->toread, dev->towrite, dev->written); | ||
1927 | /* maybe we can reply to a read */ | ||
1928 | if (test_bit(R5_UPTODATE, &dev->flags) && dev->toread) { | ||
1929 | struct bio *rbi, *rbi2; | ||
1930 | PRINTK("Return read for disc %d\n", i); | ||
1931 | spin_lock_irq(&conf->device_lock); | ||
1932 | rbi = dev->toread; | ||
1933 | dev->toread = NULL; | ||
1934 | if (test_and_clear_bit(R5_Overlap, &dev->flags)) | ||
1935 | wake_up(&conf->wait_for_overlap); | ||
1936 | spin_unlock_irq(&conf->device_lock); | ||
1937 | while (rbi && rbi->bi_sector < dev->sector + STRIPE_SECTORS) { | ||
1938 | copy_data(0, rbi, dev->page, dev->sector); | ||
1939 | rbi2 = r5_next_bio(rbi, dev->sector); | ||
1940 | spin_lock_irq(&conf->device_lock); | ||
1941 | if (--rbi->bi_phys_segments == 0) { | ||
1942 | rbi->bi_next = return_bi; | ||
1943 | return_bi = rbi; | ||
1944 | } | ||
1945 | spin_unlock_irq(&conf->device_lock); | ||
1946 | rbi = rbi2; | ||
1947 | } | ||
1948 | } | ||
1949 | |||
1950 | /* now count some things */ | ||
1951 | if (test_bit(R5_LOCKED, &dev->flags)) locked++; | ||
1952 | if (test_bit(R5_UPTODATE, &dev->flags)) uptodate++; | ||
1953 | |||
1954 | |||
1955 | if (dev->toread) to_read++; | ||
1956 | if (dev->towrite) { | ||
1957 | to_write++; | ||
1958 | if (!test_bit(R5_OVERWRITE, &dev->flags)) | ||
1959 | non_overwrite++; | ||
1960 | } | ||
1961 | if (dev->written) written++; | ||
1962 | rdev = rcu_dereference(conf->disks[i].rdev); | ||
1963 | if (!rdev || !test_bit(In_sync, &rdev->flags)) { | ||
1964 | /* The ReadError flag will just be confusing now */ | ||
1965 | clear_bit(R5_ReadError, &dev->flags); | ||
1966 | clear_bit(R5_ReWrite, &dev->flags); | ||
1967 | } | ||
1968 | if (!rdev || !test_bit(In_sync, &rdev->flags) | ||
1969 | || test_bit(R5_ReadError, &dev->flags)) { | ||
1970 | if ( failed < 2 ) | ||
1971 | failed_num[failed] = i; | ||
1972 | failed++; | ||
1973 | } else | ||
1974 | set_bit(R5_Insync, &dev->flags); | ||
1975 | } | ||
1976 | rcu_read_unlock(); | ||
1977 | PRINTK("locked=%d uptodate=%d to_read=%d" | ||
1978 | " to_write=%d failed=%d failed_num=%d,%d\n", | ||
1979 | locked, uptodate, to_read, to_write, failed, | ||
1980 | failed_num[0], failed_num[1]); | ||
1981 | /* check if the array has lost >2 devices and, if so, some requests might | ||
1982 | * need to be failed | ||
1983 | */ | ||
1984 | if (failed > 2 && to_read+to_write+written) { | ||
1985 | for (i=disks; i--; ) { | ||
1986 | int bitmap_end = 0; | ||
1987 | |||
1988 | if (test_bit(R5_ReadError, &sh->dev[i].flags)) { | ||
1989 | mdk_rdev_t *rdev; | ||
1990 | rcu_read_lock(); | ||
1991 | rdev = rcu_dereference(conf->disks[i].rdev); | ||
1992 | if (rdev && test_bit(In_sync, &rdev->flags)) | ||
1993 | /* multiple read failures in one stripe */ | ||
1994 | md_error(conf->mddev, rdev); | ||
1995 | rcu_read_unlock(); | ||
1996 | } | ||
1997 | |||
1998 | spin_lock_irq(&conf->device_lock); | ||
1999 | /* fail all writes first */ | ||
2000 | bi = sh->dev[i].towrite; | ||
2001 | sh->dev[i].towrite = NULL; | ||
2002 | if (bi) { to_write--; bitmap_end = 1; } | ||
2003 | |||
2004 | if (test_and_clear_bit(R5_Overlap, &sh->dev[i].flags)) | ||
2005 | wake_up(&conf->wait_for_overlap); | ||
2006 | |||
2007 | while (bi && bi->bi_sector < sh->dev[i].sector + STRIPE_SECTORS){ | ||
2008 | struct bio *nextbi = r5_next_bio(bi, sh->dev[i].sector); | ||
2009 | clear_bit(BIO_UPTODATE, &bi->bi_flags); | ||
2010 | if (--bi->bi_phys_segments == 0) { | ||
2011 | md_write_end(conf->mddev); | ||
2012 | bi->bi_next = return_bi; | ||
2013 | return_bi = bi; | ||
2014 | } | ||
2015 | bi = nextbi; | ||
2016 | } | ||
2017 | /* and fail all 'written' */ | ||
2018 | bi = sh->dev[i].written; | ||
2019 | sh->dev[i].written = NULL; | ||
2020 | if (bi) bitmap_end = 1; | ||
2021 | while (bi && bi->bi_sector < sh->dev[i].sector + STRIPE_SECTORS) { | ||
2022 | struct bio *bi2 = r5_next_bio(bi, sh->dev[i].sector); | ||
2023 | clear_bit(BIO_UPTODATE, &bi->bi_flags); | ||
2024 | if (--bi->bi_phys_segments == 0) { | ||
2025 | md_write_end(conf->mddev); | ||
2026 | bi->bi_next = return_bi; | ||
2027 | return_bi = bi; | ||
2028 | } | ||
2029 | bi = bi2; | ||
2030 | } | ||
2031 | |||
2032 | /* fail any reads if this device is non-operational */ | ||
2033 | if (!test_bit(R5_Insync, &sh->dev[i].flags) || | ||
2034 | test_bit(R5_ReadError, &sh->dev[i].flags)) { | ||
2035 | bi = sh->dev[i].toread; | ||
2036 | sh->dev[i].toread = NULL; | ||
2037 | if (test_and_clear_bit(R5_Overlap, &sh->dev[i].flags)) | ||
2038 | wake_up(&conf->wait_for_overlap); | ||
2039 | if (bi) to_read--; | ||
2040 | while (bi && bi->bi_sector < sh->dev[i].sector + STRIPE_SECTORS){ | ||
2041 | struct bio *nextbi = r5_next_bio(bi, sh->dev[i].sector); | ||
2042 | clear_bit(BIO_UPTODATE, &bi->bi_flags); | ||
2043 | if (--bi->bi_phys_segments == 0) { | ||
2044 | bi->bi_next = return_bi; | ||
2045 | return_bi = bi; | ||
2046 | } | ||
2047 | bi = nextbi; | ||
2048 | } | ||
2049 | } | ||
2050 | spin_unlock_irq(&conf->device_lock); | ||
2051 | if (bitmap_end) | ||
2052 | bitmap_endwrite(conf->mddev->bitmap, sh->sector, | ||
2053 | STRIPE_SECTORS, 0, 0); | ||
2054 | } | ||
2055 | } | ||
2056 | if (failed > 2 && syncing) { | ||
2057 | md_done_sync(conf->mddev, STRIPE_SECTORS,0); | ||
2058 | clear_bit(STRIPE_SYNCING, &sh->state); | ||
2059 | syncing = 0; | ||
2060 | } | ||
2061 | |||
2062 | /* | ||
2063 | * might be able to return some write requests if the parity blocks | ||
2064 | * are safe, or on a failed drive | ||
2065 | */ | ||
2066 | pdev = &sh->dev[pd_idx]; | ||
2067 | p_failed = (failed >= 1 && failed_num[0] == pd_idx) | ||
2068 | || (failed >= 2 && failed_num[1] == pd_idx); | ||
2069 | qdev = &sh->dev[qd_idx]; | ||
2070 | q_failed = (failed >= 1 && failed_num[0] == qd_idx) | ||
2071 | || (failed >= 2 && failed_num[1] == qd_idx); | ||
2072 | |||
2073 | if ( written && | ||
2074 | ( p_failed || ((test_bit(R5_Insync, &pdev->flags) | ||
2075 | && !test_bit(R5_LOCKED, &pdev->flags) | ||
2076 | && test_bit(R5_UPTODATE, &pdev->flags))) ) && | ||
2077 | ( q_failed || ((test_bit(R5_Insync, &qdev->flags) | ||
2078 | && !test_bit(R5_LOCKED, &qdev->flags) | ||
2079 | && test_bit(R5_UPTODATE, &qdev->flags))) ) ) { | ||
2080 | /* any written block on an uptodate or failed drive can be | ||
2081 | * returned. Note that if we 'wrote' to a failed drive, | ||
2082 | * it will be UPTODATE, but never LOCKED, so we don't need | ||
2083 | * to test 'failed' directly. | ||
2084 | */ | ||
2085 | for (i=disks; i--; ) | ||
2086 | if (sh->dev[i].written) { | ||
2087 | dev = &sh->dev[i]; | ||
2088 | if (!test_bit(R5_LOCKED, &dev->flags) && | ||
2089 | test_bit(R5_UPTODATE, &dev->flags) ) { | ||
2090 | /* We can return any write requests */ | ||
2091 | int bitmap_end = 0; | ||
2092 | struct bio *wbi, *wbi2; | ||
2093 | PRINTK("Return write for stripe %llu disc %d\n", | ||
2094 | (unsigned long long)sh->sector, i); | ||
2095 | spin_lock_irq(&conf->device_lock); | ||
2096 | wbi = dev->written; | ||
2097 | dev->written = NULL; | ||
2098 | while (wbi && wbi->bi_sector < dev->sector + STRIPE_SECTORS) { | ||
2099 | wbi2 = r5_next_bio(wbi, dev->sector); | ||
2100 | if (--wbi->bi_phys_segments == 0) { | ||
2101 | md_write_end(conf->mddev); | ||
2102 | wbi->bi_next = return_bi; | ||
2103 | return_bi = wbi; | ||
2104 | } | ||
2105 | wbi = wbi2; | ||
2106 | } | ||
2107 | if (dev->towrite == NULL) | ||
2108 | bitmap_end = 1; | ||
2109 | spin_unlock_irq(&conf->device_lock); | ||
2110 | if (bitmap_end) | ||
2111 | bitmap_endwrite(conf->mddev->bitmap, sh->sector, | ||
2112 | STRIPE_SECTORS, | ||
2113 | !test_bit(STRIPE_DEGRADED, &sh->state), 0); | ||
2114 | } | ||
2115 | } | ||
2116 | } | ||
2117 | |||
2118 | /* Now we might consider reading some blocks, either to check/generate | ||
2119 | * parity, or to satisfy requests | ||
2120 | * or to load a block that is being partially written. | ||
2121 | */ | ||
2122 | if (to_read || non_overwrite || (to_write && failed) || (syncing && (uptodate < disks))) { | ||
2123 | for (i=disks; i--;) { | ||
2124 | dev = &sh->dev[i]; | ||
2125 | if (!test_bit(R5_LOCKED, &dev->flags) && !test_bit(R5_UPTODATE, &dev->flags) && | ||
2126 | (dev->toread || | ||
2127 | (dev->towrite && !test_bit(R5_OVERWRITE, &dev->flags)) || | ||
2128 | syncing || | ||
2129 | (failed >= 1 && (sh->dev[failed_num[0]].toread || to_write)) || | ||
2130 | (failed >= 2 && (sh->dev[failed_num[1]].toread || to_write)) | ||
2131 | ) | ||
2132 | ) { | ||
2133 | /* we would like to get this block, possibly | ||
2134 | * by computing it, but we might not be able to | ||
2135 | */ | ||
2136 | if (uptodate == disks-1) { | ||
2137 | PRINTK("Computing stripe %llu block %d\n", | ||
2138 | (unsigned long long)sh->sector, i); | ||
2139 | compute_block_1(sh, i, 0); | ||
2140 | uptodate++; | ||
2141 | } else if ( uptodate == disks-2 && failed >= 2 ) { | ||
2142 | /* Computing 2-failure is *very* expensive; only do it if failed >= 2 */ | ||
2143 | int other; | ||
2144 | for (other=disks; other--;) { | ||
2145 | if ( other == i ) | ||
2146 | continue; | ||
2147 | if ( !test_bit(R5_UPTODATE, &sh->dev[other].flags) ) | ||
2148 | break; | ||
2149 | } | ||
2150 | BUG_ON(other < 0); | ||
2151 | PRINTK("Computing stripe %llu blocks %d,%d\n", | ||
2152 | (unsigned long long)sh->sector, i, other); | ||
2153 | compute_block_2(sh, i, other); | ||
2154 | uptodate += 2; | ||
2155 | } else if (test_bit(R5_Insync, &dev->flags)) { | ||
2156 | set_bit(R5_LOCKED, &dev->flags); | ||
2157 | set_bit(R5_Wantread, &dev->flags); | ||
2158 | #if 0 | ||
2159 | /* if I am just reading this block and we don't have | ||
2160 | a failed drive, or any pending writes then sidestep the cache */ | ||
2161 | if (sh->bh_read[i] && !sh->bh_read[i]->b_reqnext && | ||
2162 | ! syncing && !failed && !to_write) { | ||
2163 | sh->bh_cache[i]->b_page = sh->bh_read[i]->b_page; | ||
2164 | sh->bh_cache[i]->b_data = sh->bh_read[i]->b_data; | ||
2165 | } | ||
2166 | #endif | ||
2167 | locked++; | ||
2168 | PRINTK("Reading block %d (sync=%d)\n", | ||
2169 | i, syncing); | ||
2170 | } | ||
2171 | } | ||
2172 | } | ||
2173 | set_bit(STRIPE_HANDLE, &sh->state); | ||
2174 | } | ||
2175 | |||
2176 | /* now to consider writing and what else, if anything should be read */ | ||
2177 | if (to_write) { | ||
2178 | int rcw=0, must_compute=0; | ||
2179 | for (i=disks ; i--;) { | ||
2180 | dev = &sh->dev[i]; | ||
2181 | /* Would I have to read this buffer for reconstruct_write */ | ||
2182 | if (!test_bit(R5_OVERWRITE, &dev->flags) | ||
2183 | && i != pd_idx && i != qd_idx | ||
2184 | && (!test_bit(R5_LOCKED, &dev->flags) | ||
2185 | #if 0 | ||
2186 | || sh->bh_page[i] != bh->b_page | ||
2187 | #endif | ||
2188 | ) && | ||
2189 | !test_bit(R5_UPTODATE, &dev->flags)) { | ||
2190 | if (test_bit(R5_Insync, &dev->flags)) rcw++; | ||
2191 | else { | ||
2192 | PRINTK("raid6: must_compute: disk %d flags=%#lx\n", i, dev->flags); | ||
2193 | must_compute++; | ||
2194 | } | ||
2195 | } | ||
2196 | } | ||
2197 | PRINTK("for sector %llu, rcw=%d, must_compute=%d\n", | ||
2198 | (unsigned long long)sh->sector, rcw, must_compute); | ||
2199 | set_bit(STRIPE_HANDLE, &sh->state); | ||
2200 | |||
2201 | if (rcw > 0) | ||
2202 | /* want reconstruct write, but need to get some data */ | ||
2203 | for (i=disks; i--;) { | ||
2204 | dev = &sh->dev[i]; | ||
2205 | if (!test_bit(R5_OVERWRITE, &dev->flags) | ||
2206 | && !(failed == 0 && (i == pd_idx || i == qd_idx)) | ||
2207 | && !test_bit(R5_LOCKED, &dev->flags) && !test_bit(R5_UPTODATE, &dev->flags) && | ||
2208 | test_bit(R5_Insync, &dev->flags)) { | ||
2209 | if (test_bit(STRIPE_PREREAD_ACTIVE, &sh->state)) | ||
2210 | { | ||
2211 | PRINTK("Read_old stripe %llu block %d for Reconstruct\n", | ||
2212 | (unsigned long long)sh->sector, i); | ||
2213 | set_bit(R5_LOCKED, &dev->flags); | ||
2214 | set_bit(R5_Wantread, &dev->flags); | ||
2215 | locked++; | ||
2216 | } else { | ||
2217 | PRINTK("Request delayed stripe %llu block %d for Reconstruct\n", | ||
2218 | (unsigned long long)sh->sector, i); | ||
2219 | set_bit(STRIPE_DELAYED, &sh->state); | ||
2220 | set_bit(STRIPE_HANDLE, &sh->state); | ||
2221 | } | ||
2222 | } | ||
2223 | } | ||
2224 | /* now if nothing is locked, and if we have enough data, we can start a write request */ | ||
2225 | if (locked == 0 && rcw == 0 && | ||
2226 | !test_bit(STRIPE_BIT_DELAY, &sh->state)) { | ||
2227 | if ( must_compute > 0 ) { | ||
2228 | /* We have failed blocks and need to compute them */ | ||
2229 | switch ( failed ) { | ||
2230 | case 0: BUG(); | ||
2231 | case 1: compute_block_1(sh, failed_num[0], 0); break; | ||
2232 | case 2: compute_block_2(sh, failed_num[0], failed_num[1]); break; | ||
2233 | default: BUG(); /* This request should have been failed? */ | ||
2234 | } | ||
2235 | } | ||
2236 | |||
2237 | PRINTK("Computing parity for stripe %llu\n", (unsigned long long)sh->sector); | ||
2238 | compute_parity6(sh, RECONSTRUCT_WRITE); | ||
2239 | /* now every locked buffer is ready to be written */ | ||
2240 | for (i=disks; i--;) | ||
2241 | if (test_bit(R5_LOCKED, &sh->dev[i].flags)) { | ||
2242 | PRINTK("Writing stripe %llu block %d\n", | ||
2243 | (unsigned long long)sh->sector, i); | ||
2244 | locked++; | ||
2245 | set_bit(R5_Wantwrite, &sh->dev[i].flags); | ||
2246 | } | ||
2247 | /* after a RECONSTRUCT_WRITE, the stripe MUST be in-sync */ | ||
2248 | set_bit(STRIPE_INSYNC, &sh->state); | ||
2249 | |||
2250 | if (test_and_clear_bit(STRIPE_PREREAD_ACTIVE, &sh->state)) { | ||
2251 | atomic_dec(&conf->preread_active_stripes); | ||
2252 | if (atomic_read(&conf->preread_active_stripes) < IO_THRESHOLD) | ||
2253 | md_wakeup_thread(conf->mddev->thread); | ||
2254 | } | ||
2255 | } | ||
2256 | } | ||
2257 | |||
2258 | /* maybe we need to check and possibly fix the parity for this stripe | ||
2259 | * Any reads will already have been scheduled, so we just see if enough data | ||
2260 | * is available | ||
2261 | */ | ||
2262 | if (syncing && locked == 0 && !test_bit(STRIPE_INSYNC, &sh->state)) { | ||
2263 | int update_p = 0, update_q = 0; | ||
2264 | struct r5dev *dev; | ||
2265 | |||
2266 | set_bit(STRIPE_HANDLE, &sh->state); | ||
2267 | |||
2268 | BUG_ON(failed>2); | ||
2269 | BUG_ON(uptodate < disks); | ||
2270 | /* Want to check and possibly repair P and Q. | ||
2271 | * However there could be one 'failed' device, in which | ||
2272 | * case we can only check one of them, possibly using the | ||
2273 | * other to generate missing data | ||
2274 | */ | ||
2275 | |||
2276 | /* If !tmp_page, we cannot do the calculations, | ||
2277 | * but as we have set STRIPE_HANDLE, we will soon be called | ||
2278 | * by stripe_handle with a tmp_page - just wait until then. | ||
2279 | */ | ||
2280 | if (tmp_page) { | ||
2281 | if (failed == q_failed) { | ||
2282 | /* The only possible failed device holds 'Q', so it makes | ||
2283 | * sense to check P (If anything else were failed, we would | ||
2284 | * have used P to recreate it). | ||
2285 | */ | ||
2286 | compute_block_1(sh, pd_idx, 1); | ||
2287 | if (!page_is_zero(sh->dev[pd_idx].page)) { | ||
2288 | compute_block_1(sh,pd_idx,0); | ||
2289 | update_p = 1; | ||
2290 | } | ||
2291 | } | ||
2292 | if (!q_failed && failed < 2) { | ||
2293 | /* q is not failed, and we didn't use it to generate | ||
2294 | * anything, so it makes sense to check it | ||
2295 | */ | ||
2296 | memcpy(page_address(tmp_page), | ||
2297 | page_address(sh->dev[qd_idx].page), | ||
2298 | STRIPE_SIZE); | ||
2299 | compute_parity6(sh, UPDATE_PARITY); | ||
2300 | if (memcmp(page_address(tmp_page), | ||
2301 | page_address(sh->dev[qd_idx].page), | ||
2302 | STRIPE_SIZE)!= 0) { | ||
2303 | clear_bit(STRIPE_INSYNC, &sh->state); | ||
2304 | update_q = 1; | ||
2305 | } | ||
2306 | } | ||
2307 | if (update_p || update_q) { | ||
2308 | conf->mddev->resync_mismatches += STRIPE_SECTORS; | ||
2309 | if (test_bit(MD_RECOVERY_CHECK, &conf->mddev->recovery)) | ||
2310 | /* don't try to repair!! */ | ||
2311 | update_p = update_q = 0; | ||
2312 | } | ||
2313 | |||
2314 | /* now write out any block on a failed drive, | ||
2315 | * or P or Q if they need it | ||
2316 | */ | ||
2317 | |||
2318 | if (failed == 2) { | ||
2319 | dev = &sh->dev[failed_num[1]]; | ||
2320 | locked++; | ||
2321 | set_bit(R5_LOCKED, &dev->flags); | ||
2322 | set_bit(R5_Wantwrite, &dev->flags); | ||
2323 | } | ||
2324 | if (failed >= 1) { | ||
2325 | dev = &sh->dev[failed_num[0]]; | ||
2326 | locked++; | ||
2327 | set_bit(R5_LOCKED, &dev->flags); | ||
2328 | set_bit(R5_Wantwrite, &dev->flags); | ||
2329 | } | ||
2330 | |||
2331 | if (update_p) { | ||
2332 | dev = &sh->dev[pd_idx]; | ||
2333 | locked ++; | ||
2334 | set_bit(R5_LOCKED, &dev->flags); | ||
2335 | set_bit(R5_Wantwrite, &dev->flags); | ||
2336 | } | ||
2337 | if (update_q) { | ||
2338 | dev = &sh->dev[qd_idx]; | ||
2339 | locked++; | ||
2340 | set_bit(R5_LOCKED, &dev->flags); | ||
2341 | set_bit(R5_Wantwrite, &dev->flags); | ||
2342 | } | ||
2343 | clear_bit(STRIPE_DEGRADED, &sh->state); | ||
2344 | |||
2345 | set_bit(STRIPE_INSYNC, &sh->state); | ||
2346 | } | ||
2347 | } | ||
2348 | |||
2349 | if (syncing && locked == 0 && test_bit(STRIPE_INSYNC, &sh->state)) { | ||
2350 | md_done_sync(conf->mddev, STRIPE_SECTORS,1); | ||
2351 | clear_bit(STRIPE_SYNCING, &sh->state); | ||
2352 | } | ||
2353 | |||
2354 | /* If the failed drives are just a ReadError, then we might need | ||
2355 | * to progress the repair/check process | ||
2356 | */ | ||
2357 | if (failed <= 2 && ! conf->mddev->ro) | ||
2358 | for (i=0; i<failed;i++) { | ||
2359 | dev = &sh->dev[failed_num[i]]; | ||
2360 | if (test_bit(R5_ReadError, &dev->flags) | ||
2361 | && !test_bit(R5_LOCKED, &dev->flags) | ||
2362 | && test_bit(R5_UPTODATE, &dev->flags) | ||
2363 | ) { | ||
2364 | if (!test_bit(R5_ReWrite, &dev->flags)) { | ||
2365 | set_bit(R5_Wantwrite, &dev->flags); | ||
2366 | set_bit(R5_ReWrite, &dev->flags); | ||
2367 | set_bit(R5_LOCKED, &dev->flags); | ||
2368 | } else { | ||
2369 | /* let's read it back */ | ||
2370 | set_bit(R5_Wantread, &dev->flags); | ||
2371 | set_bit(R5_LOCKED, &dev->flags); | ||
2372 | } | ||
2373 | } | ||
2374 | } | ||
2375 | spin_unlock(&sh->lock); | ||
2376 | |||
2377 | while ((bi=return_bi)) { | ||
2378 | int bytes = bi->bi_size; | ||
2379 | |||
2380 | return_bi = bi->bi_next; | ||
2381 | bi->bi_next = NULL; | ||
2382 | bi->bi_size = 0; | ||
2383 | bi->bi_end_io(bi, bytes, 0); | ||
2384 | } | ||
2385 | for (i=disks; i-- ;) { | ||
2386 | int rw; | ||
2387 | struct bio *bi; | ||
2388 | mdk_rdev_t *rdev; | ||
2389 | if (test_and_clear_bit(R5_Wantwrite, &sh->dev[i].flags)) | ||
2390 | rw = 1; | ||
2391 | else if (test_and_clear_bit(R5_Wantread, &sh->dev[i].flags)) | ||
2392 | rw = 0; | ||
2393 | else | ||
2394 | continue; | ||
2395 | |||
2396 | bi = &sh->dev[i].req; | ||
2397 | |||
2398 | bi->bi_rw = rw; | ||
2399 | if (rw) | ||
2400 | bi->bi_end_io = raid5_end_write_request; | ||
2401 | else | ||
2402 | bi->bi_end_io = raid5_end_read_request; | ||
2403 | |||
2404 | rcu_read_lock(); | ||
2405 | rdev = rcu_dereference(conf->disks[i].rdev); | ||
2406 | if (rdev && test_bit(Faulty, &rdev->flags)) | ||
2407 | rdev = NULL; | ||
2408 | if (rdev) | ||
2409 | atomic_inc(&rdev->nr_pending); | ||
2410 | rcu_read_unlock(); | ||
2411 | |||
2412 | if (rdev) { | ||
2413 | if (syncing) | ||
2414 | md_sync_acct(rdev->bdev, STRIPE_SECTORS); | ||
2415 | |||
2416 | bi->bi_bdev = rdev->bdev; | ||
2417 | PRINTK("for %llu schedule op %ld on disc %d\n", | ||
2418 | (unsigned long long)sh->sector, bi->bi_rw, i); | ||
2419 | atomic_inc(&sh->count); | ||
2420 | bi->bi_sector = sh->sector + rdev->data_offset; | ||
2421 | bi->bi_flags = 1 << BIO_UPTODATE; | ||
2422 | bi->bi_vcnt = 1; | ||
2423 | bi->bi_max_vecs = 1; | ||
2424 | bi->bi_idx = 0; | ||
2425 | bi->bi_io_vec = &sh->dev[i].vec; | ||
2426 | bi->bi_io_vec[0].bv_len = STRIPE_SIZE; | ||
2427 | bi->bi_io_vec[0].bv_offset = 0; | ||
2428 | bi->bi_size = STRIPE_SIZE; | ||
2429 | bi->bi_next = NULL; | ||
2430 | if (rw == WRITE && | ||
2431 | test_bit(R5_ReWrite, &sh->dev[i].flags)) | ||
2432 | atomic_add(STRIPE_SECTORS, &rdev->corrected_errors); | ||
2433 | generic_make_request(bi); | ||
2434 | } else { | ||
2435 | if (rw == 1) | ||
2436 | set_bit(STRIPE_DEGRADED, &sh->state); | ||
2437 | PRINTK("skip op %ld on disc %d for sector %llu\n", | ||
2438 | bi->bi_rw, i, (unsigned long long)sh->sector); | ||
2439 | clear_bit(R5_LOCKED, &sh->dev[i].flags); | ||
2440 | set_bit(STRIPE_HANDLE, &sh->state); | ||
2441 | } | ||
2442 | } | ||
2443 | } | ||
2444 | |||
2445 | static void handle_stripe(struct stripe_head *sh, struct page *tmp_page) | ||
2446 | { | ||
2447 | if (sh->raid_conf->level == 6) | ||
2448 | handle_stripe6(sh, tmp_page); | ||
2449 | else | ||
2450 | handle_stripe5(sh); | ||
2451 | } | ||
2452 | |||
2453 | |||
2454 | |||
1618 | static void raid5_activate_delayed(raid5_conf_t *conf) | 2455 | static void raid5_activate_delayed(raid5_conf_t *conf) |
1619 | { | 2456 | { |
1620 | if (atomic_read(&conf->preread_active_stripes) < IO_THRESHOLD) { | 2457 | if (atomic_read(&conf->preread_active_stripes) < IO_THRESHOLD) { |
@@ -1753,7 +2590,7 @@ static int make_request(request_queue_t *q, struct bio * bi) | |||
1753 | 2590 | ||
1754 | for (;logical_sector < last_sector; logical_sector += STRIPE_SECTORS) { | 2591 | for (;logical_sector < last_sector; logical_sector += STRIPE_SECTORS) { |
1755 | DEFINE_WAIT(w); | 2592 | DEFINE_WAIT(w); |
1756 | int disks; | 2593 | int disks, data_disks; |
1757 | 2594 | ||
1758 | retry: | 2595 | retry: |
1759 | prepare_to_wait(&conf->wait_for_overlap, &w, TASK_UNINTERRUPTIBLE); | 2596 | prepare_to_wait(&conf->wait_for_overlap, &w, TASK_UNINTERRUPTIBLE); |
@@ -1781,7 +2618,9 @@ static int make_request(request_queue_t *q, struct bio * bi) | |||
1781 | } | 2618 | } |
1782 | spin_unlock_irq(&conf->device_lock); | 2619 | spin_unlock_irq(&conf->device_lock); |
1783 | } | 2620 | } |
1784 | new_sector = raid5_compute_sector(logical_sector, disks, disks - 1, | 2621 | data_disks = disks - conf->max_degraded; |
2622 | |||
2623 | new_sector = raid5_compute_sector(logical_sector, disks, data_disks, | ||
1785 | &dd_idx, &pd_idx, conf); | 2624 | &dd_idx, &pd_idx, conf); |
1786 | PRINTK("raid5: make_request, sector %llu logical %llu\n", | 2625 | PRINTK("raid5: make_request, sector %llu logical %llu\n", |
1787 | (unsigned long long)new_sector, | 2626 | (unsigned long long)new_sector, |
@@ -1833,7 +2672,7 @@ static int make_request(request_queue_t *q, struct bio * bi) | |||
1833 | } | 2672 | } |
1834 | finish_wait(&conf->wait_for_overlap, &w); | 2673 | finish_wait(&conf->wait_for_overlap, &w); |
1835 | raid5_plug_device(conf); | 2674 | raid5_plug_device(conf); |
1836 | handle_stripe(sh); | 2675 | handle_stripe(sh, NULL); |
1837 | release_stripe(sh); | 2676 | release_stripe(sh); |
1838 | } else { | 2677 | } else { |
1839 | /* cannot get stripe for read-ahead, just give-up */ | 2678 | /* cannot get stripe for read-ahead, just give-up */ |
@@ -1849,7 +2688,7 @@ static int make_request(request_queue_t *q, struct bio * bi) | |||
1849 | if (remaining == 0) { | 2688 | if (remaining == 0) { |
1850 | int bytes = bi->bi_size; | 2689 | int bytes = bi->bi_size; |
1851 | 2690 | ||
1852 | if ( bio_data_dir(bi) == WRITE ) | 2691 | if ( rw == WRITE ) |
1853 | md_write_end(mddev); | 2692 | md_write_end(mddev); |
1854 | bi->bi_size = 0; | 2693 | bi->bi_size = 0; |
1855 | bi->bi_end_io(bi, bytes, 0); | 2694 | bi->bi_end_io(bi, bytes, 0); |
@@ -1857,17 +2696,142 @@ static int make_request(request_queue_t *q, struct bio * bi) | |||
1857 | return 0; | 2696 | return 0; |
1858 | } | 2697 | } |
1859 | 2698 | ||
1860 | /* FIXME go_faster isn't used */ | 2699 | static sector_t reshape_request(mddev_t *mddev, sector_t sector_nr, int *skipped) |
1861 | static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, int go_faster) | ||
1862 | { | 2700 | { |
2701 | /* reshaping is quite different to recovery/resync so it is | ||
2702 | * handled quite separately ... here. | ||
2703 | * | ||
2704 | * On each call to sync_request, we gather one chunk worth of | ||
2705 | * destination stripes and flag them as expanding. | ||
2706 | * Then we find all the source stripes and request reads. | ||
2707 | * As the reads complete, handle_stripe will copy the data | ||
2708 | * into the destination stripe and release that stripe. | ||
2709 | */ | ||
1863 | raid5_conf_t *conf = (raid5_conf_t *) mddev->private; | 2710 | raid5_conf_t *conf = (raid5_conf_t *) mddev->private; |
1864 | struct stripe_head *sh; | 2711 | struct stripe_head *sh; |
1865 | int pd_idx; | 2712 | int pd_idx; |
1866 | sector_t first_sector, last_sector; | 2713 | sector_t first_sector, last_sector; |
2714 | int raid_disks; | ||
2715 | int data_disks; | ||
2716 | int i; | ||
2717 | int dd_idx; | ||
2718 | sector_t writepos, safepos, gap; | ||
2719 | |||
2720 | if (sector_nr == 0 && | ||
2721 | conf->expand_progress != 0) { | ||
2722 | /* restarting in the middle, skip the initial sectors */ | ||
2723 | sector_nr = conf->expand_progress; | ||
2724 | sector_div(sector_nr, conf->raid_disks-1); | ||
2725 | *skipped = 1; | ||
2726 | return sector_nr; | ||
2727 | } | ||
2728 | |||
2729 | /* we update the metadata when there is more than 3Meg | ||
2730 | * in the block range (that is rather arbitrary, should | ||
2731 | * probably be time based) or when the data about to be | ||
2732 | * copied would over-write the source of the data at | ||
2733 | * the front of the range. | ||
2734 | * i.e. one new_stripe forward from expand_progress new_maps | ||
2735 | * to after where expand_lo old_maps to | ||
2736 | */ | ||
2737 | writepos = conf->expand_progress + | ||
2738 | conf->chunk_size/512*(conf->raid_disks-1); | ||
2739 | sector_div(writepos, conf->raid_disks-1); | ||
2740 | safepos = conf->expand_lo; | ||
2741 | sector_div(safepos, conf->previous_raid_disks-1); | ||
2742 | gap = conf->expand_progress - conf->expand_lo; | ||
2743 | |||
2744 | if (writepos >= safepos || | ||
2745 | gap > (conf->raid_disks-1)*3000*2 /*3Meg*/) { | ||
2746 | /* Cannot proceed until we've updated the superblock... */ | ||
2747 | wait_event(conf->wait_for_overlap, | ||
2748 | atomic_read(&conf->reshape_stripes)==0); | ||
2749 | mddev->reshape_position = conf->expand_progress; | ||
2750 | mddev->sb_dirty = 1; | ||
2751 | md_wakeup_thread(mddev->thread); | ||
2752 | wait_event(mddev->sb_wait, mddev->sb_dirty == 0 || | ||
2753 | kthread_should_stop()); | ||
2754 | spin_lock_irq(&conf->device_lock); | ||
2755 | conf->expand_lo = mddev->reshape_position; | ||
2756 | spin_unlock_irq(&conf->device_lock); | ||
2757 | wake_up(&conf->wait_for_overlap); | ||
2758 | } | ||
2759 | |||
2760 | for (i=0; i < conf->chunk_size/512; i+= STRIPE_SECTORS) { | ||
2761 | int j; | ||
2762 | int skipped = 0; | ||
2763 | pd_idx = stripe_to_pdidx(sector_nr+i, conf, conf->raid_disks); | ||
2764 | sh = get_active_stripe(conf, sector_nr+i, | ||
2765 | conf->raid_disks, pd_idx, 0); | ||
2766 | set_bit(STRIPE_EXPANDING, &sh->state); | ||
2767 | atomic_inc(&conf->reshape_stripes); | ||
2768 | /* If any of this stripe is beyond the end of the old | ||
2769 | * array, then we need to zero those blocks | ||
2770 | */ | ||
2771 | for (j=sh->disks; j--;) { | ||
2772 | sector_t s; | ||
2773 | if (j == sh->pd_idx) | ||
2774 | continue; | ||
2775 | s = compute_blocknr(sh, j); | ||
2776 | if (s < (mddev->array_size<<1)) { | ||
2777 | skipped = 1; | ||
2778 | continue; | ||
2779 | } | ||
2780 | memset(page_address(sh->dev[j].page), 0, STRIPE_SIZE); | ||
2781 | set_bit(R5_Expanded, &sh->dev[j].flags); | ||
2782 | set_bit(R5_UPTODATE, &sh->dev[j].flags); | ||
2783 | } | ||
2784 | if (!skipped) { | ||
2785 | set_bit(STRIPE_EXPAND_READY, &sh->state); | ||
2786 | set_bit(STRIPE_HANDLE, &sh->state); | ||
2787 | } | ||
2788 | release_stripe(sh); | ||
2789 | } | ||
2790 | spin_lock_irq(&conf->device_lock); | ||
2791 | conf->expand_progress = (sector_nr + i)*(conf->raid_disks-1); | ||
2792 | spin_unlock_irq(&conf->device_lock); | ||
2793 | /* Ok, those stripe are ready. We can start scheduling | ||
2794 | * reads on the source stripes. | ||
2795 | * The source stripes are determined by mapping the first and last | ||
2796 | * block on the destination stripes. | ||
2797 | */ | ||
2798 | raid_disks = conf->previous_raid_disks; | ||
2799 | data_disks = raid_disks - 1; | ||
2800 | first_sector = | ||
2801 | raid5_compute_sector(sector_nr*(conf->raid_disks-1), | ||
2802 | raid_disks, data_disks, | ||
2803 | &dd_idx, &pd_idx, conf); | ||
2804 | last_sector = | ||
2805 | raid5_compute_sector((sector_nr+conf->chunk_size/512) | ||
2806 | *(conf->raid_disks-1) -1, | ||
2807 | raid_disks, data_disks, | ||
2808 | &dd_idx, &pd_idx, conf); | ||
2809 | if (last_sector >= (mddev->size<<1)) | ||
2810 | last_sector = (mddev->size<<1)-1; | ||
2811 | while (first_sector <= last_sector) { | ||
2812 | pd_idx = stripe_to_pdidx(first_sector, conf, conf->previous_raid_disks); | ||
2813 | sh = get_active_stripe(conf, first_sector, | ||
2814 | conf->previous_raid_disks, pd_idx, 0); | ||
2815 | set_bit(STRIPE_EXPAND_SOURCE, &sh->state); | ||
2816 | set_bit(STRIPE_HANDLE, &sh->state); | ||
2817 | release_stripe(sh); | ||
2818 | first_sector += STRIPE_SECTORS; | ||
2819 | } | ||
2820 | return conf->chunk_size>>9; | ||
2821 | } | ||
2822 | |||
2823 | /* FIXME go_faster isn't used */ | ||
2824 | static inline sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, int go_faster) | ||
2825 | { | ||
2826 | raid5_conf_t *conf = (raid5_conf_t *) mddev->private; | ||
2827 | struct stripe_head *sh; | ||
2828 | int pd_idx; | ||
1867 | int raid_disks = conf->raid_disks; | 2829 | int raid_disks = conf->raid_disks; |
1868 | int data_disks = raid_disks-1; | 2830 | int data_disks = raid_disks - conf->max_degraded; |
1869 | sector_t max_sector = mddev->size << 1; | 2831 | sector_t max_sector = mddev->size << 1; |
1870 | int sync_blocks; | 2832 | int sync_blocks; |
2833 | int still_degraded = 0; | ||
2834 | int i; | ||
1871 | 2835 | ||
1872 | if (sector_nr >= max_sector) { | 2836 | if (sector_nr >= max_sector) { |
1873 | /* just being told to finish up .. nothing much to do */ | 2837 | /* just being told to finish up .. nothing much to do */ |
@@ -1880,134 +2844,22 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i | |||
1880 | if (mddev->curr_resync < max_sector) /* aborted */ | 2844 | if (mddev->curr_resync < max_sector) /* aborted */ |
1881 | bitmap_end_sync(mddev->bitmap, mddev->curr_resync, | 2845 | bitmap_end_sync(mddev->bitmap, mddev->curr_resync, |
1882 | &sync_blocks, 1); | 2846 | &sync_blocks, 1); |
1883 | else /* compelted sync */ | 2847 | else /* completed sync */ |
1884 | conf->fullsync = 0; | 2848 | conf->fullsync = 0; |
1885 | bitmap_close_sync(mddev->bitmap); | 2849 | bitmap_close_sync(mddev->bitmap); |
1886 | 2850 | ||
1887 | return 0; | 2851 | return 0; |
1888 | } | 2852 | } |
1889 | 2853 | ||
1890 | if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery)) { | 2854 | if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery)) |
1891 | /* reshaping is quite different to recovery/resync so it is | 2855 | return reshape_request(mddev, sector_nr, skipped); |
1892 | * handled quite separately ... here. | 2856 | |
1893 | * | 2857 | /* if there is too many failed drives and we are trying |
1894 | * On each call to sync_request, we gather one chunk worth of | ||
1895 | * destination stripes and flag them as expanding. | ||
1896 | * Then we find all the source stripes and request reads. | ||
1897 | * As the reads complete, handle_stripe will copy the data | ||
1898 | * into the destination stripe and release that stripe. | ||
1899 | */ | ||
1900 | int i; | ||
1901 | int dd_idx; | ||
1902 | sector_t writepos, safepos, gap; | ||
1903 | |||
1904 | if (sector_nr == 0 && | ||
1905 | conf->expand_progress != 0) { | ||
1906 | /* restarting in the middle, skip the initial sectors */ | ||
1907 | sector_nr = conf->expand_progress; | ||
1908 | sector_div(sector_nr, conf->raid_disks-1); | ||
1909 | *skipped = 1; | ||
1910 | return sector_nr; | ||
1911 | } | ||
1912 | |||
1913 | /* we update the metadata when there is more than 3Meg | ||
1914 | * in the block range (that is rather arbitrary, should | ||
1915 | * probably be time based) or when the data about to be | ||
1916 | * copied would over-write the source of the data at | ||
1917 | * the front of the range. | ||
1918 | * i.e. one new_stripe forward from expand_progress new_maps | ||
1919 | * to after where expand_lo old_maps to | ||
1920 | */ | ||
1921 | writepos = conf->expand_progress + | ||
1922 | conf->chunk_size/512*(conf->raid_disks-1); | ||
1923 | sector_div(writepos, conf->raid_disks-1); | ||
1924 | safepos = conf->expand_lo; | ||
1925 | sector_div(safepos, conf->previous_raid_disks-1); | ||
1926 | gap = conf->expand_progress - conf->expand_lo; | ||
1927 | |||
1928 | if (writepos >= safepos || | ||
1929 | gap > (conf->raid_disks-1)*3000*2 /*3Meg*/) { | ||
1930 | /* Cannot proceed until we've updated the superblock... */ | ||
1931 | wait_event(conf->wait_for_overlap, | ||
1932 | atomic_read(&conf->reshape_stripes)==0); | ||
1933 | mddev->reshape_position = conf->expand_progress; | ||
1934 | mddev->sb_dirty = 1; | ||
1935 | md_wakeup_thread(mddev->thread); | ||
1936 | wait_event(mddev->sb_wait, mddev->sb_dirty == 0 || | ||
1937 | kthread_should_stop()); | ||
1938 | spin_lock_irq(&conf->device_lock); | ||
1939 | conf->expand_lo = mddev->reshape_position; | ||
1940 | spin_unlock_irq(&conf->device_lock); | ||
1941 | wake_up(&conf->wait_for_overlap); | ||
1942 | } | ||
1943 | |||
1944 | for (i=0; i < conf->chunk_size/512; i+= STRIPE_SECTORS) { | ||
1945 | int j; | ||
1946 | int skipped = 0; | ||
1947 | pd_idx = stripe_to_pdidx(sector_nr+i, conf, conf->raid_disks); | ||
1948 | sh = get_active_stripe(conf, sector_nr+i, | ||
1949 | conf->raid_disks, pd_idx, 0); | ||
1950 | set_bit(STRIPE_EXPANDING, &sh->state); | ||
1951 | atomic_inc(&conf->reshape_stripes); | ||
1952 | /* If any of this stripe is beyond the end of the old | ||
1953 | * array, then we need to zero those blocks | ||
1954 | */ | ||
1955 | for (j=sh->disks; j--;) { | ||
1956 | sector_t s; | ||
1957 | if (j == sh->pd_idx) | ||
1958 | continue; | ||
1959 | s = compute_blocknr(sh, j); | ||
1960 | if (s < (mddev->array_size<<1)) { | ||
1961 | skipped = 1; | ||
1962 | continue; | ||
1963 | } | ||
1964 | memset(page_address(sh->dev[j].page), 0, STRIPE_SIZE); | ||
1965 | set_bit(R5_Expanded, &sh->dev[j].flags); | ||
1966 | set_bit(R5_UPTODATE, &sh->dev[j].flags); | ||
1967 | } | ||
1968 | if (!skipped) { | ||
1969 | set_bit(STRIPE_EXPAND_READY, &sh->state); | ||
1970 | set_bit(STRIPE_HANDLE, &sh->state); | ||
1971 | } | ||
1972 | release_stripe(sh); | ||
1973 | } | ||
1974 | spin_lock_irq(&conf->device_lock); | ||
1975 | conf->expand_progress = (sector_nr + i)*(conf->raid_disks-1); | ||
1976 | spin_unlock_irq(&conf->device_lock); | ||
1977 | /* Ok, those stripe are ready. We can start scheduling | ||
1978 | * reads on the source stripes. | ||
1979 | * The source stripes are determined by mapping the first and last | ||
1980 | * block on the destination stripes. | ||
1981 | */ | ||
1982 | raid_disks = conf->previous_raid_disks; | ||
1983 | data_disks = raid_disks - 1; | ||
1984 | first_sector = | ||
1985 | raid5_compute_sector(sector_nr*(conf->raid_disks-1), | ||
1986 | raid_disks, data_disks, | ||
1987 | &dd_idx, &pd_idx, conf); | ||
1988 | last_sector = | ||
1989 | raid5_compute_sector((sector_nr+conf->chunk_size/512) | ||
1990 | *(conf->raid_disks-1) -1, | ||
1991 | raid_disks, data_disks, | ||
1992 | &dd_idx, &pd_idx, conf); | ||
1993 | if (last_sector >= (mddev->size<<1)) | ||
1994 | last_sector = (mddev->size<<1)-1; | ||
1995 | while (first_sector <= last_sector) { | ||
1996 | pd_idx = stripe_to_pdidx(first_sector, conf, conf->previous_raid_disks); | ||
1997 | sh = get_active_stripe(conf, first_sector, | ||
1998 | conf->previous_raid_disks, pd_idx, 0); | ||
1999 | set_bit(STRIPE_EXPAND_SOURCE, &sh->state); | ||
2000 | set_bit(STRIPE_HANDLE, &sh->state); | ||
2001 | release_stripe(sh); | ||
2002 | first_sector += STRIPE_SECTORS; | ||
2003 | } | ||
2004 | return conf->chunk_size>>9; | ||
2005 | } | ||
2006 | /* if there is 1 or more failed drives and we are trying | ||
2007 | * to resync, then assert that we are finished, because there is | 2858 | * to resync, then assert that we are finished, because there is |
2008 | * nothing we can do. | 2859 | * nothing we can do. |
2009 | */ | 2860 | */ |
2010 | if (mddev->degraded >= 1 && test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) { | 2861 | if (mddev->degraded >= conf->max_degraded && |
2862 | test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) { | ||
2011 | sector_t rv = (mddev->size << 1) - sector_nr; | 2863 | sector_t rv = (mddev->size << 1) - sector_nr; |
2012 | *skipped = 1; | 2864 | *skipped = 1; |
2013 | return rv; | 2865 | return rv; |
@@ -2026,17 +2878,26 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i | |||
2026 | if (sh == NULL) { | 2878 | if (sh == NULL) { |
2027 | sh = get_active_stripe(conf, sector_nr, raid_disks, pd_idx, 0); | 2879 | sh = get_active_stripe(conf, sector_nr, raid_disks, pd_idx, 0); |
2028 | /* make sure we don't swamp the stripe cache if someone else | 2880 | /* make sure we don't swamp the stripe cache if someone else |
2029 | * is trying to get access | 2881 | * is trying to get access |
2030 | */ | 2882 | */ |
2031 | schedule_timeout_uninterruptible(1); | 2883 | schedule_timeout_uninterruptible(1); |
2032 | } | 2884 | } |
2033 | bitmap_start_sync(mddev->bitmap, sector_nr, &sync_blocks, 0); | 2885 | /* Need to check if array will still be degraded after recovery/resync |
2034 | spin_lock(&sh->lock); | 2886 | * We don't need to check the 'failed' flag as when that gets set, |
2887 | * recovery aborts. | ||
2888 | */ | ||
2889 | for (i=0; i<mddev->raid_disks; i++) | ||
2890 | if (conf->disks[i].rdev == NULL) | ||
2891 | still_degraded = 1; | ||
2892 | |||
2893 | bitmap_start_sync(mddev->bitmap, sector_nr, &sync_blocks, still_degraded); | ||
2894 | |||
2895 | spin_lock(&sh->lock); | ||
2035 | set_bit(STRIPE_SYNCING, &sh->state); | 2896 | set_bit(STRIPE_SYNCING, &sh->state); |
2036 | clear_bit(STRIPE_INSYNC, &sh->state); | 2897 | clear_bit(STRIPE_INSYNC, &sh->state); |
2037 | spin_unlock(&sh->lock); | 2898 | spin_unlock(&sh->lock); |
2038 | 2899 | ||
2039 | handle_stripe(sh); | 2900 | handle_stripe(sh, NULL); |
2040 | release_stripe(sh); | 2901 | release_stripe(sh); |
2041 | 2902 | ||
2042 | return STRIPE_SECTORS; | 2903 | return STRIPE_SECTORS; |
@@ -2091,7 +2952,7 @@ static void raid5d (mddev_t *mddev) | |||
2091 | spin_unlock_irq(&conf->device_lock); | 2952 | spin_unlock_irq(&conf->device_lock); |
2092 | 2953 | ||
2093 | handled++; | 2954 | handled++; |
2094 | handle_stripe(sh); | 2955 | handle_stripe(sh, conf->spare_page); |
2095 | release_stripe(sh); | 2956 | release_stripe(sh); |
2096 | 2957 | ||
2097 | spin_lock_irq(&conf->device_lock); | 2958 | spin_lock_irq(&conf->device_lock); |
@@ -2181,8 +3042,8 @@ static int run(mddev_t *mddev) | |||
2181 | struct disk_info *disk; | 3042 | struct disk_info *disk; |
2182 | struct list_head *tmp; | 3043 | struct list_head *tmp; |
2183 | 3044 | ||
2184 | if (mddev->level != 5 && mddev->level != 4) { | 3045 | if (mddev->level != 5 && mddev->level != 4 && mddev->level != 6) { |
2185 | printk(KERN_ERR "raid5: %s: raid level not set to 4/5 (%d)\n", | 3046 | printk(KERN_ERR "raid5: %s: raid level not set to 4/5/6 (%d)\n", |
2186 | mdname(mddev), mddev->level); | 3047 | mdname(mddev), mddev->level); |
2187 | return -EIO; | 3048 | return -EIO; |
2188 | } | 3049 | } |
@@ -2251,6 +3112,11 @@ static int run(mddev_t *mddev) | |||
2251 | if ((conf->stripe_hashtbl = kzalloc(PAGE_SIZE, GFP_KERNEL)) == NULL) | 3112 | if ((conf->stripe_hashtbl = kzalloc(PAGE_SIZE, GFP_KERNEL)) == NULL) |
2252 | goto abort; | 3113 | goto abort; |
2253 | 3114 | ||
3115 | if (mddev->level == 6) { | ||
3116 | conf->spare_page = alloc_page(GFP_KERNEL); | ||
3117 | if (!conf->spare_page) | ||
3118 | goto abort; | ||
3119 | } | ||
2254 | spin_lock_init(&conf->device_lock); | 3120 | spin_lock_init(&conf->device_lock); |
2255 | init_waitqueue_head(&conf->wait_for_stripe); | 3121 | init_waitqueue_head(&conf->wait_for_stripe); |
2256 | init_waitqueue_head(&conf->wait_for_overlap); | 3122 | init_waitqueue_head(&conf->wait_for_overlap); |
@@ -2282,12 +3148,16 @@ static int run(mddev_t *mddev) | |||
2282 | } | 3148 | } |
2283 | 3149 | ||
2284 | /* | 3150 | /* |
2285 | * 0 for a fully functional array, 1 for a degraded array. | 3151 | * 0 for a fully functional array, 1 or 2 for a degraded array. |
2286 | */ | 3152 | */ |
2287 | mddev->degraded = conf->failed_disks = conf->raid_disks - conf->working_disks; | 3153 | mddev->degraded = conf->failed_disks = conf->raid_disks - conf->working_disks; |
2288 | conf->mddev = mddev; | 3154 | conf->mddev = mddev; |
2289 | conf->chunk_size = mddev->chunk_size; | 3155 | conf->chunk_size = mddev->chunk_size; |
2290 | conf->level = mddev->level; | 3156 | conf->level = mddev->level; |
3157 | if (conf->level == 6) | ||
3158 | conf->max_degraded = 2; | ||
3159 | else | ||
3160 | conf->max_degraded = 1; | ||
2291 | conf->algorithm = mddev->layout; | 3161 | conf->algorithm = mddev->layout; |
2292 | conf->max_nr_stripes = NR_STRIPES; | 3162 | conf->max_nr_stripes = NR_STRIPES; |
2293 | conf->expand_progress = mddev->reshape_position; | 3163 | conf->expand_progress = mddev->reshape_position; |
@@ -2296,6 +3166,11 @@ static int run(mddev_t *mddev) | |||
2296 | mddev->size &= ~(mddev->chunk_size/1024 -1); | 3166 | mddev->size &= ~(mddev->chunk_size/1024 -1); |
2297 | mddev->resync_max_sectors = mddev->size << 1; | 3167 | mddev->resync_max_sectors = mddev->size << 1; |
2298 | 3168 | ||
3169 | if (conf->level == 6 && conf->raid_disks < 4) { | ||
3170 | printk(KERN_ERR "raid6: not enough configured devices for %s (%d, minimum 4)\n", | ||
3171 | mdname(mddev), conf->raid_disks); | ||
3172 | goto abort; | ||
3173 | } | ||
2299 | if (!conf->chunk_size || conf->chunk_size % 4) { | 3174 | if (!conf->chunk_size || conf->chunk_size % 4) { |
2300 | printk(KERN_ERR "raid5: invalid chunk size %d for %s\n", | 3175 | printk(KERN_ERR "raid5: invalid chunk size %d for %s\n", |
2301 | conf->chunk_size, mdname(mddev)); | 3176 | conf->chunk_size, mdname(mddev)); |
@@ -2307,14 +3182,14 @@ static int run(mddev_t *mddev) | |||
2307 | conf->algorithm, mdname(mddev)); | 3182 | conf->algorithm, mdname(mddev)); |
2308 | goto abort; | 3183 | goto abort; |
2309 | } | 3184 | } |
2310 | if (mddev->degraded > 1) { | 3185 | if (mddev->degraded > conf->max_degraded) { |
2311 | printk(KERN_ERR "raid5: not enough operational devices for %s" | 3186 | printk(KERN_ERR "raid5: not enough operational devices for %s" |
2312 | " (%d/%d failed)\n", | 3187 | " (%d/%d failed)\n", |
2313 | mdname(mddev), conf->failed_disks, conf->raid_disks); | 3188 | mdname(mddev), conf->failed_disks, conf->raid_disks); |
2314 | goto abort; | 3189 | goto abort; |
2315 | } | 3190 | } |
2316 | 3191 | ||
2317 | if (mddev->degraded == 1 && | 3192 | if (mddev->degraded > 0 && |
2318 | mddev->recovery_cp != MaxSector) { | 3193 | mddev->recovery_cp != MaxSector) { |
2319 | if (mddev->ok_start_degraded) | 3194 | if (mddev->ok_start_degraded) |
2320 | printk(KERN_WARNING | 3195 | printk(KERN_WARNING |
@@ -2379,11 +3254,12 @@ static int run(mddev_t *mddev) | |||
2379 | } | 3254 | } |
2380 | 3255 | ||
2381 | /* read-ahead size must cover two whole stripes, which is | 3256 | /* read-ahead size must cover two whole stripes, which is |
2382 | * 2 * (n-1) * chunksize where 'n' is the number of raid devices | 3257 | * 2 * (datadisks) * chunksize where 'n' is the number of raid devices |
2383 | */ | 3258 | */ |
2384 | { | 3259 | { |
2385 | int stripe = (mddev->raid_disks-1) * mddev->chunk_size | 3260 | int data_disks = conf->previous_raid_disks - conf->max_degraded; |
2386 | / PAGE_SIZE; | 3261 | int stripe = data_disks * |
3262 | (mddev->chunk_size / PAGE_SIZE); | ||
2387 | if (mddev->queue->backing_dev_info.ra_pages < 2 * stripe) | 3263 | if (mddev->queue->backing_dev_info.ra_pages < 2 * stripe) |
2388 | mddev->queue->backing_dev_info.ra_pages = 2 * stripe; | 3264 | mddev->queue->backing_dev_info.ra_pages = 2 * stripe; |
2389 | } | 3265 | } |
@@ -2393,12 +3269,14 @@ static int run(mddev_t *mddev) | |||
2393 | 3269 | ||
2394 | mddev->queue->unplug_fn = raid5_unplug_device; | 3270 | mddev->queue->unplug_fn = raid5_unplug_device; |
2395 | mddev->queue->issue_flush_fn = raid5_issue_flush; | 3271 | mddev->queue->issue_flush_fn = raid5_issue_flush; |
2396 | mddev->array_size = mddev->size * (conf->previous_raid_disks - 1); | 3272 | mddev->array_size = mddev->size * (conf->previous_raid_disks - |
3273 | conf->max_degraded); | ||
2397 | 3274 | ||
2398 | return 0; | 3275 | return 0; |
2399 | abort: | 3276 | abort: |
2400 | if (conf) { | 3277 | if (conf) { |
2401 | print_raid5_conf(conf); | 3278 | print_raid5_conf(conf); |
3279 | safe_put_page(conf->spare_page); | ||
2402 | kfree(conf->disks); | 3280 | kfree(conf->disks); |
2403 | kfree(conf->stripe_hashtbl); | 3281 | kfree(conf->stripe_hashtbl); |
2404 | kfree(conf); | 3282 | kfree(conf); |
@@ -2427,23 +3305,23 @@ static int stop(mddev_t *mddev) | |||
2427 | } | 3305 | } |
2428 | 3306 | ||
2429 | #if RAID5_DEBUG | 3307 | #if RAID5_DEBUG |
2430 | static void print_sh (struct stripe_head *sh) | 3308 | static void print_sh (struct seq_file *seq, struct stripe_head *sh) |
2431 | { | 3309 | { |
2432 | int i; | 3310 | int i; |
2433 | 3311 | ||
2434 | printk("sh %llu, pd_idx %d, state %ld.\n", | 3312 | seq_printf(seq, "sh %llu, pd_idx %d, state %ld.\n", |
2435 | (unsigned long long)sh->sector, sh->pd_idx, sh->state); | 3313 | (unsigned long long)sh->sector, sh->pd_idx, sh->state); |
2436 | printk("sh %llu, count %d.\n", | 3314 | seq_printf(seq, "sh %llu, count %d.\n", |
2437 | (unsigned long long)sh->sector, atomic_read(&sh->count)); | 3315 | (unsigned long long)sh->sector, atomic_read(&sh->count)); |
2438 | printk("sh %llu, ", (unsigned long long)sh->sector); | 3316 | seq_printf(seq, "sh %llu, ", (unsigned long long)sh->sector); |
2439 | for (i = 0; i < sh->disks; i++) { | 3317 | for (i = 0; i < sh->disks; i++) { |
2440 | printk("(cache%d: %p %ld) ", | 3318 | seq_printf(seq, "(cache%d: %p %ld) ", |
2441 | i, sh->dev[i].page, sh->dev[i].flags); | 3319 | i, sh->dev[i].page, sh->dev[i].flags); |
2442 | } | 3320 | } |
2443 | printk("\n"); | 3321 | seq_printf(seq, "\n"); |
2444 | } | 3322 | } |
2445 | 3323 | ||
2446 | static void printall (raid5_conf_t *conf) | 3324 | static void printall (struct seq_file *seq, raid5_conf_t *conf) |
2447 | { | 3325 | { |
2448 | struct stripe_head *sh; | 3326 | struct stripe_head *sh; |
2449 | struct hlist_node *hn; | 3327 | struct hlist_node *hn; |
@@ -2454,7 +3332,7 @@ static void printall (raid5_conf_t *conf) | |||
2454 | hlist_for_each_entry(sh, hn, &conf->stripe_hashtbl[i], hash) { | 3332 | hlist_for_each_entry(sh, hn, &conf->stripe_hashtbl[i], hash) { |
2455 | if (sh->raid_conf != conf) | 3333 | if (sh->raid_conf != conf) |
2456 | continue; | 3334 | continue; |
2457 | print_sh(sh); | 3335 | print_sh(seq, sh); |
2458 | } | 3336 | } |
2459 | } | 3337 | } |
2460 | spin_unlock_irq(&conf->device_lock); | 3338 | spin_unlock_irq(&conf->device_lock); |
@@ -2474,9 +3352,8 @@ static void status (struct seq_file *seq, mddev_t *mddev) | |||
2474 | test_bit(In_sync, &conf->disks[i].rdev->flags) ? "U" : "_"); | 3352 | test_bit(In_sync, &conf->disks[i].rdev->flags) ? "U" : "_"); |
2475 | seq_printf (seq, "]"); | 3353 | seq_printf (seq, "]"); |
2476 | #if RAID5_DEBUG | 3354 | #if RAID5_DEBUG |
2477 | #define D(x) \ | 3355 | seq_printf (seq, "\n"); |
2478 | seq_printf (seq, "<"#x":%d>", atomic_read(&conf->x)) | 3356 | printall(seq, conf); |
2479 | printall(conf); | ||
2480 | #endif | 3357 | #endif |
2481 | } | 3358 | } |
2482 | 3359 | ||
@@ -2560,14 +3437,20 @@ static int raid5_add_disk(mddev_t *mddev, mdk_rdev_t *rdev) | |||
2560 | int disk; | 3437 | int disk; |
2561 | struct disk_info *p; | 3438 | struct disk_info *p; |
2562 | 3439 | ||
2563 | if (mddev->degraded > 1) | 3440 | if (mddev->degraded > conf->max_degraded) |
2564 | /* no point adding a device */ | 3441 | /* no point adding a device */ |
2565 | return 0; | 3442 | return 0; |
2566 | 3443 | ||
2567 | /* | 3444 | /* |
2568 | * find the disk ... | 3445 | * find the disk ... but prefer rdev->saved_raid_disk |
3446 | * if possible. | ||
2569 | */ | 3447 | */ |
2570 | for (disk=0; disk < conf->raid_disks; disk++) | 3448 | if (rdev->saved_raid_disk >= 0 && |
3449 | conf->disks[rdev->saved_raid_disk].rdev == NULL) | ||
3450 | disk = rdev->saved_raid_disk; | ||
3451 | else | ||
3452 | disk = 0; | ||
3453 | for ( ; disk < conf->raid_disks; disk++) | ||
2571 | if ((p=conf->disks + disk)->rdev == NULL) { | 3454 | if ((p=conf->disks + disk)->rdev == NULL) { |
2572 | clear_bit(In_sync, &rdev->flags); | 3455 | clear_bit(In_sync, &rdev->flags); |
2573 | rdev->raid_disk = disk; | 3456 | rdev->raid_disk = disk; |
@@ -2590,8 +3473,10 @@ static int raid5_resize(mddev_t *mddev, sector_t sectors) | |||
2590 | * any io in the removed space completes, but it hardly seems | 3473 | * any io in the removed space completes, but it hardly seems |
2591 | * worth it. | 3474 | * worth it. |
2592 | */ | 3475 | */ |
3476 | raid5_conf_t *conf = mddev_to_conf(mddev); | ||
3477 | |||
2593 | sectors &= ~((sector_t)mddev->chunk_size/512 - 1); | 3478 | sectors &= ~((sector_t)mddev->chunk_size/512 - 1); |
2594 | mddev->array_size = (sectors * (mddev->raid_disks-1))>>1; | 3479 | mddev->array_size = (sectors * (mddev->raid_disks-conf->max_degraded))>>1; |
2595 | set_capacity(mddev->gendisk, mddev->array_size << 1); | 3480 | set_capacity(mddev->gendisk, mddev->array_size << 1); |
2596 | mddev->changed = 1; | 3481 | mddev->changed = 1; |
2597 | if (sectors/2 > mddev->size && mddev->recovery_cp == MaxSector) { | 3482 | if (sectors/2 > mddev->size && mddev->recovery_cp == MaxSector) { |
@@ -2680,6 +3565,7 @@ static int raid5_start_reshape(mddev_t *mddev) | |||
2680 | set_bit(In_sync, &rdev->flags); | 3565 | set_bit(In_sync, &rdev->flags); |
2681 | conf->working_disks++; | 3566 | conf->working_disks++; |
2682 | added_devices++; | 3567 | added_devices++; |
3568 | rdev->recovery_offset = 0; | ||
2683 | sprintf(nm, "rd%d", rdev->raid_disk); | 3569 | sprintf(nm, "rd%d", rdev->raid_disk); |
2684 | sysfs_create_link(&mddev->kobj, &rdev->kobj, nm); | 3570 | sysfs_create_link(&mddev->kobj, &rdev->kobj, nm); |
2685 | } else | 3571 | } else |
@@ -2731,6 +3617,17 @@ static void end_reshape(raid5_conf_t *conf) | |||
2731 | conf->expand_progress = MaxSector; | 3617 | conf->expand_progress = MaxSector; |
2732 | spin_unlock_irq(&conf->device_lock); | 3618 | spin_unlock_irq(&conf->device_lock); |
2733 | conf->mddev->reshape_position = MaxSector; | 3619 | conf->mddev->reshape_position = MaxSector; |
3620 | |||
3621 | /* read-ahead size must cover two whole stripes, which is | ||
3622 | * 2 * (datadisks) * chunksize where 'n' is the number of raid devices | ||
3623 | */ | ||
3624 | { | ||
3625 | int data_disks = conf->previous_raid_disks - conf->max_degraded; | ||
3626 | int stripe = data_disks * | ||
3627 | (conf->mddev->chunk_size / PAGE_SIZE); | ||
3628 | if (conf->mddev->queue->backing_dev_info.ra_pages < 2 * stripe) | ||
3629 | conf->mddev->queue->backing_dev_info.ra_pages = 2 * stripe; | ||
3630 | } | ||
2734 | } | 3631 | } |
2735 | } | 3632 | } |
2736 | 3633 | ||
@@ -2762,6 +3659,23 @@ static void raid5_quiesce(mddev_t *mddev, int state) | |||
2762 | } | 3659 | } |
2763 | } | 3660 | } |
2764 | 3661 | ||
3662 | static struct mdk_personality raid6_personality = | ||
3663 | { | ||
3664 | .name = "raid6", | ||
3665 | .level = 6, | ||
3666 | .owner = THIS_MODULE, | ||
3667 | .make_request = make_request, | ||
3668 | .run = run, | ||
3669 | .stop = stop, | ||
3670 | .status = status, | ||
3671 | .error_handler = error, | ||
3672 | .hot_add_disk = raid5_add_disk, | ||
3673 | .hot_remove_disk= raid5_remove_disk, | ||
3674 | .spare_active = raid5_spare_active, | ||
3675 | .sync_request = sync_request, | ||
3676 | .resize = raid5_resize, | ||
3677 | .quiesce = raid5_quiesce, | ||
3678 | }; | ||
2765 | static struct mdk_personality raid5_personality = | 3679 | static struct mdk_personality raid5_personality = |
2766 | { | 3680 | { |
2767 | .name = "raid5", | 3681 | .name = "raid5", |
@@ -2804,6 +3718,12 @@ static struct mdk_personality raid4_personality = | |||
2804 | 3718 | ||
2805 | static int __init raid5_init(void) | 3719 | static int __init raid5_init(void) |
2806 | { | 3720 | { |
3721 | int e; | ||
3722 | |||
3723 | e = raid6_select_algo(); | ||
3724 | if ( e ) | ||
3725 | return e; | ||
3726 | register_md_personality(&raid6_personality); | ||
2807 | register_md_personality(&raid5_personality); | 3727 | register_md_personality(&raid5_personality); |
2808 | register_md_personality(&raid4_personality); | 3728 | register_md_personality(&raid4_personality); |
2809 | return 0; | 3729 | return 0; |
@@ -2811,6 +3731,7 @@ static int __init raid5_init(void) | |||
2811 | 3731 | ||
2812 | static void raid5_exit(void) | 3732 | static void raid5_exit(void) |
2813 | { | 3733 | { |
3734 | unregister_md_personality(&raid6_personality); | ||
2814 | unregister_md_personality(&raid5_personality); | 3735 | unregister_md_personality(&raid5_personality); |
2815 | unregister_md_personality(&raid4_personality); | 3736 | unregister_md_personality(&raid4_personality); |
2816 | } | 3737 | } |
@@ -2823,3 +3744,10 @@ MODULE_ALIAS("md-raid5"); | |||
2823 | MODULE_ALIAS("md-raid4"); | 3744 | MODULE_ALIAS("md-raid4"); |
2824 | MODULE_ALIAS("md-level-5"); | 3745 | MODULE_ALIAS("md-level-5"); |
2825 | MODULE_ALIAS("md-level-4"); | 3746 | MODULE_ALIAS("md-level-4"); |
3747 | MODULE_ALIAS("md-personality-8"); /* RAID6 */ | ||
3748 | MODULE_ALIAS("md-raid6"); | ||
3749 | MODULE_ALIAS("md-level-6"); | ||
3750 | |||
3751 | /* This used to be two separate modules, they were: */ | ||
3752 | MODULE_ALIAS("raid5"); | ||
3753 | MODULE_ALIAS("raid6"); | ||
diff --git a/drivers/md/raid6main.c b/drivers/md/raid6main.c deleted file mode 100644 index bc69355e0100..000000000000 --- a/drivers/md/raid6main.c +++ /dev/null | |||
@@ -1,2427 +0,0 @@ | |||
1 | /* | ||
2 | * raid6main.c : Multiple Devices driver for Linux | ||
3 | * Copyright (C) 1996, 1997 Ingo Molnar, Miguel de Icaza, Gadi Oxman | ||
4 | * Copyright (C) 1999, 2000 Ingo Molnar | ||
5 | * Copyright (C) 2002, 2003 H. Peter Anvin | ||
6 | * | ||
7 | * RAID-6 management functions. This code is derived from raid5.c. | ||
8 | * Last merge from raid5.c bkcvs version 1.79 (kernel 2.6.1). | ||
9 | * | ||
10 | * Thanks to Penguin Computing for making the RAID-6 development possible | ||
11 | * by donating a test server! | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify | ||
14 | * it under the terms of the GNU General Public License as published by | ||
15 | * the Free Software Foundation; either version 2, or (at your option) | ||
16 | * any later version. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * (for example /usr/src/linux/COPYING); if not, write to the Free | ||
20 | * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | */ | ||
22 | |||
23 | |||
24 | #include <linux/config.h> | ||
25 | #include <linux/module.h> | ||
26 | #include <linux/slab.h> | ||
27 | #include <linux/highmem.h> | ||
28 | #include <linux/bitops.h> | ||
29 | #include <asm/atomic.h> | ||
30 | #include "raid6.h" | ||
31 | |||
32 | #include <linux/raid/bitmap.h> | ||
33 | |||
34 | /* | ||
35 | * Stripe cache | ||
36 | */ | ||
37 | |||
38 | #define NR_STRIPES 256 | ||
39 | #define STRIPE_SIZE PAGE_SIZE | ||
40 | #define STRIPE_SHIFT (PAGE_SHIFT - 9) | ||
41 | #define STRIPE_SECTORS (STRIPE_SIZE>>9) | ||
42 | #define IO_THRESHOLD 1 | ||
43 | #define NR_HASH (PAGE_SIZE / sizeof(struct hlist_head)) | ||
44 | #define HASH_MASK (NR_HASH - 1) | ||
45 | |||
46 | #define stripe_hash(conf, sect) (&((conf)->stripe_hashtbl[((sect) >> STRIPE_SHIFT) & HASH_MASK])) | ||
47 | |||
48 | /* bio's attached to a stripe+device for I/O are linked together in bi_sector | ||
49 | * order without overlap. There may be several bio's per stripe+device, and | ||
50 | * a bio could span several devices. | ||
51 | * When walking this list for a particular stripe+device, we must never proceed | ||
52 | * beyond a bio that extends past this device, as the next bio might no longer | ||
53 | * be valid. | ||
54 | * This macro is used to determine the 'next' bio in the list, given the sector | ||
55 | * of the current stripe+device | ||
56 | */ | ||
57 | #define r5_next_bio(bio, sect) ( ( (bio)->bi_sector + ((bio)->bi_size>>9) < sect + STRIPE_SECTORS) ? (bio)->bi_next : NULL) | ||
58 | /* | ||
59 | * The following can be used to debug the driver | ||
60 | */ | ||
61 | #define RAID6_DEBUG 0 /* Extremely verbose printk */ | ||
62 | #define RAID6_PARANOIA 1 /* Check spinlocks */ | ||
63 | #define RAID6_DUMPSTATE 0 /* Include stripe cache state in /proc/mdstat */ | ||
64 | #if RAID6_PARANOIA && defined(CONFIG_SMP) | ||
65 | # define CHECK_DEVLOCK() assert_spin_locked(&conf->device_lock) | ||
66 | #else | ||
67 | # define CHECK_DEVLOCK() | ||
68 | #endif | ||
69 | |||
70 | #define PRINTK(x...) ((void)(RAID6_DEBUG && printk(KERN_DEBUG x))) | ||
71 | #if RAID6_DEBUG | ||
72 | #undef inline | ||
73 | #undef __inline__ | ||
74 | #define inline | ||
75 | #define __inline__ | ||
76 | #endif | ||
77 | |||
78 | #if !RAID6_USE_EMPTY_ZERO_PAGE | ||
79 | /* In .bss so it's zeroed */ | ||
80 | const char raid6_empty_zero_page[PAGE_SIZE] __attribute__((aligned(256))); | ||
81 | #endif | ||
82 | |||
83 | static inline int raid6_next_disk(int disk, int raid_disks) | ||
84 | { | ||
85 | disk++; | ||
86 | return (disk < raid_disks) ? disk : 0; | ||
87 | } | ||
88 | |||
89 | static void print_raid6_conf (raid6_conf_t *conf); | ||
90 | |||
91 | static void __release_stripe(raid6_conf_t *conf, struct stripe_head *sh) | ||
92 | { | ||
93 | if (atomic_dec_and_test(&sh->count)) { | ||
94 | BUG_ON(!list_empty(&sh->lru)); | ||
95 | BUG_ON(atomic_read(&conf->active_stripes)==0); | ||
96 | if (test_bit(STRIPE_HANDLE, &sh->state)) { | ||
97 | if (test_bit(STRIPE_DELAYED, &sh->state)) | ||
98 | list_add_tail(&sh->lru, &conf->delayed_list); | ||
99 | else if (test_bit(STRIPE_BIT_DELAY, &sh->state) && | ||
100 | conf->seq_write == sh->bm_seq) | ||
101 | list_add_tail(&sh->lru, &conf->bitmap_list); | ||
102 | else { | ||
103 | clear_bit(STRIPE_BIT_DELAY, &sh->state); | ||
104 | list_add_tail(&sh->lru, &conf->handle_list); | ||
105 | } | ||
106 | md_wakeup_thread(conf->mddev->thread); | ||
107 | } else { | ||
108 | if (test_and_clear_bit(STRIPE_PREREAD_ACTIVE, &sh->state)) { | ||
109 | atomic_dec(&conf->preread_active_stripes); | ||
110 | if (atomic_read(&conf->preread_active_stripes) < IO_THRESHOLD) | ||
111 | md_wakeup_thread(conf->mddev->thread); | ||
112 | } | ||
113 | list_add_tail(&sh->lru, &conf->inactive_list); | ||
114 | atomic_dec(&conf->active_stripes); | ||
115 | if (!conf->inactive_blocked || | ||
116 | atomic_read(&conf->active_stripes) < (conf->max_nr_stripes*3/4)) | ||
117 | wake_up(&conf->wait_for_stripe); | ||
118 | } | ||
119 | } | ||
120 | } | ||
121 | static void release_stripe(struct stripe_head *sh) | ||
122 | { | ||
123 | raid6_conf_t *conf = sh->raid_conf; | ||
124 | unsigned long flags; | ||
125 | |||
126 | spin_lock_irqsave(&conf->device_lock, flags); | ||
127 | __release_stripe(conf, sh); | ||
128 | spin_unlock_irqrestore(&conf->device_lock, flags); | ||
129 | } | ||
130 | |||
131 | static inline void remove_hash(struct stripe_head *sh) | ||
132 | { | ||
133 | PRINTK("remove_hash(), stripe %llu\n", (unsigned long long)sh->sector); | ||
134 | |||
135 | hlist_del_init(&sh->hash); | ||
136 | } | ||
137 | |||
138 | static inline void insert_hash(raid6_conf_t *conf, struct stripe_head *sh) | ||
139 | { | ||
140 | struct hlist_head *hp = stripe_hash(conf, sh->sector); | ||
141 | |||
142 | PRINTK("insert_hash(), stripe %llu\n", (unsigned long long)sh->sector); | ||
143 | |||
144 | CHECK_DEVLOCK(); | ||
145 | hlist_add_head(&sh->hash, hp); | ||
146 | } | ||
147 | |||
148 | |||
149 | /* find an idle stripe, make sure it is unhashed, and return it. */ | ||
150 | static struct stripe_head *get_free_stripe(raid6_conf_t *conf) | ||
151 | { | ||
152 | struct stripe_head *sh = NULL; | ||
153 | struct list_head *first; | ||
154 | |||
155 | CHECK_DEVLOCK(); | ||
156 | if (list_empty(&conf->inactive_list)) | ||
157 | goto out; | ||
158 | first = conf->inactive_list.next; | ||
159 | sh = list_entry(first, struct stripe_head, lru); | ||
160 | list_del_init(first); | ||
161 | remove_hash(sh); | ||
162 | atomic_inc(&conf->active_stripes); | ||
163 | out: | ||
164 | return sh; | ||
165 | } | ||
166 | |||
167 | static void shrink_buffers(struct stripe_head *sh, int num) | ||
168 | { | ||
169 | struct page *p; | ||
170 | int i; | ||
171 | |||
172 | for (i=0; i<num ; i++) { | ||
173 | p = sh->dev[i].page; | ||
174 | if (!p) | ||
175 | continue; | ||
176 | sh->dev[i].page = NULL; | ||
177 | put_page(p); | ||
178 | } | ||
179 | } | ||
180 | |||
181 | static int grow_buffers(struct stripe_head *sh, int num) | ||
182 | { | ||
183 | int i; | ||
184 | |||
185 | for (i=0; i<num; i++) { | ||
186 | struct page *page; | ||
187 | |||
188 | if (!(page = alloc_page(GFP_KERNEL))) { | ||
189 | return 1; | ||
190 | } | ||
191 | sh->dev[i].page = page; | ||
192 | } | ||
193 | return 0; | ||
194 | } | ||
195 | |||
196 | static void raid6_build_block (struct stripe_head *sh, int i); | ||
197 | |||
198 | static void init_stripe(struct stripe_head *sh, sector_t sector, int pd_idx) | ||
199 | { | ||
200 | raid6_conf_t *conf = sh->raid_conf; | ||
201 | int disks = conf->raid_disks, i; | ||
202 | |||
203 | BUG_ON(atomic_read(&sh->count) != 0); | ||
204 | BUG_ON(test_bit(STRIPE_HANDLE, &sh->state)); | ||
205 | |||
206 | CHECK_DEVLOCK(); | ||
207 | PRINTK("init_stripe called, stripe %llu\n", | ||
208 | (unsigned long long)sh->sector); | ||
209 | |||
210 | remove_hash(sh); | ||
211 | |||
212 | sh->sector = sector; | ||
213 | sh->pd_idx = pd_idx; | ||
214 | sh->state = 0; | ||
215 | |||
216 | for (i=disks; i--; ) { | ||
217 | struct r5dev *dev = &sh->dev[i]; | ||
218 | |||
219 | if (dev->toread || dev->towrite || dev->written || | ||
220 | test_bit(R5_LOCKED, &dev->flags)) { | ||
221 | PRINTK("sector=%llx i=%d %p %p %p %d\n", | ||
222 | (unsigned long long)sh->sector, i, dev->toread, | ||
223 | dev->towrite, dev->written, | ||
224 | test_bit(R5_LOCKED, &dev->flags)); | ||
225 | BUG(); | ||
226 | } | ||
227 | dev->flags = 0; | ||
228 | raid6_build_block(sh, i); | ||
229 | } | ||
230 | insert_hash(conf, sh); | ||
231 | } | ||
232 | |||
233 | static struct stripe_head *__find_stripe(raid6_conf_t *conf, sector_t sector) | ||
234 | { | ||
235 | struct stripe_head *sh; | ||
236 | struct hlist_node *hn; | ||
237 | |||
238 | CHECK_DEVLOCK(); | ||
239 | PRINTK("__find_stripe, sector %llu\n", (unsigned long long)sector); | ||
240 | hlist_for_each_entry (sh, hn, stripe_hash(conf, sector), hash) | ||
241 | if (sh->sector == sector) | ||
242 | return sh; | ||
243 | PRINTK("__stripe %llu not in cache\n", (unsigned long long)sector); | ||
244 | return NULL; | ||
245 | } | ||
246 | |||
247 | static void unplug_slaves(mddev_t *mddev); | ||
248 | |||
249 | static struct stripe_head *get_active_stripe(raid6_conf_t *conf, sector_t sector, | ||
250 | int pd_idx, int noblock) | ||
251 | { | ||
252 | struct stripe_head *sh; | ||
253 | |||
254 | PRINTK("get_stripe, sector %llu\n", (unsigned long long)sector); | ||
255 | |||
256 | spin_lock_irq(&conf->device_lock); | ||
257 | |||
258 | do { | ||
259 | wait_event_lock_irq(conf->wait_for_stripe, | ||
260 | conf->quiesce == 0, | ||
261 | conf->device_lock, /* nothing */); | ||
262 | sh = __find_stripe(conf, sector); | ||
263 | if (!sh) { | ||
264 | if (!conf->inactive_blocked) | ||
265 | sh = get_free_stripe(conf); | ||
266 | if (noblock && sh == NULL) | ||
267 | break; | ||
268 | if (!sh) { | ||
269 | conf->inactive_blocked = 1; | ||
270 | wait_event_lock_irq(conf->wait_for_stripe, | ||
271 | !list_empty(&conf->inactive_list) && | ||
272 | (atomic_read(&conf->active_stripes) | ||
273 | < (conf->max_nr_stripes *3/4) | ||
274 | || !conf->inactive_blocked), | ||
275 | conf->device_lock, | ||
276 | unplug_slaves(conf->mddev); | ||
277 | ); | ||
278 | conf->inactive_blocked = 0; | ||
279 | } else | ||
280 | init_stripe(sh, sector, pd_idx); | ||
281 | } else { | ||
282 | if (atomic_read(&sh->count)) { | ||
283 | BUG_ON(!list_empty(&sh->lru)); | ||
284 | } else { | ||
285 | if (!test_bit(STRIPE_HANDLE, &sh->state)) | ||
286 | atomic_inc(&conf->active_stripes); | ||
287 | BUG_ON(list_empty(&sh->lru)); | ||
288 | list_del_init(&sh->lru); | ||
289 | } | ||
290 | } | ||
291 | } while (sh == NULL); | ||
292 | |||
293 | if (sh) | ||
294 | atomic_inc(&sh->count); | ||
295 | |||
296 | spin_unlock_irq(&conf->device_lock); | ||
297 | return sh; | ||
298 | } | ||
299 | |||
300 | static int grow_one_stripe(raid6_conf_t *conf) | ||
301 | { | ||
302 | struct stripe_head *sh; | ||
303 | sh = kmem_cache_alloc(conf->slab_cache, GFP_KERNEL); | ||
304 | if (!sh) | ||
305 | return 0; | ||
306 | memset(sh, 0, sizeof(*sh) + (conf->raid_disks-1)*sizeof(struct r5dev)); | ||
307 | sh->raid_conf = conf; | ||
308 | spin_lock_init(&sh->lock); | ||
309 | |||
310 | if (grow_buffers(sh, conf->raid_disks)) { | ||
311 | shrink_buffers(sh, conf->raid_disks); | ||
312 | kmem_cache_free(conf->slab_cache, sh); | ||
313 | return 0; | ||
314 | } | ||
315 | /* we just created an active stripe so... */ | ||
316 | atomic_set(&sh->count, 1); | ||
317 | atomic_inc(&conf->active_stripes); | ||
318 | INIT_LIST_HEAD(&sh->lru); | ||
319 | release_stripe(sh); | ||
320 | return 1; | ||
321 | } | ||
322 | |||
323 | static int grow_stripes(raid6_conf_t *conf, int num) | ||
324 | { | ||
325 | kmem_cache_t *sc; | ||
326 | int devs = conf->raid_disks; | ||
327 | |||
328 | sprintf(conf->cache_name[0], "raid6/%s", mdname(conf->mddev)); | ||
329 | |||
330 | sc = kmem_cache_create(conf->cache_name[0], | ||
331 | sizeof(struct stripe_head)+(devs-1)*sizeof(struct r5dev), | ||
332 | 0, 0, NULL, NULL); | ||
333 | if (!sc) | ||
334 | return 1; | ||
335 | conf->slab_cache = sc; | ||
336 | while (num--) | ||
337 | if (!grow_one_stripe(conf)) | ||
338 | return 1; | ||
339 | return 0; | ||
340 | } | ||
341 | |||
342 | static int drop_one_stripe(raid6_conf_t *conf) | ||
343 | { | ||
344 | struct stripe_head *sh; | ||
345 | spin_lock_irq(&conf->device_lock); | ||
346 | sh = get_free_stripe(conf); | ||
347 | spin_unlock_irq(&conf->device_lock); | ||
348 | if (!sh) | ||
349 | return 0; | ||
350 | BUG_ON(atomic_read(&sh->count)); | ||
351 | shrink_buffers(sh, conf->raid_disks); | ||
352 | kmem_cache_free(conf->slab_cache, sh); | ||
353 | atomic_dec(&conf->active_stripes); | ||
354 | return 1; | ||
355 | } | ||
356 | |||
357 | static void shrink_stripes(raid6_conf_t *conf) | ||
358 | { | ||
359 | while (drop_one_stripe(conf)) | ||
360 | ; | ||
361 | |||
362 | if (conf->slab_cache) | ||
363 | kmem_cache_destroy(conf->slab_cache); | ||
364 | conf->slab_cache = NULL; | ||
365 | } | ||
366 | |||
367 | static int raid6_end_read_request(struct bio * bi, unsigned int bytes_done, | ||
368 | int error) | ||
369 | { | ||
370 | struct stripe_head *sh = bi->bi_private; | ||
371 | raid6_conf_t *conf = sh->raid_conf; | ||
372 | int disks = conf->raid_disks, i; | ||
373 | int uptodate = test_bit(BIO_UPTODATE, &bi->bi_flags); | ||
374 | |||
375 | if (bi->bi_size) | ||
376 | return 1; | ||
377 | |||
378 | for (i=0 ; i<disks; i++) | ||
379 | if (bi == &sh->dev[i].req) | ||
380 | break; | ||
381 | |||
382 | PRINTK("end_read_request %llu/%d, count: %d, uptodate %d.\n", | ||
383 | (unsigned long long)sh->sector, i, atomic_read(&sh->count), | ||
384 | uptodate); | ||
385 | if (i == disks) { | ||
386 | BUG(); | ||
387 | return 0; | ||
388 | } | ||
389 | |||
390 | if (uptodate) { | ||
391 | #if 0 | ||
392 | struct bio *bio; | ||
393 | unsigned long flags; | ||
394 | spin_lock_irqsave(&conf->device_lock, flags); | ||
395 | /* we can return a buffer if we bypassed the cache or | ||
396 | * if the top buffer is not in highmem. If there are | ||
397 | * multiple buffers, leave the extra work to | ||
398 | * handle_stripe | ||
399 | */ | ||
400 | buffer = sh->bh_read[i]; | ||
401 | if (buffer && | ||
402 | (!PageHighMem(buffer->b_page) | ||
403 | || buffer->b_page == bh->b_page ) | ||
404 | ) { | ||
405 | sh->bh_read[i] = buffer->b_reqnext; | ||
406 | buffer->b_reqnext = NULL; | ||
407 | } else | ||
408 | buffer = NULL; | ||
409 | spin_unlock_irqrestore(&conf->device_lock, flags); | ||
410 | if (sh->bh_page[i]==bh->b_page) | ||
411 | set_buffer_uptodate(bh); | ||
412 | if (buffer) { | ||
413 | if (buffer->b_page != bh->b_page) | ||
414 | memcpy(buffer->b_data, bh->b_data, bh->b_size); | ||
415 | buffer->b_end_io(buffer, 1); | ||
416 | } | ||
417 | #else | ||
418 | set_bit(R5_UPTODATE, &sh->dev[i].flags); | ||
419 | #endif | ||
420 | if (test_bit(R5_ReadError, &sh->dev[i].flags)) { | ||
421 | printk(KERN_INFO "raid6: read error corrected!!\n"); | ||
422 | clear_bit(R5_ReadError, &sh->dev[i].flags); | ||
423 | clear_bit(R5_ReWrite, &sh->dev[i].flags); | ||
424 | } | ||
425 | if (atomic_read(&conf->disks[i].rdev->read_errors)) | ||
426 | atomic_set(&conf->disks[i].rdev->read_errors, 0); | ||
427 | } else { | ||
428 | int retry = 0; | ||
429 | clear_bit(R5_UPTODATE, &sh->dev[i].flags); | ||
430 | atomic_inc(&conf->disks[i].rdev->read_errors); | ||
431 | if (conf->mddev->degraded) | ||
432 | printk(KERN_WARNING "raid6: read error not correctable.\n"); | ||
433 | else if (test_bit(R5_ReWrite, &sh->dev[i].flags)) | ||
434 | /* Oh, no!!! */ | ||
435 | printk(KERN_WARNING "raid6: read error NOT corrected!!\n"); | ||
436 | else if (atomic_read(&conf->disks[i].rdev->read_errors) | ||
437 | > conf->max_nr_stripes) | ||
438 | printk(KERN_WARNING | ||
439 | "raid6: Too many read errors, failing device.\n"); | ||
440 | else | ||
441 | retry = 1; | ||
442 | if (retry) | ||
443 | set_bit(R5_ReadError, &sh->dev[i].flags); | ||
444 | else { | ||
445 | clear_bit(R5_ReadError, &sh->dev[i].flags); | ||
446 | clear_bit(R5_ReWrite, &sh->dev[i].flags); | ||
447 | md_error(conf->mddev, conf->disks[i].rdev); | ||
448 | } | ||
449 | } | ||
450 | rdev_dec_pending(conf->disks[i].rdev, conf->mddev); | ||
451 | #if 0 | ||
452 | /* must restore b_page before unlocking buffer... */ | ||
453 | if (sh->bh_page[i] != bh->b_page) { | ||
454 | bh->b_page = sh->bh_page[i]; | ||
455 | bh->b_data = page_address(bh->b_page); | ||
456 | clear_buffer_uptodate(bh); | ||
457 | } | ||
458 | #endif | ||
459 | clear_bit(R5_LOCKED, &sh->dev[i].flags); | ||
460 | set_bit(STRIPE_HANDLE, &sh->state); | ||
461 | release_stripe(sh); | ||
462 | return 0; | ||
463 | } | ||
464 | |||
465 | static int raid6_end_write_request (struct bio *bi, unsigned int bytes_done, | ||
466 | int error) | ||
467 | { | ||
468 | struct stripe_head *sh = bi->bi_private; | ||
469 | raid6_conf_t *conf = sh->raid_conf; | ||
470 | int disks = conf->raid_disks, i; | ||
471 | unsigned long flags; | ||
472 | int uptodate = test_bit(BIO_UPTODATE, &bi->bi_flags); | ||
473 | |||
474 | if (bi->bi_size) | ||
475 | return 1; | ||
476 | |||
477 | for (i=0 ; i<disks; i++) | ||
478 | if (bi == &sh->dev[i].req) | ||
479 | break; | ||
480 | |||
481 | PRINTK("end_write_request %llu/%d, count %d, uptodate: %d.\n", | ||
482 | (unsigned long long)sh->sector, i, atomic_read(&sh->count), | ||
483 | uptodate); | ||
484 | if (i == disks) { | ||
485 | BUG(); | ||
486 | return 0; | ||
487 | } | ||
488 | |||
489 | spin_lock_irqsave(&conf->device_lock, flags); | ||
490 | if (!uptodate) | ||
491 | md_error(conf->mddev, conf->disks[i].rdev); | ||
492 | |||
493 | rdev_dec_pending(conf->disks[i].rdev, conf->mddev); | ||
494 | |||
495 | clear_bit(R5_LOCKED, &sh->dev[i].flags); | ||
496 | set_bit(STRIPE_HANDLE, &sh->state); | ||
497 | __release_stripe(conf, sh); | ||
498 | spin_unlock_irqrestore(&conf->device_lock, flags); | ||
499 | return 0; | ||
500 | } | ||
501 | |||
502 | |||
503 | static sector_t compute_blocknr(struct stripe_head *sh, int i); | ||
504 | |||
505 | static void raid6_build_block (struct stripe_head *sh, int i) | ||
506 | { | ||
507 | struct r5dev *dev = &sh->dev[i]; | ||
508 | int pd_idx = sh->pd_idx; | ||
509 | int qd_idx = raid6_next_disk(pd_idx, sh->raid_conf->raid_disks); | ||
510 | |||
511 | bio_init(&dev->req); | ||
512 | dev->req.bi_io_vec = &dev->vec; | ||
513 | dev->req.bi_vcnt++; | ||
514 | dev->req.bi_max_vecs++; | ||
515 | dev->vec.bv_page = dev->page; | ||
516 | dev->vec.bv_len = STRIPE_SIZE; | ||
517 | dev->vec.bv_offset = 0; | ||
518 | |||
519 | dev->req.bi_sector = sh->sector; | ||
520 | dev->req.bi_private = sh; | ||
521 | |||
522 | dev->flags = 0; | ||
523 | if (i != pd_idx && i != qd_idx) | ||
524 | dev->sector = compute_blocknr(sh, i); | ||
525 | } | ||
526 | |||
527 | static void error(mddev_t *mddev, mdk_rdev_t *rdev) | ||
528 | { | ||
529 | char b[BDEVNAME_SIZE]; | ||
530 | raid6_conf_t *conf = (raid6_conf_t *) mddev->private; | ||
531 | PRINTK("raid6: error called\n"); | ||
532 | |||
533 | if (!test_bit(Faulty, &rdev->flags)) { | ||
534 | mddev->sb_dirty = 1; | ||
535 | if (test_bit(In_sync, &rdev->flags)) { | ||
536 | conf->working_disks--; | ||
537 | mddev->degraded++; | ||
538 | conf->failed_disks++; | ||
539 | clear_bit(In_sync, &rdev->flags); | ||
540 | /* | ||
541 | * if recovery was running, make sure it aborts. | ||
542 | */ | ||
543 | set_bit(MD_RECOVERY_ERR, &mddev->recovery); | ||
544 | } | ||
545 | set_bit(Faulty, &rdev->flags); | ||
546 | printk (KERN_ALERT | ||
547 | "raid6: Disk failure on %s, disabling device." | ||
548 | " Operation continuing on %d devices\n", | ||
549 | bdevname(rdev->bdev,b), conf->working_disks); | ||
550 | } | ||
551 | } | ||
552 | |||
553 | /* | ||
554 | * Input: a 'big' sector number, | ||
555 | * Output: index of the data and parity disk, and the sector # in them. | ||
556 | */ | ||
557 | static sector_t raid6_compute_sector(sector_t r_sector, unsigned int raid_disks, | ||
558 | unsigned int data_disks, unsigned int * dd_idx, | ||
559 | unsigned int * pd_idx, raid6_conf_t *conf) | ||
560 | { | ||
561 | long stripe; | ||
562 | unsigned long chunk_number; | ||
563 | unsigned int chunk_offset; | ||
564 | sector_t new_sector; | ||
565 | int sectors_per_chunk = conf->chunk_size >> 9; | ||
566 | |||
567 | /* First compute the information on this sector */ | ||
568 | |||
569 | /* | ||
570 | * Compute the chunk number and the sector offset inside the chunk | ||
571 | */ | ||
572 | chunk_offset = sector_div(r_sector, sectors_per_chunk); | ||
573 | chunk_number = r_sector; | ||
574 | if ( r_sector != chunk_number ) { | ||
575 | printk(KERN_CRIT "raid6: ERROR: r_sector = %llu, chunk_number = %lu\n", | ||
576 | (unsigned long long)r_sector, (unsigned long)chunk_number); | ||
577 | BUG(); | ||
578 | } | ||
579 | |||
580 | /* | ||
581 | * Compute the stripe number | ||
582 | */ | ||
583 | stripe = chunk_number / data_disks; | ||
584 | |||
585 | /* | ||
586 | * Compute the data disk and parity disk indexes inside the stripe | ||
587 | */ | ||
588 | *dd_idx = chunk_number % data_disks; | ||
589 | |||
590 | /* | ||
591 | * Select the parity disk based on the user selected algorithm. | ||
592 | */ | ||
593 | |||
594 | /**** FIX THIS ****/ | ||
595 | switch (conf->algorithm) { | ||
596 | case ALGORITHM_LEFT_ASYMMETRIC: | ||
597 | *pd_idx = raid_disks - 1 - (stripe % raid_disks); | ||
598 | if (*pd_idx == raid_disks-1) | ||
599 | (*dd_idx)++; /* Q D D D P */ | ||
600 | else if (*dd_idx >= *pd_idx) | ||
601 | (*dd_idx) += 2; /* D D P Q D */ | ||
602 | break; | ||
603 | case ALGORITHM_RIGHT_ASYMMETRIC: | ||
604 | *pd_idx = stripe % raid_disks; | ||
605 | if (*pd_idx == raid_disks-1) | ||
606 | (*dd_idx)++; /* Q D D D P */ | ||
607 | else if (*dd_idx >= *pd_idx) | ||
608 | (*dd_idx) += 2; /* D D P Q D */ | ||
609 | break; | ||
610 | case ALGORITHM_LEFT_SYMMETRIC: | ||
611 | *pd_idx = raid_disks - 1 - (stripe % raid_disks); | ||
612 | *dd_idx = (*pd_idx + 2 + *dd_idx) % raid_disks; | ||
613 | break; | ||
614 | case ALGORITHM_RIGHT_SYMMETRIC: | ||
615 | *pd_idx = stripe % raid_disks; | ||
616 | *dd_idx = (*pd_idx + 2 + *dd_idx) % raid_disks; | ||
617 | break; | ||
618 | default: | ||
619 | printk (KERN_CRIT "raid6: unsupported algorithm %d\n", | ||
620 | conf->algorithm); | ||
621 | } | ||
622 | |||
623 | PRINTK("raid6: chunk_number = %lu, pd_idx = %u, dd_idx = %u\n", | ||
624 | chunk_number, *pd_idx, *dd_idx); | ||
625 | |||
626 | /* | ||
627 | * Finally, compute the new sector number | ||
628 | */ | ||
629 | new_sector = (sector_t) stripe * sectors_per_chunk + chunk_offset; | ||
630 | return new_sector; | ||
631 | } | ||
632 | |||
633 | |||
634 | static sector_t compute_blocknr(struct stripe_head *sh, int i) | ||
635 | { | ||
636 | raid6_conf_t *conf = sh->raid_conf; | ||
637 | int raid_disks = conf->raid_disks, data_disks = raid_disks - 2; | ||
638 | sector_t new_sector = sh->sector, check; | ||
639 | int sectors_per_chunk = conf->chunk_size >> 9; | ||
640 | sector_t stripe; | ||
641 | int chunk_offset; | ||
642 | int chunk_number, dummy1, dummy2, dd_idx = i; | ||
643 | sector_t r_sector; | ||
644 | int i0 = i; | ||
645 | |||
646 | chunk_offset = sector_div(new_sector, sectors_per_chunk); | ||
647 | stripe = new_sector; | ||
648 | if ( new_sector != stripe ) { | ||
649 | printk(KERN_CRIT "raid6: ERROR: new_sector = %llu, stripe = %lu\n", | ||
650 | (unsigned long long)new_sector, (unsigned long)stripe); | ||
651 | BUG(); | ||
652 | } | ||
653 | |||
654 | switch (conf->algorithm) { | ||
655 | case ALGORITHM_LEFT_ASYMMETRIC: | ||
656 | case ALGORITHM_RIGHT_ASYMMETRIC: | ||
657 | if (sh->pd_idx == raid_disks-1) | ||
658 | i--; /* Q D D D P */ | ||
659 | else if (i > sh->pd_idx) | ||
660 | i -= 2; /* D D P Q D */ | ||
661 | break; | ||
662 | case ALGORITHM_LEFT_SYMMETRIC: | ||
663 | case ALGORITHM_RIGHT_SYMMETRIC: | ||
664 | if (sh->pd_idx == raid_disks-1) | ||
665 | i--; /* Q D D D P */ | ||
666 | else { | ||
667 | /* D D P Q D */ | ||
668 | if (i < sh->pd_idx) | ||
669 | i += raid_disks; | ||
670 | i -= (sh->pd_idx + 2); | ||
671 | } | ||
672 | break; | ||
673 | default: | ||
674 | printk (KERN_CRIT "raid6: unsupported algorithm %d\n", | ||
675 | conf->algorithm); | ||
676 | } | ||
677 | |||
678 | PRINTK("raid6: compute_blocknr: pd_idx = %u, i0 = %u, i = %u\n", sh->pd_idx, i0, i); | ||
679 | |||
680 | chunk_number = stripe * data_disks + i; | ||
681 | r_sector = (sector_t)chunk_number * sectors_per_chunk + chunk_offset; | ||
682 | |||
683 | check = raid6_compute_sector (r_sector, raid_disks, data_disks, &dummy1, &dummy2, conf); | ||
684 | if (check != sh->sector || dummy1 != dd_idx || dummy2 != sh->pd_idx) { | ||
685 | printk(KERN_CRIT "raid6: compute_blocknr: map not correct\n"); | ||
686 | return 0; | ||
687 | } | ||
688 | return r_sector; | ||
689 | } | ||
690 | |||
691 | |||
692 | |||
693 | /* | ||
694 | * Copy data between a page in the stripe cache, and one or more bion | ||
695 | * The page could align with the middle of the bio, or there could be | ||
696 | * several bion, each with several bio_vecs, which cover part of the page | ||
697 | * Multiple bion are linked together on bi_next. There may be extras | ||
698 | * at the end of this list. We ignore them. | ||
699 | */ | ||
700 | static void copy_data(int frombio, struct bio *bio, | ||
701 | struct page *page, | ||
702 | sector_t sector) | ||
703 | { | ||
704 | char *pa = page_address(page); | ||
705 | struct bio_vec *bvl; | ||
706 | int i; | ||
707 | int page_offset; | ||
708 | |||
709 | if (bio->bi_sector >= sector) | ||
710 | page_offset = (signed)(bio->bi_sector - sector) * 512; | ||
711 | else | ||
712 | page_offset = (signed)(sector - bio->bi_sector) * -512; | ||
713 | bio_for_each_segment(bvl, bio, i) { | ||
714 | int len = bio_iovec_idx(bio,i)->bv_len; | ||
715 | int clen; | ||
716 | int b_offset = 0; | ||
717 | |||
718 | if (page_offset < 0) { | ||
719 | b_offset = -page_offset; | ||
720 | page_offset += b_offset; | ||
721 | len -= b_offset; | ||
722 | } | ||
723 | |||
724 | if (len > 0 && page_offset + len > STRIPE_SIZE) | ||
725 | clen = STRIPE_SIZE - page_offset; | ||
726 | else clen = len; | ||
727 | |||
728 | if (clen > 0) { | ||
729 | char *ba = __bio_kmap_atomic(bio, i, KM_USER0); | ||
730 | if (frombio) | ||
731 | memcpy(pa+page_offset, ba+b_offset, clen); | ||
732 | else | ||
733 | memcpy(ba+b_offset, pa+page_offset, clen); | ||
734 | __bio_kunmap_atomic(ba, KM_USER0); | ||
735 | } | ||
736 | if (clen < len) /* hit end of page */ | ||
737 | break; | ||
738 | page_offset += len; | ||
739 | } | ||
740 | } | ||
741 | |||
742 | #define check_xor() do { \ | ||
743 | if (count == MAX_XOR_BLOCKS) { \ | ||
744 | xor_block(count, STRIPE_SIZE, ptr); \ | ||
745 | count = 1; \ | ||
746 | } \ | ||
747 | } while(0) | ||
748 | |||
749 | /* Compute P and Q syndromes */ | ||
750 | static void compute_parity(struct stripe_head *sh, int method) | ||
751 | { | ||
752 | raid6_conf_t *conf = sh->raid_conf; | ||
753 | int i, pd_idx = sh->pd_idx, qd_idx, d0_idx, disks = conf->raid_disks, count; | ||
754 | struct bio *chosen; | ||
755 | /**** FIX THIS: This could be very bad if disks is close to 256 ****/ | ||
756 | void *ptrs[disks]; | ||
757 | |||
758 | qd_idx = raid6_next_disk(pd_idx, disks); | ||
759 | d0_idx = raid6_next_disk(qd_idx, disks); | ||
760 | |||
761 | PRINTK("compute_parity, stripe %llu, method %d\n", | ||
762 | (unsigned long long)sh->sector, method); | ||
763 | |||
764 | switch(method) { | ||
765 | case READ_MODIFY_WRITE: | ||
766 | BUG(); /* READ_MODIFY_WRITE N/A for RAID-6 */ | ||
767 | case RECONSTRUCT_WRITE: | ||
768 | for (i= disks; i-- ;) | ||
769 | if ( i != pd_idx && i != qd_idx && sh->dev[i].towrite ) { | ||
770 | chosen = sh->dev[i].towrite; | ||
771 | sh->dev[i].towrite = NULL; | ||
772 | |||
773 | if (test_and_clear_bit(R5_Overlap, &sh->dev[i].flags)) | ||
774 | wake_up(&conf->wait_for_overlap); | ||
775 | |||
776 | BUG_ON(sh->dev[i].written); | ||
777 | sh->dev[i].written = chosen; | ||
778 | } | ||
779 | break; | ||
780 | case CHECK_PARITY: | ||
781 | BUG(); /* Not implemented yet */ | ||
782 | } | ||
783 | |||
784 | for (i = disks; i--;) | ||
785 | if (sh->dev[i].written) { | ||
786 | sector_t sector = sh->dev[i].sector; | ||
787 | struct bio *wbi = sh->dev[i].written; | ||
788 | while (wbi && wbi->bi_sector < sector + STRIPE_SECTORS) { | ||
789 | copy_data(1, wbi, sh->dev[i].page, sector); | ||
790 | wbi = r5_next_bio(wbi, sector); | ||
791 | } | ||
792 | |||
793 | set_bit(R5_LOCKED, &sh->dev[i].flags); | ||
794 | set_bit(R5_UPTODATE, &sh->dev[i].flags); | ||
795 | } | ||
796 | |||
797 | // switch(method) { | ||
798 | // case RECONSTRUCT_WRITE: | ||
799 | // case CHECK_PARITY: | ||
800 | // case UPDATE_PARITY: | ||
801 | /* Note that unlike RAID-5, the ordering of the disks matters greatly. */ | ||
802 | /* FIX: Is this ordering of drives even remotely optimal? */ | ||
803 | count = 0; | ||
804 | i = d0_idx; | ||
805 | do { | ||
806 | ptrs[count++] = page_address(sh->dev[i].page); | ||
807 | if (count <= disks-2 && !test_bit(R5_UPTODATE, &sh->dev[i].flags)) | ||
808 | printk("block %d/%d not uptodate on parity calc\n", i,count); | ||
809 | i = raid6_next_disk(i, disks); | ||
810 | } while ( i != d0_idx ); | ||
811 | // break; | ||
812 | // } | ||
813 | |||
814 | raid6_call.gen_syndrome(disks, STRIPE_SIZE, ptrs); | ||
815 | |||
816 | switch(method) { | ||
817 | case RECONSTRUCT_WRITE: | ||
818 | set_bit(R5_UPTODATE, &sh->dev[pd_idx].flags); | ||
819 | set_bit(R5_UPTODATE, &sh->dev[qd_idx].flags); | ||
820 | set_bit(R5_LOCKED, &sh->dev[pd_idx].flags); | ||
821 | set_bit(R5_LOCKED, &sh->dev[qd_idx].flags); | ||
822 | break; | ||
823 | case UPDATE_PARITY: | ||
824 | set_bit(R5_UPTODATE, &sh->dev[pd_idx].flags); | ||
825 | set_bit(R5_UPTODATE, &sh->dev[qd_idx].flags); | ||
826 | break; | ||
827 | } | ||
828 | } | ||
829 | |||
830 | /* Compute one missing block */ | ||
831 | static void compute_block_1(struct stripe_head *sh, int dd_idx, int nozero) | ||
832 | { | ||
833 | raid6_conf_t *conf = sh->raid_conf; | ||
834 | int i, count, disks = conf->raid_disks; | ||
835 | void *ptr[MAX_XOR_BLOCKS], *p; | ||
836 | int pd_idx = sh->pd_idx; | ||
837 | int qd_idx = raid6_next_disk(pd_idx, disks); | ||
838 | |||
839 | PRINTK("compute_block_1, stripe %llu, idx %d\n", | ||
840 | (unsigned long long)sh->sector, dd_idx); | ||
841 | |||
842 | if ( dd_idx == qd_idx ) { | ||
843 | /* We're actually computing the Q drive */ | ||
844 | compute_parity(sh, UPDATE_PARITY); | ||
845 | } else { | ||
846 | ptr[0] = page_address(sh->dev[dd_idx].page); | ||
847 | if (!nozero) memset(ptr[0], 0, STRIPE_SIZE); | ||
848 | count = 1; | ||
849 | for (i = disks ; i--; ) { | ||
850 | if (i == dd_idx || i == qd_idx) | ||
851 | continue; | ||
852 | p = page_address(sh->dev[i].page); | ||
853 | if (test_bit(R5_UPTODATE, &sh->dev[i].flags)) | ||
854 | ptr[count++] = p; | ||
855 | else | ||
856 | printk("compute_block() %d, stripe %llu, %d" | ||
857 | " not present\n", dd_idx, | ||
858 | (unsigned long long)sh->sector, i); | ||
859 | |||
860 | check_xor(); | ||
861 | } | ||
862 | if (count != 1) | ||
863 | xor_block(count, STRIPE_SIZE, ptr); | ||
864 | if (!nozero) set_bit(R5_UPTODATE, &sh->dev[dd_idx].flags); | ||
865 | else clear_bit(R5_UPTODATE, &sh->dev[dd_idx].flags); | ||
866 | } | ||
867 | } | ||
868 | |||
869 | /* Compute two missing blocks */ | ||
870 | static void compute_block_2(struct stripe_head *sh, int dd_idx1, int dd_idx2) | ||
871 | { | ||
872 | raid6_conf_t *conf = sh->raid_conf; | ||
873 | int i, count, disks = conf->raid_disks; | ||
874 | int pd_idx = sh->pd_idx; | ||
875 | int qd_idx = raid6_next_disk(pd_idx, disks); | ||
876 | int d0_idx = raid6_next_disk(qd_idx, disks); | ||
877 | int faila, failb; | ||
878 | |||
879 | /* faila and failb are disk numbers relative to d0_idx */ | ||
880 | /* pd_idx become disks-2 and qd_idx become disks-1 */ | ||
881 | faila = (dd_idx1 < d0_idx) ? dd_idx1+(disks-d0_idx) : dd_idx1-d0_idx; | ||
882 | failb = (dd_idx2 < d0_idx) ? dd_idx2+(disks-d0_idx) : dd_idx2-d0_idx; | ||
883 | |||
884 | BUG_ON(faila == failb); | ||
885 | if ( failb < faila ) { int tmp = faila; faila = failb; failb = tmp; } | ||
886 | |||
887 | PRINTK("compute_block_2, stripe %llu, idx %d,%d (%d,%d)\n", | ||
888 | (unsigned long long)sh->sector, dd_idx1, dd_idx2, faila, failb); | ||
889 | |||
890 | if ( failb == disks-1 ) { | ||
891 | /* Q disk is one of the missing disks */ | ||
892 | if ( faila == disks-2 ) { | ||
893 | /* Missing P+Q, just recompute */ | ||
894 | compute_parity(sh, UPDATE_PARITY); | ||
895 | return; | ||
896 | } else { | ||
897 | /* We're missing D+Q; recompute D from P */ | ||
898 | compute_block_1(sh, (dd_idx1 == qd_idx) ? dd_idx2 : dd_idx1, 0); | ||
899 | compute_parity(sh, UPDATE_PARITY); /* Is this necessary? */ | ||
900 | return; | ||
901 | } | ||
902 | } | ||
903 | |||
904 | /* We're missing D+P or D+D; build pointer table */ | ||
905 | { | ||
906 | /**** FIX THIS: This could be very bad if disks is close to 256 ****/ | ||
907 | void *ptrs[disks]; | ||
908 | |||
909 | count = 0; | ||
910 | i = d0_idx; | ||
911 | do { | ||
912 | ptrs[count++] = page_address(sh->dev[i].page); | ||
913 | i = raid6_next_disk(i, disks); | ||
914 | if (i != dd_idx1 && i != dd_idx2 && | ||
915 | !test_bit(R5_UPTODATE, &sh->dev[i].flags)) | ||
916 | printk("compute_2 with missing block %d/%d\n", count, i); | ||
917 | } while ( i != d0_idx ); | ||
918 | |||
919 | if ( failb == disks-2 ) { | ||
920 | /* We're missing D+P. */ | ||
921 | raid6_datap_recov(disks, STRIPE_SIZE, faila, ptrs); | ||
922 | } else { | ||
923 | /* We're missing D+D. */ | ||
924 | raid6_2data_recov(disks, STRIPE_SIZE, faila, failb, ptrs); | ||
925 | } | ||
926 | |||
927 | /* Both the above update both missing blocks */ | ||
928 | set_bit(R5_UPTODATE, &sh->dev[dd_idx1].flags); | ||
929 | set_bit(R5_UPTODATE, &sh->dev[dd_idx2].flags); | ||
930 | } | ||
931 | } | ||
932 | |||
933 | |||
934 | /* | ||
935 | * Each stripe/dev can have one or more bion attached. | ||
936 | * toread/towrite point to the first in a chain. | ||
937 | * The bi_next chain must be in order. | ||
938 | */ | ||
939 | static int add_stripe_bio(struct stripe_head *sh, struct bio *bi, int dd_idx, int forwrite) | ||
940 | { | ||
941 | struct bio **bip; | ||
942 | raid6_conf_t *conf = sh->raid_conf; | ||
943 | int firstwrite=0; | ||
944 | |||
945 | PRINTK("adding bh b#%llu to stripe s#%llu\n", | ||
946 | (unsigned long long)bi->bi_sector, | ||
947 | (unsigned long long)sh->sector); | ||
948 | |||
949 | |||
950 | spin_lock(&sh->lock); | ||
951 | spin_lock_irq(&conf->device_lock); | ||
952 | if (forwrite) { | ||
953 | bip = &sh->dev[dd_idx].towrite; | ||
954 | if (*bip == NULL && sh->dev[dd_idx].written == NULL) | ||
955 | firstwrite = 1; | ||
956 | } else | ||
957 | bip = &sh->dev[dd_idx].toread; | ||
958 | while (*bip && (*bip)->bi_sector < bi->bi_sector) { | ||
959 | if ((*bip)->bi_sector + ((*bip)->bi_size >> 9) > bi->bi_sector) | ||
960 | goto overlap; | ||
961 | bip = &(*bip)->bi_next; | ||
962 | } | ||
963 | if (*bip && (*bip)->bi_sector < bi->bi_sector + ((bi->bi_size)>>9)) | ||
964 | goto overlap; | ||
965 | |||
966 | BUG_ON(*bip && bi->bi_next && (*bip) != bi->bi_next); | ||
967 | if (*bip) | ||
968 | bi->bi_next = *bip; | ||
969 | *bip = bi; | ||
970 | bi->bi_phys_segments ++; | ||
971 | spin_unlock_irq(&conf->device_lock); | ||
972 | spin_unlock(&sh->lock); | ||
973 | |||
974 | PRINTK("added bi b#%llu to stripe s#%llu, disk %d.\n", | ||
975 | (unsigned long long)bi->bi_sector, | ||
976 | (unsigned long long)sh->sector, dd_idx); | ||
977 | |||
978 | if (conf->mddev->bitmap && firstwrite) { | ||
979 | sh->bm_seq = conf->seq_write; | ||
980 | bitmap_startwrite(conf->mddev->bitmap, sh->sector, | ||
981 | STRIPE_SECTORS, 0); | ||
982 | set_bit(STRIPE_BIT_DELAY, &sh->state); | ||
983 | } | ||
984 | |||
985 | if (forwrite) { | ||
986 | /* check if page is covered */ | ||
987 | sector_t sector = sh->dev[dd_idx].sector; | ||
988 | for (bi=sh->dev[dd_idx].towrite; | ||
989 | sector < sh->dev[dd_idx].sector + STRIPE_SECTORS && | ||
990 | bi && bi->bi_sector <= sector; | ||
991 | bi = r5_next_bio(bi, sh->dev[dd_idx].sector)) { | ||
992 | if (bi->bi_sector + (bi->bi_size>>9) >= sector) | ||
993 | sector = bi->bi_sector + (bi->bi_size>>9); | ||
994 | } | ||
995 | if (sector >= sh->dev[dd_idx].sector + STRIPE_SECTORS) | ||
996 | set_bit(R5_OVERWRITE, &sh->dev[dd_idx].flags); | ||
997 | } | ||
998 | return 1; | ||
999 | |||
1000 | overlap: | ||
1001 | set_bit(R5_Overlap, &sh->dev[dd_idx].flags); | ||
1002 | spin_unlock_irq(&conf->device_lock); | ||
1003 | spin_unlock(&sh->lock); | ||
1004 | return 0; | ||
1005 | } | ||
1006 | |||
1007 | |||
1008 | static int page_is_zero(struct page *p) | ||
1009 | { | ||
1010 | char *a = page_address(p); | ||
1011 | return ((*(u32*)a) == 0 && | ||
1012 | memcmp(a, a+4, STRIPE_SIZE-4)==0); | ||
1013 | } | ||
1014 | /* | ||
1015 | * handle_stripe - do things to a stripe. | ||
1016 | * | ||
1017 | * We lock the stripe and then examine the state of various bits | ||
1018 | * to see what needs to be done. | ||
1019 | * Possible results: | ||
1020 | * return some read request which now have data | ||
1021 | * return some write requests which are safely on disc | ||
1022 | * schedule a read on some buffers | ||
1023 | * schedule a write of some buffers | ||
1024 | * return confirmation of parity correctness | ||
1025 | * | ||
1026 | * Parity calculations are done inside the stripe lock | ||
1027 | * buffers are taken off read_list or write_list, and bh_cache buffers | ||
1028 | * get BH_Lock set before the stripe lock is released. | ||
1029 | * | ||
1030 | */ | ||
1031 | |||
1032 | static void handle_stripe(struct stripe_head *sh, struct page *tmp_page) | ||
1033 | { | ||
1034 | raid6_conf_t *conf = sh->raid_conf; | ||
1035 | int disks = conf->raid_disks; | ||
1036 | struct bio *return_bi= NULL; | ||
1037 | struct bio *bi; | ||
1038 | int i; | ||
1039 | int syncing; | ||
1040 | int locked=0, uptodate=0, to_read=0, to_write=0, failed=0, written=0; | ||
1041 | int non_overwrite = 0; | ||
1042 | int failed_num[2] = {0, 0}; | ||
1043 | struct r5dev *dev, *pdev, *qdev; | ||
1044 | int pd_idx = sh->pd_idx; | ||
1045 | int qd_idx = raid6_next_disk(pd_idx, disks); | ||
1046 | int p_failed, q_failed; | ||
1047 | |||
1048 | PRINTK("handling stripe %llu, state=%#lx cnt=%d, pd_idx=%d, qd_idx=%d\n", | ||
1049 | (unsigned long long)sh->sector, sh->state, atomic_read(&sh->count), | ||
1050 | pd_idx, qd_idx); | ||
1051 | |||
1052 | spin_lock(&sh->lock); | ||
1053 | clear_bit(STRIPE_HANDLE, &sh->state); | ||
1054 | clear_bit(STRIPE_DELAYED, &sh->state); | ||
1055 | |||
1056 | syncing = test_bit(STRIPE_SYNCING, &sh->state); | ||
1057 | /* Now to look around and see what can be done */ | ||
1058 | |||
1059 | rcu_read_lock(); | ||
1060 | for (i=disks; i--; ) { | ||
1061 | mdk_rdev_t *rdev; | ||
1062 | dev = &sh->dev[i]; | ||
1063 | clear_bit(R5_Insync, &dev->flags); | ||
1064 | |||
1065 | PRINTK("check %d: state 0x%lx read %p write %p written %p\n", | ||
1066 | i, dev->flags, dev->toread, dev->towrite, dev->written); | ||
1067 | /* maybe we can reply to a read */ | ||
1068 | if (test_bit(R5_UPTODATE, &dev->flags) && dev->toread) { | ||
1069 | struct bio *rbi, *rbi2; | ||
1070 | PRINTK("Return read for disc %d\n", i); | ||
1071 | spin_lock_irq(&conf->device_lock); | ||
1072 | rbi = dev->toread; | ||
1073 | dev->toread = NULL; | ||
1074 | if (test_and_clear_bit(R5_Overlap, &dev->flags)) | ||
1075 | wake_up(&conf->wait_for_overlap); | ||
1076 | spin_unlock_irq(&conf->device_lock); | ||
1077 | while (rbi && rbi->bi_sector < dev->sector + STRIPE_SECTORS) { | ||
1078 | copy_data(0, rbi, dev->page, dev->sector); | ||
1079 | rbi2 = r5_next_bio(rbi, dev->sector); | ||
1080 | spin_lock_irq(&conf->device_lock); | ||
1081 | if (--rbi->bi_phys_segments == 0) { | ||
1082 | rbi->bi_next = return_bi; | ||
1083 | return_bi = rbi; | ||
1084 | } | ||
1085 | spin_unlock_irq(&conf->device_lock); | ||
1086 | rbi = rbi2; | ||
1087 | } | ||
1088 | } | ||
1089 | |||
1090 | /* now count some things */ | ||
1091 | if (test_bit(R5_LOCKED, &dev->flags)) locked++; | ||
1092 | if (test_bit(R5_UPTODATE, &dev->flags)) uptodate++; | ||
1093 | |||
1094 | |||
1095 | if (dev->toread) to_read++; | ||
1096 | if (dev->towrite) { | ||
1097 | to_write++; | ||
1098 | if (!test_bit(R5_OVERWRITE, &dev->flags)) | ||
1099 | non_overwrite++; | ||
1100 | } | ||
1101 | if (dev->written) written++; | ||
1102 | rdev = rcu_dereference(conf->disks[i].rdev); | ||
1103 | if (!rdev || !test_bit(In_sync, &rdev->flags)) { | ||
1104 | /* The ReadError flag will just be confusing now */ | ||
1105 | clear_bit(R5_ReadError, &dev->flags); | ||
1106 | clear_bit(R5_ReWrite, &dev->flags); | ||
1107 | } | ||
1108 | if (!rdev || !test_bit(In_sync, &rdev->flags) | ||
1109 | || test_bit(R5_ReadError, &dev->flags)) { | ||
1110 | if ( failed < 2 ) | ||
1111 | failed_num[failed] = i; | ||
1112 | failed++; | ||
1113 | } else | ||
1114 | set_bit(R5_Insync, &dev->flags); | ||
1115 | } | ||
1116 | rcu_read_unlock(); | ||
1117 | PRINTK("locked=%d uptodate=%d to_read=%d" | ||
1118 | " to_write=%d failed=%d failed_num=%d,%d\n", | ||
1119 | locked, uptodate, to_read, to_write, failed, | ||
1120 | failed_num[0], failed_num[1]); | ||
1121 | /* check if the array has lost >2 devices and, if so, some requests might | ||
1122 | * need to be failed | ||
1123 | */ | ||
1124 | if (failed > 2 && to_read+to_write+written) { | ||
1125 | for (i=disks; i--; ) { | ||
1126 | int bitmap_end = 0; | ||
1127 | |||
1128 | if (test_bit(R5_ReadError, &sh->dev[i].flags)) { | ||
1129 | mdk_rdev_t *rdev; | ||
1130 | rcu_read_lock(); | ||
1131 | rdev = rcu_dereference(conf->disks[i].rdev); | ||
1132 | if (rdev && test_bit(In_sync, &rdev->flags)) | ||
1133 | /* multiple read failures in one stripe */ | ||
1134 | md_error(conf->mddev, rdev); | ||
1135 | rcu_read_unlock(); | ||
1136 | } | ||
1137 | |||
1138 | spin_lock_irq(&conf->device_lock); | ||
1139 | /* fail all writes first */ | ||
1140 | bi = sh->dev[i].towrite; | ||
1141 | sh->dev[i].towrite = NULL; | ||
1142 | if (bi) { to_write--; bitmap_end = 1; } | ||
1143 | |||
1144 | if (test_and_clear_bit(R5_Overlap, &sh->dev[i].flags)) | ||
1145 | wake_up(&conf->wait_for_overlap); | ||
1146 | |||
1147 | while (bi && bi->bi_sector < sh->dev[i].sector + STRIPE_SECTORS){ | ||
1148 | struct bio *nextbi = r5_next_bio(bi, sh->dev[i].sector); | ||
1149 | clear_bit(BIO_UPTODATE, &bi->bi_flags); | ||
1150 | if (--bi->bi_phys_segments == 0) { | ||
1151 | md_write_end(conf->mddev); | ||
1152 | bi->bi_next = return_bi; | ||
1153 | return_bi = bi; | ||
1154 | } | ||
1155 | bi = nextbi; | ||
1156 | } | ||
1157 | /* and fail all 'written' */ | ||
1158 | bi = sh->dev[i].written; | ||
1159 | sh->dev[i].written = NULL; | ||
1160 | if (bi) bitmap_end = 1; | ||
1161 | while (bi && bi->bi_sector < sh->dev[i].sector + STRIPE_SECTORS) { | ||
1162 | struct bio *bi2 = r5_next_bio(bi, sh->dev[i].sector); | ||
1163 | clear_bit(BIO_UPTODATE, &bi->bi_flags); | ||
1164 | if (--bi->bi_phys_segments == 0) { | ||
1165 | md_write_end(conf->mddev); | ||
1166 | bi->bi_next = return_bi; | ||
1167 | return_bi = bi; | ||
1168 | } | ||
1169 | bi = bi2; | ||
1170 | } | ||
1171 | |||
1172 | /* fail any reads if this device is non-operational */ | ||
1173 | if (!test_bit(R5_Insync, &sh->dev[i].flags) || | ||
1174 | test_bit(R5_ReadError, &sh->dev[i].flags)) { | ||
1175 | bi = sh->dev[i].toread; | ||
1176 | sh->dev[i].toread = NULL; | ||
1177 | if (test_and_clear_bit(R5_Overlap, &sh->dev[i].flags)) | ||
1178 | wake_up(&conf->wait_for_overlap); | ||
1179 | if (bi) to_read--; | ||
1180 | while (bi && bi->bi_sector < sh->dev[i].sector + STRIPE_SECTORS){ | ||
1181 | struct bio *nextbi = r5_next_bio(bi, sh->dev[i].sector); | ||
1182 | clear_bit(BIO_UPTODATE, &bi->bi_flags); | ||
1183 | if (--bi->bi_phys_segments == 0) { | ||
1184 | bi->bi_next = return_bi; | ||
1185 | return_bi = bi; | ||
1186 | } | ||
1187 | bi = nextbi; | ||
1188 | } | ||
1189 | } | ||
1190 | spin_unlock_irq(&conf->device_lock); | ||
1191 | if (bitmap_end) | ||
1192 | bitmap_endwrite(conf->mddev->bitmap, sh->sector, | ||
1193 | STRIPE_SECTORS, 0, 0); | ||
1194 | } | ||
1195 | } | ||
1196 | if (failed > 2 && syncing) { | ||
1197 | md_done_sync(conf->mddev, STRIPE_SECTORS,0); | ||
1198 | clear_bit(STRIPE_SYNCING, &sh->state); | ||
1199 | syncing = 0; | ||
1200 | } | ||
1201 | |||
1202 | /* | ||
1203 | * might be able to return some write requests if the parity blocks | ||
1204 | * are safe, or on a failed drive | ||
1205 | */ | ||
1206 | pdev = &sh->dev[pd_idx]; | ||
1207 | p_failed = (failed >= 1 && failed_num[0] == pd_idx) | ||
1208 | || (failed >= 2 && failed_num[1] == pd_idx); | ||
1209 | qdev = &sh->dev[qd_idx]; | ||
1210 | q_failed = (failed >= 1 && failed_num[0] == qd_idx) | ||
1211 | || (failed >= 2 && failed_num[1] == qd_idx); | ||
1212 | |||
1213 | if ( written && | ||
1214 | ( p_failed || ((test_bit(R5_Insync, &pdev->flags) | ||
1215 | && !test_bit(R5_LOCKED, &pdev->flags) | ||
1216 | && test_bit(R5_UPTODATE, &pdev->flags))) ) && | ||
1217 | ( q_failed || ((test_bit(R5_Insync, &qdev->flags) | ||
1218 | && !test_bit(R5_LOCKED, &qdev->flags) | ||
1219 | && test_bit(R5_UPTODATE, &qdev->flags))) ) ) { | ||
1220 | /* any written block on an uptodate or failed drive can be | ||
1221 | * returned. Note that if we 'wrote' to a failed drive, | ||
1222 | * it will be UPTODATE, but never LOCKED, so we don't need | ||
1223 | * to test 'failed' directly. | ||
1224 | */ | ||
1225 | for (i=disks; i--; ) | ||
1226 | if (sh->dev[i].written) { | ||
1227 | dev = &sh->dev[i]; | ||
1228 | if (!test_bit(R5_LOCKED, &dev->flags) && | ||
1229 | test_bit(R5_UPTODATE, &dev->flags) ) { | ||
1230 | /* We can return any write requests */ | ||
1231 | int bitmap_end = 0; | ||
1232 | struct bio *wbi, *wbi2; | ||
1233 | PRINTK("Return write for stripe %llu disc %d\n", | ||
1234 | (unsigned long long)sh->sector, i); | ||
1235 | spin_lock_irq(&conf->device_lock); | ||
1236 | wbi = dev->written; | ||
1237 | dev->written = NULL; | ||
1238 | while (wbi && wbi->bi_sector < dev->sector + STRIPE_SECTORS) { | ||
1239 | wbi2 = r5_next_bio(wbi, dev->sector); | ||
1240 | if (--wbi->bi_phys_segments == 0) { | ||
1241 | md_write_end(conf->mddev); | ||
1242 | wbi->bi_next = return_bi; | ||
1243 | return_bi = wbi; | ||
1244 | } | ||
1245 | wbi = wbi2; | ||
1246 | } | ||
1247 | if (dev->towrite == NULL) | ||
1248 | bitmap_end = 1; | ||
1249 | spin_unlock_irq(&conf->device_lock); | ||
1250 | if (bitmap_end) | ||
1251 | bitmap_endwrite(conf->mddev->bitmap, sh->sector, | ||
1252 | STRIPE_SECTORS, | ||
1253 | !test_bit(STRIPE_DEGRADED, &sh->state), 0); | ||
1254 | } | ||
1255 | } | ||
1256 | } | ||
1257 | |||
1258 | /* Now we might consider reading some blocks, either to check/generate | ||
1259 | * parity, or to satisfy requests | ||
1260 | * or to load a block that is being partially written. | ||
1261 | */ | ||
1262 | if (to_read || non_overwrite || (to_write && failed) || (syncing && (uptodate < disks))) { | ||
1263 | for (i=disks; i--;) { | ||
1264 | dev = &sh->dev[i]; | ||
1265 | if (!test_bit(R5_LOCKED, &dev->flags) && !test_bit(R5_UPTODATE, &dev->flags) && | ||
1266 | (dev->toread || | ||
1267 | (dev->towrite && !test_bit(R5_OVERWRITE, &dev->flags)) || | ||
1268 | syncing || | ||
1269 | (failed >= 1 && (sh->dev[failed_num[0]].toread || to_write)) || | ||
1270 | (failed >= 2 && (sh->dev[failed_num[1]].toread || to_write)) | ||
1271 | ) | ||
1272 | ) { | ||
1273 | /* we would like to get this block, possibly | ||
1274 | * by computing it, but we might not be able to | ||
1275 | */ | ||
1276 | if (uptodate == disks-1) { | ||
1277 | PRINTK("Computing stripe %llu block %d\n", | ||
1278 | (unsigned long long)sh->sector, i); | ||
1279 | compute_block_1(sh, i, 0); | ||
1280 | uptodate++; | ||
1281 | } else if ( uptodate == disks-2 && failed >= 2 ) { | ||
1282 | /* Computing 2-failure is *very* expensive; only do it if failed >= 2 */ | ||
1283 | int other; | ||
1284 | for (other=disks; other--;) { | ||
1285 | if ( other == i ) | ||
1286 | continue; | ||
1287 | if ( !test_bit(R5_UPTODATE, &sh->dev[other].flags) ) | ||
1288 | break; | ||
1289 | } | ||
1290 | BUG_ON(other < 0); | ||
1291 | PRINTK("Computing stripe %llu blocks %d,%d\n", | ||
1292 | (unsigned long long)sh->sector, i, other); | ||
1293 | compute_block_2(sh, i, other); | ||
1294 | uptodate += 2; | ||
1295 | } else if (test_bit(R5_Insync, &dev->flags)) { | ||
1296 | set_bit(R5_LOCKED, &dev->flags); | ||
1297 | set_bit(R5_Wantread, &dev->flags); | ||
1298 | #if 0 | ||
1299 | /* if I am just reading this block and we don't have | ||
1300 | a failed drive, or any pending writes then sidestep the cache */ | ||
1301 | if (sh->bh_read[i] && !sh->bh_read[i]->b_reqnext && | ||
1302 | ! syncing && !failed && !to_write) { | ||
1303 | sh->bh_cache[i]->b_page = sh->bh_read[i]->b_page; | ||
1304 | sh->bh_cache[i]->b_data = sh->bh_read[i]->b_data; | ||
1305 | } | ||
1306 | #endif | ||
1307 | locked++; | ||
1308 | PRINTK("Reading block %d (sync=%d)\n", | ||
1309 | i, syncing); | ||
1310 | } | ||
1311 | } | ||
1312 | } | ||
1313 | set_bit(STRIPE_HANDLE, &sh->state); | ||
1314 | } | ||
1315 | |||
1316 | /* now to consider writing and what else, if anything should be read */ | ||
1317 | if (to_write) { | ||
1318 | int rcw=0, must_compute=0; | ||
1319 | for (i=disks ; i--;) { | ||
1320 | dev = &sh->dev[i]; | ||
1321 | /* Would I have to read this buffer for reconstruct_write */ | ||
1322 | if (!test_bit(R5_OVERWRITE, &dev->flags) | ||
1323 | && i != pd_idx && i != qd_idx | ||
1324 | && (!test_bit(R5_LOCKED, &dev->flags) | ||
1325 | #if 0 | ||
1326 | || sh->bh_page[i] != bh->b_page | ||
1327 | #endif | ||
1328 | ) && | ||
1329 | !test_bit(R5_UPTODATE, &dev->flags)) { | ||
1330 | if (test_bit(R5_Insync, &dev->flags)) rcw++; | ||
1331 | else { | ||
1332 | PRINTK("raid6: must_compute: disk %d flags=%#lx\n", i, dev->flags); | ||
1333 | must_compute++; | ||
1334 | } | ||
1335 | } | ||
1336 | } | ||
1337 | PRINTK("for sector %llu, rcw=%d, must_compute=%d\n", | ||
1338 | (unsigned long long)sh->sector, rcw, must_compute); | ||
1339 | set_bit(STRIPE_HANDLE, &sh->state); | ||
1340 | |||
1341 | if (rcw > 0) | ||
1342 | /* want reconstruct write, but need to get some data */ | ||
1343 | for (i=disks; i--;) { | ||
1344 | dev = &sh->dev[i]; | ||
1345 | if (!test_bit(R5_OVERWRITE, &dev->flags) | ||
1346 | && !(failed == 0 && (i == pd_idx || i == qd_idx)) | ||
1347 | && !test_bit(R5_LOCKED, &dev->flags) && !test_bit(R5_UPTODATE, &dev->flags) && | ||
1348 | test_bit(R5_Insync, &dev->flags)) { | ||
1349 | if (test_bit(STRIPE_PREREAD_ACTIVE, &sh->state)) | ||
1350 | { | ||
1351 | PRINTK("Read_old stripe %llu block %d for Reconstruct\n", | ||
1352 | (unsigned long long)sh->sector, i); | ||
1353 | set_bit(R5_LOCKED, &dev->flags); | ||
1354 | set_bit(R5_Wantread, &dev->flags); | ||
1355 | locked++; | ||
1356 | } else { | ||
1357 | PRINTK("Request delayed stripe %llu block %d for Reconstruct\n", | ||
1358 | (unsigned long long)sh->sector, i); | ||
1359 | set_bit(STRIPE_DELAYED, &sh->state); | ||
1360 | set_bit(STRIPE_HANDLE, &sh->state); | ||
1361 | } | ||
1362 | } | ||
1363 | } | ||
1364 | /* now if nothing is locked, and if we have enough data, we can start a write request */ | ||
1365 | if (locked == 0 && rcw == 0 && | ||
1366 | !test_bit(STRIPE_BIT_DELAY, &sh->state)) { | ||
1367 | if ( must_compute > 0 ) { | ||
1368 | /* We have failed blocks and need to compute them */ | ||
1369 | switch ( failed ) { | ||
1370 | case 0: BUG(); | ||
1371 | case 1: compute_block_1(sh, failed_num[0], 0); break; | ||
1372 | case 2: compute_block_2(sh, failed_num[0], failed_num[1]); break; | ||
1373 | default: BUG(); /* This request should have been failed? */ | ||
1374 | } | ||
1375 | } | ||
1376 | |||
1377 | PRINTK("Computing parity for stripe %llu\n", (unsigned long long)sh->sector); | ||
1378 | compute_parity(sh, RECONSTRUCT_WRITE); | ||
1379 | /* now every locked buffer is ready to be written */ | ||
1380 | for (i=disks; i--;) | ||
1381 | if (test_bit(R5_LOCKED, &sh->dev[i].flags)) { | ||
1382 | PRINTK("Writing stripe %llu block %d\n", | ||
1383 | (unsigned long long)sh->sector, i); | ||
1384 | locked++; | ||
1385 | set_bit(R5_Wantwrite, &sh->dev[i].flags); | ||
1386 | } | ||
1387 | /* after a RECONSTRUCT_WRITE, the stripe MUST be in-sync */ | ||
1388 | set_bit(STRIPE_INSYNC, &sh->state); | ||
1389 | |||
1390 | if (test_and_clear_bit(STRIPE_PREREAD_ACTIVE, &sh->state)) { | ||
1391 | atomic_dec(&conf->preread_active_stripes); | ||
1392 | if (atomic_read(&conf->preread_active_stripes) < IO_THRESHOLD) | ||
1393 | md_wakeup_thread(conf->mddev->thread); | ||
1394 | } | ||
1395 | } | ||
1396 | } | ||
1397 | |||
1398 | /* maybe we need to check and possibly fix the parity for this stripe | ||
1399 | * Any reads will already have been scheduled, so we just see if enough data | ||
1400 | * is available | ||
1401 | */ | ||
1402 | if (syncing && locked == 0 && !test_bit(STRIPE_INSYNC, &sh->state)) { | ||
1403 | int update_p = 0, update_q = 0; | ||
1404 | struct r5dev *dev; | ||
1405 | |||
1406 | set_bit(STRIPE_HANDLE, &sh->state); | ||
1407 | |||
1408 | BUG_ON(failed>2); | ||
1409 | BUG_ON(uptodate < disks); | ||
1410 | /* Want to check and possibly repair P and Q. | ||
1411 | * However there could be one 'failed' device, in which | ||
1412 | * case we can only check one of them, possibly using the | ||
1413 | * other to generate missing data | ||
1414 | */ | ||
1415 | |||
1416 | /* If !tmp_page, we cannot do the calculations, | ||
1417 | * but as we have set STRIPE_HANDLE, we will soon be called | ||
1418 | * by stripe_handle with a tmp_page - just wait until then. | ||
1419 | */ | ||
1420 | if (tmp_page) { | ||
1421 | if (failed == q_failed) { | ||
1422 | /* The only possible failed device holds 'Q', so it makes | ||
1423 | * sense to check P (If anything else were failed, we would | ||
1424 | * have used P to recreate it). | ||
1425 | */ | ||
1426 | compute_block_1(sh, pd_idx, 1); | ||
1427 | if (!page_is_zero(sh->dev[pd_idx].page)) { | ||
1428 | compute_block_1(sh,pd_idx,0); | ||
1429 | update_p = 1; | ||
1430 | } | ||
1431 | } | ||
1432 | if (!q_failed && failed < 2) { | ||
1433 | /* q is not failed, and we didn't use it to generate | ||
1434 | * anything, so it makes sense to check it | ||
1435 | */ | ||
1436 | memcpy(page_address(tmp_page), | ||
1437 | page_address(sh->dev[qd_idx].page), | ||
1438 | STRIPE_SIZE); | ||
1439 | compute_parity(sh, UPDATE_PARITY); | ||
1440 | if (memcmp(page_address(tmp_page), | ||
1441 | page_address(sh->dev[qd_idx].page), | ||
1442 | STRIPE_SIZE)!= 0) { | ||
1443 | clear_bit(STRIPE_INSYNC, &sh->state); | ||
1444 | update_q = 1; | ||
1445 | } | ||
1446 | } | ||
1447 | if (update_p || update_q) { | ||
1448 | conf->mddev->resync_mismatches += STRIPE_SECTORS; | ||
1449 | if (test_bit(MD_RECOVERY_CHECK, &conf->mddev->recovery)) | ||
1450 | /* don't try to repair!! */ | ||
1451 | update_p = update_q = 0; | ||
1452 | } | ||
1453 | |||
1454 | /* now write out any block on a failed drive, | ||
1455 | * or P or Q if they need it | ||
1456 | */ | ||
1457 | |||
1458 | if (failed == 2) { | ||
1459 | dev = &sh->dev[failed_num[1]]; | ||
1460 | locked++; | ||
1461 | set_bit(R5_LOCKED, &dev->flags); | ||
1462 | set_bit(R5_Wantwrite, &dev->flags); | ||
1463 | } | ||
1464 | if (failed >= 1) { | ||
1465 | dev = &sh->dev[failed_num[0]]; | ||
1466 | locked++; | ||
1467 | set_bit(R5_LOCKED, &dev->flags); | ||
1468 | set_bit(R5_Wantwrite, &dev->flags); | ||
1469 | } | ||
1470 | |||
1471 | if (update_p) { | ||
1472 | dev = &sh->dev[pd_idx]; | ||
1473 | locked ++; | ||
1474 | set_bit(R5_LOCKED, &dev->flags); | ||
1475 | set_bit(R5_Wantwrite, &dev->flags); | ||
1476 | } | ||
1477 | if (update_q) { | ||
1478 | dev = &sh->dev[qd_idx]; | ||
1479 | locked++; | ||
1480 | set_bit(R5_LOCKED, &dev->flags); | ||
1481 | set_bit(R5_Wantwrite, &dev->flags); | ||
1482 | } | ||
1483 | clear_bit(STRIPE_DEGRADED, &sh->state); | ||
1484 | |||
1485 | set_bit(STRIPE_INSYNC, &sh->state); | ||
1486 | } | ||
1487 | } | ||
1488 | |||
1489 | if (syncing && locked == 0 && test_bit(STRIPE_INSYNC, &sh->state)) { | ||
1490 | md_done_sync(conf->mddev, STRIPE_SECTORS,1); | ||
1491 | clear_bit(STRIPE_SYNCING, &sh->state); | ||
1492 | } | ||
1493 | |||
1494 | /* If the failed drives are just a ReadError, then we might need | ||
1495 | * to progress the repair/check process | ||
1496 | */ | ||
1497 | if (failed <= 2 && ! conf->mddev->ro) | ||
1498 | for (i=0; i<failed;i++) { | ||
1499 | dev = &sh->dev[failed_num[i]]; | ||
1500 | if (test_bit(R5_ReadError, &dev->flags) | ||
1501 | && !test_bit(R5_LOCKED, &dev->flags) | ||
1502 | && test_bit(R5_UPTODATE, &dev->flags) | ||
1503 | ) { | ||
1504 | if (!test_bit(R5_ReWrite, &dev->flags)) { | ||
1505 | set_bit(R5_Wantwrite, &dev->flags); | ||
1506 | set_bit(R5_ReWrite, &dev->flags); | ||
1507 | set_bit(R5_LOCKED, &dev->flags); | ||
1508 | } else { | ||
1509 | /* let's read it back */ | ||
1510 | set_bit(R5_Wantread, &dev->flags); | ||
1511 | set_bit(R5_LOCKED, &dev->flags); | ||
1512 | } | ||
1513 | } | ||
1514 | } | ||
1515 | spin_unlock(&sh->lock); | ||
1516 | |||
1517 | while ((bi=return_bi)) { | ||
1518 | int bytes = bi->bi_size; | ||
1519 | |||
1520 | return_bi = bi->bi_next; | ||
1521 | bi->bi_next = NULL; | ||
1522 | bi->bi_size = 0; | ||
1523 | bi->bi_end_io(bi, bytes, 0); | ||
1524 | } | ||
1525 | for (i=disks; i-- ;) { | ||
1526 | int rw; | ||
1527 | struct bio *bi; | ||
1528 | mdk_rdev_t *rdev; | ||
1529 | if (test_and_clear_bit(R5_Wantwrite, &sh->dev[i].flags)) | ||
1530 | rw = 1; | ||
1531 | else if (test_and_clear_bit(R5_Wantread, &sh->dev[i].flags)) | ||
1532 | rw = 0; | ||
1533 | else | ||
1534 | continue; | ||
1535 | |||
1536 | bi = &sh->dev[i].req; | ||
1537 | |||
1538 | bi->bi_rw = rw; | ||
1539 | if (rw) | ||
1540 | bi->bi_end_io = raid6_end_write_request; | ||
1541 | else | ||
1542 | bi->bi_end_io = raid6_end_read_request; | ||
1543 | |||
1544 | rcu_read_lock(); | ||
1545 | rdev = rcu_dereference(conf->disks[i].rdev); | ||
1546 | if (rdev && test_bit(Faulty, &rdev->flags)) | ||
1547 | rdev = NULL; | ||
1548 | if (rdev) | ||
1549 | atomic_inc(&rdev->nr_pending); | ||
1550 | rcu_read_unlock(); | ||
1551 | |||
1552 | if (rdev) { | ||
1553 | if (syncing) | ||
1554 | md_sync_acct(rdev->bdev, STRIPE_SECTORS); | ||
1555 | |||
1556 | bi->bi_bdev = rdev->bdev; | ||
1557 | PRINTK("for %llu schedule op %ld on disc %d\n", | ||
1558 | (unsigned long long)sh->sector, bi->bi_rw, i); | ||
1559 | atomic_inc(&sh->count); | ||
1560 | bi->bi_sector = sh->sector + rdev->data_offset; | ||
1561 | bi->bi_flags = 1 << BIO_UPTODATE; | ||
1562 | bi->bi_vcnt = 1; | ||
1563 | bi->bi_max_vecs = 1; | ||
1564 | bi->bi_idx = 0; | ||
1565 | bi->bi_io_vec = &sh->dev[i].vec; | ||
1566 | bi->bi_io_vec[0].bv_len = STRIPE_SIZE; | ||
1567 | bi->bi_io_vec[0].bv_offset = 0; | ||
1568 | bi->bi_size = STRIPE_SIZE; | ||
1569 | bi->bi_next = NULL; | ||
1570 | if (rw == WRITE && | ||
1571 | test_bit(R5_ReWrite, &sh->dev[i].flags)) | ||
1572 | atomic_add(STRIPE_SECTORS, &rdev->corrected_errors); | ||
1573 | generic_make_request(bi); | ||
1574 | } else { | ||
1575 | if (rw == 1) | ||
1576 | set_bit(STRIPE_DEGRADED, &sh->state); | ||
1577 | PRINTK("skip op %ld on disc %d for sector %llu\n", | ||
1578 | bi->bi_rw, i, (unsigned long long)sh->sector); | ||
1579 | clear_bit(R5_LOCKED, &sh->dev[i].flags); | ||
1580 | set_bit(STRIPE_HANDLE, &sh->state); | ||
1581 | } | ||
1582 | } | ||
1583 | } | ||
1584 | |||
1585 | static void raid6_activate_delayed(raid6_conf_t *conf) | ||
1586 | { | ||
1587 | if (atomic_read(&conf->preread_active_stripes) < IO_THRESHOLD) { | ||
1588 | while (!list_empty(&conf->delayed_list)) { | ||
1589 | struct list_head *l = conf->delayed_list.next; | ||
1590 | struct stripe_head *sh; | ||
1591 | sh = list_entry(l, struct stripe_head, lru); | ||
1592 | list_del_init(l); | ||
1593 | clear_bit(STRIPE_DELAYED, &sh->state); | ||
1594 | if (!test_and_set_bit(STRIPE_PREREAD_ACTIVE, &sh->state)) | ||
1595 | atomic_inc(&conf->preread_active_stripes); | ||
1596 | list_add_tail(&sh->lru, &conf->handle_list); | ||
1597 | } | ||
1598 | } | ||
1599 | } | ||
1600 | |||
1601 | static void activate_bit_delay(raid6_conf_t *conf) | ||
1602 | { | ||
1603 | /* device_lock is held */ | ||
1604 | struct list_head head; | ||
1605 | list_add(&head, &conf->bitmap_list); | ||
1606 | list_del_init(&conf->bitmap_list); | ||
1607 | while (!list_empty(&head)) { | ||
1608 | struct stripe_head *sh = list_entry(head.next, struct stripe_head, lru); | ||
1609 | list_del_init(&sh->lru); | ||
1610 | atomic_inc(&sh->count); | ||
1611 | __release_stripe(conf, sh); | ||
1612 | } | ||
1613 | } | ||
1614 | |||
1615 | static void unplug_slaves(mddev_t *mddev) | ||
1616 | { | ||
1617 | raid6_conf_t *conf = mddev_to_conf(mddev); | ||
1618 | int i; | ||
1619 | |||
1620 | rcu_read_lock(); | ||
1621 | for (i=0; i<mddev->raid_disks; i++) { | ||
1622 | mdk_rdev_t *rdev = rcu_dereference(conf->disks[i].rdev); | ||
1623 | if (rdev && !test_bit(Faulty, &rdev->flags) && atomic_read(&rdev->nr_pending)) { | ||
1624 | request_queue_t *r_queue = bdev_get_queue(rdev->bdev); | ||
1625 | |||
1626 | atomic_inc(&rdev->nr_pending); | ||
1627 | rcu_read_unlock(); | ||
1628 | |||
1629 | if (r_queue->unplug_fn) | ||
1630 | r_queue->unplug_fn(r_queue); | ||
1631 | |||
1632 | rdev_dec_pending(rdev, mddev); | ||
1633 | rcu_read_lock(); | ||
1634 | } | ||
1635 | } | ||
1636 | rcu_read_unlock(); | ||
1637 | } | ||
1638 | |||
1639 | static void raid6_unplug_device(request_queue_t *q) | ||
1640 | { | ||
1641 | mddev_t *mddev = q->queuedata; | ||
1642 | raid6_conf_t *conf = mddev_to_conf(mddev); | ||
1643 | unsigned long flags; | ||
1644 | |||
1645 | spin_lock_irqsave(&conf->device_lock, flags); | ||
1646 | |||
1647 | if (blk_remove_plug(q)) { | ||
1648 | conf->seq_flush++; | ||
1649 | raid6_activate_delayed(conf); | ||
1650 | } | ||
1651 | md_wakeup_thread(mddev->thread); | ||
1652 | |||
1653 | spin_unlock_irqrestore(&conf->device_lock, flags); | ||
1654 | |||
1655 | unplug_slaves(mddev); | ||
1656 | } | ||
1657 | |||
1658 | static int raid6_issue_flush(request_queue_t *q, struct gendisk *disk, | ||
1659 | sector_t *error_sector) | ||
1660 | { | ||
1661 | mddev_t *mddev = q->queuedata; | ||
1662 | raid6_conf_t *conf = mddev_to_conf(mddev); | ||
1663 | int i, ret = 0; | ||
1664 | |||
1665 | rcu_read_lock(); | ||
1666 | for (i=0; i<mddev->raid_disks && ret == 0; i++) { | ||
1667 | mdk_rdev_t *rdev = rcu_dereference(conf->disks[i].rdev); | ||
1668 | if (rdev && !test_bit(Faulty, &rdev->flags)) { | ||
1669 | struct block_device *bdev = rdev->bdev; | ||
1670 | request_queue_t *r_queue = bdev_get_queue(bdev); | ||
1671 | |||
1672 | if (!r_queue->issue_flush_fn) | ||
1673 | ret = -EOPNOTSUPP; | ||
1674 | else { | ||
1675 | atomic_inc(&rdev->nr_pending); | ||
1676 | rcu_read_unlock(); | ||
1677 | ret = r_queue->issue_flush_fn(r_queue, bdev->bd_disk, | ||
1678 | error_sector); | ||
1679 | rdev_dec_pending(rdev, mddev); | ||
1680 | rcu_read_lock(); | ||
1681 | } | ||
1682 | } | ||
1683 | } | ||
1684 | rcu_read_unlock(); | ||
1685 | return ret; | ||
1686 | } | ||
1687 | |||
1688 | static inline void raid6_plug_device(raid6_conf_t *conf) | ||
1689 | { | ||
1690 | spin_lock_irq(&conf->device_lock); | ||
1691 | blk_plug_device(conf->mddev->queue); | ||
1692 | spin_unlock_irq(&conf->device_lock); | ||
1693 | } | ||
1694 | |||
1695 | static int make_request (request_queue_t *q, struct bio * bi) | ||
1696 | { | ||
1697 | mddev_t *mddev = q->queuedata; | ||
1698 | raid6_conf_t *conf = mddev_to_conf(mddev); | ||
1699 | const unsigned int raid_disks = conf->raid_disks; | ||
1700 | const unsigned int data_disks = raid_disks - 2; | ||
1701 | unsigned int dd_idx, pd_idx; | ||
1702 | sector_t new_sector; | ||
1703 | sector_t logical_sector, last_sector; | ||
1704 | struct stripe_head *sh; | ||
1705 | const int rw = bio_data_dir(bi); | ||
1706 | |||
1707 | if (unlikely(bio_barrier(bi))) { | ||
1708 | bio_endio(bi, bi->bi_size, -EOPNOTSUPP); | ||
1709 | return 0; | ||
1710 | } | ||
1711 | |||
1712 | md_write_start(mddev, bi); | ||
1713 | |||
1714 | disk_stat_inc(mddev->gendisk, ios[rw]); | ||
1715 | disk_stat_add(mddev->gendisk, sectors[rw], bio_sectors(bi)); | ||
1716 | |||
1717 | logical_sector = bi->bi_sector & ~((sector_t)STRIPE_SECTORS-1); | ||
1718 | last_sector = bi->bi_sector + (bi->bi_size>>9); | ||
1719 | |||
1720 | bi->bi_next = NULL; | ||
1721 | bi->bi_phys_segments = 1; /* over-loaded to count active stripes */ | ||
1722 | |||
1723 | for (;logical_sector < last_sector; logical_sector += STRIPE_SECTORS) { | ||
1724 | DEFINE_WAIT(w); | ||
1725 | |||
1726 | new_sector = raid6_compute_sector(logical_sector, | ||
1727 | raid_disks, data_disks, &dd_idx, &pd_idx, conf); | ||
1728 | |||
1729 | PRINTK("raid6: make_request, sector %llu logical %llu\n", | ||
1730 | (unsigned long long)new_sector, | ||
1731 | (unsigned long long)logical_sector); | ||
1732 | |||
1733 | retry: | ||
1734 | prepare_to_wait(&conf->wait_for_overlap, &w, TASK_UNINTERRUPTIBLE); | ||
1735 | sh = get_active_stripe(conf, new_sector, pd_idx, (bi->bi_rw&RWA_MASK)); | ||
1736 | if (sh) { | ||
1737 | if (!add_stripe_bio(sh, bi, dd_idx, (bi->bi_rw&RW_MASK))) { | ||
1738 | /* Add failed due to overlap. Flush everything | ||
1739 | * and wait a while | ||
1740 | */ | ||
1741 | raid6_unplug_device(mddev->queue); | ||
1742 | release_stripe(sh); | ||
1743 | schedule(); | ||
1744 | goto retry; | ||
1745 | } | ||
1746 | finish_wait(&conf->wait_for_overlap, &w); | ||
1747 | raid6_plug_device(conf); | ||
1748 | handle_stripe(sh, NULL); | ||
1749 | release_stripe(sh); | ||
1750 | } else { | ||
1751 | /* cannot get stripe for read-ahead, just give-up */ | ||
1752 | clear_bit(BIO_UPTODATE, &bi->bi_flags); | ||
1753 | finish_wait(&conf->wait_for_overlap, &w); | ||
1754 | break; | ||
1755 | } | ||
1756 | |||
1757 | } | ||
1758 | spin_lock_irq(&conf->device_lock); | ||
1759 | if (--bi->bi_phys_segments == 0) { | ||
1760 | int bytes = bi->bi_size; | ||
1761 | |||
1762 | if (rw == WRITE ) | ||
1763 | md_write_end(mddev); | ||
1764 | bi->bi_size = 0; | ||
1765 | bi->bi_end_io(bi, bytes, 0); | ||
1766 | } | ||
1767 | spin_unlock_irq(&conf->device_lock); | ||
1768 | return 0; | ||
1769 | } | ||
1770 | |||
1771 | /* FIXME go_faster isn't used */ | ||
1772 | static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, int go_faster) | ||
1773 | { | ||
1774 | raid6_conf_t *conf = (raid6_conf_t *) mddev->private; | ||
1775 | struct stripe_head *sh; | ||
1776 | int sectors_per_chunk = conf->chunk_size >> 9; | ||
1777 | sector_t x; | ||
1778 | unsigned long stripe; | ||
1779 | int chunk_offset; | ||
1780 | int dd_idx, pd_idx; | ||
1781 | sector_t first_sector; | ||
1782 | int raid_disks = conf->raid_disks; | ||
1783 | int data_disks = raid_disks - 2; | ||
1784 | sector_t max_sector = mddev->size << 1; | ||
1785 | int sync_blocks; | ||
1786 | int still_degraded = 0; | ||
1787 | int i; | ||
1788 | |||
1789 | if (sector_nr >= max_sector) { | ||
1790 | /* just being told to finish up .. nothing much to do */ | ||
1791 | unplug_slaves(mddev); | ||
1792 | |||
1793 | if (mddev->curr_resync < max_sector) /* aborted */ | ||
1794 | bitmap_end_sync(mddev->bitmap, mddev->curr_resync, | ||
1795 | &sync_blocks, 1); | ||
1796 | else /* completed sync */ | ||
1797 | conf->fullsync = 0; | ||
1798 | bitmap_close_sync(mddev->bitmap); | ||
1799 | |||
1800 | return 0; | ||
1801 | } | ||
1802 | /* if there are 2 or more failed drives and we are trying | ||
1803 | * to resync, then assert that we are finished, because there is | ||
1804 | * nothing we can do. | ||
1805 | */ | ||
1806 | if (mddev->degraded >= 2 && test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) { | ||
1807 | sector_t rv = (mddev->size << 1) - sector_nr; | ||
1808 | *skipped = 1; | ||
1809 | return rv; | ||
1810 | } | ||
1811 | if (!bitmap_start_sync(mddev->bitmap, sector_nr, &sync_blocks, 1) && | ||
1812 | !test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery) && | ||
1813 | !conf->fullsync && sync_blocks >= STRIPE_SECTORS) { | ||
1814 | /* we can skip this block, and probably more */ | ||
1815 | sync_blocks /= STRIPE_SECTORS; | ||
1816 | *skipped = 1; | ||
1817 | return sync_blocks * STRIPE_SECTORS; /* keep things rounded to whole stripes */ | ||
1818 | } | ||
1819 | |||
1820 | x = sector_nr; | ||
1821 | chunk_offset = sector_div(x, sectors_per_chunk); | ||
1822 | stripe = x; | ||
1823 | BUG_ON(x != stripe); | ||
1824 | |||
1825 | first_sector = raid6_compute_sector((sector_t)stripe*data_disks*sectors_per_chunk | ||
1826 | + chunk_offset, raid_disks, data_disks, &dd_idx, &pd_idx, conf); | ||
1827 | sh = get_active_stripe(conf, sector_nr, pd_idx, 1); | ||
1828 | if (sh == NULL) { | ||
1829 | sh = get_active_stripe(conf, sector_nr, pd_idx, 0); | ||
1830 | /* make sure we don't swamp the stripe cache if someone else | ||
1831 | * is trying to get access | ||
1832 | */ | ||
1833 | schedule_timeout_uninterruptible(1); | ||
1834 | } | ||
1835 | /* Need to check if array will still be degraded after recovery/resync | ||
1836 | * We don't need to check the 'failed' flag as when that gets set, | ||
1837 | * recovery aborts. | ||
1838 | */ | ||
1839 | for (i=0; i<mddev->raid_disks; i++) | ||
1840 | if (conf->disks[i].rdev == NULL) | ||
1841 | still_degraded = 1; | ||
1842 | |||
1843 | bitmap_start_sync(mddev->bitmap, sector_nr, &sync_blocks, still_degraded); | ||
1844 | |||
1845 | spin_lock(&sh->lock); | ||
1846 | set_bit(STRIPE_SYNCING, &sh->state); | ||
1847 | clear_bit(STRIPE_INSYNC, &sh->state); | ||
1848 | spin_unlock(&sh->lock); | ||
1849 | |||
1850 | handle_stripe(sh, NULL); | ||
1851 | release_stripe(sh); | ||
1852 | |||
1853 | return STRIPE_SECTORS; | ||
1854 | } | ||
1855 | |||
1856 | /* | ||
1857 | * This is our raid6 kernel thread. | ||
1858 | * | ||
1859 | * We scan the hash table for stripes which can be handled now. | ||
1860 | * During the scan, completed stripes are saved for us by the interrupt | ||
1861 | * handler, so that they will not have to wait for our next wakeup. | ||
1862 | */ | ||
1863 | static void raid6d (mddev_t *mddev) | ||
1864 | { | ||
1865 | struct stripe_head *sh; | ||
1866 | raid6_conf_t *conf = mddev_to_conf(mddev); | ||
1867 | int handled; | ||
1868 | |||
1869 | PRINTK("+++ raid6d active\n"); | ||
1870 | |||
1871 | md_check_recovery(mddev); | ||
1872 | |||
1873 | handled = 0; | ||
1874 | spin_lock_irq(&conf->device_lock); | ||
1875 | while (1) { | ||
1876 | struct list_head *first; | ||
1877 | |||
1878 | if (conf->seq_flush - conf->seq_write > 0) { | ||
1879 | int seq = conf->seq_flush; | ||
1880 | spin_unlock_irq(&conf->device_lock); | ||
1881 | bitmap_unplug(mddev->bitmap); | ||
1882 | spin_lock_irq(&conf->device_lock); | ||
1883 | conf->seq_write = seq; | ||
1884 | activate_bit_delay(conf); | ||
1885 | } | ||
1886 | |||
1887 | if (list_empty(&conf->handle_list) && | ||
1888 | atomic_read(&conf->preread_active_stripes) < IO_THRESHOLD && | ||
1889 | !blk_queue_plugged(mddev->queue) && | ||
1890 | !list_empty(&conf->delayed_list)) | ||
1891 | raid6_activate_delayed(conf); | ||
1892 | |||
1893 | if (list_empty(&conf->handle_list)) | ||
1894 | break; | ||
1895 | |||
1896 | first = conf->handle_list.next; | ||
1897 | sh = list_entry(first, struct stripe_head, lru); | ||
1898 | |||
1899 | list_del_init(first); | ||
1900 | atomic_inc(&sh->count); | ||
1901 | BUG_ON(atomic_read(&sh->count)!= 1); | ||
1902 | spin_unlock_irq(&conf->device_lock); | ||
1903 | |||
1904 | handled++; | ||
1905 | handle_stripe(sh, conf->spare_page); | ||
1906 | release_stripe(sh); | ||
1907 | |||
1908 | spin_lock_irq(&conf->device_lock); | ||
1909 | } | ||
1910 | PRINTK("%d stripes handled\n", handled); | ||
1911 | |||
1912 | spin_unlock_irq(&conf->device_lock); | ||
1913 | |||
1914 | unplug_slaves(mddev); | ||
1915 | |||
1916 | PRINTK("--- raid6d inactive\n"); | ||
1917 | } | ||
1918 | |||
1919 | static ssize_t | ||
1920 | raid6_show_stripe_cache_size(mddev_t *mddev, char *page) | ||
1921 | { | ||
1922 | raid6_conf_t *conf = mddev_to_conf(mddev); | ||
1923 | if (conf) | ||
1924 | return sprintf(page, "%d\n", conf->max_nr_stripes); | ||
1925 | else | ||
1926 | return 0; | ||
1927 | } | ||
1928 | |||
1929 | static ssize_t | ||
1930 | raid6_store_stripe_cache_size(mddev_t *mddev, const char *page, size_t len) | ||
1931 | { | ||
1932 | raid6_conf_t *conf = mddev_to_conf(mddev); | ||
1933 | char *end; | ||
1934 | int new; | ||
1935 | if (len >= PAGE_SIZE) | ||
1936 | return -EINVAL; | ||
1937 | if (!conf) | ||
1938 | return -ENODEV; | ||
1939 | |||
1940 | new = simple_strtoul(page, &end, 10); | ||
1941 | if (!*page || (*end && *end != '\n') ) | ||
1942 | return -EINVAL; | ||
1943 | if (new <= 16 || new > 32768) | ||
1944 | return -EINVAL; | ||
1945 | while (new < conf->max_nr_stripes) { | ||
1946 | if (drop_one_stripe(conf)) | ||
1947 | conf->max_nr_stripes--; | ||
1948 | else | ||
1949 | break; | ||
1950 | } | ||
1951 | while (new > conf->max_nr_stripes) { | ||
1952 | if (grow_one_stripe(conf)) | ||
1953 | conf->max_nr_stripes++; | ||
1954 | else break; | ||
1955 | } | ||
1956 | return len; | ||
1957 | } | ||
1958 | |||
1959 | static struct md_sysfs_entry | ||
1960 | raid6_stripecache_size = __ATTR(stripe_cache_size, S_IRUGO | S_IWUSR, | ||
1961 | raid6_show_stripe_cache_size, | ||
1962 | raid6_store_stripe_cache_size); | ||
1963 | |||
1964 | static ssize_t | ||
1965 | stripe_cache_active_show(mddev_t *mddev, char *page) | ||
1966 | { | ||
1967 | raid6_conf_t *conf = mddev_to_conf(mddev); | ||
1968 | if (conf) | ||
1969 | return sprintf(page, "%d\n", atomic_read(&conf->active_stripes)); | ||
1970 | else | ||
1971 | return 0; | ||
1972 | } | ||
1973 | |||
1974 | static struct md_sysfs_entry | ||
1975 | raid6_stripecache_active = __ATTR_RO(stripe_cache_active); | ||
1976 | |||
1977 | static struct attribute *raid6_attrs[] = { | ||
1978 | &raid6_stripecache_size.attr, | ||
1979 | &raid6_stripecache_active.attr, | ||
1980 | NULL, | ||
1981 | }; | ||
1982 | static struct attribute_group raid6_attrs_group = { | ||
1983 | .name = NULL, | ||
1984 | .attrs = raid6_attrs, | ||
1985 | }; | ||
1986 | |||
1987 | static int run(mddev_t *mddev) | ||
1988 | { | ||
1989 | raid6_conf_t *conf; | ||
1990 | int raid_disk, memory; | ||
1991 | mdk_rdev_t *rdev; | ||
1992 | struct disk_info *disk; | ||
1993 | struct list_head *tmp; | ||
1994 | |||
1995 | if (mddev->level != 6) { | ||
1996 | PRINTK("raid6: %s: raid level not set to 6 (%d)\n", mdname(mddev), mddev->level); | ||
1997 | return -EIO; | ||
1998 | } | ||
1999 | |||
2000 | mddev->private = kzalloc(sizeof (raid6_conf_t), GFP_KERNEL); | ||
2001 | if ((conf = mddev->private) == NULL) | ||
2002 | goto abort; | ||
2003 | conf->disks = kzalloc(mddev->raid_disks * sizeof(struct disk_info), | ||
2004 | GFP_KERNEL); | ||
2005 | if (!conf->disks) | ||
2006 | goto abort; | ||
2007 | |||
2008 | conf->mddev = mddev; | ||
2009 | |||
2010 | if ((conf->stripe_hashtbl = kzalloc(PAGE_SIZE, GFP_KERNEL)) == NULL) | ||
2011 | goto abort; | ||
2012 | |||
2013 | conf->spare_page = alloc_page(GFP_KERNEL); | ||
2014 | if (!conf->spare_page) | ||
2015 | goto abort; | ||
2016 | |||
2017 | spin_lock_init(&conf->device_lock); | ||
2018 | init_waitqueue_head(&conf->wait_for_stripe); | ||
2019 | init_waitqueue_head(&conf->wait_for_overlap); | ||
2020 | INIT_LIST_HEAD(&conf->handle_list); | ||
2021 | INIT_LIST_HEAD(&conf->delayed_list); | ||
2022 | INIT_LIST_HEAD(&conf->bitmap_list); | ||
2023 | INIT_LIST_HEAD(&conf->inactive_list); | ||
2024 | atomic_set(&conf->active_stripes, 0); | ||
2025 | atomic_set(&conf->preread_active_stripes, 0); | ||
2026 | |||
2027 | PRINTK("raid6: run(%s) called.\n", mdname(mddev)); | ||
2028 | |||
2029 | ITERATE_RDEV(mddev,rdev,tmp) { | ||
2030 | raid_disk = rdev->raid_disk; | ||
2031 | if (raid_disk >= mddev->raid_disks | ||
2032 | || raid_disk < 0) | ||
2033 | continue; | ||
2034 | disk = conf->disks + raid_disk; | ||
2035 | |||
2036 | disk->rdev = rdev; | ||
2037 | |||
2038 | if (test_bit(In_sync, &rdev->flags)) { | ||
2039 | char b[BDEVNAME_SIZE]; | ||
2040 | printk(KERN_INFO "raid6: device %s operational as raid" | ||
2041 | " disk %d\n", bdevname(rdev->bdev,b), | ||
2042 | raid_disk); | ||
2043 | conf->working_disks++; | ||
2044 | } | ||
2045 | } | ||
2046 | |||
2047 | conf->raid_disks = mddev->raid_disks; | ||
2048 | |||
2049 | /* | ||
2050 | * 0 for a fully functional array, 1 or 2 for a degraded array. | ||
2051 | */ | ||
2052 | mddev->degraded = conf->failed_disks = conf->raid_disks - conf->working_disks; | ||
2053 | conf->mddev = mddev; | ||
2054 | conf->chunk_size = mddev->chunk_size; | ||
2055 | conf->level = mddev->level; | ||
2056 | conf->algorithm = mddev->layout; | ||
2057 | conf->max_nr_stripes = NR_STRIPES; | ||
2058 | |||
2059 | /* device size must be a multiple of chunk size */ | ||
2060 | mddev->size &= ~(mddev->chunk_size/1024 -1); | ||
2061 | mddev->resync_max_sectors = mddev->size << 1; | ||
2062 | |||
2063 | if (conf->raid_disks < 4) { | ||
2064 | printk(KERN_ERR "raid6: not enough configured devices for %s (%d, minimum 4)\n", | ||
2065 | mdname(mddev), conf->raid_disks); | ||
2066 | goto abort; | ||
2067 | } | ||
2068 | if (!conf->chunk_size || conf->chunk_size % 4) { | ||
2069 | printk(KERN_ERR "raid6: invalid chunk size %d for %s\n", | ||
2070 | conf->chunk_size, mdname(mddev)); | ||
2071 | goto abort; | ||
2072 | } | ||
2073 | if (conf->algorithm > ALGORITHM_RIGHT_SYMMETRIC) { | ||
2074 | printk(KERN_ERR | ||
2075 | "raid6: unsupported parity algorithm %d for %s\n", | ||
2076 | conf->algorithm, mdname(mddev)); | ||
2077 | goto abort; | ||
2078 | } | ||
2079 | if (mddev->degraded > 2) { | ||
2080 | printk(KERN_ERR "raid6: not enough operational devices for %s" | ||
2081 | " (%d/%d failed)\n", | ||
2082 | mdname(mddev), conf->failed_disks, conf->raid_disks); | ||
2083 | goto abort; | ||
2084 | } | ||
2085 | |||
2086 | if (mddev->degraded > 0 && | ||
2087 | mddev->recovery_cp != MaxSector) { | ||
2088 | if (mddev->ok_start_degraded) | ||
2089 | printk(KERN_WARNING "raid6: starting dirty degraded array:%s" | ||
2090 | "- data corruption possible.\n", | ||
2091 | mdname(mddev)); | ||
2092 | else { | ||
2093 | printk(KERN_ERR "raid6: cannot start dirty degraded array" | ||
2094 | " for %s\n", mdname(mddev)); | ||
2095 | goto abort; | ||
2096 | } | ||
2097 | } | ||
2098 | |||
2099 | { | ||
2100 | mddev->thread = md_register_thread(raid6d, mddev, "%s_raid6"); | ||
2101 | if (!mddev->thread) { | ||
2102 | printk(KERN_ERR | ||
2103 | "raid6: couldn't allocate thread for %s\n", | ||
2104 | mdname(mddev)); | ||
2105 | goto abort; | ||
2106 | } | ||
2107 | } | ||
2108 | |||
2109 | memory = conf->max_nr_stripes * (sizeof(struct stripe_head) + | ||
2110 | conf->raid_disks * ((sizeof(struct bio) + PAGE_SIZE))) / 1024; | ||
2111 | if (grow_stripes(conf, conf->max_nr_stripes)) { | ||
2112 | printk(KERN_ERR | ||
2113 | "raid6: couldn't allocate %dkB for buffers\n", memory); | ||
2114 | shrink_stripes(conf); | ||
2115 | md_unregister_thread(mddev->thread); | ||
2116 | goto abort; | ||
2117 | } else | ||
2118 | printk(KERN_INFO "raid6: allocated %dkB for %s\n", | ||
2119 | memory, mdname(mddev)); | ||
2120 | |||
2121 | if (mddev->degraded == 0) | ||
2122 | printk(KERN_INFO "raid6: raid level %d set %s active with %d out of %d" | ||
2123 | " devices, algorithm %d\n", conf->level, mdname(mddev), | ||
2124 | mddev->raid_disks-mddev->degraded, mddev->raid_disks, | ||
2125 | conf->algorithm); | ||
2126 | else | ||
2127 | printk(KERN_ALERT "raid6: raid level %d set %s active with %d" | ||
2128 | " out of %d devices, algorithm %d\n", conf->level, | ||
2129 | mdname(mddev), mddev->raid_disks - mddev->degraded, | ||
2130 | mddev->raid_disks, conf->algorithm); | ||
2131 | |||
2132 | print_raid6_conf(conf); | ||
2133 | |||
2134 | /* read-ahead size must cover two whole stripes, which is | ||
2135 | * 2 * (n-2) * chunksize where 'n' is the number of raid devices | ||
2136 | */ | ||
2137 | { | ||
2138 | int stripe = (mddev->raid_disks-2) * mddev->chunk_size | ||
2139 | / PAGE_SIZE; | ||
2140 | if (mddev->queue->backing_dev_info.ra_pages < 2 * stripe) | ||
2141 | mddev->queue->backing_dev_info.ra_pages = 2 * stripe; | ||
2142 | } | ||
2143 | |||
2144 | /* Ok, everything is just fine now */ | ||
2145 | sysfs_create_group(&mddev->kobj, &raid6_attrs_group); | ||
2146 | |||
2147 | mddev->array_size = mddev->size * (mddev->raid_disks - 2); | ||
2148 | |||
2149 | mddev->queue->unplug_fn = raid6_unplug_device; | ||
2150 | mddev->queue->issue_flush_fn = raid6_issue_flush; | ||
2151 | return 0; | ||
2152 | abort: | ||
2153 | if (conf) { | ||
2154 | print_raid6_conf(conf); | ||
2155 | safe_put_page(conf->spare_page); | ||
2156 | kfree(conf->stripe_hashtbl); | ||
2157 | kfree(conf->disks); | ||
2158 | kfree(conf); | ||
2159 | } | ||
2160 | mddev->private = NULL; | ||
2161 | printk(KERN_ALERT "raid6: failed to run raid set %s\n", mdname(mddev)); | ||
2162 | return -EIO; | ||
2163 | } | ||
2164 | |||
2165 | |||
2166 | |||
2167 | static int stop (mddev_t *mddev) | ||
2168 | { | ||
2169 | raid6_conf_t *conf = (raid6_conf_t *) mddev->private; | ||
2170 | |||
2171 | md_unregister_thread(mddev->thread); | ||
2172 | mddev->thread = NULL; | ||
2173 | shrink_stripes(conf); | ||
2174 | kfree(conf->stripe_hashtbl); | ||
2175 | blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/ | ||
2176 | sysfs_remove_group(&mddev->kobj, &raid6_attrs_group); | ||
2177 | kfree(conf); | ||
2178 | mddev->private = NULL; | ||
2179 | return 0; | ||
2180 | } | ||
2181 | |||
2182 | #if RAID6_DUMPSTATE | ||
2183 | static void print_sh (struct seq_file *seq, struct stripe_head *sh) | ||
2184 | { | ||
2185 | int i; | ||
2186 | |||
2187 | seq_printf(seq, "sh %llu, pd_idx %d, state %ld.\n", | ||
2188 | (unsigned long long)sh->sector, sh->pd_idx, sh->state); | ||
2189 | seq_printf(seq, "sh %llu, count %d.\n", | ||
2190 | (unsigned long long)sh->sector, atomic_read(&sh->count)); | ||
2191 | seq_printf(seq, "sh %llu, ", (unsigned long long)sh->sector); | ||
2192 | for (i = 0; i < sh->raid_conf->raid_disks; i++) { | ||
2193 | seq_printf(seq, "(cache%d: %p %ld) ", | ||
2194 | i, sh->dev[i].page, sh->dev[i].flags); | ||
2195 | } | ||
2196 | seq_printf(seq, "\n"); | ||
2197 | } | ||
2198 | |||
2199 | static void printall (struct seq_file *seq, raid6_conf_t *conf) | ||
2200 | { | ||
2201 | struct stripe_head *sh; | ||
2202 | struct hlist_node *hn; | ||
2203 | int i; | ||
2204 | |||
2205 | spin_lock_irq(&conf->device_lock); | ||
2206 | for (i = 0; i < NR_HASH; i++) { | ||
2207 | sh = conf->stripe_hashtbl[i]; | ||
2208 | hlist_for_each_entry(sh, hn, &conf->stripe_hashtbl[i], hash) { | ||
2209 | if (sh->raid_conf != conf) | ||
2210 | continue; | ||
2211 | print_sh(seq, sh); | ||
2212 | } | ||
2213 | } | ||
2214 | spin_unlock_irq(&conf->device_lock); | ||
2215 | } | ||
2216 | #endif | ||
2217 | |||
2218 | static void status (struct seq_file *seq, mddev_t *mddev) | ||
2219 | { | ||
2220 | raid6_conf_t *conf = (raid6_conf_t *) mddev->private; | ||
2221 | int i; | ||
2222 | |||
2223 | seq_printf (seq, " level %d, %dk chunk, algorithm %d", mddev->level, mddev->chunk_size >> 10, mddev->layout); | ||
2224 | seq_printf (seq, " [%d/%d] [", conf->raid_disks, conf->working_disks); | ||
2225 | for (i = 0; i < conf->raid_disks; i++) | ||
2226 | seq_printf (seq, "%s", | ||
2227 | conf->disks[i].rdev && | ||
2228 | test_bit(In_sync, &conf->disks[i].rdev->flags) ? "U" : "_"); | ||
2229 | seq_printf (seq, "]"); | ||
2230 | #if RAID6_DUMPSTATE | ||
2231 | seq_printf (seq, "\n"); | ||
2232 | printall(seq, conf); | ||
2233 | #endif | ||
2234 | } | ||
2235 | |||
2236 | static void print_raid6_conf (raid6_conf_t *conf) | ||
2237 | { | ||
2238 | int i; | ||
2239 | struct disk_info *tmp; | ||
2240 | |||
2241 | printk("RAID6 conf printout:\n"); | ||
2242 | if (!conf) { | ||
2243 | printk("(conf==NULL)\n"); | ||
2244 | return; | ||
2245 | } | ||
2246 | printk(" --- rd:%d wd:%d fd:%d\n", conf->raid_disks, | ||
2247 | conf->working_disks, conf->failed_disks); | ||
2248 | |||
2249 | for (i = 0; i < conf->raid_disks; i++) { | ||
2250 | char b[BDEVNAME_SIZE]; | ||
2251 | tmp = conf->disks + i; | ||
2252 | if (tmp->rdev) | ||
2253 | printk(" disk %d, o:%d, dev:%s\n", | ||
2254 | i, !test_bit(Faulty, &tmp->rdev->flags), | ||
2255 | bdevname(tmp->rdev->bdev,b)); | ||
2256 | } | ||
2257 | } | ||
2258 | |||
2259 | static int raid6_spare_active(mddev_t *mddev) | ||
2260 | { | ||
2261 | int i; | ||
2262 | raid6_conf_t *conf = mddev->private; | ||
2263 | struct disk_info *tmp; | ||
2264 | |||
2265 | for (i = 0; i < conf->raid_disks; i++) { | ||
2266 | tmp = conf->disks + i; | ||
2267 | if (tmp->rdev | ||
2268 | && !test_bit(Faulty, &tmp->rdev->flags) | ||
2269 | && !test_bit(In_sync, &tmp->rdev->flags)) { | ||
2270 | mddev->degraded--; | ||
2271 | conf->failed_disks--; | ||
2272 | conf->working_disks++; | ||
2273 | set_bit(In_sync, &tmp->rdev->flags); | ||
2274 | } | ||
2275 | } | ||
2276 | print_raid6_conf(conf); | ||
2277 | return 0; | ||
2278 | } | ||
2279 | |||
2280 | static int raid6_remove_disk(mddev_t *mddev, int number) | ||
2281 | { | ||
2282 | raid6_conf_t *conf = mddev->private; | ||
2283 | int err = 0; | ||
2284 | mdk_rdev_t *rdev; | ||
2285 | struct disk_info *p = conf->disks + number; | ||
2286 | |||
2287 | print_raid6_conf(conf); | ||
2288 | rdev = p->rdev; | ||
2289 | if (rdev) { | ||
2290 | if (test_bit(In_sync, &rdev->flags) || | ||
2291 | atomic_read(&rdev->nr_pending)) { | ||
2292 | err = -EBUSY; | ||
2293 | goto abort; | ||
2294 | } | ||
2295 | p->rdev = NULL; | ||
2296 | synchronize_rcu(); | ||
2297 | if (atomic_read(&rdev->nr_pending)) { | ||
2298 | /* lost the race, try later */ | ||
2299 | err = -EBUSY; | ||
2300 | p->rdev = rdev; | ||
2301 | } | ||
2302 | } | ||
2303 | |||
2304 | abort: | ||
2305 | |||
2306 | print_raid6_conf(conf); | ||
2307 | return err; | ||
2308 | } | ||
2309 | |||
2310 | static int raid6_add_disk(mddev_t *mddev, mdk_rdev_t *rdev) | ||
2311 | { | ||
2312 | raid6_conf_t *conf = mddev->private; | ||
2313 | int found = 0; | ||
2314 | int disk; | ||
2315 | struct disk_info *p; | ||
2316 | |||
2317 | if (mddev->degraded > 2) | ||
2318 | /* no point adding a device */ | ||
2319 | return 0; | ||
2320 | /* | ||
2321 | * find the disk ... but prefer rdev->saved_raid_disk | ||
2322 | * if possible. | ||
2323 | */ | ||
2324 | if (rdev->saved_raid_disk >= 0 && | ||
2325 | conf->disks[rdev->saved_raid_disk].rdev == NULL) | ||
2326 | disk = rdev->saved_raid_disk; | ||
2327 | else | ||
2328 | disk = 0; | ||
2329 | for ( ; disk < mddev->raid_disks; disk++) | ||
2330 | if ((p=conf->disks + disk)->rdev == NULL) { | ||
2331 | clear_bit(In_sync, &rdev->flags); | ||
2332 | rdev->raid_disk = disk; | ||
2333 | found = 1; | ||
2334 | if (rdev->saved_raid_disk != disk) | ||
2335 | conf->fullsync = 1; | ||
2336 | rcu_assign_pointer(p->rdev, rdev); | ||
2337 | break; | ||
2338 | } | ||
2339 | print_raid6_conf(conf); | ||
2340 | return found; | ||
2341 | } | ||
2342 | |||
2343 | static int raid6_resize(mddev_t *mddev, sector_t sectors) | ||
2344 | { | ||
2345 | /* no resync is happening, and there is enough space | ||
2346 | * on all devices, so we can resize. | ||
2347 | * We need to make sure resync covers any new space. | ||
2348 | * If the array is shrinking we should possibly wait until | ||
2349 | * any io in the removed space completes, but it hardly seems | ||
2350 | * worth it. | ||
2351 | */ | ||
2352 | sectors &= ~((sector_t)mddev->chunk_size/512 - 1); | ||
2353 | mddev->array_size = (sectors * (mddev->raid_disks-2))>>1; | ||
2354 | set_capacity(mddev->gendisk, mddev->array_size << 1); | ||
2355 | mddev->changed = 1; | ||
2356 | if (sectors/2 > mddev->size && mddev->recovery_cp == MaxSector) { | ||
2357 | mddev->recovery_cp = mddev->size << 1; | ||
2358 | set_bit(MD_RECOVERY_NEEDED, &mddev->recovery); | ||
2359 | } | ||
2360 | mddev->size = sectors /2; | ||
2361 | mddev->resync_max_sectors = sectors; | ||
2362 | return 0; | ||
2363 | } | ||
2364 | |||
2365 | static void raid6_quiesce(mddev_t *mddev, int state) | ||
2366 | { | ||
2367 | raid6_conf_t *conf = mddev_to_conf(mddev); | ||
2368 | |||
2369 | switch(state) { | ||
2370 | case 1: /* stop all writes */ | ||
2371 | spin_lock_irq(&conf->device_lock); | ||
2372 | conf->quiesce = 1; | ||
2373 | wait_event_lock_irq(conf->wait_for_stripe, | ||
2374 | atomic_read(&conf->active_stripes) == 0, | ||
2375 | conf->device_lock, /* nothing */); | ||
2376 | spin_unlock_irq(&conf->device_lock); | ||
2377 | break; | ||
2378 | |||
2379 | case 0: /* re-enable writes */ | ||
2380 | spin_lock_irq(&conf->device_lock); | ||
2381 | conf->quiesce = 0; | ||
2382 | wake_up(&conf->wait_for_stripe); | ||
2383 | spin_unlock_irq(&conf->device_lock); | ||
2384 | break; | ||
2385 | } | ||
2386 | } | ||
2387 | |||
2388 | static struct mdk_personality raid6_personality = | ||
2389 | { | ||
2390 | .name = "raid6", | ||
2391 | .level = 6, | ||
2392 | .owner = THIS_MODULE, | ||
2393 | .make_request = make_request, | ||
2394 | .run = run, | ||
2395 | .stop = stop, | ||
2396 | .status = status, | ||
2397 | .error_handler = error, | ||
2398 | .hot_add_disk = raid6_add_disk, | ||
2399 | .hot_remove_disk= raid6_remove_disk, | ||
2400 | .spare_active = raid6_spare_active, | ||
2401 | .sync_request = sync_request, | ||
2402 | .resize = raid6_resize, | ||
2403 | .quiesce = raid6_quiesce, | ||
2404 | }; | ||
2405 | |||
2406 | static int __init raid6_init(void) | ||
2407 | { | ||
2408 | int e; | ||
2409 | |||
2410 | e = raid6_select_algo(); | ||
2411 | if ( e ) | ||
2412 | return e; | ||
2413 | |||
2414 | return register_md_personality(&raid6_personality); | ||
2415 | } | ||
2416 | |||
2417 | static void raid6_exit (void) | ||
2418 | { | ||
2419 | unregister_md_personality(&raid6_personality); | ||
2420 | } | ||
2421 | |||
2422 | module_init(raid6_init); | ||
2423 | module_exit(raid6_exit); | ||
2424 | MODULE_LICENSE("GPL"); | ||
2425 | MODULE_ALIAS("md-personality-8"); /* RAID6 */ | ||
2426 | MODULE_ALIAS("md-raid6"); | ||
2427 | MODULE_ALIAS("md-level-6"); | ||
diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index 583d151b7486..ef52e6da01ed 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig | |||
@@ -82,9 +82,6 @@ config VIDEO_IR | |||
82 | config VIDEO_TVEEPROM | 82 | config VIDEO_TVEEPROM |
83 | tristate | 83 | tristate |
84 | 84 | ||
85 | config VIDEO_CX2341X | ||
86 | tristate | ||
87 | |||
88 | config USB_DABUSB | 85 | config USB_DABUSB |
89 | tristate "DABUSB driver" | 86 | tristate "DABUSB driver" |
90 | depends on USB | 87 | depends on USB |
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index 3152a54a2539..5e8bb41a088b 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c | |||
@@ -556,22 +556,23 @@ static int dvb_frontend_thread(void *data) | |||
556 | } | 556 | } |
557 | 557 | ||
558 | /* do an iteration of the tuning loop */ | 558 | /* do an iteration of the tuning loop */ |
559 | if (fe->ops.get_frontend_algo(fe) == FE_ALGO_HW) { | 559 | if (fe->ops.get_frontend_algo) { |
560 | /* have we been asked to retune? */ | 560 | if (fe->ops.get_frontend_algo(fe) == FE_ALGO_HW) { |
561 | params = NULL; | 561 | /* have we been asked to retune? */ |
562 | if (fepriv->state & FESTATE_RETUNE) { | 562 | params = NULL; |
563 | params = &fepriv->parameters; | 563 | if (fepriv->state & FESTATE_RETUNE) { |
564 | fepriv->state = FESTATE_TUNED; | 564 | params = &fepriv->parameters; |
565 | } | 565 | fepriv->state = FESTATE_TUNED; |
566 | } | ||
566 | 567 | ||
567 | fe->ops.tune(fe, params, fepriv->tune_mode_flags, &fepriv->delay, &s); | 568 | fe->ops.tune(fe, params, fepriv->tune_mode_flags, &fepriv->delay, &s); |
568 | if (s != fepriv->status) { | 569 | if (s != fepriv->status) { |
569 | dvb_frontend_add_event(fe, s); | 570 | dvb_frontend_add_event(fe, s); |
570 | fepriv->status = s; | 571 | fepriv->status = s; |
572 | } | ||
571 | } | 573 | } |
572 | } else { | 574 | } else |
573 | dvb_frontend_swzigzag(fe); | 575 | dvb_frontend_swzigzag(fe); |
574 | } | ||
575 | } | 576 | } |
576 | 577 | ||
577 | if (dvb_shutdown_timeout) { | 578 | if (dvb_shutdown_timeout) { |
diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c index 8832f80c05f7..7a5c99c200e8 100644 --- a/drivers/media/dvb/ttpci/av7110.c +++ b/drivers/media/dvb/ttpci/av7110.c | |||
@@ -152,13 +152,9 @@ static void init_av7110_av(struct av7110 *av7110) | |||
152 | /* remaining inits according to card and frontend type */ | 152 | /* remaining inits according to card and frontend type */ |
153 | av7110->analog_tuner_flags = 0; | 153 | av7110->analog_tuner_flags = 0; |
154 | av7110->current_input = 0; | 154 | av7110->current_input = 0; |
155 | if (dev->pci->subsystem_vendor == 0x13c2 && dev->pci->subsystem_device == 0x000a) { | 155 | if (dev->pci->subsystem_vendor == 0x13c2 && dev->pci->subsystem_device == 0x000a) |
156 | printk("dvb-ttpci: MSP3415 audio DAC @ card %d\n", | ||
157 | av7110->dvb_adapter.num); | ||
158 | av7110->adac_type = DVB_ADAC_MSP34x5; | ||
159 | av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, ADSwitch, 1, 0); // SPDIF on | 156 | av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, ADSwitch, 1, 0); // SPDIF on |
160 | } | 157 | if (i2c_writereg(av7110, 0x20, 0x00, 0x00) == 1) { |
161 | else if (i2c_writereg(av7110, 0x20, 0x00, 0x00) == 1) { | ||
162 | printk ("dvb-ttpci: Crystal audio DAC @ card %d detected\n", | 158 | printk ("dvb-ttpci: Crystal audio DAC @ card %d detected\n", |
163 | av7110->dvb_adapter.num); | 159 | av7110->dvb_adapter.num); |
164 | av7110->adac_type = DVB_ADAC_CRYSTAL; | 160 | av7110->adac_type = DVB_ADAC_CRYSTAL; |
diff --git a/drivers/media/dvb/ttpci/av7110_av.c b/drivers/media/dvb/ttpci/av7110_av.c index 2eff09f638d3..0f3a044aeb17 100644 --- a/drivers/media/dvb/ttpci/av7110_av.c +++ b/drivers/media/dvb/ttpci/av7110_av.c | |||
@@ -318,7 +318,17 @@ int av7110_set_volume(struct av7110 *av7110, int volleft, int volright) | |||
318 | msp_writereg(av7110, MSP_WR_DSP, 0x0000, val); /* loudspeaker */ | 318 | msp_writereg(av7110, MSP_WR_DSP, 0x0000, val); /* loudspeaker */ |
319 | msp_writereg(av7110, MSP_WR_DSP, 0x0006, val); /* headphonesr */ | 319 | msp_writereg(av7110, MSP_WR_DSP, 0x0006, val); /* headphonesr */ |
320 | return 0; | 320 | return 0; |
321 | |||
322 | case DVB_ADAC_MSP34x5: | ||
323 | vol = (volleft > volright) ? volleft : volright; | ||
324 | val = (vol * 0x73 / 255) << 8; | ||
325 | if (vol > 0) | ||
326 | balance = ((volright - volleft) * 127) / vol; | ||
327 | msp_writereg(av7110, MSP_WR_DSP, 0x0001, balance << 8); | ||
328 | msp_writereg(av7110, MSP_WR_DSP, 0x0000, val); /* loudspeaker */ | ||
329 | return 0; | ||
321 | } | 330 | } |
331 | |||
322 | return 0; | 332 | return 0; |
323 | } | 333 | } |
324 | 334 | ||
@@ -1267,23 +1277,32 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file, | |||
1267 | switch(av7110->audiostate.channel_select) { | 1277 | switch(av7110->audiostate.channel_select) { |
1268 | case AUDIO_STEREO: | 1278 | case AUDIO_STEREO: |
1269 | ret = audcom(av7110, AUDIO_CMD_STEREO); | 1279 | ret = audcom(av7110, AUDIO_CMD_STEREO); |
1270 | if (!ret) | 1280 | if (!ret) { |
1271 | if (av7110->adac_type == DVB_ADAC_CRYSTAL) | 1281 | if (av7110->adac_type == DVB_ADAC_CRYSTAL) |
1272 | i2c_writereg(av7110, 0x20, 0x02, 0x49); | 1282 | i2c_writereg(av7110, 0x20, 0x02, 0x49); |
1283 | else if (av7110->adac_type == DVB_ADAC_MSP34x5) | ||
1284 | msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0220); | ||
1285 | } | ||
1273 | break; | 1286 | break; |
1274 | 1287 | ||
1275 | case AUDIO_MONO_LEFT: | 1288 | case AUDIO_MONO_LEFT: |
1276 | ret = audcom(av7110, AUDIO_CMD_MONO_L); | 1289 | ret = audcom(av7110, AUDIO_CMD_MONO_L); |
1277 | if (!ret) | 1290 | if (!ret) { |
1278 | if (av7110->adac_type == DVB_ADAC_CRYSTAL) | 1291 | if (av7110->adac_type == DVB_ADAC_CRYSTAL) |
1279 | i2c_writereg(av7110, 0x20, 0x02, 0x4a); | 1292 | i2c_writereg(av7110, 0x20, 0x02, 0x4a); |
1293 | else if (av7110->adac_type == DVB_ADAC_MSP34x5) | ||
1294 | msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0200); | ||
1295 | } | ||
1280 | break; | 1296 | break; |
1281 | 1297 | ||
1282 | case AUDIO_MONO_RIGHT: | 1298 | case AUDIO_MONO_RIGHT: |
1283 | ret = audcom(av7110, AUDIO_CMD_MONO_R); | 1299 | ret = audcom(av7110, AUDIO_CMD_MONO_R); |
1284 | if (!ret) | 1300 | if (!ret) { |
1285 | if (av7110->adac_type == DVB_ADAC_CRYSTAL) | 1301 | if (av7110->adac_type == DVB_ADAC_CRYSTAL) |
1286 | i2c_writereg(av7110, 0x20, 0x02, 0x45); | 1302 | i2c_writereg(av7110, 0x20, 0x02, 0x45); |
1303 | else if (av7110->adac_type == DVB_ADAC_MSP34x5) | ||
1304 | msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0210); | ||
1305 | } | ||
1287 | break; | 1306 | break; |
1288 | 1307 | ||
1289 | default: | 1308 | default: |
diff --git a/drivers/media/dvb/ttpci/av7110_v4l.c b/drivers/media/dvb/ttpci/av7110_v4l.c index 603a22e4bfe2..64055461559d 100644 --- a/drivers/media/dvb/ttpci/av7110_v4l.c +++ b/drivers/media/dvb/ttpci/av7110_v4l.c | |||
@@ -42,7 +42,18 @@ | |||
42 | int msp_writereg(struct av7110 *av7110, u8 dev, u16 reg, u16 val) | 42 | int msp_writereg(struct av7110 *av7110, u8 dev, u16 reg, u16 val) |
43 | { | 43 | { |
44 | u8 msg[5] = { dev, reg >> 8, reg & 0xff, val >> 8 , val & 0xff }; | 44 | u8 msg[5] = { dev, reg >> 8, reg & 0xff, val >> 8 , val & 0xff }; |
45 | struct i2c_msg msgs = { .flags = 0, .addr = 0x40, .len = 5, .buf = msg }; | 45 | struct i2c_msg msgs = { .flags = 0, .len = 5, .buf = msg }; |
46 | |||
47 | switch (av7110->adac_type) { | ||
48 | case DVB_ADAC_MSP34x0: | ||
49 | msgs.addr = 0x40; | ||
50 | break; | ||
51 | case DVB_ADAC_MSP34x5: | ||
52 | msgs.addr = 0x42; | ||
53 | break; | ||
54 | default: | ||
55 | return 0; | ||
56 | } | ||
46 | 57 | ||
47 | if (i2c_transfer(&av7110->i2c_adap, &msgs, 1) != 1) { | 58 | if (i2c_transfer(&av7110->i2c_adap, &msgs, 1) != 1) { |
48 | dprintk(1, "dvb-ttpci: failed @ card %d, %u = %u\n", | 59 | dprintk(1, "dvb-ttpci: failed @ card %d, %u = %u\n", |
@@ -57,10 +68,23 @@ static int msp_readreg(struct av7110 *av7110, u8 dev, u16 reg, u16 *val) | |||
57 | u8 msg1[3] = { dev, reg >> 8, reg & 0xff }; | 68 | u8 msg1[3] = { dev, reg >> 8, reg & 0xff }; |
58 | u8 msg2[2]; | 69 | u8 msg2[2]; |
59 | struct i2c_msg msgs[2] = { | 70 | struct i2c_msg msgs[2] = { |
60 | { .flags = 0, .addr = 0x40, .len = 3, .buf = msg1 }, | 71 | { .flags = 0 , .len = 3, .buf = msg1 }, |
61 | { .flags = I2C_M_RD, .addr = 0x40, .len = 2, .buf = msg2 } | 72 | { .flags = I2C_M_RD, .len = 2, .buf = msg2 } |
62 | }; | 73 | }; |
63 | 74 | ||
75 | switch (av7110->adac_type) { | ||
76 | case DVB_ADAC_MSP34x0: | ||
77 | msgs[0].addr = 0x40; | ||
78 | msgs[1].addr = 0x40; | ||
79 | break; | ||
80 | case DVB_ADAC_MSP34x5: | ||
81 | msgs[0].addr = 0x42; | ||
82 | msgs[1].addr = 0x42; | ||
83 | break; | ||
84 | default: | ||
85 | return 0; | ||
86 | } | ||
87 | |||
64 | if (i2c_transfer(&av7110->i2c_adap, &msgs[0], 2) != 2) { | 88 | if (i2c_transfer(&av7110->i2c_adap, &msgs[0], 2) != 2) { |
65 | dprintk(1, "dvb-ttpci: failed @ card %d, %u\n", | 89 | dprintk(1, "dvb-ttpci: failed @ card %d, %u\n", |
66 | av7110->dvb_adapter.num, reg); | 90 | av7110->dvb_adapter.num, reg); |
@@ -678,17 +702,23 @@ int av7110_init_analog_module(struct av7110 *av7110) | |||
678 | { | 702 | { |
679 | u16 version1, version2; | 703 | u16 version1, version2; |
680 | 704 | ||
681 | if (i2c_writereg(av7110, 0x80, 0x0, 0x80) != 1 | 705 | if (i2c_writereg(av7110, 0x80, 0x0, 0x80) == 1 && |
682 | || i2c_writereg(av7110, 0x80, 0x0, 0) != 1) | 706 | i2c_writereg(av7110, 0x80, 0x0, 0) == 1) { |
707 | printk("dvb-ttpci: DVB-C analog module @ card %d detected, initializing MSP3400\n", | ||
708 | av7110->dvb_adapter.num); | ||
709 | av7110->adac_type = DVB_ADAC_MSP34x0; | ||
710 | } else if (i2c_writereg(av7110, 0x84, 0x0, 0x80) == 1 && | ||
711 | i2c_writereg(av7110, 0x84, 0x0, 0) == 1) { | ||
712 | printk("dvb-ttpci: DVB-C analog module @ card %d detected, initializing MSP3415\n", | ||
713 | av7110->dvb_adapter.num); | ||
714 | av7110->adac_type = DVB_ADAC_MSP34x5; | ||
715 | } else | ||
683 | return -ENODEV; | 716 | return -ENODEV; |
684 | 717 | ||
685 | printk("dvb-ttpci: DVB-C analog module @ card %d detected, initializing MSP3400\n", | ||
686 | av7110->dvb_adapter.num); | ||
687 | av7110->adac_type = DVB_ADAC_MSP34x0; | ||
688 | msleep(100); // the probing above resets the msp... | 718 | msleep(100); // the probing above resets the msp... |
689 | msp_readreg(av7110, MSP_RD_DSP, 0x001e, &version1); | 719 | msp_readreg(av7110, MSP_RD_DSP, 0x001e, &version1); |
690 | msp_readreg(av7110, MSP_RD_DSP, 0x001f, &version2); | 720 | msp_readreg(av7110, MSP_RD_DSP, 0x001f, &version2); |
691 | dprintk(1, "dvb-ttpci: @ card %d MSP3400 version 0x%04x 0x%04x\n", | 721 | dprintk(1, "dvb-ttpci: @ card %d MSP34xx version 0x%04x 0x%04x\n", |
692 | av7110->dvb_adapter.num, version1, version2); | 722 | av7110->dvb_adapter.num, version1, version2); |
693 | msp_writereg(av7110, MSP_WR_DSP, 0x0013, 0x0c00); | 723 | msp_writereg(av7110, MSP_WR_DSP, 0x0013, 0x0c00); |
694 | msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0x7f00); // loudspeaker + headphone | 724 | msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0x7f00); // loudspeaker + headphone |
@@ -697,7 +727,7 @@ int av7110_init_analog_module(struct av7110 *av7110) | |||
697 | msp_writereg(av7110, MSP_WR_DSP, 0x0004, 0x7f00); // loudspeaker volume | 727 | msp_writereg(av7110, MSP_WR_DSP, 0x0004, 0x7f00); // loudspeaker volume |
698 | msp_writereg(av7110, MSP_WR_DSP, 0x000a, 0x0220); // SCART 1 source | 728 | msp_writereg(av7110, MSP_WR_DSP, 0x000a, 0x0220); // SCART 1 source |
699 | msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0x7f00); // SCART 1 volume | 729 | msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0x7f00); // SCART 1 volume |
700 | msp_writereg(av7110, MSP_WR_DSP, 0x000d, 0x4800); // prescale SCART | 730 | msp_writereg(av7110, MSP_WR_DSP, 0x000d, 0x1900); // prescale SCART |
701 | 731 | ||
702 | if (i2c_writereg(av7110, 0x48, 0x01, 0x00)!=1) { | 732 | if (i2c_writereg(av7110, 0x48, 0x01, 0x00)!=1) { |
703 | INFO(("saa7113 not accessible.\n")); | 733 | INFO(("saa7113 not accessible.\n")); |
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 824a63c92629..e4290491fa9e 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig | |||
@@ -381,6 +381,18 @@ config VIDEO_WM8739 | |||
381 | To compile this driver as a module, choose M here: the | 381 | To compile this driver as a module, choose M here: the |
382 | module will be called wm8739. | 382 | module will be called wm8739. |
383 | 383 | ||
384 | config VIDEO_CX2341X | ||
385 | tristate "Conexant CX2341x MPEG encoders" | ||
386 | depends on VIDEO_V4L2 && EXPERIMENTAL | ||
387 | ---help--- | ||
388 | Support for the Conexant CX23416 MPEG encoders | ||
389 | and CX23415 MPEG encoder/decoders. | ||
390 | |||
391 | This module currently supports the encoding functions only. | ||
392 | |||
393 | To compile this driver as a module, choose M here: the | ||
394 | module will be called cx2341x. | ||
395 | |||
384 | source "drivers/media/video/cx25840/Kconfig" | 396 | source "drivers/media/video/cx25840/Kconfig" |
385 | 397 | ||
386 | config VIDEO_SAA711X | 398 | config VIDEO_SAA711X |
diff --git a/drivers/media/video/cx2341x.c b/drivers/media/video/cx2341x.c index 554813e6f65d..01b22eab5725 100644 --- a/drivers/media/video/cx2341x.c +++ b/drivers/media/video/cx2341x.c | |||
@@ -43,6 +43,7 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)"); | |||
43 | const u32 cx2341x_mpeg_ctrls[] = { | 43 | const u32 cx2341x_mpeg_ctrls[] = { |
44 | V4L2_CID_MPEG_CLASS, | 44 | V4L2_CID_MPEG_CLASS, |
45 | V4L2_CID_MPEG_STREAM_TYPE, | 45 | V4L2_CID_MPEG_STREAM_TYPE, |
46 | V4L2_CID_MPEG_STREAM_VBI_FMT, | ||
46 | V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ, | 47 | V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ, |
47 | V4L2_CID_MPEG_AUDIO_ENCODING, | 48 | V4L2_CID_MPEG_AUDIO_ENCODING, |
48 | V4L2_CID_MPEG_AUDIO_L2_BITRATE, | 49 | V4L2_CID_MPEG_AUDIO_L2_BITRATE, |
@@ -135,6 +136,9 @@ static int cx2341x_get_ctrl(struct cx2341x_mpeg_params *params, | |||
135 | case V4L2_CID_MPEG_STREAM_TYPE: | 136 | case V4L2_CID_MPEG_STREAM_TYPE: |
136 | ctrl->value = params->stream_type; | 137 | ctrl->value = params->stream_type; |
137 | break; | 138 | break; |
139 | case V4L2_CID_MPEG_STREAM_VBI_FMT: | ||
140 | ctrl->value = params->stream_vbi_fmt; | ||
141 | break; | ||
138 | case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE: | 142 | case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE: |
139 | ctrl->value = params->video_spatial_filter_mode; | 143 | ctrl->value = params->video_spatial_filter_mode; |
140 | break; | 144 | break; |
@@ -257,6 +261,9 @@ static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params, | |||
257 | params->video_bitrate_mode = V4L2_MPEG_VIDEO_BITRATE_MODE_CBR; | 261 | params->video_bitrate_mode = V4L2_MPEG_VIDEO_BITRATE_MODE_CBR; |
258 | } | 262 | } |
259 | break; | 263 | break; |
264 | case V4L2_CID_MPEG_STREAM_VBI_FMT: | ||
265 | params->stream_vbi_fmt = ctrl->value; | ||
266 | break; | ||
260 | case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE: | 267 | case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE: |
261 | params->video_spatial_filter_mode = ctrl->value; | 268 | params->video_spatial_filter_mode = ctrl->value; |
262 | break; | 269 | break; |
@@ -418,6 +425,14 @@ int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params, struct v4l2_queryctrl | |||
418 | qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; | 425 | qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; |
419 | return err; | 426 | return err; |
420 | 427 | ||
428 | case V4L2_CID_MPEG_STREAM_VBI_FMT: | ||
429 | if (params->capabilities & CX2341X_CAP_HAS_SLICED_VBI) | ||
430 | return v4l2_ctrl_query_fill_std(qctrl); | ||
431 | return cx2341x_ctrl_query_fill(qctrl, | ||
432 | V4L2_MPEG_STREAM_VBI_FMT_NONE, | ||
433 | V4L2_MPEG_STREAM_VBI_FMT_NONE, 1, | ||
434 | V4L2_MPEG_STREAM_VBI_FMT_NONE); | ||
435 | |||
421 | /* CX23415/6 specific */ | 436 | /* CX23415/6 specific */ |
422 | case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE: | 437 | case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE: |
423 | return cx2341x_ctrl_query_fill(qctrl, | 438 | return cx2341x_ctrl_query_fill(qctrl, |
@@ -639,6 +654,7 @@ void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p) | |||
639 | { | 654 | { |
640 | static struct cx2341x_mpeg_params default_params = { | 655 | static struct cx2341x_mpeg_params default_params = { |
641 | /* misc */ | 656 | /* misc */ |
657 | .capabilities = 0, | ||
642 | .port = CX2341X_PORT_MEMORY, | 658 | .port = CX2341X_PORT_MEMORY, |
643 | .width = 720, | 659 | .width = 720, |
644 | .height = 480, | 660 | .height = 480, |
@@ -646,6 +662,7 @@ void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p) | |||
646 | 662 | ||
647 | /* stream */ | 663 | /* stream */ |
648 | .stream_type = V4L2_MPEG_STREAM_TYPE_MPEG2_PS, | 664 | .stream_type = V4L2_MPEG_STREAM_TYPE_MPEG2_PS, |
665 | .stream_vbi_fmt = V4L2_MPEG_STREAM_VBI_FMT_NONE, | ||
649 | 666 | ||
650 | /* audio */ | 667 | /* audio */ |
651 | .audio_sampling_freq = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000, | 668 | .audio_sampling_freq = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000, |
diff --git a/drivers/media/video/cx88/Kconfig b/drivers/media/video/cx88/Kconfig index 91e1c481a164..80e23ee9801c 100644 --- a/drivers/media/video/cx88/Kconfig +++ b/drivers/media/video/cx88/Kconfig | |||
@@ -11,7 +11,6 @@ config VIDEO_CX88 | |||
11 | select VIDEO_BUF | 11 | select VIDEO_BUF |
12 | select VIDEO_TUNER | 12 | select VIDEO_TUNER |
13 | select VIDEO_TVEEPROM | 13 | select VIDEO_TVEEPROM |
14 | select VIDEO_CX2341X | ||
15 | select VIDEO_IR | 14 | select VIDEO_IR |
16 | ---help--- | 15 | ---help--- |
17 | This is a video4linux driver for Conexant 2388x based | 16 | This is a video4linux driver for Conexant 2388x based |
@@ -36,13 +35,25 @@ config VIDEO_CX88_ALSA | |||
36 | To compile this driver as a module, choose M here: the | 35 | To compile this driver as a module, choose M here: the |
37 | module will be called cx88-alsa. | 36 | module will be called cx88-alsa. |
38 | 37 | ||
38 | config VIDEO_CX88_BLACKBIRD | ||
39 | tristate "Blackbird MPEG encoder support (cx2388x + cx23416)" | ||
40 | depends on VIDEO_CX88 | ||
41 | select VIDEO_CX2341X | ||
42 | ---help--- | ||
43 | This adds support for MPEG encoder cards based on the | ||
44 | Blackbird reference design, using the Conexant 2388x | ||
45 | and 23416 chips. | ||
46 | |||
47 | To compile this driver as a module, choose M here: the | ||
48 | module will be called cx88-blackbird. | ||
49 | |||
39 | config VIDEO_CX88_DVB | 50 | config VIDEO_CX88_DVB |
40 | tristate "DVB/ATSC Support for cx2388x based TV cards" | 51 | tristate "DVB/ATSC Support for cx2388x based TV cards" |
41 | depends on VIDEO_CX88 && DVB_CORE | 52 | depends on VIDEO_CX88 && DVB_CORE |
42 | select VIDEO_BUF_DVB | 53 | select VIDEO_BUF_DVB |
43 | ---help--- | 54 | ---help--- |
44 | This adds support for DVB/ATSC cards based on the | 55 | This adds support for DVB/ATSC cards based on the |
45 | Connexant 2388x chip. | 56 | Conexant 2388x chip. |
46 | 57 | ||
47 | To compile this driver as a module, choose M here: the | 58 | To compile this driver as a module, choose M here: the |
48 | module will be called cx88-dvb. | 59 | module will be called cx88-dvb. |
diff --git a/drivers/media/video/cx88/Makefile b/drivers/media/video/cx88/Makefile index 0dcd09b9b727..352b919f30c4 100644 --- a/drivers/media/video/cx88/Makefile +++ b/drivers/media/video/cx88/Makefile | |||
@@ -3,9 +3,10 @@ cx88xx-objs := cx88-cards.o cx88-core.o cx88-i2c.o cx88-tvaudio.o \ | |||
3 | cx8800-objs := cx88-video.o cx88-vbi.o | 3 | cx8800-objs := cx88-video.o cx88-vbi.o |
4 | cx8802-objs := cx88-mpeg.o | 4 | cx8802-objs := cx88-mpeg.o |
5 | 5 | ||
6 | obj-$(CONFIG_VIDEO_CX88) += cx88xx.o cx8800.o cx8802.o cx88-blackbird.o | 6 | obj-$(CONFIG_VIDEO_CX88) += cx88xx.o cx8800.o cx8802.o |
7 | obj-$(CONFIG_VIDEO_CX88_DVB) += cx88-dvb.o | ||
8 | obj-$(CONFIG_VIDEO_CX88_ALSA) += cx88-alsa.o | 7 | obj-$(CONFIG_VIDEO_CX88_ALSA) += cx88-alsa.o |
8 | obj-$(CONFIG_VIDEO_CX88_BLACKBIRD) += cx88-blackbird.o | ||
9 | obj-$(CONFIG_VIDEO_CX88_DVB) += cx88-dvb.o | ||
9 | obj-$(CONFIG_VIDEO_CX88_VP3054) += cx88-vp3054-i2c.o | 10 | obj-$(CONFIG_VIDEO_CX88_VP3054) += cx88-vp3054-i2c.o |
10 | 11 | ||
11 | EXTRA_CFLAGS += -Idrivers/media/video | 12 | EXTRA_CFLAGS += -Idrivers/media/video |
diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c index 67fd3302e8f2..78df66671ea2 100644 --- a/drivers/media/video/cx88/cx88-blackbird.c +++ b/drivers/media/video/cx88/cx88-blackbird.c | |||
@@ -846,7 +846,7 @@ static int mpeg_do_ioctl(struct inode *inode, struct file *file, | |||
846 | BLACKBIRD_MPEG_CAPTURE, | 846 | BLACKBIRD_MPEG_CAPTURE, |
847 | BLACKBIRD_RAW_BITS_NONE); | 847 | BLACKBIRD_RAW_BITS_NONE); |
848 | 848 | ||
849 | cx88_do_ioctl( inode, file, 0, dev->core, cmd, arg, cx88_ioctl_hook ); | 849 | cx88_do_ioctl(inode, file, 0, dev->core, cmd, arg, mpeg_do_ioctl); |
850 | 850 | ||
851 | blackbird_initialize_codec(dev); | 851 | blackbird_initialize_codec(dev); |
852 | cx88_set_scale(dev->core, dev->width, dev->height, | 852 | cx88_set_scale(dev->core, dev->width, dev->height, |
@@ -855,15 +855,11 @@ static int mpeg_do_ioctl(struct inode *inode, struct file *file, | |||
855 | } | 855 | } |
856 | 856 | ||
857 | default: | 857 | default: |
858 | return cx88_do_ioctl( inode, file, 0, dev->core, cmd, arg, cx88_ioctl_hook ); | 858 | return cx88_do_ioctl(inode, file, 0, dev->core, cmd, arg, mpeg_do_ioctl); |
859 | } | 859 | } |
860 | return 0; | 860 | return 0; |
861 | } | 861 | } |
862 | 862 | ||
863 | int (*cx88_ioctl_hook)(struct inode *inode, struct file *file, | ||
864 | unsigned int cmd, void *arg); | ||
865 | unsigned int (*cx88_ioctl_translator)(unsigned int cmd); | ||
866 | |||
867 | static unsigned int mpeg_translate_ioctl(unsigned int cmd) | 863 | static unsigned int mpeg_translate_ioctl(unsigned int cmd) |
868 | { | 864 | { |
869 | return cmd; | 865 | return cmd; |
@@ -872,8 +868,8 @@ static unsigned int mpeg_translate_ioctl(unsigned int cmd) | |||
872 | static int mpeg_ioctl(struct inode *inode, struct file *file, | 868 | static int mpeg_ioctl(struct inode *inode, struct file *file, |
873 | unsigned int cmd, unsigned long arg) | 869 | unsigned int cmd, unsigned long arg) |
874 | { | 870 | { |
875 | cmd = cx88_ioctl_translator( cmd ); | 871 | cmd = mpeg_translate_ioctl( cmd ); |
876 | return video_usercopy(inode, file, cmd, arg, cx88_ioctl_hook); | 872 | return video_usercopy(inode, file, cmd, arg, mpeg_do_ioctl); |
877 | } | 873 | } |
878 | 874 | ||
879 | static int mpeg_open(struct inode *inode, struct file *file) | 875 | static int mpeg_open(struct inode *inode, struct file *file) |
@@ -1119,8 +1115,6 @@ static int blackbird_init(void) | |||
1119 | printk(KERN_INFO "cx2388x: snapshot date %04d-%02d-%02d\n", | 1115 | printk(KERN_INFO "cx2388x: snapshot date %04d-%02d-%02d\n", |
1120 | SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100); | 1116 | SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100); |
1121 | #endif | 1117 | #endif |
1122 | cx88_ioctl_hook = mpeg_do_ioctl; | ||
1123 | cx88_ioctl_translator = mpeg_translate_ioctl; | ||
1124 | return pci_register_driver(&blackbird_pci_driver); | 1118 | return pci_register_driver(&blackbird_pci_driver); |
1125 | } | 1119 | } |
1126 | 1120 | ||
@@ -1132,9 +1126,6 @@ static void blackbird_fini(void) | |||
1132 | module_init(blackbird_init); | 1126 | module_init(blackbird_init); |
1133 | module_exit(blackbird_fini); | 1127 | module_exit(blackbird_fini); |
1134 | 1128 | ||
1135 | EXPORT_SYMBOL(cx88_ioctl_hook); | ||
1136 | EXPORT_SYMBOL(cx88_ioctl_translator); | ||
1137 | |||
1138 | /* ----------------------------------------------------------- */ | 1129 | /* ----------------------------------------------------------- */ |
1139 | /* | 1130 | /* |
1140 | * Local variables: | 1131 | * Local variables: |
diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c index 67cdd8270863..f9d68f20dc88 100644 --- a/drivers/media/video/cx88/cx88-cards.c +++ b/drivers/media/video/cx88/cx88-cards.c | |||
@@ -1700,11 +1700,6 @@ void cx88_card_setup(struct cx88_core *core) | |||
1700 | /* ------------------------------------------------------------------ */ | 1700 | /* ------------------------------------------------------------------ */ |
1701 | 1701 | ||
1702 | EXPORT_SYMBOL(cx88_boards); | 1702 | EXPORT_SYMBOL(cx88_boards); |
1703 | EXPORT_SYMBOL(cx88_bcount); | ||
1704 | EXPORT_SYMBOL(cx88_subids); | ||
1705 | EXPORT_SYMBOL(cx88_idcount); | ||
1706 | EXPORT_SYMBOL(cx88_card_list); | ||
1707 | EXPORT_SYMBOL(cx88_card_setup); | ||
1708 | 1703 | ||
1709 | /* | 1704 | /* |
1710 | * Local variables: | 1705 | * Local variables: |
diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c index c56292d8d93b..26f4c0fb8c36 100644 --- a/drivers/media/video/cx88/cx88-core.c +++ b/drivers/media/video/cx88/cx88-core.c | |||
@@ -1181,8 +1181,6 @@ EXPORT_SYMBOL(cx88_set_scale); | |||
1181 | EXPORT_SYMBOL(cx88_vdev_init); | 1181 | EXPORT_SYMBOL(cx88_vdev_init); |
1182 | EXPORT_SYMBOL(cx88_core_get); | 1182 | EXPORT_SYMBOL(cx88_core_get); |
1183 | EXPORT_SYMBOL(cx88_core_put); | 1183 | EXPORT_SYMBOL(cx88_core_put); |
1184 | EXPORT_SYMBOL(cx88_start_audio_dma); | ||
1185 | EXPORT_SYMBOL(cx88_stop_audio_dma); | ||
1186 | 1184 | ||
1187 | /* | 1185 | /* |
1188 | * Local variables: | 1186 | * Local variables: |
diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c index 7efa6def0bde..70663805cc30 100644 --- a/drivers/media/video/cx88/cx88-i2c.c +++ b/drivers/media/video/cx88/cx88-i2c.c | |||
@@ -234,7 +234,6 @@ int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci) | |||
234 | /* ----------------------------------------------------------------------- */ | 234 | /* ----------------------------------------------------------------------- */ |
235 | 235 | ||
236 | EXPORT_SYMBOL(cx88_call_i2c_clients); | 236 | EXPORT_SYMBOL(cx88_call_i2c_clients); |
237 | EXPORT_SYMBOL(cx88_i2c_init); | ||
238 | 237 | ||
239 | /* | 238 | /* |
240 | * Local variables: | 239 | * Local variables: |
diff --git a/drivers/media/video/cx88/cx88-tvaudio.c b/drivers/media/video/cx88/cx88-tvaudio.c index 1e4278b588d8..5785c3481579 100644 --- a/drivers/media/video/cx88/cx88-tvaudio.c +++ b/drivers/media/video/cx88/cx88-tvaudio.c | |||
@@ -726,7 +726,7 @@ static void set_audio_standard_FM(struct cx88_core *core, | |||
726 | 726 | ||
727 | /* ----------------------------------------------------------- */ | 727 | /* ----------------------------------------------------------- */ |
728 | 728 | ||
729 | int cx88_detect_nicam(struct cx88_core *core) | 729 | static int cx88_detect_nicam(struct cx88_core *core) |
730 | { | 730 | { |
731 | int i, j = 0; | 731 | int i, j = 0; |
732 | 732 | ||
diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index 694d1d80ff3f..dcda5291b990 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c | |||
@@ -494,8 +494,7 @@ static int restart_video_queue(struct cx8800_dev *dev, | |||
494 | return 0; | 494 | return 0; |
495 | buf = list_entry(q->queued.next, struct cx88_buffer, vb.queue); | 495 | buf = list_entry(q->queued.next, struct cx88_buffer, vb.queue); |
496 | if (NULL == prev) { | 496 | if (NULL == prev) { |
497 | list_del(&buf->vb.queue); | 497 | list_move_tail(&buf->vb.queue, &q->active); |
498 | list_add_tail(&buf->vb.queue,&q->active); | ||
499 | start_video_dma(dev, q, buf); | 498 | start_video_dma(dev, q, buf); |
500 | buf->vb.state = STATE_ACTIVE; | 499 | buf->vb.state = STATE_ACTIVE; |
501 | buf->count = q->count++; | 500 | buf->count = q->count++; |
@@ -506,8 +505,7 @@ static int restart_video_queue(struct cx8800_dev *dev, | |||
506 | } else if (prev->vb.width == buf->vb.width && | 505 | } else if (prev->vb.width == buf->vb.width && |
507 | prev->vb.height == buf->vb.height && | 506 | prev->vb.height == buf->vb.height && |
508 | prev->fmt == buf->fmt) { | 507 | prev->fmt == buf->fmt) { |
509 | list_del(&buf->vb.queue); | 508 | list_move_tail(&buf->vb.queue, &q->active); |
510 | list_add_tail(&buf->vb.queue,&q->active); | ||
511 | buf->vb.state = STATE_ACTIVE; | 509 | buf->vb.state = STATE_ACTIVE; |
512 | buf->count = q->count++; | 510 | buf->count = q->count++; |
513 | prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); | 511 | prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); |
diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index dc7bc35f18f4..9a9a0fc7a41a 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h | |||
@@ -563,7 +563,6 @@ void cx88_newstation(struct cx88_core *core); | |||
563 | void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t); | 563 | void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t); |
564 | void cx88_set_stereo(struct cx88_core *core, u32 mode, int manual); | 564 | void cx88_set_stereo(struct cx88_core *core, u32 mode, int manual); |
565 | int cx88_audio_thread(void *data); | 565 | int cx88_audio_thread(void *data); |
566 | int cx88_detect_nicam(struct cx88_core *core); | ||
567 | 566 | ||
568 | /* ----------------------------------------------------------- */ | 567 | /* ----------------------------------------------------------- */ |
569 | /* cx88-input.c */ | 568 | /* cx88-input.c */ |
@@ -592,12 +591,6 @@ extern int cx88_do_ioctl(struct inode *inode, struct file *file, int radio, | |||
592 | struct cx88_core *core, unsigned int cmd, | 591 | struct cx88_core *core, unsigned int cmd, |
593 | void *arg, v4l2_kioctl driver_ioctl); | 592 | void *arg, v4l2_kioctl driver_ioctl); |
594 | 593 | ||
595 | /* ----------------------------------------------------------- */ | ||
596 | /* cx88-blackbird.c */ | ||
597 | extern int (*cx88_ioctl_hook)(struct inode *inode, struct file *file, | ||
598 | unsigned int cmd, void *arg); | ||
599 | extern unsigned int (*cx88_ioctl_translator)(unsigned int cmd); | ||
600 | |||
601 | /* | 594 | /* |
602 | * Local variables: | 595 | * Local variables: |
603 | * c-basic-offset: 8 | 596 | * c-basic-offset: 8 |
diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index e95792fd70f8..a26ded7d6fae 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c | |||
@@ -730,14 +730,10 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) | |||
730 | { | 730 | { |
731 | struct v4l2_frequency *f = arg; | 731 | struct v4l2_frequency *f = arg; |
732 | 732 | ||
733 | if (set_mode (client, t, f->type, "VIDIOC_S_FREQUENCY") | ||
734 | == EINVAL) | ||
735 | return 0; | ||
733 | switch_v4l2(); | 736 | switch_v4l2(); |
734 | if ((V4L2_TUNER_RADIO == f->type && V4L2_TUNER_RADIO != t->mode) | ||
735 | || (V4L2_TUNER_DIGITAL_TV == f->type | ||
736 | && V4L2_TUNER_DIGITAL_TV != t->mode)) { | ||
737 | if (set_mode (client, t, f->type, "VIDIOC_S_FREQUENCY") | ||
738 | == EINVAL) | ||
739 | return 0; | ||
740 | } | ||
741 | set_freq(client,f->frequency); | 737 | set_freq(client,f->frequency); |
742 | 738 | ||
743 | break; | 739 | break; |
diff --git a/drivers/media/video/usbvideo/quickcam_messenger.c b/drivers/media/video/usbvideo/quickcam_messenger.c index 3f3182a24da1..56e01b622417 100644 --- a/drivers/media/video/usbvideo/quickcam_messenger.c +++ b/drivers/media/video/usbvideo/quickcam_messenger.c | |||
@@ -33,7 +33,7 @@ | |||
33 | #include <linux/module.h> | 33 | #include <linux/module.h> |
34 | #include <linux/init.h> | 34 | #include <linux/init.h> |
35 | #include <linux/input.h> | 35 | #include <linux/input.h> |
36 | #include <linux/usb_input.h> | 36 | #include <linux/usb/input.h> |
37 | 37 | ||
38 | #include "usbvideo.h" | 38 | #include "usbvideo.h" |
39 | #include "quickcam_messenger.h" | 39 | #include "quickcam_messenger.h" |
diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c index 14e523471354..f4b3d64ebf73 100644 --- a/drivers/media/video/v4l2-common.c +++ b/drivers/media/video/v4l2-common.c | |||
@@ -1101,6 +1101,11 @@ const char **v4l2_ctrl_get_menu(u32 id) | |||
1101 | "MPEG-2 SVCD-compatible Stream", | 1101 | "MPEG-2 SVCD-compatible Stream", |
1102 | NULL | 1102 | NULL |
1103 | }; | 1103 | }; |
1104 | static const char *mpeg_stream_vbi_fmt[] = { | ||
1105 | "No VBI", | ||
1106 | "VBI in private packets, IVTV format", | ||
1107 | NULL | ||
1108 | }; | ||
1104 | 1109 | ||
1105 | switch (id) { | 1110 | switch (id) { |
1106 | case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: | 1111 | case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: |
@@ -1129,6 +1134,8 @@ const char **v4l2_ctrl_get_menu(u32 id) | |||
1129 | return mpeg_video_bitrate_mode; | 1134 | return mpeg_video_bitrate_mode; |
1130 | case V4L2_CID_MPEG_STREAM_TYPE: | 1135 | case V4L2_CID_MPEG_STREAM_TYPE: |
1131 | return mpeg_stream_type; | 1136 | return mpeg_stream_type; |
1137 | case V4L2_CID_MPEG_STREAM_VBI_FMT: | ||
1138 | return mpeg_stream_vbi_fmt; | ||
1132 | default: | 1139 | default: |
1133 | return NULL; | 1140 | return NULL; |
1134 | } | 1141 | } |
@@ -1182,6 +1189,7 @@ int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 ste | |||
1182 | case V4L2_CID_MPEG_STREAM_PID_PCR: name = "Stream PCR Program ID"; break; | 1189 | case V4L2_CID_MPEG_STREAM_PID_PCR: name = "Stream PCR Program ID"; break; |
1183 | case V4L2_CID_MPEG_STREAM_PES_ID_AUDIO: name = "Stream PES Audio ID"; break; | 1190 | case V4L2_CID_MPEG_STREAM_PES_ID_AUDIO: name = "Stream PES Audio ID"; break; |
1184 | case V4L2_CID_MPEG_STREAM_PES_ID_VIDEO: name = "Stream PES Video ID"; break; | 1191 | case V4L2_CID_MPEG_STREAM_PES_ID_VIDEO: name = "Stream PES Video ID"; break; |
1192 | case V4L2_CID_MPEG_STREAM_VBI_FMT: name = "Stream VBI Format"; break; | ||
1185 | 1193 | ||
1186 | default: | 1194 | default: |
1187 | return -EINVAL; | 1195 | return -EINVAL; |
@@ -1208,6 +1216,7 @@ int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 ste | |||
1208 | case V4L2_CID_MPEG_VIDEO_ASPECT: | 1216 | case V4L2_CID_MPEG_VIDEO_ASPECT: |
1209 | case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: | 1217 | case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: |
1210 | case V4L2_CID_MPEG_STREAM_TYPE: | 1218 | case V4L2_CID_MPEG_STREAM_TYPE: |
1219 | case V4L2_CID_MPEG_STREAM_VBI_FMT: | ||
1211 | qctrl->type = V4L2_CTRL_TYPE_MENU; | 1220 | qctrl->type = V4L2_CTRL_TYPE_MENU; |
1212 | step = 1; | 1221 | step = 1; |
1213 | break; | 1222 | break; |
@@ -1367,6 +1376,11 @@ int v4l2_ctrl_query_fill_std(struct v4l2_queryctrl *qctrl) | |||
1367 | return v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 0); | 1376 | return v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 0); |
1368 | case V4L2_CID_MPEG_STREAM_PES_ID_VIDEO: | 1377 | case V4L2_CID_MPEG_STREAM_PES_ID_VIDEO: |
1369 | return v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 0); | 1378 | return v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 0); |
1379 | case V4L2_CID_MPEG_STREAM_VBI_FMT: | ||
1380 | return v4l2_ctrl_query_fill(qctrl, | ||
1381 | V4L2_MPEG_STREAM_VBI_FMT_NONE, | ||
1382 | V4L2_MPEG_STREAM_VBI_FMT_IVTV, 1, | ||
1383 | V4L2_MPEG_STREAM_VBI_FMT_NONE); | ||
1370 | default: | 1384 | default: |
1371 | return -EINVAL; | 1385 | return -EINVAL; |
1372 | } | 1386 | } |
diff --git a/drivers/mtd/maps/sun_uflash.c b/drivers/mtd/maps/sun_uflash.c index 0758cb1d0105..24a03152d196 100644 --- a/drivers/mtd/maps/sun_uflash.c +++ b/drivers/mtd/maps/sun_uflash.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/ioport.h> | 18 | #include <linux/ioport.h> |
19 | #include <asm/ebus.h> | 19 | #include <asm/ebus.h> |
20 | #include <asm/oplib.h> | 20 | #include <asm/oplib.h> |
21 | #include <asm/prom.h> | ||
21 | #include <asm/uaccess.h> | 22 | #include <asm/uaccess.h> |
22 | #include <asm/io.h> | 23 | #include <asm/io.h> |
23 | 24 | ||
@@ -30,146 +31,140 @@ | |||
30 | #define UFLASH_WINDOW_SIZE 0x200000 | 31 | #define UFLASH_WINDOW_SIZE 0x200000 |
31 | #define UFLASH_BUSWIDTH 1 /* EBus is 8-bit */ | 32 | #define UFLASH_BUSWIDTH 1 /* EBus is 8-bit */ |
32 | 33 | ||
33 | MODULE_AUTHOR | 34 | MODULE_AUTHOR("Eric Brower <ebrower@usa.net>"); |
34 | ("Eric Brower <ebrower@usa.net>"); | 35 | MODULE_DESCRIPTION("User-programmable flash device on Sun Microsystems boardsets"); |
35 | MODULE_DESCRIPTION | 36 | MODULE_SUPPORTED_DEVICE("userflash"); |
36 | ("User-programmable flash device on Sun Microsystems boardsets"); | 37 | MODULE_LICENSE("GPL"); |
37 | MODULE_SUPPORTED_DEVICE | 38 | MODULE_VERSION("2.0"); |
38 | ("userflash"); | ||
39 | MODULE_LICENSE | ||
40 | ("GPL"); | ||
41 | 39 | ||
42 | static LIST_HEAD(device_list); | 40 | static LIST_HEAD(device_list); |
43 | struct uflash_dev { | 41 | struct uflash_dev { |
44 | char * name; /* device name */ | 42 | char *name; /* device name */ |
45 | struct map_info map; /* mtd map info */ | 43 | struct map_info map; /* mtd map info */ |
46 | struct mtd_info * mtd; /* mtd info */ | 44 | struct mtd_info *mtd; /* mtd info */ |
47 | struct list_head list; | ||
48 | }; | 45 | }; |
49 | 46 | ||
50 | 47 | ||
51 | struct map_info uflash_map_templ = { | 48 | struct map_info uflash_map_templ = { |
52 | .name = "SUNW,???-????", | 49 | .name = "SUNW,???-????", |
53 | .size = UFLASH_WINDOW_SIZE, | 50 | .size = UFLASH_WINDOW_SIZE, |
54 | .bankwidth = UFLASH_BUSWIDTH, | 51 | .bankwidth = UFLASH_BUSWIDTH, |
55 | }; | 52 | }; |
56 | 53 | ||
57 | int uflash_devinit(struct linux_ebus_device* edev) | 54 | int uflash_devinit(struct linux_ebus_device *edev, struct device_node *dp) |
58 | { | 55 | { |
59 | int iTmp, nregs; | 56 | struct uflash_dev *up; |
60 | struct linux_prom_registers regs[2]; | 57 | struct resource *res; |
61 | struct uflash_dev *pdev; | ||
62 | |||
63 | iTmp = prom_getproperty( | ||
64 | edev->prom_node, "reg", (void *)regs, sizeof(regs)); | ||
65 | if ((iTmp % sizeof(regs[0])) != 0) { | ||
66 | printk("%s: Strange reg property size %d\n", | ||
67 | UFLASH_DEVNAME, iTmp); | ||
68 | return -ENODEV; | ||
69 | } | ||
70 | 58 | ||
71 | nregs = iTmp / sizeof(regs[0]); | 59 | res = &edev->resource[0]; |
72 | 60 | ||
73 | if (nregs != 1) { | 61 | if (edev->num_addrs != 1) { |
74 | /* Non-CFI userflash device-- once I find one we | 62 | /* Non-CFI userflash device-- once I find one we |
75 | * can work on supporting it. | 63 | * can work on supporting it. |
76 | */ | 64 | */ |
77 | printk("%s: unsupported device at 0x%lx (%d regs): " \ | 65 | printk("%s: unsupported device at 0x%lx (%d regs): " \ |
78 | "email ebrower@usa.net\n", | 66 | "email ebrower@usa.net\n", |
79 | UFLASH_DEVNAME, edev->resource[0].start, nregs); | 67 | dp->full_name, res->start, edev->num_addrs); |
68 | |||
80 | return -ENODEV; | 69 | return -ENODEV; |
81 | } | 70 | } |
82 | 71 | ||
83 | if(0 == (pdev = kmalloc(sizeof(struct uflash_dev), GFP_KERNEL))) { | 72 | up = kzalloc(sizeof(struct uflash_dev), GFP_KERNEL); |
84 | printk("%s: unable to kmalloc new device\n", UFLASH_DEVNAME); | 73 | if (!up) |
85 | return(-ENOMEM); | 74 | return -ENOMEM; |
86 | } | ||
87 | 75 | ||
88 | /* copy defaults and tweak parameters */ | 76 | /* copy defaults and tweak parameters */ |
89 | memcpy(&pdev->map, &uflash_map_templ, sizeof(uflash_map_templ)); | 77 | memcpy(&up->map, &uflash_map_templ, sizeof(uflash_map_templ)); |
90 | pdev->map.size = regs[0].reg_size; | 78 | up->map.size = (res->end - res->start) + 1UL; |
91 | 79 | ||
92 | iTmp = prom_getproplen(edev->prom_node, "model"); | 80 | up->name = of_get_property(dp, "model", NULL); |
93 | pdev->name = kmalloc(iTmp, GFP_KERNEL); | 81 | if (up->name && 0 < strlen(up->name)) |
94 | prom_getstring(edev->prom_node, "model", pdev->name, iTmp); | 82 | up->map.name = up->name; |
95 | if(0 != pdev->name && 0 < strlen(pdev->name)) { | 83 | |
96 | pdev->map.name = pdev->name; | 84 | up->map.phys = res->start; |
97 | } | 85 | |
98 | pdev->map.phys = edev->resource[0].start; | 86 | up->map.virt = ioremap_nocache(res->start, up->map.size); |
99 | pdev->map.virt = ioremap_nocache(edev->resource[0].start, pdev->map.size); | 87 | if (!up->map.virt) { |
100 | if(0 == pdev->map.virt) { | 88 | printk("%s: Failed to map device.\n", dp->full_name); |
101 | printk("%s: failed to map device\n", __FUNCTION__); | 89 | kfree(up); |
102 | kfree(pdev->name); | 90 | |
103 | kfree(pdev); | 91 | return -EINVAL; |
104 | return(-1); | ||
105 | } | 92 | } |
106 | 93 | ||
107 | simple_map_init(&pdev->map); | 94 | simple_map_init(&up->map); |
108 | 95 | ||
109 | /* MTD registration */ | 96 | /* MTD registration */ |
110 | pdev->mtd = do_map_probe("cfi_probe", &pdev->map); | 97 | up->mtd = do_map_probe("cfi_probe", &up->map); |
111 | if(0 == pdev->mtd) { | 98 | if (!up->mtd) { |
112 | iounmap(pdev->map.virt); | 99 | iounmap(up->map.virt); |
113 | kfree(pdev->name); | 100 | kfree(up); |
114 | kfree(pdev); | 101 | |
115 | return(-ENXIO); | 102 | return -ENXIO; |
116 | } | 103 | } |
117 | 104 | ||
118 | list_add(&pdev->list, &device_list); | 105 | up->mtd->owner = THIS_MODULE; |
119 | 106 | ||
120 | pdev->mtd->owner = THIS_MODULE; | 107 | add_mtd_device(up->mtd); |
121 | 108 | ||
122 | add_mtd_device(pdev->mtd); | 109 | dev_set_drvdata(&edev->ofdev.dev, up); |
123 | return(0); | 110 | |
111 | return 0; | ||
124 | } | 112 | } |
125 | 113 | ||
126 | static int __init uflash_init(void) | 114 | static int __devinit uflash_probe(struct of_device *dev, const struct of_device_id *match) |
127 | { | 115 | { |
128 | struct linux_ebus *ebus = NULL; | 116 | struct linux_ebus_device *edev = to_ebus_device(&dev->dev); |
129 | struct linux_ebus_device *edev = NULL; | 117 | struct device_node *dp = dev->node; |
130 | |||
131 | for_each_ebus(ebus) { | ||
132 | for_each_ebusdev(edev, ebus) { | ||
133 | if (!strcmp(edev->prom_name, UFLASH_OBPNAME)) { | ||
134 | if(0 > prom_getproplen(edev->prom_node, "user")) { | ||
135 | DEBUG(2, "%s: ignoring device at 0x%lx\n", | ||
136 | UFLASH_DEVNAME, edev->resource[0].start); | ||
137 | } else { | ||
138 | uflash_devinit(edev); | ||
139 | } | ||
140 | } | ||
141 | } | ||
142 | } | ||
143 | 118 | ||
144 | if(list_empty(&device_list)) { | 119 | if (of_find_property(dp, "user", NULL)) |
145 | printk("%s: unable to locate device\n", UFLASH_DEVNAME); | ||
146 | return -ENODEV; | 120 | return -ENODEV; |
147 | } | 121 | |
148 | return(0); | 122 | return uflash_devinit(edev, dp); |
149 | } | 123 | } |
150 | 124 | ||
151 | static void __exit uflash_cleanup(void) | 125 | static int __devexit uflash_remove(struct of_device *dev) |
152 | { | 126 | { |
153 | struct list_head *udevlist; | 127 | struct uflash_dev *up = dev_get_drvdata(&dev->dev); |
154 | struct uflash_dev *udev; | 128 | |
155 | 129 | if (up->mtd) { | |
156 | list_for_each(udevlist, &device_list) { | 130 | del_mtd_device(up->mtd); |
157 | udev = list_entry(udevlist, struct uflash_dev, list); | 131 | map_destroy(up->mtd); |
158 | DEBUG(2, "%s: removing device %s\n", | ||
159 | UFLASH_DEVNAME, udev->name); | ||
160 | |||
161 | if(0 != udev->mtd) { | ||
162 | del_mtd_device(udev->mtd); | ||
163 | map_destroy(udev->mtd); | ||
164 | } | ||
165 | if(0 != udev->map.virt) { | ||
166 | iounmap(udev->map.virt); | ||
167 | udev->map.virt = NULL; | ||
168 | } | ||
169 | kfree(udev->name); | ||
170 | kfree(udev); | ||
171 | } | 132 | } |
133 | if (up->map.virt) { | ||
134 | iounmap(up->map.virt); | ||
135 | up->map.virt = NULL; | ||
136 | } | ||
137 | |||
138 | kfree(up); | ||
139 | |||
140 | return 0; | ||
141 | } | ||
142 | |||
143 | static struct of_device_id uflash_match[] = { | ||
144 | { | ||
145 | .name = UFLASH_OBPNAME, | ||
146 | }, | ||
147 | {}, | ||
148 | }; | ||
149 | |||
150 | MODULE_DEVICE_TABLE(of, uflash_match); | ||
151 | |||
152 | static struct of_platform_driver uflash_driver = { | ||
153 | .name = UFLASH_DEVNAME, | ||
154 | .match_table = uflash_match, | ||
155 | .probe = uflash_probe, | ||
156 | .remove = __devexit_p(uflash_remove), | ||
157 | }; | ||
158 | |||
159 | static int __init uflash_init(void) | ||
160 | { | ||
161 | return of_register_driver(&uflash_driver, &ebus_bus_type); | ||
162 | } | ||
163 | |||
164 | static void __exit uflash_exit(void) | ||
165 | { | ||
166 | of_unregister_driver(&uflash_driver); | ||
172 | } | 167 | } |
173 | 168 | ||
174 | module_init(uflash_init); | 169 | module_init(uflash_init); |
175 | module_exit(uflash_cleanup); | 170 | module_exit(uflash_exit); |
diff --git a/drivers/net/irda/nsc-ircc.c b/drivers/net/irda/nsc-ircc.c index cc7ff8f00e42..cb62f2a9676a 100644 --- a/drivers/net/irda/nsc-ircc.c +++ b/drivers/net/irda/nsc-ircc.c | |||
@@ -115,8 +115,12 @@ static nsc_chip_t chips[] = { | |||
115 | /* Contributed by Jan Frey - IBM A30/A31 */ | 115 | /* Contributed by Jan Frey - IBM A30/A31 */ |
116 | { "PC8739x", { 0x2e, 0x4e, 0x0 }, 0x20, 0xea, 0xff, | 116 | { "PC8739x", { 0x2e, 0x4e, 0x0 }, 0x20, 0xea, 0xff, |
117 | nsc_ircc_probe_39x, nsc_ircc_init_39x }, | 117 | nsc_ircc_probe_39x, nsc_ircc_init_39x }, |
118 | { "IBM", { 0x2e, 0x4e, 0x0 }, 0x20, 0xf4, 0xff, | 118 | /* IBM ThinkPads using PC8738x (T60/X60/Z60) */ |
119 | nsc_ircc_probe_39x, nsc_ircc_init_39x }, | 119 | { "IBM-PC8738x", { 0x2e, 0x4e, 0x0 }, 0x20, 0xf4, 0xff, |
120 | nsc_ircc_probe_39x, nsc_ircc_init_39x }, | ||
121 | /* IBM ThinkPads using PC8394T (T43/R52/?) */ | ||
122 | { "IBM-PC8394T", { 0x2e, 0x4e, 0x0 }, 0x20, 0xf9, 0xff, | ||
123 | nsc_ircc_probe_39x, nsc_ircc_init_39x }, | ||
120 | { NULL } | 124 | { NULL } |
121 | }; | 125 | }; |
122 | 126 | ||
diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c index 01cd8ec751ea..d643a097faa5 100644 --- a/drivers/net/ppp_generic.c +++ b/drivers/net/ppp_generic.c | |||
@@ -2578,8 +2578,7 @@ ppp_find_channel(int unit) | |||
2578 | 2578 | ||
2579 | list_for_each_entry(pch, &new_channels, list) { | 2579 | list_for_each_entry(pch, &new_channels, list) { |
2580 | if (pch->file.index == unit) { | 2580 | if (pch->file.index == unit) { |
2581 | list_del(&pch->list); | 2581 | list_move(&pch->list, &all_channels); |
2582 | list_add(&pch->list, &all_channels); | ||
2583 | return pch; | 2582 | return pch; |
2584 | } | 2583 | } |
2585 | } | 2584 | } |
diff --git a/drivers/net/wireless/bcm43xx/Kconfig b/drivers/net/wireless/bcm43xx/Kconfig index 25ea4748f0b9..533993f538fc 100644 --- a/drivers/net/wireless/bcm43xx/Kconfig +++ b/drivers/net/wireless/bcm43xx/Kconfig | |||
@@ -2,6 +2,7 @@ config BCM43XX | |||
2 | tristate "Broadcom BCM43xx wireless support" | 2 | tristate "Broadcom BCM43xx wireless support" |
3 | depends on PCI && IEEE80211 && IEEE80211_SOFTMAC && NET_RADIO && EXPERIMENTAL | 3 | depends on PCI && IEEE80211 && IEEE80211_SOFTMAC && NET_RADIO && EXPERIMENTAL |
4 | select FW_LOADER | 4 | select FW_LOADER |
5 | select HW_RANDOM | ||
5 | ---help--- | 6 | ---help--- |
6 | This is an experimental driver for the Broadcom 43xx wireless chip, | 7 | This is an experimental driver for the Broadcom 43xx wireless chip, |
7 | found in the Apple Airport Extreme and various other devices. | 8 | found in the Apple Airport Extreme and various other devices. |
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h index d8f917c21ea4..17a56828e232 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx.h | |||
@@ -1,6 +1,7 @@ | |||
1 | #ifndef BCM43xx_H_ | 1 | #ifndef BCM43xx_H_ |
2 | #define BCM43xx_H_ | 2 | #define BCM43xx_H_ |
3 | 3 | ||
4 | #include <linux/hw_random.h> | ||
4 | #include <linux/version.h> | 5 | #include <linux/version.h> |
5 | #include <linux/kernel.h> | 6 | #include <linux/kernel.h> |
6 | #include <linux/spinlock.h> | 7 | #include <linux/spinlock.h> |
@@ -82,6 +83,7 @@ | |||
82 | #define BCM43xx_MMIO_TSF_1 0x634 /* core rev < 3 only */ | 83 | #define BCM43xx_MMIO_TSF_1 0x634 /* core rev < 3 only */ |
83 | #define BCM43xx_MMIO_TSF_2 0x636 /* core rev < 3 only */ | 84 | #define BCM43xx_MMIO_TSF_2 0x636 /* core rev < 3 only */ |
84 | #define BCM43xx_MMIO_TSF_3 0x638 /* core rev < 3 only */ | 85 | #define BCM43xx_MMIO_TSF_3 0x638 /* core rev < 3 only */ |
86 | #define BCM43xx_MMIO_RNG 0x65A | ||
85 | #define BCM43xx_MMIO_POWERUP_DELAY 0x6A8 | 87 | #define BCM43xx_MMIO_POWERUP_DELAY 0x6A8 |
86 | 88 | ||
87 | /* SPROM offsets. */ | 89 | /* SPROM offsets. */ |
@@ -750,6 +752,10 @@ struct bcm43xx_private { | |||
750 | const struct firmware *initvals0; | 752 | const struct firmware *initvals0; |
751 | const struct firmware *initvals1; | 753 | const struct firmware *initvals1; |
752 | 754 | ||
755 | /* Random Number Generator. */ | ||
756 | struct hwrng rng; | ||
757 | char rng_name[20 + 1]; | ||
758 | |||
753 | /* Debugging stuff follows. */ | 759 | /* Debugging stuff follows. */ |
754 | #ifdef CONFIG_BCM43XX_DEBUG | 760 | #ifdef CONFIG_BCM43XX_DEBUG |
755 | struct bcm43xx_dfsentry *dfsentry; | 761 | struct bcm43xx_dfsentry *dfsentry; |
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index 085d7857fe31..27bcf47228e2 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c | |||
@@ -3237,6 +3237,39 @@ static void bcm43xx_security_init(struct bcm43xx_private *bcm) | |||
3237 | bcm43xx_clear_keys(bcm); | 3237 | bcm43xx_clear_keys(bcm); |
3238 | } | 3238 | } |
3239 | 3239 | ||
3240 | static int bcm43xx_rng_read(struct hwrng *rng, u32 *data) | ||
3241 | { | ||
3242 | struct bcm43xx_private *bcm = (struct bcm43xx_private *)rng->priv; | ||
3243 | unsigned long flags; | ||
3244 | |||
3245 | bcm43xx_lock_irqonly(bcm, flags); | ||
3246 | *data = bcm43xx_read16(bcm, BCM43xx_MMIO_RNG); | ||
3247 | bcm43xx_unlock_irqonly(bcm, flags); | ||
3248 | |||
3249 | return (sizeof(u16)); | ||
3250 | } | ||
3251 | |||
3252 | static void bcm43xx_rng_exit(struct bcm43xx_private *bcm) | ||
3253 | { | ||
3254 | hwrng_unregister(&bcm->rng); | ||
3255 | } | ||
3256 | |||
3257 | static int bcm43xx_rng_init(struct bcm43xx_private *bcm) | ||
3258 | { | ||
3259 | int err; | ||
3260 | |||
3261 | snprintf(bcm->rng_name, ARRAY_SIZE(bcm->rng_name), | ||
3262 | "%s_%s", KBUILD_MODNAME, bcm->net_dev->name); | ||
3263 | bcm->rng.name = bcm->rng_name; | ||
3264 | bcm->rng.data_read = bcm43xx_rng_read; | ||
3265 | bcm->rng.priv = (unsigned long)bcm; | ||
3266 | err = hwrng_register(&bcm->rng); | ||
3267 | if (err) | ||
3268 | printk(KERN_ERR PFX "RNG init failed (%d)\n", err); | ||
3269 | |||
3270 | return err; | ||
3271 | } | ||
3272 | |||
3240 | /* This is the opposite of bcm43xx_init_board() */ | 3273 | /* This is the opposite of bcm43xx_init_board() */ |
3241 | static void bcm43xx_free_board(struct bcm43xx_private *bcm) | 3274 | static void bcm43xx_free_board(struct bcm43xx_private *bcm) |
3242 | { | 3275 | { |
@@ -3248,6 +3281,7 @@ static void bcm43xx_free_board(struct bcm43xx_private *bcm) | |||
3248 | 3281 | ||
3249 | bcm43xx_set_status(bcm, BCM43xx_STAT_SHUTTINGDOWN); | 3282 | bcm43xx_set_status(bcm, BCM43xx_STAT_SHUTTINGDOWN); |
3250 | 3283 | ||
3284 | bcm43xx_rng_exit(bcm); | ||
3251 | for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) { | 3285 | for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) { |
3252 | if (!bcm->core_80211[i].available) | 3286 | if (!bcm->core_80211[i].available) |
3253 | continue; | 3287 | continue; |
@@ -3325,6 +3359,9 @@ static int bcm43xx_init_board(struct bcm43xx_private *bcm) | |||
3325 | bcm43xx_switch_core(bcm, &bcm->core_80211[0]); | 3359 | bcm43xx_switch_core(bcm, &bcm->core_80211[0]); |
3326 | bcm43xx_mac_enable(bcm); | 3360 | bcm43xx_mac_enable(bcm); |
3327 | } | 3361 | } |
3362 | err = bcm43xx_rng_init(bcm); | ||
3363 | if (err) | ||
3364 | goto err_80211_unwind; | ||
3328 | bcm43xx_macfilter_clear(bcm, BCM43xx_MACFILTER_ASSOC); | 3365 | bcm43xx_macfilter_clear(bcm, BCM43xx_MACFILTER_ASSOC); |
3329 | bcm43xx_macfilter_set(bcm, BCM43xx_MACFILTER_SELF, (u8 *)(bcm->net_dev->dev_addr)); | 3366 | bcm43xx_macfilter_set(bcm, BCM43xx_MACFILTER_SELF, (u8 *)(bcm->net_dev->dev_addr)); |
3330 | dprintk(KERN_INFO PFX "80211 cores initialized\n"); | 3367 | dprintk(KERN_INFO PFX "80211 cores initialized\n"); |
diff --git a/drivers/parport/parport_sunbpp.c b/drivers/parport/parport_sunbpp.c index 69a4bbd4cbee..7c43c5392bed 100644 --- a/drivers/parport/parport_sunbpp.c +++ b/drivers/parport/parport_sunbpp.c | |||
@@ -389,7 +389,7 @@ static struct of_device_id bpp_match[] = { | |||
389 | {}, | 389 | {}, |
390 | }; | 390 | }; |
391 | 391 | ||
392 | MODULE_DEVICE_TABLE(of, qec_sbus_match); | 392 | MODULE_DEVICE_TABLE(of, bpp_match); |
393 | 393 | ||
394 | static struct of_platform_driver bpp_sbus_driver = { | 394 | static struct of_platform_driver bpp_sbus_driver = { |
395 | .name = "bpp", | 395 | .name = "bpp", |
diff --git a/drivers/pci/msi-apic.c b/drivers/pci/msi-apic.c index 0eb5fe9003a2..5ed798b319c7 100644 --- a/drivers/pci/msi-apic.c +++ b/drivers/pci/msi-apic.c | |||
@@ -4,6 +4,7 @@ | |||
4 | 4 | ||
5 | #include <linux/pci.h> | 5 | #include <linux/pci.h> |
6 | #include <linux/irq.h> | 6 | #include <linux/irq.h> |
7 | #include <asm/smp.h> | ||
7 | 8 | ||
8 | #include "msi.h" | 9 | #include "msi.h" |
9 | 10 | ||
diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c index f94419b334f7..2eded55ae88d 100644 --- a/drivers/s390/net/lcs.c +++ b/drivers/s390/net/lcs.c | |||
@@ -1140,10 +1140,9 @@ list_modified: | |||
1140 | } | 1140 | } |
1141 | } | 1141 | } |
1142 | /* re-insert all entries from the failed_list into ipm_list */ | 1142 | /* re-insert all entries from the failed_list into ipm_list */ |
1143 | list_for_each_entry_safe(ipm, tmp, &failed_list, list) { | 1143 | list_for_each_entry_safe(ipm, tmp, &failed_list, list) |
1144 | list_del_init(&ipm->list); | 1144 | list_move_tail(&ipm->list, &card->ipm_list); |
1145 | list_add_tail(&ipm->list, &card->ipm_list); | 1145 | |
1146 | } | ||
1147 | spin_unlock_irqrestore(&card->ipm_lock, flags); | 1146 | spin_unlock_irqrestore(&card->ipm_lock, flags); |
1148 | } | 1147 | } |
1149 | 1148 | ||
diff --git a/drivers/sbus/char/cpwatchdog.c b/drivers/sbus/char/cpwatchdog.c index 5bf3dd901b65..21737b7e86a1 100644 --- a/drivers/sbus/char/cpwatchdog.c +++ b/drivers/sbus/char/cpwatchdog.c | |||
@@ -755,7 +755,7 @@ static int __init wd_init(void) | |||
755 | 755 | ||
756 | for_each_ebus(ebus) { | 756 | for_each_ebus(ebus) { |
757 | for_each_ebusdev(edev, ebus) { | 757 | for_each_ebusdev(edev, ebus) { |
758 | if (!strcmp(edev->prom_name, WD_OBPNAME)) | 758 | if (!strcmp(edev->ofdev.node->name, WD_OBPNAME)) |
759 | goto ebus_done; | 759 | goto ebus_done; |
760 | } | 760 | } |
761 | } | 761 | } |
diff --git a/drivers/sbus/char/openprom.c b/drivers/sbus/char/openprom.c index cf5b476b5496..d7e4bb41bd79 100644 --- a/drivers/sbus/char/openprom.c +++ b/drivers/sbus/char/openprom.c | |||
@@ -29,8 +29,6 @@ | |||
29 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 29 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
30 | */ | 30 | */ |
31 | 31 | ||
32 | #define PROMLIB_INTERNAL | ||
33 | |||
34 | #include <linux/config.h> | 32 | #include <linux/config.h> |
35 | #include <linux/module.h> | 33 | #include <linux/module.h> |
36 | #include <linux/kernel.h> | 34 | #include <linux/kernel.h> |
@@ -39,10 +37,10 @@ | |||
39 | #include <linux/slab.h> | 37 | #include <linux/slab.h> |
40 | #include <linux/string.h> | 38 | #include <linux/string.h> |
41 | #include <linux/miscdevice.h> | 39 | #include <linux/miscdevice.h> |
42 | #include <linux/smp_lock.h> | ||
43 | #include <linux/init.h> | 40 | #include <linux/init.h> |
44 | #include <linux/fs.h> | 41 | #include <linux/fs.h> |
45 | #include <asm/oplib.h> | 42 | #include <asm/oplib.h> |
43 | #include <asm/prom.h> | ||
46 | #include <asm/system.h> | 44 | #include <asm/system.h> |
47 | #include <asm/uaccess.h> | 45 | #include <asm/uaccess.h> |
48 | #include <asm/openpromio.h> | 46 | #include <asm/openpromio.h> |
@@ -51,15 +49,20 @@ | |||
51 | #include <asm/pbm.h> | 49 | #include <asm/pbm.h> |
52 | #endif | 50 | #endif |
53 | 51 | ||
52 | MODULE_AUTHOR("Thomas K. Dyas (tdyas@noc.rutgers.edu) and Eddie C. Dost (ecd@skynet.be)"); | ||
53 | MODULE_DESCRIPTION("OPENPROM Configuration Driver"); | ||
54 | MODULE_LICENSE("GPL"); | ||
55 | MODULE_VERSION("1.0"); | ||
56 | |||
54 | /* Private data kept by the driver for each descriptor. */ | 57 | /* Private data kept by the driver for each descriptor. */ |
55 | typedef struct openprom_private_data | 58 | typedef struct openprom_private_data |
56 | { | 59 | { |
57 | int current_node; /* Current node for SunOS ioctls. */ | 60 | struct device_node *current_node; /* Current node for SunOS ioctls. */ |
58 | int lastnode; /* Last valid node used by BSD ioctls. */ | 61 | struct device_node *lastnode; /* Last valid node used by BSD ioctls. */ |
59 | } DATA; | 62 | } DATA; |
60 | 63 | ||
61 | /* ID of the PROM node containing all of the EEPROM options. */ | 64 | /* ID of the PROM node containing all of the EEPROM options. */ |
62 | static int options_node = 0; | 65 | static struct device_node *options_node; |
63 | 66 | ||
64 | /* | 67 | /* |
65 | * Copy an openpromio structure into kernel space from user space. | 68 | * Copy an openpromio structure into kernel space from user space. |
@@ -87,9 +90,8 @@ static int copyin(struct openpromio __user *info, struct openpromio **opp_p) | |||
87 | if (bufsize > OPROMMAXPARAM) | 90 | if (bufsize > OPROMMAXPARAM) |
88 | bufsize = OPROMMAXPARAM; | 91 | bufsize = OPROMMAXPARAM; |
89 | 92 | ||
90 | if (!(*opp_p = kmalloc(sizeof(int) + bufsize + 1, GFP_KERNEL))) | 93 | if (!(*opp_p = kzalloc(sizeof(int) + bufsize + 1, GFP_KERNEL))) |
91 | return -ENOMEM; | 94 | return -ENOMEM; |
92 | memset(*opp_p, 0, sizeof(int) + bufsize + 1); | ||
93 | 95 | ||
94 | if (copy_from_user(&(*opp_p)->oprom_array, | 96 | if (copy_from_user(&(*opp_p)->oprom_array, |
95 | &info->oprom_array, bufsize)) { | 97 | &info->oprom_array, bufsize)) { |
@@ -107,10 +109,9 @@ static int getstrings(struct openpromio __user *info, struct openpromio **opp_p) | |||
107 | if (!info || !opp_p) | 109 | if (!info || !opp_p) |
108 | return -EFAULT; | 110 | return -EFAULT; |
109 | 111 | ||
110 | if (!(*opp_p = kmalloc(sizeof(int) + OPROMMAXPARAM + 1, GFP_KERNEL))) | 112 | if (!(*opp_p = kzalloc(sizeof(int) + OPROMMAXPARAM + 1, GFP_KERNEL))) |
111 | return -ENOMEM; | 113 | return -ENOMEM; |
112 | 114 | ||
113 | memset(*opp_p, 0, sizeof(int) + OPROMMAXPARAM + 1); | ||
114 | (*opp_p)->oprom_size = 0; | 115 | (*opp_p)->oprom_size = 0; |
115 | 116 | ||
116 | n = bufsize = 0; | 117 | n = bufsize = 0; |
@@ -140,16 +141,164 @@ static int copyout(void __user *info, struct openpromio *opp, int len) | |||
140 | return 0; | 141 | return 0; |
141 | } | 142 | } |
142 | 143 | ||
144 | static int opromgetprop(void __user *argp, struct device_node *dp, struct openpromio *op, int bufsize) | ||
145 | { | ||
146 | void *pval; | ||
147 | int len; | ||
148 | |||
149 | pval = of_get_property(dp, op->oprom_array, &len); | ||
150 | if (!pval || len <= 0 || len > bufsize) | ||
151 | return copyout(argp, op, sizeof(int)); | ||
152 | |||
153 | memcpy(op->oprom_array, pval, len); | ||
154 | op->oprom_array[len] = '\0'; | ||
155 | op->oprom_size = len; | ||
156 | |||
157 | return copyout(argp, op, sizeof(int) + bufsize); | ||
158 | } | ||
159 | |||
160 | static int opromnxtprop(void __user *argp, struct device_node *dp, struct openpromio *op, int bufsize) | ||
161 | { | ||
162 | struct property *prop; | ||
163 | int len; | ||
164 | |||
165 | if (op->oprom_array[0] == '\0') { | ||
166 | prop = dp->properties; | ||
167 | if (!prop) | ||
168 | return copyout(argp, op, sizeof(int)); | ||
169 | len = strlen(prop->name); | ||
170 | } else { | ||
171 | prop = of_find_property(dp, op->oprom_array, NULL); | ||
172 | |||
173 | if (!prop || | ||
174 | !prop->next || | ||
175 | (len = strlen(prop->next->name)) + 1 > bufsize) | ||
176 | return copyout(argp, op, sizeof(int)); | ||
177 | |||
178 | prop = prop->next; | ||
179 | } | ||
180 | |||
181 | memcpy(op->oprom_array, prop->name, len); | ||
182 | op->oprom_array[len] = '\0'; | ||
183 | op->oprom_size = ++len; | ||
184 | |||
185 | return copyout(argp, op, sizeof(int) + bufsize); | ||
186 | } | ||
187 | |||
188 | static int opromsetopt(struct device_node *dp, struct openpromio *op, int bufsize) | ||
189 | { | ||
190 | char *buf = op->oprom_array + strlen(op->oprom_array) + 1; | ||
191 | int len = op->oprom_array + bufsize - buf; | ||
192 | |||
193 | return of_set_property(options_node, op->oprom_array, buf, len); | ||
194 | } | ||
195 | |||
196 | static int opromnext(void __user *argp, unsigned int cmd, struct device_node *dp, struct openpromio *op, int bufsize, DATA *data) | ||
197 | { | ||
198 | phandle ph; | ||
199 | |||
200 | BUILD_BUG_ON(sizeof(phandle) != sizeof(int)); | ||
201 | |||
202 | if (bufsize < sizeof(phandle)) | ||
203 | return -EINVAL; | ||
204 | |||
205 | ph = *((int *) op->oprom_array); | ||
206 | if (ph) { | ||
207 | dp = of_find_node_by_phandle(ph); | ||
208 | if (!dp) | ||
209 | return -EINVAL; | ||
210 | |||
211 | switch (cmd) { | ||
212 | case OPROMNEXT: | ||
213 | dp = dp->sibling; | ||
214 | break; | ||
215 | |||
216 | case OPROMCHILD: | ||
217 | dp = dp->child; | ||
218 | break; | ||
219 | |||
220 | case OPROMSETCUR: | ||
221 | default: | ||
222 | break; | ||
223 | }; | ||
224 | } else { | ||
225 | /* Sibling of node zero is the root node. */ | ||
226 | if (cmd != OPROMNEXT) | ||
227 | return -EINVAL; | ||
228 | |||
229 | dp = of_find_node_by_path("/"); | ||
230 | } | ||
231 | |||
232 | ph = 0; | ||
233 | if (dp) | ||
234 | ph = dp->node; | ||
235 | |||
236 | data->current_node = dp; | ||
237 | *((int *) op->oprom_array) = ph; | ||
238 | op->oprom_size = sizeof(phandle); | ||
239 | |||
240 | return copyout(argp, op, bufsize + sizeof(int)); | ||
241 | } | ||
242 | |||
243 | static int oprompci2node(void __user *argp, struct device_node *dp, struct openpromio *op, int bufsize, DATA *data) | ||
244 | { | ||
245 | int err = -EINVAL; | ||
246 | |||
247 | if (bufsize >= 2*sizeof(int)) { | ||
248 | #ifdef CONFIG_PCI | ||
249 | struct pci_dev *pdev; | ||
250 | struct pcidev_cookie *pcp; | ||
251 | pdev = pci_find_slot (((int *) op->oprom_array)[0], | ||
252 | ((int *) op->oprom_array)[1]); | ||
253 | |||
254 | pcp = pdev->sysdata; | ||
255 | if (pcp != NULL) { | ||
256 | dp = pcp->prom_node; | ||
257 | data->current_node = dp; | ||
258 | *((int *)op->oprom_array) = dp->node; | ||
259 | op->oprom_size = sizeof(int); | ||
260 | err = copyout(argp, op, bufsize + sizeof(int)); | ||
261 | } | ||
262 | #endif | ||
263 | } | ||
264 | |||
265 | return err; | ||
266 | } | ||
267 | |||
268 | static int oprompath2node(void __user *argp, struct device_node *dp, struct openpromio *op, int bufsize, DATA *data) | ||
269 | { | ||
270 | dp = of_find_node_by_path(op->oprom_array); | ||
271 | data->current_node = dp; | ||
272 | *((int *)op->oprom_array) = dp->node; | ||
273 | op->oprom_size = sizeof(int); | ||
274 | |||
275 | return copyout(argp, op, bufsize + sizeof(int)); | ||
276 | } | ||
277 | |||
278 | static int opromgetbootargs(void __user *argp, struct openpromio *op, int bufsize) | ||
279 | { | ||
280 | char *buf = saved_command_line; | ||
281 | int len = strlen(buf); | ||
282 | |||
283 | if (len > bufsize) | ||
284 | return -EINVAL; | ||
285 | |||
286 | strcpy(op->oprom_array, buf); | ||
287 | op->oprom_size = len; | ||
288 | |||
289 | return copyout(argp, op, bufsize + sizeof(int)); | ||
290 | } | ||
291 | |||
143 | /* | 292 | /* |
144 | * SunOS and Solaris /dev/openprom ioctl calls. | 293 | * SunOS and Solaris /dev/openprom ioctl calls. |
145 | */ | 294 | */ |
146 | static int openprom_sunos_ioctl(struct inode * inode, struct file * file, | 295 | static int openprom_sunos_ioctl(struct inode * inode, struct file * file, |
147 | unsigned int cmd, unsigned long arg, int node) | 296 | unsigned int cmd, unsigned long arg, |
297 | struct device_node *dp) | ||
148 | { | 298 | { |
149 | DATA *data = (DATA *) file->private_data; | 299 | DATA *data = file->private_data; |
150 | char buffer[OPROMMAXPARAM+1], *buf; | ||
151 | struct openpromio *opp; | 300 | struct openpromio *opp; |
152 | int bufsize, len, error = 0; | 301 | int bufsize, error = 0; |
153 | static int cnt; | 302 | static int cnt; |
154 | void __user *argp = (void __user *)arg; | 303 | void __user *argp = (void __user *)arg; |
155 | 304 | ||
@@ -164,119 +313,35 @@ static int openprom_sunos_ioctl(struct inode * inode, struct file * file, | |||
164 | switch (cmd) { | 313 | switch (cmd) { |
165 | case OPROMGETOPT: | 314 | case OPROMGETOPT: |
166 | case OPROMGETPROP: | 315 | case OPROMGETPROP: |
167 | len = prom_getproplen(node, opp->oprom_array); | 316 | error = opromgetprop(argp, dp, opp, bufsize); |
168 | |||
169 | if (len <= 0 || len > bufsize) { | ||
170 | error = copyout(argp, opp, sizeof(int)); | ||
171 | break; | ||
172 | } | ||
173 | |||
174 | len = prom_getproperty(node, opp->oprom_array, buffer, bufsize); | ||
175 | |||
176 | memcpy(opp->oprom_array, buffer, len); | ||
177 | opp->oprom_array[len] = '\0'; | ||
178 | opp->oprom_size = len; | ||
179 | |||
180 | error = copyout(argp, opp, sizeof(int) + bufsize); | ||
181 | break; | 317 | break; |
182 | 318 | ||
183 | case OPROMNXTOPT: | 319 | case OPROMNXTOPT: |
184 | case OPROMNXTPROP: | 320 | case OPROMNXTPROP: |
185 | buf = prom_nextprop(node, opp->oprom_array, buffer); | 321 | error = opromnxtprop(argp, dp, opp, bufsize); |
186 | |||
187 | len = strlen(buf); | ||
188 | if (len == 0 || len + 1 > bufsize) { | ||
189 | error = copyout(argp, opp, sizeof(int)); | ||
190 | break; | ||
191 | } | ||
192 | |||
193 | memcpy(opp->oprom_array, buf, len); | ||
194 | opp->oprom_array[len] = '\0'; | ||
195 | opp->oprom_size = ++len; | ||
196 | |||
197 | error = copyout(argp, opp, sizeof(int) + bufsize); | ||
198 | break; | 322 | break; |
199 | 323 | ||
200 | case OPROMSETOPT: | 324 | case OPROMSETOPT: |
201 | case OPROMSETOPT2: | 325 | case OPROMSETOPT2: |
202 | buf = opp->oprom_array + strlen(opp->oprom_array) + 1; | 326 | error = opromsetopt(dp, opp, bufsize); |
203 | len = opp->oprom_array + bufsize - buf; | ||
204 | |||
205 | error = prom_setprop(options_node, opp->oprom_array, | ||
206 | buf, len); | ||
207 | |||
208 | if (error < 0) | ||
209 | error = -EINVAL; | ||
210 | break; | 327 | break; |
211 | 328 | ||
212 | case OPROMNEXT: | 329 | case OPROMNEXT: |
213 | case OPROMCHILD: | 330 | case OPROMCHILD: |
214 | case OPROMSETCUR: | 331 | case OPROMSETCUR: |
215 | if (bufsize < sizeof(int)) { | 332 | error = opromnext(argp, cmd, dp, opp, bufsize, data); |
216 | error = -EINVAL; | ||
217 | break; | ||
218 | } | ||
219 | |||
220 | node = *((int *) opp->oprom_array); | ||
221 | |||
222 | switch (cmd) { | ||
223 | case OPROMNEXT: node = __prom_getsibling(node); break; | ||
224 | case OPROMCHILD: node = __prom_getchild(node); break; | ||
225 | case OPROMSETCUR: break; | ||
226 | } | ||
227 | |||
228 | data->current_node = node; | ||
229 | *((int *)opp->oprom_array) = node; | ||
230 | opp->oprom_size = sizeof(int); | ||
231 | |||
232 | error = copyout(argp, opp, bufsize + sizeof(int)); | ||
233 | break; | 333 | break; |
234 | 334 | ||
235 | case OPROMPCI2NODE: | 335 | case OPROMPCI2NODE: |
236 | error = -EINVAL; | 336 | error = oprompci2node(argp, dp, opp, bufsize, data); |
237 | |||
238 | if (bufsize >= 2*sizeof(int)) { | ||
239 | #ifdef CONFIG_PCI | ||
240 | struct pci_dev *pdev; | ||
241 | struct pcidev_cookie *pcp; | ||
242 | pdev = pci_find_slot (((int *) opp->oprom_array)[0], | ||
243 | ((int *) opp->oprom_array)[1]); | ||
244 | |||
245 | pcp = pdev->sysdata; | ||
246 | if (pcp != NULL) { | ||
247 | node = pcp->prom_node->node; | ||
248 | data->current_node = node; | ||
249 | *((int *)opp->oprom_array) = node; | ||
250 | opp->oprom_size = sizeof(int); | ||
251 | error = copyout(argp, opp, bufsize + sizeof(int)); | ||
252 | } | ||
253 | #endif | ||
254 | } | ||
255 | break; | 337 | break; |
256 | 338 | ||
257 | case OPROMPATH2NODE: | 339 | case OPROMPATH2NODE: |
258 | node = prom_finddevice(opp->oprom_array); | 340 | error = oprompath2node(argp, dp, opp, bufsize, data); |
259 | data->current_node = node; | ||
260 | *((int *)opp->oprom_array) = node; | ||
261 | opp->oprom_size = sizeof(int); | ||
262 | |||
263 | error = copyout(argp, opp, bufsize + sizeof(int)); | ||
264 | break; | 341 | break; |
265 | 342 | ||
266 | case OPROMGETBOOTARGS: | 343 | case OPROMGETBOOTARGS: |
267 | buf = saved_command_line; | 344 | error = opromgetbootargs(argp, opp, bufsize); |
268 | |||
269 | len = strlen(buf); | ||
270 | |||
271 | if (len > bufsize) { | ||
272 | error = -EINVAL; | ||
273 | break; | ||
274 | } | ||
275 | |||
276 | strcpy(opp->oprom_array, buf); | ||
277 | opp->oprom_size = len; | ||
278 | |||
279 | error = copyout(argp, opp, bufsize + sizeof(int)); | ||
280 | break; | 345 | break; |
281 | 346 | ||
282 | case OPROMU2P: | 347 | case OPROMU2P: |
@@ -297,25 +362,14 @@ static int openprom_sunos_ioctl(struct inode * inode, struct file * file, | |||
297 | return error; | 362 | return error; |
298 | } | 363 | } |
299 | 364 | ||
300 | 365 | static struct device_node *get_node(phandle n, DATA *data) | |
301 | /* Return nonzero if a specific node is in the PROM device tree. */ | ||
302 | static int intree(int root, int node) | ||
303 | { | 366 | { |
304 | for (; root != 0; root = prom_getsibling(root)) | 367 | struct device_node *dp = of_find_node_by_phandle(n); |
305 | if (root == node || intree(prom_getchild(root),node)) | ||
306 | return 1; | ||
307 | return 0; | ||
308 | } | ||
309 | 368 | ||
310 | /* Return nonzero if a specific node is "valid". */ | 369 | if (dp) |
311 | static int goodnode(int n, DATA *data) | 370 | data->lastnode = dp; |
312 | { | 371 | |
313 | if (n == data->lastnode || n == prom_root_node || n == options_node) | 372 | return dp; |
314 | return 1; | ||
315 | if (n == 0 || n == -1 || !intree(prom_root_node,n)) | ||
316 | return 0; | ||
317 | data->lastnode = n; | ||
318 | return 1; | ||
319 | } | 373 | } |
320 | 374 | ||
321 | /* Copy in a whole string from userspace into kernelspace. */ | 375 | /* Copy in a whole string from userspace into kernelspace. */ |
@@ -330,7 +384,7 @@ static int copyin_string(char __user *user, size_t len, char **ptr) | |||
330 | if (!tmp) | 384 | if (!tmp) |
331 | return -ENOMEM; | 385 | return -ENOMEM; |
332 | 386 | ||
333 | if(copy_from_user(tmp, user, len)) { | 387 | if (copy_from_user(tmp, user, len)) { |
334 | kfree(tmp); | 388 | kfree(tmp); |
335 | return -EFAULT; | 389 | return -EFAULT; |
336 | } | 390 | } |
@@ -345,162 +399,187 @@ static int copyin_string(char __user *user, size_t len, char **ptr) | |||
345 | /* | 399 | /* |
346 | * NetBSD /dev/openprom ioctl calls. | 400 | * NetBSD /dev/openprom ioctl calls. |
347 | */ | 401 | */ |
348 | static int openprom_bsd_ioctl(struct inode * inode, struct file * file, | 402 | static int opiocget(void __user *argp, DATA *data) |
349 | unsigned int cmd, unsigned long arg) | ||
350 | { | 403 | { |
351 | DATA *data = (DATA *) file->private_data; | ||
352 | void __user *argp = (void __user *)arg; | ||
353 | struct opiocdesc op; | 404 | struct opiocdesc op; |
354 | int error, node, len; | 405 | struct device_node *dp; |
355 | char *str, *tmp; | 406 | char *str; |
356 | char buffer[64]; | 407 | void *pval; |
357 | static int cnt; | 408 | int err, len; |
358 | |||
359 | switch (cmd) { | ||
360 | case OPIOCGET: | ||
361 | if (copy_from_user(&op, argp, sizeof(op))) | ||
362 | return -EFAULT; | ||
363 | |||
364 | if (!goodnode(op.op_nodeid,data)) | ||
365 | return -EINVAL; | ||
366 | 409 | ||
367 | error = copyin_string(op.op_name, op.op_namelen, &str); | 410 | if (copy_from_user(&op, argp, sizeof(op))) |
368 | if (error) | 411 | return -EFAULT; |
369 | return error; | ||
370 | 412 | ||
371 | len = prom_getproplen(op.op_nodeid,str); | 413 | dp = get_node(op.op_nodeid, data); |
372 | 414 | ||
373 | if (len > op.op_buflen) { | 415 | err = copyin_string(op.op_name, op.op_namelen, &str); |
374 | kfree(str); | 416 | if (err) |
375 | return -ENOMEM; | 417 | return err; |
376 | } | ||
377 | 418 | ||
419 | pval = of_get_property(dp, str, &len); | ||
420 | err = 0; | ||
421 | if (!pval || len > op.op_buflen) { | ||
422 | err = -EINVAL; | ||
423 | } else { | ||
378 | op.op_buflen = len; | 424 | op.op_buflen = len; |
425 | if (copy_to_user(argp, &op, sizeof(op)) || | ||
426 | copy_to_user(op.op_buf, pval, len)) | ||
427 | err = -EFAULT; | ||
428 | } | ||
429 | kfree(str); | ||
379 | 430 | ||
380 | if (len <= 0) { | 431 | return err; |
381 | kfree(str); | 432 | } |
382 | /* Verified by the above copy_from_user */ | ||
383 | if (__copy_to_user(argp, &op, | ||
384 | sizeof(op))) | ||
385 | return -EFAULT; | ||
386 | return 0; | ||
387 | } | ||
388 | 433 | ||
389 | tmp = kmalloc(len + 1, GFP_KERNEL); | 434 | static int opiocnextprop(void __user *argp, DATA *data) |
390 | if (!tmp) { | 435 | { |
391 | kfree(str); | 436 | struct opiocdesc op; |
392 | return -ENOMEM; | 437 | struct device_node *dp; |
393 | } | 438 | struct property *prop; |
439 | char *str; | ||
440 | int err, len; | ||
394 | 441 | ||
395 | cnt = prom_getproperty(op.op_nodeid, str, tmp, len); | 442 | if (copy_from_user(&op, argp, sizeof(op))) |
396 | if (cnt <= 0) { | 443 | return -EFAULT; |
397 | error = -EINVAL; | ||
398 | } else { | ||
399 | tmp[len] = '\0'; | ||
400 | 444 | ||
401 | if (__copy_to_user(argp, &op, sizeof(op)) != 0 || | 445 | dp = get_node(op.op_nodeid, data); |
402 | copy_to_user(op.op_buf, tmp, len) != 0) | 446 | if (!dp) |
403 | error = -EFAULT; | 447 | return -EINVAL; |
404 | } | ||
405 | 448 | ||
406 | kfree(tmp); | 449 | err = copyin_string(op.op_name, op.op_namelen, &str); |
407 | kfree(str); | 450 | if (err) |
451 | return err; | ||
408 | 452 | ||
409 | return error; | 453 | if (str[0] == '\0') { |
454 | prop = dp->properties; | ||
455 | } else { | ||
456 | prop = of_find_property(dp, str, NULL); | ||
457 | if (prop) | ||
458 | prop = prop->next; | ||
459 | } | ||
460 | kfree(str); | ||
410 | 461 | ||
411 | case OPIOCNEXTPROP: | 462 | if (!prop) |
412 | if (copy_from_user(&op, argp, sizeof(op))) | 463 | len = 0; |
413 | return -EFAULT; | 464 | else |
465 | len = prop->length; | ||
414 | 466 | ||
415 | if (!goodnode(op.op_nodeid,data)) | 467 | if (len > op.op_buflen) |
416 | return -EINVAL; | 468 | len = op.op_buflen; |
417 | 469 | ||
418 | error = copyin_string(op.op_name, op.op_namelen, &str); | 470 | if (copy_to_user(argp, &op, sizeof(op))) |
419 | if (error) | 471 | return -EFAULT; |
420 | return error; | ||
421 | 472 | ||
422 | tmp = prom_nextprop(op.op_nodeid,str,buffer); | 473 | if (len && |
474 | copy_to_user(op.op_buf, prop->value, len)) | ||
475 | return -EFAULT; | ||
423 | 476 | ||
424 | if (tmp) { | 477 | return 0; |
425 | len = strlen(tmp); | 478 | } |
426 | if (len > op.op_buflen) | ||
427 | len = op.op_buflen; | ||
428 | else | ||
429 | op.op_buflen = len; | ||
430 | } else { | ||
431 | len = op.op_buflen = 0; | ||
432 | } | ||
433 | 479 | ||
434 | if (!access_ok(VERIFY_WRITE, argp, sizeof(op))) { | 480 | static int opiocset(void __user *argp, DATA *data) |
435 | kfree(str); | 481 | { |
436 | return -EFAULT; | 482 | struct opiocdesc op; |
437 | } | 483 | struct device_node *dp; |
484 | char *str, *tmp; | ||
485 | int err; | ||
438 | 486 | ||
439 | if (!access_ok(VERIFY_WRITE, op.op_buf, len)) { | 487 | if (copy_from_user(&op, argp, sizeof(op))) |
440 | kfree(str); | 488 | return -EFAULT; |
441 | return -EFAULT; | 489 | |
442 | } | 490 | dp = get_node(op.op_nodeid, data); |
491 | if (!dp) | ||
492 | return -EINVAL; | ||
443 | 493 | ||
444 | error = __copy_to_user(argp, &op, sizeof(op)); | 494 | err = copyin_string(op.op_name, op.op_namelen, &str); |
445 | if (!error) error = __copy_to_user(op.op_buf, tmp, len); | 495 | if (err) |
496 | return err; | ||
446 | 497 | ||
498 | err = copyin_string(op.op_buf, op.op_buflen, &tmp); | ||
499 | if (err) { | ||
447 | kfree(str); | 500 | kfree(str); |
501 | return err; | ||
502 | } | ||
448 | 503 | ||
449 | return error; | 504 | err = of_set_property(dp, str, tmp, op.op_buflen); |
450 | 505 | ||
451 | case OPIOCSET: | 506 | kfree(str); |
452 | if (copy_from_user(&op, argp, sizeof(op))) | 507 | kfree(tmp); |
453 | return -EFAULT; | ||
454 | 508 | ||
455 | if (!goodnode(op.op_nodeid,data)) | 509 | return err; |
456 | return -EINVAL; | 510 | } |
457 | 511 | ||
458 | error = copyin_string(op.op_name, op.op_namelen, &str); | 512 | static int opiocgetnext(unsigned int cmd, void __user *argp) |
459 | if (error) | 513 | { |
460 | return error; | 514 | struct device_node *dp; |
515 | phandle nd; | ||
461 | 516 | ||
462 | error = copyin_string(op.op_buf, op.op_buflen, &tmp); | 517 | BUILD_BUG_ON(sizeof(phandle) != sizeof(int)); |
463 | if (error) { | ||
464 | kfree(str); | ||
465 | return error; | ||
466 | } | ||
467 | 518 | ||
468 | len = prom_setprop(op.op_nodeid,str,tmp,op.op_buflen+1); | 519 | if (copy_from_user(&nd, argp, sizeof(phandle))) |
520 | return -EFAULT; | ||
469 | 521 | ||
470 | if (len != op.op_buflen) | 522 | if (nd == 0) { |
523 | if (cmd != OPIOCGETNEXT) | ||
471 | return -EINVAL; | 524 | return -EINVAL; |
525 | dp = of_find_node_by_path("/"); | ||
526 | } else { | ||
527 | dp = of_find_node_by_phandle(nd); | ||
528 | nd = 0; | ||
529 | if (dp) { | ||
530 | if (cmd == OPIOCGETNEXT) | ||
531 | dp = dp->sibling; | ||
532 | else | ||
533 | dp = dp->child; | ||
534 | } | ||
535 | } | ||
536 | if (dp) | ||
537 | nd = dp->node; | ||
538 | if (copy_to_user(argp, &nd, sizeof(phandle))) | ||
539 | return -EFAULT; | ||
472 | 540 | ||
473 | kfree(str); | 541 | return 0; |
474 | kfree(tmp); | 542 | } |
475 | 543 | ||
476 | return 0; | 544 | static int openprom_bsd_ioctl(struct inode * inode, struct file * file, |
545 | unsigned int cmd, unsigned long arg) | ||
546 | { | ||
547 | DATA *data = (DATA *) file->private_data; | ||
548 | void __user *argp = (void __user *)arg; | ||
549 | int err; | ||
477 | 550 | ||
478 | case OPIOCGETOPTNODE: | 551 | switch (cmd) { |
479 | if (copy_to_user(argp, &options_node, sizeof(int))) | 552 | case OPIOCGET: |
480 | return -EFAULT; | 553 | err = opiocget(argp, data); |
481 | return 0; | 554 | break; |
482 | 555 | ||
483 | case OPIOCGETNEXT: | 556 | case OPIOCNEXTPROP: |
484 | case OPIOCGETCHILD: | 557 | err = opiocnextprop(argp, data); |
485 | if (copy_from_user(&node, argp, sizeof(int))) | 558 | break; |
486 | return -EFAULT; | ||
487 | 559 | ||
488 | if (cmd == OPIOCGETNEXT) | 560 | case OPIOCSET: |
489 | node = __prom_getsibling(node); | 561 | err = opiocset(argp, data); |
490 | else | 562 | break; |
491 | node = __prom_getchild(node); | 563 | |
564 | case OPIOCGETOPTNODE: | ||
565 | BUILD_BUG_ON(sizeof(phandle) != sizeof(int)); | ||
492 | 566 | ||
493 | if (__copy_to_user(argp, &node, sizeof(int))) | 567 | if (copy_to_user(argp, &options_node->node, sizeof(phandle))) |
494 | return -EFAULT; | 568 | return -EFAULT; |
495 | 569 | ||
496 | return 0; | 570 | return 0; |
497 | 571 | ||
572 | case OPIOCGETNEXT: | ||
573 | case OPIOCGETCHILD: | ||
574 | err = opiocgetnext(cmd, argp); | ||
575 | break; | ||
576 | |||
498 | default: | 577 | default: |
499 | if (cnt++ < 10) | ||
500 | printk(KERN_INFO "openprom_bsd_ioctl: cmd 0x%X\n", cmd); | ||
501 | return -EINVAL; | 578 | return -EINVAL; |
502 | 579 | ||
503 | } | 580 | }; |
581 | |||
582 | return err; | ||
504 | } | 583 | } |
505 | 584 | ||
506 | 585 | ||
@@ -511,7 +590,6 @@ static int openprom_ioctl(struct inode * inode, struct file * file, | |||
511 | unsigned int cmd, unsigned long arg) | 590 | unsigned int cmd, unsigned long arg) |
512 | { | 591 | { |
513 | DATA *data = (DATA *) file->private_data; | 592 | DATA *data = (DATA *) file->private_data; |
514 | static int cnt; | ||
515 | 593 | ||
516 | switch (cmd) { | 594 | switch (cmd) { |
517 | case OPROMGETOPT: | 595 | case OPROMGETOPT: |
@@ -563,10 +641,8 @@ static int openprom_ioctl(struct inode * inode, struct file * file, | |||
563 | return openprom_bsd_ioctl(inode,file,cmd,arg); | 641 | return openprom_bsd_ioctl(inode,file,cmd,arg); |
564 | 642 | ||
565 | default: | 643 | default: |
566 | if (cnt++ < 10) | ||
567 | printk("openprom_ioctl: cmd 0x%X, arg 0x%lX\n", cmd, arg); | ||
568 | return -EINVAL; | 644 | return -EINVAL; |
569 | } | 645 | }; |
570 | } | 646 | } |
571 | 647 | ||
572 | static long openprom_compat_ioctl(struct file *file, unsigned int cmd, | 648 | static long openprom_compat_ioctl(struct file *file, unsigned int cmd, |
@@ -594,9 +670,7 @@ static long openprom_compat_ioctl(struct file *file, unsigned int cmd, | |||
594 | case OPROMSETCUR: | 670 | case OPROMSETCUR: |
595 | case OPROMPCI2NODE: | 671 | case OPROMPCI2NODE: |
596 | case OPROMPATH2NODE: | 672 | case OPROMPATH2NODE: |
597 | lock_kernel(); | ||
598 | rval = openprom_ioctl(file->f_dentry->d_inode, file, cmd, arg); | 673 | rval = openprom_ioctl(file->f_dentry->d_inode, file, cmd, arg); |
599 | lock_kernel(); | ||
600 | break; | 674 | break; |
601 | } | 675 | } |
602 | 676 | ||
@@ -607,13 +681,13 @@ static int openprom_open(struct inode * inode, struct file * file) | |||
607 | { | 681 | { |
608 | DATA *data; | 682 | DATA *data; |
609 | 683 | ||
610 | data = (DATA *) kmalloc(sizeof(DATA), GFP_KERNEL); | 684 | data = kmalloc(sizeof(DATA), GFP_KERNEL); |
611 | if (!data) | 685 | if (!data) |
612 | return -ENOMEM; | 686 | return -ENOMEM; |
613 | 687 | ||
614 | data->current_node = prom_root_node; | 688 | data->current_node = of_find_node_by_path("/"); |
615 | data->lastnode = prom_root_node; | 689 | data->lastnode = data->current_node; |
616 | file->private_data = (void *)data; | 690 | file->private_data = (void *) data; |
617 | 691 | ||
618 | return 0; | 692 | return 0; |
619 | } | 693 | } |
@@ -634,24 +708,30 @@ static struct file_operations openprom_fops = { | |||
634 | }; | 708 | }; |
635 | 709 | ||
636 | static struct miscdevice openprom_dev = { | 710 | static struct miscdevice openprom_dev = { |
637 | SUN_OPENPROM_MINOR, "openprom", &openprom_fops | 711 | .minor = SUN_OPENPROM_MINOR, |
712 | .name = "openprom", | ||
713 | .fops = &openprom_fops, | ||
638 | }; | 714 | }; |
639 | 715 | ||
640 | static int __init openprom_init(void) | 716 | static int __init openprom_init(void) |
641 | { | 717 | { |
642 | int error; | 718 | struct device_node *dp; |
719 | int err; | ||
643 | 720 | ||
644 | error = misc_register(&openprom_dev); | 721 | err = misc_register(&openprom_dev); |
645 | if (error) { | 722 | if (err) |
646 | printk(KERN_ERR "openprom: unable to get misc minor\n"); | 723 | return err; |
647 | return error; | ||
648 | } | ||
649 | 724 | ||
650 | options_node = prom_getchild(prom_root_node); | 725 | dp = of_find_node_by_path("/"); |
651 | options_node = prom_searchsiblings(options_node,"options"); | 726 | dp = dp->child; |
727 | while (dp) { | ||
728 | if (!strcmp(dp->name, "options")) | ||
729 | break; | ||
730 | dp = dp->sibling; | ||
731 | } | ||
732 | options_node = dp; | ||
652 | 733 | ||
653 | if (options_node == 0 || options_node == -1) { | 734 | if (!options_node) { |
654 | printk(KERN_ERR "openprom: unable to find options node\n"); | ||
655 | misc_deregister(&openprom_dev); | 735 | misc_deregister(&openprom_dev); |
656 | return -EIO; | 736 | return -EIO; |
657 | } | 737 | } |
@@ -666,4 +746,3 @@ static void __exit openprom_cleanup(void) | |||
666 | 746 | ||
667 | module_init(openprom_init); | 747 | module_init(openprom_init); |
668 | module_exit(openprom_cleanup); | 748 | module_exit(openprom_cleanup); |
669 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/sbus/char/riowatchdog.c b/drivers/sbus/char/riowatchdog.c index d1babff6a535..2a9cc8204429 100644 --- a/drivers/sbus/char/riowatchdog.c +++ b/drivers/sbus/char/riowatchdog.c | |||
@@ -211,7 +211,7 @@ static int __init riowd_bbc_init(void) | |||
211 | 211 | ||
212 | for_each_ebus(ebus) { | 212 | for_each_ebus(ebus) { |
213 | for_each_ebusdev(edev, ebus) { | 213 | for_each_ebusdev(edev, ebus) { |
214 | if (!strcmp(edev->prom_name, "bbc")) | 214 | if (!strcmp(edev->ofdev.node->name, "bbc")) |
215 | goto found_bbc; | 215 | goto found_bbc; |
216 | } | 216 | } |
217 | } | 217 | } |
@@ -238,7 +238,7 @@ static int __init riowd_init(void) | |||
238 | 238 | ||
239 | for_each_ebus(ebus) { | 239 | for_each_ebus(ebus) { |
240 | for_each_ebusdev(edev, ebus) { | 240 | for_each_ebusdev(edev, ebus) { |
241 | if (!strcmp(edev->prom_name, RIOWD_NAME)) | 241 | if (!strcmp(edev->ofdev.node->name, RIOWD_NAME)) |
242 | goto ebus_done; | 242 | goto ebus_done; |
243 | } | 243 | } |
244 | } | 244 | } |
diff --git a/drivers/scsi/aacraid/comminit.c b/drivers/scsi/aacraid/comminit.c index 35b0a6ebd3f5..7cea514e810a 100644 --- a/drivers/scsi/aacraid/comminit.c +++ b/drivers/scsi/aacraid/comminit.c | |||
@@ -104,8 +104,11 @@ static int aac_alloc_comm(struct aac_dev *dev, void **commaddr, unsigned long co | |||
104 | * always true on real computers. It also has some slight problems | 104 | * always true on real computers. It also has some slight problems |
105 | * with the GART on x86-64. I've btw never tried DMA from PCI space | 105 | * with the GART on x86-64. I've btw never tried DMA from PCI space |
106 | * on this platform but don't be surprised if its problematic. | 106 | * on this platform but don't be surprised if its problematic. |
107 | * [AK: something is very very wrong when a driver tests this symbol. | ||
108 | * Someone should figure out what the comment writer really meant here and fix | ||
109 | * the code. Or just remove that bad code. ] | ||
107 | */ | 110 | */ |
108 | #ifndef CONFIG_GART_IOMMU | 111 | #ifndef CONFIG_IOMMU |
109 | if ((num_physpages << (PAGE_SHIFT - 12)) <= AAC_MAX_HOSTPHYSMEMPAGES) { | 112 | if ((num_physpages << (PAGE_SHIFT - 12)) <= AAC_MAX_HOSTPHYSMEMPAGES) { |
110 | init->HostPhysMemPages = | 113 | init->HostPhysMemPages = |
111 | cpu_to_le32(num_physpages << (PAGE_SHIFT-12)); | 114 | cpu_to_le32(num_physpages << (PAGE_SHIFT-12)); |
diff --git a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c index 6ab035590ee6..b28712df0b77 100644 --- a/drivers/scsi/ncr53c8xx.c +++ b/drivers/scsi/ncr53c8xx.c | |||
@@ -5118,8 +5118,7 @@ static void ncr_ccb_skipped(struct ncb *np, struct ccb *cp) | |||
5118 | cp->host_status &= ~HS_SKIPMASK; | 5118 | cp->host_status &= ~HS_SKIPMASK; |
5119 | cp->start.schedule.l_paddr = | 5119 | cp->start.schedule.l_paddr = |
5120 | cpu_to_scr(NCB_SCRIPT_PHYS (np, select)); | 5120 | cpu_to_scr(NCB_SCRIPT_PHYS (np, select)); |
5121 | list_del(&cp->link_ccbq); | 5121 | list_move_tail(&cp->link_ccbq, &lp->skip_ccbq); |
5122 | list_add_tail(&cp->link_ccbq, &lp->skip_ccbq); | ||
5123 | if (cp->queued) { | 5122 | if (cp->queued) { |
5124 | --lp->queuedccbs; | 5123 | --lp->queuedccbs; |
5125 | } | 5124 | } |
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index aef093db597e..3d4487eac9b7 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c | |||
@@ -2258,8 +2258,7 @@ qla2x00_configure_fabric(scsi_qla_host_t *ha) | |||
2258 | } | 2258 | } |
2259 | 2259 | ||
2260 | /* Remove device from the new list and add it to DB */ | 2260 | /* Remove device from the new list and add it to DB */ |
2261 | list_del(&fcport->list); | 2261 | list_move_tail(&fcport->list, &ha->fcports); |
2262 | list_add_tail(&fcport->list, &ha->fcports); | ||
2263 | 2262 | ||
2264 | /* Login and update database */ | 2263 | /* Login and update database */ |
2265 | qla2x00_fabric_dev_login(ha, fcport, &next_loopid); | 2264 | qla2x00_fabric_dev_login(ha, fcport, &next_loopid); |
diff --git a/drivers/usb/host/hc_crisv10.c b/drivers/usb/host/hc_crisv10.c index 2fe7fd19437b..4a22909518f5 100644 --- a/drivers/usb/host/hc_crisv10.c +++ b/drivers/usb/host/hc_crisv10.c | |||
@@ -411,8 +411,7 @@ static inline void urb_list_move_last(struct urb *urb, int epid) | |||
411 | urb_entry_t *urb_entry = __urb_list_entry(urb, epid); | 411 | urb_entry_t *urb_entry = __urb_list_entry(urb, epid); |
412 | assert(urb_entry); | 412 | assert(urb_entry); |
413 | 413 | ||
414 | list_del(&urb_entry->list); | 414 | list_move_tail(&urb_entry->list, &urb_list[epid]); |
415 | list_add_tail(&urb_entry->list, &urb_list[epid]); | ||
416 | } | 415 | } |
417 | 416 | ||
418 | /* Get the next urb in the list. */ | 417 | /* Get the next urb in the list. */ |
diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c index 5b06fa366098..56ffc81302fc 100644 --- a/drivers/usb/serial/whiteheat.c +++ b/drivers/usb/serial/whiteheat.c | |||
@@ -686,19 +686,16 @@ static void whiteheat_close(struct usb_serial_port *port, struct file * filp) | |||
686 | wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); | 686 | wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); |
687 | urb = wrap->urb; | 687 | urb = wrap->urb; |
688 | usb_kill_urb(urb); | 688 | usb_kill_urb(urb); |
689 | list_del(tmp); | 689 | list_move(tmp, &info->rx_urbs_free); |
690 | list_add(tmp, &info->rx_urbs_free); | ||
691 | } | ||
692 | list_for_each_safe(tmp, tmp2, &info->rx_urb_q) { | ||
693 | list_del(tmp); | ||
694 | list_add(tmp, &info->rx_urbs_free); | ||
695 | } | 690 | } |
691 | list_for_each_safe(tmp, tmp2, &info->rx_urb_q) | ||
692 | list_move(tmp, &info->rx_urbs_free); | ||
693 | |||
696 | list_for_each_safe(tmp, tmp2, &info->tx_urbs_submitted) { | 694 | list_for_each_safe(tmp, tmp2, &info->tx_urbs_submitted) { |
697 | wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); | 695 | wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); |
698 | urb = wrap->urb; | 696 | urb = wrap->urb; |
699 | usb_kill_urb(urb); | 697 | usb_kill_urb(urb); |
700 | list_del(tmp); | 698 | list_move(tmp, &info->tx_urbs_free); |
701 | list_add(tmp, &info->tx_urbs_free); | ||
702 | } | 699 | } |
703 | spin_unlock_irqrestore(&info->lock, flags); | 700 | spin_unlock_irqrestore(&info->lock, flags); |
704 | 701 | ||
@@ -1080,8 +1077,7 @@ static void whiteheat_write_callback(struct urb *urb, struct pt_regs *regs) | |||
1080 | err("%s - Not my urb!", __FUNCTION__); | 1077 | err("%s - Not my urb!", __FUNCTION__); |
1081 | return; | 1078 | return; |
1082 | } | 1079 | } |
1083 | list_del(&wrap->list); | 1080 | list_move(&wrap->list, &info->tx_urbs_free); |
1084 | list_add(&wrap->list, &info->tx_urbs_free); | ||
1085 | spin_unlock(&info->lock); | 1081 | spin_unlock(&info->lock); |
1086 | 1082 | ||
1087 | if (urb->status) { | 1083 | if (urb->status) { |
@@ -1371,8 +1367,7 @@ static int start_port_read(struct usb_serial_port *port) | |||
1371 | wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); | 1367 | wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); |
1372 | urb = wrap->urb; | 1368 | urb = wrap->urb; |
1373 | usb_kill_urb(urb); | 1369 | usb_kill_urb(urb); |
1374 | list_del(tmp); | 1370 | list_move(tmp, &info->rx_urbs_free); |
1375 | list_add(tmp, &info->rx_urbs_free); | ||
1376 | } | 1371 | } |
1377 | break; | 1372 | break; |
1378 | } | 1373 | } |
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 168ede7902bd..17de4c84db69 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig | |||
@@ -4,6 +4,21 @@ | |||
4 | 4 | ||
5 | menu "Graphics support" | 5 | menu "Graphics support" |
6 | 6 | ||
7 | config FIRMWARE_EDID | ||
8 | bool "Enable firmware EDID" | ||
9 | default y | ||
10 | ---help--- | ||
11 | This enables access to the EDID transferred from the firmware. | ||
12 | On the i386, this is from the Video BIOS. Enable this if DDC/I2C | ||
13 | transfers do not work for your driver and if you are using | ||
14 | nvidiafb, i810fb or savagefb. | ||
15 | |||
16 | In general, choosing Y for this option is safe. If you | ||
17 | experience extremely long delays while booting before you get | ||
18 | something on your display, try setting this to N. Matrox cards in | ||
19 | combination with certain motherboards and monitors are known to | ||
20 | suffer from this problem. | ||
21 | |||
7 | config FB | 22 | config FB |
8 | tristate "Support for frame buffer devices" | 23 | tristate "Support for frame buffer devices" |
9 | ---help--- | 24 | ---help--- |
@@ -70,22 +85,6 @@ config FB_MACMODES | |||
70 | depends on FB | 85 | depends on FB |
71 | default n | 86 | default n |
72 | 87 | ||
73 | config FB_FIRMWARE_EDID | ||
74 | bool "Enable firmware EDID" | ||
75 | depends on FB | ||
76 | default y | ||
77 | ---help--- | ||
78 | This enables access to the EDID transferred from the firmware. | ||
79 | On the i386, this is from the Video BIOS. Enable this if DDC/I2C | ||
80 | transfers do not work for your driver and if you are using | ||
81 | nvidiafb, i810fb or savagefb. | ||
82 | |||
83 | In general, choosing Y for this option is safe. If you | ||
84 | experience extremely long delays while booting before you get | ||
85 | something on your display, try setting this to N. Matrox cards in | ||
86 | combination with certain motherboards and monitors are known to | ||
87 | suffer from this problem. | ||
88 | |||
89 | config FB_BACKLIGHT | 88 | config FB_BACKLIGHT |
90 | bool | 89 | bool |
91 | depends on FB | 90 | depends on FB |
@@ -551,10 +550,14 @@ config FB_VESA | |||
551 | You will get a boot time penguin logo at no additional cost. Please | 550 | You will get a boot time penguin logo at no additional cost. Please |
552 | read <file:Documentation/fb/vesafb.txt>. If unsure, say Y. | 551 | read <file:Documentation/fb/vesafb.txt>. If unsure, say Y. |
553 | 552 | ||
554 | config VIDEO_SELECT | 553 | config FB_IMAC |
555 | bool | 554 | bool "Intel-based Macintosh Framebuffer Support" |
556 | depends on FB_VESA | 555 | depends on (FB = y) && X86 |
557 | default y | 556 | select FB_CFB_FILLRECT |
557 | select FB_CFB_COPYAREA | ||
558 | select FB_CFB_IMAGEBLIT | ||
559 | help | ||
560 | This is the frame buffer device driver for the Intel-based Macintosh | ||
558 | 561 | ||
559 | config FB_HGA | 562 | config FB_HGA |
560 | tristate "Hercules mono graphics support" | 563 | tristate "Hercules mono graphics support" |
@@ -578,12 +581,6 @@ config FB_HGA_ACCEL | |||
578 | This will compile the Hercules mono graphics with | 581 | This will compile the Hercules mono graphics with |
579 | acceleration functions. | 582 | acceleration functions. |
580 | 583 | ||
581 | |||
582 | config VIDEO_SELECT | ||
583 | bool | ||
584 | depends on (FB = y) && X86 | ||
585 | default y | ||
586 | |||
587 | config FB_SGIVW | 584 | config FB_SGIVW |
588 | tristate "SGI Visual Workstation framebuffer support" | 585 | tristate "SGI Visual Workstation framebuffer support" |
589 | depends on FB && X86_VISWS | 586 | depends on FB && X86_VISWS |
diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 23de3b2c7856..c335e9bc3b20 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile | |||
@@ -4,15 +4,15 @@ | |||
4 | 4 | ||
5 | # Each configuration option enables a list of files. | 5 | # Each configuration option enables a list of files. |
6 | 6 | ||
7 | obj-$(CONFIG_VT) += console/ | ||
8 | obj-$(CONFIG_LOGO) += logo/ | ||
9 | obj-$(CONFIG_SYSFS) += backlight/ | ||
10 | |||
11 | obj-$(CONFIG_FB) += fb.o | 7 | obj-$(CONFIG_FB) += fb.o |
12 | fb-y := fbmem.o fbmon.o fbcmap.o fbsysfs.o \ | 8 | fb-y := fbmem.o fbmon.o fbcmap.o fbsysfs.o \ |
13 | modedb.o fbcvt.o | 9 | modedb.o fbcvt.o |
14 | fb-objs := $(fb-y) | 10 | fb-objs := $(fb-y) |
15 | 11 | ||
12 | obj-$(CONFIG_VT) += console/ | ||
13 | obj-$(CONFIG_LOGO) += logo/ | ||
14 | obj-$(CONFIG_SYSFS) += backlight/ | ||
15 | |||
16 | obj-$(CONFIG_FB_CFB_FILLRECT) += cfbfillrect.o | 16 | obj-$(CONFIG_FB_CFB_FILLRECT) += cfbfillrect.o |
17 | obj-$(CONFIG_FB_CFB_COPYAREA) += cfbcopyarea.o | 17 | obj-$(CONFIG_FB_CFB_COPYAREA) += cfbcopyarea.o |
18 | obj-$(CONFIG_FB_CFB_IMAGEBLIT) += cfbimgblt.o | 18 | obj-$(CONFIG_FB_CFB_IMAGEBLIT) += cfbimgblt.o |
@@ -97,6 +97,7 @@ obj-$(CONFIG_FB_S3C2410) += s3c2410fb.o | |||
97 | 97 | ||
98 | # Platform or fallback drivers go here | 98 | # Platform or fallback drivers go here |
99 | obj-$(CONFIG_FB_VESA) += vesafb.o | 99 | obj-$(CONFIG_FB_VESA) += vesafb.o |
100 | obj-$(CONFIG_FB_IMAC) += imacfb.o | ||
100 | obj-$(CONFIG_FB_VGA16) += vga16fb.o vgastate.o | 101 | obj-$(CONFIG_FB_VGA16) += vga16fb.o vgastate.o |
101 | obj-$(CONFIG_FB_OF) += offb.o | 102 | obj-$(CONFIG_FB_OF) += offb.o |
102 | 103 | ||
diff --git a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c index db878fd55fb2..11cf7fcb1d55 100644 --- a/drivers/video/aty/aty128fb.c +++ b/drivers/video/aty/aty128fb.c | |||
@@ -100,7 +100,7 @@ | |||
100 | 100 | ||
101 | #ifndef CONFIG_PPC_PMAC | 101 | #ifndef CONFIG_PPC_PMAC |
102 | /* default mode */ | 102 | /* default mode */ |
103 | static struct fb_var_screeninfo default_var __initdata = { | 103 | static struct fb_var_screeninfo default_var __devinitdata = { |
104 | /* 640x480, 60 Hz, Non-Interlaced (25.175 MHz dotclock) */ | 104 | /* 640x480, 60 Hz, Non-Interlaced (25.175 MHz dotclock) */ |
105 | 640, 480, 640, 480, 0, 0, 8, 0, | 105 | 640, 480, 640, 480, 0, 0, 8, 0, |
106 | {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, | 106 | {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, |
@@ -123,7 +123,7 @@ static struct fb_var_screeninfo default_var = { | |||
123 | 123 | ||
124 | /* default modedb mode */ | 124 | /* default modedb mode */ |
125 | /* 640x480, 60 Hz, Non-Interlaced (25.172 MHz dotclock) */ | 125 | /* 640x480, 60 Hz, Non-Interlaced (25.172 MHz dotclock) */ |
126 | static struct fb_videomode defaultmode __initdata = { | 126 | static struct fb_videomode defaultmode __devinitdata = { |
127 | .refresh = 60, | 127 | .refresh = 60, |
128 | .xres = 640, | 128 | .xres = 640, |
129 | .yres = 480, | 129 | .yres = 480, |
@@ -335,7 +335,7 @@ static const struct aty128_meminfo sdr_sgram = | |||
335 | static const struct aty128_meminfo ddr_sgram = | 335 | static const struct aty128_meminfo ddr_sgram = |
336 | { 4, 4, 3, 3, 2, 3, 1, 16, 31, 16, "64-bit DDR SGRAM" }; | 336 | { 4, 4, 3, 3, 2, 3, 1, 16, 31, 16, "64-bit DDR SGRAM" }; |
337 | 337 | ||
338 | static struct fb_fix_screeninfo aty128fb_fix __initdata = { | 338 | static struct fb_fix_screeninfo aty128fb_fix __devinitdata = { |
339 | .id = "ATY Rage128", | 339 | .id = "ATY Rage128", |
340 | .type = FB_TYPE_PACKED_PIXELS, | 340 | .type = FB_TYPE_PACKED_PIXELS, |
341 | .visual = FB_VISUAL_PSEUDOCOLOR, | 341 | .visual = FB_VISUAL_PSEUDOCOLOR, |
@@ -345,15 +345,15 @@ static struct fb_fix_screeninfo aty128fb_fix __initdata = { | |||
345 | .accel = FB_ACCEL_ATI_RAGE128, | 345 | .accel = FB_ACCEL_ATI_RAGE128, |
346 | }; | 346 | }; |
347 | 347 | ||
348 | static char *mode_option __initdata = NULL; | 348 | static char *mode_option __devinitdata = NULL; |
349 | 349 | ||
350 | #ifdef CONFIG_PPC_PMAC | 350 | #ifdef CONFIG_PPC_PMAC |
351 | static int default_vmode __initdata = VMODE_1024_768_60; | 351 | static int default_vmode __devinitdata = VMODE_1024_768_60; |
352 | static int default_cmode __initdata = CMODE_8; | 352 | static int default_cmode __devinitdata = CMODE_8; |
353 | #endif | 353 | #endif |
354 | 354 | ||
355 | static int default_crt_on __initdata = 0; | 355 | static int default_crt_on __devinitdata = 0; |
356 | static int default_lcd_on __initdata = 1; | 356 | static int default_lcd_on __devinitdata = 1; |
357 | 357 | ||
358 | #ifdef CONFIG_MTRR | 358 | #ifdef CONFIG_MTRR |
359 | static int mtrr = 1; | 359 | static int mtrr = 1; |
@@ -445,9 +445,9 @@ static int aty128_encode_var(struct fb_var_screeninfo *var, | |||
445 | static int aty128_decode_var(struct fb_var_screeninfo *var, | 445 | static int aty128_decode_var(struct fb_var_screeninfo *var, |
446 | struct aty128fb_par *par); | 446 | struct aty128fb_par *par); |
447 | #if 0 | 447 | #if 0 |
448 | static void __init aty128_get_pllinfo(struct aty128fb_par *par, | 448 | static void __devinit aty128_get_pllinfo(struct aty128fb_par *par, |
449 | void __iomem *bios); | 449 | void __iomem *bios); |
450 | static void __init __iomem *aty128_map_ROM(struct pci_dev *pdev, const struct aty128fb_par *par); | 450 | static void __devinit __iomem *aty128_map_ROM(struct pci_dev *pdev, const struct aty128fb_par *par); |
451 | #endif | 451 | #endif |
452 | static void aty128_timings(struct aty128fb_par *par); | 452 | static void aty128_timings(struct aty128fb_par *par); |
453 | static void aty128_init_engine(struct aty128fb_par *par); | 453 | static void aty128_init_engine(struct aty128fb_par *par); |
@@ -573,7 +573,7 @@ static void aty_pll_writeupdate(const struct aty128fb_par *par) | |||
573 | 573 | ||
574 | 574 | ||
575 | /* write to the scratch register to test r/w functionality */ | 575 | /* write to the scratch register to test r/w functionality */ |
576 | static int __init register_test(const struct aty128fb_par *par) | 576 | static int __devinit register_test(const struct aty128fb_par *par) |
577 | { | 577 | { |
578 | u32 val; | 578 | u32 val; |
579 | int flag = 0; | 579 | int flag = 0; |
@@ -772,7 +772,7 @@ static u32 depth_to_dst(u32 depth) | |||
772 | 772 | ||
773 | 773 | ||
774 | #ifndef __sparc__ | 774 | #ifndef __sparc__ |
775 | static void __iomem * __init aty128_map_ROM(const struct aty128fb_par *par, struct pci_dev *dev) | 775 | static void __iomem * __devinit aty128_map_ROM(const struct aty128fb_par *par, struct pci_dev *dev) |
776 | { | 776 | { |
777 | u16 dptr; | 777 | u16 dptr; |
778 | u8 rom_type; | 778 | u8 rom_type; |
@@ -856,7 +856,7 @@ static void __iomem * __init aty128_map_ROM(const struct aty128fb_par *par, stru | |||
856 | return NULL; | 856 | return NULL; |
857 | } | 857 | } |
858 | 858 | ||
859 | static void __init aty128_get_pllinfo(struct aty128fb_par *par, unsigned char __iomem *bios) | 859 | static void __devinit aty128_get_pllinfo(struct aty128fb_par *par, unsigned char __iomem *bios) |
860 | { | 860 | { |
861 | unsigned int bios_hdr; | 861 | unsigned int bios_hdr; |
862 | unsigned int bios_pll; | 862 | unsigned int bios_pll; |
@@ -903,7 +903,7 @@ static void __iomem * __devinit aty128_find_mem_vbios(struct aty128fb_par *par) | |||
903 | #endif /* ndef(__sparc__) */ | 903 | #endif /* ndef(__sparc__) */ |
904 | 904 | ||
905 | /* fill in known card constants if pll_block is not available */ | 905 | /* fill in known card constants if pll_block is not available */ |
906 | static void __init aty128_timings(struct aty128fb_par *par) | 906 | static void __devinit aty128_timings(struct aty128fb_par *par) |
907 | { | 907 | { |
908 | #ifdef CONFIG_PPC_OF | 908 | #ifdef CONFIG_PPC_OF |
909 | /* instead of a table lookup, assume OF has properly | 909 | /* instead of a table lookup, assume OF has properly |
@@ -1645,7 +1645,7 @@ static int aty128fb_sync(struct fb_info *info) | |||
1645 | } | 1645 | } |
1646 | 1646 | ||
1647 | #ifndef MODULE | 1647 | #ifndef MODULE |
1648 | static int __init aty128fb_setup(char *options) | 1648 | static int __devinit aty128fb_setup(char *options) |
1649 | { | 1649 | { |
1650 | char *this_opt; | 1650 | char *this_opt; |
1651 | 1651 | ||
@@ -1893,7 +1893,7 @@ static void aty128_early_resume(void *data) | |||
1893 | } | 1893 | } |
1894 | #endif /* CONFIG_PPC_PMAC */ | 1894 | #endif /* CONFIG_PPC_PMAC */ |
1895 | 1895 | ||
1896 | static int __init aty128_init(struct pci_dev *pdev, const struct pci_device_id *ent) | 1896 | static int __devinit aty128_init(struct pci_dev *pdev, const struct pci_device_id *ent) |
1897 | { | 1897 | { |
1898 | struct fb_info *info = pci_get_drvdata(pdev); | 1898 | struct fb_info *info = pci_get_drvdata(pdev); |
1899 | struct aty128fb_par *par = info->par; | 1899 | struct aty128fb_par *par = info->par; |
@@ -2037,7 +2037,7 @@ static int __init aty128_init(struct pci_dev *pdev, const struct pci_device_id * | |||
2037 | 2037 | ||
2038 | #ifdef CONFIG_PCI | 2038 | #ifdef CONFIG_PCI |
2039 | /* register a card ++ajoshi */ | 2039 | /* register a card ++ajoshi */ |
2040 | static int __init aty128_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | 2040 | static int __devinit aty128_probe(struct pci_dev *pdev, const struct pci_device_id *ent) |
2041 | { | 2041 | { |
2042 | unsigned long fb_addr, reg_addr; | 2042 | unsigned long fb_addr, reg_addr; |
2043 | struct aty128fb_par *par; | 2043 | struct aty128fb_par *par; |
@@ -2556,7 +2556,7 @@ static int aty128_pci_resume(struct pci_dev *pdev) | |||
2556 | } | 2556 | } |
2557 | 2557 | ||
2558 | 2558 | ||
2559 | static int __init aty128fb_init(void) | 2559 | static int __devinit aty128fb_init(void) |
2560 | { | 2560 | { |
2561 | #ifndef MODULE | 2561 | #ifndef MODULE |
2562 | char *option = NULL; | 2562 | char *option = NULL; |
diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c index c5185f7cf4ba..22e720611bf6 100644 --- a/drivers/video/aty/atyfb_base.c +++ b/drivers/video/aty/atyfb_base.c | |||
@@ -316,12 +316,12 @@ static int vram; | |||
316 | static int pll; | 316 | static int pll; |
317 | static int mclk; | 317 | static int mclk; |
318 | static int xclk; | 318 | static int xclk; |
319 | static int comp_sync __initdata = -1; | 319 | static int comp_sync __devinitdata = -1; |
320 | static char *mode; | 320 | static char *mode; |
321 | 321 | ||
322 | #ifdef CONFIG_PPC | 322 | #ifdef CONFIG_PPC |
323 | static int default_vmode __initdata = VMODE_CHOOSE; | 323 | static int default_vmode __devinitdata = VMODE_CHOOSE; |
324 | static int default_cmode __initdata = CMODE_CHOOSE; | 324 | static int default_cmode __devinitdata = CMODE_CHOOSE; |
325 | 325 | ||
326 | module_param_named(vmode, default_vmode, int, 0); | 326 | module_param_named(vmode, default_vmode, int, 0); |
327 | MODULE_PARM_DESC(vmode, "int: video mode for mac"); | 327 | MODULE_PARM_DESC(vmode, "int: video mode for mac"); |
@@ -330,10 +330,10 @@ MODULE_PARM_DESC(cmode, "int: color mode for mac"); | |||
330 | #endif | 330 | #endif |
331 | 331 | ||
332 | #ifdef CONFIG_ATARI | 332 | #ifdef CONFIG_ATARI |
333 | static unsigned int mach64_count __initdata = 0; | 333 | static unsigned int mach64_count __devinitdata = 0; |
334 | static unsigned long phys_vmembase[FB_MAX] __initdata = { 0, }; | 334 | static unsigned long phys_vmembase[FB_MAX] __devinitdata = { 0, }; |
335 | static unsigned long phys_size[FB_MAX] __initdata = { 0, }; | 335 | static unsigned long phys_size[FB_MAX] __devinitdata = { 0, }; |
336 | static unsigned long phys_guiregbase[FB_MAX] __initdata = { 0, }; | 336 | static unsigned long phys_guiregbase[FB_MAX] __devinitdata = { 0, }; |
337 | #endif | 337 | #endif |
338 | 338 | ||
339 | /* top -> down is an evolution of mach64 chipset, any corrections? */ | 339 | /* top -> down is an evolution of mach64 chipset, any corrections? */ |
@@ -583,7 +583,7 @@ static u32 atyfb_get_pixclock(struct fb_var_screeninfo *var, struct atyfb_par *p | |||
583 | * Apple monitor sense | 583 | * Apple monitor sense |
584 | */ | 584 | */ |
585 | 585 | ||
586 | static int __init read_aty_sense(const struct atyfb_par *par) | 586 | static int __devinit read_aty_sense(const struct atyfb_par *par) |
587 | { | 587 | { |
588 | int sense, i; | 588 | int sense, i; |
589 | 589 | ||
@@ -1281,6 +1281,14 @@ static int atyfb_set_par(struct fb_info *info) | |||
1281 | 1281 | ||
1282 | par->accel_flags = var->accel_flags; /* hack */ | 1282 | par->accel_flags = var->accel_flags; /* hack */ |
1283 | 1283 | ||
1284 | if (var->accel_flags) { | ||
1285 | info->fbops->fb_sync = atyfb_sync; | ||
1286 | info->flags &= ~FBINFO_HWACCEL_DISABLED; | ||
1287 | } else { | ||
1288 | info->fbops->fb_sync = NULL; | ||
1289 | info->flags |= FBINFO_HWACCEL_DISABLED; | ||
1290 | } | ||
1291 | |||
1284 | if (par->blitter_may_be_busy) | 1292 | if (par->blitter_may_be_busy) |
1285 | wait_for_idle(par); | 1293 | wait_for_idle(par); |
1286 | 1294 | ||
@@ -2253,7 +2261,7 @@ static void aty_bl_exit(struct atyfb_par *par) | |||
2253 | 2261 | ||
2254 | #endif /* CONFIG_FB_ATY_BACKLIGHT */ | 2262 | #endif /* CONFIG_FB_ATY_BACKLIGHT */ |
2255 | 2263 | ||
2256 | static void __init aty_calc_mem_refresh(struct atyfb_par *par, int xclk) | 2264 | static void __devinit aty_calc_mem_refresh(struct atyfb_par *par, int xclk) |
2257 | { | 2265 | { |
2258 | const int ragepro_tbl[] = { | 2266 | const int ragepro_tbl[] = { |
2259 | 44, 50, 55, 66, 75, 80, 100 | 2267 | 44, 50, 55, 66, 75, 80, 100 |
@@ -2313,7 +2321,7 @@ static int __devinit atyfb_get_timings_from_lcd(struct atyfb_par *par, | |||
2313 | } | 2321 | } |
2314 | #endif /* defined(__i386__) && defined(CONFIG_FB_ATY_GENERIC_LCD) */ | 2322 | #endif /* defined(__i386__) && defined(CONFIG_FB_ATY_GENERIC_LCD) */ |
2315 | 2323 | ||
2316 | static int __init aty_init(struct fb_info *info, const char *name) | 2324 | static int __devinit aty_init(struct fb_info *info, const char *name) |
2317 | { | 2325 | { |
2318 | struct atyfb_par *par = (struct atyfb_par *) info->par; | 2326 | struct atyfb_par *par = (struct atyfb_par *) info->par; |
2319 | const char *ramname = NULL, *xtal; | 2327 | const char *ramname = NULL, *xtal; |
@@ -2394,12 +2402,15 @@ static int __init aty_init(struct fb_info *info, const char *name) | |||
2394 | break; | 2402 | break; |
2395 | } | 2403 | } |
2396 | switch (clk_type) { | 2404 | switch (clk_type) { |
2405 | #ifdef CONFIG_ATARI | ||
2397 | case CLK_ATI18818_1: | 2406 | case CLK_ATI18818_1: |
2398 | par->pll_ops = &aty_pll_ati18818_1; | 2407 | par->pll_ops = &aty_pll_ati18818_1; |
2399 | break; | 2408 | break; |
2409 | #else | ||
2400 | case CLK_IBMRGB514: | 2410 | case CLK_IBMRGB514: |
2401 | par->pll_ops = &aty_pll_ibm514; | 2411 | par->pll_ops = &aty_pll_ibm514; |
2402 | break; | 2412 | break; |
2413 | #endif | ||
2403 | #if 0 /* dead code */ | 2414 | #if 0 /* dead code */ |
2404 | case CLK_STG1703: | 2415 | case CLK_STG1703: |
2405 | par->pll_ops = &aty_pll_stg1703; | 2416 | par->pll_ops = &aty_pll_stg1703; |
@@ -2604,7 +2615,11 @@ static int __init aty_init(struct fb_info *info, const char *name) | |||
2604 | 2615 | ||
2605 | info->fbops = &atyfb_ops; | 2616 | info->fbops = &atyfb_ops; |
2606 | info->pseudo_palette = pseudo_palette; | 2617 | info->pseudo_palette = pseudo_palette; |
2607 | info->flags = FBINFO_FLAG_DEFAULT; | 2618 | info->flags = FBINFO_DEFAULT | |
2619 | FBINFO_HWACCEL_IMAGEBLIT | | ||
2620 | FBINFO_HWACCEL_FILLRECT | | ||
2621 | FBINFO_HWACCEL_COPYAREA | | ||
2622 | FBINFO_HWACCEL_YPAN; | ||
2608 | 2623 | ||
2609 | #ifdef CONFIG_PMAC_BACKLIGHT | 2624 | #ifdef CONFIG_PMAC_BACKLIGHT |
2610 | if (M64_HAS(G3_PB_1_1) && machine_is_compatible("PowerBook1,1")) { | 2625 | if (M64_HAS(G3_PB_1_1) && machine_is_compatible("PowerBook1,1")) { |
@@ -2733,7 +2748,7 @@ aty_init_exit: | |||
2733 | } | 2748 | } |
2734 | 2749 | ||
2735 | #ifdef CONFIG_ATARI | 2750 | #ifdef CONFIG_ATARI |
2736 | static int __init store_video_par(char *video_str, unsigned char m64_num) | 2751 | static int __devinit store_video_par(char *video_str, unsigned char m64_num) |
2737 | { | 2752 | { |
2738 | char *p; | 2753 | char *p; |
2739 | unsigned long vmembase, size, guiregbase; | 2754 | unsigned long vmembase, size, guiregbase; |
@@ -3764,7 +3779,7 @@ static struct pci_driver atyfb_driver = { | |||
3764 | #endif /* CONFIG_PCI */ | 3779 | #endif /* CONFIG_PCI */ |
3765 | 3780 | ||
3766 | #ifndef MODULE | 3781 | #ifndef MODULE |
3767 | static int __init atyfb_setup(char *options) | 3782 | static int __devinit atyfb_setup(char *options) |
3768 | { | 3783 | { |
3769 | char *this_opt; | 3784 | char *this_opt; |
3770 | 3785 | ||
@@ -3836,7 +3851,7 @@ static int __init atyfb_setup(char *options) | |||
3836 | } | 3851 | } |
3837 | #endif /* MODULE */ | 3852 | #endif /* MODULE */ |
3838 | 3853 | ||
3839 | static int __init atyfb_init(void) | 3854 | static int __devinit atyfb_init(void) |
3840 | { | 3855 | { |
3841 | #ifndef MODULE | 3856 | #ifndef MODULE |
3842 | char *option = NULL; | 3857 | char *option = NULL; |
diff --git a/drivers/video/aty/mach64_accel.c b/drivers/video/aty/mach64_accel.c index c98f4a442134..1490e5e1c232 100644 --- a/drivers/video/aty/mach64_accel.c +++ b/drivers/video/aty/mach64_accel.c | |||
@@ -200,8 +200,6 @@ void atyfb_copyarea(struct fb_info *info, const struct fb_copyarea *area) | |||
200 | if (!area->width || !area->height) | 200 | if (!area->width || !area->height) |
201 | return; | 201 | return; |
202 | if (!par->accel_flags) { | 202 | if (!par->accel_flags) { |
203 | if (par->blitter_may_be_busy) | ||
204 | wait_for_idle(par); | ||
205 | cfb_copyarea(info, area); | 203 | cfb_copyarea(info, area); |
206 | return; | 204 | return; |
207 | } | 205 | } |
@@ -248,8 +246,6 @@ void atyfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) | |||
248 | if (!rect->width || !rect->height) | 246 | if (!rect->width || !rect->height) |
249 | return; | 247 | return; |
250 | if (!par->accel_flags) { | 248 | if (!par->accel_flags) { |
251 | if (par->blitter_may_be_busy) | ||
252 | wait_for_idle(par); | ||
253 | cfb_fillrect(info, rect); | 249 | cfb_fillrect(info, rect); |
254 | return; | 250 | return; |
255 | } | 251 | } |
@@ -288,14 +284,10 @@ void atyfb_imageblit(struct fb_info *info, const struct fb_image *image) | |||
288 | return; | 284 | return; |
289 | if (!par->accel_flags || | 285 | if (!par->accel_flags || |
290 | (image->depth != 1 && info->var.bits_per_pixel != image->depth)) { | 286 | (image->depth != 1 && info->var.bits_per_pixel != image->depth)) { |
291 | if (par->blitter_may_be_busy) | ||
292 | wait_for_idle(par); | ||
293 | |||
294 | cfb_imageblit(info, image); | 287 | cfb_imageblit(info, image); |
295 | return; | 288 | return; |
296 | } | 289 | } |
297 | 290 | ||
298 | wait_for_idle(par); | ||
299 | pix_width = pix_width_save = aty_ld_le32(DP_PIX_WIDTH, par); | 291 | pix_width = pix_width_save = aty_ld_le32(DP_PIX_WIDTH, par); |
300 | host_cntl = aty_ld_le32(HOST_CNTL, par) | HOST_BYTE_ALIGN; | 292 | host_cntl = aty_ld_le32(HOST_CNTL, par) | HOST_BYTE_ALIGN; |
301 | 293 | ||
@@ -425,8 +417,6 @@ void atyfb_imageblit(struct fb_info *info, const struct fb_image *image) | |||
425 | } | 417 | } |
426 | } | 418 | } |
427 | 419 | ||
428 | wait_for_idle(par); | ||
429 | |||
430 | /* restore pix_width */ | 420 | /* restore pix_width */ |
431 | wait_for_fifo(1, par); | 421 | wait_for_fifo(1, par); |
432 | aty_st_le32(DP_PIX_WIDTH, pix_width_save, par); | 422 | aty_st_le32(DP_PIX_WIDTH, pix_width_save, par); |
diff --git a/drivers/video/aty/mach64_cursor.c b/drivers/video/aty/mach64_cursor.c index ad8b7496f853..2a7f381c330f 100644 --- a/drivers/video/aty/mach64_cursor.c +++ b/drivers/video/aty/mach64_cursor.c | |||
@@ -66,11 +66,6 @@ static const u8 cursor_bits_lookup[16] = { | |||
66 | 0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55 | 66 | 0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55 |
67 | }; | 67 | }; |
68 | 68 | ||
69 | static const u8 cursor_mask_lookup[16] = { | ||
70 | 0xaa, 0x2a, 0x8a, 0x0a, 0xa2, 0x22, 0x82, 0x02, | ||
71 | 0xa8, 0x28, 0x88, 0x08, 0xa0, 0x20, 0x80, 0x00 | ||
72 | }; | ||
73 | |||
74 | static int atyfb_cursor(struct fb_info *info, struct fb_cursor *cursor) | 69 | static int atyfb_cursor(struct fb_info *info, struct fb_cursor *cursor) |
75 | { | 70 | { |
76 | struct atyfb_par *par = (struct atyfb_par *) info->par; | 71 | struct atyfb_par *par = (struct atyfb_par *) info->par; |
@@ -130,13 +125,13 @@ static int atyfb_cursor(struct fb_info *info, struct fb_cursor *cursor) | |||
130 | fg_idx = cursor->image.fg_color; | 125 | fg_idx = cursor->image.fg_color; |
131 | bg_idx = cursor->image.bg_color; | 126 | bg_idx = cursor->image.bg_color; |
132 | 127 | ||
133 | fg = (info->cmap.red[fg_idx] << 24) | | 128 | fg = ((info->cmap.red[fg_idx] & 0xff) << 24) | |
134 | (info->cmap.green[fg_idx] << 16) | | 129 | ((info->cmap.green[fg_idx] & 0xff) << 16) | |
135 | (info->cmap.blue[fg_idx] << 8) | 15; | 130 | ((info->cmap.blue[fg_idx] & 0xff) << 8) | 0xff; |
136 | 131 | ||
137 | bg = (info->cmap.red[bg_idx] << 24) | | 132 | bg = ((info->cmap.red[bg_idx] & 0xff) << 24) | |
138 | (info->cmap.green[bg_idx] << 16) | | 133 | ((info->cmap.green[bg_idx] & 0xff) << 16) | |
139 | (info->cmap.blue[bg_idx] << 8); | 134 | ((info->cmap.blue[bg_idx] & 0xff) << 8); |
140 | 135 | ||
141 | wait_for_fifo(2, par); | 136 | wait_for_fifo(2, par); |
142 | aty_st_le32(CUR_CLR0, bg, par); | 137 | aty_st_le32(CUR_CLR0, bg, par); |
@@ -166,19 +161,17 @@ static int atyfb_cursor(struct fb_info *info, struct fb_cursor *cursor) | |||
166 | switch (cursor->rop) { | 161 | switch (cursor->rop) { |
167 | case ROP_XOR: | 162 | case ROP_XOR: |
168 | // Upper 4 bits of mask data | 163 | // Upper 4 bits of mask data |
169 | fb_writeb(cursor_mask_lookup[m >> 4 ] | | 164 | fb_writeb(cursor_bits_lookup[(b ^ m) >> 4], dst++); |
170 | cursor_bits_lookup[(b ^ m) >> 4], dst++); | ||
171 | // Lower 4 bits of mask | 165 | // Lower 4 bits of mask |
172 | fb_writeb(cursor_mask_lookup[m & 0x0f ] | | 166 | fb_writeb(cursor_bits_lookup[(b ^ m) & 0x0f], |
173 | cursor_bits_lookup[(b ^ m) & 0x0f], dst++); | 167 | dst++); |
174 | break; | 168 | break; |
175 | case ROP_COPY: | 169 | case ROP_COPY: |
176 | // Upper 4 bits of mask data | 170 | // Upper 4 bits of mask data |
177 | fb_writeb(cursor_mask_lookup[m >> 4 ] | | 171 | fb_writeb(cursor_bits_lookup[(b & m) >> 4], dst++); |
178 | cursor_bits_lookup[(b & m) >> 4], dst++); | ||
179 | // Lower 4 bits of mask | 172 | // Lower 4 bits of mask |
180 | fb_writeb(cursor_mask_lookup[m & 0x0f ] | | 173 | fb_writeb(cursor_bits_lookup[(b & m) & 0x0f], |
181 | cursor_bits_lookup[(b & m) & 0x0f], dst++); | 174 | dst++); |
182 | break; | 175 | break; |
183 | } | 176 | } |
184 | } | 177 | } |
@@ -194,7 +187,7 @@ static int atyfb_cursor(struct fb_info *info, struct fb_cursor *cursor) | |||
194 | return 0; | 187 | return 0; |
195 | } | 188 | } |
196 | 189 | ||
197 | int __init aty_init_cursor(struct fb_info *info) | 190 | int __devinit aty_init_cursor(struct fb_info *info) |
198 | { | 191 | { |
199 | unsigned long addr; | 192 | unsigned long addr; |
200 | 193 | ||
diff --git a/drivers/video/aty/radeon_base.c b/drivers/video/aty/radeon_base.c index c5ecbb02e01d..68b15645b893 100644 --- a/drivers/video/aty/radeon_base.c +++ b/drivers/video/aty/radeon_base.c | |||
@@ -2379,7 +2379,6 @@ err_release_pci0: | |||
2379 | err_release_fb: | 2379 | err_release_fb: |
2380 | framebuffer_release(info); | 2380 | framebuffer_release(info); |
2381 | err_disable: | 2381 | err_disable: |
2382 | pci_disable_device(pdev); | ||
2383 | err_out: | 2382 | err_out: |
2384 | return ret; | 2383 | return ret; |
2385 | } | 2384 | } |
@@ -2436,7 +2435,6 @@ static void __devexit radeonfb_pci_unregister (struct pci_dev *pdev) | |||
2436 | #endif | 2435 | #endif |
2437 | fb_dealloc_cmap(&info->cmap); | 2436 | fb_dealloc_cmap(&info->cmap); |
2438 | framebuffer_release(info); | 2437 | framebuffer_release(info); |
2439 | pci_disable_device(pdev); | ||
2440 | } | 2438 | } |
2441 | 2439 | ||
2442 | 2440 | ||
diff --git a/drivers/video/au1100fb.c b/drivers/video/au1100fb.c index 789450bb0bc9..d63c3f485853 100644 --- a/drivers/video/au1100fb.c +++ b/drivers/video/au1100fb.c | |||
@@ -7,6 +7,8 @@ | |||
7 | * Karl Lessard <klessard@sunrisetelecom.com> | 7 | * Karl Lessard <klessard@sunrisetelecom.com> |
8 | * <c.pellegrin@exadron.com> | 8 | * <c.pellegrin@exadron.com> |
9 | * | 9 | * |
10 | * PM support added by Rodolfo Giometti <giometti@linux.it> | ||
11 | * | ||
10 | * Copyright 2002 MontaVista Software | 12 | * Copyright 2002 MontaVista Software |
11 | * Author: MontaVista Software, Inc. | 13 | * Author: MontaVista Software, Inc. |
12 | * ppopov@mvista.com or source@mvista.com | 14 | * ppopov@mvista.com or source@mvista.com |
@@ -602,17 +604,52 @@ int au1100fb_drv_remove(struct device *dev) | |||
602 | return 0; | 604 | return 0; |
603 | } | 605 | } |
604 | 606 | ||
607 | #ifdef CONFIG_PM | ||
608 | static u32 sys_clksrc; | ||
609 | static struct au1100fb_regs fbregs; | ||
610 | |||
605 | int au1100fb_drv_suspend(struct device *dev, pm_message_t state) | 611 | int au1100fb_drv_suspend(struct device *dev, pm_message_t state) |
606 | { | 612 | { |
607 | /* TODO */ | 613 | struct au1100fb_device *fbdev = dev_get_drvdata(dev); |
614 | |||
615 | if (!fbdev) | ||
616 | return 0; | ||
617 | |||
618 | /* Save the clock source state */ | ||
619 | sys_clksrc = au_readl(SYS_CLKSRC); | ||
620 | |||
621 | /* Blank the LCD */ | ||
622 | au1100fb_fb_blank(VESA_POWERDOWN, &fbdev->info); | ||
623 | |||
624 | /* Stop LCD clocking */ | ||
625 | au_writel(sys_clksrc & ~SYS_CS_ML_MASK, SYS_CLKSRC); | ||
626 | |||
627 | memcpy(&fbregs, fbdev->regs, sizeof(struct au1100fb_regs)); | ||
628 | |||
608 | return 0; | 629 | return 0; |
609 | } | 630 | } |
610 | 631 | ||
611 | int au1100fb_drv_resume(struct device *dev) | 632 | int au1100fb_drv_resume(struct device *dev) |
612 | { | 633 | { |
613 | /* TODO */ | 634 | struct au1100fb_device *fbdev = dev_get_drvdata(dev); |
635 | |||
636 | if (!fbdev) | ||
637 | return 0; | ||
638 | |||
639 | memcpy(fbdev->regs, &fbregs, sizeof(struct au1100fb_regs)); | ||
640 | |||
641 | /* Restart LCD clocking */ | ||
642 | au_writel(sys_clksrc, SYS_CLKSRC); | ||
643 | |||
644 | /* Unblank the LCD */ | ||
645 | au1100fb_fb_blank(VESA_NO_BLANKING, &fbdev->info); | ||
646 | |||
614 | return 0; | 647 | return 0; |
615 | } | 648 | } |
649 | #else | ||
650 | #define au1100fb_drv_suspend NULL | ||
651 | #define au1100fb_drv_resume NULL | ||
652 | #endif | ||
616 | 653 | ||
617 | static struct device_driver au1100fb_driver = { | 654 | static struct device_driver au1100fb_driver = { |
618 | .name = "au1100-lcd", | 655 | .name = "au1100-lcd", |
diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig index b895eaaa73fd..022f9d3473f5 100644 --- a/drivers/video/backlight/Kconfig +++ b/drivers/video/backlight/Kconfig | |||
@@ -10,7 +10,7 @@ menuconfig BACKLIGHT_LCD_SUPPORT | |||
10 | 10 | ||
11 | config BACKLIGHT_CLASS_DEVICE | 11 | config BACKLIGHT_CLASS_DEVICE |
12 | tristate "Lowlevel Backlight controls" | 12 | tristate "Lowlevel Backlight controls" |
13 | depends on BACKLIGHT_LCD_SUPPORT | 13 | depends on BACKLIGHT_LCD_SUPPORT && FB |
14 | default m | 14 | default m |
15 | help | 15 | help |
16 | This framework adds support for low-level control of the LCD | 16 | This framework adds support for low-level control of the LCD |
@@ -26,7 +26,7 @@ config BACKLIGHT_DEVICE | |||
26 | 26 | ||
27 | config LCD_CLASS_DEVICE | 27 | config LCD_CLASS_DEVICE |
28 | tristate "Lowlevel LCD controls" | 28 | tristate "Lowlevel LCD controls" |
29 | depends on BACKLIGHT_LCD_SUPPORT | 29 | depends on BACKLIGHT_LCD_SUPPORT && FB |
30 | default m | 30 | default m |
31 | help | 31 | help |
32 | This framework adds support for low-level control of LCD. | 32 | This framework adds support for low-level control of LCD. |
@@ -50,6 +50,14 @@ config BACKLIGHT_CORGI | |||
50 | If you have a Sharp Zaurus SL-C7xx, SL-Cxx00 or SL-6000x say y to enable the | 50 | If you have a Sharp Zaurus SL-C7xx, SL-Cxx00 or SL-6000x say y to enable the |
51 | backlight driver. | 51 | backlight driver. |
52 | 52 | ||
53 | config BACKLIGHT_LOCOMO | ||
54 | tristate "Sharp LOCOMO LCD/Backlight Driver" | ||
55 | depends on BACKLIGHT_DEVICE && SHARP_LOCOMO | ||
56 | default y | ||
57 | help | ||
58 | If you have a Sharp Zaurus SL-5500 (Collie) or SL-5600 (Poodle) say y to | ||
59 | enable the LCD/backlight driver. | ||
60 | |||
53 | config BACKLIGHT_HP680 | 61 | config BACKLIGHT_HP680 |
54 | tristate "HP Jornada 680 Backlight Driver" | 62 | tristate "HP Jornada 680 Backlight Driver" |
55 | depends on BACKLIGHT_DEVICE && SH_HP6XX | 63 | depends on BACKLIGHT_DEVICE && SH_HP6XX |
diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile index 744210c38e74..65e5553fc849 100644 --- a/drivers/video/backlight/Makefile +++ b/drivers/video/backlight/Makefile | |||
@@ -4,4 +4,4 @@ obj-$(CONFIG_LCD_CLASS_DEVICE) += lcd.o | |||
4 | obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o | 4 | obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o |
5 | obj-$(CONFIG_BACKLIGHT_CORGI) += corgi_bl.o | 5 | obj-$(CONFIG_BACKLIGHT_CORGI) += corgi_bl.o |
6 | obj-$(CONFIG_BACKLIGHT_HP680) += hp680_bl.o | 6 | obj-$(CONFIG_BACKLIGHT_HP680) += hp680_bl.o |
7 | obj-$(CONFIG_SHARP_LOCOMO) += locomolcd.o | 7 | obj-$(CONFIG_BACKLIGHT_LOCOMO) += locomolcd.o |
diff --git a/drivers/video/backlight/locomolcd.c b/drivers/video/backlight/locomolcd.c index 60831bb23685..bd879b7ec119 100644 --- a/drivers/video/backlight/locomolcd.c +++ b/drivers/video/backlight/locomolcd.c | |||
@@ -17,6 +17,8 @@ | |||
17 | #include <linux/delay.h> | 17 | #include <linux/delay.h> |
18 | #include <linux/device.h> | 18 | #include <linux/device.h> |
19 | #include <linux/interrupt.h> | 19 | #include <linux/interrupt.h> |
20 | #include <linux/fb.h> | ||
21 | #include <linux/backlight.h> | ||
20 | 22 | ||
21 | #include <asm/hardware/locomo.h> | 23 | #include <asm/hardware/locomo.h> |
22 | #include <asm/irq.h> | 24 | #include <asm/irq.h> |
@@ -25,7 +27,10 @@ | |||
25 | 27 | ||
26 | #include "../../../arch/arm/mach-sa1100/generic.h" | 28 | #include "../../../arch/arm/mach-sa1100/generic.h" |
27 | 29 | ||
30 | static struct backlight_device *locomolcd_bl_device; | ||
28 | static struct locomo_dev *locomolcd_dev; | 31 | static struct locomo_dev *locomolcd_dev; |
32 | static unsigned long locomolcd_flags; | ||
33 | #define LOCOMOLCD_SUSPENDED 0x01 | ||
29 | 34 | ||
30 | static void locomolcd_on(int comadj) | 35 | static void locomolcd_on(int comadj) |
31 | { | 36 | { |
@@ -89,12 +94,10 @@ void locomolcd_power(int on) | |||
89 | } | 94 | } |
90 | 95 | ||
91 | /* read comadj */ | 96 | /* read comadj */ |
92 | if (comadj == -1) { | 97 | if (comadj == -1 && machine_is_collie()) |
93 | if (machine_is_poodle()) | 98 | comadj = 128; |
94 | comadj = 118; | 99 | if (comadj == -1 && machine_is_poodle()) |
95 | if (machine_is_collie()) | 100 | comadj = 118; |
96 | comadj = 128; | ||
97 | } | ||
98 | 101 | ||
99 | if (on) | 102 | if (on) |
100 | locomolcd_on(comadj); | 103 | locomolcd_on(comadj); |
@@ -105,26 +108,100 @@ void locomolcd_power(int on) | |||
105 | } | 108 | } |
106 | EXPORT_SYMBOL(locomolcd_power); | 109 | EXPORT_SYMBOL(locomolcd_power); |
107 | 110 | ||
108 | static int poodle_lcd_probe(struct locomo_dev *dev) | 111 | |
112 | static int current_intensity; | ||
113 | |||
114 | static int locomolcd_set_intensity(struct backlight_device *bd) | ||
115 | { | ||
116 | int intensity = bd->props->brightness; | ||
117 | |||
118 | if (bd->props->power != FB_BLANK_UNBLANK) | ||
119 | intensity = 0; | ||
120 | if (bd->props->fb_blank != FB_BLANK_UNBLANK) | ||
121 | intensity = 0; | ||
122 | if (locomolcd_flags & LOCOMOLCD_SUSPENDED) | ||
123 | intensity = 0; | ||
124 | |||
125 | switch (intensity) { | ||
126 | /* AC and non-AC are handled differently, but produce same results in sharp code? */ | ||
127 | case 0: locomo_frontlight_set(locomolcd_dev, 0, 0, 161); break; | ||
128 | case 1: locomo_frontlight_set(locomolcd_dev, 117, 0, 161); break; | ||
129 | case 2: locomo_frontlight_set(locomolcd_dev, 163, 0, 148); break; | ||
130 | case 3: locomo_frontlight_set(locomolcd_dev, 194, 0, 161); break; | ||
131 | case 4: locomo_frontlight_set(locomolcd_dev, 194, 1, 161); break; | ||
132 | |||
133 | default: | ||
134 | return -ENODEV; | ||
135 | } | ||
136 | current_intensity = intensity; | ||
137 | return 0; | ||
138 | } | ||
139 | |||
140 | static int locomolcd_get_intensity(struct backlight_device *bd) | ||
141 | { | ||
142 | return current_intensity; | ||
143 | } | ||
144 | |||
145 | static struct backlight_properties locomobl_data = { | ||
146 | .owner = THIS_MODULE, | ||
147 | .get_brightness = locomolcd_get_intensity, | ||
148 | .update_status = locomolcd_set_intensity, | ||
149 | .max_brightness = 4, | ||
150 | }; | ||
151 | |||
152 | #ifdef CONFIG_PM | ||
153 | static int locomolcd_suspend(struct locomo_dev *dev, pm_message_t state) | ||
154 | { | ||
155 | locomolcd_flags |= LOCOMOLCD_SUSPENDED; | ||
156 | locomolcd_set_intensity(locomolcd_bl_device); | ||
157 | return 0; | ||
158 | } | ||
159 | |||
160 | static int locomolcd_resume(struct locomo_dev *dev) | ||
161 | { | ||
162 | locomolcd_flags &= ~LOCOMOLCD_SUSPENDED; | ||
163 | locomolcd_set_intensity(locomolcd_bl_device); | ||
164 | return 0; | ||
165 | } | ||
166 | #else | ||
167 | #define locomolcd_suspend NULL | ||
168 | #define locomolcd_resume NULL | ||
169 | #endif | ||
170 | |||
171 | static int locomolcd_probe(struct locomo_dev *dev) | ||
109 | { | 172 | { |
110 | unsigned long flags; | 173 | unsigned long flags; |
111 | 174 | ||
112 | local_irq_save(flags); | 175 | local_irq_save(flags); |
113 | locomolcd_dev = dev; | 176 | locomolcd_dev = dev; |
114 | 177 | ||
178 | locomo_gpio_set_dir(dev, LOCOMO_GPIO_FL_VR, 0); | ||
179 | |||
115 | /* the poodle_lcd_power function is called for the first time | 180 | /* the poodle_lcd_power function is called for the first time |
116 | * from fs_initcall, which is before locomo is activated. | 181 | * from fs_initcall, which is before locomo is activated. |
117 | * We need to recall poodle_lcd_power here*/ | 182 | * We need to recall poodle_lcd_power here*/ |
118 | #ifdef CONFIG_MACH_POODLE | 183 | if (machine_is_poodle()) |
119 | locomolcd_power(1); | 184 | locomolcd_power(1); |
120 | #endif | 185 | |
121 | local_irq_restore(flags); | 186 | local_irq_restore(flags); |
187 | |||
188 | locomolcd_bl_device = backlight_device_register("locomo-bl", NULL, &locomobl_data); | ||
189 | |||
190 | if (IS_ERR (locomolcd_bl_device)) | ||
191 | return PTR_ERR (locomolcd_bl_device); | ||
192 | |||
193 | /* Set up frontlight so that screen is readable */ | ||
194 | locomobl_data.brightness = 2; | ||
195 | locomolcd_set_intensity(locomolcd_bl_device); | ||
196 | |||
122 | return 0; | 197 | return 0; |
123 | } | 198 | } |
124 | 199 | ||
125 | static int poodle_lcd_remove(struct locomo_dev *dev) | 200 | static int locomolcd_remove(struct locomo_dev *dev) |
126 | { | 201 | { |
127 | unsigned long flags; | 202 | unsigned long flags; |
203 | |||
204 | backlight_device_unregister(locomolcd_bl_device); | ||
128 | local_irq_save(flags); | 205 | local_irq_save(flags); |
129 | locomolcd_dev = NULL; | 206 | locomolcd_dev = NULL; |
130 | local_irq_restore(flags); | 207 | local_irq_restore(flags); |
@@ -136,19 +213,33 @@ static struct locomo_driver poodle_lcd_driver = { | |||
136 | .name = "locomo-backlight", | 213 | .name = "locomo-backlight", |
137 | }, | 214 | }, |
138 | .devid = LOCOMO_DEVID_BACKLIGHT, | 215 | .devid = LOCOMO_DEVID_BACKLIGHT, |
139 | .probe = poodle_lcd_probe, | 216 | .probe = locomolcd_probe, |
140 | .remove = poodle_lcd_remove, | 217 | .remove = locomolcd_remove, |
218 | .suspend = locomolcd_suspend, | ||
219 | .resume = locomolcd_resume, | ||
141 | }; | 220 | }; |
142 | 221 | ||
143 | static int __init poodle_lcd_init(void) | 222 | |
223 | static int __init locomolcd_init(void) | ||
144 | { | 224 | { |
145 | int ret = locomo_driver_register(&poodle_lcd_driver); | 225 | int ret = locomo_driver_register(&poodle_lcd_driver); |
146 | if (ret) return ret; | 226 | if (ret) |
227 | return ret; | ||
147 | 228 | ||
148 | #ifdef CONFIG_SA1100_COLLIE | 229 | #ifdef CONFIG_SA1100_COLLIE |
149 | sa1100fb_lcd_power = locomolcd_power; | 230 | sa1100fb_lcd_power = locomolcd_power; |
150 | #endif | 231 | #endif |
151 | return 0; | 232 | return 0; |
152 | } | 233 | } |
153 | device_initcall(poodle_lcd_init); | ||
154 | 234 | ||
235 | static void __exit locomolcd_exit(void) | ||
236 | { | ||
237 | locomo_driver_unregister(&poodle_lcd_driver); | ||
238 | } | ||
239 | |||
240 | module_init(locomolcd_init); | ||
241 | module_exit(locomolcd_exit); | ||
242 | |||
243 | MODULE_AUTHOR("John Lenz <lenz@cs.wisc.edu>, Pavel Machek <pavel@suse.cz>"); | ||
244 | MODULE_DESCRIPTION("Collie LCD driver"); | ||
245 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/video/cfbimgblt.c b/drivers/video/cfbimgblt.c index 8ba6152db2fd..ad8a89bf8eae 100644 --- a/drivers/video/cfbimgblt.c +++ b/drivers/video/cfbimgblt.c | |||
@@ -230,6 +230,7 @@ static inline void fast_imageblit(const struct fb_image *image, struct fb_info * | |||
230 | tab = cfb_tab16; | 230 | tab = cfb_tab16; |
231 | break; | 231 | break; |
232 | case 32: | 232 | case 32: |
233 | default: | ||
233 | tab = cfb_tab32; | 234 | tab = cfb_tab32; |
234 | break; | 235 | break; |
235 | } | 236 | } |
diff --git a/drivers/video/cirrusfb.c b/drivers/video/cirrusfb.c index 1103010af54a..dda240eb7360 100644 --- a/drivers/video/cirrusfb.c +++ b/drivers/video/cirrusfb.c | |||
@@ -2227,7 +2227,6 @@ static void cirrusfb_pci_unmap (struct cirrusfb_info *cinfo) | |||
2227 | release_region(0x3C0, 32); | 2227 | release_region(0x3C0, 32); |
2228 | pci_release_regions(pdev); | 2228 | pci_release_regions(pdev); |
2229 | framebuffer_release(cinfo->info); | 2229 | framebuffer_release(cinfo->info); |
2230 | pci_disable_device(pdev); | ||
2231 | } | 2230 | } |
2232 | #endif /* CONFIG_PCI */ | 2231 | #endif /* CONFIG_PCI */ |
2233 | 2232 | ||
@@ -2458,7 +2457,6 @@ err_release_regions: | |||
2458 | err_release_fb: | 2457 | err_release_fb: |
2459 | framebuffer_release(info); | 2458 | framebuffer_release(info); |
2460 | err_disable: | 2459 | err_disable: |
2461 | pci_disable_device(pdev); | ||
2462 | err_out: | 2460 | err_out: |
2463 | return ret; | 2461 | return ret; |
2464 | } | 2462 | } |
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index 47ba1a79adcd..5dc4083552d8 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c | |||
@@ -125,6 +125,8 @@ static int softback_lines; | |||
125 | static int first_fb_vc; | 125 | static int first_fb_vc; |
126 | static int last_fb_vc = MAX_NR_CONSOLES - 1; | 126 | static int last_fb_vc = MAX_NR_CONSOLES - 1; |
127 | static int fbcon_is_default = 1; | 127 | static int fbcon_is_default = 1; |
128 | static int fbcon_has_exited; | ||
129 | |||
128 | /* font data */ | 130 | /* font data */ |
129 | static char fontname[40]; | 131 | static char fontname[40]; |
130 | 132 | ||
@@ -140,7 +142,6 @@ static const struct consw fb_con; | |||
140 | 142 | ||
141 | #define advance_row(p, delta) (unsigned short *)((unsigned long)(p) + (delta) * vc->vc_size_row) | 143 | #define advance_row(p, delta) (unsigned short *)((unsigned long)(p) + (delta) * vc->vc_size_row) |
142 | 144 | ||
143 | static void fbcon_free_font(struct display *); | ||
144 | static int fbcon_set_origin(struct vc_data *); | 145 | static int fbcon_set_origin(struct vc_data *); |
145 | 146 | ||
146 | #define CURSOR_DRAW_DELAY (1) | 147 | #define CURSOR_DRAW_DELAY (1) |
@@ -194,6 +195,9 @@ static void fbcon_redraw_move(struct vc_data *vc, struct display *p, | |||
194 | int line, int count, int dy); | 195 | int line, int count, int dy); |
195 | static void fbcon_modechanged(struct fb_info *info); | 196 | static void fbcon_modechanged(struct fb_info *info); |
196 | static void fbcon_set_all_vcs(struct fb_info *info); | 197 | static void fbcon_set_all_vcs(struct fb_info *info); |
198 | static void fbcon_start(void); | ||
199 | static void fbcon_exit(void); | ||
200 | static struct class_device *fbcon_class_device; | ||
197 | 201 | ||
198 | #ifdef CONFIG_MAC | 202 | #ifdef CONFIG_MAC |
199 | /* | 203 | /* |
@@ -252,7 +256,7 @@ static void fbcon_rotate_all(struct fb_info *info, u32 rotate) | |||
252 | if (!ops || ops->currcon < 0 || rotate > 3) | 256 | if (!ops || ops->currcon < 0 || rotate > 3) |
253 | return; | 257 | return; |
254 | 258 | ||
255 | for (i = 0; i < MAX_NR_CONSOLES; i++) { | 259 | for (i = first_fb_vc; i <= last_fb_vc; i++) { |
256 | vc = vc_cons[i].d; | 260 | vc = vc_cons[i].d; |
257 | if (!vc || vc->vc_mode != KD_TEXT || | 261 | if (!vc || vc->vc_mode != KD_TEXT || |
258 | registered_fb[con2fb_map[i]] != info) | 262 | registered_fb[con2fb_map[i]] != info) |
@@ -389,15 +393,18 @@ static void fb_flashcursor(void *private) | |||
389 | int c; | 393 | int c; |
390 | int mode; | 394 | int mode; |
391 | 395 | ||
392 | if (ops->currcon != -1) | 396 | acquire_console_sem(); |
397 | if (ops && ops->currcon != -1) | ||
393 | vc = vc_cons[ops->currcon].d; | 398 | vc = vc_cons[ops->currcon].d; |
394 | 399 | ||
395 | if (!vc || !CON_IS_VISIBLE(vc) || | 400 | if (!vc || !CON_IS_VISIBLE(vc) || |
396 | fbcon_is_inactive(vc, info) || | 401 | fbcon_is_inactive(vc, info) || |
397 | registered_fb[con2fb_map[vc->vc_num]] != info || | 402 | registered_fb[con2fb_map[vc->vc_num]] != info || |
398 | vc_cons[ops->currcon].d->vc_deccm != 1) | 403 | vc_cons[ops->currcon].d->vc_deccm != 1) { |
404 | release_console_sem(); | ||
399 | return; | 405 | return; |
400 | acquire_console_sem(); | 406 | } |
407 | |||
401 | p = &fb_display[vc->vc_num]; | 408 | p = &fb_display[vc->vc_num]; |
402 | c = scr_readw((u16 *) vc->vc_pos); | 409 | c = scr_readw((u16 *) vc->vc_pos); |
403 | mode = (!ops->cursor_flash || ops->cursor_state.enable) ? | 410 | mode = (!ops->cursor_flash || ops->cursor_state.enable) ? |
@@ -528,7 +535,7 @@ static int search_fb_in_map(int idx) | |||
528 | { | 535 | { |
529 | int i, retval = 0; | 536 | int i, retval = 0; |
530 | 537 | ||
531 | for (i = 0; i < MAX_NR_CONSOLES; i++) { | 538 | for (i = first_fb_vc; i <= last_fb_vc; i++) { |
532 | if (con2fb_map[i] == idx) | 539 | if (con2fb_map[i] == idx) |
533 | retval = 1; | 540 | retval = 1; |
534 | } | 541 | } |
@@ -539,7 +546,7 @@ static int search_for_mapped_con(void) | |||
539 | { | 546 | { |
540 | int i, retval = 0; | 547 | int i, retval = 0; |
541 | 548 | ||
542 | for (i = 0; i < MAX_NR_CONSOLES; i++) { | 549 | for (i = first_fb_vc; i <= last_fb_vc; i++) { |
543 | if (con2fb_map[i] != -1) | 550 | if (con2fb_map[i] != -1) |
544 | retval = 1; | 551 | retval = 1; |
545 | } | 552 | } |
@@ -561,6 +568,7 @@ static int fbcon_takeover(int show_logo) | |||
561 | 568 | ||
562 | err = take_over_console(&fb_con, first_fb_vc, last_fb_vc, | 569 | err = take_over_console(&fb_con, first_fb_vc, last_fb_vc, |
563 | fbcon_is_default); | 570 | fbcon_is_default); |
571 | |||
564 | if (err) { | 572 | if (err) { |
565 | for (i = first_fb_vc; i <= last_fb_vc; i++) { | 573 | for (i = first_fb_vc; i <= last_fb_vc; i++) { |
566 | con2fb_map[i] = -1; | 574 | con2fb_map[i] = -1; |
@@ -795,8 +803,8 @@ static int set_con2fb_map(int unit, int newidx, int user) | |||
795 | if (oldidx == newidx) | 803 | if (oldidx == newidx) |
796 | return 0; | 804 | return 0; |
797 | 805 | ||
798 | if (!info) | 806 | if (!info || fbcon_has_exited) |
799 | err = -EINVAL; | 807 | return -EINVAL; |
800 | 808 | ||
801 | if (!err && !search_for_mapped_con()) { | 809 | if (!err && !search_for_mapped_con()) { |
802 | info_idx = newidx; | 810 | info_idx = newidx; |
@@ -832,6 +840,9 @@ static int set_con2fb_map(int unit, int newidx, int user) | |||
832 | con2fb_init_display(vc, info, unit, show_logo); | 840 | con2fb_init_display(vc, info, unit, show_logo); |
833 | } | 841 | } |
834 | 842 | ||
843 | if (!search_fb_in_map(info_idx)) | ||
844 | info_idx = newidx; | ||
845 | |||
835 | release_console_sem(); | 846 | release_console_sem(); |
836 | return err; | 847 | return err; |
837 | } | 848 | } |
@@ -1034,6 +1045,7 @@ static const char *fbcon_startup(void) | |||
1034 | #endif /* CONFIG_MAC */ | 1045 | #endif /* CONFIG_MAC */ |
1035 | 1046 | ||
1036 | fbcon_add_cursor_timer(info); | 1047 | fbcon_add_cursor_timer(info); |
1048 | fbcon_has_exited = 0; | ||
1037 | return display_desc; | 1049 | return display_desc; |
1038 | } | 1050 | } |
1039 | 1051 | ||
@@ -1061,17 +1073,36 @@ static void fbcon_init(struct vc_data *vc, int init) | |||
1061 | 1073 | ||
1062 | /* If we are not the first console on this | 1074 | /* If we are not the first console on this |
1063 | fb, copy the font from that console */ | 1075 | fb, copy the font from that console */ |
1064 | t = &fb_display[svc->vc_num]; | 1076 | t = &fb_display[fg_console]; |
1065 | if (!vc->vc_font.data) { | 1077 | if (!p->fontdata) { |
1066 | vc->vc_font.data = (void *)(p->fontdata = t->fontdata); | 1078 | if (t->fontdata) { |
1067 | vc->vc_font.width = (*default_mode)->vc_font.width; | 1079 | struct vc_data *fvc = vc_cons[fg_console].d; |
1068 | vc->vc_font.height = (*default_mode)->vc_font.height; | 1080 | |
1069 | p->userfont = t->userfont; | 1081 | vc->vc_font.data = (void *)(p->fontdata = |
1070 | if (p->userfont) | 1082 | fvc->vc_font.data); |
1071 | REFCOUNT(p->fontdata)++; | 1083 | vc->vc_font.width = fvc->vc_font.width; |
1084 | vc->vc_font.height = fvc->vc_font.height; | ||
1085 | p->userfont = t->userfont; | ||
1086 | |||
1087 | if (p->userfont) | ||
1088 | REFCOUNT(p->fontdata)++; | ||
1089 | } else { | ||
1090 | const struct font_desc *font = NULL; | ||
1091 | |||
1092 | if (!fontname[0] || !(font = find_font(fontname))) | ||
1093 | font = get_default_font(info->var.xres, | ||
1094 | info->var.yres); | ||
1095 | vc->vc_font.width = font->width; | ||
1096 | vc->vc_font.height = font->height; | ||
1097 | vc->vc_font.data = (void *)(p->fontdata = font->data); | ||
1098 | vc->vc_font.charcount = 256; /* FIXME Need to | ||
1099 | support more fonts */ | ||
1100 | } | ||
1072 | } | 1101 | } |
1102 | |||
1073 | if (p->userfont) | 1103 | if (p->userfont) |
1074 | charcnt = FNTCHARCNT(p->fontdata); | 1104 | charcnt = FNTCHARCNT(p->fontdata); |
1105 | |||
1075 | vc->vc_can_do_color = (fb_get_color_depth(&info->var, &info->fix)!=1); | 1106 | vc->vc_can_do_color = (fb_get_color_depth(&info->var, &info->fix)!=1); |
1076 | vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800; | 1107 | vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800; |
1077 | if (charcnt == 256) { | 1108 | if (charcnt == 256) { |
@@ -1145,13 +1176,47 @@ static void fbcon_init(struct vc_data *vc, int init) | |||
1145 | ops->p = &fb_display[fg_console]; | 1176 | ops->p = &fb_display[fg_console]; |
1146 | } | 1177 | } |
1147 | 1178 | ||
1179 | static void fbcon_free_font(struct display *p) | ||
1180 | { | ||
1181 | if (p->userfont && p->fontdata && (--REFCOUNT(p->fontdata) == 0)) | ||
1182 | kfree(p->fontdata - FONT_EXTRA_WORDS * sizeof(int)); | ||
1183 | p->fontdata = NULL; | ||
1184 | p->userfont = 0; | ||
1185 | } | ||
1186 | |||
1148 | static void fbcon_deinit(struct vc_data *vc) | 1187 | static void fbcon_deinit(struct vc_data *vc) |
1149 | { | 1188 | { |
1150 | struct display *p = &fb_display[vc->vc_num]; | 1189 | struct display *p = &fb_display[vc->vc_num]; |
1190 | struct fb_info *info; | ||
1191 | struct fbcon_ops *ops; | ||
1192 | int idx; | ||
1151 | 1193 | ||
1152 | if (info_idx != -1) | ||
1153 | return; | ||
1154 | fbcon_free_font(p); | 1194 | fbcon_free_font(p); |
1195 | idx = con2fb_map[vc->vc_num]; | ||
1196 | |||
1197 | if (idx == -1) | ||
1198 | goto finished; | ||
1199 | |||
1200 | info = registered_fb[idx]; | ||
1201 | |||
1202 | if (!info) | ||
1203 | goto finished; | ||
1204 | |||
1205 | ops = info->fbcon_par; | ||
1206 | |||
1207 | if (!ops) | ||
1208 | goto finished; | ||
1209 | |||
1210 | if (CON_IS_VISIBLE(vc)) | ||
1211 | fbcon_del_cursor_timer(info); | ||
1212 | |||
1213 | ops->flags &= ~FBCON_FLAGS_INIT; | ||
1214 | finished: | ||
1215 | |||
1216 | if (!con_is_bound(&fb_con)) | ||
1217 | fbcon_exit(); | ||
1218 | |||
1219 | return; | ||
1155 | } | 1220 | } |
1156 | 1221 | ||
1157 | /* ====================================================================== */ | 1222 | /* ====================================================================== */ |
@@ -2099,12 +2164,11 @@ static int fbcon_switch(struct vc_data *vc) | |||
2099 | if (info->fbops->fb_set_par) | 2164 | if (info->fbops->fb_set_par) |
2100 | info->fbops->fb_set_par(info); | 2165 | info->fbops->fb_set_par(info); |
2101 | 2166 | ||
2102 | if (old_info != info) { | 2167 | if (old_info != info) |
2103 | fbcon_del_cursor_timer(old_info); | 2168 | fbcon_del_cursor_timer(old_info); |
2104 | fbcon_add_cursor_timer(info); | ||
2105 | } | ||
2106 | } | 2169 | } |
2107 | 2170 | ||
2171 | fbcon_add_cursor_timer(info); | ||
2108 | set_blitting_type(vc, info); | 2172 | set_blitting_type(vc, info); |
2109 | ops->cursor_reset = 1; | 2173 | ops->cursor_reset = 1; |
2110 | 2174 | ||
@@ -2222,14 +2286,6 @@ static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch) | |||
2222 | return 0; | 2286 | return 0; |
2223 | } | 2287 | } |
2224 | 2288 | ||
2225 | static void fbcon_free_font(struct display *p) | ||
2226 | { | ||
2227 | if (p->userfont && p->fontdata && (--REFCOUNT(p->fontdata) == 0)) | ||
2228 | kfree(p->fontdata - FONT_EXTRA_WORDS * sizeof(int)); | ||
2229 | p->fontdata = NULL; | ||
2230 | p->userfont = 0; | ||
2231 | } | ||
2232 | |||
2233 | static int fbcon_get_font(struct vc_data *vc, struct console_font *font) | 2289 | static int fbcon_get_font(struct vc_data *vc, struct console_font *font) |
2234 | { | 2290 | { |
2235 | u8 *fontdata = vc->vc_font.data; | 2291 | u8 *fontdata = vc->vc_font.data; |
@@ -2443,7 +2499,7 @@ static int fbcon_set_font(struct vc_data *vc, struct console_font *font, unsigne | |||
2443 | 2499 | ||
2444 | FNTSUM(new_data) = csum; | 2500 | FNTSUM(new_data) = csum; |
2445 | /* Check if the same font is on some other console already */ | 2501 | /* Check if the same font is on some other console already */ |
2446 | for (i = 0; i < MAX_NR_CONSOLES; i++) { | 2502 | for (i = first_fb_vc; i <= last_fb_vc; i++) { |
2447 | struct vc_data *tmp = vc_cons[i].d; | 2503 | struct vc_data *tmp = vc_cons[i].d; |
2448 | 2504 | ||
2449 | if (fb_display[i].userfont && | 2505 | if (fb_display[i].userfont && |
@@ -2768,7 +2824,7 @@ static void fbcon_set_all_vcs(struct fb_info *info) | |||
2768 | if (!ops || ops->currcon < 0) | 2824 | if (!ops || ops->currcon < 0) |
2769 | return; | 2825 | return; |
2770 | 2826 | ||
2771 | for (i = 0; i < MAX_NR_CONSOLES; i++) { | 2827 | for (i = first_fb_vc; i <= last_fb_vc; i++) { |
2772 | vc = vc_cons[i].d; | 2828 | vc = vc_cons[i].d; |
2773 | if (!vc || vc->vc_mode != KD_TEXT || | 2829 | if (!vc || vc->vc_mode != KD_TEXT || |
2774 | registered_fb[con2fb_map[i]] != info) | 2830 | registered_fb[con2fb_map[i]] != info) |
@@ -2830,22 +2886,57 @@ static int fbcon_mode_deleted(struct fb_info *info, | |||
2830 | return found; | 2886 | return found; |
2831 | } | 2887 | } |
2832 | 2888 | ||
2889 | static int fbcon_fb_unregistered(int idx) | ||
2890 | { | ||
2891 | int i; | ||
2892 | |||
2893 | for (i = first_fb_vc; i <= last_fb_vc; i++) { | ||
2894 | if (con2fb_map[i] == idx) | ||
2895 | con2fb_map[i] = -1; | ||
2896 | } | ||
2897 | |||
2898 | if (idx == info_idx) { | ||
2899 | info_idx = -1; | ||
2900 | |||
2901 | for (i = 0; i < FB_MAX; i++) { | ||
2902 | if (registered_fb[i] != NULL) { | ||
2903 | info_idx = i; | ||
2904 | break; | ||
2905 | } | ||
2906 | } | ||
2907 | } | ||
2908 | |||
2909 | if (info_idx != -1) { | ||
2910 | for (i = first_fb_vc; i <= last_fb_vc; i++) { | ||
2911 | if (con2fb_map[i] == -1) | ||
2912 | con2fb_map[i] = info_idx; | ||
2913 | } | ||
2914 | } | ||
2915 | |||
2916 | if (!num_registered_fb) | ||
2917 | unregister_con_driver(&fb_con); | ||
2918 | |||
2919 | return 0; | ||
2920 | } | ||
2921 | |||
2833 | static int fbcon_fb_registered(int idx) | 2922 | static int fbcon_fb_registered(int idx) |
2834 | { | 2923 | { |
2835 | int ret = 0, i; | 2924 | int ret = 0, i; |
2836 | 2925 | ||
2837 | if (info_idx == -1) { | 2926 | if (info_idx == -1) { |
2838 | for (i = 0; i < MAX_NR_CONSOLES; i++) { | 2927 | for (i = first_fb_vc; i <= last_fb_vc; i++) { |
2839 | if (con2fb_map_boot[i] == idx) { | 2928 | if (con2fb_map_boot[i] == idx) { |
2840 | info_idx = idx; | 2929 | info_idx = idx; |
2841 | break; | 2930 | break; |
2842 | } | 2931 | } |
2843 | } | 2932 | } |
2933 | |||
2844 | if (info_idx != -1) | 2934 | if (info_idx != -1) |
2845 | ret = fbcon_takeover(1); | 2935 | ret = fbcon_takeover(1); |
2846 | } else { | 2936 | } else { |
2847 | for (i = 0; i < MAX_NR_CONSOLES; i++) { | 2937 | for (i = first_fb_vc; i <= last_fb_vc; i++) { |
2848 | if (con2fb_map_boot[i] == idx) | 2938 | if (con2fb_map_boot[i] == idx && |
2939 | con2fb_map[i] == -1) | ||
2849 | set_con2fb_map(i, idx, 0); | 2940 | set_con2fb_map(i, idx, 0); |
2850 | } | 2941 | } |
2851 | } | 2942 | } |
@@ -2882,7 +2973,7 @@ static void fbcon_new_modelist(struct fb_info *info) | |||
2882 | struct fb_var_screeninfo var; | 2973 | struct fb_var_screeninfo var; |
2883 | struct fb_videomode *mode; | 2974 | struct fb_videomode *mode; |
2884 | 2975 | ||
2885 | for (i = 0; i < MAX_NR_CONSOLES; i++) { | 2976 | for (i = first_fb_vc; i <= last_fb_vc; i++) { |
2886 | if (registered_fb[con2fb_map[i]] != info) | 2977 | if (registered_fb[con2fb_map[i]] != info) |
2887 | continue; | 2978 | continue; |
2888 | if (!fb_display[i].mode) | 2979 | if (!fb_display[i].mode) |
@@ -2910,6 +3001,14 @@ static int fbcon_event_notify(struct notifier_block *self, | |||
2910 | struct fb_con2fbmap *con2fb; | 3001 | struct fb_con2fbmap *con2fb; |
2911 | int ret = 0; | 3002 | int ret = 0; |
2912 | 3003 | ||
3004 | /* | ||
3005 | * ignore all events except driver registration and deregistration | ||
3006 | * if fbcon is not active | ||
3007 | */ | ||
3008 | if (fbcon_has_exited && !(action == FB_EVENT_FB_REGISTERED || | ||
3009 | action == FB_EVENT_FB_UNREGISTERED)) | ||
3010 | goto done; | ||
3011 | |||
2913 | switch(action) { | 3012 | switch(action) { |
2914 | case FB_EVENT_SUSPEND: | 3013 | case FB_EVENT_SUSPEND: |
2915 | fbcon_suspended(info); | 3014 | fbcon_suspended(info); |
@@ -2930,6 +3029,9 @@ static int fbcon_event_notify(struct notifier_block *self, | |||
2930 | case FB_EVENT_FB_REGISTERED: | 3029 | case FB_EVENT_FB_REGISTERED: |
2931 | ret = fbcon_fb_registered(info->node); | 3030 | ret = fbcon_fb_registered(info->node); |
2932 | break; | 3031 | break; |
3032 | case FB_EVENT_FB_UNREGISTERED: | ||
3033 | ret = fbcon_fb_unregistered(info->node); | ||
3034 | break; | ||
2933 | case FB_EVENT_SET_CONSOLE_MAP: | 3035 | case FB_EVENT_SET_CONSOLE_MAP: |
2934 | con2fb = event->data; | 3036 | con2fb = event->data; |
2935 | ret = set_con2fb_map(con2fb->console - 1, | 3037 | ret = set_con2fb_map(con2fb->console - 1, |
@@ -2945,16 +3047,9 @@ static int fbcon_event_notify(struct notifier_block *self, | |||
2945 | case FB_EVENT_NEW_MODELIST: | 3047 | case FB_EVENT_NEW_MODELIST: |
2946 | fbcon_new_modelist(info); | 3048 | fbcon_new_modelist(info); |
2947 | break; | 3049 | break; |
2948 | case FB_EVENT_SET_CON_ROTATE: | ||
2949 | fbcon_rotate(info, *(int *)event->data); | ||
2950 | break; | ||
2951 | case FB_EVENT_GET_CON_ROTATE: | ||
2952 | ret = fbcon_get_rotate(info); | ||
2953 | break; | ||
2954 | case FB_EVENT_SET_CON_ROTATE_ALL: | ||
2955 | fbcon_rotate_all(info, *(int *)event->data); | ||
2956 | } | 3050 | } |
2957 | 3051 | ||
3052 | done: | ||
2958 | return ret; | 3053 | return ret; |
2959 | } | 3054 | } |
2960 | 3055 | ||
@@ -2992,27 +3087,181 @@ static struct notifier_block fbcon_event_notifier = { | |||
2992 | .notifier_call = fbcon_event_notify, | 3087 | .notifier_call = fbcon_event_notify, |
2993 | }; | 3088 | }; |
2994 | 3089 | ||
2995 | static int __init fb_console_init(void) | 3090 | static ssize_t store_rotate(struct class_device *class_device, |
3091 | const char *buf, size_t count) | ||
2996 | { | 3092 | { |
2997 | int i; | 3093 | struct fb_info *info; |
3094 | int rotate, idx; | ||
3095 | char **last = NULL; | ||
3096 | |||
3097 | if (fbcon_has_exited) | ||
3098 | return count; | ||
2998 | 3099 | ||
2999 | acquire_console_sem(); | 3100 | acquire_console_sem(); |
3000 | fb_register_client(&fbcon_event_notifier); | 3101 | idx = con2fb_map[fg_console]; |
3102 | |||
3103 | if (idx == -1 || registered_fb[idx] == NULL) | ||
3104 | goto err; | ||
3105 | |||
3106 | info = registered_fb[idx]; | ||
3107 | rotate = simple_strtoul(buf, last, 0); | ||
3108 | fbcon_rotate(info, rotate); | ||
3109 | err: | ||
3001 | release_console_sem(); | 3110 | release_console_sem(); |
3111 | return count; | ||
3112 | } | ||
3002 | 3113 | ||
3003 | for (i = 0; i < MAX_NR_CONSOLES; i++) | 3114 | static ssize_t store_rotate_all(struct class_device *class_device, |
3004 | con2fb_map[i] = -1; | 3115 | const char *buf, size_t count) |
3116 | { | ||
3117 | struct fb_info *info; | ||
3118 | int rotate, idx; | ||
3119 | char **last = NULL; | ||
3120 | |||
3121 | if (fbcon_has_exited) | ||
3122 | return count; | ||
3123 | |||
3124 | acquire_console_sem(); | ||
3125 | idx = con2fb_map[fg_console]; | ||
3126 | |||
3127 | if (idx == -1 || registered_fb[idx] == NULL) | ||
3128 | goto err; | ||
3005 | 3129 | ||
3130 | info = registered_fb[idx]; | ||
3131 | rotate = simple_strtoul(buf, last, 0); | ||
3132 | fbcon_rotate_all(info, rotate); | ||
3133 | err: | ||
3134 | release_console_sem(); | ||
3135 | return count; | ||
3136 | } | ||
3137 | |||
3138 | static ssize_t show_rotate(struct class_device *class_device, char *buf) | ||
3139 | { | ||
3140 | struct fb_info *info; | ||
3141 | int rotate = 0, idx; | ||
3142 | |||
3143 | if (fbcon_has_exited) | ||
3144 | return 0; | ||
3145 | |||
3146 | acquire_console_sem(); | ||
3147 | idx = con2fb_map[fg_console]; | ||
3148 | |||
3149 | if (idx == -1 || registered_fb[idx] == NULL) | ||
3150 | goto err; | ||
3151 | |||
3152 | info = registered_fb[idx]; | ||
3153 | rotate = fbcon_get_rotate(info); | ||
3154 | err: | ||
3155 | release_console_sem(); | ||
3156 | return snprintf(buf, PAGE_SIZE, "%d\n", rotate); | ||
3157 | } | ||
3158 | |||
3159 | static struct class_device_attribute class_device_attrs[] = { | ||
3160 | __ATTR(rotate, S_IRUGO|S_IWUSR, show_rotate, store_rotate), | ||
3161 | __ATTR(rotate_all, S_IWUSR, NULL, store_rotate_all), | ||
3162 | }; | ||
3163 | |||
3164 | static int fbcon_init_class_device(void) | ||
3165 | { | ||
3166 | int i; | ||
3167 | |||
3168 | for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++) | ||
3169 | class_device_create_file(fbcon_class_device, | ||
3170 | &class_device_attrs[i]); | ||
3171 | return 0; | ||
3172 | } | ||
3173 | |||
3174 | static void fbcon_start(void) | ||
3175 | { | ||
3006 | if (num_registered_fb) { | 3176 | if (num_registered_fb) { |
3177 | int i; | ||
3178 | |||
3179 | acquire_console_sem(); | ||
3180 | |||
3007 | for (i = 0; i < FB_MAX; i++) { | 3181 | for (i = 0; i < FB_MAX; i++) { |
3008 | if (registered_fb[i] != NULL) { | 3182 | if (registered_fb[i] != NULL) { |
3009 | info_idx = i; | 3183 | info_idx = i; |
3010 | break; | 3184 | break; |
3011 | } | 3185 | } |
3012 | } | 3186 | } |
3187 | |||
3188 | release_console_sem(); | ||
3013 | fbcon_takeover(0); | 3189 | fbcon_takeover(0); |
3014 | } | 3190 | } |
3191 | } | ||
3192 | |||
3193 | static void fbcon_exit(void) | ||
3194 | { | ||
3195 | struct fb_info *info; | ||
3196 | int i, j, mapped; | ||
3197 | |||
3198 | if (fbcon_has_exited) | ||
3199 | return; | ||
3200 | |||
3201 | #ifdef CONFIG_ATARI | ||
3202 | free_irq(IRQ_AUTO_4, fbcon_vbl_handler); | ||
3203 | #endif | ||
3204 | #ifdef CONFIG_MAC | ||
3205 | if (MACH_IS_MAC && vbl_detected) | ||
3206 | free_irq(IRQ_MAC_VBL, fbcon_vbl_handler); | ||
3207 | #endif | ||
3208 | |||
3209 | kfree((void *)softback_buf); | ||
3210 | softback_buf = 0UL; | ||
3211 | |||
3212 | for (i = 0; i < FB_MAX; i++) { | ||
3213 | mapped = 0; | ||
3214 | info = registered_fb[i]; | ||
3215 | |||
3216 | if (info == NULL) | ||
3217 | continue; | ||
3218 | |||
3219 | for (j = first_fb_vc; j <= last_fb_vc; j++) { | ||
3220 | if (con2fb_map[j] == i) | ||
3221 | mapped = 1; | ||
3222 | } | ||
3223 | |||
3224 | if (mapped) { | ||
3225 | if (info->fbops->fb_release) | ||
3226 | info->fbops->fb_release(info, 0); | ||
3227 | module_put(info->fbops->owner); | ||
3228 | |||
3229 | if (info->fbcon_par) { | ||
3230 | fbcon_del_cursor_timer(info); | ||
3231 | kfree(info->fbcon_par); | ||
3232 | info->fbcon_par = NULL; | ||
3233 | } | ||
3015 | 3234 | ||
3235 | if (info->queue.func == fb_flashcursor) | ||
3236 | info->queue.func = NULL; | ||
3237 | } | ||
3238 | } | ||
3239 | |||
3240 | fbcon_has_exited = 1; | ||
3241 | } | ||
3242 | |||
3243 | static int __init fb_console_init(void) | ||
3244 | { | ||
3245 | int i; | ||
3246 | |||
3247 | acquire_console_sem(); | ||
3248 | fb_register_client(&fbcon_event_notifier); | ||
3249 | fbcon_class_device = | ||
3250 | class_device_create(fb_class, NULL, MKDEV(0, 0), NULL, "fbcon"); | ||
3251 | |||
3252 | if (IS_ERR(fbcon_class_device)) { | ||
3253 | printk(KERN_WARNING "Unable to create class_device " | ||
3254 | "for fbcon; errno = %ld\n", | ||
3255 | PTR_ERR(fbcon_class_device)); | ||
3256 | fbcon_class_device = NULL; | ||
3257 | } else | ||
3258 | fbcon_init_class_device(); | ||
3259 | |||
3260 | for (i = 0; i < MAX_NR_CONSOLES; i++) | ||
3261 | con2fb_map[i] = -1; | ||
3262 | |||
3263 | release_console_sem(); | ||
3264 | fbcon_start(); | ||
3016 | return 0; | 3265 | return 0; |
3017 | } | 3266 | } |
3018 | 3267 | ||
@@ -3020,12 +3269,24 @@ module_init(fb_console_init); | |||
3020 | 3269 | ||
3021 | #ifdef MODULE | 3270 | #ifdef MODULE |
3022 | 3271 | ||
3272 | static void __exit fbcon_deinit_class_device(void) | ||
3273 | { | ||
3274 | int i; | ||
3275 | |||
3276 | for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++) | ||
3277 | class_device_remove_file(fbcon_class_device, | ||
3278 | &class_device_attrs[i]); | ||
3279 | } | ||
3280 | |||
3023 | static void __exit fb_console_exit(void) | 3281 | static void __exit fb_console_exit(void) |
3024 | { | 3282 | { |
3025 | acquire_console_sem(); | 3283 | acquire_console_sem(); |
3026 | fb_unregister_client(&fbcon_event_notifier); | 3284 | fb_unregister_client(&fbcon_event_notifier); |
3285 | fbcon_deinit_class_device(); | ||
3286 | class_device_destroy(fb_class, MKDEV(0, 0)); | ||
3287 | fbcon_exit(); | ||
3027 | release_console_sem(); | 3288 | release_console_sem(); |
3028 | give_up_console(&fb_con); | 3289 | unregister_con_driver(&fb_con); |
3029 | } | 3290 | } |
3030 | 3291 | ||
3031 | module_exit(fb_console_exit); | 3292 | module_exit(fb_console_exit); |
diff --git a/drivers/video/console/fbcon.h b/drivers/video/console/fbcon.h index c38c3d8e7a74..3487a636370a 100644 --- a/drivers/video/console/fbcon.h +++ b/drivers/video/console/fbcon.h | |||
@@ -175,6 +175,7 @@ extern void fbcon_set_tileops(struct vc_data *vc, struct fb_info *info); | |||
175 | #endif | 175 | #endif |
176 | extern void fbcon_set_bitops(struct fbcon_ops *ops); | 176 | extern void fbcon_set_bitops(struct fbcon_ops *ops); |
177 | extern int soft_cursor(struct fb_info *info, struct fb_cursor *cursor); | 177 | extern int soft_cursor(struct fb_info *info, struct fb_cursor *cursor); |
178 | extern struct class *fb_class; | ||
178 | 179 | ||
179 | #define FBCON_ATTRIBUTE_UNDERLINE 1 | 180 | #define FBCON_ATTRIBUTE_UNDERLINE 1 |
180 | #define FBCON_ATTRIBUTE_REVERSE 2 | 181 | #define FBCON_ATTRIBUTE_REVERSE 2 |
diff --git a/drivers/video/console/mdacon.c b/drivers/video/console/mdacon.c index 7f939d066a5a..c89f90edf8ac 100644 --- a/drivers/video/console/mdacon.c +++ b/drivers/video/console/mdacon.c | |||
@@ -308,7 +308,7 @@ static void __init mda_initialize(void) | |||
308 | outb_p(0x00, mda_gfx_port); | 308 | outb_p(0x00, mda_gfx_port); |
309 | } | 309 | } |
310 | 310 | ||
311 | static const char __init *mdacon_startup(void) | 311 | static const char *mdacon_startup(void) |
312 | { | 312 | { |
313 | mda_num_columns = 80; | 313 | mda_num_columns = 80; |
314 | mda_num_lines = 25; | 314 | mda_num_lines = 25; |
diff --git a/drivers/video/console/newport_con.c b/drivers/video/console/newport_con.c index e99fe30e568c..03041311711b 100644 --- a/drivers/video/console/newport_con.c +++ b/drivers/video/console/newport_con.c | |||
@@ -51,6 +51,7 @@ static int topscan; | |||
51 | static int xcurs_correction = 29; | 51 | static int xcurs_correction = 29; |
52 | static int newport_xsize; | 52 | static int newport_xsize; |
53 | static int newport_ysize; | 53 | static int newport_ysize; |
54 | static int newport_has_init; | ||
54 | 55 | ||
55 | static int newport_set_def_font(int unit, struct console_font *op); | 56 | static int newport_set_def_font(int unit, struct console_font *op); |
56 | 57 | ||
@@ -283,6 +284,15 @@ static void newport_get_revisions(void) | |||
283 | xcurs_correction = 21; | 284 | xcurs_correction = 21; |
284 | } | 285 | } |
285 | 286 | ||
287 | static void newport_exit(void) | ||
288 | { | ||
289 | int i; | ||
290 | |||
291 | /* free memory used by user font */ | ||
292 | for (i = 0; i < MAX_NR_CONSOLES; i++) | ||
293 | newport_set_def_font(i, NULL); | ||
294 | } | ||
295 | |||
286 | /* Can't be __init, take_over_console may call it later */ | 296 | /* Can't be __init, take_over_console may call it later */ |
287 | static const char *newport_startup(void) | 297 | static const char *newport_startup(void) |
288 | { | 298 | { |
@@ -290,8 +300,10 @@ static const char *newport_startup(void) | |||
290 | 300 | ||
291 | if (!sgi_gfxaddr) | 301 | if (!sgi_gfxaddr) |
292 | return NULL; | 302 | return NULL; |
293 | npregs = (struct newport_regs *) /* ioremap cannot fail */ | 303 | |
294 | ioremap(sgi_gfxaddr, sizeof(struct newport_regs)); | 304 | if (!npregs) |
305 | npregs = (struct newport_regs *)/* ioremap cannot fail */ | ||
306 | ioremap(sgi_gfxaddr, sizeof(struct newport_regs)); | ||
295 | npregs->cset.config = NPORT_CFG_GD0; | 307 | npregs->cset.config = NPORT_CFG_GD0; |
296 | 308 | ||
297 | if (newport_wait(npregs)) | 309 | if (newport_wait(npregs)) |
@@ -307,11 +319,11 @@ static const char *newport_startup(void) | |||
307 | newport_reset(); | 319 | newport_reset(); |
308 | newport_get_revisions(); | 320 | newport_get_revisions(); |
309 | newport_get_screensize(); | 321 | newport_get_screensize(); |
322 | newport_has_init = 1; | ||
310 | 323 | ||
311 | return "SGI Newport"; | 324 | return "SGI Newport"; |
312 | 325 | ||
313 | out_unmap: | 326 | out_unmap: |
314 | iounmap((void *)npregs); | ||
315 | return NULL; | 327 | return NULL; |
316 | } | 328 | } |
317 | 329 | ||
@@ -324,11 +336,10 @@ static void newport_init(struct vc_data *vc, int init) | |||
324 | 336 | ||
325 | static void newport_deinit(struct vc_data *c) | 337 | static void newport_deinit(struct vc_data *c) |
326 | { | 338 | { |
327 | int i; | 339 | if (!con_is_bound(&newport_con) && newport_has_init) { |
328 | 340 | newport_exit(); | |
329 | /* free memory used by user font */ | 341 | newport_has_init = 0; |
330 | for (i = 0; i < MAX_NR_CONSOLES; i++) | 342 | } |
331 | newport_set_def_font(i, NULL); | ||
332 | } | 343 | } |
333 | 344 | ||
334 | static void newport_clear(struct vc_data *vc, int sy, int sx, int height, | 345 | static void newport_clear(struct vc_data *vc, int sy, int sx, int height, |
@@ -728,16 +739,23 @@ const struct consw newport_con = { | |||
728 | #ifdef MODULE | 739 | #ifdef MODULE |
729 | static int __init newport_console_init(void) | 740 | static int __init newport_console_init(void) |
730 | { | 741 | { |
742 | |||
743 | if (!sgi_gfxaddr) | ||
744 | return NULL; | ||
745 | |||
746 | if (!npregs) | ||
747 | npregs = (struct newport_regs *)/* ioremap cannot fail */ | ||
748 | ioremap(sgi_gfxaddr, sizeof(struct newport_regs)); | ||
749 | |||
731 | return take_over_console(&newport_con, 0, MAX_NR_CONSOLES - 1, 1); | 750 | return take_over_console(&newport_con, 0, MAX_NR_CONSOLES - 1, 1); |
732 | } | 751 | } |
752 | module_init(newport_console_init); | ||
733 | 753 | ||
734 | static void __exit newport_console_exit(void) | 754 | static void __exit newport_console_exit(void) |
735 | { | 755 | { |
736 | give_up_console(&newport_con); | 756 | give_up_console(&newport_con); |
737 | iounmap((void *)npregs); | 757 | iounmap((void *)npregs); |
738 | } | 758 | } |
739 | |||
740 | module_init(newport_console_init); | ||
741 | module_exit(newport_console_exit); | 759 | module_exit(newport_console_exit); |
742 | #endif | 760 | #endif |
743 | 761 | ||
diff --git a/drivers/video/console/promcon.c b/drivers/video/console/promcon.c index 04f42fcaac59..d6e6ad537f9f 100644 --- a/drivers/video/console/promcon.c +++ b/drivers/video/console/promcon.c | |||
@@ -109,7 +109,7 @@ promcon_end(struct vc_data *conp, char *b) | |||
109 | return b - p; | 109 | return b - p; |
110 | } | 110 | } |
111 | 111 | ||
112 | const char __init *promcon_startup(void) | 112 | const char *promcon_startup(void) |
113 | { | 113 | { |
114 | const char *display_desc = "PROM"; | 114 | const char *display_desc = "PROM"; |
115 | int node; | 115 | int node; |
@@ -133,7 +133,7 @@ const char __init *promcon_startup(void) | |||
133 | return display_desc; | 133 | return display_desc; |
134 | } | 134 | } |
135 | 135 | ||
136 | static void __init | 136 | static void |
137 | promcon_init_unimap(struct vc_data *conp) | 137 | promcon_init_unimap(struct vc_data *conp) |
138 | { | 138 | { |
139 | mm_segment_t old_fs = get_fs(); | 139 | mm_segment_t old_fs = get_fs(); |
diff --git a/drivers/video/console/sticon.c b/drivers/video/console/sticon.c index fd5940f41271..45c4f227e56e 100644 --- a/drivers/video/console/sticon.c +++ b/drivers/video/console/sticon.c | |||
@@ -75,7 +75,7 @@ static inline void cursor_undrawn(void) | |||
75 | cursor_drawn = 0; | 75 | cursor_drawn = 0; |
76 | } | 76 | } |
77 | 77 | ||
78 | static const char *__init sticon_startup(void) | 78 | static const char *sticon_startup(void) |
79 | { | 79 | { |
80 | return "STI console"; | 80 | return "STI console"; |
81 | } | 81 | } |
diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index e64d42e2449e..f32b590730f2 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c | |||
@@ -114,6 +114,7 @@ static int vga_512_chars; | |||
114 | static int vga_video_font_height; | 114 | static int vga_video_font_height; |
115 | static int vga_scan_lines; | 115 | static int vga_scan_lines; |
116 | static unsigned int vga_rolled_over = 0; | 116 | static unsigned int vga_rolled_over = 0; |
117 | static int vga_init_done; | ||
117 | 118 | ||
118 | static int __init no_scroll(char *str) | 119 | static int __init no_scroll(char *str) |
119 | { | 120 | { |
@@ -190,7 +191,7 @@ static void vgacon_scrollback_init(int pitch) | |||
190 | } | 191 | } |
191 | } | 192 | } |
192 | 193 | ||
193 | static void __init vgacon_scrollback_startup(void) | 194 | static void vgacon_scrollback_startup(void) |
194 | { | 195 | { |
195 | vgacon_scrollback = alloc_bootmem(CONFIG_VGACON_SOFT_SCROLLBACK_SIZE | 196 | vgacon_scrollback = alloc_bootmem(CONFIG_VGACON_SOFT_SCROLLBACK_SIZE |
196 | * 1024); | 197 | * 1024); |
@@ -355,7 +356,7 @@ static int vgacon_scrolldelta(struct vc_data *c, int lines) | |||
355 | } | 356 | } |
356 | #endif /* CONFIG_VGACON_SOFT_SCROLLBACK */ | 357 | #endif /* CONFIG_VGACON_SOFT_SCROLLBACK */ |
357 | 358 | ||
358 | static const char __init *vgacon_startup(void) | 359 | static const char *vgacon_startup(void) |
359 | { | 360 | { |
360 | const char *display_desc = NULL; | 361 | const char *display_desc = NULL; |
361 | u16 saved1, saved2; | 362 | u16 saved1, saved2; |
@@ -523,7 +524,12 @@ static const char __init *vgacon_startup(void) | |||
523 | 524 | ||
524 | vgacon_xres = ORIG_VIDEO_COLS * VGA_FONTWIDTH; | 525 | vgacon_xres = ORIG_VIDEO_COLS * VGA_FONTWIDTH; |
525 | vgacon_yres = vga_scan_lines; | 526 | vgacon_yres = vga_scan_lines; |
526 | vgacon_scrollback_startup(); | 527 | |
528 | if (!vga_init_done) { | ||
529 | vgacon_scrollback_startup(); | ||
530 | vga_init_done = 1; | ||
531 | } | ||
532 | |||
527 | return display_desc; | 533 | return display_desc; |
528 | } | 534 | } |
529 | 535 | ||
@@ -531,10 +537,20 @@ static void vgacon_init(struct vc_data *c, int init) | |||
531 | { | 537 | { |
532 | unsigned long p; | 538 | unsigned long p; |
533 | 539 | ||
534 | /* We cannot be loaded as a module, therefore init is always 1 */ | 540 | /* |
541 | * We cannot be loaded as a module, therefore init is always 1, | ||
542 | * but vgacon_init can be called more than once, and init will | ||
543 | * not be 1. | ||
544 | */ | ||
535 | c->vc_can_do_color = vga_can_do_color; | 545 | c->vc_can_do_color = vga_can_do_color; |
536 | c->vc_cols = vga_video_num_columns; | 546 | |
537 | c->vc_rows = vga_video_num_lines; | 547 | /* set dimensions manually if init != 0 since vc_resize() will fail */ |
548 | if (init) { | ||
549 | c->vc_cols = vga_video_num_columns; | ||
550 | c->vc_rows = vga_video_num_lines; | ||
551 | } else | ||
552 | vc_resize(c, vga_video_num_columns, vga_video_num_lines); | ||
553 | |||
538 | c->vc_scan_lines = vga_scan_lines; | 554 | c->vc_scan_lines = vga_scan_lines; |
539 | c->vc_font.height = vga_video_font_height; | 555 | c->vc_font.height = vga_video_font_height; |
540 | c->vc_complement_mask = 0x7700; | 556 | c->vc_complement_mask = 0x7700; |
diff --git a/drivers/video/epson1355fb.c b/drivers/video/epson1355fb.c index 082759447bf6..f0a621ecc288 100644 --- a/drivers/video/epson1355fb.c +++ b/drivers/video/epson1355fb.c | |||
@@ -605,11 +605,6 @@ static void clearfb16(struct fb_info *info) | |||
605 | fb_writeb(0, dst); | 605 | fb_writeb(0, dst); |
606 | } | 606 | } |
607 | 607 | ||
608 | static void epson1355fb_platform_release(struct device *device) | ||
609 | { | ||
610 | dev_err(device, "This driver is broken, please bug the authors so they will fix it.\n"); | ||
611 | } | ||
612 | |||
613 | static int epson1355fb_remove(struct platform_device *dev) | 608 | static int epson1355fb_remove(struct platform_device *dev) |
614 | { | 609 | { |
615 | struct fb_info *info = platform_get_drvdata(dev); | 610 | struct fb_info *info = platform_get_drvdata(dev); |
@@ -733,13 +728,7 @@ static struct platform_driver epson1355fb_driver = { | |||
733 | }, | 728 | }, |
734 | }; | 729 | }; |
735 | 730 | ||
736 | static struct platform_device epson1355fb_device = { | 731 | static struct platform_device *epson1355fb_device; |
737 | .name = "epson1355fb", | ||
738 | .id = 0, | ||
739 | .dev = { | ||
740 | .release = epson1355fb_platform_release, | ||
741 | } | ||
742 | }; | ||
743 | 732 | ||
744 | int __init epson1355fb_init(void) | 733 | int __init epson1355fb_init(void) |
745 | { | 734 | { |
@@ -749,11 +738,21 @@ int __init epson1355fb_init(void) | |||
749 | return -ENODEV; | 738 | return -ENODEV; |
750 | 739 | ||
751 | ret = platform_driver_register(&epson1355fb_driver); | 740 | ret = platform_driver_register(&epson1355fb_driver); |
741 | |||
752 | if (!ret) { | 742 | if (!ret) { |
753 | ret = platform_device_register(&epson1355fb_device); | 743 | epson1355fb_device = platform_device_alloc("epson1355fb", 0); |
754 | if (ret) | 744 | |
745 | if (epson1355fb_device) | ||
746 | ret = platform_device_add(epson1355fb_device); | ||
747 | else | ||
748 | ret = -ENOMEM; | ||
749 | |||
750 | if (ret) { | ||
751 | platform_device_put(epson1355fb_device); | ||
755 | platform_driver_unregister(&epson1355fb_driver); | 752 | platform_driver_unregister(&epson1355fb_driver); |
753 | } | ||
756 | } | 754 | } |
755 | |||
757 | return ret; | 756 | return ret; |
758 | } | 757 | } |
759 | 758 | ||
@@ -762,7 +761,7 @@ module_init(epson1355fb_init); | |||
762 | #ifdef MODULE | 761 | #ifdef MODULE |
763 | static void __exit epson1355fb_exit(void) | 762 | static void __exit epson1355fb_exit(void) |
764 | { | 763 | { |
765 | platform_device_unregister(&epson1355fb_device); | 764 | platform_device_unregister(epson1355fb_device); |
766 | platform_driver_unregister(&epson1355fb_driver); | 765 | platform_driver_unregister(&epson1355fb_driver); |
767 | } | 766 | } |
768 | 767 | ||
diff --git a/drivers/video/fbcvt.c b/drivers/video/fbcvt.c index ac90883dc3aa..b5498999c4ec 100644 --- a/drivers/video/fbcvt.c +++ b/drivers/video/fbcvt.c | |||
@@ -376,4 +376,3 @@ int fb_find_mode_cvt(struct fb_videomode *mode, int margins, int rb) | |||
376 | 376 | ||
377 | return 0; | 377 | return 0; |
378 | } | 378 | } |
379 | EXPORT_SYMBOL(fb_find_mode_cvt); | ||
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index 372aa1776827..31143afe7c95 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c | |||
@@ -34,7 +34,6 @@ | |||
34 | #endif | 34 | #endif |
35 | #include <linux/devfs_fs_kernel.h> | 35 | #include <linux/devfs_fs_kernel.h> |
36 | #include <linux/err.h> | 36 | #include <linux/err.h> |
37 | #include <linux/kernel.h> | ||
38 | #include <linux/device.h> | 37 | #include <linux/device.h> |
39 | #include <linux/efi.h> | 38 | #include <linux/efi.h> |
40 | 39 | ||
@@ -162,7 +161,6 @@ char* fb_get_buffer_offset(struct fb_info *info, struct fb_pixmap *buf, u32 size | |||
162 | } | 161 | } |
163 | 162 | ||
164 | #ifdef CONFIG_LOGO | 163 | #ifdef CONFIG_LOGO |
165 | #include <linux/linux_logo.h> | ||
166 | 164 | ||
167 | static inline unsigned safe_shift(unsigned d, int n) | 165 | static inline unsigned safe_shift(unsigned d, int n) |
168 | { | 166 | { |
@@ -336,11 +334,11 @@ static void fb_rotate_logo_ud(const u8 *in, u8 *out, u32 width, u32 height) | |||
336 | 334 | ||
337 | static void fb_rotate_logo_cw(const u8 *in, u8 *out, u32 width, u32 height) | 335 | static void fb_rotate_logo_cw(const u8 *in, u8 *out, u32 width, u32 height) |
338 | { | 336 | { |
339 | int i, j, w = width - 1; | 337 | int i, j, h = height - 1; |
340 | 338 | ||
341 | for (i = 0; i < height; i++) | 339 | for (i = 0; i < height; i++) |
342 | for (j = 0; j < width; j++) | 340 | for (j = 0; j < width; j++) |
343 | out[height * j + w - i] = *in++; | 341 | out[height * j + h - i] = *in++; |
344 | } | 342 | } |
345 | 343 | ||
346 | static void fb_rotate_logo_ccw(const u8 *in, u8 *out, u32 width, u32 height) | 344 | static void fb_rotate_logo_ccw(const u8 *in, u8 *out, u32 width, u32 height) |
@@ -358,24 +356,24 @@ static void fb_rotate_logo(struct fb_info *info, u8 *dst, | |||
358 | u32 tmp; | 356 | u32 tmp; |
359 | 357 | ||
360 | if (rotate == FB_ROTATE_UD) { | 358 | if (rotate == FB_ROTATE_UD) { |
361 | image->dx = info->var.xres - image->width; | ||
362 | image->dy = info->var.yres - image->height; | ||
363 | fb_rotate_logo_ud(image->data, dst, image->width, | 359 | fb_rotate_logo_ud(image->data, dst, image->width, |
364 | image->height); | 360 | image->height); |
361 | image->dx = info->var.xres - image->width; | ||
362 | image->dy = info->var.yres - image->height; | ||
365 | } else if (rotate == FB_ROTATE_CW) { | 363 | } else if (rotate == FB_ROTATE_CW) { |
366 | tmp = image->width; | ||
367 | image->width = image->height; | ||
368 | image->height = tmp; | ||
369 | image->dx = info->var.xres - image->height; | ||
370 | fb_rotate_logo_cw(image->data, dst, image->width, | 364 | fb_rotate_logo_cw(image->data, dst, image->width, |
371 | image->height); | 365 | image->height); |
372 | } else if (rotate == FB_ROTATE_CCW) { | ||
373 | tmp = image->width; | 366 | tmp = image->width; |
374 | image->width = image->height; | 367 | image->width = image->height; |
375 | image->height = tmp; | 368 | image->height = tmp; |
376 | image->dy = info->var.yres - image->width; | 369 | image->dx = info->var.xres - image->width; |
370 | } else if (rotate == FB_ROTATE_CCW) { | ||
377 | fb_rotate_logo_ccw(image->data, dst, image->width, | 371 | fb_rotate_logo_ccw(image->data, dst, image->width, |
378 | image->height); | 372 | image->height); |
373 | tmp = image->width; | ||
374 | image->width = image->height; | ||
375 | image->height = tmp; | ||
376 | image->dy = info->var.yres - image->height; | ||
379 | } | 377 | } |
380 | 378 | ||
381 | image->data = dst; | 379 | image->data = dst; |
@@ -435,7 +433,7 @@ int fb_prepare_logo(struct fb_info *info, int rotate) | |||
435 | depth = info->var.green.length; | 433 | depth = info->var.green.length; |
436 | } | 434 | } |
437 | 435 | ||
438 | if (info->fix.visual == FB_VISUAL_STATIC_PSEUDOCOLOR) { | 436 | if (info->fix.visual == FB_VISUAL_STATIC_PSEUDOCOLOR && depth > 4) { |
439 | /* assume console colormap */ | 437 | /* assume console colormap */ |
440 | depth = 4; | 438 | depth = 4; |
441 | } | 439 | } |
@@ -1278,8 +1276,8 @@ static struct file_operations fb_fops = { | |||
1278 | #endif | 1276 | #endif |
1279 | }; | 1277 | }; |
1280 | 1278 | ||
1281 | static struct class *fb_class; | 1279 | struct class *fb_class; |
1282 | 1280 | EXPORT_SYMBOL(fb_class); | |
1283 | /** | 1281 | /** |
1284 | * register_framebuffer - registers a frame buffer device | 1282 | * register_framebuffer - registers a frame buffer device |
1285 | * @fb_info: frame buffer info structure | 1283 | * @fb_info: frame buffer info structure |
@@ -1355,6 +1353,7 @@ register_framebuffer(struct fb_info *fb_info) | |||
1355 | int | 1353 | int |
1356 | unregister_framebuffer(struct fb_info *fb_info) | 1354 | unregister_framebuffer(struct fb_info *fb_info) |
1357 | { | 1355 | { |
1356 | struct fb_event event; | ||
1358 | int i; | 1357 | int i; |
1359 | 1358 | ||
1360 | i = fb_info->node; | 1359 | i = fb_info->node; |
@@ -1362,13 +1361,17 @@ unregister_framebuffer(struct fb_info *fb_info) | |||
1362 | return -EINVAL; | 1361 | return -EINVAL; |
1363 | devfs_remove("fb/%d", i); | 1362 | devfs_remove("fb/%d", i); |
1364 | 1363 | ||
1365 | if (fb_info->pixmap.addr && (fb_info->pixmap.flags & FB_PIXMAP_DEFAULT)) | 1364 | if (fb_info->pixmap.addr && |
1365 | (fb_info->pixmap.flags & FB_PIXMAP_DEFAULT)) | ||
1366 | kfree(fb_info->pixmap.addr); | 1366 | kfree(fb_info->pixmap.addr); |
1367 | fb_destroy_modelist(&fb_info->modelist); | 1367 | fb_destroy_modelist(&fb_info->modelist); |
1368 | registered_fb[i]=NULL; | 1368 | registered_fb[i]=NULL; |
1369 | num_registered_fb--; | 1369 | num_registered_fb--; |
1370 | fb_cleanup_class_device(fb_info); | 1370 | fb_cleanup_class_device(fb_info); |
1371 | class_device_destroy(fb_class, MKDEV(FB_MAJOR, i)); | 1371 | class_device_destroy(fb_class, MKDEV(FB_MAJOR, i)); |
1372 | event.info = fb_info; | ||
1373 | blocking_notifier_call_chain(&fb_notifier_list, | ||
1374 | FB_EVENT_FB_UNREGISTERED, &event); | ||
1372 | return 0; | 1375 | return 0; |
1373 | } | 1376 | } |
1374 | 1377 | ||
@@ -1491,28 +1494,6 @@ int fb_new_modelist(struct fb_info *info) | |||
1491 | return err; | 1494 | return err; |
1492 | } | 1495 | } |
1493 | 1496 | ||
1494 | /** | ||
1495 | * fb_con_duit - user<->fbcon passthrough | ||
1496 | * @info: struct fb_info | ||
1497 | * @event: notification event to be passed to fbcon | ||
1498 | * @data: private data | ||
1499 | * | ||
1500 | * DESCRIPTION | ||
1501 | * This function is an fbcon-user event passing channel | ||
1502 | * which bypasses fbdev. This is hopefully temporary | ||
1503 | * until a user interface for fbcon is created | ||
1504 | */ | ||
1505 | int fb_con_duit(struct fb_info *info, int event, void *data) | ||
1506 | { | ||
1507 | struct fb_event evnt; | ||
1508 | |||
1509 | evnt.info = info; | ||
1510 | evnt.data = data; | ||
1511 | |||
1512 | return blocking_notifier_call_chain(&fb_notifier_list, event, &evnt); | ||
1513 | } | ||
1514 | EXPORT_SYMBOL(fb_con_duit); | ||
1515 | |||
1516 | static char *video_options[FB_MAX]; | 1497 | static char *video_options[FB_MAX]; |
1517 | static int ofonly; | 1498 | static int ofonly; |
1518 | 1499 | ||
@@ -1622,6 +1603,5 @@ EXPORT_SYMBOL(fb_set_suspend); | |||
1622 | EXPORT_SYMBOL(fb_register_client); | 1603 | EXPORT_SYMBOL(fb_register_client); |
1623 | EXPORT_SYMBOL(fb_unregister_client); | 1604 | EXPORT_SYMBOL(fb_unregister_client); |
1624 | EXPORT_SYMBOL(fb_get_options); | 1605 | EXPORT_SYMBOL(fb_get_options); |
1625 | EXPORT_SYMBOL(fb_new_modelist); | ||
1626 | 1606 | ||
1627 | MODULE_LICENSE("GPL"); | 1607 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/video/fbmon.c b/drivers/video/fbmon.c index 53beeb4a9998..3ccfff715a51 100644 --- a/drivers/video/fbmon.c +++ b/drivers/video/fbmon.c | |||
@@ -29,9 +29,9 @@ | |||
29 | #include <linux/tty.h> | 29 | #include <linux/tty.h> |
30 | #include <linux/fb.h> | 30 | #include <linux/fb.h> |
31 | #include <linux/module.h> | 31 | #include <linux/module.h> |
32 | #include <linux/pci.h> | ||
32 | #include <video/edid.h> | 33 | #include <video/edid.h> |
33 | #ifdef CONFIG_PPC_OF | 34 | #ifdef CONFIG_PPC_OF |
34 | #include <linux/pci.h> | ||
35 | #include <asm/prom.h> | 35 | #include <asm/prom.h> |
36 | #include <asm/pci-bridge.h> | 36 | #include <asm/pci-bridge.h> |
37 | #endif | 37 | #endif |
@@ -605,6 +605,7 @@ static int fb_get_monitor_limits(unsigned char *edid, struct fb_monspecs *specs) | |||
605 | block = edid + DETAILED_TIMING_DESCRIPTIONS_START; | 605 | block = edid + DETAILED_TIMING_DESCRIPTIONS_START; |
606 | 606 | ||
607 | DPRINTK(" Monitor Operating Limits: "); | 607 | DPRINTK(" Monitor Operating Limits: "); |
608 | |||
608 | for (i = 0; i < 4; i++, block += DETAILED_TIMING_DESCRIPTION_SIZE) { | 609 | for (i = 0; i < 4; i++, block += DETAILED_TIMING_DESCRIPTION_SIZE) { |
609 | if (edid_is_limits_block(block)) { | 610 | if (edid_is_limits_block(block)) { |
610 | specs->hfmin = H_MIN_RATE * 1000; | 611 | specs->hfmin = H_MIN_RATE * 1000; |
@@ -618,11 +619,12 @@ static int fb_get_monitor_limits(unsigned char *edid, struct fb_monspecs *specs) | |||
618 | break; | 619 | break; |
619 | } | 620 | } |
620 | } | 621 | } |
621 | 622 | ||
622 | /* estimate monitor limits based on modes supported */ | 623 | /* estimate monitor limits based on modes supported */ |
623 | if (retval) { | 624 | if (retval) { |
624 | struct fb_videomode *modes; | 625 | struct fb_videomode *modes, *mode; |
625 | int num_modes, i, hz, hscan, pixclock; | 626 | int num_modes, i, hz, hscan, pixclock; |
627 | int vtotal, htotal; | ||
626 | 628 | ||
627 | modes = fb_create_modedb(edid, &num_modes); | 629 | modes = fb_create_modedb(edid, &num_modes); |
628 | if (!modes) { | 630 | if (!modes) { |
@@ -632,20 +634,38 @@ static int fb_get_monitor_limits(unsigned char *edid, struct fb_monspecs *specs) | |||
632 | 634 | ||
633 | retval = 0; | 635 | retval = 0; |
634 | for (i = 0; i < num_modes; i++) { | 636 | for (i = 0; i < num_modes; i++) { |
635 | hz = modes[i].refresh; | 637 | mode = &modes[i]; |
636 | pixclock = PICOS2KHZ(modes[i].pixclock) * 1000; | 638 | pixclock = PICOS2KHZ(modes[i].pixclock) * 1000; |
637 | hscan = (modes[i].yres * 105 * hz + 5000)/100; | 639 | htotal = mode->xres + mode->right_margin + mode->hsync_len |
640 | + mode->left_margin; | ||
641 | vtotal = mode->yres + mode->lower_margin + mode->vsync_len | ||
642 | + mode->upper_margin; | ||
643 | |||
644 | if (mode->vmode & FB_VMODE_INTERLACED) | ||
645 | vtotal /= 2; | ||
646 | |||
647 | if (mode->vmode & FB_VMODE_DOUBLE) | ||
648 | vtotal *= 2; | ||
649 | |||
650 | hscan = (pixclock + htotal / 2) / htotal; | ||
651 | hscan = (hscan + 500) / 1000 * 1000; | ||
652 | hz = (hscan + vtotal / 2) / vtotal; | ||
638 | 653 | ||
639 | if (specs->dclkmax == 0 || specs->dclkmax < pixclock) | 654 | if (specs->dclkmax == 0 || specs->dclkmax < pixclock) |
640 | specs->dclkmax = pixclock; | 655 | specs->dclkmax = pixclock; |
656 | |||
641 | if (specs->dclkmin == 0 || specs->dclkmin > pixclock) | 657 | if (specs->dclkmin == 0 || specs->dclkmin > pixclock) |
642 | specs->dclkmin = pixclock; | 658 | specs->dclkmin = pixclock; |
659 | |||
643 | if (specs->hfmax == 0 || specs->hfmax < hscan) | 660 | if (specs->hfmax == 0 || specs->hfmax < hscan) |
644 | specs->hfmax = hscan; | 661 | specs->hfmax = hscan; |
662 | |||
645 | if (specs->hfmin == 0 || specs->hfmin > hscan) | 663 | if (specs->hfmin == 0 || specs->hfmin > hscan) |
646 | specs->hfmin = hscan; | 664 | specs->hfmin = hscan; |
665 | |||
647 | if (specs->vfmax == 0 || specs->vfmax < hz) | 666 | if (specs->vfmax == 0 || specs->vfmax < hz) |
648 | specs->vfmax = hz; | 667 | specs->vfmax = hz; |
668 | |||
649 | if (specs->vfmin == 0 || specs->vfmin > hz) | 669 | if (specs->vfmin == 0 || specs->vfmin > hz) |
650 | specs->vfmin = hz; | 670 | specs->vfmin = hz; |
651 | } | 671 | } |
@@ -1281,8 +1301,7 @@ int fb_validate_mode(const struct fb_var_screeninfo *var, struct fb_info *info) | |||
1281 | -EINVAL : 0; | 1301 | -EINVAL : 0; |
1282 | } | 1302 | } |
1283 | 1303 | ||
1284 | #if defined(CONFIG_FB_FIRMWARE_EDID) && defined(__i386__) | 1304 | #if defined(CONFIG_FIRMWARE_EDID) && defined(CONFIG_X86) |
1285 | #include <linux/pci.h> | ||
1286 | 1305 | ||
1287 | /* | 1306 | /* |
1288 | * We need to ensure that the EDID block is only returned for | 1307 | * We need to ensure that the EDID block is only returned for |
diff --git a/drivers/video/fbsysfs.c b/drivers/video/fbsysfs.c index 3ceb8c1b392e..4f78f234473d 100644 --- a/drivers/video/fbsysfs.c +++ b/drivers/video/fbsysfs.c | |||
@@ -100,13 +100,22 @@ static int mode_string(char *buf, unsigned int offset, | |||
100 | const struct fb_videomode *mode) | 100 | const struct fb_videomode *mode) |
101 | { | 101 | { |
102 | char m = 'U'; | 102 | char m = 'U'; |
103 | char v = 'p'; | ||
104 | |||
103 | if (mode->flag & FB_MODE_IS_DETAILED) | 105 | if (mode->flag & FB_MODE_IS_DETAILED) |
104 | m = 'D'; | 106 | m = 'D'; |
105 | if (mode->flag & FB_MODE_IS_VESA) | 107 | if (mode->flag & FB_MODE_IS_VESA) |
106 | m = 'V'; | 108 | m = 'V'; |
107 | if (mode->flag & FB_MODE_IS_STANDARD) | 109 | if (mode->flag & FB_MODE_IS_STANDARD) |
108 | m = 'S'; | 110 | m = 'S'; |
109 | return snprintf(&buf[offset], PAGE_SIZE - offset, "%c:%dx%d-%d\n", m, mode->xres, mode->yres, mode->refresh); | 111 | |
112 | if (mode->vmode & FB_VMODE_INTERLACED) | ||
113 | v = 'i'; | ||
114 | if (mode->vmode & FB_VMODE_DOUBLE) | ||
115 | v = 'd'; | ||
116 | |||
117 | return snprintf(&buf[offset], PAGE_SIZE - offset, "%c:%dx%d%c-%d\n", | ||
118 | m, mode->xres, mode->yres, v, mode->refresh); | ||
110 | } | 119 | } |
111 | 120 | ||
112 | static ssize_t store_mode(struct class_device *class_device, const char * buf, | 121 | static ssize_t store_mode(struct class_device *class_device, const char * buf, |
@@ -238,45 +247,6 @@ static ssize_t show_rotate(struct class_device *class_device, char *buf) | |||
238 | return snprintf(buf, PAGE_SIZE, "%d\n", fb_info->var.rotate); | 247 | return snprintf(buf, PAGE_SIZE, "%d\n", fb_info->var.rotate); |
239 | } | 248 | } |
240 | 249 | ||
241 | static ssize_t store_con_rotate(struct class_device *class_device, | ||
242 | const char *buf, size_t count) | ||
243 | { | ||
244 | struct fb_info *fb_info = class_get_devdata(class_device); | ||
245 | int rotate; | ||
246 | char **last = NULL; | ||
247 | |||
248 | acquire_console_sem(); | ||
249 | rotate = simple_strtoul(buf, last, 0); | ||
250 | fb_con_duit(fb_info, FB_EVENT_SET_CON_ROTATE, &rotate); | ||
251 | release_console_sem(); | ||
252 | return count; | ||
253 | } | ||
254 | |||
255 | static ssize_t store_con_rotate_all(struct class_device *class_device, | ||
256 | const char *buf, size_t count) | ||
257 | { | ||
258 | struct fb_info *fb_info = class_get_devdata(class_device); | ||
259 | int rotate; | ||
260 | char **last = NULL; | ||
261 | |||
262 | acquire_console_sem(); | ||
263 | rotate = simple_strtoul(buf, last, 0); | ||
264 | fb_con_duit(fb_info, FB_EVENT_SET_CON_ROTATE_ALL, &rotate); | ||
265 | release_console_sem(); | ||
266 | return count; | ||
267 | } | ||
268 | |||
269 | static ssize_t show_con_rotate(struct class_device *class_device, char *buf) | ||
270 | { | ||
271 | struct fb_info *fb_info = class_get_devdata(class_device); | ||
272 | int rotate; | ||
273 | |||
274 | acquire_console_sem(); | ||
275 | rotate = fb_con_duit(fb_info, FB_EVENT_GET_CON_ROTATE, NULL); | ||
276 | release_console_sem(); | ||
277 | return snprintf(buf, PAGE_SIZE, "%d\n", rotate); | ||
278 | } | ||
279 | |||
280 | static ssize_t store_virtual(struct class_device *class_device, | 250 | static ssize_t store_virtual(struct class_device *class_device, |
281 | const char * buf, size_t count) | 251 | const char * buf, size_t count) |
282 | { | 252 | { |
@@ -493,8 +463,6 @@ static struct class_device_attribute class_device_attrs[] = { | |||
493 | __ATTR(name, S_IRUGO, show_name, NULL), | 463 | __ATTR(name, S_IRUGO, show_name, NULL), |
494 | __ATTR(stride, S_IRUGO, show_stride, NULL), | 464 | __ATTR(stride, S_IRUGO, show_stride, NULL), |
495 | __ATTR(rotate, S_IRUGO|S_IWUSR, show_rotate, store_rotate), | 465 | __ATTR(rotate, S_IRUGO|S_IWUSR, show_rotate, store_rotate), |
496 | __ATTR(con_rotate, S_IRUGO|S_IWUSR, show_con_rotate, store_con_rotate), | ||
497 | __ATTR(con_rotate_all, S_IWUSR, NULL, store_con_rotate_all), | ||
498 | __ATTR(state, S_IRUGO|S_IWUSR, show_fbstate, store_fbstate), | 466 | __ATTR(state, S_IRUGO|S_IWUSR, show_fbstate, store_fbstate), |
499 | #ifdef CONFIG_FB_BACKLIGHT | 467 | #ifdef CONFIG_FB_BACKLIGHT |
500 | __ATTR(bl_curve, S_IRUGO|S_IWUSR, show_bl_curve, store_bl_curve), | 468 | __ATTR(bl_curve, S_IRUGO|S_IWUSR, show_bl_curve, store_bl_curve), |
diff --git a/drivers/video/geode/gx1fb_core.c b/drivers/video/geode/gx1fb_core.c index 20e69156d728..4d3a8871d3d1 100644 --- a/drivers/video/geode/gx1fb_core.c +++ b/drivers/video/geode/gx1fb_core.c | |||
@@ -376,8 +376,6 @@ static int __init gx1fb_probe(struct pci_dev *pdev, const struct pci_device_id * | |||
376 | release_mem_region(gx1_gx_base() + 0x8300, 0x100); | 376 | release_mem_region(gx1_gx_base() + 0x8300, 0x100); |
377 | } | 377 | } |
378 | 378 | ||
379 | pci_disable_device(pdev); | ||
380 | |||
381 | if (info) | 379 | if (info) |
382 | framebuffer_release(info); | 380 | framebuffer_release(info); |
383 | return ret; | 381 | return ret; |
@@ -399,7 +397,6 @@ static void gx1fb_remove(struct pci_dev *pdev) | |||
399 | iounmap(par->dc_regs); | 397 | iounmap(par->dc_regs); |
400 | release_mem_region(gx1_gx_base() + 0x8300, 0x100); | 398 | release_mem_region(gx1_gx_base() + 0x8300, 0x100); |
401 | 399 | ||
402 | pci_disable_device(pdev); | ||
403 | pci_set_drvdata(pdev, NULL); | 400 | pci_set_drvdata(pdev, NULL); |
404 | 401 | ||
405 | framebuffer_release(info); | 402 | framebuffer_release(info); |
diff --git a/drivers/video/geode/gxfb_core.c b/drivers/video/geode/gxfb_core.c index 89c34b15f5d4..5ef12a3dfa50 100644 --- a/drivers/video/geode/gxfb_core.c +++ b/drivers/video/geode/gxfb_core.c | |||
@@ -354,8 +354,6 @@ static int __init gxfb_probe(struct pci_dev *pdev, const struct pci_device_id *i | |||
354 | pci_release_region(pdev, 2); | 354 | pci_release_region(pdev, 2); |
355 | } | 355 | } |
356 | 356 | ||
357 | pci_disable_device(pdev); | ||
358 | |||
359 | if (info) | 357 | if (info) |
360 | framebuffer_release(info); | 358 | framebuffer_release(info); |
361 | return ret; | 359 | return ret; |
@@ -377,7 +375,6 @@ static void gxfb_remove(struct pci_dev *pdev) | |||
377 | iounmap(par->dc_regs); | 375 | iounmap(par->dc_regs); |
378 | pci_release_region(pdev, 2); | 376 | pci_release_region(pdev, 2); |
379 | 377 | ||
380 | pci_disable_device(pdev); | ||
381 | pci_set_drvdata(pdev, NULL); | 378 | pci_set_drvdata(pdev, NULL); |
382 | 379 | ||
383 | framebuffer_release(info); | 380 | framebuffer_release(info); |
diff --git a/drivers/video/i810/i810_main.c b/drivers/video/i810/i810_main.c index 44aa2ffff973..a1f7d80f0ac1 100644 --- a/drivers/video/i810/i810_main.c +++ b/drivers/video/i810/i810_main.c | |||
@@ -2110,9 +2110,6 @@ static void i810fb_release_resource(struct fb_info *info, | |||
2110 | if (par->res_flags & MMIO_REQ) | 2110 | if (par->res_flags & MMIO_REQ) |
2111 | release_mem_region(par->mmio_start_phys, MMIO_SIZE); | 2111 | release_mem_region(par->mmio_start_phys, MMIO_SIZE); |
2112 | 2112 | ||
2113 | if (par->res_flags & PCI_DEVICE_ENABLED) | ||
2114 | pci_disable_device(par->dev); | ||
2115 | |||
2116 | framebuffer_release(info); | 2113 | framebuffer_release(info); |
2117 | 2114 | ||
2118 | } | 2115 | } |
diff --git a/drivers/video/imacfb.c b/drivers/video/imacfb.c new file mode 100644 index 000000000000..7b1c168c834d --- /dev/null +++ b/drivers/video/imacfb.c | |||
@@ -0,0 +1,345 @@ | |||
1 | /* | ||
2 | * framebuffer driver for Intel Based Mac's | ||
3 | * | ||
4 | * (c) 2006 Edgar Hucek <gimli@dark-green.com> | ||
5 | * Original imac driver written by Gerd Knorr <kraxel@goldbach.in-berlin.de> | ||
6 | * | ||
7 | */ | ||
8 | |||
9 | #include <linux/delay.h> | ||
10 | #include <linux/errno.h> | ||
11 | #include <linux/fb.h> | ||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/init.h> | ||
14 | #include <linux/ioport.h> | ||
15 | #include <linux/mm.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/platform_device.h> | ||
18 | #include <linux/slab.h> | ||
19 | #include <linux/string.h> | ||
20 | #include <linux/tty.h> | ||
21 | |||
22 | #include <asm/io.h> | ||
23 | |||
24 | #include <video/vga.h> | ||
25 | |||
26 | typedef enum _MAC_TYPE { | ||
27 | M_I17, | ||
28 | M_I20, | ||
29 | M_MINI, | ||
30 | M_MACBOOK, | ||
31 | M_NEW | ||
32 | } MAC_TYPE; | ||
33 | |||
34 | /* --------------------------------------------------------------------- */ | ||
35 | |||
36 | static struct fb_var_screeninfo imacfb_defined __initdata = { | ||
37 | .activate = FB_ACTIVATE_NOW, | ||
38 | .height = -1, | ||
39 | .width = -1, | ||
40 | .right_margin = 32, | ||
41 | .upper_margin = 16, | ||
42 | .lower_margin = 4, | ||
43 | .vsync_len = 4, | ||
44 | .vmode = FB_VMODE_NONINTERLACED, | ||
45 | }; | ||
46 | |||
47 | static struct fb_fix_screeninfo imacfb_fix __initdata = { | ||
48 | .id = "IMAC VGA", | ||
49 | .type = FB_TYPE_PACKED_PIXELS, | ||
50 | .accel = FB_ACCEL_NONE, | ||
51 | .visual = FB_VISUAL_TRUECOLOR, | ||
52 | }; | ||
53 | |||
54 | static int inverse; | ||
55 | static int model = M_NEW; | ||
56 | static int manual_height; | ||
57 | static int manual_width; | ||
58 | |||
59 | #define DEFAULT_FB_MEM 1024*1024*16 | ||
60 | |||
61 | /* --------------------------------------------------------------------- */ | ||
62 | |||
63 | static int imacfb_setcolreg(unsigned regno, unsigned red, unsigned green, | ||
64 | unsigned blue, unsigned transp, | ||
65 | struct fb_info *info) | ||
66 | { | ||
67 | /* | ||
68 | * Set a single color register. The values supplied are | ||
69 | * already rounded down to the hardware's capabilities | ||
70 | * (according to the entries in the `var' structure). Return | ||
71 | * != 0 for invalid regno. | ||
72 | */ | ||
73 | |||
74 | if (regno >= info->cmap.len) | ||
75 | return 1; | ||
76 | |||
77 | if (regno < 16) { | ||
78 | red >>= 8; | ||
79 | green >>= 8; | ||
80 | blue >>= 8; | ||
81 | ((u32 *)(info->pseudo_palette))[regno] = | ||
82 | (red << info->var.red.offset) | | ||
83 | (green << info->var.green.offset) | | ||
84 | (blue << info->var.blue.offset); | ||
85 | } | ||
86 | return 0; | ||
87 | } | ||
88 | |||
89 | static struct fb_ops imacfb_ops = { | ||
90 | .owner = THIS_MODULE, | ||
91 | .fb_setcolreg = imacfb_setcolreg, | ||
92 | .fb_fillrect = cfb_fillrect, | ||
93 | .fb_copyarea = cfb_copyarea, | ||
94 | .fb_imageblit = cfb_imageblit, | ||
95 | }; | ||
96 | |||
97 | static int __init imacfb_setup(char *options) | ||
98 | { | ||
99 | char *this_opt; | ||
100 | |||
101 | if (!options || !*options) | ||
102 | return 0; | ||
103 | |||
104 | while ((this_opt = strsep(&options, ",")) != NULL) { | ||
105 | if (!*this_opt) continue; | ||
106 | |||
107 | if (!strcmp(this_opt, "inverse")) | ||
108 | inverse = 1; | ||
109 | else if (!strcmp(this_opt, "i17")) | ||
110 | model = M_I17; | ||
111 | else if (!strcmp(this_opt, "i20")) | ||
112 | model = M_I20; | ||
113 | else if (!strcmp(this_opt, "mini")) | ||
114 | model = M_MINI; | ||
115 | else if (!strcmp(this_opt, "macbook")) | ||
116 | model = M_MACBOOK; | ||
117 | else if (!strncmp(this_opt, "height:", 7)) | ||
118 | manual_height = simple_strtoul(this_opt+7, NULL, 0); | ||
119 | else if (!strncmp(this_opt, "width:", 6)) | ||
120 | manual_width = simple_strtoul(this_opt+6, NULL, 0); | ||
121 | } | ||
122 | return 0; | ||
123 | } | ||
124 | |||
125 | static int __init imacfb_probe(struct platform_device *dev) | ||
126 | { | ||
127 | struct fb_info *info; | ||
128 | int err; | ||
129 | unsigned int size_vmode; | ||
130 | unsigned int size_remap; | ||
131 | unsigned int size_total; | ||
132 | |||
133 | screen_info.lfb_depth = 32; | ||
134 | screen_info.lfb_size = DEFAULT_FB_MEM / 0x10000; | ||
135 | screen_info.pages=1; | ||
136 | screen_info.blue_size = 8; | ||
137 | screen_info.blue_pos = 0; | ||
138 | screen_info.green_size = 8; | ||
139 | screen_info.green_pos = 8; | ||
140 | screen_info.red_size = 8; | ||
141 | screen_info.red_pos = 16; | ||
142 | screen_info.rsvd_size = 8; | ||
143 | screen_info.rsvd_pos = 24; | ||
144 | |||
145 | switch (model) { | ||
146 | case M_I17: | ||
147 | screen_info.lfb_width = 1440; | ||
148 | screen_info.lfb_height = 900; | ||
149 | screen_info.lfb_linelength = 1472 * 4; | ||
150 | screen_info.lfb_base = 0x80010000; | ||
151 | break; | ||
152 | case M_NEW: | ||
153 | case M_I20: | ||
154 | screen_info.lfb_width = 1680; | ||
155 | screen_info.lfb_height = 1050; | ||
156 | screen_info.lfb_linelength = 1728 * 4; | ||
157 | screen_info.lfb_base = 0x80010000; | ||
158 | break; | ||
159 | case M_MINI: | ||
160 | screen_info.lfb_width = 1024; | ||
161 | screen_info.lfb_height = 768; | ||
162 | screen_info.lfb_linelength = 2048 * 4; | ||
163 | screen_info.lfb_base = 0x80000000; | ||
164 | break; | ||
165 | case M_MACBOOK: | ||
166 | screen_info.lfb_width = 1280; | ||
167 | screen_info.lfb_height = 800; | ||
168 | screen_info.lfb_linelength = 2048 * 4; | ||
169 | screen_info.lfb_base = 0x80000000; | ||
170 | break; | ||
171 | } | ||
172 | |||
173 | /* if the user wants to manually specify height/width, | ||
174 | we will override the defaults */ | ||
175 | /* TODO: eventually get auto-detection working */ | ||
176 | if (manual_height > 0) | ||
177 | screen_info.lfb_height = manual_height; | ||
178 | if (manual_width > 0) | ||
179 | screen_info.lfb_width = manual_width; | ||
180 | |||
181 | imacfb_fix.smem_start = screen_info.lfb_base; | ||
182 | imacfb_defined.bits_per_pixel = screen_info.lfb_depth; | ||
183 | imacfb_defined.xres = screen_info.lfb_width; | ||
184 | imacfb_defined.yres = screen_info.lfb_height; | ||
185 | imacfb_fix.line_length = screen_info.lfb_linelength; | ||
186 | |||
187 | /* size_vmode -- that is the amount of memory needed for the | ||
188 | * used video mode, i.e. the minimum amount of | ||
189 | * memory we need. */ | ||
190 | size_vmode = imacfb_defined.yres * imacfb_fix.line_length; | ||
191 | |||
192 | /* size_total -- all video memory we have. Used for | ||
193 | * entries, ressource allocation and bounds | ||
194 | * checking. */ | ||
195 | size_total = screen_info.lfb_size * 65536; | ||
196 | if (size_total < size_vmode) | ||
197 | size_total = size_vmode; | ||
198 | |||
199 | /* size_remap -- the amount of video memory we are going to | ||
200 | * use for imacfb. With modern cards it is no | ||
201 | * option to simply use size_total as that | ||
202 | * wastes plenty of kernel address space. */ | ||
203 | size_remap = size_vmode * 2; | ||
204 | if (size_remap < size_vmode) | ||
205 | size_remap = size_vmode; | ||
206 | if (size_remap > size_total) | ||
207 | size_remap = size_total; | ||
208 | imacfb_fix.smem_len = size_remap; | ||
209 | |||
210 | #ifndef __i386__ | ||
211 | screen_info.imacpm_seg = 0; | ||
212 | #endif | ||
213 | |||
214 | if (!request_mem_region(imacfb_fix.smem_start, size_total, "imacfb")) { | ||
215 | printk(KERN_WARNING | ||
216 | "imacfb: cannot reserve video memory at 0x%lx\n", | ||
217 | imacfb_fix.smem_start); | ||
218 | /* We cannot make this fatal. Sometimes this comes from magic | ||
219 | spaces our resource handlers simply don't know about */ | ||
220 | } | ||
221 | |||
222 | info = framebuffer_alloc(sizeof(u32) * 16, &dev->dev); | ||
223 | if (!info) { | ||
224 | err = -ENOMEM; | ||
225 | goto err_release_mem; | ||
226 | } | ||
227 | info->pseudo_palette = info->par; | ||
228 | info->par = NULL; | ||
229 | |||
230 | info->screen_base = ioremap(imacfb_fix.smem_start, imacfb_fix.smem_len); | ||
231 | if (!info->screen_base) { | ||
232 | printk(KERN_ERR "imacfb: abort, cannot ioremap video memory " | ||
233 | "0x%x @ 0x%lx\n", | ||
234 | imacfb_fix.smem_len, imacfb_fix.smem_start); | ||
235 | err = -EIO; | ||
236 | goto err_unmap; | ||
237 | } | ||
238 | |||
239 | printk(KERN_INFO "imacfb: framebuffer at 0x%lx, mapped to 0x%p, " | ||
240 | "using %dk, total %dk\n", | ||
241 | imacfb_fix.smem_start, info->screen_base, | ||
242 | size_remap/1024, size_total/1024); | ||
243 | printk(KERN_INFO "imacfb: mode is %dx%dx%d, linelength=%d, pages=%d\n", | ||
244 | imacfb_defined.xres, imacfb_defined.yres, | ||
245 | imacfb_defined.bits_per_pixel, imacfb_fix.line_length, | ||
246 | screen_info.pages); | ||
247 | |||
248 | imacfb_defined.xres_virtual = imacfb_defined.xres; | ||
249 | imacfb_defined.yres_virtual = imacfb_fix.smem_len / | ||
250 | imacfb_fix.line_length; | ||
251 | printk(KERN_INFO "imacfb: scrolling: redraw\n"); | ||
252 | imacfb_defined.yres_virtual = imacfb_defined.yres; | ||
253 | |||
254 | /* some dummy values for timing to make fbset happy */ | ||
255 | imacfb_defined.pixclock = 10000000 / imacfb_defined.xres * | ||
256 | 1000 / imacfb_defined.yres; | ||
257 | imacfb_defined.left_margin = (imacfb_defined.xres / 8) & 0xf8; | ||
258 | imacfb_defined.hsync_len = (imacfb_defined.xres / 8) & 0xf8; | ||
259 | |||
260 | imacfb_defined.red.offset = screen_info.red_pos; | ||
261 | imacfb_defined.red.length = screen_info.red_size; | ||
262 | imacfb_defined.green.offset = screen_info.green_pos; | ||
263 | imacfb_defined.green.length = screen_info.green_size; | ||
264 | imacfb_defined.blue.offset = screen_info.blue_pos; | ||
265 | imacfb_defined.blue.length = screen_info.blue_size; | ||
266 | imacfb_defined.transp.offset = screen_info.rsvd_pos; | ||
267 | imacfb_defined.transp.length = screen_info.rsvd_size; | ||
268 | |||
269 | printk(KERN_INFO "imacfb: %s: " | ||
270 | "size=%d:%d:%d:%d, shift=%d:%d:%d:%d\n", | ||
271 | "Truecolor", | ||
272 | screen_info.rsvd_size, | ||
273 | screen_info.red_size, | ||
274 | screen_info.green_size, | ||
275 | screen_info.blue_size, | ||
276 | screen_info.rsvd_pos, | ||
277 | screen_info.red_pos, | ||
278 | screen_info.green_pos, | ||
279 | screen_info.blue_pos); | ||
280 | |||
281 | imacfb_fix.ypanstep = 0; | ||
282 | imacfb_fix.ywrapstep = 0; | ||
283 | |||
284 | /* request failure does not faze us, as vgacon probably has this | ||
285 | * region already (FIXME) */ | ||
286 | request_region(0x3c0, 32, "imacfb"); | ||
287 | |||
288 | info->fbops = &imacfb_ops; | ||
289 | info->var = imacfb_defined; | ||
290 | info->fix = imacfb_fix; | ||
291 | info->flags = FBINFO_FLAG_DEFAULT; | ||
292 | |||
293 | if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) { | ||
294 | err = -ENOMEM; | ||
295 | goto err_unmap; | ||
296 | } | ||
297 | if (register_framebuffer(info)<0) { | ||
298 | err = -EINVAL; | ||
299 | goto err_fb_dealoc; | ||
300 | } | ||
301 | printk(KERN_INFO "fb%d: %s frame buffer device\n", | ||
302 | info->node, info->fix.id); | ||
303 | return 0; | ||
304 | |||
305 | err_fb_dealoc: | ||
306 | fb_dealloc_cmap(&info->cmap); | ||
307 | err_unmap: | ||
308 | iounmap(info->screen_base); | ||
309 | framebuffer_release(info); | ||
310 | err_release_mem: | ||
311 | release_mem_region(imacfb_fix.smem_start, size_total); | ||
312 | return err; | ||
313 | } | ||
314 | |||
315 | static struct platform_driver imacfb_driver = { | ||
316 | .probe = imacfb_probe, | ||
317 | .driver = { | ||
318 | .name = "imacfb", | ||
319 | }, | ||
320 | }; | ||
321 | |||
322 | static struct platform_device imacfb_device = { | ||
323 | .name = "imacfb", | ||
324 | }; | ||
325 | |||
326 | static int __init imacfb_init(void) | ||
327 | { | ||
328 | int ret; | ||
329 | char *option = NULL; | ||
330 | |||
331 | /* ignore error return of fb_get_options */ | ||
332 | fb_get_options("imacfb", &option); | ||
333 | imacfb_setup(option); | ||
334 | ret = platform_driver_register(&imacfb_driver); | ||
335 | |||
336 | if (!ret) { | ||
337 | ret = platform_device_register(&imacfb_device); | ||
338 | if (ret) | ||
339 | platform_driver_unregister(&imacfb_driver); | ||
340 | } | ||
341 | return ret; | ||
342 | } | ||
343 | module_init(imacfb_init); | ||
344 | |||
345 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/video/macmodes.c b/drivers/video/macmodes.c index c0385c6f7db5..d21321ca7c39 100644 --- a/drivers/video/macmodes.c +++ b/drivers/video/macmodes.c | |||
@@ -327,7 +327,6 @@ int mac_var_to_vmode(const struct fb_var_screeninfo *var, int *vmode, | |||
327 | } | 327 | } |
328 | return -EINVAL; | 328 | return -EINVAL; |
329 | } | 329 | } |
330 | EXPORT_SYMBOL(mac_var_to_vmode); | ||
331 | 330 | ||
332 | /** | 331 | /** |
333 | * mac_map_monitor_sense - Convert monitor sense to vmode | 332 | * mac_map_monitor_sense - Convert monitor sense to vmode |
@@ -371,8 +370,9 @@ EXPORT_SYMBOL(mac_map_monitor_sense); | |||
371 | * | 370 | * |
372 | */ | 371 | */ |
373 | 372 | ||
374 | int __init mac_find_mode(struct fb_var_screeninfo *var, struct fb_info *info, | 373 | int __devinit mac_find_mode(struct fb_var_screeninfo *var, |
375 | const char *mode_option, unsigned int default_bpp) | 374 | struct fb_info *info, const char *mode_option, |
375 | unsigned int default_bpp) | ||
376 | { | 376 | { |
377 | const struct fb_videomode *db = NULL; | 377 | const struct fb_videomode *db = NULL; |
378 | unsigned int dbsize = 0; | 378 | unsigned int dbsize = 0; |
diff --git a/drivers/video/macmodes.h b/drivers/video/macmodes.h index 232f5a09a499..babeb81f467d 100644 --- a/drivers/video/macmodes.h +++ b/drivers/video/macmodes.h | |||
@@ -55,9 +55,10 @@ extern int mac_vmode_to_var(int vmode, int cmode, | |||
55 | extern int mac_var_to_vmode(const struct fb_var_screeninfo *var, int *vmode, | 55 | extern int mac_var_to_vmode(const struct fb_var_screeninfo *var, int *vmode, |
56 | int *cmode); | 56 | int *cmode); |
57 | extern int mac_map_monitor_sense(int sense); | 57 | extern int mac_map_monitor_sense(int sense); |
58 | extern int __init mac_find_mode(struct fb_var_screeninfo *var, | 58 | extern int __devinit mac_find_mode(struct fb_var_screeninfo *var, |
59 | struct fb_info *info, const char *mode_option, | 59 | struct fb_info *info, |
60 | unsigned int default_bpp); | 60 | const char *mode_option, |
61 | unsigned int default_bpp); | ||
61 | 62 | ||
62 | 63 | ||
63 | /* | 64 | /* |
diff --git a/drivers/video/modedb.c b/drivers/video/modedb.c index 26a1c618a205..ff5454601e22 100644 --- a/drivers/video/modedb.c +++ b/drivers/video/modedb.c | |||
@@ -259,6 +259,10 @@ static const struct fb_videomode modedb[] = { | |||
259 | /* 1152x768, 60 Hz, PowerBook G4 Titanium I and II */ | 259 | /* 1152x768, 60 Hz, PowerBook G4 Titanium I and II */ |
260 | NULL, 60, 1152, 768, 15386, 158, 26, 29, 3, 136, 6, | 260 | NULL, 60, 1152, 768, 15386, 158, 26, 29, 3, 136, 6, |
261 | FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED | 261 | FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED |
262 | }, { | ||
263 | /* 1366x768, 60 Hz, 47.403 kHz hsync, WXGA 16:9 aspect ratio */ | ||
264 | NULL, 60, 1366, 768, 13806, 120, 10, 14, 3, 32, 5, | ||
265 | 0, FB_VMODE_NONINTERLACED | ||
262 | }, | 266 | }, |
263 | }; | 267 | }; |
264 | 268 | ||
@@ -787,8 +791,9 @@ struct fb_videomode *fb_find_best_mode(struct fb_var_screeninfo *var, | |||
787 | if (diff > d) { | 791 | if (diff > d) { |
788 | diff = d; | 792 | diff = d; |
789 | best = mode; | 793 | best = mode; |
790 | } else if (diff == d && mode->refresh > best->refresh) | 794 | } else if (diff == d && best && |
791 | best = mode; | 795 | mode->refresh > best->refresh) |
796 | best = mode; | ||
792 | } | 797 | } |
793 | } | 798 | } |
794 | return best; | 799 | return best; |
@@ -1016,8 +1021,6 @@ EXPORT_SYMBOL(fb_videomode_to_var); | |||
1016 | EXPORT_SYMBOL(fb_var_to_videomode); | 1021 | EXPORT_SYMBOL(fb_var_to_videomode); |
1017 | EXPORT_SYMBOL(fb_mode_is_equal); | 1022 | EXPORT_SYMBOL(fb_mode_is_equal); |
1018 | EXPORT_SYMBOL(fb_add_videomode); | 1023 | EXPORT_SYMBOL(fb_add_videomode); |
1019 | EXPORT_SYMBOL(fb_delete_videomode); | ||
1020 | EXPORT_SYMBOL(fb_destroy_modelist); | ||
1021 | EXPORT_SYMBOL(fb_match_mode); | 1024 | EXPORT_SYMBOL(fb_match_mode); |
1022 | EXPORT_SYMBOL(fb_find_best_mode); | 1025 | EXPORT_SYMBOL(fb_find_best_mode); |
1023 | EXPORT_SYMBOL(fb_find_nearest_mode); | 1026 | EXPORT_SYMBOL(fb_find_nearest_mode); |
diff --git a/drivers/video/neofb.c b/drivers/video/neofb.c index 24b12f71d5a8..2f156b724d1c 100644 --- a/drivers/video/neofb.c +++ b/drivers/video/neofb.c | |||
@@ -1333,17 +1333,22 @@ static int neofb_blank(int blank_mode, struct fb_info *info) | |||
1333 | * run "setterm -powersave powerdown" to take advantage | 1333 | * run "setterm -powersave powerdown" to take advantage |
1334 | */ | 1334 | */ |
1335 | struct neofb_par *par = info->par; | 1335 | struct neofb_par *par = info->par; |
1336 | int seqflags, lcdflags, dpmsflags, reg; | 1336 | int seqflags, lcdflags, dpmsflags, reg, tmpdisp; |
1337 | |||
1338 | 1337 | ||
1339 | /* | 1338 | /* |
1340 | * Reload the value stored in the register, if sensible. It might have | 1339 | * Read back the register bits related to display configuration. They might |
1341 | * been changed via FN keystroke. | 1340 | * have been changed underneath the driver via Fn key stroke. |
1341 | */ | ||
1342 | neoUnlock(); | ||
1343 | tmpdisp = vga_rgfx(NULL, 0x20) & 0x03; | ||
1344 | neoLock(&par->state); | ||
1345 | |||
1346 | /* In case we blank the screen, we want to store the possibly new | ||
1347 | * configuration in the driver. During un-blank, we re-apply this setting, | ||
1348 | * since the LCD bit will be cleared in order to switch off the backlight. | ||
1342 | */ | 1349 | */ |
1343 | if (par->PanelDispCntlRegRead) { | 1350 | if (par->PanelDispCntlRegRead) { |
1344 | neoUnlock(); | 1351 | par->PanelDispCntlReg1 = tmpdisp; |
1345 | par->PanelDispCntlReg1 = vga_rgfx(NULL, 0x20) & 0x03; | ||
1346 | neoLock(&par->state); | ||
1347 | } | 1352 | } |
1348 | par->PanelDispCntlRegRead = !blank_mode; | 1353 | par->PanelDispCntlRegRead = !blank_mode; |
1349 | 1354 | ||
@@ -1378,12 +1383,21 @@ static int neofb_blank(int blank_mode, struct fb_info *info) | |||
1378 | break; | 1383 | break; |
1379 | case FB_BLANK_NORMAL: /* just blank screen (backlight stays on) */ | 1384 | case FB_BLANK_NORMAL: /* just blank screen (backlight stays on) */ |
1380 | seqflags = VGA_SR01_SCREEN_OFF; /* Disable sequencer */ | 1385 | seqflags = VGA_SR01_SCREEN_OFF; /* Disable sequencer */ |
1381 | lcdflags = par->PanelDispCntlReg1 & 0x02; /* LCD normal */ | 1386 | /* |
1387 | * During a blank operation with the LID shut, we might store "LCD off" | ||
1388 | * by mistake. Due to timing issues, the BIOS may switch the lights | ||
1389 | * back on, and we turn it back off once we "unblank". | ||
1390 | * | ||
1391 | * So here is an attempt to implement ">=" - if we are in the process | ||
1392 | * of unblanking, and the LCD bit is unset in the driver but set in the | ||
1393 | * register, we must keep it. | ||
1394 | */ | ||
1395 | lcdflags = ((par->PanelDispCntlReg1 | tmpdisp) & 0x02); /* LCD normal */ | ||
1382 | dpmsflags = 0x00; /* no hsync/vsync suppression */ | 1396 | dpmsflags = 0x00; /* no hsync/vsync suppression */ |
1383 | break; | 1397 | break; |
1384 | case FB_BLANK_UNBLANK: /* unblank */ | 1398 | case FB_BLANK_UNBLANK: /* unblank */ |
1385 | seqflags = 0; /* Enable sequencer */ | 1399 | seqflags = 0; /* Enable sequencer */ |
1386 | lcdflags = par->PanelDispCntlReg1 & 0x02; /* LCD normal */ | 1400 | lcdflags = ((par->PanelDispCntlReg1 | tmpdisp) & 0x02); /* LCD normal */ |
1387 | dpmsflags = 0x00; /* no hsync/vsync suppression */ | 1401 | dpmsflags = 0x00; /* no hsync/vsync suppression */ |
1388 | #ifdef CONFIG_TOSHIBA | 1402 | #ifdef CONFIG_TOSHIBA |
1389 | /* Do we still need this ? */ | 1403 | /* Do we still need this ? */ |
diff --git a/drivers/video/nvidia/nv_hw.c b/drivers/video/nvidia/nv_hw.c index 99c3a8e6a237..9ed640d35728 100644 --- a/drivers/video/nvidia/nv_hw.c +++ b/drivers/video/nvidia/nv_hw.c | |||
@@ -886,7 +886,10 @@ void NVCalcStateExt(struct nvidia_par *par, | |||
886 | case NV_ARCH_20: | 886 | case NV_ARCH_20: |
887 | case NV_ARCH_30: | 887 | case NV_ARCH_30: |
888 | default: | 888 | default: |
889 | if (((par->Chipset & 0xffff) == 0x01A0) || | 889 | if ((par->Chipset & 0xfff0) == 0x0240) { |
890 | state->arbitration0 = 256; | ||
891 | state->arbitration1 = 0x0480; | ||
892 | } else if (((par->Chipset & 0xffff) == 0x01A0) || | ||
890 | ((par->Chipset & 0xffff) == 0x01f0)) { | 893 | ((par->Chipset & 0xffff) == 0x01f0)) { |
891 | nForceUpdateArbitrationSettings(VClk, | 894 | nForceUpdateArbitrationSettings(VClk, |
892 | pixelDepth * 8, | 895 | pixelDepth * 8, |
@@ -1235,6 +1238,7 @@ void NVLoadStateExt(struct nvidia_par *par, RIVA_HW_STATE * state) | |||
1235 | break; | 1238 | break; |
1236 | case 0x0160: | 1239 | case 0x0160: |
1237 | case 0x01D0: | 1240 | case 0x01D0: |
1241 | case 0x0240: | ||
1238 | NV_WR32(par->PMC, 0x1700, | 1242 | NV_WR32(par->PMC, 0x1700, |
1239 | NV_RD32(par->PFB, 0x020C)); | 1243 | NV_RD32(par->PFB, 0x020C)); |
1240 | NV_WR32(par->PMC, 0x1704, 0); | 1244 | NV_WR32(par->PMC, 0x1704, 0); |
@@ -1359,7 +1363,9 @@ void NVLoadStateExt(struct nvidia_par *par, RIVA_HW_STATE * state) | |||
1359 | if(((par->Chipset & 0xfff0) | 1363 | if(((par->Chipset & 0xfff0) |
1360 | != 0x0160) && | 1364 | != 0x0160) && |
1361 | ((par->Chipset & 0xfff0) | 1365 | ((par->Chipset & 0xfff0) |
1362 | != 0x0220)) | 1366 | != 0x0220) && |
1367 | ((par->Chipset & 0xfff0) | ||
1368 | != 0x240)) | ||
1363 | NV_WR32(par->PGRAPH, | 1369 | NV_WR32(par->PGRAPH, |
1364 | 0x6900 + i*4, | 1370 | 0x6900 + i*4, |
1365 | NV_RD32(par->PFB, | 1371 | NV_RD32(par->PFB, |
diff --git a/drivers/video/nvidia/nvidia.c b/drivers/video/nvidia/nvidia.c index 03a7c1e9ce38..7b5cffb27851 100644 --- a/drivers/video/nvidia/nvidia.c +++ b/drivers/video/nvidia/nvidia.c | |||
@@ -67,359 +67,10 @@ | |||
67 | #define MAX_CURS 32 | 67 | #define MAX_CURS 32 |
68 | 68 | ||
69 | static struct pci_device_id nvidiafb_pci_tbl[] = { | 69 | static struct pci_device_id nvidiafb_pci_tbl[] = { |
70 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_TNT, | 70 | {PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, |
71 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | 71 | PCI_BASE_CLASS_DISPLAY << 16, 0xff0000, 0}, |
72 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_TNT2, | 72 | { 0, } |
73 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
74 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_UTNT2, | ||
75 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
76 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_TNT_UNKNOWN, | ||
77 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
78 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_VTNT2, | ||
79 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
80 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_UVTNT2, | ||
81 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
82 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_ITNT2, | ||
83 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
84 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_SDR, | ||
85 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
86 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_DDR, | ||
87 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
88 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO, | ||
89 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
90 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_MX, | ||
91 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
92 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_MX2, | ||
93 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
94 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_GO, | ||
95 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
96 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO2_MXR, | ||
97 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
98 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_GTS, | ||
99 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
100 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_GTS2, | ||
101 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
102 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_ULTRA, | ||
103 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
104 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO2_PRO, | ||
105 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
106 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_460, | ||
107 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
108 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_440, | ||
109 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
110 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_420, | ||
111 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
112 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_440_SE, | ||
113 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
114 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_440_GO, | ||
115 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
116 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_420_GO, | ||
117 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
118 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_460_GO, | ||
119 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
120 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_420_GO_M32, | ||
121 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
122 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_500XGL, | ||
123 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
124 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_440_GO_M64, | ||
125 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
126 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_200, | ||
127 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
128 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_550XGL, | ||
129 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
130 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_500_GOGL, | ||
131 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
132 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_410_GO_M16, | ||
133 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
134 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_440_8X, | ||
135 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
136 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_440SE_8X, | ||
137 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
138 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_420_8X, | ||
139 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
140 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_4000, | ||
141 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
142 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_448_GO, | ||
143 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
144 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_488_GO, | ||
145 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
146 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_580_XGL, | ||
147 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
148 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_MAC, | ||
149 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
150 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_280_NVS, | ||
151 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
152 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_380_XGL, | ||
153 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
154 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_IGEFORCE2, | ||
155 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
156 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE3, | ||
157 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
158 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE3_1, | ||
159 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
160 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE3_2, | ||
161 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
162 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_DDC, | ||
163 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
164 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4600, | ||
165 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
166 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4400, | ||
167 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
168 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4200, | ||
169 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
170 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_900XGL, | ||
171 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
172 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_750XGL, | ||
173 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
174 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_700XGL, | ||
175 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
176 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4800, | ||
177 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
178 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4800_8X, | ||
179 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
180 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4800SE, | ||
181 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
182 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_4200_GO, | ||
183 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
184 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_980_XGL, | ||
185 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
186 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_780_XGL, | ||
187 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
188 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_700_GOGL, | ||
189 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
190 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5800_ULTRA, | ||
191 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
192 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5800, | ||
193 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
194 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_FX_2000, | ||
195 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
196 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_FX_1000, | ||
197 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
198 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5600_ULTRA, | ||
199 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
200 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5600, | ||
201 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
202 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5600SE, | ||
203 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
204 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5600, | ||
205 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
206 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5650, | ||
207 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
208 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_FX_GO700, | ||
209 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
210 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5200, | ||
211 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
212 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5200_ULTRA, | ||
213 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
214 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5200_1, | ||
215 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
216 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5200SE, | ||
217 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
218 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5200, | ||
219 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
220 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5250, | ||
221 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
222 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5250_32, | ||
223 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
224 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO_5200, | ||
225 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
226 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_NVS_280_PCI, | ||
227 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
228 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_FX_500, | ||
229 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
230 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5300, | ||
231 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
232 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5100, | ||
233 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
234 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5900_ULTRA, | ||
235 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
236 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5900, | ||
237 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
238 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5900XT, | ||
239 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
240 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5950_ULTRA, | ||
241 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
242 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_FX_3000, | ||
243 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
244 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5700_ULTRA, | ||
245 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
246 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5700, | ||
247 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
248 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5700LE, | ||
249 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
250 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5700VE, | ||
251 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
252 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5700_1, | ||
253 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
254 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5700_2, | ||
255 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
256 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_FX_GO1000, | ||
257 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
258 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_FX_1100, | ||
259 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
260 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5500, | ||
261 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
262 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5100, | ||
263 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
264 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_FX_700, | ||
265 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
266 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5900ZT, | ||
267 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
268 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6800_ULTRA, | ||
269 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
270 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6800, | ||
271 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
272 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6800_LE, | ||
273 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
274 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6800_GT, | ||
275 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
276 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_FX_4000, | ||
277 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
278 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6600_GT, | ||
279 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
280 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6600, | ||
281 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
282 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6610_XL, | ||
283 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
284 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_FX_540, | ||
285 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
286 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6200, | ||
287 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
288 | {PCI_VENDOR_ID_NVIDIA, PCIE_DEVICE_ID_NVIDIA_GEFORCE_6800_ALT1, | ||
289 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
290 | {PCI_VENDOR_ID_NVIDIA, PCIE_DEVICE_ID_NVIDIA_GEFORCE_6600_ALT1, | ||
291 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
292 | {PCI_VENDOR_ID_NVIDIA, PCIE_DEVICE_ID_NVIDIA_GEFORCE_6600_ALT2, | ||
293 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
294 | {PCI_VENDOR_ID_NVIDIA, PCIE_DEVICE_ID_NVIDIA_GEFORCE_6200_ALT1, | ||
295 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
296 | {PCI_VENDOR_ID_NVIDIA, PCIE_DEVICE_ID_NVIDIA_GEFORCE_6800_GT, | ||
297 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
298 | {PCI_VENDOR_ID_NVIDIA, PCIE_DEVICE_ID_NVIDIA_QUADRO_NVS280, | ||
299 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
300 | {PCI_VENDOR_ID_NVIDIA, 0x0252, | ||
301 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
302 | {PCI_VENDOR_ID_NVIDIA, 0x0313, | ||
303 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
304 | {PCI_VENDOR_ID_NVIDIA, 0x0316, | ||
305 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
306 | {PCI_VENDOR_ID_NVIDIA, 0x0317, | ||
307 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
308 | {PCI_VENDOR_ID_NVIDIA, 0x031D, | ||
309 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
310 | {PCI_VENDOR_ID_NVIDIA, 0x031E, | ||
311 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
312 | {PCI_VENDOR_ID_NVIDIA, 0x031F, | ||
313 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
314 | {PCI_VENDOR_ID_NVIDIA, 0x0329, | ||
315 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
316 | {PCI_VENDOR_ID_NVIDIA, 0x032F, | ||
317 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
318 | {PCI_VENDOR_ID_NVIDIA, 0x0345, | ||
319 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
320 | {PCI_VENDOR_ID_NVIDIA, 0x0349, | ||
321 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
322 | {PCI_VENDOR_ID_NVIDIA, 0x034B, | ||
323 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
324 | {PCI_VENDOR_ID_NVIDIA, 0x034F, | ||
325 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
326 | {PCI_VENDOR_ID_NVIDIA, 0x00c0, | ||
327 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
328 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_GEFORCE_6800A, | ||
329 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
330 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_GEFORCE_6800A_LE, | ||
331 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
332 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_GEFORCE_GO_6800, | ||
333 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
334 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_GEFORCE_GO_6800_ULTRA, | ||
335 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
336 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_QUADRO_FX_GO1400, | ||
337 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
338 | {PCI_VENDOR_ID_NVIDIA, 0x00cd, | ||
339 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
340 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_QUADRO_FX_1400, | ||
341 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
342 | {PCI_VENDOR_ID_NVIDIA, 0x0142, | ||
343 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
344 | {PCI_VENDOR_ID_NVIDIA, 0x0143, | ||
345 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
346 | {PCI_VENDOR_ID_NVIDIA, 0x0144, | ||
347 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
348 | {PCI_VENDOR_ID_NVIDIA, 0x0145, | ||
349 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
350 | {PCI_VENDOR_ID_NVIDIA, 0x0146, | ||
351 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
352 | {PCI_VENDOR_ID_NVIDIA, 0x0147, | ||
353 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
354 | {PCI_VENDOR_ID_NVIDIA, 0x0148, | ||
355 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
356 | {PCI_VENDOR_ID_NVIDIA, 0x0149, | ||
357 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
358 | {PCI_VENDOR_ID_NVIDIA, 0x014b, | ||
359 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
360 | {PCI_VENDOR_ID_NVIDIA, 0x14c, | ||
361 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
362 | {PCI_VENDOR_ID_NVIDIA, 0x014d, | ||
363 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
364 | {PCI_VENDOR_ID_NVIDIA, 0x0160, | ||
365 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
366 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6200_TURBOCACHE, | ||
367 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
368 | {PCI_VENDOR_ID_NVIDIA, 0x0162, | ||
369 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
370 | {PCI_VENDOR_ID_NVIDIA, 0x0163, | ||
371 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
372 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_GO_6200, | ||
373 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
374 | {PCI_VENDOR_ID_NVIDIA, 0x0165, | ||
375 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
376 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_GO_6250, | ||
377 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
378 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_GO_6200_1, | ||
379 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
380 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_GO_6250_1, | ||
381 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
382 | {PCI_VENDOR_ID_NVIDIA, 0x0169, | ||
383 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
384 | {PCI_VENDOR_ID_NVIDIA, 0x016b, | ||
385 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
386 | {PCI_VENDOR_ID_NVIDIA, 0x016c, | ||
387 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
388 | {PCI_VENDOR_ID_NVIDIA, 0x016d, | ||
389 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
390 | {PCI_VENDOR_ID_NVIDIA, 0x016e, | ||
391 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
392 | {PCI_VENDOR_ID_NVIDIA, 0x0210, | ||
393 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
394 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6800B, | ||
395 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
396 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6800B_LE, | ||
397 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
398 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6800B_GT, | ||
399 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
400 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_7800_GT, | ||
401 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
402 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_7800_GTX, | ||
403 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
404 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_GO_7800, | ||
405 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
406 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_GO_7800_GTX, | ||
407 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
408 | {PCI_VENDOR_ID_NVIDIA, 0x021d, | ||
409 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
410 | {PCI_VENDOR_ID_NVIDIA, 0x021e, | ||
411 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
412 | {PCI_VENDOR_ID_NVIDIA, 0x0220, | ||
413 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
414 | {PCI_VENDOR_ID_NVIDIA, 0x0221, | ||
415 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
416 | {PCI_VENDOR_ID_NVIDIA, 0x0222, | ||
417 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
418 | {PCI_VENDOR_ID_NVIDIA, 0x0228, | ||
419 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
420 | {0,} /* terminate list */ | ||
421 | }; | 73 | }; |
422 | |||
423 | MODULE_DEVICE_TABLE(pci, nvidiafb_pci_tbl); | 74 | MODULE_DEVICE_TABLE(pci, nvidiafb_pci_tbl); |
424 | 75 | ||
425 | /* command line data, set in nvidiafb_setup() */ | 76 | /* command line data, set in nvidiafb_setup() */ |
@@ -1465,10 +1116,10 @@ static u32 __devinit nvidia_get_chipset(struct fb_info *info) | |||
1465 | struct nvidia_par *par = info->par; | 1116 | struct nvidia_par *par = info->par; |
1466 | u32 id = (par->pci_dev->vendor << 16) | par->pci_dev->device; | 1117 | u32 id = (par->pci_dev->vendor << 16) | par->pci_dev->device; |
1467 | 1118 | ||
1468 | printk("nvidiafb: PCI id - %x\n", id); | 1119 | printk(KERN_INFO PFX "Device ID: %x \n", id); |
1120 | |||
1469 | if ((id & 0xfff0) == 0x00f0) { | 1121 | if ((id & 0xfff0) == 0x00f0) { |
1470 | /* pci-e */ | 1122 | /* pci-e */ |
1471 | printk("nvidiafb: PCI-E card\n"); | ||
1472 | id = NV_RD32(par->REGS, 0x1800); | 1123 | id = NV_RD32(par->REGS, 0x1800); |
1473 | 1124 | ||
1474 | if ((id & 0x0000ffff) == 0x000010DE) | 1125 | if ((id & 0x0000ffff) == 0x000010DE) |
@@ -1476,9 +1127,9 @@ static u32 __devinit nvidia_get_chipset(struct fb_info *info) | |||
1476 | else if ((id & 0xffff0000) == 0xDE100000) /* wrong endian */ | 1127 | else if ((id & 0xffff0000) == 0xDE100000) /* wrong endian */ |
1477 | id = 0x10DE0000 | ((id << 8) & 0x0000ff00) | | 1128 | id = 0x10DE0000 | ((id << 8) & 0x0000ff00) | |
1478 | ((id >> 8) & 0x000000ff); | 1129 | ((id >> 8) & 0x000000ff); |
1130 | printk(KERN_INFO PFX "Subsystem ID: %x \n", id); | ||
1479 | } | 1131 | } |
1480 | 1132 | ||
1481 | printk("nvidiafb: Actual id - %x\n", id); | ||
1482 | return id; | 1133 | return id; |
1483 | } | 1134 | } |
1484 | 1135 | ||
@@ -1520,6 +1171,7 @@ static u32 __devinit nvidia_get_arch(struct fb_info *info) | |||
1520 | case 0x0210: | 1171 | case 0x0210: |
1521 | case 0x0220: | 1172 | case 0x0220: |
1522 | case 0x0230: | 1173 | case 0x0230: |
1174 | case 0x0240: | ||
1523 | case 0x0290: | 1175 | case 0x0290: |
1524 | case 0x0390: | 1176 | case 0x0390: |
1525 | arch = NV_ARCH_40; | 1177 | arch = NV_ARCH_40; |
@@ -1567,7 +1219,7 @@ static int __devinit nvidiafb_probe(struct pci_dev *pd, | |||
1567 | 1219 | ||
1568 | if (pci_request_regions(pd, "nvidiafb")) { | 1220 | if (pci_request_regions(pd, "nvidiafb")) { |
1569 | printk(KERN_ERR PFX "cannot request PCI regions\n"); | 1221 | printk(KERN_ERR PFX "cannot request PCI regions\n"); |
1570 | goto err_out_request; | 1222 | goto err_out_enable; |
1571 | } | 1223 | } |
1572 | 1224 | ||
1573 | par->FlatPanel = flatpanel; | 1225 | par->FlatPanel = flatpanel; |
@@ -1596,7 +1248,6 @@ static int __devinit nvidiafb_probe(struct pci_dev *pd, | |||
1596 | } | 1248 | } |
1597 | 1249 | ||
1598 | par->Chipset = nvidia_get_chipset(info); | 1250 | par->Chipset = nvidia_get_chipset(info); |
1599 | printk(KERN_INFO PFX "nVidia device/chipset %X\n", par->Chipset); | ||
1600 | par->Architecture = nvidia_get_arch(info); | 1251 | par->Architecture = nvidia_get_arch(info); |
1601 | 1252 | ||
1602 | if (par->Architecture == 0) { | 1253 | if (par->Architecture == 0) { |
@@ -1687,10 +1338,8 @@ err_out_free_base1: | |||
1687 | nvidia_delete_i2c_busses(par); | 1338 | nvidia_delete_i2c_busses(par); |
1688 | err_out_arch: | 1339 | err_out_arch: |
1689 | iounmap(par->REGS); | 1340 | iounmap(par->REGS); |
1690 | err_out_free_base0: | 1341 | err_out_free_base0: |
1691 | pci_release_regions(pd); | 1342 | pci_release_regions(pd); |
1692 | err_out_request: | ||
1693 | pci_disable_device(pd); | ||
1694 | err_out_enable: | 1343 | err_out_enable: |
1695 | kfree(info->pixmap.addr); | 1344 | kfree(info->pixmap.addr); |
1696 | err_out_kfree: | 1345 | err_out_kfree: |
@@ -1720,7 +1369,6 @@ static void __exit nvidiafb_remove(struct pci_dev *pd) | |||
1720 | nvidia_delete_i2c_busses(par); | 1369 | nvidia_delete_i2c_busses(par); |
1721 | iounmap(par->REGS); | 1370 | iounmap(par->REGS); |
1722 | pci_release_regions(pd); | 1371 | pci_release_regions(pd); |
1723 | pci_disable_device(pd); | ||
1724 | kfree(info->pixmap.addr); | 1372 | kfree(info->pixmap.addr); |
1725 | framebuffer_release(info); | 1373 | framebuffer_release(info); |
1726 | pci_set_drvdata(pd, NULL); | 1374 | pci_set_drvdata(pd, NULL); |
diff --git a/drivers/video/riva/fbdev.c b/drivers/video/riva/fbdev.c index d4384ab1df65..12af58c5cf1f 100644 --- a/drivers/video/riva/fbdev.c +++ b/drivers/video/riva/fbdev.c | |||
@@ -2152,7 +2152,6 @@ err_iounmap_ctrl_base: | |||
2152 | err_release_region: | 2152 | err_release_region: |
2153 | pci_release_regions(pd); | 2153 | pci_release_regions(pd); |
2154 | err_disable_device: | 2154 | err_disable_device: |
2155 | pci_disable_device(pd); | ||
2156 | err_free_pixmap: | 2155 | err_free_pixmap: |
2157 | kfree(info->pixmap.addr); | 2156 | kfree(info->pixmap.addr); |
2158 | err_framebuffer_release: | 2157 | err_framebuffer_release: |
@@ -2187,7 +2186,6 @@ static void __exit rivafb_remove(struct pci_dev *pd) | |||
2187 | if (par->riva.Architecture == NV_ARCH_03) | 2186 | if (par->riva.Architecture == NV_ARCH_03) |
2188 | iounmap(par->riva.PRAMIN); | 2187 | iounmap(par->riva.PRAMIN); |
2189 | pci_release_regions(pd); | 2188 | pci_release_regions(pd); |
2190 | pci_disable_device(pd); | ||
2191 | kfree(info->pixmap.addr); | 2189 | kfree(info->pixmap.addr); |
2192 | framebuffer_release(info); | 2190 | framebuffer_release(info); |
2193 | pci_set_drvdata(pd, NULL); | 2191 | pci_set_drvdata(pd, NULL); |
diff --git a/drivers/video/s3c2410fb.c b/drivers/video/s3c2410fb.c index 9451932fbaf2..fbc411850686 100644 --- a/drivers/video/s3c2410fb.c +++ b/drivers/video/s3c2410fb.c | |||
@@ -641,6 +641,7 @@ static int __init s3c2410fb_probe(struct platform_device *pdev) | |||
641 | int ret; | 641 | int ret; |
642 | int irq; | 642 | int irq; |
643 | int i; | 643 | int i; |
644 | u32 lcdcon1; | ||
644 | 645 | ||
645 | mach_info = pdev->dev.platform_data; | 646 | mach_info = pdev->dev.platform_data; |
646 | if (mach_info == NULL) { | 647 | if (mach_info == NULL) { |
@@ -672,6 +673,11 @@ static int __init s3c2410fb_probe(struct platform_device *pdev) | |||
672 | 673 | ||
673 | memcpy(&info->regs, &mach_info->regs, sizeof(info->regs)); | 674 | memcpy(&info->regs, &mach_info->regs, sizeof(info->regs)); |
674 | 675 | ||
676 | /* Stop the video and unset ENVID if set */ | ||
677 | info->regs.lcdcon1 &= ~S3C2410_LCDCON1_ENVID; | ||
678 | lcdcon1 = readl(S3C2410_LCDCON1); | ||
679 | writel(lcdcon1 & ~S3C2410_LCDCON1_ENVID, S3C2410_LCDCON1); | ||
680 | |||
675 | info->mach_info = pdev->dev.platform_data; | 681 | info->mach_info = pdev->dev.platform_data; |
676 | 682 | ||
677 | fbinfo->fix.type = FB_TYPE_PACKED_PIXELS; | 683 | fbinfo->fix.type = FB_TYPE_PACKED_PIXELS; |
@@ -794,15 +800,14 @@ dealloc_fb: | |||
794 | * shutdown the lcd controller | 800 | * shutdown the lcd controller |
795 | */ | 801 | */ |
796 | 802 | ||
797 | static void s3c2410fb_stop_lcd(void) | 803 | static void s3c2410fb_stop_lcd(struct s3c2410fb_info *fbi) |
798 | { | 804 | { |
799 | unsigned long flags; | 805 | unsigned long flags; |
800 | unsigned long tmp; | ||
801 | 806 | ||
802 | local_irq_save(flags); | 807 | local_irq_save(flags); |
803 | 808 | ||
804 | tmp = readl(S3C2410_LCDCON1); | 809 | fbi->regs.lcdcon1 &= ~S3C2410_LCDCON1_ENVID; |
805 | writel(tmp & ~S3C2410_LCDCON1_ENVID, S3C2410_LCDCON1); | 810 | writel(fbi->regs.lcdcon1, S3C2410_LCDCON1); |
806 | 811 | ||
807 | local_irq_restore(flags); | 812 | local_irq_restore(flags); |
808 | } | 813 | } |
@@ -816,7 +821,7 @@ static int s3c2410fb_remove(struct platform_device *pdev) | |||
816 | struct s3c2410fb_info *info = fbinfo->par; | 821 | struct s3c2410fb_info *info = fbinfo->par; |
817 | int irq; | 822 | int irq; |
818 | 823 | ||
819 | s3c2410fb_stop_lcd(); | 824 | s3c2410fb_stop_lcd(info); |
820 | msleep(1); | 825 | msleep(1); |
821 | 826 | ||
822 | s3c2410fb_unmap_video_memory(info); | 827 | s3c2410fb_unmap_video_memory(info); |
@@ -844,7 +849,7 @@ static int s3c2410fb_suspend(struct platform_device *dev, pm_message_t state) | |||
844 | struct fb_info *fbinfo = platform_get_drvdata(dev); | 849 | struct fb_info *fbinfo = platform_get_drvdata(dev); |
845 | struct s3c2410fb_info *info = fbinfo->par; | 850 | struct s3c2410fb_info *info = fbinfo->par; |
846 | 851 | ||
847 | s3c2410fb_stop_lcd(); | 852 | s3c2410fb_stop_lcd(info); |
848 | 853 | ||
849 | /* sleep before disabling the clock, we need to ensure | 854 | /* sleep before disabling the clock, we need to ensure |
850 | * the LCD DMA engine is not going to get back on the bus | 855 | * the LCD DMA engine is not going to get back on the bus |
diff --git a/drivers/video/savage/savagefb.h b/drivers/video/savage/savagefb.h index 58cfdfb41833..e648a6c0f6d9 100644 --- a/drivers/video/savage/savagefb.h +++ b/drivers/video/savage/savagefb.h | |||
@@ -147,7 +147,27 @@ struct xtimings { | |||
147 | int interlaced; | 147 | int interlaced; |
148 | }; | 148 | }; |
149 | 149 | ||
150 | struct savage_reg { | ||
151 | unsigned char MiscOutReg; /* Misc */ | ||
152 | unsigned char CRTC[25]; /* Crtc Controller */ | ||
153 | unsigned char Sequencer[5]; /* Video Sequencer */ | ||
154 | unsigned char Graphics[9]; /* Video Graphics */ | ||
155 | unsigned char Attribute[21]; /* Video Atribute */ | ||
150 | 156 | ||
157 | unsigned int mode, refresh; | ||
158 | unsigned char SR08, SR0E, SR0F; | ||
159 | unsigned char SR10, SR11, SR12, SR13, SR15, SR18, SR29, SR30; | ||
160 | unsigned char SR54[8]; | ||
161 | unsigned char Clock; | ||
162 | unsigned char CR31, CR32, CR33, CR34, CR36, CR3A, CR3B, CR3C; | ||
163 | unsigned char CR40, CR41, CR42, CR43, CR45; | ||
164 | unsigned char CR50, CR51, CR53, CR55, CR58, CR5B, CR5D, CR5E; | ||
165 | unsigned char CR60, CR63, CR65, CR66, CR67, CR68, CR69, CR6D, CR6F; | ||
166 | unsigned char CR86, CR88; | ||
167 | unsigned char CR90, CR91, CRB0; | ||
168 | unsigned int STREAMS[22]; /* yuck, streams regs */ | ||
169 | unsigned int MMPR0, MMPR1, MMPR2, MMPR3; | ||
170 | }; | ||
151 | /* --------------------------------------------------------------------- */ | 171 | /* --------------------------------------------------------------------- */ |
152 | 172 | ||
153 | #define NR_PALETTE 256 | 173 | #define NR_PALETTE 256 |
@@ -167,6 +187,8 @@ struct savagefb_par { | |||
167 | struct pci_dev *pcidev; | 187 | struct pci_dev *pcidev; |
168 | savage_chipset chip; | 188 | savage_chipset chip; |
169 | struct savagefb_i2c_chan chan; | 189 | struct savagefb_i2c_chan chan; |
190 | struct savage_reg state; | ||
191 | struct savage_reg save; | ||
170 | unsigned char *edid; | 192 | unsigned char *edid; |
171 | u32 pseudo_palette[16]; | 193 | u32 pseudo_palette[16]; |
172 | int paletteEnabled; | 194 | int paletteEnabled; |
@@ -179,6 +201,7 @@ struct savagefb_par { | |||
179 | int minClock; | 201 | int minClock; |
180 | int numClocks; | 202 | int numClocks; |
181 | int clock[4]; | 203 | int clock[4]; |
204 | int MCLK, REFCLK, LCDclk; | ||
182 | struct { | 205 | struct { |
183 | u8 __iomem *vbase; | 206 | u8 __iomem *vbase; |
184 | u32 pbase; | 207 | u32 pbase; |
@@ -196,7 +219,6 @@ struct savagefb_par { | |||
196 | 219 | ||
197 | volatile u32 __iomem *bci_base; | 220 | volatile u32 __iomem *bci_base; |
198 | unsigned int bci_ptr; | 221 | unsigned int bci_ptr; |
199 | |||
200 | u32 cob_offset; | 222 | u32 cob_offset; |
201 | u32 cob_size; | 223 | u32 cob_size; |
202 | int cob_index; | 224 | int cob_index; |
@@ -204,7 +226,6 @@ struct savagefb_par { | |||
204 | void (*SavageWaitIdle) (struct savagefb_par *par); | 226 | void (*SavageWaitIdle) (struct savagefb_par *par); |
205 | void (*SavageWaitFifo) (struct savagefb_par *par, int space); | 227 | void (*SavageWaitFifo) (struct savagefb_par *par, int space); |
206 | 228 | ||
207 | int MCLK, REFCLK, LCDclk; | ||
208 | int HorizScaleFactor; | 229 | int HorizScaleFactor; |
209 | 230 | ||
210 | /* Panels size */ | 231 | /* Panels size */ |
@@ -217,26 +238,6 @@ struct savagefb_par { | |||
217 | 238 | ||
218 | int depth; | 239 | int depth; |
219 | int vwidth; | 240 | int vwidth; |
220 | |||
221 | unsigned char MiscOutReg; /* Misc */ | ||
222 | unsigned char CRTC[25]; /* Crtc Controller */ | ||
223 | unsigned char Sequencer[5]; /* Video Sequencer */ | ||
224 | unsigned char Graphics[9]; /* Video Graphics */ | ||
225 | unsigned char Attribute[21]; /* Video Atribute */ | ||
226 | |||
227 | unsigned int mode, refresh; | ||
228 | unsigned char SR08, SR0E, SR0F; | ||
229 | unsigned char SR10, SR11, SR12, SR13, SR15, SR18, SR29, SR30; | ||
230 | unsigned char SR54[8]; | ||
231 | unsigned char Clock; | ||
232 | unsigned char CR31, CR32, CR33, CR34, CR36, CR3A, CR3B, CR3C; | ||
233 | unsigned char CR40, CR41, CR42, CR43, CR45; | ||
234 | unsigned char CR50, CR51, CR53, CR55, CR58, CR5B, CR5D, CR5E; | ||
235 | unsigned char CR60, CR63, CR65, CR66, CR67, CR68, CR69, CR6D, CR6F; | ||
236 | unsigned char CR86, CR88; | ||
237 | unsigned char CR90, CR91, CRB0; | ||
238 | unsigned int STREAMS[22]; /* yuck, streams regs */ | ||
239 | unsigned int MMPR0, MMPR1, MMPR2, MMPR3; | ||
240 | }; | 241 | }; |
241 | 242 | ||
242 | #define BCI_BD_BW_DISABLE 0x10000000 | 243 | #define BCI_BD_BW_DISABLE 0x10000000 |
diff --git a/drivers/video/savage/savagefb_driver.c b/drivers/video/savage/savagefb_driver.c index 0da624e6524f..78883cf66a4d 100644 --- a/drivers/video/savage/savagefb_driver.c +++ b/drivers/video/savage/savagefb_driver.c | |||
@@ -86,15 +86,15 @@ MODULE_DESCRIPTION("FBDev driver for S3 Savage PCI/AGP Chips"); | |||
86 | 86 | ||
87 | /* --------------------------------------------------------------------- */ | 87 | /* --------------------------------------------------------------------- */ |
88 | 88 | ||
89 | static void vgaHWSeqReset (struct savagefb_par *par, int start) | 89 | static void vgaHWSeqReset(struct savagefb_par *par, int start) |
90 | { | 90 | { |
91 | if (start) | 91 | if (start) |
92 | VGAwSEQ (0x00, 0x01, par); /* Synchronous Reset */ | 92 | VGAwSEQ(0x00, 0x01, par); /* Synchronous Reset */ |
93 | else | 93 | else |
94 | VGAwSEQ (0x00, 0x03, par); /* End Reset */ | 94 | VGAwSEQ(0x00, 0x03, par); /* End Reset */ |
95 | } | 95 | } |
96 | 96 | ||
97 | static void vgaHWProtect (struct savagefb_par *par, int on) | 97 | static void vgaHWProtect(struct savagefb_par *par, int on) |
98 | { | 98 | { |
99 | unsigned char tmp; | 99 | unsigned char tmp; |
100 | 100 | ||
@@ -102,10 +102,10 @@ static void vgaHWProtect (struct savagefb_par *par, int on) | |||
102 | /* | 102 | /* |
103 | * Turn off screen and disable sequencer. | 103 | * Turn off screen and disable sequencer. |
104 | */ | 104 | */ |
105 | tmp = VGArSEQ (0x01, par); | 105 | tmp = VGArSEQ(0x01, par); |
106 | 106 | ||
107 | vgaHWSeqReset (par, 1); /* start synchronous reset */ | 107 | vgaHWSeqReset(par, 1); /* start synchronous reset */ |
108 | VGAwSEQ (0x01, tmp | 0x20, par);/* disable the display */ | 108 | VGAwSEQ(0x01, tmp | 0x20, par);/* disable the display */ |
109 | 109 | ||
110 | VGAenablePalette(par); | 110 | VGAenablePalette(par); |
111 | } else { | 111 | } else { |
@@ -113,75 +113,76 @@ static void vgaHWProtect (struct savagefb_par *par, int on) | |||
113 | * Reenable sequencer, then turn on screen. | 113 | * Reenable sequencer, then turn on screen. |
114 | */ | 114 | */ |
115 | 115 | ||
116 | tmp = VGArSEQ (0x01, par); | 116 | tmp = VGArSEQ(0x01, par); |
117 | 117 | ||
118 | VGAwSEQ (0x01, tmp & ~0x20, par);/* reenable display */ | 118 | VGAwSEQ(0x01, tmp & ~0x20, par);/* reenable display */ |
119 | vgaHWSeqReset (par, 0); /* clear synchronous reset */ | 119 | vgaHWSeqReset(par, 0); /* clear synchronous reset */ |
120 | 120 | ||
121 | VGAdisablePalette(par); | 121 | VGAdisablePalette(par); |
122 | } | 122 | } |
123 | } | 123 | } |
124 | 124 | ||
125 | static void vgaHWRestore (struct savagefb_par *par) | 125 | static void vgaHWRestore(struct savagefb_par *par, struct savage_reg *reg) |
126 | { | 126 | { |
127 | int i; | 127 | int i; |
128 | 128 | ||
129 | VGAwMISC (par->MiscOutReg, par); | 129 | VGAwMISC(reg->MiscOutReg, par); |
130 | 130 | ||
131 | for (i = 1; i < 5; i++) | 131 | for (i = 1; i < 5; i++) |
132 | VGAwSEQ (i, par->Sequencer[i], par); | 132 | VGAwSEQ(i, reg->Sequencer[i], par); |
133 | 133 | ||
134 | /* Ensure CRTC registers 0-7 are unlocked by clearing bit 7 or | 134 | /* Ensure CRTC registers 0-7 are unlocked by clearing bit 7 or |
135 | CRTC[17] */ | 135 | CRTC[17] */ |
136 | VGAwCR (17, par->CRTC[17] & ~0x80, par); | 136 | VGAwCR(17, reg->CRTC[17] & ~0x80, par); |
137 | 137 | ||
138 | for (i = 0; i < 25; i++) | 138 | for (i = 0; i < 25; i++) |
139 | VGAwCR (i, par->CRTC[i], par); | 139 | VGAwCR(i, reg->CRTC[i], par); |
140 | 140 | ||
141 | for (i = 0; i < 9; i++) | 141 | for (i = 0; i < 9; i++) |
142 | VGAwGR (i, par->Graphics[i], par); | 142 | VGAwGR(i, reg->Graphics[i], par); |
143 | 143 | ||
144 | VGAenablePalette(par); | 144 | VGAenablePalette(par); |
145 | 145 | ||
146 | for (i = 0; i < 21; i++) | 146 | for (i = 0; i < 21; i++) |
147 | VGAwATTR (i, par->Attribute[i], par); | 147 | VGAwATTR(i, reg->Attribute[i], par); |
148 | 148 | ||
149 | VGAdisablePalette(par); | 149 | VGAdisablePalette(par); |
150 | } | 150 | } |
151 | 151 | ||
152 | static void vgaHWInit (struct fb_var_screeninfo *var, | 152 | static void vgaHWInit(struct fb_var_screeninfo *var, |
153 | struct savagefb_par *par, | 153 | struct savagefb_par *par, |
154 | struct xtimings *timings) | 154 | struct xtimings *timings, |
155 | struct savage_reg *reg) | ||
155 | { | 156 | { |
156 | par->MiscOutReg = 0x23; | 157 | reg->MiscOutReg = 0x23; |
157 | 158 | ||
158 | if (!(timings->sync & FB_SYNC_HOR_HIGH_ACT)) | 159 | if (!(timings->sync & FB_SYNC_HOR_HIGH_ACT)) |
159 | par->MiscOutReg |= 0x40; | 160 | reg->MiscOutReg |= 0x40; |
160 | 161 | ||
161 | if (!(timings->sync & FB_SYNC_VERT_HIGH_ACT)) | 162 | if (!(timings->sync & FB_SYNC_VERT_HIGH_ACT)) |
162 | par->MiscOutReg |= 0x80; | 163 | reg->MiscOutReg |= 0x80; |
163 | 164 | ||
164 | /* | 165 | /* |
165 | * Time Sequencer | 166 | * Time Sequencer |
166 | */ | 167 | */ |
167 | par->Sequencer[0x00] = 0x00; | 168 | reg->Sequencer[0x00] = 0x00; |
168 | par->Sequencer[0x01] = 0x01; | 169 | reg->Sequencer[0x01] = 0x01; |
169 | par->Sequencer[0x02] = 0x0F; | 170 | reg->Sequencer[0x02] = 0x0F; |
170 | par->Sequencer[0x03] = 0x00; /* Font select */ | 171 | reg->Sequencer[0x03] = 0x00; /* Font select */ |
171 | par->Sequencer[0x04] = 0x0E; /* Misc */ | 172 | reg->Sequencer[0x04] = 0x0E; /* Misc */ |
172 | 173 | ||
173 | /* | 174 | /* |
174 | * CRTC Controller | 175 | * CRTC Controller |
175 | */ | 176 | */ |
176 | par->CRTC[0x00] = (timings->HTotal >> 3) - 5; | 177 | reg->CRTC[0x00] = (timings->HTotal >> 3) - 5; |
177 | par->CRTC[0x01] = (timings->HDisplay >> 3) - 1; | 178 | reg->CRTC[0x01] = (timings->HDisplay >> 3) - 1; |
178 | par->CRTC[0x02] = (timings->HSyncStart >> 3) - 1; | 179 | reg->CRTC[0x02] = (timings->HSyncStart >> 3) - 1; |
179 | par->CRTC[0x03] = (((timings->HSyncEnd >> 3) - 1) & 0x1f) | 0x80; | 180 | reg->CRTC[0x03] = (((timings->HSyncEnd >> 3) - 1) & 0x1f) | 0x80; |
180 | par->CRTC[0x04] = (timings->HSyncStart >> 3); | 181 | reg->CRTC[0x04] = (timings->HSyncStart >> 3); |
181 | par->CRTC[0x05] = ((((timings->HSyncEnd >> 3) - 1) & 0x20) << 2) | | 182 | reg->CRTC[0x05] = ((((timings->HSyncEnd >> 3) - 1) & 0x20) << 2) | |
182 | (((timings->HSyncEnd >> 3)) & 0x1f); | 183 | (((timings->HSyncEnd >> 3)) & 0x1f); |
183 | par->CRTC[0x06] = (timings->VTotal - 2) & 0xFF; | 184 | reg->CRTC[0x06] = (timings->VTotal - 2) & 0xFF; |
184 | par->CRTC[0x07] = (((timings->VTotal - 2) & 0x100) >> 8) | | 185 | reg->CRTC[0x07] = (((timings->VTotal - 2) & 0x100) >> 8) | |
185 | (((timings->VDisplay - 1) & 0x100) >> 7) | | 186 | (((timings->VDisplay - 1) & 0x100) >> 7) | |
186 | ((timings->VSyncStart & 0x100) >> 6) | | 187 | ((timings->VSyncStart & 0x100) >> 6) | |
187 | (((timings->VSyncStart - 1) & 0x100) >> 5) | | 188 | (((timings->VSyncStart - 1) & 0x100) >> 5) | |
@@ -189,27 +190,27 @@ static void vgaHWInit (struct fb_var_screeninfo *var, | |||
189 | (((timings->VTotal - 2) & 0x200) >> 4) | | 190 | (((timings->VTotal - 2) & 0x200) >> 4) | |
190 | (((timings->VDisplay - 1) & 0x200) >> 3) | | 191 | (((timings->VDisplay - 1) & 0x200) >> 3) | |
191 | ((timings->VSyncStart & 0x200) >> 2); | 192 | ((timings->VSyncStart & 0x200) >> 2); |
192 | par->CRTC[0x08] = 0x00; | 193 | reg->CRTC[0x08] = 0x00; |
193 | par->CRTC[0x09] = (((timings->VSyncStart - 1) & 0x200) >> 4) | 0x40; | 194 | reg->CRTC[0x09] = (((timings->VSyncStart - 1) & 0x200) >> 4) | 0x40; |
194 | 195 | ||
195 | if (timings->dblscan) | 196 | if (timings->dblscan) |
196 | par->CRTC[0x09] |= 0x80; | 197 | reg->CRTC[0x09] |= 0x80; |
197 | 198 | ||
198 | par->CRTC[0x0a] = 0x00; | 199 | reg->CRTC[0x0a] = 0x00; |
199 | par->CRTC[0x0b] = 0x00; | 200 | reg->CRTC[0x0b] = 0x00; |
200 | par->CRTC[0x0c] = 0x00; | 201 | reg->CRTC[0x0c] = 0x00; |
201 | par->CRTC[0x0d] = 0x00; | 202 | reg->CRTC[0x0d] = 0x00; |
202 | par->CRTC[0x0e] = 0x00; | 203 | reg->CRTC[0x0e] = 0x00; |
203 | par->CRTC[0x0f] = 0x00; | 204 | reg->CRTC[0x0f] = 0x00; |
204 | par->CRTC[0x10] = timings->VSyncStart & 0xff; | 205 | reg->CRTC[0x10] = timings->VSyncStart & 0xff; |
205 | par->CRTC[0x11] = (timings->VSyncEnd & 0x0f) | 0x20; | 206 | reg->CRTC[0x11] = (timings->VSyncEnd & 0x0f) | 0x20; |
206 | par->CRTC[0x12] = (timings->VDisplay - 1) & 0xff; | 207 | reg->CRTC[0x12] = (timings->VDisplay - 1) & 0xff; |
207 | par->CRTC[0x13] = var->xres_virtual >> 4; | 208 | reg->CRTC[0x13] = var->xres_virtual >> 4; |
208 | par->CRTC[0x14] = 0x00; | 209 | reg->CRTC[0x14] = 0x00; |
209 | par->CRTC[0x15] = (timings->VSyncStart - 1) & 0xff; | 210 | reg->CRTC[0x15] = (timings->VSyncStart - 1) & 0xff; |
210 | par->CRTC[0x16] = (timings->VSyncEnd - 1) & 0xff; | 211 | reg->CRTC[0x16] = (timings->VSyncEnd - 1) & 0xff; |
211 | par->CRTC[0x17] = 0xc3; | 212 | reg->CRTC[0x17] = 0xc3; |
212 | par->CRTC[0x18] = 0xff; | 213 | reg->CRTC[0x18] = 0xff; |
213 | 214 | ||
214 | /* | 215 | /* |
215 | * are these unnecessary? | 216 | * are these unnecessary? |
@@ -220,38 +221,38 @@ static void vgaHWInit (struct fb_var_screeninfo *var, | |||
220 | /* | 221 | /* |
221 | * Graphics Display Controller | 222 | * Graphics Display Controller |
222 | */ | 223 | */ |
223 | par->Graphics[0x00] = 0x00; | 224 | reg->Graphics[0x00] = 0x00; |
224 | par->Graphics[0x01] = 0x00; | 225 | reg->Graphics[0x01] = 0x00; |
225 | par->Graphics[0x02] = 0x00; | 226 | reg->Graphics[0x02] = 0x00; |
226 | par->Graphics[0x03] = 0x00; | 227 | reg->Graphics[0x03] = 0x00; |
227 | par->Graphics[0x04] = 0x00; | 228 | reg->Graphics[0x04] = 0x00; |
228 | par->Graphics[0x05] = 0x40; | 229 | reg->Graphics[0x05] = 0x40; |
229 | par->Graphics[0x06] = 0x05; /* only map 64k VGA memory !!!! */ | 230 | reg->Graphics[0x06] = 0x05; /* only map 64k VGA memory !!!! */ |
230 | par->Graphics[0x07] = 0x0F; | 231 | reg->Graphics[0x07] = 0x0F; |
231 | par->Graphics[0x08] = 0xFF; | 232 | reg->Graphics[0x08] = 0xFF; |
232 | 233 | ||
233 | 234 | ||
234 | par->Attribute[0x00] = 0x00; /* standard colormap translation */ | 235 | reg->Attribute[0x00] = 0x00; /* standard colormap translation */ |
235 | par->Attribute[0x01] = 0x01; | 236 | reg->Attribute[0x01] = 0x01; |
236 | par->Attribute[0x02] = 0x02; | 237 | reg->Attribute[0x02] = 0x02; |
237 | par->Attribute[0x03] = 0x03; | 238 | reg->Attribute[0x03] = 0x03; |
238 | par->Attribute[0x04] = 0x04; | 239 | reg->Attribute[0x04] = 0x04; |
239 | par->Attribute[0x05] = 0x05; | 240 | reg->Attribute[0x05] = 0x05; |
240 | par->Attribute[0x06] = 0x06; | 241 | reg->Attribute[0x06] = 0x06; |
241 | par->Attribute[0x07] = 0x07; | 242 | reg->Attribute[0x07] = 0x07; |
242 | par->Attribute[0x08] = 0x08; | 243 | reg->Attribute[0x08] = 0x08; |
243 | par->Attribute[0x09] = 0x09; | 244 | reg->Attribute[0x09] = 0x09; |
244 | par->Attribute[0x0a] = 0x0A; | 245 | reg->Attribute[0x0a] = 0x0A; |
245 | par->Attribute[0x0b] = 0x0B; | 246 | reg->Attribute[0x0b] = 0x0B; |
246 | par->Attribute[0x0c] = 0x0C; | 247 | reg->Attribute[0x0c] = 0x0C; |
247 | par->Attribute[0x0d] = 0x0D; | 248 | reg->Attribute[0x0d] = 0x0D; |
248 | par->Attribute[0x0e] = 0x0E; | 249 | reg->Attribute[0x0e] = 0x0E; |
249 | par->Attribute[0x0f] = 0x0F; | 250 | reg->Attribute[0x0f] = 0x0F; |
250 | par->Attribute[0x10] = 0x41; | 251 | reg->Attribute[0x10] = 0x41; |
251 | par->Attribute[0x11] = 0xFF; | 252 | reg->Attribute[0x11] = 0xFF; |
252 | par->Attribute[0x12] = 0x0F; | 253 | reg->Attribute[0x12] = 0x0F; |
253 | par->Attribute[0x13] = 0x00; | 254 | reg->Attribute[0x13] = 0x00; |
254 | par->Attribute[0x14] = 0x00; | 255 | reg->Attribute[0x14] = 0x00; |
255 | } | 256 | } |
256 | 257 | ||
257 | /* -------------------- Hardware specific routines ------------------------- */ | 258 | /* -------------------- Hardware specific routines ------------------------- */ |
@@ -304,15 +305,15 @@ savage2000_waitidle(struct savagefb_par *par) | |||
304 | while ((savage_in32(0x48C60, par) & 0x009fffff)); | 305 | while ((savage_in32(0x48C60, par) & 0x009fffff)); |
305 | } | 306 | } |
306 | 307 | ||
307 | 308 | #ifdef CONFIG_FB_SAVAGE_ACCEL | |
308 | static void | 309 | static void |
309 | SavageSetup2DEngine (struct savagefb_par *par) | 310 | SavageSetup2DEngine(struct savagefb_par *par) |
310 | { | 311 | { |
311 | unsigned long GlobalBitmapDescriptor; | 312 | unsigned long GlobalBitmapDescriptor; |
312 | 313 | ||
313 | GlobalBitmapDescriptor = 1 | 8 | BCI_BD_BW_DISABLE; | 314 | GlobalBitmapDescriptor = 1 | 8 | BCI_BD_BW_DISABLE; |
314 | BCI_BD_SET_BPP (GlobalBitmapDescriptor, par->depth); | 315 | BCI_BD_SET_BPP(GlobalBitmapDescriptor, par->depth); |
315 | BCI_BD_SET_STRIDE (GlobalBitmapDescriptor, par->vwidth); | 316 | BCI_BD_SET_STRIDE(GlobalBitmapDescriptor, par->vwidth); |
316 | 317 | ||
317 | switch(par->chip) { | 318 | switch(par->chip) { |
318 | case S3_SAVAGE3D: | 319 | case S3_SAVAGE3D: |
@@ -361,32 +362,48 @@ SavageSetup2DEngine (struct savagefb_par *par) | |||
361 | vga_out8(0x3d5, 0x0c, par); | 362 | vga_out8(0x3d5, 0x0c, par); |
362 | 363 | ||
363 | /* Set stride to use GBD. */ | 364 | /* Set stride to use GBD. */ |
364 | vga_out8 (0x3d4, 0x50, par); | 365 | vga_out8(0x3d4, 0x50, par); |
365 | vga_out8 (0x3d5, vga_in8(0x3d5, par) | 0xC1, par); | 366 | vga_out8(0x3d5, vga_in8(0x3d5, par) | 0xC1, par); |
366 | 367 | ||
367 | /* Enable 2D engine. */ | 368 | /* Enable 2D engine. */ |
368 | vga_out8 (0x3d4, 0x40, par); | 369 | vga_out8(0x3d4, 0x40, par); |
369 | vga_out8 (0x3d5, 0x01, par); | 370 | vga_out8(0x3d5, 0x01, par); |
370 | 371 | ||
371 | savage_out32 (MONO_PAT_0, ~0, par); | 372 | savage_out32(MONO_PAT_0, ~0, par); |
372 | savage_out32 (MONO_PAT_1, ~0, par); | 373 | savage_out32(MONO_PAT_1, ~0, par); |
373 | 374 | ||
374 | /* Setup plane masks */ | 375 | /* Setup plane masks */ |
375 | savage_out32 (0x8128, ~0, par); /* enable all write planes */ | 376 | savage_out32(0x8128, ~0, par); /* enable all write planes */ |
376 | savage_out32 (0x812C, ~0, par); /* enable all read planes */ | 377 | savage_out32(0x812C, ~0, par); /* enable all read planes */ |
377 | savage_out16 (0x8134, 0x27, par); | 378 | savage_out16(0x8134, 0x27, par); |
378 | savage_out16 (0x8136, 0x07, par); | 379 | savage_out16(0x8136, 0x07, par); |
379 | 380 | ||
380 | /* Now set the GBD */ | 381 | /* Now set the GBD */ |
381 | par->bci_ptr = 0; | 382 | par->bci_ptr = 0; |
382 | par->SavageWaitFifo (par, 4); | 383 | par->SavageWaitFifo(par, 4); |
383 | 384 | ||
384 | BCI_SEND( BCI_CMD_SETREG | (1 << 16) | BCI_GBD1 ); | 385 | BCI_SEND(BCI_CMD_SETREG | (1 << 16) | BCI_GBD1); |
385 | BCI_SEND( 0 ); | 386 | BCI_SEND(0); |
386 | BCI_SEND( BCI_CMD_SETREG | (1 << 16) | BCI_GBD2 ); | 387 | BCI_SEND(BCI_CMD_SETREG | (1 << 16) | BCI_GBD2); |
387 | BCI_SEND( GlobalBitmapDescriptor ); | 388 | BCI_SEND(GlobalBitmapDescriptor); |
388 | } | 389 | } |
389 | 390 | ||
391 | static void savagefb_set_clip(struct fb_info *info) | ||
392 | { | ||
393 | struct savagefb_par *par = info->par; | ||
394 | int cmd; | ||
395 | |||
396 | cmd = BCI_CMD_NOP | BCI_CMD_CLIP_NEW; | ||
397 | par->bci_ptr = 0; | ||
398 | par->SavageWaitFifo(par,3); | ||
399 | BCI_SEND(cmd); | ||
400 | BCI_SEND(BCI_CLIP_TL(0, 0)); | ||
401 | BCI_SEND(BCI_CLIP_BR(0xfff, 0xfff)); | ||
402 | } | ||
403 | #else | ||
404 | static void SavageSetup2DEngine(struct savagefb_par *par) {} | ||
405 | |||
406 | #endif | ||
390 | 407 | ||
391 | static void SavageCalcClock(long freq, int min_m, int min_n1, int max_n1, | 408 | static void SavageCalcClock(long freq, int min_m, int min_n1, int max_n1, |
392 | int min_n2, int max_n2, long freq_min, | 409 | int min_n2, int max_n2, long freq_min, |
@@ -398,11 +415,11 @@ static void SavageCalcClock(long freq, int min_m, int min_n1, int max_n1, | |||
398 | unsigned char n1, n2, best_n1=16+2, best_n2=2, best_m=125+2; | 415 | unsigned char n1, n2, best_n1=16+2, best_n2=2, best_m=125+2; |
399 | 416 | ||
400 | if (freq < freq_min / (1 << max_n2)) { | 417 | if (freq < freq_min / (1 << max_n2)) { |
401 | printk (KERN_ERR "invalid frequency %ld Khz\n", freq); | 418 | printk(KERN_ERR "invalid frequency %ld Khz\n", freq); |
402 | freq = freq_min / (1 << max_n2); | 419 | freq = freq_min / (1 << max_n2); |
403 | } | 420 | } |
404 | if (freq > freq_max / (1 << min_n2)) { | 421 | if (freq > freq_max / (1 << min_n2)) { |
405 | printk (KERN_ERR "invalid frequency %ld Khz\n", freq); | 422 | printk(KERN_ERR "invalid frequency %ld Khz\n", freq); |
406 | freq = freq_max / (1 << min_n2); | 423 | freq = freq_max / (1 << min_n2); |
407 | } | 424 | } |
408 | 425 | ||
@@ -453,12 +470,12 @@ static int common_calc_clock(long freq, int min_m, int min_n1, int max_n1, | |||
453 | BASE_FREQ; | 470 | BASE_FREQ; |
454 | if (m < min_m + 2 || m > 127+2) | 471 | if (m < min_m + 2 || m > 127+2) |
455 | continue; | 472 | continue; |
456 | if((m * BASE_FREQ >= freq_min * n1) && | 473 | if ((m * BASE_FREQ >= freq_min * n1) && |
457 | (m * BASE_FREQ <= freq_max * n1)) { | 474 | (m * BASE_FREQ <= freq_max * n1)) { |
458 | diff = freq * (1 << n2) * n1 - BASE_FREQ * m; | 475 | diff = freq * (1 << n2) * n1 - BASE_FREQ * m; |
459 | if(diff < 0) | 476 | if (diff < 0) |
460 | diff = -diff; | 477 | diff = -diff; |
461 | if(diff < best_diff) { | 478 | if (diff < best_diff) { |
462 | best_diff = diff; | 479 | best_diff = diff; |
463 | best_m = m; | 480 | best_m = m; |
464 | best_n1 = n1; | 481 | best_n1 = n1; |
@@ -468,7 +485,7 @@ static int common_calc_clock(long freq, int min_m, int min_n1, int max_n1, | |||
468 | } | 485 | } |
469 | } | 486 | } |
470 | 487 | ||
471 | if(max_n1 == 63) | 488 | if (max_n1 == 63) |
472 | *ndiv = (best_n1 - 2) | (best_n2 << 6); | 489 | *ndiv = (best_n1 - 2) | (best_n2 << 6); |
473 | else | 490 | else |
474 | *ndiv = (best_n1 - 2) | (best_n2 << 5); | 491 | *ndiv = (best_n1 - 2) | (best_n2 << 5); |
@@ -488,23 +505,23 @@ static void SavagePrintRegs(void) | |||
488 | int vgaCRReg = 0x3d5; | 505 | int vgaCRReg = 0x3d5; |
489 | 506 | ||
490 | printk(KERN_DEBUG "SR x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE " | 507 | printk(KERN_DEBUG "SR x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE " |
491 | "xF" ); | 508 | "xF"); |
492 | 509 | ||
493 | for( i = 0; i < 0x70; i++ ) { | 510 | for (i = 0; i < 0x70; i++) { |
494 | if( !(i % 16) ) | 511 | if (!(i % 16)) |
495 | printk(KERN_DEBUG "\nSR%xx ", i >> 4 ); | 512 | printk(KERN_DEBUG "\nSR%xx ", i >> 4); |
496 | vga_out8( 0x3c4, i, par); | 513 | vga_out8(0x3c4, i, par); |
497 | printk(KERN_DEBUG " %02x", vga_in8(0x3c5, par) ); | 514 | printk(KERN_DEBUG " %02x", vga_in8(0x3c5, par)); |
498 | } | 515 | } |
499 | 516 | ||
500 | printk(KERN_DEBUG "\n\nCR x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC " | 517 | printk(KERN_DEBUG "\n\nCR x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC " |
501 | "xD xE xF" ); | 518 | "xD xE xF"); |
502 | 519 | ||
503 | for( i = 0; i < 0xB7; i++ ) { | 520 | for (i = 0; i < 0xB7; i++) { |
504 | if( !(i % 16) ) | 521 | if (!(i % 16)) |
505 | printk(KERN_DEBUG "\nCR%xx ", i >> 4 ); | 522 | printk(KERN_DEBUG "\nCR%xx ", i >> 4); |
506 | vga_out8( vgaCRIndex, i, par); | 523 | vga_out8(vgaCRIndex, i, par); |
507 | printk(KERN_DEBUG " %02x", vga_in8(vgaCRReg, par) ); | 524 | printk(KERN_DEBUG " %02x", vga_in8(vgaCRReg, par)); |
508 | } | 525 | } |
509 | 526 | ||
510 | printk(KERN_DEBUG "\n\n"); | 527 | printk(KERN_DEBUG "\n\n"); |
@@ -513,156 +530,309 @@ static void SavagePrintRegs(void) | |||
513 | 530 | ||
514 | /* --------------------------------------------------------------------- */ | 531 | /* --------------------------------------------------------------------- */ |
515 | 532 | ||
516 | static void savage_get_default_par(struct savagefb_par *par) | 533 | static void savage_get_default_par(struct savagefb_par *par, struct savage_reg *reg) |
517 | { | 534 | { |
518 | unsigned char cr3a, cr53, cr66; | 535 | unsigned char cr3a, cr53, cr66; |
519 | 536 | ||
520 | vga_out16 (0x3d4, 0x4838, par); | 537 | vga_out16(0x3d4, 0x4838, par); |
521 | vga_out16 (0x3d4, 0xa039, par); | 538 | vga_out16(0x3d4, 0xa039, par); |
522 | vga_out16 (0x3c4, 0x0608, par); | 539 | vga_out16(0x3c4, 0x0608, par); |
523 | 540 | ||
524 | vga_out8 (0x3d4, 0x66, par); | 541 | vga_out8(0x3d4, 0x66, par); |
525 | cr66 = vga_in8 (0x3d5, par); | 542 | cr66 = vga_in8(0x3d5, par); |
526 | vga_out8 (0x3d5, cr66 | 0x80, par); | 543 | vga_out8(0x3d5, cr66 | 0x80, par); |
527 | vga_out8 (0x3d4, 0x3a, par); | 544 | vga_out8(0x3d4, 0x3a, par); |
528 | cr3a = vga_in8 (0x3d5, par); | 545 | cr3a = vga_in8(0x3d5, par); |
529 | vga_out8 (0x3d5, cr3a | 0x80, par); | 546 | vga_out8(0x3d5, cr3a | 0x80, par); |
530 | vga_out8 (0x3d4, 0x53, par); | 547 | vga_out8(0x3d4, 0x53, par); |
531 | cr53 = vga_in8 (0x3d5, par); | 548 | cr53 = vga_in8(0x3d5, par); |
532 | vga_out8 (0x3d5, cr53 & 0x7f, par); | 549 | vga_out8(0x3d5, cr53 & 0x7f, par); |
533 | 550 | ||
534 | vga_out8 (0x3d4, 0x66, par); | 551 | vga_out8(0x3d4, 0x66, par); |
535 | vga_out8 (0x3d5, cr66, par); | 552 | vga_out8(0x3d5, cr66, par); |
536 | vga_out8 (0x3d4, 0x3a, par); | 553 | vga_out8(0x3d4, 0x3a, par); |
537 | vga_out8 (0x3d5, cr3a, par); | 554 | vga_out8(0x3d5, cr3a, par); |
538 | 555 | ||
539 | vga_out8 (0x3d4, 0x66, par); | 556 | vga_out8(0x3d4, 0x66, par); |
540 | vga_out8 (0x3d5, cr66, par); | 557 | vga_out8(0x3d5, cr66, par); |
541 | vga_out8 (0x3d4, 0x3a, par); | 558 | vga_out8(0x3d4, 0x3a, par); |
542 | vga_out8 (0x3d5, cr3a, par); | 559 | vga_out8(0x3d5, cr3a, par); |
543 | 560 | ||
544 | /* unlock extended seq regs */ | 561 | /* unlock extended seq regs */ |
545 | vga_out8 (0x3c4, 0x08, par); | 562 | vga_out8(0x3c4, 0x08, par); |
546 | par->SR08 = vga_in8 (0x3c5, par); | 563 | reg->SR08 = vga_in8(0x3c5, par); |
547 | vga_out8 (0x3c5, 0x06, par); | 564 | vga_out8(0x3c5, 0x06, par); |
548 | 565 | ||
549 | /* now save all the extended regs we need */ | 566 | /* now save all the extended regs we need */ |
550 | vga_out8 (0x3d4, 0x31, par); | 567 | vga_out8(0x3d4, 0x31, par); |
551 | par->CR31 = vga_in8 (0x3d5, par); | 568 | reg->CR31 = vga_in8(0x3d5, par); |
552 | vga_out8 (0x3d4, 0x32, par); | 569 | vga_out8(0x3d4, 0x32, par); |
553 | par->CR32 = vga_in8 (0x3d5, par); | 570 | reg->CR32 = vga_in8(0x3d5, par); |
554 | vga_out8 (0x3d4, 0x34, par); | 571 | vga_out8(0x3d4, 0x34, par); |
555 | par->CR34 = vga_in8 (0x3d5, par); | 572 | reg->CR34 = vga_in8(0x3d5, par); |
556 | vga_out8 (0x3d4, 0x36, par); | 573 | vga_out8(0x3d4, 0x36, par); |
557 | par->CR36 = vga_in8 (0x3d5, par); | 574 | reg->CR36 = vga_in8(0x3d5, par); |
558 | vga_out8 (0x3d4, 0x3a, par); | 575 | vga_out8(0x3d4, 0x3a, par); |
559 | par->CR3A = vga_in8 (0x3d5, par); | 576 | reg->CR3A = vga_in8(0x3d5, par); |
560 | vga_out8 (0x3d4, 0x40, par); | 577 | vga_out8(0x3d4, 0x40, par); |
561 | par->CR40 = vga_in8 (0x3d5, par); | 578 | reg->CR40 = vga_in8(0x3d5, par); |
562 | vga_out8 (0x3d4, 0x42, par); | 579 | vga_out8(0x3d4, 0x42, par); |
563 | par->CR42 = vga_in8 (0x3d5, par); | 580 | reg->CR42 = vga_in8(0x3d5, par); |
564 | vga_out8 (0x3d4, 0x45, par); | 581 | vga_out8(0x3d4, 0x45, par); |
565 | par->CR45 = vga_in8 (0x3d5, par); | 582 | reg->CR45 = vga_in8(0x3d5, par); |
566 | vga_out8 (0x3d4, 0x50, par); | 583 | vga_out8(0x3d4, 0x50, par); |
567 | par->CR50 = vga_in8 (0x3d5, par); | 584 | reg->CR50 = vga_in8(0x3d5, par); |
568 | vga_out8 (0x3d4, 0x51, par); | 585 | vga_out8(0x3d4, 0x51, par); |
569 | par->CR51 = vga_in8 (0x3d5, par); | 586 | reg->CR51 = vga_in8(0x3d5, par); |
570 | vga_out8 (0x3d4, 0x53, par); | 587 | vga_out8(0x3d4, 0x53, par); |
571 | par->CR53 = vga_in8 (0x3d5, par); | 588 | reg->CR53 = vga_in8(0x3d5, par); |
572 | vga_out8 (0x3d4, 0x58, par); | 589 | vga_out8(0x3d4, 0x58, par); |
573 | par->CR58 = vga_in8 (0x3d5, par); | 590 | reg->CR58 = vga_in8(0x3d5, par); |
574 | vga_out8 (0x3d4, 0x60, par); | 591 | vga_out8(0x3d4, 0x60, par); |
575 | par->CR60 = vga_in8 (0x3d5, par); | 592 | reg->CR60 = vga_in8(0x3d5, par); |
576 | vga_out8 (0x3d4, 0x66, par); | 593 | vga_out8(0x3d4, 0x66, par); |
577 | par->CR66 = vga_in8 (0x3d5, par); | 594 | reg->CR66 = vga_in8(0x3d5, par); |
578 | vga_out8 (0x3d4, 0x67, par); | 595 | vga_out8(0x3d4, 0x67, par); |
579 | par->CR67 = vga_in8 (0x3d5, par); | 596 | reg->CR67 = vga_in8(0x3d5, par); |
580 | vga_out8 (0x3d4, 0x68, par); | 597 | vga_out8(0x3d4, 0x68, par); |
581 | par->CR68 = vga_in8 (0x3d5, par); | 598 | reg->CR68 = vga_in8(0x3d5, par); |
582 | vga_out8 (0x3d4, 0x69, par); | 599 | vga_out8(0x3d4, 0x69, par); |
583 | par->CR69 = vga_in8 (0x3d5, par); | 600 | reg->CR69 = vga_in8(0x3d5, par); |
584 | vga_out8 (0x3d4, 0x6f, par); | 601 | vga_out8(0x3d4, 0x6f, par); |
585 | par->CR6F = vga_in8 (0x3d5, par); | 602 | reg->CR6F = vga_in8(0x3d5, par); |
586 | 603 | ||
587 | vga_out8 (0x3d4, 0x33, par); | 604 | vga_out8(0x3d4, 0x33, par); |
588 | par->CR33 = vga_in8 (0x3d5, par); | 605 | reg->CR33 = vga_in8(0x3d5, par); |
589 | vga_out8 (0x3d4, 0x86, par); | 606 | vga_out8(0x3d4, 0x86, par); |
590 | par->CR86 = vga_in8 (0x3d5, par); | 607 | reg->CR86 = vga_in8(0x3d5, par); |
591 | vga_out8 (0x3d4, 0x88, par); | 608 | vga_out8(0x3d4, 0x88, par); |
592 | par->CR88 = vga_in8 (0x3d5, par); | 609 | reg->CR88 = vga_in8(0x3d5, par); |
593 | vga_out8 (0x3d4, 0x90, par); | 610 | vga_out8(0x3d4, 0x90, par); |
594 | par->CR90 = vga_in8 (0x3d5, par); | 611 | reg->CR90 = vga_in8(0x3d5, par); |
595 | vga_out8 (0x3d4, 0x91, par); | 612 | vga_out8(0x3d4, 0x91, par); |
596 | par->CR91 = vga_in8 (0x3d5, par); | 613 | reg->CR91 = vga_in8(0x3d5, par); |
597 | vga_out8 (0x3d4, 0xb0, par); | 614 | vga_out8(0x3d4, 0xb0, par); |
598 | par->CRB0 = vga_in8 (0x3d5, par) | 0x80; | 615 | reg->CRB0 = vga_in8(0x3d5, par) | 0x80; |
616 | |||
617 | /* extended mode timing regs */ | ||
618 | vga_out8(0x3d4, 0x3b, par); | ||
619 | reg->CR3B = vga_in8(0x3d5, par); | ||
620 | vga_out8(0x3d4, 0x3c, par); | ||
621 | reg->CR3C = vga_in8(0x3d5, par); | ||
622 | vga_out8(0x3d4, 0x43, par); | ||
623 | reg->CR43 = vga_in8(0x3d5, par); | ||
624 | vga_out8(0x3d4, 0x5d, par); | ||
625 | reg->CR5D = vga_in8(0x3d5, par); | ||
626 | vga_out8(0x3d4, 0x5e, par); | ||
627 | reg->CR5E = vga_in8(0x3d5, par); | ||
628 | vga_out8(0x3d4, 0x65, par); | ||
629 | reg->CR65 = vga_in8(0x3d5, par); | ||
630 | |||
631 | /* save seq extended regs for DCLK PLL programming */ | ||
632 | vga_out8(0x3c4, 0x0e, par); | ||
633 | reg->SR0E = vga_in8(0x3c5, par); | ||
634 | vga_out8(0x3c4, 0x0f, par); | ||
635 | reg->SR0F = vga_in8(0x3c5, par); | ||
636 | vga_out8(0x3c4, 0x10, par); | ||
637 | reg->SR10 = vga_in8(0x3c5, par); | ||
638 | vga_out8(0x3c4, 0x11, par); | ||
639 | reg->SR11 = vga_in8(0x3c5, par); | ||
640 | vga_out8(0x3c4, 0x12, par); | ||
641 | reg->SR12 = vga_in8(0x3c5, par); | ||
642 | vga_out8(0x3c4, 0x13, par); | ||
643 | reg->SR13 = vga_in8(0x3c5, par); | ||
644 | vga_out8(0x3c4, 0x29, par); | ||
645 | reg->SR29 = vga_in8(0x3c5, par); | ||
646 | |||
647 | vga_out8(0x3c4, 0x15, par); | ||
648 | reg->SR15 = vga_in8(0x3c5, par); | ||
649 | vga_out8(0x3c4, 0x30, par); | ||
650 | reg->SR30 = vga_in8(0x3c5, par); | ||
651 | vga_out8(0x3c4, 0x18, par); | ||
652 | reg->SR18 = vga_in8(0x3c5, par); | ||
653 | |||
654 | /* Save flat panel expansion regsters. */ | ||
655 | if (par->chip == S3_SAVAGE_MX) { | ||
656 | int i; | ||
657 | |||
658 | for (i = 0; i < 8; i++) { | ||
659 | vga_out8(0x3c4, 0x54+i, par); | ||
660 | reg->SR54[i] = vga_in8(0x3c5, par); | ||
661 | } | ||
662 | } | ||
663 | |||
664 | vga_out8(0x3d4, 0x66, par); | ||
665 | cr66 = vga_in8(0x3d5, par); | ||
666 | vga_out8(0x3d5, cr66 | 0x80, par); | ||
667 | vga_out8(0x3d4, 0x3a, par); | ||
668 | cr3a = vga_in8(0x3d5, par); | ||
669 | vga_out8(0x3d5, cr3a | 0x80, par); | ||
670 | |||
671 | /* now save MIU regs */ | ||
672 | if (par->chip != S3_SAVAGE_MX) { | ||
673 | reg->MMPR0 = savage_in32(FIFO_CONTROL_REG, par); | ||
674 | reg->MMPR1 = savage_in32(MIU_CONTROL_REG, par); | ||
675 | reg->MMPR2 = savage_in32(STREAMS_TIMEOUT_REG, par); | ||
676 | reg->MMPR3 = savage_in32(MISC_TIMEOUT_REG, par); | ||
677 | } | ||
678 | |||
679 | vga_out8(0x3d4, 0x3a, par); | ||
680 | vga_out8(0x3d5, cr3a, par); | ||
681 | vga_out8(0x3d4, 0x66, par); | ||
682 | vga_out8(0x3d5, cr66, par); | ||
683 | } | ||
684 | |||
685 | static void savage_set_default_par(struct savagefb_par *par, | ||
686 | struct savage_reg *reg) | ||
687 | { | ||
688 | unsigned char cr3a, cr53, cr66; | ||
689 | |||
690 | vga_out16(0x3d4, 0x4838, par); | ||
691 | vga_out16(0x3d4, 0xa039, par); | ||
692 | vga_out16(0x3c4, 0x0608, par); | ||
693 | |||
694 | vga_out8(0x3d4, 0x66, par); | ||
695 | cr66 = vga_in8(0x3d5, par); | ||
696 | vga_out8(0x3d5, cr66 | 0x80, par); | ||
697 | vga_out8(0x3d4, 0x3a, par); | ||
698 | cr3a = vga_in8(0x3d5, par); | ||
699 | vga_out8(0x3d5, cr3a | 0x80, par); | ||
700 | vga_out8(0x3d4, 0x53, par); | ||
701 | cr53 = vga_in8(0x3d5, par); | ||
702 | vga_out8(0x3d5, cr53 & 0x7f, par); | ||
703 | |||
704 | vga_out8(0x3d4, 0x66, par); | ||
705 | vga_out8(0x3d5, cr66, par); | ||
706 | vga_out8(0x3d4, 0x3a, par); | ||
707 | vga_out8(0x3d5, cr3a, par); | ||
708 | |||
709 | vga_out8(0x3d4, 0x66, par); | ||
710 | vga_out8(0x3d5, cr66, par); | ||
711 | vga_out8(0x3d4, 0x3a, par); | ||
712 | vga_out8(0x3d5, cr3a, par); | ||
713 | |||
714 | /* unlock extended seq regs */ | ||
715 | vga_out8(0x3c4, 0x08, par); | ||
716 | vga_out8(0x3c5, reg->SR08, par); | ||
717 | vga_out8(0x3c5, 0x06, par); | ||
718 | |||
719 | /* now restore all the extended regs we need */ | ||
720 | vga_out8(0x3d4, 0x31, par); | ||
721 | vga_out8(0x3d5, reg->CR31, par); | ||
722 | vga_out8(0x3d4, 0x32, par); | ||
723 | vga_out8(0x3d5, reg->CR32, par); | ||
724 | vga_out8(0x3d4, 0x34, par); | ||
725 | vga_out8(0x3d5, reg->CR34, par); | ||
726 | vga_out8(0x3d4, 0x36, par); | ||
727 | vga_out8(0x3d5,reg->CR36, par); | ||
728 | vga_out8(0x3d4, 0x3a, par); | ||
729 | vga_out8(0x3d5, reg->CR3A, par); | ||
730 | vga_out8(0x3d4, 0x40, par); | ||
731 | vga_out8(0x3d5, reg->CR40, par); | ||
732 | vga_out8(0x3d4, 0x42, par); | ||
733 | vga_out8(0x3d5, reg->CR42, par); | ||
734 | vga_out8(0x3d4, 0x45, par); | ||
735 | vga_out8(0x3d5, reg->CR45, par); | ||
736 | vga_out8(0x3d4, 0x50, par); | ||
737 | vga_out8(0x3d5, reg->CR50, par); | ||
738 | vga_out8(0x3d4, 0x51, par); | ||
739 | vga_out8(0x3d5, reg->CR51, par); | ||
740 | vga_out8(0x3d4, 0x53, par); | ||
741 | vga_out8(0x3d5, reg->CR53, par); | ||
742 | vga_out8(0x3d4, 0x58, par); | ||
743 | vga_out8(0x3d5, reg->CR58, par); | ||
744 | vga_out8(0x3d4, 0x60, par); | ||
745 | vga_out8(0x3d5, reg->CR60, par); | ||
746 | vga_out8(0x3d4, 0x66, par); | ||
747 | vga_out8(0x3d5, reg->CR66, par); | ||
748 | vga_out8(0x3d4, 0x67, par); | ||
749 | vga_out8(0x3d5, reg->CR67, par); | ||
750 | vga_out8(0x3d4, 0x68, par); | ||
751 | vga_out8(0x3d5, reg->CR68, par); | ||
752 | vga_out8(0x3d4, 0x69, par); | ||
753 | vga_out8(0x3d5, reg->CR69, par); | ||
754 | vga_out8(0x3d4, 0x6f, par); | ||
755 | vga_out8(0x3d5, reg->CR6F, par); | ||
756 | |||
757 | vga_out8(0x3d4, 0x33, par); | ||
758 | vga_out8(0x3d5, reg->CR33, par); | ||
759 | vga_out8(0x3d4, 0x86, par); | ||
760 | vga_out8(0x3d5, reg->CR86, par); | ||
761 | vga_out8(0x3d4, 0x88, par); | ||
762 | vga_out8(0x3d5, reg->CR88, par); | ||
763 | vga_out8(0x3d4, 0x90, par); | ||
764 | vga_out8(0x3d5, reg->CR90, par); | ||
765 | vga_out8(0x3d4, 0x91, par); | ||
766 | vga_out8(0x3d5, reg->CR91, par); | ||
767 | vga_out8(0x3d4, 0xb0, par); | ||
768 | vga_out8(0x3d5, reg->CRB0, par); | ||
599 | 769 | ||
600 | /* extended mode timing regs */ | 770 | /* extended mode timing regs */ |
601 | vga_out8 (0x3d4, 0x3b, par); | 771 | vga_out8(0x3d4, 0x3b, par); |
602 | par->CR3B = vga_in8 (0x3d5, par); | 772 | vga_out8(0x3d5, reg->CR3B, par); |
603 | vga_out8 (0x3d4, 0x3c, par); | 773 | vga_out8(0x3d4, 0x3c, par); |
604 | par->CR3C = vga_in8 (0x3d5, par); | 774 | vga_out8(0x3d5, reg->CR3C, par); |
605 | vga_out8 (0x3d4, 0x43, par); | 775 | vga_out8(0x3d4, 0x43, par); |
606 | par->CR43 = vga_in8 (0x3d5, par); | 776 | vga_out8(0x3d5, reg->CR43, par); |
607 | vga_out8 (0x3d4, 0x5d, par); | 777 | vga_out8(0x3d4, 0x5d, par); |
608 | par->CR5D = vga_in8 (0x3d5, par); | 778 | vga_out8(0x3d5, reg->CR5D, par); |
609 | vga_out8 (0x3d4, 0x5e, par); | 779 | vga_out8(0x3d4, 0x5e, par); |
610 | par->CR5E = vga_in8 (0x3d5, par); | 780 | vga_out8(0x3d5, reg->CR5E, par); |
611 | vga_out8 (0x3d4, 0x65, par); | 781 | vga_out8(0x3d4, 0x65, par); |
612 | par->CR65 = vga_in8 (0x3d5, par); | 782 | vga_out8(0x3d5, reg->CR65, par); |
613 | 783 | ||
614 | /* save seq extended regs for DCLK PLL programming */ | 784 | /* save seq extended regs for DCLK PLL programming */ |
615 | vga_out8 (0x3c4, 0x0e, par); | 785 | vga_out8(0x3c4, 0x0e, par); |
616 | par->SR0E = vga_in8 (0x3c5, par); | 786 | vga_out8(0x3c5, reg->SR0E, par); |
617 | vga_out8 (0x3c4, 0x0f, par); | 787 | vga_out8(0x3c4, 0x0f, par); |
618 | par->SR0F = vga_in8 (0x3c5, par); | 788 | vga_out8(0x3c5, reg->SR0F, par); |
619 | vga_out8 (0x3c4, 0x10, par); | 789 | vga_out8(0x3c4, 0x10, par); |
620 | par->SR10 = vga_in8 (0x3c5, par); | 790 | vga_out8(0x3c5, reg->SR10, par); |
621 | vga_out8 (0x3c4, 0x11, par); | 791 | vga_out8(0x3c4, 0x11, par); |
622 | par->SR11 = vga_in8 (0x3c5, par); | 792 | vga_out8(0x3c5, reg->SR11, par); |
623 | vga_out8 (0x3c4, 0x12, par); | 793 | vga_out8(0x3c4, 0x12, par); |
624 | par->SR12 = vga_in8 (0x3c5, par); | 794 | vga_out8(0x3c5, reg->SR12, par); |
625 | vga_out8 (0x3c4, 0x13, par); | 795 | vga_out8(0x3c4, 0x13, par); |
626 | par->SR13 = vga_in8 (0x3c5, par); | 796 | vga_out8(0x3c5, reg->SR13, par); |
627 | vga_out8 (0x3c4, 0x29, par); | 797 | vga_out8(0x3c4, 0x29, par); |
628 | par->SR29 = vga_in8 (0x3c5, par); | 798 | vga_out8(0x3c5, reg->SR29, par); |
629 | 799 | ||
630 | vga_out8 (0x3c4, 0x15, par); | 800 | vga_out8(0x3c4, 0x15, par); |
631 | par->SR15 = vga_in8 (0x3c5, par); | 801 | vga_out8(0x3c5, reg->SR15, par); |
632 | vga_out8 (0x3c4, 0x30, par); | 802 | vga_out8(0x3c4, 0x30, par); |
633 | par->SR30 = vga_in8 (0x3c5, par); | 803 | vga_out8(0x3c5, reg->SR30, par); |
634 | vga_out8 (0x3c4, 0x18, par); | 804 | vga_out8(0x3c4, 0x18, par); |
635 | par->SR18 = vga_in8 (0x3c5, par); | 805 | vga_out8(0x3c5, reg->SR18, par); |
636 | 806 | ||
637 | /* Save flat panel expansion regsters. */ | 807 | /* Save flat panel expansion regsters. */ |
638 | if (par->chip == S3_SAVAGE_MX) { | 808 | if (par->chip == S3_SAVAGE_MX) { |
639 | int i; | 809 | int i; |
640 | 810 | ||
641 | for (i = 0; i < 8; i++) { | 811 | for (i = 0; i < 8; i++) { |
642 | vga_out8 (0x3c4, 0x54+i, par); | 812 | vga_out8(0x3c4, 0x54+i, par); |
643 | par->SR54[i] = vga_in8 (0x3c5, par); | 813 | vga_out8(0x3c5, reg->SR54[i], par); |
644 | } | 814 | } |
645 | } | 815 | } |
646 | 816 | ||
647 | vga_out8 (0x3d4, 0x66, par); | 817 | vga_out8(0x3d4, 0x66, par); |
648 | cr66 = vga_in8 (0x3d5, par); | 818 | cr66 = vga_in8(0x3d5, par); |
649 | vga_out8 (0x3d5, cr66 | 0x80, par); | 819 | vga_out8(0x3d5, cr66 | 0x80, par); |
650 | vga_out8 (0x3d4, 0x3a, par); | 820 | vga_out8(0x3d4, 0x3a, par); |
651 | cr3a = vga_in8 (0x3d5, par); | 821 | cr3a = vga_in8(0x3d5, par); |
652 | vga_out8 (0x3d5, cr3a | 0x80, par); | 822 | vga_out8(0x3d5, cr3a | 0x80, par); |
653 | 823 | ||
654 | /* now save MIU regs */ | 824 | /* now save MIU regs */ |
655 | if (par->chip != S3_SAVAGE_MX) { | 825 | if (par->chip != S3_SAVAGE_MX) { |
656 | par->MMPR0 = savage_in32(FIFO_CONTROL_REG, par); | 826 | savage_out32(FIFO_CONTROL_REG, reg->MMPR0, par); |
657 | par->MMPR1 = savage_in32(MIU_CONTROL_REG, par); | 827 | savage_out32(MIU_CONTROL_REG, reg->MMPR1, par); |
658 | par->MMPR2 = savage_in32(STREAMS_TIMEOUT_REG, par); | 828 | savage_out32(STREAMS_TIMEOUT_REG, reg->MMPR2, par); |
659 | par->MMPR3 = savage_in32(MISC_TIMEOUT_REG, par); | 829 | savage_out32(MISC_TIMEOUT_REG, reg->MMPR3, par); |
660 | } | 830 | } |
661 | 831 | ||
662 | vga_out8 (0x3d4, 0x3a, par); | 832 | vga_out8(0x3d4, 0x3a, par); |
663 | vga_out8 (0x3d5, cr3a, par); | 833 | vga_out8(0x3d5, cr3a, par); |
664 | vga_out8 (0x3d4, 0x66, par); | 834 | vga_out8(0x3d4, 0x66, par); |
665 | vga_out8 (0x3d5, cr66, par); | 835 | vga_out8(0x3d5, cr66, par); |
666 | } | 836 | } |
667 | 837 | ||
668 | static void savage_update_var(struct fb_var_screeninfo *var, struct fb_videomode *modedb) | 838 | static void savage_update_var(struct fb_var_screeninfo *var, struct fb_videomode *modedb) |
@@ -683,8 +853,8 @@ static void savage_update_var(struct fb_var_screeninfo *var, struct fb_videomode | |||
683 | var->vmode = modedb->vmode; | 853 | var->vmode = modedb->vmode; |
684 | } | 854 | } |
685 | 855 | ||
686 | static int savagefb_check_var (struct fb_var_screeninfo *var, | 856 | static int savagefb_check_var(struct fb_var_screeninfo *var, |
687 | struct fb_info *info) | 857 | struct fb_info *info) |
688 | { | 858 | { |
689 | struct savagefb_par *par = info->par; | 859 | struct savagefb_par *par = info->par; |
690 | int memlen, vramlen, mode_valid = 0; | 860 | int memlen, vramlen, mode_valid = 0; |
@@ -750,10 +920,10 @@ static int savagefb_check_var (struct fb_var_screeninfo *var, | |||
750 | if (par->SavagePanelWidth && | 920 | if (par->SavagePanelWidth && |
751 | (var->xres > par->SavagePanelWidth || | 921 | (var->xres > par->SavagePanelWidth || |
752 | var->yres > par->SavagePanelHeight)) { | 922 | var->yres > par->SavagePanelHeight)) { |
753 | printk (KERN_INFO "Mode (%dx%d) larger than the LCD panel " | 923 | printk(KERN_INFO "Mode (%dx%d) larger than the LCD panel " |
754 | "(%dx%d)\n", var->xres, var->yres, | 924 | "(%dx%d)\n", var->xres, var->yres, |
755 | par->SavagePanelWidth, | 925 | par->SavagePanelWidth, |
756 | par->SavagePanelHeight); | 926 | par->SavagePanelHeight); |
757 | return -1; | 927 | return -1; |
758 | } | 928 | } |
759 | 929 | ||
@@ -788,8 +958,9 @@ static int savagefb_check_var (struct fb_var_screeninfo *var, | |||
788 | } | 958 | } |
789 | 959 | ||
790 | 960 | ||
791 | static int savagefb_decode_var (struct fb_var_screeninfo *var, | 961 | static int savagefb_decode_var(struct fb_var_screeninfo *var, |
792 | struct savagefb_par *par) | 962 | struct savagefb_par *par, |
963 | struct savage_reg *reg) | ||
793 | { | 964 | { |
794 | struct xtimings timings; | 965 | struct xtimings timings; |
795 | int width, dclk, i, j; /*, refresh; */ | 966 | int width, dclk, i, j; /*, refresh; */ |
@@ -799,7 +970,7 @@ static int savagefb_decode_var (struct fb_var_screeninfo *var, | |||
799 | 970 | ||
800 | DBG("savagefb_decode_var"); | 971 | DBG("savagefb_decode_var"); |
801 | 972 | ||
802 | memset (&timings, 0, sizeof(timings)); | 973 | memset(&timings, 0, sizeof(timings)); |
803 | 974 | ||
804 | if (!pixclock) pixclock = 10000; /* 10ns = 100MHz */ | 975 | if (!pixclock) pixclock = 10000; /* 10ns = 100MHz */ |
805 | timings.Clock = 1000000000 / pixclock; | 976 | timings.Clock = 1000000000 / pixclock; |
@@ -831,39 +1002,39 @@ static int savagefb_decode_var (struct fb_var_screeninfo *var, | |||
831 | * This will allocate the datastructure and initialize all of the | 1002 | * This will allocate the datastructure and initialize all of the |
832 | * generic VGA registers. | 1003 | * generic VGA registers. |
833 | */ | 1004 | */ |
834 | vgaHWInit (var, par, &timings); | 1005 | vgaHWInit(var, par, &timings, reg); |
835 | 1006 | ||
836 | /* We need to set CR67 whether or not we use the BIOS. */ | 1007 | /* We need to set CR67 whether or not we use the BIOS. */ |
837 | 1008 | ||
838 | dclk = timings.Clock; | 1009 | dclk = timings.Clock; |
839 | par->CR67 = 0x00; | 1010 | reg->CR67 = 0x00; |
840 | 1011 | ||
841 | switch( var->bits_per_pixel ) { | 1012 | switch(var->bits_per_pixel) { |
842 | case 8: | 1013 | case 8: |
843 | if( (par->chip == S3_SAVAGE2000) && (dclk >= 230000) ) | 1014 | if ((par->chip == S3_SAVAGE2000) && (dclk >= 230000)) |
844 | par->CR67 = 0x10; /* 8bpp, 2 pixels/clock */ | 1015 | reg->CR67 = 0x10; /* 8bpp, 2 pixels/clock */ |
845 | else | 1016 | else |
846 | par->CR67 = 0x00; /* 8bpp, 1 pixel/clock */ | 1017 | reg->CR67 = 0x00; /* 8bpp, 1 pixel/clock */ |
847 | break; | 1018 | break; |
848 | case 15: | 1019 | case 15: |
849 | if ( S3_SAVAGE_MOBILE_SERIES(par->chip) || | 1020 | if (S3_SAVAGE_MOBILE_SERIES(par->chip) || |
850 | ((par->chip == S3_SAVAGE2000) && (dclk >= 230000)) ) | 1021 | ((par->chip == S3_SAVAGE2000) && (dclk >= 230000))) |
851 | par->CR67 = 0x30; /* 15bpp, 2 pixel/clock */ | 1022 | reg->CR67 = 0x30; /* 15bpp, 2 pixel/clock */ |
852 | else | 1023 | else |
853 | par->CR67 = 0x20; /* 15bpp, 1 pixels/clock */ | 1024 | reg->CR67 = 0x20; /* 15bpp, 1 pixels/clock */ |
854 | break; | 1025 | break; |
855 | case 16: | 1026 | case 16: |
856 | if( S3_SAVAGE_MOBILE_SERIES(par->chip) || | 1027 | if (S3_SAVAGE_MOBILE_SERIES(par->chip) || |
857 | ((par->chip == S3_SAVAGE2000) && (dclk >= 230000)) ) | 1028 | ((par->chip == S3_SAVAGE2000) && (dclk >= 230000))) |
858 | par->CR67 = 0x50; /* 16bpp, 2 pixel/clock */ | 1029 | reg->CR67 = 0x50; /* 16bpp, 2 pixel/clock */ |
859 | else | 1030 | else |
860 | par->CR67 = 0x40; /* 16bpp, 1 pixels/clock */ | 1031 | reg->CR67 = 0x40; /* 16bpp, 1 pixels/clock */ |
861 | break; | 1032 | break; |
862 | case 24: | 1033 | case 24: |
863 | par->CR67 = 0x70; | 1034 | reg->CR67 = 0x70; |
864 | break; | 1035 | break; |
865 | case 32: | 1036 | case 32: |
866 | par->CR67 = 0xd0; | 1037 | reg->CR67 = 0xd0; |
867 | break; | 1038 | break; |
868 | } | 1039 | } |
869 | 1040 | ||
@@ -872,61 +1043,61 @@ static int savagefb_decode_var (struct fb_var_screeninfo *var, | |||
872 | * match. Fall back to traditional register-crunching. | 1043 | * match. Fall back to traditional register-crunching. |
873 | */ | 1044 | */ |
874 | 1045 | ||
875 | vga_out8 (0x3d4, 0x3a, par); | 1046 | vga_out8(0x3d4, 0x3a, par); |
876 | tmp = vga_in8 (0x3d5, par); | 1047 | tmp = vga_in8(0x3d5, par); |
877 | if (1 /*FIXME:psav->pci_burst*/) | 1048 | if (1 /*FIXME:psav->pci_burst*/) |
878 | par->CR3A = (tmp & 0x7f) | 0x15; | 1049 | reg->CR3A = (tmp & 0x7f) | 0x15; |
879 | else | 1050 | else |
880 | par->CR3A = tmp | 0x95; | 1051 | reg->CR3A = tmp | 0x95; |
881 | 1052 | ||
882 | par->CR53 = 0x00; | 1053 | reg->CR53 = 0x00; |
883 | par->CR31 = 0x8c; | 1054 | reg->CR31 = 0x8c; |
884 | par->CR66 = 0x89; | 1055 | reg->CR66 = 0x89; |
885 | 1056 | ||
886 | vga_out8 (0x3d4, 0x58, par); | 1057 | vga_out8(0x3d4, 0x58, par); |
887 | par->CR58 = vga_in8 (0x3d5, par) & 0x80; | 1058 | reg->CR58 = vga_in8(0x3d5, par) & 0x80; |
888 | par->CR58 |= 0x13; | 1059 | reg->CR58 |= 0x13; |
889 | 1060 | ||
890 | par->SR15 = 0x03 | 0x80; | 1061 | reg->SR15 = 0x03 | 0x80; |
891 | par->SR18 = 0x00; | 1062 | reg->SR18 = 0x00; |
892 | par->CR43 = par->CR45 = par->CR65 = 0x00; | 1063 | reg->CR43 = reg->CR45 = reg->CR65 = 0x00; |
893 | 1064 | ||
894 | vga_out8 (0x3d4, 0x40, par); | 1065 | vga_out8(0x3d4, 0x40, par); |
895 | par->CR40 = vga_in8 (0x3d5, par) & ~0x01; | 1066 | reg->CR40 = vga_in8(0x3d5, par) & ~0x01; |
896 | 1067 | ||
897 | par->MMPR0 = 0x010400; | 1068 | reg->MMPR0 = 0x010400; |
898 | par->MMPR1 = 0x00; | 1069 | reg->MMPR1 = 0x00; |
899 | par->MMPR2 = 0x0808; | 1070 | reg->MMPR2 = 0x0808; |
900 | par->MMPR3 = 0x08080810; | 1071 | reg->MMPR3 = 0x08080810; |
901 | 1072 | ||
902 | SavageCalcClock (dclk, 1, 1, 127, 0, 4, 180000, 360000, &m, &n, &r); | 1073 | SavageCalcClock(dclk, 1, 1, 127, 0, 4, 180000, 360000, &m, &n, &r); |
903 | /* m = 107; n = 4; r = 2; */ | 1074 | /* m = 107; n = 4; r = 2; */ |
904 | 1075 | ||
905 | if (par->MCLK <= 0) { | 1076 | if (par->MCLK <= 0) { |
906 | par->SR10 = 255; | 1077 | reg->SR10 = 255; |
907 | par->SR11 = 255; | 1078 | reg->SR11 = 255; |
908 | } else { | 1079 | } else { |
909 | common_calc_clock (par->MCLK, 1, 1, 31, 0, 3, 135000, 270000, | 1080 | common_calc_clock(par->MCLK, 1, 1, 31, 0, 3, 135000, 270000, |
910 | &par->SR11, &par->SR10); | 1081 | ®->SR11, ®->SR10); |
911 | /* par->SR10 = 80; // MCLK == 286000 */ | 1082 | /* reg->SR10 = 80; // MCLK == 286000 */ |
912 | /* par->SR11 = 125; */ | 1083 | /* reg->SR11 = 125; */ |
913 | } | 1084 | } |
914 | 1085 | ||
915 | par->SR12 = (r << 6) | (n & 0x3f); | 1086 | reg->SR12 = (r << 6) | (n & 0x3f); |
916 | par->SR13 = m & 0xff; | 1087 | reg->SR13 = m & 0xff; |
917 | par->SR29 = (r & 4) | (m & 0x100) >> 5 | (n & 0x40) >> 2; | 1088 | reg->SR29 = (r & 4) | (m & 0x100) >> 5 | (n & 0x40) >> 2; |
918 | 1089 | ||
919 | if (var->bits_per_pixel < 24) | 1090 | if (var->bits_per_pixel < 24) |
920 | par->MMPR0 -= 0x8000; | 1091 | reg->MMPR0 -= 0x8000; |
921 | else | 1092 | else |
922 | par->MMPR0 -= 0x4000; | 1093 | reg->MMPR0 -= 0x4000; |
923 | 1094 | ||
924 | if (timings.interlaced) | 1095 | if (timings.interlaced) |
925 | par->CR42 = 0x20; | 1096 | reg->CR42 = 0x20; |
926 | else | 1097 | else |
927 | par->CR42 = 0x00; | 1098 | reg->CR42 = 0x00; |
928 | 1099 | ||
929 | par->CR34 = 0x10; /* display fifo */ | 1100 | reg->CR34 = 0x10; /* display fifo */ |
930 | 1101 | ||
931 | i = ((((timings.HTotal >> 3) - 5) & 0x100) >> 8) | | 1102 | i = ((((timings.HTotal >> 3) - 5) & 0x100) >> 8) | |
932 | ((((timings.HDisplay >> 3) - 1) & 0x100) >> 7) | | 1103 | ((((timings.HDisplay >> 3) - 1) & 0x100) >> 7) | |
@@ -938,77 +1109,77 @@ static int savagefb_decode_var (struct fb_var_screeninfo *var, | |||
938 | if ((timings.HSyncEnd >> 3) - (timings.HSyncStart >> 3) > 32) | 1109 | if ((timings.HSyncEnd >> 3) - (timings.HSyncStart >> 3) > 32) |
939 | i |= 0x20; | 1110 | i |= 0x20; |
940 | 1111 | ||
941 | j = (par->CRTC[0] + ((i & 0x01) << 8) + | 1112 | j = (reg->CRTC[0] + ((i & 0x01) << 8) + |
942 | par->CRTC[4] + ((i & 0x10) << 4) + 1) / 2; | 1113 | reg->CRTC[4] + ((i & 0x10) << 4) + 1) / 2; |
943 | 1114 | ||
944 | if (j - (par->CRTC[4] + ((i & 0x10) << 4)) < 4) { | 1115 | if (j - (reg->CRTC[4] + ((i & 0x10) << 4)) < 4) { |
945 | if (par->CRTC[4] + ((i & 0x10) << 4) + 4 <= | 1116 | if (reg->CRTC[4] + ((i & 0x10) << 4) + 4 <= |
946 | par->CRTC[0] + ((i & 0x01) << 8)) | 1117 | reg->CRTC[0] + ((i & 0x01) << 8)) |
947 | j = par->CRTC[4] + ((i & 0x10) << 4) + 4; | 1118 | j = reg->CRTC[4] + ((i & 0x10) << 4) + 4; |
948 | else | 1119 | else |
949 | j = par->CRTC[0] + ((i & 0x01) << 8) + 1; | 1120 | j = reg->CRTC[0] + ((i & 0x01) << 8) + 1; |
950 | } | 1121 | } |
951 | 1122 | ||
952 | par->CR3B = j & 0xff; | 1123 | reg->CR3B = j & 0xff; |
953 | i |= (j & 0x100) >> 2; | 1124 | i |= (j & 0x100) >> 2; |
954 | par->CR3C = (par->CRTC[0] + ((i & 0x01) << 8)) / 2; | 1125 | reg->CR3C = (reg->CRTC[0] + ((i & 0x01) << 8)) / 2; |
955 | par->CR5D = i; | 1126 | reg->CR5D = i; |
956 | par->CR5E = (((timings.VTotal - 2) & 0x400) >> 10) | | 1127 | reg->CR5E = (((timings.VTotal - 2) & 0x400) >> 10) | |
957 | (((timings.VDisplay - 1) & 0x400) >> 9) | | 1128 | (((timings.VDisplay - 1) & 0x400) >> 9) | |
958 | (((timings.VSyncStart) & 0x400) >> 8) | | 1129 | (((timings.VSyncStart) & 0x400) >> 8) | |
959 | (((timings.VSyncStart) & 0x400) >> 6) | 0x40; | 1130 | (((timings.VSyncStart) & 0x400) >> 6) | 0x40; |
960 | width = (var->xres_virtual * ((var->bits_per_pixel+7) / 8)) >> 3; | 1131 | width = (var->xres_virtual * ((var->bits_per_pixel+7) / 8)) >> 3; |
961 | par->CR91 = par->CRTC[19] = 0xff & width; | 1132 | reg->CR91 = reg->CRTC[19] = 0xff & width; |
962 | par->CR51 = (0x300 & width) >> 4; | 1133 | reg->CR51 = (0x300 & width) >> 4; |
963 | par->CR90 = 0x80 | (width >> 8); | 1134 | reg->CR90 = 0x80 | (width >> 8); |
964 | par->MiscOutReg |= 0x0c; | 1135 | reg->MiscOutReg |= 0x0c; |
965 | 1136 | ||
966 | /* Set frame buffer description. */ | 1137 | /* Set frame buffer description. */ |
967 | 1138 | ||
968 | if (var->bits_per_pixel <= 8) | 1139 | if (var->bits_per_pixel <= 8) |
969 | par->CR50 = 0; | 1140 | reg->CR50 = 0; |
970 | else if (var->bits_per_pixel <= 16) | 1141 | else if (var->bits_per_pixel <= 16) |
971 | par->CR50 = 0x10; | 1142 | reg->CR50 = 0x10; |
972 | else | 1143 | else |
973 | par->CR50 = 0x30; | 1144 | reg->CR50 = 0x30; |
974 | 1145 | ||
975 | if (var->xres_virtual <= 640) | 1146 | if (var->xres_virtual <= 640) |
976 | par->CR50 |= 0x40; | 1147 | reg->CR50 |= 0x40; |
977 | else if (var->xres_virtual == 800) | 1148 | else if (var->xres_virtual == 800) |
978 | par->CR50 |= 0x80; | 1149 | reg->CR50 |= 0x80; |
979 | else if (var->xres_virtual == 1024) | 1150 | else if (var->xres_virtual == 1024) |
980 | par->CR50 |= 0x00; | 1151 | reg->CR50 |= 0x00; |
981 | else if (var->xres_virtual == 1152) | 1152 | else if (var->xres_virtual == 1152) |
982 | par->CR50 |= 0x01; | 1153 | reg->CR50 |= 0x01; |
983 | else if (var->xres_virtual == 1280) | 1154 | else if (var->xres_virtual == 1280) |
984 | par->CR50 |= 0xc0; | 1155 | reg->CR50 |= 0xc0; |
985 | else if (var->xres_virtual == 1600) | 1156 | else if (var->xres_virtual == 1600) |
986 | par->CR50 |= 0x81; | 1157 | reg->CR50 |= 0x81; |
987 | else | 1158 | else |
988 | par->CR50 |= 0xc1; /* Use GBD */ | 1159 | reg->CR50 |= 0xc1; /* Use GBD */ |
989 | 1160 | ||
990 | if( par->chip == S3_SAVAGE2000 ) | 1161 | if (par->chip == S3_SAVAGE2000) |
991 | par->CR33 = 0x08; | 1162 | reg->CR33 = 0x08; |
992 | else | 1163 | else |
993 | par->CR33 = 0x20; | 1164 | reg->CR33 = 0x20; |
994 | 1165 | ||
995 | par->CRTC[0x17] = 0xeb; | 1166 | reg->CRTC[0x17] = 0xeb; |
996 | 1167 | ||
997 | par->CR67 |= 1; | 1168 | reg->CR67 |= 1; |
998 | 1169 | ||
999 | vga_out8(0x3d4, 0x36, par); | 1170 | vga_out8(0x3d4, 0x36, par); |
1000 | par->CR36 = vga_in8 (0x3d5, par); | 1171 | reg->CR36 = vga_in8(0x3d5, par); |
1001 | vga_out8 (0x3d4, 0x68, par); | 1172 | vga_out8(0x3d4, 0x68, par); |
1002 | par->CR68 = vga_in8 (0x3d5, par); | 1173 | reg->CR68 = vga_in8(0x3d5, par); |
1003 | par->CR69 = 0; | 1174 | reg->CR69 = 0; |
1004 | vga_out8 (0x3d4, 0x6f, par); | 1175 | vga_out8(0x3d4, 0x6f, par); |
1005 | par->CR6F = vga_in8 (0x3d5, par); | 1176 | reg->CR6F = vga_in8(0x3d5, par); |
1006 | vga_out8 (0x3d4, 0x86, par); | 1177 | vga_out8(0x3d4, 0x86, par); |
1007 | par->CR86 = vga_in8 (0x3d5, par); | 1178 | reg->CR86 = vga_in8(0x3d5, par); |
1008 | vga_out8 (0x3d4, 0x88, par); | 1179 | vga_out8(0x3d4, 0x88, par); |
1009 | par->CR88 = vga_in8 (0x3d5, par) | 0x08; | 1180 | reg->CR88 = vga_in8(0x3d5, par) | 0x08; |
1010 | vga_out8 (0x3d4, 0xb0, par); | 1181 | vga_out8(0x3d4, 0xb0, par); |
1011 | par->CRB0 = vga_in8 (0x3d5, par) | 0x80; | 1182 | reg->CRB0 = vga_in8(0x3d5, par) | 0x80; |
1012 | 1183 | ||
1013 | return 0; | 1184 | return 0; |
1014 | } | 1185 | } |
@@ -1037,11 +1208,11 @@ static int savagefb_setcolreg(unsigned regno, | |||
1037 | 1208 | ||
1038 | switch (info->var.bits_per_pixel) { | 1209 | switch (info->var.bits_per_pixel) { |
1039 | case 8: | 1210 | case 8: |
1040 | vga_out8 (0x3c8, regno, par); | 1211 | vga_out8(0x3c8, regno, par); |
1041 | 1212 | ||
1042 | vga_out8 (0x3c9, red >> 10, par); | 1213 | vga_out8(0x3c9, red >> 10, par); |
1043 | vga_out8 (0x3c9, green >> 10, par); | 1214 | vga_out8(0x3c9, green >> 10, par); |
1044 | vga_out8 (0x3c9, blue >> 10, par); | 1215 | vga_out8(0x3c9, blue >> 10, par); |
1045 | break; | 1216 | break; |
1046 | 1217 | ||
1047 | case 16: | 1218 | case 16: |
@@ -1075,21 +1246,21 @@ static int savagefb_setcolreg(unsigned regno, | |||
1075 | return 0; | 1246 | return 0; |
1076 | } | 1247 | } |
1077 | 1248 | ||
1078 | static void savagefb_set_par_int (struct savagefb_par *par) | 1249 | static void savagefb_set_par_int(struct savagefb_par *par, struct savage_reg *reg) |
1079 | { | 1250 | { |
1080 | unsigned char tmp, cr3a, cr66, cr67; | 1251 | unsigned char tmp, cr3a, cr66, cr67; |
1081 | 1252 | ||
1082 | DBG ("savagefb_set_par_int"); | 1253 | DBG("savagefb_set_par_int"); |
1083 | 1254 | ||
1084 | par->SavageWaitIdle (par); | 1255 | par->SavageWaitIdle(par); |
1085 | 1256 | ||
1086 | vga_out8 (0x3c2, 0x23, par); | 1257 | vga_out8(0x3c2, 0x23, par); |
1087 | 1258 | ||
1088 | vga_out16 (0x3d4, 0x4838, par); | 1259 | vga_out16(0x3d4, 0x4838, par); |
1089 | vga_out16 (0x3d4, 0xa539, par); | 1260 | vga_out16(0x3d4, 0xa539, par); |
1090 | vga_out16 (0x3c4, 0x0608, par); | 1261 | vga_out16(0x3c4, 0x0608, par); |
1091 | 1262 | ||
1092 | vgaHWProtect (par, 1); | 1263 | vgaHWProtect(par, 1); |
1093 | 1264 | ||
1094 | /* | 1265 | /* |
1095 | * Some Savage/MX and /IX systems go nuts when trying to exit the | 1266 | * Some Savage/MX and /IX systems go nuts when trying to exit the |
@@ -1099,203 +1270,202 @@ static void savagefb_set_par_int (struct savagefb_par *par) | |||
1099 | */ | 1270 | */ |
1100 | 1271 | ||
1101 | VerticalRetraceWait(par); | 1272 | VerticalRetraceWait(par); |
1102 | vga_out8 (0x3d4, 0x67, par); | 1273 | vga_out8(0x3d4, 0x67, par); |
1103 | cr67 = vga_in8 (0x3d5, par); | 1274 | cr67 = vga_in8(0x3d5, par); |
1104 | vga_out8 (0x3d5, cr67/*par->CR67*/ & ~0x0c, par); /* no STREAMS yet */ | 1275 | vga_out8(0x3d5, cr67/*par->CR67*/ & ~0x0c, par); /* no STREAMS yet */ |
1105 | 1276 | ||
1106 | vga_out8 (0x3d4, 0x23, par); | 1277 | vga_out8(0x3d4, 0x23, par); |
1107 | vga_out8 (0x3d5, 0x00, par); | 1278 | vga_out8(0x3d5, 0x00, par); |
1108 | vga_out8 (0x3d4, 0x26, par); | 1279 | vga_out8(0x3d4, 0x26, par); |
1109 | vga_out8 (0x3d5, 0x00, par); | 1280 | vga_out8(0x3d5, 0x00, par); |
1110 | 1281 | ||
1111 | /* restore extended regs */ | 1282 | /* restore extended regs */ |
1112 | vga_out8 (0x3d4, 0x66, par); | 1283 | vga_out8(0x3d4, 0x66, par); |
1113 | vga_out8 (0x3d5, par->CR66, par); | 1284 | vga_out8(0x3d5, reg->CR66, par); |
1114 | vga_out8 (0x3d4, 0x3a, par); | 1285 | vga_out8(0x3d4, 0x3a, par); |
1115 | vga_out8 (0x3d5, par->CR3A, par); | 1286 | vga_out8(0x3d5, reg->CR3A, par); |
1116 | vga_out8 (0x3d4, 0x31, par); | 1287 | vga_out8(0x3d4, 0x31, par); |
1117 | vga_out8 (0x3d5, par->CR31, par); | 1288 | vga_out8(0x3d5, reg->CR31, par); |
1118 | vga_out8 (0x3d4, 0x32, par); | 1289 | vga_out8(0x3d4, 0x32, par); |
1119 | vga_out8 (0x3d5, par->CR32, par); | 1290 | vga_out8(0x3d5, reg->CR32, par); |
1120 | vga_out8 (0x3d4, 0x58, par); | 1291 | vga_out8(0x3d4, 0x58, par); |
1121 | vga_out8 (0x3d5, par->CR58, par); | 1292 | vga_out8(0x3d5, reg->CR58, par); |
1122 | vga_out8 (0x3d4, 0x53, par); | 1293 | vga_out8(0x3d4, 0x53, par); |
1123 | vga_out8 (0x3d5, par->CR53 & 0x7f, par); | 1294 | vga_out8(0x3d5, reg->CR53 & 0x7f, par); |
1124 | 1295 | ||
1125 | vga_out16 (0x3c4, 0x0608, par); | 1296 | vga_out16(0x3c4, 0x0608, par); |
1126 | 1297 | ||
1127 | /* Restore DCLK registers. */ | 1298 | /* Restore DCLK registers. */ |
1128 | 1299 | ||
1129 | vga_out8 (0x3c4, 0x0e, par); | 1300 | vga_out8(0x3c4, 0x0e, par); |
1130 | vga_out8 (0x3c5, par->SR0E, par); | 1301 | vga_out8(0x3c5, reg->SR0E, par); |
1131 | vga_out8 (0x3c4, 0x0f, par); | 1302 | vga_out8(0x3c4, 0x0f, par); |
1132 | vga_out8 (0x3c5, par->SR0F, par); | 1303 | vga_out8(0x3c5, reg->SR0F, par); |
1133 | vga_out8 (0x3c4, 0x29, par); | 1304 | vga_out8(0x3c4, 0x29, par); |
1134 | vga_out8 (0x3c5, par->SR29, par); | 1305 | vga_out8(0x3c5, reg->SR29, par); |
1135 | vga_out8 (0x3c4, 0x15, par); | 1306 | vga_out8(0x3c4, 0x15, par); |
1136 | vga_out8 (0x3c5, par->SR15, par); | 1307 | vga_out8(0x3c5, reg->SR15, par); |
1137 | 1308 | ||
1138 | /* Restore flat panel expansion regsters. */ | 1309 | /* Restore flat panel expansion regsters. */ |
1139 | if( par->chip == S3_SAVAGE_MX ) { | 1310 | if (par->chip == S3_SAVAGE_MX) { |
1140 | int i; | 1311 | int i; |
1141 | 1312 | ||
1142 | for( i = 0; i < 8; i++ ) { | 1313 | for (i = 0; i < 8; i++) { |
1143 | vga_out8 (0x3c4, 0x54+i, par); | 1314 | vga_out8(0x3c4, 0x54+i, par); |
1144 | vga_out8 (0x3c5, par->SR54[i], par); | 1315 | vga_out8(0x3c5, reg->SR54[i], par); |
1145 | } | 1316 | } |
1146 | } | 1317 | } |
1147 | 1318 | ||
1148 | vgaHWRestore (par); | 1319 | vgaHWRestore (par, reg); |
1149 | 1320 | ||
1150 | /* extended mode timing registers */ | 1321 | /* extended mode timing registers */ |
1151 | vga_out8 (0x3d4, 0x53, par); | 1322 | vga_out8(0x3d4, 0x53, par); |
1152 | vga_out8 (0x3d5, par->CR53, par); | 1323 | vga_out8(0x3d5, reg->CR53, par); |
1153 | vga_out8 (0x3d4, 0x5d, par); | 1324 | vga_out8(0x3d4, 0x5d, par); |
1154 | vga_out8 (0x3d5, par->CR5D, par); | 1325 | vga_out8(0x3d5, reg->CR5D, par); |
1155 | vga_out8 (0x3d4, 0x5e, par); | 1326 | vga_out8(0x3d4, 0x5e, par); |
1156 | vga_out8 (0x3d5, par->CR5E, par); | 1327 | vga_out8(0x3d5, reg->CR5E, par); |
1157 | vga_out8 (0x3d4, 0x3b, par); | 1328 | vga_out8(0x3d4, 0x3b, par); |
1158 | vga_out8 (0x3d5, par->CR3B, par); | 1329 | vga_out8(0x3d5, reg->CR3B, par); |
1159 | vga_out8 (0x3d4, 0x3c, par); | 1330 | vga_out8(0x3d4, 0x3c, par); |
1160 | vga_out8 (0x3d5, par->CR3C, par); | 1331 | vga_out8(0x3d5, reg->CR3C, par); |
1161 | vga_out8 (0x3d4, 0x43, par); | 1332 | vga_out8(0x3d4, 0x43, par); |
1162 | vga_out8 (0x3d5, par->CR43, par); | 1333 | vga_out8(0x3d5, reg->CR43, par); |
1163 | vga_out8 (0x3d4, 0x65, par); | 1334 | vga_out8(0x3d4, 0x65, par); |
1164 | vga_out8 (0x3d5, par->CR65, par); | 1335 | vga_out8(0x3d5, reg->CR65, par); |
1165 | 1336 | ||
1166 | /* restore the desired video mode with cr67 */ | 1337 | /* restore the desired video mode with cr67 */ |
1167 | vga_out8 (0x3d4, 0x67, par); | 1338 | vga_out8(0x3d4, 0x67, par); |
1168 | /* following part not present in X11 driver */ | 1339 | /* following part not present in X11 driver */ |
1169 | cr67 = vga_in8 (0x3d5, par) & 0xf; | 1340 | cr67 = vga_in8(0x3d5, par) & 0xf; |
1170 | vga_out8 (0x3d5, 0x50 | cr67, par); | 1341 | vga_out8(0x3d5, 0x50 | cr67, par); |
1171 | udelay (10000); | 1342 | udelay(10000); |
1172 | vga_out8 (0x3d4, 0x67, par); | 1343 | vga_out8(0x3d4, 0x67, par); |
1173 | /* end of part */ | 1344 | /* end of part */ |
1174 | vga_out8 (0x3d5, par->CR67 & ~0x0c, par); | 1345 | vga_out8(0x3d5, reg->CR67 & ~0x0c, par); |
1175 | 1346 | ||
1176 | /* other mode timing and extended regs */ | 1347 | /* other mode timing and extended regs */ |
1177 | vga_out8 (0x3d4, 0x34, par); | 1348 | vga_out8(0x3d4, 0x34, par); |
1178 | vga_out8 (0x3d5, par->CR34, par); | 1349 | vga_out8(0x3d5, reg->CR34, par); |
1179 | vga_out8 (0x3d4, 0x40, par); | 1350 | vga_out8(0x3d4, 0x40, par); |
1180 | vga_out8 (0x3d5, par->CR40, par); | 1351 | vga_out8(0x3d5, reg->CR40, par); |
1181 | vga_out8 (0x3d4, 0x42, par); | 1352 | vga_out8(0x3d4, 0x42, par); |
1182 | vga_out8 (0x3d5, par->CR42, par); | 1353 | vga_out8(0x3d5, reg->CR42, par); |
1183 | vga_out8 (0x3d4, 0x45, par); | 1354 | vga_out8(0x3d4, 0x45, par); |
1184 | vga_out8 (0x3d5, par->CR45, par); | 1355 | vga_out8(0x3d5, reg->CR45, par); |
1185 | vga_out8 (0x3d4, 0x50, par); | 1356 | vga_out8(0x3d4, 0x50, par); |
1186 | vga_out8 (0x3d5, par->CR50, par); | 1357 | vga_out8(0x3d5, reg->CR50, par); |
1187 | vga_out8 (0x3d4, 0x51, par); | 1358 | vga_out8(0x3d4, 0x51, par); |
1188 | vga_out8 (0x3d5, par->CR51, par); | 1359 | vga_out8(0x3d5, reg->CR51, par); |
1189 | 1360 | ||
1190 | /* memory timings */ | 1361 | /* memory timings */ |
1191 | vga_out8 (0x3d4, 0x36, par); | 1362 | vga_out8(0x3d4, 0x36, par); |
1192 | vga_out8 (0x3d5, par->CR36, par); | 1363 | vga_out8(0x3d5, reg->CR36, par); |
1193 | vga_out8 (0x3d4, 0x60, par); | 1364 | vga_out8(0x3d4, 0x60, par); |
1194 | vga_out8 (0x3d5, par->CR60, par); | 1365 | vga_out8(0x3d5, reg->CR60, par); |
1195 | vga_out8 (0x3d4, 0x68, par); | 1366 | vga_out8(0x3d4, 0x68, par); |
1196 | vga_out8 (0x3d5, par->CR68, par); | 1367 | vga_out8(0x3d5, reg->CR68, par); |
1197 | vga_out8 (0x3d4, 0x69, par); | 1368 | vga_out8(0x3d4, 0x69, par); |
1198 | vga_out8 (0x3d5, par->CR69, par); | 1369 | vga_out8(0x3d5, reg->CR69, par); |
1199 | vga_out8 (0x3d4, 0x6f, par); | 1370 | vga_out8(0x3d4, 0x6f, par); |
1200 | vga_out8 (0x3d5, par->CR6F, par); | 1371 | vga_out8(0x3d5, reg->CR6F, par); |
1201 | 1372 | ||
1202 | vga_out8 (0x3d4, 0x33, par); | 1373 | vga_out8(0x3d4, 0x33, par); |
1203 | vga_out8 (0x3d5, par->CR33, par); | 1374 | vga_out8(0x3d5, reg->CR33, par); |
1204 | vga_out8 (0x3d4, 0x86, par); | 1375 | vga_out8(0x3d4, 0x86, par); |
1205 | vga_out8 (0x3d5, par->CR86, par); | 1376 | vga_out8(0x3d5, reg->CR86, par); |
1206 | vga_out8 (0x3d4, 0x88, par); | 1377 | vga_out8(0x3d4, 0x88, par); |
1207 | vga_out8 (0x3d5, par->CR88, par); | 1378 | vga_out8(0x3d5, reg->CR88, par); |
1208 | vga_out8 (0x3d4, 0x90, par); | 1379 | vga_out8(0x3d4, 0x90, par); |
1209 | vga_out8 (0x3d5, par->CR90, par); | 1380 | vga_out8(0x3d5, reg->CR90, par); |
1210 | vga_out8 (0x3d4, 0x91, par); | 1381 | vga_out8(0x3d4, 0x91, par); |
1211 | vga_out8 (0x3d5, par->CR91, par); | 1382 | vga_out8(0x3d5, reg->CR91, par); |
1212 | 1383 | ||
1213 | if (par->chip == S3_SAVAGE4) { | 1384 | if (par->chip == S3_SAVAGE4) { |
1214 | vga_out8 (0x3d4, 0xb0, par); | 1385 | vga_out8(0x3d4, 0xb0, par); |
1215 | vga_out8 (0x3d5, par->CRB0, par); | 1386 | vga_out8(0x3d5, reg->CRB0, par); |
1216 | } | 1387 | } |
1217 | 1388 | ||
1218 | vga_out8 (0x3d4, 0x32, par); | 1389 | vga_out8(0x3d4, 0x32, par); |
1219 | vga_out8 (0x3d5, par->CR32, par); | 1390 | vga_out8(0x3d5, reg->CR32, par); |
1220 | 1391 | ||
1221 | /* unlock extended seq regs */ | 1392 | /* unlock extended seq regs */ |
1222 | vga_out8 (0x3c4, 0x08, par); | 1393 | vga_out8(0x3c4, 0x08, par); |
1223 | vga_out8 (0x3c5, 0x06, par); | 1394 | vga_out8(0x3c5, 0x06, par); |
1224 | 1395 | ||
1225 | /* Restore extended sequencer regs for MCLK. SR10 == 255 indicates | 1396 | /* Restore extended sequencer regs for MCLK. SR10 == 255 indicates |
1226 | * that we should leave the default SR10 and SR11 values there. | 1397 | * that we should leave the default SR10 and SR11 values there. |
1227 | */ | 1398 | */ |
1228 | if (par->SR10 != 255) { | 1399 | if (reg->SR10 != 255) { |
1229 | vga_out8 (0x3c4, 0x10, par); | 1400 | vga_out8(0x3c4, 0x10, par); |
1230 | vga_out8 (0x3c5, par->SR10, par); | 1401 | vga_out8(0x3c5, reg->SR10, par); |
1231 | vga_out8 (0x3c4, 0x11, par); | 1402 | vga_out8(0x3c4, 0x11, par); |
1232 | vga_out8 (0x3c5, par->SR11, par); | 1403 | vga_out8(0x3c5, reg->SR11, par); |
1233 | } | 1404 | } |
1234 | 1405 | ||
1235 | /* restore extended seq regs for dclk */ | 1406 | /* restore extended seq regs for dclk */ |
1236 | vga_out8 (0x3c4, 0x0e, par); | 1407 | vga_out8(0x3c4, 0x0e, par); |
1237 | vga_out8 (0x3c5, par->SR0E, par); | 1408 | vga_out8(0x3c5, reg->SR0E, par); |
1238 | vga_out8 (0x3c4, 0x0f, par); | 1409 | vga_out8(0x3c4, 0x0f, par); |
1239 | vga_out8 (0x3c5, par->SR0F, par); | 1410 | vga_out8(0x3c5, reg->SR0F, par); |
1240 | vga_out8 (0x3c4, 0x12, par); | 1411 | vga_out8(0x3c4, 0x12, par); |
1241 | vga_out8 (0x3c5, par->SR12, par); | 1412 | vga_out8(0x3c5, reg->SR12, par); |
1242 | vga_out8 (0x3c4, 0x13, par); | 1413 | vga_out8(0x3c4, 0x13, par); |
1243 | vga_out8 (0x3c5, par->SR13, par); | 1414 | vga_out8(0x3c5, reg->SR13, par); |
1244 | vga_out8 (0x3c4, 0x29, par); | 1415 | vga_out8(0x3c4, 0x29, par); |
1245 | vga_out8 (0x3c5, par->SR29, par); | 1416 | vga_out8(0x3c5, reg->SR29, par); |
1246 | 1417 | vga_out8(0x3c4, 0x18, par); | |
1247 | vga_out8 (0x3c4, 0x18, par); | 1418 | vga_out8(0x3c5, reg->SR18, par); |
1248 | vga_out8 (0x3c5, par->SR18, par); | ||
1249 | 1419 | ||
1250 | /* load new m, n pll values for dclk & mclk */ | 1420 | /* load new m, n pll values for dclk & mclk */ |
1251 | vga_out8 (0x3c4, 0x15, par); | 1421 | vga_out8(0x3c4, 0x15, par); |
1252 | tmp = vga_in8 (0x3c5, par) & ~0x21; | 1422 | tmp = vga_in8(0x3c5, par) & ~0x21; |
1253 | 1423 | ||
1254 | vga_out8 (0x3c5, tmp | 0x03, par); | 1424 | vga_out8(0x3c5, tmp | 0x03, par); |
1255 | vga_out8 (0x3c5, tmp | 0x23, par); | 1425 | vga_out8(0x3c5, tmp | 0x23, par); |
1256 | vga_out8 (0x3c5, tmp | 0x03, par); | 1426 | vga_out8(0x3c5, tmp | 0x03, par); |
1257 | vga_out8 (0x3c5, par->SR15, par); | 1427 | vga_out8(0x3c5, reg->SR15, par); |
1258 | udelay (100); | 1428 | udelay(100); |
1259 | 1429 | ||
1260 | vga_out8 (0x3c4, 0x30, par); | 1430 | vga_out8(0x3c4, 0x30, par); |
1261 | vga_out8 (0x3c5, par->SR30, par); | 1431 | vga_out8(0x3c5, reg->SR30, par); |
1262 | vga_out8 (0x3c4, 0x08, par); | 1432 | vga_out8(0x3c4, 0x08, par); |
1263 | vga_out8 (0x3c5, par->SR08, par); | 1433 | vga_out8(0x3c5, reg->SR08, par); |
1264 | 1434 | ||
1265 | /* now write out cr67 in full, possibly starting STREAMS */ | 1435 | /* now write out cr67 in full, possibly starting STREAMS */ |
1266 | VerticalRetraceWait(par); | 1436 | VerticalRetraceWait(par); |
1267 | vga_out8 (0x3d4, 0x67, par); | 1437 | vga_out8(0x3d4, 0x67, par); |
1268 | vga_out8 (0x3d5, par->CR67, par); | 1438 | vga_out8(0x3d5, reg->CR67, par); |
1269 | 1439 | ||
1270 | vga_out8 (0x3d4, 0x66, par); | 1440 | vga_out8(0x3d4, 0x66, par); |
1271 | cr66 = vga_in8 (0x3d5, par); | 1441 | cr66 = vga_in8(0x3d5, par); |
1272 | vga_out8 (0x3d5, cr66 | 0x80, par); | 1442 | vga_out8(0x3d5, cr66 | 0x80, par); |
1273 | vga_out8 (0x3d4, 0x3a, par); | 1443 | vga_out8(0x3d4, 0x3a, par); |
1274 | cr3a = vga_in8 (0x3d5, par); | 1444 | cr3a = vga_in8(0x3d5, par); |
1275 | vga_out8 (0x3d5, cr3a | 0x80, par); | 1445 | vga_out8(0x3d5, cr3a | 0x80, par); |
1276 | 1446 | ||
1277 | if (par->chip != S3_SAVAGE_MX) { | 1447 | if (par->chip != S3_SAVAGE_MX) { |
1278 | VerticalRetraceWait(par); | 1448 | VerticalRetraceWait(par); |
1279 | savage_out32 (FIFO_CONTROL_REG, par->MMPR0, par); | 1449 | savage_out32(FIFO_CONTROL_REG, reg->MMPR0, par); |
1280 | par->SavageWaitIdle (par); | 1450 | par->SavageWaitIdle(par); |
1281 | savage_out32 (MIU_CONTROL_REG, par->MMPR1, par); | 1451 | savage_out32(MIU_CONTROL_REG, reg->MMPR1, par); |
1282 | par->SavageWaitIdle (par); | 1452 | par->SavageWaitIdle(par); |
1283 | savage_out32 (STREAMS_TIMEOUT_REG, par->MMPR2, par); | 1453 | savage_out32(STREAMS_TIMEOUT_REG, reg->MMPR2, par); |
1284 | par->SavageWaitIdle (par); | 1454 | par->SavageWaitIdle(par); |
1285 | savage_out32 (MISC_TIMEOUT_REG, par->MMPR3, par); | 1455 | savage_out32(MISC_TIMEOUT_REG, reg->MMPR3, par); |
1286 | } | 1456 | } |
1287 | 1457 | ||
1288 | vga_out8 (0x3d4, 0x66, par); | 1458 | vga_out8(0x3d4, 0x66, par); |
1289 | vga_out8 (0x3d5, cr66, par); | 1459 | vga_out8(0x3d5, cr66, par); |
1290 | vga_out8 (0x3d4, 0x3a, par); | 1460 | vga_out8(0x3d4, 0x3a, par); |
1291 | vga_out8 (0x3d5, cr3a, par); | 1461 | vga_out8(0x3d5, cr3a, par); |
1292 | 1462 | ||
1293 | SavageSetup2DEngine (par); | 1463 | SavageSetup2DEngine(par); |
1294 | vgaHWProtect (par, 0); | 1464 | vgaHWProtect(par, 0); |
1295 | } | 1465 | } |
1296 | 1466 | ||
1297 | static void savagefb_update_start (struct savagefb_par *par, | 1467 | static void savagefb_update_start(struct savagefb_par *par, |
1298 | struct fb_var_screeninfo *var) | 1468 | struct fb_var_screeninfo *var) |
1299 | { | 1469 | { |
1300 | int base; | 1470 | int base; |
1301 | 1471 | ||
@@ -1305,8 +1475,8 @@ static void savagefb_update_start (struct savagefb_par *par, | |||
1305 | /* now program the start address registers */ | 1475 | /* now program the start address registers */ |
1306 | vga_out16(0x3d4, (base & 0x00ff00) | 0x0c, par); | 1476 | vga_out16(0x3d4, (base & 0x00ff00) | 0x0c, par); |
1307 | vga_out16(0x3d4, ((base & 0x00ff) << 8) | 0x0d, par); | 1477 | vga_out16(0x3d4, ((base & 0x00ff) << 8) | 0x0d, par); |
1308 | vga_out8 (0x3d4, 0x69, par); | 1478 | vga_out8(0x3d4, 0x69, par); |
1309 | vga_out8 (0x3d5, (base & 0x7f0000) >> 16, par); | 1479 | vga_out8(0x3d5, (base & 0x7f0000) >> 16, par); |
1310 | } | 1480 | } |
1311 | 1481 | ||
1312 | 1482 | ||
@@ -1325,29 +1495,14 @@ static void savagefb_set_fix(struct fb_info *info) | |||
1325 | 1495 | ||
1326 | } | 1496 | } |
1327 | 1497 | ||
1328 | #if defined(CONFIG_FB_SAVAGE_ACCEL) | 1498 | static int savagefb_set_par(struct fb_info *info) |
1329 | static void savagefb_set_clip(struct fb_info *info) | ||
1330 | { | ||
1331 | struct savagefb_par *par = info->par; | ||
1332 | int cmd; | ||
1333 | |||
1334 | cmd = BCI_CMD_NOP | BCI_CMD_CLIP_NEW; | ||
1335 | par->bci_ptr = 0; | ||
1336 | par->SavageWaitFifo(par,3); | ||
1337 | BCI_SEND(cmd); | ||
1338 | BCI_SEND(BCI_CLIP_TL(0, 0)); | ||
1339 | BCI_SEND(BCI_CLIP_BR(0xfff, 0xfff)); | ||
1340 | } | ||
1341 | #endif | ||
1342 | |||
1343 | static int savagefb_set_par (struct fb_info *info) | ||
1344 | { | 1499 | { |
1345 | struct savagefb_par *par = info->par; | 1500 | struct savagefb_par *par = info->par; |
1346 | struct fb_var_screeninfo *var = &info->var; | 1501 | struct fb_var_screeninfo *var = &info->var; |
1347 | int err; | 1502 | int err; |
1348 | 1503 | ||
1349 | DBG("savagefb_set_par"); | 1504 | DBG("savagefb_set_par"); |
1350 | err = savagefb_decode_var (var, par); | 1505 | err = savagefb_decode_var(var, par, &par->state); |
1351 | if (err) | 1506 | if (err) |
1352 | return err; | 1507 | return err; |
1353 | 1508 | ||
@@ -1366,8 +1521,8 @@ static int savagefb_set_par (struct fb_info *info) | |||
1366 | par->maxClock = par->dacSpeedBpp; | 1521 | par->maxClock = par->dacSpeedBpp; |
1367 | par->minClock = 10000; | 1522 | par->minClock = 10000; |
1368 | 1523 | ||
1369 | savagefb_set_par_int (par); | 1524 | savagefb_set_par_int(par, &par->state); |
1370 | fb_set_cmap (&info->cmap, info); | 1525 | fb_set_cmap(&info->cmap, info); |
1371 | savagefb_set_fix(info); | 1526 | savagefb_set_fix(info); |
1372 | savagefb_set_clip(info); | 1527 | savagefb_set_clip(info); |
1373 | 1528 | ||
@@ -1378,12 +1533,12 @@ static int savagefb_set_par (struct fb_info *info) | |||
1378 | /* | 1533 | /* |
1379 | * Pan or Wrap the Display | 1534 | * Pan or Wrap the Display |
1380 | */ | 1535 | */ |
1381 | static int savagefb_pan_display (struct fb_var_screeninfo *var, | 1536 | static int savagefb_pan_display(struct fb_var_screeninfo *var, |
1382 | struct fb_info *info) | 1537 | struct fb_info *info) |
1383 | { | 1538 | { |
1384 | struct savagefb_par *par = info->par; | 1539 | struct savagefb_par *par = info->par; |
1385 | 1540 | ||
1386 | savagefb_update_start (par, var); | 1541 | savagefb_update_start(par, var); |
1387 | return 0; | 1542 | return 0; |
1388 | } | 1543 | } |
1389 | 1544 | ||
@@ -1440,6 +1595,22 @@ static int savagefb_blank(int blank, struct fb_info *info) | |||
1440 | return (blank == FB_BLANK_NORMAL) ? 1 : 0; | 1595 | return (blank == FB_BLANK_NORMAL) ? 1 : 0; |
1441 | } | 1596 | } |
1442 | 1597 | ||
1598 | static void savagefb_save_state(struct fb_info *info) | ||
1599 | { | ||
1600 | struct savagefb_par *par = info->par; | ||
1601 | |||
1602 | savage_get_default_par(par, &par->save); | ||
1603 | } | ||
1604 | |||
1605 | static void savagefb_restore_state(struct fb_info *info) | ||
1606 | { | ||
1607 | struct savagefb_par *par = info->par; | ||
1608 | |||
1609 | savagefb_blank(FB_BLANK_POWERDOWN, info); | ||
1610 | savage_set_default_par(par, &par->save); | ||
1611 | savagefb_blank(FB_BLANK_UNBLANK, info); | ||
1612 | } | ||
1613 | |||
1443 | static struct fb_ops savagefb_ops = { | 1614 | static struct fb_ops savagefb_ops = { |
1444 | .owner = THIS_MODULE, | 1615 | .owner = THIS_MODULE, |
1445 | .fb_check_var = savagefb_check_var, | 1616 | .fb_check_var = savagefb_check_var, |
@@ -1447,6 +1618,8 @@ static struct fb_ops savagefb_ops = { | |||
1447 | .fb_setcolreg = savagefb_setcolreg, | 1618 | .fb_setcolreg = savagefb_setcolreg, |
1448 | .fb_pan_display = savagefb_pan_display, | 1619 | .fb_pan_display = savagefb_pan_display, |
1449 | .fb_blank = savagefb_blank, | 1620 | .fb_blank = savagefb_blank, |
1621 | .fb_save_state = savagefb_save_state, | ||
1622 | .fb_restore_state = savagefb_restore_state, | ||
1450 | #if defined(CONFIG_FB_SAVAGE_ACCEL) | 1623 | #if defined(CONFIG_FB_SAVAGE_ACCEL) |
1451 | .fb_fillrect = savagefb_fillrect, | 1624 | .fb_fillrect = savagefb_fillrect, |
1452 | .fb_copyarea = savagefb_copyarea, | 1625 | .fb_copyarea = savagefb_copyarea, |
@@ -1479,59 +1652,59 @@ static struct fb_var_screeninfo __devinitdata savagefb_var800x600x8 = { | |||
1479 | .vmode = FB_VMODE_NONINTERLACED | 1652 | .vmode = FB_VMODE_NONINTERLACED |
1480 | }; | 1653 | }; |
1481 | 1654 | ||
1482 | static void savage_enable_mmio (struct savagefb_par *par) | 1655 | static void savage_enable_mmio(struct savagefb_par *par) |
1483 | { | 1656 | { |
1484 | unsigned char val; | 1657 | unsigned char val; |
1485 | 1658 | ||
1486 | DBG ("savage_enable_mmio\n"); | 1659 | DBG("savage_enable_mmio\n"); |
1487 | 1660 | ||
1488 | val = vga_in8 (0x3c3, par); | 1661 | val = vga_in8(0x3c3, par); |
1489 | vga_out8 (0x3c3, val | 0x01, par); | 1662 | vga_out8(0x3c3, val | 0x01, par); |
1490 | val = vga_in8 (0x3cc, par); | 1663 | val = vga_in8(0x3cc, par); |
1491 | vga_out8 (0x3c2, val | 0x01, par); | 1664 | vga_out8(0x3c2, val | 0x01, par); |
1492 | 1665 | ||
1493 | if (par->chip >= S3_SAVAGE4) { | 1666 | if (par->chip >= S3_SAVAGE4) { |
1494 | vga_out8 (0x3d4, 0x40, par); | 1667 | vga_out8(0x3d4, 0x40, par); |
1495 | val = vga_in8 (0x3d5, par); | 1668 | val = vga_in8(0x3d5, par); |
1496 | vga_out8 (0x3d5, val | 1, par); | 1669 | vga_out8(0x3d5, val | 1, par); |
1497 | } | 1670 | } |
1498 | } | 1671 | } |
1499 | 1672 | ||
1500 | 1673 | ||
1501 | static void savage_disable_mmio (struct savagefb_par *par) | 1674 | static void savage_disable_mmio(struct savagefb_par *par) |
1502 | { | 1675 | { |
1503 | unsigned char val; | 1676 | unsigned char val; |
1504 | 1677 | ||
1505 | DBG ("savage_disable_mmio\n"); | 1678 | DBG("savage_disable_mmio\n"); |
1506 | 1679 | ||
1507 | if(par->chip >= S3_SAVAGE4 ) { | 1680 | if (par->chip >= S3_SAVAGE4) { |
1508 | vga_out8 (0x3d4, 0x40, par); | 1681 | vga_out8(0x3d4, 0x40, par); |
1509 | val = vga_in8 (0x3d5, par); | 1682 | val = vga_in8(0x3d5, par); |
1510 | vga_out8 (0x3d5, val | 1, par); | 1683 | vga_out8(0x3d5, val | 1, par); |
1511 | } | 1684 | } |
1512 | } | 1685 | } |
1513 | 1686 | ||
1514 | 1687 | ||
1515 | static int __devinit savage_map_mmio (struct fb_info *info) | 1688 | static int __devinit savage_map_mmio(struct fb_info *info) |
1516 | { | 1689 | { |
1517 | struct savagefb_par *par = info->par; | 1690 | struct savagefb_par *par = info->par; |
1518 | DBG ("savage_map_mmio"); | 1691 | DBG("savage_map_mmio"); |
1519 | 1692 | ||
1520 | if (S3_SAVAGE3D_SERIES (par->chip)) | 1693 | if (S3_SAVAGE3D_SERIES(par->chip)) |
1521 | par->mmio.pbase = pci_resource_start (par->pcidev, 0) + | 1694 | par->mmio.pbase = pci_resource_start(par->pcidev, 0) + |
1522 | SAVAGE_NEWMMIO_REGBASE_S3; | 1695 | SAVAGE_NEWMMIO_REGBASE_S3; |
1523 | else | 1696 | else |
1524 | par->mmio.pbase = pci_resource_start (par->pcidev, 0) + | 1697 | par->mmio.pbase = pci_resource_start(par->pcidev, 0) + |
1525 | SAVAGE_NEWMMIO_REGBASE_S4; | 1698 | SAVAGE_NEWMMIO_REGBASE_S4; |
1526 | 1699 | ||
1527 | par->mmio.len = SAVAGE_NEWMMIO_REGSIZE; | 1700 | par->mmio.len = SAVAGE_NEWMMIO_REGSIZE; |
1528 | 1701 | ||
1529 | par->mmio.vbase = ioremap (par->mmio.pbase, par->mmio.len); | 1702 | par->mmio.vbase = ioremap(par->mmio.pbase, par->mmio.len); |
1530 | if (!par->mmio.vbase) { | 1703 | if (!par->mmio.vbase) { |
1531 | printk ("savagefb: unable to map memory mapped IO\n"); | 1704 | printk("savagefb: unable to map memory mapped IO\n"); |
1532 | return -ENOMEM; | 1705 | return -ENOMEM; |
1533 | } else | 1706 | } else |
1534 | printk (KERN_INFO "savagefb: mapped io at %p\n", | 1707 | printk(KERN_INFO "savagefb: mapped io at %p\n", |
1535 | par->mmio.vbase); | 1708 | par->mmio.vbase); |
1536 | 1709 | ||
1537 | info->fix.mmio_start = par->mmio.pbase; | 1710 | info->fix.mmio_start = par->mmio.pbase; |
@@ -1540,15 +1713,15 @@ static int __devinit savage_map_mmio (struct fb_info *info) | |||
1540 | par->bci_base = (u32 __iomem *)(par->mmio.vbase + BCI_BUFFER_OFFSET); | 1713 | par->bci_base = (u32 __iomem *)(par->mmio.vbase + BCI_BUFFER_OFFSET); |
1541 | par->bci_ptr = 0; | 1714 | par->bci_ptr = 0; |
1542 | 1715 | ||
1543 | savage_enable_mmio (par); | 1716 | savage_enable_mmio(par); |
1544 | 1717 | ||
1545 | return 0; | 1718 | return 0; |
1546 | } | 1719 | } |
1547 | 1720 | ||
1548 | static void savage_unmap_mmio (struct fb_info *info) | 1721 | static void savage_unmap_mmio(struct fb_info *info) |
1549 | { | 1722 | { |
1550 | struct savagefb_par *par = info->par; | 1723 | struct savagefb_par *par = info->par; |
1551 | DBG ("savage_unmap_mmio"); | 1724 | DBG("savage_unmap_mmio"); |
1552 | 1725 | ||
1553 | savage_disable_mmio(par); | 1726 | savage_disable_mmio(par); |
1554 | 1727 | ||
@@ -1558,46 +1731,46 @@ static void savage_unmap_mmio (struct fb_info *info) | |||
1558 | } | 1731 | } |
1559 | } | 1732 | } |
1560 | 1733 | ||
1561 | static int __devinit savage_map_video (struct fb_info *info, | 1734 | static int __devinit savage_map_video(struct fb_info *info, |
1562 | int video_len) | 1735 | int video_len) |
1563 | { | 1736 | { |
1564 | struct savagefb_par *par = info->par; | 1737 | struct savagefb_par *par = info->par; |
1565 | int resource; | 1738 | int resource; |
1566 | 1739 | ||
1567 | DBG("savage_map_video"); | 1740 | DBG("savage_map_video"); |
1568 | 1741 | ||
1569 | if (S3_SAVAGE3D_SERIES (par->chip)) | 1742 | if (S3_SAVAGE3D_SERIES(par->chip)) |
1570 | resource = 0; | 1743 | resource = 0; |
1571 | else | 1744 | else |
1572 | resource = 1; | 1745 | resource = 1; |
1573 | 1746 | ||
1574 | par->video.pbase = pci_resource_start (par->pcidev, resource); | 1747 | par->video.pbase = pci_resource_start(par->pcidev, resource); |
1575 | par->video.len = video_len; | 1748 | par->video.len = video_len; |
1576 | par->video.vbase = ioremap (par->video.pbase, par->video.len); | 1749 | par->video.vbase = ioremap(par->video.pbase, par->video.len); |
1577 | 1750 | ||
1578 | if (!par->video.vbase) { | 1751 | if (!par->video.vbase) { |
1579 | printk ("savagefb: unable to map screen memory\n"); | 1752 | printk("savagefb: unable to map screen memory\n"); |
1580 | return -ENOMEM; | 1753 | return -ENOMEM; |
1581 | } else | 1754 | } else |
1582 | printk (KERN_INFO "savagefb: mapped framebuffer at %p, " | 1755 | printk(KERN_INFO "savagefb: mapped framebuffer at %p, " |
1583 | "pbase == %x\n", par->video.vbase, par->video.pbase); | 1756 | "pbase == %x\n", par->video.vbase, par->video.pbase); |
1584 | 1757 | ||
1585 | info->fix.smem_start = par->video.pbase; | 1758 | info->fix.smem_start = par->video.pbase; |
1586 | info->fix.smem_len = par->video.len - par->cob_size; | 1759 | info->fix.smem_len = par->video.len - par->cob_size; |
1587 | info->screen_base = par->video.vbase; | 1760 | info->screen_base = par->video.vbase; |
1588 | 1761 | ||
1589 | #ifdef CONFIG_MTRR | 1762 | #ifdef CONFIG_MTRR |
1590 | par->video.mtrr = mtrr_add (par->video.pbase, video_len, | 1763 | par->video.mtrr = mtrr_add(par->video.pbase, video_len, |
1591 | MTRR_TYPE_WRCOMB, 1); | 1764 | MTRR_TYPE_WRCOMB, 1); |
1592 | #endif | 1765 | #endif |
1593 | 1766 | ||
1594 | /* Clear framebuffer, it's all white in memory after boot */ | 1767 | /* Clear framebuffer, it's all white in memory after boot */ |
1595 | memset_io (par->video.vbase, 0, par->video.len); | 1768 | memset_io(par->video.vbase, 0, par->video.len); |
1596 | 1769 | ||
1597 | return 0; | 1770 | return 0; |
1598 | } | 1771 | } |
1599 | 1772 | ||
1600 | static void savage_unmap_video (struct fb_info *info) | 1773 | static void savage_unmap_video(struct fb_info *info) |
1601 | { | 1774 | { |
1602 | struct savagefb_par *par = info->par; | 1775 | struct savagefb_par *par = info->par; |
1603 | 1776 | ||
@@ -1605,16 +1778,16 @@ static void savage_unmap_video (struct fb_info *info) | |||
1605 | 1778 | ||
1606 | if (par->video.vbase) { | 1779 | if (par->video.vbase) { |
1607 | #ifdef CONFIG_MTRR | 1780 | #ifdef CONFIG_MTRR |
1608 | mtrr_del (par->video.mtrr, par->video.pbase, par->video.len); | 1781 | mtrr_del(par->video.mtrr, par->video.pbase, par->video.len); |
1609 | #endif | 1782 | #endif |
1610 | 1783 | ||
1611 | iounmap (par->video.vbase); | 1784 | iounmap(par->video.vbase); |
1612 | par->video.vbase = NULL; | 1785 | par->video.vbase = NULL; |
1613 | info->screen_base = NULL; | 1786 | info->screen_base = NULL; |
1614 | } | 1787 | } |
1615 | } | 1788 | } |
1616 | 1789 | ||
1617 | static int savage_init_hw (struct savagefb_par *par) | 1790 | static int savage_init_hw(struct savagefb_par *par) |
1618 | { | 1791 | { |
1619 | unsigned char config1, m, n, n1, n2, sr8, cr3f, cr66 = 0, tmp; | 1792 | unsigned char config1, m, n, n1, n2, sr8, cr3f, cr66 = 0, tmp; |
1620 | 1793 | ||
@@ -1656,7 +1829,7 @@ static int savage_init_hw (struct savagefb_par *par) | |||
1656 | 1829 | ||
1657 | switch (par->chip) { | 1830 | switch (par->chip) { |
1658 | case S3_SAVAGE3D: | 1831 | case S3_SAVAGE3D: |
1659 | videoRam = RamSavage3D[ (config1 & 0xC0) >> 6 ] * 1024; | 1832 | videoRam = RamSavage3D[(config1 & 0xC0) >> 6 ] * 1024; |
1660 | break; | 1833 | break; |
1661 | 1834 | ||
1662 | case S3_SAVAGE4: | 1835 | case S3_SAVAGE4: |
@@ -1667,22 +1840,22 @@ static int savage_init_hw (struct savagefb_par *par) | |||
1667 | * can do it different... | 1840 | * can do it different... |
1668 | */ | 1841 | */ |
1669 | vga_out8(0x3d4, 0x68, par); /* memory control 1 */ | 1842 | vga_out8(0x3d4, 0x68, par); /* memory control 1 */ |
1670 | if( (vga_in8(0x3d5, par) & 0xC0) == (0x01 << 6) ) | 1843 | if ((vga_in8(0x3d5, par) & 0xC0) == (0x01 << 6)) |
1671 | RamSavage4[1] = 8; | 1844 | RamSavage4[1] = 8; |
1672 | 1845 | ||
1673 | /*FALLTHROUGH*/ | 1846 | /*FALLTHROUGH*/ |
1674 | 1847 | ||
1675 | case S3_SAVAGE2000: | 1848 | case S3_SAVAGE2000: |
1676 | videoRam = RamSavage4[ (config1 & 0xE0) >> 5 ] * 1024; | 1849 | videoRam = RamSavage4[(config1 & 0xE0) >> 5] * 1024; |
1677 | break; | 1850 | break; |
1678 | 1851 | ||
1679 | case S3_SAVAGE_MX: | 1852 | case S3_SAVAGE_MX: |
1680 | case S3_SUPERSAVAGE: | 1853 | case S3_SUPERSAVAGE: |
1681 | videoRam = RamSavageMX[ (config1 & 0x0E) >> 1 ] * 1024; | 1854 | videoRam = RamSavageMX[(config1 & 0x0E) >> 1] * 1024; |
1682 | break; | 1855 | break; |
1683 | 1856 | ||
1684 | case S3_PROSAVAGE: | 1857 | case S3_PROSAVAGE: |
1685 | videoRam = RamSavageNB[ (config1 & 0xE0) >> 5 ] * 1024; | 1858 | videoRam = RamSavageNB[(config1 & 0xE0) >> 5] * 1024; |
1686 | break; | 1859 | break; |
1687 | 1860 | ||
1688 | default: | 1861 | default: |
@@ -1693,31 +1866,31 @@ static int savage_init_hw (struct savagefb_par *par) | |||
1693 | 1866 | ||
1694 | videoRambytes = videoRam * 1024; | 1867 | videoRambytes = videoRam * 1024; |
1695 | 1868 | ||
1696 | printk (KERN_INFO "savagefb: probed videoram: %dk\n", videoRam); | 1869 | printk(KERN_INFO "savagefb: probed videoram: %dk\n", videoRam); |
1697 | 1870 | ||
1698 | /* reset graphics engine to avoid memory corruption */ | 1871 | /* reset graphics engine to avoid memory corruption */ |
1699 | vga_out8 (0x3d4, 0x66, par); | 1872 | vga_out8(0x3d4, 0x66, par); |
1700 | cr66 = vga_in8 (0x3d5, par); | 1873 | cr66 = vga_in8(0x3d5, par); |
1701 | vga_out8 (0x3d5, cr66 | 0x02, par); | 1874 | vga_out8(0x3d5, cr66 | 0x02, par); |
1702 | udelay (10000); | 1875 | udelay(10000); |
1703 | 1876 | ||
1704 | vga_out8 (0x3d4, 0x66, par); | 1877 | vga_out8(0x3d4, 0x66, par); |
1705 | vga_out8 (0x3d5, cr66 & ~0x02, par); /* clear reset flag */ | 1878 | vga_out8(0x3d5, cr66 & ~0x02, par); /* clear reset flag */ |
1706 | udelay (10000); | 1879 | udelay(10000); |
1707 | 1880 | ||
1708 | 1881 | ||
1709 | /* | 1882 | /* |
1710 | * reset memory interface, 3D engine, AGP master, PCI master, | 1883 | * reset memory interface, 3D engine, AGP master, PCI master, |
1711 | * master engine unit, motion compensation/LPB | 1884 | * master engine unit, motion compensation/LPB |
1712 | */ | 1885 | */ |
1713 | vga_out8 (0x3d4, 0x3f, par); | 1886 | vga_out8(0x3d4, 0x3f, par); |
1714 | cr3f = vga_in8 (0x3d5, par); | 1887 | cr3f = vga_in8(0x3d5, par); |
1715 | vga_out8 (0x3d5, cr3f | 0x08, par); | 1888 | vga_out8(0x3d5, cr3f | 0x08, par); |
1716 | udelay (10000); | 1889 | udelay(10000); |
1717 | 1890 | ||
1718 | vga_out8 (0x3d4, 0x3f, par); | 1891 | vga_out8(0x3d4, 0x3f, par); |
1719 | vga_out8 (0x3d5, cr3f & ~0x08, par); /* clear reset flags */ | 1892 | vga_out8(0x3d5, cr3f & ~0x08, par); /* clear reset flags */ |
1720 | udelay (10000); | 1893 | udelay(10000); |
1721 | 1894 | ||
1722 | /* Savage ramdac speeds */ | 1895 | /* Savage ramdac speeds */ |
1723 | par->numClocks = 4; | 1896 | par->numClocks = 4; |
@@ -1740,7 +1913,7 @@ static int savage_init_hw (struct savagefb_par *par) | |||
1740 | n1 = n & 0x1f; | 1913 | n1 = n & 0x1f; |
1741 | n2 = (n >> 5) & 0x03; | 1914 | n2 = (n >> 5) & 0x03; |
1742 | par->MCLK = ((1431818 * (m+2)) / (n1+2) / (1 << n2) + 50) / 100; | 1915 | par->MCLK = ((1431818 * (m+2)) / (n1+2) / (1 << n2) + 50) / 100; |
1743 | printk (KERN_INFO "savagefb: Detected current MCLK value of %d kHz\n", | 1916 | printk(KERN_INFO "savagefb: Detected current MCLK value of %d kHz\n", |
1744 | par->MCLK); | 1917 | par->MCLK); |
1745 | 1918 | ||
1746 | /* check for DVI/flat panel */ | 1919 | /* check for DVI/flat panel */ |
@@ -1769,12 +1942,12 @@ static int savage_init_hw (struct savagefb_par *par) | |||
1769 | /* Check LCD panel parrmation */ | 1942 | /* Check LCD panel parrmation */ |
1770 | 1943 | ||
1771 | if (par->display_type == DISP_LCD) { | 1944 | if (par->display_type == DISP_LCD) { |
1772 | unsigned char cr6b = VGArCR( 0x6b, par); | 1945 | unsigned char cr6b = VGArCR(0x6b, par); |
1773 | 1946 | ||
1774 | int panelX = (VGArSEQ (0x61, par) + | 1947 | int panelX = (VGArSEQ(0x61, par) + |
1775 | ((VGArSEQ (0x66, par) & 0x02) << 7) + 1) * 8; | 1948 | ((VGArSEQ(0x66, par) & 0x02) << 7) + 1) * 8; |
1776 | int panelY = (VGArSEQ (0x69, par) + | 1949 | int panelY = (VGArSEQ(0x69, par) + |
1777 | ((VGArSEQ (0x6e, par) & 0x70) << 4) + 1); | 1950 | ((VGArSEQ(0x6e, par) & 0x70) << 4) + 1); |
1778 | 1951 | ||
1779 | char * sTechnology = "Unknown"; | 1952 | char * sTechnology = "Unknown"; |
1780 | 1953 | ||
@@ -1796,26 +1969,26 @@ static int savage_init_hw (struct savagefb_par *par) | |||
1796 | ActiveDUO = 0x80 | 1969 | ActiveDUO = 0x80 |
1797 | }; | 1970 | }; |
1798 | 1971 | ||
1799 | if ((VGArSEQ (0x39, par) & 0x03) == 0) { | 1972 | if ((VGArSEQ(0x39, par) & 0x03) == 0) { |
1800 | sTechnology = "TFT"; | 1973 | sTechnology = "TFT"; |
1801 | } else if ((VGArSEQ (0x30, par) & 0x01) == 0) { | 1974 | } else if ((VGArSEQ(0x30, par) & 0x01) == 0) { |
1802 | sTechnology = "DSTN"; | 1975 | sTechnology = "DSTN"; |
1803 | } else { | 1976 | } else { |
1804 | sTechnology = "STN"; | 1977 | sTechnology = "STN"; |
1805 | } | 1978 | } |
1806 | 1979 | ||
1807 | printk (KERN_INFO "savagefb: %dx%d %s LCD panel detected %s\n", | 1980 | printk(KERN_INFO "savagefb: %dx%d %s LCD panel detected %s\n", |
1808 | panelX, panelY, sTechnology, | 1981 | panelX, panelY, sTechnology, |
1809 | cr6b & ActiveLCD ? "and active" : "but not active"); | 1982 | cr6b & ActiveLCD ? "and active" : "but not active"); |
1810 | 1983 | ||
1811 | if( cr6b & ActiveLCD ) { | 1984 | if (cr6b & ActiveLCD) { |
1812 | /* | 1985 | /* |
1813 | * If the LCD is active and panel expansion is enabled, | 1986 | * If the LCD is active and panel expansion is enabled, |
1814 | * we probably want to kill the HW cursor. | 1987 | * we probably want to kill the HW cursor. |
1815 | */ | 1988 | */ |
1816 | 1989 | ||
1817 | printk (KERN_INFO "savagefb: Limiting video mode to " | 1990 | printk(KERN_INFO "savagefb: Limiting video mode to " |
1818 | "%dx%d\n", panelX, panelY ); | 1991 | "%dx%d\n", panelX, panelY); |
1819 | 1992 | ||
1820 | par->SavagePanelWidth = panelX; | 1993 | par->SavagePanelWidth = panelX; |
1821 | par->SavagePanelHeight = panelY; | 1994 | par->SavagePanelHeight = panelY; |
@@ -1824,9 +1997,10 @@ static int savage_init_hw (struct savagefb_par *par) | |||
1824 | par->display_type = DISP_CRT; | 1997 | par->display_type = DISP_CRT; |
1825 | } | 1998 | } |
1826 | 1999 | ||
1827 | savage_get_default_par (par); | 2000 | savage_get_default_par(par, &par->state); |
2001 | par->save = par->state; | ||
1828 | 2002 | ||
1829 | if( S3_SAVAGE4_SERIES(par->chip) ) { | 2003 | if (S3_SAVAGE4_SERIES(par->chip)) { |
1830 | /* | 2004 | /* |
1831 | * The Savage4 and ProSavage have COB coherency bugs which | 2005 | * The Savage4 and ProSavage have COB coherency bugs which |
1832 | * render the buffer useless. We disable it. | 2006 | * render the buffer useless. We disable it. |
@@ -1845,9 +2019,9 @@ static int savage_init_hw (struct savagefb_par *par) | |||
1845 | return videoRambytes; | 2019 | return videoRambytes; |
1846 | } | 2020 | } |
1847 | 2021 | ||
1848 | static int __devinit savage_init_fb_info (struct fb_info *info, | 2022 | static int __devinit savage_init_fb_info(struct fb_info *info, |
1849 | struct pci_dev *dev, | 2023 | struct pci_dev *dev, |
1850 | const struct pci_device_id *id) | 2024 | const struct pci_device_id *id) |
1851 | { | 2025 | { |
1852 | struct savagefb_par *par = info->par; | 2026 | struct savagefb_par *par = info->par; |
1853 | int err = 0; | 2027 | int err = 0; |
@@ -1863,63 +2037,63 @@ static int __devinit savage_init_fb_info (struct fb_info *info, | |||
1863 | switch (info->fix.accel) { | 2037 | switch (info->fix.accel) { |
1864 | case FB_ACCEL_SUPERSAVAGE: | 2038 | case FB_ACCEL_SUPERSAVAGE: |
1865 | par->chip = S3_SUPERSAVAGE; | 2039 | par->chip = S3_SUPERSAVAGE; |
1866 | snprintf (info->fix.id, 16, "SuperSavage"); | 2040 | snprintf(info->fix.id, 16, "SuperSavage"); |
1867 | break; | 2041 | break; |
1868 | case FB_ACCEL_SAVAGE4: | 2042 | case FB_ACCEL_SAVAGE4: |
1869 | par->chip = S3_SAVAGE4; | 2043 | par->chip = S3_SAVAGE4; |
1870 | snprintf (info->fix.id, 16, "Savage4"); | 2044 | snprintf(info->fix.id, 16, "Savage4"); |
1871 | break; | 2045 | break; |
1872 | case FB_ACCEL_SAVAGE3D: | 2046 | case FB_ACCEL_SAVAGE3D: |
1873 | par->chip = S3_SAVAGE3D; | 2047 | par->chip = S3_SAVAGE3D; |
1874 | snprintf (info->fix.id, 16, "Savage3D"); | 2048 | snprintf(info->fix.id, 16, "Savage3D"); |
1875 | break; | 2049 | break; |
1876 | case FB_ACCEL_SAVAGE3D_MV: | 2050 | case FB_ACCEL_SAVAGE3D_MV: |
1877 | par->chip = S3_SAVAGE3D; | 2051 | par->chip = S3_SAVAGE3D; |
1878 | snprintf (info->fix.id, 16, "Savage3D-MV"); | 2052 | snprintf(info->fix.id, 16, "Savage3D-MV"); |
1879 | break; | 2053 | break; |
1880 | case FB_ACCEL_SAVAGE2000: | 2054 | case FB_ACCEL_SAVAGE2000: |
1881 | par->chip = S3_SAVAGE2000; | 2055 | par->chip = S3_SAVAGE2000; |
1882 | snprintf (info->fix.id, 16, "Savage2000"); | 2056 | snprintf(info->fix.id, 16, "Savage2000"); |
1883 | break; | 2057 | break; |
1884 | case FB_ACCEL_SAVAGE_MX_MV: | 2058 | case FB_ACCEL_SAVAGE_MX_MV: |
1885 | par->chip = S3_SAVAGE_MX; | 2059 | par->chip = S3_SAVAGE_MX; |
1886 | snprintf (info->fix.id, 16, "Savage/MX-MV"); | 2060 | snprintf(info->fix.id, 16, "Savage/MX-MV"); |
1887 | break; | 2061 | break; |
1888 | case FB_ACCEL_SAVAGE_MX: | 2062 | case FB_ACCEL_SAVAGE_MX: |
1889 | par->chip = S3_SAVAGE_MX; | 2063 | par->chip = S3_SAVAGE_MX; |
1890 | snprintf (info->fix.id, 16, "Savage/MX"); | 2064 | snprintf(info->fix.id, 16, "Savage/MX"); |
1891 | break; | 2065 | break; |
1892 | case FB_ACCEL_SAVAGE_IX_MV: | 2066 | case FB_ACCEL_SAVAGE_IX_MV: |
1893 | par->chip = S3_SAVAGE_MX; | 2067 | par->chip = S3_SAVAGE_MX; |
1894 | snprintf (info->fix.id, 16, "Savage/IX-MV"); | 2068 | snprintf(info->fix.id, 16, "Savage/IX-MV"); |
1895 | break; | 2069 | break; |
1896 | case FB_ACCEL_SAVAGE_IX: | 2070 | case FB_ACCEL_SAVAGE_IX: |
1897 | par->chip = S3_SAVAGE_MX; | 2071 | par->chip = S3_SAVAGE_MX; |
1898 | snprintf (info->fix.id, 16, "Savage/IX"); | 2072 | snprintf(info->fix.id, 16, "Savage/IX"); |
1899 | break; | 2073 | break; |
1900 | case FB_ACCEL_PROSAVAGE_PM: | 2074 | case FB_ACCEL_PROSAVAGE_PM: |
1901 | par->chip = S3_PROSAVAGE; | 2075 | par->chip = S3_PROSAVAGE; |
1902 | snprintf (info->fix.id, 16, "ProSavagePM"); | 2076 | snprintf(info->fix.id, 16, "ProSavagePM"); |
1903 | break; | 2077 | break; |
1904 | case FB_ACCEL_PROSAVAGE_KM: | 2078 | case FB_ACCEL_PROSAVAGE_KM: |
1905 | par->chip = S3_PROSAVAGE; | 2079 | par->chip = S3_PROSAVAGE; |
1906 | snprintf (info->fix.id, 16, "ProSavageKM"); | 2080 | snprintf(info->fix.id, 16, "ProSavageKM"); |
1907 | break; | 2081 | break; |
1908 | case FB_ACCEL_S3TWISTER_P: | 2082 | case FB_ACCEL_S3TWISTER_P: |
1909 | par->chip = S3_PROSAVAGE; | 2083 | par->chip = S3_PROSAVAGE; |
1910 | snprintf (info->fix.id, 16, "TwisterP"); | 2084 | snprintf(info->fix.id, 16, "TwisterP"); |
1911 | break; | 2085 | break; |
1912 | case FB_ACCEL_S3TWISTER_K: | 2086 | case FB_ACCEL_S3TWISTER_K: |
1913 | par->chip = S3_PROSAVAGE; | 2087 | par->chip = S3_PROSAVAGE; |
1914 | snprintf (info->fix.id, 16, "TwisterK"); | 2088 | snprintf(info->fix.id, 16, "TwisterK"); |
1915 | break; | 2089 | break; |
1916 | case FB_ACCEL_PROSAVAGE_DDR: | 2090 | case FB_ACCEL_PROSAVAGE_DDR: |
1917 | par->chip = S3_PROSAVAGE; | 2091 | par->chip = S3_PROSAVAGE; |
1918 | snprintf (info->fix.id, 16, "ProSavageDDR"); | 2092 | snprintf(info->fix.id, 16, "ProSavageDDR"); |
1919 | break; | 2093 | break; |
1920 | case FB_ACCEL_PROSAVAGE_DDRK: | 2094 | case FB_ACCEL_PROSAVAGE_DDRK: |
1921 | par->chip = S3_PROSAVAGE; | 2095 | par->chip = S3_PROSAVAGE; |
1922 | snprintf (info->fix.id, 16, "ProSavage8"); | 2096 | snprintf(info->fix.id, 16, "ProSavage8"); |
1923 | break; | 2097 | break; |
1924 | } | 2098 | } |
1925 | 2099 | ||
@@ -1960,7 +2134,7 @@ static int __devinit savage_init_fb_info (struct fb_info *info, | |||
1960 | info->pixmap.buf_align = 4; | 2134 | info->pixmap.buf_align = 4; |
1961 | info->pixmap.access_align = 32; | 2135 | info->pixmap.access_align = 32; |
1962 | 2136 | ||
1963 | err = fb_alloc_cmap (&info->cmap, NR_PALETTE, 0); | 2137 | err = fb_alloc_cmap(&info->cmap, NR_PALETTE, 0); |
1964 | if (!err) | 2138 | if (!err) |
1965 | info->flags |= FBINFO_HWACCEL_COPYAREA | | 2139 | info->flags |= FBINFO_HWACCEL_COPYAREA | |
1966 | FBINFO_HWACCEL_FILLRECT | | 2140 | FBINFO_HWACCEL_FILLRECT | |
@@ -1972,8 +2146,8 @@ static int __devinit savage_init_fb_info (struct fb_info *info, | |||
1972 | 2146 | ||
1973 | /* --------------------------------------------------------------------- */ | 2147 | /* --------------------------------------------------------------------- */ |
1974 | 2148 | ||
1975 | static int __devinit savagefb_probe (struct pci_dev* dev, | 2149 | static int __devinit savagefb_probe(struct pci_dev* dev, |
1976 | const struct pci_device_id* id) | 2150 | const struct pci_device_id* id) |
1977 | { | 2151 | { |
1978 | struct fb_info *info; | 2152 | struct fb_info *info; |
1979 | struct savagefb_par *par; | 2153 | struct savagefb_par *par; |
@@ -2085,12 +2259,12 @@ static int __devinit savagefb_probe (struct pci_dev* dev, | |||
2085 | fb_destroy_modedb(info->monspecs.modedb); | 2259 | fb_destroy_modedb(info->monspecs.modedb); |
2086 | info->monspecs.modedb = NULL; | 2260 | info->monspecs.modedb = NULL; |
2087 | 2261 | ||
2088 | err = register_framebuffer (info); | 2262 | err = register_framebuffer(info); |
2089 | if (err < 0) | 2263 | if (err < 0) |
2090 | goto failed; | 2264 | goto failed; |
2091 | 2265 | ||
2092 | printk (KERN_INFO "fb: S3 %s frame buffer device\n", | 2266 | printk(KERN_INFO "fb: S3 %s frame buffer device\n", |
2093 | info->fix.id); | 2267 | info->fix.id); |
2094 | 2268 | ||
2095 | /* | 2269 | /* |
2096 | * Our driver data | 2270 | * Our driver data |
@@ -2103,10 +2277,10 @@ static int __devinit savagefb_probe (struct pci_dev* dev, | |||
2103 | #ifdef CONFIG_FB_SAVAGE_I2C | 2277 | #ifdef CONFIG_FB_SAVAGE_I2C |
2104 | savagefb_delete_i2c_busses(info); | 2278 | savagefb_delete_i2c_busses(info); |
2105 | #endif | 2279 | #endif |
2106 | fb_alloc_cmap (&info->cmap, 0, 0); | 2280 | fb_alloc_cmap(&info->cmap, 0, 0); |
2107 | savage_unmap_video(info); | 2281 | savage_unmap_video(info); |
2108 | failed_video: | 2282 | failed_video: |
2109 | savage_unmap_mmio (info); | 2283 | savage_unmap_mmio(info); |
2110 | failed_mmio: | 2284 | failed_mmio: |
2111 | kfree(info->pixmap.addr); | 2285 | kfree(info->pixmap.addr); |
2112 | failed_init: | 2286 | failed_init: |
@@ -2117,7 +2291,7 @@ static int __devinit savagefb_probe (struct pci_dev* dev, | |||
2117 | return err; | 2291 | return err; |
2118 | } | 2292 | } |
2119 | 2293 | ||
2120 | static void __devexit savagefb_remove (struct pci_dev *dev) | 2294 | static void __devexit savagefb_remove(struct pci_dev *dev) |
2121 | { | 2295 | { |
2122 | struct fb_info *info = pci_get_drvdata(dev); | 2296 | struct fb_info *info = pci_get_drvdata(dev); |
2123 | 2297 | ||
@@ -2129,16 +2303,16 @@ static void __devexit savagefb_remove (struct pci_dev *dev) | |||
2129 | * we will be leaving hooks that could cause | 2303 | * we will be leaving hooks that could cause |
2130 | * oopsen laying around. | 2304 | * oopsen laying around. |
2131 | */ | 2305 | */ |
2132 | if (unregister_framebuffer (info)) | 2306 | if (unregister_framebuffer(info)) |
2133 | printk (KERN_WARNING "savagefb: danger danger! " | 2307 | printk(KERN_WARNING "savagefb: danger danger! " |
2134 | "Oopsen imminent!\n"); | 2308 | "Oopsen imminent!\n"); |
2135 | 2309 | ||
2136 | #ifdef CONFIG_FB_SAVAGE_I2C | 2310 | #ifdef CONFIG_FB_SAVAGE_I2C |
2137 | savagefb_delete_i2c_busses(info); | 2311 | savagefb_delete_i2c_busses(info); |
2138 | #endif | 2312 | #endif |
2139 | fb_alloc_cmap (&info->cmap, 0, 0); | 2313 | fb_alloc_cmap(&info->cmap, 0, 0); |
2140 | savage_unmap_video (info); | 2314 | savage_unmap_video(info); |
2141 | savage_unmap_mmio (info); | 2315 | savage_unmap_mmio(info); |
2142 | kfree(info->pixmap.addr); | 2316 | kfree(info->pixmap.addr); |
2143 | pci_release_regions(dev); | 2317 | pci_release_regions(dev); |
2144 | framebuffer_release(info); | 2318 | framebuffer_release(info); |
@@ -2151,7 +2325,7 @@ static void __devexit savagefb_remove (struct pci_dev *dev) | |||
2151 | } | 2325 | } |
2152 | } | 2326 | } |
2153 | 2327 | ||
2154 | static int savagefb_suspend (struct pci_dev* dev, pm_message_t state) | 2328 | static int savagefb_suspend(struct pci_dev* dev, pm_message_t state) |
2155 | { | 2329 | { |
2156 | struct fb_info *info = pci_get_drvdata(dev); | 2330 | struct fb_info *info = pci_get_drvdata(dev); |
2157 | struct savagefb_par *par = info->par; | 2331 | struct savagefb_par *par = info->par; |
@@ -2177,6 +2351,7 @@ static int savagefb_suspend (struct pci_dev* dev, pm_message_t state) | |||
2177 | info->fbops->fb_sync(info); | 2351 | info->fbops->fb_sync(info); |
2178 | 2352 | ||
2179 | savagefb_blank(FB_BLANK_POWERDOWN, info); | 2353 | savagefb_blank(FB_BLANK_POWERDOWN, info); |
2354 | savage_set_default_par(par, &par->save); | ||
2180 | savage_disable_mmio(par); | 2355 | savage_disable_mmio(par); |
2181 | pci_save_state(dev); | 2356 | pci_save_state(dev); |
2182 | pci_disable_device(dev); | 2357 | pci_disable_device(dev); |
@@ -2186,7 +2361,7 @@ static int savagefb_suspend (struct pci_dev* dev, pm_message_t state) | |||
2186 | return 0; | 2361 | return 0; |
2187 | } | 2362 | } |
2188 | 2363 | ||
2189 | static int savagefb_resume (struct pci_dev* dev) | 2364 | static int savagefb_resume(struct pci_dev* dev) |
2190 | { | 2365 | { |
2191 | struct fb_info *info = pci_get_drvdata(dev); | 2366 | struct fb_info *info = pci_get_drvdata(dev); |
2192 | struct savagefb_par *par = info->par; | 2367 | struct savagefb_par *par = info->par; |
@@ -2210,15 +2385,15 @@ static int savagefb_resume (struct pci_dev* dev) | |||
2210 | pci_set_power_state(dev, PCI_D0); | 2385 | pci_set_power_state(dev, PCI_D0); |
2211 | pci_restore_state(dev); | 2386 | pci_restore_state(dev); |
2212 | 2387 | ||
2213 | if(pci_enable_device(dev)) | 2388 | if (pci_enable_device(dev)) |
2214 | DBG("err"); | 2389 | DBG("err"); |
2215 | 2390 | ||
2216 | pci_set_master(dev); | 2391 | pci_set_master(dev); |
2217 | savage_enable_mmio(par); | 2392 | savage_enable_mmio(par); |
2218 | savage_init_hw(par); | 2393 | savage_init_hw(par); |
2219 | savagefb_set_par (info); | 2394 | savagefb_set_par(info); |
2395 | fb_set_suspend(info, 0); | ||
2220 | savagefb_blank(FB_BLANK_UNBLANK, info); | 2396 | savagefb_blank(FB_BLANK_UNBLANK, info); |
2221 | fb_set_suspend (info, 0); | ||
2222 | release_console_sem(); | 2397 | release_console_sem(); |
2223 | 2398 | ||
2224 | return 0; | 2399 | return 0; |
@@ -2311,10 +2486,10 @@ static struct pci_driver savagefb_driver = { | |||
2311 | 2486 | ||
2312 | /* **************************** exit-time only **************************** */ | 2487 | /* **************************** exit-time only **************************** */ |
2313 | 2488 | ||
2314 | static void __exit savage_done (void) | 2489 | static void __exit savage_done(void) |
2315 | { | 2490 | { |
2316 | DBG("savage_done"); | 2491 | DBG("savage_done"); |
2317 | pci_unregister_driver (&savagefb_driver); | 2492 | pci_unregister_driver(&savagefb_driver); |
2318 | } | 2493 | } |
2319 | 2494 | ||
2320 | 2495 | ||
@@ -2345,7 +2520,7 @@ static int __init savagefb_init(void) | |||
2345 | return -ENODEV; | 2520 | return -ENODEV; |
2346 | 2521 | ||
2347 | savagefb_setup(option); | 2522 | savagefb_setup(option); |
2348 | return pci_register_driver (&savagefb_driver); | 2523 | return pci_register_driver(&savagefb_driver); |
2349 | 2524 | ||
2350 | } | 2525 | } |
2351 | 2526 | ||
diff --git a/drivers/video/sis/sis_main.c b/drivers/video/sis/sis_main.c index 8adf5bf91eee..c63c0e721b82 100644 --- a/drivers/video/sis/sis_main.c +++ b/drivers/video/sis/sis_main.c | |||
@@ -275,7 +275,7 @@ sisfb_search_mode(char *name, BOOLEAN quiet) | |||
275 | static void __devinit | 275 | static void __devinit |
276 | sisfb_get_vga_mode_from_kernel(void) | 276 | sisfb_get_vga_mode_from_kernel(void) |
277 | { | 277 | { |
278 | #if (defined(__i386__) || defined(__x86_64__)) && defined(CONFIG_VIDEO_SELECT) | 278 | #ifdef CONFIG_X86 |
279 | char mymode[32]; | 279 | char mymode[32]; |
280 | int mydepth = screen_info.lfb_depth; | 280 | int mydepth = screen_info.lfb_depth; |
281 | 281 | ||
diff --git a/drivers/video/skeletonfb.c b/drivers/video/skeletonfb.c index 9b707771d757..67f429e93189 100644 --- a/drivers/video/skeletonfb.c +++ b/drivers/video/skeletonfb.c | |||
@@ -906,11 +906,6 @@ static void __exit xxxfb_exit(void) | |||
906 | } | 906 | } |
907 | #endif | 907 | #endif |
908 | 908 | ||
909 | MODULE_LICENSE("GPL"); | ||
910 | module_init(xxxfb_init); | ||
911 | module_exit(xxxfb_exit); | ||
912 | |||
913 | |||
914 | /* | 909 | /* |
915 | * Setup | 910 | * Setup |
916 | */ | 911 | */ |
diff --git a/drivers/video/tgafb.c b/drivers/video/tgafb.c index 7398bd48ba6c..6c2c78ab9827 100644 --- a/drivers/video/tgafb.c +++ b/drivers/video/tgafb.c | |||
@@ -26,7 +26,6 @@ | |||
26 | #include <linux/selection.h> | 26 | #include <linux/selection.h> |
27 | #include <asm/io.h> | 27 | #include <asm/io.h> |
28 | #include <video/tgafb.h> | 28 | #include <video/tgafb.h> |
29 | #include <linux/selection.h> | ||
30 | 29 | ||
31 | /* | 30 | /* |
32 | * Local functions. | 31 | * Local functions. |
diff --git a/drivers/video/vesafb.c b/drivers/video/vesafb.c index b0b9acfdd430..5718924b677f 100644 --- a/drivers/video/vesafb.c +++ b/drivers/video/vesafb.c | |||
@@ -51,7 +51,7 @@ static int inverse = 0; | |||
51 | static int mtrr = 0; /* disable mtrr */ | 51 | static int mtrr = 0; /* disable mtrr */ |
52 | static int vram_remap __initdata = 0; /* Set amount of memory to be used */ | 52 | static int vram_remap __initdata = 0; /* Set amount of memory to be used */ |
53 | static int vram_total __initdata = 0; /* Set total amount of memory */ | 53 | static int vram_total __initdata = 0; /* Set total amount of memory */ |
54 | static int pmi_setpal = 0; /* pmi for palette changes ??? */ | 54 | static int pmi_setpal = 1; /* pmi for palette changes ??? */ |
55 | static int ypan = 0; /* 0..nothing, 1..ypan, 2..ywrap */ | 55 | static int ypan = 0; /* 0..nothing, 1..ypan, 2..ywrap */ |
56 | static unsigned short *pmi_base = NULL; | 56 | static unsigned short *pmi_base = NULL; |
57 | static void (*pmi_start)(void); | 57 | static void (*pmi_start)(void); |
@@ -80,15 +80,30 @@ static int vesafb_pan_display(struct fb_var_screeninfo *var, | |||
80 | return 0; | 80 | return 0; |
81 | } | 81 | } |
82 | 82 | ||
83 | static void vesa_setpalette(int regno, unsigned red, unsigned green, | 83 | static int vesa_setpalette(int regno, unsigned red, unsigned green, |
84 | unsigned blue) | 84 | unsigned blue) |
85 | { | 85 | { |
86 | int shift = 16 - depth; | 86 | int shift = 16 - depth; |
87 | int err = -EINVAL; | ||
88 | |||
89 | /* | ||
90 | * Try VGA registers first... | ||
91 | */ | ||
92 | if (vga_compat) { | ||
93 | outb_p(regno, dac_reg); | ||
94 | outb_p(red >> shift, dac_val); | ||
95 | outb_p(green >> shift, dac_val); | ||
96 | outb_p(blue >> shift, dac_val); | ||
97 | err = 0; | ||
98 | } | ||
87 | 99 | ||
88 | #ifdef __i386__ | 100 | #ifdef __i386__ |
89 | struct { u_char blue, green, red, pad; } entry; | 101 | /* |
102 | * Fallback to the PMI.... | ||
103 | */ | ||
104 | if (err && pmi_setpal) { | ||
105 | struct { u_char blue, green, red, pad; } entry; | ||
90 | 106 | ||
91 | if (pmi_setpal) { | ||
92 | entry.red = red >> shift; | 107 | entry.red = red >> shift; |
93 | entry.green = green >> shift; | 108 | entry.green = green >> shift; |
94 | entry.blue = blue >> shift; | 109 | entry.blue = blue >> shift; |
@@ -102,26 +117,19 @@ static void vesa_setpalette(int regno, unsigned red, unsigned green, | |||
102 | "d" (regno), /* EDX */ | 117 | "d" (regno), /* EDX */ |
103 | "D" (&entry), /* EDI */ | 118 | "D" (&entry), /* EDI */ |
104 | "S" (&pmi_pal)); /* ESI */ | 119 | "S" (&pmi_pal)); /* ESI */ |
105 | return; | 120 | err = 0; |
106 | } | 121 | } |
107 | #endif | 122 | #endif |
108 | 123 | ||
109 | /* | 124 | return err; |
110 | * without protected mode interface and if VGA compatible, | ||
111 | * try VGA registers... | ||
112 | */ | ||
113 | if (vga_compat) { | ||
114 | outb_p(regno, dac_reg); | ||
115 | outb_p(red >> shift, dac_val); | ||
116 | outb_p(green >> shift, dac_val); | ||
117 | outb_p(blue >> shift, dac_val); | ||
118 | } | ||
119 | } | 125 | } |
120 | 126 | ||
121 | static int vesafb_setcolreg(unsigned regno, unsigned red, unsigned green, | 127 | static int vesafb_setcolreg(unsigned regno, unsigned red, unsigned green, |
122 | unsigned blue, unsigned transp, | 128 | unsigned blue, unsigned transp, |
123 | struct fb_info *info) | 129 | struct fb_info *info) |
124 | { | 130 | { |
131 | int err = 0; | ||
132 | |||
125 | /* | 133 | /* |
126 | * Set a single color register. The values supplied are | 134 | * Set a single color register. The values supplied are |
127 | * already rounded down to the hardware's capabilities | 135 | * already rounded down to the hardware's capabilities |
@@ -133,7 +141,7 @@ static int vesafb_setcolreg(unsigned regno, unsigned red, unsigned green, | |||
133 | return 1; | 141 | return 1; |
134 | 142 | ||
135 | if (info->var.bits_per_pixel == 8) | 143 | if (info->var.bits_per_pixel == 8) |
136 | vesa_setpalette(regno,red,green,blue); | 144 | err = vesa_setpalette(regno,red,green,blue); |
137 | else if (regno < 16) { | 145 | else if (regno < 16) { |
138 | switch (info->var.bits_per_pixel) { | 146 | switch (info->var.bits_per_pixel) { |
139 | case 16: | 147 | case 16: |
@@ -164,7 +172,7 @@ static int vesafb_setcolreg(unsigned regno, unsigned red, unsigned green, | |||
164 | } | 172 | } |
165 | } | 173 | } |
166 | 174 | ||
167 | return 0; | 175 | return err; |
168 | } | 176 | } |
169 | 177 | ||
170 | static struct fb_ops vesafb_ops = { | 178 | static struct fb_ops vesafb_ops = { |
@@ -460,9 +468,7 @@ static struct platform_driver vesafb_driver = { | |||
460 | }, | 468 | }, |
461 | }; | 469 | }; |
462 | 470 | ||
463 | static struct platform_device vesafb_device = { | 471 | static struct platform_device *vesafb_device; |
464 | .name = "vesafb", | ||
465 | }; | ||
466 | 472 | ||
467 | static int __init vesafb_init(void) | 473 | static int __init vesafb_init(void) |
468 | { | 474 | { |
@@ -475,10 +481,19 @@ static int __init vesafb_init(void) | |||
475 | ret = platform_driver_register(&vesafb_driver); | 481 | ret = platform_driver_register(&vesafb_driver); |
476 | 482 | ||
477 | if (!ret) { | 483 | if (!ret) { |
478 | ret = platform_device_register(&vesafb_device); | 484 | vesafb_device = platform_device_alloc("vesafb", 0); |
479 | if (ret) | 485 | |
486 | if (vesafb_device) | ||
487 | ret = platform_device_add(vesafb_device); | ||
488 | else | ||
489 | ret = -ENOMEM; | ||
490 | |||
491 | if (ret) { | ||
492 | platform_device_put(vesafb_device); | ||
480 | platform_driver_unregister(&vesafb_driver); | 493 | platform_driver_unregister(&vesafb_driver); |
494 | } | ||
481 | } | 495 | } |
496 | |||
482 | return ret; | 497 | return ret; |
483 | } | 498 | } |
484 | module_init(vesafb_init); | 499 | module_init(vesafb_init); |
diff --git a/drivers/video/vfb.c b/drivers/video/vfb.c index 77eed1fd9943..d073ffb6e1f9 100644 --- a/drivers/video/vfb.c +++ b/drivers/video/vfb.c | |||
@@ -398,12 +398,6 @@ static int __init vfb_setup(char *options) | |||
398 | * Initialisation | 398 | * Initialisation |
399 | */ | 399 | */ |
400 | 400 | ||
401 | static void vfb_platform_release(struct device *device) | ||
402 | { | ||
403 | // This is called when the reference count goes to zero. | ||
404 | dev_err(device, "This driver is broken, please bug the authors so they will fix it.\n"); | ||
405 | } | ||
406 | |||
407 | static int __init vfb_probe(struct platform_device *dev) | 401 | static int __init vfb_probe(struct platform_device *dev) |
408 | { | 402 | { |
409 | struct fb_info *info; | 403 | struct fb_info *info; |
@@ -482,13 +476,7 @@ static struct platform_driver vfb_driver = { | |||
482 | }, | 476 | }, |
483 | }; | 477 | }; |
484 | 478 | ||
485 | static struct platform_device vfb_device = { | 479 | static struct platform_device *vfb_device; |
486 | .name = "vfb", | ||
487 | .id = 0, | ||
488 | .dev = { | ||
489 | .release = vfb_platform_release, | ||
490 | } | ||
491 | }; | ||
492 | 480 | ||
493 | static int __init vfb_init(void) | 481 | static int __init vfb_init(void) |
494 | { | 482 | { |
@@ -508,10 +496,19 @@ static int __init vfb_init(void) | |||
508 | ret = platform_driver_register(&vfb_driver); | 496 | ret = platform_driver_register(&vfb_driver); |
509 | 497 | ||
510 | if (!ret) { | 498 | if (!ret) { |
511 | ret = platform_device_register(&vfb_device); | 499 | vfb_device = platform_device_alloc("vfb", 0); |
512 | if (ret) | 500 | |
501 | if (vfb_device) | ||
502 | ret = platform_device_add(vfb_device); | ||
503 | else | ||
504 | ret = -ENOMEM; | ||
505 | |||
506 | if (ret) { | ||
507 | platform_device_put(vfb_device); | ||
513 | platform_driver_unregister(&vfb_driver); | 508 | platform_driver_unregister(&vfb_driver); |
509 | } | ||
514 | } | 510 | } |
511 | |||
515 | return ret; | 512 | return ret; |
516 | } | 513 | } |
517 | 514 | ||
@@ -520,7 +517,7 @@ module_init(vfb_init); | |||
520 | #ifdef MODULE | 517 | #ifdef MODULE |
521 | static void __exit vfb_exit(void) | 518 | static void __exit vfb_exit(void) |
522 | { | 519 | { |
523 | platform_device_unregister(&vfb_device); | 520 | platform_device_unregister(vfb_device); |
524 | platform_driver_unregister(&vfb_driver); | 521 | platform_driver_unregister(&vfb_driver); |
525 | } | 522 | } |
526 | 523 | ||
diff --git a/drivers/video/vga16fb.c b/drivers/video/vga16fb.c index 4fd2a272e03d..3c404c9bd36c 100644 --- a/drivers/video/vga16fb.c +++ b/drivers/video/vga16fb.c | |||
@@ -1334,9 +1334,8 @@ static int vga16fb_setup(char *options) | |||
1334 | } | 1334 | } |
1335 | #endif | 1335 | #endif |
1336 | 1336 | ||
1337 | static int __init vga16fb_probe(struct device *device) | 1337 | static int __init vga16fb_probe(struct platform_device *dev) |
1338 | { | 1338 | { |
1339 | struct platform_device *dev = to_platform_device(device); | ||
1340 | struct fb_info *info; | 1339 | struct fb_info *info; |
1341 | struct vga16fb_par *par; | 1340 | struct vga16fb_par *par; |
1342 | int i; | 1341 | int i; |
@@ -1403,7 +1402,7 @@ static int __init vga16fb_probe(struct device *device) | |||
1403 | 1402 | ||
1404 | printk(KERN_INFO "fb%d: %s frame buffer device\n", | 1403 | printk(KERN_INFO "fb%d: %s frame buffer device\n", |
1405 | info->node, info->fix.id); | 1404 | info->node, info->fix.id); |
1406 | dev_set_drvdata(device, info); | 1405 | platform_set_drvdata(dev, info); |
1407 | 1406 | ||
1408 | return 0; | 1407 | return 0; |
1409 | 1408 | ||
@@ -1417,9 +1416,9 @@ static int __init vga16fb_probe(struct device *device) | |||
1417 | return ret; | 1416 | return ret; |
1418 | } | 1417 | } |
1419 | 1418 | ||
1420 | static int vga16fb_remove(struct device *device) | 1419 | static int vga16fb_remove(struct platform_device *dev) |
1421 | { | 1420 | { |
1422 | struct fb_info *info = dev_get_drvdata(device); | 1421 | struct fb_info *info = platform_get_drvdata(dev); |
1423 | 1422 | ||
1424 | if (info) { | 1423 | if (info) { |
1425 | unregister_framebuffer(info); | 1424 | unregister_framebuffer(info); |
@@ -1432,16 +1431,15 @@ static int vga16fb_remove(struct device *device) | |||
1432 | return 0; | 1431 | return 0; |
1433 | } | 1432 | } |
1434 | 1433 | ||
1435 | static struct device_driver vga16fb_driver = { | 1434 | static struct platform_driver vga16fb_driver = { |
1436 | .name = "vga16fb", | ||
1437 | .bus = &platform_bus_type, | ||
1438 | .probe = vga16fb_probe, | 1435 | .probe = vga16fb_probe, |
1439 | .remove = vga16fb_remove, | 1436 | .remove = vga16fb_remove, |
1437 | .driver = { | ||
1438 | .name = "vga16fb", | ||
1439 | }, | ||
1440 | }; | 1440 | }; |
1441 | 1441 | ||
1442 | static struct platform_device vga16fb_device = { | 1442 | static struct platform_device *vga16fb_device; |
1443 | .name = "vga16fb", | ||
1444 | }; | ||
1445 | 1443 | ||
1446 | static int __init vga16fb_init(void) | 1444 | static int __init vga16fb_init(void) |
1447 | { | 1445 | { |
@@ -1454,12 +1452,20 @@ static int __init vga16fb_init(void) | |||
1454 | 1452 | ||
1455 | vga16fb_setup(option); | 1453 | vga16fb_setup(option); |
1456 | #endif | 1454 | #endif |
1457 | ret = driver_register(&vga16fb_driver); | 1455 | ret = platform_driver_register(&vga16fb_driver); |
1458 | 1456 | ||
1459 | if (!ret) { | 1457 | if (!ret) { |
1460 | ret = platform_device_register(&vga16fb_device); | 1458 | vga16fb_device = platform_device_alloc("vga16fb", 0); |
1461 | if (ret) | 1459 | |
1462 | driver_unregister(&vga16fb_driver); | 1460 | if (vga16fb_device) |
1461 | ret = platform_device_add(vga16fb_device); | ||
1462 | else | ||
1463 | ret = -ENOMEM; | ||
1464 | |||
1465 | if (ret) { | ||
1466 | platform_device_put(vga16fb_device); | ||
1467 | platform_driver_unregister(&vga16fb_driver); | ||
1468 | } | ||
1463 | } | 1469 | } |
1464 | 1470 | ||
1465 | return ret; | 1471 | return ret; |
@@ -1467,8 +1473,8 @@ static int __init vga16fb_init(void) | |||
1467 | 1473 | ||
1468 | static void __exit vga16fb_exit(void) | 1474 | static void __exit vga16fb_exit(void) |
1469 | { | 1475 | { |
1470 | platform_device_unregister(&vga16fb_device); | 1476 | platform_device_unregister(vga16fb_device); |
1471 | driver_unregister(&vga16fb_driver); | 1477 | platform_driver_unregister(&vga16fb_driver); |
1472 | } | 1478 | } |
1473 | 1479 | ||
1474 | MODULE_LICENSE("GPL"); | 1480 | MODULE_LICENSE("GPL"); |