diff options
Diffstat (limited to 'drivers/char')
120 files changed, 4659 insertions, 3049 deletions
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index c40e487d9f5c..bde1c665d9f4 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig | |||
@@ -439,6 +439,14 @@ config SGI_MBCS | |||
439 | If you have an SGI Altix with an attached SABrick | 439 | If you have an SGI Altix with an attached SABrick |
440 | say Y or M here, otherwise say N. | 440 | say Y or M here, otherwise say N. |
441 | 441 | ||
442 | config MSPEC | ||
443 | tristate "Memory special operations driver" | ||
444 | depends on IA64 | ||
445 | help | ||
446 | If you have an ia64 and you want to enable memory special | ||
447 | operations support (formerly known as fetchop), say Y here, | ||
448 | otherwise say N. | ||
449 | |||
442 | source "drivers/serial/Kconfig" | 450 | source "drivers/serial/Kconfig" |
443 | 451 | ||
444 | config UNIX98_PTYS | 452 | config UNIX98_PTYS |
@@ -495,6 +503,21 @@ config LEGACY_PTY_COUNT | |||
495 | When not in use, each legacy PTY occupies 12 bytes on 32-bit | 503 | When not in use, each legacy PTY occupies 12 bytes on 32-bit |
496 | architectures and 24 bytes on 64-bit architectures. | 504 | architectures and 24 bytes on 64-bit architectures. |
497 | 505 | ||
506 | config BRIQ_PANEL | ||
507 | tristate 'Total Impact briQ front panel driver' | ||
508 | depends on PPC_CHRP | ||
509 | ---help--- | ||
510 | The briQ is a small footprint CHRP computer with a frontpanel VFD, a | ||
511 | tristate led and two switches. It is the size of a CDROM drive. | ||
512 | |||
513 | If you have such one and want anything showing on the VFD then you | ||
514 | must answer Y here. | ||
515 | |||
516 | To compile this driver as a module, choose M here: the | ||
517 | module will be called briq_panel. | ||
518 | |||
519 | It's safe to say N here. | ||
520 | |||
498 | config PRINTER | 521 | config PRINTER |
499 | tristate "Parallel printer support" | 522 | tristate "Parallel printer support" |
500 | depends on PARPORT | 523 | depends on PARPORT |
@@ -596,6 +619,13 @@ config HVC_CONSOLE | |||
596 | console. This driver allows each pSeries partition to have a console | 619 | console. This driver allows each pSeries partition to have a console |
597 | which is accessed via the HMC. | 620 | which is accessed via the HMC. |
598 | 621 | ||
622 | config HVC_ISERIES | ||
623 | bool "iSeries Hypervisor Virtual Console support" | ||
624 | depends on PPC_ISERIES && !VIOCONS | ||
625 | select HVC_DRIVER | ||
626 | help | ||
627 | iSeries machines support a hypervisor virtual console. | ||
628 | |||
599 | config HVC_RTAS | 629 | config HVC_RTAS |
600 | bool "IBM RTAS Console support" | 630 | bool "IBM RTAS Console support" |
601 | depends on PPC_RTAS | 631 | depends on PPC_RTAS |
@@ -717,7 +747,7 @@ config NVRAM | |||
717 | 747 | ||
718 | config RTC | 748 | config RTC |
719 | tristate "Enhanced Real Time Clock Support" | 749 | tristate "Enhanced Real Time Clock Support" |
720 | depends on !PPC && !PARISC && !IA64 && !M68K && (!SPARC || PCI) && !FRV && !ARM | 750 | depends on !PPC && !PARISC && !IA64 && !M68K && (!SPARC || PCI) && !FRV && !ARM && !SUPERH |
721 | ---help--- | 751 | ---help--- |
722 | If you say Y here and create a character special file /dev/rtc with | 752 | If you say Y here and create a character special file /dev/rtc with |
723 | major number 10 and minor number 135 using mknod ("man mknod"), you | 753 | major number 10 and minor number 135 using mknod ("man mknod"), you |
@@ -801,14 +831,6 @@ config DS1302 | |||
801 | will get access to the real time clock (or hardware clock) built | 831 | will get access to the real time clock (or hardware clock) built |
802 | into your computer. | 832 | into your computer. |
803 | 833 | ||
804 | config S3C2410_RTC | ||
805 | bool "S3C2410 RTC Driver" | ||
806 | depends on ARCH_S3C2410 | ||
807 | help | ||
808 | RTC (Realtime Clock) driver for the clock inbuilt into the | ||
809 | Samsung S3C2410. This can provide periodic interrupt rates | ||
810 | from 1Hz to 64Hz for user programs, and wakeup from Alarm. | ||
811 | |||
812 | config COBALT_LCD | 834 | config COBALT_LCD |
813 | bool "Support for Cobalt LCD" | 835 | bool "Support for Cobalt LCD" |
814 | depends on MIPS_COBALT | 836 | depends on MIPS_COBALT |
@@ -984,6 +1006,7 @@ config GPIO_VR41XX | |||
984 | 1006 | ||
985 | config RAW_DRIVER | 1007 | config RAW_DRIVER |
986 | tristate "RAW driver (/dev/raw/rawN) (OBSOLETE)" | 1008 | tristate "RAW driver (/dev/raw/rawN) (OBSOLETE)" |
1009 | depends on BLOCK | ||
987 | help | 1010 | help |
988 | The raw driver permits block devices to be bound to /dev/raw/rawN. | 1011 | The raw driver permits block devices to be bound to /dev/raw/rawN. |
989 | Once bound, I/O against /dev/raw/rawN uses efficient zero-copy I/O. | 1012 | Once bound, I/O against /dev/raw/rawN uses efficient zero-copy I/O. |
diff --git a/drivers/char/Makefile b/drivers/char/Makefile index 6e0f4469d8bb..19114df59bbd 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile | |||
@@ -42,15 +42,18 @@ obj-$(CONFIG_AMIGA_BUILTIN_SERIAL) += amiserial.o | |||
42 | obj-$(CONFIG_SX) += sx.o generic_serial.o | 42 | obj-$(CONFIG_SX) += sx.o generic_serial.o |
43 | obj-$(CONFIG_RIO) += rio/ generic_serial.o | 43 | obj-$(CONFIG_RIO) += rio/ generic_serial.o |
44 | obj-$(CONFIG_HVC_CONSOLE) += hvc_vio.o hvsi.o | 44 | obj-$(CONFIG_HVC_CONSOLE) += hvc_vio.o hvsi.o |
45 | obj-$(CONFIG_HVC_ISERIES) += hvc_iseries.o | ||
45 | obj-$(CONFIG_HVC_RTAS) += hvc_rtas.o | 46 | obj-$(CONFIG_HVC_RTAS) += hvc_rtas.o |
46 | obj-$(CONFIG_HVC_DRIVER) += hvc_console.o | 47 | obj-$(CONFIG_HVC_DRIVER) += hvc_console.o |
47 | obj-$(CONFIG_RAW_DRIVER) += raw.o | 48 | obj-$(CONFIG_RAW_DRIVER) += raw.o |
48 | obj-$(CONFIG_SGI_SNSC) += snsc.o snsc_event.o | 49 | obj-$(CONFIG_SGI_SNSC) += snsc.o snsc_event.o |
50 | obj-$(CONFIG_MSPEC) += mspec.o | ||
49 | obj-$(CONFIG_MMTIMER) += mmtimer.o | 51 | obj-$(CONFIG_MMTIMER) += mmtimer.o |
50 | obj-$(CONFIG_VIOCONS) += viocons.o | 52 | obj-$(CONFIG_VIOCONS) += viocons.o |
51 | obj-$(CONFIG_VIOTAPE) += viotape.o | 53 | obj-$(CONFIG_VIOTAPE) += viotape.o |
52 | obj-$(CONFIG_HVCS) += hvcs.o | 54 | obj-$(CONFIG_HVCS) += hvcs.o |
53 | obj-$(CONFIG_SGI_MBCS) += mbcs.o | 55 | obj-$(CONFIG_SGI_MBCS) += mbcs.o |
56 | obj-$(CONFIG_BRIQ_PANEL) += briq_panel.o | ||
54 | 57 | ||
55 | obj-$(CONFIG_PRINTER) += lp.o | 58 | obj-$(CONFIG_PRINTER) += lp.o |
56 | obj-$(CONFIG_TIPAR) += tipar.o | 59 | obj-$(CONFIG_TIPAR) += tipar.o |
@@ -66,7 +69,6 @@ obj-$(CONFIG_EFI_RTC) += efirtc.o | |||
66 | obj-$(CONFIG_SGI_DS1286) += ds1286.o | 69 | obj-$(CONFIG_SGI_DS1286) += ds1286.o |
67 | obj-$(CONFIG_SGI_IP27_RTC) += ip27-rtc.o | 70 | obj-$(CONFIG_SGI_IP27_RTC) += ip27-rtc.o |
68 | obj-$(CONFIG_DS1302) += ds1302.o | 71 | obj-$(CONFIG_DS1302) += ds1302.o |
69 | obj-$(CONFIG_S3C2410_RTC) += s3c2410-rtc.o | ||
70 | ifeq ($(CONFIG_GENERIC_NVRAM),y) | 72 | ifeq ($(CONFIG_GENERIC_NVRAM),y) |
71 | obj-$(CONFIG_NVRAM) += generic_nvram.o | 73 | obj-$(CONFIG_NVRAM) += generic_nvram.o |
72 | else | 74 | else |
diff --git a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h index 3c623b67ea1c..8b3317fd46c9 100644 --- a/drivers/char/agp/agp.h +++ b/drivers/char/agp/agp.h | |||
@@ -117,7 +117,7 @@ struct agp_bridge_driver { | |||
117 | }; | 117 | }; |
118 | 118 | ||
119 | struct agp_bridge_data { | 119 | struct agp_bridge_data { |
120 | struct agp_version *version; | 120 | const struct agp_version *version; |
121 | struct agp_bridge_driver *driver; | 121 | struct agp_bridge_driver *driver; |
122 | struct vm_operations_struct *vm_ops; | 122 | struct vm_operations_struct *vm_ops; |
123 | void *previous_size; | 123 | void *previous_size; |
diff --git a/drivers/char/agp/amd64-agp.c b/drivers/char/agp/amd64-agp.c index 8cd52984cda5..00b17ae39736 100644 --- a/drivers/char/agp/amd64-agp.c +++ b/drivers/char/agp/amd64-agp.c | |||
@@ -409,7 +409,7 @@ static int __devinit uli_agp_init(struct pci_dev *pdev) | |||
409 | int i; | 409 | int i; |
410 | unsigned size = amd64_fetch_size(); | 410 | unsigned size = amd64_fetch_size(); |
411 | printk(KERN_INFO "Setting up ULi AGP.\n"); | 411 | printk(KERN_INFO "Setting up ULi AGP.\n"); |
412 | dev1 = pci_find_slot ((unsigned int)pdev->bus->number,PCI_DEVFN(0,0)); | 412 | dev1 = pci_get_slot (pdev->bus,PCI_DEVFN(0,0)); |
413 | if (dev1 == NULL) { | 413 | if (dev1 == NULL) { |
414 | printk(KERN_INFO PFX "Detected a ULi chipset, " | 414 | printk(KERN_INFO PFX "Detected a ULi chipset, " |
415 | "but could not fine the secondary device.\n"); | 415 | "but could not fine the secondary device.\n"); |
@@ -442,6 +442,8 @@ static int __devinit uli_agp_init(struct pci_dev *pdev) | |||
442 | enuscr= httfea+ (size * 1024 * 1024) - 1; | 442 | enuscr= httfea+ (size * 1024 * 1024) - 1; |
443 | pci_write_config_dword(dev1, ULI_X86_64_HTT_FEA_REG, httfea); | 443 | pci_write_config_dword(dev1, ULI_X86_64_HTT_FEA_REG, httfea); |
444 | pci_write_config_dword(dev1, ULI_X86_64_ENU_SCR_REG, enuscr); | 444 | pci_write_config_dword(dev1, ULI_X86_64_ENU_SCR_REG, enuscr); |
445 | |||
446 | pci_dev_put(dev1); | ||
445 | return 0; | 447 | return 0; |
446 | } | 448 | } |
447 | 449 | ||
@@ -466,7 +468,7 @@ static int __devinit nforce3_agp_init(struct pci_dev *pdev) | |||
466 | 468 | ||
467 | printk(KERN_INFO PFX "Setting up Nforce3 AGP.\n"); | 469 | printk(KERN_INFO PFX "Setting up Nforce3 AGP.\n"); |
468 | 470 | ||
469 | dev1 = pci_find_slot((unsigned int)pdev->bus->number, PCI_DEVFN(11, 0)); | 471 | dev1 = pci_get_slot(pdev->bus, PCI_DEVFN(11, 0)); |
470 | if (dev1 == NULL) { | 472 | if (dev1 == NULL) { |
471 | printk(KERN_INFO PFX "agpgart: Detected an NVIDIA " | 473 | printk(KERN_INFO PFX "agpgart: Detected an NVIDIA " |
472 | "nForce3 chipset, but could not find " | 474 | "nForce3 chipset, but could not find " |
@@ -510,6 +512,8 @@ static int __devinit nforce3_agp_init(struct pci_dev *pdev) | |||
510 | pci_write_config_dword(dev1, NVIDIA_X86_64_1_APBASE2, apbase); | 512 | pci_write_config_dword(dev1, NVIDIA_X86_64_1_APBASE2, apbase); |
511 | pci_write_config_dword(dev1, NVIDIA_X86_64_1_APLIMIT2, aplimit); | 513 | pci_write_config_dword(dev1, NVIDIA_X86_64_1_APLIMIT2, aplimit); |
512 | 514 | ||
515 | pci_dev_put(dev1); | ||
516 | |||
513 | return 0; | 517 | return 0; |
514 | } | 518 | } |
515 | 519 | ||
diff --git a/drivers/char/agp/backend.c b/drivers/char/agp/backend.c index 509adc403250..d59e037ddd12 100644 --- a/drivers/char/agp/backend.c +++ b/drivers/char/agp/backend.c | |||
@@ -44,7 +44,7 @@ | |||
44 | * past 0.99 at all due to some boolean logic error. */ | 44 | * past 0.99 at all due to some boolean logic error. */ |
45 | #define AGPGART_VERSION_MAJOR 0 | 45 | #define AGPGART_VERSION_MAJOR 0 |
46 | #define AGPGART_VERSION_MINOR 101 | 46 | #define AGPGART_VERSION_MINOR 101 |
47 | static struct agp_version agp_current_version = | 47 | static const struct agp_version agp_current_version = |
48 | { | 48 | { |
49 | .major = AGPGART_VERSION_MAJOR, | 49 | .major = AGPGART_VERSION_MAJOR, |
50 | .minor = AGPGART_VERSION_MINOR, | 50 | .minor = AGPGART_VERSION_MINOR, |
diff --git a/drivers/char/agp/efficeon-agp.c b/drivers/char/agp/efficeon-agp.c index b788b0a3bbf3..30f730ff81c1 100644 --- a/drivers/char/agp/efficeon-agp.c +++ b/drivers/char/agp/efficeon-agp.c | |||
@@ -337,13 +337,6 @@ static struct agp_bridge_driver efficeon_driver = { | |||
337 | .agp_destroy_page = agp_generic_destroy_page, | 337 | .agp_destroy_page = agp_generic_destroy_page, |
338 | }; | 338 | }; |
339 | 339 | ||
340 | |||
341 | static int agp_efficeon_resume(struct pci_dev *pdev) | ||
342 | { | ||
343 | printk(KERN_DEBUG PFX "agp_efficeon_resume()\n"); | ||
344 | return efficeon_configure(); | ||
345 | } | ||
346 | |||
347 | static int __devinit agp_efficeon_probe(struct pci_dev *pdev, | 340 | static int __devinit agp_efficeon_probe(struct pci_dev *pdev, |
348 | const struct pci_device_id *ent) | 341 | const struct pci_device_id *ent) |
349 | { | 342 | { |
@@ -414,11 +407,18 @@ static void __devexit agp_efficeon_remove(struct pci_dev *pdev) | |||
414 | agp_put_bridge(bridge); | 407 | agp_put_bridge(bridge); |
415 | } | 408 | } |
416 | 409 | ||
410 | #ifdef CONFIG_PM | ||
417 | static int agp_efficeon_suspend(struct pci_dev *dev, pm_message_t state) | 411 | static int agp_efficeon_suspend(struct pci_dev *dev, pm_message_t state) |
418 | { | 412 | { |
419 | return 0; | 413 | return 0; |
420 | } | 414 | } |
421 | 415 | ||
416 | static int agp_efficeon_resume(struct pci_dev *pdev) | ||
417 | { | ||
418 | printk(KERN_DEBUG PFX "agp_efficeon_resume()\n"); | ||
419 | return efficeon_configure(); | ||
420 | } | ||
421 | #endif | ||
422 | 422 | ||
423 | static struct pci_device_id agp_efficeon_pci_table[] = { | 423 | static struct pci_device_id agp_efficeon_pci_table[] = { |
424 | { | 424 | { |
@@ -439,8 +439,10 @@ static struct pci_driver agp_efficeon_pci_driver = { | |||
439 | .id_table = agp_efficeon_pci_table, | 439 | .id_table = agp_efficeon_pci_table, |
440 | .probe = agp_efficeon_probe, | 440 | .probe = agp_efficeon_probe, |
441 | .remove = agp_efficeon_remove, | 441 | .remove = agp_efficeon_remove, |
442 | #ifdef CONFIG_PM | ||
442 | .suspend = agp_efficeon_suspend, | 443 | .suspend = agp_efficeon_suspend, |
443 | .resume = agp_efficeon_resume, | 444 | .resume = agp_efficeon_resume, |
445 | #endif | ||
444 | }; | 446 | }; |
445 | 447 | ||
446 | static int __init agp_efficeon_init(void) | 448 | static int __init agp_efficeon_init(void) |
diff --git a/drivers/char/agp/frontend.c b/drivers/char/agp/frontend.c index d9c5a9142ad1..0f2ed2aa2d81 100644 --- a/drivers/char/agp/frontend.c +++ b/drivers/char/agp/frontend.c | |||
@@ -151,35 +151,12 @@ static void agp_add_seg_to_client(struct agp_client *client, | |||
151 | client->segments = seg; | 151 | client->segments = seg; |
152 | } | 152 | } |
153 | 153 | ||
154 | /* Originally taken from linux/mm/mmap.c from the array | ||
155 | * protection_map. | ||
156 | * The original really should be exported to modules, or | ||
157 | * some routine which does the conversion for you | ||
158 | */ | ||
159 | |||
160 | static const pgprot_t my_protect_map[16] = | ||
161 | { | ||
162 | __P000, __P001, __P010, __P011, __P100, __P101, __P110, __P111, | ||
163 | __S000, __S001, __S010, __S011, __S100, __S101, __S110, __S111 | ||
164 | }; | ||
165 | |||
166 | static pgprot_t agp_convert_mmap_flags(int prot) | 154 | static pgprot_t agp_convert_mmap_flags(int prot) |
167 | { | 155 | { |
168 | #define _trans(x,bit1,bit2) \ | ||
169 | ((bit1==bit2)?(x&bit1):(x&bit1)?bit2:0) | ||
170 | |||
171 | unsigned long prot_bits; | 156 | unsigned long prot_bits; |
172 | pgprot_t temp; | ||
173 | |||
174 | prot_bits = _trans(prot, PROT_READ, VM_READ) | | ||
175 | _trans(prot, PROT_WRITE, VM_WRITE) | | ||
176 | _trans(prot, PROT_EXEC, VM_EXEC); | ||
177 | |||
178 | prot_bits |= VM_SHARED; | ||
179 | 157 | ||
180 | temp = my_protect_map[prot_bits & 0x0000000f]; | 158 | prot_bits = calc_vm_prot_bits(prot) | VM_SHARED; |
181 | 159 | return vm_get_page_prot(prot_bits); | |
182 | return temp; | ||
183 | } | 160 | } |
184 | 161 | ||
185 | static int agp_create_segment(struct agp_client *client, struct agp_region *region) | 162 | static int agp_create_segment(struct agp_client *client, struct agp_region *region) |
diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c index cc5ea347a8a7..c39200161688 100644 --- a/drivers/char/agp/generic.c +++ b/drivers/char/agp/generic.c | |||
@@ -568,25 +568,37 @@ static void agp_v3_parse_one(u32 *requested_mode, u32 *bridge_agpstat, u32 *vga_ | |||
568 | *bridge_agpstat &= ~(AGPSTAT3_4X | AGPSTAT3_RSVD); | 568 | *bridge_agpstat &= ~(AGPSTAT3_4X | AGPSTAT3_RSVD); |
569 | goto done; | 569 | goto done; |
570 | 570 | ||
571 | } else if (*requested_mode & AGPSTAT3_4X) { | ||
572 | *bridge_agpstat &= ~(AGPSTAT3_8X | AGPSTAT3_RSVD); | ||
573 | *bridge_agpstat |= AGPSTAT3_4X; | ||
574 | goto done; | ||
575 | |||
571 | } else { | 576 | } else { |
572 | 577 | ||
573 | /* | 578 | /* |
574 | * If we didn't specify AGPx8, we can only do x4. | 579 | * If we didn't specify an AGP mode, we see if both |
575 | * If the hardware can't do x4, we're up shit creek, and never | 580 | * the graphics card, and the bridge can do x8, and use if so. |
576 | * should have got this far. | 581 | * If not, we fall back to x4 mode. |
577 | */ | 582 | */ |
578 | *bridge_agpstat &= ~(AGPSTAT3_8X | AGPSTAT3_RSVD); | 583 | if ((*bridge_agpstat & AGPSTAT3_8X) && (*vga_agpstat & AGPSTAT3_8X)) { |
579 | if ((*bridge_agpstat & AGPSTAT3_4X) && (*vga_agpstat & AGPSTAT3_4X)) | 584 | printk(KERN_INFO PFX "No AGP mode specified. Setting to highest mode " |
580 | *bridge_agpstat |= AGPSTAT3_4X; | 585 | "supported by bridge & card (x8).\n"); |
581 | else { | 586 | *bridge_agpstat &= ~(AGPSTAT3_4X | AGPSTAT3_RSVD); |
582 | printk(KERN_INFO PFX "Badness. Don't know which AGP mode to set. " | 587 | *vga_agpstat &= ~(AGPSTAT3_4X | AGPSTAT3_RSVD); |
583 | "[bridge_agpstat:%x vga_agpstat:%x fell back to:- bridge_agpstat:%x vga_agpstat:%x]\n", | 588 | } else { |
584 | origbridge, origvga, *bridge_agpstat, *vga_agpstat); | 589 | printk(KERN_INFO PFX "Fell back to AGPx4 mode because"); |
585 | if (!(*bridge_agpstat & AGPSTAT3_4X)) | 590 | if (!(*bridge_agpstat & AGPSTAT3_8X)) { |
586 | printk(KERN_INFO PFX "Bridge couldn't do AGP x4.\n"); | 591 | printk(KERN_INFO PFX "bridge couldn't do x8. bridge_agpstat:%x (orig=%x)\n", |
587 | if (!(*vga_agpstat & AGPSTAT3_4X)) | 592 | *bridge_agpstat, origbridge); |
588 | printk(KERN_INFO PFX "Graphic card couldn't do AGP x4.\n"); | 593 | *bridge_agpstat &= ~(AGPSTAT3_8X | AGPSTAT3_RSVD); |
589 | return; | 594 | *bridge_agpstat |= AGPSTAT3_4X; |
595 | } | ||
596 | if (!(*vga_agpstat & AGPSTAT3_8X)) { | ||
597 | printk(KERN_INFO PFX "graphics card couldn't do x8. vga_agpstat:%x (orig=%x)\n", | ||
598 | *vga_agpstat, origvga); | ||
599 | *vga_agpstat &= ~(AGPSTAT3_8X | AGPSTAT3_RSVD); | ||
600 | *vga_agpstat |= AGPSTAT3_4X; | ||
601 | } | ||
590 | } | 602 | } |
591 | } | 603 | } |
592 | 604 | ||
diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c index 61ac3809f997..d1ede7db5a12 100644 --- a/drivers/char/agp/intel-agp.c +++ b/drivers/char/agp/intel-agp.c | |||
@@ -2,14 +2,6 @@ | |||
2 | * Intel AGPGART routines. | 2 | * Intel AGPGART routines. |
3 | */ | 3 | */ |
4 | 4 | ||
5 | /* | ||
6 | * Intel(R) 855GM/852GM and 865G support added by David Dawes | ||
7 | * <dawes@tungstengraphics.com>. | ||
8 | * | ||
9 | * Intel(R) 915G/915GM support added by Alan Hourihane | ||
10 | * <alanh@tungstengraphics.com>. | ||
11 | */ | ||
12 | |||
13 | #include <linux/module.h> | 5 | #include <linux/module.h> |
14 | #include <linux/pci.h> | 6 | #include <linux/pci.h> |
15 | #include <linux/init.h> | 7 | #include <linux/init.h> |
@@ -17,6 +9,21 @@ | |||
17 | #include <linux/agp_backend.h> | 9 | #include <linux/agp_backend.h> |
18 | #include "agp.h" | 10 | #include "agp.h" |
19 | 11 | ||
12 | #define PCI_DEVICE_ID_INTEL_82946GZ_HB 0x2970 | ||
13 | #define PCI_DEVICE_ID_INTEL_82946GZ_IG 0x2972 | ||
14 | #define PCI_DEVICE_ID_INTEL_82965G_1_HB 0x2980 | ||
15 | #define PCI_DEVICE_ID_INTEL_82965G_1_IG 0x2982 | ||
16 | #define PCI_DEVICE_ID_INTEL_82965Q_HB 0x2990 | ||
17 | #define PCI_DEVICE_ID_INTEL_82965Q_IG 0x2992 | ||
18 | #define PCI_DEVICE_ID_INTEL_82965G_HB 0x29A0 | ||
19 | #define PCI_DEVICE_ID_INTEL_82965G_IG 0x29A2 | ||
20 | |||
21 | #define IS_I965 (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82946GZ_HB || \ | ||
22 | agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965G_1_HB || \ | ||
23 | agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965Q_HB || \ | ||
24 | agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965G_HB) | ||
25 | |||
26 | |||
20 | /* Intel 815 register */ | 27 | /* Intel 815 register */ |
21 | #define INTEL_815_APCONT 0x51 | 28 | #define INTEL_815_APCONT 0x51 |
22 | #define INTEL_815_ATTBASE_MASK ~0x1FFFFFFF | 29 | #define INTEL_815_ATTBASE_MASK ~0x1FFFFFFF |
@@ -40,6 +47,8 @@ | |||
40 | #define I915_GMCH_GMS_STOLEN_48M (0x6 << 4) | 47 | #define I915_GMCH_GMS_STOLEN_48M (0x6 << 4) |
41 | #define I915_GMCH_GMS_STOLEN_64M (0x7 << 4) | 48 | #define I915_GMCH_GMS_STOLEN_64M (0x7 << 4) |
42 | 49 | ||
50 | /* Intel 965G registers */ | ||
51 | #define I965_MSAC 0x62 | ||
43 | 52 | ||
44 | /* Intel 7505 registers */ | 53 | /* Intel 7505 registers */ |
45 | #define INTEL_I7505_APSIZE 0x74 | 54 | #define INTEL_I7505_APSIZE 0x74 |
@@ -354,6 +363,7 @@ static struct aper_size_info_fixed intel_i830_sizes[] = | |||
354 | /* The 64M mode still requires a 128k gatt */ | 363 | /* The 64M mode still requires a 128k gatt */ |
355 | {64, 16384, 5}, | 364 | {64, 16384, 5}, |
356 | {256, 65536, 6}, | 365 | {256, 65536, 6}, |
366 | {512, 131072, 7}, | ||
357 | }; | 367 | }; |
358 | 368 | ||
359 | static struct _intel_i830_private { | 369 | static struct _intel_i830_private { |
@@ -377,7 +387,11 @@ static void intel_i830_init_gtt_entries(void) | |||
377 | /* We obtain the size of the GTT, which is also stored (for some | 387 | /* We obtain the size of the GTT, which is also stored (for some |
378 | * reason) at the top of stolen memory. Then we add 4KB to that | 388 | * reason) at the top of stolen memory. Then we add 4KB to that |
379 | * for the video BIOS popup, which is also stored in there. */ | 389 | * for the video BIOS popup, which is also stored in there. */ |
380 | size = agp_bridge->driver->fetch_size() + 4; | 390 | |
391 | if (IS_I965) | ||
392 | size = 512 + 4; | ||
393 | else | ||
394 | size = agp_bridge->driver->fetch_size() + 4; | ||
381 | 395 | ||
382 | if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82830_HB || | 396 | if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82830_HB || |
383 | agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82845G_HB) { | 397 | agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82845G_HB) { |
@@ -423,7 +437,7 @@ static void intel_i830_init_gtt_entries(void) | |||
423 | if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915G_HB || | 437 | if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915G_HB || |
424 | agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB || | 438 | agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB || |
425 | agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945G_HB || | 439 | agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945G_HB || |
426 | agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GM_HB) | 440 | agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GM_HB || IS_I965 ) |
427 | gtt_entries = MB(48) - KB(size); | 441 | gtt_entries = MB(48) - KB(size); |
428 | else | 442 | else |
429 | gtt_entries = 0; | 443 | gtt_entries = 0; |
@@ -433,7 +447,7 @@ static void intel_i830_init_gtt_entries(void) | |||
433 | if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915G_HB || | 447 | if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915G_HB || |
434 | agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB || | 448 | agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB || |
435 | agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945G_HB || | 449 | agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945G_HB || |
436 | agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GM_HB) | 450 | agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GM_HB || IS_I965) |
437 | gtt_entries = MB(64) - KB(size); | 451 | gtt_entries = MB(64) - KB(size); |
438 | else | 452 | else |
439 | gtt_entries = 0; | 453 | gtt_entries = 0; |
@@ -791,6 +805,77 @@ static int intel_i915_create_gatt_table(struct agp_bridge_data *bridge) | |||
791 | 805 | ||
792 | return 0; | 806 | return 0; |
793 | } | 807 | } |
808 | static int intel_i965_fetch_size(void) | ||
809 | { | ||
810 | struct aper_size_info_fixed *values; | ||
811 | u32 offset = 0; | ||
812 | u8 temp; | ||
813 | |||
814 | #define I965_512MB_ADDRESS_MASK (3<<1) | ||
815 | |||
816 | values = A_SIZE_FIX(agp_bridge->driver->aperture_sizes); | ||
817 | |||
818 | pci_read_config_byte(intel_i830_private.i830_dev, I965_MSAC, &temp); | ||
819 | temp &= I965_512MB_ADDRESS_MASK; | ||
820 | switch (temp) { | ||
821 | case 0x00: | ||
822 | offset = 0; /* 128MB */ | ||
823 | break; | ||
824 | case 0x06: | ||
825 | offset = 3; /* 512MB */ | ||
826 | break; | ||
827 | default: | ||
828 | case 0x02: | ||
829 | offset = 2; /* 256MB */ | ||
830 | break; | ||
831 | } | ||
832 | |||
833 | agp_bridge->previous_size = agp_bridge->current_size = (void *)(values + offset); | ||
834 | |||
835 | return values[offset].size; | ||
836 | } | ||
837 | |||
838 | /* The intel i965 automatically initializes the agp aperture during POST. | ||
839 | + * Use the memory already set aside for in the GTT. | ||
840 | + */ | ||
841 | static int intel_i965_create_gatt_table(struct agp_bridge_data *bridge) | ||
842 | { | ||
843 | int page_order; | ||
844 | struct aper_size_info_fixed *size; | ||
845 | int num_entries; | ||
846 | u32 temp; | ||
847 | |||
848 | size = agp_bridge->current_size; | ||
849 | page_order = size->page_order; | ||
850 | num_entries = size->num_entries; | ||
851 | agp_bridge->gatt_table_real = NULL; | ||
852 | |||
853 | pci_read_config_dword(intel_i830_private.i830_dev, I915_MMADDR, &temp); | ||
854 | |||
855 | temp &= 0xfff00000; | ||
856 | intel_i830_private.gtt = ioremap((temp + (512 * 1024)) , 512 * 1024); | ||
857 | |||
858 | if (!intel_i830_private.gtt) | ||
859 | return -ENOMEM; | ||
860 | |||
861 | |||
862 | intel_i830_private.registers = ioremap(temp,128 * 4096); | ||
863 | if (!intel_i830_private.registers) | ||
864 | return -ENOMEM; | ||
865 | |||
866 | temp = readl(intel_i830_private.registers+I810_PGETBL_CTL) & 0xfffff000; | ||
867 | global_cache_flush(); /* FIXME: ? */ | ||
868 | |||
869 | /* we have to call this as early as possible after the MMIO base address is known */ | ||
870 | intel_i830_init_gtt_entries(); | ||
871 | |||
872 | agp_bridge->gatt_table = NULL; | ||
873 | |||
874 | agp_bridge->gatt_bus_addr = temp; | ||
875 | |||
876 | return 0; | ||
877 | } | ||
878 | |||
794 | 879 | ||
795 | static int intel_fetch_size(void) | 880 | static int intel_fetch_size(void) |
796 | { | 881 | { |
@@ -1307,7 +1392,7 @@ static struct agp_bridge_driver intel_830_driver = { | |||
1307 | .owner = THIS_MODULE, | 1392 | .owner = THIS_MODULE, |
1308 | .aperture_sizes = intel_i830_sizes, | 1393 | .aperture_sizes = intel_i830_sizes, |
1309 | .size_type = FIXED_APER_SIZE, | 1394 | .size_type = FIXED_APER_SIZE, |
1310 | .num_aperture_sizes = 3, | 1395 | .num_aperture_sizes = 4, |
1311 | .needs_scratch_page = TRUE, | 1396 | .needs_scratch_page = TRUE, |
1312 | .configure = intel_i830_configure, | 1397 | .configure = intel_i830_configure, |
1313 | .fetch_size = intel_i830_fetch_size, | 1398 | .fetch_size = intel_i830_fetch_size, |
@@ -1469,7 +1554,7 @@ static struct agp_bridge_driver intel_915_driver = { | |||
1469 | .owner = THIS_MODULE, | 1554 | .owner = THIS_MODULE, |
1470 | .aperture_sizes = intel_i830_sizes, | 1555 | .aperture_sizes = intel_i830_sizes, |
1471 | .size_type = FIXED_APER_SIZE, | 1556 | .size_type = FIXED_APER_SIZE, |
1472 | .num_aperture_sizes = 3, | 1557 | .num_aperture_sizes = 4, |
1473 | .needs_scratch_page = TRUE, | 1558 | .needs_scratch_page = TRUE, |
1474 | .configure = intel_i915_configure, | 1559 | .configure = intel_i915_configure, |
1475 | .fetch_size = intel_i915_fetch_size, | 1560 | .fetch_size = intel_i915_fetch_size, |
@@ -1489,6 +1574,29 @@ static struct agp_bridge_driver intel_915_driver = { | |||
1489 | .agp_destroy_page = agp_generic_destroy_page, | 1574 | .agp_destroy_page = agp_generic_destroy_page, |
1490 | }; | 1575 | }; |
1491 | 1576 | ||
1577 | static struct agp_bridge_driver intel_i965_driver = { | ||
1578 | .owner = THIS_MODULE, | ||
1579 | .aperture_sizes = intel_i830_sizes, | ||
1580 | .size_type = FIXED_APER_SIZE, | ||
1581 | .num_aperture_sizes = 4, | ||
1582 | .needs_scratch_page = TRUE, | ||
1583 | .configure = intel_i915_configure, | ||
1584 | .fetch_size = intel_i965_fetch_size, | ||
1585 | .cleanup = intel_i915_cleanup, | ||
1586 | .tlb_flush = intel_i810_tlbflush, | ||
1587 | .mask_memory = intel_i810_mask_memory, | ||
1588 | .masks = intel_i810_masks, | ||
1589 | .agp_enable = intel_i810_agp_enable, | ||
1590 | .cache_flush = global_cache_flush, | ||
1591 | .create_gatt_table = intel_i965_create_gatt_table, | ||
1592 | .free_gatt_table = intel_i830_free_gatt_table, | ||
1593 | .insert_memory = intel_i915_insert_entries, | ||
1594 | .remove_memory = intel_i915_remove_entries, | ||
1595 | .alloc_by_type = intel_i830_alloc_by_type, | ||
1596 | .free_by_type = intel_i810_free_by_type, | ||
1597 | .agp_alloc_page = agp_generic_alloc_page, | ||
1598 | .agp_destroy_page = agp_generic_destroy_page, | ||
1599 | }; | ||
1492 | 1600 | ||
1493 | static struct agp_bridge_driver intel_7505_driver = { | 1601 | static struct agp_bridge_driver intel_7505_driver = { |
1494 | .owner = THIS_MODULE, | 1602 | .owner = THIS_MODULE, |
@@ -1684,6 +1792,35 @@ static int __devinit agp_intel_probe(struct pci_dev *pdev, | |||
1684 | bridge->driver = &intel_845_driver; | 1792 | bridge->driver = &intel_845_driver; |
1685 | name = "945GM"; | 1793 | name = "945GM"; |
1686 | break; | 1794 | break; |
1795 | case PCI_DEVICE_ID_INTEL_82946GZ_HB: | ||
1796 | if (find_i830(PCI_DEVICE_ID_INTEL_82946GZ_IG)) | ||
1797 | bridge->driver = &intel_i965_driver; | ||
1798 | else | ||
1799 | bridge->driver = &intel_845_driver; | ||
1800 | name = "946GZ"; | ||
1801 | break; | ||
1802 | case PCI_DEVICE_ID_INTEL_82965G_1_HB: | ||
1803 | if (find_i830(PCI_DEVICE_ID_INTEL_82965G_1_IG)) | ||
1804 | bridge->driver = &intel_i965_driver; | ||
1805 | else | ||
1806 | bridge->driver = &intel_845_driver; | ||
1807 | name = "965G"; | ||
1808 | break; | ||
1809 | case PCI_DEVICE_ID_INTEL_82965Q_HB: | ||
1810 | if (find_i830(PCI_DEVICE_ID_INTEL_82965Q_IG)) | ||
1811 | bridge->driver = &intel_i965_driver; | ||
1812 | else | ||
1813 | bridge->driver = &intel_845_driver; | ||
1814 | name = "965Q"; | ||
1815 | break; | ||
1816 | case PCI_DEVICE_ID_INTEL_82965G_HB: | ||
1817 | if (find_i830(PCI_DEVICE_ID_INTEL_82965G_IG)) | ||
1818 | bridge->driver = &intel_i965_driver; | ||
1819 | else | ||
1820 | bridge->driver = &intel_845_driver; | ||
1821 | name = "965G"; | ||
1822 | break; | ||
1823 | |||
1687 | case PCI_DEVICE_ID_INTEL_7505_0: | 1824 | case PCI_DEVICE_ID_INTEL_7505_0: |
1688 | bridge->driver = &intel_7505_driver; | 1825 | bridge->driver = &intel_7505_driver; |
1689 | name = "E7505"; | 1826 | name = "E7505"; |
@@ -1766,6 +1903,7 @@ static void __devexit agp_intel_remove(struct pci_dev *pdev) | |||
1766 | agp_put_bridge(bridge); | 1903 | agp_put_bridge(bridge); |
1767 | } | 1904 | } |
1768 | 1905 | ||
1906 | #ifdef CONFIG_PM | ||
1769 | static int agp_intel_resume(struct pci_dev *pdev) | 1907 | static int agp_intel_resume(struct pci_dev *pdev) |
1770 | { | 1908 | { |
1771 | struct agp_bridge_data *bridge = pci_get_drvdata(pdev); | 1909 | struct agp_bridge_data *bridge = pci_get_drvdata(pdev); |
@@ -1786,9 +1924,12 @@ static int agp_intel_resume(struct pci_dev *pdev) | |||
1786 | intel_i830_configure(); | 1924 | intel_i830_configure(); |
1787 | else if (bridge->driver == &intel_810_driver) | 1925 | else if (bridge->driver == &intel_810_driver) |
1788 | intel_i810_configure(); | 1926 | intel_i810_configure(); |
1927 | else if (bridge->driver == &intel_i965_driver) | ||
1928 | intel_i915_configure(); | ||
1789 | 1929 | ||
1790 | return 0; | 1930 | return 0; |
1791 | } | 1931 | } |
1932 | #endif | ||
1792 | 1933 | ||
1793 | static struct pci_device_id agp_intel_pci_table[] = { | 1934 | static struct pci_device_id agp_intel_pci_table[] = { |
1794 | #define ID(x) \ | 1935 | #define ID(x) \ |
@@ -1825,6 +1966,10 @@ static struct pci_device_id agp_intel_pci_table[] = { | |||
1825 | ID(PCI_DEVICE_ID_INTEL_82915GM_HB), | 1966 | ID(PCI_DEVICE_ID_INTEL_82915GM_HB), |
1826 | ID(PCI_DEVICE_ID_INTEL_82945G_HB), | 1967 | ID(PCI_DEVICE_ID_INTEL_82945G_HB), |
1827 | ID(PCI_DEVICE_ID_INTEL_82945GM_HB), | 1968 | ID(PCI_DEVICE_ID_INTEL_82945GM_HB), |
1969 | ID(PCI_DEVICE_ID_INTEL_82946GZ_HB), | ||
1970 | ID(PCI_DEVICE_ID_INTEL_82965G_1_HB), | ||
1971 | ID(PCI_DEVICE_ID_INTEL_82965Q_HB), | ||
1972 | ID(PCI_DEVICE_ID_INTEL_82965G_HB), | ||
1828 | { } | 1973 | { } |
1829 | }; | 1974 | }; |
1830 | 1975 | ||
@@ -1835,7 +1980,9 @@ static struct pci_driver agp_intel_pci_driver = { | |||
1835 | .id_table = agp_intel_pci_table, | 1980 | .id_table = agp_intel_pci_table, |
1836 | .probe = agp_intel_probe, | 1981 | .probe = agp_intel_probe, |
1837 | .remove = __devexit_p(agp_intel_remove), | 1982 | .remove = __devexit_p(agp_intel_remove), |
1983 | #ifdef CONFIG_PM | ||
1838 | .resume = agp_intel_resume, | 1984 | .resume = agp_intel_resume, |
1985 | #endif | ||
1839 | }; | 1986 | }; |
1840 | 1987 | ||
1841 | static int __init agp_intel_init(void) | 1988 | static int __init agp_intel_init(void) |
diff --git a/drivers/char/agp/uninorth-agp.c b/drivers/char/agp/uninorth-agp.c index 1de1b12043bf..91b71e750ee1 100644 --- a/drivers/char/agp/uninorth-agp.c +++ b/drivers/char/agp/uninorth-agp.c | |||
@@ -601,8 +601,8 @@ static int __devinit agp_uninorth_probe(struct pci_dev *pdev, | |||
601 | uninorth_node = of_find_node_by_name(NULL, "u3"); | 601 | uninorth_node = of_find_node_by_name(NULL, "u3"); |
602 | } | 602 | } |
603 | if (uninorth_node) { | 603 | if (uninorth_node) { |
604 | int *revprop = (int *) | 604 | const int *revprop = get_property(uninorth_node, |
605 | get_property(uninorth_node, "device-rev", NULL); | 605 | "device-rev", NULL); |
606 | if (revprop != NULL) | 606 | if (revprop != NULL) |
607 | uninorth_rev = *revprop & 0x3f; | 607 | uninorth_rev = *revprop & 0x3f; |
608 | of_node_put(uninorth_node); | 608 | of_node_put(uninorth_node); |
diff --git a/drivers/char/agp/via-agp.c b/drivers/char/agp/via-agp.c index b8ec25d17478..c149ac9ce9a7 100644 --- a/drivers/char/agp/via-agp.c +++ b/drivers/char/agp/via-agp.c | |||
@@ -9,7 +9,7 @@ | |||
9 | #include <linux/agp_backend.h> | 9 | #include <linux/agp_backend.h> |
10 | #include "agp.h" | 10 | #include "agp.h" |
11 | 11 | ||
12 | static struct pci_device_id agp_via_pci_table[]; | 12 | static const struct pci_device_id agp_via_pci_table[]; |
13 | 13 | ||
14 | #define VIA_GARTCTRL 0x80 | 14 | #define VIA_GARTCTRL 0x80 |
15 | #define VIA_APSIZE 0x84 | 15 | #define VIA_APSIZE 0x84 |
@@ -485,7 +485,7 @@ static int agp_via_resume(struct pci_dev *pdev) | |||
485 | #endif /* CONFIG_PM */ | 485 | #endif /* CONFIG_PM */ |
486 | 486 | ||
487 | /* must be the same order as name table above */ | 487 | /* must be the same order as name table above */ |
488 | static struct pci_device_id agp_via_pci_table[] = { | 488 | static const struct pci_device_id agp_via_pci_table[] = { |
489 | #define ID(x) \ | 489 | #define ID(x) \ |
490 | { \ | 490 | { \ |
491 | .class = (PCI_CLASS_BRIDGE_HOST << 8), \ | 491 | .class = (PCI_CLASS_BRIDGE_HOST << 8), \ |
diff --git a/drivers/char/amiserial.c b/drivers/char/amiserial.c index 9d6713a93ed7..d0e92ed0a367 100644 --- a/drivers/char/amiserial.c +++ b/drivers/char/amiserial.c | |||
@@ -1958,7 +1958,7 @@ static void show_serial_version(void) | |||
1958 | } | 1958 | } |
1959 | 1959 | ||
1960 | 1960 | ||
1961 | static struct tty_operations serial_ops = { | 1961 | static const struct tty_operations serial_ops = { |
1962 | .open = rs_open, | 1962 | .open = rs_open, |
1963 | .close = rs_close, | 1963 | .close = rs_close, |
1964 | .write = rs_write, | 1964 | .write = rs_write, |
diff --git a/drivers/char/briq_panel.c b/drivers/char/briq_panel.c new file mode 100644 index 000000000000..b8c22255f6ad --- /dev/null +++ b/drivers/char/briq_panel.c | |||
@@ -0,0 +1,271 @@ | |||
1 | /* | ||
2 | * Drivers for the Total Impact PPC based computer "BRIQ" | ||
3 | * by Dr. Karsten Jeppesen | ||
4 | * | ||
5 | */ | ||
6 | |||
7 | #include <linux/module.h> | ||
8 | |||
9 | #include <linux/types.h> | ||
10 | #include <linux/errno.h> | ||
11 | #include <linux/sched.h> | ||
12 | #include <linux/tty.h> | ||
13 | #include <linux/timer.h> | ||
14 | #include <linux/config.h> | ||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/wait.h> | ||
17 | #include <linux/string.h> | ||
18 | #include <linux/slab.h> | ||
19 | #include <linux/ioport.h> | ||
20 | #include <linux/delay.h> | ||
21 | #include <linux/miscdevice.h> | ||
22 | #include <linux/fs.h> | ||
23 | #include <linux/mm.h> | ||
24 | #include <linux/init.h> | ||
25 | |||
26 | #include <asm/uaccess.h> | ||
27 | #include <asm/io.h> | ||
28 | #include <asm/prom.h> | ||
29 | |||
30 | #define BRIQ_PANEL_MINOR 156 | ||
31 | #define BRIQ_PANEL_VFD_IOPORT 0x0390 | ||
32 | #define BRIQ_PANEL_LED_IOPORT 0x0398 | ||
33 | #define BRIQ_PANEL_VER "1.1 (04/20/2002)" | ||
34 | #define BRIQ_PANEL_MSG0 "Loading Linux" | ||
35 | |||
36 | static int vfd_is_open; | ||
37 | static unsigned char vfd[40]; | ||
38 | static int vfd_cursor; | ||
39 | static unsigned char ledpb, led; | ||
40 | |||
41 | static void update_vfd(void) | ||
42 | { | ||
43 | int i; | ||
44 | |||
45 | /* cursor home */ | ||
46 | outb(0x02, BRIQ_PANEL_VFD_IOPORT); | ||
47 | for (i=0; i<20; i++) | ||
48 | outb(vfd[i], BRIQ_PANEL_VFD_IOPORT + 1); | ||
49 | |||
50 | /* cursor to next line */ | ||
51 | outb(0xc0, BRIQ_PANEL_VFD_IOPORT); | ||
52 | for (i=20; i<40; i++) | ||
53 | outb(vfd[i], BRIQ_PANEL_VFD_IOPORT + 1); | ||
54 | |||
55 | } | ||
56 | |||
57 | static void set_led(char state) | ||
58 | { | ||
59 | if (state == 'R') | ||
60 | led = 0x01; | ||
61 | else if (state == 'G') | ||
62 | led = 0x02; | ||
63 | else if (state == 'Y') | ||
64 | led = 0x03; | ||
65 | else if (state == 'X') | ||
66 | led = 0x00; | ||
67 | outb(led, BRIQ_PANEL_LED_IOPORT); | ||
68 | } | ||
69 | |||
70 | static int briq_panel_open(struct inode *ino, struct file *filep) | ||
71 | { | ||
72 | /* enforce single access */ | ||
73 | if (vfd_is_open) | ||
74 | return -EBUSY; | ||
75 | vfd_is_open = 1; | ||
76 | |||
77 | return 0; | ||
78 | } | ||
79 | |||
80 | static int briq_panel_release(struct inode *ino, struct file *filep) | ||
81 | { | ||
82 | if (!vfd_is_open) | ||
83 | return -ENODEV; | ||
84 | |||
85 | vfd_is_open = 0; | ||
86 | |||
87 | return 0; | ||
88 | } | ||
89 | |||
90 | static ssize_t briq_panel_read(struct file *file, char __user *buf, size_t count, | ||
91 | loff_t *ppos) | ||
92 | { | ||
93 | unsigned short c; | ||
94 | unsigned char cp; | ||
95 | |||
96 | #if 0 /* Can't seek (pread) on this device */ | ||
97 | if (ppos != &file->f_pos) | ||
98 | return -ESPIPE; | ||
99 | #endif | ||
100 | |||
101 | if (!vfd_is_open) | ||
102 | return -ENODEV; | ||
103 | |||
104 | c = (inb(BRIQ_PANEL_LED_IOPORT) & 0x000c) | (ledpb & 0x0003); | ||
105 | set_led(' '); | ||
106 | /* upper button released */ | ||
107 | if ((!(ledpb & 0x0004)) && (c & 0x0004)) { | ||
108 | cp = ' '; | ||
109 | ledpb = c; | ||
110 | if (copy_to_user(buf, &cp, 1)) | ||
111 | return -EFAULT; | ||
112 | return 1; | ||
113 | } | ||
114 | /* lower button released */ | ||
115 | else if ((!(ledpb & 0x0008)) && (c & 0x0008)) { | ||
116 | cp = '\r'; | ||
117 | ledpb = c; | ||
118 | if (copy_to_user(buf, &cp, 1)) | ||
119 | return -EFAULT; | ||
120 | return 1; | ||
121 | } else { | ||
122 | ledpb = c; | ||
123 | return 0; | ||
124 | } | ||
125 | } | ||
126 | |||
127 | static void scroll_vfd( void ) | ||
128 | { | ||
129 | int i; | ||
130 | |||
131 | for (i=0; i<20; i++) { | ||
132 | vfd[i] = vfd[i+20]; | ||
133 | vfd[i+20] = ' '; | ||
134 | } | ||
135 | vfd_cursor = 20; | ||
136 | } | ||
137 | |||
138 | static ssize_t briq_panel_write(struct file *file, const char __user *buf, size_t len, | ||
139 | loff_t *ppos) | ||
140 | { | ||
141 | size_t indx = len; | ||
142 | int i, esc = 0; | ||
143 | |||
144 | #if 0 /* Can't seek (pwrite) on this device */ | ||
145 | if (ppos != &file->f_pos) | ||
146 | return -ESPIPE; | ||
147 | #endif | ||
148 | |||
149 | if (!vfd_is_open) | ||
150 | return -EBUSY; | ||
151 | |||
152 | for (;;) { | ||
153 | char c; | ||
154 | if (!indx) | ||
155 | break; | ||
156 | if (get_user(c, buf)) | ||
157 | return -EFAULT; | ||
158 | if (esc) { | ||
159 | set_led(c); | ||
160 | esc = 0; | ||
161 | } else if (c == 27) { | ||
162 | esc = 1; | ||
163 | } else if (c == 12) { | ||
164 | /* do a form feed */ | ||
165 | for (i=0; i<40; i++) | ||
166 | vfd[i] = ' '; | ||
167 | vfd_cursor = 0; | ||
168 | } else if (c == 10) { | ||
169 | if (vfd_cursor < 20) | ||
170 | vfd_cursor = 20; | ||
171 | else if (vfd_cursor < 40) | ||
172 | vfd_cursor = 40; | ||
173 | else if (vfd_cursor < 60) | ||
174 | vfd_cursor = 60; | ||
175 | if (vfd_cursor > 59) | ||
176 | scroll_vfd(); | ||
177 | } else { | ||
178 | /* just a character */ | ||
179 | if (vfd_cursor > 39) | ||
180 | scroll_vfd(); | ||
181 | vfd[vfd_cursor++] = c; | ||
182 | } | ||
183 | indx--; | ||
184 | buf++; | ||
185 | } | ||
186 | update_vfd(); | ||
187 | |||
188 | return len; | ||
189 | } | ||
190 | |||
191 | static struct file_operations briq_panel_fops = { | ||
192 | .owner = THIS_MODULE, | ||
193 | .read = briq_panel_read, | ||
194 | .write = briq_panel_write, | ||
195 | .open = briq_panel_open, | ||
196 | .release = briq_panel_release, | ||
197 | }; | ||
198 | |||
199 | static struct miscdevice briq_panel_miscdev = { | ||
200 | BRIQ_PANEL_MINOR, | ||
201 | "briq_panel", | ||
202 | &briq_panel_fops | ||
203 | }; | ||
204 | |||
205 | static int __init briq_panel_init(void) | ||
206 | { | ||
207 | struct device_node *root = find_path_device("/"); | ||
208 | const char *machine; | ||
209 | int i; | ||
210 | |||
211 | machine = get_property(root, "model", NULL); | ||
212 | if (!machine || strncmp(machine, "TotalImpact,BRIQ-1", 18) != 0) | ||
213 | return -ENODEV; | ||
214 | |||
215 | printk(KERN_INFO | ||
216 | "briq_panel: v%s Dr. Karsten Jeppesen (kj@totalimpact.com)\n", | ||
217 | BRIQ_PANEL_VER); | ||
218 | |||
219 | if (!request_region(BRIQ_PANEL_VFD_IOPORT, 4, "BRIQ Front Panel")) | ||
220 | return -EBUSY; | ||
221 | |||
222 | if (!request_region(BRIQ_PANEL_LED_IOPORT, 2, "BRIQ Front Panel")) { | ||
223 | release_region(BRIQ_PANEL_VFD_IOPORT, 4); | ||
224 | return -EBUSY; | ||
225 | } | ||
226 | ledpb = inb(BRIQ_PANEL_LED_IOPORT) & 0x000c; | ||
227 | |||
228 | if (misc_register(&briq_panel_miscdev) < 0) { | ||
229 | release_region(BRIQ_PANEL_VFD_IOPORT, 4); | ||
230 | release_region(BRIQ_PANEL_LED_IOPORT, 2); | ||
231 | return -EBUSY; | ||
232 | } | ||
233 | |||
234 | outb(0x38, BRIQ_PANEL_VFD_IOPORT); /* Function set */ | ||
235 | outb(0x01, BRIQ_PANEL_VFD_IOPORT); /* Clear display */ | ||
236 | outb(0x0c, BRIQ_PANEL_VFD_IOPORT); /* Display on */ | ||
237 | outb(0x06, BRIQ_PANEL_VFD_IOPORT); /* Entry normal */ | ||
238 | for (i=0; i<40; i++) | ||
239 | vfd[i]=' '; | ||
240 | #ifndef MODULE | ||
241 | vfd[0] = 'L'; | ||
242 | vfd[1] = 'o'; | ||
243 | vfd[2] = 'a'; | ||
244 | vfd[3] = 'd'; | ||
245 | vfd[4] = 'i'; | ||
246 | vfd[5] = 'n'; | ||
247 | vfd[6] = 'g'; | ||
248 | vfd[7] = ' '; | ||
249 | vfd[8] = '.'; | ||
250 | vfd[9] = '.'; | ||
251 | vfd[10] = '.'; | ||
252 | #endif /* !MODULE */ | ||
253 | |||
254 | update_vfd(); | ||
255 | |||
256 | return 0; | ||
257 | } | ||
258 | |||
259 | static void __exit briq_panel_exit(void) | ||
260 | { | ||
261 | misc_deregister(&briq_panel_miscdev); | ||
262 | release_region(BRIQ_PANEL_VFD_IOPORT, 4); | ||
263 | release_region(BRIQ_PANEL_LED_IOPORT, 2); | ||
264 | } | ||
265 | |||
266 | module_init(briq_panel_init); | ||
267 | module_exit(briq_panel_exit); | ||
268 | |||
269 | MODULE_LICENSE("GPL"); | ||
270 | MODULE_AUTHOR("Karsten Jeppesen <karsten@jeppesens.com>"); | ||
271 | MODULE_DESCRIPTION("Driver for the Total Impact briQ front panel"); | ||
diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c index c1c67281750d..f85b4eb16618 100644 --- a/drivers/char/cyclades.c +++ b/drivers/char/cyclades.c | |||
@@ -5205,7 +5205,7 @@ done: | |||
5205 | extra ports are ignored. | 5205 | extra ports are ignored. |
5206 | */ | 5206 | */ |
5207 | 5207 | ||
5208 | static struct tty_operations cy_ops = { | 5208 | static const struct tty_operations cy_ops = { |
5209 | .open = cy_open, | 5209 | .open = cy_open, |
5210 | .close = cy_close, | 5210 | .close = cy_close, |
5211 | .write = cy_write, | 5211 | .write = cy_write, |
diff --git a/drivers/char/drm/Kconfig b/drivers/char/drm/Kconfig index 5278c388d3e7..ef833a1c27eb 100644 --- a/drivers/char/drm/Kconfig +++ b/drivers/char/drm/Kconfig | |||
@@ -60,7 +60,9 @@ config DRM_I830 | |||
60 | Choose this option if you have a system that has Intel 830M, 845G, | 60 | Choose this option if you have a system that has Intel 830M, 845G, |
61 | 852GM, 855GM or 865G integrated graphics. If M is selected, the | 61 | 852GM, 855GM or 865G integrated graphics. If M is selected, the |
62 | module will be called i830. AGP support is required for this driver | 62 | module will be called i830. AGP support is required for this driver |
63 | to work. This driver will eventually be replaced by the i915 one. | 63 | to work. This driver is used by the older X releases X.org 6.7 and |
64 | XFree86 4.3. If unsure, build this and i915 as modules and the X server | ||
65 | will load the correct one. | ||
64 | 66 | ||
65 | config DRM_I915 | 67 | config DRM_I915 |
66 | tristate "i915 driver" | 68 | tristate "i915 driver" |
@@ -68,8 +70,9 @@ config DRM_I915 | |||
68 | Choose this option if you have a system that has Intel 830M, 845G, | 70 | Choose this option if you have a system that has Intel 830M, 845G, |
69 | 852GM, 855GM 865G or 915G integrated graphics. If M is selected, the | 71 | 852GM, 855GM 865G or 915G integrated graphics. If M is selected, the |
70 | module will be called i915. AGP support is required for this driver | 72 | module will be called i915. AGP support is required for this driver |
71 | to work. This driver will eventually replace the I830 driver, when | 73 | to work. This driver is used by the Intel driver in X.org 6.8 and |
72 | later release of X start to use the new DDX and DRI. | 74 | XFree86 4.4 and above. If unsure, build this and i830 as modules and |
75 | the X server will load the correct one. | ||
73 | 76 | ||
74 | endchoice | 77 | endchoice |
75 | 78 | ||
diff --git a/drivers/char/drm/Makefile b/drivers/char/drm/Makefile index 9d180c42816c..3ad0f648c6b2 100644 --- a/drivers/char/drm/Makefile +++ b/drivers/char/drm/Makefile | |||
@@ -6,7 +6,7 @@ drm-objs := drm_auth.o drm_bufs.o drm_context.o drm_dma.o drm_drawable.o \ | |||
6 | drm_drv.o drm_fops.o drm_ioctl.o drm_irq.o \ | 6 | drm_drv.o drm_fops.o drm_ioctl.o drm_irq.o \ |
7 | drm_lock.o drm_memory.o drm_proc.o drm_stub.o drm_vm.o \ | 7 | drm_lock.o drm_memory.o drm_proc.o drm_stub.o drm_vm.o \ |
8 | drm_agpsupport.o drm_scatter.o ati_pcigart.o drm_pci.o \ | 8 | drm_agpsupport.o drm_scatter.o ati_pcigart.o drm_pci.o \ |
9 | drm_sysfs.o | 9 | drm_sysfs.o drm_hashtab.o drm_sman.o drm_mm.o |
10 | 10 | ||
11 | tdfx-objs := tdfx_drv.o | 11 | tdfx-objs := tdfx_drv.o |
12 | r128-objs := r128_drv.o r128_cce.o r128_state.o r128_irq.o | 12 | r128-objs := r128_drv.o r128_cce.o r128_state.o r128_irq.o |
@@ -16,9 +16,9 @@ i830-objs := i830_drv.o i830_dma.o i830_irq.o | |||
16 | i915-objs := i915_drv.o i915_dma.o i915_irq.o i915_mem.o | 16 | i915-objs := i915_drv.o i915_dma.o i915_irq.o i915_mem.o |
17 | radeon-objs := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o radeon_irq.o r300_cmdbuf.o | 17 | radeon-objs := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o radeon_irq.o r300_cmdbuf.o |
18 | ffb-objs := ffb_drv.o ffb_context.o | 18 | ffb-objs := ffb_drv.o ffb_context.o |
19 | sis-objs := sis_drv.o sis_ds.o sis_mm.o | 19 | sis-objs := sis_drv.o sis_mm.o |
20 | savage-objs := savage_drv.o savage_bci.o savage_state.o | 20 | savage-objs := savage_drv.o savage_bci.o savage_state.o |
21 | via-objs := via_irq.o via_drv.o via_ds.o via_map.o via_mm.o via_dma.o via_verifier.o via_video.o via_dmablit.o | 21 | via-objs := via_irq.o via_drv.o via_map.o via_mm.o via_dma.o via_verifier.o via_video.o via_dmablit.o |
22 | 22 | ||
23 | ifeq ($(CONFIG_COMPAT),y) | 23 | ifeq ($(CONFIG_COMPAT),y) |
24 | drm-objs += drm_ioc32.o | 24 | drm-objs += drm_ioc32.o |
diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h index d2a56182bc35..7690a59ace04 100644 --- a/drivers/char/drm/drmP.h +++ b/drivers/char/drm/drmP.h | |||
@@ -79,6 +79,7 @@ | |||
79 | #define __OS_HAS_MTRR (defined(CONFIG_MTRR)) | 79 | #define __OS_HAS_MTRR (defined(CONFIG_MTRR)) |
80 | 80 | ||
81 | #include "drm_os_linux.h" | 81 | #include "drm_os_linux.h" |
82 | #include "drm_hashtab.h" | ||
82 | 83 | ||
83 | /***********************************************************************/ | 84 | /***********************************************************************/ |
84 | /** \name DRM template customization defaults */ | 85 | /** \name DRM template customization defaults */ |
@@ -104,7 +105,7 @@ | |||
104 | #define DRM_DEBUG_CODE 2 /**< Include debugging code if > 1, then | 105 | #define DRM_DEBUG_CODE 2 /**< Include debugging code if > 1, then |
105 | also include looping detection. */ | 106 | also include looping detection. */ |
106 | 107 | ||
107 | #define DRM_HASH_SIZE 16 /**< Size of key hash table. Must be power of 2. */ | 108 | #define DRM_MAGIC_HASH_ORDER 4 /**< Size of key hash table. Must be power of 2. */ |
108 | #define DRM_KERNEL_CONTEXT 0 /**< Change drm_resctx if changed */ | 109 | #define DRM_KERNEL_CONTEXT 0 /**< Change drm_resctx if changed */ |
109 | #define DRM_RESERVED_CONTEXTS 1 /**< Change drm_resctx if changed */ | 110 | #define DRM_RESERVED_CONTEXTS 1 /**< Change drm_resctx if changed */ |
110 | #define DRM_LOOPING_LIMIT 5000000 | 111 | #define DRM_LOOPING_LIMIT 5000000 |
@@ -134,19 +135,12 @@ | |||
134 | #define DRM_MEM_CTXBITMAP 18 | 135 | #define DRM_MEM_CTXBITMAP 18 |
135 | #define DRM_MEM_STUB 19 | 136 | #define DRM_MEM_STUB 19 |
136 | #define DRM_MEM_SGLISTS 20 | 137 | #define DRM_MEM_SGLISTS 20 |
137 | #define DRM_MEM_CTXLIST 21 | 138 | #define DRM_MEM_CTXLIST 21 |
139 | #define DRM_MEM_MM 22 | ||
140 | #define DRM_MEM_HASHTAB 23 | ||
138 | 141 | ||
139 | #define DRM_MAX_CTXBITMAP (PAGE_SIZE * 8) | 142 | #define DRM_MAX_CTXBITMAP (PAGE_SIZE * 8) |
140 | 143 | #define DRM_MAP_HASH_OFFSET 0x10000000 | |
141 | /*@}*/ | ||
142 | |||
143 | /***********************************************************************/ | ||
144 | /** \name Backward compatibility section */ | ||
145 | /*@{*/ | ||
146 | |||
147 | #define DRM_RPR_ARG(vma) vma, | ||
148 | |||
149 | #define VM_OFFSET(vma) ((vma)->vm_pgoff << PAGE_SHIFT) | ||
150 | 144 | ||
151 | /*@}*/ | 145 | /*@}*/ |
152 | 146 | ||
@@ -211,8 +205,6 @@ | |||
211 | /*@{*/ | 205 | /*@{*/ |
212 | 206 | ||
213 | #define DRM_ARRAY_SIZE(x) ARRAY_SIZE(x) | 207 | #define DRM_ARRAY_SIZE(x) ARRAY_SIZE(x) |
214 | #define DRM_MIN(a,b) min(a,b) | ||
215 | #define DRM_MAX(a,b) max(a,b) | ||
216 | 208 | ||
217 | #define DRM_LEFTCOUNT(x) (((x)->rp + (x)->count - (x)->wp) % ((x)->count + 1)) | 209 | #define DRM_LEFTCOUNT(x) (((x)->rp + (x)->count - (x)->wp) % ((x)->count + 1)) |
218 | #define DRM_BUFCOUNT(x) ((x)->count - DRM_LEFTCOUNT(x)) | 210 | #define DRM_BUFCOUNT(x) ((x)->count - DRM_LEFTCOUNT(x)) |
@@ -286,7 +278,8 @@ typedef struct drm_devstate { | |||
286 | } drm_devstate_t; | 278 | } drm_devstate_t; |
287 | 279 | ||
288 | typedef struct drm_magic_entry { | 280 | typedef struct drm_magic_entry { |
289 | drm_magic_t magic; | 281 | drm_hash_item_t hash_item; |
282 | struct list_head head; | ||
290 | struct drm_file *priv; | 283 | struct drm_file *priv; |
291 | struct drm_magic_entry *next; | 284 | struct drm_magic_entry *next; |
292 | } drm_magic_entry_t; | 285 | } drm_magic_entry_t; |
@@ -493,6 +486,7 @@ typedef struct drm_sigdata { | |||
493 | */ | 486 | */ |
494 | typedef struct drm_map_list { | 487 | typedef struct drm_map_list { |
495 | struct list_head head; /**< list head */ | 488 | struct list_head head; /**< list head */ |
489 | drm_hash_item_t hash; | ||
496 | drm_map_t *map; /**< mapping */ | 490 | drm_map_t *map; /**< mapping */ |
497 | unsigned int user_token; | 491 | unsigned int user_token; |
498 | } drm_map_list_t; | 492 | } drm_map_list_t; |
@@ -527,6 +521,22 @@ typedef struct ati_pcigart_info { | |||
527 | drm_local_map_t mapping; | 521 | drm_local_map_t mapping; |
528 | } drm_ati_pcigart_info; | 522 | } drm_ati_pcigart_info; |
529 | 523 | ||
524 | /* | ||
525 | * Generic memory manager structs | ||
526 | */ | ||
527 | typedef struct drm_mm_node { | ||
528 | struct list_head fl_entry; | ||
529 | struct list_head ml_entry; | ||
530 | int free; | ||
531 | unsigned long start; | ||
532 | unsigned long size; | ||
533 | void *private; | ||
534 | } drm_mm_node_t; | ||
535 | |||
536 | typedef struct drm_mm { | ||
537 | drm_mm_node_t root_node; | ||
538 | } drm_mm_t; | ||
539 | |||
530 | /** | 540 | /** |
531 | * DRM driver structure. This structure represent the common code for | 541 | * DRM driver structure. This structure represent the common code for |
532 | * a family of cards. There will one drm_device for each card present | 542 | * a family of cards. There will one drm_device for each card present |
@@ -646,13 +656,15 @@ typedef struct drm_device { | |||
646 | /*@{ */ | 656 | /*@{ */ |
647 | drm_file_t *file_first; /**< file list head */ | 657 | drm_file_t *file_first; /**< file list head */ |
648 | drm_file_t *file_last; /**< file list tail */ | 658 | drm_file_t *file_last; /**< file list tail */ |
649 | drm_magic_head_t magiclist[DRM_HASH_SIZE]; /**< magic hash table */ | 659 | drm_open_hash_t magiclist; /**< magic hash table */ |
660 | struct list_head magicfree; | ||
650 | /*@} */ | 661 | /*@} */ |
651 | 662 | ||
652 | /** \name Memory management */ | 663 | /** \name Memory management */ |
653 | /*@{ */ | 664 | /*@{ */ |
654 | drm_map_list_t *maplist; /**< Linked list of regions */ | 665 | drm_map_list_t *maplist; /**< Linked list of regions */ |
655 | int map_count; /**< Number of mappable regions */ | 666 | int map_count; /**< Number of mappable regions */ |
667 | drm_open_hash_t map_hash; /**< User token hash table for maps */ | ||
656 | 668 | ||
657 | /** \name Context handle management */ | 669 | /** \name Context handle management */ |
658 | /*@{ */ | 670 | /*@{ */ |
@@ -711,10 +723,8 @@ typedef struct drm_device { | |||
711 | drm_agp_head_t *agp; /**< AGP data */ | 723 | drm_agp_head_t *agp; /**< AGP data */ |
712 | 724 | ||
713 | struct pci_dev *pdev; /**< PCI device structure */ | 725 | struct pci_dev *pdev; /**< PCI device structure */ |
714 | int pci_domain; /**< PCI bus domain number */ | 726 | int pci_vendor; /**< PCI vendor id */ |
715 | int pci_bus; /**< PCI bus number */ | 727 | int pci_device; /**< PCI device id */ |
716 | int pci_slot; /**< PCI slot number */ | ||
717 | int pci_func; /**< PCI function number */ | ||
718 | #ifdef __alpha__ | 728 | #ifdef __alpha__ |
719 | struct pci_controller *hose; | 729 | struct pci_controller *hose; |
720 | #endif | 730 | #endif |
@@ -736,6 +746,12 @@ static __inline__ int drm_core_check_feature(struct drm_device *dev, | |||
736 | return ((dev->driver->driver_features & feature) ? 1 : 0); | 746 | return ((dev->driver->driver_features & feature) ? 1 : 0); |
737 | } | 747 | } |
738 | 748 | ||
749 | #ifdef __alpha__ | ||
750 | #define drm_get_pci_domain(dev) dev->hose->bus->number | ||
751 | #else | ||
752 | #define drm_get_pci_domain(dev) 0 | ||
753 | #endif | ||
754 | |||
739 | #if __OS_HAS_AGP | 755 | #if __OS_HAS_AGP |
740 | static inline int drm_core_has_AGP(struct drm_device *dev) | 756 | static inline int drm_core_has_AGP(struct drm_device *dev) |
741 | { | 757 | { |
@@ -1011,6 +1027,18 @@ extern struct class_device *drm_sysfs_device_add(struct class *cs, | |||
1011 | drm_head_t *head); | 1027 | drm_head_t *head); |
1012 | extern void drm_sysfs_device_remove(struct class_device *class_dev); | 1028 | extern void drm_sysfs_device_remove(struct class_device *class_dev); |
1013 | 1029 | ||
1030 | /* | ||
1031 | * Basic memory manager support (drm_mm.c) | ||
1032 | */ | ||
1033 | extern drm_mm_node_t *drm_mm_get_block(drm_mm_node_t * parent, | ||
1034 | unsigned long size, | ||
1035 | unsigned alignment); | ||
1036 | extern void drm_mm_put_block(drm_mm_t *mm, drm_mm_node_t *cur); | ||
1037 | extern drm_mm_node_t *drm_mm_search_free(const drm_mm_t *mm, unsigned long size, | ||
1038 | unsigned alignment, int best_match); | ||
1039 | extern int drm_mm_init(drm_mm_t *mm, unsigned long start, unsigned long size); | ||
1040 | extern void drm_mm_takedown(drm_mm_t *mm); | ||
1041 | |||
1014 | /* Inline replacements for DRM_IOREMAP macros */ | 1042 | /* Inline replacements for DRM_IOREMAP macros */ |
1015 | static __inline__ void drm_core_ioremap(struct drm_map *map, | 1043 | static __inline__ void drm_core_ioremap(struct drm_map *map, |
1016 | struct drm_device *dev) | 1044 | struct drm_device *dev) |
diff --git a/drivers/char/drm/drm_auth.c b/drivers/char/drm/drm_auth.c index 2a37586a7ee8..c7b19d35bcd6 100644 --- a/drivers/char/drm/drm_auth.c +++ b/drivers/char/drm/drm_auth.c | |||
@@ -36,20 +36,6 @@ | |||
36 | #include "drmP.h" | 36 | #include "drmP.h" |
37 | 37 | ||
38 | /** | 38 | /** |
39 | * Generate a hash key from a magic. | ||
40 | * | ||
41 | * \param magic magic. | ||
42 | * \return hash key. | ||
43 | * | ||
44 | * The key is the modulus of the hash table size, #DRM_HASH_SIZE, which must be | ||
45 | * a power of 2. | ||
46 | */ | ||
47 | static int drm_hash_magic(drm_magic_t magic) | ||
48 | { | ||
49 | return magic & (DRM_HASH_SIZE - 1); | ||
50 | } | ||
51 | |||
52 | /** | ||
53 | * Find the file with the given magic number. | 39 | * Find the file with the given magic number. |
54 | * | 40 | * |
55 | * \param dev DRM device. | 41 | * \param dev DRM device. |
@@ -63,14 +49,12 @@ static drm_file_t *drm_find_file(drm_device_t * dev, drm_magic_t magic) | |||
63 | { | 49 | { |
64 | drm_file_t *retval = NULL; | 50 | drm_file_t *retval = NULL; |
65 | drm_magic_entry_t *pt; | 51 | drm_magic_entry_t *pt; |
66 | int hash = drm_hash_magic(magic); | 52 | drm_hash_item_t *hash; |
67 | 53 | ||
68 | mutex_lock(&dev->struct_mutex); | 54 | mutex_lock(&dev->struct_mutex); |
69 | for (pt = dev->magiclist[hash].head; pt; pt = pt->next) { | 55 | if (!drm_ht_find_item(&dev->magiclist, (unsigned long)magic, &hash)) { |
70 | if (pt->magic == magic) { | 56 | pt = drm_hash_entry(hash, drm_magic_entry_t, hash_item); |
71 | retval = pt->priv; | 57 | retval = pt->priv; |
72 | break; | ||
73 | } | ||
74 | } | 58 | } |
75 | mutex_unlock(&dev->struct_mutex); | 59 | mutex_unlock(&dev->struct_mutex); |
76 | return retval; | 60 | return retval; |
@@ -90,28 +74,20 @@ static drm_file_t *drm_find_file(drm_device_t * dev, drm_magic_t magic) | |||
90 | static int drm_add_magic(drm_device_t * dev, drm_file_t * priv, | 74 | static int drm_add_magic(drm_device_t * dev, drm_file_t * priv, |
91 | drm_magic_t magic) | 75 | drm_magic_t magic) |
92 | { | 76 | { |
93 | int hash; | ||
94 | drm_magic_entry_t *entry; | 77 | drm_magic_entry_t *entry; |
95 | 78 | ||
96 | DRM_DEBUG("%d\n", magic); | 79 | DRM_DEBUG("%d\n", magic); |
97 | 80 | ||
98 | hash = drm_hash_magic(magic); | ||
99 | entry = drm_alloc(sizeof(*entry), DRM_MEM_MAGIC); | 81 | entry = drm_alloc(sizeof(*entry), DRM_MEM_MAGIC); |
100 | if (!entry) | 82 | if (!entry) |
101 | return -ENOMEM; | 83 | return -ENOMEM; |
102 | memset(entry, 0, sizeof(*entry)); | 84 | memset(entry, 0, sizeof(*entry)); |
103 | entry->magic = magic; | ||
104 | entry->priv = priv; | 85 | entry->priv = priv; |
105 | entry->next = NULL; | ||
106 | 86 | ||
87 | entry->hash_item.key = (unsigned long)magic; | ||
107 | mutex_lock(&dev->struct_mutex); | 88 | mutex_lock(&dev->struct_mutex); |
108 | if (dev->magiclist[hash].tail) { | 89 | drm_ht_insert_item(&dev->magiclist, &entry->hash_item); |
109 | dev->magiclist[hash].tail->next = entry; | 90 | list_add_tail(&entry->head, &dev->magicfree); |
110 | dev->magiclist[hash].tail = entry; | ||
111 | } else { | ||
112 | dev->magiclist[hash].head = entry; | ||
113 | dev->magiclist[hash].tail = entry; | ||
114 | } | ||
115 | mutex_unlock(&dev->struct_mutex); | 91 | mutex_unlock(&dev->struct_mutex); |
116 | 92 | ||
117 | return 0; | 93 | return 0; |
@@ -128,34 +104,24 @@ static int drm_add_magic(drm_device_t * dev, drm_file_t * priv, | |||
128 | */ | 104 | */ |
129 | static int drm_remove_magic(drm_device_t * dev, drm_magic_t magic) | 105 | static int drm_remove_magic(drm_device_t * dev, drm_magic_t magic) |
130 | { | 106 | { |
131 | drm_magic_entry_t *prev = NULL; | ||
132 | drm_magic_entry_t *pt; | 107 | drm_magic_entry_t *pt; |
133 | int hash; | 108 | drm_hash_item_t *hash; |
134 | 109 | ||
135 | DRM_DEBUG("%d\n", magic); | 110 | DRM_DEBUG("%d\n", magic); |
136 | hash = drm_hash_magic(magic); | ||
137 | 111 | ||
138 | mutex_lock(&dev->struct_mutex); | 112 | mutex_lock(&dev->struct_mutex); |
139 | for (pt = dev->magiclist[hash].head; pt; prev = pt, pt = pt->next) { | 113 | if (drm_ht_find_item(&dev->magiclist, (unsigned long)magic, &hash)) { |
140 | if (pt->magic == magic) { | 114 | mutex_unlock(&dev->struct_mutex); |
141 | if (dev->magiclist[hash].head == pt) { | 115 | return -EINVAL; |
142 | dev->magiclist[hash].head = pt->next; | ||
143 | } | ||
144 | if (dev->magiclist[hash].tail == pt) { | ||
145 | dev->magiclist[hash].tail = prev; | ||
146 | } | ||
147 | if (prev) { | ||
148 | prev->next = pt->next; | ||
149 | } | ||
150 | mutex_unlock(&dev->struct_mutex); | ||
151 | return 0; | ||
152 | } | ||
153 | } | 116 | } |
117 | pt = drm_hash_entry(hash, drm_magic_entry_t, hash_item); | ||
118 | drm_ht_remove_item(&dev->magiclist, hash); | ||
119 | list_del(&pt->head); | ||
154 | mutex_unlock(&dev->struct_mutex); | 120 | mutex_unlock(&dev->struct_mutex); |
155 | 121 | ||
156 | drm_free(pt, sizeof(*pt), DRM_MEM_MAGIC); | 122 | drm_free(pt, sizeof(*pt), DRM_MEM_MAGIC); |
157 | 123 | ||
158 | return -EINVAL; | 124 | return 0; |
159 | } | 125 | } |
160 | 126 | ||
161 | /** | 127 | /** |
diff --git a/drivers/char/drm/drm_bufs.c b/drivers/char/drm/drm_bufs.c index 006b06d29727..029baea33b62 100644 --- a/drivers/char/drm/drm_bufs.c +++ b/drivers/char/drm/drm_bufs.c | |||
@@ -65,43 +65,29 @@ static drm_map_list_t *drm_find_matching_map(drm_device_t *dev, | |||
65 | return NULL; | 65 | return NULL; |
66 | } | 66 | } |
67 | 67 | ||
68 | /* | 68 | static int drm_map_handle(drm_device_t *dev, drm_hash_item_t *hash, |
69 | * Used to allocate 32-bit handles for mappings. | 69 | unsigned long user_token, int hashed_handle) |
70 | */ | ||
71 | #define START_RANGE 0x10000000 | ||
72 | #define END_RANGE 0x40000000 | ||
73 | |||
74 | #ifdef _LP64 | ||
75 | static __inline__ unsigned int HandleID(unsigned long lhandle, | ||
76 | drm_device_t *dev) | ||
77 | { | 70 | { |
78 | static unsigned int map32_handle = START_RANGE; | 71 | int use_hashed_handle; |
79 | unsigned int hash; | 72 | #if (BITS_PER_LONG == 64) |
80 | 73 | use_hashed_handle = ((user_token & 0xFFFFFFFF00000000UL) || hashed_handle); | |
81 | if (lhandle & 0xffffffff00000000) { | 74 | #elif (BITS_PER_LONG == 32) |
82 | hash = map32_handle; | 75 | use_hashed_handle = hashed_handle; |
83 | map32_handle += PAGE_SIZE; | 76 | #else |
84 | if (map32_handle > END_RANGE) | 77 | #error Unsupported long size. Neither 64 nor 32 bits. |
85 | map32_handle = START_RANGE; | 78 | #endif |
86 | } else | ||
87 | hash = lhandle; | ||
88 | |||
89 | while (1) { | ||
90 | drm_map_list_t *_entry; | ||
91 | list_for_each_entry(_entry, &dev->maplist->head, head) { | ||
92 | if (_entry->user_token == hash) | ||
93 | break; | ||
94 | } | ||
95 | if (&_entry->head == &dev->maplist->head) | ||
96 | return hash; | ||
97 | 79 | ||
98 | hash += PAGE_SIZE; | 80 | if (!use_hashed_handle) { |
99 | map32_handle += PAGE_SIZE; | 81 | int ret; |
82 | hash->key = user_token; | ||
83 | ret = drm_ht_insert_item(&dev->map_hash, hash); | ||
84 | if (ret != -EINVAL) | ||
85 | return ret; | ||
100 | } | 86 | } |
87 | return drm_ht_just_insert_please(&dev->map_hash, hash, | ||
88 | user_token, 32 - PAGE_SHIFT - 3, | ||
89 | PAGE_SHIFT, DRM_MAP_HASH_OFFSET); | ||
101 | } | 90 | } |
102 | #else | ||
103 | # define HandleID(x,dev) (unsigned int)(x) | ||
104 | #endif | ||
105 | 91 | ||
106 | /** | 92 | /** |
107 | * Ioctl to specify a range of memory that is available for mapping by a non-root process. | 93 | * Ioctl to specify a range of memory that is available for mapping by a non-root process. |
@@ -123,6 +109,8 @@ static int drm_addmap_core(drm_device_t * dev, unsigned int offset, | |||
123 | drm_map_t *map; | 109 | drm_map_t *map; |
124 | drm_map_list_t *list; | 110 | drm_map_list_t *list; |
125 | drm_dma_handle_t *dmah; | 111 | drm_dma_handle_t *dmah; |
112 | unsigned long user_token; | ||
113 | int ret; | ||
126 | 114 | ||
127 | map = drm_alloc(sizeof(*map), DRM_MEM_MAPS); | 115 | map = drm_alloc(sizeof(*map), DRM_MEM_MAPS); |
128 | if (!map) | 116 | if (!map) |
@@ -257,11 +245,20 @@ static int drm_addmap_core(drm_device_t * dev, unsigned int offset, | |||
257 | 245 | ||
258 | mutex_lock(&dev->struct_mutex); | 246 | mutex_lock(&dev->struct_mutex); |
259 | list_add(&list->head, &dev->maplist->head); | 247 | list_add(&list->head, &dev->maplist->head); |
248 | |||
260 | /* Assign a 32-bit handle */ | 249 | /* Assign a 32-bit handle */ |
261 | /* We do it here so that dev->struct_mutex protects the increment */ | 250 | /* We do it here so that dev->struct_mutex protects the increment */ |
262 | list->user_token = HandleID(map->type == _DRM_SHM | 251 | user_token = (map->type == _DRM_SHM) ? (unsigned long)map->handle : |
263 | ? (unsigned long)map->handle | 252 | map->offset; |
264 | : map->offset, dev); | 253 | ret = drm_map_handle(dev, &list->hash, user_token, 0); |
254 | if (ret) { | ||
255 | drm_free(map, sizeof(*map), DRM_MEM_MAPS); | ||
256 | drm_free(list, sizeof(*list), DRM_MEM_MAPS); | ||
257 | mutex_unlock(&dev->struct_mutex); | ||
258 | return ret; | ||
259 | } | ||
260 | |||
261 | list->user_token = list->hash.key; | ||
265 | mutex_unlock(&dev->struct_mutex); | 262 | mutex_unlock(&dev->struct_mutex); |
266 | 263 | ||
267 | *maplist = list; | 264 | *maplist = list; |
@@ -346,6 +343,7 @@ int drm_rmmap_locked(drm_device_t *dev, drm_local_map_t *map) | |||
346 | 343 | ||
347 | if (r_list->map == map) { | 344 | if (r_list->map == map) { |
348 | list_del(list); | 345 | list_del(list); |
346 | drm_ht_remove_key(&dev->map_hash, r_list->user_token); | ||
349 | drm_free(list, sizeof(*list), DRM_MEM_MAPS); | 347 | drm_free(list, sizeof(*list), DRM_MEM_MAPS); |
350 | break; | 348 | break; |
351 | } | 349 | } |
@@ -441,8 +439,10 @@ int drm_rmmap_ioctl(struct inode *inode, struct file *filp, | |||
441 | return -EINVAL; | 439 | return -EINVAL; |
442 | } | 440 | } |
443 | 441 | ||
444 | if (!map) | 442 | if (!map) { |
443 | mutex_unlock(&dev->struct_mutex); | ||
445 | return -EINVAL; | 444 | return -EINVAL; |
445 | } | ||
446 | 446 | ||
447 | /* Register and framebuffer maps are permanent */ | 447 | /* Register and framebuffer maps are permanent */ |
448 | if ((map->type == _DRM_REGISTERS) || (map->type == _DRM_FRAME_BUFFER)) { | 448 | if ((map->type == _DRM_REGISTERS) || (map->type == _DRM_FRAME_BUFFER)) { |
diff --git a/drivers/char/drm/drm_drv.c b/drivers/char/drm/drm_drv.c index 3c0b882a8e72..b366c5b1bd16 100644 --- a/drivers/char/drm/drm_drv.c +++ b/drivers/char/drm/drm_drv.c | |||
@@ -118,7 +118,7 @@ static drm_ioctl_desc_t drm_ioctls[] = { | |||
118 | [DRM_IOCTL_NR(DRM_IOCTL_WAIT_VBLANK)] = {drm_wait_vblank, 0}, | 118 | [DRM_IOCTL_NR(DRM_IOCTL_WAIT_VBLANK)] = {drm_wait_vblank, 0}, |
119 | }; | 119 | }; |
120 | 120 | ||
121 | #define DRIVER_IOCTL_COUNT DRM_ARRAY_SIZE( drm_ioctls ) | 121 | #define DRIVER_IOCTL_COUNT ARRAY_SIZE( drm_ioctls ) |
122 | 122 | ||
123 | /** | 123 | /** |
124 | * Take down the DRM device. | 124 | * Take down the DRM device. |
@@ -155,12 +155,13 @@ int drm_lastclose(drm_device_t * dev) | |||
155 | del_timer(&dev->timer); | 155 | del_timer(&dev->timer); |
156 | 156 | ||
157 | /* Clear pid list */ | 157 | /* Clear pid list */ |
158 | for (i = 0; i < DRM_HASH_SIZE; i++) { | 158 | if (dev->magicfree.next) { |
159 | for (pt = dev->magiclist[i].head; pt; pt = next) { | 159 | list_for_each_entry_safe(pt, next, &dev->magicfree, head) { |
160 | next = pt->next; | 160 | list_del(&pt->head); |
161 | drm_ht_remove_item(&dev->magiclist, &pt->hash_item); | ||
161 | drm_free(pt, sizeof(*pt), DRM_MEM_MAGIC); | 162 | drm_free(pt, sizeof(*pt), DRM_MEM_MAGIC); |
162 | } | 163 | } |
163 | dev->magiclist[i].head = dev->magiclist[i].tail = NULL; | 164 | drm_ht_remove(&dev->magiclist); |
164 | } | 165 | } |
165 | 166 | ||
166 | /* Clear AGP information */ | 167 | /* Clear AGP information */ |
@@ -299,6 +300,7 @@ static void drm_cleanup(drm_device_t * dev) | |||
299 | if (dev->maplist) { | 300 | if (dev->maplist) { |
300 | drm_free(dev->maplist, sizeof(*dev->maplist), DRM_MEM_MAPS); | 301 | drm_free(dev->maplist, sizeof(*dev->maplist), DRM_MEM_MAPS); |
301 | dev->maplist = NULL; | 302 | dev->maplist = NULL; |
303 | drm_ht_remove(&dev->map_hash); | ||
302 | } | 304 | } |
303 | 305 | ||
304 | drm_ctxbitmap_cleanup(dev); | 306 | drm_ctxbitmap_cleanup(dev); |
diff --git a/drivers/char/drm/drm_fops.c b/drivers/char/drm/drm_fops.c index b7f7951c4587..898f47dafec0 100644 --- a/drivers/char/drm/drm_fops.c +++ b/drivers/char/drm/drm_fops.c | |||
@@ -53,6 +53,8 @@ static int drm_setup(drm_device_t * dev) | |||
53 | return ret; | 53 | return ret; |
54 | } | 54 | } |
55 | 55 | ||
56 | dev->magicfree.next = NULL; | ||
57 | |||
56 | /* prebuild the SAREA */ | 58 | /* prebuild the SAREA */ |
57 | i = drm_addmap(dev, 0, SAREA_MAX, _DRM_SHM, _DRM_CONTAINS_LOCK, &map); | 59 | i = drm_addmap(dev, 0, SAREA_MAX, _DRM_SHM, _DRM_CONTAINS_LOCK, &map); |
58 | if (i != 0) | 60 | if (i != 0) |
@@ -69,13 +71,11 @@ static int drm_setup(drm_device_t * dev) | |||
69 | return i; | 71 | return i; |
70 | } | 72 | } |
71 | 73 | ||
72 | for (i = 0; i < DRM_ARRAY_SIZE(dev->counts); i++) | 74 | for (i = 0; i < ARRAY_SIZE(dev->counts); i++) |
73 | atomic_set(&dev->counts[i], 0); | 75 | atomic_set(&dev->counts[i], 0); |
74 | 76 | ||
75 | for (i = 0; i < DRM_HASH_SIZE; i++) { | 77 | drm_ht_create(&dev->magiclist, DRM_MAGIC_HASH_ORDER); |
76 | dev->magiclist[i].head = NULL; | 78 | INIT_LIST_HEAD(&dev->magicfree); |
77 | dev->magiclist[i].tail = NULL; | ||
78 | } | ||
79 | 79 | ||
80 | dev->ctxlist = drm_alloc(sizeof(*dev->ctxlist), DRM_MEM_CTXLIST); | 80 | dev->ctxlist = drm_alloc(sizeof(*dev->ctxlist), DRM_MEM_CTXLIST); |
81 | if (dev->ctxlist == NULL) | 81 | if (dev->ctxlist == NULL) |
diff --git a/drivers/char/drm/drm_hashtab.c b/drivers/char/drm/drm_hashtab.c new file mode 100644 index 000000000000..a0b2d6802ae4 --- /dev/null +++ b/drivers/char/drm/drm_hashtab.c | |||
@@ -0,0 +1,190 @@ | |||
1 | /************************************************************************** | ||
2 | * | ||
3 | * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND. USA. | ||
4 | * All Rights Reserved. | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
7 | * copy of this software and associated documentation files (the | ||
8 | * "Software"), to deal in the Software without restriction, including | ||
9 | * without limitation the rights to use, copy, modify, merge, publish, | ||
10 | * distribute, sub license, and/or sell copies of the Software, and to | ||
11 | * permit persons to whom the Software is furnished to do so, subject to | ||
12 | * the following conditions: | ||
13 | * | ||
14 | * The above copyright notice and this permission notice (including the | ||
15 | * next paragraph) shall be included in all copies or substantial portions | ||
16 | * of the Software. | ||
17 | * | ||
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL | ||
21 | * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, | ||
22 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR | ||
23 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE | ||
24 | * USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
25 | * | ||
26 | * | ||
27 | **************************************************************************/ | ||
28 | /* | ||
29 | * Simple open hash tab implementation. | ||
30 | * | ||
31 | * Authors: | ||
32 | * Thomas Hellström <thomas-at-tungstengraphics-dot-com> | ||
33 | */ | ||
34 | |||
35 | #include "drmP.h" | ||
36 | #include "drm_hashtab.h" | ||
37 | #include <linux/hash.h> | ||
38 | |||
39 | int drm_ht_create(drm_open_hash_t *ht, unsigned int order) | ||
40 | { | ||
41 | unsigned int i; | ||
42 | |||
43 | ht->size = 1 << order; | ||
44 | ht->order = order; | ||
45 | ht->fill = 0; | ||
46 | ht->table = vmalloc(ht->size*sizeof(*ht->table)); | ||
47 | if (!ht->table) { | ||
48 | DRM_ERROR("Out of memory for hash table\n"); | ||
49 | return -ENOMEM; | ||
50 | } | ||
51 | for (i=0; i< ht->size; ++i) { | ||
52 | INIT_HLIST_HEAD(&ht->table[i]); | ||
53 | } | ||
54 | return 0; | ||
55 | } | ||
56 | |||
57 | void drm_ht_verbose_list(drm_open_hash_t *ht, unsigned long key) | ||
58 | { | ||
59 | drm_hash_item_t *entry; | ||
60 | struct hlist_head *h_list; | ||
61 | struct hlist_node *list; | ||
62 | unsigned int hashed_key; | ||
63 | int count = 0; | ||
64 | |||
65 | hashed_key = hash_long(key, ht->order); | ||
66 | DRM_DEBUG("Key is 0x%08lx, Hashed key is 0x%08x\n", key, hashed_key); | ||
67 | h_list = &ht->table[hashed_key]; | ||
68 | hlist_for_each(list, h_list) { | ||
69 | entry = hlist_entry(list, drm_hash_item_t, head); | ||
70 | DRM_DEBUG("count %d, key: 0x%08lx\n", count++, entry->key); | ||
71 | } | ||
72 | } | ||
73 | |||
74 | static struct hlist_node *drm_ht_find_key(drm_open_hash_t *ht, | ||
75 | unsigned long key) | ||
76 | { | ||
77 | drm_hash_item_t *entry; | ||
78 | struct hlist_head *h_list; | ||
79 | struct hlist_node *list; | ||
80 | unsigned int hashed_key; | ||
81 | |||
82 | hashed_key = hash_long(key, ht->order); | ||
83 | h_list = &ht->table[hashed_key]; | ||
84 | hlist_for_each(list, h_list) { | ||
85 | entry = hlist_entry(list, drm_hash_item_t, head); | ||
86 | if (entry->key == key) | ||
87 | return list; | ||
88 | if (entry->key > key) | ||
89 | break; | ||
90 | } | ||
91 | return NULL; | ||
92 | } | ||
93 | |||
94 | |||
95 | int drm_ht_insert_item(drm_open_hash_t *ht, drm_hash_item_t *item) | ||
96 | { | ||
97 | drm_hash_item_t *entry; | ||
98 | struct hlist_head *h_list; | ||
99 | struct hlist_node *list, *parent; | ||
100 | unsigned int hashed_key; | ||
101 | unsigned long key = item->key; | ||
102 | |||
103 | hashed_key = hash_long(key, ht->order); | ||
104 | h_list = &ht->table[hashed_key]; | ||
105 | parent = NULL; | ||
106 | hlist_for_each(list, h_list) { | ||
107 | entry = hlist_entry(list, drm_hash_item_t, head); | ||
108 | if (entry->key == key) | ||
109 | return -EINVAL; | ||
110 | if (entry->key > key) | ||
111 | break; | ||
112 | parent = list; | ||
113 | } | ||
114 | if (parent) { | ||
115 | hlist_add_after(parent, &item->head); | ||
116 | } else { | ||
117 | hlist_add_head(&item->head, h_list); | ||
118 | } | ||
119 | return 0; | ||
120 | } | ||
121 | |||
122 | /* | ||
123 | * Just insert an item and return any "bits" bit key that hasn't been | ||
124 | * used before. | ||
125 | */ | ||
126 | int drm_ht_just_insert_please(drm_open_hash_t *ht, drm_hash_item_t *item, | ||
127 | unsigned long seed, int bits, int shift, | ||
128 | unsigned long add) | ||
129 | { | ||
130 | int ret; | ||
131 | unsigned long mask = (1 << bits) - 1; | ||
132 | unsigned long first, unshifted_key; | ||
133 | |||
134 | unshifted_key = hash_long(seed, bits); | ||
135 | first = unshifted_key; | ||
136 | do { | ||
137 | item->key = (unshifted_key << shift) + add; | ||
138 | ret = drm_ht_insert_item(ht, item); | ||
139 | if (ret) | ||
140 | unshifted_key = (unshifted_key + 1) & mask; | ||
141 | } while(ret && (unshifted_key != first)); | ||
142 | |||
143 | if (ret) { | ||
144 | DRM_ERROR("Available key bit space exhausted\n"); | ||
145 | return -EINVAL; | ||
146 | } | ||
147 | return 0; | ||
148 | } | ||
149 | |||
150 | int drm_ht_find_item(drm_open_hash_t *ht, unsigned long key, | ||
151 | drm_hash_item_t **item) | ||
152 | { | ||
153 | struct hlist_node *list; | ||
154 | |||
155 | list = drm_ht_find_key(ht, key); | ||
156 | if (!list) | ||
157 | return -EINVAL; | ||
158 | |||
159 | *item = hlist_entry(list, drm_hash_item_t, head); | ||
160 | return 0; | ||
161 | } | ||
162 | |||
163 | int drm_ht_remove_key(drm_open_hash_t *ht, unsigned long key) | ||
164 | { | ||
165 | struct hlist_node *list; | ||
166 | |||
167 | list = drm_ht_find_key(ht, key); | ||
168 | if (list) { | ||
169 | hlist_del_init(list); | ||
170 | ht->fill--; | ||
171 | return 0; | ||
172 | } | ||
173 | return -EINVAL; | ||
174 | } | ||
175 | |||
176 | int drm_ht_remove_item(drm_open_hash_t *ht, drm_hash_item_t *item) | ||
177 | { | ||
178 | hlist_del_init(&item->head); | ||
179 | ht->fill--; | ||
180 | return 0; | ||
181 | } | ||
182 | |||
183 | void drm_ht_remove(drm_open_hash_t *ht) | ||
184 | { | ||
185 | if (ht->table) { | ||
186 | vfree(ht->table); | ||
187 | ht->table = NULL; | ||
188 | } | ||
189 | } | ||
190 | |||
diff --git a/drivers/char/drm/drm_hashtab.h b/drivers/char/drm/drm_hashtab.h new file mode 100644 index 000000000000..40afec05bff8 --- /dev/null +++ b/drivers/char/drm/drm_hashtab.h | |||
@@ -0,0 +1,67 @@ | |||
1 | /************************************************************************** | ||
2 | * | ||
3 | * Copyright 2006 Tungsten Graphics, Inc., Bismack, ND. USA. | ||
4 | * All Rights Reserved. | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
7 | * copy of this software and associated documentation files (the | ||
8 | * "Software"), to deal in the Software without restriction, including | ||
9 | * without limitation the rights to use, copy, modify, merge, publish, | ||
10 | * distribute, sub license, and/or sell copies of the Software, and to | ||
11 | * permit persons to whom the Software is furnished to do so, subject to | ||
12 | * the following conditions: | ||
13 | * | ||
14 | * The above copyright notice and this permission notice (including the | ||
15 | * next paragraph) shall be included in all copies or substantial portions | ||
16 | * of the Software. | ||
17 | * | ||
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL | ||
21 | * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, | ||
22 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR | ||
23 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE | ||
24 | * USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
25 | * | ||
26 | * | ||
27 | **************************************************************************/ | ||
28 | /* | ||
29 | * Simple open hash tab implementation. | ||
30 | * | ||
31 | * Authors: | ||
32 | * Thomas Hellström <thomas-at-tungstengraphics-dot-com> | ||
33 | */ | ||
34 | |||
35 | #ifndef DRM_HASHTAB_H | ||
36 | #define DRM_HASHTAB_H | ||
37 | |||
38 | #define drm_hash_entry(_ptr, _type, _member) container_of(_ptr, _type, _member) | ||
39 | |||
40 | typedef struct drm_hash_item{ | ||
41 | struct hlist_node head; | ||
42 | unsigned long key; | ||
43 | } drm_hash_item_t; | ||
44 | |||
45 | typedef struct drm_open_hash{ | ||
46 | unsigned int size; | ||
47 | unsigned int order; | ||
48 | unsigned int fill; | ||
49 | struct hlist_head *table; | ||
50 | } drm_open_hash_t; | ||
51 | |||
52 | |||
53 | extern int drm_ht_create(drm_open_hash_t *ht, unsigned int order); | ||
54 | extern int drm_ht_insert_item(drm_open_hash_t *ht, drm_hash_item_t *item); | ||
55 | extern int drm_ht_just_insert_please(drm_open_hash_t *ht, drm_hash_item_t *item, | ||
56 | unsigned long seed, int bits, int shift, | ||
57 | unsigned long add); | ||
58 | extern int drm_ht_find_item(drm_open_hash_t *ht, unsigned long key, drm_hash_item_t **item); | ||
59 | |||
60 | extern void drm_ht_verbose_list(drm_open_hash_t *ht, unsigned long key); | ||
61 | extern int drm_ht_remove_key(drm_open_hash_t *ht, unsigned long key); | ||
62 | extern int drm_ht_remove_item(drm_open_hash_t *ht, drm_hash_item_t *item); | ||
63 | extern void drm_ht_remove(drm_open_hash_t *ht); | ||
64 | |||
65 | |||
66 | #endif | ||
67 | |||
diff --git a/drivers/char/drm/drm_ioc32.c b/drivers/char/drm/drm_ioc32.c index e9e2db18952d..d4f874520082 100644 --- a/drivers/char/drm/drm_ioc32.c +++ b/drivers/char/drm/drm_ioc32.c | |||
@@ -1051,7 +1051,7 @@ long drm_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) | |||
1051 | drm_ioctl_compat_t *fn; | 1051 | drm_ioctl_compat_t *fn; |
1052 | int ret; | 1052 | int ret; |
1053 | 1053 | ||
1054 | if (nr >= DRM_ARRAY_SIZE(drm_compat_ioctls)) | 1054 | if (nr >= ARRAY_SIZE(drm_compat_ioctls)) |
1055 | return -ENOTTY; | 1055 | return -ENOTTY; |
1056 | 1056 | ||
1057 | fn = drm_compat_ioctls[nr]; | 1057 | fn = drm_compat_ioctls[nr]; |
diff --git a/drivers/char/drm/drm_ioctl.c b/drivers/char/drm/drm_ioctl.c index 555f323b8a32..565895547d75 100644 --- a/drivers/char/drm/drm_ioctl.c +++ b/drivers/char/drm/drm_ioctl.c | |||
@@ -127,9 +127,10 @@ int drm_setunique(struct inode *inode, struct file *filp, | |||
127 | domain = bus >> 8; | 127 | domain = bus >> 8; |
128 | bus &= 0xff; | 128 | bus &= 0xff; |
129 | 129 | ||
130 | if ((domain != dev->pci_domain) || | 130 | if ((domain != drm_get_pci_domain(dev)) || |
131 | (bus != dev->pci_bus) || | 131 | (bus != dev->pdev->bus->number) || |
132 | (slot != dev->pci_slot) || (func != dev->pci_func)) | 132 | (slot != PCI_SLOT(dev->pdev->devfn)) || |
133 | (func != PCI_FUNC(dev->pdev->devfn))) | ||
133 | return -EINVAL; | 134 | return -EINVAL; |
134 | 135 | ||
135 | return 0; | 136 | return 0; |
@@ -140,15 +141,17 @@ static int drm_set_busid(drm_device_t * dev) | |||
140 | int len; | 141 | int len; |
141 | 142 | ||
142 | if (dev->unique != NULL) | 143 | if (dev->unique != NULL) |
143 | return EBUSY; | 144 | return 0; |
144 | 145 | ||
145 | dev->unique_len = 40; | 146 | dev->unique_len = 40; |
146 | dev->unique = drm_alloc(dev->unique_len + 1, DRM_MEM_DRIVER); | 147 | dev->unique = drm_alloc(dev->unique_len + 1, DRM_MEM_DRIVER); |
147 | if (dev->unique == NULL) | 148 | if (dev->unique == NULL) |
148 | return ENOMEM; | 149 | return -ENOMEM; |
149 | 150 | ||
150 | len = snprintf(dev->unique, dev->unique_len, "pci:%04x:%02x:%02x.%d", | 151 | len = snprintf(dev->unique, dev->unique_len, "pci:%04x:%02x:%02x.%d", |
151 | dev->pci_domain, dev->pci_bus, dev->pci_slot, dev->pci_func); | 152 | drm_get_pci_domain(dev), dev->pdev->bus->number, |
153 | PCI_SLOT(dev->pdev->devfn), | ||
154 | PCI_FUNC(dev->pdev->devfn)); | ||
152 | 155 | ||
153 | if (len > dev->unique_len) | 156 | if (len > dev->unique_len) |
154 | DRM_ERROR("Unique buffer overflowed\n"); | 157 | DRM_ERROR("Unique buffer overflowed\n"); |
@@ -157,7 +160,7 @@ static int drm_set_busid(drm_device_t * dev) | |||
157 | drm_alloc(strlen(dev->driver->pci_driver.name) + dev->unique_len + | 160 | drm_alloc(strlen(dev->driver->pci_driver.name) + dev->unique_len + |
158 | 2, DRM_MEM_DRIVER); | 161 | 2, DRM_MEM_DRIVER); |
159 | if (dev->devname == NULL) | 162 | if (dev->devname == NULL) |
160 | return ENOMEM; | 163 | return -ENOMEM; |
161 | 164 | ||
162 | sprintf(dev->devname, "%s@%s", dev->driver->pci_driver.name, | 165 | sprintf(dev->devname, "%s@%s", dev->driver->pci_driver.name, |
163 | dev->unique); | 166 | dev->unique); |
@@ -330,27 +333,32 @@ int drm_setversion(DRM_IOCTL_ARGS) | |||
330 | drm_set_version_t retv; | 333 | drm_set_version_t retv; |
331 | int if_version; | 334 | int if_version; |
332 | drm_set_version_t __user *argp = (void __user *)data; | 335 | drm_set_version_t __user *argp = (void __user *)data; |
336 | int ret; | ||
333 | 337 | ||
334 | DRM_COPY_FROM_USER_IOCTL(sv, argp, sizeof(sv)); | 338 | if (copy_from_user(&sv, argp, sizeof(sv))) |
339 | return -EFAULT; | ||
335 | 340 | ||
336 | retv.drm_di_major = DRM_IF_MAJOR; | 341 | retv.drm_di_major = DRM_IF_MAJOR; |
337 | retv.drm_di_minor = DRM_IF_MINOR; | 342 | retv.drm_di_minor = DRM_IF_MINOR; |
338 | retv.drm_dd_major = dev->driver->major; | 343 | retv.drm_dd_major = dev->driver->major; |
339 | retv.drm_dd_minor = dev->driver->minor; | 344 | retv.drm_dd_minor = dev->driver->minor; |
340 | 345 | ||
341 | DRM_COPY_TO_USER_IOCTL(argp, retv, sizeof(sv)); | 346 | if (copy_to_user(argp, &retv, sizeof(retv))) |
347 | return -EFAULT; | ||
342 | 348 | ||
343 | if (sv.drm_di_major != -1) { | 349 | if (sv.drm_di_major != -1) { |
344 | if (sv.drm_di_major != DRM_IF_MAJOR || | 350 | if (sv.drm_di_major != DRM_IF_MAJOR || |
345 | sv.drm_di_minor < 0 || sv.drm_di_minor > DRM_IF_MINOR) | 351 | sv.drm_di_minor < 0 || sv.drm_di_minor > DRM_IF_MINOR) |
346 | return EINVAL; | 352 | return -EINVAL; |
347 | if_version = DRM_IF_VERSION(sv.drm_di_major, sv.drm_di_minor); | 353 | if_version = DRM_IF_VERSION(sv.drm_di_major, sv.drm_di_minor); |
348 | dev->if_version = DRM_MAX(if_version, dev->if_version); | 354 | dev->if_version = max(if_version, dev->if_version); |
349 | if (sv.drm_di_minor >= 1) { | 355 | if (sv.drm_di_minor >= 1) { |
350 | /* | 356 | /* |
351 | * Version 1.1 includes tying of DRM to specific device | 357 | * Version 1.1 includes tying of DRM to specific device |
352 | */ | 358 | */ |
353 | drm_set_busid(dev); | 359 | ret = drm_set_busid(dev); |
360 | if (ret) | ||
361 | return ret; | ||
354 | } | 362 | } |
355 | } | 363 | } |
356 | 364 | ||
@@ -358,7 +366,7 @@ int drm_setversion(DRM_IOCTL_ARGS) | |||
358 | if (sv.drm_dd_major != dev->driver->major || | 366 | if (sv.drm_dd_major != dev->driver->major || |
359 | sv.drm_dd_minor < 0 | 367 | sv.drm_dd_minor < 0 |
360 | || sv.drm_dd_minor > dev->driver->minor) | 368 | || sv.drm_dd_minor > dev->driver->minor) |
361 | return EINVAL; | 369 | return -EINVAL; |
362 | 370 | ||
363 | if (dev->driver->set_version) | 371 | if (dev->driver->set_version) |
364 | dev->driver->set_version(dev, &sv); | 372 | dev->driver->set_version(dev, &sv); |
diff --git a/drivers/char/drm/drm_irq.c b/drivers/char/drm/drm_irq.c index ebdb7182c4fd..4553a3a1e496 100644 --- a/drivers/char/drm/drm_irq.c +++ b/drivers/char/drm/drm_irq.c | |||
@@ -64,9 +64,9 @@ int drm_irq_by_busid(struct inode *inode, struct file *filp, | |||
64 | if (copy_from_user(&p, argp, sizeof(p))) | 64 | if (copy_from_user(&p, argp, sizeof(p))) |
65 | return -EFAULT; | 65 | return -EFAULT; |
66 | 66 | ||
67 | if ((p.busnum >> 8) != dev->pci_domain || | 67 | if ((p.busnum >> 8) != drm_get_pci_domain(dev) || |
68 | (p.busnum & 0xff) != dev->pci_bus || | 68 | (p.busnum & 0xff) != dev->pdev->bus->number || |
69 | p.devnum != dev->pci_slot || p.funcnum != dev->pci_func) | 69 | p.devnum != PCI_SLOT(dev->pdev->devfn) || p.funcnum != PCI_FUNC(dev->pdev->devfn)) |
70 | return -EINVAL; | 70 | return -EINVAL; |
71 | 71 | ||
72 | p.irq = dev->irq; | 72 | p.irq = dev->irq; |
@@ -255,7 +255,8 @@ int drm_wait_vblank(DRM_IOCTL_ARGS) | |||
255 | if (!dev->irq) | 255 | if (!dev->irq) |
256 | return -EINVAL; | 256 | return -EINVAL; |
257 | 257 | ||
258 | DRM_COPY_FROM_USER_IOCTL(vblwait, argp, sizeof(vblwait)); | 258 | if (copy_from_user(&vblwait, argp, sizeof(vblwait))) |
259 | return -EFAULT; | ||
259 | 260 | ||
260 | switch (vblwait.request.type & ~_DRM_VBLANK_FLAGS_MASK) { | 261 | switch (vblwait.request.type & ~_DRM_VBLANK_FLAGS_MASK) { |
261 | case _DRM_VBLANK_RELATIVE: | 262 | case _DRM_VBLANK_RELATIVE: |
@@ -329,7 +330,8 @@ int drm_wait_vblank(DRM_IOCTL_ARGS) | |||
329 | } | 330 | } |
330 | 331 | ||
331 | done: | 332 | done: |
332 | DRM_COPY_TO_USER_IOCTL(argp, vblwait, sizeof(vblwait)); | 333 | if (copy_to_user(argp, &vblwait, sizeof(vblwait))) |
334 | return -EFAULT; | ||
333 | 335 | ||
334 | return ret; | 336 | return ret; |
335 | } | 337 | } |
diff --git a/drivers/char/drm/drm_mm.c b/drivers/char/drm/drm_mm.c new file mode 100644 index 000000000000..617526bd5b0c --- /dev/null +++ b/drivers/char/drm/drm_mm.c | |||
@@ -0,0 +1,201 @@ | |||
1 | /************************************************************************** | ||
2 | * | ||
3 | * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND., USA. | ||
4 | * All Rights Reserved. | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
7 | * copy of this software and associated documentation files (the | ||
8 | * "Software"), to deal in the Software without restriction, including | ||
9 | * without limitation the rights to use, copy, modify, merge, publish, | ||
10 | * distribute, sub license, and/or sell copies of the Software, and to | ||
11 | * permit persons to whom the Software is furnished to do so, subject to | ||
12 | * the following conditions: | ||
13 | * | ||
14 | * The above copyright notice and this permission notice (including the | ||
15 | * next paragraph) shall be included in all copies or substantial portions | ||
16 | * of the Software. | ||
17 | * | ||
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL | ||
21 | * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, | ||
22 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR | ||
23 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE | ||
24 | * USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
25 | * | ||
26 | * | ||
27 | **************************************************************************/ | ||
28 | |||
29 | /* | ||
30 | * Generic simple memory manager implementation. Intended to be used as a base | ||
31 | * class implementation for more advanced memory managers. | ||
32 | * | ||
33 | * Note that the algorithm used is quite simple and there might be substantial | ||
34 | * performance gains if a smarter free list is implemented. Currently it is just an | ||
35 | * unordered stack of free regions. This could easily be improved if an RB-tree | ||
36 | * is used instead. At least if we expect heavy fragmentation. | ||
37 | * | ||
38 | * Aligned allocations can also see improvement. | ||
39 | * | ||
40 | * Authors: | ||
41 | * Thomas Hellström <thomas-at-tungstengraphics-dot-com> | ||
42 | */ | ||
43 | |||
44 | #include "drmP.h" | ||
45 | |||
46 | drm_mm_node_t *drm_mm_get_block(drm_mm_node_t * parent, | ||
47 | unsigned long size, unsigned alignment) | ||
48 | { | ||
49 | |||
50 | drm_mm_node_t *child; | ||
51 | |||
52 | if (alignment) | ||
53 | size += alignment - 1; | ||
54 | |||
55 | if (parent->size == size) { | ||
56 | list_del_init(&parent->fl_entry); | ||
57 | parent->free = 0; | ||
58 | return parent; | ||
59 | } else { | ||
60 | child = (drm_mm_node_t *) drm_alloc(sizeof(*child), DRM_MEM_MM); | ||
61 | if (!child) | ||
62 | return NULL; | ||
63 | |||
64 | INIT_LIST_HEAD(&child->ml_entry); | ||
65 | INIT_LIST_HEAD(&child->fl_entry); | ||
66 | |||
67 | child->free = 0; | ||
68 | child->size = size; | ||
69 | child->start = parent->start; | ||
70 | |||
71 | list_add_tail(&child->ml_entry, &parent->ml_entry); | ||
72 | parent->size -= size; | ||
73 | parent->start += size; | ||
74 | } | ||
75 | return child; | ||
76 | } | ||
77 | |||
78 | /* | ||
79 | * Put a block. Merge with the previous and / or next block if they are free. | ||
80 | * Otherwise add to the free stack. | ||
81 | */ | ||
82 | |||
83 | void drm_mm_put_block(drm_mm_t * mm, drm_mm_node_t * cur) | ||
84 | { | ||
85 | |||
86 | drm_mm_node_t *list_root = &mm->root_node; | ||
87 | struct list_head *cur_head = &cur->ml_entry; | ||
88 | struct list_head *root_head = &list_root->ml_entry; | ||
89 | drm_mm_node_t *prev_node = NULL; | ||
90 | drm_mm_node_t *next_node; | ||
91 | |||
92 | int merged = 0; | ||
93 | |||
94 | if (cur_head->prev != root_head) { | ||
95 | prev_node = list_entry(cur_head->prev, drm_mm_node_t, ml_entry); | ||
96 | if (prev_node->free) { | ||
97 | prev_node->size += cur->size; | ||
98 | merged = 1; | ||
99 | } | ||
100 | } | ||
101 | if (cur_head->next != root_head) { | ||
102 | next_node = list_entry(cur_head->next, drm_mm_node_t, ml_entry); | ||
103 | if (next_node->free) { | ||
104 | if (merged) { | ||
105 | prev_node->size += next_node->size; | ||
106 | list_del(&next_node->ml_entry); | ||
107 | list_del(&next_node->fl_entry); | ||
108 | drm_free(next_node, sizeof(*next_node), | ||
109 | DRM_MEM_MM); | ||
110 | } else { | ||
111 | next_node->size += cur->size; | ||
112 | next_node->start = cur->start; | ||
113 | merged = 1; | ||
114 | } | ||
115 | } | ||
116 | } | ||
117 | if (!merged) { | ||
118 | cur->free = 1; | ||
119 | list_add(&cur->fl_entry, &list_root->fl_entry); | ||
120 | } else { | ||
121 | list_del(&cur->ml_entry); | ||
122 | drm_free(cur, sizeof(*cur), DRM_MEM_MM); | ||
123 | } | ||
124 | } | ||
125 | |||
126 | drm_mm_node_t *drm_mm_search_free(const drm_mm_t * mm, | ||
127 | unsigned long size, | ||
128 | unsigned alignment, int best_match) | ||
129 | { | ||
130 | struct list_head *list; | ||
131 | const struct list_head *free_stack = &mm->root_node.fl_entry; | ||
132 | drm_mm_node_t *entry; | ||
133 | drm_mm_node_t *best; | ||
134 | unsigned long best_size; | ||
135 | |||
136 | best = NULL; | ||
137 | best_size = ~0UL; | ||
138 | |||
139 | if (alignment) | ||
140 | size += alignment - 1; | ||
141 | |||
142 | list_for_each(list, free_stack) { | ||
143 | entry = list_entry(list, drm_mm_node_t, fl_entry); | ||
144 | if (entry->size >= size) { | ||
145 | if (!best_match) | ||
146 | return entry; | ||
147 | if (size < best_size) { | ||
148 | best = entry; | ||
149 | best_size = entry->size; | ||
150 | } | ||
151 | } | ||
152 | } | ||
153 | |||
154 | return best; | ||
155 | } | ||
156 | |||
157 | int drm_mm_init(drm_mm_t * mm, unsigned long start, unsigned long size) | ||
158 | { | ||
159 | drm_mm_node_t *child; | ||
160 | |||
161 | INIT_LIST_HEAD(&mm->root_node.ml_entry); | ||
162 | INIT_LIST_HEAD(&mm->root_node.fl_entry); | ||
163 | child = (drm_mm_node_t *) drm_alloc(sizeof(*child), DRM_MEM_MM); | ||
164 | if (!child) | ||
165 | return -ENOMEM; | ||
166 | |||
167 | INIT_LIST_HEAD(&child->ml_entry); | ||
168 | INIT_LIST_HEAD(&child->fl_entry); | ||
169 | |||
170 | child->start = start; | ||
171 | child->size = size; | ||
172 | child->free = 1; | ||
173 | |||
174 | list_add(&child->fl_entry, &mm->root_node.fl_entry); | ||
175 | list_add(&child->ml_entry, &mm->root_node.ml_entry); | ||
176 | |||
177 | return 0; | ||
178 | } | ||
179 | |||
180 | EXPORT_SYMBOL(drm_mm_init); | ||
181 | |||
182 | void drm_mm_takedown(drm_mm_t * mm) | ||
183 | { | ||
184 | struct list_head *bnode = mm->root_node.fl_entry.next; | ||
185 | drm_mm_node_t *entry; | ||
186 | |||
187 | entry = list_entry(bnode, drm_mm_node_t, fl_entry); | ||
188 | |||
189 | if (entry->ml_entry.next != &mm->root_node.ml_entry || | ||
190 | entry->fl_entry.next != &mm->root_node.fl_entry) { | ||
191 | DRM_ERROR("Memory manager not clean. Delaying takedown\n"); | ||
192 | return; | ||
193 | } | ||
194 | |||
195 | list_del(&entry->fl_entry); | ||
196 | list_del(&entry->ml_entry); | ||
197 | |||
198 | drm_free(entry, sizeof(*entry), DRM_MEM_MM); | ||
199 | } | ||
200 | |||
201 | EXPORT_SYMBOL(drm_mm_takedown); | ||
diff --git a/drivers/char/drm/drm_pciids.h b/drivers/char/drm/drm_pciids.h index b1bb3c7b568d..09398d5fbd3f 100644 --- a/drivers/char/drm/drm_pciids.h +++ b/drivers/char/drm/drm_pciids.h | |||
@@ -3,13 +3,13 @@ | |||
3 | Please contact dri-devel@lists.sf.net to add new cards to this list | 3 | Please contact dri-devel@lists.sf.net to add new cards to this list |
4 | */ | 4 | */ |
5 | #define radeon_PCI_IDS \ | 5 | #define radeon_PCI_IDS \ |
6 | {0x1002, 0x3150, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_IS_MOBILITY}, \ | 6 | {0x1002, 0x3150, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY}, \ |
7 | {0x1002, 0x3152, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \ | 7 | {0x1002, 0x3152, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ |
8 | {0x1002, 0x3154, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \ | 8 | {0x1002, 0x3154, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ |
9 | {0x1002, 0x3E50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_NEW_MEMMAP}, \ | 9 | {0x1002, 0x3E50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \ |
10 | {0x1002, 0x3E54, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_NEW_MEMMAP}, \ | 10 | {0x1002, 0x3E54, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \ |
11 | {0x1002, 0x4136, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS100|CHIP_IS_IGP}, \ | 11 | {0x1002, 0x4136, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS100|RADEON_IS_IGP}, \ |
12 | {0x1002, 0x4137, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|CHIP_IS_IGP}, \ | 12 | {0x1002, 0x4137, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|RADEON_IS_IGP}, \ |
13 | {0x1002, 0x4144, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \ | 13 | {0x1002, 0x4144, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \ |
14 | {0x1002, 0x4145, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \ | 14 | {0x1002, 0x4145, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \ |
15 | {0x1002, 0x4146, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \ | 15 | {0x1002, 0x4146, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \ |
@@ -25,35 +25,35 @@ | |||
25 | {0x1002, 0x4154, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \ | 25 | {0x1002, 0x4154, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \ |
26 | {0x1002, 0x4155, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \ | 26 | {0x1002, 0x4155, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \ |
27 | {0x1002, 0x4156, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \ | 27 | {0x1002, 0x4156, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \ |
28 | {0x1002, 0x4237, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|CHIP_IS_IGP}, \ | 28 | {0x1002, 0x4237, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|RADEON_IS_IGP}, \ |
29 | {0x1002, 0x4242, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \ | 29 | {0x1002, 0x4242, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \ |
30 | {0x1002, 0x4243, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \ | 30 | {0x1002, 0x4243, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \ |
31 | {0x1002, 0x4336, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS100|CHIP_IS_IGP|CHIP_IS_MOBILITY}, \ | 31 | {0x1002, 0x4336, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS100|RADEON_IS_IGP|RADEON_IS_MOBILITY}, \ |
32 | {0x1002, 0x4337, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|CHIP_IS_IGP|CHIP_IS_MOBILITY}, \ | 32 | {0x1002, 0x4337, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|RADEON_IS_IGP|RADEON_IS_MOBILITY}, \ |
33 | {0x1002, 0x4437, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|CHIP_IS_IGP|CHIP_IS_MOBILITY}, \ | 33 | {0x1002, 0x4437, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|RADEON_IS_IGP|RADEON_IS_MOBILITY}, \ |
34 | {0x1002, 0x4966, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250}, \ | 34 | {0x1002, 0x4966, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250}, \ |
35 | {0x1002, 0x4967, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250}, \ | 35 | {0x1002, 0x4967, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250}, \ |
36 | {0x1002, 0x4A48, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \ | 36 | {0x1002, 0x4A48, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \ |
37 | {0x1002, 0x4A49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \ | 37 | {0x1002, 0x4A49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \ |
38 | {0x1002, 0x4A4A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \ | 38 | {0x1002, 0x4A4A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \ |
39 | {0x1002, 0x4A4B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \ | 39 | {0x1002, 0x4A4B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \ |
40 | {0x1002, 0x4A4C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \ | 40 | {0x1002, 0x4A4C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \ |
41 | {0x1002, 0x4A4D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \ | 41 | {0x1002, 0x4A4D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \ |
42 | {0x1002, 0x4A4E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \ | 42 | {0x1002, 0x4A4E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ |
43 | {0x1002, 0x4A4F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \ | 43 | {0x1002, 0x4A4F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \ |
44 | {0x1002, 0x4A50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \ | 44 | {0x1002, 0x4A50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \ |
45 | {0x1002, 0x4A54, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \ | 45 | {0x1002, 0x4A54, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \ |
46 | {0x1002, 0x4B49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \ | 46 | {0x1002, 0x4B49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \ |
47 | {0x1002, 0x4B4A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \ | 47 | {0x1002, 0x4B4A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \ |
48 | {0x1002, 0x4B4B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \ | 48 | {0x1002, 0x4B4B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \ |
49 | {0x1002, 0x4B4C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \ | 49 | {0x1002, 0x4B4C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \ |
50 | {0x1002, 0x4C57, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV200|CHIP_IS_MOBILITY}, \ | 50 | {0x1002, 0x4C57, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV200|RADEON_IS_MOBILITY}, \ |
51 | {0x1002, 0x4C58, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV200|CHIP_IS_MOBILITY}, \ | 51 | {0x1002, 0x4C58, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV200|RADEON_IS_MOBILITY}, \ |
52 | {0x1002, 0x4C59, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100|CHIP_IS_MOBILITY}, \ | 52 | {0x1002, 0x4C59, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100|RADEON_IS_MOBILITY}, \ |
53 | {0x1002, 0x4C5A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100|CHIP_IS_MOBILITY}, \ | 53 | {0x1002, 0x4C5A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100|RADEON_IS_MOBILITY}, \ |
54 | {0x1002, 0x4C64, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250|CHIP_IS_MOBILITY}, \ | 54 | {0x1002, 0x4C64, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250|RADEON_IS_MOBILITY}, \ |
55 | {0x1002, 0x4C66, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250|CHIP_IS_MOBILITY}, \ | 55 | {0x1002, 0x4C66, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250|RADEON_IS_MOBILITY}, \ |
56 | {0x1002, 0x4C67, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250|CHIP_IS_MOBILITY}, \ | 56 | {0x1002, 0x4C67, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250|RADEON_IS_MOBILITY}, \ |
57 | {0x1002, 0x4E44, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \ | 57 | {0x1002, 0x4E44, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \ |
58 | {0x1002, 0x4E45, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \ | 58 | {0x1002, 0x4E45, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \ |
59 | {0x1002, 0x4E46, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \ | 59 | {0x1002, 0x4E46, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \ |
@@ -62,16 +62,16 @@ | |||
62 | {0x1002, 0x4E49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \ | 62 | {0x1002, 0x4E49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \ |
63 | {0x1002, 0x4E4A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \ | 63 | {0x1002, 0x4E4A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \ |
64 | {0x1002, 0x4E4B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \ | 64 | {0x1002, 0x4E4B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \ |
65 | {0x1002, 0x4E50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|CHIP_IS_MOBILITY}, \ | 65 | {0x1002, 0x4E50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|RADEON_IS_MOBILITY}, \ |
66 | {0x1002, 0x4E51, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|CHIP_IS_MOBILITY}, \ | 66 | {0x1002, 0x4E51, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|RADEON_IS_MOBILITY}, \ |
67 | {0x1002, 0x4E52, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|CHIP_IS_MOBILITY}, \ | 67 | {0x1002, 0x4E52, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|RADEON_IS_MOBILITY}, \ |
68 | {0x1002, 0x4E53, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|CHIP_IS_MOBILITY}, \ | 68 | {0x1002, 0x4E53, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|RADEON_IS_MOBILITY}, \ |
69 | {0x1002, 0x4E54, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|CHIP_IS_MOBILITY}, \ | 69 | {0x1002, 0x4E54, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|RADEON_IS_MOBILITY}, \ |
70 | {0x1002, 0x4E56, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|CHIP_IS_MOBILITY}, \ | 70 | {0x1002, 0x4E56, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|RADEON_IS_MOBILITY}, \ |
71 | {0x1002, 0x5144, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|CHIP_SINGLE_CRTC}, \ | 71 | {0x1002, 0x5144, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|RADEON_SINGLE_CRTC}, \ |
72 | {0x1002, 0x5145, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|CHIP_SINGLE_CRTC}, \ | 72 | {0x1002, 0x5145, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|RADEON_SINGLE_CRTC}, \ |
73 | {0x1002, 0x5146, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|CHIP_SINGLE_CRTC}, \ | 73 | {0x1002, 0x5146, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|RADEON_SINGLE_CRTC}, \ |
74 | {0x1002, 0x5147, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|CHIP_SINGLE_CRTC}, \ | 74 | {0x1002, 0x5147, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|RADEON_SINGLE_CRTC}, \ |
75 | {0x1002, 0x5148, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \ | 75 | {0x1002, 0x5148, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \ |
76 | {0x1002, 0x514C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \ | 76 | {0x1002, 0x514C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \ |
77 | {0x1002, 0x514D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \ | 77 | {0x1002, 0x514D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \ |
@@ -80,59 +80,59 @@ | |||
80 | {0x1002, 0x5159, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100}, \ | 80 | {0x1002, 0x5159, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100}, \ |
81 | {0x1002, 0x515A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100}, \ | 81 | {0x1002, 0x515A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100}, \ |
82 | {0x1002, 0x515E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100}, \ | 82 | {0x1002, 0x515E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100}, \ |
83 | {0x1002, 0x5460, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_IS_MOBILITY}, \ | 83 | {0x1002, 0x5460, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY}, \ |
84 | {0x1002, 0x5462, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_IS_MOBILITY}, \ | 84 | {0x1002, 0x5462, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY}, \ |
85 | {0x1002, 0x5464, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_IS_MOBILITY}, \ | 85 | {0x1002, 0x5464, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY}, \ |
86 | {0x1002, 0x5548, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \ | 86 | {0x1002, 0x5548, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \ |
87 | {0x1002, 0x5549, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \ | 87 | {0x1002, 0x5549, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \ |
88 | {0x1002, 0x554A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \ | 88 | {0x1002, 0x554A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \ |
89 | {0x1002, 0x554B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \ | 89 | {0x1002, 0x554B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \ |
90 | {0x1002, 0x554C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \ | 90 | {0x1002, 0x554C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \ |
91 | {0x1002, 0x554D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \ | 91 | {0x1002, 0x554D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \ |
92 | {0x1002, 0x554E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \ | 92 | {0x1002, 0x554E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \ |
93 | {0x1002, 0x554F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \ | 93 | {0x1002, 0x554F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \ |
94 | {0x1002, 0x5550, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \ | 94 | {0x1002, 0x5550, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \ |
95 | {0x1002, 0x5551, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \ | 95 | {0x1002, 0x5551, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \ |
96 | {0x1002, 0x5552, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \ | 96 | {0x1002, 0x5552, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \ |
97 | {0x1002, 0x5554, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \ | 97 | {0x1002, 0x5554, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \ |
98 | {0x1002, 0x564A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \ | 98 | {0x1002, 0x564A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ |
99 | {0x1002, 0x564B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \ | 99 | {0x1002, 0x564B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ |
100 | {0x1002, 0x564F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \ | 100 | {0x1002, 0x564F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ |
101 | {0x1002, 0x5652, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \ | 101 | {0x1002, 0x5652, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ |
102 | {0x1002, 0x5653, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \ | 102 | {0x1002, 0x5653, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ |
103 | {0x1002, 0x5834, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|CHIP_IS_IGP}, \ | 103 | {0x1002, 0x5834, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|RADEON_IS_IGP}, \ |
104 | {0x1002, 0x5835, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|CHIP_IS_IGP|CHIP_IS_MOBILITY}, \ | 104 | {0x1002, 0x5835, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|RADEON_IS_IGP|RADEON_IS_MOBILITY}, \ |
105 | {0x1002, 0x5960, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \ | 105 | {0x1002, 0x5960, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \ |
106 | {0x1002, 0x5961, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \ | 106 | {0x1002, 0x5961, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \ |
107 | {0x1002, 0x5962, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \ | 107 | {0x1002, 0x5962, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \ |
108 | {0x1002, 0x5964, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \ | 108 | {0x1002, 0x5964, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \ |
109 | {0x1002, 0x5965, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \ | 109 | {0x1002, 0x5965, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \ |
110 | {0x1002, 0x5969, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100}, \ | 110 | {0x1002, 0x5969, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100}, \ |
111 | {0x1002, 0x5b60, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_NEW_MEMMAP}, \ | 111 | {0x1002, 0x5b60, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \ |
112 | {0x1002, 0x5b62, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_NEW_MEMMAP}, \ | 112 | {0x1002, 0x5b62, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \ |
113 | {0x1002, 0x5b63, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_NEW_MEMMAP}, \ | 113 | {0x1002, 0x5b63, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \ |
114 | {0x1002, 0x5b64, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_NEW_MEMMAP}, \ | 114 | {0x1002, 0x5b64, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \ |
115 | {0x1002, 0x5b65, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_NEW_MEMMAP}, \ | 115 | {0x1002, 0x5b65, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \ |
116 | {0x1002, 0x5c61, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280|CHIP_IS_MOBILITY}, \ | 116 | {0x1002, 0x5c61, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280|RADEON_IS_MOBILITY}, \ |
117 | {0x1002, 0x5c63, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280|CHIP_IS_MOBILITY}, \ | 117 | {0x1002, 0x5c63, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280|RADEON_IS_MOBILITY}, \ |
118 | {0x1002, 0x5d48, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \ | 118 | {0x1002, 0x5d48, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ |
119 | {0x1002, 0x5d49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \ | 119 | {0x1002, 0x5d49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ |
120 | {0x1002, 0x5d4a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \ | 120 | {0x1002, 0x5d4a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ |
121 | {0x1002, 0x5d4c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \ | 121 | {0x1002, 0x5d4c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \ |
122 | {0x1002, 0x5d4d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \ | 122 | {0x1002, 0x5d4d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \ |
123 | {0x1002, 0x5d4e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \ | 123 | {0x1002, 0x5d4e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \ |
124 | {0x1002, 0x5d4f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \ | 124 | {0x1002, 0x5d4f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \ |
125 | {0x1002, 0x5d50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \ | 125 | {0x1002, 0x5d50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \ |
126 | {0x1002, 0x5d52, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \ | 126 | {0x1002, 0x5d52, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \ |
127 | {0x1002, 0x5d57, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \ | 127 | {0x1002, 0x5d57, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \ |
128 | {0x1002, 0x5e48, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_NEW_MEMMAP}, \ | 128 | {0x1002, 0x5e48, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_NEW_MEMMAP}, \ |
129 | {0x1002, 0x5e4a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_NEW_MEMMAP}, \ | 129 | {0x1002, 0x5e4a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_NEW_MEMMAP}, \ |
130 | {0x1002, 0x5e4b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_NEW_MEMMAP}, \ | 130 | {0x1002, 0x5e4b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_NEW_MEMMAP}, \ |
131 | {0x1002, 0x5e4c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_NEW_MEMMAP}, \ | 131 | {0x1002, 0x5e4c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_NEW_MEMMAP}, \ |
132 | {0x1002, 0x5e4d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_NEW_MEMMAP}, \ | 132 | {0x1002, 0x5e4d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_NEW_MEMMAP}, \ |
133 | {0x1002, 0x5e4f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_NEW_MEMMAP}, \ | 133 | {0x1002, 0x5e4f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_NEW_MEMMAP}, \ |
134 | {0x1002, 0x7834, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|CHIP_IS_IGP|CHIP_NEW_MEMMAP}, \ | 134 | {0x1002, 0x7834, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|RADEON_IS_IGP|RADEON_NEW_MEMMAP}, \ |
135 | {0x1002, 0x7835, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|CHIP_IS_IGP|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \ | 135 | {0x1002, 0x7835, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ |
136 | {0, 0, 0} | 136 | {0, 0, 0} |
137 | 137 | ||
138 | #define r128_PCI_IDS \ | 138 | #define r128_PCI_IDS \ |
@@ -209,6 +209,7 @@ | |||
209 | {0x1039, 0x0300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ | 209 | {0x1039, 0x0300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ |
210 | {0x1039, 0x5300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ | 210 | {0x1039, 0x5300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ |
211 | {0x1039, 0x6300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ | 211 | {0x1039, 0x6300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ |
212 | {0x1039, 0x6330, PCI_ANY_ID, PCI_ANY_ID, 0, 0, SIS_CHIP_315}, \ | ||
212 | {0x1039, 0x7300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ | 213 | {0x1039, 0x7300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ |
213 | {0, 0, 0} | 214 | {0, 0, 0} |
214 | 215 | ||
@@ -227,6 +228,10 @@ | |||
227 | {0x1106, 0x3122, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ | 228 | {0x1106, 0x3122, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ |
228 | {0x1106, 0x7205, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ | 229 | {0x1106, 0x7205, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ |
229 | {0x1106, 0x3108, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ | 230 | {0x1106, 0x3108, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ |
231 | {0x1106, 0x3304, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ | ||
232 | {0x1106, 0x3157, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ | ||
233 | {0x1106, 0x3344, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ | ||
234 | {0x1106, 0x7204, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ | ||
230 | {0, 0, 0} | 235 | {0, 0, 0} |
231 | 236 | ||
232 | #define i810_PCI_IDS \ | 237 | #define i810_PCI_IDS \ |
@@ -285,5 +290,9 @@ | |||
285 | {0x8086, 0x2592, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ | 290 | {0x8086, 0x2592, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ |
286 | {0x8086, 0x2772, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ | 291 | {0x8086, 0x2772, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ |
287 | {0x8086, 0x27a2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ | 292 | {0x8086, 0x27a2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ |
293 | {0x8086, 0x2972, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ | ||
294 | {0x8086, 0x2982, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ | ||
295 | {0x8086, 0x2992, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ | ||
296 | {0x8086, 0x29a2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ | ||
288 | {0, 0, 0} | 297 | {0, 0, 0} |
289 | 298 | ||
diff --git a/drivers/char/drm/drm_proc.c b/drivers/char/drm/drm_proc.c index 362a270af0f1..62d5fe15f046 100644 --- a/drivers/char/drm/drm_proc.c +++ b/drivers/char/drm/drm_proc.c | |||
@@ -510,7 +510,7 @@ static int drm__vma_info(char *buf, char **start, off_t offset, int request, | |||
510 | vma->vm_flags & VM_MAYSHARE ? 's' : 'p', | 510 | vma->vm_flags & VM_MAYSHARE ? 's' : 'p', |
511 | vma->vm_flags & VM_LOCKED ? 'l' : '-', | 511 | vma->vm_flags & VM_LOCKED ? 'l' : '-', |
512 | vma->vm_flags & VM_IO ? 'i' : '-', | 512 | vma->vm_flags & VM_IO ? 'i' : '-', |
513 | VM_OFFSET(vma)); | 513 | vma->vm_pgoff << PAGE_SHIFT); |
514 | 514 | ||
515 | #if defined(__i386__) | 515 | #if defined(__i386__) |
516 | pgprot = pgprot_val(vma->vm_page_prot); | 516 | pgprot = pgprot_val(vma->vm_page_prot); |
diff --git a/drivers/char/drm/drm_sman.c b/drivers/char/drm/drm_sman.c new file mode 100644 index 000000000000..425c82336ee0 --- /dev/null +++ b/drivers/char/drm/drm_sman.c | |||
@@ -0,0 +1,352 @@ | |||
1 | /************************************************************************** | ||
2 | * | ||
3 | * Copyright 2006 Tungsten Graphics, Inc., Bismarck., ND., USA. | ||
4 | * All Rights Reserved. | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
7 | * copy of this software and associated documentation files (the | ||
8 | * "Software"), to deal in the Software without restriction, including | ||
9 | * without limitation the rights to use, copy, modify, merge, publish, | ||
10 | * distribute, sub license, and/or sell copies of the Software, and to | ||
11 | * permit persons to whom the Software is furnished to do so, subject to | ||
12 | * the following conditions: | ||
13 | * | ||
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL | ||
17 | * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, | ||
18 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR | ||
19 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE | ||
20 | * USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
21 | * | ||
22 | * The above copyright notice and this permission notice (including the | ||
23 | * next paragraph) shall be included in all copies or substantial portions | ||
24 | * of the Software. | ||
25 | * | ||
26 | * | ||
27 | **************************************************************************/ | ||
28 | /* | ||
29 | * Simple memory manager interface that keeps track on allocate regions on a | ||
30 | * per "owner" basis. All regions associated with an "owner" can be released | ||
31 | * with a simple call. Typically if the "owner" exists. The owner is any | ||
32 | * "unsigned long" identifier. Can typically be a pointer to a file private | ||
33 | * struct or a context identifier. | ||
34 | * | ||
35 | * Authors: | ||
36 | * Thomas Hellström <thomas-at-tungstengraphics-dot-com> | ||
37 | */ | ||
38 | |||
39 | #include "drm_sman.h" | ||
40 | |||
41 | typedef struct drm_owner_item { | ||
42 | drm_hash_item_t owner_hash; | ||
43 | struct list_head sman_list; | ||
44 | struct list_head mem_blocks; | ||
45 | } drm_owner_item_t; | ||
46 | |||
47 | void drm_sman_takedown(drm_sman_t * sman) | ||
48 | { | ||
49 | drm_ht_remove(&sman->user_hash_tab); | ||
50 | drm_ht_remove(&sman->owner_hash_tab); | ||
51 | if (sman->mm) | ||
52 | drm_free(sman->mm, sman->num_managers * sizeof(*sman->mm), | ||
53 | DRM_MEM_MM); | ||
54 | } | ||
55 | |||
56 | EXPORT_SYMBOL(drm_sman_takedown); | ||
57 | |||
58 | int | ||
59 | drm_sman_init(drm_sman_t * sman, unsigned int num_managers, | ||
60 | unsigned int user_order, unsigned int owner_order) | ||
61 | { | ||
62 | int ret = 0; | ||
63 | |||
64 | sman->mm = (drm_sman_mm_t *) drm_calloc(num_managers, sizeof(*sman->mm), | ||
65 | DRM_MEM_MM); | ||
66 | if (!sman->mm) { | ||
67 | ret = -ENOMEM; | ||
68 | goto out; | ||
69 | } | ||
70 | sman->num_managers = num_managers; | ||
71 | INIT_LIST_HEAD(&sman->owner_items); | ||
72 | ret = drm_ht_create(&sman->owner_hash_tab, owner_order); | ||
73 | if (ret) | ||
74 | goto out1; | ||
75 | ret = drm_ht_create(&sman->user_hash_tab, user_order); | ||
76 | if (!ret) | ||
77 | goto out; | ||
78 | |||
79 | drm_ht_remove(&sman->owner_hash_tab); | ||
80 | out1: | ||
81 | drm_free(sman->mm, num_managers * sizeof(*sman->mm), DRM_MEM_MM); | ||
82 | out: | ||
83 | return ret; | ||
84 | } | ||
85 | |||
86 | EXPORT_SYMBOL(drm_sman_init); | ||
87 | |||
88 | static void *drm_sman_mm_allocate(void *private, unsigned long size, | ||
89 | unsigned alignment) | ||
90 | { | ||
91 | drm_mm_t *mm = (drm_mm_t *) private; | ||
92 | drm_mm_node_t *tmp; | ||
93 | |||
94 | tmp = drm_mm_search_free(mm, size, alignment, 1); | ||
95 | if (!tmp) { | ||
96 | return NULL; | ||
97 | } | ||
98 | tmp = drm_mm_get_block(tmp, size, alignment); | ||
99 | return tmp; | ||
100 | } | ||
101 | |||
102 | static void drm_sman_mm_free(void *private, void *ref) | ||
103 | { | ||
104 | drm_mm_t *mm = (drm_mm_t *) private; | ||
105 | drm_mm_node_t *node = (drm_mm_node_t *) ref; | ||
106 | |||
107 | drm_mm_put_block(mm, node); | ||
108 | } | ||
109 | |||
110 | static void drm_sman_mm_destroy(void *private) | ||
111 | { | ||
112 | drm_mm_t *mm = (drm_mm_t *) private; | ||
113 | drm_mm_takedown(mm); | ||
114 | drm_free(mm, sizeof(*mm), DRM_MEM_MM); | ||
115 | } | ||
116 | |||
117 | static unsigned long drm_sman_mm_offset(void *private, void *ref) | ||
118 | { | ||
119 | drm_mm_node_t *node = (drm_mm_node_t *) ref; | ||
120 | return node->start; | ||
121 | } | ||
122 | |||
123 | int | ||
124 | drm_sman_set_range(drm_sman_t * sman, unsigned int manager, | ||
125 | unsigned long start, unsigned long size) | ||
126 | { | ||
127 | drm_sman_mm_t *sman_mm; | ||
128 | drm_mm_t *mm; | ||
129 | int ret; | ||
130 | |||
131 | BUG_ON(manager >= sman->num_managers); | ||
132 | |||
133 | sman_mm = &sman->mm[manager]; | ||
134 | mm = drm_calloc(1, sizeof(*mm), DRM_MEM_MM); | ||
135 | if (!mm) { | ||
136 | return -ENOMEM; | ||
137 | } | ||
138 | sman_mm->private = mm; | ||
139 | ret = drm_mm_init(mm, start, size); | ||
140 | |||
141 | if (ret) { | ||
142 | drm_free(mm, sizeof(*mm), DRM_MEM_MM); | ||
143 | return ret; | ||
144 | } | ||
145 | |||
146 | sman_mm->allocate = drm_sman_mm_allocate; | ||
147 | sman_mm->free = drm_sman_mm_free; | ||
148 | sman_mm->destroy = drm_sman_mm_destroy; | ||
149 | sman_mm->offset = drm_sman_mm_offset; | ||
150 | |||
151 | return 0; | ||
152 | } | ||
153 | |||
154 | EXPORT_SYMBOL(drm_sman_set_range); | ||
155 | |||
156 | int | ||
157 | drm_sman_set_manager(drm_sman_t * sman, unsigned int manager, | ||
158 | drm_sman_mm_t * allocator) | ||
159 | { | ||
160 | BUG_ON(manager >= sman->num_managers); | ||
161 | sman->mm[manager] = *allocator; | ||
162 | |||
163 | return 0; | ||
164 | } | ||
165 | |||
166 | static drm_owner_item_t *drm_sman_get_owner_item(drm_sman_t * sman, | ||
167 | unsigned long owner) | ||
168 | { | ||
169 | int ret; | ||
170 | drm_hash_item_t *owner_hash_item; | ||
171 | drm_owner_item_t *owner_item; | ||
172 | |||
173 | ret = drm_ht_find_item(&sman->owner_hash_tab, owner, &owner_hash_item); | ||
174 | if (!ret) { | ||
175 | return drm_hash_entry(owner_hash_item, drm_owner_item_t, | ||
176 | owner_hash); | ||
177 | } | ||
178 | |||
179 | owner_item = drm_calloc(1, sizeof(*owner_item), DRM_MEM_MM); | ||
180 | if (!owner_item) | ||
181 | goto out; | ||
182 | |||
183 | INIT_LIST_HEAD(&owner_item->mem_blocks); | ||
184 | owner_item->owner_hash.key = owner; | ||
185 | if (drm_ht_insert_item(&sman->owner_hash_tab, &owner_item->owner_hash)) | ||
186 | goto out1; | ||
187 | |||
188 | list_add_tail(&owner_item->sman_list, &sman->owner_items); | ||
189 | return owner_item; | ||
190 | |||
191 | out1: | ||
192 | drm_free(owner_item, sizeof(*owner_item), DRM_MEM_MM); | ||
193 | out: | ||
194 | return NULL; | ||
195 | } | ||
196 | |||
197 | drm_memblock_item_t *drm_sman_alloc(drm_sman_t *sman, unsigned int manager, | ||
198 | unsigned long size, unsigned alignment, | ||
199 | unsigned long owner) | ||
200 | { | ||
201 | void *tmp; | ||
202 | drm_sman_mm_t *sman_mm; | ||
203 | drm_owner_item_t *owner_item; | ||
204 | drm_memblock_item_t *memblock; | ||
205 | |||
206 | BUG_ON(manager >= sman->num_managers); | ||
207 | |||
208 | sman_mm = &sman->mm[manager]; | ||
209 | tmp = sman_mm->allocate(sman_mm->private, size, alignment); | ||
210 | |||
211 | if (!tmp) { | ||
212 | return NULL; | ||
213 | } | ||
214 | |||
215 | memblock = drm_calloc(1, sizeof(*memblock), DRM_MEM_MM); | ||
216 | |||
217 | if (!memblock) | ||
218 | goto out; | ||
219 | |||
220 | memblock->mm_info = tmp; | ||
221 | memblock->mm = sman_mm; | ||
222 | memblock->sman = sman; | ||
223 | |||
224 | if (drm_ht_just_insert_please | ||
225 | (&sman->user_hash_tab, &memblock->user_hash, | ||
226 | (unsigned long)memblock, 32, 0, 0)) | ||
227 | goto out1; | ||
228 | |||
229 | owner_item = drm_sman_get_owner_item(sman, owner); | ||
230 | if (!owner_item) | ||
231 | goto out2; | ||
232 | |||
233 | list_add_tail(&memblock->owner_list, &owner_item->mem_blocks); | ||
234 | |||
235 | return memblock; | ||
236 | |||
237 | out2: | ||
238 | drm_ht_remove_item(&sman->user_hash_tab, &memblock->user_hash); | ||
239 | out1: | ||
240 | drm_free(memblock, sizeof(*memblock), DRM_MEM_MM); | ||
241 | out: | ||
242 | sman_mm->free(sman_mm->private, tmp); | ||
243 | |||
244 | return NULL; | ||
245 | } | ||
246 | |||
247 | EXPORT_SYMBOL(drm_sman_alloc); | ||
248 | |||
249 | static void drm_sman_free(drm_memblock_item_t *item) | ||
250 | { | ||
251 | drm_sman_t *sman = item->sman; | ||
252 | |||
253 | list_del(&item->owner_list); | ||
254 | drm_ht_remove_item(&sman->user_hash_tab, &item->user_hash); | ||
255 | item->mm->free(item->mm->private, item->mm_info); | ||
256 | drm_free(item, sizeof(*item), DRM_MEM_MM); | ||
257 | } | ||
258 | |||
259 | int drm_sman_free_key(drm_sman_t *sman, unsigned int key) | ||
260 | { | ||
261 | drm_hash_item_t *hash_item; | ||
262 | drm_memblock_item_t *memblock_item; | ||
263 | |||
264 | if (drm_ht_find_item(&sman->user_hash_tab, key, &hash_item)) | ||
265 | return -EINVAL; | ||
266 | |||
267 | memblock_item = drm_hash_entry(hash_item, drm_memblock_item_t, user_hash); | ||
268 | drm_sman_free(memblock_item); | ||
269 | return 0; | ||
270 | } | ||
271 | |||
272 | EXPORT_SYMBOL(drm_sman_free_key); | ||
273 | |||
274 | static void drm_sman_remove_owner(drm_sman_t *sman, | ||
275 | drm_owner_item_t *owner_item) | ||
276 | { | ||
277 | list_del(&owner_item->sman_list); | ||
278 | drm_ht_remove_item(&sman->owner_hash_tab, &owner_item->owner_hash); | ||
279 | drm_free(owner_item, sizeof(*owner_item), DRM_MEM_MM); | ||
280 | } | ||
281 | |||
282 | int drm_sman_owner_clean(drm_sman_t *sman, unsigned long owner) | ||
283 | { | ||
284 | |||
285 | drm_hash_item_t *hash_item; | ||
286 | drm_owner_item_t *owner_item; | ||
287 | |||
288 | if (drm_ht_find_item(&sman->owner_hash_tab, owner, &hash_item)) { | ||
289 | return -1; | ||
290 | } | ||
291 | |||
292 | owner_item = drm_hash_entry(hash_item, drm_owner_item_t, owner_hash); | ||
293 | if (owner_item->mem_blocks.next == &owner_item->mem_blocks) { | ||
294 | drm_sman_remove_owner(sman, owner_item); | ||
295 | return -1; | ||
296 | } | ||
297 | |||
298 | return 0; | ||
299 | } | ||
300 | |||
301 | EXPORT_SYMBOL(drm_sman_owner_clean); | ||
302 | |||
303 | static void drm_sman_do_owner_cleanup(drm_sman_t *sman, | ||
304 | drm_owner_item_t *owner_item) | ||
305 | { | ||
306 | drm_memblock_item_t *entry, *next; | ||
307 | |||
308 | list_for_each_entry_safe(entry, next, &owner_item->mem_blocks, | ||
309 | owner_list) { | ||
310 | drm_sman_free(entry); | ||
311 | } | ||
312 | drm_sman_remove_owner(sman, owner_item); | ||
313 | } | ||
314 | |||
315 | void drm_sman_owner_cleanup(drm_sman_t *sman, unsigned long owner) | ||
316 | { | ||
317 | |||
318 | drm_hash_item_t *hash_item; | ||
319 | drm_owner_item_t *owner_item; | ||
320 | |||
321 | if (drm_ht_find_item(&sman->owner_hash_tab, owner, &hash_item)) { | ||
322 | |||
323 | return; | ||
324 | } | ||
325 | |||
326 | owner_item = drm_hash_entry(hash_item, drm_owner_item_t, owner_hash); | ||
327 | drm_sman_do_owner_cleanup(sman, owner_item); | ||
328 | } | ||
329 | |||
330 | EXPORT_SYMBOL(drm_sman_owner_cleanup); | ||
331 | |||
332 | void drm_sman_cleanup(drm_sman_t *sman) | ||
333 | { | ||
334 | drm_owner_item_t *entry, *next; | ||
335 | unsigned int i; | ||
336 | drm_sman_mm_t *sman_mm; | ||
337 | |||
338 | list_for_each_entry_safe(entry, next, &sman->owner_items, sman_list) { | ||
339 | drm_sman_do_owner_cleanup(sman, entry); | ||
340 | } | ||
341 | if (sman->mm) { | ||
342 | for (i = 0; i < sman->num_managers; ++i) { | ||
343 | sman_mm = &sman->mm[i]; | ||
344 | if (sman_mm->private) { | ||
345 | sman_mm->destroy(sman_mm->private); | ||
346 | sman_mm->private = NULL; | ||
347 | } | ||
348 | } | ||
349 | } | ||
350 | } | ||
351 | |||
352 | EXPORT_SYMBOL(drm_sman_cleanup); | ||
diff --git a/drivers/char/drm/drm_sman.h b/drivers/char/drm/drm_sman.h new file mode 100644 index 000000000000..ddc732a1bf27 --- /dev/null +++ b/drivers/char/drm/drm_sman.h | |||
@@ -0,0 +1,176 @@ | |||
1 | /************************************************************************** | ||
2 | * | ||
3 | * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND., USA. | ||
4 | * All Rights Reserved. | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
7 | * copy of this software and associated documentation files (the | ||
8 | * "Software"), to deal in the Software without restriction, including | ||
9 | * without limitation the rights to use, copy, modify, merge, publish, | ||
10 | * distribute, sub license, and/or sell copies of the Software, and to | ||
11 | * permit persons to whom the Software is furnished to do so, subject to | ||
12 | * the following conditions: | ||
13 | * | ||
14 | * The above copyright notice and this permission notice (including the | ||
15 | * next paragraph) shall be included in all copies or substantial portions | ||
16 | * of the Software. | ||
17 | * | ||
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL | ||
21 | * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, | ||
22 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR | ||
23 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE | ||
24 | * USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
25 | * | ||
26 | * | ||
27 | **************************************************************************/ | ||
28 | /* | ||
29 | * Simple memory MANager interface that keeps track on allocate regions on a | ||
30 | * per "owner" basis. All regions associated with an "owner" can be released | ||
31 | * with a simple call. Typically if the "owner" exists. The owner is any | ||
32 | * "unsigned long" identifier. Can typically be a pointer to a file private | ||
33 | * struct or a context identifier. | ||
34 | * | ||
35 | * Authors: | ||
36 | * Thomas Hellström <thomas-at-tungstengraphics-dot-com> | ||
37 | */ | ||
38 | |||
39 | #ifndef DRM_SMAN_H | ||
40 | #define DRM_SMAN_H | ||
41 | |||
42 | #include "drmP.h" | ||
43 | #include "drm_hashtab.h" | ||
44 | |||
45 | /* | ||
46 | * A class that is an abstration of a simple memory allocator. | ||
47 | * The sman implementation provides a default such allocator | ||
48 | * using the drm_mm.c implementation. But the user can replace it. | ||
49 | * See the SiS implementation, which may use the SiS FB kernel module | ||
50 | * for memory management. | ||
51 | */ | ||
52 | |||
53 | typedef struct drm_sman_mm { | ||
54 | /* private info. If allocated, needs to be destroyed by the destroy | ||
55 | function */ | ||
56 | void *private; | ||
57 | |||
58 | /* Allocate a memory block with given size and alignment. | ||
59 | Return an opaque reference to the memory block */ | ||
60 | |||
61 | void *(*allocate) (void *private, unsigned long size, | ||
62 | unsigned alignment); | ||
63 | |||
64 | /* Free a memory block. "ref" is the opaque reference that we got from | ||
65 | the "alloc" function */ | ||
66 | |||
67 | void (*free) (void *private, void *ref); | ||
68 | |||
69 | /* Free all resources associated with this allocator */ | ||
70 | |||
71 | void (*destroy) (void *private); | ||
72 | |||
73 | /* Return a memory offset from the opaque reference returned from the | ||
74 | "alloc" function */ | ||
75 | |||
76 | unsigned long (*offset) (void *private, void *ref); | ||
77 | } drm_sman_mm_t; | ||
78 | |||
79 | typedef struct drm_memblock_item { | ||
80 | struct list_head owner_list; | ||
81 | drm_hash_item_t user_hash; | ||
82 | void *mm_info; | ||
83 | drm_sman_mm_t *mm; | ||
84 | struct drm_sman *sman; | ||
85 | } drm_memblock_item_t; | ||
86 | |||
87 | typedef struct drm_sman { | ||
88 | drm_sman_mm_t *mm; | ||
89 | int num_managers; | ||
90 | drm_open_hash_t owner_hash_tab; | ||
91 | drm_open_hash_t user_hash_tab; | ||
92 | struct list_head owner_items; | ||
93 | } drm_sman_t; | ||
94 | |||
95 | /* | ||
96 | * Take down a memory manager. This function should only be called after a | ||
97 | * successful init and after a call to drm_sman_cleanup. | ||
98 | */ | ||
99 | |||
100 | extern void drm_sman_takedown(drm_sman_t * sman); | ||
101 | |||
102 | /* | ||
103 | * Allocate structures for a manager. | ||
104 | * num_managers are the number of memory pools to manage. (VRAM, AGP, ....) | ||
105 | * user_order is the log2 of the number of buckets in the user hash table. | ||
106 | * set this to approximately log2 of the max number of memory regions | ||
107 | * that will be allocated for _all_ pools together. | ||
108 | * owner_order is the log2 of the number of buckets in the owner hash table. | ||
109 | * set this to approximately log2 of | ||
110 | * the number of client file connections that will | ||
111 | * be using the manager. | ||
112 | * | ||
113 | */ | ||
114 | |||
115 | extern int drm_sman_init(drm_sman_t * sman, unsigned int num_managers, | ||
116 | unsigned int user_order, unsigned int owner_order); | ||
117 | |||
118 | /* | ||
119 | * Initialize a drm_mm.c allocator. Should be called only once for each | ||
120 | * manager unless a customized allogator is used. | ||
121 | */ | ||
122 | |||
123 | extern int drm_sman_set_range(drm_sman_t * sman, unsigned int manager, | ||
124 | unsigned long start, unsigned long size); | ||
125 | |||
126 | /* | ||
127 | * Initialize a customized allocator for one of the managers. | ||
128 | * (See the SiS module). The object pointed to by "allocator" is copied, | ||
129 | * so it can be destroyed after this call. | ||
130 | */ | ||
131 | |||
132 | extern int drm_sman_set_manager(drm_sman_t * sman, unsigned int mananger, | ||
133 | drm_sman_mm_t * allocator); | ||
134 | |||
135 | /* | ||
136 | * Allocate a memory block. Aligment is not implemented yet. | ||
137 | */ | ||
138 | |||
139 | extern drm_memblock_item_t *drm_sman_alloc(drm_sman_t * sman, | ||
140 | unsigned int manager, | ||
141 | unsigned long size, | ||
142 | unsigned alignment, | ||
143 | unsigned long owner); | ||
144 | /* | ||
145 | * Free a memory block identified by its user hash key. | ||
146 | */ | ||
147 | |||
148 | extern int drm_sman_free_key(drm_sman_t * sman, unsigned int key); | ||
149 | |||
150 | /* | ||
151 | * returns 1 iff there are no stale memory blocks associated with this owner. | ||
152 | * Typically called to determine if we need to idle the hardware and call | ||
153 | * drm_sman_owner_cleanup. If there are no stale memory blocks, it removes all | ||
154 | * resources associated with owner. | ||
155 | */ | ||
156 | |||
157 | extern int drm_sman_owner_clean(drm_sman_t * sman, unsigned long owner); | ||
158 | |||
159 | /* | ||
160 | * Frees all stale memory blocks associated with this owner. Note that this | ||
161 | * requires that the hardware is finished with all blocks, so the graphics engine | ||
162 | * should be idled before this call is made. This function also frees | ||
163 | * any resources associated with "owner" and should be called when owner | ||
164 | * is not going to be referenced anymore. | ||
165 | */ | ||
166 | |||
167 | extern void drm_sman_owner_cleanup(drm_sman_t * sman, unsigned long owner); | ||
168 | |||
169 | /* | ||
170 | * Frees all stale memory blocks associated with the memory manager. | ||
171 | * See idling above. | ||
172 | */ | ||
173 | |||
174 | extern void drm_sman_cleanup(drm_sman_t * sman); | ||
175 | |||
176 | #endif | ||
diff --git a/drivers/char/drm/drm_stub.c b/drivers/char/drm/drm_stub.c index 9a842a36bb27..7b1d4e8659ba 100644 --- a/drivers/char/drm/drm_stub.c +++ b/drivers/char/drm/drm_stub.c | |||
@@ -65,22 +65,22 @@ static int drm_fill_in_dev(drm_device_t * dev, struct pci_dev *pdev, | |||
65 | mutex_init(&dev->ctxlist_mutex); | 65 | mutex_init(&dev->ctxlist_mutex); |
66 | 66 | ||
67 | dev->pdev = pdev; | 67 | dev->pdev = pdev; |
68 | dev->pci_device = pdev->device; | ||
69 | dev->pci_vendor = pdev->vendor; | ||
68 | 70 | ||
69 | #ifdef __alpha__ | 71 | #ifdef __alpha__ |
70 | dev->hose = pdev->sysdata; | 72 | dev->hose = pdev->sysdata; |
71 | dev->pci_domain = dev->hose->bus->number; | ||
72 | #else | ||
73 | dev->pci_domain = 0; | ||
74 | #endif | 73 | #endif |
75 | dev->pci_bus = pdev->bus->number; | ||
76 | dev->pci_slot = PCI_SLOT(pdev->devfn); | ||
77 | dev->pci_func = PCI_FUNC(pdev->devfn); | ||
78 | dev->irq = pdev->irq; | 74 | dev->irq = pdev->irq; |
79 | 75 | ||
80 | dev->maplist = drm_calloc(1, sizeof(*dev->maplist), DRM_MEM_MAPS); | 76 | dev->maplist = drm_calloc(1, sizeof(*dev->maplist), DRM_MEM_MAPS); |
81 | if (dev->maplist == NULL) | 77 | if (dev->maplist == NULL) |
82 | return -ENOMEM; | 78 | return -ENOMEM; |
83 | INIT_LIST_HEAD(&dev->maplist->head); | 79 | INIT_LIST_HEAD(&dev->maplist->head); |
80 | if (drm_ht_create(&dev->map_hash, 12)) { | ||
81 | drm_free(dev->maplist, sizeof(*dev->maplist), DRM_MEM_MAPS); | ||
82 | return -ENOMEM; | ||
83 | } | ||
84 | 84 | ||
85 | /* the DRM has 6 basic counters */ | 85 | /* the DRM has 6 basic counters */ |
86 | dev->counters = 6; | 86 | dev->counters = 6; |
diff --git a/drivers/char/drm/drm_vm.c b/drivers/char/drm/drm_vm.c index ffd0800ed601..b40ae438f531 100644 --- a/drivers/char/drm/drm_vm.c +++ b/drivers/char/drm/drm_vm.c | |||
@@ -59,7 +59,7 @@ static __inline__ struct page *drm_do_vm_nopage(struct vm_area_struct *vma, | |||
59 | drm_device_t *dev = priv->head->dev; | 59 | drm_device_t *dev = priv->head->dev; |
60 | drm_map_t *map = NULL; | 60 | drm_map_t *map = NULL; |
61 | drm_map_list_t *r_list; | 61 | drm_map_list_t *r_list; |
62 | struct list_head *list; | 62 | drm_hash_item_t *hash; |
63 | 63 | ||
64 | /* | 64 | /* |
65 | * Find the right map | 65 | * Find the right map |
@@ -70,14 +70,11 @@ static __inline__ struct page *drm_do_vm_nopage(struct vm_area_struct *vma, | |||
70 | if (!dev->agp || !dev->agp->cant_use_aperture) | 70 | if (!dev->agp || !dev->agp->cant_use_aperture) |
71 | goto vm_nopage_error; | 71 | goto vm_nopage_error; |
72 | 72 | ||
73 | list_for_each(list, &dev->maplist->head) { | 73 | if (drm_ht_find_item(&dev->map_hash, vma->vm_pgoff << PAGE_SHIFT, &hash)) |
74 | r_list = list_entry(list, drm_map_list_t, head); | 74 | goto vm_nopage_error; |
75 | map = r_list->map; | 75 | |
76 | if (!map) | 76 | r_list = drm_hash_entry(hash, drm_map_list_t, hash); |
77 | continue; | 77 | map = r_list->map; |
78 | if (r_list->user_token == VM_OFFSET(vma)) | ||
79 | break; | ||
80 | } | ||
81 | 78 | ||
82 | if (map && map->type == _DRM_AGP) { | 79 | if (map && map->type == _DRM_AGP) { |
83 | unsigned long offset = address - vma->vm_start; | 80 | unsigned long offset = address - vma->vm_start; |
@@ -467,7 +464,7 @@ static int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma) | |||
467 | dev = priv->head->dev; | 464 | dev = priv->head->dev; |
468 | dma = dev->dma; | 465 | dma = dev->dma; |
469 | DRM_DEBUG("start = 0x%lx, end = 0x%lx, offset = 0x%lx\n", | 466 | DRM_DEBUG("start = 0x%lx, end = 0x%lx, offset = 0x%lx\n", |
470 | vma->vm_start, vma->vm_end, VM_OFFSET(vma)); | 467 | vma->vm_start, vma->vm_end, vma->vm_pgoff << PAGE_SHIFT); |
471 | 468 | ||
472 | /* Length must match exact page count */ | 469 | /* Length must match exact page count */ |
473 | if (!dma || (length >> PAGE_SHIFT) != dma->page_count) { | 470 | if (!dma || (length >> PAGE_SHIFT) != dma->page_count) { |
@@ -521,12 +518,11 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma) | |||
521 | drm_file_t *priv = filp->private_data; | 518 | drm_file_t *priv = filp->private_data; |
522 | drm_device_t *dev = priv->head->dev; | 519 | drm_device_t *dev = priv->head->dev; |
523 | drm_map_t *map = NULL; | 520 | drm_map_t *map = NULL; |
524 | drm_map_list_t *r_list; | ||
525 | unsigned long offset = 0; | 521 | unsigned long offset = 0; |
526 | struct list_head *list; | 522 | drm_hash_item_t *hash; |
527 | 523 | ||
528 | DRM_DEBUG("start = 0x%lx, end = 0x%lx, offset = 0x%lx\n", | 524 | DRM_DEBUG("start = 0x%lx, end = 0x%lx, offset = 0x%lx\n", |
529 | vma->vm_start, vma->vm_end, VM_OFFSET(vma)); | 525 | vma->vm_start, vma->vm_end, vma->vm_pgoff << PAGE_SHIFT); |
530 | 526 | ||
531 | if (!priv->authenticated) | 527 | if (!priv->authenticated) |
532 | return -EACCES; | 528 | return -EACCES; |
@@ -535,7 +531,7 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma) | |||
535 | * the AGP mapped at physical address 0 | 531 | * the AGP mapped at physical address 0 |
536 | * --BenH. | 532 | * --BenH. |
537 | */ | 533 | */ |
538 | if (!VM_OFFSET(vma) | 534 | if (!(vma->vm_pgoff << PAGE_SHIFT) |
539 | #if __OS_HAS_AGP | 535 | #if __OS_HAS_AGP |
540 | && (!dev->agp | 536 | && (!dev->agp |
541 | || dev->agp->agp_info.device->vendor != PCI_VENDOR_ID_APPLE) | 537 | || dev->agp->agp_info.device->vendor != PCI_VENDOR_ID_APPLE) |
@@ -543,23 +539,12 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma) | |||
543 | ) | 539 | ) |
544 | return drm_mmap_dma(filp, vma); | 540 | return drm_mmap_dma(filp, vma); |
545 | 541 | ||
546 | /* A sequential search of a linked list is | 542 | if (drm_ht_find_item(&dev->map_hash, vma->vm_pgoff << PAGE_SHIFT, &hash)) { |
547 | fine here because: 1) there will only be | 543 | DRM_ERROR("Could not find map\n"); |
548 | about 5-10 entries in the list and, 2) a | 544 | return -EINVAL; |
549 | DRI client only has to do this mapping | ||
550 | once, so it doesn't have to be optimized | ||
551 | for performance, even if the list was a | ||
552 | bit longer. */ | ||
553 | list_for_each(list, &dev->maplist->head) { | ||
554 | |||
555 | r_list = list_entry(list, drm_map_list_t, head); | ||
556 | map = r_list->map; | ||
557 | if (!map) | ||
558 | continue; | ||
559 | if (r_list->user_token == VM_OFFSET(vma)) | ||
560 | break; | ||
561 | } | 545 | } |
562 | 546 | ||
547 | map = drm_hash_entry(hash, drm_map_list_t, hash)->map; | ||
563 | if (!map || ((map->flags & _DRM_RESTRICTED) && !capable(CAP_SYS_ADMIN))) | 548 | if (!map || ((map->flags & _DRM_RESTRICTED) && !capable(CAP_SYS_ADMIN))) |
564 | return -EPERM; | 549 | return -EPERM; |
565 | 550 | ||
@@ -620,7 +605,7 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma) | |||
620 | offset = dev->driver->get_reg_ofs(dev); | 605 | offset = dev->driver->get_reg_ofs(dev); |
621 | #ifdef __sparc__ | 606 | #ifdef __sparc__ |
622 | vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); | 607 | vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); |
623 | if (io_remap_pfn_range(DRM_RPR_ARG(vma) vma->vm_start, | 608 | if (io_remap_pfn_range(vma, vma->vm_start, |
624 | (map->offset + offset) >> PAGE_SHIFT, | 609 | (map->offset + offset) >> PAGE_SHIFT, |
625 | vma->vm_end - vma->vm_start, | 610 | vma->vm_end - vma->vm_start, |
626 | vma->vm_page_prot)) | 611 | vma->vm_page_prot)) |
diff --git a/drivers/char/drm/i810_dma.c b/drivers/char/drm/i810_dma.c index c658dde3633b..fa2de70f7401 100644 --- a/drivers/char/drm/i810_dma.c +++ b/drivers/char/drm/i810_dma.c | |||
@@ -106,7 +106,7 @@ static int i810_mmap_buffers(struct file *filp, struct vm_area_struct *vma) | |||
106 | unlock_kernel(); | 106 | unlock_kernel(); |
107 | 107 | ||
108 | if (io_remap_pfn_range(vma, vma->vm_start, | 108 | if (io_remap_pfn_range(vma, vma->vm_start, |
109 | VM_OFFSET(vma) >> PAGE_SHIFT, | 109 | vma->vm_pgoff, |
110 | vma->vm_end - vma->vm_start, vma->vm_page_prot)) | 110 | vma->vm_end - vma->vm_start, vma->vm_page_prot)) |
111 | return -EAGAIN; | 111 | return -EAGAIN; |
112 | return 0; | 112 | return 0; |
@@ -141,10 +141,10 @@ static int i810_map_buffer(drm_buf_t * buf, struct file *filp) | |||
141 | MAP_SHARED, buf->bus_address); | 141 | MAP_SHARED, buf->bus_address); |
142 | dev_priv->mmap_buffer = NULL; | 142 | dev_priv->mmap_buffer = NULL; |
143 | filp->f_op = old_fops; | 143 | filp->f_op = old_fops; |
144 | if ((unsigned long)buf_priv->virtual > -1024UL) { | 144 | if (IS_ERR(buf_priv->virtual)) { |
145 | /* Real error */ | 145 | /* Real error */ |
146 | DRM_ERROR("mmap error\n"); | 146 | DRM_ERROR("mmap error\n"); |
147 | retcode = (signed int)buf_priv->virtual; | 147 | retcode = PTR_ERR(buf_priv->virtual); |
148 | buf_priv->virtual = NULL; | 148 | buf_priv->virtual = NULL; |
149 | } | 149 | } |
150 | up_write(¤t->mm->mmap_sem); | 150 | up_write(¤t->mm->mmap_sem); |
@@ -808,7 +808,7 @@ static void i810_dma_dispatch_vertex(drm_device_t * dev, | |||
808 | ((GFX_OP_PRIMITIVE | prim | ((used / 4) - 2))); | 808 | ((GFX_OP_PRIMITIVE | prim | ((used / 4) - 2))); |
809 | 809 | ||
810 | if (used & 4) { | 810 | if (used & 4) { |
811 | *(u32 *) ((u32) buf_priv->kernel_virtual + used) = 0; | 811 | *(u32 *) ((char *) buf_priv->kernel_virtual + used) = 0; |
812 | used += 4; | 812 | used += 4; |
813 | } | 813 | } |
814 | 814 | ||
@@ -1166,7 +1166,7 @@ static void i810_dma_dispatch_mc(drm_device_t * dev, drm_buf_t * buf, int used, | |||
1166 | 1166 | ||
1167 | if (buf_priv->currently_mapped == I810_BUF_MAPPED) { | 1167 | if (buf_priv->currently_mapped == I810_BUF_MAPPED) { |
1168 | if (used & 4) { | 1168 | if (used & 4) { |
1169 | *(u32 *) ((u32) buf_priv->virtual + used) = 0; | 1169 | *(u32 *) ((char *) buf_priv->virtual + used) = 0; |
1170 | used += 4; | 1170 | used += 4; |
1171 | } | 1171 | } |
1172 | 1172 | ||
diff --git a/drivers/char/drm/i830_dma.c b/drivers/char/drm/i830_dma.c index b0f815d8cea8..4f0e5746ab33 100644 --- a/drivers/char/drm/i830_dma.c +++ b/drivers/char/drm/i830_dma.c | |||
@@ -108,7 +108,7 @@ static int i830_mmap_buffers(struct file *filp, struct vm_area_struct *vma) | |||
108 | unlock_kernel(); | 108 | unlock_kernel(); |
109 | 109 | ||
110 | if (io_remap_pfn_range(vma, vma->vm_start, | 110 | if (io_remap_pfn_range(vma, vma->vm_start, |
111 | VM_OFFSET(vma) >> PAGE_SHIFT, | 111 | vma->vm_pgoff, |
112 | vma->vm_end - vma->vm_start, vma->vm_page_prot)) | 112 | vma->vm_end - vma->vm_start, vma->vm_page_prot)) |
113 | return -EAGAIN; | 113 | return -EAGAIN; |
114 | return 0; | 114 | return 0; |
@@ -146,7 +146,7 @@ static int i830_map_buffer(drm_buf_t * buf, struct file *filp) | |||
146 | if (IS_ERR((void *)virtual)) { /* ugh */ | 146 | if (IS_ERR((void *)virtual)) { /* ugh */ |
147 | /* Real error */ | 147 | /* Real error */ |
148 | DRM_ERROR("mmap error\n"); | 148 | DRM_ERROR("mmap error\n"); |
149 | retcode = virtual; | 149 | retcode = PTR_ERR((void *)virtual); |
150 | buf_priv->virtual = NULL; | 150 | buf_priv->virtual = NULL; |
151 | } else { | 151 | } else { |
152 | buf_priv->virtual = (void __user *)virtual; | 152 | buf_priv->virtual = (void __user *)virtual; |
diff --git a/drivers/char/drm/i915_dma.c b/drivers/char/drm/i915_dma.c index a94233bdbc0e..fb7913ff5286 100644 --- a/drivers/char/drm/i915_dma.c +++ b/drivers/char/drm/i915_dma.c | |||
@@ -31,6 +31,11 @@ | |||
31 | #include "i915_drm.h" | 31 | #include "i915_drm.h" |
32 | #include "i915_drv.h" | 32 | #include "i915_drv.h" |
33 | 33 | ||
34 | #define IS_I965G(dev) (dev->pci_device == 0x2972 || \ | ||
35 | dev->pci_device == 0x2982 || \ | ||
36 | dev->pci_device == 0x2992 || \ | ||
37 | dev->pci_device == 0x29A2) | ||
38 | |||
34 | /* Really want an OS-independent resettable timer. Would like to have | 39 | /* Really want an OS-independent resettable timer. Would like to have |
35 | * this loop run for (eg) 3 sec, but have the timer reset every time | 40 | * this loop run for (eg) 3 sec, but have the timer reset every time |
36 | * the head pointer changes, so that EBUSY only happens if the ring | 41 | * the head pointer changes, so that EBUSY only happens if the ring |
@@ -255,7 +260,7 @@ static int i915_dma_init(DRM_IOCTL_ARGS) | |||
255 | retcode = i915_dma_resume(dev); | 260 | retcode = i915_dma_resume(dev); |
256 | break; | 261 | break; |
257 | default: | 262 | default: |
258 | retcode = -EINVAL; | 263 | retcode = DRM_ERR(EINVAL); |
259 | break; | 264 | break; |
260 | } | 265 | } |
261 | 266 | ||
@@ -347,7 +352,7 @@ static int i915_emit_cmds(drm_device_t * dev, int __user * buffer, int dwords) | |||
347 | if ((dwords+1) * sizeof(int) >= dev_priv->ring.Size - 8) | 352 | if ((dwords+1) * sizeof(int) >= dev_priv->ring.Size - 8) |
348 | return DRM_ERR(EINVAL); | 353 | return DRM_ERR(EINVAL); |
349 | 354 | ||
350 | BEGIN_LP_RING(((dwords+1)&~1)); | 355 | BEGIN_LP_RING((dwords+1)&~1); |
351 | 356 | ||
352 | for (i = 0; i < dwords;) { | 357 | for (i = 0; i < dwords;) { |
353 | int cmd, sz; | 358 | int cmd, sz; |
@@ -386,7 +391,7 @@ static int i915_emit_box(drm_device_t * dev, | |||
386 | RING_LOCALS; | 391 | RING_LOCALS; |
387 | 392 | ||
388 | if (DRM_COPY_FROM_USER_UNCHECKED(&box, &boxes[i], sizeof(box))) { | 393 | if (DRM_COPY_FROM_USER_UNCHECKED(&box, &boxes[i], sizeof(box))) { |
389 | return EFAULT; | 394 | return DRM_ERR(EFAULT); |
390 | } | 395 | } |
391 | 396 | ||
392 | if (box.y2 <= box.y1 || box.x2 <= box.x1 || box.y2 <= 0 || box.x2 <= 0) { | 397 | if (box.y2 <= box.y1 || box.x2 <= box.x1 || box.y2 <= 0 || box.x2 <= 0) { |
@@ -395,24 +400,40 @@ static int i915_emit_box(drm_device_t * dev, | |||
395 | return DRM_ERR(EINVAL); | 400 | return DRM_ERR(EINVAL); |
396 | } | 401 | } |
397 | 402 | ||
398 | BEGIN_LP_RING(6); | 403 | if (IS_I965G(dev)) { |
399 | OUT_RING(GFX_OP_DRAWRECT_INFO); | 404 | BEGIN_LP_RING(4); |
400 | OUT_RING(DR1); | 405 | OUT_RING(GFX_OP_DRAWRECT_INFO_I965); |
401 | OUT_RING((box.x1 & 0xffff) | (box.y1 << 16)); | 406 | OUT_RING((box.x1 & 0xffff) | (box.y1 << 16)); |
402 | OUT_RING(((box.x2 - 1) & 0xffff) | ((box.y2 - 1) << 16)); | 407 | OUT_RING(((box.x2 - 1) & 0xffff) | ((box.y2 - 1) << 16)); |
403 | OUT_RING(DR4); | 408 | OUT_RING(DR4); |
404 | OUT_RING(0); | 409 | ADVANCE_LP_RING(); |
405 | ADVANCE_LP_RING(); | 410 | } else { |
411 | BEGIN_LP_RING(6); | ||
412 | OUT_RING(GFX_OP_DRAWRECT_INFO); | ||
413 | OUT_RING(DR1); | ||
414 | OUT_RING((box.x1 & 0xffff) | (box.y1 << 16)); | ||
415 | OUT_RING(((box.x2 - 1) & 0xffff) | ((box.y2 - 1) << 16)); | ||
416 | OUT_RING(DR4); | ||
417 | OUT_RING(0); | ||
418 | ADVANCE_LP_RING(); | ||
419 | } | ||
406 | 420 | ||
407 | return 0; | 421 | return 0; |
408 | } | 422 | } |
409 | 423 | ||
424 | /* XXX: Emitting the counter should really be moved to part of the IRQ | ||
425 | * emit. For now, do it in both places: | ||
426 | */ | ||
427 | |||
410 | static void i915_emit_breadcrumb(drm_device_t *dev) | 428 | static void i915_emit_breadcrumb(drm_device_t *dev) |
411 | { | 429 | { |
412 | drm_i915_private_t *dev_priv = dev->dev_private; | 430 | drm_i915_private_t *dev_priv = dev->dev_private; |
413 | RING_LOCALS; | 431 | RING_LOCALS; |
414 | 432 | ||
415 | dev_priv->sarea_priv->last_enqueue = dev_priv->counter++; | 433 | dev_priv->sarea_priv->last_enqueue = ++dev_priv->counter; |
434 | |||
435 | if (dev_priv->counter > 0x7FFFFFFFUL) | ||
436 | dev_priv->sarea_priv->last_enqueue = dev_priv->counter = 1; | ||
416 | 437 | ||
417 | BEGIN_LP_RING(4); | 438 | BEGIN_LP_RING(4); |
418 | OUT_RING(CMD_STORE_DWORD_IDX); | 439 | OUT_RING(CMD_STORE_DWORD_IDX); |
diff --git a/drivers/char/drm/i915_drm.h b/drivers/char/drm/i915_drm.h index 5aa3e0e3bb45..6af83e613f27 100644 --- a/drivers/char/drm/i915_drm.h +++ b/drivers/char/drm/i915_drm.h | |||
@@ -98,6 +98,12 @@ typedef struct _drm_i915_sarea { | |||
98 | int rotated_size; | 98 | int rotated_size; |
99 | int rotated_pitch; | 99 | int rotated_pitch; |
100 | int virtualX, virtualY; | 100 | int virtualX, virtualY; |
101 | |||
102 | unsigned int front_tiled; | ||
103 | unsigned int back_tiled; | ||
104 | unsigned int depth_tiled; | ||
105 | unsigned int rotated_tiled; | ||
106 | unsigned int rotated2_tiled; | ||
101 | } drm_i915_sarea_t; | 107 | } drm_i915_sarea_t; |
102 | 108 | ||
103 | /* Flags for perf_boxes | 109 | /* Flags for perf_boxes |
diff --git a/drivers/char/drm/i915_drv.h b/drivers/char/drm/i915_drv.h index 2d565031c002..fdc2bf192714 100644 --- a/drivers/char/drm/i915_drv.h +++ b/drivers/char/drm/i915_drv.h | |||
@@ -146,9 +146,9 @@ extern void i915_mem_release(drm_device_t * dev, | |||
146 | #define BEGIN_LP_RING(n) do { \ | 146 | #define BEGIN_LP_RING(n) do { \ |
147 | if (I915_VERBOSE) \ | 147 | if (I915_VERBOSE) \ |
148 | DRM_DEBUG("BEGIN_LP_RING(%d) in %s\n", \ | 148 | DRM_DEBUG("BEGIN_LP_RING(%d) in %s\n", \ |
149 | n, __FUNCTION__); \ | 149 | (n), __FUNCTION__); \ |
150 | if (dev_priv->ring.space < n*4) \ | 150 | if (dev_priv->ring.space < (n)*4) \ |
151 | i915_wait_ring(dev, n*4, __FUNCTION__); \ | 151 | i915_wait_ring(dev, (n)*4, __FUNCTION__); \ |
152 | outcount = 0; \ | 152 | outcount = 0; \ |
153 | outring = dev_priv->ring.tail; \ | 153 | outring = dev_priv->ring.tail; \ |
154 | ringmask = dev_priv->ring.tail_mask; \ | 154 | ringmask = dev_priv->ring.tail_mask; \ |
@@ -157,7 +157,7 @@ extern void i915_mem_release(drm_device_t * dev, | |||
157 | 157 | ||
158 | #define OUT_RING(n) do { \ | 158 | #define OUT_RING(n) do { \ |
159 | if (I915_VERBOSE) DRM_DEBUG(" OUT_RING %x\n", (int)(n)); \ | 159 | if (I915_VERBOSE) DRM_DEBUG(" OUT_RING %x\n", (int)(n)); \ |
160 | *(volatile unsigned int *)(virt + outring) = n; \ | 160 | *(volatile unsigned int *)(virt + outring) = (n); \ |
161 | outcount++; \ | 161 | outcount++; \ |
162 | outring += 4; \ | 162 | outring += 4; \ |
163 | outring &= ringmask; \ | 163 | outring &= ringmask; \ |
@@ -254,6 +254,8 @@ extern int i915_wait_ring(drm_device_t * dev, int n, const char *caller); | |||
254 | #define GFX_OP_DESTBUFFER_VARS ((0x3<<29)|(0x1d<<24)|(0x85<<16)|0x0) | 254 | #define GFX_OP_DESTBUFFER_VARS ((0x3<<29)|(0x1d<<24)|(0x85<<16)|0x0) |
255 | #define GFX_OP_DRAWRECT_INFO ((0x3<<29)|(0x1d<<24)|(0x80<<16)|(0x3)) | 255 | #define GFX_OP_DRAWRECT_INFO ((0x3<<29)|(0x1d<<24)|(0x80<<16)|(0x3)) |
256 | 256 | ||
257 | #define GFX_OP_DRAWRECT_INFO_I965 ((0x7900<<16)|0x2) | ||
258 | |||
257 | #define MI_BATCH_BUFFER ((0x30<<23)|1) | 259 | #define MI_BATCH_BUFFER ((0x30<<23)|1) |
258 | #define MI_BATCH_BUFFER_START (0x31<<23) | 260 | #define MI_BATCH_BUFFER_START (0x31<<23) |
259 | #define MI_BATCH_BUFFER_END (0xA<<23) | 261 | #define MI_BATCH_BUFFER_END (0xA<<23) |
diff --git a/drivers/char/drm/i915_irq.c b/drivers/char/drm/i915_irq.c index cd96cfa430db..0d4a162aa385 100644 --- a/drivers/char/drm/i915_irq.c +++ b/drivers/char/drm/i915_irq.c | |||
@@ -71,21 +71,27 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) | |||
71 | static int i915_emit_irq(drm_device_t * dev) | 71 | static int i915_emit_irq(drm_device_t * dev) |
72 | { | 72 | { |
73 | drm_i915_private_t *dev_priv = dev->dev_private; | 73 | drm_i915_private_t *dev_priv = dev->dev_private; |
74 | u32 ret; | ||
75 | RING_LOCALS; | 74 | RING_LOCALS; |
76 | 75 | ||
77 | i915_kernel_lost_context(dev); | 76 | i915_kernel_lost_context(dev); |
78 | 77 | ||
79 | DRM_DEBUG("%s\n", __FUNCTION__); | 78 | DRM_DEBUG("%s\n", __FUNCTION__); |
80 | 79 | ||
81 | ret = dev_priv->counter; | 80 | dev_priv->sarea_priv->last_enqueue = ++dev_priv->counter; |
82 | 81 | ||
83 | BEGIN_LP_RING(2); | 82 | if (dev_priv->counter > 0x7FFFFFFFUL) |
83 | dev_priv->sarea_priv->last_enqueue = dev_priv->counter = 1; | ||
84 | |||
85 | BEGIN_LP_RING(6); | ||
86 | OUT_RING(CMD_STORE_DWORD_IDX); | ||
87 | OUT_RING(20); | ||
88 | OUT_RING(dev_priv->counter); | ||
89 | OUT_RING(0); | ||
84 | OUT_RING(0); | 90 | OUT_RING(0); |
85 | OUT_RING(GFX_OP_USER_INTERRUPT); | 91 | OUT_RING(GFX_OP_USER_INTERRUPT); |
86 | ADVANCE_LP_RING(); | 92 | ADVANCE_LP_RING(); |
87 | 93 | ||
88 | return ret; | 94 | return dev_priv->counter; |
89 | } | 95 | } |
90 | 96 | ||
91 | static int i915_wait_irq(drm_device_t * dev, int irq_nr) | 97 | static int i915_wait_irq(drm_device_t * dev, int irq_nr) |
diff --git a/drivers/char/drm/radeon_cp.c b/drivers/char/drm/radeon_cp.c index 5ad43ba7b5aa..5ed965688293 100644 --- a/drivers/char/drm/radeon_cp.c +++ b/drivers/char/drm/radeon_cp.c | |||
@@ -864,13 +864,13 @@ static int radeon_do_pixcache_flush(drm_radeon_private_t * dev_priv) | |||
864 | 864 | ||
865 | dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE; | 865 | dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE; |
866 | 866 | ||
867 | tmp = RADEON_READ(RADEON_RB2D_DSTCACHE_CTLSTAT); | 867 | tmp = RADEON_READ(RADEON_RB3D_DSTCACHE_CTLSTAT); |
868 | tmp |= RADEON_RB2D_DC_FLUSH_ALL; | 868 | tmp |= RADEON_RB3D_DC_FLUSH_ALL; |
869 | RADEON_WRITE(RADEON_RB2D_DSTCACHE_CTLSTAT, tmp); | 869 | RADEON_WRITE(RADEON_RB3D_DSTCACHE_CTLSTAT, tmp); |
870 | 870 | ||
871 | for (i = 0; i < dev_priv->usec_timeout; i++) { | 871 | for (i = 0; i < dev_priv->usec_timeout; i++) { |
872 | if (!(RADEON_READ(RADEON_RB2D_DSTCACHE_CTLSTAT) | 872 | if (!(RADEON_READ(RADEON_RB3D_DSTCACHE_CTLSTAT) |
873 | & RADEON_RB2D_DC_BUSY)) { | 873 | & RADEON_RB3D_DC_BUSY)) { |
874 | return 0; | 874 | return 0; |
875 | } | 875 | } |
876 | DRM_UDELAY(1); | 876 | DRM_UDELAY(1); |
@@ -1130,7 +1130,7 @@ static void radeon_cp_init_ring_buffer(drm_device_t * dev, | |||
1130 | | (dev_priv->fb_location >> 16)); | 1130 | | (dev_priv->fb_location >> 16)); |
1131 | 1131 | ||
1132 | #if __OS_HAS_AGP | 1132 | #if __OS_HAS_AGP |
1133 | if (dev_priv->flags & CHIP_IS_AGP) { | 1133 | if (dev_priv->flags & RADEON_IS_AGP) { |
1134 | RADEON_WRITE(RADEON_AGP_BASE, (unsigned int)dev->agp->base); | 1134 | RADEON_WRITE(RADEON_AGP_BASE, (unsigned int)dev->agp->base); |
1135 | RADEON_WRITE(RADEON_MC_AGP_LOCATION, | 1135 | RADEON_WRITE(RADEON_MC_AGP_LOCATION, |
1136 | (((dev_priv->gart_vm_start - 1 + | 1136 | (((dev_priv->gart_vm_start - 1 + |
@@ -1158,7 +1158,7 @@ static void radeon_cp_init_ring_buffer(drm_device_t * dev, | |||
1158 | dev_priv->ring.tail = cur_read_ptr; | 1158 | dev_priv->ring.tail = cur_read_ptr; |
1159 | 1159 | ||
1160 | #if __OS_HAS_AGP | 1160 | #if __OS_HAS_AGP |
1161 | if (dev_priv->flags & CHIP_IS_AGP) { | 1161 | if (dev_priv->flags & RADEON_IS_AGP) { |
1162 | RADEON_WRITE(RADEON_CP_RB_RPTR_ADDR, | 1162 | RADEON_WRITE(RADEON_CP_RB_RPTR_ADDR, |
1163 | dev_priv->ring_rptr->offset | 1163 | dev_priv->ring_rptr->offset |
1164 | - dev->agp->base + dev_priv->gart_vm_start); | 1164 | - dev->agp->base + dev_priv->gart_vm_start); |
@@ -1258,6 +1258,13 @@ static void radeon_test_writeback(drm_radeon_private_t * dev_priv) | |||
1258 | dev_priv->writeback_works = 0; | 1258 | dev_priv->writeback_works = 0; |
1259 | DRM_INFO("writeback forced off\n"); | 1259 | DRM_INFO("writeback forced off\n"); |
1260 | } | 1260 | } |
1261 | |||
1262 | if (!dev_priv->writeback_works) { | ||
1263 | /* Disable writeback to avoid unnecessary bus master transfer */ | ||
1264 | RADEON_WRITE(RADEON_CP_RB_CNTL, RADEON_READ(RADEON_CP_RB_CNTL) | | ||
1265 | RADEON_RB_NO_UPDATE); | ||
1266 | RADEON_WRITE(RADEON_SCRATCH_UMSK, 0); | ||
1267 | } | ||
1261 | } | 1268 | } |
1262 | 1269 | ||
1263 | /* Enable or disable PCI-E GART on the chip */ | 1270 | /* Enable or disable PCI-E GART on the chip */ |
@@ -1295,7 +1302,7 @@ static void radeon_set_pcigart(drm_radeon_private_t * dev_priv, int on) | |||
1295 | { | 1302 | { |
1296 | u32 tmp; | 1303 | u32 tmp; |
1297 | 1304 | ||
1298 | if (dev_priv->flags & CHIP_IS_PCIE) { | 1305 | if (dev_priv->flags & RADEON_IS_PCIE) { |
1299 | radeon_set_pciegart(dev_priv, on); | 1306 | radeon_set_pciegart(dev_priv, on); |
1300 | return; | 1307 | return; |
1301 | } | 1308 | } |
@@ -1333,20 +1340,22 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init) | |||
1333 | DRM_DEBUG("\n"); | 1340 | DRM_DEBUG("\n"); |
1334 | 1341 | ||
1335 | /* if we require new memory map but we don't have it fail */ | 1342 | /* if we require new memory map but we don't have it fail */ |
1336 | if ((dev_priv->flags & CHIP_NEW_MEMMAP) && !dev_priv->new_memmap) | 1343 | if ((dev_priv->flags & RADEON_NEW_MEMMAP) && !dev_priv->new_memmap) { |
1337 | { | 1344 | DRM_ERROR("Cannot initialise DRM on this card\nThis card requires a new X.org DDX for 3D\n"); |
1338 | DRM_ERROR("Cannot initialise DRM on this card\nThis card requires a new X.org DDX\n"); | ||
1339 | radeon_do_cleanup_cp(dev); | 1345 | radeon_do_cleanup_cp(dev); |
1340 | return DRM_ERR(EINVAL); | 1346 | return DRM_ERR(EINVAL); |
1341 | } | 1347 | } |
1342 | 1348 | ||
1343 | if (init->is_pci && (dev_priv->flags & CHIP_IS_AGP)) | 1349 | if (init->is_pci && (dev_priv->flags & RADEON_IS_AGP)) { |
1344 | { | ||
1345 | DRM_DEBUG("Forcing AGP card to PCI mode\n"); | 1350 | DRM_DEBUG("Forcing AGP card to PCI mode\n"); |
1346 | dev_priv->flags &= ~CHIP_IS_AGP; | 1351 | dev_priv->flags &= ~RADEON_IS_AGP; |
1352 | } else if (!(dev_priv->flags & (RADEON_IS_AGP | RADEON_IS_PCI | RADEON_IS_PCIE)) | ||
1353 | && !init->is_pci) { | ||
1354 | DRM_DEBUG("Restoring AGP flag\n"); | ||
1355 | dev_priv->flags |= RADEON_IS_AGP; | ||
1347 | } | 1356 | } |
1348 | 1357 | ||
1349 | if ((!(dev_priv->flags & CHIP_IS_AGP)) && !dev->sg) { | 1358 | if ((!(dev_priv->flags & RADEON_IS_AGP)) && !dev->sg) { |
1350 | DRM_ERROR("PCI GART memory not allocated!\n"); | 1359 | DRM_ERROR("PCI GART memory not allocated!\n"); |
1351 | radeon_do_cleanup_cp(dev); | 1360 | radeon_do_cleanup_cp(dev); |
1352 | return DRM_ERR(EINVAL); | 1361 | return DRM_ERR(EINVAL); |
@@ -1489,7 +1498,7 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init) | |||
1489 | init->sarea_priv_offset); | 1498 | init->sarea_priv_offset); |
1490 | 1499 | ||
1491 | #if __OS_HAS_AGP | 1500 | #if __OS_HAS_AGP |
1492 | if (dev_priv->flags & CHIP_IS_AGP) { | 1501 | if (dev_priv->flags & RADEON_IS_AGP) { |
1493 | drm_core_ioremap(dev_priv->cp_ring, dev); | 1502 | drm_core_ioremap(dev_priv->cp_ring, dev); |
1494 | drm_core_ioremap(dev_priv->ring_rptr, dev); | 1503 | drm_core_ioremap(dev_priv->ring_rptr, dev); |
1495 | drm_core_ioremap(dev->agp_buffer_map, dev); | 1504 | drm_core_ioremap(dev->agp_buffer_map, dev); |
@@ -1548,7 +1557,7 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init) | |||
1548 | * align it down. | 1557 | * align it down. |
1549 | */ | 1558 | */ |
1550 | #if __OS_HAS_AGP | 1559 | #if __OS_HAS_AGP |
1551 | if (dev_priv->flags & CHIP_IS_AGP) { | 1560 | if (dev_priv->flags & RADEON_IS_AGP) { |
1552 | base = dev->agp->base; | 1561 | base = dev->agp->base; |
1553 | /* Check if valid */ | 1562 | /* Check if valid */ |
1554 | if ((base + dev_priv->gart_size) > dev_priv->fb_location && | 1563 | if ((base + dev_priv->gart_size) > dev_priv->fb_location && |
@@ -1578,7 +1587,7 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init) | |||
1578 | } | 1587 | } |
1579 | 1588 | ||
1580 | #if __OS_HAS_AGP | 1589 | #if __OS_HAS_AGP |
1581 | if (dev_priv->flags & CHIP_IS_AGP) | 1590 | if (dev_priv->flags & RADEON_IS_AGP) |
1582 | dev_priv->gart_buffers_offset = (dev->agp_buffer_map->offset | 1591 | dev_priv->gart_buffers_offset = (dev->agp_buffer_map->offset |
1583 | - dev->agp->base | 1592 | - dev->agp->base |
1584 | + dev_priv->gart_vm_start); | 1593 | + dev_priv->gart_vm_start); |
@@ -1604,7 +1613,7 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init) | |||
1604 | dev_priv->ring.high_mark = RADEON_RING_HIGH_MARK; | 1613 | dev_priv->ring.high_mark = RADEON_RING_HIGH_MARK; |
1605 | 1614 | ||
1606 | #if __OS_HAS_AGP | 1615 | #if __OS_HAS_AGP |
1607 | if (dev_priv->flags & CHIP_IS_AGP) { | 1616 | if (dev_priv->flags & RADEON_IS_AGP) { |
1608 | /* Turn off PCI GART */ | 1617 | /* Turn off PCI GART */ |
1609 | radeon_set_pcigart(dev_priv, 0); | 1618 | radeon_set_pcigart(dev_priv, 0); |
1610 | } else | 1619 | } else |
@@ -1624,7 +1633,7 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init) | |||
1624 | dev_priv->gart_info.mapping.handle; | 1633 | dev_priv->gart_info.mapping.handle; |
1625 | 1634 | ||
1626 | dev_priv->gart_info.is_pcie = | 1635 | dev_priv->gart_info.is_pcie = |
1627 | !!(dev_priv->flags & CHIP_IS_PCIE); | 1636 | !!(dev_priv->flags & RADEON_IS_PCIE); |
1628 | dev_priv->gart_info.gart_table_location = | 1637 | dev_priv->gart_info.gart_table_location = |
1629 | DRM_ATI_GART_FB; | 1638 | DRM_ATI_GART_FB; |
1630 | 1639 | ||
@@ -1636,7 +1645,7 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init) | |||
1636 | DRM_ATI_GART_MAIN; | 1645 | DRM_ATI_GART_MAIN; |
1637 | dev_priv->gart_info.addr = NULL; | 1646 | dev_priv->gart_info.addr = NULL; |
1638 | dev_priv->gart_info.bus_addr = 0; | 1647 | dev_priv->gart_info.bus_addr = 0; |
1639 | if (dev_priv->flags & CHIP_IS_PCIE) { | 1648 | if (dev_priv->flags & RADEON_IS_PCIE) { |
1640 | DRM_ERROR | 1649 | DRM_ERROR |
1641 | ("Cannot use PCI Express without GART in FB memory\n"); | 1650 | ("Cannot use PCI Express without GART in FB memory\n"); |
1642 | radeon_do_cleanup_cp(dev); | 1651 | radeon_do_cleanup_cp(dev); |
@@ -1678,7 +1687,7 @@ static int radeon_do_cleanup_cp(drm_device_t * dev) | |||
1678 | drm_irq_uninstall(dev); | 1687 | drm_irq_uninstall(dev); |
1679 | 1688 | ||
1680 | #if __OS_HAS_AGP | 1689 | #if __OS_HAS_AGP |
1681 | if (dev_priv->flags & CHIP_IS_AGP) { | 1690 | if (dev_priv->flags & RADEON_IS_AGP) { |
1682 | if (dev_priv->cp_ring != NULL) { | 1691 | if (dev_priv->cp_ring != NULL) { |
1683 | drm_core_ioremapfree(dev_priv->cp_ring, dev); | 1692 | drm_core_ioremapfree(dev_priv->cp_ring, dev); |
1684 | dev_priv->cp_ring = NULL; | 1693 | dev_priv->cp_ring = NULL; |
@@ -1733,7 +1742,7 @@ static int radeon_do_resume_cp(drm_device_t * dev) | |||
1733 | DRM_DEBUG("Starting radeon_do_resume_cp()\n"); | 1742 | DRM_DEBUG("Starting radeon_do_resume_cp()\n"); |
1734 | 1743 | ||
1735 | #if __OS_HAS_AGP | 1744 | #if __OS_HAS_AGP |
1736 | if (dev_priv->flags & CHIP_IS_AGP) { | 1745 | if (dev_priv->flags & RADEON_IS_AGP) { |
1737 | /* Turn off PCI GART */ | 1746 | /* Turn off PCI GART */ |
1738 | radeon_set_pcigart(dev_priv, 0); | 1747 | radeon_set_pcigart(dev_priv, 0); |
1739 | } else | 1748 | } else |
@@ -2177,13 +2186,15 @@ int radeon_driver_load(struct drm_device *dev, unsigned long flags) | |||
2177 | dev->dev_private = (void *)dev_priv; | 2186 | dev->dev_private = (void *)dev_priv; |
2178 | dev_priv->flags = flags; | 2187 | dev_priv->flags = flags; |
2179 | 2188 | ||
2180 | switch (flags & CHIP_FAMILY_MASK) { | 2189 | switch (flags & RADEON_FAMILY_MASK) { |
2181 | case CHIP_R100: | 2190 | case CHIP_R100: |
2182 | case CHIP_RV200: | 2191 | case CHIP_RV200: |
2183 | case CHIP_R200: | 2192 | case CHIP_R200: |
2184 | case CHIP_R300: | 2193 | case CHIP_R300: |
2194 | case CHIP_R350: | ||
2185 | case CHIP_R420: | 2195 | case CHIP_R420: |
2186 | dev_priv->flags |= CHIP_HAS_HIERZ; | 2196 | case CHIP_RV410: |
2197 | dev_priv->flags |= RADEON_HAS_HIERZ; | ||
2187 | break; | 2198 | break; |
2188 | default: | 2199 | default: |
2189 | /* all other chips have no hierarchical z buffer */ | 2200 | /* all other chips have no hierarchical z buffer */ |
@@ -2191,13 +2202,14 @@ int radeon_driver_load(struct drm_device *dev, unsigned long flags) | |||
2191 | } | 2202 | } |
2192 | 2203 | ||
2193 | if (drm_device_is_agp(dev)) | 2204 | if (drm_device_is_agp(dev)) |
2194 | dev_priv->flags |= CHIP_IS_AGP; | 2205 | dev_priv->flags |= RADEON_IS_AGP; |
2195 | 2206 | else if (drm_device_is_pcie(dev)) | |
2196 | if (drm_device_is_pcie(dev)) | 2207 | dev_priv->flags |= RADEON_IS_PCIE; |
2197 | dev_priv->flags |= CHIP_IS_PCIE; | 2208 | else |
2209 | dev_priv->flags |= RADEON_IS_PCI; | ||
2198 | 2210 | ||
2199 | DRM_DEBUG("%s card detected\n", | 2211 | DRM_DEBUG("%s card detected\n", |
2200 | ((dev_priv->flags & CHIP_IS_AGP) ? "AGP" : (((dev_priv->flags & CHIP_IS_PCIE) ? "PCIE" : "PCI")))); | 2212 | ((dev_priv->flags & RADEON_IS_AGP) ? "AGP" : (((dev_priv->flags & RADEON_IS_PCIE) ? "PCIE" : "PCI")))); |
2201 | return ret; | 2213 | return ret; |
2202 | } | 2214 | } |
2203 | 2215 | ||
diff --git a/drivers/char/drm/radeon_drv.c b/drivers/char/drm/radeon_drv.c index eb985c2a31e9..2eb652ec6745 100644 --- a/drivers/char/drm/radeon_drv.c +++ b/drivers/char/drm/radeon_drv.c | |||
@@ -44,7 +44,7 @@ module_param_named(no_wb, radeon_no_wb, int, 0444); | |||
44 | static int dri_library_name(struct drm_device *dev, char *buf) | 44 | static int dri_library_name(struct drm_device *dev, char *buf) |
45 | { | 45 | { |
46 | drm_radeon_private_t *dev_priv = dev->dev_private; | 46 | drm_radeon_private_t *dev_priv = dev->dev_private; |
47 | int family = dev_priv->flags & CHIP_FAMILY_MASK; | 47 | int family = dev_priv->flags & RADEON_FAMILY_MASK; |
48 | 48 | ||
49 | return snprintf(buf, PAGE_SIZE, "%s\n", | 49 | return snprintf(buf, PAGE_SIZE, "%s\n", |
50 | (family < CHIP_R200) ? "radeon" : | 50 | (family < CHIP_R200) ? "radeon" : |
diff --git a/drivers/char/drm/radeon_drv.h b/drivers/char/drm/radeon_drv.h index e5a256f5429c..f45cd7f147a5 100644 --- a/drivers/char/drm/radeon_drv.h +++ b/drivers/char/drm/radeon_drv.h | |||
@@ -133,15 +133,16 @@ enum radeon_cp_microcode_version { | |||
133 | * Chip flags | 133 | * Chip flags |
134 | */ | 134 | */ |
135 | enum radeon_chip_flags { | 135 | enum radeon_chip_flags { |
136 | CHIP_FAMILY_MASK = 0x0000ffffUL, | 136 | RADEON_FAMILY_MASK = 0x0000ffffUL, |
137 | CHIP_FLAGS_MASK = 0xffff0000UL, | 137 | RADEON_FLAGS_MASK = 0xffff0000UL, |
138 | CHIP_IS_MOBILITY = 0x00010000UL, | 138 | RADEON_IS_MOBILITY = 0x00010000UL, |
139 | CHIP_IS_IGP = 0x00020000UL, | 139 | RADEON_IS_IGP = 0x00020000UL, |
140 | CHIP_SINGLE_CRTC = 0x00040000UL, | 140 | RADEON_SINGLE_CRTC = 0x00040000UL, |
141 | CHIP_IS_AGP = 0x00080000UL, | 141 | RADEON_IS_AGP = 0x00080000UL, |
142 | CHIP_HAS_HIERZ = 0x00100000UL, | 142 | RADEON_HAS_HIERZ = 0x00100000UL, |
143 | CHIP_IS_PCIE = 0x00200000UL, | 143 | RADEON_IS_PCIE = 0x00200000UL, |
144 | CHIP_NEW_MEMMAP = 0x00400000UL, | 144 | RADEON_NEW_MEMMAP = 0x00400000UL, |
145 | RADEON_IS_PCI = 0x00800000UL, | ||
145 | }; | 146 | }; |
146 | 147 | ||
147 | #define GET_RING_HEAD(dev_priv) (dev_priv->writeback_works ? \ | 148 | #define GET_RING_HEAD(dev_priv) (dev_priv->writeback_works ? \ |
@@ -424,6 +425,8 @@ extern int r300_do_cp_cmdbuf(drm_device_t * dev, DRMFILE filp, | |||
424 | #define RADEON_RB3D_COLOROFFSET 0x1c40 | 425 | #define RADEON_RB3D_COLOROFFSET 0x1c40 |
425 | #define RADEON_RB3D_COLORPITCH 0x1c48 | 426 | #define RADEON_RB3D_COLORPITCH 0x1c48 |
426 | 427 | ||
428 | #define RADEON_SRC_X_Y 0x1590 | ||
429 | |||
427 | #define RADEON_DP_GUI_MASTER_CNTL 0x146c | 430 | #define RADEON_DP_GUI_MASTER_CNTL 0x146c |
428 | # define RADEON_GMC_SRC_PITCH_OFFSET_CNTL (1 << 0) | 431 | # define RADEON_GMC_SRC_PITCH_OFFSET_CNTL (1 << 0) |
429 | # define RADEON_GMC_DST_PITCH_OFFSET_CNTL (1 << 1) | 432 | # define RADEON_GMC_DST_PITCH_OFFSET_CNTL (1 << 1) |
@@ -441,6 +444,7 @@ extern int r300_do_cp_cmdbuf(drm_device_t * dev, DRMFILE filp, | |||
441 | # define RADEON_ROP3_S 0x00cc0000 | 444 | # define RADEON_ROP3_S 0x00cc0000 |
442 | # define RADEON_ROP3_P 0x00f00000 | 445 | # define RADEON_ROP3_P 0x00f00000 |
443 | #define RADEON_DP_WRITE_MASK 0x16cc | 446 | #define RADEON_DP_WRITE_MASK 0x16cc |
447 | #define RADEON_SRC_PITCH_OFFSET 0x1428 | ||
444 | #define RADEON_DST_PITCH_OFFSET 0x142c | 448 | #define RADEON_DST_PITCH_OFFSET 0x142c |
445 | #define RADEON_DST_PITCH_OFFSET_C 0x1c80 | 449 | #define RADEON_DST_PITCH_OFFSET_C 0x1c80 |
446 | # define RADEON_DST_TILE_LINEAR (0 << 30) | 450 | # define RADEON_DST_TILE_LINEAR (0 << 30) |
@@ -545,6 +549,11 @@ extern int r300_do_cp_cmdbuf(drm_device_t * dev, DRMFILE filp, | |||
545 | # define RADEON_RB3D_ZC_FREE (1 << 2) | 549 | # define RADEON_RB3D_ZC_FREE (1 << 2) |
546 | # define RADEON_RB3D_ZC_FLUSH_ALL 0x5 | 550 | # define RADEON_RB3D_ZC_FLUSH_ALL 0x5 |
547 | # define RADEON_RB3D_ZC_BUSY (1 << 31) | 551 | # define RADEON_RB3D_ZC_BUSY (1 << 31) |
552 | #define RADEON_RB3D_DSTCACHE_CTLSTAT 0x325c | ||
553 | # define RADEON_RB3D_DC_FLUSH (3 << 0) | ||
554 | # define RADEON_RB3D_DC_FREE (3 << 2) | ||
555 | # define RADEON_RB3D_DC_FLUSH_ALL 0xf | ||
556 | # define RADEON_RB3D_DC_BUSY (1 << 31) | ||
548 | #define RADEON_RB3D_ZSTENCILCNTL 0x1c2c | 557 | #define RADEON_RB3D_ZSTENCILCNTL 0x1c2c |
549 | # define RADEON_Z_TEST_MASK (7 << 4) | 558 | # define RADEON_Z_TEST_MASK (7 << 4) |
550 | # define RADEON_Z_TEST_ALWAYS (7 << 4) | 559 | # define RADEON_Z_TEST_ALWAYS (7 << 4) |
@@ -681,6 +690,7 @@ extern int r300_do_cp_cmdbuf(drm_device_t * dev, DRMFILE filp, | |||
681 | #define RADEON_CP_RB_BASE 0x0700 | 690 | #define RADEON_CP_RB_BASE 0x0700 |
682 | #define RADEON_CP_RB_CNTL 0x0704 | 691 | #define RADEON_CP_RB_CNTL 0x0704 |
683 | # define RADEON_BUF_SWAP_32BIT (2 << 16) | 692 | # define RADEON_BUF_SWAP_32BIT (2 << 16) |
693 | # define RADEON_RB_NO_UPDATE (1 << 27) | ||
684 | #define RADEON_CP_RB_RPTR_ADDR 0x070c | 694 | #define RADEON_CP_RB_RPTR_ADDR 0x070c |
685 | #define RADEON_CP_RB_RPTR 0x0710 | 695 | #define RADEON_CP_RB_RPTR 0x0710 |
686 | #define RADEON_CP_RB_WPTR 0x0714 | 696 | #define RADEON_CP_RB_WPTR 0x0714 |
@@ -986,13 +996,13 @@ do { \ | |||
986 | } while (0) | 996 | } while (0) |
987 | 997 | ||
988 | #define RADEON_FLUSH_CACHE() do { \ | 998 | #define RADEON_FLUSH_CACHE() do { \ |
989 | OUT_RING( CP_PACKET0( RADEON_RB2D_DSTCACHE_CTLSTAT, 0 ) ); \ | 999 | OUT_RING( CP_PACKET0( RADEON_RB3D_DSTCACHE_CTLSTAT, 0 ) ); \ |
990 | OUT_RING( RADEON_RB2D_DC_FLUSH ); \ | 1000 | OUT_RING( RADEON_RB3D_DC_FLUSH ); \ |
991 | } while (0) | 1001 | } while (0) |
992 | 1002 | ||
993 | #define RADEON_PURGE_CACHE() do { \ | 1003 | #define RADEON_PURGE_CACHE() do { \ |
994 | OUT_RING( CP_PACKET0( RADEON_RB2D_DSTCACHE_CTLSTAT, 0 ) ); \ | 1004 | OUT_RING( CP_PACKET0( RADEON_RB3D_DSTCACHE_CTLSTAT, 0 ) ); \ |
995 | OUT_RING( RADEON_RB2D_DC_FLUSH_ALL ); \ | 1005 | OUT_RING( RADEON_RB3D_DC_FLUSH_ALL ); \ |
996 | } while (0) | 1006 | } while (0) |
997 | 1007 | ||
998 | #define RADEON_FLUSH_ZCACHE() do { \ | 1008 | #define RADEON_FLUSH_ZCACHE() do { \ |
diff --git a/drivers/char/drm/radeon_state.c b/drivers/char/drm/radeon_state.c index 39a7f685e3fd..feac5f005d47 100644 --- a/drivers/char/drm/radeon_state.c +++ b/drivers/char/drm/radeon_state.c | |||
@@ -42,7 +42,11 @@ static __inline__ int radeon_check_and_fixup_offset(drm_radeon_private_t * | |||
42 | drm_file_t * filp_priv, | 42 | drm_file_t * filp_priv, |
43 | u32 *offset) | 43 | u32 *offset) |
44 | { | 44 | { |
45 | u32 off = *offset; | 45 | u64 off = *offset; |
46 | u32 fb_start = dev_priv->fb_location; | ||
47 | u32 fb_end = fb_start + dev_priv->fb_size - 1; | ||
48 | u32 gart_start = dev_priv->gart_vm_start; | ||
49 | u32 gart_end = gart_start + dev_priv->gart_size - 1; | ||
46 | struct drm_radeon_driver_file_fields *radeon_priv; | 50 | struct drm_radeon_driver_file_fields *radeon_priv; |
47 | 51 | ||
48 | /* Hrm ... the story of the offset ... So this function converts | 52 | /* Hrm ... the story of the offset ... So this function converts |
@@ -62,10 +66,8 @@ static __inline__ int radeon_check_and_fixup_offset(drm_radeon_private_t * | |||
62 | /* First, the best case, the offset already lands in either the | 66 | /* First, the best case, the offset already lands in either the |
63 | * framebuffer or the GART mapped space | 67 | * framebuffer or the GART mapped space |
64 | */ | 68 | */ |
65 | if ((off >= dev_priv->fb_location && | 69 | if ((off >= fb_start && off <= fb_end) || |
66 | off < (dev_priv->fb_location + dev_priv->fb_size)) || | 70 | (off >= gart_start && off <= gart_end)) |
67 | (off >= dev_priv->gart_vm_start && | ||
68 | off < (dev_priv->gart_vm_start + dev_priv->gart_size))) | ||
69 | return 0; | 71 | return 0; |
70 | 72 | ||
71 | /* Ok, that didn't happen... now check if we have a zero based | 73 | /* Ok, that didn't happen... now check if we have a zero based |
@@ -78,16 +80,13 @@ static __inline__ int radeon_check_and_fixup_offset(drm_radeon_private_t * | |||
78 | } | 80 | } |
79 | 81 | ||
80 | /* Finally, assume we aimed at a GART offset if beyond the fb */ | 82 | /* Finally, assume we aimed at a GART offset if beyond the fb */ |
81 | if (off > (dev_priv->fb_location + dev_priv->fb_size)) | 83 | if (off > fb_end) |
82 | off = off - (dev_priv->fb_location + dev_priv->fb_size) + | 84 | off = off - fb_end - 1 + gart_start; |
83 | dev_priv->gart_vm_start; | ||
84 | 85 | ||
85 | /* Now recheck and fail if out of bounds */ | 86 | /* Now recheck and fail if out of bounds */ |
86 | if ((off >= dev_priv->fb_location && | 87 | if ((off >= fb_start && off <= fb_end) || |
87 | off < (dev_priv->fb_location + dev_priv->fb_size)) || | 88 | (off >= gart_start && off <= gart_end)) { |
88 | (off >= dev_priv->gart_vm_start && | 89 | DRM_DEBUG("offset fixed up to 0x%x\n", (unsigned int)off); |
89 | off < (dev_priv->gart_vm_start + dev_priv->gart_size))) { | ||
90 | DRM_DEBUG("offset fixed up to 0x%x\n", off); | ||
91 | *offset = off; | 90 | *offset = off; |
92 | return 0; | 91 | return 0; |
93 | } | 92 | } |
@@ -869,7 +868,7 @@ static void radeon_cp_dispatch_clear(drm_device_t * dev, | |||
869 | */ | 868 | */ |
870 | dev_priv->sarea_priv->ctx_owner = 0; | 869 | dev_priv->sarea_priv->ctx_owner = 0; |
871 | 870 | ||
872 | if ((dev_priv->flags & CHIP_HAS_HIERZ) | 871 | if ((dev_priv->flags & RADEON_HAS_HIERZ) |
873 | && (flags & RADEON_USE_HIERZ)) { | 872 | && (flags & RADEON_USE_HIERZ)) { |
874 | /* FIXME : reverse engineer that for Rx00 cards */ | 873 | /* FIXME : reverse engineer that for Rx00 cards */ |
875 | /* FIXME : the mask supposedly contains low-res z values. So can't set | 874 | /* FIXME : the mask supposedly contains low-res z values. So can't set |
@@ -914,7 +913,7 @@ static void radeon_cp_dispatch_clear(drm_device_t * dev, | |||
914 | for (i = 0; i < nbox; i++) { | 913 | for (i = 0; i < nbox; i++) { |
915 | int tileoffset, nrtilesx, nrtilesy, j; | 914 | int tileoffset, nrtilesx, nrtilesy, j; |
916 | /* it looks like r200 needs rv-style clears, at least if hierz is not enabled? */ | 915 | /* it looks like r200 needs rv-style clears, at least if hierz is not enabled? */ |
917 | if ((dev_priv->flags & CHIP_HAS_HIERZ) | 916 | if ((dev_priv->flags & RADEON_HAS_HIERZ) |
918 | && !(dev_priv->microcode_version == UCODE_R200)) { | 917 | && !(dev_priv->microcode_version == UCODE_R200)) { |
919 | /* FIXME : figure this out for r200 (when hierz is enabled). Or | 918 | /* FIXME : figure this out for r200 (when hierz is enabled). Or |
920 | maybe r200 actually doesn't need to put the low-res z value into | 919 | maybe r200 actually doesn't need to put the low-res z value into |
@@ -998,7 +997,7 @@ static void radeon_cp_dispatch_clear(drm_device_t * dev, | |||
998 | } | 997 | } |
999 | 998 | ||
1000 | /* TODO don't always clear all hi-level z tiles */ | 999 | /* TODO don't always clear all hi-level z tiles */ |
1001 | if ((dev_priv->flags & CHIP_HAS_HIERZ) | 1000 | if ((dev_priv->flags & RADEON_HAS_HIERZ) |
1002 | && (dev_priv->microcode_version == UCODE_R200) | 1001 | && (dev_priv->microcode_version == UCODE_R200) |
1003 | && (flags & RADEON_USE_HIERZ)) | 1002 | && (flags & RADEON_USE_HIERZ)) |
1004 | /* r100 and cards without hierarchical z-buffer have no high-level z-buffer */ | 1003 | /* r100 and cards without hierarchical z-buffer have no high-level z-buffer */ |
@@ -1270,9 +1269,9 @@ static void radeon_cp_dispatch_swap(drm_device_t * dev) | |||
1270 | 1269 | ||
1271 | DRM_DEBUG("dispatch swap %d,%d-%d,%d\n", x, y, w, h); | 1270 | DRM_DEBUG("dispatch swap %d,%d-%d,%d\n", x, y, w, h); |
1272 | 1271 | ||
1273 | BEGIN_RING(7); | 1272 | BEGIN_RING(9); |
1274 | 1273 | ||
1275 | OUT_RING(CP_PACKET3(RADEON_CNTL_BITBLT_MULTI, 5)); | 1274 | OUT_RING(CP_PACKET0(RADEON_DP_GUI_MASTER_CNTL, 0)); |
1276 | OUT_RING(RADEON_GMC_SRC_PITCH_OFFSET_CNTL | | 1275 | OUT_RING(RADEON_GMC_SRC_PITCH_OFFSET_CNTL | |
1277 | RADEON_GMC_DST_PITCH_OFFSET_CNTL | | 1276 | RADEON_GMC_DST_PITCH_OFFSET_CNTL | |
1278 | RADEON_GMC_BRUSH_NONE | | 1277 | RADEON_GMC_BRUSH_NONE | |
@@ -1284,6 +1283,7 @@ static void radeon_cp_dispatch_swap(drm_device_t * dev) | |||
1284 | 1283 | ||
1285 | /* Make this work even if front & back are flipped: | 1284 | /* Make this work even if front & back are flipped: |
1286 | */ | 1285 | */ |
1286 | OUT_RING(CP_PACKET0(RADEON_SRC_PITCH_OFFSET, 1)); | ||
1287 | if (dev_priv->current_page == 0) { | 1287 | if (dev_priv->current_page == 0) { |
1288 | OUT_RING(dev_priv->back_pitch_offset); | 1288 | OUT_RING(dev_priv->back_pitch_offset); |
1289 | OUT_RING(dev_priv->front_pitch_offset); | 1289 | OUT_RING(dev_priv->front_pitch_offset); |
@@ -1292,6 +1292,7 @@ static void radeon_cp_dispatch_swap(drm_device_t * dev) | |||
1292 | OUT_RING(dev_priv->back_pitch_offset); | 1292 | OUT_RING(dev_priv->back_pitch_offset); |
1293 | } | 1293 | } |
1294 | 1294 | ||
1295 | OUT_RING(CP_PACKET0(RADEON_SRC_X_Y, 2)); | ||
1295 | OUT_RING((x << 16) | y); | 1296 | OUT_RING((x << 16) | y); |
1296 | OUT_RING((x << 16) | y); | 1297 | OUT_RING((x << 16) | y); |
1297 | OUT_RING((w << 16) | h); | 1298 | OUT_RING((w << 16) | h); |
@@ -2987,16 +2988,21 @@ static int radeon_cp_getparam(DRM_IOCTL_ARGS) | |||
2987 | case RADEON_PARAM_GART_TEX_HANDLE: | 2988 | case RADEON_PARAM_GART_TEX_HANDLE: |
2988 | value = dev_priv->gart_textures_offset; | 2989 | value = dev_priv->gart_textures_offset; |
2989 | break; | 2990 | break; |
2990 | 2991 | case RADEON_PARAM_SCRATCH_OFFSET: | |
2992 | if (!dev_priv->writeback_works) | ||
2993 | return DRM_ERR(EINVAL); | ||
2994 | value = RADEON_SCRATCH_REG_OFFSET; | ||
2995 | break; | ||
2991 | case RADEON_PARAM_CARD_TYPE: | 2996 | case RADEON_PARAM_CARD_TYPE: |
2992 | if (dev_priv->flags & CHIP_IS_PCIE) | 2997 | if (dev_priv->flags & RADEON_IS_PCIE) |
2993 | value = RADEON_CARD_PCIE; | 2998 | value = RADEON_CARD_PCIE; |
2994 | else if (dev_priv->flags & CHIP_IS_AGP) | 2999 | else if (dev_priv->flags & RADEON_IS_AGP) |
2995 | value = RADEON_CARD_AGP; | 3000 | value = RADEON_CARD_AGP; |
2996 | else | 3001 | else |
2997 | value = RADEON_CARD_PCI; | 3002 | value = RADEON_CARD_PCI; |
2998 | break; | 3003 | break; |
2999 | default: | 3004 | default: |
3005 | DRM_DEBUG("Invalid parameter %d\n", param.param); | ||
3000 | return DRM_ERR(EINVAL); | 3006 | return DRM_ERR(EINVAL); |
3001 | } | 3007 | } |
3002 | 3008 | ||
diff --git a/drivers/char/drm/sis_drv.c b/drivers/char/drm/sis_drv.c index 5e9dc86f2956..3d5b3218b6ff 100644 --- a/drivers/char/drm/sis_drv.c +++ b/drivers/char/drm/sis_drv.c | |||
@@ -35,11 +35,44 @@ static struct pci_device_id pciidlist[] = { | |||
35 | sisdrv_PCI_IDS | 35 | sisdrv_PCI_IDS |
36 | }; | 36 | }; |
37 | 37 | ||
38 | static int sis_driver_load(drm_device_t *dev, unsigned long chipset) | ||
39 | { | ||
40 | drm_sis_private_t *dev_priv; | ||
41 | int ret; | ||
42 | |||
43 | dev_priv = drm_calloc(1, sizeof(drm_sis_private_t), DRM_MEM_DRIVER); | ||
44 | if (dev_priv == NULL) | ||
45 | return DRM_ERR(ENOMEM); | ||
46 | |||
47 | dev->dev_private = (void *)dev_priv; | ||
48 | dev_priv->chipset = chipset; | ||
49 | ret = drm_sman_init(&dev_priv->sman, 2, 12, 8); | ||
50 | if (ret) { | ||
51 | drm_free(dev_priv, sizeof(dev_priv), DRM_MEM_DRIVER); | ||
52 | } | ||
53 | |||
54 | return ret; | ||
55 | } | ||
56 | |||
57 | static int sis_driver_unload(drm_device_t *dev) | ||
58 | { | ||
59 | drm_sis_private_t *dev_priv = dev->dev_private; | ||
60 | |||
61 | drm_sman_takedown(&dev_priv->sman); | ||
62 | drm_free(dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER); | ||
63 | |||
64 | return 0; | ||
65 | } | ||
66 | |||
38 | static struct drm_driver driver = { | 67 | static struct drm_driver driver = { |
39 | .driver_features = DRIVER_USE_AGP | DRIVER_USE_MTRR, | 68 | .driver_features = DRIVER_USE_AGP | DRIVER_USE_MTRR, |
40 | .context_ctor = sis_init_context, | 69 | .load = sis_driver_load, |
41 | .context_dtor = sis_final_context, | 70 | .unload = sis_driver_unload, |
42 | .reclaim_buffers = drm_core_reclaim_buffers, | 71 | .context_dtor = NULL, |
72 | .dma_quiescent = sis_idle, | ||
73 | .reclaim_buffers = NULL, | ||
74 | .reclaim_buffers_locked = sis_reclaim_buffers_locked, | ||
75 | .lastclose = sis_lastclose, | ||
43 | .get_map_ofs = drm_core_get_map_ofs, | 76 | .get_map_ofs = drm_core_get_map_ofs, |
44 | .get_reg_ofs = drm_core_get_reg_ofs, | 77 | .get_reg_ofs = drm_core_get_reg_ofs, |
45 | .ioctls = sis_ioctls, | 78 | .ioctls = sis_ioctls, |
diff --git a/drivers/char/drm/sis_drv.h b/drivers/char/drm/sis_drv.h index e218e5269503..2b8d6f6ed7c0 100644 --- a/drivers/char/drm/sis_drv.h +++ b/drivers/char/drm/sis_drv.h | |||
@@ -31,23 +31,39 @@ | |||
31 | /* General customization: | 31 | /* General customization: |
32 | */ | 32 | */ |
33 | 33 | ||
34 | #define DRIVER_AUTHOR "SIS" | 34 | #define DRIVER_AUTHOR "SIS, Tungsten Graphics" |
35 | #define DRIVER_NAME "sis" | 35 | #define DRIVER_NAME "sis" |
36 | #define DRIVER_DESC "SIS 300/630/540" | 36 | #define DRIVER_DESC "SIS 300/630/540" |
37 | #define DRIVER_DATE "20030826" | 37 | #define DRIVER_DATE "20060704" |
38 | #define DRIVER_MAJOR 1 | 38 | #define DRIVER_MAJOR 1 |
39 | #define DRIVER_MINOR 1 | 39 | #define DRIVER_MINOR 2 |
40 | #define DRIVER_PATCHLEVEL 0 | 40 | #define DRIVER_PATCHLEVEL 1 |
41 | 41 | ||
42 | #include "sis_ds.h" | 42 | enum sis_family { |
43 | SIS_OTHER = 0, | ||
44 | SIS_CHIP_315 = 1, | ||
45 | }; | ||
46 | |||
47 | #include "drm_sman.h" | ||
48 | |||
49 | #define SIS_BASE (dev_priv->mmio) | ||
50 | #define SIS_READ(reg) DRM_READ32(SIS_BASE, reg); | ||
51 | #define SIS_WRITE(reg, val) DRM_WRITE32(SIS_BASE, reg, val); | ||
43 | 52 | ||
44 | typedef struct drm_sis_private { | 53 | typedef struct drm_sis_private { |
45 | memHeap_t *AGPHeap; | 54 | drm_local_map_t *mmio; |
46 | memHeap_t *FBHeap; | 55 | unsigned int idle_fault; |
56 | drm_sman_t sman; | ||
57 | unsigned int chipset; | ||
58 | int vram_initialized; | ||
59 | int agp_initialized; | ||
60 | unsigned long vram_offset; | ||
61 | unsigned long agp_offset; | ||
47 | } drm_sis_private_t; | 62 | } drm_sis_private_t; |
48 | 63 | ||
49 | extern int sis_init_context(drm_device_t * dev, int context); | 64 | extern int sis_idle(drm_device_t *dev); |
50 | extern int sis_final_context(drm_device_t * dev, int context); | 65 | extern void sis_reclaim_buffers_locked(drm_device_t *dev, struct file *filp); |
66 | extern void sis_lastclose(drm_device_t *dev); | ||
51 | 67 | ||
52 | extern drm_ioctl_desc_t sis_ioctls[]; | 68 | extern drm_ioctl_desc_t sis_ioctls[]; |
53 | extern int sis_max_ioctl; | 69 | extern int sis_max_ioctl; |
diff --git a/drivers/char/drm/sis_ds.c b/drivers/char/drm/sis_ds.c deleted file mode 100644 index 2e485d482943..000000000000 --- a/drivers/char/drm/sis_ds.c +++ /dev/null | |||
@@ -1,299 +0,0 @@ | |||
1 | /* sis_ds.c -- Private header for Direct Rendering Manager -*- linux-c -*- | ||
2 | * Created: Mon Jan 4 10:05:05 1999 by sclin@sis.com.tw | ||
3 | * | ||
4 | * Copyright 2000 Silicon Integrated Systems Corp, Inc., HsinChu, Taiwan. | ||
5 | * All rights reserved. | ||
6 | * | ||
7 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
8 | * copy of this software and associated documentation files (the "Software"), | ||
9 | * to deal in the Software without restriction, including without limitation | ||
10 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
11 | * and/or sell copies of the Software, and to permit persons to whom the | ||
12 | * Software is furnished to do so, subject to the following conditions: | ||
13 | * | ||
14 | * The above copyright notice and this permission notice (including the next | ||
15 | * paragraph) shall be included in all copies or substantial portions of the | ||
16 | * Software. | ||
17 | * | ||
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
21 | * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
22 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
23 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
24 | * DEALINGS IN THE SOFTWARE. | ||
25 | * | ||
26 | * Authors: | ||
27 | * Sung-Ching Lin <sclin@sis.com.tw> | ||
28 | * | ||
29 | */ | ||
30 | |||
31 | #include "drmP.h" | ||
32 | #include "drm.h" | ||
33 | #include "sis_ds.h" | ||
34 | |||
35 | /* Set Data Structure, not check repeated value | ||
36 | * temporarily used | ||
37 | */ | ||
38 | |||
39 | set_t *setInit(void) | ||
40 | { | ||
41 | int i; | ||
42 | set_t *set; | ||
43 | |||
44 | set = (set_t *) drm_alloc(sizeof(set_t), DRM_MEM_DRIVER); | ||
45 | if (set != NULL) { | ||
46 | for (i = 0; i < SET_SIZE; i++) { | ||
47 | set->list[i].free_next = i + 1; | ||
48 | set->list[i].alloc_next = -1; | ||
49 | } | ||
50 | set->list[SET_SIZE - 1].free_next = -1; | ||
51 | set->free = 0; | ||
52 | set->alloc = -1; | ||
53 | set->trace = -1; | ||
54 | } | ||
55 | return set; | ||
56 | } | ||
57 | |||
58 | int setAdd(set_t * set, ITEM_TYPE item) | ||
59 | { | ||
60 | int free = set->free; | ||
61 | |||
62 | if (free != -1) { | ||
63 | set->list[free].val = item; | ||
64 | set->free = set->list[free].free_next; | ||
65 | } else { | ||
66 | return 0; | ||
67 | } | ||
68 | |||
69 | set->list[free].alloc_next = set->alloc; | ||
70 | set->alloc = free; | ||
71 | set->list[free].free_next = -1; | ||
72 | |||
73 | return 1; | ||
74 | } | ||
75 | |||
76 | int setDel(set_t * set, ITEM_TYPE item) | ||
77 | { | ||
78 | int alloc = set->alloc; | ||
79 | int prev = -1; | ||
80 | |||
81 | while (alloc != -1) { | ||
82 | if (set->list[alloc].val == item) { | ||
83 | if (prev != -1) | ||
84 | set->list[prev].alloc_next = | ||
85 | set->list[alloc].alloc_next; | ||
86 | else | ||
87 | set->alloc = set->list[alloc].alloc_next; | ||
88 | break; | ||
89 | } | ||
90 | prev = alloc; | ||
91 | alloc = set->list[alloc].alloc_next; | ||
92 | } | ||
93 | |||
94 | if (alloc == -1) | ||
95 | return 0; | ||
96 | |||
97 | set->list[alloc].free_next = set->free; | ||
98 | set->free = alloc; | ||
99 | set->list[alloc].alloc_next = -1; | ||
100 | |||
101 | return 1; | ||
102 | } | ||
103 | |||
104 | /* setFirst -> setAdd -> setNext is wrong */ | ||
105 | |||
106 | int setFirst(set_t * set, ITEM_TYPE * item) | ||
107 | { | ||
108 | if (set->alloc == -1) | ||
109 | return 0; | ||
110 | |||
111 | *item = set->list[set->alloc].val; | ||
112 | set->trace = set->list[set->alloc].alloc_next; | ||
113 | |||
114 | return 1; | ||
115 | } | ||
116 | |||
117 | int setNext(set_t * set, ITEM_TYPE * item) | ||
118 | { | ||
119 | if (set->trace == -1) | ||
120 | return 0; | ||
121 | |||
122 | *item = set->list[set->trace].val; | ||
123 | set->trace = set->list[set->trace].alloc_next; | ||
124 | |||
125 | return 1; | ||
126 | } | ||
127 | |||
128 | int setDestroy(set_t * set) | ||
129 | { | ||
130 | drm_free(set, sizeof(set_t), DRM_MEM_DRIVER); | ||
131 | |||
132 | return 1; | ||
133 | } | ||
134 | |||
135 | /* | ||
136 | * GLX Hardware Device Driver common code | ||
137 | * Copyright (C) 1999 Wittawat Yamwong | ||
138 | * | ||
139 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
140 | * copy of this software and associated documentation files (the "Software"), | ||
141 | * to deal in the Software without restriction, including without limitation | ||
142 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
143 | * and/or sell copies of the Software, and to permit persons to whom the | ||
144 | * Software is furnished to do so, subject to the following conditions: | ||
145 | * | ||
146 | * The above copyright notice and this permission notice shall be included | ||
147 | * in all copies or substantial portions of the Software. | ||
148 | * | ||
149 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | ||
150 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
151 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
152 | * WITTAWAT YAMWONG, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM, | ||
153 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR | ||
154 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE | ||
155 | * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
156 | * | ||
157 | */ | ||
158 | |||
159 | #define ISFREE(bptr) ((bptr)->free) | ||
160 | |||
161 | memHeap_t *mmInit(int ofs, int size) | ||
162 | { | ||
163 | PMemBlock blocks; | ||
164 | |||
165 | if (size <= 0) | ||
166 | return NULL; | ||
167 | |||
168 | blocks = (TMemBlock *) drm_calloc(1, sizeof(TMemBlock), DRM_MEM_DRIVER); | ||
169 | if (blocks != NULL) { | ||
170 | blocks->ofs = ofs; | ||
171 | blocks->size = size; | ||
172 | blocks->free = 1; | ||
173 | return (memHeap_t *) blocks; | ||
174 | } else | ||
175 | return NULL; | ||
176 | } | ||
177 | |||
178 | /* Checks if a pointer 'b' is part of the heap 'heap' */ | ||
179 | int mmBlockInHeap(memHeap_t * heap, PMemBlock b) | ||
180 | { | ||
181 | TMemBlock *p; | ||
182 | |||
183 | if (heap == NULL || b == NULL) | ||
184 | return 0; | ||
185 | |||
186 | p = heap; | ||
187 | while (p != NULL && p != b) { | ||
188 | p = p->next; | ||
189 | } | ||
190 | if (p == b) | ||
191 | return 1; | ||
192 | else | ||
193 | return 0; | ||
194 | } | ||
195 | |||
196 | static TMemBlock *SliceBlock(TMemBlock * p, | ||
197 | int startofs, int size, | ||
198 | int reserved, int alignment) | ||
199 | { | ||
200 | TMemBlock *newblock; | ||
201 | |||
202 | /* break left */ | ||
203 | if (startofs > p->ofs) { | ||
204 | newblock = (TMemBlock *) drm_calloc(1, sizeof(TMemBlock), | ||
205 | DRM_MEM_DRIVER); | ||
206 | newblock->ofs = startofs; | ||
207 | newblock->size = p->size - (startofs - p->ofs); | ||
208 | newblock->free = 1; | ||
209 | newblock->next = p->next; | ||
210 | p->size -= newblock->size; | ||
211 | p->next = newblock; | ||
212 | p = newblock; | ||
213 | } | ||
214 | |||
215 | /* break right */ | ||
216 | if (size < p->size) { | ||
217 | newblock = (TMemBlock *) drm_calloc(1, sizeof(TMemBlock), | ||
218 | DRM_MEM_DRIVER); | ||
219 | newblock->ofs = startofs + size; | ||
220 | newblock->size = p->size - size; | ||
221 | newblock->free = 1; | ||
222 | newblock->next = p->next; | ||
223 | p->size = size; | ||
224 | p->next = newblock; | ||
225 | } | ||
226 | |||
227 | /* p = middle block */ | ||
228 | p->align = alignment; | ||
229 | p->free = 0; | ||
230 | p->reserved = reserved; | ||
231 | return p; | ||
232 | } | ||
233 | |||
234 | PMemBlock mmAllocMem(memHeap_t * heap, int size, int align2, int startSearch) | ||
235 | { | ||
236 | int mask, startofs, endofs; | ||
237 | TMemBlock *p; | ||
238 | |||
239 | if (heap == NULL || align2 < 0 || size <= 0) | ||
240 | return NULL; | ||
241 | |||
242 | mask = (1 << align2) - 1; | ||
243 | startofs = 0; | ||
244 | p = (TMemBlock *) heap; | ||
245 | while (p != NULL) { | ||
246 | if (ISFREE(p)) { | ||
247 | startofs = (p->ofs + mask) & ~mask; | ||
248 | if (startofs < startSearch) { | ||
249 | startofs = startSearch; | ||
250 | } | ||
251 | endofs = startofs + size; | ||
252 | if (endofs <= (p->ofs + p->size)) | ||
253 | break; | ||
254 | } | ||
255 | p = p->next; | ||
256 | } | ||
257 | if (p == NULL) | ||
258 | return NULL; | ||
259 | p = SliceBlock(p, startofs, size, 0, mask + 1); | ||
260 | p->heap = heap; | ||
261 | return p; | ||
262 | } | ||
263 | |||
264 | static __inline__ int Join2Blocks(TMemBlock * p) | ||
265 | { | ||
266 | if (p->free && p->next && p->next->free) { | ||
267 | TMemBlock *q = p->next; | ||
268 | p->size += q->size; | ||
269 | p->next = q->next; | ||
270 | drm_free(q, sizeof(TMemBlock), DRM_MEM_DRIVER); | ||
271 | return 1; | ||
272 | } | ||
273 | return 0; | ||
274 | } | ||
275 | |||
276 | int mmFreeMem(PMemBlock b) | ||
277 | { | ||
278 | TMemBlock *p, *prev; | ||
279 | |||
280 | if (b == NULL) | ||
281 | return 0; | ||
282 | if (b->heap == NULL) | ||
283 | return -1; | ||
284 | |||
285 | p = b->heap; | ||
286 | prev = NULL; | ||
287 | while (p != NULL && p != b) { | ||
288 | prev = p; | ||
289 | p = p->next; | ||
290 | } | ||
291 | if (p == NULL || p->free || p->reserved) | ||
292 | return -1; | ||
293 | |||
294 | p->free = 1; | ||
295 | Join2Blocks(p); | ||
296 | if (prev) | ||
297 | Join2Blocks(prev); | ||
298 | return 0; | ||
299 | } | ||
diff --git a/drivers/char/drm/sis_ds.h b/drivers/char/drm/sis_ds.h deleted file mode 100644 index 94f2b4728b63..000000000000 --- a/drivers/char/drm/sis_ds.h +++ /dev/null | |||
@@ -1,146 +0,0 @@ | |||
1 | /* sis_ds.h -- Private header for Direct Rendering Manager -*- linux-c -*- | ||
2 | * Created: Mon Jan 4 10:05:05 1999 by sclin@sis.com.tw | ||
3 | */ | ||
4 | /* | ||
5 | * Copyright 2000 Silicon Integrated Systems Corp, Inc., HsinChu, Taiwan. | ||
6 | * All rights reserved. | ||
7 | * | ||
8 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
9 | * copy of this software and associated documentation files (the "Software"), | ||
10 | * to deal in the Software without restriction, including without limitation | ||
11 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
12 | * and/or sell copies of the Software, and to permit persons to whom the | ||
13 | * Software is furnished to do so, subject to the following conditions: | ||
14 | * | ||
15 | * The above copyright notice and this permission notice (including the next | ||
16 | * paragraph) shall be included in all copies or substantial portions of the | ||
17 | * Software. | ||
18 | * | ||
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
22 | * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
23 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
24 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
25 | * DEALINGS IN THE SOFTWARE. | ||
26 | * | ||
27 | * Authors: | ||
28 | * Sung-Ching Lin <sclin@sis.com.tw> | ||
29 | * | ||
30 | */ | ||
31 | |||
32 | #ifndef __SIS_DS_H__ | ||
33 | #define __SIS_DS_H__ | ||
34 | |||
35 | /* Set Data Structure */ | ||
36 | |||
37 | #define SET_SIZE 5000 | ||
38 | |||
39 | typedef unsigned long ITEM_TYPE; | ||
40 | |||
41 | typedef struct { | ||
42 | ITEM_TYPE val; | ||
43 | int alloc_next, free_next; | ||
44 | } list_item_t; | ||
45 | |||
46 | typedef struct { | ||
47 | int alloc; | ||
48 | int free; | ||
49 | int trace; | ||
50 | list_item_t list[SET_SIZE]; | ||
51 | } set_t; | ||
52 | |||
53 | set_t *setInit(void); | ||
54 | int setAdd(set_t * set, ITEM_TYPE item); | ||
55 | int setDel(set_t * set, ITEM_TYPE item); | ||
56 | int setFirst(set_t * set, ITEM_TYPE * item); | ||
57 | int setNext(set_t * set, ITEM_TYPE * item); | ||
58 | int setDestroy(set_t * set); | ||
59 | |||
60 | /* | ||
61 | * GLX Hardware Device Driver common code | ||
62 | * Copyright (C) 1999 Wittawat Yamwong | ||
63 | * | ||
64 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
65 | * copy of this software and associated documentation files (the "Software"), | ||
66 | * to deal in the Software without restriction, including without limitation | ||
67 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
68 | * and/or sell copies of the Software, and to permit persons to whom the | ||
69 | * Software is furnished to do so, subject to the following conditions: | ||
70 | * | ||
71 | * The above copyright notice and this permission notice shall be included | ||
72 | * in all copies or substantial portions of the Software. | ||
73 | * | ||
74 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | ||
75 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
76 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
77 | * WITTAWAT YAMWONG, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM, | ||
78 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR | ||
79 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE | ||
80 | * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
81 | * | ||
82 | */ | ||
83 | |||
84 | struct mem_block_t { | ||
85 | struct mem_block_t *next; | ||
86 | struct mem_block_t *heap; | ||
87 | int ofs, size; | ||
88 | int align; | ||
89 | unsigned int free:1; | ||
90 | unsigned int reserved:1; | ||
91 | }; | ||
92 | typedef struct mem_block_t TMemBlock; | ||
93 | typedef struct mem_block_t *PMemBlock; | ||
94 | |||
95 | /* a heap is just the first block in a chain */ | ||
96 | typedef struct mem_block_t memHeap_t; | ||
97 | |||
98 | static __inline__ int mmBlockSize(PMemBlock b) | ||
99 | { | ||
100 | return b->size; | ||
101 | } | ||
102 | |||
103 | static __inline__ int mmOffset(PMemBlock b) | ||
104 | { | ||
105 | return b->ofs; | ||
106 | } | ||
107 | |||
108 | static __inline__ void mmMarkReserved(PMemBlock b) | ||
109 | { | ||
110 | b->reserved = 1; | ||
111 | } | ||
112 | |||
113 | /* | ||
114 | * input: total size in bytes | ||
115 | * return: a heap pointer if OK, NULL if error | ||
116 | */ | ||
117 | memHeap_t *mmInit(int ofs, int size); | ||
118 | |||
119 | /* | ||
120 | * Allocate 'size' bytes with 2^align2 bytes alignment, | ||
121 | * restrict the search to free memory after 'startSearch' | ||
122 | * depth and back buffers should be in different 4mb banks | ||
123 | * to get better page hits if possible | ||
124 | * input: size = size of block | ||
125 | * align2 = 2^align2 bytes alignment | ||
126 | * startSearch = linear offset from start of heap to begin search | ||
127 | * return: pointer to the allocated block, 0 if error | ||
128 | */ | ||
129 | PMemBlock mmAllocMem(memHeap_t * heap, int size, int align2, int startSearch); | ||
130 | |||
131 | /* | ||
132 | * Returns 1 if the block 'b' is part of the heap 'heap' | ||
133 | */ | ||
134 | int mmBlockInHeap(PMemBlock heap, PMemBlock b); | ||
135 | |||
136 | /* | ||
137 | * Free block starts at offset | ||
138 | * input: pointer to a block | ||
139 | * return: 0 if OK, -1 if error | ||
140 | */ | ||
141 | int mmFreeMem(PMemBlock b); | ||
142 | |||
143 | /* For debuging purpose. */ | ||
144 | void mmDumpMemInfo(memHeap_t * mmInit); | ||
145 | |||
146 | #endif /* __SIS_DS_H__ */ | ||
diff --git a/drivers/char/drm/sis_mm.c b/drivers/char/drm/sis_mm.c index 5e9936bc307f..d26f5dbb7853 100644 --- a/drivers/char/drm/sis_mm.c +++ b/drivers/char/drm/sis_mm.c | |||
@@ -1,414 +1,348 @@ | |||
1 | /* sis_mm.c -- Private header for Direct Rendering Manager -*- linux-c -*- | 1 | /************************************************************************** |
2 | * Created: Mon Jan 4 10:05:05 1999 by sclin@sis.com.tw | ||
3 | * | 2 | * |
4 | * Copyright 2000 Silicon Integrated Systems Corp, Inc., HsinChu, Taiwan. | 3 | * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND., USA. |
5 | * All rights reserved. | 4 | * All Rights Reserved. |
6 | * | 5 | * |
7 | * Permission is hereby granted, free of charge, to any person obtaining a | 6 | * Permission is hereby granted, free of charge, to any person obtaining a |
8 | * copy of this software and associated documentation files (the "Software"), | 7 | * copy of this software and associated documentation files (the |
9 | * to deal in the Software without restriction, including without limitation | 8 | * "Software"), to deal in the Software without restriction, including |
10 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | 9 | * without limitation the rights to use, copy, modify, merge, publish, |
11 | * and/or sell copies of the Software, and to permit persons to whom the | 10 | * distribute, sub license, and/or sell copies of the Software, and to |
12 | * Software is furnished to do so, subject to the following conditions: | 11 | * permit persons to whom the Software is furnished to do so, subject to |
12 | * the following conditions: | ||
13 | * | 13 | * |
14 | * The above copyright notice and this permission notice (including the next | 14 | * The above copyright notice and this permission notice (including the |
15 | * paragraph) shall be included in all copies or substantial portions of the | 15 | * next paragraph) shall be included in all copies or substantial portions |
16 | * Software. | 16 | * of the Software. |
17 | * | 17 | * |
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL |
21 | * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR | 21 | * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, |
22 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | 22 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR |
23 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | 23 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE |
24 | * DEALINGS IN THE SOFTWARE. | 24 | * USE OR OTHER DEALINGS IN THE SOFTWARE. |
25 | * | 25 | * |
26 | * Authors: | ||
27 | * Sung-Ching Lin <sclin@sis.com.tw> | ||
28 | * | 26 | * |
27 | **************************************************************************/ | ||
28 | |||
29 | /* | ||
30 | * Authors: | ||
31 | * Thomas Hellström <thomas-at-tungstengraphics-dot-com> | ||
29 | */ | 32 | */ |
30 | 33 | ||
31 | #include "drmP.h" | 34 | #include "drmP.h" |
32 | #include "sis_drm.h" | 35 | #include "sis_drm.h" |
33 | #include "sis_drv.h" | 36 | #include "sis_drv.h" |
34 | #include "sis_ds.h" | 37 | |
35 | #if defined(__linux__) && defined(CONFIG_FB_SIS) | ||
36 | #include <video/sisfb.h> | 38 | #include <video/sisfb.h> |
37 | #endif | ||
38 | 39 | ||
39 | #define MAX_CONTEXT 100 | ||
40 | #define VIDEO_TYPE 0 | 40 | #define VIDEO_TYPE 0 |
41 | #define AGP_TYPE 1 | 41 | #define AGP_TYPE 1 |
42 | 42 | ||
43 | typedef struct { | ||
44 | int used; | ||
45 | int context; | ||
46 | set_t *sets[2]; /* 0 for video, 1 for AGP */ | ||
47 | } sis_context_t; | ||
48 | 43 | ||
49 | static sis_context_t global_ppriv[MAX_CONTEXT]; | 44 | #if defined(CONFIG_FB_SIS) |
45 | /* fb management via fb device */ | ||
50 | 46 | ||
51 | static int add_alloc_set(int context, int type, unsigned int val) | 47 | #define SIS_MM_ALIGN_SHIFT 0 |
52 | { | 48 | #define SIS_MM_ALIGN_MASK 0 |
53 | int i, retval = 0; | ||
54 | 49 | ||
55 | for (i = 0; i < MAX_CONTEXT; i++) { | 50 | static void *sis_sman_mm_allocate(void *private, unsigned long size, |
56 | if (global_ppriv[i].used && global_ppriv[i].context == context) { | 51 | unsigned alignment) |
57 | retval = setAdd(global_ppriv[i].sets[type], val); | ||
58 | break; | ||
59 | } | ||
60 | } | ||
61 | return retval; | ||
62 | } | ||
63 | |||
64 | static int del_alloc_set(int context, int type, unsigned int val) | ||
65 | { | 52 | { |
66 | int i, retval = 0; | 53 | struct sis_memreq req; |
67 | 54 | ||
68 | for (i = 0; i < MAX_CONTEXT; i++) { | 55 | req.size = size; |
69 | if (global_ppriv[i].used && global_ppriv[i].context == context) { | 56 | sis_malloc(&req); |
70 | retval = setDel(global_ppriv[i].sets[type], val); | 57 | if (req.size == 0) |
71 | break; | 58 | return NULL; |
72 | } | 59 | else |
73 | } | 60 | return (void *)~req.offset; |
74 | return retval; | ||
75 | } | 61 | } |
76 | 62 | ||
77 | /* fb management via fb device */ | 63 | static void sis_sman_mm_free(void *private, void *ref) |
78 | #if defined(__linux__) && defined(CONFIG_FB_SIS) | ||
79 | |||
80 | static int sis_fb_init(DRM_IOCTL_ARGS) | ||
81 | { | 64 | { |
82 | return 0; | 65 | sis_free(~((unsigned long)ref)); |
83 | } | 66 | } |
84 | 67 | ||
85 | static int sis_fb_alloc(DRM_IOCTL_ARGS) | 68 | static void sis_sman_mm_destroy(void *private) |
86 | { | 69 | { |
87 | drm_sis_mem_t fb; | 70 | ; |
88 | struct sis_memreq req; | ||
89 | drm_sis_mem_t __user *argp = (drm_sis_mem_t __user *)data; | ||
90 | int retval = 0; | ||
91 | |||
92 | DRM_COPY_FROM_USER_IOCTL(fb, argp, sizeof(fb)); | ||
93 | |||
94 | req.size = fb.size; | ||
95 | sis_malloc(&req); | ||
96 | if (req.offset) { | ||
97 | /* TODO */ | ||
98 | fb.offset = req.offset; | ||
99 | fb.free = req.offset; | ||
100 | if (!add_alloc_set(fb.context, VIDEO_TYPE, fb.free)) { | ||
101 | DRM_DEBUG("adding to allocation set fails\n"); | ||
102 | sis_free(req.offset); | ||
103 | retval = DRM_ERR(EINVAL); | ||
104 | } | ||
105 | } else { | ||
106 | fb.offset = 0; | ||
107 | fb.size = 0; | ||
108 | fb.free = 0; | ||
109 | } | ||
110 | |||
111 | DRM_COPY_TO_USER_IOCTL(argp, fb, sizeof(fb)); | ||
112 | |||
113 | DRM_DEBUG("alloc fb, size = %d, offset = %d\n", fb.size, req.offset); | ||
114 | |||
115 | return retval; | ||
116 | } | 71 | } |
117 | 72 | ||
118 | static int sis_fb_free(DRM_IOCTL_ARGS) | 73 | static unsigned long sis_sman_mm_offset(void *private, void *ref) |
119 | { | 74 | { |
120 | drm_sis_mem_t fb; | 75 | return ~((unsigned long)ref); |
121 | int retval = 0; | 76 | } |
122 | |||
123 | DRM_COPY_FROM_USER_IOCTL(fb, (drm_sis_mem_t __user *) data, sizeof(fb)); | ||
124 | |||
125 | if (!fb.free) | ||
126 | return DRM_ERR(EINVAL); | ||
127 | 77 | ||
128 | if (!del_alloc_set(fb.context, VIDEO_TYPE, fb.free)) | 78 | #else /* CONFIG_FB_SIS */ |
129 | retval = DRM_ERR(EINVAL); | ||
130 | sis_free(fb.free); | ||
131 | 79 | ||
132 | DRM_DEBUG("free fb, offset = 0x%lx\n", fb.free); | 80 | #define SIS_MM_ALIGN_SHIFT 4 |
81 | #define SIS_MM_ALIGN_MASK ( (1 << SIS_MM_ALIGN_SHIFT) - 1) | ||
133 | 82 | ||
134 | return retval; | 83 | #endif /* CONFIG_FB_SIS */ |
135 | } | ||
136 | 84 | ||
137 | #else | ||
138 | |||
139 | /* Called by the X Server to initialize the FB heap. Allocations will fail | ||
140 | * unless this is called. Offset is the beginning of the heap from the | ||
141 | * framebuffer offset (MaxXFBMem in XFree86). | ||
142 | * | ||
143 | * Memory layout according to Thomas Winischofer: | ||
144 | * |------------------|DDDDDDDDDDDDDDDDDDDDDDDDDDDDD|HHHH|CCCCCCCCCCC| | ||
145 | * | ||
146 | * X driver/sisfb HW- Command- | ||
147 | * framebuffer memory DRI heap Cursor queue | ||
148 | */ | ||
149 | static int sis_fb_init(DRM_IOCTL_ARGS) | 85 | static int sis_fb_init(DRM_IOCTL_ARGS) |
150 | { | 86 | { |
151 | DRM_DEVICE; | 87 | DRM_DEVICE; |
152 | drm_sis_private_t *dev_priv = dev->dev_private; | 88 | drm_sis_private_t *dev_priv = dev->dev_private; |
153 | drm_sis_fb_t fb; | 89 | drm_sis_fb_t fb; |
90 | int ret; | ||
154 | 91 | ||
155 | DRM_COPY_FROM_USER_IOCTL(fb, (drm_sis_fb_t __user *) data, sizeof(fb)); | 92 | DRM_COPY_FROM_USER_IOCTL(fb, (drm_sis_fb_t __user *) data, sizeof(fb)); |
156 | 93 | ||
157 | if (dev_priv == NULL) { | 94 | mutex_lock(&dev->struct_mutex); |
158 | dev->dev_private = drm_calloc(1, sizeof(drm_sis_private_t), | 95 | #if defined(CONFIG_FB_SIS) |
159 | DRM_MEM_DRIVER); | 96 | { |
160 | dev_priv = dev->dev_private; | 97 | drm_sman_mm_t sman_mm; |
161 | if (dev_priv == NULL) | 98 | sman_mm.private = (void *)0xFFFFFFFF; |
162 | return ENOMEM; | 99 | sman_mm.allocate = sis_sman_mm_allocate; |
100 | sman_mm.free = sis_sman_mm_free; | ||
101 | sman_mm.destroy = sis_sman_mm_destroy; | ||
102 | sman_mm.offset = sis_sman_mm_offset; | ||
103 | ret = | ||
104 | drm_sman_set_manager(&dev_priv->sman, VIDEO_TYPE, &sman_mm); | ||
163 | } | 105 | } |
106 | #else | ||
107 | ret = drm_sman_set_range(&dev_priv->sman, VIDEO_TYPE, 0, | ||
108 | fb.size >> SIS_MM_ALIGN_SHIFT); | ||
109 | #endif | ||
164 | 110 | ||
165 | if (dev_priv->FBHeap != NULL) | 111 | if (ret) { |
166 | return DRM_ERR(EINVAL); | 112 | DRM_ERROR("VRAM memory manager initialisation error\n"); |
113 | mutex_unlock(&dev->struct_mutex); | ||
114 | return ret; | ||
115 | } | ||
167 | 116 | ||
168 | dev_priv->FBHeap = mmInit(fb.offset, fb.size); | 117 | dev_priv->vram_initialized = 1; |
118 | dev_priv->vram_offset = fb.offset; | ||
169 | 119 | ||
120 | mutex_unlock(&dev->struct_mutex); | ||
170 | DRM_DEBUG("offset = %u, size = %u", fb.offset, fb.size); | 121 | DRM_DEBUG("offset = %u, size = %u", fb.offset, fb.size); |
171 | 122 | ||
172 | return 0; | 123 | return 0; |
173 | } | 124 | } |
174 | 125 | ||
175 | static int sis_fb_alloc(DRM_IOCTL_ARGS) | 126 | static int sis_drm_alloc(drm_device_t * dev, drm_file_t * priv, |
127 | unsigned long data, int pool) | ||
176 | { | 128 | { |
177 | DRM_DEVICE; | ||
178 | drm_sis_private_t *dev_priv = dev->dev_private; | 129 | drm_sis_private_t *dev_priv = dev->dev_private; |
179 | drm_sis_mem_t __user *argp = (drm_sis_mem_t __user *)data; | 130 | drm_sis_mem_t __user *argp = (drm_sis_mem_t __user *) data; |
180 | drm_sis_mem_t fb; | 131 | drm_sis_mem_t mem; |
181 | PMemBlock block; | ||
182 | int retval = 0; | 132 | int retval = 0; |
133 | drm_memblock_item_t *item; | ||
134 | |||
135 | DRM_COPY_FROM_USER_IOCTL(mem, argp, sizeof(mem)); | ||
183 | 136 | ||
184 | if (dev_priv == NULL || dev_priv->FBHeap == NULL) | 137 | mutex_lock(&dev->struct_mutex); |
138 | |||
139 | if (0 == ((pool == 0) ? dev_priv->vram_initialized : | ||
140 | dev_priv->agp_initialized)) { | ||
141 | DRM_ERROR | ||
142 | ("Attempt to allocate from uninitialized memory manager.\n"); | ||
185 | return DRM_ERR(EINVAL); | 143 | return DRM_ERR(EINVAL); |
144 | } | ||
186 | 145 | ||
187 | DRM_COPY_FROM_USER_IOCTL(fb, argp, sizeof(fb)); | 146 | mem.size = (mem.size + SIS_MM_ALIGN_MASK) >> SIS_MM_ALIGN_SHIFT; |
188 | 147 | item = drm_sman_alloc(&dev_priv->sman, pool, mem.size, 0, | |
189 | block = mmAllocMem(dev_priv->FBHeap, fb.size, 0, 0); | 148 | (unsigned long)priv); |
190 | if (block) { | 149 | |
191 | /* TODO */ | 150 | mutex_unlock(&dev->struct_mutex); |
192 | fb.offset = block->ofs; | 151 | if (item) { |
193 | fb.free = (unsigned long)block; | 152 | mem.offset = ((pool == 0) ? |
194 | if (!add_alloc_set(fb.context, VIDEO_TYPE, fb.free)) { | 153 | dev_priv->vram_offset : dev_priv->agp_offset) + |
195 | DRM_DEBUG("adding to allocation set fails\n"); | 154 | (item->mm-> |
196 | mmFreeMem((PMemBlock) fb.free); | 155 | offset(item->mm, item->mm_info) << SIS_MM_ALIGN_SHIFT); |
197 | retval = DRM_ERR(EINVAL); | 156 | mem.free = item->user_hash.key; |
198 | } | 157 | mem.size = mem.size << SIS_MM_ALIGN_SHIFT; |
199 | } else { | 158 | } else { |
200 | fb.offset = 0; | 159 | mem.offset = 0; |
201 | fb.size = 0; | 160 | mem.size = 0; |
202 | fb.free = 0; | 161 | mem.free = 0; |
162 | retval = DRM_ERR(ENOMEM); | ||
203 | } | 163 | } |
204 | 164 | ||
205 | DRM_COPY_TO_USER_IOCTL(argp, fb, sizeof(fb)); | 165 | DRM_COPY_TO_USER_IOCTL(argp, mem, sizeof(mem)); |
206 | 166 | ||
207 | DRM_DEBUG("alloc fb, size = %d, offset = %d\n", fb.size, fb.offset); | 167 | DRM_DEBUG("alloc %d, size = %d, offset = %d\n", pool, mem.size, |
168 | mem.offset); | ||
208 | 169 | ||
209 | return retval; | 170 | return retval; |
210 | } | 171 | } |
211 | 172 | ||
212 | static int sis_fb_free(DRM_IOCTL_ARGS) | 173 | static int sis_drm_free(DRM_IOCTL_ARGS) |
213 | { | 174 | { |
214 | DRM_DEVICE; | 175 | DRM_DEVICE; |
215 | drm_sis_private_t *dev_priv = dev->dev_private; | 176 | drm_sis_private_t *dev_priv = dev->dev_private; |
216 | drm_sis_mem_t fb; | 177 | drm_sis_mem_t mem; |
178 | int ret; | ||
217 | 179 | ||
218 | if (dev_priv == NULL || dev_priv->FBHeap == NULL) | 180 | DRM_COPY_FROM_USER_IOCTL(mem, (drm_sis_mem_t __user *) data, |
219 | return DRM_ERR(EINVAL); | 181 | sizeof(mem)); |
220 | 182 | ||
221 | DRM_COPY_FROM_USER_IOCTL(fb, (drm_sis_mem_t __user *) data, sizeof(fb)); | 183 | mutex_lock(&dev->struct_mutex); |
184 | ret = drm_sman_free_key(&dev_priv->sman, mem.free); | ||
185 | mutex_unlock(&dev->struct_mutex); | ||
186 | DRM_DEBUG("free = 0x%lx\n", mem.free); | ||
222 | 187 | ||
223 | if (!mmBlockInHeap(dev_priv->FBHeap, (PMemBlock) fb.free)) | 188 | return ret; |
224 | return DRM_ERR(EINVAL); | ||
225 | |||
226 | if (!del_alloc_set(fb.context, VIDEO_TYPE, fb.free)) | ||
227 | return DRM_ERR(EINVAL); | ||
228 | mmFreeMem((PMemBlock) fb.free); | ||
229 | |||
230 | DRM_DEBUG("free fb, free = 0x%lx\n", fb.free); | ||
231 | |||
232 | return 0; | ||
233 | } | 189 | } |
234 | 190 | ||
235 | #endif | 191 | static int sis_fb_alloc(DRM_IOCTL_ARGS) |
236 | 192 | { | |
237 | /* agp memory management */ | 193 | DRM_DEVICE; |
194 | return sis_drm_alloc(dev, priv, data, VIDEO_TYPE); | ||
195 | } | ||
238 | 196 | ||
239 | static int sis_ioctl_agp_init(DRM_IOCTL_ARGS) | 197 | static int sis_ioctl_agp_init(DRM_IOCTL_ARGS) |
240 | { | 198 | { |
241 | DRM_DEVICE; | 199 | DRM_DEVICE; |
242 | drm_sis_private_t *dev_priv = dev->dev_private; | 200 | drm_sis_private_t *dev_priv = dev->dev_private; |
243 | drm_sis_agp_t agp; | 201 | drm_sis_agp_t agp; |
244 | 202 | int ret; | |
245 | if (dev_priv == NULL) { | 203 | dev_priv = dev->dev_private; |
246 | dev->dev_private = drm_calloc(1, sizeof(drm_sis_private_t), | ||
247 | DRM_MEM_DRIVER); | ||
248 | dev_priv = dev->dev_private; | ||
249 | if (dev_priv == NULL) | ||
250 | return ENOMEM; | ||
251 | } | ||
252 | |||
253 | if (dev_priv->AGPHeap != NULL) | ||
254 | return DRM_ERR(EINVAL); | ||
255 | 204 | ||
256 | DRM_COPY_FROM_USER_IOCTL(agp, (drm_sis_agp_t __user *) data, | 205 | DRM_COPY_FROM_USER_IOCTL(agp, (drm_sis_agp_t __user *) data, |
257 | sizeof(agp)); | 206 | sizeof(agp)); |
207 | mutex_lock(&dev->struct_mutex); | ||
208 | ret = drm_sman_set_range(&dev_priv->sman, AGP_TYPE, 0, | ||
209 | agp.size >> SIS_MM_ALIGN_SHIFT); | ||
210 | |||
211 | if (ret) { | ||
212 | DRM_ERROR("AGP memory manager initialisation error\n"); | ||
213 | mutex_unlock(&dev->struct_mutex); | ||
214 | return ret; | ||
215 | } | ||
258 | 216 | ||
259 | dev_priv->AGPHeap = mmInit(agp.offset, agp.size); | 217 | dev_priv->agp_initialized = 1; |
218 | dev_priv->agp_offset = agp.offset; | ||
219 | mutex_unlock(&dev->struct_mutex); | ||
260 | 220 | ||
261 | DRM_DEBUG("offset = %u, size = %u", agp.offset, agp.size); | 221 | DRM_DEBUG("offset = %u, size = %u", agp.offset, agp.size); |
262 | |||
263 | return 0; | 222 | return 0; |
264 | } | 223 | } |
265 | 224 | ||
266 | static int sis_ioctl_agp_alloc(DRM_IOCTL_ARGS) | 225 | static int sis_ioctl_agp_alloc(DRM_IOCTL_ARGS) |
267 | { | 226 | { |
268 | DRM_DEVICE; | 227 | DRM_DEVICE; |
269 | drm_sis_private_t *dev_priv = dev->dev_private; | ||
270 | drm_sis_mem_t __user *argp = (drm_sis_mem_t __user *)data; | ||
271 | drm_sis_mem_t agp; | ||
272 | PMemBlock block; | ||
273 | int retval = 0; | ||
274 | 228 | ||
275 | if (dev_priv == NULL || dev_priv->AGPHeap == NULL) | 229 | return sis_drm_alloc(dev, priv, data, AGP_TYPE); |
276 | return DRM_ERR(EINVAL); | 230 | } |
277 | 231 | ||
278 | DRM_COPY_FROM_USER_IOCTL(agp, argp, sizeof(agp)); | 232 | static drm_local_map_t *sis_reg_init(drm_device_t *dev) |
279 | 233 | { | |
280 | block = mmAllocMem(dev_priv->AGPHeap, agp.size, 0, 0); | 234 | drm_map_list_t *entry; |
281 | if (block) { | 235 | drm_local_map_t *map; |
282 | /* TODO */ | 236 | |
283 | agp.offset = block->ofs; | 237 | list_for_each_entry(entry, &dev->maplist->head, head) { |
284 | agp.free = (unsigned long)block; | 238 | map = entry->map; |
285 | if (!add_alloc_set(agp.context, AGP_TYPE, agp.free)) { | 239 | if (!map) |
286 | DRM_DEBUG("adding to allocation set fails\n"); | 240 | continue; |
287 | mmFreeMem((PMemBlock) agp.free); | 241 | if (map->type == _DRM_REGISTERS) { |
288 | retval = -1; | 242 | return map; |
289 | } | 243 | } |
290 | } else { | ||
291 | agp.offset = 0; | ||
292 | agp.size = 0; | ||
293 | agp.free = 0; | ||
294 | } | 244 | } |
295 | 245 | return NULL; | |
296 | DRM_COPY_TO_USER_IOCTL(argp, agp, sizeof(agp)); | ||
297 | |||
298 | DRM_DEBUG("alloc agp, size = %d, offset = %d\n", agp.size, agp.offset); | ||
299 | |||
300 | return retval; | ||
301 | } | 246 | } |
302 | 247 | ||
303 | static int sis_ioctl_agp_free(DRM_IOCTL_ARGS) | 248 | int sis_idle(drm_device_t *dev) |
304 | { | 249 | { |
305 | DRM_DEVICE; | ||
306 | drm_sis_private_t *dev_priv = dev->dev_private; | 250 | drm_sis_private_t *dev_priv = dev->dev_private; |
307 | drm_sis_mem_t agp; | 251 | uint32_t idle_reg; |
308 | 252 | unsigned long end; | |
309 | if (dev_priv == NULL || dev_priv->AGPHeap == NULL) | 253 | int i; |
310 | return DRM_ERR(EINVAL); | ||
311 | 254 | ||
312 | DRM_COPY_FROM_USER_IOCTL(agp, (drm_sis_mem_t __user *) data, | 255 | if (dev_priv->idle_fault) |
313 | sizeof(agp)); | 256 | return 0; |
314 | 257 | ||
315 | if (!mmBlockInHeap(dev_priv->AGPHeap, (PMemBlock) agp.free)) | 258 | if (dev_priv->mmio == NULL) { |
316 | return DRM_ERR(EINVAL); | 259 | dev_priv->mmio = sis_reg_init(dev); |
260 | if (dev_priv->mmio == NULL) { | ||
261 | DRM_ERROR("Could not find register map.\n"); | ||
262 | return 0; | ||
263 | } | ||
264 | } | ||
265 | |||
266 | /* | ||
267 | * Implement a device switch here if needed | ||
268 | */ | ||
269 | |||
270 | if (dev_priv->chipset != SIS_CHIP_315) | ||
271 | return 0; | ||
272 | |||
273 | /* | ||
274 | * Timeout after 3 seconds. We cannot use DRM_WAIT_ON here | ||
275 | * because its polling frequency is too low. | ||
276 | */ | ||
277 | |||
278 | end = jiffies + (DRM_HZ * 3); | ||
279 | |||
280 | for (i=0; i<4; ++i) { | ||
281 | do { | ||
282 | idle_reg = SIS_READ(0x85cc); | ||
283 | } while ( !time_after_eq(jiffies, end) && | ||
284 | ((idle_reg & 0x80000000) != 0x80000000)); | ||
285 | } | ||
317 | 286 | ||
318 | mmFreeMem((PMemBlock) agp.free); | 287 | if (time_after_eq(jiffies, end)) { |
319 | if (!del_alloc_set(agp.context, AGP_TYPE, agp.free)) | 288 | DRM_ERROR("Graphics engine idle timeout. " |
320 | return DRM_ERR(EINVAL); | 289 | "Disabling idle check\n"); |
290 | dev_priv->idle_fault = 1; | ||
291 | } | ||
321 | 292 | ||
322 | DRM_DEBUG("free agp, free = 0x%lx\n", agp.free); | 293 | /* |
294 | * The caller never sees an error code. It gets trapped | ||
295 | * in libdrm. | ||
296 | */ | ||
323 | 297 | ||
324 | return 0; | 298 | return 0; |
325 | } | 299 | } |
326 | 300 | ||
327 | int sis_init_context(struct drm_device *dev, int context) | ||
328 | { | ||
329 | int i; | ||
330 | 301 | ||
331 | for (i = 0; i < MAX_CONTEXT; i++) { | 302 | void sis_lastclose(struct drm_device *dev) |
332 | if (global_ppriv[i].used && | 303 | { |
333 | (global_ppriv[i].context == context)) | 304 | drm_sis_private_t *dev_priv = dev->dev_private; |
334 | break; | ||
335 | } | ||
336 | 305 | ||
337 | if (i >= MAX_CONTEXT) { | 306 | if (!dev_priv) |
338 | for (i = 0; i < MAX_CONTEXT; i++) { | 307 | return; |
339 | if (!global_ppriv[i].used) { | ||
340 | global_ppriv[i].context = context; | ||
341 | global_ppriv[i].used = 1; | ||
342 | global_ppriv[i].sets[0] = setInit(); | ||
343 | global_ppriv[i].sets[1] = setInit(); | ||
344 | DRM_DEBUG("init allocation set, socket=%d, " | ||
345 | "context = %d\n", i, context); | ||
346 | break; | ||
347 | } | ||
348 | } | ||
349 | if ((i >= MAX_CONTEXT) || (global_ppriv[i].sets[0] == NULL) || | ||
350 | (global_ppriv[i].sets[1] == NULL)) { | ||
351 | return 0; | ||
352 | } | ||
353 | } | ||
354 | 308 | ||
355 | return 1; | 309 | mutex_lock(&dev->struct_mutex); |
310 | drm_sman_cleanup(&dev_priv->sman); | ||
311 | dev_priv->vram_initialized = 0; | ||
312 | dev_priv->agp_initialized = 0; | ||
313 | dev_priv->mmio = NULL; | ||
314 | mutex_unlock(&dev->struct_mutex); | ||
356 | } | 315 | } |
357 | 316 | ||
358 | int sis_final_context(struct drm_device *dev, int context) | 317 | void sis_reclaim_buffers_locked(drm_device_t * dev, struct file *filp) |
359 | { | 318 | { |
360 | int i; | 319 | drm_sis_private_t *dev_priv = dev->dev_private; |
320 | drm_file_t *priv = filp->private_data; | ||
361 | 321 | ||
362 | for (i = 0; i < MAX_CONTEXT; i++) { | 322 | mutex_lock(&dev->struct_mutex); |
363 | if (global_ppriv[i].used && | 323 | if (drm_sman_owner_clean(&dev_priv->sman, (unsigned long)priv)) { |
364 | (global_ppriv[i].context == context)) | 324 | mutex_unlock(&dev->struct_mutex); |
365 | break; | 325 | return; |
366 | } | 326 | } |
367 | 327 | ||
368 | if (i < MAX_CONTEXT) { | 328 | if (dev->driver->dma_quiescent) { |
369 | set_t *set; | 329 | dev->driver->dma_quiescent(dev); |
370 | ITEM_TYPE item; | ||
371 | int retval; | ||
372 | |||
373 | DRM_DEBUG("find socket %d, context = %d\n", i, context); | ||
374 | |||
375 | /* Video Memory */ | ||
376 | set = global_ppriv[i].sets[0]; | ||
377 | retval = setFirst(set, &item); | ||
378 | while (retval) { | ||
379 | DRM_DEBUG("free video memory 0x%lx\n", item); | ||
380 | #if defined(__linux__) && defined(CONFIG_FB_SIS) | ||
381 | sis_free(item); | ||
382 | #else | ||
383 | mmFreeMem((PMemBlock) item); | ||
384 | #endif | ||
385 | retval = setNext(set, &item); | ||
386 | } | ||
387 | setDestroy(set); | ||
388 | |||
389 | /* AGP Memory */ | ||
390 | set = global_ppriv[i].sets[1]; | ||
391 | retval = setFirst(set, &item); | ||
392 | while (retval) { | ||
393 | DRM_DEBUG("free agp memory 0x%lx\n", item); | ||
394 | mmFreeMem((PMemBlock) item); | ||
395 | retval = setNext(set, &item); | ||
396 | } | ||
397 | setDestroy(set); | ||
398 | |||
399 | global_ppriv[i].used = 0; | ||
400 | } | 330 | } |
401 | 331 | ||
402 | return 1; | 332 | drm_sman_owner_cleanup(&dev_priv->sman, (unsigned long)priv); |
333 | mutex_unlock(&dev->struct_mutex); | ||
334 | return; | ||
403 | } | 335 | } |
404 | 336 | ||
405 | drm_ioctl_desc_t sis_ioctls[] = { | 337 | drm_ioctl_desc_t sis_ioctls[] = { |
406 | [DRM_IOCTL_NR(DRM_SIS_FB_ALLOC)] = {sis_fb_alloc, DRM_AUTH}, | 338 | [DRM_IOCTL_NR(DRM_SIS_FB_ALLOC)] = {sis_fb_alloc, DRM_AUTH}, |
407 | [DRM_IOCTL_NR(DRM_SIS_FB_FREE)] = {sis_fb_free, DRM_AUTH}, | 339 | [DRM_IOCTL_NR(DRM_SIS_FB_FREE)] = {sis_drm_free, DRM_AUTH}, |
408 | [DRM_IOCTL_NR(DRM_SIS_AGP_INIT)] = {sis_ioctl_agp_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, | 340 | [DRM_IOCTL_NR(DRM_SIS_AGP_INIT)] = |
341 | {sis_ioctl_agp_init, DRM_AUTH | DRM_MASTER | DRM_ROOT_ONLY}, | ||
409 | [DRM_IOCTL_NR(DRM_SIS_AGP_ALLOC)] = {sis_ioctl_agp_alloc, DRM_AUTH}, | 342 | [DRM_IOCTL_NR(DRM_SIS_AGP_ALLOC)] = {sis_ioctl_agp_alloc, DRM_AUTH}, |
410 | [DRM_IOCTL_NR(DRM_SIS_AGP_FREE)] = {sis_ioctl_agp_free, DRM_AUTH}, | 343 | [DRM_IOCTL_NR(DRM_SIS_AGP_FREE)] = {sis_drm_free, DRM_AUTH}, |
411 | [DRM_IOCTL_NR(DRM_SIS_FB_INIT)] = {sis_fb_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY} | 344 | [DRM_IOCTL_NR(DRM_SIS_FB_INIT)] = |
345 | {sis_fb_init, DRM_AUTH | DRM_MASTER | DRM_ROOT_ONLY} | ||
412 | }; | 346 | }; |
413 | 347 | ||
414 | int sis_max_ioctl = DRM_ARRAY_SIZE(sis_ioctls); | 348 | int sis_max_ioctl = DRM_ARRAY_SIZE(sis_ioctls); |
diff --git a/drivers/char/drm/via_dmablit.c b/drivers/char/drm/via_dmablit.c index 78a81a4a99c5..60c1695db300 100644 --- a/drivers/char/drm/via_dmablit.c +++ b/drivers/char/drm/via_dmablit.c | |||
@@ -41,9 +41,9 @@ | |||
41 | 41 | ||
42 | #include <linux/pagemap.h> | 42 | #include <linux/pagemap.h> |
43 | 43 | ||
44 | #define VIA_PGDN(x) (((unsigned long)(x)) & PAGE_MASK) | 44 | #define VIA_PGDN(x) (((unsigned long)(x)) & PAGE_MASK) |
45 | #define VIA_PGOFF(x) (((unsigned long)(x)) & ~PAGE_MASK) | 45 | #define VIA_PGOFF(x) (((unsigned long)(x)) & ~PAGE_MASK) |
46 | #define VIA_PFN(x) ((unsigned long)(x) >> PAGE_SHIFT) | 46 | #define VIA_PFN(x) ((unsigned long)(x) >> PAGE_SHIFT) |
47 | 47 | ||
48 | typedef struct _drm_via_descriptor { | 48 | typedef struct _drm_via_descriptor { |
49 | uint32_t mem_addr; | 49 | uint32_t mem_addr; |
@@ -121,19 +121,19 @@ via_map_blit_for_device(struct pci_dev *pdev, | |||
121 | 121 | ||
122 | while (line_len > 0) { | 122 | while (line_len > 0) { |
123 | 123 | ||
124 | remaining_len = min(PAGE_SIZE-VIA_PGOFF(cur_mem), line_len); | 124 | remaining_len = min(PAGE_SIZE-VIA_PGOFF(cur_mem), line_len); |
125 | line_len -= remaining_len; | 125 | line_len -= remaining_len; |
126 | 126 | ||
127 | if (mode == 1) { | 127 | if (mode == 1) { |
128 | desc_ptr->mem_addr = | 128 | desc_ptr->mem_addr = |
129 | dma_map_page(&pdev->dev, | 129 | dma_map_page(&pdev->dev, |
130 | vsg->pages[VIA_PFN(cur_mem) - | 130 | vsg->pages[VIA_PFN(cur_mem) - |
131 | VIA_PFN(first_addr)], | 131 | VIA_PFN(first_addr)], |
132 | VIA_PGOFF(cur_mem), remaining_len, | 132 | VIA_PGOFF(cur_mem), remaining_len, |
133 | vsg->direction); | 133 | vsg->direction); |
134 | desc_ptr->dev_addr = cur_fb; | 134 | desc_ptr->dev_addr = cur_fb; |
135 | 135 | ||
136 | desc_ptr->size = remaining_len; | 136 | desc_ptr->size = remaining_len; |
137 | desc_ptr->next = (uint32_t) next; | 137 | desc_ptr->next = (uint32_t) next; |
138 | next = dma_map_single(&pdev->dev, desc_ptr, sizeof(*desc_ptr), | 138 | next = dma_map_single(&pdev->dev, desc_ptr, sizeof(*desc_ptr), |
139 | DMA_TO_DEVICE); | 139 | DMA_TO_DEVICE); |
@@ -162,7 +162,7 @@ via_map_blit_for_device(struct pci_dev *pdev, | |||
162 | 162 | ||
163 | /* | 163 | /* |
164 | * Function that frees up all resources for a blit. It is usable even if the | 164 | * Function that frees up all resources for a blit. It is usable even if the |
165 | * blit info has only be partially built as long as the status enum is consistent | 165 | * blit info has only been partially built as long as the status enum is consistent |
166 | * with the actual status of the used resources. | 166 | * with the actual status of the used resources. |
167 | */ | 167 | */ |
168 | 168 | ||
@@ -238,8 +238,11 @@ via_lock_all_dma_pages(drm_via_sg_info_t *vsg, drm_via_dmablit_t *xfer) | |||
238 | return DRM_ERR(ENOMEM); | 238 | return DRM_ERR(ENOMEM); |
239 | memset(vsg->pages, 0, sizeof(struct page *) * vsg->num_pages); | 239 | memset(vsg->pages, 0, sizeof(struct page *) * vsg->num_pages); |
240 | down_read(¤t->mm->mmap_sem); | 240 | down_read(¤t->mm->mmap_sem); |
241 | ret = get_user_pages(current, current->mm, (unsigned long) xfer->mem_addr, | 241 | ret = get_user_pages(current, current->mm, |
242 | vsg->num_pages, vsg->direction, 0, vsg->pages, NULL); | 242 | (unsigned long)xfer->mem_addr, |
243 | vsg->num_pages, | ||
244 | (vsg->direction == DMA_FROM_DEVICE), | ||
245 | 0, vsg->pages, NULL); | ||
243 | 246 | ||
244 | up_read(¤t->mm->mmap_sem); | 247 | up_read(¤t->mm->mmap_sem); |
245 | if (ret != vsg->num_pages) { | 248 | if (ret != vsg->num_pages) { |
@@ -475,9 +478,15 @@ via_dmablit_timer(unsigned long data) | |||
475 | if (!timer_pending(&blitq->poll_timer)) { | 478 | if (!timer_pending(&blitq->poll_timer)) { |
476 | blitq->poll_timer.expires = jiffies+1; | 479 | blitq->poll_timer.expires = jiffies+1; |
477 | add_timer(&blitq->poll_timer); | 480 | add_timer(&blitq->poll_timer); |
478 | } | ||
479 | via_dmablit_handler(dev, engine, 0); | ||
480 | 481 | ||
482 | /* | ||
483 | * Rerun handler to delete timer if engines are off, and | ||
484 | * to shorten abort latency. This is a little nasty. | ||
485 | */ | ||
486 | |||
487 | via_dmablit_handler(dev, engine, 0); | ||
488 | |||
489 | } | ||
481 | } | 490 | } |
482 | 491 | ||
483 | 492 | ||
@@ -597,15 +606,27 @@ via_build_sg_info(drm_device_t *dev, drm_via_sg_info_t *vsg, drm_via_dmablit_t * | |||
597 | * (Not a big limitation anyway.) | 606 | * (Not a big limitation anyway.) |
598 | */ | 607 | */ |
599 | 608 | ||
600 | if (((xfer->mem_stride - xfer->line_length) >= PAGE_SIZE) || | 609 | if ((xfer->mem_stride - xfer->line_length) >= PAGE_SIZE) { |
601 | (xfer->mem_stride > 2048*4)) { | ||
602 | DRM_ERROR("Too large system memory stride. Stride: %d, " | 610 | DRM_ERROR("Too large system memory stride. Stride: %d, " |
603 | "Length: %d\n", xfer->mem_stride, xfer->line_length); | 611 | "Length: %d\n", xfer->mem_stride, xfer->line_length); |
604 | return DRM_ERR(EINVAL); | 612 | return DRM_ERR(EINVAL); |
605 | } | 613 | } |
606 | 614 | ||
607 | if (xfer->num_lines > 2048) { | 615 | if ((xfer->mem_stride == xfer->line_length) && |
608 | DRM_ERROR("Too many PCI DMA bitblt lines.\n"); | 616 | (xfer->fb_stride == xfer->line_length)) { |
617 | xfer->mem_stride *= xfer->num_lines; | ||
618 | xfer->line_length = xfer->mem_stride; | ||
619 | xfer->fb_stride = xfer->mem_stride; | ||
620 | xfer->num_lines = 1; | ||
621 | } | ||
622 | |||
623 | /* | ||
624 | * Don't lock an arbitrary large number of pages, since that causes a | ||
625 | * DOS security hole. | ||
626 | */ | ||
627 | |||
628 | if (xfer->num_lines > 2048 || (xfer->num_lines*xfer->mem_stride > (2048*2048*4))) { | ||
629 | DRM_ERROR("Too large PCI DMA bitblt.\n"); | ||
609 | return DRM_ERR(EINVAL); | 630 | return DRM_ERR(EINVAL); |
610 | } | 631 | } |
611 | 632 | ||
@@ -628,16 +649,17 @@ via_build_sg_info(drm_device_t *dev, drm_via_sg_info_t *vsg, drm_via_dmablit_t * | |||
628 | 649 | ||
629 | #ifdef VIA_BUGFREE | 650 | #ifdef VIA_BUGFREE |
630 | if ((((unsigned long)xfer->mem_addr & 3) != ((unsigned long)xfer->fb_addr & 3)) || | 651 | if ((((unsigned long)xfer->mem_addr & 3) != ((unsigned long)xfer->fb_addr & 3)) || |
631 | ((xfer->mem_stride & 3) != (xfer->fb_stride & 3))) { | 652 | ((xfer->num_lines > 1) && ((xfer->mem_stride & 3) != (xfer->fb_stride & 3)))) { |
632 | DRM_ERROR("Invalid DRM bitblt alignment.\n"); | 653 | DRM_ERROR("Invalid DRM bitblt alignment.\n"); |
633 | return DRM_ERR(EINVAL); | 654 | return DRM_ERR(EINVAL); |
634 | } | 655 | } |
635 | #else | 656 | #else |
636 | if ((((unsigned long)xfer->mem_addr & 15) || | 657 | if ((((unsigned long)xfer->mem_addr & 15) || |
637 | ((unsigned long)xfer->fb_addr & 3)) || (xfer->mem_stride & 15) || | 658 | ((unsigned long)xfer->fb_addr & 3)) || |
638 | (xfer->fb_stride & 3)) { | 659 | ((xfer->num_lines > 1) && |
660 | ((xfer->mem_stride & 15) || (xfer->fb_stride & 3)))) { | ||
639 | DRM_ERROR("Invalid DRM bitblt alignment.\n"); | 661 | DRM_ERROR("Invalid DRM bitblt alignment.\n"); |
640 | return DRM_ERR(EINVAL); | 662 | return DRM_ERR(EINVAL); |
641 | } | 663 | } |
642 | #endif | 664 | #endif |
643 | 665 | ||
@@ -715,7 +737,7 @@ via_dmablit(drm_device_t *dev, drm_via_dmablit_t *xfer) | |||
715 | drm_via_private_t *dev_priv = (drm_via_private_t *)dev->dev_private; | 737 | drm_via_private_t *dev_priv = (drm_via_private_t *)dev->dev_private; |
716 | drm_via_sg_info_t *vsg; | 738 | drm_via_sg_info_t *vsg; |
717 | drm_via_blitq_t *blitq; | 739 | drm_via_blitq_t *blitq; |
718 | int ret; | 740 | int ret; |
719 | int engine; | 741 | int engine; |
720 | unsigned long irqsave; | 742 | unsigned long irqsave; |
721 | 743 | ||
@@ -756,7 +778,7 @@ via_dmablit(drm_device_t *dev, drm_via_dmablit_t *xfer) | |||
756 | 778 | ||
757 | /* | 779 | /* |
758 | * Sync on a previously submitted blit. Note that the X server use signals extensively, and | 780 | * Sync on a previously submitted blit. Note that the X server use signals extensively, and |
759 | * that there is a very big proability that this IOCTL will be interrupted by a signal. In that | 781 | * that there is a very big probability that this IOCTL will be interrupted by a signal. In that |
760 | * case it returns with -EAGAIN for the signal to be delivered. | 782 | * case it returns with -EAGAIN for the signal to be delivered. |
761 | * The caller should then reissue the IOCTL. This is similar to what is being done for drmGetLock(). | 783 | * The caller should then reissue the IOCTL. This is similar to what is being done for drmGetLock(). |
762 | */ | 784 | */ |
diff --git a/drivers/char/drm/via_drm.h b/drivers/char/drm/via_drm.h index 47f0b5b26379..e4ee97d7156f 100644 --- a/drivers/char/drm/via_drm.h +++ b/drivers/char/drm/via_drm.h | |||
@@ -250,6 +250,12 @@ typedef struct drm_via_blitsync { | |||
250 | unsigned engine; | 250 | unsigned engine; |
251 | } drm_via_blitsync_t; | 251 | } drm_via_blitsync_t; |
252 | 252 | ||
253 | /* - * Below,"flags" is currently unused but will be used for possible future | ||
254 | * extensions like kernel space bounce buffers for bad alignments and | ||
255 | * blit engine busy-wait polling for better latency in the absence of | ||
256 | * interrupts. | ||
257 | */ | ||
258 | |||
253 | typedef struct drm_via_dmablit { | 259 | typedef struct drm_via_dmablit { |
254 | uint32_t num_lines; | 260 | uint32_t num_lines; |
255 | uint32_t line_length; | 261 | uint32_t line_length; |
@@ -260,7 +266,7 @@ typedef struct drm_via_dmablit { | |||
260 | unsigned char *mem_addr; | 266 | unsigned char *mem_addr; |
261 | uint32_t mem_stride; | 267 | uint32_t mem_stride; |
262 | 268 | ||
263 | int bounce_buffer; | 269 | uint32_t flags; |
264 | int to_fb; | 270 | int to_fb; |
265 | 271 | ||
266 | drm_via_blitsync_t sync; | 272 | drm_via_blitsync_t sync; |
diff --git a/drivers/char/drm/via_drv.c b/drivers/char/drm/via_drv.c index b3d364d793d7..bb9dde8b1911 100644 --- a/drivers/char/drm/via_drv.c +++ b/drivers/char/drm/via_drv.c | |||
@@ -43,7 +43,6 @@ static struct drm_driver driver = { | |||
43 | DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL, | 43 | DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL, |
44 | .load = via_driver_load, | 44 | .load = via_driver_load, |
45 | .unload = via_driver_unload, | 45 | .unload = via_driver_unload, |
46 | .context_ctor = via_init_context, | ||
47 | .context_dtor = via_final_context, | 46 | .context_dtor = via_final_context, |
48 | .vblank_wait = via_driver_vblank_wait, | 47 | .vblank_wait = via_driver_vblank_wait, |
49 | .irq_preinstall = via_driver_irq_preinstall, | 48 | .irq_preinstall = via_driver_irq_preinstall, |
@@ -53,6 +52,8 @@ static struct drm_driver driver = { | |||
53 | .dma_quiescent = via_driver_dma_quiescent, | 52 | .dma_quiescent = via_driver_dma_quiescent, |
54 | .dri_library_name = dri_library_name, | 53 | .dri_library_name = dri_library_name, |
55 | .reclaim_buffers = drm_core_reclaim_buffers, | 54 | .reclaim_buffers = drm_core_reclaim_buffers, |
55 | .reclaim_buffers_locked = via_reclaim_buffers_locked, | ||
56 | .lastclose = via_lastclose, | ||
56 | .get_map_ofs = drm_core_get_map_ofs, | 57 | .get_map_ofs = drm_core_get_map_ofs, |
57 | .get_reg_ofs = drm_core_get_reg_ofs, | 58 | .get_reg_ofs = drm_core_get_reg_ofs, |
58 | .ioctls = via_ioctls, | 59 | .ioctls = via_ioctls, |
diff --git a/drivers/char/drm/via_drv.h b/drivers/char/drm/via_drv.h index 52bcc7b1ba45..d21b5b75da0f 100644 --- a/drivers/char/drm/via_drv.h +++ b/drivers/char/drm/via_drv.h | |||
@@ -24,15 +24,16 @@ | |||
24 | #ifndef _VIA_DRV_H_ | 24 | #ifndef _VIA_DRV_H_ |
25 | #define _VIA_DRV_H_ | 25 | #define _VIA_DRV_H_ |
26 | 26 | ||
27 | #include "drm_sman.h" | ||
27 | #define DRIVER_AUTHOR "Various" | 28 | #define DRIVER_AUTHOR "Various" |
28 | 29 | ||
29 | #define DRIVER_NAME "via" | 30 | #define DRIVER_NAME "via" |
30 | #define DRIVER_DESC "VIA Unichrome / Pro" | 31 | #define DRIVER_DESC "VIA Unichrome / Pro" |
31 | #define DRIVER_DATE "20051116" | 32 | #define DRIVER_DATE "20060529" |
32 | 33 | ||
33 | #define DRIVER_MAJOR 2 | 34 | #define DRIVER_MAJOR 2 |
34 | #define DRIVER_MINOR 7 | 35 | #define DRIVER_MINOR 10 |
35 | #define DRIVER_PATCHLEVEL 4 | 36 | #define DRIVER_PATCHLEVEL 0 |
36 | 37 | ||
37 | #include "via_verifier.h" | 38 | #include "via_verifier.h" |
38 | 39 | ||
@@ -85,6 +86,12 @@ typedef struct drm_via_private { | |||
85 | uint32_t irq_enable_mask; | 86 | uint32_t irq_enable_mask; |
86 | uint32_t irq_pending_mask; | 87 | uint32_t irq_pending_mask; |
87 | int *irq_map; | 88 | int *irq_map; |
89 | unsigned int idle_fault; | ||
90 | drm_sman_t sman; | ||
91 | int vram_initialized; | ||
92 | int agp_initialized; | ||
93 | unsigned long vram_offset; | ||
94 | unsigned long agp_offset; | ||
88 | drm_via_blitq_t blit_queues[VIA_NUM_BLIT_ENGINES]; | 95 | drm_via_blitq_t blit_queues[VIA_NUM_BLIT_ENGINES]; |
89 | } drm_via_private_t; | 96 | } drm_via_private_t; |
90 | 97 | ||
@@ -135,6 +142,9 @@ extern void via_init_futex(drm_via_private_t * dev_priv); | |||
135 | extern void via_cleanup_futex(drm_via_private_t * dev_priv); | 142 | extern void via_cleanup_futex(drm_via_private_t * dev_priv); |
136 | extern void via_release_futex(drm_via_private_t * dev_priv, int context); | 143 | extern void via_release_futex(drm_via_private_t * dev_priv, int context); |
137 | 144 | ||
145 | extern void via_reclaim_buffers_locked(drm_device_t *dev, struct file *filp); | ||
146 | extern void via_lastclose(drm_device_t *dev); | ||
147 | |||
138 | extern void via_dmablit_handler(drm_device_t *dev, int engine, int from_irq); | 148 | extern void via_dmablit_handler(drm_device_t *dev, int engine, int from_irq); |
139 | extern void via_init_dmablit(drm_device_t *dev); | 149 | extern void via_init_dmablit(drm_device_t *dev); |
140 | 150 | ||
diff --git a/drivers/char/drm/via_ds.c b/drivers/char/drm/via_ds.c deleted file mode 100644 index 9429736b3b96..000000000000 --- a/drivers/char/drm/via_ds.c +++ /dev/null | |||
@@ -1,273 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved. | ||
3 | * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved. | ||
4 | * Copyright 2000 Silicon Integrated Systems Corp, Inc., HsinChu, Taiwan. | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
7 | * copy of this software and associated documentation files (the "Software"), | ||
8 | * to deal in the Software without restriction, including without limitation | ||
9 | * the rights to use, copy, modify, merge, publish, distribute, sub license, | ||
10 | * and/or sell copies of the Software, and to permit persons to whom the | ||
11 | * Software is furnished to do so, subject to the following conditions: | ||
12 | * | ||
13 | * The above copyright notice and this permission notice (including the | ||
14 | * next paragraph) shall be included in all copies or substantial portions | ||
15 | * of the Software. | ||
16 | * | ||
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
19 | * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL | ||
20 | * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
21 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
22 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
23 | * DEALINGS IN THE SOFTWARE. | ||
24 | */ | ||
25 | #include "drmP.h" | ||
26 | |||
27 | #include "via_ds.h" | ||
28 | extern unsigned int VIA_DEBUG; | ||
29 | |||
30 | set_t *via_setInit(void) | ||
31 | { | ||
32 | int i; | ||
33 | set_t *set; | ||
34 | set = (set_t *) drm_alloc(sizeof(set_t), DRM_MEM_DRIVER); | ||
35 | for (i = 0; i < SET_SIZE; i++) { | ||
36 | set->list[i].free_next = i + 1; | ||
37 | set->list[i].alloc_next = -1; | ||
38 | } | ||
39 | set->list[SET_SIZE - 1].free_next = -1; | ||
40 | set->free = 0; | ||
41 | set->alloc = -1; | ||
42 | set->trace = -1; | ||
43 | return set; | ||
44 | } | ||
45 | |||
46 | int via_setAdd(set_t * set, ITEM_TYPE item) | ||
47 | { | ||
48 | int free = set->free; | ||
49 | if (free != -1) { | ||
50 | set->list[free].val = item; | ||
51 | set->free = set->list[free].free_next; | ||
52 | } else { | ||
53 | return 0; | ||
54 | } | ||
55 | set->list[free].alloc_next = set->alloc; | ||
56 | set->alloc = free; | ||
57 | set->list[free].free_next = -1; | ||
58 | return 1; | ||
59 | } | ||
60 | |||
61 | int via_setDel(set_t * set, ITEM_TYPE item) | ||
62 | { | ||
63 | int alloc = set->alloc; | ||
64 | int prev = -1; | ||
65 | |||
66 | while (alloc != -1) { | ||
67 | if (set->list[alloc].val == item) { | ||
68 | if (prev != -1) | ||
69 | set->list[prev].alloc_next = | ||
70 | set->list[alloc].alloc_next; | ||
71 | else | ||
72 | set->alloc = set->list[alloc].alloc_next; | ||
73 | break; | ||
74 | } | ||
75 | prev = alloc; | ||
76 | alloc = set->list[alloc].alloc_next; | ||
77 | } | ||
78 | |||
79 | if (alloc == -1) | ||
80 | return 0; | ||
81 | |||
82 | set->list[alloc].free_next = set->free; | ||
83 | set->free = alloc; | ||
84 | set->list[alloc].alloc_next = -1; | ||
85 | |||
86 | return 1; | ||
87 | } | ||
88 | |||
89 | /* setFirst -> setAdd -> setNext is wrong */ | ||
90 | |||
91 | int via_setFirst(set_t * set, ITEM_TYPE * item) | ||
92 | { | ||
93 | if (set->alloc == -1) | ||
94 | return 0; | ||
95 | |||
96 | *item = set->list[set->alloc].val; | ||
97 | set->trace = set->list[set->alloc].alloc_next; | ||
98 | |||
99 | return 1; | ||
100 | } | ||
101 | |||
102 | int via_setNext(set_t * set, ITEM_TYPE * item) | ||
103 | { | ||
104 | if (set->trace == -1) | ||
105 | return 0; | ||
106 | |||
107 | *item = set->list[set->trace].val; | ||
108 | set->trace = set->list[set->trace].alloc_next; | ||
109 | |||
110 | return 1; | ||
111 | } | ||
112 | |||
113 | int via_setDestroy(set_t * set) | ||
114 | { | ||
115 | drm_free(set, sizeof(set_t), DRM_MEM_DRIVER); | ||
116 | |||
117 | return 1; | ||
118 | } | ||
119 | |||
120 | #define ISFREE(bptr) ((bptr)->free) | ||
121 | |||
122 | #define fprintf(fmt, arg...) do{}while(0) | ||
123 | |||
124 | memHeap_t *via_mmInit(int ofs, int size) | ||
125 | { | ||
126 | PMemBlock blocks; | ||
127 | |||
128 | if (size <= 0) | ||
129 | return NULL; | ||
130 | |||
131 | blocks = (TMemBlock *) drm_calloc(1, sizeof(TMemBlock), DRM_MEM_DRIVER); | ||
132 | |||
133 | if (blocks) { | ||
134 | blocks->ofs = ofs; | ||
135 | blocks->size = size; | ||
136 | blocks->free = 1; | ||
137 | return (memHeap_t *) blocks; | ||
138 | } else | ||
139 | return NULL; | ||
140 | } | ||
141 | |||
142 | static TMemBlock *SliceBlock(TMemBlock * p, | ||
143 | int startofs, int size, | ||
144 | int reserved, int alignment) | ||
145 | { | ||
146 | TMemBlock *newblock; | ||
147 | |||
148 | /* break left */ | ||
149 | if (startofs > p->ofs) { | ||
150 | newblock = | ||
151 | (TMemBlock *) drm_calloc(1, sizeof(TMemBlock), | ||
152 | DRM_MEM_DRIVER); | ||
153 | newblock->ofs = startofs; | ||
154 | newblock->size = p->size - (startofs - p->ofs); | ||
155 | newblock->free = 1; | ||
156 | newblock->next = p->next; | ||
157 | p->size -= newblock->size; | ||
158 | p->next = newblock; | ||
159 | p = newblock; | ||
160 | } | ||
161 | |||
162 | /* break right */ | ||
163 | if (size < p->size) { | ||
164 | newblock = | ||
165 | (TMemBlock *) drm_calloc(1, sizeof(TMemBlock), | ||
166 | DRM_MEM_DRIVER); | ||
167 | newblock->ofs = startofs + size; | ||
168 | newblock->size = p->size - size; | ||
169 | newblock->free = 1; | ||
170 | newblock->next = p->next; | ||
171 | p->size = size; | ||
172 | p->next = newblock; | ||
173 | } | ||
174 | |||
175 | /* p = middle block */ | ||
176 | p->align = alignment; | ||
177 | p->free = 0; | ||
178 | p->reserved = reserved; | ||
179 | return p; | ||
180 | } | ||
181 | |||
182 | PMemBlock via_mmAllocMem(memHeap_t * heap, int size, int align2, | ||
183 | int startSearch) | ||
184 | { | ||
185 | int mask, startofs, endofs; | ||
186 | TMemBlock *p; | ||
187 | |||
188 | if (!heap || align2 < 0 || size <= 0) | ||
189 | return NULL; | ||
190 | |||
191 | mask = (1 << align2) - 1; | ||
192 | startofs = 0; | ||
193 | p = (TMemBlock *) heap; | ||
194 | |||
195 | while (p) { | ||
196 | if (ISFREE(p)) { | ||
197 | startofs = (p->ofs + mask) & ~mask; | ||
198 | |||
199 | if (startofs < startSearch) | ||
200 | startofs = startSearch; | ||
201 | |||
202 | endofs = startofs + size; | ||
203 | |||
204 | if (endofs <= (p->ofs + p->size)) | ||
205 | break; | ||
206 | } | ||
207 | |||
208 | p = p->next; | ||
209 | } | ||
210 | |||
211 | if (!p) | ||
212 | return NULL; | ||
213 | |||
214 | p = SliceBlock(p, startofs, size, 0, mask + 1); | ||
215 | p->heap = heap; | ||
216 | |||
217 | return p; | ||
218 | } | ||
219 | |||
220 | static __inline__ int Join2Blocks(TMemBlock * p) | ||
221 | { | ||
222 | if (p->free && p->next && p->next->free) { | ||
223 | TMemBlock *q = p->next; | ||
224 | p->size += q->size; | ||
225 | p->next = q->next; | ||
226 | drm_free(q, sizeof(TMemBlock), DRM_MEM_DRIVER); | ||
227 | |||
228 | return 1; | ||
229 | } | ||
230 | |||
231 | return 0; | ||
232 | } | ||
233 | |||
234 | int via_mmFreeMem(PMemBlock b) | ||
235 | { | ||
236 | TMemBlock *p, *prev; | ||
237 | |||
238 | if (!b) | ||
239 | return 0; | ||
240 | |||
241 | if (!b->heap) { | ||
242 | fprintf(stderr, "no heap\n"); | ||
243 | |||
244 | return -1; | ||
245 | } | ||
246 | |||
247 | p = b->heap; | ||
248 | prev = NULL; | ||
249 | |||
250 | while (p && p != b) { | ||
251 | prev = p; | ||
252 | p = p->next; | ||
253 | } | ||
254 | |||
255 | if (!p || p->free || p->reserved) { | ||
256 | if (!p) | ||
257 | fprintf(stderr, "block not found in heap\n"); | ||
258 | else if (p->free) | ||
259 | fprintf(stderr, "block already free\n"); | ||
260 | else | ||
261 | fprintf(stderr, "block is reserved\n"); | ||
262 | |||
263 | return -1; | ||
264 | } | ||
265 | |||
266 | p->free = 1; | ||
267 | Join2Blocks(p); | ||
268 | |||
269 | if (prev) | ||
270 | Join2Blocks(prev); | ||
271 | |||
272 | return 0; | ||
273 | } | ||
diff --git a/drivers/char/drm/via_ds.h b/drivers/char/drm/via_ds.h deleted file mode 100644 index d2bb9f37ca38..000000000000 --- a/drivers/char/drm/via_ds.h +++ /dev/null | |||
@@ -1,104 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved. | ||
3 | * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved. | ||
4 | * Copyright 2000 Silicon Integrated Systems Corp, Inc., HsinChu, Taiwan. | ||
5 | * All rights reserved. | ||
6 | * | ||
7 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
8 | * copy of this software and associated documentation files (the "Software"), | ||
9 | * to deal in the Software without restriction, including without limitation | ||
10 | * the rights to use, copy, modify, merge, publish, distribute, sub license, | ||
11 | * and/or sell copies of the Software, and to permit persons to whom the | ||
12 | * Software is furnished to do so, subject to the following conditions: | ||
13 | * | ||
14 | * The above copyright notice and this permission notice (including the | ||
15 | * next paragraph) shall be included in all copies or substantial portions | ||
16 | * of the Software. | ||
17 | * | ||
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL | ||
21 | * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
22 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
23 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
24 | * DEALINGS IN THE SOFTWARE. | ||
25 | */ | ||
26 | #ifndef _via_ds_h_ | ||
27 | #define _via_ds_h_ | ||
28 | |||
29 | #include "drmP.h" | ||
30 | |||
31 | /* Set Data Structure */ | ||
32 | #define SET_SIZE 5000 | ||
33 | typedef unsigned long ITEM_TYPE; | ||
34 | |||
35 | typedef struct { | ||
36 | ITEM_TYPE val; | ||
37 | int alloc_next, free_next; | ||
38 | } list_item_t; | ||
39 | |||
40 | typedef struct { | ||
41 | int alloc; | ||
42 | int free; | ||
43 | int trace; | ||
44 | list_item_t list[SET_SIZE]; | ||
45 | } set_t; | ||
46 | |||
47 | set_t *via_setInit(void); | ||
48 | int via_setAdd(set_t * set, ITEM_TYPE item); | ||
49 | int via_setDel(set_t * set, ITEM_TYPE item); | ||
50 | int via_setFirst(set_t * set, ITEM_TYPE * item); | ||
51 | int via_setNext(set_t * set, ITEM_TYPE * item); | ||
52 | int via_setDestroy(set_t * set); | ||
53 | |||
54 | #endif | ||
55 | |||
56 | #ifndef MM_INC | ||
57 | #define MM_INC | ||
58 | |||
59 | struct mem_block_t { | ||
60 | struct mem_block_t *next; | ||
61 | struct mem_block_t *heap; | ||
62 | int ofs, size; | ||
63 | int align; | ||
64 | unsigned int free:1; | ||
65 | unsigned int reserved:1; | ||
66 | }; | ||
67 | typedef struct mem_block_t TMemBlock; | ||
68 | typedef struct mem_block_t *PMemBlock; | ||
69 | |||
70 | /* a heap is just the first block in a chain */ | ||
71 | typedef struct mem_block_t memHeap_t; | ||
72 | |||
73 | static __inline__ int mmBlockSize(PMemBlock b) | ||
74 | { | ||
75 | return b->size; | ||
76 | } | ||
77 | |||
78 | static __inline__ int mmOffset(PMemBlock b) | ||
79 | { | ||
80 | return b->ofs; | ||
81 | } | ||
82 | |||
83 | static __inline__ void mmMarkReserved(PMemBlock b) | ||
84 | { | ||
85 | b->reserved = 1; | ||
86 | } | ||
87 | |||
88 | /* | ||
89 | * input: total size in bytes | ||
90 | * return: a heap pointer if OK, NULL if error | ||
91 | */ | ||
92 | memHeap_t *via_mmInit(int ofs, int size); | ||
93 | |||
94 | PMemBlock via_mmAllocMem(memHeap_t * heap, int size, int align2, | ||
95 | int startSearch); | ||
96 | |||
97 | /* | ||
98 | * Free block starts at offset | ||
99 | * input: pointer to a block | ||
100 | * return: 0 if OK, -1 if error | ||
101 | */ | ||
102 | int via_mmFreeMem(PMemBlock b); | ||
103 | |||
104 | #endif | ||
diff --git a/drivers/char/drm/via_map.c b/drivers/char/drm/via_map.c index c6a08e96285b..782011e0a58d 100644 --- a/drivers/char/drm/via_map.c +++ b/drivers/char/drm/via_map.c | |||
@@ -98,6 +98,7 @@ int via_map_init(DRM_IOCTL_ARGS) | |||
98 | int via_driver_load(drm_device_t *dev, unsigned long chipset) | 98 | int via_driver_load(drm_device_t *dev, unsigned long chipset) |
99 | { | 99 | { |
100 | drm_via_private_t *dev_priv; | 100 | drm_via_private_t *dev_priv; |
101 | int ret = 0; | ||
101 | 102 | ||
102 | dev_priv = drm_calloc(1, sizeof(drm_via_private_t), DRM_MEM_DRIVER); | 103 | dev_priv = drm_calloc(1, sizeof(drm_via_private_t), DRM_MEM_DRIVER); |
103 | if (dev_priv == NULL) | 104 | if (dev_priv == NULL) |
@@ -108,13 +109,19 @@ int via_driver_load(drm_device_t *dev, unsigned long chipset) | |||
108 | if (chipset == VIA_PRO_GROUP_A) | 109 | if (chipset == VIA_PRO_GROUP_A) |
109 | dev_priv->pro_group_a = 1; | 110 | dev_priv->pro_group_a = 1; |
110 | 111 | ||
111 | return 0; | 112 | ret = drm_sman_init(&dev_priv->sman, 2, 12, 8); |
113 | if (ret) { | ||
114 | drm_free(dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER); | ||
115 | } | ||
116 | return ret; | ||
112 | } | 117 | } |
113 | 118 | ||
114 | int via_driver_unload(drm_device_t *dev) | 119 | int via_driver_unload(drm_device_t *dev) |
115 | { | 120 | { |
116 | drm_via_private_t *dev_priv = dev->dev_private; | 121 | drm_via_private_t *dev_priv = dev->dev_private; |
117 | 122 | ||
123 | drm_sman_takedown(&dev_priv->sman); | ||
124 | |||
118 | drm_free(dev_priv, sizeof(drm_via_private_t), DRM_MEM_DRIVER); | 125 | drm_free(dev_priv, sizeof(drm_via_private_t), DRM_MEM_DRIVER); |
119 | 126 | ||
120 | return 0; | 127 | return 0; |
diff --git a/drivers/char/drm/via_mm.c b/drivers/char/drm/via_mm.c index 33e0cb12e4c3..2fcf0577a7aa 100644 --- a/drivers/char/drm/via_mm.c +++ b/drivers/char/drm/via_mm.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved. | 2 | * Copyright 2006 Tungsten Graphics Inc., Bismarck, ND., USA. |
3 | * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved. | 3 | * All rights reserved. |
4 | * | 4 | * |
5 | * Permission is hereby granted, free of charge, to any person obtaining a | 5 | * Permission is hereby granted, free of charge, to any person obtaining a |
6 | * copy of this software and associated documentation files (the "Software"), | 6 | * copy of this software and associated documentation files (the "Software"), |
@@ -16,347 +16,194 @@ | |||
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL | 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL |
19 | * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR | 19 | * THE AUTHORS OR COPYRIGHT HOLDERS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, |
20 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | 20 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
21 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | 21 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
22 | * DEALINGS IN THE SOFTWARE. | 22 | * DEALINGS IN THE SOFTWARE. |
23 | */ | 23 | */ |
24 | /* | ||
25 | * Authors: Thomas Hellström <thomas-at-tungstengraphics-dot-com> | ||
26 | */ | ||
27 | |||
24 | #include "drmP.h" | 28 | #include "drmP.h" |
25 | #include "via_drm.h" | 29 | #include "via_drm.h" |
26 | #include "via_drv.h" | 30 | #include "via_drv.h" |
27 | #include "via_ds.h" | 31 | #include "drm_sman.h" |
28 | #include "via_mm.h" | ||
29 | |||
30 | #define MAX_CONTEXT 100 | ||
31 | |||
32 | typedef struct { | ||
33 | int used; | ||
34 | int context; | ||
35 | set_t *sets[2]; /* 0 for frame buffer, 1 for AGP , 2 for System */ | ||
36 | } via_context_t; | ||
37 | |||
38 | static via_context_t global_ppriv[MAX_CONTEXT]; | ||
39 | 32 | ||
40 | static int via_agp_alloc(drm_via_mem_t * mem); | 33 | #define VIA_MM_ALIGN_SHIFT 4 |
41 | static int via_agp_free(drm_via_mem_t * mem); | 34 | #define VIA_MM_ALIGN_MASK ( (1 << VIA_MM_ALIGN_SHIFT) - 1) |
42 | static int via_fb_alloc(drm_via_mem_t * mem); | ||
43 | static int via_fb_free(drm_via_mem_t * mem); | ||
44 | |||
45 | static int add_alloc_set(int context, int type, unsigned long val) | ||
46 | { | ||
47 | int i, retval = 0; | ||
48 | |||
49 | for (i = 0; i < MAX_CONTEXT; i++) { | ||
50 | if (global_ppriv[i].used && global_ppriv[i].context == context) { | ||
51 | retval = via_setAdd(global_ppriv[i].sets[type], val); | ||
52 | break; | ||
53 | } | ||
54 | } | ||
55 | |||
56 | return retval; | ||
57 | } | ||
58 | |||
59 | static int del_alloc_set(int context, int type, unsigned long val) | ||
60 | { | ||
61 | int i, retval = 0; | ||
62 | |||
63 | for (i = 0; i < MAX_CONTEXT; i++) | ||
64 | if (global_ppriv[i].used && global_ppriv[i].context == context) { | ||
65 | retval = via_setDel(global_ppriv[i].sets[type], val); | ||
66 | break; | ||
67 | } | ||
68 | |||
69 | return retval; | ||
70 | } | ||
71 | |||
72 | /* agp memory management */ | ||
73 | static memHeap_t *AgpHeap = NULL; | ||
74 | 35 | ||
75 | int via_agp_init(DRM_IOCTL_ARGS) | 36 | int via_agp_init(DRM_IOCTL_ARGS) |
76 | { | 37 | { |
38 | DRM_DEVICE; | ||
77 | drm_via_agp_t agp; | 39 | drm_via_agp_t agp; |
40 | drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; | ||
41 | int ret; | ||
78 | 42 | ||
79 | DRM_COPY_FROM_USER_IOCTL(agp, (drm_via_agp_t __user *) data, | 43 | DRM_COPY_FROM_USER_IOCTL(agp, (drm_via_agp_t __user *) data, |
80 | sizeof(agp)); | 44 | sizeof(agp)); |
45 | mutex_lock(&dev->struct_mutex); | ||
46 | ret = drm_sman_set_range(&dev_priv->sman, VIA_MEM_AGP, 0, | ||
47 | agp.size >> VIA_MM_ALIGN_SHIFT); | ||
48 | |||
49 | if (ret) { | ||
50 | DRM_ERROR("AGP memory manager initialisation error\n"); | ||
51 | mutex_unlock(&dev->struct_mutex); | ||
52 | return ret; | ||
53 | } | ||
81 | 54 | ||
82 | AgpHeap = via_mmInit(agp.offset, agp.size); | 55 | dev_priv->agp_initialized = 1; |
83 | 56 | dev_priv->agp_offset = agp.offset; | |
84 | DRM_DEBUG("offset = %lu, size = %lu", (unsigned long)agp.offset, | 57 | mutex_unlock(&dev->struct_mutex); |
85 | (unsigned long)agp.size); | ||
86 | 58 | ||
59 | DRM_DEBUG("offset = %u, size = %u", agp.offset, agp.size); | ||
87 | return 0; | 60 | return 0; |
88 | } | 61 | } |
89 | 62 | ||
90 | /* fb memory management */ | ||
91 | static memHeap_t *FBHeap = NULL; | ||
92 | |||
93 | int via_fb_init(DRM_IOCTL_ARGS) | 63 | int via_fb_init(DRM_IOCTL_ARGS) |
94 | { | 64 | { |
65 | DRM_DEVICE; | ||
95 | drm_via_fb_t fb; | 66 | drm_via_fb_t fb; |
67 | drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; | ||
68 | int ret; | ||
96 | 69 | ||
97 | DRM_COPY_FROM_USER_IOCTL(fb, (drm_via_fb_t __user *) data, sizeof(fb)); | 70 | DRM_COPY_FROM_USER_IOCTL(fb, (drm_via_fb_t __user *) data, sizeof(fb)); |
98 | 71 | ||
99 | FBHeap = via_mmInit(fb.offset, fb.size); | 72 | mutex_lock(&dev->struct_mutex); |
73 | ret = drm_sman_set_range(&dev_priv->sman, VIA_MEM_VIDEO, 0, | ||
74 | fb.size >> VIA_MM_ALIGN_SHIFT); | ||
100 | 75 | ||
101 | DRM_DEBUG("offset = %lu, size = %lu", (unsigned long)fb.offset, | 76 | if (ret) { |
102 | (unsigned long)fb.size); | 77 | DRM_ERROR("VRAM memory manager initialisation error\n"); |
78 | mutex_unlock(&dev->struct_mutex); | ||
79 | return ret; | ||
80 | } | ||
103 | 81 | ||
104 | return 0; | 82 | dev_priv->vram_initialized = 1; |
105 | } | 83 | dev_priv->vram_offset = fb.offset; |
106 | 84 | ||
107 | int via_init_context(struct drm_device *dev, int context) | 85 | mutex_unlock(&dev->struct_mutex); |
108 | { | 86 | DRM_DEBUG("offset = %u, size = %u", fb.offset, fb.size); |
109 | int i; | 87 | |
110 | 88 | return 0; | |
111 | for (i = 0; i < MAX_CONTEXT; i++) | ||
112 | if (global_ppriv[i].used && | ||
113 | (global_ppriv[i].context == context)) | ||
114 | break; | ||
115 | |||
116 | if (i >= MAX_CONTEXT) { | ||
117 | for (i = 0; i < MAX_CONTEXT; i++) { | ||
118 | if (!global_ppriv[i].used) { | ||
119 | global_ppriv[i].context = context; | ||
120 | global_ppriv[i].used = 1; | ||
121 | global_ppriv[i].sets[0] = via_setInit(); | ||
122 | global_ppriv[i].sets[1] = via_setInit(); | ||
123 | DRM_DEBUG("init allocation set, socket=%d," | ||
124 | " context = %d\n", i, context); | ||
125 | break; | ||
126 | } | ||
127 | } | ||
128 | |||
129 | if ((i >= MAX_CONTEXT) || (global_ppriv[i].sets[0] == NULL) || | ||
130 | (global_ppriv[i].sets[1] == NULL)) { | ||
131 | return 0; | ||
132 | } | ||
133 | } | ||
134 | 89 | ||
135 | return 1; | ||
136 | } | 90 | } |
137 | 91 | ||
138 | int via_final_context(struct drm_device *dev, int context) | 92 | int via_final_context(struct drm_device *dev, int context) |
139 | { | 93 | { |
140 | int i; | ||
141 | drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; | 94 | drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; |
142 | 95 | ||
143 | for (i = 0; i < MAX_CONTEXT; i++) | ||
144 | if (global_ppriv[i].used && | ||
145 | (global_ppriv[i].context == context)) | ||
146 | break; | ||
147 | |||
148 | if (i < MAX_CONTEXT) { | ||
149 | set_t *set; | ||
150 | ITEM_TYPE item; | ||
151 | int retval; | ||
152 | |||
153 | DRM_DEBUG("find socket %d, context = %d\n", i, context); | ||
154 | |||
155 | /* Video Memory */ | ||
156 | set = global_ppriv[i].sets[0]; | ||
157 | retval = via_setFirst(set, &item); | ||
158 | while (retval) { | ||
159 | DRM_DEBUG("free video memory 0x%lx\n", item); | ||
160 | via_mmFreeMem((PMemBlock) item); | ||
161 | retval = via_setNext(set, &item); | ||
162 | } | ||
163 | via_setDestroy(set); | ||
164 | |||
165 | /* AGP Memory */ | ||
166 | set = global_ppriv[i].sets[1]; | ||
167 | retval = via_setFirst(set, &item); | ||
168 | while (retval) { | ||
169 | DRM_DEBUG("free agp memory 0x%lx\n", item); | ||
170 | via_mmFreeMem((PMemBlock) item); | ||
171 | retval = via_setNext(set, &item); | ||
172 | } | ||
173 | via_setDestroy(set); | ||
174 | global_ppriv[i].used = 0; | ||
175 | } | ||
176 | via_release_futex(dev_priv, context); | 96 | via_release_futex(dev_priv, context); |
177 | 97 | ||
178 | #if defined(__linux__) | ||
179 | /* Linux specific until context tracking code gets ported to BSD */ | 98 | /* Linux specific until context tracking code gets ported to BSD */ |
180 | /* Last context, perform cleanup */ | 99 | /* Last context, perform cleanup */ |
181 | if (dev->ctx_count == 1 && dev->dev_private) { | 100 | if (dev->ctx_count == 1 && dev->dev_private) { |
182 | DRM_DEBUG("Last Context\n"); | 101 | DRM_DEBUG("Last Context\n"); |
183 | if (dev->irq) | 102 | if (dev->irq) |
184 | drm_irq_uninstall(dev); | 103 | drm_irq_uninstall(dev); |
185 | |||
186 | via_cleanup_futex(dev_priv); | 104 | via_cleanup_futex(dev_priv); |
187 | via_do_cleanup_map(dev); | 105 | via_do_cleanup_map(dev); |
188 | } | 106 | } |
189 | #endif | ||
190 | |||
191 | return 1; | 107 | return 1; |
192 | } | 108 | } |
193 | 109 | ||
110 | void via_lastclose(struct drm_device *dev) | ||
111 | { | ||
112 | drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; | ||
113 | |||
114 | if (!dev_priv) | ||
115 | return; | ||
116 | |||
117 | mutex_lock(&dev->struct_mutex); | ||
118 | drm_sman_cleanup(&dev_priv->sman); | ||
119 | dev_priv->vram_initialized = 0; | ||
120 | dev_priv->agp_initialized = 0; | ||
121 | mutex_unlock(&dev->struct_mutex); | ||
122 | } | ||
123 | |||
194 | int via_mem_alloc(DRM_IOCTL_ARGS) | 124 | int via_mem_alloc(DRM_IOCTL_ARGS) |
195 | { | 125 | { |
126 | DRM_DEVICE; | ||
127 | |||
196 | drm_via_mem_t mem; | 128 | drm_via_mem_t mem; |
129 | int retval = 0; | ||
130 | drm_memblock_item_t *item; | ||
131 | drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; | ||
132 | unsigned long tmpSize; | ||
197 | 133 | ||
198 | DRM_COPY_FROM_USER_IOCTL(mem, (drm_via_mem_t __user *) data, | 134 | DRM_COPY_FROM_USER_IOCTL(mem, (drm_via_mem_t __user *) data, |
199 | sizeof(mem)); | 135 | sizeof(mem)); |
200 | 136 | ||
201 | switch (mem.type) { | 137 | if (mem.type > VIA_MEM_AGP) { |
202 | case VIA_MEM_VIDEO: | 138 | DRM_ERROR("Unknown memory type allocation\n"); |
203 | if (via_fb_alloc(&mem) < 0) | 139 | return DRM_ERR(EINVAL); |
204 | return -EFAULT; | ||
205 | DRM_COPY_TO_USER_IOCTL((drm_via_mem_t __user *) data, mem, | ||
206 | sizeof(mem)); | ||
207 | return 0; | ||
208 | case VIA_MEM_AGP: | ||
209 | if (via_agp_alloc(&mem) < 0) | ||
210 | return -EFAULT; | ||
211 | DRM_COPY_TO_USER_IOCTL((drm_via_mem_t __user *) data, mem, | ||
212 | sizeof(mem)); | ||
213 | return 0; | ||
214 | } | 140 | } |
215 | 141 | mutex_lock(&dev->struct_mutex); | |
216 | return -EFAULT; | 142 | if (0 == ((mem.type == VIA_MEM_VIDEO) ? dev_priv->vram_initialized : |
217 | } | 143 | dev_priv->agp_initialized)) { |
218 | 144 | DRM_ERROR | |
219 | static int via_fb_alloc(drm_via_mem_t * mem) | 145 | ("Attempt to allocate from uninitialized memory manager.\n"); |
220 | { | 146 | mutex_unlock(&dev->struct_mutex); |
221 | drm_via_mm_t fb; | 147 | return DRM_ERR(EINVAL); |
222 | PMemBlock block; | ||
223 | int retval = 0; | ||
224 | |||
225 | if (!FBHeap) | ||
226 | return -1; | ||
227 | |||
228 | fb.size = mem->size; | ||
229 | fb.context = mem->context; | ||
230 | |||
231 | block = via_mmAllocMem(FBHeap, fb.size, 5, 0); | ||
232 | if (block) { | ||
233 | fb.offset = block->ofs; | ||
234 | fb.free = (unsigned long)block; | ||
235 | if (!add_alloc_set(fb.context, VIA_MEM_VIDEO, fb.free)) { | ||
236 | DRM_DEBUG("adding to allocation set fails\n"); | ||
237 | via_mmFreeMem((PMemBlock) fb.free); | ||
238 | retval = -1; | ||
239 | } | ||
240 | } else { | ||
241 | fb.offset = 0; | ||
242 | fb.size = 0; | ||
243 | fb.free = 0; | ||
244 | retval = -1; | ||
245 | } | 148 | } |
246 | 149 | ||
247 | mem->offset = fb.offset; | 150 | tmpSize = (mem.size + VIA_MM_ALIGN_MASK) >> VIA_MM_ALIGN_SHIFT; |
248 | mem->index = fb.free; | 151 | item = drm_sman_alloc(&dev_priv->sman, mem.type, tmpSize, 0, |
249 | 152 | (unsigned long)priv); | |
250 | DRM_DEBUG("alloc fb, size = %d, offset = %d\n", fb.size, | 153 | mutex_unlock(&dev->struct_mutex); |
251 | (int)fb.offset); | 154 | if (item) { |
252 | 155 | mem.offset = ((mem.type == VIA_MEM_VIDEO) ? | |
253 | return retval; | 156 | dev_priv->vram_offset : dev_priv->agp_offset) + |
254 | } | 157 | (item->mm-> |
255 | 158 | offset(item->mm, item->mm_info) << VIA_MM_ALIGN_SHIFT); | |
256 | static int via_agp_alloc(drm_via_mem_t * mem) | 159 | mem.index = item->user_hash.key; |
257 | { | ||
258 | drm_via_mm_t agp; | ||
259 | PMemBlock block; | ||
260 | int retval = 0; | ||
261 | |||
262 | if (!AgpHeap) | ||
263 | return -1; | ||
264 | |||
265 | agp.size = mem->size; | ||
266 | agp.context = mem->context; | ||
267 | |||
268 | block = via_mmAllocMem(AgpHeap, agp.size, 5, 0); | ||
269 | if (block) { | ||
270 | agp.offset = block->ofs; | ||
271 | agp.free = (unsigned long)block; | ||
272 | if (!add_alloc_set(agp.context, VIA_MEM_AGP, agp.free)) { | ||
273 | DRM_DEBUG("adding to allocation set fails\n"); | ||
274 | via_mmFreeMem((PMemBlock) agp.free); | ||
275 | retval = -1; | ||
276 | } | ||
277 | } else { | 160 | } else { |
278 | agp.offset = 0; | 161 | mem.offset = 0; |
279 | agp.size = 0; | 162 | mem.size = 0; |
280 | agp.free = 0; | 163 | mem.index = 0; |
164 | DRM_DEBUG("Video memory allocation failed\n"); | ||
165 | retval = DRM_ERR(ENOMEM); | ||
281 | } | 166 | } |
167 | DRM_COPY_TO_USER_IOCTL((drm_via_mem_t __user *) data, mem, sizeof(mem)); | ||
282 | 168 | ||
283 | mem->offset = agp.offset; | ||
284 | mem->index = agp.free; | ||
285 | |||
286 | DRM_DEBUG("alloc agp, size = %d, offset = %d\n", agp.size, | ||
287 | (unsigned int)agp.offset); | ||
288 | return retval; | 169 | return retval; |
289 | } | 170 | } |
290 | 171 | ||
291 | int via_mem_free(DRM_IOCTL_ARGS) | 172 | int via_mem_free(DRM_IOCTL_ARGS) |
292 | { | 173 | { |
174 | DRM_DEVICE; | ||
175 | drm_via_private_t *dev_priv = dev->dev_private; | ||
293 | drm_via_mem_t mem; | 176 | drm_via_mem_t mem; |
177 | int ret; | ||
294 | 178 | ||
295 | DRM_COPY_FROM_USER_IOCTL(mem, (drm_via_mem_t __user *) data, | 179 | DRM_COPY_FROM_USER_IOCTL(mem, (drm_via_mem_t __user *) data, |
296 | sizeof(mem)); | 180 | sizeof(mem)); |
297 | 181 | ||
298 | switch (mem.type) { | 182 | mutex_lock(&dev->struct_mutex); |
183 | ret = drm_sman_free_key(&dev_priv->sman, mem.index); | ||
184 | mutex_unlock(&dev->struct_mutex); | ||
185 | DRM_DEBUG("free = 0x%lx\n", mem.index); | ||
299 | 186 | ||
300 | case VIA_MEM_VIDEO: | 187 | return ret; |
301 | if (via_fb_free(&mem) == 0) | ||
302 | return 0; | ||
303 | break; | ||
304 | case VIA_MEM_AGP: | ||
305 | if (via_agp_free(&mem) == 0) | ||
306 | return 0; | ||
307 | break; | ||
308 | } | ||
309 | |||
310 | return -EFAULT; | ||
311 | } | 188 | } |
312 | 189 | ||
313 | static int via_fb_free(drm_via_mem_t * mem) | ||
314 | { | ||
315 | drm_via_mm_t fb; | ||
316 | int retval = 0; | ||
317 | |||
318 | if (!FBHeap) { | ||
319 | return -1; | ||
320 | } | ||
321 | |||
322 | fb.free = mem->index; | ||
323 | fb.context = mem->context; | ||
324 | |||
325 | if (!fb.free) { | ||
326 | return -1; | ||
327 | |||
328 | } | ||
329 | |||
330 | via_mmFreeMem((PMemBlock) fb.free); | ||
331 | |||
332 | if (!del_alloc_set(fb.context, VIA_MEM_VIDEO, fb.free)) { | ||
333 | retval = -1; | ||
334 | } | ||
335 | |||
336 | DRM_DEBUG("free fb, free = %ld\n", fb.free); | ||
337 | 190 | ||
338 | return retval; | 191 | void via_reclaim_buffers_locked(drm_device_t * dev, struct file *filp) |
339 | } | ||
340 | |||
341 | static int via_agp_free(drm_via_mem_t * mem) | ||
342 | { | 192 | { |
343 | drm_via_mm_t agp; | 193 | drm_via_private_t *dev_priv = dev->dev_private; |
344 | 194 | drm_file_t *priv = filp->private_data; | |
345 | int retval = 0; | ||
346 | 195 | ||
347 | agp.free = mem->index; | 196 | mutex_lock(&dev->struct_mutex); |
348 | agp.context = mem->context; | 197 | if (drm_sman_owner_clean(&dev_priv->sman, (unsigned long)priv)) { |
349 | 198 | mutex_unlock(&dev->struct_mutex); | |
350 | if (!agp.free) | 199 | return; |
351 | return -1; | ||
352 | |||
353 | via_mmFreeMem((PMemBlock) agp.free); | ||
354 | |||
355 | if (!del_alloc_set(agp.context, VIA_MEM_AGP, agp.free)) { | ||
356 | retval = -1; | ||
357 | } | 200 | } |
358 | 201 | ||
359 | DRM_DEBUG("free agp, free = %ld\n", agp.free); | 202 | if (dev->driver->dma_quiescent) { |
203 | dev->driver->dma_quiescent(dev); | ||
204 | } | ||
360 | 205 | ||
361 | return retval; | 206 | drm_sman_owner_cleanup(&dev_priv->sman, (unsigned long)priv); |
207 | mutex_unlock(&dev->struct_mutex); | ||
208 | return; | ||
362 | } | 209 | } |
diff --git a/drivers/char/ds1286.c b/drivers/char/ds1286.c index 21c8229f5443..6d58b0370802 100644 --- a/drivers/char/ds1286.c +++ b/drivers/char/ds1286.c | |||
@@ -104,7 +104,7 @@ static int ds1286_ioctl(struct inode *inode, struct file *file, | |||
104 | switch (cmd) { | 104 | switch (cmd) { |
105 | case RTC_AIE_OFF: /* Mask alarm int. enab. bit */ | 105 | case RTC_AIE_OFF: /* Mask alarm int. enab. bit */ |
106 | { | 106 | { |
107 | unsigned int flags; | 107 | unsigned long flags; |
108 | unsigned char val; | 108 | unsigned char val; |
109 | 109 | ||
110 | if (!capable(CAP_SYS_TIME)) | 110 | if (!capable(CAP_SYS_TIME)) |
@@ -120,7 +120,7 @@ static int ds1286_ioctl(struct inode *inode, struct file *file, | |||
120 | } | 120 | } |
121 | case RTC_AIE_ON: /* Allow alarm interrupts. */ | 121 | case RTC_AIE_ON: /* Allow alarm interrupts. */ |
122 | { | 122 | { |
123 | unsigned int flags; | 123 | unsigned long flags; |
124 | unsigned char val; | 124 | unsigned char val; |
125 | 125 | ||
126 | if (!capable(CAP_SYS_TIME)) | 126 | if (!capable(CAP_SYS_TIME)) |
@@ -136,7 +136,7 @@ static int ds1286_ioctl(struct inode *inode, struct file *file, | |||
136 | } | 136 | } |
137 | case RTC_WIE_OFF: /* Mask watchdog int. enab. bit */ | 137 | case RTC_WIE_OFF: /* Mask watchdog int. enab. bit */ |
138 | { | 138 | { |
139 | unsigned int flags; | 139 | unsigned long flags; |
140 | unsigned char val; | 140 | unsigned char val; |
141 | 141 | ||
142 | if (!capable(CAP_SYS_TIME)) | 142 | if (!capable(CAP_SYS_TIME)) |
@@ -152,7 +152,7 @@ static int ds1286_ioctl(struct inode *inode, struct file *file, | |||
152 | } | 152 | } |
153 | case RTC_WIE_ON: /* Allow watchdog interrupts. */ | 153 | case RTC_WIE_ON: /* Allow watchdog interrupts. */ |
154 | { | 154 | { |
155 | unsigned int flags; | 155 | unsigned long flags; |
156 | unsigned char val; | 156 | unsigned char val; |
157 | 157 | ||
158 | if (!capable(CAP_SYS_TIME)) | 158 | if (!capable(CAP_SYS_TIME)) |
@@ -434,7 +434,7 @@ static inline unsigned char ds1286_is_updating(void) | |||
434 | static void ds1286_get_time(struct rtc_time *rtc_tm) | 434 | static void ds1286_get_time(struct rtc_time *rtc_tm) |
435 | { | 435 | { |
436 | unsigned char save_control; | 436 | unsigned char save_control; |
437 | unsigned int flags; | 437 | unsigned long flags; |
438 | unsigned long uip_watchdog = jiffies; | 438 | unsigned long uip_watchdog = jiffies; |
439 | 439 | ||
440 | /* | 440 | /* |
@@ -494,7 +494,8 @@ static int ds1286_set_time(struct rtc_time *rtc_tm) | |||
494 | { | 494 | { |
495 | unsigned char mon, day, hrs, min, sec, leap_yr; | 495 | unsigned char mon, day, hrs, min, sec, leap_yr; |
496 | unsigned char save_control; | 496 | unsigned char save_control; |
497 | unsigned int yrs, flags; | 497 | unsigned int yrs; |
498 | unsigned long flags; | ||
498 | 499 | ||
499 | 500 | ||
500 | yrs = rtc_tm->tm_year + 1900; | 501 | yrs = rtc_tm->tm_year + 1900; |
@@ -552,7 +553,7 @@ static int ds1286_set_time(struct rtc_time *rtc_tm) | |||
552 | static void ds1286_get_alm_time(struct rtc_time *alm_tm) | 553 | static void ds1286_get_alm_time(struct rtc_time *alm_tm) |
553 | { | 554 | { |
554 | unsigned char cmd; | 555 | unsigned char cmd; |
555 | unsigned int flags; | 556 | unsigned long flags; |
556 | 557 | ||
557 | /* | 558 | /* |
558 | * Only the values that we read from the RTC are set. That | 559 | * Only the values that we read from the RTC are set. That |
diff --git a/drivers/char/epca.c b/drivers/char/epca.c index 86d290e9f307..3baa2ab8cbd4 100644 --- a/drivers/char/epca.c +++ b/drivers/char/epca.c | |||
@@ -1125,7 +1125,7 @@ static void __exit epca_module_exit(void) | |||
1125 | 1125 | ||
1126 | module_exit(epca_module_exit); | 1126 | module_exit(epca_module_exit); |
1127 | 1127 | ||
1128 | static struct tty_operations pc_ops = { | 1128 | static const struct tty_operations pc_ops = { |
1129 | .open = pc_open, | 1129 | .open = pc_open, |
1130 | .close = pc_close, | 1130 | .close = pc_close, |
1131 | .write = pc_write, | 1131 | .write = pc_write, |
diff --git a/drivers/char/esp.c b/drivers/char/esp.c index afcd83d9984b..05788c75d7fc 100644 --- a/drivers/char/esp.c +++ b/drivers/char/esp.c | |||
@@ -2376,7 +2376,7 @@ static inline int autoconfig(struct esp_struct * info) | |||
2376 | return (port_detected); | 2376 | return (port_detected); |
2377 | } | 2377 | } |
2378 | 2378 | ||
2379 | static struct tty_operations esp_ops = { | 2379 | static const struct tty_operations esp_ops = { |
2380 | .open = esp_open, | 2380 | .open = esp_open, |
2381 | .close = rs_close, | 2381 | .close = rs_close, |
2382 | .write = rs_write, | 2382 | .write = rs_write, |
diff --git a/drivers/char/generic_serial.c b/drivers/char/generic_serial.c index 5e59c0b42731..4711d9b3a595 100644 --- a/drivers/char/generic_serial.c +++ b/drivers/char/generic_serial.c | |||
@@ -746,11 +746,9 @@ void gs_set_termios (struct tty_struct * tty, | |||
746 | gs_dprintk (GS_DEBUG_TERMIOS, "termios structure (%p):\n", tiosp); | 746 | gs_dprintk (GS_DEBUG_TERMIOS, "termios structure (%p):\n", tiosp); |
747 | } | 747 | } |
748 | 748 | ||
749 | #if 0 | ||
750 | /* This is an optimization that is only allowed for dumb cards */ | 749 | /* This is an optimization that is only allowed for dumb cards */ |
751 | /* Smart cards require knowledge of iflags and oflags too: that | 750 | /* Smart cards require knowledge of iflags and oflags too: that |
752 | might change hardware cooking mode.... */ | 751 | might change hardware cooking mode.... */ |
753 | #endif | ||
754 | if (old_termios) { | 752 | if (old_termios) { |
755 | if( (tiosp->c_iflag == old_termios->c_iflag) | 753 | if( (tiosp->c_iflag == old_termios->c_iflag) |
756 | && (tiosp->c_oflag == old_termios->c_oflag) | 754 | && (tiosp->c_oflag == old_termios->c_oflag) |
@@ -774,14 +772,7 @@ void gs_set_termios (struct tty_struct * tty, | |||
774 | if(!memcmp(tiosp->c_cc, old_termios->c_cc, NCC)) printk("c_cc changed\n"); | 772 | if(!memcmp(tiosp->c_cc, old_termios->c_cc, NCC)) printk("c_cc changed\n"); |
775 | } | 773 | } |
776 | 774 | ||
777 | baudrate = tiosp->c_cflag & CBAUD; | 775 | baudrate = tty_get_baud_rate(tty); |
778 | if (baudrate & CBAUDEX) { | ||
779 | baudrate &= ~CBAUDEX; | ||
780 | if ((baudrate < 1) || (baudrate > 4)) | ||
781 | tiosp->c_cflag &= ~CBAUDEX; | ||
782 | else | ||
783 | baudrate += 15; | ||
784 | } | ||
785 | 776 | ||
786 | baudrate = gs_baudrates[baudrate]; | 777 | baudrate = gs_baudrates[baudrate]; |
787 | if ((tiosp->c_cflag & CBAUD) == B38400) { | 778 | if ((tiosp->c_cflag & CBAUD) == B38400) { |
diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c index 8afba339f05a..58b0eb581114 100644 --- a/drivers/char/hpet.c +++ b/drivers/char/hpet.c | |||
@@ -868,8 +868,8 @@ int hpet_alloc(struct hpet_data *hdp) | |||
868 | do_div(temp, period); | 868 | do_div(temp, period); |
869 | hpetp->hp_tick_freq = temp; /* ticks per second */ | 869 | hpetp->hp_tick_freq = temp; /* ticks per second */ |
870 | 870 | ||
871 | printk(KERN_INFO "hpet%d: at MMIO 0x%lx (virtual 0x%p), IRQ%s", | 871 | printk(KERN_INFO "hpet%d: at MMIO 0x%lx, IRQ%s", |
872 | hpetp->hp_which, hdp->hd_phys_address, hdp->hd_address, | 872 | hpetp->hp_which, hdp->hd_phys_address, |
873 | hpetp->hp_ntimer > 1 ? "s" : ""); | 873 | hpetp->hp_ntimer > 1 ? "s" : ""); |
874 | for (i = 0; i < hpetp->hp_ntimer; i++) | 874 | for (i = 0; i < hpetp->hp_ntimer; i++) |
875 | printk("%s %d", i > 0 ? "," : "", hdp->hd_irq[i]); | 875 | printk("%s %d", i > 0 ? "," : "", hdp->hd_irq[i]); |
diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c index 613d67f1c7f0..4053d1cd393f 100644 --- a/drivers/char/hvc_console.c +++ b/drivers/char/hvc_console.c | |||
@@ -80,7 +80,8 @@ struct hvc_struct { | |||
80 | struct tty_struct *tty; | 80 | struct tty_struct *tty; |
81 | unsigned int count; | 81 | unsigned int count; |
82 | int do_wakeup; | 82 | int do_wakeup; |
83 | char outbuf[N_OUTBUF] __ALIGNED__; | 83 | char *outbuf; |
84 | int outbuf_size; | ||
84 | int n_outbuf; | 85 | int n_outbuf; |
85 | uint32_t vtermno; | 86 | uint32_t vtermno; |
86 | struct hv_ops *ops; | 87 | struct hv_ops *ops; |
@@ -319,10 +320,8 @@ static int hvc_open(struct tty_struct *tty, struct file * filp) | |||
319 | struct kobject *kobjp; | 320 | struct kobject *kobjp; |
320 | 321 | ||
321 | /* Auto increments kobject reference if found. */ | 322 | /* Auto increments kobject reference if found. */ |
322 | if (!(hp = hvc_get_by_index(tty->index))) { | 323 | if (!(hp = hvc_get_by_index(tty->index))) |
323 | printk(KERN_WARNING "hvc_console: tty open failed, no vty associated with tty.\n"); | ||
324 | return -ENODEV; | 324 | return -ENODEV; |
325 | } | ||
326 | 325 | ||
327 | spin_lock_irqsave(&hp->lock, flags); | 326 | spin_lock_irqsave(&hp->lock, flags); |
328 | /* Check and then increment for fast path open. */ | 327 | /* Check and then increment for fast path open. */ |
@@ -505,7 +504,7 @@ static int hvc_write(struct tty_struct *tty, const unsigned char *buf, int count | |||
505 | if (hp->n_outbuf > 0) | 504 | if (hp->n_outbuf > 0) |
506 | hvc_push(hp); | 505 | hvc_push(hp); |
507 | 506 | ||
508 | while (count > 0 && (rsize = N_OUTBUF - hp->n_outbuf) > 0) { | 507 | while (count > 0 && (rsize = hp->outbuf_size - hp->n_outbuf) > 0) { |
509 | if (rsize > count) | 508 | if (rsize > count) |
510 | rsize = count; | 509 | rsize = count; |
511 | memcpy(hp->outbuf + hp->n_outbuf, buf, rsize); | 510 | memcpy(hp->outbuf + hp->n_outbuf, buf, rsize); |
@@ -538,7 +537,7 @@ static int hvc_write_room(struct tty_struct *tty) | |||
538 | if (!hp) | 537 | if (!hp) |
539 | return -1; | 538 | return -1; |
540 | 539 | ||
541 | return N_OUTBUF - hp->n_outbuf; | 540 | return hp->outbuf_size - hp->n_outbuf; |
542 | } | 541 | } |
543 | 542 | ||
544 | static int hvc_chars_in_buffer(struct tty_struct *tty) | 543 | static int hvc_chars_in_buffer(struct tty_struct *tty) |
@@ -697,7 +696,7 @@ int khvcd(void *unused) | |||
697 | return 0; | 696 | return 0; |
698 | } | 697 | } |
699 | 698 | ||
700 | static struct tty_operations hvc_ops = { | 699 | static const struct tty_operations hvc_ops = { |
701 | .open = hvc_open, | 700 | .open = hvc_open, |
702 | .close = hvc_close, | 701 | .close = hvc_close, |
703 | .write = hvc_write, | 702 | .write = hvc_write, |
@@ -729,12 +728,13 @@ static struct kobj_type hvc_kobj_type = { | |||
729 | }; | 728 | }; |
730 | 729 | ||
731 | struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int irq, | 730 | struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int irq, |
732 | struct hv_ops *ops) | 731 | struct hv_ops *ops, int outbuf_size) |
733 | { | 732 | { |
734 | struct hvc_struct *hp; | 733 | struct hvc_struct *hp; |
735 | int i; | 734 | int i; |
736 | 735 | ||
737 | hp = kmalloc(sizeof(*hp), GFP_KERNEL); | 736 | hp = kmalloc(ALIGN(sizeof(*hp), sizeof(long)) + outbuf_size, |
737 | GFP_KERNEL); | ||
738 | if (!hp) | 738 | if (!hp) |
739 | return ERR_PTR(-ENOMEM); | 739 | return ERR_PTR(-ENOMEM); |
740 | 740 | ||
@@ -743,6 +743,8 @@ struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int irq, | |||
743 | hp->vtermno = vtermno; | 743 | hp->vtermno = vtermno; |
744 | hp->irq = irq; | 744 | hp->irq = irq; |
745 | hp->ops = ops; | 745 | hp->ops = ops; |
746 | hp->outbuf_size = outbuf_size; | ||
747 | hp->outbuf = &((char *)hp)[ALIGN(sizeof(*hp), sizeof(long))]; | ||
746 | 748 | ||
747 | kobject_init(&hp->kobj); | 749 | kobject_init(&hp->kobj); |
748 | hp->kobj.ktype = &hvc_kobj_type; | 750 | hp->kobj.ktype = &hvc_kobj_type; |
diff --git a/drivers/char/hvc_console.h b/drivers/char/hvc_console.h index 96b7401319c1..8c59818050e6 100644 --- a/drivers/char/hvc_console.h +++ b/drivers/char/hvc_console.h | |||
@@ -56,7 +56,7 @@ extern int hvc_instantiate(uint32_t vtermno, int index, struct hv_ops *ops); | |||
56 | 56 | ||
57 | /* register a vterm for hvc tty operation (module_init or hotplug add) */ | 57 | /* register a vterm for hvc tty operation (module_init or hotplug add) */ |
58 | extern struct hvc_struct * __devinit hvc_alloc(uint32_t vtermno, int irq, | 58 | extern struct hvc_struct * __devinit hvc_alloc(uint32_t vtermno, int irq, |
59 | struct hv_ops *ops); | 59 | struct hv_ops *ops, int outbuf_size); |
60 | /* remove a vterm from hvc tty operation (modele_exit or hotplug remove) */ | 60 | /* remove a vterm from hvc tty operation (modele_exit or hotplug remove) */ |
61 | extern int __devexit hvc_remove(struct hvc_struct *hp); | 61 | extern int __devexit hvc_remove(struct hvc_struct *hp); |
62 | 62 | ||
diff --git a/drivers/char/hvc_iseries.c b/drivers/char/hvc_iseries.c new file mode 100644 index 000000000000..4747729459c7 --- /dev/null +++ b/drivers/char/hvc_iseries.c | |||
@@ -0,0 +1,594 @@ | |||
1 | /* | ||
2 | * iSeries vio driver interface to hvc_console.c | ||
3 | * | ||
4 | * This code is based heavily on hvc_vio.c and viocons.c | ||
5 | * | ||
6 | * Copyright (C) 2006 Stephen Rothwell, IBM Corporation | ||
7 | * | ||
8 | * 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 | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
21 | */ | ||
22 | #include <stdarg.h> | ||
23 | #include <linux/types.h> | ||
24 | #include <linux/init.h> | ||
25 | #include <linux/kernel.h> | ||
26 | #include <linux/spinlock.h> | ||
27 | #include <linux/console.h> | ||
28 | |||
29 | #include <asm/hvconsole.h> | ||
30 | #include <asm/vio.h> | ||
31 | #include <asm/prom.h> | ||
32 | #include <asm/iseries/vio.h> | ||
33 | #include <asm/iseries/hv_call.h> | ||
34 | #include <asm/iseries/hv_lp_config.h> | ||
35 | #include <asm/iseries/hv_lp_event.h> | ||
36 | |||
37 | #include "hvc_console.h" | ||
38 | |||
39 | #define VTTY_PORTS 10 | ||
40 | |||
41 | static DEFINE_SPINLOCK(consolelock); | ||
42 | static DEFINE_SPINLOCK(consoleloglock); | ||
43 | |||
44 | static const char hvc_driver_name[] = "hvc_console"; | ||
45 | |||
46 | #define IN_BUF_SIZE 200 | ||
47 | |||
48 | /* | ||
49 | * Our port information. | ||
50 | */ | ||
51 | static struct port_info { | ||
52 | HvLpIndex lp; | ||
53 | u64 seq; /* sequence number of last HV send */ | ||
54 | u64 ack; /* last ack from HV */ | ||
55 | struct hvc_struct *hp; | ||
56 | int in_start; | ||
57 | int in_end; | ||
58 | unsigned char in_buf[IN_BUF_SIZE]; | ||
59 | } port_info[VTTY_PORTS] = { | ||
60 | [ 0 ... VTTY_PORTS - 1 ] = { | ||
61 | .lp = HvLpIndexInvalid | ||
62 | } | ||
63 | }; | ||
64 | |||
65 | #define viochar_is_console(pi) ((pi) == &port_info[0]) | ||
66 | |||
67 | static struct vio_device_id hvc_driver_table[] __devinitdata = { | ||
68 | {"serial", "IBM,iSeries-vty"}, | ||
69 | { "", "" } | ||
70 | }; | ||
71 | MODULE_DEVICE_TABLE(vio, hvc_driver_table); | ||
72 | |||
73 | static void hvlog(char *fmt, ...) | ||
74 | { | ||
75 | int i; | ||
76 | unsigned long flags; | ||
77 | va_list args; | ||
78 | static char buf[256]; | ||
79 | |||
80 | spin_lock_irqsave(&consoleloglock, flags); | ||
81 | va_start(args, fmt); | ||
82 | i = vscnprintf(buf, sizeof(buf) - 1, fmt, args); | ||
83 | va_end(args); | ||
84 | buf[i++] = '\r'; | ||
85 | HvCall_writeLogBuffer(buf, i); | ||
86 | spin_unlock_irqrestore(&consoleloglock, flags); | ||
87 | } | ||
88 | |||
89 | /* | ||
90 | * Initialize the common fields in a charLpEvent | ||
91 | */ | ||
92 | static void init_data_event(struct viocharlpevent *viochar, HvLpIndex lp) | ||
93 | { | ||
94 | struct HvLpEvent *hev = &viochar->event; | ||
95 | |||
96 | memset(viochar, 0, sizeof(struct viocharlpevent)); | ||
97 | |||
98 | hev->flags = HV_LP_EVENT_VALID | HV_LP_EVENT_DEFERRED_ACK | | ||
99 | HV_LP_EVENT_INT; | ||
100 | hev->xType = HvLpEvent_Type_VirtualIo; | ||
101 | hev->xSubtype = viomajorsubtype_chario | viochardata; | ||
102 | hev->xSourceLp = HvLpConfig_getLpIndex(); | ||
103 | hev->xTargetLp = lp; | ||
104 | hev->xSizeMinus1 = sizeof(struct viocharlpevent); | ||
105 | hev->xSourceInstanceId = viopath_sourceinst(lp); | ||
106 | hev->xTargetInstanceId = viopath_targetinst(lp); | ||
107 | } | ||
108 | |||
109 | static int get_chars(uint32_t vtermno, char *buf, int count) | ||
110 | { | ||
111 | struct port_info *pi; | ||
112 | int n = 0; | ||
113 | unsigned long flags; | ||
114 | |||
115 | if (vtermno >= VTTY_PORTS) | ||
116 | return -EINVAL; | ||
117 | if (count == 0) | ||
118 | return 0; | ||
119 | |||
120 | pi = &port_info[vtermno]; | ||
121 | spin_lock_irqsave(&consolelock, flags); | ||
122 | |||
123 | if (pi->in_end == 0) | ||
124 | goto done; | ||
125 | |||
126 | n = pi->in_end - pi->in_start; | ||
127 | if (n > count) | ||
128 | n = count; | ||
129 | memcpy(buf, &pi->in_buf[pi->in_start], n); | ||
130 | pi->in_start += n; | ||
131 | if (pi->in_start == pi->in_end) { | ||
132 | pi->in_start = 0; | ||
133 | pi->in_end = 0; | ||
134 | } | ||
135 | done: | ||
136 | spin_unlock_irqrestore(&consolelock, flags); | ||
137 | return n; | ||
138 | } | ||
139 | |||
140 | static int put_chars(uint32_t vtermno, const char *buf, int count) | ||
141 | { | ||
142 | struct viocharlpevent *viochar; | ||
143 | struct port_info *pi; | ||
144 | HvLpEvent_Rc hvrc; | ||
145 | unsigned long flags; | ||
146 | int sent = 0; | ||
147 | |||
148 | if (vtermno >= VTTY_PORTS) | ||
149 | return -EINVAL; | ||
150 | |||
151 | pi = &port_info[vtermno]; | ||
152 | |||
153 | spin_lock_irqsave(&consolelock, flags); | ||
154 | |||
155 | if (viochar_is_console(pi) && !viopath_isactive(pi->lp)) { | ||
156 | spin_lock_irqsave(&consoleloglock, flags); | ||
157 | HvCall_writeLogBuffer(buf, count); | ||
158 | spin_unlock_irqrestore(&consoleloglock, flags); | ||
159 | sent = count; | ||
160 | goto done; | ||
161 | } | ||
162 | |||
163 | viochar = vio_get_event_buffer(viomajorsubtype_chario); | ||
164 | if (viochar == NULL) { | ||
165 | hvlog("\n\rviocons: Can't get viochar buffer."); | ||
166 | goto done; | ||
167 | } | ||
168 | |||
169 | while ((count > 0) && ((pi->seq - pi->ack) < VIOCHAR_WINDOW)) { | ||
170 | int len; | ||
171 | |||
172 | len = (count > VIOCHAR_MAX_DATA) ? VIOCHAR_MAX_DATA : count; | ||
173 | |||
174 | if (viochar_is_console(pi)) { | ||
175 | spin_lock_irqsave(&consoleloglock, flags); | ||
176 | HvCall_writeLogBuffer(buf, len); | ||
177 | spin_unlock_irqrestore(&consoleloglock, flags); | ||
178 | } | ||
179 | |||
180 | init_data_event(viochar, pi->lp); | ||
181 | |||
182 | viochar->len = len; | ||
183 | viochar->event.xCorrelationToken = pi->seq++; | ||
184 | viochar->event.xSizeMinus1 = | ||
185 | offsetof(struct viocharlpevent, data) + len; | ||
186 | |||
187 | memcpy(viochar->data, buf, len); | ||
188 | |||
189 | hvrc = HvCallEvent_signalLpEvent(&viochar->event); | ||
190 | if (hvrc) | ||
191 | hvlog("\n\rerror sending event! return code %d\n\r", | ||
192 | (int)hvrc); | ||
193 | sent += len; | ||
194 | count -= len; | ||
195 | buf += len; | ||
196 | } | ||
197 | |||
198 | vio_free_event_buffer(viomajorsubtype_chario, viochar); | ||
199 | done: | ||
200 | spin_unlock_irqrestore(&consolelock, flags); | ||
201 | return sent; | ||
202 | } | ||
203 | |||
204 | static struct hv_ops hvc_get_put_ops = { | ||
205 | .get_chars = get_chars, | ||
206 | .put_chars = put_chars, | ||
207 | }; | ||
208 | |||
209 | static int __devinit hvc_vio_probe(struct vio_dev *vdev, | ||
210 | const struct vio_device_id *id) | ||
211 | { | ||
212 | struct hvc_struct *hp; | ||
213 | struct port_info *pi; | ||
214 | |||
215 | /* probed with invalid parameters. */ | ||
216 | if (!vdev || !id) | ||
217 | return -EPERM; | ||
218 | |||
219 | if (vdev->unit_address >= VTTY_PORTS) | ||
220 | return -ENODEV; | ||
221 | |||
222 | pi = &port_info[vdev->unit_address]; | ||
223 | |||
224 | hp = hvc_alloc(vdev->unit_address, vdev->irq, &hvc_get_put_ops, | ||
225 | VIOCHAR_MAX_DATA); | ||
226 | if (IS_ERR(hp)) | ||
227 | return PTR_ERR(hp); | ||
228 | pi->hp = hp; | ||
229 | dev_set_drvdata(&vdev->dev, pi); | ||
230 | |||
231 | return 0; | ||
232 | } | ||
233 | |||
234 | static int __devexit hvc_vio_remove(struct vio_dev *vdev) | ||
235 | { | ||
236 | struct port_info *pi = dev_get_drvdata(&vdev->dev); | ||
237 | struct hvc_struct *hp = pi->hp; | ||
238 | |||
239 | return hvc_remove(hp); | ||
240 | } | ||
241 | |||
242 | static struct vio_driver hvc_vio_driver = { | ||
243 | .id_table = hvc_driver_table, | ||
244 | .probe = hvc_vio_probe, | ||
245 | .remove = hvc_vio_remove, | ||
246 | .driver = { | ||
247 | .name = hvc_driver_name, | ||
248 | .owner = THIS_MODULE, | ||
249 | } | ||
250 | }; | ||
251 | |||
252 | static void hvc_open_event(struct HvLpEvent *event) | ||
253 | { | ||
254 | unsigned long flags; | ||
255 | struct viocharlpevent *cevent = (struct viocharlpevent *)event; | ||
256 | u8 port = cevent->virtual_device; | ||
257 | struct port_info *pi; | ||
258 | int reject = 0; | ||
259 | |||
260 | if (hvlpevent_is_ack(event)) { | ||
261 | if (port >= VTTY_PORTS) | ||
262 | return; | ||
263 | |||
264 | spin_lock_irqsave(&consolelock, flags); | ||
265 | |||
266 | pi = &port_info[port]; | ||
267 | if (event->xRc == HvLpEvent_Rc_Good) { | ||
268 | pi->seq = pi->ack = 0; | ||
269 | /* | ||
270 | * This line allows connections from the primary | ||
271 | * partition but once one is connected from the | ||
272 | * primary partition nothing short of a reboot | ||
273 | * of linux will allow access from the hosting | ||
274 | * partition again without a required iSeries fix. | ||
275 | */ | ||
276 | pi->lp = event->xTargetLp; | ||
277 | } | ||
278 | |||
279 | spin_unlock_irqrestore(&consolelock, flags); | ||
280 | if (event->xRc != HvLpEvent_Rc_Good) | ||
281 | printk(KERN_WARNING | ||
282 | "hvc: handle_open_event: event->xRc == (%d).\n", | ||
283 | event->xRc); | ||
284 | |||
285 | if (event->xCorrelationToken != 0) { | ||
286 | atomic_t *aptr= (atomic_t *)event->xCorrelationToken; | ||
287 | atomic_set(aptr, 1); | ||
288 | } else | ||
289 | printk(KERN_WARNING | ||
290 | "hvc: weird...got open ack without atomic\n"); | ||
291 | return; | ||
292 | } | ||
293 | |||
294 | /* This had better require an ack, otherwise complain */ | ||
295 | if (!hvlpevent_need_ack(event)) { | ||
296 | printk(KERN_WARNING "hvc: viocharopen without ack bit!\n"); | ||
297 | return; | ||
298 | } | ||
299 | |||
300 | spin_lock_irqsave(&consolelock, flags); | ||
301 | |||
302 | /* Make sure this is a good virtual tty */ | ||
303 | if (port >= VTTY_PORTS) { | ||
304 | event->xRc = HvLpEvent_Rc_SubtypeError; | ||
305 | cevent->subtype_result_code = viorc_openRejected; | ||
306 | /* | ||
307 | * Flag state here since we can't printk while holding | ||
308 | * the consolelock spinlock. | ||
309 | */ | ||
310 | reject = 1; | ||
311 | } else { | ||
312 | pi = &port_info[port]; | ||
313 | if ((pi->lp != HvLpIndexInvalid) && | ||
314 | (pi->lp != event->xSourceLp)) { | ||
315 | /* | ||
316 | * If this is tty is already connected to a different | ||
317 | * partition, fail. | ||
318 | */ | ||
319 | event->xRc = HvLpEvent_Rc_SubtypeError; | ||
320 | cevent->subtype_result_code = viorc_openRejected; | ||
321 | reject = 2; | ||
322 | } else { | ||
323 | pi->lp = event->xSourceLp; | ||
324 | event->xRc = HvLpEvent_Rc_Good; | ||
325 | cevent->subtype_result_code = viorc_good; | ||
326 | pi->seq = pi->ack = 0; | ||
327 | } | ||
328 | } | ||
329 | |||
330 | spin_unlock_irqrestore(&consolelock, flags); | ||
331 | |||
332 | if (reject == 1) | ||
333 | printk(KERN_WARNING "hvc: open rejected: bad virtual tty.\n"); | ||
334 | else if (reject == 2) | ||
335 | printk(KERN_WARNING "hvc: open rejected: console in exclusive " | ||
336 | "use by another partition.\n"); | ||
337 | |||
338 | /* Return the acknowledgement */ | ||
339 | HvCallEvent_ackLpEvent(event); | ||
340 | } | ||
341 | |||
342 | /* | ||
343 | * Handle a close charLpEvent. This should ONLY be an Interrupt because the | ||
344 | * virtual console should never actually issue a close event to the hypervisor | ||
345 | * because the virtual console never goes away. A close event coming from the | ||
346 | * hypervisor simply means that there are no client consoles connected to the | ||
347 | * virtual console. | ||
348 | */ | ||
349 | static void hvc_close_event(struct HvLpEvent *event) | ||
350 | { | ||
351 | unsigned long flags; | ||
352 | struct viocharlpevent *cevent = (struct viocharlpevent *)event; | ||
353 | u8 port = cevent->virtual_device; | ||
354 | |||
355 | if (!hvlpevent_is_int(event)) { | ||
356 | printk(KERN_WARNING | ||
357 | "hvc: got unexpected close acknowlegement\n"); | ||
358 | return; | ||
359 | } | ||
360 | |||
361 | if (port >= VTTY_PORTS) { | ||
362 | printk(KERN_WARNING | ||
363 | "hvc: close message from invalid virtual device.\n"); | ||
364 | return; | ||
365 | } | ||
366 | |||
367 | /* For closes, just mark the console partition invalid */ | ||
368 | spin_lock_irqsave(&consolelock, flags); | ||
369 | |||
370 | if (port_info[port].lp == event->xSourceLp) | ||
371 | port_info[port].lp = HvLpIndexInvalid; | ||
372 | |||
373 | spin_unlock_irqrestore(&consolelock, flags); | ||
374 | } | ||
375 | |||
376 | static void hvc_data_event(struct HvLpEvent *event) | ||
377 | { | ||
378 | unsigned long flags; | ||
379 | struct viocharlpevent *cevent = (struct viocharlpevent *)event; | ||
380 | struct port_info *pi; | ||
381 | int n; | ||
382 | u8 port = cevent->virtual_device; | ||
383 | |||
384 | if (port >= VTTY_PORTS) { | ||
385 | printk(KERN_WARNING "hvc: data on invalid virtual device %d\n", | ||
386 | port); | ||
387 | return; | ||
388 | } | ||
389 | if (cevent->len == 0) | ||
390 | return; | ||
391 | |||
392 | /* | ||
393 | * Change 05/01/2003 - Ryan Arnold: If a partition other than | ||
394 | * the current exclusive partition tries to send us data | ||
395 | * events then just drop them on the floor because we don't | ||
396 | * want his stinking data. He isn't authorized to receive | ||
397 | * data because he wasn't the first one to get the console, | ||
398 | * therefore he shouldn't be allowed to send data either. | ||
399 | * This will work without an iSeries fix. | ||
400 | */ | ||
401 | pi = &port_info[port]; | ||
402 | if (pi->lp != event->xSourceLp) | ||
403 | return; | ||
404 | |||
405 | spin_lock_irqsave(&consolelock, flags); | ||
406 | |||
407 | n = IN_BUF_SIZE - pi->in_end; | ||
408 | if (n > cevent->len) | ||
409 | n = cevent->len; | ||
410 | if (n > 0) { | ||
411 | memcpy(&pi->in_buf[pi->in_end], cevent->data, n); | ||
412 | pi->in_end += n; | ||
413 | } | ||
414 | spin_unlock_irqrestore(&consolelock, flags); | ||
415 | if (n == 0) | ||
416 | printk(KERN_WARNING "hvc: input buffer overflow\n"); | ||
417 | } | ||
418 | |||
419 | static void hvc_ack_event(struct HvLpEvent *event) | ||
420 | { | ||
421 | struct viocharlpevent *cevent = (struct viocharlpevent *)event; | ||
422 | unsigned long flags; | ||
423 | u8 port = cevent->virtual_device; | ||
424 | |||
425 | if (port >= VTTY_PORTS) { | ||
426 | printk(KERN_WARNING "hvc: data on invalid virtual device\n"); | ||
427 | return; | ||
428 | } | ||
429 | |||
430 | spin_lock_irqsave(&consolelock, flags); | ||
431 | port_info[port].ack = event->xCorrelationToken; | ||
432 | spin_unlock_irqrestore(&consolelock, flags); | ||
433 | } | ||
434 | |||
435 | static void hvc_config_event(struct HvLpEvent *event) | ||
436 | { | ||
437 | struct viocharlpevent *cevent = (struct viocharlpevent *)event; | ||
438 | |||
439 | if (cevent->data[0] == 0x01) | ||
440 | printk(KERN_INFO "hvc: window resized to %d: %d: %d: %d\n", | ||
441 | cevent->data[1], cevent->data[2], | ||
442 | cevent->data[3], cevent->data[4]); | ||
443 | else | ||
444 | printk(KERN_WARNING "hvc: unknown config event\n"); | ||
445 | } | ||
446 | |||
447 | static void hvc_handle_event(struct HvLpEvent *event) | ||
448 | { | ||
449 | int charminor; | ||
450 | |||
451 | if (event == NULL) | ||
452 | return; | ||
453 | |||
454 | charminor = event->xSubtype & VIOMINOR_SUBTYPE_MASK; | ||
455 | switch (charminor) { | ||
456 | case viocharopen: | ||
457 | hvc_open_event(event); | ||
458 | break; | ||
459 | case viocharclose: | ||
460 | hvc_close_event(event); | ||
461 | break; | ||
462 | case viochardata: | ||
463 | hvc_data_event(event); | ||
464 | break; | ||
465 | case viocharack: | ||
466 | hvc_ack_event(event); | ||
467 | break; | ||
468 | case viocharconfig: | ||
469 | hvc_config_event(event); | ||
470 | break; | ||
471 | default: | ||
472 | if (hvlpevent_is_int(event) && hvlpevent_need_ack(event)) { | ||
473 | event->xRc = HvLpEvent_Rc_InvalidSubtype; | ||
474 | HvCallEvent_ackLpEvent(event); | ||
475 | } | ||
476 | } | ||
477 | } | ||
478 | |||
479 | static int send_open(HvLpIndex remoteLp, void *sem) | ||
480 | { | ||
481 | return HvCallEvent_signalLpEventFast(remoteLp, | ||
482 | HvLpEvent_Type_VirtualIo, | ||
483 | viomajorsubtype_chario | viocharopen, | ||
484 | HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, | ||
485 | viopath_sourceinst(remoteLp), | ||
486 | viopath_targetinst(remoteLp), | ||
487 | (u64)(unsigned long)sem, VIOVERSION << 16, | ||
488 | 0, 0, 0, 0); | ||
489 | } | ||
490 | |||
491 | static int hvc_vio_init(void) | ||
492 | { | ||
493 | atomic_t wait_flag; | ||
494 | int rc; | ||
495 | |||
496 | /* +2 for fudge */ | ||
497 | rc = viopath_open(HvLpConfig_getPrimaryLpIndex(), | ||
498 | viomajorsubtype_chario, VIOCHAR_WINDOW + 2); | ||
499 | if (rc) | ||
500 | printk(KERN_WARNING "hvc: error opening to primary %d\n", rc); | ||
501 | |||
502 | if (viopath_hostLp == HvLpIndexInvalid) | ||
503 | vio_set_hostlp(); | ||
504 | |||
505 | /* | ||
506 | * And if the primary is not the same as the hosting LP, open to the | ||
507 | * hosting lp | ||
508 | */ | ||
509 | if ((viopath_hostLp != HvLpIndexInvalid) && | ||
510 | (viopath_hostLp != HvLpConfig_getPrimaryLpIndex())) { | ||
511 | printk(KERN_INFO "hvc: open path to hosting (%d)\n", | ||
512 | viopath_hostLp); | ||
513 | rc = viopath_open(viopath_hostLp, viomajorsubtype_chario, | ||
514 | VIOCHAR_WINDOW + 2); /* +2 for fudge */ | ||
515 | if (rc) | ||
516 | printk(KERN_WARNING | ||
517 | "error opening to partition %d: %d\n", | ||
518 | viopath_hostLp, rc); | ||
519 | } | ||
520 | |||
521 | if (vio_setHandler(viomajorsubtype_chario, hvc_handle_event) < 0) | ||
522 | printk(KERN_WARNING | ||
523 | "hvc: error seting handler for console events!\n"); | ||
524 | |||
525 | /* | ||
526 | * First, try to open the console to the hosting lp. | ||
527 | * Wait on a semaphore for the response. | ||
528 | */ | ||
529 | atomic_set(&wait_flag, 0); | ||
530 | if ((viopath_isactive(viopath_hostLp)) && | ||
531 | (send_open(viopath_hostLp, &wait_flag) == 0)) { | ||
532 | printk(KERN_INFO "hvc: hosting partition %d\n", viopath_hostLp); | ||
533 | while (atomic_read(&wait_flag) == 0) | ||
534 | mb(); | ||
535 | atomic_set(&wait_flag, 0); | ||
536 | } | ||
537 | |||
538 | /* | ||
539 | * If we don't have an active console, try the primary | ||
540 | */ | ||
541 | if ((!viopath_isactive(port_info[0].lp)) && | ||
542 | (viopath_isactive(HvLpConfig_getPrimaryLpIndex())) && | ||
543 | (send_open(HvLpConfig_getPrimaryLpIndex(), &wait_flag) == 0)) { | ||
544 | printk(KERN_INFO "hvc: opening console to primary partition\n"); | ||
545 | while (atomic_read(&wait_flag) == 0) | ||
546 | mb(); | ||
547 | } | ||
548 | |||
549 | /* Register as a vio device to receive callbacks */ | ||
550 | rc = vio_register_driver(&hvc_vio_driver); | ||
551 | |||
552 | return rc; | ||
553 | } | ||
554 | module_init(hvc_vio_init); /* after drivers/char/hvc_console.c */ | ||
555 | |||
556 | static void hvc_vio_exit(void) | ||
557 | { | ||
558 | vio_unregister_driver(&hvc_vio_driver); | ||
559 | } | ||
560 | module_exit(hvc_vio_exit); | ||
561 | |||
562 | /* the device tree order defines our numbering */ | ||
563 | static int hvc_find_vtys(void) | ||
564 | { | ||
565 | struct device_node *vty; | ||
566 | int num_found = 0; | ||
567 | |||
568 | for (vty = of_find_node_by_name(NULL, "vty"); vty != NULL; | ||
569 | vty = of_find_node_by_name(vty, "vty")) { | ||
570 | uint32_t *vtermno; | ||
571 | |||
572 | /* We have statically defined space for only a certain number | ||
573 | * of console adapters. | ||
574 | */ | ||
575 | if ((num_found >= MAX_NR_HVC_CONSOLES) || | ||
576 | (num_found >= VTTY_PORTS)) | ||
577 | break; | ||
578 | |||
579 | vtermno = (uint32_t *)get_property(vty, "reg", NULL); | ||
580 | if (!vtermno) | ||
581 | continue; | ||
582 | |||
583 | if (!device_is_compatible(vty, "IBM,iSeries-vty")) | ||
584 | continue; | ||
585 | |||
586 | if (num_found == 0) | ||
587 | add_preferred_console("hvc", 0, NULL); | ||
588 | hvc_instantiate(*vtermno, num_found, &hvc_get_put_ops); | ||
589 | ++num_found; | ||
590 | } | ||
591 | |||
592 | return num_found; | ||
593 | } | ||
594 | console_initcall(hvc_find_vtys); | ||
diff --git a/drivers/char/hvc_rtas.c b/drivers/char/hvc_rtas.c index 57106e02fd2e..4b97eaf18602 100644 --- a/drivers/char/hvc_rtas.c +++ b/drivers/char/hvc_rtas.c | |||
@@ -94,7 +94,7 @@ static int hvc_rtas_init(void) | |||
94 | 94 | ||
95 | /* Allocate an hvc_struct for the console device we instantiated | 95 | /* Allocate an hvc_struct for the console device we instantiated |
96 | * earlier. Save off hp so that we can return it on exit */ | 96 | * earlier. Save off hp so that we can return it on exit */ |
97 | hp = hvc_alloc(hvc_rtas_cookie, NO_IRQ, &hvc_rtas_get_put_ops); | 97 | hp = hvc_alloc(hvc_rtas_cookie, NO_IRQ, &hvc_rtas_get_put_ops, 16); |
98 | if (IS_ERR(hp)) | 98 | if (IS_ERR(hp)) |
99 | return PTR_ERR(hp); | 99 | return PTR_ERR(hp); |
100 | 100 | ||
diff --git a/drivers/char/hvc_vio.c b/drivers/char/hvc_vio.c index 9add81ceb440..cc95941148fb 100644 --- a/drivers/char/hvc_vio.c +++ b/drivers/char/hvc_vio.c | |||
@@ -90,7 +90,8 @@ static int __devinit hvc_vio_probe(struct vio_dev *vdev, | |||
90 | if (!vdev || !id) | 90 | if (!vdev || !id) |
91 | return -EPERM; | 91 | return -EPERM; |
92 | 92 | ||
93 | hp = hvc_alloc(vdev->unit_address, vdev->irq, &hvc_get_put_ops); | 93 | hp = hvc_alloc(vdev->unit_address, vdev->irq, &hvc_get_put_ops, |
94 | MAX_VIO_PUT_CHARS); | ||
94 | if (IS_ERR(hp)) | 95 | if (IS_ERR(hp)) |
95 | return PTR_ERR(hp); | 96 | return PTR_ERR(hp); |
96 | dev_set_drvdata(&vdev->dev, hp); | 97 | dev_set_drvdata(&vdev->dev, hp); |
@@ -140,7 +141,7 @@ static int hvc_find_vtys(void) | |||
140 | 141 | ||
141 | for (vty = of_find_node_by_name(NULL, "vty"); vty != NULL; | 142 | for (vty = of_find_node_by_name(NULL, "vty"); vty != NULL; |
142 | vty = of_find_node_by_name(vty, "vty")) { | 143 | vty = of_find_node_by_name(vty, "vty")) { |
143 | uint32_t *vtermno; | 144 | const uint32_t *vtermno; |
144 | 145 | ||
145 | /* We have statically defined space for only a certain number | 146 | /* We have statically defined space for only a certain number |
146 | * of console adapters. | 147 | * of console adapters. |
@@ -148,7 +149,7 @@ static int hvc_find_vtys(void) | |||
148 | if (num_found >= MAX_NR_HVC_CONSOLES) | 149 | if (num_found >= MAX_NR_HVC_CONSOLES) |
149 | break; | 150 | break; |
150 | 151 | ||
151 | vtermno = (uint32_t *)get_property(vty, "reg", NULL); | 152 | vtermno = get_property(vty, "reg", NULL); |
152 | if (!vtermno) | 153 | if (!vtermno) |
153 | continue; | 154 | continue; |
154 | 155 | ||
diff --git a/drivers/char/hvcs.c b/drivers/char/hvcs.c index 4589ff302b07..0b89bcde8c52 100644 --- a/drivers/char/hvcs.c +++ b/drivers/char/hvcs.c | |||
@@ -1306,7 +1306,7 @@ static int hvcs_chars_in_buffer(struct tty_struct *tty) | |||
1306 | return hvcsd->chars_in_buffer; | 1306 | return hvcsd->chars_in_buffer; |
1307 | } | 1307 | } |
1308 | 1308 | ||
1309 | static struct tty_operations hvcs_ops = { | 1309 | static const struct tty_operations hvcs_ops = { |
1310 | .open = hvcs_open, | 1310 | .open = hvcs_open, |
1311 | .close = hvcs_close, | 1311 | .close = hvcs_close, |
1312 | .hangup = hvcs_hangup, | 1312 | .hangup = hvcs_hangup, |
diff --git a/drivers/char/hvsi.c b/drivers/char/hvsi.c index 017f755632a3..c07dc58d5c1d 100644 --- a/drivers/char/hvsi.c +++ b/drivers/char/hvsi.c | |||
@@ -1130,7 +1130,7 @@ static int hvsi_tiocmset(struct tty_struct *tty, struct file *file, | |||
1130 | } | 1130 | } |
1131 | 1131 | ||
1132 | 1132 | ||
1133 | static struct tty_operations hvsi_ops = { | 1133 | static const struct tty_operations hvsi_ops = { |
1134 | .open = hvsi_open, | 1134 | .open = hvsi_open, |
1135 | .close = hvsi_close, | 1135 | .close = hvsi_close, |
1136 | .write = hvsi_write, | 1136 | .write = hvsi_write, |
@@ -1274,11 +1274,10 @@ static int __init hvsi_console_init(void) | |||
1274 | vty != NULL; | 1274 | vty != NULL; |
1275 | vty = of_find_compatible_node(vty, "serial", "hvterm-protocol")) { | 1275 | vty = of_find_compatible_node(vty, "serial", "hvterm-protocol")) { |
1276 | struct hvsi_struct *hp; | 1276 | struct hvsi_struct *hp; |
1277 | uint32_t *vtermno; | 1277 | const uint32_t *vtermno, *irq; |
1278 | uint32_t *irq; | ||
1279 | 1278 | ||
1280 | vtermno = (uint32_t *)get_property(vty, "reg", NULL); | 1279 | vtermno = get_property(vty, "reg", NULL); |
1281 | irq = (uint32_t *)get_property(vty, "interrupts", NULL); | 1280 | irq = get_property(vty, "interrupts", NULL); |
1282 | if (!vtermno || !irq) | 1281 | if (!vtermno || !irq) |
1283 | continue; | 1282 | continue; |
1284 | 1283 | ||
diff --git a/drivers/char/hw_random/intel-rng.c b/drivers/char/hw_random/intel-rng.c index ccd7e7102234..8efbc9c0e545 100644 --- a/drivers/char/hw_random/intel-rng.c +++ b/drivers/char/hw_random/intel-rng.c | |||
@@ -50,6 +50,43 @@ | |||
50 | #define INTEL_RNG_ADDR_LEN 3 | 50 | #define INTEL_RNG_ADDR_LEN 3 |
51 | 51 | ||
52 | /* | 52 | /* |
53 | * LPC bridge PCI config space registers | ||
54 | */ | ||
55 | #define FWH_DEC_EN1_REG_OLD 0xe3 | ||
56 | #define FWH_DEC_EN1_REG_NEW 0xd9 /* high byte of 16-bit register */ | ||
57 | #define FWH_F8_EN_MASK 0x80 | ||
58 | |||
59 | #define BIOS_CNTL_REG_OLD 0x4e | ||
60 | #define BIOS_CNTL_REG_NEW 0xdc | ||
61 | #define BIOS_CNTL_WRITE_ENABLE_MASK 0x01 | ||
62 | #define BIOS_CNTL_LOCK_ENABLE_MASK 0x02 | ||
63 | |||
64 | /* | ||
65 | * Magic address at which Intel Firmware Hubs get accessed | ||
66 | */ | ||
67 | #define INTEL_FWH_ADDR 0xffff0000 | ||
68 | #define INTEL_FWH_ADDR_LEN 2 | ||
69 | |||
70 | /* | ||
71 | * Intel Firmware Hub command codes (write to any address inside the device) | ||
72 | */ | ||
73 | #define INTEL_FWH_RESET_CMD 0xff /* aka READ_ARRAY */ | ||
74 | #define INTEL_FWH_READ_ID_CMD 0x90 | ||
75 | |||
76 | /* | ||
77 | * Intel Firmware Hub Read ID command result addresses | ||
78 | */ | ||
79 | #define INTEL_FWH_MANUFACTURER_CODE_ADDRESS 0x000000 | ||
80 | #define INTEL_FWH_DEVICE_CODE_ADDRESS 0x000001 | ||
81 | |||
82 | /* | ||
83 | * Intel Firmware Hub Read ID command result values | ||
84 | */ | ||
85 | #define INTEL_FWH_MANUFACTURER_CODE 0x89 | ||
86 | #define INTEL_FWH_DEVICE_CODE_8M 0xac | ||
87 | #define INTEL_FWH_DEVICE_CODE_4M 0xad | ||
88 | |||
89 | /* | ||
53 | * Data for PCI driver interface | 90 | * Data for PCI driver interface |
54 | * | 91 | * |
55 | * This data only exists for exporting the supported | 92 | * This data only exists for exporting the supported |
@@ -58,12 +95,50 @@ | |||
58 | * want to register another driver on the same PCI id. | 95 | * want to register another driver on the same PCI id. |
59 | */ | 96 | */ |
60 | static const struct pci_device_id pci_tbl[] = { | 97 | static const struct pci_device_id pci_tbl[] = { |
61 | { 0x8086, 0x2418, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, | 98 | /* AA |
62 | { 0x8086, 0x2428, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, | 99 | { 0x8086, 0x2418, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, */ |
63 | { 0x8086, 0x2430, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, | 100 | { 0x8086, 0x2410, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* AA */ |
64 | { 0x8086, 0x2448, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, | 101 | /* AB |
65 | { 0x8086, 0x244e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, | 102 | { 0x8086, 0x2428, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, */ |
66 | { 0x8086, 0x245e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, | 103 | { 0x8086, 0x2420, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* AB */ |
104 | /* ?? | ||
105 | { 0x8086, 0x2430, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, */ | ||
106 | /* BAM, CAM, DBM, FBM, GxM | ||
107 | { 0x8086, 0x2448, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, */ | ||
108 | { 0x8086, 0x244c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* BAM */ | ||
109 | { 0x8086, 0x248c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* CAM */ | ||
110 | { 0x8086, 0x24cc, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* DBM */ | ||
111 | { 0x8086, 0x2641, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* FBM */ | ||
112 | { 0x8086, 0x27b9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* GxM */ | ||
113 | { 0x8086, 0x27bd, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* GxM DH */ | ||
114 | /* BA, CA, DB, Ex, 6300, Fx, 631x/632x, Gx | ||
115 | { 0x8086, 0x244e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, */ | ||
116 | { 0x8086, 0x2440, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* BA */ | ||
117 | { 0x8086, 0x2480, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* CA */ | ||
118 | { 0x8086, 0x24c0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* DB */ | ||
119 | { 0x8086, 0x24d0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* Ex */ | ||
120 | { 0x8086, 0x25a1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 6300 */ | ||
121 | { 0x8086, 0x2640, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* Fx */ | ||
122 | { 0x8086, 0x2670, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */ | ||
123 | { 0x8086, 0x2671, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */ | ||
124 | { 0x8086, 0x2672, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */ | ||
125 | { 0x8086, 0x2673, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */ | ||
126 | { 0x8086, 0x2674, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */ | ||
127 | { 0x8086, 0x2675, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */ | ||
128 | { 0x8086, 0x2676, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */ | ||
129 | { 0x8086, 0x2677, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */ | ||
130 | { 0x8086, 0x2678, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */ | ||
131 | { 0x8086, 0x2679, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */ | ||
132 | { 0x8086, 0x267a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */ | ||
133 | { 0x8086, 0x267b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */ | ||
134 | { 0x8086, 0x267c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */ | ||
135 | { 0x8086, 0x267d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */ | ||
136 | { 0x8086, 0x267e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */ | ||
137 | { 0x8086, 0x267f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */ | ||
138 | { 0x8086, 0x27b8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* Gx */ | ||
139 | /* E | ||
140 | { 0x8086, 0x245e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, */ | ||
141 | { 0x8086, 0x2450, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* E */ | ||
67 | { 0, }, /* terminate list */ | 142 | { 0, }, /* terminate list */ |
68 | }; | 143 | }; |
69 | MODULE_DEVICE_TABLE(pci, pci_tbl); | 144 | MODULE_DEVICE_TABLE(pci, pci_tbl); |
@@ -138,22 +213,115 @@ static struct hwrng intel_rng = { | |||
138 | }; | 213 | }; |
139 | 214 | ||
140 | 215 | ||
216 | #ifdef CONFIG_SMP | ||
217 | static char __initdata waitflag; | ||
218 | |||
219 | static void __init intel_init_wait(void *unused) | ||
220 | { | ||
221 | while (waitflag) | ||
222 | cpu_relax(); | ||
223 | } | ||
224 | #endif | ||
225 | |||
141 | static int __init mod_init(void) | 226 | static int __init mod_init(void) |
142 | { | 227 | { |
143 | int err = -ENODEV; | 228 | int err = -ENODEV; |
229 | unsigned i; | ||
230 | struct pci_dev *dev = NULL; | ||
144 | void __iomem *mem; | 231 | void __iomem *mem; |
145 | u8 hw_status; | 232 | unsigned long flags; |
233 | u8 bios_cntl_off, fwh_dec_en1_off; | ||
234 | u8 bios_cntl_val = 0xff, fwh_dec_en1_val = 0xff; | ||
235 | u8 hw_status, mfc, dvc; | ||
146 | 236 | ||
147 | if (!pci_dev_present(pci_tbl)) | 237 | for (i = 0; !dev && pci_tbl[i].vendor; ++i) |
238 | dev = pci_get_device(pci_tbl[i].vendor, pci_tbl[i].device, NULL); | ||
239 | |||
240 | if (!dev) | ||
148 | goto out; /* Device not found. */ | 241 | goto out; /* Device not found. */ |
149 | 242 | ||
243 | /* Check for Intel 82802 */ | ||
244 | if (dev->device < 0x2640) { | ||
245 | fwh_dec_en1_off = FWH_DEC_EN1_REG_OLD; | ||
246 | bios_cntl_off = BIOS_CNTL_REG_OLD; | ||
247 | } else { | ||
248 | fwh_dec_en1_off = FWH_DEC_EN1_REG_NEW; | ||
249 | bios_cntl_off = BIOS_CNTL_REG_NEW; | ||
250 | } | ||
251 | |||
252 | pci_read_config_byte(dev, fwh_dec_en1_off, &fwh_dec_en1_val); | ||
253 | pci_read_config_byte(dev, bios_cntl_off, &bios_cntl_val); | ||
254 | |||
255 | mem = ioremap_nocache(INTEL_FWH_ADDR, INTEL_FWH_ADDR_LEN); | ||
256 | if (mem == NULL) { | ||
257 | pci_dev_put(dev); | ||
258 | err = -EBUSY; | ||
259 | goto out; | ||
260 | } | ||
261 | |||
262 | /* | ||
263 | * Since the BIOS code/data is going to disappear from its normal | ||
264 | * location with the Read ID command, all activity on the system | ||
265 | * must be stopped until the state is back to normal. | ||
266 | */ | ||
267 | #ifdef CONFIG_SMP | ||
268 | set_mb(waitflag, 1); | ||
269 | if (smp_call_function(intel_init_wait, NULL, 1, 0) != 0) { | ||
270 | set_mb(waitflag, 0); | ||
271 | pci_dev_put(dev); | ||
272 | printk(KERN_ERR PFX "cannot run on all processors\n"); | ||
273 | err = -EAGAIN; | ||
274 | goto err_unmap; | ||
275 | } | ||
276 | #endif | ||
277 | local_irq_save(flags); | ||
278 | |||
279 | if (!(fwh_dec_en1_val & FWH_F8_EN_MASK)) | ||
280 | pci_write_config_byte(dev, | ||
281 | fwh_dec_en1_off, | ||
282 | fwh_dec_en1_val | FWH_F8_EN_MASK); | ||
283 | if (!(bios_cntl_val & | ||
284 | (BIOS_CNTL_LOCK_ENABLE_MASK|BIOS_CNTL_WRITE_ENABLE_MASK))) | ||
285 | pci_write_config_byte(dev, | ||
286 | bios_cntl_off, | ||
287 | bios_cntl_val | BIOS_CNTL_WRITE_ENABLE_MASK); | ||
288 | |||
289 | writeb(INTEL_FWH_RESET_CMD, mem); | ||
290 | writeb(INTEL_FWH_READ_ID_CMD, mem); | ||
291 | mfc = readb(mem + INTEL_FWH_MANUFACTURER_CODE_ADDRESS); | ||
292 | dvc = readb(mem + INTEL_FWH_DEVICE_CODE_ADDRESS); | ||
293 | writeb(INTEL_FWH_RESET_CMD, mem); | ||
294 | |||
295 | if (!(bios_cntl_val & | ||
296 | (BIOS_CNTL_LOCK_ENABLE_MASK|BIOS_CNTL_WRITE_ENABLE_MASK))) | ||
297 | pci_write_config_byte(dev, bios_cntl_off, bios_cntl_val); | ||
298 | if (!(fwh_dec_en1_val & FWH_F8_EN_MASK)) | ||
299 | pci_write_config_byte(dev, fwh_dec_en1_off, fwh_dec_en1_val); | ||
300 | |||
301 | local_irq_restore(flags); | ||
302 | #ifdef CONFIG_SMP | ||
303 | /* Tell other CPUs to resume. */ | ||
304 | set_mb(waitflag, 0); | ||
305 | #endif | ||
306 | |||
307 | iounmap(mem); | ||
308 | pci_dev_put(dev); | ||
309 | |||
310 | if (mfc != INTEL_FWH_MANUFACTURER_CODE || | ||
311 | (dvc != INTEL_FWH_DEVICE_CODE_8M && | ||
312 | dvc != INTEL_FWH_DEVICE_CODE_4M)) { | ||
313 | printk(KERN_ERR PFX "FWH not detected\n"); | ||
314 | err = -ENODEV; | ||
315 | goto out; | ||
316 | } | ||
317 | |||
150 | err = -ENOMEM; | 318 | err = -ENOMEM; |
151 | mem = ioremap(INTEL_RNG_ADDR, INTEL_RNG_ADDR_LEN); | 319 | mem = ioremap(INTEL_RNG_ADDR, INTEL_RNG_ADDR_LEN); |
152 | if (!mem) | 320 | if (!mem) |
153 | goto out; | 321 | goto out; |
154 | intel_rng.priv = (unsigned long)mem; | 322 | intel_rng.priv = (unsigned long)mem; |
155 | 323 | ||
156 | /* Check for Intel 82802 */ | 324 | /* Check for Random Number Generator */ |
157 | err = -ENODEV; | 325 | err = -ENODEV; |
158 | hw_status = hwstatus_get(mem); | 326 | hw_status = hwstatus_get(mem); |
159 | if ((hw_status & INTEL_RNG_PRESENT) == 0) | 327 | if ((hw_status & INTEL_RNG_PRESENT) == 0) |
diff --git a/drivers/char/ip2/ip2main.c b/drivers/char/ip2/ip2main.c index 7907ae88c2f4..4828bc914ce3 100644 --- a/drivers/char/ip2/ip2main.c +++ b/drivers/char/ip2/ip2main.c | |||
@@ -436,6 +436,7 @@ cleanup_module(void) | |||
436 | #ifdef CONFIG_PCI | 436 | #ifdef CONFIG_PCI |
437 | if (ip2config.type[i] == PCI && ip2config.pci_dev[i]) { | 437 | if (ip2config.type[i] == PCI && ip2config.pci_dev[i]) { |
438 | pci_disable_device(ip2config.pci_dev[i]); | 438 | pci_disable_device(ip2config.pci_dev[i]); |
439 | pci_dev_put(ip2config.pci_dev[i]); | ||
439 | ip2config.pci_dev[i] = NULL; | 440 | ip2config.pci_dev[i] = NULL; |
440 | } | 441 | } |
441 | #endif | 442 | #endif |
@@ -457,7 +458,7 @@ cleanup_module(void) | |||
457 | } | 458 | } |
458 | #endif /* MODULE */ | 459 | #endif /* MODULE */ |
459 | 460 | ||
460 | static struct tty_operations ip2_ops = { | 461 | static const struct tty_operations ip2_ops = { |
461 | .open = ip2_open, | 462 | .open = ip2_open, |
462 | .close = ip2_close, | 463 | .close = ip2_close, |
463 | .write = ip2_write, | 464 | .write = ip2_write, |
@@ -505,6 +506,7 @@ ip2_loadmain(int *iop, int *irqp, unsigned char *firmware, int firmsize) | |||
505 | static int loaded; | 506 | static int loaded; |
506 | i2eBordStrPtr pB = NULL; | 507 | i2eBordStrPtr pB = NULL; |
507 | int rc = -1; | 508 | int rc = -1; |
509 | static struct pci_dev *pci_dev_i = NULL; | ||
508 | 510 | ||
509 | ip2trace (ITRC_NO_PORT, ITRC_INIT, ITRC_ENTER, 0 ); | 511 | ip2trace (ITRC_NO_PORT, ITRC_INIT, ITRC_ENTER, 0 ); |
510 | 512 | ||
@@ -588,8 +590,7 @@ ip2_loadmain(int *iop, int *irqp, unsigned char *firmware, int firmsize) | |||
588 | case PCI: | 590 | case PCI: |
589 | #ifdef CONFIG_PCI | 591 | #ifdef CONFIG_PCI |
590 | { | 592 | { |
591 | struct pci_dev *pci_dev_i = NULL; | 593 | pci_dev_i = pci_get_device(PCI_VENDOR_ID_COMPUTONE, |
592 | pci_dev_i = pci_find_device(PCI_VENDOR_ID_COMPUTONE, | ||
593 | PCI_DEVICE_ID_COMPUTONE_IP2EX, pci_dev_i); | 594 | PCI_DEVICE_ID_COMPUTONE_IP2EX, pci_dev_i); |
594 | if (pci_dev_i != NULL) { | 595 | if (pci_dev_i != NULL) { |
595 | unsigned int addr; | 596 | unsigned int addr; |
@@ -600,7 +601,7 @@ ip2_loadmain(int *iop, int *irqp, unsigned char *firmware, int firmsize) | |||
600 | break; | 601 | break; |
601 | } | 602 | } |
602 | ip2config.type[i] = PCI; | 603 | ip2config.type[i] = PCI; |
603 | ip2config.pci_dev[i] = pci_dev_i; | 604 | ip2config.pci_dev[i] = pci_dev_get(pci_dev_i); |
604 | status = | 605 | status = |
605 | pci_read_config_dword(pci_dev_i, PCI_BASE_ADDRESS_1, &addr); | 606 | pci_read_config_dword(pci_dev_i, PCI_BASE_ADDRESS_1, &addr); |
606 | if ( addr & 1 ) { | 607 | if ( addr & 1 ) { |
@@ -641,6 +642,9 @@ ip2_loadmain(int *iop, int *irqp, unsigned char *firmware, int firmsize) | |||
641 | break; | 642 | break; |
642 | } /* switch */ | 643 | } /* switch */ |
643 | } /* for */ | 644 | } /* for */ |
645 | if (pci_dev_i) | ||
646 | pci_dev_put(pci_dev_i); | ||
647 | |||
644 | for ( i = 0; i < IP2_MAX_BOARDS; ++i ) { | 648 | for ( i = 0; i < IP2_MAX_BOARDS; ++i ) { |
645 | if ( ip2config.addr[i] ) { | 649 | if ( ip2config.addr[i] ) { |
646 | pB = kmalloc( sizeof(i2eBordStr), GFP_KERNEL); | 650 | pB = kmalloc( sizeof(i2eBordStr), GFP_KERNEL); |
diff --git a/drivers/char/ipmi/ipmi_devintf.c b/drivers/char/ipmi/ipmi_devintf.c index 68d7c61a864e..81fcf0ce21d1 100644 --- a/drivers/char/ipmi/ipmi_devintf.c +++ b/drivers/char/ipmi/ipmi_devintf.c | |||
@@ -377,7 +377,8 @@ static int ipmi_ioctl(struct inode *inode, | |||
377 | break; | 377 | break; |
378 | } | 378 | } |
379 | 379 | ||
380 | rv = ipmi_register_for_cmd(priv->user, val.netfn, val.cmd); | 380 | rv = ipmi_register_for_cmd(priv->user, val.netfn, val.cmd, |
381 | IPMI_CHAN_ALL); | ||
381 | break; | 382 | break; |
382 | } | 383 | } |
383 | 384 | ||
@@ -390,7 +391,36 @@ static int ipmi_ioctl(struct inode *inode, | |||
390 | break; | 391 | break; |
391 | } | 392 | } |
392 | 393 | ||
393 | rv = ipmi_unregister_for_cmd(priv->user, val.netfn, val.cmd); | 394 | rv = ipmi_unregister_for_cmd(priv->user, val.netfn, val.cmd, |
395 | IPMI_CHAN_ALL); | ||
396 | break; | ||
397 | } | ||
398 | |||
399 | case IPMICTL_REGISTER_FOR_CMD_CHANS: | ||
400 | { | ||
401 | struct ipmi_cmdspec_chans val; | ||
402 | |||
403 | if (copy_from_user(&val, arg, sizeof(val))) { | ||
404 | rv = -EFAULT; | ||
405 | break; | ||
406 | } | ||
407 | |||
408 | rv = ipmi_register_for_cmd(priv->user, val.netfn, val.cmd, | ||
409 | val.chans); | ||
410 | break; | ||
411 | } | ||
412 | |||
413 | case IPMICTL_UNREGISTER_FOR_CMD_CHANS: | ||
414 | { | ||
415 | struct ipmi_cmdspec_chans val; | ||
416 | |||
417 | if (copy_from_user(&val, arg, sizeof(val))) { | ||
418 | rv = -EFAULT; | ||
419 | break; | ||
420 | } | ||
421 | |||
422 | rv = ipmi_unregister_for_cmd(priv->user, val.netfn, val.cmd, | ||
423 | val.chans); | ||
394 | break; | 424 | break; |
395 | } | 425 | } |
396 | 426 | ||
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index 843d34c8627c..2455e8d478ac 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c | |||
@@ -96,6 +96,7 @@ struct cmd_rcvr | |||
96 | ipmi_user_t user; | 96 | ipmi_user_t user; |
97 | unsigned char netfn; | 97 | unsigned char netfn; |
98 | unsigned char cmd; | 98 | unsigned char cmd; |
99 | unsigned int chans; | ||
99 | 100 | ||
100 | /* | 101 | /* |
101 | * This is used to form a linked lised during mass deletion. | 102 | * This is used to form a linked lised during mass deletion. |
@@ -953,24 +954,41 @@ int ipmi_set_gets_events(ipmi_user_t user, int val) | |||
953 | 954 | ||
954 | static struct cmd_rcvr *find_cmd_rcvr(ipmi_smi_t intf, | 955 | static struct cmd_rcvr *find_cmd_rcvr(ipmi_smi_t intf, |
955 | unsigned char netfn, | 956 | unsigned char netfn, |
956 | unsigned char cmd) | 957 | unsigned char cmd, |
958 | unsigned char chan) | ||
957 | { | 959 | { |
958 | struct cmd_rcvr *rcvr; | 960 | struct cmd_rcvr *rcvr; |
959 | 961 | ||
960 | list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link) { | 962 | list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link) { |
961 | if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)) | 963 | if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd) |
964 | && (rcvr->chans & (1 << chan))) | ||
962 | return rcvr; | 965 | return rcvr; |
963 | } | 966 | } |
964 | return NULL; | 967 | return NULL; |
965 | } | 968 | } |
966 | 969 | ||
970 | static int is_cmd_rcvr_exclusive(ipmi_smi_t intf, | ||
971 | unsigned char netfn, | ||
972 | unsigned char cmd, | ||
973 | unsigned int chans) | ||
974 | { | ||
975 | struct cmd_rcvr *rcvr; | ||
976 | |||
977 | list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link) { | ||
978 | if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd) | ||
979 | && (rcvr->chans & chans)) | ||
980 | return 0; | ||
981 | } | ||
982 | return 1; | ||
983 | } | ||
984 | |||
967 | int ipmi_register_for_cmd(ipmi_user_t user, | 985 | int ipmi_register_for_cmd(ipmi_user_t user, |
968 | unsigned char netfn, | 986 | unsigned char netfn, |
969 | unsigned char cmd) | 987 | unsigned char cmd, |
988 | unsigned int chans) | ||
970 | { | 989 | { |
971 | ipmi_smi_t intf = user->intf; | 990 | ipmi_smi_t intf = user->intf; |
972 | struct cmd_rcvr *rcvr; | 991 | struct cmd_rcvr *rcvr; |
973 | struct cmd_rcvr *entry; | ||
974 | int rv = 0; | 992 | int rv = 0; |
975 | 993 | ||
976 | 994 | ||
@@ -979,12 +997,12 @@ int ipmi_register_for_cmd(ipmi_user_t user, | |||
979 | return -ENOMEM; | 997 | return -ENOMEM; |
980 | rcvr->cmd = cmd; | 998 | rcvr->cmd = cmd; |
981 | rcvr->netfn = netfn; | 999 | rcvr->netfn = netfn; |
1000 | rcvr->chans = chans; | ||
982 | rcvr->user = user; | 1001 | rcvr->user = user; |
983 | 1002 | ||
984 | mutex_lock(&intf->cmd_rcvrs_mutex); | 1003 | mutex_lock(&intf->cmd_rcvrs_mutex); |
985 | /* Make sure the command/netfn is not already registered. */ | 1004 | /* Make sure the command/netfn is not already registered. */ |
986 | entry = find_cmd_rcvr(intf, netfn, cmd); | 1005 | if (!is_cmd_rcvr_exclusive(intf, netfn, cmd, chans)) { |
987 | if (entry) { | ||
988 | rv = -EBUSY; | 1006 | rv = -EBUSY; |
989 | goto out_unlock; | 1007 | goto out_unlock; |
990 | } | 1008 | } |
@@ -1001,24 +1019,39 @@ int ipmi_register_for_cmd(ipmi_user_t user, | |||
1001 | 1019 | ||
1002 | int ipmi_unregister_for_cmd(ipmi_user_t user, | 1020 | int ipmi_unregister_for_cmd(ipmi_user_t user, |
1003 | unsigned char netfn, | 1021 | unsigned char netfn, |
1004 | unsigned char cmd) | 1022 | unsigned char cmd, |
1023 | unsigned int chans) | ||
1005 | { | 1024 | { |
1006 | ipmi_smi_t intf = user->intf; | 1025 | ipmi_smi_t intf = user->intf; |
1007 | struct cmd_rcvr *rcvr; | 1026 | struct cmd_rcvr *rcvr; |
1027 | struct cmd_rcvr *rcvrs = NULL; | ||
1028 | int i, rv = -ENOENT; | ||
1008 | 1029 | ||
1009 | mutex_lock(&intf->cmd_rcvrs_mutex); | 1030 | mutex_lock(&intf->cmd_rcvrs_mutex); |
1010 | /* Make sure the command/netfn is not already registered. */ | 1031 | for (i = 0; i < IPMI_NUM_CHANNELS; i++) { |
1011 | rcvr = find_cmd_rcvr(intf, netfn, cmd); | 1032 | if (((1 << i) & chans) == 0) |
1012 | if ((rcvr) && (rcvr->user == user)) { | 1033 | continue; |
1013 | list_del_rcu(&rcvr->link); | 1034 | rcvr = find_cmd_rcvr(intf, netfn, cmd, i); |
1014 | mutex_unlock(&intf->cmd_rcvrs_mutex); | 1035 | if (rcvr == NULL) |
1015 | synchronize_rcu(); | 1036 | continue; |
1037 | if (rcvr->user == user) { | ||
1038 | rv = 0; | ||
1039 | rcvr->chans &= ~chans; | ||
1040 | if (rcvr->chans == 0) { | ||
1041 | list_del_rcu(&rcvr->link); | ||
1042 | rcvr->next = rcvrs; | ||
1043 | rcvrs = rcvr; | ||
1044 | } | ||
1045 | } | ||
1046 | } | ||
1047 | mutex_unlock(&intf->cmd_rcvrs_mutex); | ||
1048 | synchronize_rcu(); | ||
1049 | while (rcvrs) { | ||
1050 | rcvr = rcvrs; | ||
1051 | rcvrs = rcvr->next; | ||
1016 | kfree(rcvr); | 1052 | kfree(rcvr); |
1017 | return 0; | ||
1018 | } else { | ||
1019 | mutex_unlock(&intf->cmd_rcvrs_mutex); | ||
1020 | return -ENOENT; | ||
1021 | } | 1053 | } |
1054 | return rv; | ||
1022 | } | 1055 | } |
1023 | 1056 | ||
1024 | void ipmi_user_set_run_to_completion(ipmi_user_t user, int val) | 1057 | void ipmi_user_set_run_to_completion(ipmi_user_t user, int val) |
@@ -2548,6 +2581,7 @@ static int handle_ipmb_get_msg_cmd(ipmi_smi_t intf, | |||
2548 | int rv = 0; | 2581 | int rv = 0; |
2549 | unsigned char netfn; | 2582 | unsigned char netfn; |
2550 | unsigned char cmd; | 2583 | unsigned char cmd; |
2584 | unsigned char chan; | ||
2551 | ipmi_user_t user = NULL; | 2585 | ipmi_user_t user = NULL; |
2552 | struct ipmi_ipmb_addr *ipmb_addr; | 2586 | struct ipmi_ipmb_addr *ipmb_addr; |
2553 | struct ipmi_recv_msg *recv_msg; | 2587 | struct ipmi_recv_msg *recv_msg; |
@@ -2568,9 +2602,10 @@ static int handle_ipmb_get_msg_cmd(ipmi_smi_t intf, | |||
2568 | 2602 | ||
2569 | netfn = msg->rsp[4] >> 2; | 2603 | netfn = msg->rsp[4] >> 2; |
2570 | cmd = msg->rsp[8]; | 2604 | cmd = msg->rsp[8]; |
2605 | chan = msg->rsp[3] & 0xf; | ||
2571 | 2606 | ||
2572 | rcu_read_lock(); | 2607 | rcu_read_lock(); |
2573 | rcvr = find_cmd_rcvr(intf, netfn, cmd); | 2608 | rcvr = find_cmd_rcvr(intf, netfn, cmd, chan); |
2574 | if (rcvr) { | 2609 | if (rcvr) { |
2575 | user = rcvr->user; | 2610 | user = rcvr->user; |
2576 | kref_get(&user->refcount); | 2611 | kref_get(&user->refcount); |
@@ -2728,6 +2763,7 @@ static int handle_lan_get_msg_cmd(ipmi_smi_t intf, | |||
2728 | int rv = 0; | 2763 | int rv = 0; |
2729 | unsigned char netfn; | 2764 | unsigned char netfn; |
2730 | unsigned char cmd; | 2765 | unsigned char cmd; |
2766 | unsigned char chan; | ||
2731 | ipmi_user_t user = NULL; | 2767 | ipmi_user_t user = NULL; |
2732 | struct ipmi_lan_addr *lan_addr; | 2768 | struct ipmi_lan_addr *lan_addr; |
2733 | struct ipmi_recv_msg *recv_msg; | 2769 | struct ipmi_recv_msg *recv_msg; |
@@ -2748,9 +2784,10 @@ static int handle_lan_get_msg_cmd(ipmi_smi_t intf, | |||
2748 | 2784 | ||
2749 | netfn = msg->rsp[6] >> 2; | 2785 | netfn = msg->rsp[6] >> 2; |
2750 | cmd = msg->rsp[10]; | 2786 | cmd = msg->rsp[10]; |
2787 | chan = msg->rsp[3] & 0xf; | ||
2751 | 2788 | ||
2752 | rcu_read_lock(); | 2789 | rcu_read_lock(); |
2753 | rcvr = find_cmd_rcvr(intf, netfn, cmd); | 2790 | rcvr = find_cmd_rcvr(intf, netfn, cmd, chan); |
2754 | if (rcvr) { | 2791 | if (rcvr) { |
2755 | user = rcvr->user; | 2792 | user = rcvr->user; |
2756 | kref_get(&user->refcount); | 2793 | kref_get(&user->refcount); |
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index abca98beac14..908521e36d81 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c | |||
@@ -916,7 +916,11 @@ static int smi_start_processing(void *send_info, | |||
916 | new_smi->last_timeout_jiffies = jiffies; | 916 | new_smi->last_timeout_jiffies = jiffies; |
917 | mod_timer(&new_smi->si_timer, jiffies + SI_TIMEOUT_JIFFIES); | 917 | mod_timer(&new_smi->si_timer, jiffies + SI_TIMEOUT_JIFFIES); |
918 | 918 | ||
919 | if (new_smi->si_type != SI_BT) { | 919 | /* |
920 | * The BT interface is efficient enough to not need a thread, | ||
921 | * and there is no need for a thread if we have interrupts. | ||
922 | */ | ||
923 | if ((new_smi->si_type != SI_BT) && (!new_smi->irq)) { | ||
920 | new_smi->thread = kthread_run(ipmi_thread, new_smi, | 924 | new_smi->thread = kthread_run(ipmi_thread, new_smi, |
921 | "kipmi%d", new_smi->intf_num); | 925 | "kipmi%d", new_smi->intf_num); |
922 | if (IS_ERR(new_smi->thread)) { | 926 | if (IS_ERR(new_smi->thread)) { |
diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c index 913be23e0a24..ea2bbf80ad33 100644 --- a/drivers/char/isicom.c +++ b/drivers/char/isicom.c | |||
@@ -1550,7 +1550,7 @@ static void isicom_unregister_ioregion(struct pci_dev *pdev) | |||
1550 | board->base = 0; | 1550 | board->base = 0; |
1551 | } | 1551 | } |
1552 | 1552 | ||
1553 | static struct tty_operations isicom_ops = { | 1553 | static const struct tty_operations isicom_ops = { |
1554 | .open = isicom_open, | 1554 | .open = isicom_open, |
1555 | .close = isicom_close, | 1555 | .close = isicom_close, |
1556 | .write = isicom_write, | 1556 | .write = isicom_write, |
@@ -1756,9 +1756,12 @@ static int __devinit load_firmware(struct pci_dev *pdev, | |||
1756 | if (retval) | 1756 | if (retval) |
1757 | goto end; | 1757 | goto end; |
1758 | 1758 | ||
1759 | retval = -EIO; | ||
1760 | |||
1759 | for (frame = (struct stframe *)fw->data; | 1761 | for (frame = (struct stframe *)fw->data; |
1760 | frame < (struct stframe *)(fw->data + fw->size); | 1762 | frame < (struct stframe *)(fw->data + fw->size); |
1761 | frame++) { | 1763 | frame = (struct stframe *)((u8 *)(frame + 1) + |
1764 | frame->count)) { | ||
1762 | if (WaitTillCardIsFree(base)) | 1765 | if (WaitTillCardIsFree(base)) |
1763 | goto errrelfw; | 1766 | goto errrelfw; |
1764 | 1767 | ||
@@ -1797,23 +1800,12 @@ static int __devinit load_firmware(struct pci_dev *pdev, | |||
1797 | } | 1800 | } |
1798 | } | 1801 | } |
1799 | 1802 | ||
1800 | retval = -EIO; | ||
1801 | |||
1802 | if (WaitTillCardIsFree(base)) | ||
1803 | goto errrelfw; | ||
1804 | |||
1805 | outw(0xf2, base); | ||
1806 | outw(0x800, base); | ||
1807 | outw(0x0, base); | ||
1808 | outw(0x0, base); | ||
1809 | InterruptTheCard(base); | ||
1810 | outw(0x0, base + 0x4); /* for ISI4608 cards */ | ||
1811 | |||
1812 | /* XXX: should we test it by reading it back and comparing with original like | 1803 | /* XXX: should we test it by reading it back and comparing with original like |
1813 | * in load firmware package? */ | 1804 | * in load firmware package? */ |
1814 | for (frame = (struct stframe*)fw->data; | 1805 | for (frame = (struct stframe *)fw->data; |
1815 | frame < (struct stframe*)(fw->data + fw->size); | 1806 | frame < (struct stframe *)(fw->data + fw->size); |
1816 | frame++) { | 1807 | frame = (struct stframe *)((u8 *)(frame + 1) + |
1808 | frame->count)) { | ||
1817 | if (WaitTillCardIsFree(base)) | 1809 | if (WaitTillCardIsFree(base)) |
1818 | goto errrelfw; | 1810 | goto errrelfw; |
1819 | 1811 | ||
@@ -1863,6 +1855,17 @@ static int __devinit load_firmware(struct pci_dev *pdev, | |||
1863 | } | 1855 | } |
1864 | } | 1856 | } |
1865 | 1857 | ||
1858 | /* xfer ctrl */ | ||
1859 | if (WaitTillCardIsFree(base)) | ||
1860 | goto errrelfw; | ||
1861 | |||
1862 | outw(0xf2, base); | ||
1863 | outw(0x800, base); | ||
1864 | outw(0x0, base); | ||
1865 | outw(0x0, base); | ||
1866 | InterruptTheCard(base); | ||
1867 | outw(0x0, base + 0x4); /* for ISI4608 cards */ | ||
1868 | |||
1866 | board->status |= FIRMWARE_LOADED; | 1869 | board->status |= FIRMWARE_LOADED; |
1867 | retval = 0; | 1870 | retval = 0; |
1868 | 1871 | ||
diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c index 84dfc4278139..d6e031542c6b 100644 --- a/drivers/char/istallion.c +++ b/drivers/char/istallion.c | |||
@@ -612,16 +612,6 @@ MODULE_DEVICE_TABLE(pci, istallion_pci_tbl); | |||
612 | #define MINOR2BRD(min) (((min) & 0xc0) >> 6) | 612 | #define MINOR2BRD(min) (((min) & 0xc0) >> 6) |
613 | #define MINOR2PORT(min) ((min) & 0x3f) | 613 | #define MINOR2PORT(min) ((min) & 0x3f) |
614 | 614 | ||
615 | /* | ||
616 | * Define a baud rate table that converts termios baud rate selector | ||
617 | * into the actual baud rate value. All baud rate calculations are based | ||
618 | * on the actual baud rate required. | ||
619 | */ | ||
620 | static unsigned int stli_baudrates[] = { | ||
621 | 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, | ||
622 | 9600, 19200, 38400, 57600, 115200, 230400, 460800, 921600 | ||
623 | }; | ||
624 | |||
625 | /*****************************************************************************/ | 615 | /*****************************************************************************/ |
626 | 616 | ||
627 | /* | 617 | /* |
@@ -2747,15 +2737,7 @@ static void stli_mkasyport(stliport_t *portp, asyport_t *pp, struct termios *tio | |||
2747 | /* | 2737 | /* |
2748 | * Start of by setting the baud, char size, parity and stop bit info. | 2738 | * Start of by setting the baud, char size, parity and stop bit info. |
2749 | */ | 2739 | */ |
2750 | pp->baudout = tiosp->c_cflag & CBAUD; | 2740 | pp->baudout = tty_get_baud_rate(portp->tty); |
2751 | if (pp->baudout & CBAUDEX) { | ||
2752 | pp->baudout &= ~CBAUDEX; | ||
2753 | if ((pp->baudout < 1) || (pp->baudout > 4)) | ||
2754 | tiosp->c_cflag &= ~CBAUDEX; | ||
2755 | else | ||
2756 | pp->baudout += 15; | ||
2757 | } | ||
2758 | pp->baudout = stli_baudrates[pp->baudout]; | ||
2759 | if ((tiosp->c_cflag & CBAUD) == B38400) { | 2741 | if ((tiosp->c_cflag & CBAUD) == B38400) { |
2760 | if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) | 2742 | if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) |
2761 | pp->baudout = 57600; | 2743 | pp->baudout = 57600; |
@@ -3488,7 +3470,7 @@ static int stli_initecp(stlibrd_t *brdp) | |||
3488 | */ | 3470 | */ |
3489 | EBRDENABLE(brdp); | 3471 | EBRDENABLE(brdp); |
3490 | sigsp = (cdkecpsig_t __iomem *) EBRDGETMEMPTR(brdp, CDK_SIGADDR); | 3472 | sigsp = (cdkecpsig_t __iomem *) EBRDGETMEMPTR(brdp, CDK_SIGADDR); |
3491 | memcpy(&sig, sigsp, sizeof(cdkecpsig_t)); | 3473 | memcpy_fromio(&sig, sigsp, sizeof(cdkecpsig_t)); |
3492 | EBRDDISABLE(brdp); | 3474 | EBRDDISABLE(brdp); |
3493 | 3475 | ||
3494 | if (sig.magic != cpu_to_le32(ECP_MAGIC)) | 3476 | if (sig.magic != cpu_to_le32(ECP_MAGIC)) |
@@ -4654,7 +4636,7 @@ static int stli_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, un | |||
4654 | return rc; | 4636 | return rc; |
4655 | } | 4637 | } |
4656 | 4638 | ||
4657 | static struct tty_operations stli_ops = { | 4639 | static const struct tty_operations stli_ops = { |
4658 | .open = stli_open, | 4640 | .open = stli_open, |
4659 | .close = stli_close, | 4641 | .close = stli_close, |
4660 | .write = stli_write, | 4642 | .write = stli_write, |
diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c index ca234ce8004a..e2011669c7bb 100644 --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c | |||
@@ -108,7 +108,11 @@ const int NR_TYPES = ARRAY_SIZE(max_vals); | |||
108 | struct kbd_struct kbd_table[MAX_NR_CONSOLES]; | 108 | struct kbd_struct kbd_table[MAX_NR_CONSOLES]; |
109 | static struct kbd_struct *kbd = kbd_table; | 109 | static struct kbd_struct *kbd = kbd_table; |
110 | 110 | ||
111 | int spawnpid, spawnsig; | 111 | struct vt_spawn_console vt_spawn_con = { |
112 | .lock = SPIN_LOCK_UNLOCKED, | ||
113 | .pid = NULL, | ||
114 | .sig = 0, | ||
115 | }; | ||
112 | 116 | ||
113 | /* | 117 | /* |
114 | * Variables exported for vt.c | 118 | * Variables exported for vt.c |
@@ -578,9 +582,13 @@ static void fn_compose(struct vc_data *vc, struct pt_regs *regs) | |||
578 | 582 | ||
579 | static void fn_spawn_con(struct vc_data *vc, struct pt_regs *regs) | 583 | static void fn_spawn_con(struct vc_data *vc, struct pt_regs *regs) |
580 | { | 584 | { |
581 | if (spawnpid) | 585 | spin_lock(&vt_spawn_con.lock); |
582 | if (kill_proc(spawnpid, spawnsig, 1)) | 586 | if (vt_spawn_con.pid) |
583 | spawnpid = 0; | 587 | if (kill_pid(vt_spawn_con.pid, vt_spawn_con.sig, 1)) { |
588 | put_pid(vt_spawn_con.pid); | ||
589 | vt_spawn_con.pid = NULL; | ||
590 | } | ||
591 | spin_unlock(&vt_spawn_con.lock); | ||
584 | } | 592 | } |
585 | 593 | ||
586 | static void fn_SAK(struct vc_data *vc, struct pt_regs *regs) | 594 | static void fn_SAK(struct vc_data *vc, struct pt_regs *regs) |
diff --git a/drivers/char/lp.c b/drivers/char/lp.c index f875fda3b089..1ecea7d448f1 100644 --- a/drivers/char/lp.c +++ b/drivers/char/lp.c | |||
@@ -906,7 +906,7 @@ static int __init lp_init (void) | |||
906 | lp_class = class_create(THIS_MODULE, "printer"); | 906 | lp_class = class_create(THIS_MODULE, "printer"); |
907 | if (IS_ERR(lp_class)) { | 907 | if (IS_ERR(lp_class)) { |
908 | err = PTR_ERR(lp_class); | 908 | err = PTR_ERR(lp_class); |
909 | goto out_devfs; | 909 | goto out_reg; |
910 | } | 910 | } |
911 | 911 | ||
912 | if (parport_register_driver (&lp_driver)) { | 912 | if (parport_register_driver (&lp_driver)) { |
@@ -927,7 +927,7 @@ static int __init lp_init (void) | |||
927 | 927 | ||
928 | out_class: | 928 | out_class: |
929 | class_destroy(lp_class); | 929 | class_destroy(lp_class); |
930 | out_devfs: | 930 | out_reg: |
931 | unregister_chrdev(LP_MAJOR, "lp"); | 931 | unregister_chrdev(LP_MAJOR, "lp"); |
932 | return err; | 932 | return err; |
933 | } | 933 | } |
diff --git a/drivers/char/mbcs.c b/drivers/char/mbcs.c index 0385650f6077..636354722658 100644 --- a/drivers/char/mbcs.c +++ b/drivers/char/mbcs.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/delay.h> | 22 | #include <linux/delay.h> |
23 | #include <linux/device.h> | 23 | #include <linux/device.h> |
24 | #include <linux/mm.h> | 24 | #include <linux/mm.h> |
25 | #include <linux/fs.h> | ||
25 | #include <linux/uio.h> | 26 | #include <linux/uio.h> |
26 | #include <asm/io.h> | 27 | #include <asm/io.h> |
27 | #include <asm/uaccess.h> | 28 | #include <asm/uaccess.h> |
@@ -447,15 +448,15 @@ loff_t mbcs_sram_llseek(struct file * filp, loff_t off, int whence) | |||
447 | loff_t newpos; | 448 | loff_t newpos; |
448 | 449 | ||
449 | switch (whence) { | 450 | switch (whence) { |
450 | case 0: /* SEEK_SET */ | 451 | case SEEK_SET: |
451 | newpos = off; | 452 | newpos = off; |
452 | break; | 453 | break; |
453 | 454 | ||
454 | case 1: /* SEEK_CUR */ | 455 | case SEEK_CUR: |
455 | newpos = filp->f_pos + off; | 456 | newpos = filp->f_pos + off; |
456 | break; | 457 | break; |
457 | 458 | ||
458 | case 2: /* SEEK_END */ | 459 | case SEEK_END: |
459 | newpos = MBCS_SRAM_SIZE + off; | 460 | newpos = MBCS_SRAM_SIZE + off; |
460 | break; | 461 | break; |
461 | 462 | ||
diff --git a/drivers/char/mem.c b/drivers/char/mem.c index 917b20402664..6511012cbdcd 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c | |||
@@ -238,6 +238,32 @@ static pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn, | |||
238 | } | 238 | } |
239 | #endif | 239 | #endif |
240 | 240 | ||
241 | #ifndef CONFIG_MMU | ||
242 | static unsigned long get_unmapped_area_mem(struct file *file, | ||
243 | unsigned long addr, | ||
244 | unsigned long len, | ||
245 | unsigned long pgoff, | ||
246 | unsigned long flags) | ||
247 | { | ||
248 | if (!valid_mmap_phys_addr_range(pgoff, len)) | ||
249 | return (unsigned long) -EINVAL; | ||
250 | return pgoff; | ||
251 | } | ||
252 | |||
253 | /* can't do an in-place private mapping if there's no MMU */ | ||
254 | static inline int private_mapping_ok(struct vm_area_struct *vma) | ||
255 | { | ||
256 | return vma->vm_flags & VM_MAYSHARE; | ||
257 | } | ||
258 | #else | ||
259 | #define get_unmapped_area_mem NULL | ||
260 | |||
261 | static inline int private_mapping_ok(struct vm_area_struct *vma) | ||
262 | { | ||
263 | return 1; | ||
264 | } | ||
265 | #endif | ||
266 | |||
241 | static int mmap_mem(struct file * file, struct vm_area_struct * vma) | 267 | static int mmap_mem(struct file * file, struct vm_area_struct * vma) |
242 | { | 268 | { |
243 | size_t size = vma->vm_end - vma->vm_start; | 269 | size_t size = vma->vm_end - vma->vm_start; |
@@ -245,6 +271,9 @@ static int mmap_mem(struct file * file, struct vm_area_struct * vma) | |||
245 | if (!valid_mmap_phys_addr_range(vma->vm_pgoff, size)) | 271 | if (!valid_mmap_phys_addr_range(vma->vm_pgoff, size)) |
246 | return -EINVAL; | 272 | return -EINVAL; |
247 | 273 | ||
274 | if (!private_mapping_ok(vma)) | ||
275 | return -ENOSYS; | ||
276 | |||
248 | vma->vm_page_prot = phys_mem_access_prot(file, vma->vm_pgoff, | 277 | vma->vm_page_prot = phys_mem_access_prot(file, vma->vm_pgoff, |
249 | size, | 278 | size, |
250 | vma->vm_page_prot); | 279 | vma->vm_page_prot); |
@@ -522,7 +551,7 @@ static ssize_t write_kmem(struct file * file, const char __user * buf, | |||
522 | return virtr + wrote; | 551 | return virtr + wrote; |
523 | } | 552 | } |
524 | 553 | ||
525 | #if defined(CONFIG_ISA) || !defined(__mc68000__) | 554 | #if (defined(CONFIG_ISA) || defined(CONFIG_PCI)) && !defined(__mc68000__) |
526 | static ssize_t read_port(struct file * file, char __user * buf, | 555 | static ssize_t read_port(struct file * file, char __user * buf, |
527 | size_t count, loff_t *ppos) | 556 | size_t count, loff_t *ppos) |
528 | { | 557 | { |
@@ -782,6 +811,7 @@ static const struct file_operations mem_fops = { | |||
782 | .write = write_mem, | 811 | .write = write_mem, |
783 | .mmap = mmap_mem, | 812 | .mmap = mmap_mem, |
784 | .open = open_mem, | 813 | .open = open_mem, |
814 | .get_unmapped_area = get_unmapped_area_mem, | ||
785 | }; | 815 | }; |
786 | 816 | ||
787 | static const struct file_operations kmem_fops = { | 817 | static const struct file_operations kmem_fops = { |
@@ -790,6 +820,7 @@ static const struct file_operations kmem_fops = { | |||
790 | .write = write_kmem, | 820 | .write = write_kmem, |
791 | .mmap = mmap_kmem, | 821 | .mmap = mmap_kmem, |
792 | .open = open_kmem, | 822 | .open = open_kmem, |
823 | .get_unmapped_area = get_unmapped_area_mem, | ||
793 | }; | 824 | }; |
794 | 825 | ||
795 | static const struct file_operations null_fops = { | 826 | static const struct file_operations null_fops = { |
@@ -799,7 +830,7 @@ static const struct file_operations null_fops = { | |||
799 | .splice_write = splice_write_null, | 830 | .splice_write = splice_write_null, |
800 | }; | 831 | }; |
801 | 832 | ||
802 | #if defined(CONFIG_ISA) || !defined(__mc68000__) | 833 | #if (defined(CONFIG_ISA) || defined(CONFIG_PCI)) && !defined(__mc68000__) |
803 | static const struct file_operations port_fops = { | 834 | static const struct file_operations port_fops = { |
804 | .llseek = memory_lseek, | 835 | .llseek = memory_lseek, |
805 | .read = read_port, | 836 | .read = read_port, |
@@ -815,6 +846,10 @@ static const struct file_operations zero_fops = { | |||
815 | .mmap = mmap_zero, | 846 | .mmap = mmap_zero, |
816 | }; | 847 | }; |
817 | 848 | ||
849 | /* | ||
850 | * capabilities for /dev/zero | ||
851 | * - permits private mappings, "copies" are taken of the source of zeros | ||
852 | */ | ||
818 | static struct backing_dev_info zero_bdi = { | 853 | static struct backing_dev_info zero_bdi = { |
819 | .capabilities = BDI_CAP_MAP_COPY, | 854 | .capabilities = BDI_CAP_MAP_COPY, |
820 | }; | 855 | }; |
@@ -862,14 +897,18 @@ static int memory_open(struct inode * inode, struct file * filp) | |||
862 | switch (iminor(inode)) { | 897 | switch (iminor(inode)) { |
863 | case 1: | 898 | case 1: |
864 | filp->f_op = &mem_fops; | 899 | filp->f_op = &mem_fops; |
900 | filp->f_mapping->backing_dev_info = | ||
901 | &directly_mappable_cdev_bdi; | ||
865 | break; | 902 | break; |
866 | case 2: | 903 | case 2: |
867 | filp->f_op = &kmem_fops; | 904 | filp->f_op = &kmem_fops; |
905 | filp->f_mapping->backing_dev_info = | ||
906 | &directly_mappable_cdev_bdi; | ||
868 | break; | 907 | break; |
869 | case 3: | 908 | case 3: |
870 | filp->f_op = &null_fops; | 909 | filp->f_op = &null_fops; |
871 | break; | 910 | break; |
872 | #if defined(CONFIG_ISA) || !defined(__mc68000__) | 911 | #if (defined(CONFIG_ISA) || defined(CONFIG_PCI)) && !defined(__mc68000__) |
873 | case 4: | 912 | case 4: |
874 | filp->f_op = &port_fops; | 913 | filp->f_op = &port_fops; |
875 | break; | 914 | break; |
@@ -916,7 +955,7 @@ static const struct { | |||
916 | {1, "mem", S_IRUSR | S_IWUSR | S_IRGRP, &mem_fops}, | 955 | {1, "mem", S_IRUSR | S_IWUSR | S_IRGRP, &mem_fops}, |
917 | {2, "kmem", S_IRUSR | S_IWUSR | S_IRGRP, &kmem_fops}, | 956 | {2, "kmem", S_IRUSR | S_IWUSR | S_IRGRP, &kmem_fops}, |
918 | {3, "null", S_IRUGO | S_IWUGO, &null_fops}, | 957 | {3, "null", S_IRUGO | S_IWUGO, &null_fops}, |
919 | #if defined(CONFIG_ISA) || !defined(__mc68000__) | 958 | #if (defined(CONFIG_ISA) || defined(CONFIG_PCI)) && !defined(__mc68000__) |
920 | {4, "port", S_IRUSR | S_IWUSR | S_IRGRP, &port_fops}, | 959 | {4, "port", S_IRUSR | S_IWUSR | S_IRGRP, &port_fops}, |
921 | #endif | 960 | #endif |
922 | {5, "zero", S_IRUGO | S_IWUGO, &zero_fops}, | 961 | {5, "zero", S_IRUGO | S_IWUGO, &zero_fops}, |
diff --git a/drivers/char/moxa.c b/drivers/char/moxa.c index a369dd6877d8..b401383808c2 100644 --- a/drivers/char/moxa.c +++ b/drivers/char/moxa.c | |||
@@ -260,7 +260,7 @@ static void MoxaPortEnable(int); | |||
260 | static void MoxaPortDisable(int); | 260 | static void MoxaPortDisable(int); |
261 | static long MoxaPortGetMaxBaud(int); | 261 | static long MoxaPortGetMaxBaud(int); |
262 | static long MoxaPortSetBaud(int, long); | 262 | static long MoxaPortSetBaud(int, long); |
263 | static int MoxaPortSetTermio(int, struct termios *); | 263 | static int MoxaPortSetTermio(int, struct termios *, speed_t); |
264 | static int MoxaPortGetLineOut(int, int *, int *); | 264 | static int MoxaPortGetLineOut(int, int *, int *); |
265 | static void MoxaPortLineCtrl(int, int, int); | 265 | static void MoxaPortLineCtrl(int, int, int); |
266 | static void MoxaPortFlowCtrl(int, int, int, int, int, int); | 266 | static void MoxaPortFlowCtrl(int, int, int, int, int, int); |
@@ -281,7 +281,7 @@ static int moxa_get_serial_info(struct moxa_str *, struct serial_struct __user * | |||
281 | static int moxa_set_serial_info(struct moxa_str *, struct serial_struct __user *); | 281 | static int moxa_set_serial_info(struct moxa_str *, struct serial_struct __user *); |
282 | static void MoxaSetFifo(int port, int enable); | 282 | static void MoxaSetFifo(int port, int enable); |
283 | 283 | ||
284 | static struct tty_operations moxa_ops = { | 284 | static const struct tty_operations moxa_ops = { |
285 | .open = moxa_open, | 285 | .open = moxa_open, |
286 | .close = moxa_close, | 286 | .close = moxa_close, |
287 | .write = moxa_write, | 287 | .write = moxa_write, |
@@ -986,7 +986,7 @@ static void set_tty_param(struct tty_struct *tty) | |||
986 | if (ts->c_iflag & IXANY) | 986 | if (ts->c_iflag & IXANY) |
987 | xany = 1; | 987 | xany = 1; |
988 | MoxaPortFlowCtrl(ch->port, rts, cts, txflow, rxflow, xany); | 988 | MoxaPortFlowCtrl(ch->port, rts, cts, txflow, rxflow, xany); |
989 | MoxaPortSetTermio(ch->port, ts); | 989 | MoxaPortSetTermio(ch->port, ts, tty_get_baud_rate(tty)); |
990 | } | 990 | } |
991 | 991 | ||
992 | static int block_till_ready(struct tty_struct *tty, struct file *filp, | 992 | static int block_till_ready(struct tty_struct *tty, struct file *filp, |
@@ -1900,9 +1900,10 @@ int MoxaPortsOfCard(int cardno) | |||
1900 | * | 1900 | * |
1901 | * Function 12: Configure the port. | 1901 | * Function 12: Configure the port. |
1902 | * Syntax: | 1902 | * Syntax: |
1903 | * int MoxaPortSetTermio(int port, struct termios *termio); | 1903 | * int MoxaPortSetTermio(int port, struct termios *termio, speed_t baud); |
1904 | * int port : port number (0 - 127) | 1904 | * int port : port number (0 - 127) |
1905 | * struct termios * termio : termio structure pointer | 1905 | * struct termios * termio : termio structure pointer |
1906 | * speed_t baud : baud rate | ||
1906 | * | 1907 | * |
1907 | * return: -1 : this port is invalid or termio == NULL | 1908 | * return: -1 : this port is invalid or termio == NULL |
1908 | * 0 : setting O.K. | 1909 | * 0 : setting O.K. |
@@ -2182,11 +2183,10 @@ long MoxaPortSetBaud(int port, long baud) | |||
2182 | return (baud); | 2183 | return (baud); |
2183 | } | 2184 | } |
2184 | 2185 | ||
2185 | int MoxaPortSetTermio(int port, struct termios *termio) | 2186 | int MoxaPortSetTermio(int port, struct termios *termio, speed_t baud) |
2186 | { | 2187 | { |
2187 | void __iomem *ofsAddr; | 2188 | void __iomem *ofsAddr; |
2188 | tcflag_t cflag; | 2189 | tcflag_t cflag; |
2189 | long baud; | ||
2190 | tcflag_t mode = 0; | 2190 | tcflag_t mode = 0; |
2191 | 2191 | ||
2192 | if (moxaChkPort[port] == 0 || termio == 0) | 2192 | if (moxaChkPort[port] == 0 || termio == 0) |
@@ -2222,77 +2222,9 @@ int MoxaPortSetTermio(int port, struct termios *termio) | |||
2222 | 2222 | ||
2223 | moxafunc(ofsAddr, FC_SetDataMode, (ushort) mode); | 2223 | moxafunc(ofsAddr, FC_SetDataMode, (ushort) mode); |
2224 | 2224 | ||
2225 | cflag &= (CBAUD | CBAUDEX); | ||
2226 | #ifndef B921600 | ||
2227 | #define B921600 (B460800+1) | ||
2228 | #endif | ||
2229 | switch (cflag) { | ||
2230 | case B921600: | ||
2231 | baud = 921600L; | ||
2232 | break; | ||
2233 | case B460800: | ||
2234 | baud = 460800L; | ||
2235 | break; | ||
2236 | case B230400: | ||
2237 | baud = 230400L; | ||
2238 | break; | ||
2239 | case B115200: | ||
2240 | baud = 115200L; | ||
2241 | break; | ||
2242 | case B57600: | ||
2243 | baud = 57600L; | ||
2244 | break; | ||
2245 | case B38400: | ||
2246 | baud = 38400L; | ||
2247 | break; | ||
2248 | case B19200: | ||
2249 | baud = 19200L; | ||
2250 | break; | ||
2251 | case B9600: | ||
2252 | baud = 9600L; | ||
2253 | break; | ||
2254 | case B4800: | ||
2255 | baud = 4800L; | ||
2256 | break; | ||
2257 | case B2400: | ||
2258 | baud = 2400L; | ||
2259 | break; | ||
2260 | case B1800: | ||
2261 | baud = 1800L; | ||
2262 | break; | ||
2263 | case B1200: | ||
2264 | baud = 1200L; | ||
2265 | break; | ||
2266 | case B600: | ||
2267 | baud = 600L; | ||
2268 | break; | ||
2269 | case B300: | ||
2270 | baud = 300L; | ||
2271 | break; | ||
2272 | case B200: | ||
2273 | baud = 200L; | ||
2274 | break; | ||
2275 | case B150: | ||
2276 | baud = 150L; | ||
2277 | break; | ||
2278 | case B134: | ||
2279 | baud = 134L; | ||
2280 | break; | ||
2281 | case B110: | ||
2282 | baud = 110L; | ||
2283 | break; | ||
2284 | case B75: | ||
2285 | baud = 75L; | ||
2286 | break; | ||
2287 | case B50: | ||
2288 | baud = 50L; | ||
2289 | break; | ||
2290 | default: | ||
2291 | baud = 0; | ||
2292 | } | ||
2293 | if ((moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_ISA) || | 2225 | if ((moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_ISA) || |
2294 | (moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_PCI)) { | 2226 | (moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_PCI)) { |
2295 | if (baud == 921600L) | 2227 | if (baud >= 921600L) |
2296 | return (-1); | 2228 | return (-1); |
2297 | } | 2229 | } |
2298 | MoxaPortSetBaud(port, baud); | 2230 | MoxaPortSetBaud(port, baud); |
diff --git a/drivers/char/mspec.c b/drivers/char/mspec.c new file mode 100644 index 000000000000..5426b1e5595f --- /dev/null +++ b/drivers/char/mspec.c | |||
@@ -0,0 +1,421 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2001-2006 Silicon Graphics, Inc. All rights | ||
3 | * reserved. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of version 2 of the GNU General Public License | ||
7 | * as published by the Free Software Foundation. | ||
8 | */ | ||
9 | |||
10 | /* | ||
11 | * SN Platform Special Memory (mspec) Support | ||
12 | * | ||
13 | * This driver exports the SN special memory (mspec) facility to user | ||
14 | * processes. | ||
15 | * There are three types of memory made available thru this driver: | ||
16 | * fetchops, uncached and cached. | ||
17 | * | ||
18 | * Fetchops are atomic memory operations that are implemented in the | ||
19 | * memory controller on SGI SN hardware. | ||
20 | * | ||
21 | * Uncached are used for memory write combining feature of the ia64 | ||
22 | * cpu. | ||
23 | * | ||
24 | * Cached are used for areas of memory that are used as cached addresses | ||
25 | * on our partition and used as uncached addresses from other partitions. | ||
26 | * Due to a design constraint of the SN2 Shub, you can not have processors | ||
27 | * on the same FSB perform both a cached and uncached reference to the | ||
28 | * same cache line. These special memory cached regions prevent the | ||
29 | * kernel from ever dropping in a TLB entry and therefore prevent the | ||
30 | * processor from ever speculating a cache line from this page. | ||
31 | */ | ||
32 | |||
33 | #include <linux/config.h> | ||
34 | #include <linux/types.h> | ||
35 | #include <linux/kernel.h> | ||
36 | #include <linux/module.h> | ||
37 | #include <linux/init.h> | ||
38 | #include <linux/errno.h> | ||
39 | #include <linux/miscdevice.h> | ||
40 | #include <linux/spinlock.h> | ||
41 | #include <linux/mm.h> | ||
42 | #include <linux/vmalloc.h> | ||
43 | #include <linux/string.h> | ||
44 | #include <linux/slab.h> | ||
45 | #include <linux/numa.h> | ||
46 | #include <asm/page.h> | ||
47 | #include <asm/system.h> | ||
48 | #include <asm/pgtable.h> | ||
49 | #include <asm/atomic.h> | ||
50 | #include <asm/tlbflush.h> | ||
51 | #include <asm/uncached.h> | ||
52 | #include <asm/sn/addrs.h> | ||
53 | #include <asm/sn/arch.h> | ||
54 | #include <asm/sn/mspec.h> | ||
55 | #include <asm/sn/sn_cpuid.h> | ||
56 | #include <asm/sn/io.h> | ||
57 | #include <asm/sn/bte.h> | ||
58 | #include <asm/sn/shubio.h> | ||
59 | |||
60 | |||
61 | #define FETCHOP_ID "SGI Fetchop," | ||
62 | #define CACHED_ID "Cached," | ||
63 | #define UNCACHED_ID "Uncached" | ||
64 | #define REVISION "4.0" | ||
65 | #define MSPEC_BASENAME "mspec" | ||
66 | |||
67 | /* | ||
68 | * Page types allocated by the device. | ||
69 | */ | ||
70 | enum { | ||
71 | MSPEC_FETCHOP = 1, | ||
72 | MSPEC_CACHED, | ||
73 | MSPEC_UNCACHED | ||
74 | }; | ||
75 | |||
76 | static int is_sn2; | ||
77 | |||
78 | /* | ||
79 | * One of these structures is allocated when an mspec region is mmaped. The | ||
80 | * structure is pointed to by the vma->vm_private_data field in the vma struct. | ||
81 | * This structure is used to record the addresses of the mspec pages. | ||
82 | */ | ||
83 | struct vma_data { | ||
84 | atomic_t refcnt; /* Number of vmas sharing the data. */ | ||
85 | spinlock_t lock; /* Serialize access to the vma. */ | ||
86 | int count; /* Number of pages allocated. */ | ||
87 | int type; /* Type of pages allocated. */ | ||
88 | unsigned long maddr[0]; /* Array of MSPEC addresses. */ | ||
89 | }; | ||
90 | |||
91 | /* used on shub2 to clear FOP cache in the HUB */ | ||
92 | static unsigned long scratch_page[MAX_NUMNODES]; | ||
93 | #define SH2_AMO_CACHE_ENTRIES 4 | ||
94 | |||
95 | static inline int | ||
96 | mspec_zero_block(unsigned long addr, int len) | ||
97 | { | ||
98 | int status; | ||
99 | |||
100 | if (is_sn2) { | ||
101 | if (is_shub2()) { | ||
102 | int nid; | ||
103 | void *p; | ||
104 | int i; | ||
105 | |||
106 | nid = nasid_to_cnodeid(get_node_number(__pa(addr))); | ||
107 | p = (void *)TO_AMO(scratch_page[nid]); | ||
108 | |||
109 | for (i=0; i < SH2_AMO_CACHE_ENTRIES; i++) { | ||
110 | FETCHOP_LOAD_OP(p, FETCHOP_LOAD); | ||
111 | p += FETCHOP_VAR_SIZE; | ||
112 | } | ||
113 | } | ||
114 | |||
115 | status = bte_copy(0, addr & ~__IA64_UNCACHED_OFFSET, len, | ||
116 | BTE_WACQUIRE | BTE_ZERO_FILL, NULL); | ||
117 | } else { | ||
118 | memset((char *) addr, 0, len); | ||
119 | status = 0; | ||
120 | } | ||
121 | return status; | ||
122 | } | ||
123 | |||
124 | /* | ||
125 | * mspec_open | ||
126 | * | ||
127 | * Called when a device mapping is created by a means other than mmap | ||
128 | * (via fork, etc.). Increments the reference count on the underlying | ||
129 | * mspec data so it is not freed prematurely. | ||
130 | */ | ||
131 | static void | ||
132 | mspec_open(struct vm_area_struct *vma) | ||
133 | { | ||
134 | struct vma_data *vdata; | ||
135 | |||
136 | vdata = vma->vm_private_data; | ||
137 | atomic_inc(&vdata->refcnt); | ||
138 | } | ||
139 | |||
140 | /* | ||
141 | * mspec_close | ||
142 | * | ||
143 | * Called when unmapping a device mapping. Frees all mspec pages | ||
144 | * belonging to the vma. | ||
145 | */ | ||
146 | static void | ||
147 | mspec_close(struct vm_area_struct *vma) | ||
148 | { | ||
149 | struct vma_data *vdata; | ||
150 | int i, pages, result, vdata_size; | ||
151 | |||
152 | vdata = vma->vm_private_data; | ||
153 | if (!atomic_dec_and_test(&vdata->refcnt)) | ||
154 | return; | ||
155 | |||
156 | pages = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT; | ||
157 | vdata_size = sizeof(struct vma_data) + pages * sizeof(long); | ||
158 | for (i = 0; i < pages; i++) { | ||
159 | if (vdata->maddr[i] == 0) | ||
160 | continue; | ||
161 | /* | ||
162 | * Clear the page before sticking it back | ||
163 | * into the pool. | ||
164 | */ | ||
165 | result = mspec_zero_block(vdata->maddr[i], PAGE_SIZE); | ||
166 | if (!result) | ||
167 | uncached_free_page(vdata->maddr[i]); | ||
168 | else | ||
169 | printk(KERN_WARNING "mspec_close(): " | ||
170 | "failed to zero page %i\n", | ||
171 | result); | ||
172 | } | ||
173 | |||
174 | if (vdata_size <= PAGE_SIZE) | ||
175 | kfree(vdata); | ||
176 | else | ||
177 | vfree(vdata); | ||
178 | } | ||
179 | |||
180 | |||
181 | /* | ||
182 | * mspec_nopfn | ||
183 | * | ||
184 | * Creates a mspec page and maps it to user space. | ||
185 | */ | ||
186 | static unsigned long | ||
187 | mspec_nopfn(struct vm_area_struct *vma, unsigned long address) | ||
188 | { | ||
189 | unsigned long paddr, maddr; | ||
190 | unsigned long pfn; | ||
191 | int index; | ||
192 | struct vma_data *vdata = vma->vm_private_data; | ||
193 | |||
194 | index = (address - vma->vm_start) >> PAGE_SHIFT; | ||
195 | maddr = (volatile unsigned long) vdata->maddr[index]; | ||
196 | if (maddr == 0) { | ||
197 | maddr = uncached_alloc_page(numa_node_id()); | ||
198 | if (maddr == 0) | ||
199 | return NOPFN_OOM; | ||
200 | |||
201 | spin_lock(&vdata->lock); | ||
202 | if (vdata->maddr[index] == 0) { | ||
203 | vdata->count++; | ||
204 | vdata->maddr[index] = maddr; | ||
205 | } else { | ||
206 | uncached_free_page(maddr); | ||
207 | maddr = vdata->maddr[index]; | ||
208 | } | ||
209 | spin_unlock(&vdata->lock); | ||
210 | } | ||
211 | |||
212 | if (vdata->type == MSPEC_FETCHOP) | ||
213 | paddr = TO_AMO(maddr); | ||
214 | else | ||
215 | paddr = __pa(TO_CAC(maddr)); | ||
216 | |||
217 | pfn = paddr >> PAGE_SHIFT; | ||
218 | |||
219 | return pfn; | ||
220 | } | ||
221 | |||
222 | static struct vm_operations_struct mspec_vm_ops = { | ||
223 | .open = mspec_open, | ||
224 | .close = mspec_close, | ||
225 | .nopfn = mspec_nopfn | ||
226 | }; | ||
227 | |||
228 | /* | ||
229 | * mspec_mmap | ||
230 | * | ||
231 | * Called when mmaping the device. Initializes the vma with a fault handler | ||
232 | * and private data structure necessary to allocate, track, and free the | ||
233 | * underlying pages. | ||
234 | */ | ||
235 | static int | ||
236 | mspec_mmap(struct file *file, struct vm_area_struct *vma, int type) | ||
237 | { | ||
238 | struct vma_data *vdata; | ||
239 | int pages, vdata_size; | ||
240 | |||
241 | if (vma->vm_pgoff != 0) | ||
242 | return -EINVAL; | ||
243 | |||
244 | if ((vma->vm_flags & VM_SHARED) == 0) | ||
245 | return -EINVAL; | ||
246 | |||
247 | if ((vma->vm_flags & VM_WRITE) == 0) | ||
248 | return -EPERM; | ||
249 | |||
250 | pages = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT; | ||
251 | vdata_size = sizeof(struct vma_data) + pages * sizeof(long); | ||
252 | if (vdata_size <= PAGE_SIZE) | ||
253 | vdata = kmalloc(vdata_size, GFP_KERNEL); | ||
254 | else | ||
255 | vdata = vmalloc(vdata_size); | ||
256 | if (!vdata) | ||
257 | return -ENOMEM; | ||
258 | memset(vdata, 0, vdata_size); | ||
259 | |||
260 | vdata->type = type; | ||
261 | spin_lock_init(&vdata->lock); | ||
262 | vdata->refcnt = ATOMIC_INIT(1); | ||
263 | vma->vm_private_data = vdata; | ||
264 | |||
265 | vma->vm_flags |= (VM_IO | VM_LOCKED | VM_RESERVED | VM_PFNMAP); | ||
266 | if (vdata->type == MSPEC_FETCHOP || vdata->type == MSPEC_UNCACHED) | ||
267 | vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); | ||
268 | vma->vm_ops = &mspec_vm_ops; | ||
269 | |||
270 | return 0; | ||
271 | } | ||
272 | |||
273 | static int | ||
274 | fetchop_mmap(struct file *file, struct vm_area_struct *vma) | ||
275 | { | ||
276 | return mspec_mmap(file, vma, MSPEC_FETCHOP); | ||
277 | } | ||
278 | |||
279 | static int | ||
280 | cached_mmap(struct file *file, struct vm_area_struct *vma) | ||
281 | { | ||
282 | return mspec_mmap(file, vma, MSPEC_CACHED); | ||
283 | } | ||
284 | |||
285 | static int | ||
286 | uncached_mmap(struct file *file, struct vm_area_struct *vma) | ||
287 | { | ||
288 | return mspec_mmap(file, vma, MSPEC_UNCACHED); | ||
289 | } | ||
290 | |||
291 | static struct file_operations fetchop_fops = { | ||
292 | .owner = THIS_MODULE, | ||
293 | .mmap = fetchop_mmap | ||
294 | }; | ||
295 | |||
296 | static struct miscdevice fetchop_miscdev = { | ||
297 | .minor = MISC_DYNAMIC_MINOR, | ||
298 | .name = "sgi_fetchop", | ||
299 | .fops = &fetchop_fops | ||
300 | }; | ||
301 | |||
302 | static struct file_operations cached_fops = { | ||
303 | .owner = THIS_MODULE, | ||
304 | .mmap = cached_mmap | ||
305 | }; | ||
306 | |||
307 | static struct miscdevice cached_miscdev = { | ||
308 | .minor = MISC_DYNAMIC_MINOR, | ||
309 | .name = "mspec_cached", | ||
310 | .fops = &cached_fops | ||
311 | }; | ||
312 | |||
313 | static struct file_operations uncached_fops = { | ||
314 | .owner = THIS_MODULE, | ||
315 | .mmap = uncached_mmap | ||
316 | }; | ||
317 | |||
318 | static struct miscdevice uncached_miscdev = { | ||
319 | .minor = MISC_DYNAMIC_MINOR, | ||
320 | .name = "mspec_uncached", | ||
321 | .fops = &uncached_fops | ||
322 | }; | ||
323 | |||
324 | /* | ||
325 | * mspec_init | ||
326 | * | ||
327 | * Called at boot time to initialize the mspec facility. | ||
328 | */ | ||
329 | static int __init | ||
330 | mspec_init(void) | ||
331 | { | ||
332 | int ret; | ||
333 | int nid; | ||
334 | |||
335 | /* | ||
336 | * The fetchop device only works on SN2 hardware, uncached and cached | ||
337 | * memory drivers should both be valid on all ia64 hardware | ||
338 | */ | ||
339 | if (ia64_platform_is("sn2")) { | ||
340 | is_sn2 = 1; | ||
341 | if (is_shub2()) { | ||
342 | ret = -ENOMEM; | ||
343 | for_each_online_node(nid) { | ||
344 | int actual_nid; | ||
345 | int nasid; | ||
346 | unsigned long phys; | ||
347 | |||
348 | scratch_page[nid] = uncached_alloc_page(nid); | ||
349 | if (scratch_page[nid] == 0) | ||
350 | goto free_scratch_pages; | ||
351 | phys = __pa(scratch_page[nid]); | ||
352 | nasid = get_node_number(phys); | ||
353 | actual_nid = nasid_to_cnodeid(nasid); | ||
354 | if (actual_nid != nid) | ||
355 | goto free_scratch_pages; | ||
356 | } | ||
357 | } | ||
358 | |||
359 | ret = misc_register(&fetchop_miscdev); | ||
360 | if (ret) { | ||
361 | printk(KERN_ERR | ||
362 | "%s: failed to register device %i\n", | ||
363 | FETCHOP_ID, ret); | ||
364 | goto free_scratch_pages; | ||
365 | } | ||
366 | } | ||
367 | ret = misc_register(&cached_miscdev); | ||
368 | if (ret) { | ||
369 | printk(KERN_ERR "%s: failed to register device %i\n", | ||
370 | CACHED_ID, ret); | ||
371 | if (is_sn2) | ||
372 | misc_deregister(&fetchop_miscdev); | ||
373 | goto free_scratch_pages; | ||
374 | } | ||
375 | ret = misc_register(&uncached_miscdev); | ||
376 | if (ret) { | ||
377 | printk(KERN_ERR "%s: failed to register device %i\n", | ||
378 | UNCACHED_ID, ret); | ||
379 | misc_deregister(&cached_miscdev); | ||
380 | if (is_sn2) | ||
381 | misc_deregister(&fetchop_miscdev); | ||
382 | goto free_scratch_pages; | ||
383 | } | ||
384 | |||
385 | printk(KERN_INFO "%s %s initialized devices: %s %s %s\n", | ||
386 | MSPEC_BASENAME, REVISION, is_sn2 ? FETCHOP_ID : "", | ||
387 | CACHED_ID, UNCACHED_ID); | ||
388 | |||
389 | return 0; | ||
390 | |||
391 | free_scratch_pages: | ||
392 | for_each_node(nid) { | ||
393 | if (scratch_page[nid] != 0) | ||
394 | uncached_free_page(scratch_page[nid]); | ||
395 | } | ||
396 | return ret; | ||
397 | } | ||
398 | |||
399 | static void __exit | ||
400 | mspec_exit(void) | ||
401 | { | ||
402 | int nid; | ||
403 | |||
404 | misc_deregister(&uncached_miscdev); | ||
405 | misc_deregister(&cached_miscdev); | ||
406 | if (is_sn2) { | ||
407 | misc_deregister(&fetchop_miscdev); | ||
408 | |||
409 | for_each_node(nid) { | ||
410 | if (scratch_page[nid] != 0) | ||
411 | uncached_free_page(scratch_page[nid]); | ||
412 | } | ||
413 | } | ||
414 | } | ||
415 | |||
416 | module_init(mspec_init); | ||
417 | module_exit(mspec_exit); | ||
418 | |||
419 | MODULE_AUTHOR("Silicon Graphics, Inc. <linux-altix@sgi.com>"); | ||
420 | MODULE_DESCRIPTION("Driver for SGI SN special memory operations"); | ||
421 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/char/mwave/mwavedd.c b/drivers/char/mwave/mwavedd.c index 39a2e661ff55..8d14823b0514 100644 --- a/drivers/char/mwave/mwavedd.c +++ b/drivers/char/mwave/mwavedd.c | |||
@@ -297,7 +297,7 @@ static int mwave_ioctl(struct inode *inode, struct file *file, | |||
297 | " ipcnum %x, usIntCount %x\n", | 297 | " ipcnum %x, usIntCount %x\n", |
298 | ipcnum, | 298 | ipcnum, |
299 | pDrvData->IPCs[ipcnum].usIntCount); | 299 | pDrvData->IPCs[ipcnum].usIntCount); |
300 | if (ipcnum > ARRAY_SIZE(pDrvData->IPCs)) { | 300 | if (ipcnum >= ARRAY_SIZE(pDrvData->IPCs)) { |
301 | PRINTK_ERROR(KERN_ERR_MWAVE | 301 | PRINTK_ERROR(KERN_ERR_MWAVE |
302 | "mwavedd::mwave_ioctl:" | 302 | "mwavedd::mwave_ioctl:" |
303 | " IOCTL_MW_GET_IPC: Error:" | 303 | " IOCTL_MW_GET_IPC: Error:" |
@@ -355,7 +355,7 @@ static int mwave_ioctl(struct inode *inode, struct file *file, | |||
355 | "mwavedd::mwave_ioctl IOCTL_MW_UNREGISTER_IPC" | 355 | "mwavedd::mwave_ioctl IOCTL_MW_UNREGISTER_IPC" |
356 | " ipcnum %x\n", | 356 | " ipcnum %x\n", |
357 | ipcnum); | 357 | ipcnum); |
358 | if (ipcnum > ARRAY_SIZE(pDrvData->IPCs)) { | 358 | if (ipcnum >= ARRAY_SIZE(pDrvData->IPCs)) { |
359 | PRINTK_ERROR(KERN_ERR_MWAVE | 359 | PRINTK_ERROR(KERN_ERR_MWAVE |
360 | "mwavedd::mwave_ioctl:" | 360 | "mwavedd::mwave_ioctl:" |
361 | " IOCTL_MW_UNREGISTER_IPC:" | 361 | " IOCTL_MW_UNREGISTER_IPC:" |
diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c index 556abd3e0d07..8253fca8efd5 100644 --- a/drivers/char/mxser.c +++ b/drivers/char/mxser.c | |||
@@ -453,7 +453,7 @@ static int CheckIsMoxaMust(int io) | |||
453 | 453 | ||
454 | /* above is modified by Victor Yu. 08-15-2002 */ | 454 | /* above is modified by Victor Yu. 08-15-2002 */ |
455 | 455 | ||
456 | static struct tty_operations mxser_ops = { | 456 | static const struct tty_operations mxser_ops = { |
457 | .open = mxser_open, | 457 | .open = mxser_open, |
458 | .close = mxser_close, | 458 | .close = mxser_close, |
459 | .write = mxser_write, | 459 | .write = mxser_write, |
@@ -2554,71 +2554,7 @@ static int mxser_change_speed(struct mxser_struct *info, struct termios *old_ter | |||
2554 | #define B921600 (B460800 +1) | 2554 | #define B921600 (B460800 +1) |
2555 | #endif | 2555 | #endif |
2556 | if (mxser_set_baud_method[info->port] == 0) { | 2556 | if (mxser_set_baud_method[info->port] == 0) { |
2557 | switch (cflag & (CBAUD | CBAUDEX)) { | 2557 | baud = tty_get_baud_rate(info->tty); |
2558 | case B921600: | ||
2559 | baud = 921600; | ||
2560 | break; | ||
2561 | case B460800: | ||
2562 | baud = 460800; | ||
2563 | break; | ||
2564 | case B230400: | ||
2565 | baud = 230400; | ||
2566 | break; | ||
2567 | case B115200: | ||
2568 | baud = 115200; | ||
2569 | break; | ||
2570 | case B57600: | ||
2571 | baud = 57600; | ||
2572 | break; | ||
2573 | case B38400: | ||
2574 | baud = 38400; | ||
2575 | break; | ||
2576 | case B19200: | ||
2577 | baud = 19200; | ||
2578 | break; | ||
2579 | case B9600: | ||
2580 | baud = 9600; | ||
2581 | break; | ||
2582 | case B4800: | ||
2583 | baud = 4800; | ||
2584 | break; | ||
2585 | case B2400: | ||
2586 | baud = 2400; | ||
2587 | break; | ||
2588 | case B1800: | ||
2589 | baud = 1800; | ||
2590 | break; | ||
2591 | case B1200: | ||
2592 | baud = 1200; | ||
2593 | break; | ||
2594 | case B600: | ||
2595 | baud = 600; | ||
2596 | break; | ||
2597 | case B300: | ||
2598 | baud = 300; | ||
2599 | break; | ||
2600 | case B200: | ||
2601 | baud = 200; | ||
2602 | break; | ||
2603 | case B150: | ||
2604 | baud = 150; | ||
2605 | break; | ||
2606 | case B134: | ||
2607 | baud = 134; | ||
2608 | break; | ||
2609 | case B110: | ||
2610 | baud = 110; | ||
2611 | break; | ||
2612 | case B75: | ||
2613 | baud = 75; | ||
2614 | break; | ||
2615 | case B50: | ||
2616 | baud = 50; | ||
2617 | break; | ||
2618 | default: | ||
2619 | baud = 0; | ||
2620 | break; | ||
2621 | } | ||
2622 | mxser_set_baud(info, baud); | 2558 | mxser_set_baud(info, baud); |
2623 | } | 2559 | } |
2624 | 2560 | ||
diff --git a/drivers/char/nwbutton.c b/drivers/char/nwbutton.c index 7c57ebfa8640..ea1aa7764f8e 100644 --- a/drivers/char/nwbutton.c +++ b/drivers/char/nwbutton.c | |||
@@ -127,9 +127,8 @@ static void button_consume_callbacks (int bpcount) | |||
127 | static void button_sequence_finished (unsigned long parameters) | 127 | static void button_sequence_finished (unsigned long parameters) |
128 | { | 128 | { |
129 | #ifdef CONFIG_NWBUTTON_REBOOT /* Reboot using button is enabled */ | 129 | #ifdef CONFIG_NWBUTTON_REBOOT /* Reboot using button is enabled */ |
130 | if (button_press_count == reboot_count) { | 130 | if (button_press_count == reboot_count) |
131 | kill_proc (1, SIGINT, 1); /* Ask init to reboot us */ | 131 | kill_cad_pid(SIGINT, 1); /* Ask init to reboot us */ |
132 | } | ||
133 | #endif /* CONFIG_NWBUTTON_REBOOT */ | 132 | #endif /* CONFIG_NWBUTTON_REBOOT */ |
134 | button_consume_callbacks (button_press_count); | 133 | button_consume_callbacks (button_press_count); |
135 | bcount = sprintf (button_output_buffer, "%d\n", button_press_count); | 134 | bcount = sprintf (button_output_buffer, "%d\n", button_press_count); |
diff --git a/drivers/char/pc8736x_gpio.c b/drivers/char/pc8736x_gpio.c index 84e5a68635f1..ecfaf180e5bd 100644 --- a/drivers/char/pc8736x_gpio.c +++ b/drivers/char/pc8736x_gpio.c | |||
@@ -188,16 +188,6 @@ static void pc8736x_gpio_set(unsigned minor, int val) | |||
188 | pc8736x_gpio_shadow[port] = val; | 188 | pc8736x_gpio_shadow[port] = val; |
189 | } | 189 | } |
190 | 190 | ||
191 | static void pc8736x_gpio_set_high(unsigned index) | ||
192 | { | ||
193 | pc8736x_gpio_set(index, 1); | ||
194 | } | ||
195 | |||
196 | static void pc8736x_gpio_set_low(unsigned index) | ||
197 | { | ||
198 | pc8736x_gpio_set(index, 0); | ||
199 | } | ||
200 | |||
201 | static int pc8736x_gpio_current(unsigned minor) | 191 | static int pc8736x_gpio_current(unsigned minor) |
202 | { | 192 | { |
203 | int port, bit; | 193 | int port, bit; |
diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index 00f574cbb0d4..dd845cbefe94 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c | |||
@@ -3010,7 +3010,7 @@ static struct pcmcia_driver mgslpc_driver = { | |||
3010 | .resume = mgslpc_resume, | 3010 | .resume = mgslpc_resume, |
3011 | }; | 3011 | }; |
3012 | 3012 | ||
3013 | static struct tty_operations mgslpc_ops = { | 3013 | static const struct tty_operations mgslpc_ops = { |
3014 | .open = mgslpc_open, | 3014 | .open = mgslpc_open, |
3015 | .close = mgslpc_close, | 3015 | .close = mgslpc_close, |
3016 | .write = mgslpc_write, | 3016 | .write = mgslpc_write, |
diff --git a/drivers/char/pty.c b/drivers/char/pty.c index 34dd4c38110e..80d3eedd7f96 100644 --- a/drivers/char/pty.c +++ b/drivers/char/pty.c | |||
@@ -224,7 +224,7 @@ static void pty_set_termios(struct tty_struct *tty, struct termios *old_termios) | |||
224 | tty->termios->c_cflag |= (CS8 | CREAD); | 224 | tty->termios->c_cflag |= (CS8 | CREAD); |
225 | } | 225 | } |
226 | 226 | ||
227 | static struct tty_operations pty_ops = { | 227 | static const struct tty_operations pty_ops = { |
228 | .open = pty_open, | 228 | .open = pty_open, |
229 | .close = pty_close, | 229 | .close = pty_close, |
230 | .write = pty_write, | 230 | .write = pty_write, |
diff --git a/drivers/char/random.c b/drivers/char/random.c index 4c3a5ca9d8f7..07f47a0208a7 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c | |||
@@ -655,6 +655,7 @@ void add_interrupt_randomness(int irq) | |||
655 | add_timer_randomness(irq_timer_state[irq], 0x100 + irq); | 655 | add_timer_randomness(irq_timer_state[irq], 0x100 + irq); |
656 | } | 656 | } |
657 | 657 | ||
658 | #ifdef CONFIG_BLOCK | ||
658 | void add_disk_randomness(struct gendisk *disk) | 659 | void add_disk_randomness(struct gendisk *disk) |
659 | { | 660 | { |
660 | if (!disk || !disk->random) | 661 | if (!disk || !disk->random) |
@@ -667,6 +668,7 @@ void add_disk_randomness(struct gendisk *disk) | |||
667 | } | 668 | } |
668 | 669 | ||
669 | EXPORT_SYMBOL(add_disk_randomness); | 670 | EXPORT_SYMBOL(add_disk_randomness); |
671 | #endif | ||
670 | 672 | ||
671 | #define EXTRACT_SIZE 10 | 673 | #define EXTRACT_SIZE 10 |
672 | 674 | ||
@@ -887,8 +889,8 @@ static void init_std_data(struct entropy_store *r) | |||
887 | 889 | ||
888 | do_gettimeofday(&tv); | 890 | do_gettimeofday(&tv); |
889 | add_entropy_words(r, (__u32 *)&tv, sizeof(tv)/4); | 891 | add_entropy_words(r, (__u32 *)&tv, sizeof(tv)/4); |
890 | add_entropy_words(r, (__u32 *)&system_utsname, | 892 | add_entropy_words(r, (__u32 *)utsname(), |
891 | sizeof(system_utsname)/4); | 893 | sizeof(*(utsname()))/4); |
892 | } | 894 | } |
893 | 895 | ||
894 | static int __init rand_initialize(void) | 896 | static int __init rand_initialize(void) |
@@ -918,6 +920,7 @@ void rand_initialize_irq(int irq) | |||
918 | } | 920 | } |
919 | } | 921 | } |
920 | 922 | ||
923 | #ifdef CONFIG_BLOCK | ||
921 | void rand_initialize_disk(struct gendisk *disk) | 924 | void rand_initialize_disk(struct gendisk *disk) |
922 | { | 925 | { |
923 | struct timer_rand_state *state; | 926 | struct timer_rand_state *state; |
@@ -932,6 +935,7 @@ void rand_initialize_disk(struct gendisk *disk) | |||
932 | disk->random = state; | 935 | disk->random = state; |
933 | } | 936 | } |
934 | } | 937 | } |
938 | #endif | ||
935 | 939 | ||
936 | static ssize_t | 940 | static ssize_t |
937 | random_read(struct file * file, char __user * buf, size_t nbytes, loff_t *ppos) | 941 | random_read(struct file * file, char __user * buf, size_t nbytes, loff_t *ppos) |
diff --git a/drivers/char/raw.c b/drivers/char/raw.c index 579868af4a54..89b718e326e5 100644 --- a/drivers/char/raw.c +++ b/drivers/char/raw.c | |||
@@ -238,39 +238,14 @@ out: | |||
238 | return err; | 238 | return err; |
239 | } | 239 | } |
240 | 240 | ||
241 | static ssize_t raw_file_write(struct file *file, const char __user *buf, | ||
242 | size_t count, loff_t *ppos) | ||
243 | { | ||
244 | struct iovec local_iov = { | ||
245 | .iov_base = (char __user *)buf, | ||
246 | .iov_len = count | ||
247 | }; | ||
248 | |||
249 | return generic_file_write_nolock(file, &local_iov, 1, ppos); | ||
250 | } | ||
251 | |||
252 | static ssize_t raw_file_aio_write(struct kiocb *iocb, const char __user *buf, | ||
253 | size_t count, loff_t pos) | ||
254 | { | ||
255 | struct iovec local_iov = { | ||
256 | .iov_base = (char __user *)buf, | ||
257 | .iov_len = count | ||
258 | }; | ||
259 | |||
260 | return generic_file_aio_write_nolock(iocb, &local_iov, 1, &iocb->ki_pos); | ||
261 | } | ||
262 | |||
263 | |||
264 | static const struct file_operations raw_fops = { | 241 | static const struct file_operations raw_fops = { |
265 | .read = generic_file_read, | 242 | .read = do_sync_read, |
266 | .aio_read = generic_file_aio_read, | 243 | .aio_read = generic_file_aio_read, |
267 | .write = raw_file_write, | 244 | .write = do_sync_write, |
268 | .aio_write = raw_file_aio_write, | 245 | .aio_write = generic_file_aio_write_nolock, |
269 | .open = raw_open, | 246 | .open = raw_open, |
270 | .release= raw_release, | 247 | .release= raw_release, |
271 | .ioctl = raw_ioctl, | 248 | .ioctl = raw_ioctl, |
272 | .readv = generic_file_readv, | ||
273 | .writev = generic_file_writev, | ||
274 | .owner = THIS_MODULE, | 249 | .owner = THIS_MODULE, |
275 | }; | 250 | }; |
276 | 251 | ||
@@ -288,31 +263,34 @@ static struct cdev raw_cdev = { | |||
288 | static int __init raw_init(void) | 263 | static int __init raw_init(void) |
289 | { | 264 | { |
290 | dev_t dev = MKDEV(RAW_MAJOR, 0); | 265 | dev_t dev = MKDEV(RAW_MAJOR, 0); |
266 | int ret; | ||
291 | 267 | ||
292 | if (register_chrdev_region(dev, MAX_RAW_MINORS, "raw")) | 268 | ret = register_chrdev_region(dev, MAX_RAW_MINORS, "raw"); |
269 | if (ret) | ||
293 | goto error; | 270 | goto error; |
294 | 271 | ||
295 | cdev_init(&raw_cdev, &raw_fops); | 272 | cdev_init(&raw_cdev, &raw_fops); |
296 | if (cdev_add(&raw_cdev, dev, MAX_RAW_MINORS)) { | 273 | ret = cdev_add(&raw_cdev, dev, MAX_RAW_MINORS); |
274 | if (ret) { | ||
297 | kobject_put(&raw_cdev.kobj); | 275 | kobject_put(&raw_cdev.kobj); |
298 | unregister_chrdev_region(dev, MAX_RAW_MINORS); | 276 | goto error_region; |
299 | goto error; | ||
300 | } | 277 | } |
301 | 278 | ||
302 | raw_class = class_create(THIS_MODULE, "raw"); | 279 | raw_class = class_create(THIS_MODULE, "raw"); |
303 | if (IS_ERR(raw_class)) { | 280 | if (IS_ERR(raw_class)) { |
304 | printk(KERN_ERR "Error creating raw class.\n"); | 281 | printk(KERN_ERR "Error creating raw class.\n"); |
305 | cdev_del(&raw_cdev); | 282 | cdev_del(&raw_cdev); |
306 | unregister_chrdev_region(dev, MAX_RAW_MINORS); | 283 | ret = PTR_ERR(raw_class); |
307 | goto error; | 284 | goto error_region; |
308 | } | 285 | } |
309 | class_device_create(raw_class, NULL, MKDEV(RAW_MAJOR, 0), NULL, "rawctl"); | 286 | class_device_create(raw_class, NULL, MKDEV(RAW_MAJOR, 0), NULL, "rawctl"); |
310 | 287 | ||
311 | return 0; | 288 | return 0; |
312 | 289 | ||
290 | error_region: | ||
291 | unregister_chrdev_region(dev, MAX_RAW_MINORS); | ||
313 | error: | 292 | error: |
314 | printk(KERN_ERR "error register raw device\n"); | 293 | return ret; |
315 | return 1; | ||
316 | } | 294 | } |
317 | 295 | ||
318 | static void __exit raw_exit(void) | 296 | static void __exit raw_exit(void) |
diff --git a/drivers/char/rio/rio_linux.c b/drivers/char/rio/rio_linux.c index 3fa80aaf4527..202a3b0945b7 100644 --- a/drivers/char/rio/rio_linux.c +++ b/drivers/char/rio/rio_linux.c | |||
@@ -727,7 +727,7 @@ static struct vpd_prom *get_VPD_PROM(struct Host *hp) | |||
727 | return &vpdp; | 727 | return &vpdp; |
728 | } | 728 | } |
729 | 729 | ||
730 | static struct tty_operations rio_ops = { | 730 | static const struct tty_operations rio_ops = { |
731 | .open = riotopen, | 731 | .open = riotopen, |
732 | .close = gs_close, | 732 | .close = gs_close, |
733 | .write = gs_write, | 733 | .write = gs_write, |
diff --git a/drivers/char/riscom8.c b/drivers/char/riscom8.c index f1c94f771af5..214d850112fd 100644 --- a/drivers/char/riscom8.c +++ b/drivers/char/riscom8.c | |||
@@ -675,26 +675,12 @@ static void rc_change_speed(struct riscom_board *bp, struct riscom_port *port) | |||
675 | port->COR2 = 0; | 675 | port->COR2 = 0; |
676 | port->MSVR = MSVR_RTS; | 676 | port->MSVR = MSVR_RTS; |
677 | 677 | ||
678 | baud = C_BAUD(tty); | 678 | baud = tty_get_baud_rate(tty); |
679 | |||
680 | if (baud & CBAUDEX) { | ||
681 | baud &= ~CBAUDEX; | ||
682 | if (baud < 1 || baud > 2) | ||
683 | port->tty->termios->c_cflag &= ~CBAUDEX; | ||
684 | else | ||
685 | baud += 15; | ||
686 | } | ||
687 | if (baud == 15) { | ||
688 | if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) | ||
689 | baud ++; | ||
690 | if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) | ||
691 | baud += 2; | ||
692 | } | ||
693 | 679 | ||
694 | /* Select port on the board */ | 680 | /* Select port on the board */ |
695 | rc_out(bp, CD180_CAR, port_No(port)); | 681 | rc_out(bp, CD180_CAR, port_No(port)); |
696 | 682 | ||
697 | if (!baud_table[baud]) { | 683 | if (!baud) { |
698 | /* Drop DTR & exit */ | 684 | /* Drop DTR & exit */ |
699 | bp->DTR |= (1u << port_No(port)); | 685 | bp->DTR |= (1u << port_No(port)); |
700 | rc_out(bp, RC_DTR, bp->DTR); | 686 | rc_out(bp, RC_DTR, bp->DTR); |
@@ -710,7 +696,7 @@ static void rc_change_speed(struct riscom_board *bp, struct riscom_port *port) | |||
710 | */ | 696 | */ |
711 | 697 | ||
712 | /* Set baud rate for port */ | 698 | /* Set baud rate for port */ |
713 | tmp = (((RC_OSCFREQ + baud_table[baud]/2) / baud_table[baud] + | 699 | tmp = (((RC_OSCFREQ + baud/2) / baud + |
714 | CD180_TPC/2) / CD180_TPC); | 700 | CD180_TPC/2) / CD180_TPC); |
715 | 701 | ||
716 | rc_out(bp, CD180_RBPRH, (tmp >> 8) & 0xff); | 702 | rc_out(bp, CD180_RBPRH, (tmp >> 8) & 0xff); |
@@ -718,7 +704,7 @@ static void rc_change_speed(struct riscom_board *bp, struct riscom_port *port) | |||
718 | rc_out(bp, CD180_RBPRL, tmp & 0xff); | 704 | rc_out(bp, CD180_RBPRL, tmp & 0xff); |
719 | rc_out(bp, CD180_TBPRL, tmp & 0xff); | 705 | rc_out(bp, CD180_TBPRL, tmp & 0xff); |
720 | 706 | ||
721 | baud = (baud_table[baud] + 5) / 10; /* Estimated CPS */ | 707 | baud = (baud + 5) / 10; /* Estimated CPS */ |
722 | 708 | ||
723 | /* Two timer ticks seems enough to wakeup something like SLIP driver */ | 709 | /* Two timer ticks seems enough to wakeup something like SLIP driver */ |
724 | tmp = ((baud + HZ/2) / HZ) * 2 - CD180_NFIFO; | 710 | tmp = ((baud + HZ/2) / HZ) * 2 - CD180_NFIFO; |
@@ -1597,7 +1583,7 @@ static void do_softint(void *private_) | |||
1597 | } | 1583 | } |
1598 | } | 1584 | } |
1599 | 1585 | ||
1600 | static struct tty_operations riscom_ops = { | 1586 | static const struct tty_operations riscom_ops = { |
1601 | .open = rc_open, | 1587 | .open = rc_open, |
1602 | .close = rc_close, | 1588 | .close = rc_close, |
1603 | .write = rc_write, | 1589 | .write = rc_write, |
diff --git a/drivers/char/rocket.c b/drivers/char/rocket.c index 0ac131881322..bac80056f7e0 100644 --- a/drivers/char/rocket.c +++ b/drivers/char/rocket.c | |||
@@ -2334,7 +2334,7 @@ static int __init init_ISA(int i) | |||
2334 | return (1); | 2334 | return (1); |
2335 | } | 2335 | } |
2336 | 2336 | ||
2337 | static struct tty_operations rocket_ops = { | 2337 | static const struct tty_operations rocket_ops = { |
2338 | .open = rp_open, | 2338 | .open = rp_open, |
2339 | .close = rp_close, | 2339 | .close = rp_close, |
2340 | .write = rp_write, | 2340 | .write = rp_write, |
diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c index 6e6a7c7a7eff..656f8c0ca52e 100644 --- a/drivers/char/rtc.c +++ b/drivers/char/rtc.c | |||
@@ -209,11 +209,12 @@ static const unsigned char days_in_mo[] = | |||
209 | */ | 209 | */ |
210 | static inline unsigned char rtc_is_updating(void) | 210 | static inline unsigned char rtc_is_updating(void) |
211 | { | 211 | { |
212 | unsigned long flags; | ||
212 | unsigned char uip; | 213 | unsigned char uip; |
213 | 214 | ||
214 | spin_lock_irq(&rtc_lock); | 215 | spin_lock_irqsave(&rtc_lock, flags); |
215 | uip = (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP); | 216 | uip = (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP); |
216 | spin_unlock_irq(&rtc_lock); | 217 | spin_unlock_irqrestore(&rtc_lock, flags); |
217 | return uip; | 218 | return uip; |
218 | } | 219 | } |
219 | 220 | ||
@@ -1261,10 +1262,8 @@ void rtc_get_rtc_time(struct rtc_time *rtc_tm) | |||
1261 | * Once the read clears, read the RTC time (again via ioctl). Easy. | 1262 | * Once the read clears, read the RTC time (again via ioctl). Easy. |
1262 | */ | 1263 | */ |
1263 | 1264 | ||
1264 | while (rtc_is_updating() != 0 && jiffies - uip_watchdog < 2*HZ/100) { | 1265 | while (rtc_is_updating() != 0 && jiffies - uip_watchdog < 2*HZ/100) |
1265 | barrier(); | ||
1266 | cpu_relax(); | 1266 | cpu_relax(); |
1267 | } | ||
1268 | 1267 | ||
1269 | /* | 1268 | /* |
1270 | * Only the values that we read from the RTC are set. We leave | 1269 | * Only the values that we read from the RTC are set. We leave |
diff --git a/drivers/char/s3c2410-rtc.c b/drivers/char/s3c2410-rtc.c deleted file mode 100644 index 5458ef1634e5..000000000000 --- a/drivers/char/s3c2410-rtc.c +++ /dev/null | |||
@@ -1,591 +0,0 @@ | |||
1 | /* drivers/char/s3c2410_rtc.c | ||
2 | * | ||
3 | * Copyright (c) 2004 Simtec Electronics <linux@simtec.co.uk> | ||
4 | * http://www.simtec.co.uk/products/SWLINUX/ | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * S3C2410 Internal RTC Driver | ||
11 | * | ||
12 | * Changelog: | ||
13 | * 08-Nov-2004 BJD Initial creation | ||
14 | * 12-Nov-2004 BJD Added periodic IRQ and PM code | ||
15 | * 22-Nov-2004 BJD Sign-test on alarm code to check for <0 | ||
16 | * 10-Mar-2005 LCVR Changed S3C2410_VA_RTC to S3C24XX_VA_RTC | ||
17 | */ | ||
18 | |||
19 | #include <linux/module.h> | ||
20 | #include <linux/fs.h> | ||
21 | #include <linux/string.h> | ||
22 | #include <linux/init.h> | ||
23 | #include <linux/platform_device.h> | ||
24 | #include <linux/interrupt.h> | ||
25 | #include <linux/rtc.h> | ||
26 | #include <linux/bcd.h> | ||
27 | #include <linux/clk.h> | ||
28 | |||
29 | #include <asm/hardware.h> | ||
30 | #include <asm/uaccess.h> | ||
31 | #include <asm/io.h> | ||
32 | #include <asm/irq.h> | ||
33 | #include <asm/rtc.h> | ||
34 | |||
35 | #include <asm/mach/time.h> | ||
36 | |||
37 | #include <asm/arch/regs-rtc.h> | ||
38 | |||
39 | /* need this for the RTC_AF definitions */ | ||
40 | #include <linux/mc146818rtc.h> | ||
41 | |||
42 | #undef S3C24XX_VA_RTC | ||
43 | #define S3C24XX_VA_RTC s3c2410_rtc_base | ||
44 | |||
45 | static struct resource *s3c2410_rtc_mem; | ||
46 | |||
47 | static void __iomem *s3c2410_rtc_base; | ||
48 | static int s3c2410_rtc_alarmno = NO_IRQ; | ||
49 | static int s3c2410_rtc_tickno = NO_IRQ; | ||
50 | static int s3c2410_rtc_freq = 1; | ||
51 | |||
52 | static DEFINE_SPINLOCK(s3c2410_rtc_pie_lock); | ||
53 | |||
54 | /* IRQ Handlers */ | ||
55 | |||
56 | static irqreturn_t s3c2410_rtc_alarmirq(int irq, void *id, struct pt_regs *r) | ||
57 | { | ||
58 | rtc_update(1, RTC_AF | RTC_IRQF); | ||
59 | return IRQ_HANDLED; | ||
60 | } | ||
61 | |||
62 | static irqreturn_t s3c2410_rtc_tickirq(int irq, void *id, struct pt_regs *r) | ||
63 | { | ||
64 | rtc_update(1, RTC_PF | RTC_IRQF); | ||
65 | return IRQ_HANDLED; | ||
66 | } | ||
67 | |||
68 | /* Update control registers */ | ||
69 | static void s3c2410_rtc_setaie(int to) | ||
70 | { | ||
71 | unsigned int tmp; | ||
72 | |||
73 | pr_debug("%s: aie=%d\n", __FUNCTION__, to); | ||
74 | |||
75 | tmp = readb(S3C2410_RTCALM); | ||
76 | |||
77 | if (to) | ||
78 | tmp |= S3C2410_RTCALM_ALMEN; | ||
79 | else | ||
80 | tmp &= ~S3C2410_RTCALM_ALMEN; | ||
81 | |||
82 | |||
83 | writeb(tmp, S3C2410_RTCALM); | ||
84 | } | ||
85 | |||
86 | static void s3c2410_rtc_setpie(int to) | ||
87 | { | ||
88 | unsigned int tmp; | ||
89 | |||
90 | pr_debug("%s: pie=%d\n", __FUNCTION__, to); | ||
91 | |||
92 | spin_lock_irq(&s3c2410_rtc_pie_lock); | ||
93 | tmp = readb(S3C2410_TICNT) & ~S3C2410_TICNT_ENABLE; | ||
94 | |||
95 | if (to) | ||
96 | tmp |= S3C2410_TICNT_ENABLE; | ||
97 | |||
98 | writeb(tmp, S3C2410_TICNT); | ||
99 | spin_unlock_irq(&s3c2410_rtc_pie_lock); | ||
100 | } | ||
101 | |||
102 | static void s3c2410_rtc_setfreq(int freq) | ||
103 | { | ||
104 | unsigned int tmp; | ||
105 | |||
106 | spin_lock_irq(&s3c2410_rtc_pie_lock); | ||
107 | tmp = readb(S3C2410_TICNT) & S3C2410_TICNT_ENABLE; | ||
108 | |||
109 | s3c2410_rtc_freq = freq; | ||
110 | |||
111 | tmp |= (128 / freq)-1; | ||
112 | |||
113 | writeb(tmp, S3C2410_TICNT); | ||
114 | spin_unlock_irq(&s3c2410_rtc_pie_lock); | ||
115 | } | ||
116 | |||
117 | /* Time read/write */ | ||
118 | |||
119 | static int s3c2410_rtc_gettime(struct rtc_time *rtc_tm) | ||
120 | { | ||
121 | unsigned int have_retried = 0; | ||
122 | |||
123 | retry_get_time: | ||
124 | rtc_tm->tm_min = readb(S3C2410_RTCMIN); | ||
125 | rtc_tm->tm_hour = readb(S3C2410_RTCHOUR); | ||
126 | rtc_tm->tm_mday = readb(S3C2410_RTCDATE); | ||
127 | rtc_tm->tm_mon = readb(S3C2410_RTCMON); | ||
128 | rtc_tm->tm_year = readb(S3C2410_RTCYEAR); | ||
129 | rtc_tm->tm_sec = readb(S3C2410_RTCSEC); | ||
130 | |||
131 | /* the only way to work out wether the system was mid-update | ||
132 | * when we read it is to check the second counter, and if it | ||
133 | * is zero, then we re-try the entire read | ||
134 | */ | ||
135 | |||
136 | if (rtc_tm->tm_sec == 0 && !have_retried) { | ||
137 | have_retried = 1; | ||
138 | goto retry_get_time; | ||
139 | } | ||
140 | |||
141 | pr_debug("read time %02x.%02x.%02x %02x/%02x/%02x\n", | ||
142 | rtc_tm->tm_year, rtc_tm->tm_mon, rtc_tm->tm_mday, | ||
143 | rtc_tm->tm_hour, rtc_tm->tm_min, rtc_tm->tm_sec); | ||
144 | |||
145 | BCD_TO_BIN(rtc_tm->tm_sec); | ||
146 | BCD_TO_BIN(rtc_tm->tm_min); | ||
147 | BCD_TO_BIN(rtc_tm->tm_hour); | ||
148 | BCD_TO_BIN(rtc_tm->tm_mday); | ||
149 | BCD_TO_BIN(rtc_tm->tm_mon); | ||
150 | BCD_TO_BIN(rtc_tm->tm_year); | ||
151 | |||
152 | rtc_tm->tm_year += 100; | ||
153 | rtc_tm->tm_mon -= 1; | ||
154 | |||
155 | return 0; | ||
156 | } | ||
157 | |||
158 | |||
159 | static int s3c2410_rtc_settime(struct rtc_time *tm) | ||
160 | { | ||
161 | /* the rtc gets round the y2k problem by just not supporting it */ | ||
162 | |||
163 | if (tm->tm_year < 100) | ||
164 | return -EINVAL; | ||
165 | |||
166 | writeb(BIN2BCD(tm->tm_sec), S3C2410_RTCSEC); | ||
167 | writeb(BIN2BCD(tm->tm_min), S3C2410_RTCMIN); | ||
168 | writeb(BIN2BCD(tm->tm_hour), S3C2410_RTCHOUR); | ||
169 | writeb(BIN2BCD(tm->tm_mday), S3C2410_RTCDATE); | ||
170 | writeb(BIN2BCD(tm->tm_mon + 1), S3C2410_RTCMON); | ||
171 | writeb(BIN2BCD(tm->tm_year - 100), S3C2410_RTCYEAR); | ||
172 | |||
173 | return 0; | ||
174 | } | ||
175 | |||
176 | static int s3c2410_rtc_getalarm(struct rtc_wkalrm *alrm) | ||
177 | { | ||
178 | struct rtc_time *alm_tm = &alrm->time; | ||
179 | unsigned int alm_en; | ||
180 | |||
181 | alm_tm->tm_sec = readb(S3C2410_ALMSEC); | ||
182 | alm_tm->tm_min = readb(S3C2410_ALMMIN); | ||
183 | alm_tm->tm_hour = readb(S3C2410_ALMHOUR); | ||
184 | alm_tm->tm_mon = readb(S3C2410_ALMMON); | ||
185 | alm_tm->tm_mday = readb(S3C2410_ALMDATE); | ||
186 | alm_tm->tm_year = readb(S3C2410_ALMYEAR); | ||
187 | |||
188 | alm_en = readb(S3C2410_RTCALM); | ||
189 | |||
190 | pr_debug("read alarm %02x %02x.%02x.%02x %02x/%02x/%02x\n", | ||
191 | alm_en, | ||
192 | alm_tm->tm_year, alm_tm->tm_mon, alm_tm->tm_mday, | ||
193 | alm_tm->tm_hour, alm_tm->tm_min, alm_tm->tm_sec); | ||
194 | |||
195 | |||
196 | /* decode the alarm enable field */ | ||
197 | |||
198 | if (alm_en & S3C2410_RTCALM_SECEN) { | ||
199 | BCD_TO_BIN(alm_tm->tm_sec); | ||
200 | } else { | ||
201 | alm_tm->tm_sec = 0xff; | ||
202 | } | ||
203 | |||
204 | if (alm_en & S3C2410_RTCALM_MINEN) { | ||
205 | BCD_TO_BIN(alm_tm->tm_min); | ||
206 | } else { | ||
207 | alm_tm->tm_min = 0xff; | ||
208 | } | ||
209 | |||
210 | if (alm_en & S3C2410_RTCALM_HOUREN) { | ||
211 | BCD_TO_BIN(alm_tm->tm_hour); | ||
212 | } else { | ||
213 | alm_tm->tm_hour = 0xff; | ||
214 | } | ||
215 | |||
216 | if (alm_en & S3C2410_RTCALM_DAYEN) { | ||
217 | BCD_TO_BIN(alm_tm->tm_mday); | ||
218 | } else { | ||
219 | alm_tm->tm_mday = 0xff; | ||
220 | } | ||
221 | |||
222 | if (alm_en & S3C2410_RTCALM_MONEN) { | ||
223 | BCD_TO_BIN(alm_tm->tm_mon); | ||
224 | alm_tm->tm_mon -= 1; | ||
225 | } else { | ||
226 | alm_tm->tm_mon = 0xff; | ||
227 | } | ||
228 | |||
229 | if (alm_en & S3C2410_RTCALM_YEAREN) { | ||
230 | BCD_TO_BIN(alm_tm->tm_year); | ||
231 | } else { | ||
232 | alm_tm->tm_year = 0xffff; | ||
233 | } | ||
234 | |||
235 | /* todo - set alrm->enabled ? */ | ||
236 | |||
237 | return 0; | ||
238 | } | ||
239 | |||
240 | static int s3c2410_rtc_setalarm(struct rtc_wkalrm *alrm) | ||
241 | { | ||
242 | struct rtc_time *tm = &alrm->time; | ||
243 | unsigned int alrm_en; | ||
244 | |||
245 | pr_debug("s3c2410_rtc_setalarm: %d, %02x/%02x/%02x %02x.%02x.%02x\n", | ||
246 | alrm->enabled, | ||
247 | tm->tm_mday & 0xff, tm->tm_mon & 0xff, tm->tm_year & 0xff, | ||
248 | tm->tm_hour & 0xff, tm->tm_min & 0xff, tm->tm_sec); | ||
249 | |||
250 | if (alrm->enabled || 1) { | ||
251 | alrm_en = readb(S3C2410_RTCALM) & S3C2410_RTCALM_ALMEN; | ||
252 | writeb(0x00, S3C2410_RTCALM); | ||
253 | |||
254 | if (tm->tm_sec < 60 && tm->tm_sec >= 0) { | ||
255 | alrm_en |= S3C2410_RTCALM_SECEN; | ||
256 | writeb(BIN2BCD(tm->tm_sec), S3C2410_ALMSEC); | ||
257 | } | ||
258 | |||
259 | if (tm->tm_min < 60 && tm->tm_min >= 0) { | ||
260 | alrm_en |= S3C2410_RTCALM_MINEN; | ||
261 | writeb(BIN2BCD(tm->tm_min), S3C2410_ALMMIN); | ||
262 | } | ||
263 | |||
264 | if (tm->tm_hour < 24 && tm->tm_hour >= 0) { | ||
265 | alrm_en |= S3C2410_RTCALM_HOUREN; | ||
266 | writeb(BIN2BCD(tm->tm_hour), S3C2410_ALMHOUR); | ||
267 | } | ||
268 | |||
269 | pr_debug("setting S3C2410_RTCALM to %08x\n", alrm_en); | ||
270 | |||
271 | writeb(alrm_en, S3C2410_RTCALM); | ||
272 | enable_irq_wake(s3c2410_rtc_alarmno); | ||
273 | } else { | ||
274 | alrm_en = readb(S3C2410_RTCALM); | ||
275 | alrm_en &= ~S3C2410_RTCALM_ALMEN; | ||
276 | writeb(alrm_en, S3C2410_RTCALM); | ||
277 | disable_irq_wake(s3c2410_rtc_alarmno); | ||
278 | } | ||
279 | |||
280 | return 0; | ||
281 | } | ||
282 | |||
283 | static int s3c2410_rtc_ioctl(unsigned int cmd, unsigned long arg) | ||
284 | { | ||
285 | switch (cmd) { | ||
286 | case RTC_AIE_OFF: | ||
287 | case RTC_AIE_ON: | ||
288 | s3c2410_rtc_setaie((cmd == RTC_AIE_ON) ? 1 : 0); | ||
289 | return 0; | ||
290 | |||
291 | case RTC_PIE_OFF: | ||
292 | case RTC_PIE_ON: | ||
293 | s3c2410_rtc_setpie((cmd == RTC_PIE_ON) ? 1 : 0); | ||
294 | return 0; | ||
295 | |||
296 | case RTC_IRQP_READ: | ||
297 | return put_user(s3c2410_rtc_freq, (unsigned long __user *)arg); | ||
298 | |||
299 | case RTC_IRQP_SET: | ||
300 | if (arg < 1 || arg > 64) | ||
301 | return -EINVAL; | ||
302 | |||
303 | if (!capable(CAP_SYS_RESOURCE)) | ||
304 | return -EACCES; | ||
305 | |||
306 | /* check for power of 2 */ | ||
307 | |||
308 | if ((arg & (arg-1)) != 0) | ||
309 | return -EINVAL; | ||
310 | |||
311 | pr_debug("s3c2410_rtc: setting frequency %ld\n", arg); | ||
312 | |||
313 | s3c2410_rtc_setfreq(arg); | ||
314 | return 0; | ||
315 | |||
316 | case RTC_UIE_ON: | ||
317 | case RTC_UIE_OFF: | ||
318 | return -EINVAL; | ||
319 | } | ||
320 | |||
321 | return -EINVAL; | ||
322 | } | ||
323 | |||
324 | static int s3c2410_rtc_proc(char *buf) | ||
325 | { | ||
326 | unsigned int rtcalm = readb(S3C2410_RTCALM); | ||
327 | unsigned int ticnt = readb (S3C2410_TICNT); | ||
328 | char *p = buf; | ||
329 | |||
330 | p += sprintf(p, "alarm_IRQ\t: %s\n", | ||
331 | (rtcalm & S3C2410_RTCALM_ALMEN) ? "yes" : "no" ); | ||
332 | p += sprintf(p, "periodic_IRQ\t: %s\n", | ||
333 | (ticnt & S3C2410_TICNT_ENABLE) ? "yes" : "no" ); | ||
334 | p += sprintf(p, "periodic_freq\t: %d\n", s3c2410_rtc_freq); | ||
335 | |||
336 | return p - buf; | ||
337 | } | ||
338 | |||
339 | static int s3c2410_rtc_open(void) | ||
340 | { | ||
341 | int ret; | ||
342 | |||
343 | ret = request_irq(s3c2410_rtc_alarmno, s3c2410_rtc_alarmirq, | ||
344 | IRQF_DISABLED, "s3c2410-rtc alarm", NULL); | ||
345 | |||
346 | if (ret) | ||
347 | printk(KERN_ERR "IRQ%d already in use\n", s3c2410_rtc_alarmno); | ||
348 | |||
349 | ret = request_irq(s3c2410_rtc_tickno, s3c2410_rtc_tickirq, | ||
350 | IRQF_DISABLED, "s3c2410-rtc tick", NULL); | ||
351 | |||
352 | if (ret) { | ||
353 | printk(KERN_ERR "IRQ%d already in use\n", s3c2410_rtc_tickno); | ||
354 | goto tick_err; | ||
355 | } | ||
356 | |||
357 | return ret; | ||
358 | |||
359 | tick_err: | ||
360 | free_irq(s3c2410_rtc_alarmno, NULL); | ||
361 | return ret; | ||
362 | } | ||
363 | |||
364 | static void s3c2410_rtc_release(void) | ||
365 | { | ||
366 | /* do not clear AIE here, it may be needed for wake */ | ||
367 | |||
368 | s3c2410_rtc_setpie(0); | ||
369 | free_irq(s3c2410_rtc_alarmno, NULL); | ||
370 | free_irq(s3c2410_rtc_tickno, NULL); | ||
371 | } | ||
372 | |||
373 | static struct rtc_ops s3c2410_rtcops = { | ||
374 | .owner = THIS_MODULE, | ||
375 | .open = s3c2410_rtc_open, | ||
376 | .release = s3c2410_rtc_release, | ||
377 | .ioctl = s3c2410_rtc_ioctl, | ||
378 | .read_time = s3c2410_rtc_gettime, | ||
379 | .set_time = s3c2410_rtc_settime, | ||
380 | .read_alarm = s3c2410_rtc_getalarm, | ||
381 | .set_alarm = s3c2410_rtc_setalarm, | ||
382 | .proc = s3c2410_rtc_proc, | ||
383 | }; | ||
384 | |||
385 | static void s3c2410_rtc_enable(struct platform_device *pdev, int en) | ||
386 | { | ||
387 | unsigned int tmp; | ||
388 | |||
389 | if (s3c2410_rtc_base == NULL) | ||
390 | return; | ||
391 | |||
392 | if (!en) { | ||
393 | tmp = readb(S3C2410_RTCCON); | ||
394 | writeb(tmp & ~S3C2410_RTCCON_RTCEN, S3C2410_RTCCON); | ||
395 | |||
396 | tmp = readb(S3C2410_TICNT); | ||
397 | writeb(tmp & ~S3C2410_TICNT_ENABLE, S3C2410_TICNT); | ||
398 | } else { | ||
399 | /* re-enable the device, and check it is ok */ | ||
400 | |||
401 | if ((readb(S3C2410_RTCCON) & S3C2410_RTCCON_RTCEN) == 0){ | ||
402 | dev_info(&pdev->dev, "rtc disabled, re-enabling\n"); | ||
403 | |||
404 | tmp = readb(S3C2410_RTCCON); | ||
405 | writeb(tmp | S3C2410_RTCCON_RTCEN , S3C2410_RTCCON); | ||
406 | } | ||
407 | |||
408 | if ((readb(S3C2410_RTCCON) & S3C2410_RTCCON_CNTSEL)){ | ||
409 | dev_info(&pdev->dev, "removing S3C2410_RTCCON_CNTSEL\n"); | ||
410 | |||
411 | tmp = readb(S3C2410_RTCCON); | ||
412 | writeb(tmp& ~S3C2410_RTCCON_CNTSEL , S3C2410_RTCCON); | ||
413 | } | ||
414 | |||
415 | if ((readb(S3C2410_RTCCON) & S3C2410_RTCCON_CLKRST)){ | ||
416 | dev_info(&pdev->dev, "removing S3C2410_RTCCON_CLKRST\n"); | ||
417 | |||
418 | tmp = readb(S3C2410_RTCCON); | ||
419 | writeb(tmp & ~S3C2410_RTCCON_CLKRST, S3C2410_RTCCON); | ||
420 | } | ||
421 | } | ||
422 | } | ||
423 | |||
424 | static int s3c2410_rtc_remove(struct platform_device *dev) | ||
425 | { | ||
426 | unregister_rtc(&s3c2410_rtcops); | ||
427 | |||
428 | s3c2410_rtc_setpie(0); | ||
429 | s3c2410_rtc_setaie(0); | ||
430 | |||
431 | if (s3c2410_rtc_mem != NULL) { | ||
432 | pr_debug("s3c2410_rtc: releasing s3c2410_rtc_mem\n"); | ||
433 | iounmap(s3c2410_rtc_base); | ||
434 | release_resource(s3c2410_rtc_mem); | ||
435 | kfree(s3c2410_rtc_mem); | ||
436 | } | ||
437 | |||
438 | return 0; | ||
439 | } | ||
440 | |||
441 | static int s3c2410_rtc_probe(struct platform_device *pdev) | ||
442 | { | ||
443 | struct resource *res; | ||
444 | int ret; | ||
445 | |||
446 | pr_debug("%s: probe=%p\n", __FUNCTION__, pdev); | ||
447 | |||
448 | /* find the IRQs */ | ||
449 | |||
450 | s3c2410_rtc_tickno = platform_get_irq(pdev, 1); | ||
451 | if (s3c2410_rtc_tickno < 0) { | ||
452 | dev_err(&pdev->dev, "no irq for rtc tick\n"); | ||
453 | return -ENOENT; | ||
454 | } | ||
455 | |||
456 | s3c2410_rtc_alarmno = platform_get_irq(pdev, 0); | ||
457 | if (s3c2410_rtc_alarmno < 0) { | ||
458 | dev_err(&pdev->dev, "no irq for alarm\n"); | ||
459 | return -ENOENT; | ||
460 | } | ||
461 | |||
462 | pr_debug("s3c2410_rtc: tick irq %d, alarm irq %d\n", | ||
463 | s3c2410_rtc_tickno, s3c2410_rtc_alarmno); | ||
464 | |||
465 | /* get the memory region */ | ||
466 | |||
467 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
468 | if (res == NULL) { | ||
469 | dev_err(&pdev->dev, "failed to get memory region resource\n"); | ||
470 | return -ENOENT; | ||
471 | } | ||
472 | |||
473 | s3c2410_rtc_mem = request_mem_region(res->start, res->end-res->start+1, | ||
474 | pdev->name); | ||
475 | |||
476 | if (s3c2410_rtc_mem == NULL) { | ||
477 | dev_err(&pdev->dev, "failed to reserve memory region\n"); | ||
478 | ret = -ENOENT; | ||
479 | goto exit_err; | ||
480 | } | ||
481 | |||
482 | s3c2410_rtc_base = ioremap(res->start, res->end - res->start + 1); | ||
483 | if (s3c2410_rtc_base == NULL) { | ||
484 | dev_err(&pdev->dev, "failed ioremap()\n"); | ||
485 | ret = -EINVAL; | ||
486 | goto exit_err; | ||
487 | } | ||
488 | |||
489 | s3c2410_rtc_mem = res; | ||
490 | pr_debug("s3c2410_rtc_base=%p\n", s3c2410_rtc_base); | ||
491 | |||
492 | pr_debug("s3c2410_rtc: RTCCON=%02x\n", readb(S3C2410_RTCCON)); | ||
493 | |||
494 | /* check to see if everything is setup correctly */ | ||
495 | |||
496 | s3c2410_rtc_enable(pdev, 1); | ||
497 | |||
498 | pr_debug("s3c2410_rtc: RTCCON=%02x\n", readb(S3C2410_RTCCON)); | ||
499 | |||
500 | s3c2410_rtc_setfreq(s3c2410_rtc_freq); | ||
501 | |||
502 | /* register RTC and exit */ | ||
503 | |||
504 | register_rtc(&s3c2410_rtcops); | ||
505 | return 0; | ||
506 | |||
507 | exit_err: | ||
508 | dev_err(&pdev->dev, "error %d during initialisation\n", ret); | ||
509 | |||
510 | return ret; | ||
511 | } | ||
512 | |||
513 | #ifdef CONFIG_PM | ||
514 | |||
515 | /* S3C2410 RTC Power management control */ | ||
516 | |||
517 | static struct timespec s3c2410_rtc_delta; | ||
518 | |||
519 | static int ticnt_save; | ||
520 | |||
521 | static int s3c2410_rtc_suspend(struct platform_device *pdev, pm_message_t state) | ||
522 | { | ||
523 | struct rtc_time tm; | ||
524 | struct timespec time; | ||
525 | |||
526 | time.tv_nsec = 0; | ||
527 | |||
528 | /* save TICNT for anyone using periodic interrupts */ | ||
529 | |||
530 | ticnt_save = readb(S3C2410_TICNT); | ||
531 | |||
532 | /* calculate time delta for suspend */ | ||
533 | |||
534 | s3c2410_rtc_gettime(&tm); | ||
535 | rtc_tm_to_time(&tm, &time.tv_sec); | ||
536 | save_time_delta(&s3c2410_rtc_delta, &time); | ||
537 | s3c2410_rtc_enable(pdev, 0); | ||
538 | |||
539 | return 0; | ||
540 | } | ||
541 | |||
542 | static int s3c2410_rtc_resume(struct platform_device *pdev) | ||
543 | { | ||
544 | struct rtc_time tm; | ||
545 | struct timespec time; | ||
546 | |||
547 | time.tv_nsec = 0; | ||
548 | |||
549 | s3c2410_rtc_enable(pdev, 1); | ||
550 | s3c2410_rtc_gettime(&tm); | ||
551 | rtc_tm_to_time(&tm, &time.tv_sec); | ||
552 | restore_time_delta(&s3c2410_rtc_delta, &time); | ||
553 | |||
554 | writeb(ticnt_save, S3C2410_TICNT); | ||
555 | return 0; | ||
556 | } | ||
557 | #else | ||
558 | #define s3c2410_rtc_suspend NULL | ||
559 | #define s3c2410_rtc_resume NULL | ||
560 | #endif | ||
561 | |||
562 | static struct platform_driver s3c2410_rtcdrv = { | ||
563 | .probe = s3c2410_rtc_probe, | ||
564 | .remove = s3c2410_rtc_remove, | ||
565 | .suspend = s3c2410_rtc_suspend, | ||
566 | .resume = s3c2410_rtc_resume, | ||
567 | .driver = { | ||
568 | .name = "s3c2410-rtc", | ||
569 | .owner = THIS_MODULE, | ||
570 | }, | ||
571 | }; | ||
572 | |||
573 | static char __initdata banner[] = "S3C2410 RTC, (c) 2004 Simtec Electronics\n"; | ||
574 | |||
575 | static int __init s3c2410_rtc_init(void) | ||
576 | { | ||
577 | printk(banner); | ||
578 | return platform_driver_register(&s3c2410_rtcdrv); | ||
579 | } | ||
580 | |||
581 | static void __exit s3c2410_rtc_exit(void) | ||
582 | { | ||
583 | platform_driver_unregister(&s3c2410_rtcdrv); | ||
584 | } | ||
585 | |||
586 | module_init(s3c2410_rtc_init); | ||
587 | module_exit(s3c2410_rtc_exit); | ||
588 | |||
589 | MODULE_DESCRIPTION("S3C24XX RTC Driver"); | ||
590 | MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>"); | ||
591 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/char/scx200_gpio.c b/drivers/char/scx200_gpio.c index b956c7babd18..99e5272e3c53 100644 --- a/drivers/char/scx200_gpio.c +++ b/drivers/char/scx200_gpio.c | |||
@@ -44,7 +44,7 @@ struct nsc_gpio_ops scx200_gpio_ops = { | |||
44 | .gpio_change = scx200_gpio_change, | 44 | .gpio_change = scx200_gpio_change, |
45 | .gpio_current = scx200_gpio_current | 45 | .gpio_current = scx200_gpio_current |
46 | }; | 46 | }; |
47 | EXPORT_SYMBOL(scx200_gpio_ops); | 47 | EXPORT_SYMBOL_GPL(scx200_gpio_ops); |
48 | 48 | ||
49 | static int scx200_gpio_open(struct inode *inode, struct file *file) | 49 | static int scx200_gpio_open(struct inode *inode, struct file *file) |
50 | { | 50 | { |
@@ -69,7 +69,7 @@ static const struct file_operations scx200_gpio_fileops = { | |||
69 | .release = scx200_gpio_release, | 69 | .release = scx200_gpio_release, |
70 | }; | 70 | }; |
71 | 71 | ||
72 | struct cdev scx200_gpio_cdev; /* use 1 cdev for all pins */ | 72 | static struct cdev scx200_gpio_cdev; /* use 1 cdev for all pins */ |
73 | 73 | ||
74 | static int __init scx200_gpio_init(void) | 74 | static int __init scx200_gpio_init(void) |
75 | { | 75 | { |
diff --git a/drivers/char/selection.c b/drivers/char/selection.c index 71093a9fc462..74cff839c857 100644 --- a/drivers/char/selection.c +++ b/drivers/char/selection.c | |||
@@ -33,7 +33,7 @@ extern void poke_blanked_console(void); | |||
33 | 33 | ||
34 | /* Variables for selection control. */ | 34 | /* Variables for selection control. */ |
35 | /* Use a dynamic buffer, instead of static (Dec 1994) */ | 35 | /* Use a dynamic buffer, instead of static (Dec 1994) */ |
36 | struct vc_data *sel_cons; /* must not be disallocated */ | 36 | struct vc_data *sel_cons; /* must not be deallocated */ |
37 | static volatile int sel_start = -1; /* cleared by clear_selection */ | 37 | static volatile int sel_start = -1; /* cleared by clear_selection */ |
38 | static int sel_end; | 38 | static int sel_end; |
39 | static int sel_buffer_lth; | 39 | static int sel_buffer_lth; |
diff --git a/drivers/char/ser_a2232.c b/drivers/char/ser_a2232.c index 510bd3e0e88b..65c751d0d643 100644 --- a/drivers/char/ser_a2232.c +++ b/drivers/char/ser_a2232.c | |||
@@ -661,7 +661,7 @@ static void a2232_init_portstructs(void) | |||
661 | } | 661 | } |
662 | } | 662 | } |
663 | 663 | ||
664 | static struct tty_operations a2232_ops = { | 664 | static const struct tty_operations a2232_ops = { |
665 | .open = a2232_open, | 665 | .open = a2232_open, |
666 | .close = gs_close, | 666 | .close = gs_close, |
667 | .write = gs_write, | 667 | .write = gs_write, |
diff --git a/drivers/char/serial167.c b/drivers/char/serial167.c index 21a710cb4bba..b4ea1266b663 100644 --- a/drivers/char/serial167.c +++ b/drivers/char/serial167.c | |||
@@ -2158,7 +2158,7 @@ mvme167_serial_console_setup(int cflag) | |||
2158 | rcor >> 5, rbpr); | 2158 | rcor >> 5, rbpr); |
2159 | } /* serial_console_init */ | 2159 | } /* serial_console_init */ |
2160 | 2160 | ||
2161 | static struct tty_operations cy_ops = { | 2161 | static const struct tty_operations cy_ops = { |
2162 | .open = cy_open, | 2162 | .open = cy_open, |
2163 | .close = cy_close, | 2163 | .close = cy_close, |
2164 | .write = cy_write, | 2164 | .write = cy_write, |
diff --git a/drivers/char/snsc_event.c b/drivers/char/snsc_event.c index d12d4f629cec..864854c58866 100644 --- a/drivers/char/snsc_event.c +++ b/drivers/char/snsc_event.c | |||
@@ -220,7 +220,7 @@ scdrv_dispatch_event(char *event, int len) | |||
220 | " Sending SIGPWR to init...\n"); | 220 | " Sending SIGPWR to init...\n"); |
221 | 221 | ||
222 | /* give a SIGPWR signal to init proc */ | 222 | /* give a SIGPWR signal to init proc */ |
223 | kill_proc(1, SIGPWR, 0); | 223 | kill_cad_pid(SIGPWR, 0); |
224 | } else { | 224 | } else { |
225 | /* print to system log */ | 225 | /* print to system log */ |
226 | printk("%s|$(0x%x)%s\n", severity, esp_code, desc); | 226 | printk("%s|$(0x%x)%s\n", severity, esp_code, desc); |
diff --git a/drivers/char/specialix.c b/drivers/char/specialix.c index a1d303f9a33d..902c48dca3bc 100644 --- a/drivers/char/specialix.c +++ b/drivers/char/specialix.c | |||
@@ -182,7 +182,6 @@ static int sx_poll = HZ; | |||
182 | #define RS_EVENT_WRITE_WAKEUP 0 | 182 | #define RS_EVENT_WRITE_WAKEUP 0 |
183 | 183 | ||
184 | static struct tty_driver *specialix_driver; | 184 | static struct tty_driver *specialix_driver; |
185 | static unsigned char * tmp_buf; | ||
186 | 185 | ||
187 | static unsigned long baud_table[] = { | 186 | static unsigned long baud_table[] = { |
188 | 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, | 187 | 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, |
@@ -1087,24 +1086,16 @@ static void sx_change_speed(struct specialix_board *bp, struct specialix_port *p | |||
1087 | port->MSVR = (sx_in(bp, CD186x_MSVR) & MSVR_RTS); | 1086 | port->MSVR = (sx_in(bp, CD186x_MSVR) & MSVR_RTS); |
1088 | spin_unlock_irqrestore(&bp->lock, flags); | 1087 | spin_unlock_irqrestore(&bp->lock, flags); |
1089 | dprintk (SX_DEBUG_TERMIOS, "sx: got MSVR=%02x.\n", port->MSVR); | 1088 | dprintk (SX_DEBUG_TERMIOS, "sx: got MSVR=%02x.\n", port->MSVR); |
1090 | baud = C_BAUD(tty); | 1089 | baud = tty_get_baud_rate(tty); |
1091 | 1090 | ||
1092 | if (baud & CBAUDEX) { | 1091 | if (baud == 38400) { |
1093 | baud &= ~CBAUDEX; | ||
1094 | if (baud < 1 || baud > 2) | ||
1095 | port->tty->termios->c_cflag &= ~CBAUDEX; | ||
1096 | else | ||
1097 | baud += 15; | ||
1098 | } | ||
1099 | if (baud == 15) { | ||
1100 | if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) | 1092 | if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) |
1101 | baud ++; | 1093 | baud ++; |
1102 | if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) | 1094 | if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) |
1103 | baud += 2; | 1095 | baud += 2; |
1104 | } | 1096 | } |
1105 | 1097 | ||
1106 | 1098 | if (!baud) { | |
1107 | if (!baud_table[baud]) { | ||
1108 | /* Drop DTR & exit */ | 1099 | /* Drop DTR & exit */ |
1109 | dprintk (SX_DEBUG_TERMIOS, "Dropping DTR... Hmm....\n"); | 1100 | dprintk (SX_DEBUG_TERMIOS, "Dropping DTR... Hmm....\n"); |
1110 | if (!SX_CRTSCTS (tty)) { | 1101 | if (!SX_CRTSCTS (tty)) { |
@@ -1134,7 +1125,7 @@ static void sx_change_speed(struct specialix_board *bp, struct specialix_port *p | |||
1134 | "This is an untested option, please be carefull.\n", | 1125 | "This is an untested option, please be carefull.\n", |
1135 | port_No (port), tmp); | 1126 | port_No (port), tmp); |
1136 | else | 1127 | else |
1137 | tmp = (((SX_OSCFREQ + baud_table[baud]/2) / baud_table[baud] + | 1128 | tmp = (((SX_OSCFREQ + baud/2) / baud + |
1138 | CD186x_TPC/2) / CD186x_TPC); | 1129 | CD186x_TPC/2) / CD186x_TPC); |
1139 | 1130 | ||
1140 | if ((tmp < 0x10) && time_before(again, jiffies)) { | 1131 | if ((tmp < 0x10) && time_before(again, jiffies)) { |
@@ -1682,7 +1673,7 @@ static int sx_write(struct tty_struct * tty, | |||
1682 | 1673 | ||
1683 | bp = port_Board(port); | 1674 | bp = port_Board(port); |
1684 | 1675 | ||
1685 | if (!port->xmit_buf || !tmp_buf) { | 1676 | if (!port->xmit_buf) { |
1686 | func_exit(); | 1677 | func_exit(); |
1687 | return 0; | 1678 | return 0; |
1688 | } | 1679 | } |
@@ -2372,7 +2363,7 @@ static void do_softint(void *private_) | |||
2372 | func_exit(); | 2363 | func_exit(); |
2373 | } | 2364 | } |
2374 | 2365 | ||
2375 | static struct tty_operations sx_ops = { | 2366 | static const struct tty_operations sx_ops = { |
2376 | .open = sx_open, | 2367 | .open = sx_open, |
2377 | .close = sx_close, | 2368 | .close = sx_close, |
2378 | .write = sx_write, | 2369 | .write = sx_write, |
@@ -2406,12 +2397,6 @@ static int sx_init_drivers(void) | |||
2406 | return 1; | 2397 | return 1; |
2407 | } | 2398 | } |
2408 | 2399 | ||
2409 | if (!(tmp_buf = (unsigned char *) get_zeroed_page(GFP_KERNEL))) { | ||
2410 | printk(KERN_ERR "sx: Couldn't get free page.\n"); | ||
2411 | put_tty_driver(specialix_driver); | ||
2412 | func_exit(); | ||
2413 | return 1; | ||
2414 | } | ||
2415 | specialix_driver->owner = THIS_MODULE; | 2400 | specialix_driver->owner = THIS_MODULE; |
2416 | specialix_driver->name = "ttyW"; | 2401 | specialix_driver->name = "ttyW"; |
2417 | specialix_driver->major = SPECIALIX_NORMAL_MAJOR; | 2402 | specialix_driver->major = SPECIALIX_NORMAL_MAJOR; |
@@ -2425,7 +2410,6 @@ static int sx_init_drivers(void) | |||
2425 | 2410 | ||
2426 | if ((error = tty_register_driver(specialix_driver))) { | 2411 | if ((error = tty_register_driver(specialix_driver))) { |
2427 | put_tty_driver(specialix_driver); | 2412 | put_tty_driver(specialix_driver); |
2428 | free_page((unsigned long)tmp_buf); | ||
2429 | printk(KERN_ERR "sx: Couldn't register specialix IO8+ driver, error = %d\n", | 2413 | printk(KERN_ERR "sx: Couldn't register specialix IO8+ driver, error = %d\n", |
2430 | error); | 2414 | error); |
2431 | func_exit(); | 2415 | func_exit(); |
@@ -2451,7 +2435,6 @@ static void sx_release_drivers(void) | |||
2451 | { | 2435 | { |
2452 | func_enter(); | 2436 | func_enter(); |
2453 | 2437 | ||
2454 | free_page((unsigned long)tmp_buf); | ||
2455 | tty_unregister_driver(specialix_driver); | 2438 | tty_unregister_driver(specialix_driver); |
2456 | put_tty_driver(specialix_driver); | 2439 | put_tty_driver(specialix_driver); |
2457 | func_exit(); | 2440 | func_exit(); |
diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c index 3beb2203d24b..bd711537ec4e 100644 --- a/drivers/char/stallion.c +++ b/drivers/char/stallion.c | |||
@@ -2993,7 +2993,7 @@ static int stl_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, uns | |||
2993 | return(rc); | 2993 | return(rc); |
2994 | } | 2994 | } |
2995 | 2995 | ||
2996 | static struct tty_operations stl_ops = { | 2996 | static const struct tty_operations stl_ops = { |
2997 | .open = stl_open, | 2997 | .open = stl_open, |
2998 | .close = stl_close, | 2998 | .close = stl_close, |
2999 | .write = stl_write, | 2999 | .write = stl_write, |
diff --git a/drivers/char/sx.c b/drivers/char/sx.c index e1cd2bc4b1e4..57e31e5eaedb 100644 --- a/drivers/char/sx.c +++ b/drivers/char/sx.c | |||
@@ -2226,7 +2226,7 @@ static int probe_si (struct sx_board *board) | |||
2226 | return 1; | 2226 | return 1; |
2227 | } | 2227 | } |
2228 | 2228 | ||
2229 | static struct tty_operations sx_ops = { | 2229 | static const struct tty_operations sx_ops = { |
2230 | .break_ctl = sx_break, | 2230 | .break_ctl = sx_break, |
2231 | .open = sx_open, | 2231 | .open = sx_open, |
2232 | .close = gs_close, | 2232 | .close = gs_close, |
diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c index 78b1b1a2732b..244dc308c770 100644 --- a/drivers/char/synclink.c +++ b/drivers/char/synclink.c | |||
@@ -4360,7 +4360,7 @@ static struct mgsl_struct* mgsl_allocate_device(void) | |||
4360 | 4360 | ||
4361 | } /* end of mgsl_allocate_device()*/ | 4361 | } /* end of mgsl_allocate_device()*/ |
4362 | 4362 | ||
4363 | static struct tty_operations mgsl_ops = { | 4363 | static const struct tty_operations mgsl_ops = { |
4364 | .open = mgsl_open, | 4364 | .open = mgsl_open, |
4365 | .close = mgsl_close, | 4365 | .close = mgsl_close, |
4366 | .write = mgsl_write, | 4366 | .write = mgsl_write, |
diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c index 2f07b085536b..bdc7cb248b8f 100644 --- a/drivers/char/synclink_gt.c +++ b/drivers/char/synclink_gt.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * $Id: synclink_gt.c,v 4.25 2006/02/06 21:20:33 paulkf Exp $ | 2 | * $Id: synclink_gt.c,v 4.36 2006/08/28 20:47:14 paulkf Exp $ |
3 | * | 3 | * |
4 | * Device driver for Microgate SyncLink GT serial adapters. | 4 | * Device driver for Microgate SyncLink GT serial adapters. |
5 | * | 5 | * |
@@ -91,12 +91,12 @@ | |||
91 | * module identification | 91 | * module identification |
92 | */ | 92 | */ |
93 | static char *driver_name = "SyncLink GT"; | 93 | static char *driver_name = "SyncLink GT"; |
94 | static char *driver_version = "$Revision: 4.25 $"; | 94 | static char *driver_version = "$Revision: 4.36 $"; |
95 | static char *tty_driver_name = "synclink_gt"; | 95 | static char *tty_driver_name = "synclink_gt"; |
96 | static char *tty_dev_prefix = "ttySLG"; | 96 | static char *tty_dev_prefix = "ttySLG"; |
97 | MODULE_LICENSE("GPL"); | 97 | MODULE_LICENSE("GPL"); |
98 | #define MGSL_MAGIC 0x5401 | 98 | #define MGSL_MAGIC 0x5401 |
99 | #define MAX_DEVICES 12 | 99 | #define MAX_DEVICES 32 |
100 | 100 | ||
101 | static struct pci_device_id pci_table[] = { | 101 | static struct pci_device_id pci_table[] = { |
102 | {PCI_VENDOR_ID_MICROGATE, SYNCLINK_GT_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,}, | 102 | {PCI_VENDOR_ID_MICROGATE, SYNCLINK_GT_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,}, |
@@ -461,7 +461,7 @@ static int adapter_test(struct slgt_info *info); | |||
461 | static void reset_adapter(struct slgt_info *info); | 461 | static void reset_adapter(struct slgt_info *info); |
462 | static void reset_port(struct slgt_info *info); | 462 | static void reset_port(struct slgt_info *info); |
463 | static void async_mode(struct slgt_info *info); | 463 | static void async_mode(struct slgt_info *info); |
464 | static void hdlc_mode(struct slgt_info *info); | 464 | static void sync_mode(struct slgt_info *info); |
465 | 465 | ||
466 | static void rx_stop(struct slgt_info *info); | 466 | static void rx_stop(struct slgt_info *info); |
467 | static void rx_start(struct slgt_info *info); | 467 | static void rx_start(struct slgt_info *info); |
@@ -881,7 +881,9 @@ static int write(struct tty_struct *tty, | |||
881 | if (!count) | 881 | if (!count) |
882 | goto cleanup; | 882 | goto cleanup; |
883 | 883 | ||
884 | if (info->params.mode == MGSL_MODE_RAW) { | 884 | if (info->params.mode == MGSL_MODE_RAW || |
885 | info->params.mode == MGSL_MODE_MONOSYNC || | ||
886 | info->params.mode == MGSL_MODE_BISYNC) { | ||
885 | unsigned int bufs_needed = (count/DMABUFSIZE); | 887 | unsigned int bufs_needed = (count/DMABUFSIZE); |
886 | unsigned int bufs_free = free_tbuf_count(info); | 888 | unsigned int bufs_free = free_tbuf_count(info); |
887 | if (count % DMABUFSIZE) | 889 | if (count % DMABUFSIZE) |
@@ -1897,6 +1899,8 @@ static void bh_handler(void* context) | |||
1897 | while(rx_get_frame(info)); | 1899 | while(rx_get_frame(info)); |
1898 | break; | 1900 | break; |
1899 | case MGSL_MODE_RAW: | 1901 | case MGSL_MODE_RAW: |
1902 | case MGSL_MODE_MONOSYNC: | ||
1903 | case MGSL_MODE_BISYNC: | ||
1900 | while(rx_get_buf(info)); | 1904 | while(rx_get_buf(info)); |
1901 | break; | 1905 | break; |
1902 | } | 1906 | } |
@@ -2362,10 +2366,9 @@ static void program_hw(struct slgt_info *info) | |||
2362 | rx_stop(info); | 2366 | rx_stop(info); |
2363 | tx_stop(info); | 2367 | tx_stop(info); |
2364 | 2368 | ||
2365 | if (info->params.mode == MGSL_MODE_HDLC || | 2369 | if (info->params.mode != MGSL_MODE_ASYNC || |
2366 | info->params.mode == MGSL_MODE_RAW || | ||
2367 | info->netcount) | 2370 | info->netcount) |
2368 | hdlc_mode(info); | 2371 | sync_mode(info); |
2369 | else | 2372 | else |
2370 | async_mode(info); | 2373 | async_mode(info); |
2371 | 2374 | ||
@@ -2564,6 +2567,10 @@ static int rx_enable(struct slgt_info *info, int enable) | |||
2564 | if (enable) { | 2567 | if (enable) { |
2565 | if (!info->rx_enabled) | 2568 | if (!info->rx_enabled) |
2566 | rx_start(info); | 2569 | rx_start(info); |
2570 | else if (enable == 2) { | ||
2571 | /* force hunt mode (write 1 to RCR[3]) */ | ||
2572 | wr_reg16(info, RCR, rd_reg16(info, RCR) | BIT3); | ||
2573 | } | ||
2567 | } else { | 2574 | } else { |
2568 | if (info->rx_enabled) | 2575 | if (info->rx_enabled) |
2569 | rx_stop(info); | 2576 | rx_stop(info); |
@@ -3434,7 +3441,7 @@ static void __devexit remove_one(struct pci_dev *dev) | |||
3434 | { | 3441 | { |
3435 | } | 3442 | } |
3436 | 3443 | ||
3437 | static struct tty_operations ops = { | 3444 | static const struct tty_operations ops = { |
3438 | .open = open, | 3445 | .open = open, |
3439 | .close = close, | 3446 | .close = close, |
3440 | .write = write, | 3447 | .write = write, |
@@ -3748,7 +3755,7 @@ static void tx_start(struct slgt_info *info) | |||
3748 | { | 3755 | { |
3749 | if (!info->tx_enabled) { | 3756 | if (!info->tx_enabled) { |
3750 | wr_reg16(info, TCR, | 3757 | wr_reg16(info, TCR, |
3751 | (unsigned short)(rd_reg16(info, TCR) | BIT1)); | 3758 | (unsigned short)((rd_reg16(info, TCR) | BIT1) & ~BIT2)); |
3752 | info->tx_enabled = TRUE; | 3759 | info->tx_enabled = TRUE; |
3753 | } | 3760 | } |
3754 | 3761 | ||
@@ -3775,13 +3782,18 @@ static void tx_start(struct slgt_info *info) | |||
3775 | tdma_reset(info); | 3782 | tdma_reset(info); |
3776 | /* set 1st descriptor address */ | 3783 | /* set 1st descriptor address */ |
3777 | wr_reg32(info, TDDAR, info->tbufs[info->tbuf_start].pdesc); | 3784 | wr_reg32(info, TDDAR, info->tbufs[info->tbuf_start].pdesc); |
3778 | if (info->params.mode == MGSL_MODE_RAW) | 3785 | switch(info->params.mode) { |
3786 | case MGSL_MODE_RAW: | ||
3787 | case MGSL_MODE_MONOSYNC: | ||
3788 | case MGSL_MODE_BISYNC: | ||
3779 | wr_reg32(info, TDCSR, BIT2 + BIT0); /* IRQ + DMA enable */ | 3789 | wr_reg32(info, TDCSR, BIT2 + BIT0); /* IRQ + DMA enable */ |
3780 | else | 3790 | break; |
3791 | default: | ||
3781 | wr_reg32(info, TDCSR, BIT0); /* DMA enable */ | 3792 | wr_reg32(info, TDCSR, BIT0); /* DMA enable */ |
3793 | } | ||
3782 | } | 3794 | } |
3783 | 3795 | ||
3784 | if (info->params.mode != MGSL_MODE_RAW) { | 3796 | if (info->params.mode == MGSL_MODE_HDLC) { |
3785 | info->tx_timer.expires = jiffies + msecs_to_jiffies(5000); | 3797 | info->tx_timer.expires = jiffies + msecs_to_jiffies(5000); |
3786 | add_timer(&info->tx_timer); | 3798 | add_timer(&info->tx_timer); |
3787 | } | 3799 | } |
@@ -3814,7 +3826,6 @@ static void tx_stop(struct slgt_info *info) | |||
3814 | /* reset and disable transmitter */ | 3826 | /* reset and disable transmitter */ |
3815 | val = rd_reg16(info, TCR) & ~BIT1; /* clear enable bit */ | 3827 | val = rd_reg16(info, TCR) & ~BIT1; /* clear enable bit */ |
3816 | wr_reg16(info, TCR, (unsigned short)(val | BIT2)); /* set reset bit */ | 3828 | wr_reg16(info, TCR, (unsigned short)(val | BIT2)); /* set reset bit */ |
3817 | wr_reg16(info, TCR, val); /* clear reset */ | ||
3818 | 3829 | ||
3819 | slgt_irq_off(info, IRQ_TXDATA + IRQ_TXIDLE + IRQ_TXUNDER); | 3830 | slgt_irq_off(info, IRQ_TXDATA + IRQ_TXIDLE + IRQ_TXUNDER); |
3820 | 3831 | ||
@@ -3982,7 +3993,7 @@ static void async_mode(struct slgt_info *info) | |||
3982 | enable_loopback(info); | 3993 | enable_loopback(info); |
3983 | } | 3994 | } |
3984 | 3995 | ||
3985 | static void hdlc_mode(struct slgt_info *info) | 3996 | static void sync_mode(struct slgt_info *info) |
3986 | { | 3997 | { |
3987 | unsigned short val; | 3998 | unsigned short val; |
3988 | 3999 | ||
@@ -3992,7 +4003,7 @@ static void hdlc_mode(struct slgt_info *info) | |||
3992 | 4003 | ||
3993 | /* TCR (tx control) | 4004 | /* TCR (tx control) |
3994 | * | 4005 | * |
3995 | * 15..13 mode, 000=HDLC 001=raw sync | 4006 | * 15..13 mode, 000=HDLC 001=raw 010=async 011=monosync 100=bisync |
3996 | * 12..10 encoding | 4007 | * 12..10 encoding |
3997 | * 09 CRC enable | 4008 | * 09 CRC enable |
3998 | * 08 CRC32 | 4009 | * 08 CRC32 |
@@ -4006,8 +4017,11 @@ static void hdlc_mode(struct slgt_info *info) | |||
4006 | */ | 4017 | */ |
4007 | val = 0; | 4018 | val = 0; |
4008 | 4019 | ||
4009 | if (info->params.mode == MGSL_MODE_RAW) | 4020 | switch(info->params.mode) { |
4010 | val |= BIT13; | 4021 | case MGSL_MODE_MONOSYNC: val |= BIT14 + BIT13; break; |
4022 | case MGSL_MODE_BISYNC: val |= BIT15; break; | ||
4023 | case MGSL_MODE_RAW: val |= BIT13; break; | ||
4024 | } | ||
4011 | if (info->if_mode & MGSL_INTERFACE_RTS_EN) | 4025 | if (info->if_mode & MGSL_INTERFACE_RTS_EN) |
4012 | val |= BIT7; | 4026 | val |= BIT7; |
4013 | 4027 | ||
@@ -4058,7 +4072,7 @@ static void hdlc_mode(struct slgt_info *info) | |||
4058 | 4072 | ||
4059 | /* RCR (rx control) | 4073 | /* RCR (rx control) |
4060 | * | 4074 | * |
4061 | * 15..13 mode, 000=HDLC 001=raw sync | 4075 | * 15..13 mode, 000=HDLC 001=raw 010=async 011=monosync 100=bisync |
4062 | * 12..10 encoding | 4076 | * 12..10 encoding |
4063 | * 09 CRC enable | 4077 | * 09 CRC enable |
4064 | * 08 CRC32 | 4078 | * 08 CRC32 |
@@ -4069,8 +4083,11 @@ static void hdlc_mode(struct slgt_info *info) | |||
4069 | */ | 4083 | */ |
4070 | val = 0; | 4084 | val = 0; |
4071 | 4085 | ||
4072 | if (info->params.mode == MGSL_MODE_RAW) | 4086 | switch(info->params.mode) { |
4073 | val |= BIT13; | 4087 | case MGSL_MODE_MONOSYNC: val |= BIT14 + BIT13; break; |
4088 | case MGSL_MODE_BISYNC: val |= BIT15; break; | ||
4089 | case MGSL_MODE_RAW: val |= BIT13; break; | ||
4090 | } | ||
4074 | 4091 | ||
4075 | switch(info->params.encoding) | 4092 | switch(info->params.encoding) |
4076 | { | 4093 | { |
@@ -4309,10 +4326,15 @@ static void free_rbufs(struct slgt_info *info, unsigned int i, unsigned int last | |||
4309 | while(!done) { | 4326 | while(!done) { |
4310 | /* reset current buffer for reuse */ | 4327 | /* reset current buffer for reuse */ |
4311 | info->rbufs[i].status = 0; | 4328 | info->rbufs[i].status = 0; |
4312 | if (info->params.mode == MGSL_MODE_RAW) | 4329 | switch(info->params.mode) { |
4330 | case MGSL_MODE_RAW: | ||
4331 | case MGSL_MODE_MONOSYNC: | ||
4332 | case MGSL_MODE_BISYNC: | ||
4313 | set_desc_count(info->rbufs[i], info->raw_rx_size); | 4333 | set_desc_count(info->rbufs[i], info->raw_rx_size); |
4314 | else | 4334 | break; |
4335 | default: | ||
4315 | set_desc_count(info->rbufs[i], DMABUFSIZE); | 4336 | set_desc_count(info->rbufs[i], DMABUFSIZE); |
4337 | } | ||
4316 | 4338 | ||
4317 | if (i == last) | 4339 | if (i == last) |
4318 | done = 1; | 4340 | done = 1; |
@@ -4477,13 +4499,24 @@ cleanup: | |||
4477 | static int rx_get_buf(struct slgt_info *info) | 4499 | static int rx_get_buf(struct slgt_info *info) |
4478 | { | 4500 | { |
4479 | unsigned int i = info->rbuf_current; | 4501 | unsigned int i = info->rbuf_current; |
4502 | unsigned int count; | ||
4480 | 4503 | ||
4481 | if (!desc_complete(info->rbufs[i])) | 4504 | if (!desc_complete(info->rbufs[i])) |
4482 | return 0; | 4505 | return 0; |
4483 | DBGDATA(info, info->rbufs[i].buf, desc_count(info->rbufs[i]), "rx"); | 4506 | count = desc_count(info->rbufs[i]); |
4484 | DBGINFO(("rx_get_buf size=%d\n", desc_count(info->rbufs[i]))); | 4507 | switch(info->params.mode) { |
4485 | ldisc_receive_buf(info->tty, info->rbufs[i].buf, | 4508 | case MGSL_MODE_MONOSYNC: |
4486 | info->flag_buf, desc_count(info->rbufs[i])); | 4509 | case MGSL_MODE_BISYNC: |
4510 | /* ignore residue in byte synchronous modes */ | ||
4511 | if (desc_residue(info->rbufs[i])) | ||
4512 | count--; | ||
4513 | break; | ||
4514 | } | ||
4515 | DBGDATA(info, info->rbufs[i].buf, count, "rx"); | ||
4516 | DBGINFO(("rx_get_buf size=%d\n", count)); | ||
4517 | if (count) | ||
4518 | ldisc_receive_buf(info->tty, info->rbufs[i].buf, | ||
4519 | info->flag_buf, count); | ||
4487 | free_rbufs(info, i, i); | 4520 | free_rbufs(info, i, i); |
4488 | return 1; | 4521 | return 1; |
4489 | } | 4522 | } |
@@ -4549,8 +4582,13 @@ static void tx_load(struct slgt_info *info, const char *buf, unsigned int size) | |||
4549 | size -= count; | 4582 | size -= count; |
4550 | buf += count; | 4583 | buf += count; |
4551 | 4584 | ||
4552 | if (!size && info->params.mode != MGSL_MODE_RAW) | 4585 | /* |
4553 | set_desc_eof(*d, 1); /* HDLC: set EOF of last desc */ | 4586 | * set EOF bit for last buffer of HDLC frame or |
4587 | * for every buffer in raw mode | ||
4588 | */ | ||
4589 | if ((!size && info->params.mode == MGSL_MODE_HDLC) || | ||
4590 | info->params.mode == MGSL_MODE_RAW) | ||
4591 | set_desc_eof(*d, 1); | ||
4554 | else | 4592 | else |
4555 | set_desc_eof(*d, 0); | 4593 | set_desc_eof(*d, 0); |
4556 | 4594 | ||
diff --git a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c index 66f3754fbbdf..6eb75dcd7961 100644 --- a/drivers/char/synclinkmp.c +++ b/drivers/char/synclinkmp.c | |||
@@ -3929,7 +3929,7 @@ void device_init(int adapter_num, struct pci_dev *pdev) | |||
3929 | } | 3929 | } |
3930 | } | 3930 | } |
3931 | 3931 | ||
3932 | static struct tty_operations ops = { | 3932 | static const struct tty_operations ops = { |
3933 | .open = open, | 3933 | .open = open, |
3934 | .close = close, | 3934 | .close = close, |
3935 | .write = write, | 3935 | .write = write, |
diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c index ee3ca8f1768e..6b4d4d1e343d 100644 --- a/drivers/char/sysrq.c +++ b/drivers/char/sysrq.c | |||
@@ -113,6 +113,7 @@ static struct sysrq_key_op sysrq_crashdump_op = { | |||
113 | static void sysrq_handle_reboot(int key, struct pt_regs *pt_regs, | 113 | static void sysrq_handle_reboot(int key, struct pt_regs *pt_regs, |
114 | struct tty_struct *tty) | 114 | struct tty_struct *tty) |
115 | { | 115 | { |
116 | lockdep_off(); | ||
116 | local_irq_enable(); | 117 | local_irq_enable(); |
117 | emergency_restart(); | 118 | emergency_restart(); |
118 | } | 119 | } |
@@ -208,7 +209,7 @@ static void send_sig_all(int sig) | |||
208 | struct task_struct *p; | 209 | struct task_struct *p; |
209 | 210 | ||
210 | for_each_process(p) { | 211 | for_each_process(p) { |
211 | if (p->mm && p->pid != 1) | 212 | if (p->mm && !is_init(p)) |
212 | /* Not swapper, init nor kernel thread */ | 213 | /* Not swapper, init nor kernel thread */ |
213 | force_sig(sig, p); | 214 | force_sig(sig, p); |
214 | } | 215 | } |
diff --git a/drivers/char/tpm/tpm_atmel.h b/drivers/char/tpm/tpm_atmel.h index 2e68eeb8a2cd..aefd683c60b7 100644 --- a/drivers/char/tpm/tpm_atmel.h +++ b/drivers/char/tpm/tpm_atmel.h | |||
@@ -37,7 +37,7 @@ static void __iomem * atmel_get_base_addr(unsigned long *base, int *region_size) | |||
37 | { | 37 | { |
38 | struct device_node *dn; | 38 | struct device_node *dn; |
39 | unsigned long address, size; | 39 | unsigned long address, size; |
40 | unsigned int *reg; | 40 | const unsigned int *reg; |
41 | int reglen; | 41 | int reglen; |
42 | int naddrc; | 42 | int naddrc; |
43 | int nsizec; | 43 | int nsizec; |
@@ -52,7 +52,7 @@ static void __iomem * atmel_get_base_addr(unsigned long *base, int *region_size) | |||
52 | return NULL; | 52 | return NULL; |
53 | } | 53 | } |
54 | 54 | ||
55 | reg = (unsigned int *) get_property(dn, "reg", ®len); | 55 | reg = get_property(dn, "reg", ®len); |
56 | naddrc = prom_n_addr_cells(dn); | 56 | naddrc = prom_n_addr_cells(dn); |
57 | nsizec = prom_n_size_cells(dn); | 57 | nsizec = prom_n_size_cells(dn); |
58 | 58 | ||
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index bb0d9199e994..e90ea39c7c4b 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c | |||
@@ -129,6 +129,7 @@ LIST_HEAD(tty_drivers); /* linked list of tty drivers */ | |||
129 | /* Semaphore to protect creating and releasing a tty. This is shared with | 129 | /* Semaphore to protect creating and releasing a tty. This is shared with |
130 | vt.c for deeply disgusting hack reasons */ | 130 | vt.c for deeply disgusting hack reasons */ |
131 | DEFINE_MUTEX(tty_mutex); | 131 | DEFINE_MUTEX(tty_mutex); |
132 | EXPORT_SYMBOL(tty_mutex); | ||
132 | 133 | ||
133 | #ifdef CONFIG_UNIX98_PTYS | 134 | #ifdef CONFIG_UNIX98_PTYS |
134 | extern struct tty_driver *ptm_driver; /* Unix98 pty masters; for /dev/ptmx */ | 135 | extern struct tty_driver *ptm_driver; /* Unix98 pty masters; for /dev/ptmx */ |
@@ -160,17 +161,11 @@ static void release_mem(struct tty_struct *tty, int idx); | |||
160 | * been initialized in any way but has been zeroed | 161 | * been initialized in any way but has been zeroed |
161 | * | 162 | * |
162 | * Locking: none | 163 | * Locking: none |
163 | * FIXME: use kzalloc | ||
164 | */ | 164 | */ |
165 | 165 | ||
166 | static struct tty_struct *alloc_tty_struct(void) | 166 | static struct tty_struct *alloc_tty_struct(void) |
167 | { | 167 | { |
168 | struct tty_struct *tty; | 168 | return kzalloc(sizeof(struct tty_struct), GFP_KERNEL); |
169 | |||
170 | tty = kmalloc(sizeof(struct tty_struct), GFP_KERNEL); | ||
171 | if (tty) | ||
172 | memset(tty, 0, sizeof(struct tty_struct)); | ||
173 | return tty; | ||
174 | } | 169 | } |
175 | 170 | ||
176 | static void tty_buffer_free_all(struct tty_struct *); | 171 | static void tty_buffer_free_all(struct tty_struct *); |
@@ -483,10 +478,9 @@ int tty_insert_flip_string(struct tty_struct *tty, const unsigned char *chars, | |||
483 | tb->used += space; | 478 | tb->used += space; |
484 | copied += space; | 479 | copied += space; |
485 | chars += space; | 480 | chars += space; |
486 | } | 481 | /* There is a small chance that we need to split the data over |
487 | /* There is a small chance that we need to split the data over | 482 | several buffers. If this is the case we must loop */ |
488 | several buffers. If this is the case we must loop */ | 483 | } while (unlikely(size > copied)); |
489 | while (unlikely(size > copied)); | ||
490 | return copied; | 484 | return copied; |
491 | } | 485 | } |
492 | EXPORT_SYMBOL(tty_insert_flip_string); | 486 | EXPORT_SYMBOL(tty_insert_flip_string); |
@@ -521,10 +515,9 @@ int tty_insert_flip_string_flags(struct tty_struct *tty, | |||
521 | copied += space; | 515 | copied += space; |
522 | chars += space; | 516 | chars += space; |
523 | flags += space; | 517 | flags += space; |
524 | } | 518 | /* There is a small chance that we need to split the data over |
525 | /* There is a small chance that we need to split the data over | 519 | several buffers. If this is the case we must loop */ |
526 | several buffers. If this is the case we must loop */ | 520 | } while (unlikely(size > copied)); |
527 | while (unlikely(size > copied)); | ||
528 | return copied; | 521 | return copied; |
529 | } | 522 | } |
530 | EXPORT_SYMBOL(tty_insert_flip_string_flags); | 523 | EXPORT_SYMBOL(tty_insert_flip_string_flags); |
@@ -626,9 +619,9 @@ EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags); | |||
626 | 619 | ||
627 | static void tty_set_termios_ldisc(struct tty_struct *tty, int num) | 620 | static void tty_set_termios_ldisc(struct tty_struct *tty, int num) |
628 | { | 621 | { |
629 | down(&tty->termios_sem); | 622 | mutex_lock(&tty->termios_mutex); |
630 | tty->termios->c_line = num; | 623 | tty->termios->c_line = num; |
631 | up(&tty->termios_sem); | 624 | mutex_unlock(&tty->termios_mutex); |
632 | } | 625 | } |
633 | 626 | ||
634 | /* | 627 | /* |
@@ -1346,9 +1339,9 @@ static void do_tty_hangup(void *data) | |||
1346 | */ | 1339 | */ |
1347 | if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) | 1340 | if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) |
1348 | { | 1341 | { |
1349 | down(&tty->termios_sem); | 1342 | mutex_lock(&tty->termios_mutex); |
1350 | *tty->termios = tty->driver->init_termios; | 1343 | *tty->termios = tty->driver->init_termios; |
1351 | up(&tty->termios_sem); | 1344 | mutex_unlock(&tty->termios_mutex); |
1352 | } | 1345 | } |
1353 | 1346 | ||
1354 | /* Defer ldisc switch */ | 1347 | /* Defer ldisc switch */ |
@@ -2072,8 +2065,9 @@ fail_no_mem: | |||
2072 | 2065 | ||
2073 | /* call the tty release_mem routine to clean out this slot */ | 2066 | /* call the tty release_mem routine to clean out this slot */ |
2074 | release_mem_out: | 2067 | release_mem_out: |
2075 | printk(KERN_INFO "init_dev: ldisc open failed, " | 2068 | if (printk_ratelimit()) |
2076 | "clearing slot %d\n", idx); | 2069 | printk(KERN_INFO "init_dev: ldisc open failed, " |
2070 | "clearing slot %d\n", idx); | ||
2077 | release_mem(tty, idx); | 2071 | release_mem(tty, idx); |
2078 | goto end_init; | 2072 | goto end_init; |
2079 | } | 2073 | } |
@@ -2726,6 +2720,8 @@ static int tty_fasync(int fd, struct file * filp, int on) | |||
2726 | * Locking: | 2720 | * Locking: |
2727 | * Called functions take tty_ldisc_lock | 2721 | * Called functions take tty_ldisc_lock |
2728 | * current->signal->tty check is safe without locks | 2722 | * current->signal->tty check is safe without locks |
2723 | * | ||
2724 | * FIXME: may race normal receive processing | ||
2729 | */ | 2725 | */ |
2730 | 2726 | ||
2731 | static int tiocsti(struct tty_struct *tty, char __user *p) | 2727 | static int tiocsti(struct tty_struct *tty, char __user *p) |
@@ -2748,18 +2744,21 @@ static int tiocsti(struct tty_struct *tty, char __user *p) | |||
2748 | * @tty; tty | 2744 | * @tty; tty |
2749 | * @arg: user buffer for result | 2745 | * @arg: user buffer for result |
2750 | * | 2746 | * |
2751 | * Copies the kernel idea of the window size into the user buffer. No | 2747 | * Copies the kernel idea of the window size into the user buffer. |
2752 | * locking is done. | ||
2753 | * | 2748 | * |
2754 | * FIXME: Returning random values racing a window size set is wrong | 2749 | * Locking: tty->termios_sem is taken to ensure the winsize data |
2755 | * should lock here against that | 2750 | * is consistent. |
2756 | */ | 2751 | */ |
2757 | 2752 | ||
2758 | static int tiocgwinsz(struct tty_struct *tty, struct winsize __user * arg) | 2753 | static int tiocgwinsz(struct tty_struct *tty, struct winsize __user * arg) |
2759 | { | 2754 | { |
2760 | if (copy_to_user(arg, &tty->winsize, sizeof(*arg))) | 2755 | int err; |
2761 | return -EFAULT; | 2756 | |
2762 | return 0; | 2757 | mutex_lock(&tty->termios_mutex); |
2758 | err = copy_to_user(arg, &tty->winsize, sizeof(*arg)); | ||
2759 | mutex_unlock(&tty->termios_mutex); | ||
2760 | |||
2761 | return err ? -EFAULT: 0; | ||
2763 | } | 2762 | } |
2764 | 2763 | ||
2765 | /** | 2764 | /** |
@@ -2772,12 +2771,11 @@ static int tiocgwinsz(struct tty_struct *tty, struct winsize __user * arg) | |||
2772 | * actually has driver level meaning and triggers a VC resize. | 2771 | * actually has driver level meaning and triggers a VC resize. |
2773 | * | 2772 | * |
2774 | * Locking: | 2773 | * Locking: |
2775 | * The console_sem is used to ensure we do not try and resize | 2774 | * Called function use the console_sem is used to ensure we do |
2776 | * the console twice at once. | 2775 | * not try and resize the console twice at once. |
2777 | * FIXME: Two racing size sets may leave the console and kernel | 2776 | * The tty->termios_sem is used to ensure we don't double |
2778 | * parameters disagreeing. Is this exploitable ? | 2777 | * resize and get confused. Lock order - tty->termios.sem before |
2779 | * FIXME: Random values racing a window size get is wrong | 2778 | * console sem |
2780 | * should lock here against that | ||
2781 | */ | 2779 | */ |
2782 | 2780 | ||
2783 | static int tiocswinsz(struct tty_struct *tty, struct tty_struct *real_tty, | 2781 | static int tiocswinsz(struct tty_struct *tty, struct tty_struct *real_tty, |
@@ -2787,17 +2785,18 @@ static int tiocswinsz(struct tty_struct *tty, struct tty_struct *real_tty, | |||
2787 | 2785 | ||
2788 | if (copy_from_user(&tmp_ws, arg, sizeof(*arg))) | 2786 | if (copy_from_user(&tmp_ws, arg, sizeof(*arg))) |
2789 | return -EFAULT; | 2787 | return -EFAULT; |
2788 | |||
2789 | mutex_lock(&tty->termios_mutex); | ||
2790 | if (!memcmp(&tmp_ws, &tty->winsize, sizeof(*arg))) | 2790 | if (!memcmp(&tmp_ws, &tty->winsize, sizeof(*arg))) |
2791 | return 0; | 2791 | goto done; |
2792 | |||
2792 | #ifdef CONFIG_VT | 2793 | #ifdef CONFIG_VT |
2793 | if (tty->driver->type == TTY_DRIVER_TYPE_CONSOLE) { | 2794 | if (tty->driver->type == TTY_DRIVER_TYPE_CONSOLE) { |
2794 | int rc; | 2795 | if (vc_lock_resize(tty->driver_data, tmp_ws.ws_col, |
2795 | 2796 | tmp_ws.ws_row)) { | |
2796 | acquire_console_sem(); | 2797 | mutex_unlock(&tty->termios_mutex); |
2797 | rc = vc_resize(tty->driver_data, tmp_ws.ws_col, tmp_ws.ws_row); | 2798 | return -ENXIO; |
2798 | release_console_sem(); | 2799 | } |
2799 | if (rc) | ||
2800 | return -ENXIO; | ||
2801 | } | 2800 | } |
2802 | #endif | 2801 | #endif |
2803 | if (tty->pgrp > 0) | 2802 | if (tty->pgrp > 0) |
@@ -2806,6 +2805,8 @@ static int tiocswinsz(struct tty_struct *tty, struct tty_struct *real_tty, | |||
2806 | kill_pg(real_tty->pgrp, SIGWINCH, 1); | 2805 | kill_pg(real_tty->pgrp, SIGWINCH, 1); |
2807 | tty->winsize = tmp_ws; | 2806 | tty->winsize = tmp_ws; |
2808 | real_tty->winsize = tmp_ws; | 2807 | real_tty->winsize = tmp_ws; |
2808 | done: | ||
2809 | mutex_unlock(&tty->termios_mutex); | ||
2809 | return 0; | 2810 | return 0; |
2810 | } | 2811 | } |
2811 | 2812 | ||
@@ -2880,9 +2881,7 @@ static int fionbio(struct file *file, int __user *p) | |||
2880 | * Locking: | 2881 | * Locking: |
2881 | * Takes tasklist lock internally to walk sessions | 2882 | * Takes tasklist lock internally to walk sessions |
2882 | * Takes task_lock() when updating signal->tty | 2883 | * Takes task_lock() when updating signal->tty |
2883 | * | 2884 | * Takes tty_mutex() to protect tty instance |
2884 | * FIXME: tty_mutex is needed to protect signal->tty references. | ||
2885 | * FIXME: why task_lock on the signal->tty reference ?? | ||
2886 | * | 2885 | * |
2887 | */ | 2886 | */ |
2888 | 2887 | ||
@@ -2917,9 +2916,11 @@ static int tiocsctty(struct tty_struct *tty, int arg) | |||
2917 | } else | 2916 | } else |
2918 | return -EPERM; | 2917 | return -EPERM; |
2919 | } | 2918 | } |
2919 | mutex_lock(&tty_mutex); | ||
2920 | task_lock(current); | 2920 | task_lock(current); |
2921 | current->signal->tty = tty; | 2921 | current->signal->tty = tty; |
2922 | task_unlock(current); | 2922 | task_unlock(current); |
2923 | mutex_unlock(&tty_mutex); | ||
2923 | current->signal->tty_old_pgrp = 0; | 2924 | current->signal->tty_old_pgrp = 0; |
2924 | tty->session = current->signal->session; | 2925 | tty->session = current->signal->session; |
2925 | tty->pgrp = process_group(current); | 2926 | tty->pgrp = process_group(current); |
@@ -2959,8 +2960,6 @@ static int tiocgpgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t | |||
2959 | * permitted where the tty session is our session. | 2960 | * permitted where the tty session is our session. |
2960 | * | 2961 | * |
2961 | * Locking: None | 2962 | * Locking: None |
2962 | * | ||
2963 | * FIXME: current->signal->tty referencing is unsafe. | ||
2964 | */ | 2963 | */ |
2965 | 2964 | ||
2966 | static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p) | 2965 | static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p) |
@@ -3039,19 +3038,20 @@ static int tiocsetd(struct tty_struct *tty, int __user *p) | |||
3039 | * timed break functionality. | 3038 | * timed break functionality. |
3040 | * | 3039 | * |
3041 | * Locking: | 3040 | * Locking: |
3042 | * None | 3041 | * atomic_write_lock serializes |
3043 | * | 3042 | * |
3044 | * FIXME: | ||
3045 | * What if two overlap | ||
3046 | */ | 3043 | */ |
3047 | 3044 | ||
3048 | static int send_break(struct tty_struct *tty, unsigned int duration) | 3045 | static int send_break(struct tty_struct *tty, unsigned int duration) |
3049 | { | 3046 | { |
3047 | if (mutex_lock_interruptible(&tty->atomic_write_lock)) | ||
3048 | return -EINTR; | ||
3050 | tty->driver->break_ctl(tty, -1); | 3049 | tty->driver->break_ctl(tty, -1); |
3051 | if (!signal_pending(current)) { | 3050 | if (!signal_pending(current)) { |
3052 | msleep_interruptible(duration); | 3051 | msleep_interruptible(duration); |
3053 | } | 3052 | } |
3054 | tty->driver->break_ctl(tty, 0); | 3053 | tty->driver->break_ctl(tty, 0); |
3054 | mutex_unlock(&tty->atomic_write_lock); | ||
3055 | if (signal_pending(current)) | 3055 | if (signal_pending(current)) |
3056 | return -EINTR; | 3056 | return -EINTR; |
3057 | return 0; | 3057 | return 0; |
@@ -3144,6 +3144,8 @@ int tty_ioctl(struct inode * inode, struct file * file, | |||
3144 | if (tty_paranoia_check(tty, inode, "tty_ioctl")) | 3144 | if (tty_paranoia_check(tty, inode, "tty_ioctl")) |
3145 | return -EINVAL; | 3145 | return -EINVAL; |
3146 | 3146 | ||
3147 | /* CHECKME: is this safe as one end closes ? */ | ||
3148 | |||
3147 | real_tty = tty; | 3149 | real_tty = tty; |
3148 | if (tty->driver->type == TTY_DRIVER_TYPE_PTY && | 3150 | if (tty->driver->type == TTY_DRIVER_TYPE_PTY && |
3149 | tty->driver->subtype == PTY_TYPE_MASTER) | 3151 | tty->driver->subtype == PTY_TYPE_MASTER) |
@@ -3580,7 +3582,7 @@ static void initialize_tty_struct(struct tty_struct *tty) | |||
3580 | tty_buffer_init(tty); | 3582 | tty_buffer_init(tty); |
3581 | INIT_WORK(&tty->buf.work, flush_to_ldisc, tty); | 3583 | INIT_WORK(&tty->buf.work, flush_to_ldisc, tty); |
3582 | init_MUTEX(&tty->buf.pty_sem); | 3584 | init_MUTEX(&tty->buf.pty_sem); |
3583 | init_MUTEX(&tty->termios_sem); | 3585 | mutex_init(&tty->termios_mutex); |
3584 | init_waitqueue_head(&tty->write_wait); | 3586 | init_waitqueue_head(&tty->write_wait); |
3585 | init_waitqueue_head(&tty->read_wait); | 3587 | init_waitqueue_head(&tty->read_wait); |
3586 | INIT_WORK(&tty->hangup_work, do_tty_hangup, tty); | 3588 | INIT_WORK(&tty->hangup_work, do_tty_hangup, tty); |
@@ -3678,7 +3680,8 @@ void put_tty_driver(struct tty_driver *driver) | |||
3678 | kfree(driver); | 3680 | kfree(driver); |
3679 | } | 3681 | } |
3680 | 3682 | ||
3681 | void tty_set_operations(struct tty_driver *driver, struct tty_operations *op) | 3683 | void tty_set_operations(struct tty_driver *driver, |
3684 | const struct tty_operations *op) | ||
3682 | { | 3685 | { |
3683 | driver->open = op->open; | 3686 | driver->open = op->open; |
3684 | driver->close = op->close; | 3687 | driver->close = op->close; |
diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c index 4ad47d321bd4..3b6fa7b0be8b 100644 --- a/drivers/char/tty_ioctl.c +++ b/drivers/char/tty_ioctl.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/mm.h> | 20 | #include <linux/mm.h> |
21 | #include <linux/module.h> | 21 | #include <linux/module.h> |
22 | #include <linux/bitops.h> | 22 | #include <linux/bitops.h> |
23 | #include <linux/mutex.h> | ||
23 | 24 | ||
24 | #include <asm/io.h> | 25 | #include <asm/io.h> |
25 | #include <asm/uaccess.h> | 26 | #include <asm/uaccess.h> |
@@ -131,7 +132,7 @@ static void change_termios(struct tty_struct * tty, struct termios * new_termios | |||
131 | 132 | ||
132 | /* FIXME: we need to decide on some locking/ordering semantics | 133 | /* FIXME: we need to decide on some locking/ordering semantics |
133 | for the set_termios notification eventually */ | 134 | for the set_termios notification eventually */ |
134 | down(&tty->termios_sem); | 135 | mutex_lock(&tty->termios_mutex); |
135 | 136 | ||
136 | *tty->termios = *new_termios; | 137 | *tty->termios = *new_termios; |
137 | unset_locked_termios(tty->termios, &old_termios, tty->termios_locked); | 138 | unset_locked_termios(tty->termios, &old_termios, tty->termios_locked); |
@@ -176,7 +177,7 @@ static void change_termios(struct tty_struct * tty, struct termios * new_termios | |||
176 | (ld->set_termios)(tty, &old_termios); | 177 | (ld->set_termios)(tty, &old_termios); |
177 | tty_ldisc_deref(ld); | 178 | tty_ldisc_deref(ld); |
178 | } | 179 | } |
179 | up(&tty->termios_sem); | 180 | mutex_unlock(&tty->termios_mutex); |
180 | } | 181 | } |
181 | 182 | ||
182 | /** | 183 | /** |
@@ -284,13 +285,13 @@ static int get_sgttyb(struct tty_struct * tty, struct sgttyb __user * sgttyb) | |||
284 | { | 285 | { |
285 | struct sgttyb tmp; | 286 | struct sgttyb tmp; |
286 | 287 | ||
287 | down(&tty->termios_sem); | 288 | mutex_lock(&tty->termios_mutex); |
288 | tmp.sg_ispeed = 0; | 289 | tmp.sg_ispeed = 0; |
289 | tmp.sg_ospeed = 0; | 290 | tmp.sg_ospeed = 0; |
290 | tmp.sg_erase = tty->termios->c_cc[VERASE]; | 291 | tmp.sg_erase = tty->termios->c_cc[VERASE]; |
291 | tmp.sg_kill = tty->termios->c_cc[VKILL]; | 292 | tmp.sg_kill = tty->termios->c_cc[VKILL]; |
292 | tmp.sg_flags = get_sgflags(tty); | 293 | tmp.sg_flags = get_sgflags(tty); |
293 | up(&tty->termios_sem); | 294 | mutex_unlock(&tty->termios_mutex); |
294 | 295 | ||
295 | return copy_to_user(sgttyb, &tmp, sizeof(tmp)) ? -EFAULT : 0; | 296 | return copy_to_user(sgttyb, &tmp, sizeof(tmp)) ? -EFAULT : 0; |
296 | } | 297 | } |
@@ -345,12 +346,12 @@ static int set_sgttyb(struct tty_struct * tty, struct sgttyb __user * sgttyb) | |||
345 | if (copy_from_user(&tmp, sgttyb, sizeof(tmp))) | 346 | if (copy_from_user(&tmp, sgttyb, sizeof(tmp))) |
346 | return -EFAULT; | 347 | return -EFAULT; |
347 | 348 | ||
348 | down(&tty->termios_sem); | 349 | mutex_lock(&tty->termios_mutex); |
349 | termios = *tty->termios; | 350 | termios = *tty->termios; |
350 | termios.c_cc[VERASE] = tmp.sg_erase; | 351 | termios.c_cc[VERASE] = tmp.sg_erase; |
351 | termios.c_cc[VKILL] = tmp.sg_kill; | 352 | termios.c_cc[VKILL] = tmp.sg_kill; |
352 | set_sgflags(&termios, tmp.sg_flags); | 353 | set_sgflags(&termios, tmp.sg_flags); |
353 | up(&tty->termios_sem); | 354 | mutex_unlock(&tty->termios_mutex); |
354 | change_termios(tty, &termios); | 355 | change_termios(tty, &termios); |
355 | return 0; | 356 | return 0; |
356 | } | 357 | } |
@@ -422,24 +423,28 @@ static int set_ltchars(struct tty_struct * tty, struct ltchars __user * ltchars) | |||
422 | * | 423 | * |
423 | * Send a high priority character to the tty even if stopped | 424 | * Send a high priority character to the tty even if stopped |
424 | * | 425 | * |
425 | * Locking: none | 426 | * Locking: none for xchar method, write ordering for write method. |
426 | * | ||
427 | * FIXME: overlapping calls with start/stop tty lose state of tty | ||
428 | */ | 427 | */ |
429 | 428 | ||
430 | static void send_prio_char(struct tty_struct *tty, char ch) | 429 | static int send_prio_char(struct tty_struct *tty, char ch) |
431 | { | 430 | { |
432 | int was_stopped = tty->stopped; | 431 | int was_stopped = tty->stopped; |
433 | 432 | ||
434 | if (tty->driver->send_xchar) { | 433 | if (tty->driver->send_xchar) { |
435 | tty->driver->send_xchar(tty, ch); | 434 | tty->driver->send_xchar(tty, ch); |
436 | return; | 435 | return 0; |
437 | } | 436 | } |
437 | |||
438 | if (mutex_lock_interruptible(&tty->atomic_write_lock)) | ||
439 | return -ERESTARTSYS; | ||
440 | |||
438 | if (was_stopped) | 441 | if (was_stopped) |
439 | start_tty(tty); | 442 | start_tty(tty); |
440 | tty->driver->write(tty, &ch, 1); | 443 | tty->driver->write(tty, &ch, 1); |
441 | if (was_stopped) | 444 | if (was_stopped) |
442 | stop_tty(tty); | 445 | stop_tty(tty); |
446 | mutex_unlock(&tty->atomic_write_lock); | ||
447 | return 0; | ||
443 | } | 448 | } |
444 | 449 | ||
445 | int n_tty_ioctl(struct tty_struct * tty, struct file * file, | 450 | int n_tty_ioctl(struct tty_struct * tty, struct file * file, |
@@ -513,11 +518,11 @@ int n_tty_ioctl(struct tty_struct * tty, struct file * file, | |||
513 | break; | 518 | break; |
514 | case TCIOFF: | 519 | case TCIOFF: |
515 | if (STOP_CHAR(tty) != __DISABLED_CHAR) | 520 | if (STOP_CHAR(tty) != __DISABLED_CHAR) |
516 | send_prio_char(tty, STOP_CHAR(tty)); | 521 | return send_prio_char(tty, STOP_CHAR(tty)); |
517 | break; | 522 | break; |
518 | case TCION: | 523 | case TCION: |
519 | if (START_CHAR(tty) != __DISABLED_CHAR) | 524 | if (START_CHAR(tty) != __DISABLED_CHAR) |
520 | send_prio_char(tty, START_CHAR(tty)); | 525 | return send_prio_char(tty, START_CHAR(tty)); |
521 | break; | 526 | break; |
522 | default: | 527 | default: |
523 | return -EINVAL; | 528 | return -EINVAL; |
@@ -592,11 +597,11 @@ int n_tty_ioctl(struct tty_struct * tty, struct file * file, | |||
592 | case TIOCSSOFTCAR: | 597 | case TIOCSSOFTCAR: |
593 | if (get_user(arg, (unsigned int __user *) arg)) | 598 | if (get_user(arg, (unsigned int __user *) arg)) |
594 | return -EFAULT; | 599 | return -EFAULT; |
595 | down(&tty->termios_sem); | 600 | mutex_lock(&tty->termios_mutex); |
596 | tty->termios->c_cflag = | 601 | tty->termios->c_cflag = |
597 | ((tty->termios->c_cflag & ~CLOCAL) | | 602 | ((tty->termios->c_cflag & ~CLOCAL) | |
598 | (arg ? CLOCAL : 0)); | 603 | (arg ? CLOCAL : 0)); |
599 | up(&tty->termios_sem); | 604 | mutex_unlock(&tty->termios_mutex); |
600 | return 0; | 605 | return 0; |
601 | default: | 606 | default: |
602 | return -ENOIOCTLCMD; | 607 | return -ENOIOCTLCMD; |
diff --git a/drivers/char/vc_screen.c b/drivers/char/vc_screen.c index a9247b5213d5..bd7a98c6ea7a 100644 --- a/drivers/char/vc_screen.c +++ b/drivers/char/vc_screen.c | |||
@@ -474,14 +474,15 @@ static const struct file_operations vcs_fops = { | |||
474 | 474 | ||
475 | static struct class *vc_class; | 475 | static struct class *vc_class; |
476 | 476 | ||
477 | void vcs_make_devfs(struct tty_struct *tty) | 477 | void vcs_make_sysfs(struct tty_struct *tty) |
478 | { | 478 | { |
479 | class_device_create(vc_class, NULL, MKDEV(VCS_MAJOR, tty->index + 1), | 479 | class_device_create(vc_class, NULL, MKDEV(VCS_MAJOR, tty->index + 1), |
480 | NULL, "vcs%u", tty->index + 1); | 480 | NULL, "vcs%u", tty->index + 1); |
481 | class_device_create(vc_class, NULL, MKDEV(VCS_MAJOR, tty->index + 129), | 481 | class_device_create(vc_class, NULL, MKDEV(VCS_MAJOR, tty->index + 129), |
482 | NULL, "vcsa%u", tty->index + 1); | 482 | NULL, "vcsa%u", tty->index + 1); |
483 | } | 483 | } |
484 | void vcs_remove_devfs(struct tty_struct *tty) | 484 | |
485 | void vcs_remove_sysfs(struct tty_struct *tty) | ||
485 | { | 486 | { |
486 | class_device_destroy(vc_class, MKDEV(VCS_MAJOR, tty->index + 1)); | 487 | class_device_destroy(vc_class, MKDEV(VCS_MAJOR, tty->index + 1)); |
487 | class_device_destroy(vc_class, MKDEV(VCS_MAJOR, tty->index + 129)); | 488 | class_device_destroy(vc_class, MKDEV(VCS_MAJOR, tty->index + 129)); |
diff --git a/drivers/char/viocons.c b/drivers/char/viocons.c index 766f7864c6c6..a362ee9c92dd 100644 --- a/drivers/char/viocons.c +++ b/drivers/char/viocons.c | |||
@@ -43,7 +43,6 @@ | |||
43 | #include <linux/sysrq.h> | 43 | #include <linux/sysrq.h> |
44 | 44 | ||
45 | #include <asm/iseries/vio.h> | 45 | #include <asm/iseries/vio.h> |
46 | |||
47 | #include <asm/iseries/hv_lp_event.h> | 46 | #include <asm/iseries/hv_lp_event.h> |
48 | #include <asm/iseries/hv_call_event.h> | 47 | #include <asm/iseries/hv_call_event.h> |
49 | #include <asm/iseries/hv_lp_config.h> | 48 | #include <asm/iseries/hv_lp_config.h> |
@@ -67,35 +66,6 @@ static int vio_sysrq_pressed; | |||
67 | extern int sysrq_enabled; | 66 | extern int sysrq_enabled; |
68 | #endif | 67 | #endif |
69 | 68 | ||
70 | /* | ||
71 | * The structure of the events that flow between us and OS/400. You can't | ||
72 | * mess with this unless the OS/400 side changes too | ||
73 | */ | ||
74 | struct viocharlpevent { | ||
75 | struct HvLpEvent event; | ||
76 | u32 reserved; | ||
77 | u16 version; | ||
78 | u16 subtype_result_code; | ||
79 | u8 virtual_device; | ||
80 | u8 len; | ||
81 | u8 data[VIOCHAR_MAX_DATA]; | ||
82 | }; | ||
83 | |||
84 | #define VIOCHAR_WINDOW 10 | ||
85 | #define VIOCHAR_HIGHWATERMARK 3 | ||
86 | |||
87 | enum viocharsubtype { | ||
88 | viocharopen = 0x0001, | ||
89 | viocharclose = 0x0002, | ||
90 | viochardata = 0x0003, | ||
91 | viocharack = 0x0004, | ||
92 | viocharconfig = 0x0005 | ||
93 | }; | ||
94 | |||
95 | enum viochar_rc { | ||
96 | viochar_rc_ebusy = 1 | ||
97 | }; | ||
98 | |||
99 | #define VIOCHAR_NUM_BUF 16 | 69 | #define VIOCHAR_NUM_BUF 16 |
100 | 70 | ||
101 | /* | 71 | /* |
@@ -1077,7 +1047,7 @@ static int send_open(HvLpIndex remoteLp, void *sem) | |||
1077 | 0, 0, 0, 0); | 1047 | 0, 0, 0, 0); |
1078 | } | 1048 | } |
1079 | 1049 | ||
1080 | static struct tty_operations serial_ops = { | 1050 | static const struct tty_operations serial_ops = { |
1081 | .open = viotty_open, | 1051 | .open = viotty_open, |
1082 | .close = viotty_close, | 1052 | .close = viotty_close, |
1083 | .write = viotty_write, | 1053 | .write = viotty_write, |
@@ -1183,6 +1153,7 @@ static int __init viocons_init(void) | |||
1183 | port_info[i].magic = VIOTTY_MAGIC; | 1153 | port_info[i].magic = VIOTTY_MAGIC; |
1184 | } | 1154 | } |
1185 | HvCall_setLogBufferFormatAndCodepage(HvCall_LogBuffer_ASCII, 437); | 1155 | HvCall_setLogBufferFormatAndCodepage(HvCall_LogBuffer_ASCII, 437); |
1156 | add_preferred_console("viocons", 0, NULL); | ||
1186 | register_console(&viocons_early); | 1157 | register_console(&viocons_early); |
1187 | return 0; | 1158 | return 0; |
1188 | } | 1159 | } |
diff --git a/drivers/char/viotape.c b/drivers/char/viotape.c index b72b2049aaae..73c78bf75d7f 100644 --- a/drivers/char/viotape.c +++ b/drivers/char/viotape.c | |||
@@ -940,7 +940,6 @@ static void vioHandleTapeEvent(struct HvLpEvent *event) | |||
940 | 940 | ||
941 | static int viotape_probe(struct vio_dev *vdev, const struct vio_device_id *id) | 941 | static int viotape_probe(struct vio_dev *vdev, const struct vio_device_id *id) |
942 | { | 942 | { |
943 | char tapename[32]; | ||
944 | int i = vdev->unit_address; | 943 | int i = vdev->unit_address; |
945 | int j; | 944 | int j; |
946 | 945 | ||
@@ -956,10 +955,9 @@ static int viotape_probe(struct vio_dev *vdev, const struct vio_device_id *id) | |||
956 | "iseries!vt%d", i); | 955 | "iseries!vt%d", i); |
957 | class_device_create(tape_class, NULL, MKDEV(VIOTAPE_MAJOR, i | 0x80), | 956 | class_device_create(tape_class, NULL, MKDEV(VIOTAPE_MAJOR, i | 0x80), |
958 | NULL, "iseries!nvt%d", i); | 957 | NULL, "iseries!nvt%d", i); |
959 | sprintf(tapename, "iseries/vt%d", i); | 958 | printk(VIOTAPE_KERN_INFO "tape iseries/vt%d is iSeries " |
960 | printk(VIOTAPE_KERN_INFO "tape %s is iSeries " | ||
961 | "resource %10.10s type %4.4s, model %3.3s\n", | 959 | "resource %10.10s type %4.4s, model %3.3s\n", |
962 | tapename, viotape_unitinfo[i].rsrcname, | 960 | i, viotape_unitinfo[i].rsrcname, |
963 | viotape_unitinfo[i].type, viotape_unitinfo[i].model); | 961 | viotape_unitinfo[i].type, viotape_unitinfo[i].model); |
964 | return 0; | 962 | return 0; |
965 | } | 963 | } |
diff --git a/drivers/char/vme_scc.c b/drivers/char/vme_scc.c index bfe5ea948f6a..c2ca31eb850b 100644 --- a/drivers/char/vme_scc.c +++ b/drivers/char/vme_scc.c | |||
@@ -113,7 +113,7 @@ static struct real_driver scc_real_driver = { | |||
113 | }; | 113 | }; |
114 | 114 | ||
115 | 115 | ||
116 | static struct tty_operations scc_ops = { | 116 | static const struct tty_operations scc_ops = { |
117 | .open = scc_open, | 117 | .open = scc_open, |
118 | .close = gs_close, | 118 | .close = gs_close, |
119 | .write = gs_write, | 119 | .write = gs_write, |
diff --git a/drivers/char/vt.c b/drivers/char/vt.c index da7e66a2a38b..ec0c070bf15f 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c | |||
@@ -63,6 +63,13 @@ | |||
63 | * | 63 | * |
64 | * Removed console_lock, enabled interrupts across all console operations | 64 | * Removed console_lock, enabled interrupts across all console operations |
65 | * 13 March 2001, Andrew Morton | 65 | * 13 March 2001, Andrew Morton |
66 | * | ||
67 | * Fixed UTF-8 mode so alternate charset modes always work according | ||
68 | * to control sequences interpreted in do_con_trol function | ||
69 | * preserving backward VT100 semigraphics compatibility, | ||
70 | * malformed UTF sequences represented as sequences of replacement glyphs, | ||
71 | * original codes or '?' as a last resort if replacement glyph is undefined | ||
72 | * by Adam Tla/lka <atlka@pg.gda.pl>, Aug 2006 | ||
66 | */ | 73 | */ |
67 | 74 | ||
68 | #include <linux/module.h> | 75 | #include <linux/module.h> |
@@ -128,8 +135,8 @@ const struct consw *conswitchp; | |||
128 | #define DEFAULT_BELL_PITCH 750 | 135 | #define DEFAULT_BELL_PITCH 750 |
129 | #define DEFAULT_BELL_DURATION (HZ/8) | 136 | #define DEFAULT_BELL_DURATION (HZ/8) |
130 | 137 | ||
131 | extern void vcs_make_devfs(struct tty_struct *tty); | 138 | extern void vcs_make_sysfs(struct tty_struct *tty); |
132 | extern void vcs_remove_devfs(struct tty_struct *tty); | 139 | extern void vcs_remove_sysfs(struct tty_struct *tty); |
133 | 140 | ||
134 | extern void console_map_init(void); | 141 | extern void console_map_init(void); |
135 | #ifdef CONFIG_PROM_CONSOLE | 142 | #ifdef CONFIG_PROM_CONSOLE |
@@ -730,7 +737,8 @@ int vc_allocate(unsigned int currcons) /* return 0 on success */ | |||
730 | visual_init(vc, currcons, 1); | 737 | visual_init(vc, currcons, 1); |
731 | if (!*vc->vc_uni_pagedir_loc) | 738 | if (!*vc->vc_uni_pagedir_loc) |
732 | con_set_default_unimap(vc); | 739 | con_set_default_unimap(vc); |
733 | vc->vc_screenbuf = kmalloc(vc->vc_screenbuf_size, GFP_KERNEL); | 740 | if (!vc->vc_kmalloced) |
741 | vc->vc_screenbuf = kmalloc(vc->vc_screenbuf_size, GFP_KERNEL); | ||
734 | if (!vc->vc_screenbuf) { | 742 | if (!vc->vc_screenbuf) { |
735 | kfree(vc); | 743 | kfree(vc); |
736 | vc_cons[currcons].d = NULL; | 744 | vc_cons[currcons].d = NULL; |
@@ -878,14 +886,24 @@ int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines) | |||
878 | return err; | 886 | return err; |
879 | } | 887 | } |
880 | 888 | ||
889 | int vc_lock_resize(struct vc_data *vc, unsigned int cols, unsigned int lines) | ||
890 | { | ||
891 | int rc; | ||
892 | |||
893 | acquire_console_sem(); | ||
894 | rc = vc_resize(vc, cols, lines); | ||
895 | release_console_sem(); | ||
896 | return rc; | ||
897 | } | ||
881 | 898 | ||
882 | void vc_disallocate(unsigned int currcons) | 899 | void vc_deallocate(unsigned int currcons) |
883 | { | 900 | { |
884 | WARN_CONSOLE_UNLOCKED(); | 901 | WARN_CONSOLE_UNLOCKED(); |
885 | 902 | ||
886 | if (vc_cons_allocated(currcons)) { | 903 | if (vc_cons_allocated(currcons)) { |
887 | struct vc_data *vc = vc_cons[currcons].d; | 904 | struct vc_data *vc = vc_cons[currcons].d; |
888 | vc->vc_sw->con_deinit(vc); | 905 | vc->vc_sw->con_deinit(vc); |
906 | put_pid(vc->vt_pid); | ||
889 | module_put(vc->vc_sw->owner); | 907 | module_put(vc->vc_sw->owner); |
890 | if (vc->vc_kmalloced) | 908 | if (vc->vc_kmalloced) |
891 | kfree(vc->vc_screenbuf); | 909 | kfree(vc->vc_screenbuf); |
@@ -2005,17 +2023,23 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co | |||
2005 | /* Do no translation at all in control states */ | 2023 | /* Do no translation at all in control states */ |
2006 | if (vc->vc_state != ESnormal) { | 2024 | if (vc->vc_state != ESnormal) { |
2007 | tc = c; | 2025 | tc = c; |
2008 | } else if (vc->vc_utf) { | 2026 | } else if (vc->vc_utf && !vc->vc_disp_ctrl) { |
2009 | /* Combine UTF-8 into Unicode */ | 2027 | /* Combine UTF-8 into Unicode */ |
2010 | /* Incomplete characters silently ignored */ | 2028 | /* Malformed sequences as sequences of replacement glyphs */ |
2029 | rescan_last_byte: | ||
2011 | if(c > 0x7f) { | 2030 | if(c > 0x7f) { |
2012 | if (vc->vc_utf_count > 0 && (c & 0xc0) == 0x80) { | 2031 | if (vc->vc_utf_count) { |
2013 | vc->vc_utf_char = (vc->vc_utf_char << 6) | (c & 0x3f); | 2032 | if ((c & 0xc0) == 0x80) { |
2014 | vc->vc_utf_count--; | 2033 | vc->vc_utf_char = (vc->vc_utf_char << 6) | (c & 0x3f); |
2015 | if (vc->vc_utf_count == 0) | 2034 | if (--vc->vc_utf_count) { |
2016 | tc = c = vc->vc_utf_char; | 2035 | vc->vc_npar++; |
2017 | else continue; | 2036 | continue; |
2037 | } | ||
2038 | tc = c = vc->vc_utf_char; | ||
2039 | } else | ||
2040 | goto replacement_glyph; | ||
2018 | } else { | 2041 | } else { |
2042 | vc->vc_npar = 0; | ||
2019 | if ((c & 0xe0) == 0xc0) { | 2043 | if ((c & 0xe0) == 0xc0) { |
2020 | vc->vc_utf_count = 1; | 2044 | vc->vc_utf_count = 1; |
2021 | vc->vc_utf_char = (c & 0x1f); | 2045 | vc->vc_utf_char = (c & 0x1f); |
@@ -2032,14 +2056,15 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co | |||
2032 | vc->vc_utf_count = 5; | 2056 | vc->vc_utf_count = 5; |
2033 | vc->vc_utf_char = (c & 0x01); | 2057 | vc->vc_utf_char = (c & 0x01); |
2034 | } else | 2058 | } else |
2035 | vc->vc_utf_count = 0; | 2059 | goto replacement_glyph; |
2036 | continue; | 2060 | continue; |
2037 | } | 2061 | } |
2038 | } else { | 2062 | } else { |
2063 | if (vc->vc_utf_count) | ||
2064 | goto replacement_glyph; | ||
2039 | tc = c; | 2065 | tc = c; |
2040 | vc->vc_utf_count = 0; | ||
2041 | } | 2066 | } |
2042 | } else { /* no utf */ | 2067 | } else { /* no utf or alternate charset mode */ |
2043 | tc = vc->vc_translate[vc->vc_toggle_meta ? (c | 0x80) : c]; | 2068 | tc = vc->vc_translate[vc->vc_toggle_meta ? (c | 0x80) : c]; |
2044 | } | 2069 | } |
2045 | 2070 | ||
@@ -2054,31 +2079,33 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co | |||
2054 | * direct-to-font zone in UTF-8 mode. | 2079 | * direct-to-font zone in UTF-8 mode. |
2055 | */ | 2080 | */ |
2056 | ok = tc && (c >= 32 || | 2081 | ok = tc && (c >= 32 || |
2057 | (!vc->vc_utf && !(((vc->vc_disp_ctrl ? CTRL_ALWAYS | 2082 | !(vc->vc_disp_ctrl ? (CTRL_ALWAYS >> c) & 1 : |
2058 | : CTRL_ACTION) >> c) & 1))) | 2083 | vc->vc_utf || ((CTRL_ACTION >> c) & 1))) |
2059 | && (c != 127 || vc->vc_disp_ctrl) | 2084 | && (c != 127 || vc->vc_disp_ctrl) |
2060 | && (c != 128+27); | 2085 | && (c != 128+27); |
2061 | 2086 | ||
2062 | if (vc->vc_state == ESnormal && ok) { | 2087 | if (vc->vc_state == ESnormal && ok) { |
2063 | /* Now try to find out how to display it */ | 2088 | /* Now try to find out how to display it */ |
2064 | tc = conv_uni_to_pc(vc, tc); | 2089 | tc = conv_uni_to_pc(vc, tc); |
2065 | if ( tc == -4 ) { | 2090 | if (tc & ~charmask) { |
2091 | if ( tc == -4 ) { | ||
2066 | /* If we got -4 (not found) then see if we have | 2092 | /* If we got -4 (not found) then see if we have |
2067 | defined a replacement character (U+FFFD) */ | 2093 | defined a replacement character (U+FFFD) */ |
2068 | tc = conv_uni_to_pc(vc, 0xfffd); | 2094 | replacement_glyph: |
2069 | 2095 | tc = conv_uni_to_pc(vc, 0xfffd); | |
2070 | /* One reason for the -4 can be that we just | 2096 | if (!(tc & ~charmask)) |
2071 | did a clear_unimap(); | 2097 | goto display_glyph; |
2072 | try at least to show something. */ | 2098 | } else if ( tc != -3 ) |
2073 | if (tc == -4) | 2099 | continue; /* nothing to display */ |
2074 | tc = c; | 2100 | /* no hash table or no replacement -- |
2075 | } else if ( tc == -3 ) { | 2101 | * hope for the best */ |
2076 | /* Bad hash table -- hope for the best */ | 2102 | if ( c & ~charmask ) |
2077 | tc = c; | 2103 | tc = '?'; |
2078 | } | 2104 | else |
2079 | if (tc & ~charmask) | 2105 | tc = c; |
2080 | continue; /* Conversion failed */ | 2106 | } |
2081 | 2107 | ||
2108 | display_glyph: | ||
2082 | if (vc->vc_need_wrap || vc->vc_decim) | 2109 | if (vc->vc_need_wrap || vc->vc_decim) |
2083 | FLUSH | 2110 | FLUSH |
2084 | if (vc->vc_need_wrap) { | 2111 | if (vc->vc_need_wrap) { |
@@ -2102,6 +2129,15 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co | |||
2102 | vc->vc_x++; | 2129 | vc->vc_x++; |
2103 | draw_to = (vc->vc_pos += 2); | 2130 | draw_to = (vc->vc_pos += 2); |
2104 | } | 2131 | } |
2132 | if (vc->vc_utf_count) { | ||
2133 | if (vc->vc_npar) { | ||
2134 | vc->vc_npar--; | ||
2135 | goto display_glyph; | ||
2136 | } | ||
2137 | vc->vc_utf_count = 0; | ||
2138 | c = orig; | ||
2139 | goto rescan_last_byte; | ||
2140 | } | ||
2105 | continue; | 2141 | continue; |
2106 | } | 2142 | } |
2107 | FLUSH | 2143 | FLUSH |
@@ -2498,7 +2534,7 @@ static int con_open(struct tty_struct *tty, struct file *filp) | |||
2498 | tty->winsize.ws_col = vc_cons[currcons].d->vc_cols; | 2534 | tty->winsize.ws_col = vc_cons[currcons].d->vc_cols; |
2499 | } | 2535 | } |
2500 | release_console_sem(); | 2536 | release_console_sem(); |
2501 | vcs_make_devfs(tty); | 2537 | vcs_make_sysfs(tty); |
2502 | return ret; | 2538 | return ret; |
2503 | } | 2539 | } |
2504 | } | 2540 | } |
@@ -2511,7 +2547,7 @@ static int con_open(struct tty_struct *tty, struct file *filp) | |||
2511 | * and taking a ref against the tty while we're in the process of forgetting | 2547 | * and taking a ref against the tty while we're in the process of forgetting |
2512 | * about it and cleaning things up. | 2548 | * about it and cleaning things up. |
2513 | * | 2549 | * |
2514 | * This is because vcs_remove_devfs() can sleep and will drop the BKL. | 2550 | * This is because vcs_remove_sysfs() can sleep and will drop the BKL. |
2515 | */ | 2551 | */ |
2516 | static void con_close(struct tty_struct *tty, struct file *filp) | 2552 | static void con_close(struct tty_struct *tty, struct file *filp) |
2517 | { | 2553 | { |
@@ -2524,7 +2560,7 @@ static void con_close(struct tty_struct *tty, struct file *filp) | |||
2524 | vc->vc_tty = NULL; | 2560 | vc->vc_tty = NULL; |
2525 | tty->driver_data = NULL; | 2561 | tty->driver_data = NULL; |
2526 | release_console_sem(); | 2562 | release_console_sem(); |
2527 | vcs_remove_devfs(tty); | 2563 | vcs_remove_sysfs(tty); |
2528 | mutex_unlock(&tty_mutex); | 2564 | mutex_unlock(&tty_mutex); |
2529 | /* | 2565 | /* |
2530 | * tty_mutex is released, but we still hold BKL, so there is | 2566 | * tty_mutex is released, but we still hold BKL, so there is |
@@ -2639,7 +2675,7 @@ static int __init con_init(void) | |||
2639 | } | 2675 | } |
2640 | console_initcall(con_init); | 2676 | console_initcall(con_init); |
2641 | 2677 | ||
2642 | static struct tty_operations con_ops = { | 2678 | static const struct tty_operations con_ops = { |
2643 | .open = con_open, | 2679 | .open = con_open, |
2644 | .close = con_close, | 2680 | .close = con_close, |
2645 | .write = con_write, | 2681 | .write = con_write, |
@@ -3765,6 +3801,7 @@ EXPORT_SYMBOL(default_blu); | |||
3765 | EXPORT_SYMBOL(update_region); | 3801 | EXPORT_SYMBOL(update_region); |
3766 | EXPORT_SYMBOL(redraw_screen); | 3802 | EXPORT_SYMBOL(redraw_screen); |
3767 | EXPORT_SYMBOL(vc_resize); | 3803 | EXPORT_SYMBOL(vc_resize); |
3804 | EXPORT_SYMBOL(vc_lock_resize); | ||
3768 | EXPORT_SYMBOL(fg_console); | 3805 | EXPORT_SYMBOL(fg_console); |
3769 | EXPORT_SYMBOL(console_blank_hook); | 3806 | EXPORT_SYMBOL(console_blank_hook); |
3770 | EXPORT_SYMBOL(console_blanked); | 3807 | EXPORT_SYMBOL(console_blanked); |
diff --git a/drivers/char/vt_ioctl.c b/drivers/char/vt_ioctl.c index a5628a8b6620..ac5d60edbafa 100644 --- a/drivers/char/vt_ioctl.c +++ b/drivers/char/vt_ioctl.c | |||
@@ -96,7 +96,7 @@ do_kdsk_ioctl(int cmd, struct kbentry __user *user_kbe, int perm, struct kbd_str | |||
96 | if (!perm) | 96 | if (!perm) |
97 | return -EPERM; | 97 | return -EPERM; |
98 | if (!i && v == K_NOSUCHMAP) { | 98 | if (!i && v == K_NOSUCHMAP) { |
99 | /* disallocate map */ | 99 | /* deallocate map */ |
100 | key_map = key_maps[s]; | 100 | key_map = key_maps[s]; |
101 | if (s && key_map) { | 101 | if (s && key_map) { |
102 | key_maps[s] = NULL; | 102 | key_maps[s] = NULL; |
@@ -645,13 +645,16 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, | |||
645 | */ | 645 | */ |
646 | case KDSIGACCEPT: | 646 | case KDSIGACCEPT: |
647 | { | 647 | { |
648 | extern int spawnpid, spawnsig; | ||
649 | if (!perm || !capable(CAP_KILL)) | 648 | if (!perm || !capable(CAP_KILL)) |
650 | return -EPERM; | 649 | return -EPERM; |
651 | if (!valid_signal(arg) || arg < 1 || arg == SIGKILL) | 650 | if (!valid_signal(arg) || arg < 1 || arg == SIGKILL) |
652 | return -EINVAL; | 651 | return -EINVAL; |
653 | spawnpid = current->pid; | 652 | |
654 | spawnsig = arg; | 653 | spin_lock_irq(&vt_spawn_con.lock); |
654 | put_pid(vt_spawn_con.pid); | ||
655 | vt_spawn_con.pid = get_pid(task_pid(current)); | ||
656 | vt_spawn_con.sig = arg; | ||
657 | spin_unlock_irq(&vt_spawn_con.lock); | ||
655 | return 0; | 658 | return 0; |
656 | } | 659 | } |
657 | 660 | ||
@@ -669,7 +672,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, | |||
669 | vc->vt_mode = tmp; | 672 | vc->vt_mode = tmp; |
670 | /* the frsig is ignored, so we set it to 0 */ | 673 | /* the frsig is ignored, so we set it to 0 */ |
671 | vc->vt_mode.frsig = 0; | 674 | vc->vt_mode.frsig = 0; |
672 | vc->vt_pid = current->pid; | 675 | put_pid(xchg(&vc->vt_pid, get_pid(task_pid(current)))); |
673 | /* no switch is required -- saw@shade.msu.ru */ | 676 | /* no switch is required -- saw@shade.msu.ru */ |
674 | vc->vt_newvt = -1; | 677 | vc->vt_newvt = -1; |
675 | release_console_sem(); | 678 | release_console_sem(); |
@@ -819,20 +822,20 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, | |||
819 | if (arg > MAX_NR_CONSOLES) | 822 | if (arg > MAX_NR_CONSOLES) |
820 | return -ENXIO; | 823 | return -ENXIO; |
821 | if (arg == 0) { | 824 | if (arg == 0) { |
822 | /* disallocate all unused consoles, but leave 0 */ | 825 | /* deallocate all unused consoles, but leave 0 */ |
823 | acquire_console_sem(); | 826 | acquire_console_sem(); |
824 | for (i=1; i<MAX_NR_CONSOLES; i++) | 827 | for (i=1; i<MAX_NR_CONSOLES; i++) |
825 | if (! VT_BUSY(i)) | 828 | if (! VT_BUSY(i)) |
826 | vc_disallocate(i); | 829 | vc_deallocate(i); |
827 | release_console_sem(); | 830 | release_console_sem(); |
828 | } else { | 831 | } else { |
829 | /* disallocate a single console, if possible */ | 832 | /* deallocate a single console, if possible */ |
830 | arg--; | 833 | arg--; |
831 | if (VT_BUSY(arg)) | 834 | if (VT_BUSY(arg)) |
832 | return -EBUSY; | 835 | return -EBUSY; |
833 | if (arg) { /* leave 0 */ | 836 | if (arg) { /* leave 0 */ |
834 | acquire_console_sem(); | 837 | acquire_console_sem(); |
835 | vc_disallocate(arg); | 838 | vc_deallocate(arg); |
836 | release_console_sem(); | 839 | release_console_sem(); |
837 | } | 840 | } |
838 | } | 841 | } |
@@ -847,11 +850,8 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, | |||
847 | if (get_user(ll, &vtsizes->v_rows) || | 850 | if (get_user(ll, &vtsizes->v_rows) || |
848 | get_user(cc, &vtsizes->v_cols)) | 851 | get_user(cc, &vtsizes->v_cols)) |
849 | return -EFAULT; | 852 | return -EFAULT; |
850 | for (i = 0; i < MAX_NR_CONSOLES; i++) { | 853 | for (i = 0; i < MAX_NR_CONSOLES; i++) |
851 | acquire_console_sem(); | 854 | vc_lock_resize(vc_cons[i].d, cc, ll); |
852 | vc_resize(vc_cons[i].d, cc, ll); | ||
853 | release_console_sem(); | ||
854 | } | ||
855 | return 0; | 855 | return 0; |
856 | } | 856 | } |
857 | 857 | ||
@@ -1063,7 +1063,7 @@ void reset_vc(struct vc_data *vc) | |||
1063 | vc->vt_mode.relsig = 0; | 1063 | vc->vt_mode.relsig = 0; |
1064 | vc->vt_mode.acqsig = 0; | 1064 | vc->vt_mode.acqsig = 0; |
1065 | vc->vt_mode.frsig = 0; | 1065 | vc->vt_mode.frsig = 0; |
1066 | vc->vt_pid = -1; | 1066 | put_pid(xchg(&vc->vt_pid, NULL)); |
1067 | vc->vt_newvt = -1; | 1067 | vc->vt_newvt = -1; |
1068 | if (!in_interrupt()) /* Via keyboard.c:SAK() - akpm */ | 1068 | if (!in_interrupt()) /* Via keyboard.c:SAK() - akpm */ |
1069 | reset_palette(vc); | 1069 | reset_palette(vc); |
@@ -1114,7 +1114,7 @@ static void complete_change_console(struct vc_data *vc) | |||
1114 | * tell us if the process has gone or something else | 1114 | * tell us if the process has gone or something else |
1115 | * is awry | 1115 | * is awry |
1116 | */ | 1116 | */ |
1117 | if (kill_proc(vc->vt_pid, vc->vt_mode.acqsig, 1) != 0) { | 1117 | if (kill_pid(vc->vt_pid, vc->vt_mode.acqsig, 1) != 0) { |
1118 | /* | 1118 | /* |
1119 | * The controlling process has died, so we revert back to | 1119 | * The controlling process has died, so we revert back to |
1120 | * normal operation. In this case, we'll also change back | 1120 | * normal operation. In this case, we'll also change back |
@@ -1174,7 +1174,7 @@ void change_console(struct vc_data *new_vc) | |||
1174 | * tell us if the process has gone or something else | 1174 | * tell us if the process has gone or something else |
1175 | * is awry | 1175 | * is awry |
1176 | */ | 1176 | */ |
1177 | if (kill_proc(vc->vt_pid, vc->vt_mode.relsig, 1) == 0) { | 1177 | if (kill_pid(vc->vt_pid, vc->vt_mode.relsig, 1) == 0) { |
1178 | /* | 1178 | /* |
1179 | * It worked. Mark the vt to switch to and | 1179 | * It worked. Mark the vt to switch to and |
1180 | * return. The process needs to send us a | 1180 | * return. The process needs to send us a |
diff --git a/drivers/char/watchdog/Kconfig b/drivers/char/watchdog/Kconfig index fff89c2d88fd..77ab7e020da0 100644 --- a/drivers/char/watchdog/Kconfig +++ b/drivers/char/watchdog/Kconfig | |||
@@ -165,6 +165,13 @@ config EP93XX_WATCHDOG | |||
165 | To compile this driver as a module, choose M here: the | 165 | To compile this driver as a module, choose M here: the |
166 | module will be called ep93xx_wdt. | 166 | module will be called ep93xx_wdt. |
167 | 167 | ||
168 | config OMAP_WATCHDOG | ||
169 | tristate "OMAP Watchdog" | ||
170 | depends on WATCHDOG && (ARCH_OMAP16XX || ARCH_OMAP24XX) | ||
171 | help | ||
172 | Support for TI OMAP1610/OMAP1710/OMAP2420 watchdog. Say 'Y' here to | ||
173 | enable the OMAP1610/OMAP1710 watchdog timer. | ||
174 | |||
168 | # X86 (i386 + ia64 + x86_64) Architecture | 175 | # X86 (i386 + ia64 + x86_64) Architecture |
169 | 176 | ||
170 | config ACQUIRE_WDT | 177 | config ACQUIRE_WDT |
@@ -510,6 +517,14 @@ config SH_WDT | |||
510 | To compile this driver as a module, choose M here: the | 517 | To compile this driver as a module, choose M here: the |
511 | module will be called shwdt. | 518 | module will be called shwdt. |
512 | 519 | ||
520 | config SH_WDT_MMAP | ||
521 | bool "Allow mmap of SH WDT" | ||
522 | default n | ||
523 | depends on SH_WDT | ||
524 | help | ||
525 | If you say Y here, user applications will be able to mmap the | ||
526 | WDT/CPG registers. | ||
527 | # | ||
513 | # SPARC64 Architecture | 528 | # SPARC64 Architecture |
514 | 529 | ||
515 | config WATCHDOG_CP1XXX | 530 | config WATCHDOG_CP1XXX |
diff --git a/drivers/char/watchdog/Makefile b/drivers/char/watchdog/Makefile index 6ab77b61a643..5099f8be8cc5 100644 --- a/drivers/char/watchdog/Makefile +++ b/drivers/char/watchdog/Makefile | |||
@@ -24,6 +24,7 @@ obj-$(CONFIG_USBPCWATCHDOG) += pcwd_usb.o | |||
24 | 24 | ||
25 | # ARM Architecture | 25 | # ARM Architecture |
26 | obj-$(CONFIG_AT91_WATCHDOG) += at91_wdt.o | 26 | obj-$(CONFIG_AT91_WATCHDOG) += at91_wdt.o |
27 | obj-$(CONFIG_OMAP_WATCHDOG) += omap_wdt.o | ||
27 | obj-$(CONFIG_21285_WATCHDOG) += wdt285.o | 28 | obj-$(CONFIG_21285_WATCHDOG) += wdt285.o |
28 | obj-$(CONFIG_977_WATCHDOG) += wdt977.o | 29 | obj-$(CONFIG_977_WATCHDOG) += wdt977.o |
29 | obj-$(CONFIG_IXP2000_WATCHDOG) += ixp2000_wdt.o | 30 | obj-$(CONFIG_IXP2000_WATCHDOG) += ixp2000_wdt.o |
diff --git a/drivers/char/watchdog/omap_wdt.c b/drivers/char/watchdog/omap_wdt.c new file mode 100644 index 000000000000..8f90b90a5021 --- /dev/null +++ b/drivers/char/watchdog/omap_wdt.c | |||
@@ -0,0 +1,391 @@ | |||
1 | /* | ||
2 | * linux/drivers/char/watchdog/omap_wdt.c | ||
3 | * | ||
4 | * Watchdog driver for the TI OMAP 16xx & 24xx 32KHz (non-secure) watchdog | ||
5 | * | ||
6 | * Author: MontaVista Software, Inc. | ||
7 | * <gdavis@mvista.com> or <source@mvista.com> | ||
8 | * | ||
9 | * 2003 (c) MontaVista Software, Inc. This file is licensed under the | ||
10 | * terms of the GNU General Public License version 2. This program is | ||
11 | * licensed "as is" without any warranty of any kind, whether express | ||
12 | * or implied. | ||
13 | * | ||
14 | * History: | ||
15 | * | ||
16 | * 20030527: George G. Davis <gdavis@mvista.com> | ||
17 | * Initially based on linux-2.4.19-rmk7-pxa1/drivers/char/sa1100_wdt.c | ||
18 | * (c) Copyright 2000 Oleg Drokin <green@crimea.edu> | ||
19 | * Based on SoftDog driver by Alan Cox <alan@redhat.com> | ||
20 | * | ||
21 | * Copyright (c) 2004 Texas Instruments. | ||
22 | * 1. Modified to support OMAP1610 32-KHz watchdog timer | ||
23 | * 2. Ported to 2.6 kernel | ||
24 | * | ||
25 | * Copyright (c) 2005 David Brownell | ||
26 | * Use the driver model and standard identifiers; handle bigger timeouts. | ||
27 | */ | ||
28 | |||
29 | #include <linux/module.h> | ||
30 | #include <linux/config.h> | ||
31 | #include <linux/types.h> | ||
32 | #include <linux/kernel.h> | ||
33 | #include <linux/fs.h> | ||
34 | #include <linux/mm.h> | ||
35 | #include <linux/miscdevice.h> | ||
36 | #include <linux/watchdog.h> | ||
37 | #include <linux/reboot.h> | ||
38 | #include <linux/smp_lock.h> | ||
39 | #include <linux/init.h> | ||
40 | #include <linux/err.h> | ||
41 | #include <linux/platform_device.h> | ||
42 | #include <linux/moduleparam.h> | ||
43 | #include <linux/clk.h> | ||
44 | |||
45 | #include <asm/io.h> | ||
46 | #include <asm/uaccess.h> | ||
47 | #include <asm/hardware.h> | ||
48 | #include <asm/bitops.h> | ||
49 | |||
50 | #include <asm/arch/prcm.h> | ||
51 | |||
52 | #include "omap_wdt.h" | ||
53 | |||
54 | static unsigned timer_margin; | ||
55 | module_param(timer_margin, uint, 0); | ||
56 | MODULE_PARM_DESC(timer_margin, "initial watchdog timeout (in seconds)"); | ||
57 | |||
58 | static int omap_wdt_users; | ||
59 | static struct clk *armwdt_ck = NULL; | ||
60 | static struct clk *mpu_wdt_ick = NULL; | ||
61 | static struct clk *mpu_wdt_fck = NULL; | ||
62 | |||
63 | static unsigned int wdt_trgr_pattern = 0x1234; | ||
64 | |||
65 | static void omap_wdt_ping(void) | ||
66 | { | ||
67 | /* wait for posted write to complete */ | ||
68 | while ((omap_readl(OMAP_WATCHDOG_WPS)) & 0x08) | ||
69 | cpu_relax(); | ||
70 | wdt_trgr_pattern = ~wdt_trgr_pattern; | ||
71 | omap_writel(wdt_trgr_pattern, (OMAP_WATCHDOG_TGR)); | ||
72 | /* wait for posted write to complete */ | ||
73 | while ((omap_readl(OMAP_WATCHDOG_WPS)) & 0x08) | ||
74 | cpu_relax(); | ||
75 | /* reloaded WCRR from WLDR */ | ||
76 | } | ||
77 | |||
78 | static void omap_wdt_enable(void) | ||
79 | { | ||
80 | /* Sequence to enable the watchdog */ | ||
81 | omap_writel(0xBBBB, OMAP_WATCHDOG_SPR); | ||
82 | while ((omap_readl(OMAP_WATCHDOG_WPS)) & 0x10) | ||
83 | cpu_relax(); | ||
84 | omap_writel(0x4444, OMAP_WATCHDOG_SPR); | ||
85 | while ((omap_readl(OMAP_WATCHDOG_WPS)) & 0x10) | ||
86 | cpu_relax(); | ||
87 | } | ||
88 | |||
89 | static void omap_wdt_disable(void) | ||
90 | { | ||
91 | /* sequence required to disable watchdog */ | ||
92 | omap_writel(0xAAAA, OMAP_WATCHDOG_SPR); /* TIMER_MODE */ | ||
93 | while (omap_readl(OMAP_WATCHDOG_WPS) & 0x10) | ||
94 | cpu_relax(); | ||
95 | omap_writel(0x5555, OMAP_WATCHDOG_SPR); /* TIMER_MODE */ | ||
96 | while (omap_readl(OMAP_WATCHDOG_WPS) & 0x10) | ||
97 | cpu_relax(); | ||
98 | } | ||
99 | |||
100 | static void omap_wdt_adjust_timeout(unsigned new_timeout) | ||
101 | { | ||
102 | if (new_timeout < TIMER_MARGIN_MIN) | ||
103 | new_timeout = TIMER_MARGIN_DEFAULT; | ||
104 | if (new_timeout > TIMER_MARGIN_MAX) | ||
105 | new_timeout = TIMER_MARGIN_MAX; | ||
106 | timer_margin = new_timeout; | ||
107 | } | ||
108 | |||
109 | static void omap_wdt_set_timeout(void) | ||
110 | { | ||
111 | u32 pre_margin = GET_WLDR_VAL(timer_margin); | ||
112 | |||
113 | /* just count up at 32 KHz */ | ||
114 | while (omap_readl(OMAP_WATCHDOG_WPS) & 0x04) | ||
115 | cpu_relax(); | ||
116 | omap_writel(pre_margin, OMAP_WATCHDOG_LDR); | ||
117 | while (omap_readl(OMAP_WATCHDOG_WPS) & 0x04) | ||
118 | cpu_relax(); | ||
119 | } | ||
120 | |||
121 | /* | ||
122 | * Allow only one task to hold it open | ||
123 | */ | ||
124 | |||
125 | static int omap_wdt_open(struct inode *inode, struct file *file) | ||
126 | { | ||
127 | if (test_and_set_bit(1, (unsigned long *)&omap_wdt_users)) | ||
128 | return -EBUSY; | ||
129 | |||
130 | if (cpu_is_omap16xx()) | ||
131 | clk_enable(armwdt_ck); /* Enable the clock */ | ||
132 | |||
133 | if (cpu_is_omap24xx()) { | ||
134 | clk_enable(mpu_wdt_ick); /* Enable the interface clock */ | ||
135 | clk_enable(mpu_wdt_fck); /* Enable the functional clock */ | ||
136 | } | ||
137 | |||
138 | /* initialize prescaler */ | ||
139 | while (omap_readl(OMAP_WATCHDOG_WPS) & 0x01) | ||
140 | cpu_relax(); | ||
141 | omap_writel((1 << 5) | (PTV << 2), OMAP_WATCHDOG_CNTRL); | ||
142 | while (omap_readl(OMAP_WATCHDOG_WPS) & 0x01) | ||
143 | cpu_relax(); | ||
144 | |||
145 | omap_wdt_set_timeout(); | ||
146 | omap_wdt_enable(); | ||
147 | return 0; | ||
148 | } | ||
149 | |||
150 | static int omap_wdt_release(struct inode *inode, struct file *file) | ||
151 | { | ||
152 | /* | ||
153 | * Shut off the timer unless NOWAYOUT is defined. | ||
154 | */ | ||
155 | #ifndef CONFIG_WATCHDOG_NOWAYOUT | ||
156 | omap_wdt_disable(); | ||
157 | |||
158 | if (cpu_is_omap16xx()) { | ||
159 | clk_disable(armwdt_ck); /* Disable the clock */ | ||
160 | clk_put(armwdt_ck); | ||
161 | armwdt_ck = NULL; | ||
162 | } | ||
163 | |||
164 | if (cpu_is_omap24xx()) { | ||
165 | clk_disable(mpu_wdt_ick); /* Disable the clock */ | ||
166 | clk_disable(mpu_wdt_fck); /* Disable the clock */ | ||
167 | clk_put(mpu_wdt_ick); | ||
168 | clk_put(mpu_wdt_fck); | ||
169 | mpu_wdt_ick = NULL; | ||
170 | mpu_wdt_fck = NULL; | ||
171 | } | ||
172 | #else | ||
173 | printk(KERN_CRIT "omap_wdt: Unexpected close, not stopping!\n"); | ||
174 | #endif | ||
175 | omap_wdt_users = 0; | ||
176 | return 0; | ||
177 | } | ||
178 | |||
179 | static ssize_t | ||
180 | omap_wdt_write(struct file *file, const char __user *data, | ||
181 | size_t len, loff_t *ppos) | ||
182 | { | ||
183 | /* Refresh LOAD_TIME. */ | ||
184 | if (len) | ||
185 | omap_wdt_ping(); | ||
186 | return len; | ||
187 | } | ||
188 | |||
189 | static int | ||
190 | omap_wdt_ioctl(struct inode *inode, struct file *file, | ||
191 | unsigned int cmd, unsigned long arg) | ||
192 | { | ||
193 | int new_margin; | ||
194 | static struct watchdog_info ident = { | ||
195 | .identity = "OMAP Watchdog", | ||
196 | .options = WDIOF_SETTIMEOUT, | ||
197 | .firmware_version = 0, | ||
198 | }; | ||
199 | |||
200 | switch (cmd) { | ||
201 | default: | ||
202 | return -ENOIOCTLCMD; | ||
203 | case WDIOC_GETSUPPORT: | ||
204 | return copy_to_user((struct watchdog_info __user *)arg, &ident, | ||
205 | sizeof(ident)); | ||
206 | case WDIOC_GETSTATUS: | ||
207 | return put_user(0, (int __user *)arg); | ||
208 | case WDIOC_GETBOOTSTATUS: | ||
209 | if (cpu_is_omap16xx()) | ||
210 | return put_user(omap_readw(ARM_SYSST), | ||
211 | (int __user *)arg); | ||
212 | if (cpu_is_omap24xx()) | ||
213 | return put_user(omap_prcm_get_reset_sources(), | ||
214 | (int __user *)arg); | ||
215 | case WDIOC_KEEPALIVE: | ||
216 | omap_wdt_ping(); | ||
217 | return 0; | ||
218 | case WDIOC_SETTIMEOUT: | ||
219 | if (get_user(new_margin, (int __user *)arg)) | ||
220 | return -EFAULT; | ||
221 | omap_wdt_adjust_timeout(new_margin); | ||
222 | |||
223 | omap_wdt_disable(); | ||
224 | omap_wdt_set_timeout(); | ||
225 | omap_wdt_enable(); | ||
226 | |||
227 | omap_wdt_ping(); | ||
228 | /* Fall */ | ||
229 | case WDIOC_GETTIMEOUT: | ||
230 | return put_user(timer_margin, (int __user *)arg); | ||
231 | } | ||
232 | } | ||
233 | |||
234 | static struct file_operations omap_wdt_fops = { | ||
235 | .owner = THIS_MODULE, | ||
236 | .write = omap_wdt_write, | ||
237 | .ioctl = omap_wdt_ioctl, | ||
238 | .open = omap_wdt_open, | ||
239 | .release = omap_wdt_release, | ||
240 | }; | ||
241 | |||
242 | static struct miscdevice omap_wdt_miscdev = { | ||
243 | .minor = WATCHDOG_MINOR, | ||
244 | .name = "watchdog", | ||
245 | .fops = &omap_wdt_fops | ||
246 | }; | ||
247 | |||
248 | static int __init omap_wdt_probe(struct platform_device *pdev) | ||
249 | { | ||
250 | struct resource *res, *mem; | ||
251 | int ret; | ||
252 | |||
253 | /* reserve static register mappings */ | ||
254 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
255 | if (!res) | ||
256 | return -ENOENT; | ||
257 | |||
258 | mem = request_mem_region(res->start, res->end - res->start + 1, | ||
259 | pdev->name); | ||
260 | if (mem == NULL) | ||
261 | return -EBUSY; | ||
262 | |||
263 | platform_set_drvdata(pdev, mem); | ||
264 | |||
265 | omap_wdt_users = 0; | ||
266 | |||
267 | if (cpu_is_omap16xx()) { | ||
268 | armwdt_ck = clk_get(&pdev->dev, "armwdt_ck"); | ||
269 | if (IS_ERR(armwdt_ck)) { | ||
270 | ret = PTR_ERR(armwdt_ck); | ||
271 | armwdt_ck = NULL; | ||
272 | goto fail; | ||
273 | } | ||
274 | } | ||
275 | |||
276 | if (cpu_is_omap24xx()) { | ||
277 | mpu_wdt_ick = clk_get(&pdev->dev, "mpu_wdt_ick"); | ||
278 | if (IS_ERR(mpu_wdt_ick)) { | ||
279 | ret = PTR_ERR(mpu_wdt_ick); | ||
280 | mpu_wdt_ick = NULL; | ||
281 | goto fail; | ||
282 | } | ||
283 | mpu_wdt_fck = clk_get(&pdev->dev, "mpu_wdt_fck"); | ||
284 | if (IS_ERR(mpu_wdt_fck)) { | ||
285 | ret = PTR_ERR(mpu_wdt_fck); | ||
286 | mpu_wdt_fck = NULL; | ||
287 | goto fail; | ||
288 | } | ||
289 | } | ||
290 | |||
291 | omap_wdt_disable(); | ||
292 | omap_wdt_adjust_timeout(timer_margin); | ||
293 | |||
294 | omap_wdt_miscdev.dev = &pdev->dev; | ||
295 | ret = misc_register(&omap_wdt_miscdev); | ||
296 | if (ret) | ||
297 | goto fail; | ||
298 | |||
299 | pr_info("OMAP Watchdog Timer: initial timeout %d sec\n", timer_margin); | ||
300 | |||
301 | /* autogate OCP interface clock */ | ||
302 | omap_writel(0x01, OMAP_WATCHDOG_SYS_CONFIG); | ||
303 | return 0; | ||
304 | |||
305 | fail: | ||
306 | if (armwdt_ck) | ||
307 | clk_put(armwdt_ck); | ||
308 | if (mpu_wdt_ick) | ||
309 | clk_put(mpu_wdt_ick); | ||
310 | if (mpu_wdt_fck) | ||
311 | clk_put(mpu_wdt_fck); | ||
312 | release_resource(mem); | ||
313 | return ret; | ||
314 | } | ||
315 | |||
316 | static void omap_wdt_shutdown(struct platform_device *pdev) | ||
317 | { | ||
318 | omap_wdt_disable(); | ||
319 | } | ||
320 | |||
321 | static int omap_wdt_remove(struct platform_device *pdev) | ||
322 | { | ||
323 | struct resource *mem = platform_get_drvdata(pdev); | ||
324 | misc_deregister(&omap_wdt_miscdev); | ||
325 | release_resource(mem); | ||
326 | if (armwdt_ck) | ||
327 | clk_put(armwdt_ck); | ||
328 | if (mpu_wdt_ick) | ||
329 | clk_put(mpu_wdt_ick); | ||
330 | if (mpu_wdt_fck) | ||
331 | clk_put(mpu_wdt_fck); | ||
332 | return 0; | ||
333 | } | ||
334 | |||
335 | #ifdef CONFIG_PM | ||
336 | |||
337 | /* REVISIT ... not clear this is the best way to handle system suspend; and | ||
338 | * it's very inappropriate for selective device suspend (e.g. suspending this | ||
339 | * through sysfs rather than by stopping the watchdog daemon). Also, this | ||
340 | * may not play well enough with NOWAYOUT... | ||
341 | */ | ||
342 | |||
343 | static int omap_wdt_suspend(struct platform_device *pdev, pm_message_t state) | ||
344 | { | ||
345 | if (omap_wdt_users) | ||
346 | omap_wdt_disable(); | ||
347 | return 0; | ||
348 | } | ||
349 | |||
350 | static int omap_wdt_resume(struct platform_device *pdev) | ||
351 | { | ||
352 | if (omap_wdt_users) { | ||
353 | omap_wdt_enable(); | ||
354 | omap_wdt_ping(); | ||
355 | } | ||
356 | return 0; | ||
357 | } | ||
358 | |||
359 | #else | ||
360 | #define omap_wdt_suspend NULL | ||
361 | #define omap_wdt_resume NULL | ||
362 | #endif | ||
363 | |||
364 | static struct platform_driver omap_wdt_driver = { | ||
365 | .probe = omap_wdt_probe, | ||
366 | .remove = omap_wdt_remove, | ||
367 | .shutdown = omap_wdt_shutdown, | ||
368 | .suspend = omap_wdt_suspend, | ||
369 | .resume = omap_wdt_resume, | ||
370 | .driver = { | ||
371 | .owner = THIS_MODULE, | ||
372 | .name = "omap_wdt", | ||
373 | }, | ||
374 | }; | ||
375 | |||
376 | static int __init omap_wdt_init(void) | ||
377 | { | ||
378 | return platform_driver_register(&omap_wdt_driver); | ||
379 | } | ||
380 | |||
381 | static void __exit omap_wdt_exit(void) | ||
382 | { | ||
383 | platform_driver_unregister(&omap_wdt_driver); | ||
384 | } | ||
385 | |||
386 | module_init(omap_wdt_init); | ||
387 | module_exit(omap_wdt_exit); | ||
388 | |||
389 | MODULE_AUTHOR("George G. Davis"); | ||
390 | MODULE_LICENSE("GPL"); | ||
391 | MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); | ||
diff --git a/drivers/char/watchdog/omap_wdt.h b/drivers/char/watchdog/omap_wdt.h new file mode 100644 index 000000000000..52a532a5114a --- /dev/null +++ b/drivers/char/watchdog/omap_wdt.h | |||
@@ -0,0 +1,64 @@ | |||
1 | /* | ||
2 | * linux/drivers/char/watchdog/omap_wdt.h | ||
3 | * | ||
4 | * BRIEF MODULE DESCRIPTION | ||
5 | * OMAP Watchdog timer register definitions | ||
6 | * | ||
7 | * Copyright (C) 2004 Texas Instruments. | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify it | ||
10 | * under the terms of the GNU General Public License as published by the | ||
11 | * Free Software Foundation; either version 2 of the License, or (at your | ||
12 | * option) any later version. | ||
13 | * | ||
14 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED | ||
15 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
16 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN | ||
17 | * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
18 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
19 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | ||
20 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | ||
21 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
23 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
24 | * | ||
25 | * You should have received a copy of the GNU General Public License along | ||
26 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
27 | * 675 Mass Ave, Cambridge, MA 02139, USA. | ||
28 | */ | ||
29 | |||
30 | #ifndef _OMAP_WATCHDOG_H | ||
31 | #define _OMAP_WATCHDOG_H | ||
32 | |||
33 | #define OMAP1610_WATCHDOG_BASE 0xfffeb000 | ||
34 | #define OMAP2420_WATCHDOG_BASE 0x48022000 /*WDT Timer 2 */ | ||
35 | |||
36 | #ifdef CONFIG_ARCH_OMAP24XX | ||
37 | #define OMAP_WATCHDOG_BASE OMAP2420_WATCHDOG_BASE | ||
38 | #else | ||
39 | #define OMAP_WATCHDOG_BASE OMAP1610_WATCHDOG_BASE | ||
40 | #define RM_RSTST_WKUP 0 | ||
41 | #endif | ||
42 | |||
43 | #define OMAP_WATCHDOG_REV (OMAP_WATCHDOG_BASE + 0x00) | ||
44 | #define OMAP_WATCHDOG_SYS_CONFIG (OMAP_WATCHDOG_BASE + 0x10) | ||
45 | #define OMAP_WATCHDOG_STATUS (OMAP_WATCHDOG_BASE + 0x14) | ||
46 | #define OMAP_WATCHDOG_CNTRL (OMAP_WATCHDOG_BASE + 0x24) | ||
47 | #define OMAP_WATCHDOG_CRR (OMAP_WATCHDOG_BASE + 0x28) | ||
48 | #define OMAP_WATCHDOG_LDR (OMAP_WATCHDOG_BASE + 0x2c) | ||
49 | #define OMAP_WATCHDOG_TGR (OMAP_WATCHDOG_BASE + 0x30) | ||
50 | #define OMAP_WATCHDOG_WPS (OMAP_WATCHDOG_BASE + 0x34) | ||
51 | #define OMAP_WATCHDOG_SPR (OMAP_WATCHDOG_BASE + 0x48) | ||
52 | |||
53 | /* Using the prescaler, the OMAP watchdog could go for many | ||
54 | * months before firing. These limits work without scaling, | ||
55 | * with the 60 second default assumed by most tools and docs. | ||
56 | */ | ||
57 | #define TIMER_MARGIN_MAX (24 * 60 * 60) /* 1 day */ | ||
58 | #define TIMER_MARGIN_DEFAULT 60 /* 60 secs */ | ||
59 | #define TIMER_MARGIN_MIN 1 | ||
60 | |||
61 | #define PTV 0 /* prescale */ | ||
62 | #define GET_WLDR_VAL(secs) (0xffffffff - ((secs) * (32768/(1<<PTV))) + 1) | ||
63 | |||
64 | #endif /* _OMAP_WATCHDOG_H */ | ||
diff --git a/drivers/char/watchdog/shwdt.c b/drivers/char/watchdog/shwdt.c index 1355038f1044..e5b8c64f1d65 100644 --- a/drivers/char/watchdog/shwdt.c +++ b/drivers/char/watchdog/shwdt.c | |||
@@ -27,7 +27,7 @@ | |||
27 | #include <linux/notifier.h> | 27 | #include <linux/notifier.h> |
28 | #include <linux/ioport.h> | 28 | #include <linux/ioport.h> |
29 | #include <linux/fs.h> | 29 | #include <linux/fs.h> |
30 | 30 | #include <linux/mm.h> | |
31 | #include <asm/io.h> | 31 | #include <asm/io.h> |
32 | #include <asm/uaccess.h> | 32 | #include <asm/uaccess.h> |
33 | #include <asm/watchdog.h> | 33 | #include <asm/watchdog.h> |
@@ -125,7 +125,6 @@ static void sh_wdt_start(void) | |||
125 | 125 | ||
126 | /** | 126 | /** |
127 | * sh_wdt_stop - Stop the Watchdog | 127 | * sh_wdt_stop - Stop the Watchdog |
128 | * | ||
129 | * Stops the watchdog. | 128 | * Stops the watchdog. |
130 | */ | 129 | */ |
131 | static void sh_wdt_stop(void) | 130 | static void sh_wdt_stop(void) |
@@ -141,22 +140,20 @@ static void sh_wdt_stop(void) | |||
141 | 140 | ||
142 | /** | 141 | /** |
143 | * sh_wdt_keepalive - Keep the Userspace Watchdog Alive | 142 | * sh_wdt_keepalive - Keep the Userspace Watchdog Alive |
144 | * | ||
145 | * The Userspace watchdog got a KeepAlive: schedule the next heartbeat. | 143 | * The Userspace watchdog got a KeepAlive: schedule the next heartbeat. |
146 | */ | 144 | */ |
147 | static void sh_wdt_keepalive(void) | 145 | static inline void sh_wdt_keepalive(void) |
148 | { | 146 | { |
149 | next_heartbeat = jiffies + (heartbeat * HZ); | 147 | next_heartbeat = jiffies + (heartbeat * HZ); |
150 | } | 148 | } |
151 | 149 | ||
152 | /** | 150 | /** |
153 | * sh_wdt_set_heartbeat - Set the Userspace Watchdog heartbeat | 151 | * sh_wdt_set_heartbeat - Set the Userspace Watchdog heartbeat |
154 | * | ||
155 | * Set the Userspace Watchdog heartbeat | 152 | * Set the Userspace Watchdog heartbeat |
156 | */ | 153 | */ |
157 | static int sh_wdt_set_heartbeat(int t) | 154 | static int sh_wdt_set_heartbeat(int t) |
158 | { | 155 | { |
159 | if ((t < 1) || (t > 3600)) /* arbitrary upper limit */ | 156 | if (unlikely((t < 1) || (t > 3600))) /* arbitrary upper limit */ |
160 | return -EINVAL; | 157 | return -EINVAL; |
161 | 158 | ||
162 | heartbeat = t; | 159 | heartbeat = t; |
@@ -165,7 +162,6 @@ static int sh_wdt_set_heartbeat(int t) | |||
165 | 162 | ||
166 | /** | 163 | /** |
167 | * sh_wdt_ping - Ping the Watchdog | 164 | * sh_wdt_ping - Ping the Watchdog |
168 | * | ||
169 | * @data: Unused | 165 | * @data: Unused |
170 | * | 166 | * |
171 | * Clears overflow bit, resets timer counter. | 167 | * Clears overflow bit, resets timer counter. |
@@ -182,14 +178,13 @@ static void sh_wdt_ping(unsigned long data) | |||
182 | sh_wdt_write_cnt(0); | 178 | sh_wdt_write_cnt(0); |
183 | 179 | ||
184 | mod_timer(&timer, next_ping_period(clock_division_ratio)); | 180 | mod_timer(&timer, next_ping_period(clock_division_ratio)); |
185 | } else { | 181 | } else |
186 | printk(KERN_WARNING PFX "Heartbeat lost! Will not ping the watchdog\n"); | 182 | printk(KERN_WARNING PFX "Heartbeat lost! Will not ping " |
187 | } | 183 | "the watchdog\n"); |
188 | } | 184 | } |
189 | 185 | ||
190 | /** | 186 | /** |
191 | * sh_wdt_open - Open the Device | 187 | * sh_wdt_open - Open the Device |
192 | * | ||
193 | * @inode: inode of device | 188 | * @inode: inode of device |
194 | * @file: file handle of device | 189 | * @file: file handle of device |
195 | * | 190 | * |
@@ -209,7 +204,6 @@ static int sh_wdt_open(struct inode *inode, struct file *file) | |||
209 | 204 | ||
210 | /** | 205 | /** |
211 | * sh_wdt_close - Close the Device | 206 | * sh_wdt_close - Close the Device |
212 | * | ||
213 | * @inode: inode of device | 207 | * @inode: inode of device |
214 | * @file: file handle of device | 208 | * @file: file handle of device |
215 | * | 209 | * |
@@ -220,7 +214,8 @@ static int sh_wdt_close(struct inode *inode, struct file *file) | |||
220 | if (shwdt_expect_close == 42) { | 214 | if (shwdt_expect_close == 42) { |
221 | sh_wdt_stop(); | 215 | sh_wdt_stop(); |
222 | } else { | 216 | } else { |
223 | printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n"); | 217 | printk(KERN_CRIT PFX "Unexpected close, not " |
218 | "stopping watchdog!\n"); | ||
224 | sh_wdt_keepalive(); | 219 | sh_wdt_keepalive(); |
225 | } | 220 | } |
226 | 221 | ||
@@ -232,7 +227,6 @@ static int sh_wdt_close(struct inode *inode, struct file *file) | |||
232 | 227 | ||
233 | /** | 228 | /** |
234 | * sh_wdt_write - Write to Device | 229 | * sh_wdt_write - Write to Device |
235 | * | ||
236 | * @file: file handle of device | 230 | * @file: file handle of device |
237 | * @buf: buffer to write | 231 | * @buf: buffer to write |
238 | * @count: length of buffer | 232 | * @count: length of buffer |
@@ -264,8 +258,56 @@ static ssize_t sh_wdt_write(struct file *file, const char *buf, | |||
264 | } | 258 | } |
265 | 259 | ||
266 | /** | 260 | /** |
267 | * sh_wdt_ioctl - Query Device | 261 | * sh_wdt_mmap - map WDT/CPG registers into userspace |
262 | * @file: file structure for the device | ||
263 | * @vma: VMA to map the registers into | ||
264 | * | ||
265 | * A simple mmap() implementation for the corner cases where the counter | ||
266 | * needs to be mapped in userspace directly. Due to the relatively small | ||
267 | * size of the area, neighbouring registers not necessarily tied to the | ||
268 | * CPG will also be accessible through the register page, so this remains | ||
269 | * configurable for users that really know what they're doing. | ||
268 | * | 270 | * |
271 | * Additionaly, the register page maps in the CPG register base relative | ||
272 | * to the nearest page-aligned boundary, which requires that userspace do | ||
273 | * the appropriate CPU subtype math for calculating the page offset for | ||
274 | * the counter value. | ||
275 | */ | ||
276 | static int sh_wdt_mmap(struct file *file, struct vm_area_struct *vma) | ||
277 | { | ||
278 | int ret = -ENOSYS; | ||
279 | |||
280 | #ifdef CONFIG_SH_WDT_MMAP | ||
281 | unsigned long addr; | ||
282 | |||
283 | /* Only support the simple cases where we map in a register page. */ | ||
284 | if (((vma->vm_end - vma->vm_start) != PAGE_SIZE) || vma->vm_pgoff) | ||
285 | return -EINVAL; | ||
286 | |||
287 | /* | ||
288 | * Pick WTCNT as the start, it's usually the first register after the | ||
289 | * FRQCR, and neither one are generally page-aligned out of the box. | ||
290 | */ | ||
291 | addr = WTCNT & ~(PAGE_SIZE - 1); | ||
292 | |||
293 | vma->vm_flags |= VM_IO; | ||
294 | vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); | ||
295 | |||
296 | if (io_remap_pfn_range(vma, vma->vm_start, addr >> PAGE_SHIFT, | ||
297 | PAGE_SIZE, vma->vm_page_prot)) { | ||
298 | printk(KERN_ERR PFX "%s: io_remap_pfn_range failed\n", | ||
299 | __FUNCTION__); | ||
300 | return -EAGAIN; | ||
301 | } | ||
302 | |||
303 | ret = 0; | ||
304 | #endif | ||
305 | |||
306 | return ret; | ||
307 | } | ||
308 | |||
309 | /** | ||
310 | * sh_wdt_ioctl - Query Device | ||
269 | * @inode: inode of device | 311 | * @inode: inode of device |
270 | * @file: file handle of device | 312 | * @file: file handle of device |
271 | * @cmd: watchdog command | 313 | * @cmd: watchdog command |
@@ -326,7 +368,6 @@ static int sh_wdt_ioctl(struct inode *inode, struct file *file, | |||
326 | 368 | ||
327 | /** | 369 | /** |
328 | * sh_wdt_notify_sys - Notifier Handler | 370 | * sh_wdt_notify_sys - Notifier Handler |
329 | * | ||
330 | * @this: notifier block | 371 | * @this: notifier block |
331 | * @code: notifier event | 372 | * @code: notifier event |
332 | * @unused: unused | 373 | * @unused: unused |
@@ -337,9 +378,8 @@ static int sh_wdt_ioctl(struct inode *inode, struct file *file, | |||
337 | static int sh_wdt_notify_sys(struct notifier_block *this, | 378 | static int sh_wdt_notify_sys(struct notifier_block *this, |
338 | unsigned long code, void *unused) | 379 | unsigned long code, void *unused) |
339 | { | 380 | { |
340 | if (code == SYS_DOWN || code == SYS_HALT) { | 381 | if (code == SYS_DOWN || code == SYS_HALT) |
341 | sh_wdt_stop(); | 382 | sh_wdt_stop(); |
342 | } | ||
343 | 383 | ||
344 | return NOTIFY_DONE; | 384 | return NOTIFY_DONE; |
345 | } | 385 | } |
@@ -351,10 +391,12 @@ static const struct file_operations sh_wdt_fops = { | |||
351 | .ioctl = sh_wdt_ioctl, | 391 | .ioctl = sh_wdt_ioctl, |
352 | .open = sh_wdt_open, | 392 | .open = sh_wdt_open, |
353 | .release = sh_wdt_close, | 393 | .release = sh_wdt_close, |
394 | .mmap = sh_wdt_mmap, | ||
354 | }; | 395 | }; |
355 | 396 | ||
356 | static struct watchdog_info sh_wdt_info = { | 397 | static struct watchdog_info sh_wdt_info = { |
357 | .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE, | 398 | .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | |
399 | WDIOF_MAGICCLOSE, | ||
358 | .firmware_version = 1, | 400 | .firmware_version = 1, |
359 | .identity = "SH WDT", | 401 | .identity = "SH WDT", |
360 | }; | 402 | }; |
@@ -371,7 +413,6 @@ static struct miscdevice sh_wdt_miscdev = { | |||
371 | 413 | ||
372 | /** | 414 | /** |
373 | * sh_wdt_init - Initialize module | 415 | * sh_wdt_init - Initialize module |
374 | * | ||
375 | * Registers the device and notifier handler. Actual device | 416 | * Registers the device and notifier handler. Actual device |
376 | * initialization is handled by sh_wdt_open(). | 417 | * initialization is handled by sh_wdt_open(). |
377 | */ | 418 | */ |
@@ -381,15 +422,15 @@ static int __init sh_wdt_init(void) | |||
381 | 422 | ||
382 | if ((clock_division_ratio < 0x5) || (clock_division_ratio > 0x7)) { | 423 | if ((clock_division_ratio < 0x5) || (clock_division_ratio > 0x7)) { |
383 | clock_division_ratio = WTCSR_CKS_4096; | 424 | clock_division_ratio = WTCSR_CKS_4096; |
384 | printk(KERN_INFO PFX "clock_division_ratio value must be 0x5<=x<=0x7, using %d\n", | 425 | printk(KERN_INFO PFX "clock_division_ratio value must " |
385 | clock_division_ratio); | 426 | "be 0x5<=x<=0x7, using %d\n", clock_division_ratio); |
386 | } | 427 | } |
387 | 428 | ||
388 | if (sh_wdt_set_heartbeat(heartbeat)) | 429 | rc = sh_wdt_set_heartbeat(heartbeat); |
389 | { | 430 | if (unlikely(rc)) { |
390 | heartbeat = WATCHDOG_HEARTBEAT; | 431 | heartbeat = WATCHDOG_HEARTBEAT; |
391 | printk(KERN_INFO PFX "heartbeat value must be 1<=x<=3600, using %d\n", | 432 | printk(KERN_INFO PFX "heartbeat value must " |
392 | heartbeat); | 433 | "be 1<=x<=3600, using %d\n", heartbeat); |
393 | } | 434 | } |
394 | 435 | ||
395 | init_timer(&timer); | 436 | init_timer(&timer); |
@@ -397,15 +438,16 @@ static int __init sh_wdt_init(void) | |||
397 | timer.data = 0; | 438 | timer.data = 0; |
398 | 439 | ||
399 | rc = register_reboot_notifier(&sh_wdt_notifier); | 440 | rc = register_reboot_notifier(&sh_wdt_notifier); |
400 | if (rc) { | 441 | if (unlikely(rc)) { |
401 | printk(KERN_ERR PFX "Can't register reboot notifier (err=%d)\n", rc); | 442 | printk(KERN_ERR PFX "Can't register reboot notifier (err=%d)\n", |
443 | rc); | ||
402 | return rc; | 444 | return rc; |
403 | } | 445 | } |
404 | 446 | ||
405 | rc = misc_register(&sh_wdt_miscdev); | 447 | rc = misc_register(&sh_wdt_miscdev); |
406 | if (rc) { | 448 | if (unlikely(rc)) { |
407 | printk(KERN_ERR PFX "Can't register miscdev on minor=%d (err=%d)\n", | 449 | printk(KERN_ERR PFX "Can't register miscdev on " |
408 | sh_wdt_miscdev.minor, rc); | 450 | "minor=%d (err=%d)\n", sh_wdt_miscdev.minor, rc); |
409 | unregister_reboot_notifier(&sh_wdt_notifier); | 451 | unregister_reboot_notifier(&sh_wdt_notifier); |
410 | return rc; | 452 | return rc; |
411 | } | 453 | } |
@@ -418,7 +460,6 @@ static int __init sh_wdt_init(void) | |||
418 | 460 | ||
419 | /** | 461 | /** |
420 | * sh_wdt_exit - Deinitialize module | 462 | * sh_wdt_exit - Deinitialize module |
421 | * | ||
422 | * Unregisters the device and notifier handler. Actual device | 463 | * Unregisters the device and notifier handler. Actual device |
423 | * deinitialization is handled by sh_wdt_close(). | 464 | * deinitialization is handled by sh_wdt_close(). |
424 | */ | 465 | */ |
@@ -434,14 +475,13 @@ MODULE_LICENSE("GPL"); | |||
434 | MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); | 475 | MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); |
435 | 476 | ||
436 | module_param(clock_division_ratio, int, 0); | 477 | module_param(clock_division_ratio, int, 0); |
437 | MODULE_PARM_DESC(clock_division_ratio, "Clock division ratio. Valid ranges are from 0x5 (1.31ms) to 0x7 (5.25ms). Defaults to 0x7."); | 478 | MODULE_PARM_DESC(clock_division_ratio, "Clock division ratio. Valid ranges are from 0x5 (1.31ms) to 0x7 (5.25ms). (default=" __MODULE_STRING(clock_division_ratio) ")"); |
438 | 479 | ||
439 | module_param(heartbeat, int, 0); | 480 | module_param(heartbeat, int, 0); |
440 | MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (1<=heartbeat<=3600, default=" __MODULE_STRING(WATCHDOG_HEARTBEAT) ")"); | 481 | MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (1<=heartbeat<=3600, default=" __MODULE_STRING(WATCHDOG_HEARTBEAT) ")"); |
441 | 482 | ||
442 | module_param(nowayout, int, 0); | 483 | module_param(nowayout, int, 0); |
443 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); | 484 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); |
444 | 485 | ||
445 | module_init(sh_wdt_init); | 486 | module_init(sh_wdt_init); |
446 | module_exit(sh_wdt_exit); | 487 | module_exit(sh_wdt_exit); |
447 | |||