diff options
Diffstat (limited to 'drivers/char')
109 files changed, 3298 insertions, 2681 deletions
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index d0c978fbc20..abcafac6473 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -6,6 +6,7 @@ menu "Character devices" config VT bool "Virtual terminal" if EMBEDDED + depends on !S390 select INPUT default y if !VIOCONS ---help--- @@ -81,6 +82,7 @@ config VT_HW_CONSOLE_BINDING config SERIAL_NONSTANDARD bool "Non-standard serial port support" + depends on HAS_IOMEM ---help--- Say Y here if you have any non-standard serial boards -- boards which aren't supported using the standard "dumb" serial driver. @@ -127,7 +129,7 @@ config ROCKETPORT config CYCLADES tristate "Cyclades async mux support" - depends on SERIAL_NONSTANDARD + depends on SERIAL_NONSTANDARD && (PCI || ISA) ---help--- This driver supports Cyclades Z and Y multiserial boards. You would need something like this to connect more than two modems to @@ -631,7 +633,8 @@ config HVC_CONSOLE config HVC_ISERIES bool "iSeries Hypervisor Virtual Console support" - depends on PPC_ISERIES && !VIOCONS + depends on PPC_ISERIES + default y select HVC_DRIVER help iSeries machines support a hypervisor virtual console. @@ -764,7 +767,7 @@ config NVRAM config RTC tristate "Enhanced Real Time Clock Support" - depends on !PPC && !PARISC && !IA64 && !M68K && (!SPARC || PCI) && !FRV && !ARM && !SUPERH + depends on !PPC && !PARISC && !IA64 && !M68K && (!SPARC || PCI) && !FRV && !ARM && !SUPERH && !S390 ---help--- If you say Y here and create a character special file /dev/rtc with major number 10 and minor number 135 using mknod ("man mknod"), you @@ -812,7 +815,7 @@ config SGI_IP27_RTC config GEN_RTC tristate "Generic /dev/rtc emulation" - depends on RTC!=y && !IA64 && !ARM && !M32R && !SPARC && !FRV + depends on RTC!=y && !IA64 && !ARM && !M32R && !SPARC && !FRV && !S390 ---help--- If you say Y here and create a character special file /dev/rtc with major number 10 and minor number 135 using mknod ("man mknod"), you @@ -857,6 +860,7 @@ config COBALT_LCD config DTLK tristate "Double Talk PC internal speech card support" + depends on ISA help This driver is for the DoubleTalk PC, a speech synthesizer manufactured by RC Systems (<http://www.rcsys.com/>). It is also @@ -905,8 +909,8 @@ config SONYPI To compile this driver as a module, choose M here: the module will be called sonypi. -config TANBAC_TB0219 - tristate "TANBAC TB0219 base board support" +config GPIO_TB0219 + tristate "TANBAC TB0219 GPIO support" depends on TANBAC_TB022X select GPIO_VR41XX @@ -1042,7 +1046,7 @@ config HPET_MMAP config HANGCHECK_TIMER tristate "Hangcheck timer" - depends on X86 || IA64 || PPC64 + depends on X86 || IA64 || PPC64 || S390 help The hangcheck-timer module detects when the system has gone out to lunch past a certain margin. It can reboot the system @@ -1071,5 +1075,13 @@ config TELCLOCK /sys/devices/platform/telco_clock, with a number of files for controlling the behavior of this hardware. +config DEVPORT + bool + depends on !M68K + depends on ISA || PCI + default y + +source "drivers/s390/char/Kconfig" + endmenu diff --git a/drivers/char/Makefile b/drivers/char/Makefile index ae8567cc529..2f56ecc035a 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -91,7 +91,7 @@ obj-$(CONFIG_PC8736x_GPIO) += pc8736x_gpio.o obj-$(CONFIG_NSC_GPIO) += nsc_gpio.o obj-$(CONFIG_CS5535_GPIO) += cs5535_gpio.o obj-$(CONFIG_GPIO_VR41XX) += vr41xx_giu.o -obj-$(CONFIG_TANBAC_TB0219) += tb0219.o +obj-$(CONFIG_GPIO_TB0219) += tb0219.o obj-$(CONFIG_TELCLOCK) += tlclk.o obj-$(CONFIG_WATCHDOG) += watchdog/ diff --git a/drivers/char/agp/ali-agp.c b/drivers/char/agp/ali-agp.c index 5b684fddcc0..4941ddb7893 100644 --- a/drivers/char/agp/ali-agp.c +++ b/drivers/char/agp/ali-agp.c @@ -145,6 +145,7 @@ static void *m1541_alloc_page(struct agp_bridge_data *bridge) void *addr = agp_generic_alloc_page(agp_bridge); u32 temp; + global_flush_tlb(); if (!addr) return NULL; @@ -160,6 +161,7 @@ static void ali_destroy_page(void * addr) if (addr) { global_cache_flush(); /* is this really needed? --hch */ agp_generic_destroy_page(addr); + global_flush_tlb(); } } diff --git a/drivers/char/agp/alpha-agp.c b/drivers/char/agp/alpha-agp.c index b0acf41c0db..aa8f3a39a70 100644 --- a/drivers/char/agp/alpha-agp.c +++ b/drivers/char/agp/alpha-agp.c @@ -173,7 +173,7 @@ alpha_core_agp_setup(void) /* * Build a fake pci_dev struct */ - pdev = kmalloc(sizeof(struct pci_dev), GFP_KERNEL); + pdev = alloc_pci_dev(); if (!pdev) return -ENOMEM; pdev->vendor = 0xffff; diff --git a/drivers/char/agp/amd64-agp.c b/drivers/char/agp/amd64-agp.c index 485720486d6..c9f0f250d78 100644 --- a/drivers/char/agp/amd64-agp.c +++ b/drivers/char/agp/amd64-agp.c @@ -14,6 +14,7 @@ #include <linux/agp_backend.h> #include <linux/mmzone.h> #include <asm/page.h> /* PAGE_SIZE */ +#include <asm/e820.h> #include <asm/k8.h> #include "agp.h" @@ -259,7 +260,6 @@ static const struct agp_bridge_driver amd_8151_driver = { /* Some basic sanity checks for the aperture. */ static int __devinit aperture_valid(u64 aper, u32 size) { - u32 pfn, c; if (aper == 0) { printk(KERN_ERR PFX "No aperture\n"); return 0; @@ -272,14 +272,9 @@ static int __devinit aperture_valid(u64 aper, u32 size) printk(KERN_ERR PFX "Aperture out of bounds\n"); return 0; } - pfn = aper >> PAGE_SHIFT; - for (c = 0; c < size/PAGE_SIZE; c++) { - if (!pfn_valid(pfn + c)) - break; - if (!PageReserved(pfn_to_page(pfn + c))) { - printk(KERN_ERR PFX "Aperture pointing to RAM\n"); - return 0; - } + if (e820_any_mapped(aper, aper + size, E820_RAM)) { + printk(KERN_ERR PFX "Aperture pointing to RAM\n"); + return 0; } /* Request the Aperture. This catches cases when someone else diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c index f902d71947b..45aeb917ec6 100644 --- a/drivers/char/agp/generic.c +++ b/drivers/char/agp/generic.c @@ -51,28 +51,6 @@ int agp_memory_reserved; */ EXPORT_SYMBOL_GPL(agp_memory_reserved); -#if defined(CONFIG_X86) -int map_page_into_agp(struct page *page) -{ - int i; - i = change_page_attr(page, 1, PAGE_KERNEL_NOCACHE); - /* Caller's responsibility to call global_flush_tlb() for - * performance reasons */ - return i; -} -EXPORT_SYMBOL_GPL(map_page_into_agp); - -int unmap_page_from_agp(struct page *page) -{ - int i; - i = change_page_attr(page, 1, PAGE_KERNEL); - /* Caller's responsibility to call global_flush_tlb() for - * performance reasons */ - return i; -} -EXPORT_SYMBOL_GPL(unmap_page_from_agp); -#endif - /* * Generic routines for handling agp_memory structures - * They use the basic page allocation routines to do the brunt of the work. diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c index 55392a45a14..9c69f2e761f 100644 --- a/drivers/char/agp/intel-agp.c +++ b/drivers/char/agp/intel-agp.c @@ -186,8 +186,9 @@ static void *i8xx_alloc_pages(void) return NULL; if (change_page_attr(page, 4, PAGE_KERNEL_NOCACHE) < 0) { + change_page_attr(page, 4, PAGE_KERNEL); global_flush_tlb(); - __free_page(page); + __free_pages(page, 2); return NULL; } global_flush_tlb(); @@ -209,7 +210,7 @@ static void i8xx_destroy_pages(void *addr) global_flush_tlb(); put_page(page); unlock_page(page); - free_pages((unsigned long)addr, 2); + __free_pages(page, 2); atomic_dec(&agp_bridge->current_memory_agp); } @@ -315,9 +316,6 @@ static struct agp_memory *alloc_agpphysmem_i8xx(size_t pg_count, int type) struct agp_memory *new; void *addr; - if (pg_count != 1 && pg_count != 4) - return NULL; - switch (pg_count) { case 1: addr = agp_bridge->driver->agp_alloc_page(agp_bridge); global_flush_tlb(); diff --git a/drivers/char/agp/nvidia-agp.c b/drivers/char/agp/nvidia-agp.c index 0c9dab557c9..6cd7373dcdf 100644 --- a/drivers/char/agp/nvidia-agp.c +++ b/drivers/char/agp/nvidia-agp.c @@ -320,11 +320,11 @@ static int __devinit agp_nvidia_probe(struct pci_dev *pdev, u8 cap_ptr; nvidia_private.dev_1 = - pci_find_slot((unsigned int)pdev->bus->number, PCI_DEVFN(0, 1)); + pci_get_bus_and_slot((unsigned int)pdev->bus->number, PCI_DEVFN(0, 1)); nvidia_private.dev_2 = - pci_find_slot((unsigned int)pdev->bus->number, PCI_DEVFN(0, 2)); + pci_get_bus_and_slot((unsigned int)pdev->bus->number, PCI_DEVFN(0, 2)); nvidia_private.dev_3 = - pci_find_slot((unsigned int)pdev->bus->number, PCI_DEVFN(30, 0)); + pci_get_bus_and_slot((unsigned int)pdev->bus->number, PCI_DEVFN(30, 0)); if (!nvidia_private.dev_1 || !nvidia_private.dev_2 || !nvidia_private.dev_3) { printk(KERN_INFO PFX "Detected an NVIDIA nForce/nForce2 " @@ -443,6 +443,9 @@ static int __init agp_nvidia_init(void) static void __exit agp_nvidia_cleanup(void) { pci_unregister_driver(&agp_nvidia_pci_driver); + pci_dev_put(nvidia_private.dev_1); + pci_dev_put(nvidia_private.dev_2); + pci_dev_put(nvidia_private.dev_3); } module_init(agp_nvidia_init); diff --git a/drivers/char/agp/parisc-agp.c b/drivers/char/agp/parisc-agp.c index 3d83b461cca..f4562cc2234 100644 --- a/drivers/char/agp/parisc-agp.c +++ b/drivers/char/agp/parisc-agp.c @@ -329,7 +329,7 @@ parisc_agp_setup(void __iomem *ioc_hpa, void __iomem *lba_hpa) struct agp_bridge_data *bridge; int error = 0; - fake_bridge_dev = kmalloc(sizeof (struct pci_dev), GFP_KERNEL); + fake_bridge_dev = alloc_pci_dev(); if (!fake_bridge_dev) { error = -ENOMEM; goto fail; diff --git a/drivers/char/agp/sgi-agp.c b/drivers/char/agp/sgi-agp.c index ee8f50edde1..cda608c42be 100644 --- a/drivers/char/agp/sgi-agp.c +++ b/drivers/char/agp/sgi-agp.c @@ -47,9 +47,8 @@ static void *sgi_tioca_alloc_page(struct agp_bridge_data *bridge) nid = info->ca_closest_node; page = alloc_pages_node(nid, GFP_KERNEL, 0); - if (page == NULL) { - return 0; - } + if (!page) + return NULL; get_page(page); SetPageLocked(page); diff --git a/drivers/char/agp/sis-agp.c b/drivers/char/agp/sis-agp.c index 125f4282d95..eb1a1c73819 100644 --- a/drivers/char/agp/sis-agp.c +++ b/drivers/char/agp/sis-agp.c @@ -143,96 +143,6 @@ static struct agp_bridge_driver sis_driver = { .agp_type_to_mask_type = agp_generic_type_to_mask_type, }; -static struct agp_device_ids sis_agp_device_ids[] __devinitdata = -{ - { - .device_id = PCI_DEVICE_ID_SI_5591_AGP, - .chipset_name = "5591", - }, - { - .device_id = PCI_DEVICE_ID_SI_530, - .chipset_name = "530", - }, - { - .device_id = PCI_DEVICE_ID_SI_540, - .chipset_name = "540", - }, - { - .device_id = PCI_DEVICE_ID_SI_550, - .chipset_name = "550", - }, - { - .device_id = PCI_DEVICE_ID_SI_620, - .chipset_name = "620", - }, - { - .device_id = PCI_DEVICE_ID_SI_630, - .chipset_name = "630", - }, - { - .device_id = PCI_DEVICE_ID_SI_635, - .chipset_name = "635", - }, - { - .device_id = PCI_DEVICE_ID_SI_645, - .chipset_name = "645", - }, - { - .device_id = PCI_DEVICE_ID_SI_646, - .chipset_name = "646", - }, - { - .device_id = PCI_DEVICE_ID_SI_648, - .chipset_name = "648", - }, - { - .device_id = PCI_DEVICE_ID_SI_650, - .chipset_name = "650", - }, - { - .device_id = PCI_DEVICE_ID_SI_651, - .chipset_name = "651", - }, - { - .device_id = PCI_DEVICE_ID_SI_655, - .chipset_name = "655", - }, - { - .device_id = PCI_DEVICE_ID_SI_661, - .chipset_name = "661", - }, - { - .device_id = PCI_DEVICE_ID_SI_730, - .chipset_name = "730", - }, - { - .device_id = PCI_DEVICE_ID_SI_735, - .chipset_name = "735", - }, - { - .device_id = PCI_DEVICE_ID_SI_740, - .chipset_name = "740", - }, - { - .device_id = PCI_DEVICE_ID_SI_741, - .chipset_name = "741", - }, - { - .device_id = PCI_DEVICE_ID_SI_745, - .chipset_name = "745", - }, - { - .device_id = PCI_DEVICE_ID_SI_746, - .chipset_name = "746", - }, - { - .device_id = PCI_DEVICE_ID_SI_760, - .chipset_name = "760", - }, - { }, /* dummy final entry, always present */ -}; - - // chipsets that require the 'delay hack' static int sis_broken_chipsets[] __devinitdata = { PCI_DEVICE_ID_SI_648, @@ -269,29 +179,15 @@ static void __devinit sis_get_driver(struct agp_bridge_data *bridge) static int __devinit agp_sis_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { - struct agp_device_ids *devs = sis_agp_device_ids; struct agp_bridge_data *bridge; u8 cap_ptr; - int j; cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP); if (!cap_ptr) return -ENODEV; - /* probe for known chipsets */ - for (j = 0; devs[j].chipset_name; j++) { - if (pdev->device == devs[j].device_id) { - printk(KERN_INFO PFX "Detected SiS %s chipset\n", - devs[j].chipset_name); - goto found; - } - } - - printk(KERN_ERR PFX "Unsupported SiS chipset (device id: %04x)\n", - pdev->device); - return -ENODEV; -found: + printk(KERN_INFO PFX "Detected SiS chipset - id:%i\n", pdev->device); bridge = agp_alloc_bridge(); if (!bridge) return -ENOMEM; @@ -320,12 +216,172 @@ static void __devexit agp_sis_remove(struct pci_dev *pdev) static struct pci_device_id agp_sis_pci_table[] = { { - .class = (PCI_CLASS_BRIDGE_HOST << 8), - .class_mask = ~0, - .vendor = PCI_VENDOR_ID_SI, - .device = PCI_ANY_ID, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, + .class = (PCI_CLASS_BRIDGE_HOST << 8), + .class_mask = ~0, + .vendor = PCI_VENDOR_ID_SI, + .device = PCI_DEVICE_ID_SI_5591_AGP, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + { + .class = (PCI_CLASS_BRIDGE_HOST << 8), + .class_mask = ~0, + .vendor = PCI_VENDOR_ID_SI, + .device = PCI_DEVICE_ID_SI_530, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + { + .class = (PCI_CLASS_BRIDGE_HOST << 8), + .class_mask = ~0, + .vendor = PCI_VENDOR_ID_SI, + .device = PCI_DEVICE_ID_SI_540, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + { + .class = (PCI_CLASS_BRIDGE_HOST << 8), + .class_mask = ~0, + .vendor = PCI_VENDOR_ID_SI, + .device = PCI_DEVICE_ID_SI_550, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + { + .class = (PCI_CLASS_BRIDGE_HOST << 8), + .class_mask = ~0, + .vendor = PCI_VENDOR_ID_SI, + .device = PCI_DEVICE_ID_SI_620, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + { + .class = (PCI_CLASS_BRIDGE_HOST << 8), + .class_mask = ~0, + .vendor = PCI_VENDOR_ID_SI, + .device = PCI_DEVICE_ID_SI_630, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + { + .class = (PCI_CLASS_BRIDGE_HOST << 8), + .class_mask = ~0, + .vendor = PCI_VENDOR_ID_SI, + .device = PCI_DEVICE_ID_SI_635, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + { + .class = (PCI_CLASS_BRIDGE_HOST << 8), + .class_mask = ~0, + .vendor = PCI_VENDOR_ID_SI, + .device = PCI_DEVICE_ID_SI_645, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + { + .class = (PCI_CLASS_BRIDGE_HOST << 8), + .class_mask = ~0, + .vendor = PCI_VENDOR_ID_SI, + .device = PCI_DEVICE_ID_SI_646, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + { + .class = (PCI_CLASS_BRIDGE_HOST << 8), + .class_mask = ~0, + .vendor = PCI_VENDOR_ID_SI, + .device = PCI_DEVICE_ID_SI_648, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + { + .class = (PCI_CLASS_BRIDGE_HOST << 8), + .class_mask = ~0, + .vendor = PCI_VENDOR_ID_SI, + .device = PCI_DEVICE_ID_SI_650, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + { + .class = (PCI_CLASS_BRIDGE_HOST << 8), + .class_mask = ~0, + .vendor = PCI_VENDOR_ID_SI, + .device = PCI_DEVICE_ID_SI_651, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + { + .class = (PCI_CLASS_BRIDGE_HOST << 8), + .class_mask = ~0, + .vendor = PCI_VENDOR_ID_SI, + .device = PCI_DEVICE_ID_SI_655, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + { + .class = (PCI_CLASS_BRIDGE_HOST << 8), + .class_mask = ~0, + .vendor = PCI_VENDOR_ID_SI, + .device = PCI_DEVICE_ID_SI_661, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + { + .class = (PCI_CLASS_BRIDGE_HOST << 8), + .class_mask = ~0, + .vendor = PCI_VENDOR_ID_SI, + .device = PCI_DEVICE_ID_SI_730, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + { + .class = (PCI_CLASS_BRIDGE_HOST << 8), + .class_mask = ~0, + .vendor = PCI_VENDOR_ID_SI, + .device = PCI_DEVICE_ID_SI_735, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + { + .class = (PCI_CLASS_BRIDGE_HOST << 8), + .class_mask = ~0, + .vendor = PCI_VENDOR_ID_SI, + .device = PCI_DEVICE_ID_SI_740, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + { + .class = (PCI_CLASS_BRIDGE_HOST << 8), + .class_mask = ~0, + .vendor = PCI_VENDOR_ID_SI, + .device = PCI_DEVICE_ID_SI_741, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + { + .class = (PCI_CLASS_BRIDGE_HOST << 8), + .class_mask = ~0, + .vendor = PCI_VENDOR_ID_SI, + .device = PCI_DEVICE_ID_SI_745, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + { + .class = (PCI_CLASS_BRIDGE_HOST << 8), + .class_mask = ~0, + .vendor = PCI_VENDOR_ID_SI, + .device = PCI_DEVICE_ID_SI_746, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + { + .class = (PCI_CLASS_BRIDGE_HOST << 8), + .class_mask = ~0, + .vendor = PCI_VENDOR_ID_SI, + .device = PCI_DEVICE_ID_SI_760, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, }, { } }; diff --git a/drivers/char/agp/sworks-agp.c b/drivers/char/agp/sworks-agp.c index 55212a3811f..551ef25063e 100644 --- a/drivers/char/agp/sworks-agp.c +++ b/drivers/char/agp/sworks-agp.c @@ -455,15 +455,6 @@ static int __devinit agp_serverworks_probe(struct pci_dev *pdev, u32 temp, temp2; u8 cap_ptr = 0; - /* Everything is on func 1 here so we are hardcoding function one */ - bridge_dev = pci_find_slot((unsigned int)pdev->bus->number, - PCI_DEVFN(0, 1)); - if (!bridge_dev) { - printk(KERN_INFO PFX "Detected a Serverworks chipset " - "but could not find the secondary device.\n"); - return -ENODEV; - } - cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP); switch (pdev->device) { @@ -483,6 +474,15 @@ static int __devinit agp_serverworks_probe(struct pci_dev *pdev, return -ENODEV; } + /* Everything is on func 1 here so we are hardcoding function one */ + bridge_dev = pci_get_bus_and_slot((unsigned int)pdev->bus->number, + PCI_DEVFN(0, 1)); + if (!bridge_dev) { + printk(KERN_INFO PFX "Detected a Serverworks chipset " + "but could not find the secondary device.\n"); + return -ENODEV; + } + serverworks_private.svrwrks_dev = bridge_dev; serverworks_private.gart_addr_ofs = 0x10; @@ -515,7 +515,7 @@ static int __devinit agp_serverworks_probe(struct pci_dev *pdev, bridge->driver = &sworks_driver; bridge->dev_private_data = &serverworks_private, - bridge->dev = pdev; + bridge->dev = pci_dev_get(pdev); pci_set_drvdata(pdev, bridge); return agp_add_bridge(bridge); @@ -525,8 +525,11 @@ static void __devexit agp_serverworks_remove(struct pci_dev *pdev) { struct agp_bridge_data *bridge = pci_get_drvdata(pdev); + pci_dev_put(bridge->dev); agp_remove_bridge(bridge); agp_put_bridge(bridge); + pci_dev_put(serverworks_private.svrwrks_dev); + serverworks_private.svrwrks_dev = NULL; } static struct pci_device_id agp_serverworks_pci_table[] = { diff --git a/drivers/char/agp/uninorth-agp.c b/drivers/char/agp/uninorth-agp.c index 91b062126a6..42c0a600b1a 100644 --- a/drivers/char/agp/uninorth-agp.c +++ b/drivers/char/agp/uninorth-agp.c @@ -613,7 +613,7 @@ static int __devinit agp_uninorth_probe(struct pci_dev *pdev, uninorth_node = of_find_node_by_name(NULL, "u3"); } if (uninorth_node) { - const int *revprop = get_property(uninorth_node, + const int *revprop = of_get_property(uninorth_node, "device-rev", NULL); if (revprop != NULL) uninorth_rev = *revprop & 0x3f; diff --git a/drivers/char/amiserial.c b/drivers/char/amiserial.c index 0e2b72f2b88..4eaceabd8ce 100644 --- a/drivers/char/amiserial.c +++ b/drivers/char/amiserial.c @@ -1574,7 +1574,7 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout) if (timeout && time_after(jiffies, orig_jiffies + timeout)) break; } - current->state = TASK_RUNNING; + __set_current_state(TASK_RUNNING); #ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies); #endif @@ -1700,7 +1700,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, #endif schedule(); } - current->state = TASK_RUNNING; + __set_current_state(TASK_RUNNING); remove_wait_queue(&info->open_wait, &wait); if (extra_count) state->count++; diff --git a/drivers/char/briq_panel.c b/drivers/char/briq_panel.c index c70d52ace8b..ed53f541d9e 100644 --- a/drivers/char/briq_panel.c +++ b/drivers/char/briq_panel.c @@ -206,7 +206,7 @@ static int __init briq_panel_init(void) const char *machine; int i; - machine = get_property(root, "model", NULL); + machine = of_get_property(root, "model", NULL); if (!machine || strncmp(machine, "TotalImpact,BRIQ-1", 18) != 0) { of_node_put(root); return -ENODEV; diff --git a/drivers/char/consolemap.c b/drivers/char/consolemap.c index b99b7561260..fd40b959afd 100644 --- a/drivers/char/consolemap.c +++ b/drivers/char/consolemap.c @@ -626,10 +626,10 @@ conv_uni_to_pc(struct vc_data *conp, long ucs) /* Only 16-bit codes supported at this time */ if (ucs > 0xffff) - ucs = 0xfffd; /* U+FFFD: REPLACEMENT CHARACTER */ - else if (ucs < 0x20 || ucs >= 0xfffe) + return -4; /* Not found */ + else if (ucs < 0x20) return -1; /* Not a printable character */ - else if (ucs == 0xfeff || (ucs >= 0x200a && ucs <= 0x200f)) + else if (ucs == 0xfeff || (ucs >= 0x200b && ucs <= 0x200f)) return -2; /* Zero-width space */ /* * UNI_DIRECT_BASE indicates the start of the region in the User Zone diff --git a/drivers/char/cs5535_gpio.c b/drivers/char/cs5535_gpio.c index c02d9e99e05..fe6d2407bae 100644 --- a/drivers/char/cs5535_gpio.c +++ b/drivers/char/cs5535_gpio.c @@ -44,6 +44,7 @@ static struct pci_device_id divil_pci[] = { { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA) }, { } /* NULL entry */ }; +MODULE_DEVICE_TABLE(pci, divil_pci); static struct cdev cs5535_gpio_cdev; diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c index 16dc5d1d3cb..c72ee97d389 100644 --- a/drivers/char/cyclades.c +++ b/drivers/char/cyclades.c @@ -10,15 +10,14 @@ * * Initially written by Randolph Bentson <bentson@grieg.seaslug.org>. * Modified and maintained by Marcio Saito <marcio@cyclades.com>. - * Currently maintained by Cyclades team <async@cyclades.com>. * - * For Technical support and installation problems, please send e-mail - * to support@cyclades.com. + * Copyright (C) 2007 Jiri Slaby <jirislaby@gmail.com> * * Much of the design and some of the code came from serial.c * which was copyright (C) 1991, 1992 Linus Torvalds. It was * extensively rewritten by Theodore Ts'o, 8/16/92 -- 9/14/92, * and then fixed as suggested by Michael K. Johnson 12/12/92. + * Converted to pci probing and cleaned up by Jiri Slaby. * * This version supports shared IRQ's (only for PCI boards). * @@ -591,7 +590,7 @@ * */ -#define CY_VERSION "2.4" +#define CY_VERSION "2.5" /* If you need to install more boards than NR_CARDS, change the constant in the definition below. No other change is necessary to support up to @@ -624,12 +623,6 @@ #undef CY_ENABLE_MONITORING #undef CY_PCI_DEBUG -#if 0 -#define PAUSE __asm__("nop") -#else -#define PAUSE do {} while (0) -#endif - /* * Include section */ @@ -659,17 +652,6 @@ #include <asm/irq.h> #include <asm/uaccess.h> -#define CY_LOCK(info,flags) \ - do { \ - spin_lock_irqsave(&cy_card[info->card].card_lock, flags); \ - } while (0) - -#define CY_UNLOCK(info,flags) \ - do { \ - spin_unlock_irqrestore(&cy_card[info->card].card_lock, flags); \ - } while (0) - -#include <linux/types.h> #include <linux/kernel.h> #include <linux/pci.h> @@ -682,13 +664,13 @@ static void cy_send_xchar(struct tty_struct *tty, char ch); #define IS_CYC_Z(card) ((card).num_chips == -1) #define Z_FPGA_CHECK(card) \ - ((cy_readl(&((struct RUNTIME_9060 __iomem *) \ + ((readl(&((struct RUNTIME_9060 __iomem *) \ ((card).ctl_addr))->init_ctrl) & (1<<17)) != 0) -#define ISZLOADED(card) (((ZO_V1==cy_readl(&((struct RUNTIME_9060 __iomem *) \ +#define ISZLOADED(card) (((ZO_V1==readl(&((struct RUNTIME_9060 __iomem *) \ ((card).ctl_addr))->mail_box_0)) || \ Z_FPGA_CHECK(card)) && \ - (ZFIRM_ID==cy_readl(&((struct FIRM_ID __iomem *) \ + (ZFIRM_ID==readl(&((struct FIRM_ID __iomem *) \ ((card).base_addr+ID_ADDRESS))->signature))) #ifndef SERIAL_XMIT_SIZE @@ -725,8 +707,8 @@ static unsigned int cy_isa_addresses[] = { #define NR_ISA_ADDRS ARRAY_SIZE(cy_isa_addresses) #ifdef MODULE -static long maddr[NR_CARDS] = { 0, }; -static int irq[NR_CARDS] = { 0, }; +static long maddr[NR_CARDS]; +static int irq[NR_CARDS]; module_param_array(maddr, long, NULL, 0); module_param_array(irq, int, NULL, 0); @@ -739,11 +721,6 @@ module_param_array(irq, int, NULL, 0); */ static struct cyclades_card cy_card[NR_CARDS]; -/* This is the per-channel data structure containing pointers, flags - and variables for the port. This driver supports a maximum of NR_PORTS. -*/ -static struct cyclades_port cy_port[NR_PORTS]; - static int cy_next_channel; /* next minor available */ /* @@ -825,9 +802,6 @@ static int cy_chip_offset[] = { 0x0000, /* PCI related definitions */ -static unsigned short cy_pci_nboard; -static unsigned short cy_isa_nboard; -static unsigned short cy_nboard; #ifdef CONFIG_PCI static struct pci_device_id cy_pci_dev_id[] __devinitdata = { { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Y_Lo) }, /* PCI < 1Mb */ @@ -845,7 +819,7 @@ MODULE_DEVICE_TABLE(pci, cy_pci_dev_id); static void cy_start(struct tty_struct *); static void set_line_char(struct cyclades_port *); -static int cyz_issue_cmd(struct cyclades_card *, uclong, ucchar, uclong); +static int cyz_issue_cmd(struct cyclades_card *, __u32, __u8, __u32); #ifdef CONFIG_ISA static unsigned detect_isa_irq(void __iomem *); #endif /* CONFIG_ISA */ @@ -858,7 +832,6 @@ static void cyz_poll(unsigned long); /* The Cyclades-Z polling cycle is defined by this variable */ static long cyz_polling_cycle = CZ_DEF_POLL; -static int cyz_timeron = 0; static DEFINE_TIMER(cyz_timerlist, cyz_poll, 0, 0); #else /* CONFIG_CYZ_INTR */ @@ -871,21 +844,14 @@ static inline int serial_paranoia_check(struct cyclades_port *info, { #ifdef SERIAL_PARANOIA_CHECK if (!info) { - printk("cyc Warning: null cyclades_port for (%s) in %s\n", - name, routine); - return 1; - } - - if ((long)info < (long)(&cy_port[0]) || - (long)(&cy_port[NR_PORTS]) < (long)info) { - printk("cyc Warning: cyclades_port out of range for (%s) in " - "%s\n", name, routine); + printk(KERN_WARNING "cyc Warning: null cyclades_port for (%s) " + "in %s\n", name, routine); return 1; } if (info->magic != CYCLADES_MAGIC) { - printk("cyc Warning: bad magic number for serial struct (%s) " - "in %s\n", name, routine); + printk(KERN_WARNING "cyc Warning: bad magic number for serial " + "struct (%s) in %s\n", name, routine); return 1; } #endif @@ -943,22 +909,16 @@ do_softint(struct work_struct *work) if (test_and_clear_bit(Cy_EVENT_OPEN_WAKEUP, &info->event)) wake_up_interruptible(&info->open_wait); #ifdef CONFIG_CYZ_INTR - if (test_and_clear_bit(Cy_EVENT_Z_RX_FULL, &info->event)) { - if (cyz_rx_full_timer[info->line].function == NULL) { - cyz_rx_full_timer[info->line].expires = jiffies + 1; - cyz_rx_full_timer[info->line].function = cyz_rx_restart; - cyz_rx_full_timer[info->line].data = - (unsigned long)info; - add_timer(&cyz_rx_full_timer[info->line]); - } - } + if (test_and_clear_bit(Cy_EVENT_Z_RX_FULL, &info->event) && + !timer_pending(&cyz_rx_full_timer[info->line])) + mod_timer(&cyz_rx_full_timer[info->line], jiffies + 1); #endif if (test_and_clear_bit(Cy_EVENT_DELTA_WAKEUP, &info->event)) wake_up_interruptible(&info->delta_msr_wait); tty_wakeup(tty); #ifdef Z_WAKE if (test_and_clear_bit(Cy_EVENT_SHUTDOWN_WAKEUP, &info->event)) - wake_up_interruptible(&info->shutdown_wait); + complete(&info->shutdown_wait); #endif } /* do_softint */ @@ -975,11 +935,11 @@ do_softint(struct work_struct *work) */ static int cyy_issue_cmd(void __iomem * base_addr, u_char cmd, int index) { - volatile int i; + unsigned int i; /* Check to see that the previous command has completed */ for (i = 0; i < 100; i++) { - if (cy_readb(base_addr + (CyCCR << index)) == 0) { + if (readb(base_addr + (CyCCR << index)) == 0) { break; } udelay(10L); @@ -1022,7 +982,7 @@ static unsigned detect_isa_irq(void __iomem * address) cy_writeb(address + (CyCAR << index), 0); cy_writeb(address + (CySRER << index), - cy_readb(address + (CySRER << index)) | CyTxRdy); + readb(address + (CySRER << index)) | CyTxRdy); local_irq_restore(flags); /* Wait ... */ @@ -1032,11 +992,11 @@ static unsigned detect_isa_irq(void __iomem * address) irq = probe_irq_off(irqs); /* Clean up */ - save_xir = (u_char) cy_readb(address + (CyTIR << index)); - save_car = cy_readb(address + (CyCAR << index)); + save_xir = (u_char) readb(address + (CyTIR << index)); + save_car = readb(address + (CyCAR << index)); cy_writeb(address + (CyCAR << index), (save_xir & 0x3)); cy_writeb(address + (CySRER << index), - cy_readb(address + (CySRER << index)) & ~CyTxRdy); + readb(address + (CySRER << index)) & ~CyTxRdy); cy_writeb(address + (CyTIR << index), (save_xir & 0x3f)); cy_writeb(address + (CyCAR << index), (save_car)); cy_writeb(address + (Cy_ClrIntr << index), 0); @@ -1051,45 +1011,43 @@ static void cyy_intr_chip(struct cyclades_card *cinfo, int chip, { struct cyclades_port *info; struct tty_struct *tty; - volatile int char_count; - int i, j, len, mdm_change, mdm_status, outch; + int char_count; + int j, len, mdm_change, mdm_status, outch; int save_xir, channel, save_car; char data; if (status & CySRReceive) { /* reception interrupt */ #ifdef CY_DEBUG_INTERRUPTS - printk("cyy_interrupt: rcvd intr, chip %d\n\r", chip); + printk(KERN_DEBUG "cyy_interrupt: rcvd intr, chip %d\n", chip); #endif /* determine the channel & change to that context */ spin_lock(&cinfo->card_lock); - save_xir = (u_char) cy_readb(base_addr + (CyRIR << index)); + save_xir = (u_char) readb(base_addr + (CyRIR << index)); channel = (u_short) (save_xir & CyIRChannel); - i = channel + chip * 4 + cinfo->first_line; - info = &cy_port[i]; - info->last_active = jiffies; - save_car = cy_readb(base_addr + (CyCAR << index)); + info = &cinfo->ports[channel + chip * 4]; + save_car = readb(base_addr + (CyCAR << index)); cy_writeb(base_addr + (CyCAR << index), save_xir); /* if there is nowhere to put the data, discard it */ - if (info->tty == 0) { - j = (cy_readb(base_addr + (CyRIVR << index)) & + if (info->tty == NULL) { + j = (readb(base_addr + (CyRIVR << index)) & CyIVRMask); if (j == CyIVRRxEx) { /* exception */ - data = cy_readb(base_addr + (CyRDSR << index)); + data = readb(base_addr + (CyRDSR << index)); } else { /* normal character reception */ - char_count = cy_readb(base_addr + + char_count = readb(base_addr + (CyRDCR << index)); while (char_count--) { - data = cy_readb(base_addr + + data = readb(base_addr + (CyRDSR << index)); } } } else { /* there is an open port for this data */ tty = info->tty; - j = (cy_readb(base_addr + (CyRIVR << index)) & + j = (readb(base_addr + (CyRIVR << index)) & CyIVRMask); if (j == CyIVRRxEx) { /* exception */ - data = cy_readb(base_addr + (CyRDSR << index)); + data = readb(base_addr + (CyRDSR << index)); /* For statistics only */ if (data & CyBREAK) @@ -1110,7 +1068,7 @@ static void cyy_intr_chip(struct cyclades_card *cinfo, int chip, if (data & CyBREAK) { tty_insert_flip_char( tty, - cy_readb( + readb( base_addr + (CyRDSR << index)), @@ -1123,7 +1081,7 @@ static void cyy_intr_chip(struct cyclades_card *cinfo, int chip, } else if (data & CyFRAME) { tty_insert_flip_char( tty, - cy_readb( + readb( base_addr + (CyRDSR << index)), @@ -1135,7 +1093,7 @@ static void cyy_intr_chip(struct cyclades_card *cinfo, int chip, /* Pieces of seven... */ tty_insert_flip_char( tty, - cy_readb( + readb( base_addr + (CyRDSR << index)), @@ -1154,7 +1112,7 @@ static void cyy_intr_chip(struct cyclades_card *cinfo, int chip, */ tty_insert_flip_char( tty, - cy_readb( + readb( base_addr + (CyRDSR << index)), @@ -1186,7 +1144,7 @@ static void cyy_intr_chip(struct cyclades_card *cinfo, int chip, } } else { /* normal character reception */ /* load # chars available from the chip */ - char_count = cy_readb(base_addr + + char_count = readb(base_addr + (CyRDCR << index)); #ifdef CY_ENABLE_MONITORING @@ -1198,7 +1156,7 @@ static void cyy_intr_chip(struct cyclades_card *cinfo, int chip, #endif len = tty_buffer_request_room(tty, char_count); while (len--) { - data = cy_readb(base_addr + + data = readb(base_addr + (CyRDSR << index)); tty_insert_flip_char(tty, data, TTY_NORMAL); @@ -1223,29 +1181,27 @@ static void cyy_intr_chip(struct cyclades_card *cinfo, int chip, is empty, we know we can always stuff a dozen characters. */ #ifdef CY_DEBUG_INTERRUPTS - printk("cyy_interrupt: xmit intr, chip %d\n\r", chip); + printk(KERN_DEBUG "cyy_interrupt: xmit intr, chip %d\n", chip); #endif /* determine the channel & change to that context */ spin_lock(&cinfo->card_lock); - save_xir = (u_char) cy_readb(base_addr + (CyTIR << index)); + save_xir = (u_char) readb(base_addr + (CyTIR << index)); channel = (u_short) (save_xir & CyIRChannel); - i = channel + chip * 4 + cinfo->first_line; - save_car = cy_readb(base_addr + (CyCAR << index)); + save_car = readb(base_addr + (CyCAR << index)); cy_writeb(base_addr + (CyCAR << index), save_xir); /* validate the port# (as configured and open) */ - if ((i < 0) || (NR_PORTS <= i)) { + if (channel + chip * 4 >= cinfo->nports) { cy_writeb(base_addr + (CySRER << index), - cy_readb(base_addr + (CySRER << index)) & + readb(base_addr + (CySRER << index)) & ~CyTxRdy); goto txend; } - info = &cy_port[i]; - info->last_active = jiffies; - if (info->tty == 0) { + info = &cinfo->ports[channel + chip * 4]; + if (info->tty == NULL) { cy_writeb(base_addr + (CySRER << index), - cy_readb(base_addr + (CySRER << index)) & + readb(base_addr + (CySRER << index)) & ~CyTxRdy); goto txdone; } @@ -1278,29 +1234,29 @@ static void cyy_intr_chip(struct cyclades_card *cinfo, int chip, while (char_count-- > 0) { if (!info->xmit_cnt) { - if (cy_readb(base_addr + (CySRER << index)) & + if (readb(base_addr + (CySRER << index)) & CyTxMpty) { cy_writeb(base_addr + (CySRER << index), - cy_readb(base_addr + + readb(base_addr + (CySRER << index)) & ~CyTxMpty); } else { cy_writeb(base_addr + (CySRER << index), - (cy_readb(base_addr + + (readb(base_addr + (CySRER << index)) & ~CyTxRdy) | CyTxMpty); } goto txdone; } - if (info->xmit_buf == 0) { + if (info->xmit_buf == NULL) { cy_writeb(base_addr + (CySRER << index), - cy_readb(base_addr + (CySRER << index))& + readb(base_addr + (CySRER << index)) & ~CyTxRdy); goto txdone; } if (info->tty->stopped || info->tty->hw_stopped) { cy_writeb(base_addr + (CySRER << index), - cy_readb(base_addr + (CySRER << index))& + readb(base_addr + (CySRER << index)) & ~CyTxRdy); goto txdone; } @@ -1333,7 +1289,6 @@ static void cyy_intr_chip(struct cyclades_card *cinfo, int chip, 0); info->icount.tx++; char_count--; - } else { } } } @@ -1353,19 +1308,16 @@ txend: /* determine the channel & change to that context */ spin_lock(&cinfo->card_lock); - save_xir = (u_char) cy_readb(base_addr + (CyMIR << index)); + save_xir = (u_char) readb(base_addr + (CyMIR << index)); channel = (u_short) (save_xir & CyIRChannel); - info = &cy_port[channel + chip * 4 + cinfo->first_line]; - info->last_active = jiffies; - save_car = cy_readb(base_addr + (CyCAR << index)); + info = &cinfo->ports[channel + chip * 4]; + save_car = readb(base_addr + (CyCAR << index)); cy_writeb(base_addr + (CyCAR << index), save_xir); - mdm_change = cy_readb(base_addr + (CyMISR << index)); - mdm_status = cy_readb(base_addr + (CyMSVR1 << index)); + mdm_change = readb(base_addr + (CyMISR << index)); + mdm_status = readb(base_addr + (CyMSVR1 << index)); - if (info->tty == 0) { /* no place for data, ignore it */ - ; - } else { + if (info->tty) { if (mdm_change & CyANY_DELTA) { /* For statistics only */ if (mdm_change & CyDCD) @@ -1398,7 +1350,7 @@ txend: info->tty->hw_stopped = 0; cy_writeb(base_addr + (CySRER << index), - cy_readb(base_addr + + readb(base_addr + (CySRER << index))| CyTxRdy); @@ -1412,17 +1364,17 @@ txend: info->tty->hw_stopped = 1; cy_writeb(base_addr + (CySRER << index), - cy_readb(base_addr + + readb(base_addr + (CySRER << index)) & ~CyTxRdy); } } } - if (mdm_change & CyDSR) { +/* if (mdm_change & CyDSR) { } if (mdm_change & CyRI) { - } + }*/ } /* end of service */ cy_writeb(base_addr + (CyMIR << index), (save_xir & 0x3f)); @@ -1438,16 +1390,16 @@ txend: static irqreturn_t cyy_interrupt(int irq, void *dev_id) { int status; - struct cyclades_card *cinfo; + struct cyclades_card *cinfo = dev_id; void __iomem *base_addr, *card_base_addr; int chip; int index; int too_many; int had_work; - if ((cinfo = (struct cyclades_card *)dev_id) == 0) { + if (unlikely(cinfo == NULL)) { #ifdef CY_DEBUG_INTERRUPTS - printk("cyy_interrupt: spurious interrupt %d\n\r", irq); + printk(KERN_DEBUG "cyy_interrupt: spurious interrupt %d\n",irq); #endif return IRQ_NONE; /* spurious interrupt */ } @@ -1455,6 +1407,10 @@ static irqreturn_t cyy_interrupt(int irq, void *dev_id) card_base_addr = cinfo->base_addr; index = cinfo->bus_index; + /* card was not initialized yet (e.g. DEBUG_SHIRQ) */ + if (unlikely(card_base_addr == NULL)) + return IRQ_HANDLED; + /* This loop checks all chips in the card. Make a note whenever _any_ chip had some work to do, as this is considered an indication that there will be more to do. Only when no chip @@ -1466,7 +1422,7 @@ static irqreturn_t cyy_interrupt(int irq, void *dev_id) base_addr = cinfo->base_addr + (cy_chip_offset[chip] << index); too_many = 0; - while ((status = cy_readb(base_addr + + while ((status = readb(base_addr + (CySVRR << index))) != 0x00) { had_work++; /* The purpose of the following test is to ensure that @@ -1498,7 +1454,7 @@ static irqreturn_t cyy_interrupt(int irq, void *dev_id) static int cyz_fetch_msg(struct cyclades_card *cinfo, - uclong * channel, ucchar * cmd, uclong * param) + __u32 * channel, __u8 * cmd, __u32 * param) { struct FIRM_ID __iomem *firm_id; struct ZFW_CTRL __iomem *zfw_ctrl; @@ -1509,16 +1465,15 @@ cyz_fetch_msg(struct cyclades_card *cinfo, if (!ISZLOADED(*cinfo)) { return -1; } - zfw_ctrl = cinfo->base_addr + (cy_readl(&firm_id->zfwctrl_addr) & - 0xfffff); + zfw_ctrl = cinfo->base_addr + (readl(&firm_id->zfwctrl_addr) & 0xfffff); board_ctrl = &zfw_ctrl->board_ctrl; - loc_doorbell = cy_readl(&((struct RUNTIME_9060 __iomem *) + loc_doorbell = readl(&((struct RUNTIME_9060 __iomem *) (cinfo->ctl_addr))->loc_doorbell); if (loc_doorbell) { *cmd = (char)(0xff & loc_doorbell); - *channel = cy_readl(&board_ctrl->fwcmd_channel); - *param = (uclong) cy_readl(&board_ctrl->fwcmd_param); + *channel = readl(&board_ctrl->fwcmd_channel); + *param = (__u32) readl(&board_ctrl->fwcmd_param); cy_writel(&((struct RUNTIME_9060 __iomem *)(cinfo->ctl_addr))-> loc_doorbell, 0xffffffff); return 1; @@ -1528,28 +1483,27 @@ cyz_fetch_msg(struct cyclades_card *cinfo, static int cyz_issue_cmd(struct cyclades_card *cinfo, - uclong channel, ucchar cmd, uclong param) + __u32 channel, __u8 cmd, __u32 param) { struct FIRM_ID __iomem *firm_id; struct ZFW_CTRL __iomem *zfw_ctrl; struct BOARD_CTRL __iomem *board_ctrl; - unsigned long __iomem *pci_doorbell; + __u32 __iomem *pci_doorbell; int index; firm_id = cinfo->base_addr + ID_ADDRESS; if (!ISZLOADED(*cinfo)) { return -1; } - zfw_ctrl = cinfo->base_addr + (cy_readl(&firm_id->zfwctrl_addr) & - 0xfffff); + zfw_ctrl = cinfo->base_addr + (readl(&firm_id->zfwctrl_addr) & 0xfffff); board_ctrl = &zfw_ctrl->board_ctrl; index = 0; pci_doorbell = &((struct RUNTIME_9060 __iomem *)(cinfo->ctl_addr))->pci_doorbell; - while ((cy_readl(pci_doorbell) & 0xff) != 0) { + while ((readl(pci_doorbell) & 0xff) != 0) { if (index++ == 1000) { - return (int)(cy_readl(pci_doorbell) & 0xff); + return (int)(readl(pci_doorbell) & 0xff); } udelay(50L); } @@ -1561,34 +1515,30 @@ cyz_issue_cmd(struct cyclades_card *cinfo, } /* cyz_issue_cmd */ static void -cyz_handle_rx(struct cyclades_port *info, - volatile struct CH_CTRL __iomem * ch_ctrl, - volatile struct BUF_CTRL __iomem * buf_ctrl) +cyz_handle_rx(struct cyclades_port *info, struct CH_CTRL __iomem *ch_ctrl, + struct BUF_CTRL __iomem *buf_ctrl) { - struct cyclades_card *cinfo = &cy_card[info->card]; + struct cyclades_card *cinfo = info->card; struct tty_struct *tty = info->tty; - volatile int char_count; + int char_count; int len; #ifdef BLOCKMOVE - int small_count; + unsigned char *buf; #else char data; #endif - volatile uclong rx_put, rx_get, new_rx_get, rx_bufsize, rx_bufaddr; + __u32 rx_put, rx_get, new_rx_get, rx_bufsize, rx_bufaddr; - rx_get = new_rx_get = cy_readl(&buf_ctrl->rx_get); - rx_put = cy_readl(&buf_ctrl->rx_put); - rx_bufsize = cy_readl(&buf_ctrl->rx_bufsize); - rx_bufaddr = cy_readl(&buf_ctrl->rx_bufaddr); + rx_get = new_rx_get = readl(&buf_ctrl->rx_get); + rx_put = readl(&buf_ctrl->rx_put); + rx_bufsize = readl(&buf_ctrl->rx_bufsize); + rx_bufaddr = readl(&buf_ctrl->rx_bufaddr); if (rx_put >= rx_get) char_count = rx_put - rx_get; else char_count = rx_put - rx_get + rx_bufsize; if (char_count) { - info->last_active = jiffies; - info->jiffies[1] = jiffies; - #ifdef CY_ENABLE_MONITORING info->mon.int_count++; info->mon.char_count += char_count; @@ -1596,7 +1546,7 @@ cyz_handle_rx(struct cyclades_port *info, info->mon.char_max = char_count; info->mon.char_last = char_count; #endif - if (tty == 0) { + if (tty == NULL) { /* flush received characters */ new_rx_get = (new_rx_get + char_count) & (rx_bufsize - 1); @@ -1606,30 +1556,28 @@ cyz_handle_rx(struct cyclades_port *info, /* we'd like to use memcpy(t, f, n) and memset(s, c, count) for performance, but because of buffer boundaries, there may be several steps to the operation */ - while (0 < (small_count = min_t(unsigned int, - rx_bufsize - new_rx_get, - min_t(unsigned int, TTY_FLIPBUF_SIZE - - tty->flip.count, char_count)))){ - memcpy_fromio(tty->flip.char_buf_ptr, - (char *)(cinfo->base_addr + rx_bufaddr + - new_rx_get), - small_count); + while (1) { + len = tty_prepare_flip_string(tty, &buf, + char_count); + if (!len) + break; - tty->flip.char_buf_ptr += small_count; - memset(tty->flip.flag_buf_ptr, TTY_NORMAL, - small_count); - tty->flip.flag_buf_ptr += small_count; - new_rx_get = (new_rx_get + small_count) & + len = min_t(unsigned int, min(len, char_count), + rx_bufsize - new_rx_get); + + memcpy_fromio(buf, cinfo->base_addr + + rx_bufaddr + new_rx_get, len); + + new_rx_get = (new_rx_get + len) & (rx_bufsize - 1); - char_count -= small_count; - info->icount.rx += small_count; - info->idle_stats.recv_bytes += small_count; - tty->flip.count += small_count; + char_count -= len; + info->icount.rx += len; + info->idle_stats.recv_bytes += len; } #else len = tty_buffer_request_room(tty, char_count); while (len--) { - data = cy_readb(cinfo->base_addr + rx_bufaddr + + data = readb(cinfo->base_addr + rx_bufaddr + new_rx_get); new_rx_get = (new_rx_get + 1)& (rx_bufsize - 1); tty_insert_flip_char(tty, data, TTY_NORMAL); @@ -1640,13 +1588,12 @@ cyz_handle_rx(struct cyclades_port *info, #ifdef CONFIG_CYZ_INTR /* Recalculate the number of chars in the RX buffer and issue a cmd in case it's higher than the RX high water mark */ - rx_put = cy_readl(&buf_ctrl->rx_put); + rx_put = readl(&buf_ctrl->rx_put); if (rx_put >= rx_get) char_count = rx_put - rx_get; else char_count = rx_put - rx_get + rx_bufsize; - if (char_count >= (int)cy_readl(&buf_ctrl-> - rx_threshold)) { + if (char_count >= (int)readl(&buf_ctrl->rx_threshold)) { cy_sched_event(info, Cy_EVENT_Z_RX_FULL); } #endif @@ -1659,26 +1606,25 @@ cyz_handle_rx(struct cyclades_port *info, } static void -cyz_handle_tx(struct cyclades_port *info, - volatile struct CH_CTRL __iomem * ch_ctrl, - volatile struct BUF_CTRL __iomem * buf_ctrl) +cyz_handle_tx(struct cyclades_port *info, struct CH_CTRL __iomem *ch_ctrl, + struct BUF_CTRL __iomem *buf_ctrl) { - struct cyclades_card *cinfo = &cy_card[info->card]; + struct cyclades_card *cinfo = info->card; struct tty_struct *tty = info->tty; char data; - volatile int char_count; + int char_count; #ifdef BLOCKMOVE int small_count; #endif - volatile uclong tx_put, tx_get, tx_bufsize, tx_bufaddr; + __u32 tx_put, tx_get, tx_bufsize, tx_bufaddr; if (info->xmit_cnt <= 0) /* Nothing to transmit */ return; - tx_get = cy_readl(&buf_ctrl->tx_get); - tx_put = cy_readl(&buf_ctrl->tx_put); - tx_bufsize = cy_readl(&buf_ctrl->tx_bufsize); - tx_bufaddr = cy_readl(&buf_ctrl->tx_bufaddr); + tx_get = readl(&buf_ctrl->tx_get); + tx_put = readl(&buf_ctrl->tx_put); + tx_bufsize = readl(&buf_ctrl->tx_bufsize); + tx_bufaddr = readl(&buf_ctrl->tx_bufaddr); if (tx_put >= tx_get) char_count = tx_get - tx_put - 1 + tx_bufsize; else @@ -1686,9 +1632,8 @@ cyz_handle_tx(struct cyclades_port *info, if (char_count) { - if (tty == 0) { + if (tty == NULL) goto ztxdone; - } if (info->x_char) { /* send special char */ data = info->x_char; @@ -1698,8 +1643,6 @@ cyz_handle_tx(struct cyclades_port *info, info->x_char = 0; char_count--; info->icount.tx++; - info->last_active = jiffies; - info->jiffies[2] = jiffies; } #ifdef BLOCKMOVE while (0 < (small_count = min_t(unsigned int, @@ -1719,8 +1662,6 @@ cyz_handle_tx(struct cyclades_port *info, info->xmit_cnt -= small_count; info->xmit_tail = (info->xmit_tail + small_count) & (SERIAL_XMIT_SIZE - 1); - info->last_active = jiffies; - info->jiffies[2] = jiffies; } #else while (info->xmit_cnt && char_count) { @@ -1733,8 +1674,6 @@ cyz_handle_tx(struct cyclades_port *info, tx_put = (tx_put + 1) & (tx_bufsize - 1); char_count--; info->icount.tx++; - info->last_active = jiffies; - info->jiffies[2] = jiffies; } #endif ztxdone: @@ -1750,33 +1689,32 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo) { struct tty_struct *tty; struct cyclades_port *info; - static volatile struct FIRM_ID __iomem *firm_id; - static volatile struct ZFW_CTRL __iomem *zfw_ctrl; - static volatile struct BOARD_CTRL __iomem *board_ctrl; - static volatile struct CH_CTRL __iomem *ch_ctrl; - static volatile struct BUF_CTRL __iomem *buf_ctrl; - uclong channel; - ucchar cmd; - uclong param; - uclong hw_ver, fw_ver; + static struct FIRM_ID __iomem *firm_id; + static struct ZFW_CTRL __iomem *zfw_ctrl; + static struct BOARD_CTRL __iomem *board_ctrl; + static struct CH_CTRL __iomem *ch_ctrl; + static struct BUF_CTRL __iomem *buf_ctrl; + __u32 channel; + __u8 cmd; + __u32 param; + __u32 hw_ver, fw_ver; int special_count; int delta_count; firm_id = cinfo->base_addr + ID_ADDRESS; - zfw_ctrl = cinfo->base_addr + (cy_readl(&firm_id->zfwctrl_addr) & - 0xfffff); + zfw_ctrl = cinfo->base_addr + (readl(&firm_id->zfwctrl_addr) & 0xfffff); board_ctrl = &zfw_ctrl->board_ctrl; - fw_ver = cy_readl(&board_ctrl->fw_version); - hw_ver = cy_readl(&((struct RUNTIME_9060 __iomem *)(cinfo->ctl_addr))-> + fw_ver = readl(&board_ctrl->fw_version); + hw_ver = readl(&((struct RUNTIME_9060 __iomem *)(cinfo->ctl_addr))-> mail_box_0); while (cyz_fetch_msg(cinfo, &channel, &cmd, ¶m) == 1) { special_count = 0; delta_count = 0; - info = &cy_port[channel + cinfo->first_line]; - if ((tty = info->tty) == 0) { + info = &cinfo->ports[channel]; + if ((tty = info->tty) == NULL) continue; - } + ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]); buf_ctrl = &(zfw_ctrl->buf_ctrl[channel]); @@ -1801,7 +1739,7 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo) delta_count++; if (info->flags & ASYNC_CHECK_CD) { if ((fw_ver > 241 ? ((u_long) param) : - cy_readl(&ch_ctrl->rs_status)) & + readl(&ch_ctrl->rs_status)) & C_RS_DCD) { cy_sched_event(info, Cy_EVENT_OPEN_WAKEUP); @@ -1833,8 +1771,8 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo) case C_CM_INTBACK2: /* Reception Interrupt */ #ifdef CY_DEBUG_INTERRUPTS - printk("cyz_interrupt: rcvd intr, card %d, " - "port %ld\n\r", info->card, channel); + printk(KERN_DEBUG "cyz_interrupt: rcvd intr, card %d, " + "port %ld\n", info->card, channel); #endif cyz_handle_rx(info, ch_ctrl, buf_ctrl); break; @@ -1843,8 +1781,8 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo) case C_CM_INTBACK: /* Transmission Interrupt */ #ifdef CY_DEBUG_INTERRUPTS - printk("cyz_interrupt: xmit intr, card %d, " - "port %ld\n\r", info->card, channel); + printk(KERN_DEBUG "cyz_interrupt: xmit intr, card %d, " + "port %ld\n", info->card, channel); #endif cyz_handle_tx(info, ch_ctrl, buf_ctrl); break; @@ -1865,18 +1803,19 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo) #ifdef CONFIG_CYZ_INTR static irqreturn_t cyz_interrupt(int irq, void *dev_id) { - struct cyclades_card *cinfo; + struct cyclades_card *cinfo = dev_id; - if ((cinfo = (struct cyclades_card *)dev_id) == 0) { + if (unlikely(cinfo == NULL)) { #ifdef CY_DEBUG_INTERRUPTS - printk("cyz_interrupt: spurious interrupt %d\n\r", irq); + printk(KERN_DEBUG "cyz_interrupt: spurious interrupt %d\n",irq); #endif return IRQ_NONE; /* spurious interrupt */ } - if (!ISZLOADED(*cinfo)) { + if (unlikely(!ISZLOADED(*cinfo))) { #ifdef CY_DEBUG_INTERRUPTS - printk("cyz_interrupt: board not yet loaded (IRQ%d).\n\r", irq); + printk(KERN_DEBUG "cyz_interrupt: board not yet loaded " + "(IRQ%d).\n", irq); #endif return IRQ_NONE; } @@ -1890,19 +1829,18 @@ static irqreturn_t cyz_interrupt(int irq, void *dev_id) static void cyz_rx_restart(unsigned long arg) { struct cyclades_port *info = (struct cyclades_port *)arg; + struct cyclades_card *card = info->card; int retval; - int card = info->card; - uclong channel = (info->line) - (cy_card[card].first_line); + __u32 channel = info->line - card->first_line; unsigned long flags; - CY_LOCK(info, flags); - retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_INTBACK2, 0L); + spin_lock_irqsave(&card->card_lock, flags); + retval = cyz_issue_cmd(card, channel, C_CM_INTBACK2, 0L); if (retval != 0) { - printk("cyc:cyz_rx_restart retval on ttyC%d was %x\n", + printk(KERN_ERR "cyc:cyz_rx_restart retval on ttyC%d was %x\n", info->line, retval); } - cyz_rx_full_timer[info->line].function = NULL; - CY_UNLOCK(info, flags); + spin_unlock_irqrestore(&card->card_lock, flags); } #else /* CONFIG_CYZ_INTR */ @@ -1912,14 +1850,14 @@ static void cyz_poll(unsigned long arg) struct cyclades_card *cinfo; struct cyclades_port *info; struct tty_struct *tty; - static volatile struct FIRM_ID *firm_id; - static volatile struct ZFW_CTRL *zfw_ctrl; - static volatile struct BOARD_CTRL *board_ctrl; - static volatile struct CH_CTRL *ch_ctrl; - static volatile struct BUF_CTRL *buf_ctrl; + static struct FIRM_ID *firm_id; + static struct ZFW_CTRL *zfw_ctrl; + static struct BOARD_CTRL *board_ctrl; + static struct CH_CTRL *ch_ctrl; + static struct BUF_CTRL *buf_ctrl; + unsigned long expires = jiffies + HZ; int card, port; - cyz_timerlist.expires = jiffies + (HZ); for (card = 0; card < NR_CARDS; card++) { cinfo = &cy_card[card]; @@ -1930,12 +1868,12 @@ static void cyz_poll(unsigned long arg) firm_id = cinfo->base_addr + ID_ADDRESS; zfw_ctrl = cinfo->base_addr + - (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff); + (readl(&firm_id->zfwctrl_addr) & 0xfffff); board_ctrl = &(zfw_ctrl->board_ctrl); /* Skip first polling cycle to avoid racing conditions with the FW */ if (!cinfo->intr_enabled) { - cinfo->nports = (int)cy_readl(&board_ctrl->n_channel); + cinfo->nports = (int)readl(&board_ctrl->n_channel); cinfo->intr_enabled = 1; continue; } @@ -1943,7 +1881,7 @@ static void cyz_poll(unsigned long arg) cyz_handle_cmd(cinfo); for (port = 0; port < cinfo->nports; port++) { - info = &cy_port[port + cinfo->first_line]; + info = &cinfo->ports[port]; tty = info->tty; ch_ctrl = &(zfw_ctrl->ch_ctrl[port]); buf_ctrl = &(zfw_ctrl->buf_ctrl[port]); @@ -1953,9 +1891,9 @@ static void cyz_poll(unsigned long arg) cyz_handle_tx(info, ch_ctrl, buf_ctrl); } /* poll every 'cyz_polling_cycle' period */ - cyz_timerlist.expires = jiffies + cyz_polling_cycle; + expires = jiffies + cyz_polling_cycle; } - add_timer(&cyz_timerlist); + mod_timer(&cyz_timerlist, expires); } /* cyz_poll */ #endif /* CONFIG_CYZ_INTR */ @@ -1968,20 +1906,21 @@ static void cyz_poll(unsigned long arg) */ static int startup(struct cyclades_port *info) { + struct cyclades_card *card; unsigned long flags; int retval = 0; void __iomem *base_addr; - int card, chip, channel, index; + int chip, channel, index; unsigned long page; card = info->card; - channel = (info->line) - (cy_card[card].first_line); + channel = info->line - card->first_line; page = get_zeroed_page(GFP_KERNEL); if (!page) return -ENOMEM; - CY_LOCK(info, flags); + spin_lock_irqsave(&card->card_lock, flags); if (info->flags & ASYNC_INITIALIZED) { free_page(page); @@ -2001,24 +1940,22 @@ static int startup(struct cyclades_port *info) else info->xmit_buf = (unsigned char *)page; - CY_UNLOCK(info, flags); + spin_unlock_irqrestore(&card->card_lock, flags); set_line_char(info); - if (!IS_CYC_Z(cy_card[card])) { + if (!IS_CYC_Z(*card)) { chip = channel >> 2; channel &= 0x03; - index = cy_card[card].bus_index; - base_addr = cy_card[card].base_addr + - (cy_chip_offset[chip] << index); + index = card->bus_index; + base_addr = card->base_addr + (cy_chip_offset[chip] << index); #ifdef CY_DEBUG_OPEN - printk("cyc startup card %d, chip %d, channel %d, " - "base_addr %lx\n", - card, chip, channel, (long)base_addr); - /**/ + printk(KERN_DEBUG "cyc startup card %d, chip %d, channel %d, " + "base_addr %p\n", + card, chip, channel, base_addr); #endif - CY_LOCK(info, flags); + spin_lock_irqsave(&card->card_lock, flags); cy_writeb(base_addr + (CyCAR << index), (u_char) channel); @@ -2034,14 +1971,14 @@ static int startup(struct cyclades_port *info) cy_writeb(base_addr + (CyMSVR2 << index), CyDTR); #ifdef CY_DEBUG_DTR - printk("cyc:startup raising DTR\n"); - printk(" status: 0x%x, 0x%x\n", - cy_readb(base_addr + (CyMSVR1 << index)), - cy_readb(base_addr + (CyMSVR2 << index))); + printk(KERN_DEBUG "cyc:startup raising DTR\n"); + printk(KERN_DEBUG " status: 0x%x, 0x%x\n", + readb(base_addr + (CyMSVR1 << index)), + readb(base_addr + (CyMSVR2 << index))); #endif cy_writeb(base_addr + (CySRER << index), - cy_readb(base_addr + (CySRER << index)) | CyRxData); + readb(base_addr + (CySRER << index)) | CyRxData); info->flags |= ASYNC_INITIALIZED; if (info->tty) { @@ -2054,7 +1991,7 @@ static int startup(struct cyclades_port *info) info->idle_stats.recv_idle = info->idle_stats.xmit_idle = jiffies; - CY_UNLOCK(info, flags); + spin_unlock_irqrestore(&card->card_lock, flags); } else { struct FIRM_ID __iomem *firm_id; @@ -2063,24 +2000,23 @@ static int startup(struct cyclades_port *info) struct CH_CTRL __iomem *ch_ctrl; int retval; - base_addr = cy_card[card].base_addr; + base_addr = card->base_addr; firm_id = base_addr + ID_ADDRESS; - if (!ISZLOADED(cy_card[card])) { + if (!ISZLOADED(*card)) { return -ENODEV; } - zfw_ctrl = cy_card[card].base_addr + - (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff); + zfw_ctrl = card->base_addr + + (readl(&firm_id->zfwctrl_addr) & 0xfffff); board_ctrl = &zfw_ctrl->board_ctrl; ch_ctrl = zfw_ctrl->ch_ctrl; #ifdef CY_DEBUG_OPEN - printk("cyc startup Z card %d, channel %d, base_addr %lx\n", - card, channel, (long)base_addr); - /**/ + printk(KERN_DEBUG "cyc startup Z card %d, channel %d, " + "base_addr %p\n", card, channel, base_addr); #endif - CY_LOCK(info, flags); + spin_lock_irqsave(&card->card_lock, flags); cy_writel(&ch_ctrl[channel].op_mode, C_CH_ENABLE); #ifdef Z_WAKE @@ -2102,33 +2038,31 @@ static int startup(struct cyclades_port *info) #endif /* CONFIG_CYZ_INTR */ #endif /* Z_WAKE */ - retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_IOCTL, 0L); + retval = cyz_issue_cmd(card, channel, C_CM_IOCTL, 0L); if (retval != 0) { - printk("cyc:startup(1) retval on ttyC%d was %x\n", - info->line, retval); + printk(KERN_ERR "cyc:startup(1) retval on ttyC%d was " + "%x\n", info->line, retval); } /* Flush RX buffers before raising DTR and RTS */ - retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_FLUSH_RX, - 0L); + retval = cyz_issue_cmd(card, channel, C_CM_FLUSH_RX, 0L); if (retval != 0) { - printk("cyc:startup(2) retval on ttyC%d was %x\n", - info->line, retval); + printk(KERN_ERR "cyc:startup(2) retval on ttyC%d was " + "%x\n", info->line, retval); } /* set timeout !!! */ /* set RTS and DTR !!! */ cy_writel(&ch_ctrl[channel].rs_control, - cy_readl(&ch_ctrl[channel].rs_control) | C_RS_RTS | + readl(&ch_ctrl[channel].rs_control) | C_RS_RTS | C_RS_DTR); - retval = cyz_issue_cmd(&cy_card[info->card], channel, - C_CM_IOCTLM, 0L); + retval = cyz_issue_cmd(card, channel, C_CM_IOCTLM, 0L); if (retval != 0) { - printk("cyc:startup(3) retval on ttyC%d was %x\n", - info->line, retval); + printk(KERN_ERR "cyc:startup(3) retval on ttyC%d was " + "%x\n", info->line, retval); } #ifdef CY_DEBUG_DTR - printk("cyc:startup raising Z DTR\n"); + printk(KERN_DEBUG "cyc:startup raising Z DTR\n"); #endif /* enable send, recv, modem !!! */ @@ -2144,51 +2078,50 @@ static int startup(struct cyclades_port *info) info->idle_stats.recv_idle = info->idle_stats.xmit_idle = jiffies; - CY_UNLOCK(info, flags); + spin_unlock_irqrestore(&card->card_lock, flags); } #ifdef CY_DEBUG_OPEN - printk(" cyc startup done\n"); + printk(KERN_DEBUG "cyc startup done\n"); #endif return 0; errout: - CY_UNLOCK(info, flags); + spin_unlock_irqrestore(&card->card_lock, flags); return retval; } /* startup */ static void start_xmit(struct cyclades_port *info) { + struct cyclades_card *card; unsigned long flags; void __iomem *base_addr; - int card, chip, channel, index; + int chip, channel, index; card = info->card; - channel = (info->line) - (cy_card[card].first_line); - if (!IS_CYC_Z(cy_card[card])) { + channel = info->line - card->first_line; + if (!IS_CYC_Z(*card)) { chip = channel >> 2; channel &= 0x03; - index = cy_card[card].bus_index; - base_addr = cy_card[card].base_addr + - (cy_chip_offset[chip] << index); + index = card->bus_index; + base_addr = card->base_addr + (cy_chip_offset[chip] << index); - CY_LOCK(info, flags); + spin_lock_irqsave(&card->card_lock, flags); cy_writeb(base_addr + (CyCAR << index), channel); cy_writeb(base_addr + (CySRER << index), - cy_readb(base_addr + (CySRER << index)) | CyTxRdy); - CY_UNLOCK(info, flags); + readb(base_addr + (CySRER << index)) | CyTxRdy); + spin_unlock_irqrestore(&card->card_lock, flags); } else { #ifdef CONFIG_CYZ_INTR int retval; - CY_LOCK(info, flags); - retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_INTBACK, - 0L); + spin_lock_irqsave(&card->card_lock, flags); + retval = cyz_issue_cmd(card, channel, C_CM_INTBACK, 0L); if (retval != 0) { - printk("cyc:start_xmit retval on ttyC%d was %x\n", - info->line, retval); + printk(KERN_ERR "cyc:start_xmit retval on ttyC%d was " + "%x\n", info->line, retval); } - CY_UNLOCK(info, flags); + spin_unlock_irqrestore(&card->card_lock, flags); #else /* CONFIG_CYZ_INTR */ /* Don't have to do anything at this time */ #endif /* CONFIG_CYZ_INTR */ @@ -2201,30 +2134,30 @@ static void start_xmit(struct cyclades_port *info) */ static void shutdown(struct cyclades_port *info) { + struct cyclades_card *card; unsigned long flags; void __iomem *base_addr; - int card, chip, channel, index; + int chip, channel, index; if (!(info->flags & ASYNC_INITIALIZED)) { return; } card = info->card; - channel = info->line - cy_card[card].first_line; - if (!IS_CYC_Z(cy_card[card])) { + channel = info->line - card->first_line; + if (!IS_CYC_Z(*card)) { chip = channel >> 2; channel &= 0x03; - index = cy_card[card].bus_index; - base_addr = cy_card[card].base_addr + - (cy_chip_offset[chip] << index); + index = card->bus_index; + base_addr = card->base_addr + (cy_chip_offset[chip] << index); #ifdef CY_DEBUG_OPEN - printk("cyc shutdown Y card %d, chip %d, channel %d, " - "base_addr %lx\n", - card, chip, channel, (long)base_addr); + printk(KERN_DEBUG "cyc shutdown Y card %d, chip %d, " + "channel %d, base_addr %p\n", + card, chip, channel, base_addr); #endif - CY_LOCK(info, flags); + spin_lock_irqsave(&card->card_lock, flags); /* Clear delta_msr_wait queue to avoid mem leaks. */ wake_up_interruptible(&info->delta_msr_wait); @@ -2240,10 +2173,10 @@ static void shutdown(struct cyclades_port *info) cy_writeb(base_addr + (CyMSVR1 << index), ~CyRTS); cy_writeb(base_addr + (CyMSVR2 << index), ~CyDTR); #ifdef CY_DEBUG_DTR - printk("cyc shutdown dropping DTR\n"); - printk(" status: 0x%x, 0x%x\n", - cy_readb(base_addr + (CyMSVR1 << index)), - cy_readb(base_addr + (CyMSVR2 << index))); + printk(KERN_DEBUG "cyc shutdown dropping DTR\n"); + printk(KERN_DEBUG " status: 0x%x, 0x%x\n", + readb(base_addr + (CyMSVR1 << index)), + readb(base_addr + (CyMSVR2 << index))); #endif } cyy_issue_cmd(base_addr, CyCHAN_CTL | CyDIS_RCVR, index); @@ -2254,7 +2187,7 @@ static void shutdown(struct cyclades_port *info) set_bit(TTY_IO_ERROR, &info->tty->flags); } info->flags &= ~ASYNC_INITIALIZED; - CY_UNLOCK(info, flags); + spin_unlock_irqrestore(&card->card_lock, flags); } else { struct FIRM_ID __iomem *firm_id; struct ZFW_CTRL __iomem *zfw_ctrl; @@ -2262,23 +2195,23 @@ static void shutdown(struct cyclades_port *info) struct CH_CTRL __iomem *ch_ctrl; int retval; - base_addr = cy_card[card].base_addr; + base_addr = card->base_addr; #ifdef CY_DEBUG_OPEN - printk("cyc shutdown Z card %d, channel %d, base_addr %lx\n", - card, channel, (long)base_addr); + printk(KERN_DEBUG "cyc shutdown Z card %d, channel %d, " + "base_addr %p\n", card, channel, base_addr); #endif firm_id = base_addr + ID_ADDRESS; - if (!ISZLOADED(cy_card[card])) { + if (!ISZLOADED(*card)) { return; } - zfw_ctrl = cy_card[card].base_addr + - (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff); + zfw_ctrl = card->base_addr + + (readl(&firm_id->zfwctrl_addr) & 0xfffff); board_ctrl = &zfw_ctrl->board_ctrl; ch_ctrl = zfw_ctrl->ch_ctrl; - CY_LOCK(info, flags); + spin_lock_irqsave(&card->card_lock, flags); if (info->xmit_buf) { unsigned char *temp; @@ -2289,16 +2222,16 @@ static void shutdown(struct cyclades_port *info) if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) { cy_writel(&ch_ctrl[channel].rs_control, - (uclong)(cy_readl(&ch_ctrl[channel].rs_control)& + (__u32)(readl(&ch_ctrl[channel].rs_control) & ~(C_RS_RTS | C_RS_DTR))); - retval = cyz_issue_cmd(&cy_card[info->card], channel, + retval = cyz_issue_cmd(info->card, channel, C_CM_IOCTLM, 0L); if (retval != 0) { - printk("cyc:shutdown retval on ttyC%d was %x\n", - info->line, retval); + printk(KERN_ERR"cyc:shutdown retval on ttyC%d " + "was %x\n", info->line, retval); } #ifdef CY_DEBUG_DTR - printk("cyc:shutdown dropping Z DTR\n"); + printk(KERN_DEBUG "cyc:shutdown dropping Z DTR\n"); #endif } @@ -2307,11 +2240,11 @@ static void shutdown(struct cyclades_port *info) } info->flags &= ~ASYNC_INITIALIZED; - CY_UNLOCK(info, flags); + spin_unlock_irqrestore(&card->card_lock, flags); } #ifdef CY_DEBUG_OPEN - printk(" cyc shutdown done\n"); + printk(KERN_DEBUG "cyc shutdown done\n"); #endif } /* shutdown */ @@ -2332,7 +2265,7 @@ block_til_ready(struct tty_struct *tty, struct file *filp, int retval; void __iomem *base_addr; - cinfo = &cy_card[info->card]; + cinfo = info->card; channel = info->line - cinfo->first_line; /* @@ -2340,9 +2273,8 @@ block_til_ready(struct tty_struct *tty, struct file *filp, * until it's done, and then try again. */ if (tty_hung_up_p(filp) || (info->flags & ASYNC_CLOSING)) { - if (info->flags & ASYNC_CLOSING) { - interruptible_sleep_on(&info->close_wait); - } + wait_event_interruptible(info->close_wait, + !(info->flags & ASYNC_CLOSING)); return (info->flags & ASYNC_HUP_NOTIFY) ? -EAGAIN: -ERESTARTSYS; } @@ -2365,17 +2297,16 @@ block_til_ready(struct tty_struct *tty, struct file *filp, retval = 0; add_wait_queue(&info->open_wait, &wait); #ifdef CY_DEBUG_OPEN - printk("cyc block_til_ready before block: ttyC%d, count = %d\n", - info->line, info->count); - /**/ + printk(KERN_DEBUG "cyc block_til_ready before block: ttyC%d, " + "count = %d\n", info->line, info->count); #endif - CY_LOCK(info, flags); + spin_lock_irqsave(&cinfo->card_lock, flags); if (!tty_hung_up_p(filp)) info->count--; - CY_UNLOCK(info, flags); + spin_unlock_irqrestore(&cinfo->card_lock, flags); #ifdef CY_DEBUG_COUNT - printk("cyc block_til_ready: (%d): decrementing count to %d\n", - current->pid, info->count); + printk(KERN_DEBUG "cyc block_til_ready: (%d): decrementing count to " + "%d\n", current->pid, info->count); #endif info->blocked_open++; @@ -2386,7 +2317,7 @@ block_til_ready(struct tty_struct *tty, struct file *filp, base_addr = cinfo->base_addr + (cy_chip_offset[chip] << index); while (1) { - CY_LOCK(info, flags); + spin_lock_irqsave(&cinfo->card_lock, flags); if ((tty->termios->c_cflag & CBAUD)) { cy_writeb(base_addr + (CyCAR << index), (u_char) channel); @@ -2395,15 +2326,14 @@ block_til_ready(struct tty_struct *tty, struct file *filp, cy_writeb(base_addr + (CyMSVR2 << index), CyDTR); #ifdef CY_DEBUG_DTR - printk("cyc:block_til_ready raising DTR\n"); - printk(" status: 0x%x, 0x%x\n", - cy_readb(base_addr + - (CyMSVR1 << index)), - cy_readb(base_addr + - (CyMSVR2 << index))); + printk(KERN_DEBUG "cyc:block_til_ready raising " + "DTR\n"); + printk(KERN_DEBUG " status: 0x%x, 0x%x\n", + readb(base_addr + (CyMSVR1 << index)), + readb(base_addr + (CyMSVR2 << index))); #endif } - CY_UNLOCK(info, flags); + spin_unlock_irqrestore(&cinfo->card_lock, flags); set_current_state(TASK_INTERRUPTIBLE); if (tty_hung_up_p(filp) || @@ -2413,26 +2343,25 @@ block_til_ready(struct tty_struct *tty, struct file *filp, break; } - CY_LOCK(info, flags); + spin_lock_irqsave(&cinfo->card_lock, flags); cy_writeb(base_addr + (CyCAR << index), (u_char) channel); if (!(info->flags & ASYNC_CLOSING) && (C_CLOCAL(tty) || - (cy_readb(base_addr + + (readb(base_addr + (CyMSVR1 << index)) & CyDCD))) { - CY_UNLOCK(info, flags); + spin_unlock_irqrestore(&cinfo->card_lock, flags); break; } - CY_UNLOCK(info, flags); + spin_unlock_irqrestore(&cinfo->card_lock, flags); if (signal_pending(current)) { retval = -ERESTARTSYS; break; } #ifdef CY_DEBUG_OPEN - printk("cyc block_til_ready blocking: ttyC%d, " - "count = %d\n", - info->line, info->count); - /**/ + printk(KERN_DEBUG "cyc block_til_ready blocking: " + "ttyC%d, count = %d\n", + info->line, info->count); #endif schedule(); } @@ -2446,31 +2375,30 @@ block_til_ready(struct tty_struct *tty, struct file *filp, base_addr = cinfo->base_addr; firm_id = base_addr + ID_ADDRESS; if (!ISZLOADED(*cinfo)) { - current->state = TASK_RUNNING; + __set_current_state(TASK_RUNNING); remove_wait_queue(&info->open_wait, &wait); return -EINVAL; } - zfw_ctrl = base_addr + (cy_readl(&firm_id->zfwctrl_addr) & - 0xfffff); + zfw_ctrl = base_addr + (readl(&firm_id->zfwctrl_addr)& 0xfffff); board_ctrl = &zfw_ctrl->board_ctrl; ch_ctrl = zfw_ctrl->ch_ctrl; while (1) { if ((tty->termios->c_cflag & CBAUD)) { cy_writel(&ch_ctrl[channel].rs_control, - cy_readl(&ch_ctrl[channel]. - rs_control) | (C_RS_RTS | - C_RS_DTR)); - retval = cyz_issue_cmd(&cy_card[info->card], - channel, C_CM_IOCTLM, 0L); + readl(&ch_ctrl[channel].rs_control) | + C_RS_RTS | C_RS_DTR); + retval = cyz_issue_cmd(cinfo, + channel, C_CM_IOCTLM, 0L); if (retval != 0) { - printk("cyc:block_til_ready retval on " - "ttyC%d was %x\n", + printk(KERN_ERR "cyc:block_til_ready " + "retval on ttyC%d was %x\n", info->line, retval); } #ifdef CY_DEBUG_DTR - printk("cyc:block_til_ready raising Z DTR\n"); + printk(KERN_DEBUG "cyc:block_til_ready raising " + "Z DTR\n"); #endif } @@ -2482,7 +2410,7 @@ block_til_ready(struct tty_struct *tty, struct file *filp, break; } if (!(info->flags & ASYNC_CLOSING) && (C_CLOCAL(tty) || - (cy_readl(&ch_ctrl[channel].rs_status) & + (readl(&ch_ctrl[channel].rs_status) & C_RS_DCD))) { break; } @@ -2491,28 +2419,26 @@ block_til_ready(struct tty_struct *tty, struct file *filp, break; } #ifdef CY_DEBUG_OPEN - printk("cyc block_til_ready blocking: ttyC%d, " - "count = %d\n", - info->line, info->count); - /**/ + printk(KERN_DEBUG "cyc block_til_ready blocking: " + "ttyC%d, count = %d\n", + info->line, info->count); #endif schedule(); } } - current->state = TASK_RUNNING; + __set_current_state(TASK_RUNNING); remove_wait_queue(&info->open_wait, &wait); if (!tty_hung_up_p(filp)) { info->count++; #ifdef CY_DEBUG_COUNT - printk("cyc:block_til_ready (%d): incrementing count to %d\n", - current->pid, info->count); + printk(KERN_DEBUG "cyc:block_til_ready (%d): incrementing " + "count to %d\n", current->pid, info->count); #endif } info->blocked_open--; #ifdef CY_DEBUG_OPEN - printk("cyc:block_til_ready after blocking: ttyC%d, count = %d\n", - info->line, info->count); - /**/ + printk(KERN_DEBUG "cyc:block_til_ready after blocking: ttyC%d, " + "count = %d\n", info->line, info->count); #endif if (retval) return retval; @@ -2527,13 +2453,20 @@ block_til_ready(struct tty_struct *tty, struct file *filp, static int cy_open(struct tty_struct *tty, struct file *filp) { struct cyclades_port *info; + unsigned int i; int retval, line; line = tty->index; if ((line < 0) || (NR_PORTS <= line)) { return -ENODEV; } - info = &cy_port[line]; + for (i = 0; i < NR_CARDS; i++) + if (line < cy_card[i].first_line + cy_card[i].nports && + line >= cy_card[i].first_line) + break; + if (i >= NR_CARDS) + return -ENODEV; + info = &cy_card[i].ports[line - cy_card[i].first_line]; if (info->line < 0) { return -ENODEV; } @@ -2542,23 +2475,23 @@ static int cy_open(struct tty_struct *tty, struct file *filp) treat it as absent from the system. This will make the user pay attention. */ - if (IS_CYC_Z(cy_card[info->card])) { - struct cyclades_card *cinfo = &cy_card[info->card]; + if (IS_CYC_Z(*info->card)) { + struct cyclades_card *cinfo = info->card; struct FIRM_ID __iomem *firm_id = cinfo->base_addr + ID_ADDRESS; if (!ISZLOADED(*cinfo)) { - if (((ZE_V1 == cy_readl( - &((struct RUNTIME_9060 __iomem *) + if (((ZE_V1 == readl(&((struct RUNTIME_9060 __iomem *) (cinfo->ctl_addr))->mail_box_0)) && Z_FPGA_CHECK(*cinfo)) && - (ZFIRM_HLT == cy_readl( + (ZFIRM_HLT == readl( &firm_id->signature))) { - printk("cyc:Cyclades-Z Error: you need an " - "external power supply for this number " - "of ports.\n\rFirmware halted.\r\n"); + printk(KERN_ERR "cyc:Cyclades-Z Error: you " + "need an external power supply for " + "this number of ports.\nFirmware " + "halted.\n"); } else { - printk("cyc:Cyclades-Z firmware not yet " - "loaded\n"); + printk(KERN_ERR "cyc:Cyclades-Z firmware not " + "yet loaded\n"); } return -ENODEV; } @@ -2572,24 +2505,23 @@ static int cy_open(struct tty_struct *tty, struct file *filp) struct BOARD_CTRL __iomem *board_ctrl; zfw_ctrl = cinfo->base_addr + - (cy_readl(&firm_id->zfwctrl_addr) & - 0xfffff); + (readl(&firm_id->zfwctrl_addr) & + 0xfffff); board_ctrl = &zfw_ctrl->board_ctrl; /* Enable interrupts on the PLX chip */ cy_writew(cinfo->ctl_addr + 0x68, - cy_readw(cinfo->ctl_addr + - 0x68) | 0x0900); + readw(cinfo->ctl_addr + 0x68) | 0x0900); /* Enable interrupts on the FW */ retval = cyz_issue_cmd(cinfo, 0, C_CM_IRQ_ENBL, 0L); if (retval != 0) { - printk("cyc:IRQ enable retval was %x\n", - retval); + printk(KERN_ERR "cyc:IRQ enable retval " + "was %x\n", retval); } cinfo->nports = - (int)cy_readl(&board_ctrl->n_channel); + (int)readl(&board_ctrl->n_channel); cinfo->intr_enabled = 1; } } @@ -2599,7 +2531,7 @@ static int cy_open(struct tty_struct *tty, struct file *filp) return -ENODEV; } #ifdef CY_DEBUG_OTHER - printk("cyc:cy_open ttyC%d\n", info->line); /* */ + printk(KERN_DEBUG "cyc:cy_open ttyC%d\n", info->line); #endif tty->driver_data = info; info->tty = tty; @@ -2607,12 +2539,12 @@ static int cy_open(struct tty_struct *tty, struct file *filp) return -ENODEV; } #ifdef CY_DEBUG_OPEN - printk("cyc:cy_open ttyC%d, count = %d\n", info->line, info->count); - /**/ + printk(KERN_DEBUG "cyc:cy_open ttyC%d, count = %d\n", info->line, + info->count); #endif info->count++; #ifdef CY_DEBUG_COUNT - printk("cyc:cy_open (%d): incrementing count to %d\n", + printk(KERN_DEBUG "cyc:cy_open (%d): incrementing count to %d\n", current->pid, info->count); #endif @@ -2620,8 +2552,8 @@ static int cy_open(struct tty_struct *tty, struct file *filp) * If the port is the middle of closing, bail out now */ if (tty_hung_up_p(filp) || (info->flags & ASYNC_CLOSING)) { - if (info->flags & ASYNC_CLOSING) - interruptible_sleep_on(&info->close_wait); + wait_event_interruptible(info->close_wait, + !(info->flags & ASYNC_CLOSING)); return (info->flags & ASYNC_HUP_NOTIFY) ? -EAGAIN: -ERESTARTSYS; } @@ -2636,8 +2568,8 @@ static int cy_open(struct tty_struct *tty, struct file *filp) retval = block_til_ready(tty, filp, info); if (retval) { #ifdef CY_DEBUG_OPEN - printk("cyc:cy_open returning after block_til_ready with %d\n", - retval); + printk(KERN_DEBUG "cyc:cy_open returning after block_til_ready " + "with %d\n", retval); #endif return retval; } @@ -2645,8 +2577,7 @@ static int cy_open(struct tty_struct *tty, struct file *filp) info->throttle = 0; #ifdef CY_DEBUG_OPEN - printk(" cyc:cy_open done\n"); - /**/ + printk(KERN_DEBUG "cyc:cy_open done\n"); #endif return 0; } /* cy_open */ @@ -2656,9 +2587,10 @@ static int cy_open(struct tty_struct *tty, struct file *filp) */ static void cy_wait_until_sent(struct tty_struct *tty, int timeout) { - struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; + struct cyclades_card *card; + struct cyclades_port *info = tty->driver_data; void __iomem *base_addr; - int card, chip, channel, index; + int chip, channel, index; unsigned long orig_jiffies; int char_time; @@ -2697,20 +2629,19 @@ static void cy_wait_until_sent(struct tty_struct *tty, int timeout) if (!timeout || timeout > 2 * info->timeout) timeout = 2 * info->timeout; #ifdef CY_DEBUG_WAIT_UNTIL_SENT - printk("In cy_wait_until_sent(%d) check=%lu...", timeout, char_time); - printk("jiff=%lu...", jiffies); + printk(KERN_DEBUG "In cy_wait_until_sent(%d) check=%d, jiff=%lu...", + timeout, char_time, jiffies); #endif card = info->card; - channel = (info->line) - (cy_card[card].first_line); - if (!IS_CYC_Z(cy_card[card])) { + channel = (info->line) - (card->first_line); + if (!IS_CYC_Z(*card)) { chip = channel >> 2; channel &= 0x03; - index = cy_card[card].bus_index; - base_addr = - cy_card[card].base_addr + (cy_chip_offset[chip] << index); - while (cy_readb(base_addr + (CySRER << index)) & CyTxRdy) { + index = card->bus_index; + base_addr = card->base_addr + (cy_chip_offset[chip] << index); + while (readb(base_addr + (CySRER << index)) & CyTxRdy) { #ifdef CY_DEBUG_WAIT_UNTIL_SENT - printk("Not clean (jiff=%lu)...", jiffies); + printk(KERN_DEBUG "Not clean (jiff=%lu)...", jiffies); #endif if (msleep_interruptible(jiffies_to_msecs(char_time))) break; @@ -2718,13 +2649,11 @@ static void cy_wait_until_sent(struct tty_struct *tty, int timeout) timeout)) break; } - } else { - /* Nothing to do! */ } /* Run one more char cycle */ msleep_interruptible(jiffies_to_msecs(char_time * 5)); #ifdef CY_DEBUG_WAIT_UNTIL_SENT - printk("Clean (jiff=%lu)...done\n", jiffies); + printk(KERN_DEBUG "Clean (jiff=%lu)...done\n", jiffies); #endif } @@ -2733,25 +2662,29 @@ static void cy_wait_until_sent(struct tty_struct *tty, int timeout) */ static void cy_close(struct tty_struct *tty, struct file *filp) { - struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; + struct cyclades_port *info = tty->driver_data; + struct cyclades_card *card; unsigned long flags; #ifdef CY_DEBUG_OTHER - printk("cyc:cy_close ttyC%d\n", info->line); + printk(KERN_DEBUG "cyc:cy_close ttyC%d\n", info->line); #endif if (!info || serial_paranoia_check(info, tty->name, "cy_close")) { return; } - CY_LOCK(info, flags); + card = info->card; + + spin_lock_irqsave(&card->card_lock, flags); /* If the TTY is being hung up, nothing to do */ if (tty_hung_up_p(filp)) { - CY_UNLOCK(info, flags); + spin_unlock_irqrestore(&card->card_lock, flags); return; } #ifdef CY_DEBUG_OPEN - printk("cyc:cy_close ttyC%d, count = %d\n", info->line, info->count); + printk(KERN_DEBUG "cyc:cy_close ttyC%d, count = %d\n", info->line, + info->count); #endif if ((tty->count == 1) && (info->count != 1)) { /* @@ -2761,22 +2694,22 @@ static void cy_close(struct tty_struct *tty, struct file *filp) * one, we've got real problems, since it means the * serial port won't be shutdown. */ - printk("cyc:cy_close: bad serial port count; tty->count is 1, " - "info->count is %d\n", info->count); + printk(KERN_ERR "cyc:cy_close: bad serial port count; " + "tty->count is 1, info->count is %d\n", info->count); info->count = 1; } #ifdef CY_DEBUG_COUNT - printk("cyc:cy_close at (%d): decrementing count to %d\n", + printk(KERN_DEBUG "cyc:cy_close at (%d): decrementing count to %d\n", current->pid, info->count - 1); #endif if (--info->count < 0) { #ifdef CY_DEBUG_COUNT - printk("cyc:cyc_close setting count to 0\n"); + printk(KERN_DEBUG "cyc:cyc_close setting count to 0\n"); #endif info->count = 0; } if (info->count) { - CY_UNLOCK(info, flags); + spin_unlock_irqrestore(&card->card_lock, flags); return; } info->flags |= ASYNC_CLOSING; @@ -2786,81 +2719,80 @@ static void cy_close(struct tty_struct *tty, struct file *filp) * the line discipline to only process XON/XOFF characters. */ tty->closing = 1; - CY_UNLOCK(info, flags); + spin_unlock_irqrestore(&card->card_lock, flags); if (info->closing_wait != CY_CLOSING_WAIT_NONE) { tty_wait_until_sent(tty, info->closing_wait); } - CY_LOCK(info, flags); + spin_lock_irqsave(&card->card_lock, flags); - if (!IS_CYC_Z(cy_card[info->card])) { - int channel = info->line - cy_card[info->card].first_line; - int index = cy_card[info->card].bus_index; - void __iomem *base_addr = cy_card[info->card].base_addr + + if (!IS_CYC_Z(*card)) { + int channel = info->line - card->first_line; + int index = card->bus_index; + void __iomem *base_addr = card->base_addr + (cy_chip_offset[channel >> 2] << index); /* Stop accepting input */ channel &= 0x03; cy_writeb(base_addr + (CyCAR << index), (u_char) channel); cy_writeb(base_addr + (CySRER << index), - cy_readb(base_addr + (CySRER << index)) & ~CyRxData); + readb(base_addr + (CySRER << index)) & ~CyRxData); if (info->flags & ASYNC_INITIALIZED) { /* Waiting for on-board buffers to be empty before closing the port */ - CY_UNLOCK(info, flags); + spin_unlock_irqrestore(&card->card_lock, flags); cy_wait_until_sent(tty, info->timeout); - CY_LOCK(info, flags); + spin_lock_irqsave(&card->card_lock, flags); } } else { #ifdef Z_WAKE /* Waiting for on-board buffers to be empty before closing the port */ - void __iomem *base_addr = cy_card[info->card].base_addr; + void __iomem *base_addr = card->base_addr; struct FIRM_ID __iomem *firm_id = base_addr + ID_ADDRESS; struct ZFW_CTRL __iomem *zfw_ctrl = - base_addr + (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff); + base_addr + (readl(&firm_id->zfwctrl_addr) & 0xfffff); struct CH_CTRL __iomem *ch_ctrl = zfw_ctrl->ch_ctrl; - int channel = info->line - cy_card[info->card].first_line; + int channel = info->line - card->first_line; int retval; - if (cy_readl(&ch_ctrl[channel].flow_status) != C_FS_TXIDLE) { - retval = cyz_issue_cmd(&cy_card[info->card], channel, - C_CM_IOCTLW, 0L); + if (readl(&ch_ctrl[channel].flow_status) != C_FS_TXIDLE) { + retval = cyz_issue_cmd(card, channel, C_CM_IOCTLW, 0L); if (retval != 0) { - printk("cyc:cy_close retval on ttyC%d was %x\n", - info->line, retval); + printk(KERN_DEBUG "cyc:cy_close retval on " + "ttyC%d was %x\n", info->line, retval); } - CY_UNLOCK(info, flags); - interruptible_sleep_on(&info->shutdown_wait); - CY_LOCK(info, flags); + spin_unlock_irqrestore(&card->card_lock, flags); + wait_for_completion_interruptible(&info->shutdown_wait); + spin_lock_irqsave(&card->card_lock, flags); } #endif } - CY_UNLOCK(info, flags); + spin_unlock_irqrestore(&card->card_lock, flags); shutdown(info); if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); tty_ldisc_flush(tty); - CY_LOCK(info, flags); + spin_lock_irqsave(&card->card_lock, flags); tty->closing = 0; info->event = 0; info->tty = NULL; if (info->blocked_open) { - CY_UNLOCK(info, flags); + spin_unlock_irqrestore(&card->card_lock, flags); if (info->close_delay) { msleep_interruptible(jiffies_to_msecs (info->close_delay)); } wake_up_interruptible(&info->open_wait); - CY_LOCK(info, flags); + spin_lock_irqsave(&card->card_lock, flags); } info->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING); wake_up_interruptible(&info->close_wait); #ifdef CY_DEBUG_OTHER - printk(" cyc:cy_close done\n"); + printk(KERN_DEBUG "cyc:cy_close done\n"); #endif - CY_UNLOCK(info, flags); + spin_unlock_irqrestore(&card->card_lock, flags); } /* cy_close */ /* This routine gets called when tty_write has put something into @@ -2878,12 +2810,12 @@ static void cy_close(struct tty_struct *tty, struct file *filp) */ static int cy_write(struct tty_struct *tty, const unsigned char *buf, int count) { - struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; + struct cyclades_port *info = tty->driver_data; unsigned long flags; int c, ret = 0; #ifdef CY_DEBUG_IO - printk("cyc:cy_write ttyC%d\n", info->line); /* */ + printk(KERN_DEBUG "cyc:cy_write ttyC%d\n", info->line); #endif if (serial_paranoia_check(info, tty->name, "cy_write")) { @@ -2893,7 +2825,7 @@ static int cy_write(struct tty_struct *tty, const unsigned char *buf, int count) if (!info->xmit_buf) return 0; - CY_LOCK(info, flags); + spin_lock_irqsave(&info->card->card_lock, flags); while (1) { c = min(count, min((int)(SERIAL_XMIT_SIZE - info->xmit_cnt - 1), (int)(SERIAL_XMIT_SIZE - info->xmit_head))); @@ -2909,7 +2841,7 @@ static int cy_write(struct tty_struct *tty, const unsigned char *buf, int count) count -= c; ret += c; } - CY_UNLOCK(info, flags); + spin_unlock_irqrestore(&info->card->card_lock, flags); info->idle_stats.xmit_bytes += ret; info->idle_stats.xmit_idle = jiffies; @@ -2929,11 +2861,11 @@ static int cy_write(struct tty_struct *tty, const unsigned char *buf, int count) */ static void cy_put_char(struct tty_struct *tty, unsigned char ch) { - struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; + struct cyclades_port *info = tty->driver_data; unsigned long flags; #ifdef CY_DEBUG_IO - printk("cyc:cy_put_char ttyC%d\n", info->line); + printk(KERN_DEBUG "cyc:cy_put_char ttyC%d\n", info->line); #endif if (serial_paranoia_check(info, tty->name, "cy_put_char")) @@ -2942,9 +2874,9 @@ static void cy_put_char(struct tty_struct *tty, unsigned char ch) if (!info->xmit_buf) return; - CY_LOCK(info, flags); + spin_lock_irqsave(&info->card->card_lock, flags); if (info->xmit_cnt >= (int)(SERIAL_XMIT_SIZE - 1)) { - CY_UNLOCK(info, flags); + spin_unlock_irqrestore(&info->card->card_lock, flags); return; } @@ -2953,7 +2885,7 @@ static void cy_put_char(struct tty_struct *tty, unsigned char ch) info->xmit_cnt++; info->idle_stats.xmit_bytes++; info->idle_stats.xmit_idle = jiffies; - CY_UNLOCK(info, flags); + spin_unlock_irqrestore(&info->card->card_lock, flags); } /* cy_put_char */ /* @@ -2962,10 +2894,10 @@ static void cy_put_char(struct tty_struct *tty, unsigned char ch) */ static void cy_flush_chars(struct tty_struct *tty) { - struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; + struct cyclades_port *info = tty->driver_data; #ifdef CY_DEBUG_IO - printk("cyc:cy_flush_chars ttyC%d\n", info->line); /* */ + printk(KERN_DEBUG "cyc:cy_flush_chars ttyC%d\n", info->line); #endif if (serial_paranoia_check(info, tty->name, "cy_flush_chars")) @@ -2986,11 +2918,11 @@ static void cy_flush_chars(struct tty_struct *tty) */ static int cy_write_room(struct tty_struct *tty) { - struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; + struct cyclades_port *info = tty->driver_data; int ret; #ifdef CY_DEBUG_IO - printk("cyc:cy_write_room ttyC%d\n", info->line); /* */ + printk(KERN_DEBUG "cyc:cy_write_room ttyC%d\n", info->line); #endif if (serial_paranoia_check(info, tty->name, "cy_write_room")) @@ -3003,46 +2935,49 @@ static int cy_write_room(struct tty_struct *tty) static int cy_chars_in_buffer(struct tty_struct *tty) { - struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; - int card, channel; + struct cyclades_card *card; + struct cyclades_port *info = tty->driver_data; + int channel; if (serial_paranoia_check(info, tty->name, "cy_chars_in_buffer")) return 0; card = info->card; - channel = (info->line) - (cy_card[card].first_line); + channel = (info->line) - (card->first_line); #ifdef Z_EXT_CHARS_IN_BUFFER if (!IS_CYC_Z(cy_card[card])) { #endif /* Z_EXT_CHARS_IN_BUFFER */ #ifdef CY_DEBUG_IO - printk("cyc:cy_chars_in_buffer ttyC%d %d\n", info->line, info->xmit_cnt); /* */ + printk(KERN_DEBUG "cyc:cy_chars_in_buffer ttyC%d %d\n", + info->line, info->xmit_cnt); #endif return info->xmit_cnt; #ifdef Z_EXT_CHARS_IN_BUFFER } else { - static volatile struct FIRM_ID *firm_id; - static volatile struct ZFW_CTRL *zfw_ctrl; - static volatile struct CH_CTRL *ch_ctrl; - static volatile struct BUF_CTRL *buf_ctrl; + static struct FIRM_ID *firm_id; + static struct ZFW_CTRL *zfw_ctrl; + static struct CH_CTRL *ch_ctrl; + static struct BUF_CTRL *buf_ctrl; int char_count; - volatile uclong tx_put, tx_get, tx_bufsize; + __u32 tx_put, tx_get, tx_bufsize; - firm_id = cy_card[card].base_addr + ID_ADDRESS; - zfw_ctrl = cy_card[card].base_addr + - (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff); + firm_id = card->base_addr + ID_ADDRESS; + zfw_ctrl = card->base_addr + + (readl(&firm_id->zfwctrl_addr) & 0xfffff); ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]); buf_ctrl = &(zfw_ctrl->buf_ctrl[channel]); - tx_get = cy_readl(&buf_ctrl->tx_get); - tx_put = cy_readl(&buf_ctrl->tx_put); - tx_bufsize = cy_readl(&buf_ctrl->tx_bufsize); + tx_get = readl(&buf_ctrl->tx_get); + tx_put = readl(&buf_ctrl->tx_put); + tx_bufsize = readl(&buf_ctrl->tx_bufsize); if (tx_put >= tx_get) char_count = tx_put - tx_get; else char_count = tx_put - tx_get + tx_bufsize; #ifdef CY_DEBUG_IO - printk("cyc:cy_chars_in_buffer ttyC%d %d\n", info->line, info->xmit_cnt + char_count); /* */ + printk(KERN_DEBUG "cyc:cy_chars_in_buffer ttyC%d %d\n", + info->line, info->xmit_cnt + char_count); #endif return info->xmit_cnt + char_count; } @@ -3055,10 +2990,10 @@ static int cy_chars_in_buffer(struct tty_struct *tty) * ------------------------------------------------------------ */ -static void cyy_baud_calc(struct cyclades_port *info, uclong baud) +static void cyy_baud_calc(struct cyclades_port *info, __u32 baud) { int co, co_val, bpr; - uclong cy_clock = ((info->chip_rev >= CD1400_REV_J) ? 60000000 : + __u32 cy_clock = ((info->chip_rev >= CD1400_REV_J) ? 60000000 : 25000000); if (baud == 0) { @@ -3086,9 +3021,10 @@ static void cyy_baud_calc(struct cyclades_port *info, uclong baud) */ static void set_line_char(struct cyclades_port *info) { + struct cyclades_card *card; unsigned long flags; void __iomem *base_addr; - int card, chip, channel, index; + int chip, channel, index; unsigned cflag, iflag; unsigned short chip_number; int baud, baud_rate = 0; @@ -3118,12 +3054,12 @@ static void set_line_char(struct cyclades_port *info) } card = info->card; - channel = (info->line) - (cy_card[card].first_line); + channel = info->line - card->first_line; chip_number = channel / 4; - if (!IS_CYC_Z(cy_card[card])) { + if (!IS_CYC_Z(*card)) { - index = cy_card[card].bus_index; + index = card->bus_index; /* baud rate */ baud = tty_get_baud_rate(info->tty); @@ -3241,10 +3177,9 @@ static void set_line_char(struct cyclades_port *info) chip = channel >> 2; channel &= 0x03; - base_addr = cy_card[card].base_addr + - (cy_chip_offset[chip] << index); + base_addr = card->base_addr + (cy_chip_offset[chip] << index); - CY_LOCK(info, flags); + spin_lock_irqsave(&card->card_lock, flags); cy_writeb(base_addr + (CyCAR << index), (u_char) channel); /* tx and rx baud rate */ @@ -3276,8 +3211,7 @@ static void set_line_char(struct cyclades_port *info) if (C_CLOCAL(info->tty)) { /* without modem intr */ cy_writeb(base_addr + (CySRER << index), - cy_readb(base_addr + - (CySRER << index)) | CyMdmCh); + readb(base_addr + (CySRER << index)) | CyMdmCh); /* act on 1->0 modem transitions */ if ((cflag & CRTSCTS) && info->rflow) { cy_writeb(base_addr + (CyMCOR1 << index), @@ -3291,7 +3225,7 @@ static void set_line_char(struct cyclades_port *info) } else { /* without modem intr */ cy_writeb(base_addr + (CySRER << index), - cy_readb(base_addr + + readb(base_addr + (CySRER << index)) | CyMdmCh); /* act on 1->0 modem transitions */ if ((cflag & CRTSCTS) && info->rflow) { @@ -3316,10 +3250,10 @@ static void set_line_char(struct cyclades_port *info) ~CyDTR); } #ifdef CY_DEBUG_DTR - printk("cyc:set_line_char dropping DTR\n"); - printk(" status: 0x%x, 0x%x\n", - cy_readb(base_addr + (CyMSVR1 << index)), - cy_readb(base_addr + (CyMSVR2 << index))); + printk(KERN_DEBUG "cyc:set_line_char dropping DTR\n"); + printk(KERN_DEBUG " status: 0x%x, 0x%x\n", + readb(base_addr + (CyMSVR1 << index)), + readb(base_addr + (CyMSVR2 << index))); #endif } else { if (info->rtsdtr_inv) { @@ -3330,17 +3264,17 @@ static void set_line_char(struct cyclades_port *info) CyDTR); } #ifdef CY_DEBUG_DTR - printk("cyc:set_line_char raising DTR\n"); - printk(" status: 0x%x, 0x%x\n", - cy_readb(base_addr + (CyMSVR1 << index)), - cy_readb(base_addr + (CyMSVR2 << index))); + printk(KERN_DEBUG "cyc:set_line_char raising DTR\n"); + printk(KERN_DEBUG " status: 0x%x, 0x%x\n", + readb(base_addr + (CyMSVR1 << index)), + readb(base_addr + (CyMSVR2 << index))); #endif } if (info->tty) { clear_bit(TTY_IO_ERROR, &info->tty->flags); } - CY_UNLOCK(info, flags); + spin_unlock_irqrestore(&card->card_lock, flags); } else { struct FIRM_ID __iomem *firm_id; @@ -3348,16 +3282,16 @@ static void set_line_char(struct cyclades_port *info) struct BOARD_CTRL __iomem *board_ctrl; struct CH_CTRL __iomem *ch_ctrl; struct BUF_CTRL __iomem *buf_ctrl; - uclong sw_flow; + __u32 sw_flow; int retval; - firm_id = cy_card[card].base_addr + ID_ADDRESS; - if (!ISZLOADED(cy_card[card])) { + firm_id = card->base_addr + ID_ADDRESS; + if (!ISZLOADED(*card)) { return; } - zfw_ctrl = cy_card[card].base_addr + - (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff); + zfw_ctrl = card->base_addr + + (readl(&firm_id->zfwctrl_addr) & 0xfffff); board_ctrl = &zfw_ctrl->board_ctrl; ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]); buf_ctrl = &zfw_ctrl->buf_ctrl[channel]; @@ -3408,10 +3342,10 @@ static void set_line_char(struct cyclades_port *info) } if (cflag & CSTOPB) { cy_writel(&ch_ctrl->comm_data_l, - cy_readl(&ch_ctrl->comm_data_l) | C_DL_2STOP); + readl(&ch_ctrl->comm_data_l) | C_DL_2STOP); } else { cy_writel(&ch_ctrl->comm_data_l, - cy_readl(&ch_ctrl->comm_data_l) | C_DL_1STOP); + readl(&ch_ctrl->comm_data_l) | C_DL_1STOP); } if (cflag & PARENB) { if (cflag & PARODD) { @@ -3426,12 +3360,10 @@ static void set_line_char(struct cyclades_port *info) /* CTS flow control flag */ if (cflag & CRTSCTS) { cy_writel(&ch_ctrl->hw_flow, - cy_readl(&ch_ctrl-> - hw_flow) | C_RS_CTS | C_RS_RTS); + readl(&ch_ctrl->hw_flow) | C_RS_CTS | C_RS_RTS); } else { - cy_writel(&ch_ctrl->hw_flow, - cy_readl(&ch_ctrl-> - hw_flow) & ~(C_RS_CTS | C_RS_RTS)); + cy_writel(&ch_ctrl->hw_flow, readl(&ch_ctrl->hw_flow) & + ~(C_RS_CTS | C_RS_RTS)); } /* As the HW flow control is done in firmware, the driver doesn't need to care about it */ @@ -3446,10 +3378,10 @@ static void set_line_char(struct cyclades_port *info) } cy_writel(&ch_ctrl->sw_flow, sw_flow); - retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_IOCTL, 0L); + retval = cyz_issue_cmd(card, channel, C_CM_IOCTL, 0L); if (retval != 0) { - printk("cyc:set_line_char retval on ttyC%d was %x\n", - info->line, retval); + printk(KERN_ERR "cyc:set_line_char retval on ttyC%d " + "was %x\n", info->line, retval); } /* CD sensitivity */ @@ -3461,22 +3393,22 @@ static void set_line_char(struct cyclades_port *info) if (baud == 0) { /* baud rate is zero, turn off line */ cy_writel(&ch_ctrl->rs_control, - cy_readl(&ch_ctrl->rs_control) & ~C_RS_DTR); + readl(&ch_ctrl->rs_control) & ~C_RS_DTR); #ifdef CY_DEBUG_DTR - printk("cyc:set_line_char dropping Z DTR\n"); + printk(KERN_DEBUG "cyc:set_line_char dropping Z DTR\n"); #endif } else { cy_writel(&ch_ctrl->rs_control, - cy_readl(&ch_ctrl->rs_control) | C_RS_DTR); + readl(&ch_ctrl->rs_control) | C_RS_DTR); #ifdef CY_DEBUG_DTR - printk("cyc:set_line_char raising Z DTR\n"); + printk(KERN_DEBUG "cyc:set_line_char raising Z DTR\n"); #endif } - retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_IOCTLM,0L); + retval = cyz_issue_cmd(card, channel, C_CM_IOCTLM,0L); if (retval != 0) { - printk("cyc:set_line_char(2) retval on ttyC%d was %x\n", - info->line, retval); + printk(KERN_ERR "cyc:set_line_char(2) retval on ttyC%d " + "was %x\n", info->line, retval); } if (info->tty) { @@ -3490,14 +3422,15 @@ get_serial_info(struct cyclades_port *info, struct serial_struct __user * retinfo) { struct serial_struct tmp; - struct cyclades_card *cinfo = &cy_card[info->card]; + struct cyclades_card *cinfo = info->card; if (!retinfo) return -EFAULT; memset(&tmp, 0, sizeof(tmp)); tmp.type = info->type; tmp.line = info->line; - tmp.port = info->card * 0x100 + info->line - cinfo->first_line; + tmp.port = (info->card - cy_card) * 0x100 + info->line - + cinfo->first_line; tmp.irq = cinfo->irq; tmp.flags = info->flags; tmp.close_delay = info->close_delay; @@ -3566,25 +3499,25 @@ check_and_exit: */ static int get_lsr_info(struct cyclades_port *info, unsigned int __user * value) { - int card, chip, channel, index; + struct cyclades_card *card; + int chip, channel, index; unsigned char status; unsigned int result; unsigned long flags; void __iomem *base_addr; card = info->card; - channel = (info->line) - (cy_card[card].first_line); - if (!IS_CYC_Z(cy_card[card])) { + channel = (info->line) - (card->first_line); + if (!IS_CYC_Z(*card)) { chip = channel >> 2; channel &= 0x03; - index = cy_card[card].bus_index; - base_addr = - cy_card[card].base_addr + (cy_chip_offset[chip] << index); + index = card->bus_index; + base_addr = card->base_addr + (cy_chip_offset[chip] << index); - CY_LOCK(info, flags); - status = cy_readb(base_addr + (CySRER << index)) & + spin_lock_irqsave(&card->card_lock, flags); + status = readb(base_addr + (CySRER << index)) & (CyTxRdy | CyTxMpty); - CY_UNLOCK(info, flags); + spin_unlock_irqrestore(&card->card_lock, flags); result = (status ? 0 : TIOCSER_TEMT); } else { /* Not supported yet */ @@ -3595,8 +3528,9 @@ static int get_lsr_info(struct cyclades_port *info, unsigned int __user * value) static int cy_tiocmget(struct tty_struct *tty, struct file *file) { - struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; - int card, chip, channel, index; + struct cyclades_port *info = tty->driver_data; + struct cyclades_card *card; + int chip, channel, index; void __iomem *base_addr; unsigned long flags; unsigned char status; @@ -3611,19 +3545,18 @@ static int cy_tiocmget(struct tty_struct *tty, struct file *file) return -ENODEV; card = info->card; - channel = (info->line) - (cy_card[card].first_line); - if (!IS_CYC_Z(cy_card[card])) { + channel = info->line - card->first_line; + if (!IS_CYC_Z(*card)) { chip = channel >> 2; channel &= 0x03; - index = cy_card[card].bus_index; - base_addr = - cy_card[card].base_addr + (cy_chip_offset[chip] << index); + index = card->bus_index; + base_addr = card->base_addr + (cy_chip_offset[chip] << index); - CY_LOCK(info, flags); + spin_lock_irqsave(&card->card_lock, flags); cy_writeb(base_addr + (CyCAR << index), (u_char) channel); - status = cy_readb(base_addr + (CyMSVR1 << index)); - status |= cy_readb(base_addr + (CyMSVR2 << index)); - CY_UNLOCK(info, flags); + status = readb(base_addr + (CyMSVR1 << index)); + status |= readb(base_addr + (CyMSVR2 << index)); + spin_unlock_irqrestore(&card->card_lock, flags); if (info->rtsdtr_inv) { result = ((status & CyRTS) ? TIOCM_DTR : 0) | @@ -3637,19 +3570,14 @@ static int cy_tiocmget(struct tty_struct *tty, struct file *file) ((status & CyDSR) ? TIOCM_DSR : 0) | ((status & CyCTS) ? TIOCM_CTS : 0); } else { - base_addr = cy_card[card].base_addr; - - if (cy_card[card].num_chips != -1) { - return -EINVAL; - } - - firm_id = cy_card[card].base_addr + ID_ADDRESS; - if (ISZLOADED(cy_card[card])) { - zfw_ctrl = cy_card[card].base_addr + - (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff); + base_addr = card->base_addr; + firm_id = card->base_addr + ID_ADDRESS; + if (ISZLOADED(*card)) { + zfw_ctrl = card->base_addr + + (readl(&firm_id->zfwctrl_addr) & 0xfffff); board_ctrl = &zfw_ctrl->board_ctrl; ch_ctrl = zfw_ctrl->ch_ctrl; - lstatus = cy_readl(&ch_ctrl[channel].rs_status); + lstatus = readl(&ch_ctrl[channel].rs_status); result = ((lstatus & C_RS_RTS) ? TIOCM_RTS : 0) | ((lstatus & C_RS_DTR) ? TIOCM_DTR : 0) | ((lstatus & C_RS_DCD) ? TIOCM_CAR : 0) | @@ -3669,8 +3597,9 @@ static int cy_tiocmset(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear) { - struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; - int card, chip, channel, index; + struct cyclades_port *info = tty->driver_data; + struct cyclades_card *card; + int chip, channel, index; void __iomem *base_addr; unsigned long flags; struct FIRM_ID __iomem *firm_id; @@ -3683,16 +3612,15 @@ cy_tiocmset(struct tty_struct *tty, struct file *file, return -ENODEV; card = info->card; - channel = (info->line) - (cy_card[card].first_line); - if (!IS_CYC_Z(cy_card[card])) { + channel = (info->line) - (card->first_line); + if (!IS_CYC_Z(*card)) { chip = channel >> 2; channel &= 0x03; - index = cy_card[card].bus_index; - base_addr = - cy_card[card].base_addr + (cy_chip_offset[chip] << index); + index = card->bus_index; + base_addr = card->base_addr + (cy_chip_offset[chip] << index); if (set & TIOCM_RTS) { - CY_LOCK(info, flags); + spin_lock_irqsave(&card->card_lock, flags); cy_writeb(base_addr + (CyCAR << index), (u_char) channel); if (info->rtsdtr_inv) { @@ -3702,10 +3630,10 @@ cy_tiocmset(struct tty_struct *tty, struct file *file, cy_writeb(base_addr + (CyMSVR1 << index), CyRTS); } - CY_UNLOCK(info, flags); + spin_unlock_irqrestore(&card->card_lock, flags); } if (clear & TIOCM_RTS) { - CY_LOCK(info, flags); + spin_lock_irqsave(&card->card_lock, flags); cy_writeb(base_addr + (CyCAR << index), (u_char) channel); if (info->rtsdtr_inv) { @@ -3715,10 +3643,10 @@ cy_tiocmset(struct tty_struct *tty, struct file *file, cy_writeb(base_addr + (CyMSVR1 << index), ~CyRTS); } - CY_UNLOCK(info, flags); + spin_unlock_irqrestore(&card->card_lock, flags); } if (set & TIOCM_DTR) { - CY_LOCK(info, flags); + spin_lock_irqsave(&card->card_lock, flags); cy_writeb(base_addr + (CyCAR << index), (u_char) channel); if (info->rtsdtr_inv) { @@ -3729,15 +3657,15 @@ cy_tiocmset(struct tty_struct *tty, struct file *file, CyDTR); } #ifdef CY_DEBUG_DTR - printk("cyc:set_modem_info raising DTR\n"); - printk(" status: 0x%x, 0x%x\n", - cy_readb(base_addr + (CyMSVR1 << index)), - cy_readb(base_addr + (CyMSVR2 << index))); + printk(KERN_DEBUG "cyc:set_modem_info raising DTR\n"); + printk(KERN_DEBUG " status: 0x%x, 0x%x\n", + readb(base_addr + (CyMSVR1 << index)), + readb(base_addr + (CyMSVR2 << index))); #endif - CY_UNLOCK(info, flags); + spin_unlock_irqrestore(&card->card_lock, flags); } if (clear & TIOCM_DTR) { - CY_LOCK(info, flags); + spin_lock_irqsave(&card->card_lock, flags); cy_writeb(base_addr + (CyCAR << index), (u_char) channel); if (info->rtsdtr_inv) { @@ -3749,68 +3677,69 @@ cy_tiocmset(struct tty_struct *tty, struct file *file, } #ifdef CY_DEBUG_DTR - printk("cyc:set_modem_info dropping DTR\n"); - printk(" status: 0x%x, 0x%x\n", - cy_readb(base_addr + (CyMSVR1 << index)), - cy_readb(base_addr + (CyMSVR2 << index))); + printk(KERN_DEBUG "cyc:set_modem_info dropping DTR\n"); + printk(KERN_DEBUG " status: 0x%x, 0x%x\n", + readb(base_addr + (CyMSVR1 << index)), + readb(base_addr + (CyMSVR2 << index))); #endif - CY_UNLOCK(info, flags); + spin_unlock_irqrestore(&card->card_lock, flags); } } else { - base_addr = cy_card[card].base_addr; + base_addr = card->base_addr; - firm_id = cy_card[card].base_addr + ID_ADDRESS; - if (ISZLOADED(cy_card[card])) { - zfw_ctrl = cy_card[card].base_addr + - (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff); + firm_id = card->base_addr + ID_ADDRESS; + if (ISZLOADED(*card)) { + zfw_ctrl = card->base_addr + + (readl(&firm_id->zfwctrl_addr) & 0xfffff); board_ctrl = &zfw_ctrl->board_ctrl; ch_ctrl = zfw_ctrl->ch_ctrl; if (set & TIOCM_RTS) { - CY_LOCK(info, flags); + spin_lock_irqsave(&card->card_lock, flags); cy_writel(&ch_ctrl[channel].rs_control, - cy_readl(&ch_ctrl[channel]. - rs_control) | C_RS_RTS); - CY_UNLOCK(info, flags); + readl(&ch_ctrl[channel].rs_control) | + C_RS_RTS); + spin_unlock_irqrestore(&card->card_lock, flags); } if (clear & TIOCM_RTS) { - CY_LOCK(info, flags); + spin_lock_irqsave(&card->card_lock, flags); cy_writel(&ch_ctrl[channel].rs_control, - cy_readl(&ch_ctrl[channel]. - rs_control) & ~C_RS_RTS); - CY_UNLOCK(info, flags); + readl(&ch_ctrl[channel].rs_control) & + ~C_RS_RTS); + spin_unlock_irqrestore(&card->card_lock, flags); } if (set & TIOCM_DTR) { - CY_LOCK(info, flags); + spin_lock_irqsave(&card->card_lock, flags); cy_writel(&ch_ctrl[channel].rs_control, - cy_readl(&ch_ctrl[channel]. - rs_control) | C_RS_DTR); + readl(&ch_ctrl[channel].rs_control) | + C_RS_DTR); #ifdef CY_DEBUG_DTR - printk("cyc:set_modem_info raising Z DTR\n"); + printk(KERN_DEBUG "cyc:set_modem_info raising " + "Z DTR\n"); #endif - CY_UNLOCK(info, flags); + spin_unlock_irqrestore(&card->card_lock, flags); } if (clear & TIOCM_DTR) { - CY_LOCK(info, flags); + spin_lock_irqsave(&card->card_lock, flags); cy_writel(&ch_ctrl[channel].rs_control, - cy_readl(&ch_ctrl[channel]. - rs_control) & ~C_RS_DTR); + readl(&ch_ctrl[channel].rs_control) & + ~C_RS_DTR); #ifdef CY_DEBUG_DTR - printk("cyc:set_modem_info clearing Z DTR\n"); + printk(KERN_DEBUG "cyc:set_modem_info clearing " + "Z DTR\n"); #endif - CY_UNLOCK(info, flags); + spin_unlock_irqrestore(&card->card_lock, flags); } } else { return -ENODEV; } - CY_LOCK(info, flags); - retval = cyz_issue_cmd(&cy_card[info->card], - channel, C_CM_IOCTLM, 0L); + spin_lock_irqsave(&card->card_lock, flags); + retval = cyz_issue_cmd(card, channel, C_CM_IOCTLM, 0L); if (retval != 0) { - printk("cyc:set_modem_info retval on ttyC%d was %x\n", - info->line, retval); + printk(KERN_ERR "cyc:set_modem_info retval on ttyC%d " + "was %x\n", info->line, retval); } - CY_UNLOCK(info, flags); + spin_unlock_irqrestore(&card->card_lock, flags); } return 0; } /* cy_tiocmset */ @@ -3820,14 +3749,17 @@ cy_tiocmset(struct tty_struct *tty, struct file *file, */ static void cy_break(struct tty_struct *tty, int break_state) { - struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; + struct cyclades_port *info = tty->driver_data; + struct cyclades_card *card; unsigned long flags; if (serial_paranoia_check(info, tty->name, "cy_break")) return; - CY_LOCK(info, flags); - if (!IS_CYC_Z(cy_card[info->card])) { + card = info->card; + + spin_lock_irqsave(&card->card_lock, flags); + if (!IS_CYC_Z(*card)) { /* Let the transmit ISR take care of this (since it requires stuffing characters into the output stream). */ @@ -3835,18 +3767,18 @@ static void cy_break(struct tty_struct *tty, int break_state) if (!info->breakon) { info->breakon = 1; if (!info->xmit_cnt) { - CY_UNLOCK(info, flags); + spin_unlock_irqrestore(&card->card_lock, flags); start_xmit(info); - CY_LOCK(info, flags); + spin_lock_irqsave(&card->card_lock, flags); } } } else { if (!info->breakoff) { info->breakoff = 1; if (!info->xmit_cnt) { - CY_UNLOCK(info, flags); + spin_unlock_irqrestore(&card->card_lock, flags); start_xmit(info); - CY_LOCK(info, flags); + spin_lock_irqsave(&card->card_lock, flags); } } } @@ -3854,24 +3786,25 @@ static void cy_break(struct tty_struct *tty, int break_state) int retval; if (break_state == -1) { - retval = cyz_issue_cmd(&cy_card[info->card], - info->line - cy_card[info->card].first_line, + retval = cyz_issue_cmd(card, + info->line - card->first_line, C_CM_SET_BREAK, 0L); if (retval != 0) { - printk("cyc:cy_break (set) retval on ttyC%d " - "was %x\n", info->line, retval); + printk(KERN_ERR "cyc:cy_break (set) retval on " + "ttyC%d was %x\n", info->line, retval); } } else { - retval = cyz_issue_cmd(&cy_card[info->card], - info->line - cy_card[info->card].first_line, + retval = cyz_issue_cmd(card, + info->line - card->first_line, C_CM_CLR_BREAK, 0L); if (retval != 0) { - printk("cyc:cy_break (clr) retval on ttyC%d " - "was %x\n", info->line, retval); + printk(KERN_DEBUG "cyc:cy_break (clr) retval " + "on ttyC%d was %x\n", info->line, + retval); } } } - CY_UNLOCK(info, flags); + spin_unlock_irqrestore(&card->card_lock, flags); } /* cy_break */ static int @@ -3889,28 +3822,27 @@ get_mon_info(struct cyclades_port *info, struct cyclades_monitor __user * mon) static int set_threshold(struct cyclades_port *info, unsigned long value) { + struct cyclades_card *card; void __iomem *base_addr; - int card, channel, chip, index; + int channel, chip, index; unsigned long flags; card = info->card; - channel = info->line - cy_card[card].first_line; - if (!IS_CYC_Z(cy_card[card])) { + channel = info->line - card->first_line; + if (!IS_CYC_Z(*card)) { chip = channel >> 2; channel &= 0x03; - index = cy_card[card].bus_index; + index = card->bus_index; base_addr = - cy_card[card].base_addr + (cy_chip_offset[chip] << index); + card->base_addr + (cy_chip_offset[chip] << index); info->cor3 &= ~CyREC_FIFO; info->cor3 |= value & CyREC_FIFO; - CY_LOCK(info, flags); + spin_lock_irqsave(&card->card_lock, flags); cy_writeb(base_addr + (CyCOR3 << index), info->cor3); cyy_issue_cmd(base_addr, CyCOR_CHANGE | CyCOR3ch, index); - CY_UNLOCK(info, flags); - } else { - /* Nothing to do! */ + spin_unlock_irqrestore(&card->card_lock, flags); } return 0; } /* set_threshold */ @@ -3918,25 +3850,23 @@ static int set_threshold(struct cyclades_port *info, unsigned long value) static int get_threshold(struct cyclades_port *info, unsigned long __user * value) { + struct cyclades_card *card; void __iomem *base_addr; - int card, channel, chip, index; + int channel, chip, index; unsigned long tmp; card = info->card; - channel = info->line - cy_card[card].first_line; - if (!IS_CYC_Z(cy_card[card])) { + channel = info->line - card->first_line; + if (!IS_CYC_Z(*card)) { chip = channel >> 2; channel &= 0x03; - index = cy_card[card].bus_index; - base_addr = - cy_card[card].base_addr + (cy_chip_offset[chip] << index); + index = card->bus_index; + base_addr = card->base_addr + (cy_chip_offset[chip] << index); - tmp = cy_readb(base_addr + (CyCOR3 << index)) & CyREC_FIFO; + tmp = readb(base_addr + (CyCOR3 << index)) & CyREC_FIFO; return put_user(tmp, value); - } else { - /* Nothing to do! */ - return 0; } + return 0; } /* get_threshold */ static int @@ -3954,49 +3884,45 @@ get_default_threshold(struct cyclades_port *info, unsigned long __user * value) static int set_timeout(struct cyclades_port *info, unsigned long value) { + struct cyclades_card *card; void __iomem *base_addr; - int card, channel, chip, index; + int channel, chip, index; unsigned long flags; card = info->card; - channel = info->line - cy_card[card].first_line; - if (!IS_CYC_Z(cy_card[card])) { + channel = info->line - card->first_line; + if (!IS_CYC_Z(*card)) { chip = channel >> 2; channel &= 0x03; - index = cy_card[card].bus_index; - base_addr = - cy_card[card].base_addr + (cy_chip_offset[chip] << index); + index = card->bus_index; + base_addr = card->base_addr + (cy_chip_offset[chip] << index); - CY_LOCK(info, flags); + spin_lock_irqsave(&card->card_lock, flags); cy_writeb(base_addr + (CyRTPR << index), value & 0xff); - CY_UNLOCK(info, flags); - } else { - /* Nothing to do! */ + spin_unlock_irqrestore(&card->card_lock, flags); } return 0; } /* set_timeout */ static int get_timeout(struct cyclades_port *info, unsigned long __user * value) { + struct cyclades_card *card; void __iomem *base_addr; - int card, channel, chip, index; + int channel, chip, index; unsigned long tmp; card = info->card; - channel = info->line - cy_card[card].first_line; - if (!IS_CYC_Z(cy_card[card])) { + channel = info->line - card->first_line; + if (!IS_CYC_Z(*card)) { chip = channel >> 2; channel &= 0x03; - index = cy_card[card].bus_index; - base_addr = - cy_card[card].base_addr + (cy_chip_offset[chip] << index); + index = card->bus_index; + base_addr = card->base_addr + (cy_chip_offset[chip] << index); - tmp = cy_readb(base_addr + (CyRTPR << index)); + tmp = readb(base_addr + (CyRTPR << index)); return put_user(tmp, value); - } else { - /* Nothing to do! */ - return 0; } + return 0; } /* get_timeout */ static int set_default_timeout(struct cyclades_port *info, unsigned long value) @@ -4020,7 +3946,7 @@ static int cy_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg) { - struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; + struct cyclades_port *info = tty->driver_data; struct cyclades_icount cprev, cnow; /* kernel counter temps */ struct serial_icounter_struct __user *p_cuser; /* user space */ int ret_val = 0; @@ -4031,7 +3957,8 @@ cy_ioctl(struct tty_struct *tty, struct file *file, return -ENODEV; #ifdef CY_DEBUG_OTHER - printk("cyc:cy_ioctl ttyC%d, cmd = %x arg = %lx\n", info->line, cmd, arg); /* */ + printk(KERN_DEBUG "cyc:cy_ioctl ttyC%d, cmd = %x arg = %lx\n", + info->line, cmd, arg); #endif switch (cmd) { @@ -4076,14 +4003,6 @@ cy_ioctl(struct tty_struct *tty, struct file *file, case CYGETRTSDTR_INV: ret_val = info->rtsdtr_inv; break; - case CYGETCARDINFO: - if (copy_to_user(argp, &cy_card[info->card], - sizeof(struct cyclades_card))) { - ret_val = -EFAULT; - break; - } - ret_val = 0; - break; case CYGETCD1400VER: ret_val = info->chip_rev; break; @@ -4119,34 +4038,22 @@ cy_ioctl(struct tty_struct *tty, struct file *file, * Caller should use TIOCGICOUNT to see which one it was */ case TIOCMIWAIT: - CY_LOCK(info, flags); + spin_lock_irqsave(&info->card->card_lock, flags); /* note the counters on entry */ - cprev = info->icount; - CY_UNLOCK(info, flags); - while (1) { - interruptible_sleep_on(&info->delta_msr_wait); - /* see if a signal did it */ - if (signal_pending(current)) { - return -ERESTARTSYS; - } - - CY_LOCK(info, flags); + cnow = info->icount; + spin_unlock_irqrestore(&info->card->card_lock, flags); + ret_val = wait_event_interruptible(info->delta_msr_wait, ({ + cprev = cnow; + spin_lock_irqsave(&info->card->card_lock, flags); cnow = info->icount; /* atomic copy */ - CY_UNLOCK(info, flags); + spin_unlock_irqrestore(&info->card->card_lock, flags); - if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && - cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) { - return -EIO; /* no change => error */ - } - if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || - ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || - ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || - ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) { - return 0; - } - cprev = cnow; - } - /* NOTREACHED */ + ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || + ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || + ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || + ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)); + })); + break; /* * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) @@ -4155,9 +4062,9 @@ cy_ioctl(struct tty_struct *tty, struct file *file, * RI where only 0->1 is counted. */ case TIOCGICOUNT: - CY_LOCK(info, flags); + spin_lock_irqsave(&info->card->card_lock, flags); cnow = info->icount; - CY_UNLOCK(info, flags); + spin_unlock_irqrestore(&info->card->card_lock, flags); p_cuser = argp; ret_val = put_user(cnow.cts, &p_cuser->cts); if (ret_val) @@ -4199,7 +4106,7 @@ cy_ioctl(struct tty_struct *tty, struct file *file, } #ifdef CY_DEBUG_OTHER - printk(" cyc:cy_ioctl done\n"); + printk(KERN_DEBUG "cyc:cy_ioctl done\n"); #endif return ret_val; @@ -4213,10 +4120,10 @@ cy_ioctl(struct tty_struct *tty, struct file *file, */ static void cy_set_termios(struct tty_struct *tty, struct ktermios *old_termios) { - struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; + struct cyclades_port *info = tty->driver_data; #ifdef CY_DEBUG_OTHER - printk("cyc:cy_set_termios ttyC%d\n", info->line); + printk(KERN_DEBUG "cyc:cy_set_termios ttyC%d\n", info->line); #endif if (tty->termios->c_cflag == old_termios->c_cflag && @@ -4248,8 +4155,9 @@ static void cy_set_termios(struct tty_struct *tty, struct ktermios *old_termios) */ static void cy_send_xchar(struct tty_struct *tty, char ch) { - struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; - int card, channel; + struct cyclades_port *info = tty->driver_data; + struct cyclades_card *card; + int channel; if (serial_paranoia_check(info, tty->name, "cy_send_xchar")) return; @@ -4260,15 +4168,13 @@ static void cy_send_xchar(struct tty_struct *tty, char ch) cy_start(tty); card = info->card; - channel = info->line - cy_card[card].first_line; + channel = info->line - card->first_line; - if (IS_CYC_Z(cy_card[card])) { + if (IS_CYC_Z(*card)) { if (ch == STOP_CHAR(tty)) - cyz_issue_cmd(&cy_card[card], channel, C_CM_SENDXOFF, - 0L); + cyz_issue_cmd(card, channel, C_CM_SENDXOFF, 0L); else if (ch == START_CHAR(tty)) - cyz_issue_cmd(&cy_card[card], channel, C_CM_SENDXON, - 0L); + cyz_issue_cmd(card, channel, C_CM_SENDXON, 0L); } } @@ -4278,15 +4184,16 @@ static void cy_send_xchar(struct tty_struct *tty, char ch) */ static void cy_throttle(struct tty_struct *tty) { - struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; + struct cyclades_port *info = tty->driver_data; + struct cyclades_card *card; unsigned long flags; void __iomem *base_addr; - int card, chip, channel, index; + int chip, channel, index; #ifdef CY_DEBUG_THROTTLE char buf[64]; - printk("cyc:throttle %s: %d....ttyC%d\n", tty_name(tty, buf), + printk(KERN_DEBUG "cyc:throttle %s: %ld...ttyC%d\n", tty_name(tty, buf), tty->ldisc.chars_in_buffer(tty), info->line); #endif @@ -4297,22 +4204,22 @@ static void cy_throttle(struct tty_struct *tty) card = info->card; if (I_IXOFF(tty)) { - if (!IS_CYC_Z(cy_card[card])) + if (!IS_CYC_Z(*card)) cy_send_xchar(tty, STOP_CHAR(tty)); else info->throttle = 1; } if (tty->termios->c_cflag & CRTSCTS) { - channel = info->line - cy_card[card].first_line; - if (!IS_CYC_Z(cy_card[card])) { + channel = info->line - card->first_line; + if (!IS_CYC_Z(*card)) { chip = channel >> 2; channel &= 0x03; - index = cy_card[card].bus_index; - base_addr = cy_card[card].base_addr + + index = card->bus_index; + base_addr = card->base_addr + (cy_chip_offset[chip] << index); - CY_LOCK(info, flags); + spin_lock_irqsave(&card->card_lock, flags); cy_writeb(base_addr + (CyCAR << index), (u_char) channel); if (info->rtsdtr_inv) { @@ -4322,7 +4229,7 @@ static void cy_throttle(struct tty_struct *tty) cy_writeb(base_addr + (CyMSVR1 << index), ~CyRTS); } - CY_UNLOCK(info, flags); + spin_unlock_irqrestore(&card->card_lock, flags); } else { info->throttle = 1; } @@ -4336,16 +4243,17 @@ static void cy_throttle(struct tty_struct *tty) */ static void cy_unthrottle(struct tty_struct *tty) { - struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; + struct cyclades_port *info = tty->driver_data; + struct cyclades_card *card; unsigned long flags; void __iomem *base_addr; - int card, chip, channel, index; + int chip, channel, index; #ifdef CY_DEBUG_THROTTLE char buf[64]; - printk("cyc:unthrottle %s: %d....ttyC%d\n", tty_name(tty, buf), - tty->ldisc.chars_in_buffer(tty), info->line); + printk(KERN_DEBUG "cyc:unthrottle %s: %ld...ttyC%d\n", + tty_name(tty, buf), tty->ldisc.chars_in_buffer(tty),info->line); #endif if (serial_paranoia_check(info, tty->name, "cy_unthrottle")) { @@ -4361,15 +4269,15 @@ static void cy_unthrottle(struct tty_struct *tty) if (tty->termios->c_cflag & CRTSCTS) { card = info->card; - channel = info->line - cy_card[card].first_line; - if (!IS_CYC_Z(cy_card[card])) { + channel = info->line - card->first_line; + if (!IS_CYC_Z(*card)) { chip = channel >> 2; channel &= 0x03; - index = cy_card[card].bus_index; - base_addr = cy_card[card].base_addr + + index = card->bus_index; + base_addr = card->base_addr + (cy_chip_offset[chip] << index); - CY_LOCK(info, flags); + spin_lock_irqsave(&card->card_lock, flags); cy_writeb(base_addr + (CyCAR << index), (u_char) channel); if (info->rtsdtr_inv) { @@ -4379,7 +4287,7 @@ static void cy_unthrottle(struct tty_struct *tty) cy_writeb(base_addr + (CyMSVR1 << index), CyRTS); } - CY_UNLOCK(info, flags); + spin_unlock_irqrestore(&card->card_lock, flags); } else { info->throttle = 0; } @@ -4392,102 +4300,96 @@ static void cy_unthrottle(struct tty_struct *tty) static void cy_stop(struct tty_struct *tty) { struct cyclades_card *cinfo; - struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; + struct cyclades_port *info = tty->driver_data; void __iomem *base_addr; int chip, channel, index; unsigned long flags; #ifdef CY_DEBUG_OTHER - printk("cyc:cy_stop ttyC%d\n", info->line); /* */ + printk(KERN_DEBUG "cyc:cy_stop ttyC%d\n", info->line); #endif if (serial_paranoia_check(info, tty->name, "cy_stop")) return; - cinfo = &cy_card[info->card]; + cinfo = info->card; channel = info->line - cinfo->first_line; if (!IS_CYC_Z(*cinfo)) { index = cinfo->bus_index; chip = channel >> 2; channel &= 0x03; - base_addr = cy_card[info->card].base_addr + - (cy_chip_offset[chip] << index); + base_addr = cinfo->base_addr + (cy_chip_offset[chip] << index); - CY_LOCK(info, flags); + spin_lock_irqsave(&cinfo->card_lock, flags); cy_writeb(base_addr + (CyCAR << index), (u_char)(channel & 0x0003)); /* index channel */ cy_writeb(base_addr + (CySRER << index), - cy_readb(base_addr + (CySRER << index)) & ~CyTxRdy); - CY_UNLOCK(info, flags); - } else { - /* Nothing to do! */ + readb(base_addr + (CySRER << index)) & ~CyTxRdy); + spin_unlock_irqrestore(&cinfo->card_lock, flags); } } /* cy_stop */ static void cy_start(struct tty_struct *tty) { struct cyclades_card *cinfo; - struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; + struct cyclades_port *info = tty->driver_data; void __iomem *base_addr; int chip, channel, index; unsigned long flags; #ifdef CY_DEBUG_OTHER - printk("cyc:cy_start ttyC%d\n", info->line); /* */ + printk(KERN_DEBUG "cyc:cy_start ttyC%d\n", info->line); #endif if (serial_paranoia_check(info, tty->name, "cy_start")) return; - cinfo = &cy_card[info->card]; + cinfo = info->card; channel = info->line - cinfo->first_line; index = cinfo->bus_index; if (!IS_CYC_Z(*cinfo)) { chip = channel >> 2; channel &= 0x03; - base_addr = cy_card[info->card].base_addr + - (cy_chip_offset[chip] << index); + base_addr = cinfo->base_addr + (cy_chip_offset[chip] << index); - CY_LOCK(info, flags); + spin_lock_irqsave(&cinfo->card_lock, flags); cy_writeb(base_addr + (CyCAR << index), (u_char) (channel & 0x0003)); /* index channel */ cy_writeb(base_addr + (CySRER << index), - cy_readb(base_addr + (CySRER << index)) | CyTxRdy); - CY_UNLOCK(info, flags); - } else { - /* Nothing to do! */ + readb(base_addr + (CySRER << index)) | CyTxRdy); + spin_unlock_irqrestore(&cinfo->card_lock, flags); } } /* cy_start */ static void cy_flush_buffer(struct tty_struct *tty) { - struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; - int card, channel, retval; + struct cyclades_port *info = tty->driver_data; + struct cyclades_card *card; + int channel, retval; unsigned long flags; #ifdef CY_DEBUG_IO - printk("cyc:cy_flush_buffer ttyC%d\n", info->line); /* */ + printk(KERN_DEBUG "cyc:cy_flush_buffer ttyC%d\n", info->line); #endif if (serial_paranoia_check(info, tty->name, "cy_flush_buffer")) return; card = info->card; - channel = (info->line) - (cy_card[card].first_line); + channel = info->line - card->first_line; - CY_LOCK(info, flags); + spin_lock_irqsave(&card->card_lock, flags); info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; - CY_UNLOCK(info, flags); + spin_unlock_irqrestore(&card->card_lock, flags); - if (IS_CYC_Z(cy_card[card])) { /* If it is a Z card, flush the on-board + if (IS_CYC_Z(*card)) { /* If it is a Z card, flush the on-board buffers as well */ - CY_LOCK(info, flags); - retval = - cyz_issue_cmd(&cy_card[card], channel, C_CM_FLUSH_TX, 0L); + spin_lock_irqsave(&card->card_lock, flags); + retval = cyz_issue_cmd(card, channel, C_CM_FLUSH_TX, 0L); if (retval != 0) { - printk("cyc: flush_buffer retval on ttyC%d was %x\n", - info->line, retval); + printk(KERN_ERR "cyc: flush_buffer retval on ttyC%d " + "was %x\n", info->line, retval); } - CY_UNLOCK(info, flags); + spin_unlock_irqrestore(&card->card_lock, flags); } tty_wakeup(tty); } /* cy_flush_buffer */ @@ -4497,10 +4399,10 @@ static void cy_flush_buffer(struct tty_struct *tty) */ static void cy_hangup(struct tty_struct *tty) { - struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; + struct cyclades_port *info = tty->driver_data; #ifdef CY_DEBUG_OTHER - printk("cyc:cy_hangup ttyC%d\n", info->line); /* */ + printk(KERN_DEBUG "cyc:cy_hangup ttyC%d\n", info->line); #endif if (serial_paranoia_check(info, tty->name, "cy_hangup")) @@ -4511,7 +4413,8 @@ static void cy_hangup(struct tty_struct *tty) info->event = 0; info->count = 0; #ifdef CY_DEBUG_COUNT - printk("cyc:cy_hangup (%d): setting count to 0\n", current->pid); + printk(KERN_DEBUG "cyc:cy_hangup (%d): setting count to 0\n", + current->pid); #endif info->tty = NULL; info->flags &= ~ASYNC_NORMAL_ACTIVE; @@ -4526,10 +4429,107 @@ static void cy_hangup(struct tty_struct *tty) * --------------------------------------------------------------------- */ +static int __devinit cy_init_card(struct cyclades_card *cinfo) +{ + struct cyclades_port *info; + u32 mailbox; + unsigned int nports; + unsigned short chip_number; + int index, port; + + spin_lock_init(&cinfo->card_lock); + + if (IS_CYC_Z(*cinfo)) { /* Cyclades-Z */ + mailbox = readl(&((struct RUNTIME_9060 __iomem *) + cinfo->ctl_addr)->mail_box_0); + nports = (mailbox == ZE_V1) ? ZE_V1_NPORTS : 8; + cinfo->intr_enabled = 0; + cinfo->nports = 0; /* Will be correctly set later, after + Z FW is loaded */ + } else { + index = cinfo->bus_index; + nports = cinfo->nports = CyPORTS_PER_CHIP * cinfo->num_chips; + } + + cinfo->ports = kzalloc(sizeof(*cinfo->ports) * nports, GFP_KERNEL); + if (cinfo->ports == NULL) { + printk(KERN_ERR "Cyclades: cannot allocate ports\n"); + cinfo->nports = 0; + return -ENOMEM; + } + + for (port = cinfo->first_line; port < cinfo->first_line + nports; + port++) { + info = &cinfo->ports[port - cinfo->first_line]; + info->magic = CYCLADES_MAGIC; + info->card = cinfo; + info->line = port; + info->flags = STD_COM_FLAGS; + info->closing_wait = CLOSING_WAIT_DELAY; + info->close_delay = 5 * HZ / 10; + + INIT_WORK(&info->tqueue, do_softint); + init_waitqueue_head(&info->open_wait); + init_waitqueue_head(&info->close_wait); + init_completion(&info->shutdown_wait); + init_waitqueue_head(&info->delta_msr_wait); + + if (IS_CYC_Z(*cinfo)) { + info->type = PORT_STARTECH; + if (mailbox == ZO_V1) + info->xmit_fifo_size = CYZ_FIFO_SIZE; + else + info->xmit_fifo_size = 4 * CYZ_FIFO_SIZE; +#ifdef CONFIG_CYZ_INTR + setup_timer(&cyz_rx_full_timer[port], + cyz_rx_restart, (unsigned long)info); +#endif + } else { + info->type = PORT_CIRRUS; + info->xmit_fifo_size = CyMAX_CHAR_FIFO; + info->cor1 = CyPARITY_NONE | Cy_1_STOP | Cy_8_BITS; + info->cor2 = CyETC; + info->cor3 = 0x08; /* _very_ small rcv threshold */ + + chip_number = (port - cinfo->first_line) / 4; + if ((info->chip_rev = readb(cinfo->base_addr + + (cy_chip_offset[chip_number] << + index) + (CyGFRCR << index))) >= + CD1400_REV_J) { + /* It is a CD1400 rev. J or later */ + info->tbpr = baud_bpr_60[13]; /* Tx BPR */ + info->tco = baud_co_60[13]; /* Tx CO */ + info->rbpr = baud_bpr_60[13]; /* Rx BPR */ + info->rco = baud_co_60[13]; /* Rx CO */ + info->rtsdtr_inv = 1; + } else { + info->tbpr = baud_bpr_25[13]; /* Tx BPR */ + info->tco = baud_co_25[13]; /* Tx CO */ + info->rbpr = baud_bpr_25[13]; /* Rx BPR */ + info->rco = baud_co_25[13]; /* Rx CO */ + info->rtsdtr_inv = 0; + } + info->read_status_mask = CyTIMEOUT | CySPECHAR | + CyBREAK | CyPARITY | CyFRAME | CyOVERRUN; + } + + } + +#ifndef CONFIG_CYZ_INTR + if (IS_CYC_Z(*cinfo) && !timer_pending(&cyz_timerlist)) { + mod_timer(&cyz_timerlist, jiffies + 1); +#ifdef CY_PCI_DEBUG + printk(KERN_DEBUG "Cyclades-Z polling initialized\n"); +#endif + } +#endif + return 0; +} + /* initialize chips on Cyclom-Y card -- return number of valid chips (which is number of ports/4) */ -static unsigned short __init -cyy_init_card(void __iomem * true_base_addr, int index) +static unsigned short __devinit cyy_init_card(void __iomem *true_base_addr, + int index) { unsigned int chip_number; void __iomem *base_addr; @@ -4544,7 +4544,7 @@ cyy_init_card(void __iomem * true_base_addr, int index) base_addr = true_base_addr + (cy_chip_offset[chip_number] << index); mdelay(1); - if (cy_readb(base_addr + (CyCCR << index)) != 0x00) { + if (readb(base_addr + (CyCCR << index)) != 0x00) { /************* printk(" chip #%d at %#6lx is never idle (CCR != 0)\n", chip_number, (unsigned long)base_addr); @@ -4561,7 +4561,7 @@ cyy_init_card(void __iomem * true_base_addr, int index) chip 4 GFRCR register appears at chip 0, there is no chip 4 and this must be a Cyclom-16Y, not a Cyclom-32Ye. */ - if (chip_number == 4 && cy_readb(true_base_addr + + if (chip_number == 4 && readb(true_base_addr + (cy_chip_offset[0] << index) + (CyGFRCR << index)) == 0) { return chip_number; @@ -4570,7 +4570,7 @@ cyy_init_card(void __iomem * true_base_addr, int index) cy_writeb(base_addr + (CyCCR << index), CyCHIP_RESET); mdelay(1); - if (cy_readb(base_addr + (CyGFRCR << index)) == 0x00) { + if (readb(base_addr + (CyGFRCR << index)) == 0x00) { /* printk(" chip #%d at %#6lx is not responding ", chip_number, (unsigned long)base_addr); @@ -4578,7 +4578,7 @@ cyy_init_card(void __iomem * true_base_addr, int index) */ return chip_number; } - if ((0xf0 & (cy_readb(base_addr + (CyGFRCR << index)))) != + if ((0xf0 & (readb(base_addr + (CyGFRCR << index)))) != 0x40) { /* printk(" chip #%d at %#6lx is not valid (GFRCR == " @@ -4589,7 +4589,7 @@ cyy_init_card(void __iomem * true_base_addr, int index) return chip_number; } cy_writeb(base_addr + (CyGCR << index), CyCH0_SERIAL); - if (cy_readb(base_addr + (CyGFRCR << index)) >= CD1400_REV_J) { + if (readb(base_addr + (CyGFRCR << index)) >= CD1400_REV_J) { /* It is a CD1400 rev. J or later */ /* Impossible to reach 5ms with this chip. Changed to 2ms instead (f = 500 Hz). */ @@ -4602,7 +4602,7 @@ cyy_init_card(void __iomem * true_base_addr, int index) /* printk(" chip #%d at %#6lx is rev 0x%2x\n", chip_number, (unsigned long)base_addr, - cy_readb(base_addr+(CyGFRCR<<index))); + readb(base_addr+(CyGFRCR<<index))); */ } return chip_number; @@ -4647,9 +4647,15 @@ static int __init cy_detect_isa(void) /* probe for CD1400... */ cy_isa_address = ioremap(isa_address, CyISA_Ywin); + if (cy_isa_address == NULL) { + printk(KERN_ERR "Cyclom-Y/ISA: can't remap base " + "address\n"); + continue; + } cy_isa_nchan = CyPORTS_PER_CHIP * cyy_init_card(cy_isa_address, 0); if (cy_isa_nchan == 0) { + iounmap(cy_isa_address); continue; } #ifdef MODULE @@ -4660,40 +4666,42 @@ static int __init cy_detect_isa(void) /* find out the board's irq by probing */ cy_isa_irq = detect_isa_irq(cy_isa_address); if (cy_isa_irq == 0) { - printk("Cyclom-Y/ISA found at 0x%lx ", + printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but the " + "IRQ could not be detected.\n", (unsigned long)cy_isa_address); - printk("but the IRQ could not be detected.\n"); + iounmap(cy_isa_address); continue; } if ((cy_next_channel + cy_isa_nchan) > NR_PORTS) { - printk("Cyclom-Y/ISA found at 0x%lx ", + printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but no " + "more channels are available. Change NR_PORTS " + "in cyclades.c and recompile kernel.\n", (unsigned long)cy_isa_address); - printk("but no more channels are available.\n"); - printk("Change NR_PORTS in cyclades.c and recompile " - "kernel.\n"); + iounmap(cy_isa_address); return nboard; } /* fill the next cy_card structure available */ for (j = 0; j < NR_CARDS; j++) { - if (cy_card[j].base_addr == 0) + if (cy_card[j].base_addr == NULL) break; } if (j == NR_CARDS) { /* no more cy_cards available */ - printk("Cyclom-Y/ISA found at 0x%lx ", + printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but no " + "more cards can be used. Change NR_CARDS in " + "cyclades.c and recompile kernel.\n", (unsigned long)cy_isa_address); - printk("but no more cards can be used .\n"); - printk("Change NR_CARDS in cyclades.c and recompile " - "kernel.\n"); + iounmap(cy_isa_address); return nboard; } /* allocate IRQ */ if (request_irq(cy_isa_irq, cyy_interrupt, IRQF_DISABLED, "Cyclom-Y", &cy_card[j])) { - printk("Cyclom-Y/ISA found at 0x%lx ", - (unsigned long)cy_isa_address); - printk("but could not allocate IRQ#%d.\n", cy_isa_irq); + printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but " + "could not allocate IRQ#%d.\n", + (unsigned long)cy_isa_address, cy_isa_irq); + iounmap(cy_isa_address); return nboard; } @@ -4704,15 +4712,23 @@ static int __init cy_detect_isa(void) cy_card[j].bus_index = 0; cy_card[j].first_line = cy_next_channel; cy_card[j].num_chips = cy_isa_nchan / 4; + if (cy_init_card(&cy_card[j])) { + cy_card[j].base_addr = NULL; + free_irq(cy_isa_irq, &cy_card[j]); + iounmap(cy_isa_address); + continue; + } nboard++; - /* print message */ - printk("Cyclom-Y/ISA #%d: 0x%lx-0x%lx, IRQ%d, ", + printk(KERN_INFO "Cyclom-Y/ISA #%d: 0x%lx-0x%lx, IRQ%d found: " + "%d channels starting from port %d\n", j + 1, (unsigned long)cy_isa_address, (unsigned long)(cy_isa_address + (CyISA_Ywin - 1)), - cy_isa_irq); - printk("%d channels starting from port %d.\n", - cy_isa_nchan, cy_next_channel); + cy_isa_irq, cy_isa_nchan, cy_next_channel); + + for (j = cy_next_channel; + j < cy_next_channel + cy_isa_nchan; j++) + tty_register_device(cy_serial_driver, j, NULL); cy_next_channel += cy_isa_nchan; } return nboard; @@ -4721,510 +4737,310 @@ static int __init cy_detect_isa(void) #endif /* CONFIG_ISA */ } /* cy_detect_isa */ -static void plx_init(void __iomem * addr, uclong initctl) +#ifdef CONFIG_PCI +static void __devinit plx_init(void __iomem * addr, __u32 initctl) { /* Reset PLX */ - cy_writel(addr + initctl, cy_readl(addr + initctl) | 0x40000000); + cy_writel(addr + initctl, readl(addr + initctl) | 0x40000000); udelay(100L); - cy_writel(addr + initctl, cy_readl(addr + initctl) & ~0x40000000); + cy_writel(addr + initctl, readl(addr + initctl) & ~0x40000000); /* Reload Config. Registers from EEPROM */ - cy_writel(addr + initctl, cy_readl(addr + initctl) | 0x20000000); + cy_writel(addr + initctl, readl(addr + initctl) | 0x20000000); udelay(100L); - cy_writel(addr + initctl, cy_readl(addr + initctl) & ~0x20000000); + cy_writel(addr + initctl, readl(addr + initctl) & ~0x20000000); } -/* - * --------------------------------------------------------------------- - * cy_detect_pci() - Test PCI bus presence and Cyclom-Ye/PCI. - * sets global variables and return the number of PCI boards found. - * --------------------------------------------------------------------- - */ -static int __init cy_detect_pci(void) +static int __devinit cy_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) { -#ifdef CONFIG_PCI - - struct pci_dev *pdev = NULL; - unsigned char cyy_rev_id; - unsigned char cy_pci_irq = 0; - uclong cy_pci_phys0, cy_pci_phys2; - void __iomem *cy_pci_addr0, *cy_pci_addr2; - unsigned short i, j, cy_pci_nchan, plx_ver; - unsigned short device_id, dev_index = 0; - uclong mailbox; - uclong ZeIndex = 0; - void __iomem *Ze_addr0[NR_CARDS], *Ze_addr2[NR_CARDS]; - uclong Ze_phys0[NR_CARDS], Ze_phys2[NR_CARDS]; - unsigned char Ze_irq[NR_CARDS]; - struct pci_dev *Ze_pdev[NR_CARDS]; - - for (i = 0; i < NR_CARDS; i++) { - /* look for a Cyclades card by vendor and device id */ - while ((device_id = cy_pci_dev_id[dev_index].device) != 0) { - if ((pdev = pci_get_device(PCI_VENDOR_ID_CYCLADES, - device_id, pdev)) == NULL) { - dev_index++; /* try next device id */ - } else { - break; /* found a board */ - } - } - - if (device_id == 0) - break; - - if (pci_enable_device(pdev)) - continue; - - /* read PCI configuration area */ - cy_pci_irq = pdev->irq; - cy_pci_phys0 = pci_resource_start(pdev, 0); - cy_pci_phys2 = pci_resource_start(pdev, 2); - pci_read_config_byte(pdev, PCI_REVISION_ID, &cyy_rev_id); + void __iomem *addr0 = NULL, *addr2 = NULL; + char *card_name = NULL; + u32 mailbox; + unsigned int device_id, nchan = 0, card_no, i; + unsigned char plx_ver; + int retval, irq; + + retval = pci_enable_device(pdev); + if (retval) { + dev_err(&pdev->dev, "cannot enable device\n"); + goto err; + } - device_id &= ~PCI_DEVICE_ID_MASK; + /* read PCI configuration area */ + irq = pdev->irq; + device_id = pdev->device & ~PCI_DEVICE_ID_MASK; - if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo || - device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) { -#ifdef CY_PCI_DEBUG - printk("Cyclom-Y/PCI (bus=0x0%x, pci_id=0x%x, ", - pdev->bus->number, pdev->devfn); - printk("rev_id=%d) IRQ%d\n", - cyy_rev_id, (int)cy_pci_irq); - printk("Cyclom-Y/PCI:found winaddr=0x%lx " - "ctladdr=0x%lx\n", - (ulong)cy_pci_phys2, (ulong)cy_pci_phys0); +#if defined(__alpha__) + if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo) { /* below 1M? */ + dev_err(&pdev->dev, "Cyclom-Y/PCI not supported for low " + "addresses on Alpha systems.\n"); + retval = -EIO; + goto err_dis; + } #endif + if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Lo) { + dev_err(&pdev->dev, "Cyclades-Z/PCI not supported for low " + "addresses\n"); + retval = -EIO; + goto err_dis; + } - if (pci_resource_flags(pdev, 2) & IORESOURCE_IO) { - printk(" Warning: PCI I/O bit incorrectly " - "set. Ignoring it...\n"); - pdev->resource[2].flags &= ~IORESOURCE_IO; - } + if (pci_resource_flags(pdev, 2) & IORESOURCE_IO) { + dev_warn(&pdev->dev, "PCI I/O bit incorrectly set. Ignoring " + "it...\n"); + pdev->resource[2].flags &= ~IORESOURCE_IO; + } - /* Although we don't use this I/O region, we should - request it from the kernel anyway, to avoid problems - with other drivers accessing it. */ - if (pci_request_regions(pdev, "Cyclom-Y") != 0) { - printk(KERN_ERR "cyclades: failed to reserve " - "PCI resources\n"); - continue; - } -#if defined(__alpha__) - if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo) { /* below 1M? */ - printk("Cyclom-Y/PCI (bus=0x0%x, pci_id=0x%x, ", - pdev->bus->number, pdev->devfn); - printk("rev_id=%d) IRQ%d\n", - cyy_rev_id, (int)cy_pci_irq); - printk("Cyclom-Y/PCI:found winaddr=0x%lx " - "ctladdr=0x%lx\n", - (ulong)cy_pci_phys2, - (ulong)cy_pci_phys0); - printk("Cyclom-Y/PCI not supported for low " - "addresses in Alpha systems.\n"); - i--; - continue; - } -#endif - cy_pci_addr0 = ioremap(cy_pci_phys0, CyPCI_Yctl); - cy_pci_addr2 = ioremap(cy_pci_phys2, CyPCI_Ywin); + retval = pci_request_regions(pdev, "cyclades"); + if (retval) { + dev_err(&pdev->dev, "failed to reserve resources\n"); + goto err_dis; + } -#ifdef CY_PCI_DEBUG - printk("Cyclom-Y/PCI: relocate winaddr=0x%lx " - "ctladdr=0x%lx\n", - (u_long)cy_pci_addr2, (u_long)cy_pci_addr0); -#endif - cy_pci_nchan = (unsigned short)(CyPORTS_PER_CHIP * - cyy_init_card(cy_pci_addr2, 1)); - if (cy_pci_nchan == 0) { - printk("Cyclom-Y PCI host card with "); - printk("no Serial-Modules at 0x%lx.\n", - (ulong) cy_pci_phys2); - i--; - continue; - } - if ((cy_next_channel + cy_pci_nchan) > NR_PORTS) { - printk("Cyclom-Y/PCI found at 0x%lx ", - (ulong) cy_pci_phys2); - printk("but no channels are available.\n"); - printk("Change NR_PORTS in cyclades.c and " - "recompile kernel.\n"); - return i; - } - /* fill the next cy_card structure available */ - for (j = 0; j < NR_CARDS; j++) { - if (cy_card[j].base_addr == 0) - break; - } - if (j == NR_CARDS) { /* no more cy_cards available */ - printk("Cyclom-Y/PCI found at 0x%lx ", - (ulong) cy_pci_phys2); - printk("but no more cards can be used.\n"); - printk("Change NR_CARDS in cyclades.c and " - "recompile kernel.\n"); - return i; - } + retval = -EIO; + if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo || + device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) { + card_name = "Cyclom-Y"; - /* allocate IRQ */ - if (request_irq(cy_pci_irq, cyy_interrupt, - IRQF_SHARED, "Cyclom-Y", &cy_card[j])) { - printk("Cyclom-Y/PCI found at 0x%lx ", - (ulong) cy_pci_phys2); - printk("but could not allocate IRQ%d.\n", - cy_pci_irq); - return i; - } + addr0 = pci_iomap(pdev, 0, CyPCI_Yctl); + if (addr0 == NULL) { + dev_err(&pdev->dev, "can't remap ctl region\n"); + goto err_reg; + } + addr2 = pci_iomap(pdev, 2, CyPCI_Ywin); + if (addr2 == NULL) { + dev_err(&pdev->dev, "can't remap base region\n"); + goto err_unmap; + } - /* set cy_card */ - cy_card[j].base_phys = (ulong) cy_pci_phys2; - cy_card[j].ctl_phys = (ulong) cy_pci_phys0; - cy_card[j].base_addr = cy_pci_addr2; - cy_card[j].ctl_addr = cy_pci_addr0; - cy_card[j].irq = (int)cy_pci_irq; - cy_card[j].bus_index = 1; - cy_card[j].first_line = cy_next_channel; - cy_card[j].num_chips = cy_pci_nchan / 4; - cy_card[j].pdev = pdev; - - /* enable interrupts in the PCI interface */ - plx_ver = cy_readb(cy_pci_addr2 + CyPLX_VER) & 0x0f; - switch (plx_ver) { - case PLX_9050: - - cy_writeb(cy_pci_addr0 + 0x4c, 0x43); - break; + nchan = CyPORTS_PER_CHIP * cyy_init_card(addr2, 1); + if (nchan == 0) { + dev_err(&pdev->dev, "Cyclom-Y PCI host card with no " + "Serial-Modules\n"); + return -EIO; + } + } else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Hi) { + struct RUNTIME_9060 __iomem *ctl_addr; - case PLX_9060: - case PLX_9080: - default: /* Old boards, use PLX_9060 */ - - plx_init(cy_pci_addr0, 0x6c); - /* For some yet unknown reason, once the PLX9060 reloads - the EEPROM, the IRQ is lost and, thus, we have to - re-write it to the PCI config. registers. - This will remain here until we find a permanent - fix. */ - pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, - cy_pci_irq); - - cy_writew(cy_pci_addr0 + 0x68, - cy_readw(cy_pci_addr0 + - 0x68) | 0x0900); - break; - } + ctl_addr = addr0 = pci_iomap(pdev, 0, CyPCI_Zctl); + if (addr0 == NULL) { + dev_err(&pdev->dev, "can't remap ctl region\n"); + goto err_reg; + } - /* print message */ - printk("Cyclom-Y/PCI #%d: 0x%lx-0x%lx, IRQ%d, ", - j + 1, (ulong)cy_pci_phys2, - (ulong) (cy_pci_phys2 + CyPCI_Ywin - 1), - (int)cy_pci_irq); - printk("%d channels starting from port %d.\n", - cy_pci_nchan, cy_next_channel); - - cy_next_channel += cy_pci_nchan; - } else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Lo) { - /* print message */ - printk("Cyclades-Z/PCI (bus=0x0%x, pci_id=0x%x, ", - pdev->bus->number, pdev->devfn); - printk("rev_id=%d) IRQ%d\n", - cyy_rev_id, (int)cy_pci_irq); - printk("Cyclades-Z/PCI: found winaddr=0x%lx " - "ctladdr=0x%lx\n", - (ulong)cy_pci_phys2, (ulong)cy_pci_phys0); - printk("Cyclades-Z/PCI not supported for low " - "addresses\n"); - break; - } else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Hi) { -#ifdef CY_PCI_DEBUG - printk("Cyclades-Z/PCI (bus=0x0%x, pci_id=0x%x, ", - pdev->bus->number, pdev->devfn); - printk("rev_id=%d) IRQ%d\n", - cyy_rev_id, (int)cy_pci_irq); - printk("Cyclades-Z/PCI: found winaddr=0x%lx " - "ctladdr=0x%lx\n", - (ulong) cy_pci_phys2, (ulong) cy_pci_phys0); -#endif - cy_pci_addr0 = ioremap(cy_pci_phys0, CyPCI_Zctl); - - /* Disable interrupts on the PLX before resetting it */ - cy_writew(cy_pci_addr0 + 0x68, - cy_readw(cy_pci_addr0 + 0x68) & ~0x0900); - - plx_init(cy_pci_addr0, 0x6c); - /* For some yet unknown reason, once the PLX9060 reloads - the EEPROM, the IRQ is lost and, thus, we have to - re-write it to the PCI config. registers. - This will remain here until we find a permanent - fix. */ - pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, - cy_pci_irq); - - mailbox = - (uclong)cy_readl(&((struct RUNTIME_9060 __iomem *) - cy_pci_addr0)->mail_box_0); - - if (pci_resource_flags(pdev, 2) & IORESOURCE_IO) { - printk(" Warning: PCI I/O bit incorrectly " - "set. Ignoring it...\n"); - pdev->resource[2].flags &= ~IORESOURCE_IO; - } + /* Disable interrupts on the PLX before resetting it */ + cy_writew(addr0 + 0x68, + readw(addr0 + 0x68) & ~0x0900); + + plx_init(addr0, 0x6c); + /* For some yet unknown reason, once the PLX9060 reloads + the EEPROM, the IRQ is lost and, thus, we have to + re-write it to the PCI config. registers. + This will remain here until we find a permanent + fix. */ + pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, irq); + + mailbox = (u32)readl(&ctl_addr->mail_box_0); + + addr2 = pci_iomap(pdev, 2, mailbox == ZE_V1 ? + CyPCI_Ze_win : CyPCI_Zwin); + if (addr2 == NULL) { + dev_err(&pdev->dev, "can't remap base region\n"); + goto err_unmap; + } - /* Although we don't use this I/O region, we should - request it from the kernel anyway, to avoid problems - with other drivers accessing it. */ - if (pci_request_regions(pdev, "Cyclades-Z") != 0) { - printk(KERN_ERR "cyclades: failed to reserve " - "PCI resources\n"); - continue; - } + if (mailbox == ZE_V1) { + card_name = "Cyclades-Ze"; - if (mailbox == ZE_V1) { - cy_pci_addr2 = ioremap(cy_pci_phys2, - CyPCI_Ze_win); - if (ZeIndex == NR_CARDS) { - printk("Cyclades-Ze/PCI found at " - "0x%lx but no more cards can " - "be used.\nChange NR_CARDS in " - "cyclades.c and recompile " - "kernel.\n", - (ulong)cy_pci_phys2); - } else { - Ze_phys0[ZeIndex] = cy_pci_phys0; - Ze_phys2[ZeIndex] = cy_pci_phys2; - Ze_addr0[ZeIndex] = cy_pci_addr0; - Ze_addr2[ZeIndex] = cy_pci_addr2; - Ze_irq[ZeIndex] = cy_pci_irq; - Ze_pdev[ZeIndex] = pdev; - ZeIndex++; - } - i--; - continue; - } else { - cy_pci_addr2 = ioremap(cy_pci_phys2,CyPCI_Zwin); - } + readl(&ctl_addr->mail_box_0); + nchan = ZE_V1_NPORTS; + } else { + card_name = "Cyclades-8Zo"; #ifdef CY_PCI_DEBUG - printk("Cyclades-Z/PCI: relocate winaddr=0x%lx " - "ctladdr=0x%lx\n", - (ulong) cy_pci_addr2, (ulong) cy_pci_addr0); if (mailbox == ZO_V1) { - cy_writel(&((struct RUNTIME_9060 *) - (cy_pci_addr0))->loc_addr_base, - WIN_CREG); - PAUSE; - printk("Cyclades-8Zo/PCI: FPGA id %lx, ver " - "%lx\n", (ulong) (0xff & - cy_readl(&((struct CUSTOM_REG *) - (cy_pci_addr2))->fpga_id)), - (ulong)(0xff & - cy_readl(&((struct CUSTOM_REG *) - (cy_pci_addr2))-> - fpga_version))); - cy_writel(&((struct RUNTIME_9060 *) - (cy_pci_addr0))->loc_addr_base, - WIN_RAM); + cy_writel(&ctl_addr->loc_addr_base, WIN_CREG); + dev_info(&pdev->dev, "Cyclades-8Zo/PCI: FPGA " + "id %lx, ver %lx\n", (ulong)(0xff & + readl(&((struct CUSTOM_REG *)addr2)-> + fpga_id)), (ulong)(0xff & + readl(&((struct CUSTOM_REG *)addr2)-> + fpga_version))); + cy_writel(&ctl_addr->loc_addr_base, WIN_RAM); } else { - printk("Cyclades-Z/PCI: New Cyclades-Z board. " - "FPGA not loaded\n"); + dev_info(&pdev->dev, "Cyclades-Z/PCI: New " + "Cyclades-Z board. FPGA not loaded\n"); } #endif /* The following clears the firmware id word. This ensures that the driver will not attempt to talk to the board until it has been properly initialized. */ - PAUSE; if ((mailbox == ZO_V1) || (mailbox == ZO_V2)) - cy_writel(cy_pci_addr2 + ID_ADDRESS, 0L); + cy_writel(addr2 + ID_ADDRESS, 0L); /* This must be a Cyclades-8Zo/PCI. The extendable version will have a different device_id and will be allocated its maximum number of ports. */ - cy_pci_nchan = 8; - - if ((cy_next_channel + cy_pci_nchan) > NR_PORTS) { - printk("Cyclades-8Zo/PCI found at 0x%lx but" - "no channels are available.\nChange " - "NR_PORTS in cyclades.c and recompile " - "kernel.\n", (ulong)cy_pci_phys2); - return i; - } - - /* fill the next cy_card structure available */ - for (j = 0; j < NR_CARDS; j++) { - if (cy_card[j].base_addr == 0) - break; - } - if (j == NR_CARDS) { /* no more cy_cards available */ - printk("Cyclades-8Zo/PCI found at 0x%lx but" - "no more cards can be used.\nChange " - "NR_CARDS in cyclades.c and recompile " - "kernel.\n", (ulong)cy_pci_phys2); - return i; - } -#ifdef CONFIG_CYZ_INTR - /* allocate IRQ only if board has an IRQ */ - if ((cy_pci_irq != 0) && (cy_pci_irq != 255)) { - if (request_irq(cy_pci_irq, cyz_interrupt, - IRQF_SHARED, "Cyclades-Z", - &cy_card[j])) { - printk("Cyclom-8Zo/PCI found at 0x%lx " - "but could not allocate " - "IRQ%d.\n", (ulong)cy_pci_phys2, - cy_pci_irq); - return i; - } - } -#endif /* CONFIG_CYZ_INTR */ - - /* set cy_card */ - cy_card[j].base_phys = cy_pci_phys2; - cy_card[j].ctl_phys = cy_pci_phys0; - cy_card[j].base_addr = cy_pci_addr2; - cy_card[j].ctl_addr = cy_pci_addr0; - cy_card[j].irq = (int)cy_pci_irq; - cy_card[j].bus_index = 1; - cy_card[j].first_line = cy_next_channel; - cy_card[j].num_chips = -1; - cy_card[j].pdev = pdev; - - /* print message */ -#ifdef CONFIG_CYZ_INTR - /* don't report IRQ if board is no IRQ */ - if ((cy_pci_irq != 0) && (cy_pci_irq != 255)) - printk("Cyclades-8Zo/PCI #%d: 0x%lx-0x%lx, " - "IRQ%d, ", j + 1, (ulong)cy_pci_phys2, - (ulong) (cy_pci_phys2 + CyPCI_Zwin - 1), - (int)cy_pci_irq); - else -#endif /* CONFIG_CYZ_INTR */ - printk("Cyclades-8Zo/PCI #%d: 0x%lx-0x%lx, ", - j + 1, (ulong)cy_pci_phys2, - (ulong)(cy_pci_phys2 + CyPCI_Zwin - 1)); - - printk("%d channels starting from port %d.\n", - cy_pci_nchan, cy_next_channel); - cy_next_channel += cy_pci_nchan; + nchan = 8; } } - for (; ZeIndex != 0 && i < NR_CARDS; i++) { - cy_pci_phys0 = Ze_phys0[0]; - cy_pci_phys2 = Ze_phys2[0]; - cy_pci_addr0 = Ze_addr0[0]; - cy_pci_addr2 = Ze_addr2[0]; - cy_pci_irq = Ze_irq[0]; - pdev = Ze_pdev[0]; - for (j = 0; j < ZeIndex - 1; j++) { - Ze_phys0[j] = Ze_phys0[j + 1]; - Ze_phys2[j] = Ze_phys2[j + 1]; - Ze_addr0[j] = Ze_addr0[j + 1]; - Ze_addr2[j] = Ze_addr2[j + 1]; - Ze_irq[j] = Ze_irq[j + 1]; - Ze_pdev[j] = Ze_pdev[j + 1]; - } - ZeIndex--; - mailbox = (uclong)cy_readl(&((struct RUNTIME_9060 __iomem *) - cy_pci_addr0)->mail_box_0); -#ifdef CY_PCI_DEBUG - printk("Cyclades-Z/PCI: relocate winaddr=0x%lx ctladdr=0x%lx\n", - (ulong)cy_pci_addr2, (ulong)cy_pci_addr0); - printk("Cyclades-Z/PCI: New Cyclades-Z board. FPGA not " - "loaded\n"); -#endif - PAUSE; - /* This must be the new Cyclades-Ze/PCI. */ - cy_pci_nchan = ZE_V1_NPORTS; - - if ((cy_next_channel + cy_pci_nchan) > NR_PORTS) { - printk("Cyclades-Ze/PCI found at 0x%lx but no channels " - "are available.\nChange NR_PORTS in cyclades.c " - "and recompile kernel.\n", - (ulong) cy_pci_phys2); - return i; - } + if ((cy_next_channel + nchan) > NR_PORTS) { + dev_err(&pdev->dev, "Cyclades-8Zo/PCI found, but no " + "channels are available. Change NR_PORTS in " + "cyclades.c and recompile kernel.\n"); + goto err_unmap; + } + /* fill the next cy_card structure available */ + for (card_no = 0; card_no < NR_CARDS; card_no++) { + if (cy_card[card_no].base_addr == NULL) + break; + } + if (card_no == NR_CARDS) { /* no more cy_cards available */ + dev_err(&pdev->dev, "Cyclades-8Zo/PCI found, but no " + "more cards can be used. Change NR_CARDS in " + "cyclades.c and recompile kernel.\n"); + goto err_unmap; + } - /* fill the next cy_card structure available */ - for (j = 0; j < NR_CARDS; j++) { - if (cy_card[j].base_addr == 0) - break; - } - if (j == NR_CARDS) { /* no more cy_cards available */ - printk("Cyclades-Ze/PCI found at 0x%lx but no more " - "cards can be used.\nChange NR_CARDS in " - "cyclades.c and recompile kernel.\n", - (ulong) cy_pci_phys2); - return i; + if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo || + device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) { + /* allocate IRQ */ + retval = request_irq(irq, cyy_interrupt, + IRQF_SHARED, "Cyclom-Y", &cy_card[card_no]); + if (retval) { + dev_err(&pdev->dev, "could not allocate IRQ\n"); + goto err_unmap; } + cy_card[card_no].num_chips = nchan / 4; + } else { #ifdef CONFIG_CYZ_INTR /* allocate IRQ only if board has an IRQ */ - if ((cy_pci_irq != 0) && (cy_pci_irq != 255)) { - if (request_irq(cy_pci_irq, cyz_interrupt, + if (irq != 0 && irq != 255) { + retval = request_irq(irq, cyz_interrupt, IRQF_SHARED, "Cyclades-Z", - &cy_card[j])) { - printk("Cyclom-Ze/PCI found at 0x%lx ", - (ulong) cy_pci_phys2); - printk("but could not allocate IRQ%d.\n", - cy_pci_irq); - return i; + &cy_card[card_no]); + if (retval) { + dev_err(&pdev->dev, "could not allocate IRQ\n"); + goto err_unmap; } } #endif /* CONFIG_CYZ_INTR */ + cy_card[card_no].num_chips = -1; + } - /* set cy_card */ - cy_card[j].base_phys = cy_pci_phys2; - cy_card[j].ctl_phys = cy_pci_phys0; - cy_card[j].base_addr = cy_pci_addr2; - cy_card[j].ctl_addr = cy_pci_addr0; - cy_card[j].irq = (int)cy_pci_irq; - cy_card[j].bus_index = 1; - cy_card[j].first_line = cy_next_channel; - cy_card[j].num_chips = -1; - cy_card[j].pdev = pdev; + /* set cy_card */ + cy_card[card_no].base_addr = addr2; + cy_card[card_no].ctl_addr = addr0; + cy_card[card_no].irq = irq; + cy_card[card_no].bus_index = 1; + cy_card[card_no].first_line = cy_next_channel; + retval = cy_init_card(&cy_card[card_no]); + if (retval) + goto err_null; - /* print message */ -#ifdef CONFIG_CYZ_INTR - /* don't report IRQ if board is no IRQ */ - if ((cy_pci_irq != 0) && (cy_pci_irq != 255)) - printk("Cyclades-Ze/PCI #%d: 0x%lx-0x%lx, IRQ%d, ", - j + 1, (ulong) cy_pci_phys2, - (ulong) (cy_pci_phys2 + CyPCI_Ze_win - 1), - (int)cy_pci_irq); - else -#endif /* CONFIG_CYZ_INTR */ - printk("Cyclades-Ze/PCI #%d: 0x%lx-0x%lx, ", - j + 1, (ulong) cy_pci_phys2, - (ulong) (cy_pci_phys2 + CyPCI_Ze_win - 1)); + pci_set_drvdata(pdev, &cy_card[card_no]); - printk("%d channels starting from port %d.\n", - cy_pci_nchan, cy_next_channel); - cy_next_channel += cy_pci_nchan; - } - if (ZeIndex != 0) { - printk("Cyclades-Ze/PCI found at 0x%x but no more cards can be " - "used.\nChange NR_CARDS in cyclades.c and recompile " - "kernel.\n", (unsigned int)Ze_phys2[0]); + if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo || + device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) { + /* enable interrupts in the PCI interface */ + plx_ver = readb(addr2 + CyPLX_VER) & 0x0f; + switch (plx_ver) { + case PLX_9050: + + cy_writeb(addr0 + 0x4c, 0x43); + break; + + case PLX_9060: + case PLX_9080: + default: /* Old boards, use PLX_9060 */ + + plx_init(addr0, 0x6c); + /* For some yet unknown reason, once the PLX9060 reloads + the EEPROM, the IRQ is lost and, thus, we have to + re-write it to the PCI config. registers. + This will remain here until we find a permanent + fix. */ + pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, irq); + + cy_writew(addr0 + 0x68, readw(addr0 + 0x68) | 0x0900); + break; + } } - return i; -#else + + dev_info(&pdev->dev, "%s/PCI #%d found: %d channels starting from " + "port %d.\n", card_name, card_no + 1, nchan, cy_next_channel); + for (i = cy_next_channel; i < cy_next_channel + nchan; i++) + tty_register_device(cy_serial_driver, i, &pdev->dev); + cy_next_channel += nchan; + return 0; -#endif /* ifdef CONFIG_PCI */ -} /* cy_detect_pci */ +err_null: + cy_card[card_no].base_addr = NULL; + free_irq(irq, &cy_card[card_no]); +err_unmap: + pci_iounmap(pdev, addr0); + if (addr2) + pci_iounmap(pdev, addr2); +err_reg: + pci_release_regions(pdev); +err_dis: + pci_disable_device(pdev); +err: + return retval; +} -/* - * This routine prints out the appropriate serial driver version number - * and identifies which options were configured into this driver. - */ -static inline void show_version(void) +static void __devexit cy_pci_remove(struct pci_dev *pdev) { - printk("Cyclades driver " CY_VERSION "\n"); - printk(" built %s %s\n", __DATE__, __TIME__); -} /* show_version */ + struct cyclades_card *cinfo = pci_get_drvdata(pdev); + unsigned int i; + + /* non-Z with old PLX */ + if (!IS_CYC_Z(*cinfo) && (readb(cinfo->base_addr + CyPLX_VER) & 0x0f) == + PLX_9050) + cy_writeb(cinfo->ctl_addr + 0x4c, 0); + else +#ifndef CONFIG_CYZ_INTR + if (!IS_CYC_Z(*cinfo)) +#endif + cy_writew(cinfo->ctl_addr + 0x68, + readw(cinfo->ctl_addr + 0x68) & ~0x0900); + + pci_iounmap(pdev, cinfo->base_addr); + if (cinfo->ctl_addr) + pci_iounmap(pdev, cinfo->ctl_addr); + if (cinfo->irq +#ifndef CONFIG_CYZ_INTR + && !IS_CYC_Z(*cinfo) +#endif /* CONFIG_CYZ_INTR */ + ) + free_irq(cinfo->irq, cinfo); + pci_release_regions(pdev); + + cinfo->base_addr = NULL; + for (i = cinfo->first_line; i < cinfo->first_line + + cinfo->nports; i++) + tty_unregister_device(cy_serial_driver, i); + cinfo->nports = 0; + kfree(cinfo->ports); +} + +static struct pci_driver cy_pci_driver = { + .name = "cyclades", + .id_table = cy_pci_dev_id, + .probe = cy_pci_probe, + .remove = __devexit_p(cy_pci_remove) +}; +#endif static int cyclades_get_proc_info(char *buf, char **start, off_t offset, int length, int *eof, void *data) { struct cyclades_port *info; - int i; + unsigned int i, j; int len = 0; off_t begin = 0; off_t pos = 0; @@ -5238,33 +5054,34 @@ cyclades_get_proc_info(char *buf, char **start, off_t offset, int length, len += size; /* Output one line for each known port */ - for (i = 0; i < NR_PORTS && cy_port[i].line >= 0; i++) { - info = &cy_port[i]; - - if (info->count) - size = sprintf(buf + len, "%3d %8lu %10lu %8lu %10lu " - "%8lu %9lu %6ld\n", info->line, - (cur_jifs - info->idle_stats.in_use) / HZ, - info->idle_stats.xmit_bytes, - (cur_jifs - info->idle_stats.xmit_idle) / HZ, - info->idle_stats.recv_bytes, - (cur_jifs - info->idle_stats.recv_idle) / HZ, - info->idle_stats.overruns, - (long)info->tty->ldisc.num); - else - size = sprintf(buf + len, "%3d %8lu %10lu %8lu %10lu " - "%8lu %9lu %6ld\n", - info->line, 0L, 0L, 0L, 0L, 0L, 0L, 0L); - len += size; - pos = begin + len; - - if (pos < offset) { - len = 0; - begin = pos; + for (i = 0; i < NR_CARDS; i++) + for (j = 0; j < cy_card[i].nports; j++) { + info = &cy_card[i].ports[j]; + + if (info->count) + size = sprintf(buf + len, "%3d %8lu %10lu %8lu " + "%10lu %8lu %9lu %6ld\n", info->line, + (cur_jifs - info->idle_stats.in_use) / + HZ, info->idle_stats.xmit_bytes, + (cur_jifs - info->idle_stats.xmit_idle)/ + HZ, info->idle_stats.recv_bytes, + (cur_jifs - info->idle_stats.recv_idle)/ + HZ, info->idle_stats.overruns, + (long)info->tty->ldisc.num); + else + size = sprintf(buf + len, "%3d %8lu %10lu %8lu " + "%10lu %8lu %9lu %6ld\n", + info->line, 0L, 0L, 0L, 0L, 0L, 0L, 0L); + len += size; + pos = begin + len; + + if (pos < offset) { + len = 0; + begin = pos; + } + if (pos > offset + length) + goto done; } - if (pos > offset + length) - goto done; - } *eof = 1; done: *start = buf + (offset - begin); /* Start of wanted data */ @@ -5319,18 +5136,15 @@ static const struct tty_operations cy_ops = { static int __init cy_init(void) { - struct cyclades_port *info; - struct cyclades_card *cinfo; - int number_z_boards = 0; - int board, port, i, index; - unsigned long mailbox; - unsigned short chip_number; - int nports; + unsigned int nboards; + int retval = -ENOMEM; cy_serial_driver = alloc_tty_driver(NR_PORTS); if (!cy_serial_driver) - return -ENOMEM; - show_version(); + goto err; + + printk(KERN_INFO "Cyclades driver " CY_VERSION " (built %s %s)\n", + __DATE__, __TIME__); /* Initialize the tty_driver structure */ @@ -5344,15 +5158,13 @@ static int __init cy_init(void) cy_serial_driver->init_termios = tty_std_termios; cy_serial_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; - cy_serial_driver->flags = TTY_DRIVER_REAL_RAW; + cy_serial_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; tty_set_operations(cy_serial_driver, &cy_ops); - if (tty_register_driver(cy_serial_driver)) - panic("Couldn't register Cyclades serial driver\n"); - - for (i = 0; i < NR_CARDS; i++) { - /* base_addr=0 indicates board not found */ - cy_card[i].base_addr = NULL; + retval = tty_register_driver(cy_serial_driver); + if (retval) { + printk(KERN_ERR "Couldn't register Cyclades serial driver\n"); + goto err_frtty; } /* the code below is responsible to find the boards. Each different @@ -5363,223 +5175,68 @@ static int __init cy_init(void) the cy_next_channel. */ /* look for isa boards */ - cy_isa_nboard = cy_detect_isa(); + nboards = cy_detect_isa(); +#ifdef CONFIG_PCI /* look for pci boards */ - cy_pci_nboard = cy_detect_pci(); - - cy_nboard = cy_isa_nboard + cy_pci_nboard; - - /* invalidate remaining cy_card structures */ - for (i = 0; i < NR_CARDS; i++) { - if (cy_card[i].base_addr == 0) { - cy_card[i].first_line = -1; - cy_card[i].ctl_addr = NULL; - cy_card[i].irq = 0; - cy_card[i].bus_index = 0; - cy_card[i].first_line = 0; - cy_card[i].num_chips = 0; - } - } - /* invalidate remaining cy_port structures */ - for (i = cy_next_channel; i < NR_PORTS; i++) { - cy_port[i].line = -1; - cy_port[i].magic = -1; - } - - /* initialize per-port data structures for each valid board found */ - for (board = 0; board < cy_nboard; board++) { - cinfo = &cy_card[board]; - if (cinfo->num_chips == -1) { /* Cyclades-Z */ - number_z_boards++; - mailbox = cy_readl(&((struct RUNTIME_9060 __iomem *) - cy_card[board].ctl_addr)-> - mail_box_0); - nports = (mailbox == ZE_V1) ? ZE_V1_NPORTS : 8; - cinfo->intr_enabled = 0; - cinfo->nports = 0; /* Will be correctly set later, after - Z FW is loaded */ - spin_lock_init(&cinfo->card_lock); - for (port = cinfo->first_line; - port < cinfo->first_line + nports; port++) { - info = &cy_port[port]; - info->magic = CYCLADES_MAGIC; - info->type = PORT_STARTECH; - info->card = board; - info->line = port; - info->chip_rev = 0; - info->flags = STD_COM_FLAGS; - info->tty = NULL; - if (mailbox == ZO_V1) - info->xmit_fifo_size = CYZ_FIFO_SIZE; - else - info->xmit_fifo_size = - 4 * CYZ_FIFO_SIZE; - info->cor1 = 0; - info->cor2 = 0; - info->cor3 = 0; - info->cor4 = 0; - info->cor5 = 0; - info->tbpr = 0; - info->tco = 0; - info->rbpr = 0; - info->rco = 0; - info->custom_divisor = 0; - info->close_delay = 5 * HZ / 10; - info->closing_wait = CLOSING_WAIT_DELAY; - info->icount.cts = info->icount.dsr = - info->icount.rng = info->icount.dcd = 0; - info->icount.rx = info->icount.tx = 0; - info->icount.frame = info->icount.parity = 0; - info->icount.overrun = info->icount.brk = 0; - info->x_char = 0; - info->event = 0; - info->count = 0; - info->blocked_open = 0; - info->default_threshold = 0; - info->default_timeout = 0; - INIT_WORK(&info->tqueue, do_softint); - init_waitqueue_head(&info->open_wait); - init_waitqueue_head(&info->close_wait); - init_waitqueue_head(&info->shutdown_wait); - init_waitqueue_head(&info->delta_msr_wait); - /* info->session */ - /* info->pgrp */ - info->read_status_mask = 0; - /* info->timeout */ - /* Bentson's vars */ - info->jiffies[0] = 0; - info->jiffies[1] = 0; - info->jiffies[2] = 0; - info->rflush_count = 0; -#ifdef CONFIG_CYZ_INTR - init_timer(&cyz_rx_full_timer[port]); - cyz_rx_full_timer[port].function = NULL; + retval = pci_register_driver(&cy_pci_driver); + if (retval && !nboards) + goto err_unr; #endif - } - continue; - } else { /* Cyclom-Y of some kind */ - index = cinfo->bus_index; - spin_lock_init(&cinfo->card_lock); - cinfo->nports = CyPORTS_PER_CHIP * cinfo->num_chips; - for (port = cinfo->first_line; - port < cinfo->first_line + cinfo->nports; port++) { - info = &cy_port[port]; - info->magic = CYCLADES_MAGIC; - info->type = PORT_CIRRUS; - info->card = board; - info->line = port; - info->flags = STD_COM_FLAGS; - info->tty = NULL; - info->xmit_fifo_size = CyMAX_CHAR_FIFO; - info->cor1 = - CyPARITY_NONE | Cy_1_STOP | Cy_8_BITS; - info->cor2 = CyETC; - info->cor3 = 0x08; /* _very_ small rcv threshold */ - info->cor4 = 0; - info->cor5 = 0; - info->custom_divisor = 0; - info->close_delay = 5 * HZ / 10; - info->closing_wait = CLOSING_WAIT_DELAY; - info->icount.cts = info->icount.dsr = - info->icount.rng = info->icount.dcd = 0; - info->icount.rx = info->icount.tx = 0; - info->icount.frame = info->icount.parity = 0; - info->icount.overrun = info->icount.brk = 0; - chip_number = (port - cinfo->first_line) / 4; - if ((info->chip_rev = - cy_readb(cinfo->base_addr + - (cy_chip_offset[chip_number] << - index) + (CyGFRCR << index))) >= - CD1400_REV_J) { - /* It is a CD1400 rev. J or later */ - info->tbpr = baud_bpr_60[13]; /* Tx BPR */ - info->tco = baud_co_60[13]; /* Tx CO */ - info->rbpr = baud_bpr_60[13]; /* Rx BPR */ - info->rco = baud_co_60[13]; /* Rx CO */ - info->rflow = 0; - info->rtsdtr_inv = 1; - } else { - info->tbpr = baud_bpr_25[13]; /* Tx BPR */ - info->tco = baud_co_25[13]; /* Tx CO */ - info->rbpr = baud_bpr_25[13]; /* Rx BPR */ - info->rco = baud_co_25[13]; /* Rx CO */ - info->rflow = 0; - info->rtsdtr_inv = 0; - } - info->x_char = 0; - info->event = 0; - info->count = 0; - info->blocked_open = 0; - info->default_threshold = 0; - info->default_timeout = 0; - INIT_WORK(&info->tqueue, do_softint); - init_waitqueue_head(&info->open_wait); - init_waitqueue_head(&info->close_wait); - init_waitqueue_head(&info->shutdown_wait); - init_waitqueue_head(&info->delta_msr_wait); - /* info->session */ - /* info->pgrp */ - info->read_status_mask = - CyTIMEOUT | CySPECHAR | CyBREAK - | CyPARITY | CyFRAME | CyOVERRUN; - /* info->timeout */ - } - } - } - -#ifndef CONFIG_CYZ_INTR - if (number_z_boards && !cyz_timeron) { - cyz_timeron++; - cyz_timerlist.expires = jiffies + 1; - add_timer(&cyz_timerlist); -#ifdef CY_PCI_DEBUG - printk("Cyclades-Z polling initialized\n"); -#endif - } -#endif /* CONFIG_CYZ_INTR */ return 0; - +err_unr: + tty_unregister_driver(cy_serial_driver); +err_frtty: + put_tty_driver(cy_serial_driver); +err: + return retval; } /* cy_init */ static void __exit cy_cleanup_module(void) { + struct cyclades_card *card; int i, e1; #ifndef CONFIG_CYZ_INTR - if (cyz_timeron){ - cyz_timeron = 0; - del_timer(&cyz_timerlist); - } + del_timer_sync(&cyz_timerlist); #endif /* CONFIG_CYZ_INTR */ if ((e1 = tty_unregister_driver(cy_serial_driver))) - printk("cyc: failed to unregister Cyclades serial driver(%d)\n", - e1); + printk(KERN_ERR "failed to unregister Cyclades serial " + "driver(%d)\n", e1); - put_tty_driver(cy_serial_driver); +#ifdef CONFIG_PCI + pci_unregister_driver(&cy_pci_driver); +#endif for (i = 0; i < NR_CARDS; i++) { - if (cy_card[i].base_addr) { - iounmap(cy_card[i].base_addr); - if (cy_card[i].ctl_addr) - iounmap(cy_card[i].ctl_addr); - if (cy_card[i].irq + card = &cy_card[i]; + if (card->base_addr) { + /* clear interrupt */ + cy_writeb(card->base_addr + Cy_ClrIntr, 0); + iounmap(card->base_addr); + if (card->ctl_addr) + iounmap(card->ctl_addr); + if (card->irq #ifndef CONFIG_CYZ_INTR - && cy_card[i].num_chips != -1 /* not a Z card */ + && !IS_CYC_Z(*card) #endif /* CONFIG_CYZ_INTR */ ) - free_irq(cy_card[i].irq, &cy_card[i]); -#ifdef CONFIG_PCI - if (cy_card[i].pdev) - pci_release_regions(cy_card[i].pdev); -#endif + free_irq(card->irq, card); + for (e1 = card->first_line; + e1 < card->first_line + + card->nports; e1++) + tty_unregister_device(cy_serial_driver, e1); + kfree(card->ports); } } + + put_tty_driver(cy_serial_driver); } /* cy_cleanup_module */ module_init(cy_init); module_exit(cy_cleanup_module); MODULE_LICENSE("GPL"); +MODULE_VERSION(CY_VERSION); diff --git a/drivers/char/digi.h b/drivers/char/digi.h deleted file mode 100644 index 19df0e879b1..00000000000 --- a/drivers/char/digi.h +++ /dev/null @@ -1,71 +0,0 @@ -/* Definitions for DigiBoard ditty(1) command. */ - -#if !defined(TIOCMODG) -#define TIOCMODG (('d'<<8) | 250) /* get modem ctrl state */ -#define TIOCMODS (('d'<<8) | 251) /* set modem ctrl state */ -#endif - -#if !defined(TIOCMSET) -#define TIOCMSET (('d'<<8) | 252) /* set modem ctrl state */ -#define TIOCMGET (('d'<<8) | 253) /* set modem ctrl state */ -#endif - -#if !defined(TIOCMBIC) -#define TIOCMBIC (('d'<<8) | 254) /* set modem ctrl state */ -#define TIOCMBIS (('d'<<8) | 255) /* set modem ctrl state */ -#endif - -#if !defined(TIOCSDTR) -#define TIOCSDTR (('e'<<8) | 0) /* set DTR */ -#define TIOCCDTR (('e'<<8) | 1) /* clear DTR */ -#endif - -/************************************************************************ - * Ioctl command arguments for DIGI parameters. - ************************************************************************/ -#define DIGI_GETA (('e'<<8) | 94) /* Read params */ - -#define DIGI_SETA (('e'<<8) | 95) /* Set params */ -#define DIGI_SETAW (('e'<<8) | 96) /* Drain & set params */ -#define DIGI_SETAF (('e'<<8) | 97) /* Drain, flush & set params */ - -#define DIGI_GETFLOW (('e'<<8) | 99) /* Get startc/stopc flow */ - /* control characters */ -#define DIGI_SETFLOW (('e'<<8) | 100) /* Set startc/stopc flow */ - /* control characters */ -#define DIGI_GETAFLOW (('e'<<8) | 101) /* Get Aux. startc/stopc */ - /* flow control chars */ -#define DIGI_SETAFLOW (('e'<<8) | 102) /* Set Aux. startc/stopc */ - /* flow control chars */ - -struct digiflow_struct { - unsigned char startc; /* flow cntl start char */ - unsigned char stopc; /* flow cntl stop char */ -}; - -typedef struct digiflow_struct digiflow_t; - - -/************************************************************************ - * Values for digi_flags - ************************************************************************/ -#define DIGI_IXON 0x0001 /* Handle IXON in the FEP */ -#define DIGI_FAST 0x0002 /* Fast baud rates */ -#define RTSPACE 0x0004 /* RTS input flow control */ -#define CTSPACE 0x0008 /* CTS output flow control */ -#define DSRPACE 0x0010 /* DSR output flow control */ -#define DCDPACE 0x0020 /* DCD output flow control */ -#define DTRPACE 0x0040 /* DTR input flow control */ -#define DIGI_FORCEDCD 0x0100 /* Force carrier */ -#define DIGI_ALTPIN 0x0200 /* Alternate RJ-45 pin config */ -#define DIGI_AIXON 0x0400 /* Aux flow control in fep */ - - -/************************************************************************ - * Structure used with ioctl commands for DIGI parameters. - ************************************************************************/ -struct digi_struct { - unsigned short digi_flags; /* Flags (see above) */ -}; - -typedef struct digi_struct digi_t; diff --git a/drivers/char/drm/README.drm b/drivers/char/drm/README.drm index 6441e01e587..af74cd79a27 100644 --- a/drivers/char/drm/README.drm +++ b/drivers/char/drm/README.drm @@ -1,6 +1,6 @@ ************************************************************ * For the very latest on DRI development, please see: * -* http://dri.sourceforge.net/ * +* http://dri.freedesktop.org/ * ************************************************************ The Direct Rendering Manager (drm) is a device-independent kernel-level @@ -26,21 +26,19 @@ ways: Documentation on the DRI is available from: - http://precisioninsight.com/piinsights.html + http://dri.freedesktop.org/wiki/Documentation + http://sourceforge.net/project/showfiles.php?group_id=387 + http://dri.sourceforge.net/doc/ For specific information about kernel-level support, see: The Direct Rendering Manager, Kernel Support for the Direct Rendering Infrastructure - http://precisioninsight.com/dr/drm.html + http://dri.sourceforge.net/doc/drm_low_level.html Hardware Locking for the Direct Rendering Infrastructure - http://precisioninsight.com/dr/locking.html + http://dri.sourceforge.net/doc/hardware_locking_low_level.html A Security Analysis of the Direct Rendering Infrastructure - http://precisioninsight.com/dr/security.html + http://dri.sourceforge.net/doc/security_low_level.html -************************************************************ -* For the very latest on DRI development, please see: * -* http://dri.sourceforge.net/ * -************************************************************ diff --git a/drivers/char/drm/ati_pcigart.c b/drivers/char/drm/ati_pcigart.c index bd7be09ea53..5b91bc04ea4 100644 --- a/drivers/char/drm/ati_pcigart.c +++ b/drivers/char/drm/ati_pcigart.c @@ -33,59 +33,44 @@ #include "drmP.h" -#if PAGE_SIZE == 65536 -# define ATI_PCIGART_TABLE_ORDER 0 -# define ATI_PCIGART_TABLE_PAGES (1 << 0) -#elif PAGE_SIZE == 16384 -# define ATI_PCIGART_TABLE_ORDER 1 -# define ATI_PCIGART_TABLE_PAGES (1 << 1) -#elif PAGE_SIZE == 8192 -# define ATI_PCIGART_TABLE_ORDER 2 -# define ATI_PCIGART_TABLE_PAGES (1 << 2) -#elif PAGE_SIZE == 4096 -# define ATI_PCIGART_TABLE_ORDER 3 -# define ATI_PCIGART_TABLE_PAGES (1 << 3) -#else -# error - PAGE_SIZE not 64K, 16K, 8K or 4K -#endif - -# define ATI_MAX_PCIGART_PAGES 8192 /**< 32 MB aperture, 4K pages */ # define ATI_PCIGART_PAGE_SIZE 4096 /**< PCI GART page size */ -static void *drm_ati_alloc_pcigart_table(void) +static void *drm_ati_alloc_pcigart_table(int order) { unsigned long address; struct page *page; int i; - DRM_DEBUG("%s\n", __FUNCTION__); + + DRM_DEBUG("%s: alloc %d order\n", __FUNCTION__, order); address = __get_free_pages(GFP_KERNEL | __GFP_COMP, - ATI_PCIGART_TABLE_ORDER); + order); if (address == 0UL) { return NULL; } page = virt_to_page(address); - for (i = 0; i < ATI_PCIGART_TABLE_PAGES; i++, page++) + for (i = 0; i < order; i++, page++) SetPageReserved(page); DRM_DEBUG("%s: returning 0x%08lx\n", __FUNCTION__, address); return (void *)address; } -static void drm_ati_free_pcigart_table(void *address) +static void drm_ati_free_pcigart_table(void *address, int order) { struct page *page; int i; + int num_pages = 1 << order; DRM_DEBUG("%s\n", __FUNCTION__); page = virt_to_page((unsigned long)address); - for (i = 0; i < ATI_PCIGART_TABLE_PAGES; i++, page++) + for (i = 0; i < num_pages; i++, page++) ClearPageReserved(page); - free_pages((unsigned long)address, ATI_PCIGART_TABLE_ORDER); + free_pages((unsigned long)address, order); } int drm_ati_pcigart_cleanup(drm_device_t *dev, drm_ati_pcigart_info *gart_info) @@ -93,6 +78,8 @@ int drm_ati_pcigart_cleanup(drm_device_t *dev, drm_ati_pcigart_info *gart_info) drm_sg_mem_t *entry = dev->sg; unsigned long pages; int i; + int order; + int num_pages, max_pages; /* we need to support large memory configurations */ if (!entry) { @@ -100,15 +87,19 @@ int drm_ati_pcigart_cleanup(drm_device_t *dev, drm_ati_pcigart_info *gart_info) return 0; } + order = drm_order((gart_info->table_size + (PAGE_SIZE-1)) / PAGE_SIZE); + num_pages = 1 << order; + if (gart_info->bus_addr) { if (gart_info->gart_table_location == DRM_ATI_GART_MAIN) { pci_unmap_single(dev->pdev, gart_info->bus_addr, - ATI_PCIGART_TABLE_PAGES * PAGE_SIZE, + num_pages * PAGE_SIZE, PCI_DMA_TODEVICE); } - pages = (entry->pages <= ATI_MAX_PCIGART_PAGES) - ? entry->pages : ATI_MAX_PCIGART_PAGES; + max_pages = (gart_info->table_size / sizeof(u32)); + pages = (entry->pages <= max_pages) + ? entry->pages : max_pages; for (i = 0; i < pages; i++) { if (!entry->busaddr[i]) @@ -123,13 +114,12 @@ int drm_ati_pcigart_cleanup(drm_device_t *dev, drm_ati_pcigart_info *gart_info) if (gart_info->gart_table_location == DRM_ATI_GART_MAIN && gart_info->addr) { - drm_ati_free_pcigart_table(gart_info->addr); + drm_ati_free_pcigart_table(gart_info->addr, order); gart_info->addr = NULL; } return 1; } - EXPORT_SYMBOL(drm_ati_pcigart_cleanup); int drm_ati_pcigart_init(drm_device_t *dev, drm_ati_pcigart_info *gart_info) @@ -139,6 +129,9 @@ int drm_ati_pcigart_init(drm_device_t *dev, drm_ati_pcigart_info *gart_info) unsigned long pages; u32 *pci_gart, page_base, bus_address = 0; int i, j, ret = 0; + int order; + int max_pages; + int num_pages; if (!entry) { DRM_ERROR("no scatter/gather memory!\n"); @@ -148,7 +141,10 @@ int drm_ati_pcigart_init(drm_device_t *dev, drm_ati_pcigart_info *gart_info) if (gart_info->gart_table_location == DRM_ATI_GART_MAIN) { DRM_DEBUG("PCI: no table in VRAM: using normal RAM\n"); - address = drm_ati_alloc_pcigart_table(); + order = drm_order((gart_info->table_size + + (PAGE_SIZE-1)) / PAGE_SIZE); + num_pages = 1 << order; + address = drm_ati_alloc_pcigart_table(order); if (!address) { DRM_ERROR("cannot allocate PCI GART page!\n"); goto done; @@ -160,11 +156,13 @@ int drm_ati_pcigart_init(drm_device_t *dev, drm_ati_pcigart_info *gart_info) } bus_address = pci_map_single(dev->pdev, address, - ATI_PCIGART_TABLE_PAGES * - PAGE_SIZE, PCI_DMA_TODEVICE); + num_pages * PAGE_SIZE, + PCI_DMA_TODEVICE); if (bus_address == 0) { DRM_ERROR("unable to map PCIGART pages!\n"); - drm_ati_free_pcigart_table(address); + order = drm_order((gart_info->table_size + + (PAGE_SIZE-1)) / PAGE_SIZE); + drm_ati_free_pcigart_table(address, order); address = NULL; goto done; } @@ -177,10 +175,11 @@ int drm_ati_pcigart_init(drm_device_t *dev, drm_ati_pcigart_info *gart_info) pci_gart = (u32 *) address; - pages = (entry->pages <= ATI_MAX_PCIGART_PAGES) - ? entry->pages : ATI_MAX_PCIGART_PAGES; + max_pages = (gart_info->table_size / sizeof(u32)); + pages = (entry->pages <= max_pages) + ? entry->pages : max_pages; - memset(pci_gart, 0, ATI_MAX_PCIGART_PAGES * sizeof(u32)); + memset(pci_gart, 0, max_pages * sizeof(u32)); for (i = 0; i < pages; i++) { /* we need to support large memory configurations */ @@ -198,10 +197,18 @@ int drm_ati_pcigart_init(drm_device_t *dev, drm_ati_pcigart_info *gart_info) page_base = (u32) entry->busaddr[i]; for (j = 0; j < (PAGE_SIZE / ATI_PCIGART_PAGE_SIZE); j++) { - if (gart_info->is_pcie) + switch(gart_info->gart_reg_if) { + case DRM_ATI_GART_IGP: + *pci_gart = cpu_to_le32((page_base) | 0xc); + break; + case DRM_ATI_GART_PCIE: *pci_gart = cpu_to_le32((page_base >> 8) | 0xc); - else + break; + default: + case DRM_ATI_GART_PCI: *pci_gart = cpu_to_le32(page_base); + break; + } pci_gart++; page_base += ATI_PCIGART_PAGE_SIZE; } @@ -220,5 +227,4 @@ int drm_ati_pcigart_init(drm_device_t *dev, drm_ati_pcigart_info *gart_info) gart_info->bus_addr = bus_address; return ret; } - EXPORT_SYMBOL(drm_ati_pcigart_init); diff --git a/drivers/char/drm/drm.h b/drivers/char/drm/drm.h index 8db9041e306..089198491f1 100644 --- a/drivers/char/drm/drm.h +++ b/drivers/char/drm/drm.h @@ -654,11 +654,13 @@ typedef struct drm_set_version { /** * Device specific ioctls should only be in their respective headers - * The device specific ioctl range is from 0x40 to 0x79. + * The device specific ioctl range is from 0x40 to 0x99. + * Generic IOCTLS restart at 0xA0. * * \sa drmCommandNone(), drmCommandRead(), drmCommandWrite(), and * drmCommandReadWrite(). */ #define DRM_COMMAND_BASE 0x40 +#define DRM_COMMAND_END 0xA0 #endif diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h index 85d99e21e18..d494315752a 100644 --- a/drivers/char/drm/drmP.h +++ b/drivers/char/drm/drmP.h @@ -414,6 +414,10 @@ typedef struct drm_lock_data { struct file *filp; /**< File descr of lock holder (0=kernel) */ wait_queue_head_t lock_queue; /**< Queue of blocked processes */ unsigned long lock_time; /**< Time of last lock in jiffies */ + spinlock_t spinlock; + uint32_t kernel_waiters; + uint32_t user_waiters; + int idle_has_lock; } drm_lock_data_t; /** @@ -515,12 +519,17 @@ typedef struct drm_vbl_sig { #define DRM_ATI_GART_MAIN 1 #define DRM_ATI_GART_FB 2 +#define DRM_ATI_GART_PCI 1 +#define DRM_ATI_GART_PCIE 2 +#define DRM_ATI_GART_IGP 3 + typedef struct ati_pcigart_info { int gart_table_location; - int is_pcie; + int gart_reg_if; void *addr; dma_addr_t bus_addr; drm_local_map_t mapping; + int table_size; } drm_ati_pcigart_info; /* @@ -590,6 +599,8 @@ struct drm_driver { void (*reclaim_buffers) (struct drm_device * dev, struct file * filp); void (*reclaim_buffers_locked) (struct drm_device *dev, struct file *filp); + void (*reclaim_buffers_idlelocked) (struct drm_device *dev, + struct file * filp); unsigned long (*get_map_ofs) (drm_map_t * map); unsigned long (*get_reg_ofs) (struct drm_device * dev); void (*set_version) (struct drm_device * dev, drm_set_version_t * sv); @@ -764,7 +775,7 @@ static __inline__ int drm_core_check_feature(struct drm_device *dev, } #ifdef __alpha__ -#define drm_get_pci_domain(dev) dev->hose->bus->number +#define drm_get_pci_domain(dev) dev->hose->index #else #define drm_get_pci_domain(dev) 0 #endif @@ -915,9 +926,18 @@ extern int drm_lock(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); extern int drm_unlock(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); -extern int drm_lock_take(__volatile__ unsigned int *lock, unsigned int context); -extern int drm_lock_free(drm_device_t * dev, - __volatile__ unsigned int *lock, unsigned int context); +extern int drm_lock_take(drm_lock_data_t *lock_data, unsigned int context); +extern int drm_lock_free(drm_lock_data_t *lock_data, unsigned int context); +extern void drm_idlelock_take(drm_lock_data_t *lock_data); +extern void drm_idlelock_release(drm_lock_data_t *lock_data); + +/* + * These are exported to drivers so that they can implement fencing using + * DMA quiscent + idle. DMA quiescent usually requires the hardware lock. + */ + +extern int drm_i_have_hw_lock(struct file *filp); +extern int drm_kernel_take_hw_lock(struct file *filp); /* Buffer management support (drm_bufs.h) */ extern int drm_addbufs_agp(drm_device_t * dev, drm_buf_desc_t * request); diff --git a/drivers/char/drm/drm_bufs.c b/drivers/char/drm/drm_bufs.c index a6828cc14e5..c11345856ff 100644 --- a/drivers/char/drm/drm_bufs.c +++ b/drivers/char/drm/drm_bufs.c @@ -57,7 +57,8 @@ static drm_map_list_t *drm_find_matching_map(drm_device_t *dev, list_for_each(list, &dev->maplist->head) { drm_map_list_t *entry = list_entry(list, drm_map_list_t, head); if (entry->map && map->type == entry->map->type && - entry->map->offset == map->offset) { + ((entry->map->offset == map->offset) || + (map->type == _DRM_SHM && map->flags==_DRM_CONTAINS_LOCK))) { return entry; } } @@ -180,8 +181,20 @@ static int drm_addmap_core(drm_device_t * dev, unsigned int offset, if (map->type == _DRM_REGISTERS) map->handle = ioremap(map->offset, map->size); break; - case _DRM_SHM: + list = drm_find_matching_map(dev, map); + if (list != NULL) { + if(list->map->size != map->size) { + DRM_DEBUG("Matching maps of type %d with " + "mismatched sizes, (%ld vs %ld)\n", + map->type, map->size, list->map->size); + list->map->size = map->size; + } + + drm_free(map, sizeof(*map), DRM_MEM_MAPS); + *maplist = list; + return 0; + } map->handle = vmalloc_user(map->size); DRM_DEBUG("%lu %d %p\n", map->size, drm_order(map->size), map->handle); @@ -200,15 +213,45 @@ static int drm_addmap_core(drm_device_t * dev, unsigned int offset, dev->sigdata.lock = dev->lock.hw_lock = map->handle; /* Pointer to lock */ } break; - case _DRM_AGP: - if (drm_core_has_AGP(dev)) { + case _DRM_AGP: { + drm_agp_mem_t *entry; + int valid = 0; + + if (!drm_core_has_AGP(dev)) { + drm_free(map, sizeof(*map), DRM_MEM_MAPS); + return -EINVAL; + } #ifdef __alpha__ - map->offset += dev->hose->mem_space->start; + map->offset += dev->hose->mem_space->start; #endif - map->offset += dev->agp->base; - map->mtrr = dev->agp->agp_mtrr; /* for getmap */ + /* Note: dev->agp->base may actually be 0 when the DRM + * is not in control of AGP space. But if user space is + * it should already have added the AGP base itself. + */ + map->offset += dev->agp->base; + map->mtrr = dev->agp->agp_mtrr; /* for getmap */ + + /* This assumes the DRM is in total control of AGP space. + * It's not always the case as AGP can be in the control + * of user space (i.e. i810 driver). So this loop will get + * skipped and we double check that dev->agp->memory is + * actually set as well as being invalid before EPERM'ing + */ + for (entry = dev->agp->memory; entry; entry = entry->next) { + if ((map->offset >= entry->bound) && + (map->offset + map->size <= entry->bound + entry->pages * PAGE_SIZE)) { + valid = 1; + break; + } } + if (dev->agp->memory && !valid) { + drm_free(map, sizeof(*map), DRM_MEM_MAPS); + return -EPERM; + } + DRM_DEBUG("AGP offset = 0x%08lx, size = 0x%08lx\n", map->offset, map->size); + break; + } case _DRM_SCATTER_GATHER: if (!dev->sg) { drm_free(map, sizeof(*map), DRM_MEM_MAPS); @@ -267,7 +310,7 @@ static int drm_addmap_core(drm_device_t * dev, unsigned int offset, *maplist = list; return 0; -} + } int drm_addmap(drm_device_t * dev, unsigned int offset, unsigned int size, drm_map_type_t type, @@ -519,6 +562,7 @@ int drm_addbufs_agp(drm_device_t * dev, drm_buf_desc_t * request) { drm_device_dma_t *dma = dev->dma; drm_buf_entry_t *entry; + drm_agp_mem_t *agp_entry; drm_buf_t *buf; unsigned long offset; unsigned long agp_offset; @@ -529,7 +573,7 @@ int drm_addbufs_agp(drm_device_t * dev, drm_buf_desc_t * request) int page_order; int total; int byte_count; - int i; + int i, valid; drm_buf_t **temp_buflist; if (!dma) @@ -560,6 +604,19 @@ int drm_addbufs_agp(drm_device_t * dev, drm_buf_desc_t * request) if (dev->queue_count) return -EBUSY; /* Not while in use */ + /* Make sure buffers are located in AGP memory that we own */ + valid = 0; + for (agp_entry = dev->agp->memory; agp_entry; agp_entry = agp_entry->next) { + if ((agp_offset >= agp_entry->bound) && + (agp_offset + total * count <= agp_entry->bound + agp_entry->pages * PAGE_SIZE)) { + valid = 1; + break; + } + } + if (dev->agp->memory && !valid) { + DRM_DEBUG("zone invalid\n"); + return -EINVAL; + } spin_lock(&dev->count_lock); if (dev->buf_use) { spin_unlock(&dev->count_lock); diff --git a/drivers/char/drm/drm_dma.c b/drivers/char/drm/drm_dma.c index 892db709698..32ed19c9ec1 100644 --- a/drivers/char/drm/drm_dma.c +++ b/drivers/char/drm/drm_dma.c @@ -65,7 +65,7 @@ int drm_dma_setup(drm_device_t * dev) * \param dev DRM device. * * Free all pages associated with DMA buffers, the buffers and pages lists, and - * finally the the drm_device::dma structure itself. + * finally the drm_device::dma structure itself. */ void drm_dma_takedown(drm_device_t * dev) { diff --git a/drivers/char/drm/drm_drv.c b/drivers/char/drm/drm_drv.c index f5b9b2480c1..8e77b7ed0f4 100644 --- a/drivers/char/drm/drm_drv.c +++ b/drivers/char/drm/drm_drv.c @@ -15,8 +15,6 @@ * #define DRIVER_DESC "Matrox G200/G400" * #define DRIVER_DATE "20001127" * - * #define DRIVER_IOCTL_COUNT DRM_ARRAY_SIZE( mga_ioctls ) - * * #define drm_x mga_##x * \endcode */ @@ -120,7 +118,7 @@ static drm_ioctl_desc_t drm_ioctls[] = { [DRM_IOCTL_NR(DRM_IOCTL_UPDATE_DRAW)] = {drm_update_drawable_info, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, }; -#define DRIVER_IOCTL_COUNT ARRAY_SIZE( drm_ioctls ) +#define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls ) /** * Take down the DRM device. @@ -496,11 +494,14 @@ int drm_ioctl(struct inode *inode, struct file *filp, (long)old_encode_dev(priv->head->device), priv->authenticated); - if (nr < DRIVER_IOCTL_COUNT) - ioctl = &drm_ioctls[nr]; - else if ((nr >= DRM_COMMAND_BASE) - && (nr < DRM_COMMAND_BASE + dev->driver->num_ioctls)) + if ((nr >= DRM_CORE_IOCTL_COUNT) && + ((nr < DRM_COMMAND_BASE) || (nr >= DRM_COMMAND_END))) + goto err_i1; + if ((nr >= DRM_COMMAND_BASE) && (nr < DRM_COMMAND_END) && + (nr < DRM_COMMAND_BASE + dev->driver->num_ioctls)) ioctl = &dev->driver->ioctls[nr - DRM_COMMAND_BASE]; + else if ((nr >= DRM_COMMAND_END) || (nr < DRM_COMMAND_BASE)) + ioctl = &drm_ioctls[nr]; else goto err_i1; diff --git a/drivers/char/drm/drm_fops.c b/drivers/char/drm/drm_fops.c index 898f47dafec..3b159cab3bc 100644 --- a/drivers/char/drm/drm_fops.c +++ b/drivers/char/drm/drm_fops.c @@ -46,6 +46,7 @@ static int drm_setup(drm_device_t * dev) drm_local_map_t *map; int i; int ret; + u32 sareapage; if (dev->driver->firstopen) { ret = dev->driver->firstopen(dev); @@ -56,7 +57,8 @@ static int drm_setup(drm_device_t * dev) dev->magicfree.next = NULL; /* prebuild the SAREA */ - i = drm_addmap(dev, 0, SAREA_MAX, _DRM_SHM, _DRM_CONTAINS_LOCK, &map); + sareapage = max_t(unsigned, SAREA_MAX, PAGE_SIZE); + i = drm_addmap(dev, 0, sareapage, _DRM_SHM, _DRM_CONTAINS_LOCK, &map); if (i != 0) return i; @@ -84,7 +86,7 @@ static int drm_setup(drm_device_t * dev) INIT_LIST_HEAD(&dev->ctxlist->head); dev->vmalist = NULL; - dev->sigdata.lock = dev->lock.hw_lock = NULL; + dev->sigdata.lock = NULL; init_waitqueue_head(&dev->lock.lock_queue); dev->queue_count = 0; dev->queue_reserved = 0; @@ -354,58 +356,56 @@ int drm_release(struct inode *inode, struct file *filp) current->pid, (long)old_encode_dev(priv->head->device), dev->open_count); - if (priv->lock_count && dev->lock.hw_lock && - _DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) && - dev->lock.filp == filp) { - DRM_DEBUG("File %p released, freeing lock for context %d\n", - filp, _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)); - - if (dev->driver->reclaim_buffers_locked) + if (dev->driver->reclaim_buffers_locked && dev->lock.hw_lock) { + if (drm_i_have_hw_lock(filp)) { dev->driver->reclaim_buffers_locked(dev, filp); - - drm_lock_free(dev, &dev->lock.hw_lock->lock, - _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)); - - /* FIXME: may require heavy-handed reset of - hardware at this point, possibly - processed via a callback to the X - server. */ - } else if (dev->driver->reclaim_buffers_locked && priv->lock_count - && dev->lock.hw_lock) { - /* The lock is required to reclaim buffers */ - DECLARE_WAITQUEUE(entry, current); - - add_wait_queue(&dev->lock.lock_queue, &entry); - for (;;) { - __set_current_state(TASK_INTERRUPTIBLE); - if (!dev->lock.hw_lock) { - /* Device has been unregistered */ - retcode = -EINTR; - break; + } else { + unsigned long _end=jiffies + 3*DRM_HZ; + int locked = 0; + + drm_idlelock_take(&dev->lock); + + /* + * Wait for a while. + */ + + do{ + spin_lock(&dev->lock.spinlock); + locked = dev->lock.idle_has_lock; + spin_unlock(&dev->lock.spinlock); + if (locked) + break; + schedule(); + } while (!time_after_eq(jiffies, _end)); + + if (!locked) { + DRM_ERROR("reclaim_buffers_locked() deadlock. Please rework this\n" + "\tdriver to use reclaim_buffers_idlelocked() instead.\n" + "\tI will go on reclaiming the buffers anyway.\n"); } - if (drm_lock_take(&dev->lock.hw_lock->lock, - DRM_KERNEL_CONTEXT)) { - dev->lock.filp = filp; - dev->lock.lock_time = jiffies; - atomic_inc(&dev->counts[_DRM_STAT_LOCKS]); - break; /* Got lock */ - } - /* Contention */ - schedule(); - if (signal_pending(current)) { - retcode = -ERESTARTSYS; - break; - } - } - __set_current_state(TASK_RUNNING); - remove_wait_queue(&dev->lock.lock_queue, &entry); - if (!retcode) { + dev->driver->reclaim_buffers_locked(dev, filp); - drm_lock_free(dev, &dev->lock.hw_lock->lock, - DRM_KERNEL_CONTEXT); + drm_idlelock_release(&dev->lock); } } + if (dev->driver->reclaim_buffers_idlelocked && dev->lock.hw_lock) { + + drm_idlelock_take(&dev->lock); + dev->driver->reclaim_buffers_idlelocked(dev, filp); + drm_idlelock_release(&dev->lock); + + } + + if (drm_i_have_hw_lock(filp)) { + DRM_DEBUG("File %p released, freeing lock for context %d\n", + filp, _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)); + + drm_lock_free(&dev->lock, + _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)); + } + + if (drm_core_check_feature(dev, DRIVER_HAVE_DMA) && !dev->driver->reclaim_buffers_locked) { dev->driver->reclaim_buffers(dev, filp); diff --git a/drivers/char/drm/drm_hashtab.c b/drivers/char/drm/drm_hashtab.c index a0b2d6802ae..31acb621dcc 100644 --- a/drivers/char/drm/drm_hashtab.c +++ b/drivers/char/drm/drm_hashtab.c @@ -43,7 +43,16 @@ int drm_ht_create(drm_open_hash_t *ht, unsigned int order) ht->size = 1 << order; ht->order = order; ht->fill = 0; - ht->table = vmalloc(ht->size*sizeof(*ht->table)); + ht->table = NULL; + ht->use_vmalloc = ((ht->size * sizeof(*ht->table)) > PAGE_SIZE); + if (!ht->use_vmalloc) { + ht->table = drm_calloc(ht->size, sizeof(*ht->table), + DRM_MEM_HASHTAB); + } + if (!ht->table) { + ht->use_vmalloc = 1; + ht->table = vmalloc(ht->size*sizeof(*ht->table)); + } if (!ht->table) { DRM_ERROR("Out of memory for hash table\n"); return -ENOMEM; @@ -183,7 +192,11 @@ int drm_ht_remove_item(drm_open_hash_t *ht, drm_hash_item_t *item) void drm_ht_remove(drm_open_hash_t *ht) { if (ht->table) { - vfree(ht->table); + if (ht->use_vmalloc) + vfree(ht->table); + else + drm_free(ht->table, ht->size * sizeof(*ht->table), + DRM_MEM_HASHTAB); ht->table = NULL; } } diff --git a/drivers/char/drm/drm_hashtab.h b/drivers/char/drm/drm_hashtab.h index 40afec05bff..613091c970a 100644 --- a/drivers/char/drm/drm_hashtab.h +++ b/drivers/char/drm/drm_hashtab.h @@ -47,6 +47,7 @@ typedef struct drm_open_hash{ unsigned int order; unsigned int fill; struct hlist_head *table; + int use_vmalloc; } drm_open_hash_t; diff --git a/drivers/char/drm/drm_irq.c b/drivers/char/drm/drm_irq.c index 9d00c51fe2c..2e75331fd83 100644 --- a/drivers/char/drm/drm_irq.c +++ b/drivers/char/drm/drm_irq.c @@ -424,7 +424,7 @@ static void drm_locked_tasklet_func(unsigned long data) spin_lock_irqsave(&dev->tasklet_lock, irqflags); if (!dev->locked_tasklet_func || - !drm_lock_take(&dev->lock.hw_lock->lock, + !drm_lock_take(&dev->lock, DRM_KERNEL_CONTEXT)) { spin_unlock_irqrestore(&dev->tasklet_lock, irqflags); return; @@ -435,7 +435,7 @@ static void drm_locked_tasklet_func(unsigned long data) dev->locked_tasklet_func(dev); - drm_lock_free(dev, &dev->lock.hw_lock->lock, + drm_lock_free(&dev->lock, DRM_KERNEL_CONTEXT); dev->locked_tasklet_func = NULL; diff --git a/drivers/char/drm/drm_lock.c b/drivers/char/drm/drm_lock.c index e9993ba461a..befd1af19df 100644 --- a/drivers/char/drm/drm_lock.c +++ b/drivers/char/drm/drm_lock.c @@ -35,9 +35,6 @@ #include "drmP.h" -static int drm_lock_transfer(drm_device_t * dev, - __volatile__ unsigned int *lock, - unsigned int context); static int drm_notifier(void *priv); /** @@ -80,6 +77,9 @@ int drm_lock(struct inode *inode, struct file *filp, return -EINVAL; add_wait_queue(&dev->lock.lock_queue, &entry); + spin_lock(&dev->lock.spinlock); + dev->lock.user_waiters++; + spin_unlock(&dev->lock.spinlock); for (;;) { __set_current_state(TASK_INTERRUPTIBLE); if (!dev->lock.hw_lock) { @@ -87,7 +87,7 @@ int drm_lock(struct inode *inode, struct file *filp, ret = -EINTR; break; } - if (drm_lock_take(&dev->lock.hw_lock->lock, lock.context)) { + if (drm_lock_take(&dev->lock, lock.context)) { dev->lock.filp = filp; dev->lock.lock_time = jiffies; atomic_inc(&dev->counts[_DRM_STAT_LOCKS]); @@ -101,12 +101,14 @@ int drm_lock(struct inode *inode, struct file *filp, break; } } + spin_lock(&dev->lock.spinlock); + dev->lock.user_waiters--; + spin_unlock(&dev->lock.spinlock); __set_current_state(TASK_RUNNING); remove_wait_queue(&dev->lock.lock_queue, &entry); - DRM_DEBUG("%d %s\n", lock.context, ret ? "interrupted" : "has lock"); - if (ret) - return ret; + DRM_DEBUG( "%d %s\n", lock.context, ret ? "interrupted" : "has lock" ); + if (ret) return ret; sigemptyset(&dev->sigmask); sigaddset(&dev->sigmask, SIGSTOP); @@ -127,14 +129,12 @@ int drm_lock(struct inode *inode, struct file *filp, } } - /* dev->driver->kernel_context_switch isn't used by any of the x86 - * drivers but is used by the Sparc driver. - */ if (dev->driver->kernel_context_switch && dev->last_context != lock.context) { dev->driver->kernel_context_switch(dev, dev->last_context, lock.context); } + return 0; } @@ -184,12 +184,8 @@ int drm_unlock(struct inode *inode, struct file *filp, if (dev->driver->kernel_context_switch_unlock) dev->driver->kernel_context_switch_unlock(dev); else { - drm_lock_transfer(dev, &dev->lock.hw_lock->lock, - DRM_KERNEL_CONTEXT); - - if (drm_lock_free(dev, &dev->lock.hw_lock->lock, - DRM_KERNEL_CONTEXT)) { - DRM_ERROR("\n"); + if (drm_lock_free(&dev->lock,lock.context)) { + /* FIXME: Should really bail out here. */ } } @@ -206,18 +202,26 @@ int drm_unlock(struct inode *inode, struct file *filp, * * Attempt to mark the lock as held by the given context, via the \p cmpxchg instruction. */ -int drm_lock_take(__volatile__ unsigned int *lock, unsigned int context) +int drm_lock_take(drm_lock_data_t *lock_data, + unsigned int context) { unsigned int old, new, prev; + volatile unsigned int *lock = &lock_data->hw_lock->lock; + spin_lock(&lock_data->spinlock); do { old = *lock; if (old & _DRM_LOCK_HELD) new = old | _DRM_LOCK_CONT; - else - new = context | _DRM_LOCK_HELD; + else { + new = context | _DRM_LOCK_HELD | + ((lock_data->user_waiters + lock_data->kernel_waiters > 1) ? + _DRM_LOCK_CONT : 0); + } prev = cmpxchg(lock, old, new); } while (prev != old); + spin_unlock(&lock_data->spinlock); + if (_DRM_LOCKING_CONTEXT(old) == context) { if (old & _DRM_LOCK_HELD) { if (context != DRM_KERNEL_CONTEXT) { @@ -227,7 +231,8 @@ int drm_lock_take(__volatile__ unsigned int *lock, unsigned int context) return 0; } } - if (new == (context | _DRM_LOCK_HELD)) { + + if ((_DRM_LOCKING_CONTEXT(new)) == context && (new & _DRM_LOCK_HELD)) { /* Have lock */ return 1; } @@ -246,13 +251,13 @@ int drm_lock_take(__volatile__ unsigned int *lock, unsigned int context) * Resets the lock file pointer. * Marks the lock as held by the given context, via the \p cmpxchg instruction. */ -static int drm_lock_transfer(drm_device_t * dev, - __volatile__ unsigned int *lock, +static int drm_lock_transfer(drm_lock_data_t *lock_data, unsigned int context) { unsigned int old, new, prev; + volatile unsigned int *lock = &lock_data->hw_lock->lock; - dev->lock.filp = NULL; + lock_data->filp = NULL; do { old = *lock; new = context | _DRM_LOCK_HELD; @@ -272,23 +277,32 @@ static int drm_lock_transfer(drm_device_t * dev, * Marks the lock as not held, via the \p cmpxchg instruction. Wakes any task * waiting on the lock queue. */ -int drm_lock_free(drm_device_t * dev, - __volatile__ unsigned int *lock, unsigned int context) +int drm_lock_free(drm_lock_data_t *lock_data, unsigned int context) { unsigned int old, new, prev; + volatile unsigned int *lock = &lock_data->hw_lock->lock; + + spin_lock(&lock_data->spinlock); + if (lock_data->kernel_waiters != 0) { + drm_lock_transfer(lock_data, 0); + lock_data->idle_has_lock = 1; + spin_unlock(&lock_data->spinlock); + return 1; + } + spin_unlock(&lock_data->spinlock); - dev->lock.filp = NULL; do { old = *lock; - new = 0; + new = _DRM_LOCKING_CONTEXT(old); prev = cmpxchg(lock, old, new); } while (prev != old); + if (_DRM_LOCK_IS_HELD(old) && _DRM_LOCKING_CONTEXT(old) != context) { DRM_ERROR("%d freed heavyweight lock held by %d\n", context, _DRM_LOCKING_CONTEXT(old)); return 1; } - wake_up_interruptible(&dev->lock.lock_queue); + wake_up_interruptible(&lock_data->lock_queue); return 0; } @@ -322,3 +336,67 @@ static int drm_notifier(void *priv) } while (prev != old); return 0; } + +/** + * This function returns immediately and takes the hw lock + * with the kernel context if it is free, otherwise it gets the highest priority when and if + * it is eventually released. + * + * This guarantees that the kernel will _eventually_ have the lock _unless_ it is held + * by a blocked process. (In the latter case an explicit wait for the hardware lock would cause + * a deadlock, which is why the "idlelock" was invented). + * + * This should be sufficient to wait for GPU idle without + * having to worry about starvation. + */ + +void drm_idlelock_take(drm_lock_data_t *lock_data) +{ + int ret = 0; + + spin_lock(&lock_data->spinlock); + lock_data->kernel_waiters++; + if (!lock_data->idle_has_lock) { + + spin_unlock(&lock_data->spinlock); + ret = drm_lock_take(lock_data, DRM_KERNEL_CONTEXT); + spin_lock(&lock_data->spinlock); + + if (ret == 1) + lock_data->idle_has_lock = 1; + } + spin_unlock(&lock_data->spinlock); +} +EXPORT_SYMBOL(drm_idlelock_take); + +void drm_idlelock_release(drm_lock_data_t *lock_data) +{ + unsigned int old, prev; + volatile unsigned int *lock = &lock_data->hw_lock->lock; + + spin_lock(&lock_data->spinlock); + if (--lock_data->kernel_waiters == 0) { + if (lock_data->idle_has_lock) { + do { + old = *lock; + prev = cmpxchg(lock, old, DRM_KERNEL_CONTEXT); + } while (prev != old); + wake_up_interruptible(&lock_data->lock_queue); + lock_data->idle_has_lock = 0; + } + } + spin_unlock(&lock_data->spinlock); +} +EXPORT_SYMBOL(drm_idlelock_release); + + +int drm_i_have_hw_lock(struct file *filp) +{ + DRM_DEVICE; + + return (priv->lock_count && dev->lock.hw_lock && + _DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) && + dev->lock.filp == filp); +} + +EXPORT_SYMBOL(drm_i_have_hw_lock); diff --git a/drivers/char/drm/drm_mm.c b/drivers/char/drm/drm_mm.c index 9b46b85027d..2ec1d9f2626 100644 --- a/drivers/char/drm/drm_mm.c +++ b/drivers/char/drm/drm_mm.c @@ -274,7 +274,6 @@ int drm_mm_init(drm_mm_t * mm, unsigned long start, unsigned long size) return drm_mm_create_tail_node(mm, start, size); } -EXPORT_SYMBOL(drm_mm_init); void drm_mm_takedown(drm_mm_t * mm) { @@ -295,4 +294,3 @@ void drm_mm_takedown(drm_mm_t * mm) drm_free(entry, sizeof(*entry), DRM_MEM_MM); } -EXPORT_SYMBOL(drm_mm_takedown); diff --git a/drivers/char/drm/drm_os_linux.h b/drivers/char/drm/drm_os_linux.h index 2908b72daa6..0fe7b449792 100644 --- a/drivers/char/drm/drm_os_linux.h +++ b/drivers/char/drm/drm_os_linux.h @@ -70,9 +70,6 @@ static __inline__ int mtrr_del(int reg, unsigned long base, unsigned long size) #endif -/** Task queue handler arguments */ -#define DRM_TASKQUEUE_ARGS void *arg - /** For data going into the kernel through the ioctl argument */ #define DRM_COPY_FROM_USER_IOCTL(arg1, arg2, arg3) \ if ( copy_from_user(&arg1, arg2, arg3) ) \ diff --git a/drivers/char/drm/drm_pciids.h b/drivers/char/drm/drm_pciids.h index ad54b845978..31cdde83713 100644 --- a/drivers/char/drm/drm_pciids.h +++ b/drivers/char/drm/drm_pciids.h @@ -102,6 +102,7 @@ {0x1002, 0x5653, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ {0x1002, 0x5834, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|RADEON_IS_IGP}, \ {0x1002, 0x5835, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|RADEON_IS_IGP|RADEON_IS_MOBILITY}, \ + {0x1002, 0x5955, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS400|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART}, \ {0x1002, 0x5960, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \ {0x1002, 0x5961, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \ {0x1002, 0x5962, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \ @@ -230,10 +231,10 @@ {0x1106, 0x7205, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {0x1106, 0x3108, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {0x1106, 0x3304, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ - {0x1106, 0x3157, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {0x1106, 0x3344, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {0x1106, 0x3343, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {0x1106, 0x3230, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VIA_DX9_0}, \ + {0x1106, 0x3157, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VIA_PRO_GROUP_A}, \ {0, 0, 0} #define i810_PCI_IDS \ @@ -296,5 +297,6 @@ {0x8086, 0x2982, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {0x8086, 0x2992, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {0x8086, 0x29a2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x8086, 0x2a02, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {0, 0, 0} diff --git a/drivers/char/drm/drm_proc.c b/drivers/char/drm/drm_proc.c index 7fd0da71214..b204498d1a2 100644 --- a/drivers/char/drm/drm_proc.c +++ b/drivers/char/drm/drm_proc.c @@ -72,7 +72,7 @@ static struct drm_proc_list { #endif }; -#define DRM_PROC_ENTRIES (sizeof(drm_proc_list)/sizeof(drm_proc_list[0])) +#define DRM_PROC_ENTRIES ARRAY_SIZE(drm_proc_list) /** * Initialize the DRI proc filesystem for a device. diff --git a/drivers/char/drm/drm_stub.c b/drivers/char/drm/drm_stub.c index 120d10256fe..19408adcc77 100644 --- a/drivers/char/drm/drm_stub.c +++ b/drivers/char/drm/drm_stub.c @@ -62,6 +62,7 @@ static int drm_fill_in_dev(drm_device_t * dev, struct pci_dev *pdev, spin_lock_init(&dev->count_lock); spin_lock_init(&dev->drw_lock); spin_lock_init(&dev->tasklet_lock); + spin_lock_init(&dev->lock.spinlock); init_timer(&dev->timer); mutex_init(&dev->struct_mutex); mutex_init(&dev->ctxlist_mutex); diff --git a/drivers/char/drm/drm_vm.c b/drivers/char/drm/drm_vm.c index 54a63284895..b5c5b9fa84c 100644 --- a/drivers/char/drm/drm_vm.c +++ b/drivers/char/drm/drm_vm.c @@ -41,6 +41,30 @@ static void drm_vm_open(struct vm_area_struct *vma); static void drm_vm_close(struct vm_area_struct *vma); +static pgprot_t drm_io_prot(uint32_t map_type, struct vm_area_struct *vma) +{ + pgprot_t tmp = vm_get_page_prot(vma->vm_flags); + +#if defined(__i386__) || defined(__x86_64__) + if (boot_cpu_data.x86 > 3 && map_type != _DRM_AGP) { + pgprot_val(tmp) |= _PAGE_PCD; + pgprot_val(tmp) &= ~_PAGE_PWT; + } +#elif defined(__powerpc__) + pgprot_val(tmp) |= _PAGE_NO_CACHE; + if (map_type == _DRM_REGISTERS) + pgprot_val(tmp) |= _PAGE_GUARDED; +#endif +#if defined(__ia64__) + if (efi_range_is_wc(vma->vm_start, vma->vm_end - + vma->vm_start)) + tmp = pgprot_writecombine(tmp); + else + tmp = pgprot_noncached(tmp); +#endif + return tmp; +} + /** * \c nopage method for AGP virtual memory. * @@ -133,7 +157,7 @@ static __inline__ struct page *drm_do_vm_nopage(struct vm_area_struct *vma, * \param address access address. * \return pointer to the page structure. * - * Get the the mapping, find the real physical page to map, get the page, and + * Get the mapping, find the real physical page to map, get the page, and * return it. */ static __inline__ struct page *drm_do_vm_shm_nopage(struct vm_area_struct *vma, @@ -151,8 +175,7 @@ static __inline__ struct page *drm_do_vm_shm_nopage(struct vm_area_struct *vma, offset = address - vma->vm_start; i = (unsigned long)map->handle + offset; - page = (map->type == _DRM_CONSISTENT) ? - virt_to_page((void *)i) : vmalloc_to_page((void *)i); + page = vmalloc_to_page((void *)i); if (!page) return NOPAGE_SIGBUS; get_page(page); @@ -389,7 +412,7 @@ static struct vm_operations_struct drm_vm_sg_ops = { * Create a new drm_vma_entry structure as the \p vma private data entry and * add it to drm_device::vmalist. */ -static void drm_vm_open(struct vm_area_struct *vma) +static void drm_vm_open_locked(struct vm_area_struct *vma) { drm_file_t *priv = vma->vm_file->private_data; drm_device_t *dev = priv->head->dev; @@ -401,15 +424,23 @@ static void drm_vm_open(struct vm_area_struct *vma) vma_entry = drm_alloc(sizeof(*vma_entry), DRM_MEM_VMAS); if (vma_entry) { - mutex_lock(&dev->struct_mutex); vma_entry->vma = vma; vma_entry->next = dev->vmalist; vma_entry->pid = current->pid; dev->vmalist = vma_entry; - mutex_unlock(&dev->struct_mutex); } } +static void drm_vm_open(struct vm_area_struct *vma) +{ + drm_file_t *priv = vma->vm_file->private_data; + drm_device_t *dev = priv->head->dev; + + mutex_lock(&dev->struct_mutex); + drm_vm_open_locked(vma); + mutex_unlock(&dev->struct_mutex); +} + /** * \c close method for all virtual memory types. * @@ -460,7 +491,6 @@ static int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma) drm_device_dma_t *dma; unsigned long length = vma->vm_end - vma->vm_start; - lock_kernel(); dev = priv->head->dev; dma = dev->dma; DRM_DEBUG("start = 0x%lx, end = 0x%lx, page offset = 0x%lx\n", @@ -468,10 +498,8 @@ static int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma) /* Length must match exact page count */ if (!dma || (length >> PAGE_SHIFT) != dma->page_count) { - unlock_kernel(); return -EINVAL; } - unlock_kernel(); if (!capable(CAP_SYS_ADMIN) && (dma->flags & _DRM_DMA_USE_PCI_RO)) { @@ -494,7 +522,7 @@ static int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma) vma->vm_flags |= VM_RESERVED; /* Don't swap */ vma->vm_file = filp; /* Needed for drm_vm_open() */ - drm_vm_open(vma); + drm_vm_open_locked(vma); return 0; } @@ -529,7 +557,7 @@ EXPORT_SYMBOL(drm_core_get_reg_ofs); * according to the mapping type and remaps the pages. Finally sets the file * pointer and calls vm_open(). */ -int drm_mmap(struct file *filp, struct vm_area_struct *vma) +static int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma) { drm_file_t *priv = filp->private_data; drm_device_t *dev = priv->head->dev; @@ -565,7 +593,7 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma) return -EPERM; /* Check for valid size. */ - if (map->size != vma->vm_end - vma->vm_start) + if (map->size < vma->vm_end - vma->vm_start) return -EINVAL; if (!capable(CAP_SYS_ADMIN) && (map->flags & _DRM_READ_ONLY)) { @@ -600,37 +628,16 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma) /* fall through to _DRM_FRAME_BUFFER... */ case _DRM_FRAME_BUFFER: case _DRM_REGISTERS: -#if defined(__i386__) || defined(__x86_64__) - if (boot_cpu_data.x86 > 3 && map->type != _DRM_AGP) { - pgprot_val(vma->vm_page_prot) |= _PAGE_PCD; - pgprot_val(vma->vm_page_prot) &= ~_PAGE_PWT; - } -#elif defined(__powerpc__) - pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE; - if (map->type == _DRM_REGISTERS) - pgprot_val(vma->vm_page_prot) |= _PAGE_GUARDED; -#endif - vma->vm_flags |= VM_IO; /* not in core dump */ -#if defined(__ia64__) - if (efi_range_is_wc(vma->vm_start, vma->vm_end - vma->vm_start)) - vma->vm_page_prot = - pgprot_writecombine(vma->vm_page_prot); - else - vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); -#endif offset = dev->driver->get_reg_ofs(dev); + vma->vm_flags |= VM_IO; /* not in core dump */ + vma->vm_page_prot = drm_io_prot(map->type, vma); #ifdef __sparc__ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); +#endif if (io_remap_pfn_range(vma, vma->vm_start, (map->offset + offset) >> PAGE_SHIFT, vma->vm_end - vma->vm_start, vma->vm_page_prot)) -#else - if (io_remap_pfn_range(vma, vma->vm_start, - (map->offset + offset) >> PAGE_SHIFT, - vma->vm_end - vma->vm_start, - vma->vm_page_prot)) -#endif return -EAGAIN; DRM_DEBUG(" Type = %d; start = 0x%lx, end = 0x%lx," " offset = 0x%lx\n", @@ -638,10 +645,15 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma) vma->vm_start, vma->vm_end, map->offset + offset); vma->vm_ops = &drm_vm_ops; break; - case _DRM_SHM: case _DRM_CONSISTENT: - /* Consistent memory is really like shared memory. It's only - * allocate in a different way */ + /* Consistent memory is really like shared memory. But + * it's allocated in a different way, so avoid nopage */ + if (remap_pfn_range(vma, vma->vm_start, + page_to_pfn(virt_to_page(map->handle)), + vma->vm_end - vma->vm_start, vma->vm_page_prot)) + return -EAGAIN; + /* fall through to _DRM_SHM */ + case _DRM_SHM: vma->vm_ops = &drm_vm_shm_ops; vma->vm_private_data = (void *)map; /* Don't let this area swap. Change when @@ -659,8 +671,20 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma) vma->vm_flags |= VM_RESERVED; /* Don't swap */ vma->vm_file = filp; /* Needed for drm_vm_open() */ - drm_vm_open(vma); + drm_vm_open_locked(vma); return 0; } +int drm_mmap(struct file *filp, struct vm_area_struct *vma) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->head->dev; + int ret; + + mutex_lock(&dev->struct_mutex); + ret = drm_mmap_locked(filp, vma); + mutex_unlock(&dev->struct_mutex); + + return ret; +} EXPORT_SYMBOL(drm_mmap); diff --git a/drivers/char/drm/i915_dma.c b/drivers/char/drm/i915_dma.c index 9354ce3b009..1ba15d9a171 100644 --- a/drivers/char/drm/i915_dma.c +++ b/drivers/char/drm/i915_dma.c @@ -34,7 +34,8 @@ #define IS_I965G(dev) (dev->pci_device == 0x2972 || \ dev->pci_device == 0x2982 || \ dev->pci_device == 0x2992 || \ - dev->pci_device == 0x29A2) + dev->pci_device == 0x29A2 || \ + dev->pci_device == 0x2A02) /* Really want an OS-independent resettable timer. Would like to have * this loop run for (eg) 3 sec, but have the timer reset every time diff --git a/drivers/char/drm/r128_cce.c b/drivers/char/drm/r128_cce.c index db5a60450e6..1014602c43a 100644 --- a/drivers/char/drm/r128_cce.c +++ b/drivers/char/drm/r128_cce.c @@ -560,9 +560,10 @@ static int r128_do_init_cce(drm_device_t * dev, drm_r128_init_t * init) if (dev_priv->is_pci) { #endif dev_priv->gart_info.gart_table_location = DRM_ATI_GART_MAIN; + dev_priv->gart_info.table_size = R128_PCIGART_TABLE_SIZE; dev_priv->gart_info.addr = NULL; dev_priv->gart_info.bus_addr = 0; - dev_priv->gart_info.is_pcie = 0; + dev_priv->gart_info.gart_reg_if = DRM_ATI_GART_PCI; if (!drm_ati_pcigart_init(dev, &dev_priv->gart_info)) { DRM_ERROR("failed to init PCI GART!\n"); dev->dev_private = (void *)dev_priv; diff --git a/drivers/char/drm/r128_drv.h b/drivers/char/drm/r128_drv.h index f1efb49de8d..9086835686d 100644 --- a/drivers/char/drm/r128_drv.h +++ b/drivers/char/drm/r128_drv.h @@ -383,6 +383,8 @@ extern long r128_compat_ioctl(struct file *filp, unsigned int cmd, #define R128_PERFORMANCE_BOXES 0 +#define R128_PCIGART_TABLE_SIZE 32768 + #define R128_READ(reg) DRM_READ32( dev_priv->mmio, (reg) ) #define R128_WRITE(reg,val) DRM_WRITE32( dev_priv->mmio, (reg), (val) ) #define R128_READ8(reg) DRM_READ8( dev_priv->mmio, (reg) ) diff --git a/drivers/char/drm/r300_reg.h b/drivers/char/drm/r300_reg.h index a881f96c983..ecda760ae8c 100644 --- a/drivers/char/drm/r300_reg.h +++ b/drivers/char/drm/r300_reg.h @@ -293,7 +293,7 @@ I am fairly certain that they are correct unless stated otherwise in comments. # define R300_PVS_CNTL_1_PROGRAM_START_SHIFT 0 # define R300_PVS_CNTL_1_POS_END_SHIFT 10 # define R300_PVS_CNTL_1_PROGRAM_END_SHIFT 20 -/* Addresses are relative the the vertex program parameters area. */ +/* Addresses are relative to the vertex program parameters area. */ #define R300_VAP_PVS_CNTL_2 0x22D4 # define R300_PVS_CNTL_2_PARAM_OFFSET_SHIFT 0 # define R300_PVS_CNTL_2_PARAM_COUNT_SHIFT 16 diff --git a/drivers/char/drm/radeon_cp.c b/drivers/char/drm/radeon_cp.c index 5ed96568829..68338389d83 100644 --- a/drivers/char/drm/radeon_cp.c +++ b/drivers/char/drm/radeon_cp.c @@ -830,6 +830,15 @@ static int RADEON_READ_PCIE(drm_radeon_private_t *dev_priv, int addr) return RADEON_READ(RADEON_PCIE_DATA); } +static u32 RADEON_READ_IGPGART(drm_radeon_private_t *dev_priv, int addr) +{ + u32 ret; + RADEON_WRITE(RADEON_IGPGART_INDEX, addr & 0x7f); + ret = RADEON_READ(RADEON_IGPGART_DATA); + RADEON_WRITE(RADEON_IGPGART_INDEX, 0x7f); + return ret; +} + #if RADEON_FIFO_DEBUG static void radeon_status(drm_radeon_private_t * dev_priv) { @@ -1267,7 +1276,44 @@ static void radeon_test_writeback(drm_radeon_private_t * dev_priv) } } -/* Enable or disable PCI-E GART on the chip */ +/* Enable or disable IGP GART on the chip */ +static void radeon_set_igpgart(drm_radeon_private_t * dev_priv, int on) +{ + u32 temp, tmp; + + tmp = RADEON_READ(RADEON_AIC_CNTL); + if (on) { + DRM_DEBUG("programming igpgart %08X %08lX %08X\n", + dev_priv->gart_vm_start, + (long)dev_priv->gart_info.bus_addr, + dev_priv->gart_size); + + RADEON_WRITE_IGPGART(RADEON_IGPGART_UNK_18, 0x1000); + RADEON_WRITE_IGPGART(RADEON_IGPGART_ENABLE, 0x1); + RADEON_WRITE_IGPGART(RADEON_IGPGART_CTRL, 0x42040800); + RADEON_WRITE_IGPGART(RADEON_IGPGART_BASE_ADDR, + dev_priv->gart_info.bus_addr); + + temp = RADEON_READ_IGPGART(dev_priv, RADEON_IGPGART_UNK_39); + RADEON_WRITE_IGPGART(RADEON_IGPGART_UNK_39, temp); + + RADEON_WRITE(RADEON_AGP_BASE, (unsigned int)dev_priv->gart_vm_start); + dev_priv->gart_size = 32*1024*1024; + RADEON_WRITE(RADEON_MC_AGP_LOCATION, + (((dev_priv->gart_vm_start - 1 + + dev_priv->gart_size) & 0xffff0000) | + (dev_priv->gart_vm_start >> 16))); + + temp = RADEON_READ_IGPGART(dev_priv, RADEON_IGPGART_ENABLE); + RADEON_WRITE_IGPGART(RADEON_IGPGART_ENABLE, temp); + + RADEON_READ_IGPGART(dev_priv, RADEON_IGPGART_FLUSH); + RADEON_WRITE_IGPGART(RADEON_IGPGART_FLUSH, 0x1); + RADEON_READ_IGPGART(dev_priv, RADEON_IGPGART_FLUSH); + RADEON_WRITE_IGPGART(RADEON_IGPGART_FLUSH, 0x0); + } +} + static void radeon_set_pciegart(drm_radeon_private_t * dev_priv, int on) { u32 tmp = RADEON_READ_PCIE(dev_priv, RADEON_PCIE_TX_GART_CNTL); @@ -1302,6 +1348,11 @@ static void radeon_set_pcigart(drm_radeon_private_t * dev_priv, int on) { u32 tmp; + if (dev_priv->flags & RADEON_IS_IGPGART) { + radeon_set_igpgart(dev_priv, on); + return; + } + if (dev_priv->flags & RADEON_IS_PCIE) { radeon_set_pciegart(dev_priv, on); return; @@ -1560,8 +1611,8 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init) if (dev_priv->flags & RADEON_IS_AGP) { base = dev->agp->base; /* Check if valid */ - if ((base + dev_priv->gart_size) > dev_priv->fb_location && - base < (dev_priv->fb_location + dev_priv->fb_size)) { + if ((base + dev_priv->gart_size - 1) >= dev_priv->fb_location && + base < (dev_priv->fb_location + dev_priv->fb_size - 1)) { DRM_INFO("Can't use AGP base @0x%08lx, won't fit\n", dev->agp->base); base = 0; @@ -1571,8 +1622,8 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init) /* If not or if AGP is at 0 (Macs), try to put it elsewhere */ if (base == 0) { base = dev_priv->fb_location + dev_priv->fb_size; - if (((base + dev_priv->gart_size) & 0xfffffffful) - < base) + if (base < dev_priv->fb_location || + ((base + dev_priv->gart_size) & 0xfffffffful) < base) base = dev_priv->fb_location - dev_priv->gart_size; } @@ -1620,20 +1671,22 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init) #endif { /* if we have an offset set from userspace */ - if (dev_priv->pcigart_offset) { + if (dev_priv->pcigart_offset_set) { dev_priv->gart_info.bus_addr = dev_priv->pcigart_offset + dev_priv->fb_location; dev_priv->gart_info.mapping.offset = dev_priv->gart_info.bus_addr; dev_priv->gart_info.mapping.size = - RADEON_PCIGART_TABLE_SIZE; + dev_priv->gart_info.table_size; drm_core_ioremap(&dev_priv->gart_info.mapping, dev); dev_priv->gart_info.addr = dev_priv->gart_info.mapping.handle; - dev_priv->gart_info.is_pcie = - !!(dev_priv->flags & RADEON_IS_PCIE); + if (dev_priv->flags & RADEON_IS_PCIE) + dev_priv->gart_info.gart_reg_if = DRM_ATI_GART_PCIE; + else + dev_priv->gart_info.gart_reg_if = DRM_ATI_GART_PCI; dev_priv->gart_info.gart_table_location = DRM_ATI_GART_FB; @@ -1641,6 +1694,10 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init) dev_priv->gart_info.addr, dev_priv->pcigart_offset); } else { + if (dev_priv->flags & RADEON_IS_IGPGART) + dev_priv->gart_info.gart_reg_if = DRM_ATI_GART_IGP; + else + dev_priv->gart_info.gart_reg_if = DRM_ATI_GART_PCI; dev_priv->gart_info.gart_table_location = DRM_ATI_GART_MAIN; dev_priv->gart_info.addr = NULL; @@ -1714,7 +1771,7 @@ static int radeon_do_cleanup_cp(drm_device_t * dev) if (dev_priv->gart_info.gart_table_location == DRM_ATI_GART_FB) { drm_core_ioremapfree(&dev_priv->gart_info.mapping, dev); - dev_priv->gart_info.addr = NULL; + dev_priv->gart_info.addr = 0; } } /* only clear to the start of flags */ @@ -2222,6 +2279,8 @@ int radeon_driver_firstopen(struct drm_device *dev) drm_local_map_t *map; drm_radeon_private_t *dev_priv = dev->dev_private; + dev_priv->gart_info.table_size = RADEON_PCIGART_TABLE_SIZE; + ret = drm_addmap(dev, drm_get_resource_start(dev, 2), drm_get_resource_len(dev, 2), _DRM_REGISTERS, _DRM_READ_ONLY, &dev_priv->mmio); diff --git a/drivers/char/drm/radeon_drm.h b/drivers/char/drm/radeon_drm.h index 8d6350dd536..66c4b6fed04 100644 --- a/drivers/char/drm/radeon_drm.h +++ b/drivers/char/drm/radeon_drm.h @@ -707,6 +707,7 @@ typedef struct drm_radeon_setparam { #define RADEON_SETPARAM_SWITCH_TILING 2 /* enable/disable color tiling */ #define RADEON_SETPARAM_PCIGART_LOCATION 3 /* PCI Gart Location */ #define RADEON_SETPARAM_NEW_MEMMAP 4 /* Use new memory map */ +#define RADEON_SETPARAM_PCIGART_TABLE_SIZE 5 /* PCI GART Table Size */ /* 1.14: Clients can allocate/free a surface */ diff --git a/drivers/char/drm/radeon_drv.h b/drivers/char/drm/radeon_drv.h index 8b105f1460a..54f49ef4bef 100644 --- a/drivers/char/drm/radeon_drv.h +++ b/drivers/char/drm/radeon_drv.h @@ -95,9 +95,11 @@ * 1.24- Add general-purpose packet for manipulating scratch registers (r300) * 1.25- Add support for r200 vertex programs (R200_EMIT_VAP_PVS_CNTL, * new packet type) + * 1.26- Add support for variable size PCI(E) gart aperture + * 1.27- Add support for IGP GART */ #define DRIVER_MAJOR 1 -#define DRIVER_MINOR 25 +#define DRIVER_MINOR 27 #define DRIVER_PATCHLEVEL 0 /* @@ -143,6 +145,7 @@ enum radeon_chip_flags { RADEON_IS_PCIE = 0x00200000UL, RADEON_NEW_MEMMAP = 0x00400000UL, RADEON_IS_PCI = 0x00800000UL, + RADEON_IS_IGPGART = 0x01000000UL, }; #define GET_RING_HEAD(dev_priv) (dev_priv->writeback_works ? \ @@ -240,7 +243,6 @@ typedef struct drm_radeon_private { int do_boxes; int page_flipping; - int current_page; u32 color_fmt; unsigned int front_offset; @@ -280,6 +282,7 @@ typedef struct drm_radeon_private { struct radeon_virt_surface virt_surfaces[2 * RADEON_MAX_SURFACES]; unsigned long pcigart_offset; + unsigned int pcigart_offset_set; drm_ati_pcigart_info gart_info; u32 scratch_ages[5]; @@ -432,6 +435,15 @@ extern int r300_do_cp_cmdbuf(drm_device_t * dev, DRMFILE filp, #define RADEON_PCIE_TX_GART_END_LO 0x16 #define RADEON_PCIE_TX_GART_END_HI 0x17 +#define RADEON_IGPGART_INDEX 0x168 +#define RADEON_IGPGART_DATA 0x16c +#define RADEON_IGPGART_UNK_18 0x18 +#define RADEON_IGPGART_CTRL 0x2b +#define RADEON_IGPGART_BASE_ADDR 0x2c +#define RADEON_IGPGART_FLUSH 0x2e +#define RADEON_IGPGART_ENABLE 0x38 +#define RADEON_IGPGART_UNK_39 0x39 + #define RADEON_MPP_TB_CONFIG 0x01c0 #define RADEON_MEM_CNTL 0x0140 #define RADEON_MEM_SDRAM_MODE_REG 0x0158 @@ -964,6 +976,14 @@ do { \ RADEON_WRITE( RADEON_CLOCK_CNTL_DATA, (val) ); \ } while (0) +#define RADEON_WRITE_IGPGART( addr, val ) \ +do { \ + RADEON_WRITE( RADEON_IGPGART_INDEX, \ + ((addr) & 0x7f) | (1 << 8)); \ + RADEON_WRITE( RADEON_IGPGART_DATA, (val) ); \ + RADEON_WRITE( RADEON_IGPGART_INDEX, 0x7f ); \ +} while (0) + #define RADEON_WRITE_PCIE( addr, val ) \ do { \ RADEON_WRITE8( RADEON_PCIE_INDEX, \ diff --git a/drivers/char/drm/radeon_state.c b/drivers/char/drm/radeon_state.c index 938eccb78cc..98c5f1d3a8e 100644 --- a/drivers/char/drm/radeon_state.c +++ b/drivers/char/drm/radeon_state.c @@ -773,7 +773,7 @@ static void radeon_clear_box(drm_radeon_private_t * dev_priv, RADEON_GMC_SRC_DATATYPE_COLOR | RADEON_ROP3_P | RADEON_GMC_CLR_CMP_CNTL_DIS); - if (dev_priv->page_flipping && dev_priv->current_page == 1) { + if (dev_priv->sarea_priv->pfCurrentPage == 1) { OUT_RING(dev_priv->front_pitch_offset); } else { OUT_RING(dev_priv->back_pitch_offset); @@ -861,7 +861,7 @@ static void radeon_cp_dispatch_clear(drm_device_t * dev, dev_priv->stats.clears++; - if (dev_priv->page_flipping && dev_priv->current_page == 1) { + if (dev_priv->sarea_priv->pfCurrentPage == 1) { unsigned int tmp = flags; flags &= ~(RADEON_FRONT | RADEON_BACK); @@ -1382,7 +1382,7 @@ static void radeon_cp_dispatch_swap(drm_device_t * dev) /* Make this work even if front & back are flipped: */ OUT_RING(CP_PACKET0(RADEON_SRC_PITCH_OFFSET, 1)); - if (dev_priv->current_page == 0) { + if (dev_priv->sarea_priv->pfCurrentPage == 0) { OUT_RING(dev_priv->back_pitch_offset); OUT_RING(dev_priv->front_pitch_offset); } else { @@ -1416,12 +1416,12 @@ static void radeon_cp_dispatch_flip(drm_device_t * dev) { drm_radeon_private_t *dev_priv = dev->dev_private; drm_sarea_t *sarea = (drm_sarea_t *) dev_priv->sarea->handle; - int offset = (dev_priv->current_page == 1) + int offset = (dev_priv->sarea_priv->pfCurrentPage == 1) ? dev_priv->front_offset : dev_priv->back_offset; RING_LOCALS; - DRM_DEBUG("%s: page=%d pfCurrentPage=%d\n", + DRM_DEBUG("%s: pfCurrentPage=%d\n", __FUNCTION__, - dev_priv->current_page, dev_priv->sarea_priv->pfCurrentPage); + dev_priv->sarea_priv->pfCurrentPage); /* Do some trivial performance monitoring... */ @@ -1449,8 +1449,8 @@ static void radeon_cp_dispatch_flip(drm_device_t * dev) * performing the swapbuffer ioctl. */ dev_priv->sarea_priv->last_frame++; - dev_priv->sarea_priv->pfCurrentPage = dev_priv->current_page = - 1 - dev_priv->current_page; + dev_priv->sarea_priv->pfCurrentPage = + 1 - dev_priv->sarea_priv->pfCurrentPage; BEGIN_RING(2); @@ -2152,24 +2152,10 @@ static int radeon_do_init_pageflip(drm_device_t * dev) ADVANCE_RING(); dev_priv->page_flipping = 1; - dev_priv->current_page = 0; - dev_priv->sarea_priv->pfCurrentPage = dev_priv->current_page; - return 0; -} - -/* Called whenever a client dies, from drm_release. - * NOTE: Lock isn't necessarily held when this is called! - */ -static int radeon_do_cleanup_pageflip(drm_device_t * dev) -{ - drm_radeon_private_t *dev_priv = dev->dev_private; - DRM_DEBUG("\n"); - - if (dev_priv->current_page != 0) - radeon_cp_dispatch_flip(dev); + if (dev_priv->sarea_priv->pfCurrentPage != 1) + dev_priv->sarea_priv->pfCurrentPage = 0; - dev_priv->page_flipping = 0; return 0; } @@ -3145,10 +3131,16 @@ static int radeon_cp_setparam(DRM_IOCTL_ARGS) break; case RADEON_SETPARAM_PCIGART_LOCATION: dev_priv->pcigart_offset = sp.value; + dev_priv->pcigart_offset_set = 1; break; case RADEON_SETPARAM_NEW_MEMMAP: dev_priv->new_memmap = sp.value; break; + case RADEON_SETPARAM_PCIGART_TABLE_SIZE: + dev_priv->gart_info.table_size = sp.value; + if (dev_priv->gart_info.table_size < RADEON_PCIGART_TABLE_SIZE) + dev_priv->gart_info.table_size = RADEON_PCIGART_TABLE_SIZE; + break; default: DRM_DEBUG("Invalid parameter %d\n", sp.param); return DRM_ERR(EINVAL); @@ -3168,9 +3160,7 @@ void radeon_driver_preclose(drm_device_t * dev, DRMFILE filp) { if (dev->dev_private) { drm_radeon_private_t *dev_priv = dev->dev_private; - if (dev_priv->page_flipping) { - radeon_do_cleanup_pageflip(dev); - } + dev_priv->page_flipping = 0; radeon_mem_release(filp, dev_priv->gart_heap); radeon_mem_release(filp, dev_priv->fb_heap); radeon_surfaces_release(filp, dev_priv); @@ -3179,6 +3169,14 @@ void radeon_driver_preclose(drm_device_t * dev, DRMFILE filp) void radeon_driver_lastclose(drm_device_t * dev) { + if (dev->dev_private) { + drm_radeon_private_t *dev_priv = dev->dev_private; + + if (dev_priv->sarea_priv && + dev_priv->sarea_priv->pfCurrentPage != 0) + radeon_cp_dispatch_flip(dev); + } + radeon_do_release(dev); } diff --git a/drivers/char/drm/sis_drv.c b/drivers/char/drm/sis_drv.c index 3d5b3218b6f..690e0af8e7c 100644 --- a/drivers/char/drm/sis_drv.c +++ b/drivers/char/drm/sis_drv.c @@ -71,7 +71,7 @@ static struct drm_driver driver = { .context_dtor = NULL, .dma_quiescent = sis_idle, .reclaim_buffers = NULL, - .reclaim_buffers_locked = sis_reclaim_buffers_locked, + .reclaim_buffers_idlelocked = sis_reclaim_buffers_locked, .lastclose = sis_lastclose, .get_map_ofs = drm_core_get_map_ofs, .get_reg_ofs = drm_core_get_reg_ofs, diff --git a/drivers/char/drm/via_dma.c b/drivers/char/drm/via_dma.c index c0539c6299c..13a9c5ca459 100644 --- a/drivers/char/drm/via_dma.c +++ b/drivers/char/drm/via_dma.c @@ -252,7 +252,7 @@ static int via_dma_init(DRM_IOCTL_ARGS) break; case VIA_DMA_INITIALIZED: retcode = (dev_priv->ring.virtual_start != NULL) ? - 0 : DRM_ERR(EFAULT); + 0 : DRM_ERR(EFAULT); break; default: retcode = DRM_ERR(EINVAL); @@ -432,56 +432,34 @@ static int via_hook_segment(drm_via_private_t * dev_priv, { int paused, count; volatile uint32_t *paused_at = dev_priv->last_pause_ptr; + uint32_t reader,ptr; + paused = 0; via_flush_write_combine(); - while (!*(via_get_dma(dev_priv) - 1)) ; - *dev_priv->last_pause_ptr = pause_addr_lo; + (void) *(volatile uint32_t *)(via_get_dma(dev_priv) -1); + *paused_at = pause_addr_lo; via_flush_write_combine(); - - /* - * The below statement is inserted to really force the flush. - * Not sure it is needed. - */ - - while (!*dev_priv->last_pause_ptr) ; + (void) *paused_at; + reader = *(dev_priv->hw_addr_ptr); + ptr = ((volatile char *)paused_at - dev_priv->dma_ptr) + + dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr + 4; dev_priv->last_pause_ptr = via_get_dma(dev_priv) - 1; - while (!*dev_priv->last_pause_ptr) ; - paused = 0; - count = 20; - - while (!(paused = (VIA_READ(0x41c) & 0x80000000)) && count--) ; - if ((count <= 8) && (count >= 0)) { - uint32_t rgtr, ptr; - rgtr = *(dev_priv->hw_addr_ptr); - ptr = ((volatile char *)dev_priv->last_pause_ptr - - dev_priv->dma_ptr) + dev_priv->dma_offset + - (uint32_t) dev_priv->agpAddr + 4 - CMDBUF_ALIGNMENT_SIZE; - if (rgtr <= ptr) { - DRM_ERROR - ("Command regulator\npaused at count %d, address %x, " - "while current pause address is %x.\n" - "Please mail this message to " - "<unichrome-devel@lists.sourceforge.net>\n", count, - rgtr, ptr); - } + if ((ptr - reader) <= dev_priv->dma_diff ) { + count = 10000000; + while (!(paused = (VIA_READ(0x41c) & 0x80000000)) && count--); } if (paused && !no_pci_fire) { - uint32_t rgtr, ptr; - uint32_t ptr_low; + reader = *(dev_priv->hw_addr_ptr); + if ((ptr - reader) == dev_priv->dma_diff) { - count = 1000000; - while ((VIA_READ(VIA_REG_STATUS) & VIA_CMD_RGTR_BUSY) - && count--) ; + /* + * There is a concern that these writes may stall the PCI bus + * if the GPU is not idle. However, idling the GPU first + * doesn't make a difference. + */ - rgtr = *(dev_priv->hw_addr_ptr); - ptr = ((volatile char *)paused_at - dev_priv->dma_ptr) + - dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr + 4; - - ptr_low = (ptr > 3 * CMDBUF_ALIGNMENT_SIZE) ? - ptr - 3 * CMDBUF_ALIGNMENT_SIZE : 0; - if (rgtr <= ptr && rgtr >= ptr_low) { VIA_WRITE(VIA_REG_TRANSET, (HC_ParaType_PreCR << 16)); VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_hi); VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_lo); @@ -494,6 +472,9 @@ static int via_hook_segment(drm_via_private_t * dev_priv, static int via_wait_idle(drm_via_private_t * dev_priv) { int count = 10000000; + + while (!(VIA_READ(VIA_REG_STATUS) & VIA_VR_QUEUE_BUSY) && count--); + while (count-- && (VIA_READ(VIA_REG_STATUS) & (VIA_CMD_RGTR_BUSY | VIA_2D_ENG_BUSY | VIA_3D_ENG_BUSY))) ; @@ -537,6 +518,9 @@ static void via_cmdbuf_start(drm_via_private_t * dev_priv) uint32_t end_addr, end_addr_lo; uint32_t command; uint32_t agp_base; + uint32_t ptr; + uint32_t reader; + int count; dev_priv->dma_low = 0; @@ -554,7 +538,7 @@ static void via_cmdbuf_start(drm_via_private_t * dev_priv) &pause_addr_hi, &pause_addr_lo, 1) - 1; via_flush_write_combine(); - while (!*dev_priv->last_pause_ptr) ; + (void) *(volatile uint32_t *)dev_priv->last_pause_ptr; VIA_WRITE(VIA_REG_TRANSET, (HC_ParaType_PreCR << 16)); VIA_WRITE(VIA_REG_TRANSPACE, command); @@ -566,6 +550,24 @@ static void via_cmdbuf_start(drm_via_private_t * dev_priv) DRM_WRITEMEMORYBARRIER(); VIA_WRITE(VIA_REG_TRANSPACE, command | HC_HAGPCMNT_MASK); VIA_READ(VIA_REG_TRANSPACE); + + dev_priv->dma_diff = 0; + + count = 10000000; + while (!(VIA_READ(0x41c) & 0x80000000) && count--); + + reader = *(dev_priv->hw_addr_ptr); + ptr = ((volatile char *)dev_priv->last_pause_ptr - dev_priv->dma_ptr) + + dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr + 4; + + /* + * This is the difference between where we tell the + * command reader to pause and where it actually pauses. + * This differs between hw implementation so we need to + * detect it. + */ + + dev_priv->dma_diff = ptr - reader; } static void via_pad_cache(drm_via_private_t * dev_priv, int qwords) @@ -592,7 +594,6 @@ static void via_cmdbuf_jump(drm_via_private_t * dev_priv) uint32_t pause_addr_lo, pause_addr_hi; uint32_t jump_addr_lo, jump_addr_hi; volatile uint32_t *last_pause_ptr; - uint32_t dma_low_save1, dma_low_save2; agp_base = dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr; via_align_cmd(dev_priv, HC_HAGPBpID_JUMP, 0, &jump_addr_hi, @@ -619,31 +620,11 @@ static void via_cmdbuf_jump(drm_via_private_t * dev_priv) &pause_addr_lo, 0); *last_pause_ptr = pause_addr_lo; - dma_low_save1 = dev_priv->dma_low; - - /* - * Now, set a trap that will pause the regulator if it tries to rerun the old - * command buffer. (Which may happen if via_hook_segment detecs a command regulator pause - * and reissues the jump command over PCI, while the regulator has already taken the jump - * and actually paused at the current buffer end). - * There appears to be no other way to detect this condition, since the hw_addr_pointer - * does not seem to get updated immediately when a jump occurs. - */ - last_pause_ptr = - via_align_cmd(dev_priv, HC_HAGPBpID_PAUSE, 0, &pause_addr_hi, - &pause_addr_lo, 0) - 1; - via_align_cmd(dev_priv, HC_HAGPBpID_PAUSE, 0, &pause_addr_hi, - &pause_addr_lo, 0); - *last_pause_ptr = pause_addr_lo; - - dma_low_save2 = dev_priv->dma_low; - dev_priv->dma_low = dma_low_save1; - via_hook_segment(dev_priv, jump_addr_hi, jump_addr_lo, 0); - dev_priv->dma_low = dma_low_save2; - via_hook_segment(dev_priv, pause_addr_hi, pause_addr_lo, 0); + via_hook_segment( dev_priv, jump_addr_hi, jump_addr_lo, 0); } + static void via_cmdbuf_rewind(drm_via_private_t * dev_priv) { via_cmdbuf_jump(dev_priv); diff --git a/drivers/char/drm/via_drv.c b/drivers/char/drm/via_drv.c index bb9dde8b191..2d4957ab256 100644 --- a/drivers/char/drm/via_drv.c +++ b/drivers/char/drm/via_drv.c @@ -52,7 +52,8 @@ static struct drm_driver driver = { .dma_quiescent = via_driver_dma_quiescent, .dri_library_name = dri_library_name, .reclaim_buffers = drm_core_reclaim_buffers, - .reclaim_buffers_locked = via_reclaim_buffers_locked, + .reclaim_buffers_locked = NULL, + .reclaim_buffers_idlelocked = via_reclaim_buffers_locked, .lastclose = via_lastclose, .get_map_ofs = drm_core_get_map_ofs, .get_reg_ofs = drm_core_get_reg_ofs, diff --git a/drivers/char/drm/via_drv.h b/drivers/char/drm/via_drv.h index 8b8778d4a42..b46ca8e6306 100644 --- a/drivers/char/drm/via_drv.h +++ b/drivers/char/drm/via_drv.h @@ -29,11 +29,11 @@ #define DRIVER_NAME "via" #define DRIVER_DESC "VIA Unichrome / Pro" -#define DRIVER_DATE "20061227" +#define DRIVER_DATE "20070202" #define DRIVER_MAJOR 2 #define DRIVER_MINOR 11 -#define DRIVER_PATCHLEVEL 0 +#define DRIVER_PATCHLEVEL 1 #include "via_verifier.h" @@ -93,6 +93,7 @@ typedef struct drm_via_private { unsigned long vram_offset; unsigned long agp_offset; drm_via_blitq_t blit_queues[VIA_NUM_BLIT_ENGINES]; + uint32_t dma_diff; } drm_via_private_t; enum via_family { diff --git a/drivers/char/drm/via_mm.h b/drivers/char/drm/via_mm.h deleted file mode 100644 index d57efda57c7..00000000000 --- a/drivers/char/drm/via_mm.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved. - * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sub license, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL - * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ -#ifndef _via_drm_mm_h_ -#define _via_drm_mm_h_ - -typedef struct { - unsigned int context; - unsigned int size; - unsigned long offset; - unsigned long free; -} drm_via_mm_t; - -typedef struct { - unsigned int size; - unsigned long handle; - void *virtual; -} drm_via_dma_t; - -#endif diff --git a/drivers/char/ds1620.c b/drivers/char/ds1620.c index 3d7efc26aad..334ad5bbe6b 100644 --- a/drivers/char/ds1620.c +++ b/drivers/char/ds1620.c @@ -4,7 +4,6 @@ */ #include <linux/module.h> #include <linux/miscdevice.h> -#include <linux/smp_lock.h> #include <linux/delay.h> #include <linux/proc_fs.h> #include <linux/capability.h> diff --git a/drivers/char/dsp56k.c b/drivers/char/dsp56k.c index db984e481d4..9b8278e1f4f 100644 --- a/drivers/char/dsp56k.c +++ b/drivers/char/dsp56k.c @@ -32,7 +32,6 @@ #include <linux/fs.h> #include <linux/mm.h> #include <linux/init.h> -#include <linux/smp_lock.h> #include <linux/device.h> #include <asm/atarihw.h> diff --git a/drivers/char/dtlk.c b/drivers/char/dtlk.c index d8dbdb91623..abde6ddefe6 100644 --- a/drivers/char/dtlk.c +++ b/drivers/char/dtlk.c @@ -62,7 +62,6 @@ #include <linux/init.h> /* for __init, module_{init,exit} */ #include <linux/poll.h> /* for POLLIN, etc. */ #include <linux/dtlk.h> /* local header file for DoubleTalk values */ -#include <linux/smp_lock.h> #ifdef TRACING #define TRACE_TEXT(str) printk(str); @@ -325,16 +324,22 @@ static int dtlk_release(struct inode *inode, struct file *file) static int __init dtlk_init(void) { + int err; + dtlk_port_lpc = 0; dtlk_port_tts = 0; dtlk_busy = 0; dtlk_major = register_chrdev(0, "dtlk", &dtlk_fops); - if (dtlk_major == 0) { + if (dtlk_major < 0) { printk(KERN_ERR "DoubleTalk PC - cannot register device\n"); - return 0; + return dtlk_major; + } + err = dtlk_dev_probe(); + if (err) { + unregister_chrdev(dtlk_major, "dtlk"); + return err; } - if (dtlk_dev_probe() == 0) - printk(", MAJOR %d\n", dtlk_major); + printk(", MAJOR %d\n", dtlk_major); init_waitqueue_head(&dtlk_process_list); diff --git a/drivers/char/ec3104_keyb.c b/drivers/char/ec3104_keyb.c index 77f58ed6d59..020011495d9 100644 --- a/drivers/char/ec3104_keyb.c +++ b/drivers/char/ec3104_keyb.c @@ -41,7 +41,6 @@ #include <linux/miscdevice.h> #include <linux/slab.h> #include <linux/kbd_kern.h> -#include <linux/smp_lock.h> #include <linux/bitops.h> #include <asm/keyboard.h> diff --git a/drivers/char/epca.c b/drivers/char/epca.c index de5be30484a..c6c56fb8ba5 100644 --- a/drivers/char/epca.c +++ b/drivers/char/epca.c @@ -949,7 +949,7 @@ static int block_til_ready(struct tty_struct *tty, } /* End forever while */ - current->state = TASK_RUNNING; + __set_current_state(TASK_RUNNING); remove_wait_queue(&ch->open_wait, &wait); if (!tty_hung_up_p(filp)) ch->count++; diff --git a/drivers/char/genrtc.c b/drivers/char/genrtc.c index 23b25ada65e..9e1fc02967f 100644 --- a/drivers/char/genrtc.c +++ b/drivers/char/genrtc.c @@ -12,7 +12,7 @@ * * This driver allows use of the real time clock (built into * nearly all computers) from user space. It exports the /dev/rtc - * interface supporting various ioctl() and also the /proc/dev/rtc + * interface supporting various ioctl() and also the /proc/driver/rtc * pseudo-file for status information. * * The ioctls can be used to set the interrupt behaviour where @@ -207,7 +207,7 @@ static ssize_t gen_rtc_read(struct file *file, char __user *buf, sizeof(unsigned long); } out: - current->state = TASK_RUNNING; + __set_current_state(TASK_RUNNING); remove_wait_queue(&gen_rtc_wait, &wait); return retval; @@ -377,7 +377,7 @@ static int gen_rtc_release(struct inode *inode, struct file *file) #ifdef CONFIG_PROC_FS /* - * Info exported via "/proc/rtc". + * Info exported via "/proc/driver/rtc". */ static int gen_rtc_proc_output(char *buf) diff --git a/drivers/char/hangcheck-timer.c b/drivers/char/hangcheck-timer.c index ae76a9ffe89..f0e7263dfcd 100644 --- a/drivers/char/hangcheck-timer.c +++ b/drivers/char/hangcheck-timer.c @@ -44,7 +44,6 @@ #include <linux/fs.h> #include <linux/mm.h> #include <linux/reboot.h> -#include <linux/smp_lock.h> #include <linux/init.h> #include <linux/delay.h> #include <asm/uaccess.h> diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c index 0f9ed7b46a6..322bc5f7d86 100644 --- a/drivers/char/hvc_console.c +++ b/drivers/char/hvc_console.c @@ -111,7 +111,7 @@ static int last_hvc = -1; * lock held. If successful, this function increments the kobject reference * count against the target hvc_struct so it should be released when finished. */ -struct hvc_struct *hvc_get_by_index(int index) +static struct hvc_struct *hvc_get_by_index(int index) { struct hvc_struct *hp; unsigned long flags; @@ -150,7 +150,8 @@ static uint32_t vtermnos[MAX_NR_HVC_CONSOLES] = * hvc_console_setup() finds adapters. */ -void hvc_console_print(struct console *co, const char *b, unsigned count) +static void hvc_console_print(struct console *co, const char *b, + unsigned count) { char c[N_OUTBUF] __ALIGNED__; unsigned i = 0, n = 0; @@ -208,7 +209,7 @@ static int __init hvc_console_setup(struct console *co, char *options) return 0; } -struct console hvc_con_driver = { +static struct console hvc_con_driver = { .name = "hvc", .write = hvc_console_print, .device = hvc_console_device, @@ -278,7 +279,6 @@ int hvc_instantiate(uint32_t vtermno, int index, struct hv_ops *ops) return 0; } -EXPORT_SYMBOL(hvc_instantiate); /* Wake the sleeping khvcd */ static void hvc_kick(void) @@ -792,7 +792,6 @@ struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int irq, return hp; } -EXPORT_SYMBOL(hvc_alloc); int __devexit hvc_remove(struct hvc_struct *hp) { @@ -828,11 +827,10 @@ int __devexit hvc_remove(struct hvc_struct *hp) tty_hangup(tty); return 0; } -EXPORT_SYMBOL(hvc_remove); /* Driver initialization. Follow console initialization. This is where the TTY * interfaces start to become available. */ -int __init hvc_init(void) +static int __init hvc_init(void) { struct tty_driver *drv; diff --git a/drivers/char/hvc_iseries.c b/drivers/char/hvc_iseries.c index ec420fe8a90..b37f1d5a5be 100644 --- a/drivers/char/hvc_iseries.c +++ b/drivers/char/hvc_iseries.c @@ -579,7 +579,7 @@ static int hvc_find_vtys(void) if (!vtermno) continue; - if (!device_is_compatible(vty, "IBM,iSeries-vty")) + if (!of_device_is_compatible(vty, "IBM,iSeries-vty")) continue; if (num_found == 0) diff --git a/drivers/char/hvc_vio.c b/drivers/char/hvc_vio.c index 94a542e20ef..79711aa4b41 100644 --- a/drivers/char/hvc_vio.c +++ b/drivers/char/hvc_vio.c @@ -157,7 +157,7 @@ static int hvc_find_vtys(void) if (!vtermno) continue; - if (device_is_compatible(vty, "hvterm1")) { + if (of_device_is_compatible(vty, "hvterm1")) { hvc_instantiate(*vtermno, num_found, &hvc_get_put_ops); ++num_found; } diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig index 5f3acd8e64b..7cda04b3353 100644 --- a/drivers/char/hw_random/Kconfig +++ b/drivers/char/hw_random/Kconfig @@ -91,3 +91,17 @@ config HW_RANDOM_OMAP module will be called omap-rng. If unsure, say Y. + +config HW_RANDOM_PASEMI + tristate "PA Semi HW Random Number Generator support" + depends on HW_RANDOM && PPC_PASEMI + default HW_RANDOM + ---help--- + This driver provides kernel-side support for the Random Number + Generator hardware found on PA6T-1682M processor. + + To compile this driver as a module, choose M here: the + module will be called pasemi-rng. + + If unsure, say Y. + diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile index c41fa19454e..c8b7300e2fb 100644 --- a/drivers/char/hw_random/Makefile +++ b/drivers/char/hw_random/Makefile @@ -10,3 +10,4 @@ obj-$(CONFIG_HW_RANDOM_GEODE) += geode-rng.o obj-$(CONFIG_HW_RANDOM_VIA) += via-rng.o obj-$(CONFIG_HW_RANDOM_IXP4XX) += ixp4xx-rng.o obj-$(CONFIG_HW_RANDOM_OMAP) += omap-rng.o +obj-$(CONFIG_HW_RANDOM_PASEMI) += pasemi-rng.o diff --git a/drivers/char/hw_random/intel-rng.c b/drivers/char/hw_random/intel-rng.c index cc1046e6ee0..4ae9811d1a6 100644 --- a/drivers/char/hw_random/intel-rng.c +++ b/drivers/char/hw_random/intel-rng.c @@ -24,10 +24,11 @@ * warranty of any kind, whether express or implied. */ -#include <linux/module.h> +#include <linux/hw_random.h> #include <linux/kernel.h> +#include <linux/module.h> #include <linux/pci.h> -#include <linux/hw_random.h> +#include <linux/stop_machine.h> #include <asm/io.h> @@ -217,30 +218,117 @@ static struct hwrng intel_rng = { .data_read = intel_rng_data_read, }; +struct intel_rng_hw { + struct pci_dev *dev; + void __iomem *mem; + u8 bios_cntl_off; + u8 bios_cntl_val; + u8 fwh_dec_en1_off; + u8 fwh_dec_en1_val; +}; -#ifdef CONFIG_SMP -static char __initdata waitflag; +static int __init intel_rng_hw_init(void *_intel_rng_hw) +{ + struct intel_rng_hw *intel_rng_hw = _intel_rng_hw; + u8 mfc, dvc; + + /* interrupts disabled in stop_machine_run call */ + + if (!(intel_rng_hw->fwh_dec_en1_val & FWH_F8_EN_MASK)) + pci_write_config_byte(intel_rng_hw->dev, + intel_rng_hw->fwh_dec_en1_off, + intel_rng_hw->fwh_dec_en1_val | + FWH_F8_EN_MASK); + if (!(intel_rng_hw->bios_cntl_val & BIOS_CNTL_WRITE_ENABLE_MASK)) + pci_write_config_byte(intel_rng_hw->dev, + intel_rng_hw->bios_cntl_off, + intel_rng_hw->bios_cntl_val | + BIOS_CNTL_WRITE_ENABLE_MASK); + + writeb(INTEL_FWH_RESET_CMD, intel_rng_hw->mem); + writeb(INTEL_FWH_READ_ID_CMD, intel_rng_hw->mem); + mfc = readb(intel_rng_hw->mem + INTEL_FWH_MANUFACTURER_CODE_ADDRESS); + dvc = readb(intel_rng_hw->mem + INTEL_FWH_DEVICE_CODE_ADDRESS); + writeb(INTEL_FWH_RESET_CMD, intel_rng_hw->mem); + + if (!(intel_rng_hw->bios_cntl_val & + (BIOS_CNTL_LOCK_ENABLE_MASK|BIOS_CNTL_WRITE_ENABLE_MASK))) + pci_write_config_byte(intel_rng_hw->dev, + intel_rng_hw->bios_cntl_off, + intel_rng_hw->bios_cntl_val); + if (!(intel_rng_hw->fwh_dec_en1_val & FWH_F8_EN_MASK)) + pci_write_config_byte(intel_rng_hw->dev, + intel_rng_hw->fwh_dec_en1_off, + intel_rng_hw->fwh_dec_en1_val); -static void __init intel_init_wait(void *unused) + if (mfc != INTEL_FWH_MANUFACTURER_CODE || + (dvc != INTEL_FWH_DEVICE_CODE_8M && + dvc != INTEL_FWH_DEVICE_CODE_4M)) { + printk(KERN_ERR PFX "FWH not detected\n"); + return -ENODEV; + } + + return 0; +} + +static int __init intel_init_hw_struct(struct intel_rng_hw *intel_rng_hw, + struct pci_dev *dev) { - while (waitflag) - cpu_relax(); + intel_rng_hw->bios_cntl_val = 0xff; + intel_rng_hw->fwh_dec_en1_val = 0xff; + intel_rng_hw->dev = dev; + + /* Check for Intel 82802 */ + if (dev->device < 0x2640) { + intel_rng_hw->fwh_dec_en1_off = FWH_DEC_EN1_REG_OLD; + intel_rng_hw->bios_cntl_off = BIOS_CNTL_REG_OLD; + } else { + intel_rng_hw->fwh_dec_en1_off = FWH_DEC_EN1_REG_NEW; + intel_rng_hw->bios_cntl_off = BIOS_CNTL_REG_NEW; + } + + pci_read_config_byte(dev, intel_rng_hw->fwh_dec_en1_off, + &intel_rng_hw->fwh_dec_en1_val); + pci_read_config_byte(dev, intel_rng_hw->bios_cntl_off, + &intel_rng_hw->bios_cntl_val); + + if ((intel_rng_hw->bios_cntl_val & + (BIOS_CNTL_LOCK_ENABLE_MASK|BIOS_CNTL_WRITE_ENABLE_MASK)) + == BIOS_CNTL_LOCK_ENABLE_MASK) { + static __initdata /*const*/ char warning[] = + KERN_WARNING PFX "Firmware space is locked read-only. " + KERN_WARNING PFX "If you can't or\n don't want to " + KERN_WARNING PFX "disable this in firmware setup, and " + KERN_WARNING PFX "if\n you are certain that your " + KERN_WARNING PFX "system has a functional\n RNG, try" + KERN_WARNING PFX "using the 'no_fwh_detect' option.\n"; + + if (no_fwh_detect) + return -ENODEV; + printk(warning); + return -EBUSY; + } + + intel_rng_hw->mem = ioremap_nocache(INTEL_FWH_ADDR, INTEL_FWH_ADDR_LEN); + if (intel_rng_hw->mem == NULL) + return -EBUSY; + + return 0; } -#endif + static int __init mod_init(void) { int err = -ENODEV; - unsigned i; + int i; struct pci_dev *dev = NULL; - void __iomem *mem; - unsigned long flags; - u8 bios_cntl_off, fwh_dec_en1_off; - u8 bios_cntl_val = 0xff, fwh_dec_en1_val = 0xff; - u8 hw_status, mfc, dvc; + void __iomem *mem = mem; + u8 hw_status; + struct intel_rng_hw *intel_rng_hw; for (i = 0; !dev && pci_tbl[i].vendor; ++i) - dev = pci_get_device(pci_tbl[i].vendor, pci_tbl[i].device, NULL); + dev = pci_get_device(pci_tbl[i].vendor, pci_tbl[i].device, + NULL); if (!dev) goto out; /* Device not found. */ @@ -250,39 +338,18 @@ static int __init mod_init(void) goto fwh_done; } - /* Check for Intel 82802 */ - if (dev->device < 0x2640) { - fwh_dec_en1_off = FWH_DEC_EN1_REG_OLD; - bios_cntl_off = BIOS_CNTL_REG_OLD; - } else { - fwh_dec_en1_off = FWH_DEC_EN1_REG_NEW; - bios_cntl_off = BIOS_CNTL_REG_NEW; - } - - pci_read_config_byte(dev, fwh_dec_en1_off, &fwh_dec_en1_val); - pci_read_config_byte(dev, bios_cntl_off, &bios_cntl_val); - - if ((bios_cntl_val & - (BIOS_CNTL_LOCK_ENABLE_MASK|BIOS_CNTL_WRITE_ENABLE_MASK)) - == BIOS_CNTL_LOCK_ENABLE_MASK) { - static __initdata /*const*/ char warning[] = - KERN_WARNING PFX "Firmware space is locked read-only. If you can't or\n" - KERN_WARNING PFX "don't want to disable this in firmware setup, and if\n" - KERN_WARNING PFX "you are certain that your system has a functional\n" - KERN_WARNING PFX "RNG, try using the 'no_fwh_detect' option.\n"; - + intel_rng_hw = kmalloc(sizeof(*intel_rng_hw), GFP_KERNEL); + if (!intel_rng_hw) { pci_dev_put(dev); - if (no_fwh_detect) - goto fwh_done; - printk(warning); - err = -EBUSY; goto out; } - mem = ioremap_nocache(INTEL_FWH_ADDR, INTEL_FWH_ADDR_LEN); - if (mem == NULL) { + err = intel_init_hw_struct(intel_rng_hw, dev); + if (err) { pci_dev_put(dev); - err = -EBUSY; + kfree(intel_rng_hw); + if (err == -ENODEV) + goto fwh_done; goto out; } @@ -290,59 +357,18 @@ static int __init mod_init(void) * Since the BIOS code/data is going to disappear from its normal * location with the Read ID command, all activity on the system * must be stopped until the state is back to normal. + * + * Use stop_machine_run because IPIs can be blocked by disabling + * interrupts. */ -#ifdef CONFIG_SMP - set_mb(waitflag, 1); - if (smp_call_function(intel_init_wait, NULL, 1, 0) != 0) { - set_mb(waitflag, 0); - pci_dev_put(dev); - printk(KERN_ERR PFX "cannot run on all processors\n"); - err = -EAGAIN; - goto err_unmap; - } -#endif - local_irq_save(flags); - - if (!(fwh_dec_en1_val & FWH_F8_EN_MASK)) - pci_write_config_byte(dev, - fwh_dec_en1_off, - fwh_dec_en1_val | FWH_F8_EN_MASK); - if (!(bios_cntl_val & BIOS_CNTL_WRITE_ENABLE_MASK)) - pci_write_config_byte(dev, - bios_cntl_off, - bios_cntl_val | BIOS_CNTL_WRITE_ENABLE_MASK); - - writeb(INTEL_FWH_RESET_CMD, mem); - writeb(INTEL_FWH_READ_ID_CMD, mem); - mfc = readb(mem + INTEL_FWH_MANUFACTURER_CODE_ADDRESS); - dvc = readb(mem + INTEL_FWH_DEVICE_CODE_ADDRESS); - writeb(INTEL_FWH_RESET_CMD, mem); - - if (!(bios_cntl_val & - (BIOS_CNTL_LOCK_ENABLE_MASK|BIOS_CNTL_WRITE_ENABLE_MASK))) - pci_write_config_byte(dev, bios_cntl_off, bios_cntl_val); - if (!(fwh_dec_en1_val & FWH_F8_EN_MASK)) - pci_write_config_byte(dev, fwh_dec_en1_off, fwh_dec_en1_val); - - local_irq_restore(flags); -#ifdef CONFIG_SMP - /* Tell other CPUs to resume. */ - set_mb(waitflag, 0); -#endif - - iounmap(mem); + err = stop_machine_run(intel_rng_hw_init, intel_rng_hw, NR_CPUS); pci_dev_put(dev); - - if (mfc != INTEL_FWH_MANUFACTURER_CODE || - (dvc != INTEL_FWH_DEVICE_CODE_8M && - dvc != INTEL_FWH_DEVICE_CODE_4M)) { - printk(KERN_ERR PFX "FWH not detected\n"); - err = -ENODEV; + iounmap(intel_rng_hw->mem); + kfree(intel_rng_hw); + if (err) goto out; - } fwh_done: - err = -ENOMEM; mem = ioremap(INTEL_RNG_ADDR, INTEL_RNG_ADDR_LEN); if (!mem) @@ -352,22 +378,21 @@ fwh_done: /* Check for Random Number Generator */ err = -ENODEV; hw_status = hwstatus_get(mem); - if ((hw_status & INTEL_RNG_PRESENT) == 0) - goto err_unmap; + if ((hw_status & INTEL_RNG_PRESENT) == 0) { + iounmap(mem); + goto out; + } printk(KERN_INFO "Intel 82802 RNG detected\n"); err = hwrng_register(&intel_rng); if (err) { printk(KERN_ERR PFX "RNG registering failed (%d)\n", err); - goto err_unmap; + iounmap(mem); } out: return err; -err_unmap: - iounmap(mem); - goto out; } static void __exit mod_exit(void) diff --git a/drivers/char/hw_random/pasemi-rng.c b/drivers/char/hw_random/pasemi-rng.c new file mode 100644 index 00000000000..fa6040b6c8f --- /dev/null +++ b/drivers/char/hw_random/pasemi-rng.c @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2006-2007 PA Semi, Inc + * + * Maintained by: Olof Johansson <olof@lixom.net> + * + * Driver for the PWRficient onchip rng + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/platform_device.h> +#include <linux/hw_random.h> +#include <asm/of_platform.h> +#include <asm/io.h> + +#define SDCRNG_CTL_REG 0x00 +#define SDCRNG_CTL_FVLD_M 0x0000f000 +#define SDCRNG_CTL_FVLD_S 12 +#define SDCRNG_CTL_KSZ 0x00000800 +#define SDCRNG_CTL_RSRC_CRG 0x00000010 +#define SDCRNG_CTL_RSRC_RRG 0x00000000 +#define SDCRNG_CTL_CE 0x00000004 +#define SDCRNG_CTL_RE 0x00000002 +#define SDCRNG_CTL_DR 0x00000001 +#define SDCRNG_CTL_SELECT_RRG_RNG (SDCRNG_CTL_RE | SDCRNG_CTL_RSRC_RRG) +#define SDCRNG_CTL_SELECT_CRG_RNG (SDCRNG_CTL_CE | SDCRNG_CTL_RSRC_CRG) +#define SDCRNG_VAL_REG 0x20 + +#define MODULE_NAME "pasemi_rng" + +static int pasemi_rng_data_present(struct hwrng *rng) +{ + void __iomem *rng_regs = (void __iomem *)rng->priv; + + return (in_le32(rng_regs + SDCRNG_CTL_REG) + & SDCRNG_CTL_FVLD_M) ? 1 : 0; +} + +static int pasemi_rng_data_read(struct hwrng *rng, u32 *data) +{ + void __iomem *rng_regs = (void __iomem *)rng->priv; + *data = in_le32(rng_regs + SDCRNG_VAL_REG); + return 4; +} + +static int pasemi_rng_init(struct hwrng *rng) +{ + void __iomem *rng_regs = (void __iomem *)rng->priv; + u32 ctl; + + ctl = SDCRNG_CTL_DR | SDCRNG_CTL_SELECT_RRG_RNG | SDCRNG_CTL_KSZ; + out_le32(rng_regs + SDCRNG_CTL_REG, ctl); + out_le32(rng_regs + SDCRNG_CTL_REG, ctl & ~SDCRNG_CTL_DR); + + return 0; +} + +static void pasemi_rng_cleanup(struct hwrng *rng) +{ + void __iomem *rng_regs = (void __iomem *)rng->priv; + u32 ctl; + + ctl = SDCRNG_CTL_RE | SDCRNG_CTL_CE; + out_le32(rng_regs + SDCRNG_CTL_REG, + in_le32(rng_regs + SDCRNG_CTL_REG) & ~ctl); +} + +static struct hwrng pasemi_rng = { + .name = MODULE_NAME, + .init = pasemi_rng_init, + .cleanup = pasemi_rng_cleanup, + .data_present = pasemi_rng_data_present, + .data_read = pasemi_rng_data_read, +}; + +static int __devinit rng_probe(struct of_device *ofdev, + const struct of_device_id *match) +{ + void __iomem *rng_regs; + struct device_node *rng_np = ofdev->node; + struct resource res; + int err = 0; + + err = of_address_to_resource(rng_np, 0, &res); + if (err) + return -ENODEV; + + rng_regs = ioremap(res.start, 0x100); + + if (!rng_regs) + return -ENOMEM; + + pasemi_rng.priv = (unsigned long)rng_regs; + + printk(KERN_INFO "Registering PA Semi RNG\n"); + + err = hwrng_register(&pasemi_rng); + + if (err) + iounmap(rng_regs); + + return err; +} + +static int __devexit rng_remove(struct of_device *dev) +{ + void __iomem *rng_regs = (void __iomem *)pasemi_rng.priv; + + hwrng_unregister(&pasemi_rng); + iounmap(rng_regs); + + return 0; +} + +static struct of_device_id rng_match[] = { + { + .compatible = "1682m-rng", + }, + {}, +}; + +static struct of_platform_driver rng_driver = { + .name = "pasemi-rng", + .match_table = rng_match, + .probe = rng_probe, + .remove = rng_remove, +}; + +static int __init rng_init(void) +{ + return of_register_platform_driver(&rng_driver); +} +module_init(rng_init); + +static void __exit rng_exit(void) +{ + of_unregister_platform_driver(&rng_driver); +} +module_exit(rng_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Egor Martovetsky <egor@pasemi.com>"); +MODULE_DESCRIPTION("H/W RNG driver for PA Semi processor"); diff --git a/drivers/char/hw_random/via-rng.c b/drivers/char/hw_random/via-rng.c index 9ebf84d1865..ec435cb25c4 100644 --- a/drivers/char/hw_random/via-rng.c +++ b/drivers/char/hw_random/via-rng.c @@ -26,7 +26,6 @@ #include <linux/module.h> #include <linux/kernel.h> -#include <linux/pci.h> #include <linux/hw_random.h> #include <asm/io.h> #include <asm/msr.h> diff --git a/drivers/char/i8k.c b/drivers/char/i8k.c index 353d9f3cf8d..0289705967d 100644 --- a/drivers/char/i8k.c +++ b/drivers/char/i8k.c @@ -22,6 +22,7 @@ #include <linux/proc_fs.h> #include <linux/seq_file.h> #include <linux/dmi.h> +#include <linux/capability.h> #include <asm/uaccess.h> #include <asm/io.h> diff --git a/drivers/char/ip27-rtc.c b/drivers/char/ip27-rtc.c index a48da02aad2..932264a657d 100644 --- a/drivers/char/ip27-rtc.c +++ b/drivers/char/ip27-rtc.c @@ -35,7 +35,6 @@ #include <linux/init.h> #include <linux/poll.h> #include <linux/proc_fs.h> -#include <linux/smp_lock.h> #include <asm/m48t35.h> #include <asm/sn/ioc3.h> diff --git a/drivers/char/ipmi/Kconfig b/drivers/char/ipmi/Kconfig index a6dcb291815..b894f67fdf1 100644 --- a/drivers/char/ipmi/Kconfig +++ b/drivers/char/ipmi/Kconfig @@ -3,6 +3,8 @@ # menu "IPMI" + depends on HAS_IOMEM + config IPMI_HANDLER tristate 'IPMI top-level message handler' help diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index e22146546ad..6c5d15de331 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -9,6 +9,7 @@ * source@mvista.com * * Copyright 2002 MontaVista Software Inc. + * Copyright 2006 IBM Corp., Christian Krafft <krafft@de.ibm.com> * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -64,6 +65,11 @@ #include <linux/string.h> #include <linux/ctype.h> +#ifdef CONFIG_PPC_OF +#include <asm/of_device.h> +#include <asm/of_platform.h> +#endif + #define PFX "ipmi_si: " /* Measure times between events in the driver. */ @@ -76,6 +82,12 @@ #define SI_SHORT_TIMEOUT_USEC 250 /* .25ms when the SM request a short timeout */ +/* Bit for BMC global enables. */ +#define IPMI_BMC_RCV_MSG_INTR 0x01 +#define IPMI_BMC_EVT_MSG_INTR 0x02 +#define IPMI_BMC_EVT_MSG_BUFF 0x04 +#define IPMI_BMC_SYS_LOG 0x08 + enum si_intf_state { SI_NORMAL, SI_GETTING_FLAGS, @@ -84,7 +96,9 @@ enum si_intf_state { SI_CLEARING_FLAGS_THEN_SET_IRQ, SI_GETTING_MESSAGES, SI_ENABLE_INTERRUPTS1, - SI_ENABLE_INTERRUPTS2 + SI_ENABLE_INTERRUPTS2, + SI_DISABLE_INTERRUPTS1, + SI_DISABLE_INTERRUPTS2 /* FIXME - add watchdog stuff. */ }; @@ -333,6 +347,17 @@ static void start_enable_irq(struct smi_info *smi_info) smi_info->si_state = SI_ENABLE_INTERRUPTS1; } +static void start_disable_irq(struct smi_info *smi_info) +{ + unsigned char msg[2]; + + msg[0] = (IPMI_NETFN_APP_REQUEST << 2); + msg[1] = IPMI_GET_BMC_GLOBAL_ENABLES_CMD; + + smi_info->handlers->start_transaction(smi_info->si_sm, msg, 2); + smi_info->si_state = SI_DISABLE_INTERRUPTS1; +} + static void start_clear_flags(struct smi_info *smi_info) { unsigned char msg[3]; @@ -353,7 +378,7 @@ static void start_clear_flags(struct smi_info *smi_info) static inline void disable_si_irq(struct smi_info *smi_info) { if ((smi_info->irq) && (!smi_info->interrupt_disabled)) { - disable_irq_nosync(smi_info->irq); + start_disable_irq(smi_info); smi_info->interrupt_disabled = 1; } } @@ -361,7 +386,7 @@ static inline void disable_si_irq(struct smi_info *smi_info) static inline void enable_si_irq(struct smi_info *smi_info) { if ((smi_info->irq) && (smi_info->interrupt_disabled)) { - enable_irq(smi_info->irq); + start_enable_irq(smi_info); smi_info->interrupt_disabled = 0; } } @@ -583,7 +608,9 @@ static void handle_transaction_done(struct smi_info *smi_info) } else { msg[0] = (IPMI_NETFN_APP_REQUEST << 2); msg[1] = IPMI_SET_BMC_GLOBAL_ENABLES_CMD; - msg[2] = msg[3] | 1; /* enable msg queue int */ + msg[2] = (msg[3] | + IPMI_BMC_RCV_MSG_INTR | + IPMI_BMC_EVT_MSG_INTR); smi_info->handlers->start_transaction( smi_info->si_sm, msg, 3); smi_info->si_state = SI_ENABLE_INTERRUPTS2; @@ -605,6 +632,45 @@ static void handle_transaction_done(struct smi_info *smi_info) smi_info->si_state = SI_NORMAL; break; } + + case SI_DISABLE_INTERRUPTS1: + { + unsigned char msg[4]; + + /* We got the flags from the SMI, now handle them. */ + smi_info->handlers->get_result(smi_info->si_sm, msg, 4); + if (msg[2] != 0) { + printk(KERN_WARNING + "ipmi_si: Could not disable interrupts" + ", failed get.\n"); + smi_info->si_state = SI_NORMAL; + } else { + msg[0] = (IPMI_NETFN_APP_REQUEST << 2); + msg[1] = IPMI_SET_BMC_GLOBAL_ENABLES_CMD; + msg[2] = (msg[3] & + ~(IPMI_BMC_RCV_MSG_INTR | + IPMI_BMC_EVT_MSG_INTR)); + smi_info->handlers->start_transaction( + smi_info->si_sm, msg, 3); + smi_info->si_state = SI_DISABLE_INTERRUPTS2; + } + break; + } + + case SI_DISABLE_INTERRUPTS2: + { + unsigned char msg[4]; + + /* We got the flags from the SMI, now handle them. */ + smi_info->handlers->get_result(smi_info->si_sm, msg, 4); + if (msg[2] != 0) { + printk(KERN_WARNING + "ipmi_si: Could not disable interrupts" + ", failed set.\n"); + } + smi_info->si_state = SI_NORMAL; + break; + } } } @@ -858,9 +924,6 @@ static void smi_timeout(unsigned long data) struct timeval t; #endif - if (atomic_read(&smi_info->stop_operation)) - return; - spin_lock_irqsave(&(smi_info->si_lock), flags); #ifdef DEBUG_TIMING do_gettimeofday(&t); @@ -916,15 +979,11 @@ static irqreturn_t si_irq_handler(int irq, void *data) smi_info->interrupts++; spin_unlock(&smi_info->count_lock); - if (atomic_read(&smi_info->stop_operation)) - goto out; - #ifdef DEBUG_TIMING do_gettimeofday(&t); printk("**Interrupt: %d.%9.9d\n", t.tv_sec, t.tv_usec); #endif smi_event_handler(smi_info, 0); - out: spin_unlock_irqrestore(&(smi_info->si_lock), flags); return IRQ_HANDLED; } @@ -1006,6 +1065,7 @@ static DEFINE_MUTEX(smi_infos_lock); static int smi_num; /* Used to sequence the SMIs */ #define DEFAULT_REGSPACING 1 +#define DEFAULT_REGSIZE 1 static int si_trydefaults = 1; static char *si_type[SI_MAX_PARMS]; @@ -1111,7 +1171,7 @@ static int std_irq_setup(struct smi_info *info) if (info->si_type == SI_BT) { rv = request_irq(info->irq, si_bt_irq_handler, - IRQF_DISABLED, + IRQF_SHARED | IRQF_DISABLED, DEVICE_NAME, info); if (!rv) @@ -1121,7 +1181,7 @@ static int std_irq_setup(struct smi_info *info) } else rv = request_irq(info->irq, si_irq_handler, - IRQF_DISABLED, + IRQF_SHARED | IRQF_DISABLED, DEVICE_NAME, info); if (rv) { @@ -1701,15 +1761,11 @@ static u32 ipmi_acpi_gpe(void *context) smi_info->interrupts++; spin_unlock(&smi_info->count_lock); - if (atomic_read(&smi_info->stop_operation)) - goto out; - #ifdef DEBUG_TIMING do_gettimeofday(&t); printk("**ACPI_GPE: %d.%9.9d\n", t.tv_sec, t.tv_usec); #endif smi_event_handler(smi_info, 0); - out: spin_unlock_irqrestore(&(smi_info->si_lock), flags); return ACPI_INTERRUPT_HANDLED; @@ -2133,12 +2189,15 @@ static int __devinit ipmi_pci_probe(struct pci_dev *pdev, info->irq_setup = std_irq_setup; info->dev = &pdev->dev; + pci_set_drvdata(pdev, info); return try_smi_init(info); } static void __devexit ipmi_pci_remove(struct pci_dev *pdev) { + struct smi_info *info = pci_get_drvdata(pdev); + cleanup_one_si(info); } #ifdef CONFIG_PM @@ -2172,6 +2231,99 @@ static struct pci_driver ipmi_pci_driver = { #endif /* CONFIG_PCI */ +#ifdef CONFIG_PPC_OF +static int __devinit ipmi_of_probe(struct of_device *dev, + const struct of_device_id *match) +{ + struct smi_info *info; + struct resource resource; + const int *regsize, *regspacing, *regshift; + struct device_node *np = dev->node; + int ret; + int proplen; + + dev_info(&dev->dev, PFX "probing via device tree\n"); + + ret = of_address_to_resource(np, 0, &resource); + if (ret) { + dev_warn(&dev->dev, PFX "invalid address from OF\n"); + return ret; + } + + regsize = get_property(np, "reg-size", &proplen); + if (regsize && proplen != 4) { + dev_warn(&dev->dev, PFX "invalid regsize from OF\n"); + return -EINVAL; + } + + regspacing = get_property(np, "reg-spacing", &proplen); + if (regspacing && proplen != 4) { + dev_warn(&dev->dev, PFX "invalid regspacing from OF\n"); + return -EINVAL; + } + + regshift = get_property(np, "reg-shift", &proplen); + if (regshift && proplen != 4) { + dev_warn(&dev->dev, PFX "invalid regshift from OF\n"); + return -EINVAL; + } + + info = kzalloc(sizeof(*info), GFP_KERNEL); + + if (!info) { + dev_err(&dev->dev, + PFX "could not allocate memory for OF probe\n"); + return -ENOMEM; + } + + info->si_type = (enum si_type) match->data; + info->addr_source = "device-tree"; + info->io_setup = mem_setup; + info->irq_setup = std_irq_setup; + + info->io.addr_type = IPMI_MEM_ADDR_SPACE; + info->io.addr_data = resource.start; + + info->io.regsize = regsize ? *regsize : DEFAULT_REGSIZE; + info->io.regspacing = regspacing ? *regspacing : DEFAULT_REGSPACING; + info->io.regshift = regshift ? *regshift : 0; + + info->irq = irq_of_parse_and_map(dev->node, 0); + info->dev = &dev->dev; + + dev_dbg(&dev->dev, "addr 0x%lx regsize %ld spacing %ld irq %x\n", + info->io.addr_data, info->io.regsize, info->io.regspacing, + info->irq); + + dev->dev.driver_data = (void*) info; + + return try_smi_init(info); +} + +static int __devexit ipmi_of_remove(struct of_device *dev) +{ + cleanup_one_si(dev->dev.driver_data); + return 0; +} + +static struct of_device_id ipmi_match[] = +{ + { .type = "ipmi", .compatible = "ipmi-kcs", .data = (void *)(unsigned long) SI_KCS }, + { .type = "ipmi", .compatible = "ipmi-smic", .data = (void *)(unsigned long) SI_SMIC }, + { .type = "ipmi", .compatible = "ipmi-bt", .data = (void *)(unsigned long) SI_BT }, + {}, +}; + +static struct of_platform_driver ipmi_of_platform_driver = +{ + .name = "ipmi", + .match_table = ipmi_match, + .probe = ipmi_of_probe, + .remove = __devexit_p(ipmi_of_remove), +}; +#endif /* CONFIG_PPC_OF */ + + static int try_get_dev_id(struct smi_info *smi_info) { unsigned char msg[2]; @@ -2801,6 +2953,10 @@ static __devinit int init_ipmi_si(void) } #endif +#ifdef CONFIG_PPC_OF + of_register_platform_driver(&ipmi_of_platform_driver); +#endif + if (si_trydefaults) { mutex_lock(&smi_infos_lock); if (list_empty(&smi_infos)) { @@ -2838,28 +2994,33 @@ static void cleanup_one_si(struct smi_info *to_clean) list_del(&to_clean->link); - /* Tell the timer and interrupt handlers that we are shutting - down. */ - spin_lock_irqsave(&(to_clean->si_lock), flags); - spin_lock(&(to_clean->msg_lock)); - + /* Tell the driver that we are shutting down. */ atomic_inc(&to_clean->stop_operation); - if (to_clean->irq_cleanup) - to_clean->irq_cleanup(to_clean); - - spin_unlock(&(to_clean->msg_lock)); - spin_unlock_irqrestore(&(to_clean->si_lock), flags); - - /* Wait until we know that we are out of any interrupt - handlers might have been running before we freed the - interrupt. */ - synchronize_sched(); - + /* Make sure the timer and thread are stopped and will not run + again. */ wait_for_timer_and_thread(to_clean); - /* Interrupts and timeouts are stopped, now make sure the - interface is in a clean state. */ + /* Timeouts are stopped, now make sure the interrupts are off + for the device. A little tricky with locks to make sure + there are no races. */ + spin_lock_irqsave(&to_clean->si_lock, flags); + while (to_clean->curr_msg || (to_clean->si_state != SI_NORMAL)) { + spin_unlock_irqrestore(&to_clean->si_lock, flags); + poll(to_clean); + schedule_timeout_uninterruptible(1); + spin_lock_irqsave(&to_clean->si_lock, flags); + } + disable_si_irq(to_clean); + spin_unlock_irqrestore(&to_clean->si_lock, flags); + while (to_clean->curr_msg || (to_clean->si_state != SI_NORMAL)) { + poll(to_clean); + schedule_timeout_uninterruptible(1); + } + + /* Clean up interrupts and make sure that everything is done. */ + if (to_clean->irq_cleanup) + to_clean->irq_cleanup(to_clean); while (to_clean->curr_msg || (to_clean->si_state != SI_NORMAL)) { poll(to_clean); schedule_timeout_uninterruptible(1); @@ -2898,6 +3059,10 @@ static __exit void cleanup_ipmi_si(void) pci_unregister_driver(&ipmi_pci_driver); #endif +#ifdef CONFIG_PPC_OF + of_unregister_platform_driver(&ipmi_of_platform_driver); +#endif + mutex_lock(&smi_infos_lock); list_for_each_entry_safe(e, tmp_e, &smi_infos, link) cleanup_one_si(e); diff --git a/drivers/char/ipmi/ipmi_watchdog.c b/drivers/char/ipmi/ipmi_watchdog.c index 6b634e8d951..147c12047cf 100644 --- a/drivers/char/ipmi/ipmi_watchdog.c +++ b/drivers/char/ipmi/ipmi_watchdog.c @@ -39,6 +39,7 @@ #include <linux/miscdevice.h> #include <linux/init.h> #include <linux/completion.h> +#include <linux/kdebug.h> #include <linux/rwsem.h> #include <linux/errno.h> #include <asm/uaccess.h> @@ -49,9 +50,18 @@ #include <linux/poll.h> #include <linux/string.h> #include <linux/ctype.h> +#include <linux/delay.h> #include <asm/atomic.h> -#ifdef CONFIG_X86_LOCAL_APIC -#include <asm/apic.h> + +#ifdef CONFIG_X86 +/* This is ugly, but I've determined that x86 is the only architecture + that can reasonably support the IPMI NMI watchdog timeout at this + time. If another architecture adds this capability somehow, it + will have to be a somewhat different mechanism and I have no idea + how it will work. So in the unlikely event that another + architecture supports this, we can figure out a good generic + mechanism for it at that time. */ +#define HAVE_DIE_NMI_POST #endif #define PFX "IPMI Watchdog: " @@ -317,6 +327,11 @@ static unsigned char ipmi_version_minor; /* If a pretimeout occurs, this is used to allow only one panic to happen. */ static atomic_t preop_panic_excl = ATOMIC_INIT(-1); +#ifdef HAVE_DIE_NMI_POST +static int testing_nmi; +static int nmi_handler_registered; +#endif + static int ipmi_heartbeat(void); static void panic_halt_ipmi_heartbeat(void); @@ -358,6 +373,10 @@ static int i_ipmi_set_timeout(struct ipmi_smi_msg *smi_msg, int hbnow = 0; + /* These can be cleared as we are setting the timeout. */ + ipmi_start_timer_on_heartbeat = 0; + pretimeout_since_last_heartbeat = 0; + data[0] = 0; WDOG_SET_TIMER_USE(data[0], WDOG_TIMER_USE_SMS_OS); @@ -432,13 +451,12 @@ static int ipmi_set_timeout(int do_heartbeat) wait_for_completion(&set_timeout_wait); + mutex_unlock(&set_timeout_lock); + if ((do_heartbeat == IPMI_SET_TIMEOUT_FORCE_HB) || ((send_heartbeat_now) && (do_heartbeat == IPMI_SET_TIMEOUT_HB_IF_NECESSARY))) - { rv = ipmi_heartbeat(); - } - mutex_unlock(&set_timeout_lock); out: return rv; @@ -518,12 +536,10 @@ static int ipmi_heartbeat(void) int rv; struct ipmi_system_interface_addr addr; - if (ipmi_ignore_heartbeat) { + if (ipmi_ignore_heartbeat) return 0; - } if (ipmi_start_timer_on_heartbeat) { - ipmi_start_timer_on_heartbeat = 0; ipmi_watchdog_state = action_val; return ipmi_set_timeout(IPMI_SET_TIMEOUT_FORCE_HB); } else if (pretimeout_since_last_heartbeat) { @@ -531,7 +547,6 @@ static int ipmi_heartbeat(void) We don't want to set the action, though, we want to leave that alone (thus it can't be combined with the above operation. */ - pretimeout_since_last_heartbeat = 0; return ipmi_set_timeout(IPMI_SET_TIMEOUT_HB_IF_NECESSARY); } @@ -919,6 +934,45 @@ static void ipmi_register_watchdog(int ipmi_intf) printk(KERN_CRIT PFX "Unable to register misc device\n"); } +#ifdef HAVE_DIE_NMI_POST + if (nmi_handler_registered) { + int old_pretimeout = pretimeout; + int old_timeout = timeout; + int old_preop_val = preop_val; + + /* Set the pretimeout to go off in a second and give + ourselves plenty of time to stop the timer. */ + ipmi_watchdog_state = WDOG_TIMEOUT_RESET; + preop_val = WDOG_PREOP_NONE; /* Make sure nothing happens */ + pretimeout = 99; + timeout = 100; + + testing_nmi = 1; + + rv = ipmi_set_timeout(IPMI_SET_TIMEOUT_FORCE_HB); + if (rv) { + printk(KERN_WARNING PFX "Error starting timer to" + " test NMI: 0x%x. The NMI pretimeout will" + " likely not work\n", rv); + rv = 0; + goto out_restore; + } + + msleep(1500); + + if (testing_nmi != 2) { + printk(KERN_WARNING PFX "IPMI NMI didn't seem to" + " occur. The NMI pretimeout will" + " likely not work\n"); + } + out_restore: + testing_nmi = 0; + preop_val = old_preop_val; + pretimeout = old_pretimeout; + timeout = old_timeout; + } +#endif + out: up_write(®ister_sem); @@ -928,6 +982,10 @@ static void ipmi_register_watchdog(int ipmi_intf) ipmi_watchdog_state = action_val; ipmi_set_timeout(IPMI_SET_TIMEOUT_FORCE_HB); printk(KERN_INFO PFX "Starting now!\n"); + } else { + /* Stop the timer now. */ + ipmi_watchdog_state = WDOG_TIMEOUT_NONE; + ipmi_set_timeout(IPMI_SET_TIMEOUT_NO_HB); } } @@ -964,17 +1022,28 @@ static void ipmi_unregister_watchdog(int ipmi_intf) up_write(®ister_sem); } -#ifdef HAVE_NMI_HANDLER +#ifdef HAVE_DIE_NMI_POST static int -ipmi_nmi(void *dev_id, int cpu, int handled) +ipmi_nmi(struct notifier_block *self, unsigned long val, void *data) { + if (val != DIE_NMI_POST) + return NOTIFY_OK; + + if (testing_nmi) { + testing_nmi = 2; + return NOTIFY_STOP; + } + /* If we are not expecting a timeout, ignore it. */ if (ipmi_watchdog_state == WDOG_TIMEOUT_NONE) - return NOTIFY_DONE; + return NOTIFY_OK; + + if (preaction_val != WDOG_PRETIMEOUT_NMI) + return NOTIFY_OK; /* If no one else handled the NMI, we assume it was the IPMI watchdog. */ - if ((!handled) && (preop_val == WDOG_PREOP_PANIC)) { + if (preop_val == WDOG_PREOP_PANIC) { /* On some machines, the heartbeat will give an error and not work unless we re-enable the timer. So do so. */ @@ -983,18 +1052,12 @@ ipmi_nmi(void *dev_id, int cpu, int handled) panic(PFX "pre-timeout"); } - return NOTIFY_DONE; + return NOTIFY_STOP; } -static struct nmi_handler ipmi_nmi_handler = -{ - .link = LIST_HEAD_INIT(ipmi_nmi_handler.link), - .dev_name = "ipmi_watchdog", - .dev_id = NULL, - .handler = ipmi_nmi, - .priority = 0, /* Call us last. */ +static struct notifier_block ipmi_nmi_handler = { + .notifier_call = ipmi_nmi }; -int nmi_handler_registered; #endif static int wdog_reboot_handler(struct notifier_block *this, @@ -1111,7 +1174,7 @@ static int preaction_op(const char *inval, char *outval) preaction_val = WDOG_PRETIMEOUT_NONE; else if (strcmp(inval, "pre_smi") == 0) preaction_val = WDOG_PRETIMEOUT_SMI; -#ifdef HAVE_NMI_HANDLER +#ifdef HAVE_DIE_NMI_POST else if (strcmp(inval, "pre_nmi") == 0) preaction_val = WDOG_PRETIMEOUT_NMI; #endif @@ -1145,7 +1208,7 @@ static int preop_op(const char *inval, char *outval) static void check_parms(void) { -#ifdef HAVE_NMI_HANDLER +#ifdef HAVE_DIE_NMI_POST int do_nmi = 0; int rv; @@ -1158,20 +1221,9 @@ static void check_parms(void) preop_op("preop_none", NULL); do_nmi = 0; } -#ifdef CONFIG_X86_LOCAL_APIC - if (nmi_watchdog == NMI_IO_APIC) { - printk(KERN_WARNING PFX "nmi_watchdog is set to IO APIC" - " mode (value is %d), that is incompatible" - " with using NMI in the IPMI watchdog." - " Disabling IPMI nmi pretimeout.\n", - nmi_watchdog); - preaction_val = WDOG_PRETIMEOUT_NONE; - do_nmi = 0; - } -#endif } if (do_nmi && !nmi_handler_registered) { - rv = request_nmi(&ipmi_nmi_handler); + rv = register_die_notifier(&ipmi_nmi_handler); if (rv) { printk(KERN_WARNING PFX "Can't register nmi handler\n"); @@ -1179,7 +1231,7 @@ static void check_parms(void) } else nmi_handler_registered = 1; } else if (!do_nmi && nmi_handler_registered) { - release_nmi(&ipmi_nmi_handler); + unregister_die_notifier(&ipmi_nmi_handler); nmi_handler_registered = 0; } #endif @@ -1215,9 +1267,9 @@ static int __init ipmi_wdog_init(void) rv = ipmi_smi_watcher_register(&smi_watcher); if (rv) { -#ifdef HAVE_NMI_HANDLER - if (preaction_val == WDOG_PRETIMEOUT_NMI) - release_nmi(&ipmi_nmi_handler); +#ifdef HAVE_DIE_NMI_POST + if (nmi_handler_registered) + unregister_die_notifier(&ipmi_nmi_handler); #endif atomic_notifier_chain_unregister(&panic_notifier_list, &wdog_panic_notifier); @@ -1236,9 +1288,9 @@ static void __exit ipmi_wdog_exit(void) ipmi_smi_watcher_unregister(&smi_watcher); ipmi_unregister_watchdog(watchdog_ifnum); -#ifdef HAVE_NMI_HANDLER +#ifdef HAVE_DIE_NMI_POST if (nmi_handler_registered) - release_nmi(&ipmi_nmi_handler); + unregister_die_notifier(&ipmi_nmi_handler); #endif atomic_notifier_chain_unregister(&panic_notifier_list, diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c index 43ab9edc76f..761f77740d6 100644 --- a/drivers/char/isicom.c +++ b/drivers/char/isicom.c @@ -137,11 +137,10 @@ #define InterruptTheCard(base) outw(0, (base) + 0xc) #define ClearInterrupt(base) inw((base) + 0x0a) +#define pr_dbg(str...) pr_debug("ISICOM: " str) #ifdef DEBUG -#define pr_dbg(str...) printk(KERN_DEBUG "ISICOM: " str) #define isicom_paranoia_check(a, b, c) __isicom_paranoia_check((a), (b), (c)) #else -#define pr_dbg(str...) do { } while (0) #define isicom_paranoia_check(a, b, c) 0 #endif diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c index cb8d691576d..1b094509b1d 100644 --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c @@ -41,7 +41,6 @@ #include <linux/input.h> #include <linux/reboot.h> -static void kbd_disconnect(struct input_handle *handle); extern void ctrl_alt_del(void); /* @@ -110,7 +109,7 @@ struct kbd_struct kbd_table[MAX_NR_CONSOLES]; static struct kbd_struct *kbd = kbd_table; struct vt_spawn_console vt_spawn_con = { - .lock = SPIN_LOCK_UNLOCKED, + .lock = __SPIN_LOCK_UNLOCKED(vt_spawn_con.lock), .pid = NULL, .sig = 0, }; @@ -159,65 +158,41 @@ static int sysrq_alt_use; static int sysrq_alt; /* - * Translation of scancodes to keycodes. We set them on only the first attached - * keyboard - for per-keyboard setting, /dev/input/event is more useful. + * Translation of scancodes to keycodes. We set them on only the first + * keyboard in the list that accepts the scancode and keycode. + * Explanation for not choosing the first attached keyboard anymore: + * USB keyboards for example have two event devices: one for all "normal" + * keys and one for extra function keys (like "volume up", "make coffee", + * etc.). So this means that scancodes for the extra function keys won't + * be valid for the first event device, but will be for the second. */ int getkeycode(unsigned int scancode) { - struct list_head *node; - struct input_dev *dev = NULL; + struct input_handle *handle; + int keycode; + int error = -ENODEV; - list_for_each(node, &kbd_handler.h_list) { - struct input_handle *handle = to_handle_h(node); - if (handle->dev->keycodesize) { - dev = handle->dev; - break; - } + list_for_each_entry(handle, &kbd_handler.h_list, h_node) { + error = handle->dev->getkeycode(handle->dev, scancode, &keycode); + if (!error) + return keycode; } - if (!dev) - return -ENODEV; - - if (scancode >= dev->keycodemax) - return -EINVAL; - - return INPUT_KEYCODE(dev, scancode); + return error; } int setkeycode(unsigned int scancode, unsigned int keycode) { - struct list_head *node; - struct input_dev *dev = NULL; - unsigned int i, oldkey; + struct input_handle *handle; + int error = -ENODEV; - list_for_each(node, &kbd_handler.h_list) { - struct input_handle *handle = to_handle_h(node); - if (handle->dev->keycodesize) { - dev = handle->dev; + list_for_each_entry(handle, &kbd_handler.h_list, h_node) { + error = handle->dev->setkeycode(handle->dev, scancode, keycode); + if (!error) break; - } } - if (!dev) - return -ENODEV; - - if (scancode >= dev->keycodemax) - return -EINVAL; - if (keycode < 0 || keycode > KEY_MAX) - return -EINVAL; - if (dev->keycodesize < sizeof(keycode) && (keycode >> (dev->keycodesize * 8))) - return -EINVAL; - - oldkey = SET_INPUT_KEYCODE(dev, scancode, keycode); - - clear_bit(oldkey, dev->keybit); - set_bit(keycode, dev->keybit); - - for (i = 0; i < dev->keycodemax; i++) - if (INPUT_KEYCODE(dev,i) == oldkey) - set_bit(oldkey, dev->keybit); - - return 0; + return error; } /* @@ -225,10 +200,9 @@ int setkeycode(unsigned int scancode, unsigned int keycode) */ static void kd_nosound(unsigned long ignored) { - struct list_head *node; + struct input_handle *handle; - list_for_each(node, &kbd_handler.h_list) { - struct input_handle *handle = to_handle_h(node); + list_for_each_entry(handle, &kbd_handler.h_list, h_node) { if (test_bit(EV_SND, handle->dev->evbit)) { if (test_bit(SND_TONE, handle->dev->sndbit)) input_inject_event(handle, EV_SND, SND_TONE, 0); @@ -1161,7 +1135,7 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw) if ((raw_mode = (kbd->kbdmode == VC_RAW)) && !hw_raw) if (emulate_raw(vc, keycode, !down << 7)) - if (keycode < BTN_MISC) + if (keycode < BTN_MISC && printk_ratelimit()) printk(KERN_WARNING "keyboard.c: can't emulate rawmode for keycode %d\n", keycode); #ifdef CONFIG_MAGIC_SYSRQ /* Handle the SysRq Hack */ @@ -1285,11 +1259,11 @@ static void kbd_event(struct input_handle *handle, unsigned int event_type, * likes it, it can open it and get events from it. In this (kbd_connect) * function, we should decide which VT to bind that keyboard to initially. */ -static struct input_handle *kbd_connect(struct input_handler *handler, - struct input_dev *dev, - const struct input_device_id *id) +static int kbd_connect(struct input_handler *handler, struct input_dev *dev, + const struct input_device_id *id) { struct input_handle *handle; + int error; int i; for (i = KEY_RESERVED; i < BTN_MISC; i++) @@ -1297,24 +1271,37 @@ static struct input_handle *kbd_connect(struct input_handler *handler, break; if (i == BTN_MISC && !test_bit(EV_SND, dev->evbit)) - return NULL; + return -ENODEV; handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL); if (!handle) - return NULL; + return -ENOMEM; handle->dev = dev; handle->handler = handler; handle->name = "kbd"; - input_open_device(handle); + error = input_register_handle(handle); + if (error) + goto err_free_handle; + + error = input_open_device(handle); + if (error) + goto err_unregister_handle; + + return 0; - return handle; + err_unregister_handle: + input_unregister_handle(handle); + err_free_handle: + kfree(handle); + return error; } static void kbd_disconnect(struct input_handle *handle) { input_close_device(handle); + input_unregister_handle(handle); kfree(handle); } diff --git a/drivers/char/lp.c b/drivers/char/lp.c index b51d08be0bc..62051f8b091 100644 --- a/drivers/char/lp.c +++ b/drivers/char/lp.c @@ -118,7 +118,6 @@ #include <linux/kernel.h> #include <linux/major.h> #include <linux/sched.h> -#include <linux/smp_lock.h> #include <linux/slab.h> #include <linux/fcntl.h> #include <linux/delay.h> @@ -139,9 +138,6 @@ /* if you have more than 8 printers, remember to increase LP_NO */ #define LP_NO 8 -/* ROUND_UP macro from fs/select.c */ -#define ROUND_UP(x,y) (((x)+(y)-1)/(y)) - static struct lp_struct lp_table[LP_NO]; static unsigned int lp_count = 0; @@ -652,7 +648,7 @@ static int lp_ioctl(struct inode *inode, struct file *file, (par_timeout.tv_usec < 0)) { return -EINVAL; } - to_jiffies = ROUND_UP(par_timeout.tv_usec, 1000000/HZ); + to_jiffies = DIV_ROUND_UP(par_timeout.tv_usec, 1000000/HZ); to_jiffies += par_timeout.tv_sec * (long) HZ; if (to_jiffies <= 0) { return -EINVAL; @@ -803,7 +799,7 @@ static int lp_register(int nr, struct parport *port) if (reset) lp_reset(nr); - class_device_create(lp_class, NULL, MKDEV(LP_MAJOR, nr), NULL, + class_device_create(lp_class, NULL, MKDEV(LP_MAJOR, nr), port->dev, "lp%d", nr); printk(KERN_INFO "lp%d: using %s (%s).\n", nr, port->name, diff --git a/drivers/char/mem.c b/drivers/char/mem.c index 5f066963f17..cc9a9d0df97 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -18,7 +18,6 @@ #include <linux/raw.h> #include <linux/tty.h> #include <linux/capability.h> -#include <linux/smp_lock.h> #include <linux/ptrace.h> #include <linux/device.h> #include <linux/highmem.h> @@ -552,7 +551,7 @@ static ssize_t write_kmem(struct file * file, const char __user * buf, return virtr + wrote; } -#if (defined(CONFIG_ISA) || defined(CONFIG_PCI)) && !defined(__mc68000__) +#ifdef CONFIG_DEVPORT static ssize_t read_port(struct file * file, char __user * buf, size_t count, loff_t *ppos) { @@ -835,7 +834,7 @@ static const struct file_operations null_fops = { .splice_write = splice_write_null, }; -#if (defined(CONFIG_ISA) || defined(CONFIG_PCI)) && !defined(__mc68000__) +#ifdef CONFIG_DEVPORT static const struct file_operations port_fops = { .llseek = memory_lseek, .read = read_port, @@ -913,7 +912,7 @@ static int memory_open(struct inode * inode, struct file * filp) case 3: filp->f_op = &null_fops; break; -#if (defined(CONFIG_ISA) || defined(CONFIG_PCI)) && !defined(__mc68000__) +#ifdef CONFIG_DEVPORT case 4: filp->f_op = &port_fops; break; @@ -960,7 +959,7 @@ static const struct { {1, "mem", S_IRUSR | S_IWUSR | S_IRGRP, &mem_fops}, {2, "kmem", S_IRUSR | S_IWUSR | S_IRGRP, &kmem_fops}, {3, "null", S_IRUGO | S_IWUGO, &null_fops}, -#if (defined(CONFIG_ISA) || defined(CONFIG_PCI)) && !defined(__mc68000__) +#ifdef CONFIG_DEVPORT {4, "port", S_IRUSR | S_IWUSR | S_IRGRP, &port_fops}, #endif {5, "zero", S_IRUGO | S_IWUGO, &zero_fops}, diff --git a/drivers/char/misc.c b/drivers/char/misc.c index 7e975f60692..4e6fb9651a1 100644 --- a/drivers/char/misc.c +++ b/drivers/char/misc.c @@ -41,6 +41,7 @@ #include <linux/kernel.h> #include <linux/major.h> #include <linux/slab.h> +#include <linux/mutex.h> #include <linux/proc_fs.h> #include <linux/seq_file.h> #include <linux/stat.h> @@ -53,7 +54,7 @@ * Head entry for the doubly linked miscdevice list */ static LIST_HEAD(misc_list); -static DECLARE_MUTEX(misc_sem); +static DEFINE_MUTEX(misc_mtx); /* * Assigned numbers, used for dynamic minors @@ -69,7 +70,7 @@ static void *misc_seq_start(struct seq_file *seq, loff_t *pos) struct miscdevice *p; loff_t off = 0; - down(&misc_sem); + mutex_lock(&misc_mtx); list_for_each_entry(p, &misc_list, list) { if (*pos == off++) return p; @@ -89,7 +90,7 @@ static void *misc_seq_next(struct seq_file *seq, void *v, loff_t *pos) static void misc_seq_stop(struct seq_file *seq, void *v) { - up(&misc_sem); + mutex_unlock(&misc_mtx); } static int misc_seq_show(struct seq_file *seq, void *v) @@ -129,7 +130,7 @@ static int misc_open(struct inode * inode, struct file * file) int err = -ENODEV; const struct file_operations *old_fops, *new_fops = NULL; - down(&misc_sem); + mutex_lock(&misc_mtx); list_for_each_entry(c, &misc_list, list) { if (c->minor == minor) { @@ -139,9 +140,9 @@ static int misc_open(struct inode * inode, struct file * file) } if (!new_fops) { - up(&misc_sem); + mutex_unlock(&misc_mtx); request_module("char-major-%d-%d", MISC_MAJOR, minor); - down(&misc_sem); + mutex_lock(&misc_mtx); list_for_each_entry(c, &misc_list, list) { if (c->minor == minor) { @@ -165,7 +166,7 @@ static int misc_open(struct inode * inode, struct file * file) } fops_put(old_fops); fail: - up(&misc_sem); + mutex_unlock(&misc_mtx); return err; } @@ -201,10 +202,10 @@ int misc_register(struct miscdevice * misc) INIT_LIST_HEAD(&misc->list); - down(&misc_sem); + mutex_lock(&misc_mtx); list_for_each_entry(c, &misc_list, list) { if (c->minor == misc->minor) { - up(&misc_sem); + mutex_unlock(&misc_mtx); return -EBUSY; } } @@ -215,7 +216,7 @@ int misc_register(struct miscdevice * misc) if ( (misc_minors[i>>3] & (1 << (i&7))) == 0) break; if (i<0) { - up(&misc_sem); + mutex_unlock(&misc_mtx); return -EBUSY; } misc->minor = i; @@ -238,7 +239,7 @@ int misc_register(struct miscdevice * misc) */ list_add(&misc->list, &misc_list); out: - up(&misc_sem); + mutex_unlock(&misc_mtx); return err; } @@ -259,13 +260,13 @@ int misc_deregister(struct miscdevice * misc) if (list_empty(&misc->list)) return -EINVAL; - down(&misc_sem); + mutex_lock(&misc_mtx); list_del(&misc->list); device_destroy(misc_class, MKDEV(MISC_MAJOR, misc->minor)); if (i < DYNAMIC_MINORS && i>0) { misc_minors[i>>3] &= ~(1 << (misc->minor & 7)); } - up(&misc_sem); + mutex_unlock(&misc_mtx); return 0; } diff --git a/drivers/char/mmtimer.c b/drivers/char/mmtimer.c index c09160383a5..6e55cfb9c65 100644 --- a/drivers/char/mmtimer.c +++ b/drivers/char/mmtimer.c @@ -705,15 +705,13 @@ static int __init mmtimer_init(void) maxn++; /* Allocate list of node ptrs to mmtimer_t's */ - timers = kmalloc(sizeof(mmtimer_t *)*maxn, GFP_KERNEL); + timers = kzalloc(sizeof(mmtimer_t *)*maxn, GFP_KERNEL); if (timers == NULL) { printk(KERN_ERR "%s: failed to allocate memory for device\n", MMTIMER_NAME); goto out3; } - memset(timers,0,(sizeof(mmtimer_t *)*maxn)); - /* Allocate mmtimer_t's for each online node */ for_each_online_node(node) { timers[node] = kmalloc_node(sizeof(mmtimer_t)*NUM_COMPARATORS, GFP_KERNEL, node); diff --git a/drivers/char/moxa.c b/drivers/char/moxa.c index 7dbaee8d940..e0d35c20c04 100644 --- a/drivers/char/moxa.c +++ b/drivers/char/moxa.c @@ -1582,7 +1582,7 @@ copy: if(copy_from_user(&dltmp, argp, sizeof(struct dl_str))) return -EFAULT; - if(dltmp.cardno < 0 || dltmp.cardno >= MAX_BOARDS) + if(dltmp.cardno < 0 || dltmp.cardno >= MAX_BOARDS || dltmp.len < 0) return -EINVAL; switch(cmd) @@ -2529,6 +2529,8 @@ static int moxaloadbios(int cardno, unsigned char __user *tmp, int len) void __iomem *baseAddr; int i; + if(len < 0 || len > sizeof(moxaBuff)) + return -EINVAL; if(copy_from_user(moxaBuff, tmp, len)) return -EFAULT; baseAddr = moxa_boards[cardno].basemem; @@ -2576,7 +2578,7 @@ static int moxaload320b(int cardno, unsigned char __user *tmp, int len) void __iomem *baseAddr; int i; - if(len > sizeof(moxaBuff)) + if(len < 0 || len > sizeof(moxaBuff)) return -EINVAL; if(copy_from_user(moxaBuff, tmp, len)) return -EFAULT; @@ -2596,6 +2598,8 @@ static int moxaloadcode(int cardno, unsigned char __user *tmp, int len) void __iomem *baseAddr, *ofsAddr; int retval, port, i; + if(len < 0 || len > sizeof(moxaBuff)) + return -EINVAL; if(copy_from_user(moxaBuff, tmp, len)) return -EFAULT; baseAddr = moxa_boards[cardno].basemem; diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c index 80a01150b86..5953a45d7e9 100644 --- a/drivers/char/mxser.c +++ b/drivers/char/mxser.c @@ -54,7 +54,6 @@ #include <linux/gfp.h> #include <linux/ioport.h> #include <linux/mm.h> -#include <linux/smp_lock.h> #include <linux/delay.h> #include <linux/pci.h> diff --git a/drivers/char/mxser_new.c b/drivers/char/mxser_new.c index f7603b6aeb8..6cde448cd5b 100644 --- a/drivers/char/mxser_new.c +++ b/drivers/char/mxser_new.c @@ -37,7 +37,6 @@ #include <linux/gfp.h> #include <linux/ioport.h> #include <linux/mm.h> -#include <linux/smp_lock.h> #include <linux/delay.h> #include <linux/pci.h> diff --git a/drivers/char/n_r3964.c b/drivers/char/n_r3964.c index 65f2d3a96b8..14557a4822c 100644 --- a/drivers/char/n_r3964.c +++ b/drivers/char/n_r3964.c @@ -1088,13 +1088,13 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file, /* block until there is a message: */ add_wait_queue(&pInfo->read_wait, &wait); repeat: - current->state = TASK_INTERRUPTIBLE; + __set_current_state(TASK_INTERRUPTIBLE); pMsg = remove_msg(pInfo, pClient); if (!pMsg && !signal_pending(current)) { schedule(); goto repeat; } - current->state = TASK_RUNNING; + __set_current_state(TASK_RUNNING); remove_wait_queue(&pInfo->read_wait, &wait); } diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c index 6ac3ca4c723..b3d4ccc33a4 100644 --- a/drivers/char/n_tty.c +++ b/drivers/char/n_tty.c @@ -1544,21 +1544,18 @@ static unsigned int normal_poll(struct tty_struct * tty, struct file * file, pol } struct tty_ldisc tty_ldisc_N_TTY = { - TTY_LDISC_MAGIC, /* magic */ - "n_tty", /* name */ - 0, /* num */ - 0, /* flags */ - n_tty_open, /* open */ - n_tty_close, /* close */ - n_tty_flush_buffer, /* flush_buffer */ - n_tty_chars_in_buffer, /* chars_in_buffer */ - read_chan, /* read */ - write_chan, /* write */ - n_tty_ioctl, /* ioctl */ - n_tty_set_termios, /* set_termios */ - normal_poll, /* poll */ - NULL, /* hangup */ - n_tty_receive_buf, /* receive_buf */ - n_tty_write_wakeup /* write_wakeup */ + .magic = TTY_LDISC_MAGIC, + .name = "n_tty", + .open = n_tty_open, + .close = n_tty_close, + .flush_buffer = n_tty_flush_buffer, + .chars_in_buffer = n_tty_chars_in_buffer, + .read = read_chan, + .write = write_chan, + .ioctl = n_tty_ioctl, + .set_termios = n_tty_set_termios, + .poll = normal_poll, + .receive_buf = n_tty_receive_buf, + .write_wakeup = n_tty_write_wakeup }; diff --git a/drivers/char/pcmcia/Kconfig b/drivers/char/pcmcia/Kconfig index 27c1179ee52..f25facd97bb 100644 --- a/drivers/char/pcmcia/Kconfig +++ b/drivers/char/pcmcia/Kconfig @@ -21,6 +21,7 @@ config SYNCLINK_CS config CARDMAN_4000 tristate "Omnikey Cardman 4000 support" depends on PCMCIA + select BITREVERSE help Enable support for the Omnikey Cardman 4000 PCMCIA Smartcard reader. diff --git a/drivers/char/pcmcia/cm4000_cs.c b/drivers/char/pcmcia/cm4000_cs.c index e91b43a014b..fee58e03dbe 100644 --- a/drivers/char/pcmcia/cm4000_cs.c +++ b/drivers/char/pcmcia/cm4000_cs.c @@ -31,6 +31,7 @@ #include <linux/init.h> #include <linux/fs.h> #include <linux/delay.h> +#include <linux/bitrev.h> #include <asm/uaccess.h> #include <asm/io.h> @@ -194,41 +195,17 @@ static inline unsigned char xinb(unsigned short port) } #endif -#define b_0000 15 -#define b_0001 14 -#define b_0010 13 -#define b_0011 12 -#define b_0100 11 -#define b_0101 10 -#define b_0110 9 -#define b_0111 8 -#define b_1000 7 -#define b_1001 6 -#define b_1010 5 -#define b_1011 4 -#define b_1100 3 -#define b_1101 2 -#define b_1110 1 -#define b_1111 0 - -static unsigned char irtab[16] = { - b_0000, b_1000, b_0100, b_1100, - b_0010, b_1010, b_0110, b_1110, - b_0001, b_1001, b_0101, b_1101, - b_0011, b_1011, b_0111, b_1111 -}; +static inline unsigned char invert_revert(unsigned char ch) +{ + return bitrev8(~ch); +} static void str_invert_revert(unsigned char *b, int len) { int i; for (i = 0; i < len; i++) - b[i] = (irtab[b[i] & 0x0f] << 4) | irtab[b[i] >> 4]; -} - -static unsigned char invert_revert(unsigned char ch) -{ - return (irtab[ch & 0x0f] << 4) | irtab[ch >> 4]; + b[i] = invert_revert(b[i]); } #define ATRLENCK(dev,pos) \ @@ -1114,7 +1091,7 @@ static ssize_t cmm_write(struct file *filp, const char __user *buf, /* * wait for atr to become valid. * note: it is important to lock this code. if we dont, the monitor - * could be run between test_bit and the the call the sleep on the + * could be run between test_bit and the call to sleep on the * atr-queue. if *then* the monitor detects atr valid, it will wake up * any process on the atr-queue, *but* since we have been interrupted, * we do not yet sleep on this queue. this would result in a missed @@ -1881,8 +1858,11 @@ static int cm4000_probe(struct pcmcia_device *link) init_waitqueue_head(&dev->readq); ret = cm4000_config(link, i); - if (ret) + if (ret) { + dev_table[i] = NULL; + kfree(dev); return ret; + } class_device_create(cmm_class, NULL, MKDEV(major, i), NULL, "cmm%d", i); @@ -1907,7 +1887,7 @@ static void cm4000_detach(struct pcmcia_device *link) cm4000_release(link); dev_table[devno] = NULL; - kfree(dev); + kfree(dev); class_device_destroy(cmm_class, MKDEV(major, devno)); @@ -1956,12 +1936,14 @@ static int __init cmm_init(void) if (major < 0) { printk(KERN_WARNING MODULE_NAME ": could not get major number\n"); + class_destroy(cmm_class); return major; } rc = pcmcia_register_driver(&cm4000_driver); if (rc < 0) { unregister_chrdev(major, DEVICE_NAME); + class_destroy(cmm_class); return rc; } diff --git a/drivers/char/pcmcia/cm4040_cs.c b/drivers/char/pcmcia/cm4040_cs.c index f2e4ec4fd40..af88181a17f 100644 --- a/drivers/char/pcmcia/cm4040_cs.c +++ b/drivers/char/pcmcia/cm4040_cs.c @@ -636,8 +636,11 @@ static int reader_probe(struct pcmcia_device *link) setup_timer(&dev->poll_timer, cm4040_do_poll, 0); ret = reader_config(link, i); - if (ret) + if (ret) { + dev_table[i] = NULL; + kfree(dev); return ret; + } class_device_create(cmx_class, NULL, MKDEV(major, i), NULL, "cmx%d", i); @@ -708,12 +711,14 @@ static int __init cm4040_init(void) if (major < 0) { printk(KERN_WARNING MODULE_NAME ": could not get major number\n"); + class_destroy(cmx_class); return major; } rc = pcmcia_register_driver(&reader_driver); if (rc < 0) { unregister_chrdev(major, DEVICE_NAME); + class_destroy(cmx_class); return rc; } diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index 157b1d09ab5..13808f6083a 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c @@ -42,7 +42,6 @@ #include <linux/timer.h> #include <linux/time.h> #include <linux/interrupt.h> -#include <linux/pci.h> #include <linux/tty.h> #include <linux/tty_flip.h> #include <linux/serial.h> diff --git a/drivers/char/ppdev.c b/drivers/char/ppdev.c index 4abd1eff61d..84ac64fc48a 100644 --- a/drivers/char/ppdev.c +++ b/drivers/char/ppdev.c @@ -66,7 +66,6 @@ #include <linux/poll.h> #include <linux/major.h> #include <linux/ppdev.h> -#include <linux/smp_lock.h> #include <linux/device.h> #include <asm/uaccess.h> @@ -752,7 +751,7 @@ static const struct file_operations pp_fops = { static void pp_attach(struct parport *port) { - device_create(ppdev_class, NULL, MKDEV(PP_MAJOR, port->number), + device_create(ppdev_class, port->dev, MKDEV(PP_MAJOR, port->number), "parport%d", port->number); } diff --git a/drivers/char/rio/riocmd.c b/drivers/char/rio/riocmd.c index 245f03195b7..8cc60b69346 100644 --- a/drivers/char/rio/riocmd.c +++ b/drivers/char/rio/riocmd.c @@ -402,7 +402,7 @@ static int RIOCommandRup(struct rio_info *p, uint Rup, struct Host *HostP, struc rio_dprintk(RIO_DEBUG_CMD, "CONTROL information: Host number %Zd, name ``%s''\n", HostP - p->RIOHosts, HostP->Name); rio_dprintk(RIO_DEBUG_CMD, "CONTROL information: Rup number 0x%x\n", rup); - if (Rup >= (unsigned short) MAX_RUP) { + if (Rup < (unsigned short) MAX_RUP) { rio_dprintk(RIO_DEBUG_CMD, "CONTROL information: This is the RUP for RTA ``%s''\n", HostP->Mapping[Rup].Name); } else rio_dprintk(RIO_DEBUG_CMD, "CONTROL information: This is the RUP for link ``%c'' of host ``%s''\n", ('A' + Rup - MAX_RUP), HostP->Name); diff --git a/drivers/char/riscom8.c b/drivers/char/riscom8.c index 70145254fb9..3494e3fc44b 100644 --- a/drivers/char/riscom8.c +++ b/drivers/char/riscom8.c @@ -980,7 +980,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, } schedule(); } - current->state = TASK_RUNNING; + __set_current_state(TASK_RUNNING); remove_wait_queue(&port->open_wait, &wait); if (!tty_hung_up_p(filp)) port->count++; diff --git a/drivers/char/rocket.c b/drivers/char/rocket.c index 76357c855ce..a3fd7e7ba5a 100644 --- a/drivers/char/rocket.c +++ b/drivers/char/rocket.c @@ -65,10 +65,6 @@ /****** Kernel includes ******/ -#ifdef MODVERSIONS -#include <config/modversions.h> -#endif - #include <linux/module.h> #include <linux/errno.h> #include <linux/major.h> @@ -85,6 +81,7 @@ #include <linux/string.h> #include <linux/fcntl.h> #include <linux/ptrace.h> +#include <linux/mutex.h> #include <linux/ioport.h> #include <linux/delay.h> #include <linux/wait.h> @@ -93,7 +90,6 @@ #include <asm/atomic.h> #include <linux/bitops.h> #include <linux/spinlock.h> -#include <asm/semaphore.h> #include <linux/init.h> /****** RocketPort includes ******/ @@ -702,7 +698,7 @@ static void init_r_port(int board, int aiop, int chan, struct pci_dev *pci_dev) } } spin_lock_init(&info->slock); - sema_init(&info->write_sem, 1); + mutex_init(&info->write_mtx); rp_table[line] = info; if (pci_dev) tty_register_device(rocket_driver, line, &pci_dev->dev); @@ -947,7 +943,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, #endif schedule(); /* Don't hold spinlock here, will hang PC */ } - current->state = TASK_RUNNING; + __set_current_state(TASK_RUNNING); remove_wait_queue(&info->open_wait, &wait); spin_lock_irqsave(&info->slock, flags); @@ -1018,9 +1014,6 @@ static int rp_open(struct tty_struct *tty, struct file *filp) /* * Info->count is now 1; so it's safe to sleep now. */ - info->session = process_session(current); - info->pgrp = process_group(current); - if ((info->flags & ROCKET_INITIALIZED) == 0) { cp = &info->channel; sSetRxTrigger(cp, TRIG_1); @@ -1602,7 +1595,7 @@ static void rp_wait_until_sent(struct tty_struct *tty, int timeout) if (signal_pending(current)) break; } - current->state = TASK_RUNNING; + __set_current_state(TASK_RUNNING); #ifdef ROCKET_DEBUG_WAIT_UNTIL_SENT printk(KERN_INFO "txcnt = %d (jiff=%lu)...done\n", txcnt, jiffies); #endif @@ -1661,8 +1654,11 @@ static void rp_put_char(struct tty_struct *tty, unsigned char ch) if (rocket_paranoia_check(info, "rp_put_char")) return; - /* Grab the port write semaphore, locking out other processes that try to write to this port */ - down(&info->write_sem); + /* + * Grab the port write mutex, locking out other processes that try to + * write to this port + */ + mutex_lock(&info->write_mtx); #ifdef ROCKET_DEBUG_WRITE printk(KERN_INFO "rp_put_char %c...", ch); @@ -1684,12 +1680,12 @@ static void rp_put_char(struct tty_struct *tty, unsigned char ch) info->xmit_fifo_room--; } spin_unlock_irqrestore(&info->slock, flags); - up(&info->write_sem); + mutex_unlock(&info->write_mtx); } /* * Exception handler - write routine, called when user app writes to the device. - * A per port write semaphore is used to protect from another process writing to + * A per port write mutex is used to protect from another process writing to * this port at the same time. This other process could be running on the other CPU * or get control of the CPU if the copy_from_user() blocks due to a page fault (swapped out). * Spinlocks protect the info xmit members. @@ -1706,7 +1702,7 @@ static int rp_write(struct tty_struct *tty, if (count <= 0 || rocket_paranoia_check(info, "rp_write")) return 0; - down_interruptible(&info->write_sem); + mutex_lock_interruptible(&info->write_mtx); #ifdef ROCKET_DEBUG_WRITE printk(KERN_INFO "rp_write %d chars...", count); @@ -1777,7 +1773,7 @@ end: wake_up_interruptible(&tty->poll_wait); #endif } - up(&info->write_sem); + mutex_unlock(&info->write_mtx); return retval; } @@ -1852,6 +1848,12 @@ static void rp_flush_buffer(struct tty_struct *tty) #ifdef CONFIG_PCI +static struct pci_device_id __devinitdata rocket_pci_ids[] = { + { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_ANY_ID) }, + { } +}; +MODULE_DEVICE_TABLE(pci, rocket_pci_ids); + /* * Called when a PCI card is found. Retrieves and stores model information, * init's aiopic and serial port hardware. diff --git a/drivers/char/rocket_int.h b/drivers/char/rocket_int.h index 3a8bcc85bc1..b4c53dfa795 100644 --- a/drivers/char/rocket_int.h +++ b/drivers/char/rocket_int.h @@ -15,6 +15,8 @@ #define ROCKET_TYPE_MODEMIII 3 #define ROCKET_TYPE_PC104 4 +#include <linux/mutex.h> + #include <asm/io.h> #include <asm/byteorder.h> @@ -1156,8 +1158,6 @@ struct r_port { int xmit_head; int xmit_tail; int xmit_cnt; - int session; - int pgrp; int cd_status; int ignore_status_mask; int read_status_mask; @@ -1171,7 +1171,7 @@ struct r_port { struct wait_queue *close_wait; #endif spinlock_t slock; - struct semaphore write_sem; + struct mutex write_mtx; }; #define RPORT_MAGIC 0x525001 diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c index c7dac9b1335..20380a2c4de 100644 --- a/drivers/char/rtc.c +++ b/drivers/char/rtc.c @@ -388,7 +388,7 @@ static ssize_t rtc_read(struct file *file, char __user *buf, if (!retval) retval = count; out: - current->state = TASK_RUNNING; + __set_current_state(TASK_RUNNING); remove_wait_queue(&rtc_wait, &wait); return retval; diff --git a/drivers/char/selection.c b/drivers/char/selection.c index 74cff839c85..a69f094d1ed 100644 --- a/drivers/char/selection.c +++ b/drivers/char/selection.c @@ -299,7 +299,7 @@ int paste_selection(struct tty_struct *tty) pasted += count; } remove_wait_queue(&vc->paste_wait, &wait); - current->state = TASK_RUNNING; + __set_current_state(TASK_RUNNING); tty_ldisc_deref(ld); return 0; diff --git a/drivers/char/serial167.c b/drivers/char/serial167.c index 5fd314adc1f..c585b4738f8 100644 --- a/drivers/char/serial167.c +++ b/drivers/char/serial167.c @@ -1892,7 +1892,7 @@ block_til_ready(struct tty_struct *tty, struct file *filp, #endif schedule(); } - current->state = TASK_RUNNING; + __set_current_state(TASK_RUNNING); remove_wait_queue(&info->open_wait, &wait); if (!tty_hung_up_p(filp)) { info->count++; diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c index ce4db6f5236..f02a0795983 100644 --- a/drivers/char/synclink.c +++ b/drivers/char/synclink.c @@ -4010,8 +4010,13 @@ static int mgsl_alloc_intermediate_txbuffer_memory(struct mgsl_struct *info) for ( i=0; i<info->num_tx_holding_buffers; ++i) { info->tx_holding_buffers[i].buffer = kmalloc(info->max_frame_size, GFP_KERNEL); - if ( info->tx_holding_buffers[i].buffer == NULL ) + if (info->tx_holding_buffers[i].buffer == NULL) { + for (--i; i >= 0; i--) { + kfree(info->tx_holding_buffers[i].buffer); + info->tx_holding_buffers[i].buffer = NULL; + } return -ENOMEM; + } } return 0; diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c index 0a367cd4121..02b49bc0002 100644 --- a/drivers/char/synclink_gt.c +++ b/drivers/char/synclink_gt.c @@ -1171,6 +1171,112 @@ static int ioctl(struct tty_struct *tty, struct file *file, } /* + * support for 32 bit ioctl calls on 64 bit systems + */ +#ifdef CONFIG_COMPAT +static long get_params32(struct slgt_info *info, struct MGSL_PARAMS32 __user *user_params) +{ + struct MGSL_PARAMS32 tmp_params; + + DBGINFO(("%s get_params32\n", info->device_name)); + tmp_params.mode = (compat_ulong_t)info->params.mode; + tmp_params.loopback = info->params.loopback; + tmp_params.flags = info->params.flags; + tmp_params.encoding = info->params.encoding; + tmp_params.clock_speed = (compat_ulong_t)info->params.clock_speed; + tmp_params.addr_filter = info->params.addr_filter; + tmp_params.crc_type = info->params.crc_type; + tmp_params.preamble_length = info->params.preamble_length; + tmp_params.preamble = info->params.preamble; + tmp_params.data_rate = (compat_ulong_t)info->params.data_rate; + tmp_params.data_bits = info->params.data_bits; + tmp_params.stop_bits = info->params.stop_bits; + tmp_params.parity = info->params.parity; + if (copy_to_user(user_params, &tmp_params, sizeof(struct MGSL_PARAMS32))) + return -EFAULT; + return 0; +} + +static long set_params32(struct slgt_info *info, struct MGSL_PARAMS32 __user *new_params) +{ + struct MGSL_PARAMS32 tmp_params; + + DBGINFO(("%s set_params32\n", info->device_name)); + if (copy_from_user(&tmp_params, new_params, sizeof(struct MGSL_PARAMS32))) + return -EFAULT; + + spin_lock(&info->lock); + info->params.mode = tmp_params.mode; + info->params.loopback = tmp_params.loopback; + info->params.flags = tmp_params.flags; + info->params.encoding = tmp_params.encoding; + info->params.clock_speed = tmp_params.clock_speed; + info->params.addr_filter = tmp_params.addr_filter; + info->params.crc_type = tmp_params.crc_type; + info->params.preamble_length = tmp_params.preamble_length; + info->params.preamble = tmp_params.preamble; + info->params.data_rate = tmp_params.data_rate; + info->params.data_bits = tmp_params.data_bits; + info->params.stop_bits = tmp_params.stop_bits; + info->params.parity = tmp_params.parity; + spin_unlock(&info->lock); + + change_params(info); + + return 0; +} + +static long slgt_compat_ioctl(struct tty_struct *tty, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct slgt_info *info = tty->driver_data; + int rc = -ENOIOCTLCMD; + + if (sanity_check(info, tty->name, "compat_ioctl")) + return -ENODEV; + DBGINFO(("%s compat_ioctl() cmd=%08X\n", info->device_name, cmd)); + + switch (cmd) { + + case MGSL_IOCSPARAMS32: + rc = set_params32(info, compat_ptr(arg)); + break; + + case MGSL_IOCGPARAMS32: + rc = get_params32(info, compat_ptr(arg)); + break; + + case MGSL_IOCGPARAMS: + case MGSL_IOCSPARAMS: + case MGSL_IOCGTXIDLE: + case MGSL_IOCGSTATS: + case MGSL_IOCWAITEVENT: + case MGSL_IOCGIF: + case MGSL_IOCSGPIO: + case MGSL_IOCGGPIO: + case MGSL_IOCWAITGPIO: + case TIOCGICOUNT: + rc = ioctl(tty, file, cmd, (unsigned long)(compat_ptr(arg))); + break; + + case MGSL_IOCSTXIDLE: + case MGSL_IOCTXENABLE: + case MGSL_IOCRXENABLE: + case MGSL_IOCTXABORT: + case TIOCMIWAIT: + case MGSL_IOCSIF: + rc = ioctl(tty, file, cmd, arg); + break; + } + + DBGINFO(("%s compat_ioctl() cmd=%08X rc=%d\n", info->device_name, cmd, rc)); + return rc; +} +#else +#define slgt_compat_ioctl NULL +#endif /* ifdef CONFIG_COMPAT */ + +/* * proc fs support */ static inline int line_info(char *buf, struct slgt_info *info) @@ -3415,6 +3521,9 @@ static void device_init(int adapter_num, struct pci_dev *pdev) } } } + + for (i=0; i < port_count; ++i) + tty_register_device(serial_driver, port_array[i]->line, &(port_array[i]->pdev->dev)); } static int __devinit init_one(struct pci_dev *dev, @@ -3443,6 +3552,7 @@ static const struct tty_operations ops = { .chars_in_buffer = chars_in_buffer, .flush_buffer = flush_buffer, .ioctl = ioctl, + .compat_ioctl = slgt_compat_ioctl, .throttle = throttle, .unthrottle = unthrottle, .send_xchar = send_xchar, @@ -3466,6 +3576,8 @@ static void slgt_cleanup(void) printk("unload %s %s\n", driver_name, driver_version); if (serial_driver) { + for (info=slgt_device_list ; info != NULL ; info=info->next_device) + tty_unregister_device(serial_driver, info->line); if ((rc = tty_unregister_driver(serial_driver))) DBGERR(("tty_unregister_driver error=%d\n", rc)); put_tty_driver(serial_driver); @@ -3506,23 +3618,10 @@ static int __init slgt_init(void) printk("%s %s\n", driver_name, driver_version); - slgt_device_count = 0; - if ((rc = pci_register_driver(&pci_driver)) < 0) { - printk("%s pci_register_driver error=%d\n", driver_name, rc); - return rc; - } - pci_registered = 1; - - if (!slgt_device_list) { - printk("%s no devices found\n",driver_name); - pci_unregister_driver(&pci_driver); - return -ENODEV; - } - serial_driver = alloc_tty_driver(MAX_DEVICES); if (!serial_driver) { - rc = -ENOMEM; - goto error; + printk("%s can't allocate tty driver\n", driver_name); + return -ENOMEM; } /* Initialize the tty_driver structure */ @@ -3539,7 +3638,7 @@ static int __init slgt_init(void) B9600 | CS8 | CREAD | HUPCL | CLOCAL; serial_driver->init_termios.c_ispeed = 9600; serial_driver->init_termios.c_ospeed = 9600; - serial_driver->flags = TTY_DRIVER_REAL_RAW; + serial_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; tty_set_operations(serial_driver, &ops); if ((rc = tty_register_driver(serial_driver)) < 0) { DBGERR(("%s can't register serial driver\n", driver_name)); @@ -3552,6 +3651,16 @@ static int __init slgt_init(void) driver_name, driver_version, serial_driver->major); + slgt_device_count = 0; + if ((rc = pci_register_driver(&pci_driver)) < 0) { + printk("%s pci_register_driver error=%d\n", driver_name, rc); + goto error; + } + pci_registered = 1; + + if (!slgt_device_list) + printk("%s no devices found\n",driver_name); + return 0; error: diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c index 1d8c4ae6155..39cc318011e 100644 --- a/drivers/char/sysrq.c +++ b/drivers/char/sysrq.c @@ -24,7 +24,6 @@ #include <linux/sysrq.h> #include <linux/kbd_kern.h> #include <linux/quotaops.h> -#include <linux/smp_lock.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/suspend.h> diff --git a/drivers/char/tipar.c b/drivers/char/tipar.c index 47fb20f6969..35b40b99653 100644 --- a/drivers/char/tipar.c +++ b/drivers/char/tipar.c @@ -442,7 +442,7 @@ tipar_register(int nr, struct parport *port) } class_device_create(tipar_class, NULL, MKDEV(TIPAR_MAJOR, - TIPAR_MINOR + nr), NULL, "par%d", nr); + TIPAR_MINOR + nr), port->dev, "par%d", nr); /* Display informations */ pr_info("tipar%d: using %s (%s)\n", nr, port->name, (port->irq == diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig index fe00c7dfb64..dc4e1ff7f56 100644 --- a/drivers/char/tpm/Kconfig +++ b/drivers/char/tpm/Kconfig @@ -3,6 +3,7 @@ # menu "TPM devices" + depends on HAS_IOMEM config TCG_TPM tristate "TPM Hardware Support" @@ -33,7 +34,7 @@ config TCG_NSC tristate "National Semiconductor TPM Interface" depends on TCG_TPM && PNPACPI ---help--- - If you have a TPM security chip from National Semicondutor + If you have a TPM security chip from National Semiconductor say Yes and it will be accessible from within Linux. To compile this driver as a module, choose M here; the module will be called tpm_nsc. diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index e5a254a434f..9bb542913b8 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c @@ -24,7 +24,9 @@ */ #include <linux/poll.h> +#include <linux/mutex.h> #include <linux/spinlock.h> + #include "tpm.h" enum tpm_const { @@ -328,10 +330,10 @@ static void timeout_work(struct work_struct *work) { struct tpm_chip *chip = container_of(work, struct tpm_chip, work); - down(&chip->buffer_mutex); + mutex_lock(&chip->buffer_mutex); atomic_set(&chip->data_pending, 0); memset(chip->data_buffer, 0, TPM_BUFSIZE); - up(&chip->buffer_mutex); + mutex_unlock(&chip->buffer_mutex); } /* @@ -380,7 +382,7 @@ static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, return -E2BIG; } - down(&chip->tpm_mutex); + mutex_lock(&chip->tpm_mutex); if ((rc = chip->vendor.send(chip, (u8 *) buf, count)) < 0) { dev_err(chip->dev, @@ -419,7 +421,7 @@ out_recv: dev_err(chip->dev, "tpm_transmit: tpm_recv: error %zd\n", rc); out: - up(&chip->tpm_mutex); + mutex_unlock(&chip->tpm_mutex); return rc; } @@ -942,12 +944,12 @@ int tpm_release(struct inode *inode, struct file *file) { struct tpm_chip *chip = file->private_data; + flush_scheduled_work(); spin_lock(&driver_lock); file->private_data = NULL; - chip->num_opens--; del_singleshot_timer_sync(&chip->user_read_timer); - flush_scheduled_work(); atomic_set(&chip->data_pending, 0); + chip->num_opens--; put_device(chip->dev); kfree(chip->data_buffer); spin_unlock(&driver_lock); @@ -966,14 +968,14 @@ ssize_t tpm_write(struct file *file, const char __user *buf, while (atomic_read(&chip->data_pending) != 0) msleep(TPM_TIMEOUT); - down(&chip->buffer_mutex); + mutex_lock(&chip->buffer_mutex); if (in_size > TPM_BUFSIZE) in_size = TPM_BUFSIZE; if (copy_from_user (chip->data_buffer, (void __user *) buf, in_size)) { - up(&chip->buffer_mutex); + mutex_unlock(&chip->buffer_mutex); return -EFAULT; } @@ -981,7 +983,7 @@ ssize_t tpm_write(struct file *file, const char __user *buf, out_size = tpm_transmit(chip, chip->data_buffer, TPM_BUFSIZE); atomic_set(&chip->data_pending, out_size); - up(&chip->buffer_mutex); + mutex_unlock(&chip->buffer_mutex); /* Set a timeout by which the reader must come claim the result */ mod_timer(&chip->user_read_timer, jiffies + (60 * HZ)); @@ -1004,10 +1006,10 @@ ssize_t tpm_read(struct file *file, char __user *buf, if (size < ret_size) ret_size = size; - down(&chip->buffer_mutex); + mutex_lock(&chip->buffer_mutex); if (copy_to_user(buf, chip->data_buffer, ret_size)) ret_size = -EFAULT; - up(&chip->buffer_mutex); + mutex_unlock(&chip->buffer_mutex); } return ret_size; @@ -1097,11 +1099,16 @@ struct tpm_chip *tpm_register_hardware(struct device *dev, const struct tpm_vend /* Driver specific per-device data */ chip = kzalloc(sizeof(*chip), GFP_KERNEL); - if (chip == NULL) + devname = kmalloc(DEVNAME_SIZE, GFP_KERNEL); + + if (chip == NULL || devname == NULL) { + kfree(chip); + kfree(devname); return NULL; + } - init_MUTEX(&chip->buffer_mutex); - init_MUTEX(&chip->tpm_mutex); + mutex_init(&chip->buffer_mutex); + mutex_init(&chip->tpm_mutex); INIT_LIST_HEAD(&chip->list); INIT_WORK(&chip->work, timeout_work); @@ -1124,7 +1131,6 @@ struct tpm_chip *tpm_register_hardware(struct device *dev, const struct tpm_vend set_bit(chip->dev_num, dev_mask); - devname = kmalloc(DEVNAME_SIZE, GFP_KERNEL); scnprintf(devname, DEVNAME_SIZE, "%s%d", "tpm", chip->dev_num); chip->vendor.miscdev.name = devname; diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index bb9a43c6cf3..b2e2b002a1b 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -19,9 +19,9 @@ * */ #include <linux/module.h> -#include <linux/pci.h> #include <linux/delay.h> #include <linux/fs.h> +#include <linux/mutex.h> #include <linux/sched.h> #include <linux/miscdevice.h> #include <linux/platform_device.h> @@ -95,11 +95,11 @@ struct tpm_chip { /* Data passed to and from the tpm via the read/write calls */ u8 *data_buffer; atomic_t data_pending; - struct semaphore buffer_mutex; + struct mutex buffer_mutex; struct timer_list user_read_timer; /* user needs to claim result */ struct work_struct work; - struct semaphore tpm_mutex; /* tpm is processing */ + struct mutex tpm_mutex; /* tpm is processing */ struct tpm_vendor_specific vendor; diff --git a/drivers/char/tpm/tpm_atmel.h b/drivers/char/tpm/tpm_atmel.h index 3c852009196..c912d8691cb 100644 --- a/drivers/char/tpm/tpm_atmel.h +++ b/drivers/char/tpm/tpm_atmel.h @@ -47,12 +47,12 @@ static void __iomem * atmel_get_base_addr(unsigned long *base, int *region_size) if (!dn) return NULL; - if (!device_is_compatible(dn, "AT97SC3201")) { + if (!of_device_is_compatible(dn, "AT97SC3201")) { of_node_put(dn); return NULL; } - reg = get_property(dn, "reg", ®len); + reg = of_get_property(dn, "reg", ®len); naddrc = of_n_addr_cells(dn); nsizec = of_n_size_cells(dn); diff --git a/drivers/char/tpm/tpm_infineon.c b/drivers/char/tpm/tpm_infineon.c index 1353b5a6bae..967002a5a1e 100644 --- a/drivers/char/tpm/tpm_infineon.c +++ b/drivers/char/tpm/tpm_infineon.c @@ -30,12 +30,60 @@ #define TPM_MAX_TRIES 5000 #define TPM_INFINEON_DEV_VEN_VALUE 0x15D1 -/* These values will be filled after PnP-call */ -static int TPM_INF_DATA; -static int TPM_INF_ADDR; -static int TPM_INF_BASE; -static int TPM_INF_ADDR_LEN; -static int TPM_INF_PORT_LEN; +#define TPM_INF_IO_PORT 0x0 +#define TPM_INF_IO_MEM 0x1 + +#define TPM_INF_ADDR 0x0 +#define TPM_INF_DATA 0x1 + +struct tpm_inf_dev { + int iotype; + + void __iomem *mem_base; /* MMIO ioremap'd addr */ + unsigned long map_base; /* phys MMIO base */ + unsigned long map_size; /* MMIO region size */ + unsigned int index_off; /* index register offset */ + + unsigned int data_regs; /* Data registers */ + unsigned int data_size; + + unsigned int config_port; /* IO Port config index reg */ + unsigned int config_size; +}; + +static struct tpm_inf_dev tpm_dev; + +static inline void tpm_data_out(unsigned char data, unsigned char offset) +{ + if (tpm_dev.iotype == TPM_INF_IO_PORT) + outb(data, tpm_dev.data_regs + offset); + else + writeb(data, tpm_dev.mem_base + tpm_dev.data_regs + offset); +} + +static inline unsigned char tpm_data_in(unsigned char offset) +{ + if (tpm_dev.iotype == TPM_INF_IO_PORT) + return inb(tpm_dev.data_regs + offset); + else + return readb(tpm_dev.mem_base + tpm_dev.data_regs + offset); +} + +static inline void tpm_config_out(unsigned char data, unsigned char offset) +{ + if (tpm_dev.iotype == TPM_INF_IO_PORT) + outb(data, tpm_dev.config_port + offset); + else + writeb(data, tpm_dev.mem_base + tpm_dev.index_off + offset); +} + +static inline unsigned char tpm_config_in(unsigned char offset) +{ + if (tpm_dev.iotype == TPM_INF_IO_PORT) + return inb(tpm_dev.config_port + offset); + else + return readb(tpm_dev.mem_base + tpm_dev.index_off + offset); +} /* TPM header definitions */ enum infineon_tpm_header { @@ -105,7 +153,7 @@ static int empty_fifo(struct tpm_chip *chip, int clear_wrfifo) if (clear_wrfifo) { for (i = 0; i < 4096; i++) { - status = inb(chip->vendor.base + WRFIFO); + status = tpm_data_in(WRFIFO); if (status == 0xff) { if (check == 5) break; @@ -125,8 +173,8 @@ static int empty_fifo(struct tpm_chip *chip, int clear_wrfifo) */ i = 0; do { - status = inb(chip->vendor.base + RDFIFO); - status = inb(chip->vendor.base + STAT); + status = tpm_data_in(RDFIFO); + status = tpm_data_in(STAT); i++; if (i == TPM_MAX_TRIES) return -EIO; @@ -139,7 +187,7 @@ static int wait(struct tpm_chip *chip, int wait_for_bit) int status; int i; for (i = 0; i < TPM_MAX_TRIES; i++) { - status = inb(chip->vendor.base + STAT); + status = tpm_data_in(STAT); /* check the status-register if wait_for_bit is set */ if (status & 1 << wait_for_bit) break; @@ -158,7 +206,7 @@ static int wait(struct tpm_chip *chip, int wait_for_bit) static void wait_and_send(struct tpm_chip *chip, u8 sendbyte) { wait(chip, STAT_XFE); - outb(sendbyte, chip->vendor.base + WRFIFO); + tpm_data_out(sendbyte, WRFIFO); } /* Note: WTX means Waiting-Time-Extension. Whenever the TPM needs more @@ -205,7 +253,7 @@ recv_begin: ret = wait(chip, STAT_RDA); if (ret) return -EIO; - buf[i] = inb(chip->vendor.base + RDFIFO); + buf[i] = tpm_data_in(RDFIFO); } if (buf[0] != TPM_VL_VER) { @@ -220,7 +268,7 @@ recv_begin: for (i = 0; i < size; i++) { wait(chip, STAT_RDA); - buf[i] = inb(chip->vendor.base + RDFIFO); + buf[i] = tpm_data_in(RDFIFO); } if ((size == 0x6D00) && (buf[1] == 0x80)) { @@ -269,7 +317,7 @@ static int tpm_inf_send(struct tpm_chip *chip, u8 * buf, size_t count) u8 count_high, count_low, count_4, count_3, count_2, count_1; /* Disabling Reset, LP and IRQC */ - outb(RESET_LP_IRQC_DISABLE, chip->vendor.base + CMD); + tpm_data_out(RESET_LP_IRQC_DISABLE, CMD); ret = empty_fifo(chip, 1); if (ret) { @@ -320,7 +368,7 @@ static void tpm_inf_cancel(struct tpm_chip *chip) static u8 tpm_inf_status(struct tpm_chip *chip) { - return inb(chip->vendor.base + STAT); + return tpm_data_in(STAT); } static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL); @@ -381,51 +429,88 @@ static int __devinit tpm_inf_pnp_probe(struct pnp_dev *dev, /* read IO-ports through PnP */ if (pnp_port_valid(dev, 0) && pnp_port_valid(dev, 1) && !(pnp_port_flags(dev, 0) & IORESOURCE_DISABLED)) { - TPM_INF_ADDR = pnp_port_start(dev, 0); - TPM_INF_ADDR_LEN = pnp_port_len(dev, 0); - TPM_INF_DATA = (TPM_INF_ADDR + 1); - TPM_INF_BASE = pnp_port_start(dev, 1); - TPM_INF_PORT_LEN = pnp_port_len(dev, 1); - if ((TPM_INF_PORT_LEN < 4) || (TPM_INF_ADDR_LEN < 2)) { + + tpm_dev.iotype = TPM_INF_IO_PORT; + + tpm_dev.config_port = pnp_port_start(dev, 0); + tpm_dev.config_size = pnp_port_len(dev, 0); + tpm_dev.data_regs = pnp_port_start(dev, 1); + tpm_dev.data_size = pnp_port_len(dev, 1); + if ((tpm_dev.data_size < 4) || (tpm_dev.config_size < 2)) { rc = -EINVAL; goto err_last; } dev_info(&dev->dev, "Found %s with ID %s\n", dev->name, dev_id->id); - if (!((TPM_INF_BASE >> 8) & 0xff)) { + if (!((tpm_dev.data_regs >> 8) & 0xff)) { rc = -EINVAL; goto err_last; } /* publish my base address and request region */ - if (request_region - (TPM_INF_BASE, TPM_INF_PORT_LEN, "tpm_infineon0") == NULL) { + if (request_region(tpm_dev.data_regs, tpm_dev.data_size, + "tpm_infineon0") == NULL) { rc = -EINVAL; goto err_last; } - if (request_region - (TPM_INF_ADDR, TPM_INF_ADDR_LEN, "tpm_infineon0") == NULL) { + if (request_region(tpm_dev.config_port, tpm_dev.config_size, + "tpm_infineon0") == NULL) { + release_region(tpm_dev.data_regs, tpm_dev.data_size); rc = -EINVAL; goto err_last; } + } else if (pnp_mem_valid(dev, 0) && + !(pnp_mem_flags(dev, 0) & IORESOURCE_DISABLED)) { + + tpm_dev.iotype = TPM_INF_IO_MEM; + + tpm_dev.map_base = pnp_mem_start(dev, 0); + tpm_dev.map_size = pnp_mem_len(dev, 0); + + dev_info(&dev->dev, "Found %s with ID %s\n", + dev->name, dev_id->id); + + /* publish my base address and request region */ + if (request_mem_region(tpm_dev.map_base, tpm_dev.map_size, + "tpm_infineon0") == NULL) { + rc = -EINVAL; + goto err_last; + } + + tpm_dev.mem_base = ioremap(tpm_dev.map_base, tpm_dev.map_size); + if (tpm_dev.mem_base == NULL) { + release_mem_region(tpm_dev.map_base, tpm_dev.map_size); + rc = -EINVAL; + goto err_last; + } + + /* + * The only known MMIO based Infineon TPM system provides + * a single large mem region with the device config + * registers at the default TPM_ADDR. The data registers + * seem like they could be placed anywhere within the MMIO + * region, but lets just put them at zero offset. + */ + tpm_dev.index_off = TPM_ADDR; + tpm_dev.data_regs = 0x0; } else { rc = -EINVAL; goto err_last; } /* query chip for its vendor, its version number a.s.o. */ - outb(ENABLE_REGISTER_PAIR, TPM_INF_ADDR); - outb(IDVENL, TPM_INF_ADDR); - vendorid[1] = inb(TPM_INF_DATA); - outb(IDVENH, TPM_INF_ADDR); - vendorid[0] = inb(TPM_INF_DATA); - outb(IDPDL, TPM_INF_ADDR); - productid[1] = inb(TPM_INF_DATA); - outb(IDPDH, TPM_INF_ADDR); - productid[0] = inb(TPM_INF_DATA); - outb(CHIP_ID1, TPM_INF_ADDR); - version[1] = inb(TPM_INF_DATA); - outb(CHIP_ID2, TPM_INF_ADDR); - version[0] = inb(TPM_INF_DATA); + tpm_config_out(ENABLE_REGISTER_PAIR, TPM_INF_ADDR); + tpm_config_out(IDVENL, TPM_INF_ADDR); + vendorid[1] = tpm_config_in(TPM_INF_DATA); + tpm_config_out(IDVENH, TPM_INF_ADDR); + vendorid[0] = tpm_config_in(TPM_INF_DATA); + tpm_config_out(IDPDL, TPM_INF_ADDR); + productid[1] = tpm_config_in(TPM_INF_DATA); + tpm_config_out(IDPDH, TPM_INF_ADDR); + productid[0] = tpm_config_in(TPM_INF_DATA); + tpm_config_out(CHIP_ID1, TPM_INF_ADDR); + version[1] = tpm_config_in(TPM_INF_DATA); + tpm_config_out(CHIP_ID2, TPM_INF_ADDR); + version[0] = tpm_config_in(TPM_INF_DATA); switch ((productid[0] << 8) | productid[1]) { case 6: @@ -442,51 +527,54 @@ static int __devinit tpm_inf_pnp_probe(struct pnp_dev *dev, if ((vendorid[0] << 8 | vendorid[1]) == (TPM_INFINEON_DEV_VEN_VALUE)) { /* configure TPM with IO-ports */ - outb(IOLIMH, TPM_INF_ADDR); - outb(((TPM_INF_BASE >> 8) & 0xff), TPM_INF_DATA); - outb(IOLIML, TPM_INF_ADDR); - outb((TPM_INF_BASE & 0xff), TPM_INF_DATA); + tpm_config_out(IOLIMH, TPM_INF_ADDR); + tpm_config_out((tpm_dev.data_regs >> 8) & 0xff, TPM_INF_DATA); + tpm_config_out(IOLIML, TPM_INF_ADDR); + tpm_config_out((tpm_dev.data_regs & 0xff), TPM_INF_DATA); /* control if IO-ports are set correctly */ - outb(IOLIMH, TPM_INF_ADDR); - ioh = inb(TPM_INF_DATA); - outb(IOLIML, TPM_INF_ADDR); - iol = inb(TPM_INF_DATA); + tpm_config_out(IOLIMH, TPM_INF_ADDR); + ioh = tpm_config_in(TPM_INF_DATA); + tpm_config_out(IOLIML, TPM_INF_ADDR); + iol = tpm_config_in(TPM_INF_DATA); - if ((ioh << 8 | iol) != TPM_INF_BASE) { + if ((ioh << 8 | iol) != tpm_dev.data_regs) { dev_err(&dev->dev, - "Could not set IO-ports to 0x%x\n", - TPM_INF_BASE); + "Could not set IO-data registers to 0x%x\n", + tpm_dev.data_regs); rc = -EIO; goto err_release_region; } /* activate register */ - outb(TPM_DAR, TPM_INF_ADDR); - outb(0x01, TPM_INF_DATA); - outb(DISABLE_REGISTER_PAIR, TPM_INF_ADDR); + tpm_config_out(TPM_DAR, TPM_INF_ADDR); + tpm_config_out(0x01, TPM_INF_DATA); + tpm_config_out(DISABLE_REGISTER_PAIR, TPM_INF_ADDR); /* disable RESET, LP and IRQC */ - outb(RESET_LP_IRQC_DISABLE, TPM_INF_BASE + CMD); + tpm_data_out(RESET_LP_IRQC_DISABLE, CMD); /* Finally, we're done, print some infos */ dev_info(&dev->dev, "TPM found: " - "config base 0x%x, " - "io base 0x%x, " + "config base 0x%lx, " + "data base 0x%lx, " "chip version 0x%02x%02x, " "vendor id 0x%x%x (Infineon), " "product id 0x%02x%02x" "%s\n", - TPM_INF_ADDR, - TPM_INF_BASE, + tpm_dev.iotype == TPM_INF_IO_PORT ? + tpm_dev.config_port : + tpm_dev.map_base + tpm_dev.index_off, + tpm_dev.iotype == TPM_INF_IO_PORT ? + tpm_dev.data_regs : + tpm_dev.map_base + tpm_dev.data_regs, version[0], version[1], vendorid[0], vendorid[1], productid[0], productid[1], chipname); - if (!(chip = tpm_register_hardware(&dev->dev, &tpm_inf))) { + if (!(chip = tpm_register_hardware(&dev->dev, &tpm_inf))) goto err_release_region; - } - chip->vendor.base = TPM_INF_BASE; + return 0; } else { rc = -ENODEV; @@ -494,8 +582,13 @@ static int __devinit tpm_inf_pnp_probe(struct pnp_dev *dev, } err_release_region: - release_region(TPM_INF_BASE, TPM_INF_PORT_LEN); - release_region(TPM_INF_ADDR, TPM_INF_ADDR_LEN); + if (tpm_dev.iotype == TPM_INF_IO_PORT) { + release_region(tpm_dev.data_regs, tpm_dev.data_size); + release_region(tpm_dev.config_port, tpm_dev.config_size); + } else { + iounmap(tpm_dev.mem_base); + release_mem_region(tpm_dev.map_base, tpm_dev.map_size); + } err_last: return rc; @@ -506,8 +599,14 @@ static __devexit void tpm_inf_pnp_remove(struct pnp_dev *dev) struct tpm_chip *chip = pnp_get_drvdata(dev); if (chip) { - release_region(TPM_INF_BASE, TPM_INF_PORT_LEN); - release_region(TPM_INF_ADDR, TPM_INF_ADDR_LEN); + if (tpm_dev.iotype == TPM_INF_IO_PORT) { + release_region(tpm_dev.data_regs, tpm_dev.data_size); + release_region(tpm_dev.config_port, + tpm_dev.config_size); + } else { + iounmap(tpm_dev.mem_base); + release_mem_region(tpm_dev.map_base, tpm_dev.map_size); + } tpm_remove_hardware(chip->dev); } } @@ -539,5 +638,5 @@ module_exit(cleanup_inf); MODULE_AUTHOR("Marcel Selhorst <selhorst@crypto.rub.de>"); MODULE_DESCRIPTION("Driver for Infineon TPM SLD 9630 TT 1.1 / SLB 9635 TT 1.2"); -MODULE_VERSION("1.8"); +MODULE_VERSION("1.9"); MODULE_LICENSE("GPL"); diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 7a32df59490..fe62c2170d0 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -141,8 +141,6 @@ static DECLARE_MUTEX(allocated_ptys_lock); static int ptmx_open(struct inode *, struct file *); #endif -extern void disable_early_printk(void); - static void initialize_tty_struct(struct tty_struct *tty); static ssize_t tty_read(struct file *, char __user *, size_t, loff_t *); @@ -153,10 +151,16 @@ static int tty_open(struct inode *, struct file *); static int tty_release(struct inode *, struct file *); int tty_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg); +#ifdef CONFIG_COMPAT +static long tty_compat_ioctl(struct file * file, unsigned int cmd, + unsigned long arg); +#else +#define tty_compat_ioctl NULL +#endif static int tty_fasync(int fd, struct file * filp, int on); static void release_tty(struct tty_struct *tty, int idx); -static struct pid *__proc_set_tty(struct task_struct *tsk, - struct tty_struct *tty); +static void __proc_set_tty(struct task_struct *tsk, struct tty_struct *tty); +static void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty); /** * alloc_tty_struct - allocate a tty object @@ -936,13 +940,6 @@ restart: return -EINVAL; /* - * No more input please, we are switching. The new ldisc - * will update this value in the ldisc open function - */ - - tty->receive_room = 0; - - /* * Problem: What do we do if this blocks ? */ @@ -953,6 +950,13 @@ restart: return 0; } + /* + * No more input please, we are switching. The new ldisc + * will update this value in the ldisc open function + */ + + tty->receive_room = 0; + o_ldisc = tty->ldisc; o_tty = tty->link; @@ -1145,8 +1149,8 @@ static unsigned int hung_up_tty_poll(struct file * filp, poll_table * wait) return POLLIN | POLLOUT | POLLERR | POLLHUP | POLLRDNORM | POLLWRNORM; } -static int hung_up_tty_ioctl(struct inode * inode, struct file * file, - unsigned int cmd, unsigned long arg) +static long hung_up_tty_ioctl(struct file * file, + unsigned int cmd, unsigned long arg) { return cmd == TIOCSPGRP ? -ENOTTY : -EIO; } @@ -1157,6 +1161,7 @@ static const struct file_operations tty_fops = { .write = tty_write, .poll = tty_poll, .ioctl = tty_ioctl, + .compat_ioctl = tty_compat_ioctl, .open = tty_open, .release = tty_release, .fasync = tty_fasync, @@ -1169,6 +1174,7 @@ static const struct file_operations ptmx_fops = { .write = tty_write, .poll = tty_poll, .ioctl = tty_ioctl, + .compat_ioctl = tty_compat_ioctl, .open = ptmx_open, .release = tty_release, .fasync = tty_fasync, @@ -1181,6 +1187,7 @@ static const struct file_operations console_fops = { .write = redirected_tty_write, .poll = tty_poll, .ioctl = tty_ioctl, + .compat_ioctl = tty_compat_ioctl, .open = tty_open, .release = tty_release, .fasync = tty_fasync, @@ -1191,7 +1198,8 @@ static const struct file_operations hung_up_tty_fops = { .read = hung_up_tty_read, .write = hung_up_tty_write, .poll = hung_up_tty_poll, - .ioctl = hung_up_tty_ioctl, + .unlocked_ioctl = hung_up_tty_ioctl, + .compat_ioctl = hung_up_tty_ioctl, .release = tty_release, }; @@ -1534,10 +1542,9 @@ void disassociate_ctty(int on_exit) } spin_lock_irq(¤t->sighand->siglock); - tty_pgrp = current->signal->tty_old_pgrp; + put_pid(current->signal->tty_old_pgrp); current->signal->tty_old_pgrp = NULL; spin_unlock_irq(¤t->sighand->siglock); - put_pid(tty_pgrp); mutex_lock(&tty_mutex); /* It is possible that do_tty_hangup has free'd this tty */ @@ -1562,13 +1569,25 @@ void disassociate_ctty(int on_exit) unlock_kernel(); } +/** + * + * no_tty - Ensure the current process does not have a controlling tty + */ +void no_tty(void) +{ + struct task_struct *tsk = current; + if (tsk->signal->leader) + disassociate_ctty(0); + proc_clear_tty(tsk); +} + /** - * stop_tty - propogate flow control + * stop_tty - propagate flow control * @tty: tty to stop * * Perform flow control to the driver. For PTY/TTY pairs we - * must also propogate the TIOCKPKT status. May be called + * must also propagate the TIOCKPKT status. May be called * on an already stopped device and will not re-call the driver * method. * @@ -1598,11 +1617,11 @@ void stop_tty(struct tty_struct *tty) EXPORT_SYMBOL(stop_tty); /** - * start_tty - propogate flow control + * start_tty - propagate flow control * @tty: tty to start * * Start a tty that has been stopped if at all possible. Perform - * any neccessary wakeups and propogate the TIOCPKT status. If this + * any neccessary wakeups and propagate the TIOCPKT status. If this * is the tty was previous stopped and is being started then the * driver start method is invoked and the line discipline woken. * @@ -2508,7 +2527,6 @@ static int tty_open(struct inode * inode, struct file * filp) int index; dev_t device = inode->i_rdev; unsigned short saved_flags = filp->f_flags; - struct pid *old_pgrp; nonseekable_open(inode, filp); @@ -2602,17 +2620,15 @@ got_driver: goto retry_open; } - old_pgrp = NULL; mutex_lock(&tty_mutex); spin_lock_irq(¤t->sighand->siglock); if (!noctty && current->signal->leader && !current->signal->tty && tty->session == NULL) - old_pgrp = __proc_set_tty(current, tty); + __proc_set_tty(current, tty); spin_unlock_irq(¤t->sighand->siglock); mutex_unlock(&tty_mutex); - put_pid(old_pgrp); return 0; } @@ -3287,9 +3303,7 @@ int tty_ioctl(struct inode * inode, struct file * file, case TIOCNOTTY: if (current->signal->tty != tty) return -ENOTTY; - if (current->signal->leader) - disassociate_ctty(0); - proc_clear_tty(current); + no_tty(); return 0; case TIOCSCTTY: return tiocsctty(tty, arg); @@ -3353,6 +3367,32 @@ int tty_ioctl(struct inode * inode, struct file * file, return retval; } +#ifdef CONFIG_COMPAT +static long tty_compat_ioctl(struct file * file, unsigned int cmd, + unsigned long arg) +{ + struct inode *inode = file->f_dentry->d_inode; + struct tty_struct *tty = file->private_data; + struct tty_ldisc *ld; + int retval = -ENOIOCTLCMD; + + if (tty_paranoia_check(tty, inode, "tty_ioctl")) + return -EINVAL; + + if (tty->driver->compat_ioctl) { + retval = (tty->driver->compat_ioctl)(tty, file, cmd, arg); + if (retval != -ENOIOCTLCMD) + return retval; + } + + ld = tty_ldisc_ref_wait(tty); + if (ld->compat_ioctl) + retval = ld->compat_ioctl(tty, file, cmd, arg); + tty_ldisc_deref(ld); + + return retval; +} +#endif /* * This implements the "Secure Attention Key" --- the idea is to @@ -3685,6 +3725,7 @@ void tty_set_operations(struct tty_driver *driver, driver->write_room = op->write_room; driver->chars_in_buffer = op->chars_in_buffer; driver->ioctl = op->ioctl; + driver->compat_ioctl = op->compat_ioctl; driver->set_termios = op->set_termios; driver->throttle = op->throttle; driver->unthrottle = op->unthrottle; @@ -3720,11 +3761,10 @@ int tty_register_driver(struct tty_driver *driver) if (driver->flags & TTY_DRIVER_INSTALLED) return 0; - if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM)) { - p = kmalloc(driver->num * 3 * sizeof(void *), GFP_KERNEL); + if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM) && driver->num) { + p = kzalloc(driver->num * 3 * sizeof(void *), GFP_KERNEL); if (!p) return -ENOMEM; - memset(p, 0, driver->num * 3 * sizeof(void *)); } if (!driver->major) { @@ -3767,7 +3807,9 @@ int tty_register_driver(struct tty_driver *driver) if (!driver->put_char) driver->put_char = tty_default_put_char; + mutex_lock(&tty_mutex); list_add(&driver->tty_drivers, &tty_drivers); + mutex_unlock(&tty_mutex); if ( !(driver->flags & TTY_DRIVER_DYNAMIC_DEV) ) { for(i = 0; i < driver->num; i++) @@ -3793,8 +3835,9 @@ int tty_unregister_driver(struct tty_driver *driver) unregister_chrdev_region(MKDEV(driver->major, driver->minor_start), driver->num); - + mutex_lock(&tty_mutex); list_del(&driver->tty_drivers); + mutex_unlock(&tty_mutex); /* * Free the termios and termios_locked structures because @@ -3837,11 +3880,9 @@ void proc_clear_tty(struct task_struct *p) p->signal->tty = NULL; spin_unlock_irq(&p->sighand->siglock); } -EXPORT_SYMBOL(proc_clear_tty); -static struct pid *__proc_set_tty(struct task_struct *tsk, struct tty_struct *tty) +static void __proc_set_tty(struct task_struct *tsk, struct tty_struct *tty) { - struct pid *old_pgrp; if (tty) { /* We should not have a session or pgrp to here but.... */ put_pid(tty->session); @@ -3849,21 +3890,16 @@ static struct pid *__proc_set_tty(struct task_struct *tsk, struct tty_struct *tt tty->session = get_pid(task_session(tsk)); tty->pgrp = get_pid(task_pgrp(tsk)); } - old_pgrp = tsk->signal->tty_old_pgrp; + put_pid(tsk->signal->tty_old_pgrp); tsk->signal->tty = tty; tsk->signal->tty_old_pgrp = NULL; - return old_pgrp; } -void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty) +static void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty) { - struct pid *old_pgrp; - spin_lock_irq(&tsk->sighand->siglock); - old_pgrp = __proc_set_tty(tsk, tty); + __proc_set_tty(tsk, tty); spin_unlock_irq(&tsk->sighand->siglock); - - put_pid(old_pgrp); } struct tty_struct *get_current_tty(void) @@ -3898,9 +3934,6 @@ void __init console_init(void) * set up the console device so that later boot sequences can * inform about problems etc.. */ -#ifdef CONFIG_EARLY_PRINTK - disable_early_printk(); -#endif call = __con_initcall_start; while (call < __con_initcall_end) { (*call)(); diff --git a/drivers/char/vc_screen.c b/drivers/char/vc_screen.c index 791930320a1..83aeedda200 100644 --- a/drivers/char/vc_screen.c +++ b/drivers/char/vc_screen.c @@ -28,12 +28,13 @@ #include <linux/interrupt.h> #include <linux/mm.h> #include <linux/init.h> +#include <linux/mutex.h> #include <linux/vt_kern.h> #include <linux/selection.h> #include <linux/kbd_kern.h> #include <linux/console.h> -#include <linux/smp_lock.h> #include <linux/device.h> + #include <asm/uaccess.h> #include <asm/byteorder.h> #include <asm/unaligned.h> @@ -70,11 +71,11 @@ static loff_t vcs_lseek(struct file *file, loff_t offset, int orig) { int size; - down(&con_buf_sem); + mutex_lock(&con_buf_mtx); size = vcs_size(file->f_path.dentry->d_inode); switch (orig) { default: - up(&con_buf_sem); + mutex_unlock(&con_buf_mtx); return -EINVAL; case 2: offset += size; @@ -85,11 +86,11 @@ static loff_t vcs_lseek(struct file *file, loff_t offset, int orig) break; } if (offset < 0 || offset > size) { - up(&con_buf_sem); + mutex_unlock(&con_buf_mtx); return -EINVAL; } file->f_pos = offset; - up(&con_buf_sem); + mutex_unlock(&con_buf_mtx); return file->f_pos; } @@ -106,7 +107,7 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) unsigned short *org = NULL; ssize_t ret; - down(&con_buf_sem); + mutex_lock(&con_buf_mtx); pos = *ppos; @@ -263,7 +264,7 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) ret = read; unlock_out: release_console_sem(); - up(&con_buf_sem); + mutex_unlock(&con_buf_mtx); return ret; } @@ -280,7 +281,7 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) u16 *org0 = NULL, *org = NULL; size_t ret; - down(&con_buf_sem); + mutex_lock(&con_buf_mtx); pos = *ppos; @@ -450,7 +451,7 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) unlock_out: release_console_sem(); - up(&con_buf_sem); + mutex_unlock(&con_buf_mtx); return ret; } diff --git a/drivers/char/vt.c b/drivers/char/vt.c index 1bbb45b937f..bbd9fc41287 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c @@ -86,6 +86,7 @@ #include <linux/mm.h> #include <linux/console.h> #include <linux/init.h> +#include <linux/mutex.h> #include <linux/vt_kern.h> #include <linux/selection.h> #include <linux/tiocl.h> @@ -157,6 +158,8 @@ static void blank_screen_t(unsigned long dummy); static void set_palette(struct vc_data *vc); static int printable; /* Is console ready for printing? */ +static int default_utf8; +module_param(default_utf8, int, S_IRUGO | S_IWUSR); /* * ignore_poke: don't unblank the screen when things are typed. This is @@ -348,10 +351,12 @@ void update_region(struct vc_data *vc, unsigned long start, int count) /* Structure of attributes is hardware-dependent */ -static u8 build_attr(struct vc_data *vc, u8 _color, u8 _intensity, u8 _blink, u8 _underline, u8 _reverse) +static u8 build_attr(struct vc_data *vc, u8 _color, u8 _intensity, u8 _blink, + u8 _underline, u8 _reverse, u8 _italic) { if (vc->vc_sw->con_build_attr) - return vc->vc_sw->con_build_attr(vc, _color, _intensity, _blink, _underline, _reverse); + return vc->vc_sw->con_build_attr(vc, _color, _intensity, + _blink, _underline, _reverse, _italic); #ifndef VT_BUF_VRAM_ONLY /* @@ -368,10 +373,13 @@ static u8 build_attr(struct vc_data *vc, u8 _color, u8 _intensity, u8 _blink, u8 u8 a = vc->vc_color; if (!vc->vc_can_do_color) return _intensity | + (_italic ? 2 : 0) | (_underline ? 4 : 0) | (_reverse ? 8 : 0) | (_blink ? 0x80 : 0); - if (_underline) + if (_italic) + a = (a & 0xF0) | vc->vc_itcolor; + else if (_underline) a = (a & 0xf0) | vc->vc_ulcolor; else if (_intensity == 0) a = (a & 0xf0) | vc->vc_ulcolor; @@ -392,8 +400,10 @@ static u8 build_attr(struct vc_data *vc, u8 _color, u8 _intensity, u8 _blink, u8 static void update_attr(struct vc_data *vc) { - vc->vc_attr = build_attr(vc, vc->vc_color, vc->vc_intensity, vc->vc_blink, vc->vc_underline, vc->vc_reverse ^ vc->vc_decscnm); - vc->vc_video_erase_char = (build_attr(vc, vc->vc_color, 1, vc->vc_blink, 0, vc->vc_decscnm) << 8) | ' '; + vc->vc_attr = build_attr(vc, vc->vc_color, vc->vc_intensity, + vc->vc_blink, vc->vc_underline, + vc->vc_reverse ^ vc->vc_decscnm, vc->vc_italic); + vc->vc_video_erase_char = (build_attr(vc, vc->vc_color, 1, vc->vc_blink, 0, vc->vc_decscnm, 0) << 8) | ' '; } /* Note: inverting the screen twice should revert to the original state */ @@ -934,6 +944,10 @@ int default_grn[] = {0x00,0x00,0xaa,0x55,0x00,0x00,0xaa,0xaa, int default_blu[] = {0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa,0xaa, 0x55,0x55,0x55,0x55,0xff,0xff,0xff,0xff}; +module_param_array(default_red, int, NULL, S_IRUGO | S_IWUSR); +module_param_array(default_grn, int, NULL, S_IRUGO | S_IWUSR); +module_param_array(default_blu, int, NULL, S_IRUGO | S_IWUSR); + /* * gotoxy() must verify all boundaries, because the arguments * might also be negative. If the given position is out of @@ -1132,6 +1146,7 @@ static void csi_X(struct vc_data *vc, int vpar) /* erase the following vpar posi static void default_attr(struct vc_data *vc) { vc->vc_intensity = 1; + vc->vc_italic = 0; vc->vc_underline = 0; vc->vc_reverse = 0; vc->vc_blink = 0; @@ -1154,6 +1169,9 @@ static void csi_m(struct vc_data *vc) case 2: vc->vc_intensity = 0; break; + case 3: + vc->vc_italic = 1; + break; case 4: vc->vc_underline = 1; break; @@ -1194,6 +1212,9 @@ static void csi_m(struct vc_data *vc) case 22: vc->vc_intensity = 1; break; + case 23: + vc->vc_italic = 0; + break; case 24: vc->vc_underline = 0; break; @@ -1454,6 +1475,7 @@ static void save_cur(struct vc_data *vc) vc->vc_saved_x = vc->vc_x; vc->vc_saved_y = vc->vc_y; vc->vc_s_intensity = vc->vc_intensity; + vc->vc_s_italic = vc->vc_italic; vc->vc_s_underline = vc->vc_underline; vc->vc_s_blink = vc->vc_blink; vc->vc_s_reverse = vc->vc_reverse; @@ -1468,6 +1490,7 @@ static void restore_cur(struct vc_data *vc) { gotoxy(vc, vc->vc_saved_x, vc->vc_saved_y); vc->vc_intensity = vc->vc_s_intensity; + vc->vc_italic = vc->vc_s_italic; vc->vc_underline = vc->vc_s_underline; vc->vc_blink = vc->vc_s_blink; vc->vc_reverse = vc->vc_s_reverse; @@ -1497,7 +1520,7 @@ static void reset_terminal(struct vc_data *vc, int do_clear) vc->vc_charset = 0; vc->vc_need_wrap = 0; vc->vc_report_mouse = 0; - vc->vc_utf = 0; + vc->vc_utf = default_utf8; vc->vc_utf_count = 0; vc->vc_disp_ctrl = 0; @@ -1930,7 +1953,47 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c) * kernel memory allocation is available. */ char con_buf[CON_BUF_SIZE]; -DECLARE_MUTEX(con_buf_sem); +DEFINE_MUTEX(con_buf_mtx); + +/* is_double_width() is based on the wcwidth() implementation by + * Markus Kuhn -- 2003-05-20 (Unicode 4.0) + * Latest version: http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c + */ +struct interval { + uint32_t first; + uint32_t last; +}; + +static int bisearch(uint32_t ucs, const struct interval *table, int max) +{ + int min = 0; + int mid; + + if (ucs < table[0].first || ucs > table[max].last) + return 0; + while (max >= min) { + mid = (min + max) / 2; + if (ucs > table[mid].last) + min = mid + 1; + else if (ucs < table[mid].first) + max = mid - 1; + else + return 1; + } + return 0; +} + +static int is_double_width(uint32_t ucs) +{ + static const struct interval double_width[] = { + { 0x1100, 0x115F }, { 0x2329, 0x232A }, { 0x2E80, 0x303E }, + { 0x3040, 0xA4CF }, { 0xAC00, 0xD7A3 }, { 0xF900, 0xFAFF }, + { 0xFE30, 0xFE6F }, { 0xFF00, 0xFF60 }, { 0xFFE0, 0xFFE6 }, + { 0x20000, 0x2FFFD }, { 0x30000, 0x3FFFD } + }; + return bisearch(ucs, double_width, + sizeof(double_width) / sizeof(*double_width) - 1); +} /* acquires console_sem */ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int count) @@ -1948,6 +2011,10 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co unsigned int currcons; unsigned long draw_from = 0, draw_to = 0; struct vc_data *vc; + unsigned char vc_attr; + uint8_t rescan; + uint8_t inverse; + uint8_t width; u16 himask, charmask; const unsigned char *orig_buf = NULL; int orig_count; @@ -1983,7 +2050,7 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co /* At this point 'buf' is guaranteed to be a kernel buffer * and therefore no access to userspace (and therefore sleeping) - * will be needed. The con_buf_sem serializes all tty based + * will be needed. The con_buf_mtx serializes all tty based * console rendering and vcs write/read operations. We hold * the console spinlock during the entire write. */ @@ -2010,53 +2077,86 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co buf++; n++; count--; + rescan = 0; + inverse = 0; + width = 1; /* Do no translation at all in control states */ if (vc->vc_state != ESnormal) { tc = c; } else if (vc->vc_utf && !vc->vc_disp_ctrl) { - /* Combine UTF-8 into Unicode */ - /* Malformed sequences as sequences of replacement glyphs */ + /* Combine UTF-8 into Unicode in vc_utf_char. + * vc_utf_count is the number of continuation bytes still + * expected to arrive. + * vc_npar is the number of continuation bytes arrived so + * far + */ rescan_last_byte: - if(c > 0x7f) { + if ((c & 0xc0) == 0x80) { + /* Continuation byte received */ + static const uint32_t utf8_length_changes[] = { 0x0000007f, 0x000007ff, 0x0000ffff, 0x001fffff, 0x03ffffff, 0x7fffffff }; if (vc->vc_utf_count) { - if ((c & 0xc0) == 0x80) { - vc->vc_utf_char = (vc->vc_utf_char << 6) | (c & 0x3f); - if (--vc->vc_utf_count) { - vc->vc_npar++; - continue; - } - tc = c = vc->vc_utf_char; - } else - goto replacement_glyph; - } else { - vc->vc_npar = 0; - if ((c & 0xe0) == 0xc0) { - vc->vc_utf_count = 1; - vc->vc_utf_char = (c & 0x1f); - } else if ((c & 0xf0) == 0xe0) { - vc->vc_utf_count = 2; - vc->vc_utf_char = (c & 0x0f); - } else if ((c & 0xf8) == 0xf0) { - vc->vc_utf_count = 3; - vc->vc_utf_char = (c & 0x07); - } else if ((c & 0xfc) == 0xf8) { - vc->vc_utf_count = 4; - vc->vc_utf_char = (c & 0x03); - } else if ((c & 0xfe) == 0xfc) { - vc->vc_utf_count = 5; - vc->vc_utf_char = (c & 0x01); - } else - goto replacement_glyph; + vc->vc_utf_char = (vc->vc_utf_char << 6) | (c & 0x3f); + vc->vc_npar++; + if (--vc->vc_utf_count) { + /* Still need some bytes */ continue; - } + } + /* Got a whole character */ + c = vc->vc_utf_char; + /* Reject overlong sequences */ + if (c <= utf8_length_changes[vc->vc_npar - 1] || + c > utf8_length_changes[vc->vc_npar]) + c = 0xfffd; + } else { + /* Unexpected continuation byte */ + vc->vc_utf_count = 0; + c = 0xfffd; + } } else { - if (vc->vc_utf_count) - goto replacement_glyph; - tc = c; + /* Single ASCII byte or first byte of a sequence received */ + if (vc->vc_utf_count) { + /* Continuation byte expected */ + rescan = 1; + vc->vc_utf_count = 0; + c = 0xfffd; + } else if (c > 0x7f) { + /* First byte of a multibyte sequence received */ + vc->vc_npar = 0; + if ((c & 0xe0) == 0xc0) { + vc->vc_utf_count = 1; + vc->vc_utf_char = (c & 0x1f); + } else if ((c & 0xf0) == 0xe0) { + vc->vc_utf_count = 2; + vc->vc_utf_char = (c & 0x0f); + } else if ((c & 0xf8) == 0xf0) { + vc->vc_utf_count = 3; + vc->vc_utf_char = (c & 0x07); + } else if ((c & 0xfc) == 0xf8) { + vc->vc_utf_count = 4; + vc->vc_utf_char = (c & 0x03); + } else if ((c & 0xfe) == 0xfc) { + vc->vc_utf_count = 5; + vc->vc_utf_char = (c & 0x01); + } else { + /* 254 and 255 are invalid */ + c = 0xfffd; + } + if (vc->vc_utf_count) { + /* Still need some bytes */ + continue; + } + } + /* Nothing to do if an ASCII byte was received */ } + /* End of UTF-8 decoding. */ + /* c is the received character, or U+FFFD for invalid sequences. */ + /* Replace invalid Unicode code points with U+FFFD too */ + if ((c >= 0xd800 && c <= 0xdfff) || c == 0xfffe || c == 0xffff) + c = 0xfffd; + tc = c; } else { /* no utf or alternate charset mode */ - tc = vc->vc_translate[vc->vc_toggle_meta ? (c | 0x80) : c]; + tc = vc->vc_translate[vc->vc_toggle_meta ? (c | 0x80) : c]; } /* If the original code was a control character we @@ -2076,56 +2176,80 @@ rescan_last_byte: && (c != 128+27); if (vc->vc_state == ESnormal && ok) { + if (vc->vc_utf && !vc->vc_disp_ctrl) { + if (is_double_width(c)) + width = 2; + } /* Now try to find out how to display it */ tc = conv_uni_to_pc(vc, tc); if (tc & ~charmask) { - if ( tc == -4 ) { - /* If we got -4 (not found) then see if we have - defined a replacement character (U+FFFD) */ -replacement_glyph: - tc = conv_uni_to_pc(vc, 0xfffd); - if (!(tc & ~charmask)) - goto display_glyph; - } else if ( tc != -3 ) - continue; /* nothing to display */ - /* no hash table or no replacement -- - * hope for the best */ - if ( c & ~charmask ) - tc = '?'; - else - tc = c; + if (tc == -1 || tc == -2) { + continue; /* nothing to display */ + } + /* Glyph not found */ + if (!(vc->vc_utf && !vc->vc_disp_ctrl) && !(c & ~charmask)) { + /* In legacy mode use the glyph we get by a 1:1 mapping. + This would make absolutely no sense with Unicode in mind. */ + tc = c; + } else { + /* Display U+FFFD. If it's not found, display an inverse question mark. */ + tc = conv_uni_to_pc(vc, 0xfffd); + if (tc < 0) { + inverse = 1; + tc = conv_uni_to_pc(vc, '?'); + if (tc < 0) tc = '?'; + } + } } -display_glyph: - if (vc->vc_need_wrap || vc->vc_decim) - FLUSH - if (vc->vc_need_wrap) { - cr(vc); - lf(vc); - } - if (vc->vc_decim) - insert_char(vc, 1); - scr_writew(himask ? - ((vc->vc_attr << 8) & ~himask) + ((tc & 0x100) ? himask : 0) + (tc & 0xff) : - (vc->vc_attr << 8) + tc, - (u16 *) vc->vc_pos); - if (DO_UPDATE(vc) && draw_x < 0) { - draw_x = vc->vc_x; - draw_from = vc->vc_pos; - } - if (vc->vc_x == vc->vc_cols - 1) { - vc->vc_need_wrap = vc->vc_decawm; - draw_to = vc->vc_pos + 2; + if (!inverse) { + vc_attr = vc->vc_attr; } else { - vc->vc_x++; - draw_to = (vc->vc_pos += 2); + /* invert vc_attr */ + if (!vc->vc_can_do_color) { + vc_attr = (vc->vc_attr) ^ 0x08; + } else if (vc->vc_hi_font_mask == 0x100) { + vc_attr = ((vc->vc_attr) & 0x11) | (((vc->vc_attr) & 0xe0) >> 4) | (((vc->vc_attr) & 0x0e) << 4); + } else { + vc_attr = ((vc->vc_attr) & 0x88) | (((vc->vc_attr) & 0x70) >> 4) | (((vc->vc_attr) & 0x07) << 4); + } } - if (vc->vc_utf_count) { - if (vc->vc_npar) { - vc->vc_npar--; - goto display_glyph; + + while (1) { + if (vc->vc_need_wrap || vc->vc_decim) + FLUSH + if (vc->vc_need_wrap) { + cr(vc); + lf(vc); + } + if (vc->vc_decim) + insert_char(vc, 1); + scr_writew(himask ? + ((vc_attr << 8) & ~himask) + ((tc & 0x100) ? himask : 0) + (tc & 0xff) : + (vc_attr << 8) + tc, + (u16 *) vc->vc_pos); + if (DO_UPDATE(vc) && draw_x < 0) { + draw_x = vc->vc_x; + draw_from = vc->vc_pos; + } + if (vc->vc_x == vc->vc_cols - 1) { + vc->vc_need_wrap = vc->vc_decawm; + draw_to = vc->vc_pos + 2; + } else { + vc->vc_x++; + draw_to = (vc->vc_pos += 2); } - vc->vc_utf_count = 0; + + if (!--width) break; + + tc = conv_uni_to_pc(vc, ' '); /* A space is printed in the second column */ + if (tc < 0) tc = ' '; + } + + if (rescan) { + rescan = 0; + inverse = 0; + width = 1; c = orig; goto rescan_last_byte; } @@ -2581,6 +2705,11 @@ static void con_close(struct tty_struct *tty, struct file *filp) mutex_unlock(&tty_mutex); } +static int default_italic_color = 2; // green (ASCII) +static int default_underline_color = 3; // cyan (ASCII) +module_param_named(italic, default_italic_color, int, S_IRUGO | S_IWUSR); +module_param_named(underline, default_underline_color, int, S_IRUGO | S_IWUSR); + static void vc_init(struct vc_data *vc, unsigned int rows, unsigned int cols, int do_clear) { @@ -2600,7 +2729,8 @@ static void vc_init(struct vc_data *vc, unsigned int rows, vc->vc_palette[k++] = default_blu[j] ; } vc->vc_def_color = 0x07; /* white */ - vc->vc_ulcolor = 0x0f; /* bold white */ + vc->vc_ulcolor = default_underline_color; + vc->vc_itcolor = default_italic_color; vc->vc_halfcolor = 0x08; /* grey */ init_waitqueue_head(&vc->paste_wait); reset_terminal(vc, do_clear); diff --git a/drivers/char/vt_ioctl.c b/drivers/char/vt_ioctl.c index c9f2dd620e8..c6f6f420973 100644 --- a/drivers/char/vt_ioctl.c +++ b/drivers/char/vt_ioctl.c @@ -1061,7 +1061,7 @@ int vt_waitactive(int vt) schedule(); } remove_wait_queue(&vt_activate_queue, &wait); - current->state = TASK_RUNNING; + __set_current_state(TASK_RUNNING); return retval; } diff --git a/drivers/char/watchdog/omap_wdt.c b/drivers/char/watchdog/omap_wdt.c index 84074a697dc..b36fa8de213 100644 --- a/drivers/char/watchdog/omap_wdt.c +++ b/drivers/char/watchdog/omap_wdt.c @@ -34,7 +34,6 @@ #include <linux/miscdevice.h> #include <linux/watchdog.h> #include <linux/reboot.h> -#include <linux/smp_lock.h> #include <linux/init.h> #include <linux/err.h> #include <linux/platform_device.h> diff --git a/drivers/char/watchdog/sc1200wdt.c b/drivers/char/watchdog/sc1200wdt.c index 1e4a8d751a7..2f7ba7a514f 100644 --- a/drivers/char/watchdog/sc1200wdt.c +++ b/drivers/char/watchdog/sc1200wdt.c @@ -38,7 +38,6 @@ #include <linux/init.h> #include <linux/pnp.h> #include <linux/fs.h> -#include <linux/pci.h> #include <asm/semaphore.h> #include <asm/io.h> diff --git a/drivers/char/watchdog/scx200_wdt.c b/drivers/char/watchdog/scx200_wdt.c index fc0e0347f9d..d4fd0fa2f17 100644 --- a/drivers/char/watchdog/scx200_wdt.c +++ b/drivers/char/watchdog/scx200_wdt.c @@ -25,7 +25,7 @@ #include <linux/notifier.h> #include <linux/reboot.h> #include <linux/fs.h> -#include <linux/pci.h> +#include <linux/ioport.h> #include <linux/scx200.h> #include <asm/uaccess.h> |