diff options
Diffstat (limited to 'drivers/char')
114 files changed, 4009 insertions, 3518 deletions
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index a26d91743b24..ef683ebd367c 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 && !SUPERH ---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 @@ -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/agp/agp.h b/drivers/char/agp/agp.h index fdbca25a3948..35ab1a9f8e8b 100644 --- a/drivers/char/agp/agp.h +++ b/drivers/char/agp/agp.h @@ -176,7 +176,7 @@ struct agp_bridge_data { #define I830_GMCH_MEM_MASK 0x1 #define I830_GMCH_MEM_64M 0x1 #define I830_GMCH_MEM_128M 0 -#define I830_GMCH_GMS_MASK 0x70 +#define I830_GMCH_GMS_MASK 0xF0 #define I830_GMCH_GMS_DISABLED 0x00 #define I830_GMCH_GMS_LOCAL 0x10 #define I830_GMCH_GMS_STOLEN_512 0x20 @@ -231,6 +231,10 @@ struct agp_bridge_data { #define I965_PGETBL_SIZE_512KB (0 << 1) #define I965_PGETBL_SIZE_256KB (1 << 1) #define I965_PGETBL_SIZE_128KB (2 << 1) +#define G33_PGETBL_SIZE_MASK (3 << 8) +#define G33_PGETBL_SIZE_1M (1 << 8) +#define G33_PGETBL_SIZE_2M (2 << 8) + #define I810_DRAM_CTL 0x3000 #define I810_DRAM_ROW_0 0x00000001 #define I810_DRAM_ROW_0_SDRAM 0x00000001 diff --git a/drivers/char/agp/amd64-agp.c b/drivers/char/agp/amd64-agp.c index c9f0f250d78f..801abdd29066 100644 --- a/drivers/char/agp/amd64-agp.c +++ b/drivers/char/agp/amd64-agp.c @@ -268,7 +268,7 @@ static int __devinit aperture_valid(u64 aper, u32 size) printk(KERN_ERR PFX "Aperture too small (%d MB)\n", size>>20); return 0; } - if (aper + size > 0xffffffff) { + if ((u64)aper + size > 0x100000000ULL) { printk(KERN_ERR PFX "Aperture out of bounds\n"); return 0; } diff --git a/drivers/char/agp/frontend.c b/drivers/char/agp/frontend.c index 679d7f972439..c7ed617aa7ff 100644 --- a/drivers/char/agp/frontend.c +++ b/drivers/char/agp/frontend.c @@ -37,6 +37,7 @@ #include <linux/agpgart.h> #include <linux/slab.h> #include <linux/mm.h> +#include <linux/sched.h> #include <asm/uaccess.h> #include <asm/pgtable.h> #include "agp.h" diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c index 45aeb917ec63..d535c406b319 100644 --- a/drivers/char/agp/generic.c +++ b/drivers/char/agp/generic.c @@ -37,6 +37,7 @@ #include <linux/vmalloc.h> #include <linux/dma-mapping.h> #include <linux/mm.h> +#include <linux/sched.h> #include <asm/io.h> #include <asm/cacheflush.h> #include <asm/pgtable.h> diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c index 9c69f2e761f5..a1240603912c 100644 --- a/drivers/char/agp/intel-agp.c +++ b/drivers/char/agp/intel-agp.c @@ -20,6 +20,14 @@ #define PCI_DEVICE_ID_INTEL_82965G_IG 0x29A2 #define PCI_DEVICE_ID_INTEL_82965GM_HB 0x2A00 #define PCI_DEVICE_ID_INTEL_82965GM_IG 0x2A02 +#define PCI_DEVICE_ID_INTEL_82965GME_IG 0x2A12 +#define PCI_DEVICE_ID_INTEL_82945GME_IG 0x27AE +#define PCI_DEVICE_ID_INTEL_G33_HB 0x29C0 +#define PCI_DEVICE_ID_INTEL_G33_IG 0x29C2 +#define PCI_DEVICE_ID_INTEL_Q35_HB 0x29B0 +#define PCI_DEVICE_ID_INTEL_Q35_IG 0x29B2 +#define PCI_DEVICE_ID_INTEL_Q33_HB 0x29D0 +#define PCI_DEVICE_ID_INTEL_Q33_IG 0x29D2 #define IS_I965 (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82946GZ_HB || \ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965G_1_HB || \ @@ -27,6 +35,9 @@ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965G_HB || \ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965GM_HB) +#define IS_G33 (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_G33_HB || \ + agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_Q35_HB || \ + agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_Q33_HB) extern int agp_memory_reserved; @@ -53,6 +64,8 @@ extern int agp_memory_reserved; #define I915_PTEADDR 0x1C #define I915_GMCH_GMS_STOLEN_48M (0x6 << 4) #define I915_GMCH_GMS_STOLEN_64M (0x7 << 4) +#define G33_GMCH_GMS_STOLEN_128M (0x8 << 4) +#define G33_GMCH_GMS_STOLEN_256M (0x9 << 4) /* Intel 965G registers */ #define I965_MSAC 0x62 @@ -86,11 +99,18 @@ static struct gatt_mask intel_i810_masks[] = .type = INTEL_AGP_CACHED_MEMORY} }; -static struct _intel_i810_private { - struct pci_dev *i810_dev; /* device one */ - volatile u8 __iomem *registers; +static struct _intel_private { + struct pci_dev *pcidev; /* device one */ + u8 __iomem *registers; + u32 __iomem *gtt; /* I915G */ int num_dcache_entries; -} intel_i810_private; + /* gtt_entries is the number of gtt entries that are already mapped + * to stolen memory. Stolen memory is larger than the memory mapped + * through gtt_entries, as it includes some reserved space for the BIOS + * popup and for the GTT. + */ + int gtt_entries; /* i830+ */ +} intel_private; static int intel_i810_fetch_size(void) { @@ -127,32 +147,32 @@ static int intel_i810_configure(void) current_size = A_SIZE_FIX(agp_bridge->current_size); - if (!intel_i810_private.registers) { - pci_read_config_dword(intel_i810_private.i810_dev, I810_MMADDR, &temp); + if (!intel_private.registers) { + pci_read_config_dword(intel_private.pcidev, I810_MMADDR, &temp); temp &= 0xfff80000; - intel_i810_private.registers = ioremap(temp, 128 * 4096); - if (!intel_i810_private.registers) { + intel_private.registers = ioremap(temp, 128 * 4096); + if (!intel_private.registers) { printk(KERN_ERR PFX "Unable to remap memory.\n"); return -ENOMEM; } } - if ((readl(intel_i810_private.registers+I810_DRAM_CTL) + if ((readl(intel_private.registers+I810_DRAM_CTL) & I810_DRAM_ROW_0) == I810_DRAM_ROW_0_SDRAM) { /* This will need to be dynamically assigned */ printk(KERN_INFO PFX "detected 4MB dedicated video ram.\n"); - intel_i810_private.num_dcache_entries = 1024; + intel_private.num_dcache_entries = 1024; } - pci_read_config_dword(intel_i810_private.i810_dev, I810_GMADDR, &temp); + pci_read_config_dword(intel_private.pcidev, I810_GMADDR, &temp); agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); - writel(agp_bridge->gatt_bus_addr | I810_PGETBL_ENABLED, intel_i810_private.registers+I810_PGETBL_CTL); - readl(intel_i810_private.registers+I810_PGETBL_CTL); /* PCI Posting. */ + writel(agp_bridge->gatt_bus_addr | I810_PGETBL_ENABLED, intel_private.registers+I810_PGETBL_CTL); + readl(intel_private.registers+I810_PGETBL_CTL); /* PCI Posting. */ if (agp_bridge->driver->needs_scratch_page) { for (i = 0; i < current_size->num_entries; i++) { - writel(agp_bridge->scratch_page, intel_i810_private.registers+I810_PTE_BASE+(i*4)); - readl(intel_i810_private.registers+I810_PTE_BASE+(i*4)); /* PCI posting. */ + writel(agp_bridge->scratch_page, intel_private.registers+I810_PTE_BASE+(i*4)); + readl(intel_private.registers+I810_PTE_BASE+(i*4)); /* PCI posting. */ } } global_cache_flush(); @@ -161,9 +181,9 @@ static int intel_i810_configure(void) static void intel_i810_cleanup(void) { - writel(0, intel_i810_private.registers+I810_PGETBL_CTL); - readl(intel_i810_private.registers); /* PCI Posting. */ - iounmap(intel_i810_private.registers); + writel(0, intel_private.registers+I810_PGETBL_CTL); + readl(intel_private.registers); /* PCI Posting. */ + iounmap(intel_private.registers); } static void intel_i810_tlbflush(struct agp_memory *mem) @@ -261,9 +281,9 @@ static int intel_i810_insert_entries(struct agp_memory *mem, off_t pg_start, global_cache_flush(); for (i = pg_start; i < (pg_start + mem->page_count); i++) { writel((i*4096)|I810_PTE_LOCAL|I810_PTE_VALID, - intel_i810_private.registers+I810_PTE_BASE+(i*4)); + intel_private.registers+I810_PTE_BASE+(i*4)); } - readl(intel_i810_private.registers+I810_PTE_BASE+((i-1)*4)); + readl(intel_private.registers+I810_PTE_BASE+((i-1)*4)); break; case AGP_PHYS_MEMORY: case AGP_NORMAL_MEMORY: @@ -273,9 +293,9 @@ static int intel_i810_insert_entries(struct agp_memory *mem, off_t pg_start, writel(agp_bridge->driver->mask_memory(agp_bridge, mem->memory[i], mask_type), - intel_i810_private.registers+I810_PTE_BASE+(j*4)); + intel_private.registers+I810_PTE_BASE+(j*4)); } - readl(intel_i810_private.registers+I810_PTE_BASE+((j-1)*4)); + readl(intel_private.registers+I810_PTE_BASE+((j-1)*4)); break; default: goto out_err; @@ -298,9 +318,9 @@ static int intel_i810_remove_entries(struct agp_memory *mem, off_t pg_start, return 0; for (i = pg_start; i < (mem->page_count + pg_start); i++) { - writel(agp_bridge->scratch_page, intel_i810_private.registers+I810_PTE_BASE+(i*4)); + writel(agp_bridge->scratch_page, intel_private.registers+I810_PTE_BASE+(i*4)); } - readl(intel_i810_private.registers+I810_PTE_BASE+((i-1)*4)); + readl(intel_private.registers+I810_PTE_BASE+((i-1)*4)); agp_bridge->driver->tlb_flush(mem); return 0; @@ -354,7 +374,7 @@ static struct agp_memory *intel_i810_alloc_by_type(size_t pg_count, int type) struct agp_memory *new; if (type == AGP_DCACHE_MEMORY) { - if (pg_count != intel_i810_private.num_dcache_entries) + if (pg_count != intel_private.num_dcache_entries) return NULL; new = agp_create_memory(1); @@ -404,18 +424,6 @@ static struct aper_size_info_fixed intel_i830_sizes[] = {512, 131072, 7}, }; -static struct _intel_i830_private { - struct pci_dev *i830_dev; /* device one */ - volatile u8 __iomem *registers; - volatile u32 __iomem *gtt; /* I915G */ - /* gtt_entries is the number of gtt entries that are already mapped - * to stolen memory. Stolen memory is larger than the memory mapped - * through gtt_entries, as it includes some reserved space for the BIOS - * popup and for the GTT. - */ - int gtt_entries; -} intel_i830_private; - static void intel_i830_init_gtt_entries(void) { u16 gmch_ctrl; @@ -429,7 +437,7 @@ static void intel_i830_init_gtt_entries(void) if (IS_I965) { u32 pgetbl_ctl; - pgetbl_ctl = readl(intel_i830_private.registers+I810_PGETBL_CTL); + pgetbl_ctl = readl(intel_private.registers+I810_PGETBL_CTL); /* The 965 has a field telling us the size of the GTT, * which may be larger than what is necessary to map the @@ -451,6 +459,22 @@ static void intel_i830_init_gtt_entries(void) size = 512; } size += 4; /* add in BIOS popup space */ + } else if (IS_G33) { + /* G33's GTT size defined in gmch_ctrl */ + switch (gmch_ctrl & G33_PGETBL_SIZE_MASK) { + case G33_PGETBL_SIZE_1M: + size = 1024; + break; + case G33_PGETBL_SIZE_2M: + size = 2048; + break; + default: + printk(KERN_INFO PFX "Unknown page table size 0x%x, " + "assuming 512KB\n", + (gmch_ctrl & G33_PGETBL_SIZE_MASK)); + size = 512; + } + size += 4; } else { /* On previous hardware, the GTT size was just what was * required to map the aperture. @@ -471,7 +495,7 @@ static void intel_i830_init_gtt_entries(void) gtt_entries = MB(8) - KB(size); break; case I830_GMCH_GMS_LOCAL: - rdct = readb(intel_i830_private.registers+I830_RDRAM_CHANNEL_TYPE); + rdct = readb(intel_private.registers+I830_RDRAM_CHANNEL_TYPE); gtt_entries = (I830_RDRAM_ND(rdct) + 1) * MB(ddt[I830_RDRAM_DDT(rdct)]); local = 1; @@ -502,7 +526,8 @@ static void intel_i830_init_gtt_entries(void) if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915G_HB || agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB || agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945G_HB || - agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GM_HB || IS_I965 ) + agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GM_HB || + IS_I965 || IS_G33) gtt_entries = MB(48) - KB(size); else gtt_entries = 0; @@ -512,10 +537,24 @@ static void intel_i830_init_gtt_entries(void) if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915G_HB || agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB || agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945G_HB || - agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GM_HB || IS_I965) + agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GM_HB || + IS_I965 || IS_G33) gtt_entries = MB(64) - KB(size); else gtt_entries = 0; + break; + case G33_GMCH_GMS_STOLEN_128M: + if (IS_G33) + gtt_entries = MB(128) - KB(size); + else + gtt_entries = 0; + break; + case G33_GMCH_GMS_STOLEN_256M: + if (IS_G33) + gtt_entries = MB(256) - KB(size); + else + gtt_entries = 0; + break; default: gtt_entries = 0; break; @@ -529,7 +568,7 @@ static void intel_i830_init_gtt_entries(void) "No pre-allocated video memory detected.\n"); gtt_entries /= KB(4); - intel_i830_private.gtt_entries = gtt_entries; + intel_private.gtt_entries = gtt_entries; } /* The intel i830 automatically initializes the agp aperture during POST. @@ -547,14 +586,14 @@ static int intel_i830_create_gatt_table(struct agp_bridge_data *bridge) num_entries = size->num_entries; agp_bridge->gatt_table_real = NULL; - pci_read_config_dword(intel_i830_private.i830_dev,I810_MMADDR,&temp); + pci_read_config_dword(intel_private.pcidev,I810_MMADDR,&temp); temp &= 0xfff80000; - intel_i830_private.registers = ioremap(temp,128 * 4096); - if (!intel_i830_private.registers) + intel_private.registers = ioremap(temp,128 * 4096); + if (!intel_private.registers) return -ENOMEM; - temp = readl(intel_i830_private.registers+I810_PGETBL_CTL) & 0xfffff000; + temp = readl(intel_private.registers+I810_PGETBL_CTL) & 0xfffff000; global_cache_flush(); /* FIXME: ?? */ /* we have to call this as early as possible after the MMIO base address is known */ @@ -614,20 +653,20 @@ static int intel_i830_configure(void) current_size = A_SIZE_FIX(agp_bridge->current_size); - pci_read_config_dword(intel_i830_private.i830_dev,I810_GMADDR,&temp); + pci_read_config_dword(intel_private.pcidev,I810_GMADDR,&temp); agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); pci_read_config_word(agp_bridge->dev,I830_GMCH_CTRL,&gmch_ctrl); gmch_ctrl |= I830_GMCH_ENABLED; pci_write_config_word(agp_bridge->dev,I830_GMCH_CTRL,gmch_ctrl); - writel(agp_bridge->gatt_bus_addr|I810_PGETBL_ENABLED, intel_i830_private.registers+I810_PGETBL_CTL); - readl(intel_i830_private.registers+I810_PGETBL_CTL); /* PCI Posting. */ + writel(agp_bridge->gatt_bus_addr|I810_PGETBL_ENABLED, intel_private.registers+I810_PGETBL_CTL); + readl(intel_private.registers+I810_PGETBL_CTL); /* PCI Posting. */ if (agp_bridge->driver->needs_scratch_page) { - for (i = intel_i830_private.gtt_entries; i < current_size->num_entries; i++) { - writel(agp_bridge->scratch_page, intel_i830_private.registers+I810_PTE_BASE+(i*4)); - readl(intel_i830_private.registers+I810_PTE_BASE+(i*4)); /* PCI Posting. */ + for (i = intel_private.gtt_entries; i < current_size->num_entries; i++) { + writel(agp_bridge->scratch_page, intel_private.registers+I810_PTE_BASE+(i*4)); + readl(intel_private.registers+I810_PTE_BASE+(i*4)); /* PCI Posting. */ } } @@ -637,7 +676,7 @@ static int intel_i830_configure(void) static void intel_i830_cleanup(void) { - iounmap(intel_i830_private.registers); + iounmap(intel_private.registers); } static int intel_i830_insert_entries(struct agp_memory *mem,off_t pg_start, int type) @@ -653,9 +692,9 @@ static int intel_i830_insert_entries(struct agp_memory *mem,off_t pg_start, int temp = agp_bridge->current_size; num_entries = A_SIZE_FIX(temp)->num_entries; - if (pg_start < intel_i830_private.gtt_entries) { - printk (KERN_DEBUG PFX "pg_start == 0x%.8lx,intel_i830_private.gtt_entries == 0x%.8x\n", - pg_start,intel_i830_private.gtt_entries); + if (pg_start < intel_private.gtt_entries) { + printk (KERN_DEBUG PFX "pg_start == 0x%.8lx,intel_private.gtt_entries == 0x%.8x\n", + pg_start,intel_private.gtt_entries); printk (KERN_INFO PFX "Trying to insert into local/stolen memory\n"); goto out_err; @@ -683,9 +722,9 @@ static int intel_i830_insert_entries(struct agp_memory *mem,off_t pg_start, int for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { writel(agp_bridge->driver->mask_memory(agp_bridge, mem->memory[i], mask_type), - intel_i830_private.registers+I810_PTE_BASE+(j*4)); + intel_private.registers+I810_PTE_BASE+(j*4)); } - readl(intel_i830_private.registers+I810_PTE_BASE+((j-1)*4)); + readl(intel_private.registers+I810_PTE_BASE+((j-1)*4)); agp_bridge->driver->tlb_flush(mem); out: @@ -703,15 +742,15 @@ static int intel_i830_remove_entries(struct agp_memory *mem,off_t pg_start, if (mem->page_count == 0) return 0; - if (pg_start < intel_i830_private.gtt_entries) { + if (pg_start < intel_private.gtt_entries) { printk (KERN_INFO PFX "Trying to disable local/stolen memory\n"); return -EINVAL; } for (i = pg_start; i < (mem->page_count + pg_start); i++) { - writel(agp_bridge->scratch_page, intel_i830_private.registers+I810_PTE_BASE+(i*4)); + writel(agp_bridge->scratch_page, intel_private.registers+I810_PTE_BASE+(i*4)); } - readl(intel_i830_private.registers+I810_PTE_BASE+((i-1)*4)); + readl(intel_private.registers+I810_PTE_BASE+((i-1)*4)); agp_bridge->driver->tlb_flush(mem); return 0; @@ -734,7 +773,7 @@ static int intel_i915_configure(void) current_size = A_SIZE_FIX(agp_bridge->current_size); - pci_read_config_dword(intel_i830_private.i830_dev, I915_GMADDR, &temp); + pci_read_config_dword(intel_private.pcidev, I915_GMADDR, &temp); agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); @@ -742,13 +781,13 @@ static int intel_i915_configure(void) gmch_ctrl |= I830_GMCH_ENABLED; pci_write_config_word(agp_bridge->dev,I830_GMCH_CTRL,gmch_ctrl); - writel(agp_bridge->gatt_bus_addr|I810_PGETBL_ENABLED, intel_i830_private.registers+I810_PGETBL_CTL); - readl(intel_i830_private.registers+I810_PGETBL_CTL); /* PCI Posting. */ + writel(agp_bridge->gatt_bus_addr|I810_PGETBL_ENABLED, intel_private.registers+I810_PGETBL_CTL); + readl(intel_private.registers+I810_PGETBL_CTL); /* PCI Posting. */ if (agp_bridge->driver->needs_scratch_page) { - for (i = intel_i830_private.gtt_entries; i < current_size->num_entries; i++) { - writel(agp_bridge->scratch_page, intel_i830_private.gtt+i); - readl(intel_i830_private.gtt+i); /* PCI Posting. */ + for (i = intel_private.gtt_entries; i < current_size->num_entries; i++) { + writel(agp_bridge->scratch_page, intel_private.gtt+i); + readl(intel_private.gtt+i); /* PCI Posting. */ } } @@ -758,8 +797,8 @@ static int intel_i915_configure(void) static void intel_i915_cleanup(void) { - iounmap(intel_i830_private.gtt); - iounmap(intel_i830_private.registers); + iounmap(intel_private.gtt); + iounmap(intel_private.registers); } static int intel_i915_insert_entries(struct agp_memory *mem,off_t pg_start, @@ -776,9 +815,9 @@ static int intel_i915_insert_entries(struct agp_memory *mem,off_t pg_start, temp = agp_bridge->current_size; num_entries = A_SIZE_FIX(temp)->num_entries; - if (pg_start < intel_i830_private.gtt_entries) { - printk (KERN_DEBUG PFX "pg_start == 0x%.8lx,intel_i830_private.gtt_entries == 0x%.8x\n", - pg_start,intel_i830_private.gtt_entries); + if (pg_start < intel_private.gtt_entries) { + printk (KERN_DEBUG PFX "pg_start == 0x%.8lx,intel_private.gtt_entries == 0x%.8x\n", + pg_start,intel_private.gtt_entries); printk (KERN_INFO PFX "Trying to insert into local/stolen memory\n"); goto out_err; @@ -805,10 +844,10 @@ static int intel_i915_insert_entries(struct agp_memory *mem,off_t pg_start, for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { writel(agp_bridge->driver->mask_memory(agp_bridge, - mem->memory[i], mask_type), intel_i830_private.gtt+j); + mem->memory[i], mask_type), intel_private.gtt+j); } - readl(intel_i830_private.gtt+j-1); + readl(intel_private.gtt+j-1); agp_bridge->driver->tlb_flush(mem); out: @@ -826,15 +865,15 @@ static int intel_i915_remove_entries(struct agp_memory *mem,off_t pg_start, if (mem->page_count == 0) return 0; - if (pg_start < intel_i830_private.gtt_entries) { + if (pg_start < intel_private.gtt_entries) { printk (KERN_INFO PFX "Trying to disable local/stolen memory\n"); return -EINVAL; } for (i = pg_start; i < (mem->page_count + pg_start); i++) { - writel(agp_bridge->scratch_page, intel_i830_private.gtt+i); + writel(agp_bridge->scratch_page, intel_private.gtt+i); } - readl(intel_i830_private.gtt+i-1); + readl(intel_private.gtt+i-1); agp_bridge->driver->tlb_flush(mem); return 0; @@ -850,7 +889,7 @@ static int intel_i9xx_fetch_size(void) int aper_size; /* size in megabytes */ int i; - aper_size = pci_resource_len(intel_i830_private.i830_dev, 2) / MB(1); + aper_size = pci_resource_len(intel_private.pcidev, 2) / MB(1); for (i = 0; i < num_sizes; i++) { if (aper_size == intel_i830_sizes[i].size) { @@ -878,20 +917,20 @@ static int intel_i915_create_gatt_table(struct agp_bridge_data *bridge) num_entries = size->num_entries; agp_bridge->gatt_table_real = NULL; - pci_read_config_dword(intel_i830_private.i830_dev, I915_MMADDR, &temp); - pci_read_config_dword(intel_i830_private.i830_dev, I915_PTEADDR,&temp2); + pci_read_config_dword(intel_private.pcidev, I915_MMADDR, &temp); + pci_read_config_dword(intel_private.pcidev, I915_PTEADDR,&temp2); - intel_i830_private.gtt = ioremap(temp2, 256 * 1024); - if (!intel_i830_private.gtt) + intel_private.gtt = ioremap(temp2, 256 * 1024); + if (!intel_private.gtt) return -ENOMEM; temp &= 0xfff80000; - intel_i830_private.registers = ioremap(temp,128 * 4096); - if (!intel_i830_private.registers) + intel_private.registers = ioremap(temp,128 * 4096); + if (!intel_private.registers) return -ENOMEM; - temp = readl(intel_i830_private.registers+I810_PGETBL_CTL) & 0xfffff000; + temp = readl(intel_private.registers+I810_PGETBL_CTL) & 0xfffff000; global_cache_flush(); /* FIXME: ? */ /* we have to call this as early as possible after the MMIO base address is known */ @@ -938,20 +977,20 @@ static int intel_i965_create_gatt_table(struct agp_bridge_data *bridge) num_entries = size->num_entries; agp_bridge->gatt_table_real = NULL; - pci_read_config_dword(intel_i830_private.i830_dev, I915_MMADDR, &temp); + pci_read_config_dword(intel_private.pcidev, I915_MMADDR, &temp); temp &= 0xfff00000; - intel_i830_private.gtt = ioremap((temp + (512 * 1024)) , 512 * 1024); + intel_private.gtt = ioremap((temp + (512 * 1024)) , 512 * 1024); - if (!intel_i830_private.gtt) + if (!intel_private.gtt) return -ENOMEM; - intel_i830_private.registers = ioremap(temp,128 * 4096); - if (!intel_i830_private.registers) + intel_private.registers = ioremap(temp,128 * 4096); + if (!intel_private.registers) return -ENOMEM; - temp = readl(intel_i830_private.registers+I810_PGETBL_CTL) & 0xfffff000; + temp = readl(intel_private.registers+I810_PGETBL_CTL) & 0xfffff000; global_cache_flush(); /* FIXME: ? */ /* we have to call this as early as possible after the MMIO base address is known */ @@ -1722,41 +1761,127 @@ static const struct agp_bridge_driver intel_7505_driver = { .agp_type_to_mask_type = agp_generic_type_to_mask_type, }; -static int find_i810(u16 device) -{ - struct pci_dev *i810_dev; - - i810_dev = pci_get_device(PCI_VENDOR_ID_INTEL, device, NULL); - if (!i810_dev) - return 0; - intel_i810_private.i810_dev = i810_dev; - return 1; -} +static const struct agp_bridge_driver intel_g33_driver = { + .owner = THIS_MODULE, + .aperture_sizes = intel_i830_sizes, + .size_type = FIXED_APER_SIZE, + .num_aperture_sizes = 4, + .needs_scratch_page = TRUE, + .configure = intel_i915_configure, + .fetch_size = intel_i9xx_fetch_size, + .cleanup = intel_i915_cleanup, + .tlb_flush = intel_i810_tlbflush, + .mask_memory = intel_i965_mask_memory, + .masks = intel_i810_masks, + .agp_enable = intel_i810_agp_enable, + .cache_flush = global_cache_flush, + .create_gatt_table = intel_i915_create_gatt_table, + .free_gatt_table = intel_i830_free_gatt_table, + .insert_memory = intel_i915_insert_entries, + .remove_memory = intel_i915_remove_entries, + .alloc_by_type = intel_i830_alloc_by_type, + .free_by_type = intel_i810_free_by_type, + .agp_alloc_page = agp_generic_alloc_page, + .agp_destroy_page = agp_generic_destroy_page, + .agp_type_to_mask_type = intel_i830_type_to_mask_type, +}; -static int find_i830(u16 device) +static int find_gmch(u16 device) { - struct pci_dev *i830_dev; + struct pci_dev *gmch_device; - i830_dev = pci_get_device(PCI_VENDOR_ID_INTEL, device, NULL); - if (i830_dev && PCI_FUNC(i830_dev->devfn) != 0) { - i830_dev = pci_get_device(PCI_VENDOR_ID_INTEL, - device, i830_dev); + gmch_device = pci_get_device(PCI_VENDOR_ID_INTEL, device, NULL); + if (gmch_device && PCI_FUNC(gmch_device->devfn) != 0) { + gmch_device = pci_get_device(PCI_VENDOR_ID_INTEL, + device, gmch_device); } - if (!i830_dev) + if (!gmch_device) return 0; - intel_i830_private.i830_dev = i830_dev; + intel_private.pcidev = gmch_device; return 1; } +/* Table to describe Intel GMCH and AGP/PCIE GART drivers. At least one of + * driver and gmch_driver must be non-null, and find_gmch will determine + * which one should be used if a gmch_chip_id is present. + */ +static const struct intel_driver_description { + unsigned int chip_id; + unsigned int gmch_chip_id; + unsigned int multi_gmch_chip; /* if we have more gfx chip type on this HB. */ + char *name; + const struct agp_bridge_driver *driver; + const struct agp_bridge_driver *gmch_driver; +} intel_agp_chipsets[] = { + { PCI_DEVICE_ID_INTEL_82443LX_0, 0, 0, "440LX", &intel_generic_driver, NULL }, + { PCI_DEVICE_ID_INTEL_82443BX_0, 0, 0, "440BX", &intel_generic_driver, NULL }, + { PCI_DEVICE_ID_INTEL_82443GX_0, 0, 0, "440GX", &intel_generic_driver, NULL }, + { PCI_DEVICE_ID_INTEL_82810_MC1, PCI_DEVICE_ID_INTEL_82810_IG1, 0, "i810", + NULL, &intel_810_driver }, + { PCI_DEVICE_ID_INTEL_82810_MC3, PCI_DEVICE_ID_INTEL_82810_IG3, 0, "i810", + NULL, &intel_810_driver }, + { PCI_DEVICE_ID_INTEL_82810E_MC, PCI_DEVICE_ID_INTEL_82810E_IG, 0, "i810", + NULL, &intel_810_driver }, + { PCI_DEVICE_ID_INTEL_82815_MC, PCI_DEVICE_ID_INTEL_82815_CGC, 0, "i815", + &intel_815_driver, &intel_810_driver }, + { PCI_DEVICE_ID_INTEL_82820_HB, 0, 0, "i820", &intel_820_driver, NULL }, + { PCI_DEVICE_ID_INTEL_82820_UP_HB, 0, 0, "i820", &intel_820_driver, NULL }, + { PCI_DEVICE_ID_INTEL_82830_HB, PCI_DEVICE_ID_INTEL_82830_CGC, 0, "830M", + &intel_830mp_driver, &intel_830_driver }, + { PCI_DEVICE_ID_INTEL_82840_HB, 0, 0, "i840", &intel_840_driver, NULL }, + { PCI_DEVICE_ID_INTEL_82845_HB, 0, 0, "845G", &intel_845_driver, NULL }, + { PCI_DEVICE_ID_INTEL_82845G_HB, PCI_DEVICE_ID_INTEL_82845G_IG, 0, "830M", + &intel_845_driver, &intel_830_driver }, + { PCI_DEVICE_ID_INTEL_82850_HB, 0, 0, "i850", &intel_850_driver, NULL }, + { PCI_DEVICE_ID_INTEL_82855PM_HB, 0, 0, "855PM", &intel_845_driver, NULL }, + { PCI_DEVICE_ID_INTEL_82855GM_HB, PCI_DEVICE_ID_INTEL_82855GM_IG, 0, "855GM", + &intel_845_driver, &intel_830_driver }, + { PCI_DEVICE_ID_INTEL_82860_HB, 0, 0, "i860", &intel_860_driver, NULL }, + { PCI_DEVICE_ID_INTEL_82865_HB, PCI_DEVICE_ID_INTEL_82865_IG, 0, "865", + &intel_845_driver, &intel_830_driver }, + { PCI_DEVICE_ID_INTEL_82875_HB, 0, 0, "i875", &intel_845_driver, NULL }, + { PCI_DEVICE_ID_INTEL_82915G_HB, PCI_DEVICE_ID_INTEL_82915G_IG, 0, "915G", + NULL, &intel_915_driver }, + { PCI_DEVICE_ID_INTEL_82915GM_HB, PCI_DEVICE_ID_INTEL_82915GM_IG, 0, "915GM", + NULL, &intel_915_driver }, + { PCI_DEVICE_ID_INTEL_82945G_HB, PCI_DEVICE_ID_INTEL_82945G_IG, 0, "945G", + NULL, &intel_915_driver }, + { PCI_DEVICE_ID_INTEL_82945GM_HB, PCI_DEVICE_ID_INTEL_82945GM_IG, 1, "945GM", + NULL, &intel_915_driver }, + { PCI_DEVICE_ID_INTEL_82945GM_HB, PCI_DEVICE_ID_INTEL_82945GME_IG, 0, "945GME", + NULL, &intel_915_driver }, + { PCI_DEVICE_ID_INTEL_82946GZ_HB, PCI_DEVICE_ID_INTEL_82946GZ_IG, 0, "946GZ", + NULL, &intel_i965_driver }, + { PCI_DEVICE_ID_INTEL_82965G_1_HB, PCI_DEVICE_ID_INTEL_82965G_1_IG, 0, "965G", + NULL, &intel_i965_driver }, + { PCI_DEVICE_ID_INTEL_82965Q_HB, PCI_DEVICE_ID_INTEL_82965Q_IG, 0, "965Q", + NULL, &intel_i965_driver }, + { PCI_DEVICE_ID_INTEL_82965G_HB, PCI_DEVICE_ID_INTEL_82965G_IG, 0, "965G", + NULL, &intel_i965_driver }, + { PCI_DEVICE_ID_INTEL_82965GM_HB, PCI_DEVICE_ID_INTEL_82965GM_IG, 1, "965GM", + NULL, &intel_i965_driver }, + { PCI_DEVICE_ID_INTEL_82965GM_HB, PCI_DEVICE_ID_INTEL_82965GME_IG, 0, "965GME/GLE", + NULL, &intel_i965_driver }, + { PCI_DEVICE_ID_INTEL_7505_0, 0, 0, "E7505", &intel_7505_driver, NULL }, + { PCI_DEVICE_ID_INTEL_7205_0, 0, 0, "E7205", &intel_7505_driver, NULL }, + { PCI_DEVICE_ID_INTEL_G33_HB, PCI_DEVICE_ID_INTEL_G33_IG, 0, "G33", + NULL, &intel_g33_driver }, + { PCI_DEVICE_ID_INTEL_Q35_HB, PCI_DEVICE_ID_INTEL_Q35_IG, 0, "Q35", + NULL, &intel_g33_driver }, + { PCI_DEVICE_ID_INTEL_Q33_HB, PCI_DEVICE_ID_INTEL_Q33_IG, 0, "Q33", + NULL, &intel_g33_driver }, + { 0, 0, 0, NULL, NULL, NULL } +}; + static int __devinit agp_intel_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { struct agp_bridge_data *bridge; - char *name = "(unknown)"; u8 cap_ptr = 0; struct resource *r; + int i; cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP); @@ -1764,195 +1889,49 @@ static int __devinit agp_intel_probe(struct pci_dev *pdev, if (!bridge) return -ENOMEM; - switch (pdev->device) { - case PCI_DEVICE_ID_INTEL_82443LX_0: - bridge->driver = &intel_generic_driver; - name = "440LX"; - break; - case PCI_DEVICE_ID_INTEL_82443BX_0: - bridge->driver = &intel_generic_driver; - name = "440BX"; - break; - case PCI_DEVICE_ID_INTEL_82443GX_0: - bridge->driver = &intel_generic_driver; - name = "440GX"; - break; - case PCI_DEVICE_ID_INTEL_82810_MC1: - name = "i810"; - if (!find_i810(PCI_DEVICE_ID_INTEL_82810_IG1)) - goto fail; - bridge->driver = &intel_810_driver; - break; - case PCI_DEVICE_ID_INTEL_82810_MC3: - name = "i810 DC100"; - if (!find_i810(PCI_DEVICE_ID_INTEL_82810_IG3)) - goto fail; - bridge->driver = &intel_810_driver; - break; - case PCI_DEVICE_ID_INTEL_82810E_MC: - name = "i810 E"; - if (!find_i810(PCI_DEVICE_ID_INTEL_82810E_IG)) - goto fail; - bridge->driver = &intel_810_driver; - break; - case PCI_DEVICE_ID_INTEL_82815_MC: - /* - * The i815 can operate either as an i810 style - * integrated device, or as an AGP4X motherboard. - */ - if (find_i810(PCI_DEVICE_ID_INTEL_82815_CGC)) - bridge->driver = &intel_810_driver; - else - bridge->driver = &intel_815_driver; - name = "i815"; - break; - case PCI_DEVICE_ID_INTEL_82820_HB: - case PCI_DEVICE_ID_INTEL_82820_UP_HB: - bridge->driver = &intel_820_driver; - name = "i820"; - break; - case PCI_DEVICE_ID_INTEL_82830_HB: - if (find_i830(PCI_DEVICE_ID_INTEL_82830_CGC)) - bridge->driver = &intel_830_driver; - else - bridge->driver = &intel_830mp_driver; - name = "830M"; - break; - case PCI_DEVICE_ID_INTEL_82840_HB: - bridge->driver = &intel_840_driver; - name = "i840"; - break; - case PCI_DEVICE_ID_INTEL_82845_HB: - bridge->driver = &intel_845_driver; - name = "i845"; - break; - case PCI_DEVICE_ID_INTEL_82845G_HB: - if (find_i830(PCI_DEVICE_ID_INTEL_82845G_IG)) - bridge->driver = &intel_830_driver; - else - bridge->driver = &intel_845_driver; - name = "845G"; - break; - case PCI_DEVICE_ID_INTEL_82850_HB: - bridge->driver = &intel_850_driver; - name = "i850"; - break; - case PCI_DEVICE_ID_INTEL_82855PM_HB: - bridge->driver = &intel_845_driver; - name = "855PM"; - break; - case PCI_DEVICE_ID_INTEL_82855GM_HB: - if (find_i830(PCI_DEVICE_ID_INTEL_82855GM_IG)) { - bridge->driver = &intel_830_driver; - name = "855"; - } else { - bridge->driver = &intel_845_driver; - name = "855GM"; + for (i = 0; intel_agp_chipsets[i].name != NULL; i++) { + /* In case that multiple models of gfx chip may + stand on same host bridge type, this can be + sure we detect the right IGD. */ + if (pdev->device == intel_agp_chipsets[i].chip_id) { + if ((intel_agp_chipsets[i].gmch_chip_id != 0) && + find_gmch(intel_agp_chipsets[i].gmch_chip_id)) { + bridge->driver = + intel_agp_chipsets[i].gmch_driver; + break; + } else if (intel_agp_chipsets[i].multi_gmch_chip) { + continue; + } else { + bridge->driver = intel_agp_chipsets[i].driver; + break; + } } - break; - case PCI_DEVICE_ID_INTEL_82860_HB: - bridge->driver = &intel_860_driver; - name = "i860"; - break; - case PCI_DEVICE_ID_INTEL_82865_HB: - if (find_i830(PCI_DEVICE_ID_INTEL_82865_IG)) - bridge->driver = &intel_830_driver; - else - bridge->driver = &intel_845_driver; - name = "865"; - break; - case PCI_DEVICE_ID_INTEL_82875_HB: - bridge->driver = &intel_845_driver; - name = "i875"; - break; - case PCI_DEVICE_ID_INTEL_82915G_HB: - if (find_i830(PCI_DEVICE_ID_INTEL_82915G_IG)) - bridge->driver = &intel_915_driver; - else - bridge->driver = &intel_845_driver; - name = "915G"; - break; - case PCI_DEVICE_ID_INTEL_82915GM_HB: - if (find_i830(PCI_DEVICE_ID_INTEL_82915GM_IG)) - bridge->driver = &intel_915_driver; - else - bridge->driver = &intel_845_driver; - name = "915GM"; - break; - case PCI_DEVICE_ID_INTEL_82945G_HB: - if (find_i830(PCI_DEVICE_ID_INTEL_82945G_IG)) - bridge->driver = &intel_915_driver; - else - bridge->driver = &intel_845_driver; - name = "945G"; - break; - case PCI_DEVICE_ID_INTEL_82945GM_HB: - if (find_i830(PCI_DEVICE_ID_INTEL_82945GM_IG)) - bridge->driver = &intel_915_driver; - else - bridge->driver = &intel_845_driver; - name = "945GM"; - break; - case PCI_DEVICE_ID_INTEL_82946GZ_HB: - if (find_i830(PCI_DEVICE_ID_INTEL_82946GZ_IG)) - bridge->driver = &intel_i965_driver; - else - bridge->driver = &intel_845_driver; - name = "946GZ"; - break; - case PCI_DEVICE_ID_INTEL_82965G_1_HB: - if (find_i830(PCI_DEVICE_ID_INTEL_82965G_1_IG)) - bridge->driver = &intel_i965_driver; - else - bridge->driver = &intel_845_driver; - name = "965G"; - break; - case PCI_DEVICE_ID_INTEL_82965Q_HB: - if (find_i830(PCI_DEVICE_ID_INTEL_82965Q_IG)) - bridge->driver = &intel_i965_driver; - else - bridge->driver = &intel_845_driver; - name = "965Q"; - break; - case PCI_DEVICE_ID_INTEL_82965G_HB: - if (find_i830(PCI_DEVICE_ID_INTEL_82965G_IG)) - bridge->driver = &intel_i965_driver; - else - bridge->driver = &intel_845_driver; - name = "965G"; - break; - case PCI_DEVICE_ID_INTEL_82965GM_HB: - if (find_i830(PCI_DEVICE_ID_INTEL_82965GM_IG)) - bridge->driver = &intel_i965_driver; - else - bridge->driver = &intel_845_driver; - name = "965GM"; - break; - case PCI_DEVICE_ID_INTEL_7505_0: - bridge->driver = &intel_7505_driver; - name = "E7505"; - break; - case PCI_DEVICE_ID_INTEL_7205_0: - bridge->driver = &intel_7505_driver; - name = "E7205"; - break; - default: + } + + if (intel_agp_chipsets[i].name == NULL) { if (cap_ptr) - printk(KERN_WARNING PFX "Unsupported Intel chipset (device id: %04x)\n", - pdev->device); + printk(KERN_WARNING PFX "Unsupported Intel chipset" + "(device id: %04x)\n", pdev->device); agp_put_bridge(bridge); return -ENODEV; - }; + } + + if (bridge->driver == NULL) { + /* bridge has no AGP and no IGD detected */ + if (cap_ptr) + printk(KERN_WARNING PFX "Failed to find bridge device " + "(chip_id: %04x)\n", + intel_agp_chipsets[i].gmch_chip_id); + agp_put_bridge(bridge); + return -ENODEV; + } bridge->dev = pdev; bridge->capndx = cap_ptr; + bridge->dev_private_data = &intel_private; - if (bridge->driver == &intel_810_driver) - bridge->dev_private_data = &intel_i810_private; - else if (bridge->driver == &intel_830_driver) - bridge->dev_private_data = &intel_i830_private; - - printk(KERN_INFO PFX "Detected an Intel %s Chipset.\n", name); + printk(KERN_INFO PFX "Detected an Intel %s Chipset.\n", + intel_agp_chipsets[i].name); /* * The following fixes the case where the BIOS has "forgotten" to @@ -1988,12 +1967,6 @@ static int __devinit agp_intel_probe(struct pci_dev *pdev, pci_set_drvdata(pdev, bridge); return agp_add_bridge(bridge); - -fail: - printk(KERN_ERR PFX "Detected an Intel %s chipset, " - "but could not find the secondary device.\n", name); - agp_put_bridge(bridge); - return -ENODEV; } static void __devexit agp_intel_remove(struct pci_dev *pdev) @@ -2002,10 +1975,8 @@ static void __devexit agp_intel_remove(struct pci_dev *pdev) agp_remove_bridge(bridge); - if (intel_i810_private.i810_dev) - pci_dev_put(intel_i810_private.i810_dev); - if (intel_i830_private.i830_dev) - pci_dev_put(intel_i830_private.i830_dev); + if (intel_private.pcidev) + pci_dev_put(intel_private.pcidev); agp_put_bridge(bridge); } @@ -2021,10 +1992,8 @@ static int agp_intel_resume(struct pci_dev *pdev) * as host bridge (00:00) resumes before graphics device (02:00), * then our access to its pci space can work right. */ - if (intel_i810_private.i810_dev) - pci_restore_state(intel_i810_private.i810_dev); - if (intel_i830_private.i830_dev) - pci_restore_state(intel_i830_private.i830_dev); + if (intel_private.pcidev) + pci_restore_state(intel_private.pcidev); if (bridge->driver == &intel_generic_driver) intel_configure(); @@ -2087,6 +2056,9 @@ static struct pci_device_id agp_intel_pci_table[] = { ID(PCI_DEVICE_ID_INTEL_82965Q_HB), ID(PCI_DEVICE_ID_INTEL_82965G_HB), ID(PCI_DEVICE_ID_INTEL_82965GM_HB), + ID(PCI_DEVICE_ID_INTEL_G33_HB), + ID(PCI_DEVICE_ID_INTEL_Q35_HB), + ID(PCI_DEVICE_ID_INTEL_Q33_HB), { } }; diff --git a/drivers/char/agp/uninorth-agp.c b/drivers/char/agp/uninorth-agp.c index 91b062126a68..42c0a600b1ac 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/agp/via-agp.c b/drivers/char/agp/via-agp.c index a2bb4eccaab4..9aaf401a8975 100644 --- a/drivers/char/agp/via-agp.c +++ b/drivers/char/agp/via-agp.c @@ -384,9 +384,9 @@ static struct agp_device_ids via_agp_device_ids[] __devinitdata = .device_id = PCI_DEVICE_ID_VIA_P4M800CE, .chipset_name = "VT3314", }, - /* CX700 */ + /* VT3324 / CX700 */ { - .device_id = PCI_DEVICE_ID_VIA_CX700, + .device_id = PCI_DEVICE_ID_VIA_VT3324, .chipset_name = "CX700", }, /* VT3336 */ @@ -540,7 +540,7 @@ static const struct pci_device_id agp_via_pci_table[] = { ID(PCI_DEVICE_ID_VIA_83_87XX_1), ID(PCI_DEVICE_ID_VIA_3296_0), ID(PCI_DEVICE_ID_VIA_P4M800CE), - ID(PCI_DEVICE_ID_VIA_CX700), + ID(PCI_DEVICE_ID_VIA_VT3324), ID(PCI_DEVICE_ID_VIA_VT3336), ID(PCI_DEVICE_ID_VIA_P4M890), { } diff --git a/drivers/char/amiserial.c b/drivers/char/amiserial.c index 0e2b72f2b887..4eaceabd8cea 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 c70d52ace8b2..ed53f541d9e8 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 b99b7561260d..fd40b959afdd 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 c02d9e99e050..fe6d2407baed 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 16dc5d1d3cb4..ca376b92162c 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) @@ -1103,6 +1061,7 @@ static void cyy_intr_chip(struct cyclades_card *cinfo, int chip, if (data & info->ignore_status_mask) { info->icount.rx++; + spin_unlock(&cinfo->card_lock); return; } if (tty_buffer_request_room(tty, 1)) { @@ -1110,7 +1069,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 +1082,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 +1094,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 +1113,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 +1145,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 +1157,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 +1182,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 +1235,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 +1290,6 @@ static void cyy_intr_chip(struct cyclades_card *cinfo, int chip, 0); info->icount.tx++; char_count--; - } else { } } } @@ -1353,19 +1309,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 +1351,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 +1365,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 +1391,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 +1408,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 +1423,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 +1455,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 +1466,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 +1484,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 +1516,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 +1547,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 +1557,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 +1589,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 +1607,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 +1633,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 +1644,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 +1663,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 +1675,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 +1690,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 +1740,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 +1772,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 +1782,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 +1804,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 +1830,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 +1851,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 +1869,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 +1882,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 +1892,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 +1907,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 +1941,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 +1972,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 +1992,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 +2001,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 +2039,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 +2079,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 +2135,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 +2174,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 +2188,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 +2196,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 +2223,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 +2241,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 +2266,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 +2274,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 +2298,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 +2318,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 +2327,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 +2344,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 +2376,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 +2411,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 +2420,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 +2454,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 +2476,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 +2506,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 +2532,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 +2540,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 +2553,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 +2569,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 +2578,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 +2588,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 +2630,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 +2650,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 +2663,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 +2695,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 +2720,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 +2811,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 +2826,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 +2842,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 +2862,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 +2875,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 +2886,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 +2895,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 +2919,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 +2936,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 +2991,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 +3022,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 +3055,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 +3178,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 +3212,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 +3226,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 +3251,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 +3265,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 +3283,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 +3343,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 +3361,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 +3379,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 +3394,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 +3423,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 +3500,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 +3529,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 +3546,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 +3571,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 +3598,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 +3613,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 +3631,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 +3644,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 +3658,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 +3678,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 +3750,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 +3768,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 +3787,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 +3823,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 +3851,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 +3885,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 +3947,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 +3958,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 +4004,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 +4039,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 +4063,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 +4107,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 +4121,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 +4156,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 +4169,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 +4185,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 +4205,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 +4230,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 +4244,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 +4270,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 +4288,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 +4301,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 +4400,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 +4414,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 +4430,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 +4545,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 +4562,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 +4571,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 +4579,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 +4590,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 +4603,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 +4648,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 +4667,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 +4713,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 +4738,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 +5055,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 +5137,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 +5159,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 +5176,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 19df0e879b1b..000000000000 --- 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/Kconfig b/drivers/char/drm/Kconfig index ef833a1c27eb..0b7ffa5191c6 100644 --- a/drivers/char/drm/Kconfig +++ b/drivers/char/drm/Kconfig @@ -6,7 +6,7 @@ # config DRM tristate "Direct Rendering Manager (XFree86 4.1.0 and higher DRI support)" - depends on (AGP || AGP=n) && PCI + depends on (AGP || AGP=n) && PCI && !EMULATED_CMPXCHG help Kernel-level support for the Direct Rendering Infrastructure (DRI) introduced in XFree86 4.0. If you say Y here, you need to select diff --git a/drivers/char/drm/ati_pcigart.c b/drivers/char/drm/ati_pcigart.c index bd7be09ea53d..5b91bc04ea4e 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/drmP.h b/drivers/char/drm/drmP.h index 80041d5b792d..d494315752a2 100644 --- a/drivers/char/drm/drmP.h +++ b/drivers/char/drm/drmP.h @@ -519,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; /* diff --git a/drivers/char/drm/drm_dma.c b/drivers/char/drm/drm_dma.c index 892db7096986..32ed19c9ec1c 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_drawable.c b/drivers/char/drm/drm_drawable.c index de37d5f74563..b33313be2547 100644 --- a/drivers/char/drm/drm_drawable.c +++ b/drivers/char/drm/drm_drawable.c @@ -172,38 +172,49 @@ int drm_rmdraw(DRM_IOCTL_ARGS) bitfield_length = idx + 1; - if (idx != id / (8 * sizeof(*bitfield))) - bitfield = drm_alloc(bitfield_length * - sizeof(*bitfield), DRM_MEM_BUFS); + bitfield = NULL; - if (!bitfield && bitfield_length) { - bitfield = dev->drw_bitfield; - bitfield_length = dev->drw_bitfield_length; + if (bitfield_length) { + if (bitfield_length != dev->drw_bitfield_length) + bitfield = drm_alloc(bitfield_length * + sizeof(*bitfield), + DRM_MEM_BUFS); + + if (!bitfield) { + bitfield = dev->drw_bitfield; + bitfield_length = dev->drw_bitfield_length; + } } } if (bitfield != dev->drw_bitfield) { info_length = 8 * sizeof(*bitfield) * bitfield_length; - info = drm_alloc(info_length * sizeof(*info), DRM_MEM_BUFS); + if (info_length) { + info = drm_alloc(info_length * sizeof(*info), + DRM_MEM_BUFS); - if (!info && info_length) { - info = dev->drw_info; - info_length = dev->drw_info_length; - } + if (!info) { + info = dev->drw_info; + info_length = dev->drw_info_length; + } + } else + info = NULL; spin_lock_irqsave(&dev->drw_lock, irqflags); - memcpy(bitfield, dev->drw_bitfield, bitfield_length * - sizeof(*bitfield)); + if (bitfield) + memcpy(bitfield, dev->drw_bitfield, bitfield_length * + sizeof(*bitfield)); drm_free(dev->drw_bitfield, sizeof(*bitfield) * dev->drw_bitfield_length, DRM_MEM_BUFS); dev->drw_bitfield = bitfield; dev->drw_bitfield_length = bitfield_length; if (info != dev->drw_info) { - memcpy(info, dev->drw_info, info_length * - sizeof(*info)); + if (info) + memcpy(info, dev->drw_info, info_length * + sizeof(*info)); drm_free(dev->drw_info, sizeof(*info) * dev->drw_info_length, DRM_MEM_BUFS); dev->drw_info = info; diff --git a/drivers/char/drm/drm_drv.c b/drivers/char/drm/drm_drv.c index 26bec30ee86e..8e77b7ed0f44 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,11 @@ int drm_ioctl(struct inode *inode, struct file *filp, (long)old_encode_dev(priv->head->device), priv->authenticated); - if ((nr >= DRIVER_IOCTL_COUNT) && + 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)) + 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]; diff --git a/drivers/char/drm/drm_os_linux.h b/drivers/char/drm/drm_os_linux.h index 2908b72daa6e..0fe7b4497927 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 01cf482d2d00..30b200b01314 100644 --- a/drivers/char/drm/drm_pciids.h +++ b/drivers/char/drm/drm_pciids.h @@ -102,12 +102,20 @@ {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, 0x5954, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS400|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART}, \ + {0x1002, 0x5955, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS400|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART}, \ + {0x1002, 0x5974, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS400|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART}, \ + {0x1002, 0x5975, 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}, \ {0x1002, 0x5964, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \ {0x1002, 0x5965, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \ {0x1002, 0x5969, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100}, \ + {0x1002, 0x5a41, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS400|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART}, \ + {0x1002, 0x5a42, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS400|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART}, \ + {0x1002, 0x5a61, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS400|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART}, \ + {0x1002, 0x5a62, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS400|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART}, \ {0x1002, 0x5b60, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \ {0x1002, 0x5b62, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \ {0x1002, 0x5b63, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \ @@ -211,6 +219,8 @@ {0x1039, 0x6300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {0x1039, 0x6330, PCI_ANY_ID, PCI_ANY_ID, 0, 0, SIS_CHIP_315}, \ {0x1039, 0x7300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x18CA, 0x0040, PCI_ANY_ID, PCI_ANY_ID, 0, 0, SIS_CHIP_315}, \ + {0x18CA, 0x0042, PCI_ANY_ID, PCI_ANY_ID, 0, 0, SIS_CHIP_315}, \ {0, 0, 0} #define tdfx_PCI_IDS \ @@ -292,10 +302,15 @@ {0x8086, 0x2592, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {0x8086, 0x2772, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {0x8086, 0x27a2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x8086, 0x27ae, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {0x8086, 0x2972, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {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, 0x29b2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x8086, 0x29c2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x8086, 0x29d2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {0x8086, 0x2a02, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x8086, 0x2a12, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {0, 0, 0} diff --git a/drivers/char/drm/drm_vm.c b/drivers/char/drm/drm_vm.c index 35540cfb43dd..b5c5b9fa84c3 100644 --- a/drivers/char/drm/drm_vm.c +++ b/drivers/char/drm/drm_vm.c @@ -157,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, diff --git a/drivers/char/drm/i915_dma.c b/drivers/char/drm/i915_dma.c index 1ba15d9a171a..ea52740af4f6 100644 --- a/drivers/char/drm/i915_dma.c +++ b/drivers/char/drm/i915_dma.c @@ -35,7 +35,12 @@ dev->pci_device == 0x2982 || \ dev->pci_device == 0x2992 || \ dev->pci_device == 0x29A2 || \ - dev->pci_device == 0x2A02) + dev->pci_device == 0x2A02 || \ + dev->pci_device == 0x2A12) + +#define IS_G33(dev) (dev->pci_device == 0x29b2 || \ + dev->pci_device == 0x29c2 || \ + dev->pci_device == 0x29d2) /* 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 @@ -106,6 +111,12 @@ static int i915_dma_cleanup(drm_device_t * dev) I915_WRITE(0x02080, 0x1ffff000); } + if (dev_priv->status_gfx_addr) { + dev_priv->status_gfx_addr = 0; + drm_core_ioremapfree(&dev_priv->hws_map, dev); + I915_WRITE(0x2080, 0x1ffff000); + } + drm_free(dev->dev_private, sizeof(drm_i915_private_t), DRM_MEM_DRIVER); @@ -179,26 +190,24 @@ static int i915_initialize(drm_device_t * dev, dev_priv->allow_batchbuffer = 1; /* Program Hardware Status Page */ - dev_priv->status_page_dmah = drm_pci_alloc(dev, PAGE_SIZE, PAGE_SIZE, - 0xffffffff); + if (!IS_G33(dev)) { + dev_priv->status_page_dmah = + drm_pci_alloc(dev, PAGE_SIZE, PAGE_SIZE, 0xffffffff); + + if (!dev_priv->status_page_dmah) { + dev->dev_private = (void *)dev_priv; + i915_dma_cleanup(dev); + DRM_ERROR("Can not allocate hardware status page\n"); + return DRM_ERR(ENOMEM); + } + dev_priv->hw_status_page = dev_priv->status_page_dmah->vaddr; + dev_priv->dma_status_page = dev_priv->status_page_dmah->busaddr; - if (!dev_priv->status_page_dmah) { - dev->dev_private = (void *)dev_priv; - i915_dma_cleanup(dev); - DRM_ERROR("Can not allocate hardware status page\n"); - return DRM_ERR(ENOMEM); + memset(dev_priv->hw_status_page, 0, PAGE_SIZE); + I915_WRITE(0x02080, dev_priv->dma_status_page); } - dev_priv->hw_status_page = dev_priv->status_page_dmah->vaddr; - dev_priv->dma_status_page = dev_priv->status_page_dmah->busaddr; - - memset(dev_priv->hw_status_page, 0, PAGE_SIZE); - DRM_DEBUG("hw status page @ %p\n", dev_priv->hw_status_page); - - I915_WRITE(0x02080, dev_priv->dma_status_page); DRM_DEBUG("Enabled hardware status page\n"); - dev->dev_private = (void *)dev_priv; - return 0; } @@ -231,7 +240,10 @@ static int i915_dma_resume(drm_device_t * dev) } DRM_DEBUG("hw status page @ %p\n", dev_priv->hw_status_page); - I915_WRITE(0x02080, dev_priv->dma_status_page); + if (dev_priv->status_gfx_addr != 0) + I915_WRITE(0x02080, dev_priv->status_gfx_addr); + else + I915_WRITE(0x02080, dev_priv->dma_status_page); DRM_DEBUG("Enabled hardware status page\n"); return 0; @@ -739,6 +751,47 @@ static int i915_setparam(DRM_IOCTL_ARGS) return 0; } +static int i915_set_status_page(DRM_IOCTL_ARGS) +{ + DRM_DEVICE; + drm_i915_private_t *dev_priv = dev->dev_private; + drm_i915_hws_addr_t hws; + + if (!dev_priv) { + DRM_ERROR("%s called with no initialization\n", __FUNCTION__); + return DRM_ERR(EINVAL); + } + DRM_COPY_FROM_USER_IOCTL(hws, (drm_i915_hws_addr_t __user *) data, + sizeof(hws)); + printk(KERN_DEBUG "set status page addr 0x%08x\n", (u32)hws.addr); + + dev_priv->status_gfx_addr = hws.addr & (0x1ffff<<12); + + dev_priv->hws_map.offset = dev->agp->agp_info.aper_base + hws.addr; + dev_priv->hws_map.size = 4*1024; + dev_priv->hws_map.type = 0; + dev_priv->hws_map.flags = 0; + dev_priv->hws_map.mtrr = 0; + + drm_core_ioremap(&dev_priv->hws_map, dev); + if (dev_priv->hws_map.handle == NULL) { + dev->dev_private = (void *)dev_priv; + i915_dma_cleanup(dev); + dev_priv->status_gfx_addr = 0; + DRM_ERROR("can not ioremap virtual address for" + " G33 hw status page\n"); + return DRM_ERR(ENOMEM); + } + dev_priv->hw_status_page = dev_priv->hws_map.handle; + + memset(dev_priv->hw_status_page, 0, PAGE_SIZE); + I915_WRITE(0x02080, dev_priv->status_gfx_addr); + DRM_DEBUG("load hws 0x2080 with gfx mem 0x%x\n", + dev_priv->status_gfx_addr); + DRM_DEBUG("load hws at %p\n", dev_priv->hw_status_page); + return 0; +} + int i915_driver_load(drm_device_t *dev, unsigned long flags) { /* i915 has 4 more counters */ @@ -785,6 +838,7 @@ drm_ioctl_desc_t i915_ioctls[] = { [DRM_IOCTL_NR(DRM_I915_SET_VBLANK_PIPE)] = { i915_vblank_pipe_set, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY }, [DRM_IOCTL_NR(DRM_I915_GET_VBLANK_PIPE)] = { i915_vblank_pipe_get, DRM_AUTH }, [DRM_IOCTL_NR(DRM_I915_VBLANK_SWAP)] = {i915_vblank_swap, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_I915_HWS_ADDR)] = {i915_set_status_page, DRM_AUTH}, }; int i915_max_ioctl = DRM_ARRAY_SIZE(i915_ioctls); diff --git a/drivers/char/drm/i915_drm.h b/drivers/char/drm/i915_drm.h index 96a468886a7a..7b7b68b96f31 100644 --- a/drivers/char/drm/i915_drm.h +++ b/drivers/char/drm/i915_drm.h @@ -142,6 +142,7 @@ typedef struct _drm_i915_sarea { #define DRM_I915_SET_VBLANK_PIPE 0x0d #define DRM_I915_GET_VBLANK_PIPE 0x0e #define DRM_I915_VBLANK_SWAP 0x0f +#define DRM_I915_HWS_ADDR 0x11 #define DRM_IOCTL_I915_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT, drm_i915_init_t) #define DRM_IOCTL_I915_FLUSH DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLUSH) @@ -262,4 +263,8 @@ typedef struct drm_i915_vblank_swap { unsigned int sequence; } drm_i915_vblank_swap_t; +typedef struct drm_i915_hws_addr { + uint64_t addr; +} drm_i915_hws_addr_t; + #endif /* _I915_DRM_H_ */ diff --git a/drivers/char/drm/i915_drv.h b/drivers/char/drm/i915_drv.h index 93cdcfe6aa84..85e323acb95d 100644 --- a/drivers/char/drm/i915_drv.h +++ b/drivers/char/drm/i915_drv.h @@ -91,6 +91,8 @@ typedef struct drm_i915_private { void *hw_status_page; dma_addr_t dma_status_page; unsigned long counter; + unsigned int status_gfx_addr; + drm_local_map_t hws_map; unsigned int cpp; int back_offset; diff --git a/drivers/char/drm/i915_irq.c b/drivers/char/drm/i915_irq.c index 78c1ae28f17c..b92062a239f1 100644 --- a/drivers/char/drm/i915_irq.c +++ b/drivers/char/drm/i915_irq.c @@ -582,7 +582,7 @@ void i915_driver_irq_postinstall(drm_device_t * dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - dev_priv->swaps_lock = SPIN_LOCK_UNLOCKED; + spin_lock_init(&dev_priv->swaps_lock); INIT_LIST_HEAD(&dev_priv->vbl_swaps.head); dev_priv->swaps_pending = 0; diff --git a/drivers/char/drm/r128_cce.c b/drivers/char/drm/r128_cce.c index db5a60450e68..1014602c43a7 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 f1efb49de8df..9086835686dc 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 a881f96c983e..ecda760ae8c0 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 c1850ecac302..68338389d836 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; @@ -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 8d6350dd5360..66c4b6fed04f 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 8b105f1460a7..54f49ef4bef0 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_ioc32.c b/drivers/char/drm/radeon_ioc32.c index 1f1f9cc055a4..56decda2a71f 100644 --- a/drivers/char/drm/radeon_ioc32.c +++ b/drivers/char/drm/radeon_ioc32.c @@ -349,6 +349,36 @@ static int compat_radeon_irq_emit(struct file *file, unsigned int cmd, DRM_IOCTL_RADEON_IRQ_EMIT, (unsigned long)request); } +/* The two 64-bit arches where alignof(u64)==4 in 32-bit code */ +#if defined (CONFIG_X86_64) || defined(CONFIG_IA64) +typedef struct drm_radeon_setparam32 { + int param; + u64 value; +} __attribute__((packed)) drm_radeon_setparam32_t; + +static int compat_radeon_cp_setparam(struct file *file, unsigned int cmd, + unsigned long arg) +{ + drm_radeon_setparam32_t req32; + drm_radeon_setparam_t __user *request; + + if (copy_from_user(&req32, (void __user *) arg, sizeof(req32))) + return -EFAULT; + + request = compat_alloc_user_space(sizeof(*request)); + if (!access_ok(VERIFY_WRITE, request, sizeof(*request)) + || __put_user(req32.param, &request->param) + || __put_user((void __user *)(unsigned long)req32.value, + &request->value)) + return -EFAULT; + + return drm_ioctl(file->f_dentry->d_inode, file, + DRM_IOCTL_RADEON_SETPARAM, (unsigned long) request); +} +#else +#define compat_radeon_cp_setparam NULL +#endif /* X86_64 || IA64 */ + drm_ioctl_compat_t *radeon_compat_ioctls[] = { [DRM_RADEON_CP_INIT] = compat_radeon_cp_init, [DRM_RADEON_CLEAR] = compat_radeon_cp_clear, @@ -357,6 +387,7 @@ drm_ioctl_compat_t *radeon_compat_ioctls[] = { [DRM_RADEON_VERTEX2] = compat_radeon_cp_vertex2, [DRM_RADEON_CMDBUF] = compat_radeon_cp_cmdbuf, [DRM_RADEON_GETPARAM] = compat_radeon_cp_getparam, + [DRM_RADEON_SETPARAM] = compat_radeon_cp_setparam, [DRM_RADEON_ALLOC] = compat_radeon_mem_alloc, [DRM_RADEON_IRQ_EMIT] = compat_radeon_irq_emit, }; diff --git a/drivers/char/drm/radeon_state.c b/drivers/char/drm/radeon_state.c index 938eccb78cc0..98c5f1d3a8e7 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.h b/drivers/char/drm/sis_drv.h index 2b8d6f6ed7c0..70d4ede75fe8 100644 --- a/drivers/char/drm/sis_drv.h +++ b/drivers/char/drm/sis_drv.h @@ -33,11 +33,11 @@ #define DRIVER_AUTHOR "SIS, Tungsten Graphics" #define DRIVER_NAME "sis" -#define DRIVER_DESC "SIS 300/630/540" -#define DRIVER_DATE "20060704" +#define DRIVER_DESC "SIS 300/630/540 and XGI V3XE/V5/V8" +#define DRIVER_DATE "20070626" #define DRIVER_MAJOR 1 -#define DRIVER_MINOR 2 -#define DRIVER_PATCHLEVEL 1 +#define DRIVER_MINOR 3 +#define DRIVER_PATCHLEVEL 0 enum sis_family { SIS_OTHER = 0, diff --git a/drivers/char/drm/via_dma.c b/drivers/char/drm/via_dma.c index c0539c6299cf..13a9c5ca4593 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.h b/drivers/char/drm/via_drv.h index 8b8778d4a423..b46ca8e6306d 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/ds1620.c b/drivers/char/ds1620.c index 3d7efc26aad6..334ad5bbe6b6 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 db984e481d4c..9b8278e1f4f8 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 d8dbdb916232..abde6ddefe69 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 77f58ed6d59a..020011495d91 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 de5be30484ad..c6c56fb8ba50 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 23b25ada65ea..9e1fc02967ff 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 ae76a9ffe89f..0e8ceea5ea78 100644 --- a/drivers/char/hangcheck-timer.c +++ b/drivers/char/hangcheck-timer.c @@ -44,12 +44,11 @@ #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> #include <linux/sysrq.h> - +#include <linux/timer.h> #define VERSION_STR "0.9.0" diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c index 0f9ed7b46a6d..322bc5f7d86b 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 ec420fe8a908..b37f1d5a5be6 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 94a542e20efb..79711aa4b41d 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 5f3acd8e64b8..7cda04b33534 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 c41fa19454e3..c8b7300e2fb1 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 cc1046e6ee02..4ae9811d1a6c 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 000000000000..fa6040b6c8f2 --- /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/i8k.c b/drivers/char/i8k.c index 353d9f3cf8d7..0289705967de 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 a48da02aad2f..932264a657d0 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 a6dcb2918157..b894f67fdf14 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 e22146546add..78e1b962fe35 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; @@ -1859,10 +1915,10 @@ static __devinit int try_init_acpi(struct SPMITable *spmi) if (spmi->addr.space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) { info->io_setup = mem_setup; - info->io.addr_type = IPMI_IO_ADDR_SPACE; + info->io.addr_type = IPMI_MEM_ADDR_SPACE; } else if (spmi->addr.space_id == ACPI_ADR_SPACE_SYSTEM_IO) { info->io_setup = port_setup; - info->io.addr_type = IPMI_MEM_ADDR_SPACE; + info->io.addr_type = IPMI_IO_ADDR_SPACE; } else { kfree(info); printk("ipmi_si: Unknown ACPI I/O Address type\n"); @@ -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)) { @@ -2818,6 +2974,10 @@ static __devinit int init_ipmi_si(void) #ifdef CONFIG_PCI pci_unregister_driver(&ipmi_pci_driver); #endif + +#ifdef CONFIG_PPC_OF + of_unregister_platform_driver(&ipmi_of_platform_driver); +#endif driver_unregister(&ipmi_driver); printk("ipmi_si: Unable to find any System Interface(s)\n"); return -ENODEV; @@ -2838,28 +2998,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 +3063,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 6b634e8d9519..41f78e2c158f 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> @@ -50,6 +51,7 @@ #include <linux/string.h> #include <linux/ctype.h> #include <asm/atomic.h> + #ifdef CONFIG_X86_LOCAL_APIC #include <asm/apic.h> #endif diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c index 43ab9edc76f5..761f77740d67 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 c06e86ad1dab..1b094509b1d2 100644 --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c @@ -109,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, }; diff --git a/drivers/char/lp.c b/drivers/char/lp.c index b51d08be0bcf..62051f8b0910 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 5f066963f171..cc9a9d0df979 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 7e975f606924..4e6fb9651a16 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 c09160383a53..6e55cfb9c65a 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 7dbaee8d9402..e0d35c20c04f 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 80a01150b86c..5953a45d7e96 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 f7603b6aeb87..6cde448cd5b2 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 65f2d3a96b85..14557a4822c0 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 6ac3ca4c723c..154f42203b05 100644 --- a/drivers/char/n_tty.c +++ b/drivers/char/n_tty.c @@ -1191,6 +1191,7 @@ static int job_control(struct tty_struct *tty, struct file *file) is_current_pgrp_orphaned()) return -EIO; kill_pgrp(task_pgrp(current), SIGTTIN, 1); + set_thread_flag(TIF_SIGPENDING); return -ERESTARTSYS; } } @@ -1544,21 +1545,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 27c1179ee527..f25facd97bb4 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 e91b43a014b0..fee58e03dbe2 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 f2e4ec4fd407..af88181a17f4 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/ppdev.c b/drivers/char/ppdev.c index 4abd1eff61d6..84ac64fc48a1 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/random.c b/drivers/char/random.c index 46c1b97748b6..7f5271272f91 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -760,7 +760,7 @@ static size_t account(struct entropy_store *r, size_t nbytes, int min, static void extract_buf(struct entropy_store *r, __u8 *out) { - int i, x; + int i; __u32 data[16], buf[5 + SHA_WORKSPACE_WORDS]; sha_init(buf); @@ -772,9 +772,11 @@ static void extract_buf(struct entropy_store *r, __u8 *out) * attempts to find previous ouputs), unless the hash * function can be inverted. */ - for (i = 0, x = 0; i < r->poolinfo->poolwords; i += 16, x+=2) { - sha_transform(buf, (__u8 *)r->pool+i, buf + 5); - add_entropy_words(r, &buf[x % 5], 1); + for (i = 0; i < r->poolinfo->poolwords; i += 16) { + /* hash blocks of 16 words = 512 bits */ + sha_transform(buf, (__u8 *)(r->pool + i), buf + 5); + /* feed back portion of the resulting hash */ + add_entropy_words(r, &buf[i % 5], 1); } /* @@ -782,7 +784,7 @@ static void extract_buf(struct entropy_store *r, __u8 *out) * portion of the pool while mixing, and hash one * final time. */ - __add_entropy_words(r, &buf[x % 5], 1, data); + __add_entropy_words(r, &buf[i % 5], 1, data); sha_transform(buf, (__u8 *)data, buf + 5); /* @@ -792,7 +794,7 @@ static void extract_buf(struct entropy_store *r, __u8 *out) buf[0] ^= buf[3]; buf[1] ^= buf[4]; - buf[0] ^= rol32(buf[3], 16); + buf[2] ^= rol32(buf[2], 16); memcpy(out, buf, EXTRACT_SIZE); memset(buf, 0, sizeof(buf)); } @@ -1018,37 +1020,44 @@ random_poll(struct file *file, poll_table * wait) return mask; } -static ssize_t -random_write(struct file * file, const char __user * buffer, - size_t count, loff_t *ppos) +static int +write_pool(struct entropy_store *r, const char __user *buffer, size_t count) { - int ret = 0; size_t bytes; __u32 buf[16]; const char __user *p = buffer; - size_t c = count; - while (c > 0) { - bytes = min(c, sizeof(buf)); + while (count > 0) { + bytes = min(count, sizeof(buf)); + if (copy_from_user(&buf, p, bytes)) + return -EFAULT; - bytes -= copy_from_user(&buf, p, bytes); - if (!bytes) { - ret = -EFAULT; - break; - } - c -= bytes; + count -= bytes; p += bytes; - add_entropy_words(&input_pool, buf, (bytes + 3) / 4); - } - if (p == buffer) { - return (ssize_t)ret; - } else { - struct inode *inode = file->f_path.dentry->d_inode; - inode->i_mtime = current_fs_time(inode->i_sb); - mark_inode_dirty(inode); - return (ssize_t)(p - buffer); + add_entropy_words(r, buf, (bytes + 3) / 4); } + + return 0; +} + +static ssize_t +random_write(struct file * file, const char __user * buffer, + size_t count, loff_t *ppos) +{ + size_t ret; + struct inode *inode = file->f_path.dentry->d_inode; + + ret = write_pool(&blocking_pool, buffer, count); + if (ret) + return ret; + ret = write_pool(&nonblocking_pool, buffer, count); + if (ret) + return ret; + + inode->i_mtime = current_fs_time(inode->i_sb); + mark_inode_dirty(inode); + return (ssize_t)count; } static int @@ -1087,8 +1096,8 @@ random_ioctl(struct inode * inode, struct file * file, return -EINVAL; if (get_user(size, p++)) return -EFAULT; - retval = random_write(file, (const char __user *) p, - size, &file->f_pos); + retval = write_pool(&input_pool, (const char __user *)p, + size); if (retval < 0) return retval; credit_entropy_store(&input_pool, ent_count); diff --git a/drivers/char/rio/riocmd.c b/drivers/char/rio/riocmd.c index 245f03195b7c..8cc60b693460 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 70145254fb9d..3494e3fc44bf 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 76357c855ce3..a3fd7e7ba5a9 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 3a8bcc85bc14..b4c53dfa7951 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 c7dac9b13351..20380a2c4dee 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 74cff839c857..a69f094d1ed3 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 5fd314adc1f2..c585b4738f86 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/snsc_event.c b/drivers/char/snsc_event.c index 2f56e8c54897..1b75b0b7d542 100644 --- a/drivers/char/snsc_event.c +++ b/drivers/char/snsc_event.c @@ -203,8 +203,6 @@ scdrv_dispatch_event(char *event, int len) class = (code & EV_CLASS_MASK); if (class == EV_CLASS_PWRD_NOTIFY || code == ENV_PWRDN_PEND) { - struct task_struct *p; - if (snsc_shutting_down) return; diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c index e45113a7a472..8c73ccb8830f 100644 --- a/drivers/char/stallion.c +++ b/drivers/char/stallion.c @@ -2172,11 +2172,12 @@ static int __devinit stl_initech(struct stlbrd *brdp) } status = inb(ioaddr + ECH_PNLSTATUS); if ((status & ECH_PNLIDMASK) != nxtid) - goto err_fr; + break; panelp = kzalloc(sizeof(struct stlpanel), GFP_KERNEL); if (!panelp) { printk("STALLION: failed to allocate memory " "(size=%Zd)\n", sizeof(struct stlpanel)); + retval = -ENOMEM; goto err_fr; } panelp->magic = STL_PANELMAGIC; @@ -2223,8 +2224,10 @@ static int __devinit stl_initech(struct stlbrd *brdp) brdp->nrports += panelp->nrports; brdp->panels[panelnr++] = panelp; if ((brdp->brdtype != BRD_ECHPCI) && - (ioaddr >= (brdp->ioaddr2 + brdp->iosize2))) + (ioaddr >= (brdp->ioaddr2 + brdp->iosize2))) { + retval = -EINVAL; goto err_fr; + } } brdp->nrpanels = panelnr; @@ -2371,6 +2374,7 @@ static int __devinit stl_pciprobe(struct pci_dev *pdev, dev_err(&pdev->dev, "too many boards found, " "maximum supported %d\n", STL_MAXBRDS); mutex_unlock(&stl_brdslock); + retval = -ENODEV; goto err_fr; } brdp->brdnr = (unsigned int)brdnr; @@ -4710,6 +4714,29 @@ static int __init stallion_module_init(void) spin_lock_init(&stallion_lock); spin_lock_init(&brd_lock); + stl_serial = alloc_tty_driver(STL_MAXBRDS * STL_MAXPORTS); + if (!stl_serial) { + retval = -ENOMEM; + goto err; + } + + stl_serial->owner = THIS_MODULE; + stl_serial->driver_name = stl_drvname; + stl_serial->name = "ttyE"; + stl_serial->major = STL_SERIALMAJOR; + stl_serial->minor_start = 0; + stl_serial->type = TTY_DRIVER_TYPE_SERIAL; + stl_serial->subtype = SERIAL_TYPE_NORMAL; + stl_serial->init_termios = stl_deftermios; + stl_serial->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; + tty_set_operations(stl_serial, &stl_ops); + + retval = tty_register_driver(stl_serial); + if (retval) { + printk("STALLION: failed to register serial driver\n"); + goto err_frtty; + } + /* * Find any dynamically supported boards. That is via module load * line options. @@ -4726,26 +4753,23 @@ static int __init stallion_module_init(void) brdp->ioaddr2 = conf.ioaddr2; brdp->irq = conf.irq; brdp->irqtype = conf.irqtype; - if (stl_brdinit(brdp)) + stl_brds[brdp->brdnr] = brdp; + if (stl_brdinit(brdp)) { + stl_brds[brdp->brdnr] = NULL; kfree(brdp); - else { + } else { for (j = 0; j < brdp->nrports; j++) tty_register_device(stl_serial, brdp->brdnr * STL_MAXPORTS + j, NULL); - stl_brds[brdp->brdnr] = brdp; stl_nrbrds = i + 1; } } /* this has to be _after_ isa finding because of locking */ retval = pci_register_driver(&stl_pcidriver); - if (retval && stl_nrbrds == 0) - goto err; - - stl_serial = alloc_tty_driver(STL_MAXBRDS * STL_MAXPORTS); - if (!stl_serial) { - retval = -ENOMEM; - goto err_pcidr; + if (retval && stl_nrbrds == 0) { + printk(KERN_ERR "STALLION: can't register pci driver\n"); + goto err_unrtty; } /* @@ -4756,43 +4780,18 @@ static int __init stallion_module_init(void) printk("STALLION: failed to register serial board device\n"); stallion_class = class_create(THIS_MODULE, "staliomem"); - if (IS_ERR(stallion_class)) { - retval = PTR_ERR(stallion_class); - goto err_reg; - } + if (IS_ERR(stallion_class)) + printk("STALLION: failed to create class\n"); for (i = 0; i < 4; i++) class_device_create(stallion_class, NULL, MKDEV(STL_SIOMEMMAJOR, i), NULL, "staliomem%d", i); - stl_serial->owner = THIS_MODULE; - stl_serial->driver_name = stl_drvname; - stl_serial->name = "ttyE"; - stl_serial->major = STL_SERIALMAJOR; - stl_serial->minor_start = 0; - stl_serial->type = TTY_DRIVER_TYPE_SERIAL; - stl_serial->subtype = SERIAL_TYPE_NORMAL; - stl_serial->init_termios = stl_deftermios; - stl_serial->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; - tty_set_operations(stl_serial, &stl_ops); - - retval = tty_register_driver(stl_serial); - if (retval) { - printk("STALLION: failed to register serial driver\n"); - goto err_clsdev; - } - return 0; -err_clsdev: - for (i = 0; i < 4; i++) - class_device_destroy(stallion_class, MKDEV(STL_SIOMEMMAJOR, i)); - class_destroy(stallion_class); -err_reg: - unregister_chrdev(STL_SIOMEMMAJOR, "staliomem"); +err_unrtty: + tty_unregister_driver(stl_serial); +err_frtty: put_tty_driver(stl_serial); -err_pcidr: - pci_unregister_driver(&stl_pcidriver); - stl_free_isabrds(); err: return retval; } @@ -4821,8 +4820,6 @@ static void __exit stallion_module_exit(void) tty_unregister_device(stl_serial, brdp->brdnr * STL_MAXPORTS + j); } - tty_unregister_driver(stl_serial); - put_tty_driver(stl_serial); for (i = 0; i < 4; i++) class_device_destroy(stallion_class, MKDEV(STL_SIOMEMMAJOR, i)); @@ -4834,6 +4831,9 @@ static void __exit stallion_module_exit(void) pci_unregister_driver(&stl_pcidriver); stl_free_isabrds(); + + tty_unregister_driver(stl_serial); + put_tty_driver(stl_serial); } module_init(stallion_module_init); diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c index ce4db6f52362..f02a0795983f 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 0a367cd4121f..02b49bc00028 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 1d8c4ae61551..39cc318011ea 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 47fb20f69695..35b40b996534 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 fe00c7dfb649..dc4e1ff7f56f 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 e5a254a434f8..9bb542913b86 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 9f273f032b0f..b2e2b002a1bb 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -21,6 +21,7 @@ #include <linux/module.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> @@ -94,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 3c852009196e..9363bcf0a402 100644 --- a/drivers/char/tpm/tpm_atmel.h +++ b/drivers/char/tpm/tpm_atmel.h @@ -23,6 +23,9 @@ */ #ifdef CONFIG_PPC64 + +#include <asm/prom.h> + #define atmel_getb(chip, offset) readb(chip->vendor->iobase + offset); #define atmel_putb(val, chip, offset) writeb(val, chip->vendor->iobase + offset) #define atmel_request_region request_mem_region @@ -47,12 +50,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 1353b5a6bae8..967002a5a1e5 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 389da364e6b6..a96f26a63fa2 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 @@ -365,6 +369,29 @@ static void tty_buffer_free(struct tty_struct *tty, struct tty_buffer *b) } /** + * tty_buffer_flush - flush full tty buffers + * @tty: tty to flush + * + * flush all the buffers containing receive data + * + * Locking: none + */ + +static void tty_buffer_flush(struct tty_struct *tty) +{ + struct tty_buffer *thead; + unsigned long flags; + + spin_lock_irqsave(&tty->buf.lock, flags); + while((thead = tty->buf.head) != NULL) { + tty->buf.head = thead->next; + tty_buffer_free(tty, thead); + } + tty->buf.tail = NULL; + spin_unlock_irqrestore(&tty->buf.lock, flags); +} + +/** * tty_buffer_find - find a free tty buffer * @tty: tty owning the buffer * @size: characters wanted @@ -936,13 +963,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 +973,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; @@ -1121,7 +1148,8 @@ int tty_check_change(struct tty_struct * tty) return 0; if (is_current_pgrp_orphaned()) return -EIO; - (void) kill_pgrp(task_pgrp(current), SIGTTOU, 1); + kill_pgrp(task_pgrp(current), SIGTTOU, 1); + set_thread_flag(TIF_SIGPENDING); return -ERESTARTSYS; } @@ -1151,12 +1179,19 @@ static int hung_up_tty_ioctl(struct inode * inode, struct file * file, return cmd == TIOCSPGRP ? -ENOTTY : -EIO; } +static long hung_up_tty_compat_ioctl(struct file * file, + unsigned int cmd, unsigned long arg) +{ + return cmd == TIOCSPGRP ? -ENOTTY : -EIO; +} + static const struct file_operations tty_fops = { .llseek = no_llseek, .read = tty_read, .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 +1204,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 +1217,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, @@ -1192,6 +1229,7 @@ static const struct file_operations hung_up_tty_fops = { .write = hung_up_tty_write, .poll = hung_up_tty_poll, .ioctl = hung_up_tty_ioctl, + .compat_ioctl = hung_up_tty_compat_ioctl, .release = tty_release, }; @@ -1240,6 +1278,7 @@ void tty_ldisc_flush(struct tty_struct *tty) ld->flush_buffer(tty); tty_ldisc_deref(ld); } + tty_buffer_flush(tty); } EXPORT_SYMBOL_GPL(tty_ldisc_flush); @@ -1534,10 +1573,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 +1600,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 +1648,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 +2558,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 +2651,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 +3334,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); @@ -3336,6 +3381,15 @@ int tty_ioctl(struct inode * inode, struct file * file, case TIOCMBIC: case TIOCMBIS: return tty_tiocmset(tty, file, cmd, p); + case TCFLSH: + switch (arg) { + case TCIFLUSH: + case TCIOFLUSH: + /* flush tty buffer and allow ldisc to process ioctl */ + tty_buffer_flush(tty); + break; + } + break; } if (tty->driver->ioctl) { retval = (tty->driver->ioctl)(tty, file, cmd, arg); @@ -3353,6 +3407,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 +3765,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; @@ -3766,7 +3847,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++) @@ -3792,8 +3875,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 @@ -3838,9 +3922,8 @@ void proc_clear_tty(struct task_struct *p) } 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); @@ -3848,21 +3931,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) @@ -3897,9 +3975,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 791930320a13..83aeedda200c 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 1bbb45b937fd..6650ae1c088f 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 -- 2007-05-26 (Unicode 5.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 }, + { 0xFE10, 0xFE19 }, { 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,88 @@ 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 < 128) && !(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, + but do this for ASCII characters since a font may lack + Unicode mapping info and we don't want to end up with + having question marks only. */ + 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) + if (!inverse) { + vc_attr = vc->vc_attr; + } else { + /* 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); + } 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; + + 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); + } + + if (!--width) break; + + tc = conv_uni_to_pc(vc, ' '); /* A space is printed in the second column */ + if (tc < 0) tc = ' '; } - 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); + + if (inverse) { + FLUSH } - if (vc->vc_utf_count) { - if (vc->vc_npar) { - vc->vc_npar--; - goto display_glyph; - } - vc->vc_utf_count = 0; + + if (rescan) { + rescan = 0; + inverse = 0; + width = 1; c = orig; goto rescan_last_byte; } @@ -2581,6 +2713,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 +2737,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 c9f2dd620e87..c6f6f4209739 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/Kconfig b/drivers/char/watchdog/Kconfig index 60198a78974c..53f5538c0c05 100644 --- a/drivers/char/watchdog/Kconfig +++ b/drivers/char/watchdog/Kconfig @@ -2,9 +2,7 @@ # Watchdog device configuration # -menu "Watchdog Cards" - -config WATCHDOG +menuconfig WATCHDOG bool "Watchdog Timer Support" ---help--- If you say Y here (and to one of the following options) and create a @@ -28,9 +26,10 @@ config WATCHDOG If unsure, say N. +if WATCHDOG + config WATCHDOG_NOWAYOUT bool "Disable watchdog shutdown on close" - depends on WATCHDOG help The default watchdog behaviour (which you get if you say N here) is to stop the timer if the process managing it closes the file @@ -43,13 +42,11 @@ config WATCHDOG_NOWAYOUT # comment "Watchdog Device Drivers" - depends on WATCHDOG # Architecture Independent config SOFT_WATCHDOG tristate "Software watchdog" - depends on WATCHDOG help A software monitoring watchdog. This will fail to reboot your system from some situations that the hardware watchdog will recover @@ -62,14 +59,14 @@ config SOFT_WATCHDOG config AT91RM9200_WATCHDOG tristate "AT91RM9200 watchdog" - depends on WATCHDOG && ARCH_AT91RM9200 + depends on ARCH_AT91RM9200 help Watchdog timer embedded into AT91RM9200 chips. This will reboot your system when the timeout is reached. config 21285_WATCHDOG tristate "DC21285 watchdog" - depends on WATCHDOG && FOOTBRIDGE + depends on FOOTBRIDGE help The Intel Footbridge chip contains a built-in watchdog circuit. Say Y here if you wish to use this. Alternatively say M to compile the @@ -83,7 +80,7 @@ config 21285_WATCHDOG config 977_WATCHDOG tristate "NetWinder WB83C977 watchdog" - depends on WATCHDOG && FOOTBRIDGE && ARCH_NETWINDER + depends on FOOTBRIDGE && ARCH_NETWINDER help Say Y here to include support for the WB977 watchdog included in NetWinder machines. Alternatively say M to compile the driver as @@ -93,7 +90,7 @@ config 977_WATCHDOG config IXP2000_WATCHDOG tristate "IXP2000 Watchdog" - depends on WATCHDOG && ARCH_IXP2000 + depends on ARCH_IXP2000 help Say Y here if to include support for the watchdog timer in the Intel IXP2000(2400, 2800, 2850) network processors. @@ -104,7 +101,7 @@ config IXP2000_WATCHDOG config IXP4XX_WATCHDOG tristate "IXP4xx Watchdog" - depends on WATCHDOG && ARCH_IXP4XX + depends on ARCH_IXP4XX help Say Y here if to include support for the watchdog timer in the Intel IXP4xx network processors. This driver can @@ -118,9 +115,16 @@ config IXP4XX_WATCHDOG Say N if you are unsure. +config KS8695_WATCHDOG + tristate "KS8695 watchdog" + depends on ARCH_KS8695 + help + Watchdog timer embedded into KS8695 processor. This will reboot your + system when the timeout is reached. + config S3C2410_WATCHDOG tristate "S3C2410 Watchdog" - depends on WATCHDOG && ARCH_S3C2410 + depends on ARCH_S3C2410 help Watchdog timer block in the Samsung S3C2410 chips. This will reboot the system when the timer expires with the watchdog @@ -136,7 +140,7 @@ config S3C2410_WATCHDOG config SA1100_WATCHDOG tristate "SA1100/PXA2xx watchdog" - depends on WATCHDOG && ( ARCH_SA1100 || ARCH_PXA ) + depends on ARCH_SA1100 || ARCH_PXA help Watchdog timer embedded into SA11x0 and PXA2xx chips. This will reboot your system when timeout is reached. @@ -148,7 +152,7 @@ config SA1100_WATCHDOG config MPCORE_WATCHDOG tristate "MPcore watchdog" - depends on WATCHDOG && ARM_MPCORE_PLATFORM && LOCAL_TIMERS + depends on ARM_MPCORE_PLATFORM && LOCAL_TIMERS help Watchdog timer embedded into the MPcore system. @@ -157,7 +161,7 @@ config MPCORE_WATCHDOG config EP93XX_WATCHDOG tristate "EP93xx Watchdog" - depends on WATCHDOG && ARCH_EP93XX + depends on ARCH_EP93XX help Say Y here if to include support for the watchdog timer embedded in the Cirrus Logic EP93xx family of devices. @@ -167,14 +171,14 @@ config EP93XX_WATCHDOG config OMAP_WATCHDOG tristate "OMAP Watchdog" - depends on WATCHDOG && (ARCH_OMAP16XX || ARCH_OMAP24XX) + depends on ARCH_OMAP16XX || ARCH_OMAP24XX help Support for TI OMAP1610/OMAP1710/OMAP2420 watchdog. Say 'Y' here to enable the OMAP1610/OMAP1710 watchdog timer. config PNX4008_WATCHDOG tristate "PNX4008 Watchdog" - depends on WATCHDOG && ARCH_PNX4008 + depends on ARCH_PNX4008 help Say Y here if to include support for the watchdog timer in the PNX4008 processor. @@ -187,7 +191,7 @@ config PNX4008_WATCHDOG config ACQUIRE_WDT tristate "Acquire SBC Watchdog Timer" - depends on WATCHDOG && X86 + depends on X86 ---help--- This is the driver for the hardware watchdog on Single Board Computers produced by Acquire Inc (and others). This watchdog @@ -201,7 +205,7 @@ config ACQUIRE_WDT config ADVANTECH_WDT tristate "Advantech SBC Watchdog Timer" - depends on WATCHDOG && X86 + depends on X86 help If you are configuring a Linux kernel for the Advantech single-board computer, say `Y' here to support its built-in watchdog timer @@ -210,7 +214,7 @@ config ADVANTECH_WDT config ALIM1535_WDT tristate "ALi M1535 PMU Watchdog Timer" - depends on WATCHDOG && X86 && PCI + depends on X86 && PCI ---help--- This is the driver for the hardware watchdog on the ALi M1535 PMU. @@ -221,7 +225,7 @@ config ALIM1535_WDT config ALIM7101_WDT tristate "ALi M7101 PMU Computer Watchdog" - depends on WATCHDOG && X86 && PCI + depends on X86 && PCI help This is the driver for the hardware watchdog on the ALi M7101 PMU as used in the x86 Cobalt servers. @@ -233,7 +237,7 @@ config ALIM7101_WDT config SC520_WDT tristate "AMD Elan SC520 processor Watchdog" - depends on WATCHDOG && X86 + depends on X86 help This is the driver for the hardware watchdog built in to the AMD "Elan" SC520 microcomputer commonly used in embedded systems. @@ -246,7 +250,7 @@ config SC520_WDT config EUROTECH_WDT tristate "Eurotech CPU-1220/1410 Watchdog Timer" - depends on WATCHDOG && X86 + depends on X86 help Enable support for the watchdog timer on the Eurotech CPU-1220 and CPU-1410 cards. These are PC/104 SBCs. Spec sheets and product @@ -254,7 +258,7 @@ config EUROTECH_WDT config IB700_WDT tristate "IB700 SBC Watchdog Timer" - depends on WATCHDOG && X86 + depends on X86 ---help--- This is the driver for the hardware watchdog on the IB700 Single Board Computer produced by TMC Technology (www.tmc-uk.com). This watchdog @@ -270,7 +274,7 @@ config IB700_WDT config IBMASR tristate "IBM Automatic Server Restart" - depends on WATCHDOG && X86 + depends on X86 help This is the driver for the IBM Automatic Server Restart watchdog timer built-in into some eServer xSeries machines. @@ -280,7 +284,7 @@ config IBMASR config WAFER_WDT tristate "ICP Wafer 5823 Single Board Computer Watchdog" - depends on WATCHDOG && X86 + depends on X86 help This is a driver for the hardware watchdog on the ICP Wafer 5823 Single Board Computer (and probably other similar models). @@ -290,7 +294,7 @@ config WAFER_WDT config I6300ESB_WDT tristate "Intel 6300ESB Timer/Watchdog" - depends on WATCHDOG && X86 && PCI + depends on X86 && PCI ---help--- Hardware driver for the watchdog timer built into the Intel 6300ESB controller hub. @@ -298,31 +302,9 @@ config I6300ESB_WDT To compile this driver as a module, choose M here: the module will be called i6300esb. -config I8XX_TCO - tristate "Intel i8xx TCO Timer/Watchdog" - depends on WATCHDOG && (X86 || IA64) && PCI - default n - ---help--- - Hardware driver for the TCO timer built into the Intel 82801 - I/O Controller Hub family. The TCO (Total Cost of Ownership) - timer is a watchdog timer that will reboot the machine after - its second expiration. The expiration time can be configured - with the "heartbeat" parameter. - - On some motherboards the driver may fail to reset the chipset's - NO_REBOOT flag which prevents the watchdog from rebooting the - machine. If this is the case you will get a kernel message like - "failed to reset NO_REBOOT flag, reboot disabled by hardware". - - To compile this driver as a module, choose M here: the - module will be called i8xx_tco. - - Note: This driver will be removed in the near future. Please - use the Intel TCO Timer/Watchdog driver. - config ITCO_WDT tristate "Intel TCO Timer/Watchdog" - depends on WATCHDOG && (X86 || IA64) && PCI + depends on (X86 || IA64) && PCI ---help--- Hardware driver for the intel TCO timer based watchdog devices. These drivers are included in the Intel 82801 I/O Controller @@ -351,7 +333,7 @@ config ITCO_VENDOR_SUPPORT config SC1200_WDT tristate "National Semiconductor PC87307/PC97307 (ala SC1200) Watchdog" - depends on WATCHDOG && X86 + depends on X86 help This is a driver for National Semiconductor PC87307/PC97307 hardware watchdog cards as found on the SC1200. This watchdog is mainly used @@ -365,7 +347,7 @@ config SC1200_WDT config SCx200_WDT tristate "National Semiconductor SCx200 Watchdog" - depends on WATCHDOG && SCx200 && PCI + depends on SCx200 && PCI help Enable the built-in watchdog timer support on the National Semiconductor SCx200 processors. @@ -374,7 +356,7 @@ config SCx200_WDT config PC87413_WDT tristate "NS PC87413 watchdog" - depends on WATCHDOG && X86 + depends on X86 ---help--- This is the driver for the hardware watchdog on the PC87413 chipset This watchdog simply watches your kernel to make sure it doesn't @@ -388,7 +370,7 @@ config PC87413_WDT config 60XX_WDT tristate "SBC-60XX Watchdog Timer" - depends on WATCHDOG && X86 + depends on X86 help This driver can be used with the watchdog timer found on some single board computers, namely the 6010 PII based computer. @@ -402,7 +384,7 @@ config 60XX_WDT config SBC8360_WDT tristate "SBC8360 Watchdog Timer" - depends on WATCHDOG && X86 + depends on X86 ---help--- This is the driver for the hardware watchdog on the SBC8360 Single @@ -415,7 +397,7 @@ config SBC8360_WDT config CPU5_WDT tristate "SMA CPU5 Watchdog" - depends on WATCHDOG && X86 + depends on X86 ---help--- TBD. To compile this driver as a module, choose M here: the @@ -423,7 +405,7 @@ config CPU5_WDT config SMSC37B787_WDT tristate "Winbond SMsC37B787 Watchdog Timer" - depends on WATCHDOG && X86 + depends on X86 ---help--- This is the driver for the hardware watchdog component on the Winbond SMsC37B787 chipset as used on the NetRunner Mainboard @@ -443,7 +425,7 @@ config SMSC37B787_WDT config W83627HF_WDT tristate "W83627HF Watchdog Timer" - depends on WATCHDOG && X86 + depends on X86 ---help--- This is the driver for the hardware watchdog on the W83627HF chipset as used in Advantech PC-9578 and Tyan S2721-533 motherboards @@ -458,7 +440,7 @@ config W83627HF_WDT config W83697HF_WDT tristate "W83697HF/W83697HG Watchdog Timer" - depends on WATCHDOG && X86 + depends on X86 ---help--- This is the driver for the hardware watchdog on the W83697HF/HG chipset as used in Dedibox/VIA motherboards (and likely others). @@ -473,7 +455,7 @@ config W83697HF_WDT config W83877F_WDT tristate "W83877F (EMACS) Watchdog Timer" - depends on WATCHDOG && X86 + depends on X86 ---help--- This is the driver for the hardware watchdog on the W83877F chipset as used in EMACS PC-104 motherboards (and likely others). This @@ -488,7 +470,7 @@ config W83877F_WDT config W83977F_WDT tristate "W83977F (PCM-5335) Watchdog Timer" - depends on WATCHDOG && X86 + depends on X86 ---help--- This is the driver for the hardware watchdog on the W83977F I/O chip as used in AAEON's PCM-5335 SBC (and likely others). This @@ -501,7 +483,7 @@ config W83977F_WDT config MACHZ_WDT tristate "ZF MachZ Watchdog" - depends on WATCHDOG && X86 + depends on X86 ---help--- If you are using a ZF Micro MachZ processor, say Y here, otherwise N. This is the driver for the watchdog timer built-in on that @@ -514,7 +496,7 @@ config MACHZ_WDT config SBC_EPX_C3_WATCHDOG tristate "Winsystems SBC EPX-C3 watchdog" - depends on WATCHDOG && X86 + depends on X86 ---help--- This is the driver for the built-in watchdog timer on the EPX-C3 Single-board computer made by Winsystems, Inc. @@ -537,19 +519,19 @@ config SBC_EPX_C3_WATCHDOG config 8xx_WDT tristate "MPC8xx Watchdog Timer" - depends on WATCHDOG && 8xx + depends on 8xx config 83xx_WDT tristate "MPC83xx Watchdog Timer" - depends on WATCHDOG && PPC_83xx + depends on PPC_83xx config MV64X60_WDT tristate "MV64X60 (Marvell Discovery) Watchdog Timer" - depends on WATCHDOG && MV64X60 + depends on MV64X60 config BOOKE_WDT bool "PowerPC Book-E Watchdog Timer" - depends on WATCHDOG && (BOOKE || 4xx) + depends on BOOKE || 4xx ---help--- Please see Documentation/watchdog/watchdog-api.txt for more information. @@ -558,7 +540,7 @@ config BOOKE_WDT config WATCHDOG_RTAS tristate "RTAS watchdog" - depends on WATCHDOG && PPC_RTAS + depends on PPC_RTAS help This driver adds watchdog support for the RTAS watchdog. @@ -569,16 +551,23 @@ config WATCHDOG_RTAS config INDYDOG tristate "Indy/I2 Hardware Watchdog" - depends on WATCHDOG && SGI_IP22 + depends on SGI_IP22 help Hardware driver for the Indy's/I2's watchdog. This is a watchdog timer that will reboot the machine after a 60 second timer expired and no process has written to /dev/watchdog during that time. +config WDT_MTX1 + tristate "MTX-1 Hardware Watchdog" + depends on MIPS_MTX1 + help + Hardware driver for the MTX-1 boards. This is a watchdog timer that + will reboot the machine after a 100 seconds timer expired. + config WDT_RM9K_GPI tristate "RM9000/GPI hardware watchdog" - depends on WATCHDOG && CPU_RM9000 + depends on CPU_RM9000 help Watchdog implementation using the GPI hardware found on PMC-Sierra RM9xxx CPUs. @@ -590,7 +579,7 @@ config WDT_RM9K_GPI config ZVM_WATCHDOG tristate "z/VM Watchdog Timer" - depends on WATCHDOG && S390 + depends on S390 help IBM s/390 and zSeries machines running under z/VM 5.1 or later provide a virtual watchdog timer to their guest that cause a @@ -604,7 +593,7 @@ config ZVM_WATCHDOG config SH_WDT tristate "SuperH Watchdog" - depends on WATCHDOG && SUPERH + depends on SUPERH help This driver adds watchdog support for the integrated watchdog in the SuperH processors. If you have one of these processors and wish @@ -631,7 +620,7 @@ config SH_WDT_MMAP config WATCHDOG_CP1XXX tristate "CP1XXX Hardware Watchdog support" - depends on WATCHDOG && SPARC64 && PCI + depends on SPARC64 && PCI ---help--- This is the driver for the hardware watchdog timers present on Sun Microsystems CompactPCI models CP1400 and CP1500. @@ -645,7 +634,7 @@ config WATCHDOG_CP1XXX config WATCHDOG_RIO tristate "RIO Hardware Watchdog support" - depends on WATCHDOG && SPARC64 && PCI + depends on SPARC64 && PCI help Say Y here to support the hardware watchdog capability on Sun RIO machines. The watchdog timeout period is normally one minute but @@ -656,11 +645,11 @@ config WATCHDOG_RIO # comment "ISA-based Watchdog Cards" - depends on WATCHDOG && ISA + depends on ISA config PCWATCHDOG tristate "Berkshire Products ISA-PC Watchdog" - depends on WATCHDOG && ISA + depends on ISA ---help--- This is the driver for the Berkshire Products ISA-PC Watchdog card. This card simply watches your kernel to make sure it doesn't freeze, @@ -676,7 +665,7 @@ config PCWATCHDOG config MIXCOMWD tristate "Mixcom Watchdog" - depends on WATCHDOG && ISA + depends on ISA ---help--- This is a driver for the Mixcom hardware watchdog cards. This watchdog simply watches your kernel to make sure it doesn't freeze, @@ -690,7 +679,7 @@ config MIXCOMWD config WDT tristate "WDT Watchdog timer" - depends on WATCHDOG && ISA + depends on ISA ---help--- If you have a WDT500P or WDT501P watchdog board, say Y here, otherwise N. It is not possible to probe for this board, which means @@ -720,11 +709,11 @@ config WDT_501 # comment "PCI-based Watchdog Cards" - depends on WATCHDOG && PCI + depends on PCI config PCIPCWATCHDOG tristate "Berkshire Products PCI-PC Watchdog" - depends on WATCHDOG && PCI + depends on PCI ---help--- This is the driver for the Berkshire Products PCI-PC Watchdog card. This card simply watches your kernel to make sure it doesn't freeze, @@ -739,7 +728,7 @@ config PCIPCWATCHDOG config WDTPCI tristate "PCI-WDT500/501 Watchdog timer" - depends on WATCHDOG && PCI + depends on PCI ---help--- If you have a PCI-WDT500/501 watchdog board, say Y here, otherwise N. @@ -766,11 +755,11 @@ config WDT_501_PCI # comment "USB-based Watchdog Cards" - depends on WATCHDOG && USB + depends on USB config USBPCWATCHDOG tristate "Berkshire Products USB-PC Watchdog" - depends on WATCHDOG && USB + depends on USB ---help--- This is the driver for the Berkshire Products USB-PC Watchdog card. This card simply watches your kernel to make sure it doesn't freeze, @@ -783,4 +772,4 @@ config USBPCWATCHDOG Most people will say N. -endmenu +endif # WATCHDOG diff --git a/drivers/char/watchdog/Makefile b/drivers/char/watchdog/Makefile index 2cd8ff8d10ac..d90f649038c2 100644 --- a/drivers/char/watchdog/Makefile +++ b/drivers/char/watchdog/Makefile @@ -29,6 +29,7 @@ obj-$(CONFIG_21285_WATCHDOG) += wdt285.o obj-$(CONFIG_977_WATCHDOG) += wdt977.o obj-$(CONFIG_IXP2000_WATCHDOG) += ixp2000_wdt.o obj-$(CONFIG_IXP4XX_WATCHDOG) += ixp4xx_wdt.o +obj-$(CONFIG_KS8695_WATCHDOG) += ks8695_wdt.o obj-$(CONFIG_S3C2410_WATCHDOG) += s3c2410_wdt.o obj-$(CONFIG_SA1100_WATCHDOG) += sa1100_wdt.o obj-$(CONFIG_MPCORE_WATCHDOG) += mpcore_wdt.o @@ -46,7 +47,6 @@ obj-$(CONFIG_IB700_WDT) += ib700wdt.o obj-$(CONFIG_IBMASR) += ibmasr.o obj-$(CONFIG_WAFER_WDT) += wafer5823wdt.o obj-$(CONFIG_I6300ESB_WDT) += i6300esb.o -obj-$(CONFIG_I8XX_TCO) += i8xx_tco.o obj-$(CONFIG_ITCO_WDT) += iTCO_wdt.o iTCO_vendor_support.o obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o obj-$(CONFIG_SCx200_WDT) += scx200_wdt.o @@ -73,6 +73,7 @@ obj-$(CONFIG_WATCHDOG_RTAS) += wdrtas.o # MIPS Architecture obj-$(CONFIG_INDYDOG) += indydog.o +obj-$(CONFIG_WDT_MTX1) += mtx-1_wdt.o obj-$(CONFIG_WDT_RM9K_GPI) += rm9k_wdt.o # S390 Architecture diff --git a/drivers/char/watchdog/booke_wdt.c b/drivers/char/watchdog/booke_wdt.c index 0e23f29f71ab..0f5c77ddd39d 100644 --- a/drivers/char/watchdog/booke_wdt.c +++ b/drivers/char/watchdog/booke_wdt.c @@ -24,7 +24,7 @@ #include <asm/uaccess.h> #include <asm/system.h> -/* If the kernel parameter wdt_enable=1, the watchdog will be enabled at boot. +/* If the kernel parameter wdt=1, the watchdog will be enabled at boot. * Also, the wdt_period sets the watchdog timer period timeout. * For E500 cpus the wdt_period sets which bit changing from 0->1 will * trigger a watchog timeout. This watchdog timeout will occur 3 times, the diff --git a/drivers/char/watchdog/cpu5wdt.c b/drivers/char/watchdog/cpu5wdt.c index bcd7e36ca0aa..d0d45a8b09f0 100644 --- a/drivers/char/watchdog/cpu5wdt.c +++ b/drivers/char/watchdog/cpu5wdt.c @@ -220,17 +220,17 @@ static int __devinit cpu5wdt_init(void) if ( verbose ) printk(KERN_DEBUG PFX "port=0x%x, verbose=%i\n", port, verbose); - if ( (err = misc_register(&cpu5wdt_misc)) < 0 ) { - printk(KERN_ERR PFX "misc_register failed\n"); - goto no_misc; - } - if ( !request_region(port, CPU5WDT_EXTENT, PFX) ) { printk(KERN_ERR PFX "request_region failed\n"); err = -EBUSY; goto no_port; } + if ( (err = misc_register(&cpu5wdt_misc)) < 0 ) { + printk(KERN_ERR PFX "misc_register failed\n"); + goto no_misc; + } + /* watchdog reboot? */ val = inb(port + CPU5WDT_STATUS_REG); val = (val >> 2) & 1; @@ -250,9 +250,9 @@ static int __devinit cpu5wdt_init(void) return 0; -no_port: - misc_deregister(&cpu5wdt_misc); no_misc: + release_region(port, CPU5WDT_EXTENT); +no_port: return err; } diff --git a/drivers/char/watchdog/eurotechwdt.c b/drivers/char/watchdog/eurotechwdt.c index f70387f01b2b..b070324e27a6 100644 --- a/drivers/char/watchdog/eurotechwdt.c +++ b/drivers/char/watchdog/eurotechwdt.c @@ -413,17 +413,10 @@ static int __init eurwdt_init(void) { int ret; - ret = misc_register(&eurwdt_miscdev); - if (ret) { - printk(KERN_ERR "eurwdt: can't misc_register on minor=%d\n", - WATCHDOG_MINOR); - goto out; - } - ret = request_irq(irq, eurwdt_interrupt, IRQF_DISABLED, "eurwdt", NULL); if(ret) { printk(KERN_ERR "eurwdt: IRQ %d is not free.\n", irq); - goto outmisc; + goto out; } if (!request_region(io, 2, "eurwdt")) { @@ -438,6 +431,13 @@ static int __init eurwdt_init(void) goto outreg; } + ret = misc_register(&eurwdt_miscdev); + if (ret) { + printk(KERN_ERR "eurwdt: can't misc_register on minor=%d\n", + WATCHDOG_MINOR); + goto outreboot; + } + eurwdt_unlock_chip(); ret = 0; @@ -448,14 +448,14 @@ static int __init eurwdt_init(void) out: return ret; +outreboot: + unregister_reboot_notifier(&eurwdt_notifier); + outreg: release_region(io, 2); outirq: free_irq(irq, NULL); - -outmisc: - misc_deregister(&eurwdt_miscdev); goto out; } diff --git a/drivers/char/watchdog/i8xx_tco.c b/drivers/char/watchdog/i8xx_tco.c deleted file mode 100644 index a62ef48a15ae..000000000000 --- a/drivers/char/watchdog/i8xx_tco.c +++ /dev/null @@ -1,571 +0,0 @@ -/* - * i8xx_tco: TCO timer driver for i8xx chipsets - * - * (c) Copyright 2000 kernel concepts <nils@kernelconcepts.de>, All Rights Reserved. - * http://www.kernelconcepts.de - * - * 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 Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Neither kernel concepts nor Nils Faerber admit liability nor provide - * warranty for any of this software. This material is provided - * "AS-IS" and at no charge. - * - * (c) Copyright 2000 kernel concepts <nils@kernelconcepts.de> - * developed for - * Jentro AG, Haar/Munich (Germany) - * - * TCO timer driver for i8xx chipsets - * based on softdog.c by Alan Cox <alan@redhat.com> - * - * The TCO timer is implemented in the following I/O controller hubs: - * (See the intel documentation on http://developer.intel.com.) - * 82801AA (ICH) : document number 290655-003, 290677-014, - * 82801AB (ICHO) : document number 290655-003, 290677-014, - * 82801BA (ICH2) : document number 290687-002, 298242-027, - * 82801BAM (ICH2-M) : document number 290687-002, 298242-027, - * 82801CA (ICH3-S) : document number 290733-003, 290739-013, - * 82801CAM (ICH3-M) : document number 290716-001, 290718-007, - * 82801DB (ICH4) : document number 290744-001, 290745-020, - * 82801DBM (ICH4-M) : document number 252337-001, 252663-005, - * 82801E (C-ICH) : document number 273599-001, 273645-002, - * 82801EB (ICH5) : document number 252516-001, 252517-003, - * 82801ER (ICH5R) : document number 252516-001, 252517-003, - * - * 20000710 Nils Faerber - * Initial Version 0.01 - * 20000728 Nils Faerber - * 0.02 Fix for SMI_EN->TCO_EN bit, some cleanups - * 20011214 Matt Domsch <Matt_Domsch@dell.com> - * 0.03 Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT - * Didn't add timeout option as i810_margin already exists. - * 20020224 Joel Becker, Wim Van Sebroeck - * 0.04 Support for 82801CA(M) chipset, timer margin needs to be > 3, - * add support for WDIOC_SETTIMEOUT and WDIOC_GETTIMEOUT. - * 20020412 Rob Radez <rob@osinvestor.com>, Wim Van Sebroeck - * 0.05 Fix possible timer_alive race, add expect close support, - * clean up ioctls (WDIOC_GETSTATUS, WDIOC_GETBOOTSTATUS and - * WDIOC_SETOPTIONS), made i810tco_getdevice __init, - * removed boot_status, removed tco_timer_read, - * added support for 82801DB and 82801E chipset, - * added support for 82801EB and 8280ER chipset, - * general cleanup. - * 20030921 Wim Van Sebroeck <wim@iguana.be> - * 0.06 change i810_margin to heartbeat, use module_param, - * added notify system support, renamed module to i8xx_tco. - * 20050128 Wim Van Sebroeck <wim@iguana.be> - * 0.07 Added support for the ICH4-M, ICH6, ICH6R, ICH6-M, ICH6W and ICH6RW - * chipsets. Also added support for the "undocumented" ICH7 chipset. - * 20050807 Wim Van Sebroeck <wim@iguana.be> - * 0.08 Make sure that the watchdog is only "armed" when started. - * (Kernel Bug 4251) - * 20060416 Wim Van Sebroeck <wim@iguana.be> - * 0.09 Remove support for the ICH6, ICH6R, ICH6-M, ICH6W and ICH6RW and - * ICH7 chipsets. (See Kernel Bug 6031 - other code will support these - * chipsets) - */ - -/* - * Includes, defines, variables, module parameters, ... - */ - -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/types.h> -#include <linux/miscdevice.h> -#include <linux/watchdog.h> -#include <linux/notifier.h> -#include <linux/reboot.h> -#include <linux/init.h> -#include <linux/fs.h> -#include <linux/pci.h> -#include <linux/ioport.h> - -#include <asm/uaccess.h> -#include <asm/io.h> - -#include "i8xx_tco.h" - -/* Module and version information */ -#define TCO_VERSION "0.09" -#define TCO_MODULE_NAME "i8xx TCO timer" -#define TCO_DRIVER_NAME TCO_MODULE_NAME ", v" TCO_VERSION -#define PFX TCO_MODULE_NAME ": " - -/* internal variables */ -static unsigned int ACPIBASE; -static spinlock_t tco_lock; /* Guards the hardware */ -static unsigned long timer_alive; -static char tco_expect_close; -static struct pci_dev *i8xx_tco_pci; - -/* module parameters */ -#define WATCHDOG_HEARTBEAT 30 /* 30 sec default heartbeat (2<heartbeat<39) */ -static int heartbeat = WATCHDOG_HEARTBEAT; /* in seconds */ -module_param(heartbeat, int, 0); -MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (2<heartbeat<39, default=" __MODULE_STRING(WATCHDOG_HEARTBEAT) ")"); - -static int nowayout = WATCHDOG_NOWAYOUT; -module_param(nowayout, int, 0); -MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); - -/* - * Some TCO specific functions - */ - -static inline unsigned char seconds_to_ticks(int seconds) -{ - /* the internal timer is stored as ticks which decrement - * every 0.6 seconds */ - return (seconds * 10) / 6; -} - -static int tco_timer_start (void) -{ - unsigned char val; - - spin_lock(&tco_lock); - - /* disable chipset's NO_REBOOT bit */ - pci_read_config_byte (i8xx_tco_pci, 0xd4, &val); - val &= 0xfd; - pci_write_config_byte (i8xx_tco_pci, 0xd4, val); - - /* Bit 11: TCO Timer Halt -> 0 = The TCO timer is enabled to count */ - val = inb (TCO1_CNT + 1); - val &= 0xf7; - outb (val, TCO1_CNT + 1); - val = inb (TCO1_CNT + 1); - - spin_unlock(&tco_lock); - - if (val & 0x08) - return -1; - return 0; -} - -static int tco_timer_stop (void) -{ - unsigned char val, val1; - - spin_lock(&tco_lock); - /* Bit 11: TCO Timer Halt -> 1 = The TCO timer is disabled */ - val = inb (TCO1_CNT + 1); - val |= 0x08; - outb (val, TCO1_CNT + 1); - val = inb (TCO1_CNT + 1); - - /* Set the NO_REBOOT bit to prevent later reboots, just for sure */ - pci_read_config_byte (i8xx_tco_pci, 0xd4, &val1); - val1 |= 0x02; - pci_write_config_byte (i8xx_tco_pci, 0xd4, val1); - - spin_unlock(&tco_lock); - - if ((val & 0x08) == 0) - return -1; - return 0; -} - -static int tco_timer_keepalive (void) -{ - spin_lock(&tco_lock); - /* Reload the timer by writing to the TCO Timer Reload register */ - outb (0x01, TCO1_RLD); - spin_unlock(&tco_lock); - return 0; -} - -static int tco_timer_set_heartbeat (int t) -{ - unsigned char val; - unsigned char tmrval; - - tmrval = seconds_to_ticks(t); - /* from the specs: */ - /* "Values of 0h-3h are ignored and should not be attempted" */ - if (tmrval > 0x3f || tmrval < 0x04) - return -EINVAL; - - /* Write new heartbeat to watchdog */ - spin_lock(&tco_lock); - val = inb (TCO1_TMR); - val &= 0xc0; - val |= tmrval; - outb (val, TCO1_TMR); - val = inb (TCO1_TMR); - spin_unlock(&tco_lock); - - if ((val & 0x3f) != tmrval) - return -EINVAL; - - heartbeat = t; - return 0; -} - -static int tco_timer_get_timeleft (int *time_left) -{ - unsigned char val; - - spin_lock(&tco_lock); - - /* read the TCO Timer */ - val = inb (TCO1_RLD); - val &= 0x3f; - - spin_unlock(&tco_lock); - - *time_left = (int)((val * 6) / 10); - - return 0; -} - -/* - * /dev/watchdog handling - */ - -static int i8xx_tco_open (struct inode *inode, struct file *file) -{ - /* /dev/watchdog can only be opened once */ - if (test_and_set_bit(0, &timer_alive)) - return -EBUSY; - - /* - * Reload and activate timer - */ - tco_timer_keepalive (); - tco_timer_start (); - return nonseekable_open(inode, file); -} - -static int i8xx_tco_release (struct inode *inode, struct file *file) -{ - /* - * Shut off the timer. - */ - if (tco_expect_close == 42) { - tco_timer_stop (); - } else { - printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n"); - tco_timer_keepalive (); - } - clear_bit(0, &timer_alive); - tco_expect_close = 0; - return 0; -} - -static ssize_t i8xx_tco_write (struct file *file, const char __user *data, - size_t len, loff_t * ppos) -{ - /* See if we got the magic character 'V' and reload the timer */ - if (len) { - if (!nowayout) { - size_t i; - - /* note: just in case someone wrote the magic character - * five months ago... */ - tco_expect_close = 0; - - /* scan to see whether or not we got the magic character */ - for (i = 0; i != len; i++) { - char c; - if(get_user(c, data+i)) - return -EFAULT; - if (c == 'V') - tco_expect_close = 42; - } - } - - /* someone wrote to us, we should reload the timer */ - tco_timer_keepalive (); - } - return len; -} - -static int i8xx_tco_ioctl (struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - int new_options, retval = -EINVAL; - int new_heartbeat; - int time_left; - void __user *argp = (void __user *)arg; - int __user *p = argp; - static struct watchdog_info ident = { - .options = WDIOF_SETTIMEOUT | - WDIOF_KEEPALIVEPING | - WDIOF_MAGICCLOSE, - .firmware_version = 0, - .identity = TCO_MODULE_NAME, - }; - - switch (cmd) { - case WDIOC_GETSUPPORT: - return copy_to_user(argp, &ident, - sizeof (ident)) ? -EFAULT : 0; - - case WDIOC_GETSTATUS: - case WDIOC_GETBOOTSTATUS: - return put_user (0, p); - - case WDIOC_KEEPALIVE: - tco_timer_keepalive (); - return 0; - - case WDIOC_SETOPTIONS: - { - if (get_user (new_options, p)) - return -EFAULT; - - if (new_options & WDIOS_DISABLECARD) { - tco_timer_stop (); - retval = 0; - } - - if (new_options & WDIOS_ENABLECARD) { - tco_timer_keepalive (); - tco_timer_start (); - retval = 0; - } - - return retval; - } - - case WDIOC_SETTIMEOUT: - { - if (get_user(new_heartbeat, p)) - return -EFAULT; - - if (tco_timer_set_heartbeat(new_heartbeat)) - return -EINVAL; - - tco_timer_keepalive (); - /* Fall */ - } - - case WDIOC_GETTIMEOUT: - return put_user(heartbeat, p); - - case WDIOC_GETTIMELEFT: - { - if (tco_timer_get_timeleft(&time_left)) - return -EINVAL; - - return put_user(time_left, p); - } - - default: - return -ENOTTY; - } -} - -/* - * Notify system - */ - -static int i8xx_tco_notify_sys (struct notifier_block *this, unsigned long code, void *unused) -{ - if (code==SYS_DOWN || code==SYS_HALT) { - /* Turn the WDT off */ - tco_timer_stop (); - } - - return NOTIFY_DONE; -} - -/* - * Kernel Interfaces - */ - -static const struct file_operations i8xx_tco_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .write = i8xx_tco_write, - .ioctl = i8xx_tco_ioctl, - .open = i8xx_tco_open, - .release = i8xx_tco_release, -}; - -static struct miscdevice i8xx_tco_miscdev = { - .minor = WATCHDOG_MINOR, - .name = "watchdog", - .fops = &i8xx_tco_fops, -}; - -static struct notifier_block i8xx_tco_notifier = { - .notifier_call = i8xx_tco_notify_sys, -}; - -/* - * Data for PCI driver interface - * - * This data only exists for exporting the supported - * PCI ids via MODULE_DEVICE_TABLE. We do not actually - * register a pci_driver, because someone else might one day - * want to register another driver on the same PCI id. - */ -static struct pci_device_id i8xx_tco_pci_tbl[] = { - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_0) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_0) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_10) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801E_0) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_1) }, - { }, /* End of list */ -}; -MODULE_DEVICE_TABLE (pci, i8xx_tco_pci_tbl); - -/* - * Init & exit routines - */ - -static unsigned char __init i8xx_tco_getdevice (void) -{ - struct pci_dev *dev = NULL; - u8 val1, val2; - u16 badr; - /* - * Find the PCI device - */ - - for_each_pci_dev(dev) - if (pci_match_id(i8xx_tco_pci_tbl, dev)) { - i8xx_tco_pci = dev; - break; - } - - if (i8xx_tco_pci) { - /* - * Find the ACPI base I/O address which is the base - * for the TCO registers (TCOBASE=ACPIBASE + 0x60) - * ACPIBASE is bits [15:7] from 0x40-0x43 - */ - pci_read_config_byte (i8xx_tco_pci, 0x40, &val1); - pci_read_config_byte (i8xx_tco_pci, 0x41, &val2); - badr = ((val2 << 1) | (val1 >> 7)) << 7; - ACPIBASE = badr; - /* Something's wrong here, ACPIBASE has to be set */ - if (badr == 0x0001 || badr == 0x0000) { - printk (KERN_ERR PFX "failed to get TCOBASE address\n"); - pci_dev_put(i8xx_tco_pci); - return 0; - } - - /* Check chipset's NO_REBOOT bit */ - pci_read_config_byte (i8xx_tco_pci, 0xd4, &val1); - if (val1 & 0x02) { - val1 &= 0xfd; - pci_write_config_byte (i8xx_tco_pci, 0xd4, val1); - pci_read_config_byte (i8xx_tco_pci, 0xd4, &val1); - if (val1 & 0x02) { - printk (KERN_ERR PFX "failed to reset NO_REBOOT flag, reboot disabled by hardware\n"); - pci_dev_put(i8xx_tco_pci); - return 0; /* Cannot reset NO_REBOOT bit */ - } - } - /* Disable reboots untill the watchdog starts */ - val1 |= 0x02; - pci_write_config_byte (i8xx_tco_pci, 0xd4, val1); - - /* Set the TCO_EN bit in SMI_EN register */ - if (!request_region (SMI_EN + 1, 1, "i8xx TCO")) { - printk (KERN_ERR PFX "I/O address 0x%04x already in use\n", - SMI_EN + 1); - pci_dev_put(i8xx_tco_pci); - return 0; - } - val1 = inb (SMI_EN + 1); - val1 &= 0xdf; - outb (val1, SMI_EN + 1); - release_region (SMI_EN + 1, 1); - return 1; - } - return 0; -} - -static int __init watchdog_init (void) -{ - int ret; - - spin_lock_init(&tco_lock); - - /* Check whether or not the hardware watchdog is there */ - if (!i8xx_tco_getdevice () || i8xx_tco_pci == NULL) - return -ENODEV; - - if (!request_region (TCOBASE, 0x10, "i8xx TCO")) { - printk (KERN_ERR PFX "I/O address 0x%04x already in use\n", - TCOBASE); - ret = -EIO; - goto out; - } - - /* Clear out the (probably old) status */ - outb (0, TCO1_STS); - outb (3, TCO2_STS); - - /* Check that the heartbeat value is within it's range ; if not reset to the default */ - if (tco_timer_set_heartbeat (heartbeat)) { - heartbeat = WATCHDOG_HEARTBEAT; - tco_timer_set_heartbeat (heartbeat); - printk(KERN_INFO PFX "heartbeat value must be 2<heartbeat<39, using %d\n", - heartbeat); - } - - ret = register_reboot_notifier(&i8xx_tco_notifier); - if (ret != 0) { - printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", - ret); - goto unreg_region; - } - - ret = misc_register(&i8xx_tco_miscdev); - if (ret != 0) { - printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", - WATCHDOG_MINOR, ret); - goto unreg_notifier; - } - - tco_timer_stop (); - - printk (KERN_INFO PFX "initialized (0x%04x). heartbeat=%d sec (nowayout=%d)\n", - TCOBASE, heartbeat, nowayout); - - return 0; - -unreg_notifier: - unregister_reboot_notifier(&i8xx_tco_notifier); -unreg_region: - release_region (TCOBASE, 0x10); -out: - pci_dev_put(i8xx_tco_pci); - return ret; -} - -static void __exit watchdog_cleanup (void) -{ - /* Stop the timer before we leave */ - if (!nowayout) - tco_timer_stop (); - - /* Deregister */ - misc_deregister (&i8xx_tco_miscdev); - unregister_reboot_notifier(&i8xx_tco_notifier); - release_region (TCOBASE, 0x10); - - pci_dev_put(i8xx_tco_pci); -} - -module_init(watchdog_init); -module_exit(watchdog_cleanup); - -MODULE_AUTHOR("Nils Faerber"); -MODULE_DESCRIPTION("TCO timer driver for i8xx chipsets"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); diff --git a/drivers/char/watchdog/i8xx_tco.h b/drivers/char/watchdog/i8xx_tco.h deleted file mode 100644 index cc14eb8ac3d6..000000000000 --- a/drivers/char/watchdog/i8xx_tco.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * i8xx_tco: TCO timer driver for i8xx chipsets - * - * (c) Copyright 2000 kernel concepts <nils@kernelconcepts.de>, All Rights Reserved. - * http://www.kernelconcepts.de - * - * 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 Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Neither kernel concepts nor Nils Faerber admit liability nor provide - * warranty for any of this software. This material is provided - * "AS-IS" and at no charge. - * - * (c) Copyright 2000 kernel concepts <nils@kernelconcepts.de> - * developed for - * Jentro AG, Haar/Munich (Germany) - * - * TCO timer driver for i8xx chipsets - * based on softdog.c by Alan Cox <alan@redhat.com> - * - * For history and the complete list of supported I/O Controller Hub's - * see i8xx_tco.c - */ - - -/* - * Some address definitions for the TCO - */ - -#define TCOBASE ACPIBASE + 0x60 /* TCO base address */ -#define TCO1_RLD TCOBASE + 0x00 /* TCO Timer Reload and Current Value */ -#define TCO1_TMR TCOBASE + 0x01 /* TCO Timer Initial Value */ -#define TCO1_DAT_IN TCOBASE + 0x02 /* TCO Data In Register */ -#define TCO1_DAT_OUT TCOBASE + 0x03 /* TCO Data Out Register */ -#define TCO1_STS TCOBASE + 0x04 /* TCO1 Status Register */ -#define TCO2_STS TCOBASE + 0x06 /* TCO2 Status Register */ -#define TCO1_CNT TCOBASE + 0x08 /* TCO1 Control Register */ -#define TCO2_CNT TCOBASE + 0x0a /* TCO2 Control Register */ - -#define SMI_EN ACPIBASE + 0x30 /* SMI Control and Enable Register */ diff --git a/drivers/char/watchdog/iTCO_wdt.c b/drivers/char/watchdog/iTCO_wdt.c index 3c9684ccd2f9..eac4f9b9f007 100644 --- a/drivers/char/watchdog/iTCO_wdt.c +++ b/drivers/char/watchdog/iTCO_wdt.c @@ -571,7 +571,7 @@ static int iTCO_wdt_init(struct pci_dev *pdev, const struct pci_device_id *ent, * ACPIBASE is bits [15:7] from 0x40-0x43 */ pci_read_config_dword(pdev, 0x40, &base_address); - base_address &= 0x00007f80; + base_address &= 0x0000ff80; if (base_address == 0x00000000) { /* Something's wrong here, ACPIBASE has to be set */ printk(KERN_ERR PFX "failed to get TCOBASE address\n"); diff --git a/drivers/char/watchdog/ibmasr.c b/drivers/char/watchdog/ibmasr.c index 8195f5023d85..94155f6136c2 100644 --- a/drivers/char/watchdog/ibmasr.c +++ b/drivers/char/watchdog/ibmasr.c @@ -367,18 +367,17 @@ static int __init ibmasr_init(void) if (!asr_type) return -ENODEV; + rc = asr_get_base_address(); + if (rc) + return rc; + rc = misc_register(&asr_miscdev); if (rc < 0) { + release_region(asr_base, asr_length); printk(KERN_ERR PFX "failed to register misc device\n"); return rc; } - rc = asr_get_base_address(); - if (rc) { - misc_deregister(&asr_miscdev); - return rc; - } - return 0; } diff --git a/drivers/char/watchdog/ixp2000_wdt.c b/drivers/char/watchdog/ixp2000_wdt.c index fd955dbd588c..dc7548dcaf35 100644 --- a/drivers/char/watchdog/ixp2000_wdt.c +++ b/drivers/char/watchdog/ixp2000_wdt.c @@ -205,7 +205,7 @@ static void __exit ixp2000_wdt_exit(void) module_init(ixp2000_wdt_init); module_exit(ixp2000_wdt_exit); -MODULE_AUTHOR("Deepak Saxena <dsaxena@plexity.net">); +MODULE_AUTHOR("Deepak Saxena <dsaxena@plexity.net>"); MODULE_DESCRIPTION("IXP2000 Network Processor Watchdog"); module_param(heartbeat, int, 0); diff --git a/drivers/char/watchdog/ks8695_wdt.c b/drivers/char/watchdog/ks8695_wdt.c new file mode 100644 index 000000000000..7150fb945eaf --- /dev/null +++ b/drivers/char/watchdog/ks8695_wdt.c @@ -0,0 +1,308 @@ +/* + * Watchdog driver for Kendin/Micrel KS8695. + * + * (C) 2007 Andrew Victor + * + * 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. + */ + +#include <linux/errno.h> +#include <linux/fs.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/miscdevice.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/platform_device.h> +#include <linux/types.h> +#include <linux/watchdog.h> +#include <asm/bitops.h> +#include <asm/io.h> +#include <asm/uaccess.h> +#include <asm/arch/regs-timer.h> + + +#define WDT_DEFAULT_TIME 5 /* seconds */ +#define WDT_MAX_TIME 171 /* seconds */ + +static int wdt_time = WDT_DEFAULT_TIME; +static int nowayout = WATCHDOG_NOWAYOUT; + +module_param(wdt_time, int, 0); +MODULE_PARM_DESC(wdt_time, "Watchdog time in seconds. (default="__MODULE_STRING(WDT_DEFAULT_TIME) ")"); + +#ifdef CONFIG_WATCHDOG_NOWAYOUT +module_param(nowayout, int, 0); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); +#endif + + +static unsigned long ks8695wdt_busy; + +/* ......................................................................... */ + +/* + * Disable the watchdog. + */ +static void inline ks8695_wdt_stop(void) +{ + unsigned long tmcon; + + /* disable timer0 */ + tmcon = __raw_readl(KS8695_TMR_VA + KS8695_TMCON); + __raw_writel(tmcon & ~TMCON_T0EN, KS8695_TMR_VA + KS8695_TMCON); +} + +/* + * Enable and reset the watchdog. + */ +static void inline ks8695_wdt_start(void) +{ + unsigned long tmcon; + unsigned long tval = wdt_time * CLOCK_TICK_RATE; + + /* disable timer0 */ + tmcon = __raw_readl(KS8695_TMR_VA + KS8695_TMCON); + __raw_writel(tmcon & ~TMCON_T0EN, KS8695_TMR_VA + KS8695_TMCON); + + /* program timer0 */ + __raw_writel(tval | T0TC_WATCHDOG, KS8695_TMR_VA + KS8695_T0TC); + + /* re-enable timer0 */ + tmcon = __raw_readl(KS8695_TMR_VA + KS8695_TMCON); + __raw_writel(tmcon | TMCON_T0EN, KS8695_TMR_VA + KS8695_TMCON); +} + +/* + * Reload the watchdog timer. (ie, pat the watchdog) + */ +static void inline ks8695_wdt_reload(void) +{ + unsigned long tmcon; + + /* disable, then re-enable timer0 */ + tmcon = __raw_readl(KS8695_TMR_VA + KS8695_TMCON); + __raw_writel(tmcon & ~TMCON_T0EN, KS8695_TMR_VA + KS8695_TMCON); + __raw_writel(tmcon | TMCON_T0EN, KS8695_TMR_VA + KS8695_TMCON); +} + +/* + * Change the watchdog time interval. + */ +static int ks8695_wdt_settimeout(int new_time) +{ + /* + * All counting occurs at SLOW_CLOCK / 128 = 0.256 Hz + * + * Since WDV is a 16-bit counter, the maximum period is + * 65536 / 0.256 = 256 seconds. + */ + if ((new_time <= 0) || (new_time > WDT_MAX_TIME)) + return -EINVAL; + + /* Set new watchdog time. It will be used when ks8695_wdt_start() is called. */ + wdt_time = new_time; + return 0; +} + +/* ......................................................................... */ + +/* + * Watchdog device is opened, and watchdog starts running. + */ +static int ks8695_wdt_open(struct inode *inode, struct file *file) +{ + if (test_and_set_bit(0, &ks8695wdt_busy)) + return -EBUSY; + + ks8695_wdt_start(); + return nonseekable_open(inode, file); +} + +/* + * Close the watchdog device. + * If CONFIG_WATCHDOG_NOWAYOUT is NOT defined then the watchdog is also + * disabled. + */ +static int ks8695_wdt_close(struct inode *inode, struct file *file) +{ + if (!nowayout) + ks8695_wdt_stop(); /* Disable the watchdog when file is closed */ + + clear_bit(0, &ks8695wdt_busy); + return 0; +} + +static struct watchdog_info ks8695_wdt_info = { + .identity = "ks8695 watchdog", + .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, +}; + +/* + * Handle commands from user-space. + */ +static int ks8695_wdt_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + void __user *argp = (void __user *)arg; + int __user *p = argp; + int new_value; + + switch(cmd) { + case WDIOC_KEEPALIVE: + ks8695_wdt_reload(); /* pat the watchdog */ + return 0; + + case WDIOC_GETSUPPORT: + return copy_to_user(argp, &ks8695_wdt_info, sizeof(ks8695_wdt_info)) ? -EFAULT : 0; + + case WDIOC_SETTIMEOUT: + if (get_user(new_value, p)) + return -EFAULT; + + if (ks8695_wdt_settimeout(new_value)) + return -EINVAL; + + /* Enable new time value */ + ks8695_wdt_start(); + + /* Return current value */ + return put_user(wdt_time, p); + + case WDIOC_GETTIMEOUT: + return put_user(wdt_time, p); + + case WDIOC_GETSTATUS: + case WDIOC_GETBOOTSTATUS: + return put_user(0, p); + + case WDIOC_SETOPTIONS: + if (get_user(new_value, p)) + return -EFAULT; + + if (new_value & WDIOS_DISABLECARD) + ks8695_wdt_stop(); + if (new_value & WDIOS_ENABLECARD) + ks8695_wdt_start(); + return 0; + + default: + return -ENOTTY; + } +} + +/* + * Pat the watchdog whenever device is written to. + */ +static ssize_t ks8695_wdt_write(struct file *file, const char *data, size_t len, loff_t *ppos) +{ + ks8695_wdt_reload(); /* pat the watchdog */ + return len; +} + +/* ......................................................................... */ + +static const struct file_operations ks8695wdt_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .ioctl = ks8695_wdt_ioctl, + .open = ks8695_wdt_open, + .release = ks8695_wdt_close, + .write = ks8695_wdt_write, +}; + +static struct miscdevice ks8695wdt_miscdev = { + .minor = WATCHDOG_MINOR, + .name = "watchdog", + .fops = &ks8695wdt_fops, +}; + +static int __init ks8695wdt_probe(struct platform_device *pdev) +{ + int res; + + if (ks8695wdt_miscdev.parent) + return -EBUSY; + ks8695wdt_miscdev.parent = &pdev->dev; + + res = misc_register(&ks8695wdt_miscdev); + if (res) + return res; + + printk("KS8695 Watchdog Timer enabled (%d seconds%s)\n", wdt_time, nowayout ? ", nowayout" : ""); + return 0; +} + +static int __exit ks8695wdt_remove(struct platform_device *pdev) +{ + int res; + + res = misc_deregister(&ks8695wdt_miscdev); + if (!res) + ks8695wdt_miscdev.parent = NULL; + + return res; +} + +static void ks8695wdt_shutdown(struct platform_device *pdev) +{ + ks8695_wdt_stop(); +} + +#ifdef CONFIG_PM + +static int ks8695wdt_suspend(struct platform_device *pdev, pm_message_t message) +{ + ks8695_wdt_stop(); + return 0; +} + +static int ks8695wdt_resume(struct platform_device *pdev) +{ + if (ks8695wdt_busy) + ks8695_wdt_start(); + return 0; +} + +#else +#define ks8695wdt_suspend NULL +#define ks8695wdt_resume NULL +#endif + +static struct platform_driver ks8695wdt_driver = { + .probe = ks8695wdt_probe, + .remove = __exit_p(ks8695wdt_remove), + .shutdown = ks8695wdt_shutdown, + .suspend = ks8695wdt_suspend, + .resume = ks8695wdt_resume, + .driver = { + .name = "ks8695_wdt", + .owner = THIS_MODULE, + }, +}; + +static int __init ks8695_wdt_init(void) +{ + /* Check that the heartbeat value is within range; if not reset to the default */ + if (ks8695_wdt_settimeout(wdt_time)) { + ks8695_wdt_settimeout(WDT_DEFAULT_TIME); + pr_info("ks8695_wdt: wdt_time value must be 1 <= wdt_time <= %i, using %d\n", wdt_time, WDT_MAX_TIME); + } + + return platform_driver_register(&ks8695wdt_driver); +} + +static void __exit ks8695_wdt_exit(void) +{ + platform_driver_unregister(&ks8695wdt_driver); +} + +module_init(ks8695_wdt_init); +module_exit(ks8695_wdt_exit); + +MODULE_AUTHOR("Andrew Victor"); +MODULE_DESCRIPTION("Watchdog driver for KS8695"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); diff --git a/drivers/char/watchdog/machzwd.c b/drivers/char/watchdog/machzwd.c index 76c7fa37fa6c..a0d27160c80e 100644 --- a/drivers/char/watchdog/machzwd.c +++ b/drivers/char/watchdog/machzwd.c @@ -440,13 +440,6 @@ static int __init zf_init(void) spin_lock_init(&zf_lock); spin_lock_init(&zf_port_lock); - ret = misc_register(&zf_miscdev); - if (ret){ - printk(KERN_ERR "can't misc_register on minor=%d\n", - WATCHDOG_MINOR); - goto out; - } - if(!request_region(ZF_IOBASE, 3, "MachZ ZFL WDT")){ printk(KERN_ERR "cannot reserve I/O ports at %d\n", ZF_IOBASE); @@ -461,16 +454,23 @@ static int __init zf_init(void) goto no_reboot; } + ret = misc_register(&zf_miscdev); + if (ret){ + printk(KERN_ERR "can't misc_register on minor=%d\n", + WATCHDOG_MINOR); + goto no_misc; + } + zf_set_status(0); zf_set_control(0); return 0; +no_misc: + unregister_reboot_notifier(&zf_notifier); no_reboot: release_region(ZF_IOBASE, 3); no_region: - misc_deregister(&zf_miscdev); -out: return ret; } diff --git a/drivers/char/watchdog/mtx-1_wdt.c b/drivers/char/watchdog/mtx-1_wdt.c new file mode 100644 index 000000000000..419ab445c944 --- /dev/null +++ b/drivers/char/watchdog/mtx-1_wdt.c @@ -0,0 +1,238 @@ +/* + * Driver for the MTX-1 Watchdog. + * + * (C) Copyright 2005 4G Systems <info@4g-systems.biz>, All Rights Reserved. + * http://www.4g-systems.biz + * + * (C) Copyright 2007 OpenWrt.org, Florian Fainelli <florian@openwrt.org> + * + * 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 Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Neither Michael Stickel nor 4G Systems admit liability nor provide + * warranty for any of this software. This material is provided + * "AS-IS" and at no charge. + * + * (c) Copyright 2005 4G Systems <info@4g-systems.biz> + * + * Release 0.01. + * Author: Michael Stickel michael.stickel@4g-systems.biz + * + * Release 0.02. + * Author: Florian Fainelli florian@openwrt.org + * use the Linux watchdog/timer APIs + * + * The Watchdog is configured to reset the MTX-1 + * if it is not triggered for 100 seconds. + * It should not be triggered more often than 1.6 seconds. + * + * A timer triggers the watchdog every 5 seconds, until + * it is opened for the first time. After the first open + * it MUST be triggered every 2..95 seconds. + */ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/types.h> +#include <linux/errno.h> +#include <linux/miscdevice.h> +#include <linux/fs.h> +#include <linux/init.h> +#include <linux/ioport.h> +#include <linux/timer.h> +#include <linux/completion.h> +#include <linux/jiffies.h> +#include <linux/watchdog.h> +#include <asm/io.h> +#include <asm/uaccess.h> + +#include <asm/mach-au1x00/au1000.h> + +#define MTX1_WDT_INTERVAL (5 * HZ) + +static int ticks = 100 * HZ; + +static struct { + struct completion stop; + volatile int running; + struct timer_list timer; + volatile int queue; + int default_ticks; + unsigned long inuse; +} mtx1_wdt_device; + +static void mtx1_wdt_trigger(unsigned long unused) +{ + u32 tmp; + + if (mtx1_wdt_device.running) + ticks--; + /* + * toggle GPIO2_15 + */ + tmp = au_readl(GPIO2_DIR); + tmp = (tmp & ~(1<<15)) | ((~tmp) & (1<<15)); + au_writel (tmp, GPIO2_DIR); + + if (mtx1_wdt_device.queue && ticks) + mod_timer(&mtx1_wdt_device.timer, jiffies + MTX1_WDT_INTERVAL); + else { + complete(&mtx1_wdt_device.stop); + } +} + +static void mtx1_wdt_reset(void) +{ + ticks = mtx1_wdt_device.default_ticks; +} + + +static void mtx1_wdt_start(void) +{ + if (!mtx1_wdt_device.queue) { + mtx1_wdt_device.queue = 1; + au_writel (au_readl(GPIO2_DIR) | (u32)(1<<15), GPIO2_DIR); + mod_timer(&mtx1_wdt_device.timer, jiffies + MTX1_WDT_INTERVAL); + } + mtx1_wdt_device.running++; +} + +static int mtx1_wdt_stop(void) +{ + if (mtx1_wdt_device.queue) { + mtx1_wdt_device.queue = 0; + au_writel (au_readl(GPIO2_DIR) & ~((u32)(1<<15)), GPIO2_DIR); + } + + ticks = mtx1_wdt_device.default_ticks; + + return 0; +} + +/* Filesystem functions */ + +static int mtx1_wdt_open(struct inode *inode, struct file *file) +{ + if (test_and_set_bit(0, &mtx1_wdt_device.inuse)) + return -EBUSY; + + return nonseekable_open(inode, file); +} + + +static int mtx1_wdt_release(struct inode *inode, struct file *file) +{ + clear_bit(0, &mtx1_wdt_device.inuse); + return 0; +} + +static int mtx1_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + void __user *argp = (void __user *)arg; + unsigned int value; + static struct watchdog_info ident = + { + .options = WDIOF_CARDRESET, + .identity = "MTX-1 WDT", + }; + + switch(cmd) { + case WDIOC_KEEPALIVE: + mtx1_wdt_reset(); + break; + case WDIOC_GETSTATUS: + if ( copy_to_user(argp, &value, sizeof(int)) ) + return -EFAULT; + break; + case WDIOC_GETSUPPORT: + if ( copy_to_user(argp, &ident, sizeof(ident)) ) + return -EFAULT; + break; + case WDIOC_SETOPTIONS: + if ( copy_from_user(&value, argp, sizeof(int)) ) + return -EFAULT; + switch(value) { + case WDIOS_ENABLECARD: + mtx1_wdt_start(); + break; + case WDIOS_DISABLECARD: + return mtx1_wdt_stop(); + default: + return -EINVAL; + } + break; + default: + return -ENOTTY; + } + return 0; +} + + +static ssize_t mtx1_wdt_write(struct file *file, const char *buf, size_t count, loff_t *ppos) +{ + if (!count) + return -EIO; + + mtx1_wdt_reset(); + return count; +} + +static struct file_operations mtx1_wdt_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .ioctl = mtx1_wdt_ioctl, + .open = mtx1_wdt_open, + .write = mtx1_wdt_write, + .release = mtx1_wdt_release +}; + + +static struct miscdevice mtx1_wdt_misc = { + .minor = WATCHDOG_MINOR, + .name = "watchdog", + .fops = &mtx1_wdt_fops +}; + + +static int __init mtx1_wdt_init(void) +{ + int ret; + + if ((ret = misc_register(&mtx1_wdt_misc)) < 0) { + printk(KERN_ERR " mtx-1_wdt : failed to register\n"); + return ret; + } + + init_completion(&mtx1_wdt_device.stop); + mtx1_wdt_device.queue = 0; + + clear_bit(0, &mtx1_wdt_device.inuse); + + setup_timer(&mtx1_wdt_device.timer, mtx1_wdt_trigger, 0L); + + mtx1_wdt_device.default_ticks = ticks; + + mtx1_wdt_start(); + + printk(KERN_INFO "MTX-1 Watchdog driver\n"); + + return 0; +} + +static void __exit mtx1_wdt_exit(void) +{ + if (mtx1_wdt_device.queue) { + mtx1_wdt_device.queue = 0; + wait_for_completion(&mtx1_wdt_device.stop); + } + misc_deregister(&mtx1_wdt_misc); +} + +module_init(mtx1_wdt_init); +module_exit(mtx1_wdt_exit); + +MODULE_AUTHOR("Michael Stickel, Florian Fainelli"); +MODULE_DESCRIPTION("Driver for the MTX-1 watchdog"); +MODULE_LICENSE("GPL"); diff --git a/drivers/char/watchdog/omap_wdt.c b/drivers/char/watchdog/omap_wdt.c index 84074a697dce..b36fa8de2131 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/pcwd.c b/drivers/char/watchdog/pcwd.c index 6e8b5705b5b7..7b41434fac8c 100644 --- a/drivers/char/watchdog/pcwd.c +++ b/drivers/char/watchdog/pcwd.c @@ -59,10 +59,10 @@ #include <linux/jiffies.h> /* For jiffies stuff */ #include <linux/miscdevice.h> /* For MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR) */ #include <linux/watchdog.h> /* For the watchdog specific items */ -#include <linux/notifier.h> /* For notifier support */ -#include <linux/reboot.h> /* For reboot_notifier stuff */ +#include <linux/reboot.h> /* For kernel_power_off() */ #include <linux/init.h> /* For __init/__exit/... */ #include <linux/fs.h> /* For file operations */ +#include <linux/isa.h> /* For isa devices */ #include <linux/ioport.h> /* For io-port access */ #include <linux/spinlock.h> /* For spin_lock/spin_unlock/... */ @@ -70,8 +70,8 @@ #include <asm/io.h> /* For inb/outb/... */ /* Module and version information */ -#define WATCHDOG_VERSION "1.18" -#define WATCHDOG_DATE "21 Jan 2007" +#define WATCHDOG_VERSION "1.20" +#define WATCHDOG_DATE "18 Feb 2007" #define WATCHDOG_DRIVER_NAME "ISA-PC Watchdog" #define WATCHDOG_NAME "pcwd" #define PFX WATCHDOG_NAME ": " @@ -89,6 +89,15 @@ #define PCWD_REVISION_C 2 /* + * These are the auto-probe addresses available. + * + * Revision A only uses ports 0x270 and 0x370. Revision C introduced 0x350. + * Revision A has an address range of 2 addresses, while Revision C has 4. + */ +#define PCWD_ISA_NR_CARDS 3 +static int pcwd_ioports[] = { 0x270, 0x350, 0x370, 0x000 }; + +/* * These are the defines that describe the control status bits for the * PCI-PC Watchdog card. */ @@ -485,7 +494,7 @@ static int pcwd_get_status(int *status) if (control_status & WD_T110) { *status |= WDIOF_OVERHEAT; if (temp_panic) { - printk (KERN_INFO PFX "Temperature overheat trip!\n"); + printk(KERN_INFO PFX "Temperature overheat trip!\n"); kernel_power_off(); /* or should we just do a: panic(PFX "Temperature overheat trip!\n"); */ } @@ -497,7 +506,7 @@ static int pcwd_get_status(int *status) if (control_status & WD_REVC_TTRP) { *status |= WDIOF_OVERHEAT; if (temp_panic) { - printk (KERN_INFO PFX "Temperature overheat trip!\n"); + printk(KERN_INFO PFX "Temperature overheat trip!\n"); kernel_power_off(); /* or should we just do a: panic(PFX "Temperature overheat trip!\n"); */ } @@ -734,20 +743,6 @@ static int pcwd_temp_close(struct inode *inode, struct file *file) } /* - * Notify system - */ - -static int pcwd_notify_sys(struct notifier_block *this, unsigned long code, void *unused) -{ - if (code==SYS_DOWN || code==SYS_HALT) { - /* Turn the WDT off */ - pcwd_stop(); - } - - return NOTIFY_DONE; -} - -/* * Kernel Interfaces */ @@ -780,10 +775,6 @@ static struct miscdevice temp_miscdev = { .fops = &pcwd_temp_fops, }; -static struct notifier_block pcwd_notifier = { - .notifier_call = pcwd_notify_sys, -}; - /* * Init & exit routines */ @@ -803,10 +794,67 @@ static inline int get_revision(void) return r; } -static int __devinit pcwatchdog_init(int base_addr) +/* + * The ISA cards have a heartbeat bit in one of the registers, which + * register is card dependent. The heartbeat bit is monitored, and if + * found, is considered proof that a Berkshire card has been found. + * The initial rate is once per second at board start up, then twice + * per second for normal operation. + */ +static int __devinit pcwd_isa_match(struct device *dev, unsigned int id) +{ + int base_addr=pcwd_ioports[id]; + int port0, last_port0; /* Reg 0, in case it's REV A */ + int port1, last_port1; /* Register 1 for REV C cards */ + int i; + int retval; + + if (debug >= DEBUG) + printk(KERN_DEBUG PFX "pcwd_isa_match id=%d\n", + id); + + if (!request_region (base_addr, 4, "PCWD")) { + printk(KERN_INFO PFX "Port 0x%04x unavailable\n", base_addr); + return 0; + } + + retval = 0; + + port0 = inb_p(base_addr); /* For REV A boards */ + port1 = inb_p(base_addr + 1); /* For REV C boards */ + if (port0 != 0xff || port1 != 0xff) { + /* Not an 'ff' from a floating bus, so must be a card! */ + for (i = 0; i < 4; ++i) { + + msleep(500); + + last_port0 = port0; + last_port1 = port1; + + port0 = inb_p(base_addr); + port1 = inb_p(base_addr + 1); + + /* Has either hearbeat bit changed? */ + if ((port0 ^ last_port0) & WD_HRTBT || + (port1 ^ last_port1) & WD_REVC_HRBT) { + retval = 1; + break; + } + } + } + release_region (base_addr, 4); + + return retval; +} + +static int __devinit pcwd_isa_probe(struct device *dev, unsigned int id) { int ret; + if (debug >= DEBUG) + printk(KERN_DEBUG PFX "pcwd_isa_probe id=%d\n", + id); + cards_found++; if (cards_found == 1) printk(KERN_INFO PFX "v%s Ken Hollis (kenji@bitgate.com)\n", WD_VER); @@ -816,11 +864,13 @@ static int __devinit pcwatchdog_init(int base_addr) return -ENODEV; } - if (base_addr == 0x0000) { + if (pcwd_ioports[id] == 0x0000) { printk(KERN_ERR PFX "No I/O-Address for card detected\n"); return -ENODEV; } - pcwd_private.io_addr = base_addr; + pcwd_private.io_addr = pcwd_ioports[id]; + + spin_lock_init(&pcwd_private.io_lock); /* Check card's revision */ pcwd_private.revision = get_revision(); @@ -828,8 +878,8 @@ static int __devinit pcwatchdog_init(int base_addr) if (!request_region(pcwd_private.io_addr, (pcwd_private.revision == PCWD_REVISION_A) ? 2 : 4, "PCWD")) { printk(KERN_ERR PFX "I/O address 0x%04x already in use\n", pcwd_private.io_addr); - pcwd_private.io_addr = 0x0000; - return -EIO; + ret=-EIO; + goto error_request_region; } /* Initial variables */ @@ -865,24 +915,12 @@ static int __devinit pcwatchdog_init(int base_addr) WATCHDOG_HEARTBEAT); } - ret = register_reboot_notifier(&pcwd_notifier); - if (ret) { - printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", - ret); - release_region(pcwd_private.io_addr, (pcwd_private.revision == PCWD_REVISION_A) ? 2 : 4); - pcwd_private.io_addr = 0x0000; - return ret; - } - if (pcwd_private.supports_temp) { ret = misc_register(&temp_miscdev); if (ret) { printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", TEMP_MINOR, ret); - unregister_reboot_notifier(&pcwd_notifier); - release_region(pcwd_private.io_addr, (pcwd_private.revision == PCWD_REVISION_A) ? 2 : 4); - pcwd_private.io_addr = 0x0000; - return ret; + goto error_misc_register_temp; } } @@ -890,22 +928,34 @@ static int __devinit pcwatchdog_init(int base_addr) if (ret) { printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", WATCHDOG_MINOR, ret); - if (pcwd_private.supports_temp) - misc_deregister(&temp_miscdev); - unregister_reboot_notifier(&pcwd_notifier); - release_region(pcwd_private.io_addr, (pcwd_private.revision == PCWD_REVISION_A) ? 2 : 4); - pcwd_private.io_addr = 0x0000; - return ret; + goto error_misc_register_watchdog; } printk(KERN_INFO PFX "initialized. heartbeat=%d sec (nowayout=%d)\n", heartbeat, nowayout); return 0; + +error_misc_register_watchdog: + if (pcwd_private.supports_temp) + misc_deregister(&temp_miscdev); +error_misc_register_temp: + release_region(pcwd_private.io_addr, (pcwd_private.revision == PCWD_REVISION_A) ? 2 : 4); +error_request_region: + pcwd_private.io_addr = 0x0000; + cards_found--; + return ret; } -static void __devexit pcwatchdog_exit(void) +static int __devexit pcwd_isa_remove(struct device *dev, unsigned int id) { + if (debug >= DEBUG) + printk(KERN_DEBUG PFX "pcwd_isa_remove id=%d\n", + id); + + if (!pcwd_private.io_addr) + return 1; + /* Disable the board */ if (!nowayout) pcwd_stop(); @@ -914,102 +964,50 @@ static void __devexit pcwatchdog_exit(void) misc_deregister(&pcwd_miscdev); if (pcwd_private.supports_temp) misc_deregister(&temp_miscdev); - unregister_reboot_notifier(&pcwd_notifier); release_region(pcwd_private.io_addr, (pcwd_private.revision == PCWD_REVISION_A) ? 2 : 4); pcwd_private.io_addr = 0x0000; cards_found--; + + return 0; } -/* - * The ISA cards have a heartbeat bit in one of the registers, which - * register is card dependent. The heartbeat bit is monitored, and if - * found, is considered proof that a Berkshire card has been found. - * The initial rate is once per second at board start up, then twice - * per second for normal operation. - */ -static int __init pcwd_checkcard(int base_addr) +static void pcwd_isa_shutdown(struct device *dev, unsigned int id) { - int port0, last_port0; /* Reg 0, in case it's REV A */ - int port1, last_port1; /* Register 1 for REV C cards */ - int i; - int retval; - - if (!request_region (base_addr, 4, "PCWD")) { - printk (KERN_INFO PFX "Port 0x%04x unavailable\n", base_addr); - return 0; - } - - retval = 0; - - port0 = inb_p(base_addr); /* For REV A boards */ - port1 = inb_p(base_addr + 1); /* For REV C boards */ - if (port0 != 0xff || port1 != 0xff) { - /* Not an 'ff' from a floating bus, so must be a card! */ - for (i = 0; i < 4; ++i) { - - msleep(500); - - last_port0 = port0; - last_port1 = port1; - - port0 = inb_p(base_addr); - port1 = inb_p(base_addr + 1); - - /* Has either hearbeat bit changed? */ - if ((port0 ^ last_port0) & WD_HRTBT || - (port1 ^ last_port1) & WD_REVC_HRBT) { - retval = 1; - break; - } - } - } - release_region (base_addr, 4); + if (debug >= DEBUG) + printk(KERN_DEBUG PFX "pcwd_isa_shutdown id=%d\n", + id); - return retval; + pcwd_stop(); } -/* - * These are the auto-probe addresses available. - * - * Revision A only uses ports 0x270 and 0x370. Revision C introduced 0x350. - * Revision A has an address range of 2 addresses, while Revision C has 4. - */ -static int pcwd_ioports[] = { 0x270, 0x350, 0x370, 0x000 }; +static struct isa_driver pcwd_isa_driver = { + .match = pcwd_isa_match, + .probe = pcwd_isa_probe, + .remove = __devexit_p(pcwd_isa_remove), + .shutdown = pcwd_isa_shutdown, + .driver = { + .owner = THIS_MODULE, + .name = WATCHDOG_NAME, + }, +}; static int __init pcwd_init_module(void) { - int i, found = 0; - - spin_lock_init(&pcwd_private.io_lock); - - for (i = 0; pcwd_ioports[i] != 0; i++) { - if (pcwd_checkcard(pcwd_ioports[i])) { - if (!(pcwatchdog_init(pcwd_ioports[i]))) - found++; - } - } - - if (!found) { - printk (KERN_INFO PFX "No card detected, or port not available\n"); - return -ENODEV; - } - - return 0; + return isa_register_driver(&pcwd_isa_driver, PCWD_ISA_NR_CARDS); } static void __exit pcwd_cleanup_module(void) { - if (pcwd_private.io_addr) - pcwatchdog_exit(); - + isa_unregister_driver(&pcwd_isa_driver); printk(KERN_INFO PFX "Watchdog Module Unloaded.\n"); } module_init(pcwd_init_module); module_exit(pcwd_cleanup_module); -MODULE_AUTHOR("Ken Hollis <kenji@bitgate.com>"); +MODULE_AUTHOR("Ken Hollis <kenji@bitgate.com>, Wim Van Sebroeck <wim@iguana.be>"); MODULE_DESCRIPTION("Berkshire ISA-PC Watchdog driver"); +MODULE_VERSION(WATCHDOG_VERSION); MODULE_LICENSE("GPL"); MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); MODULE_ALIAS_MISCDEV(TEMP_MINOR); diff --git a/drivers/char/watchdog/pcwd_usb.c b/drivers/char/watchdog/pcwd_usb.c index 31037f9c9ffe..1e7a6719d5ba 100644 --- a/drivers/char/watchdog/pcwd_usb.c +++ b/drivers/char/watchdog/pcwd_usb.c @@ -146,7 +146,7 @@ struct usb_pcwd_private { atomic_t cmd_received; /* true if we received a report after a command */ int exists; /* Wether or not the device exists */ - struct semaphore sem; /* locks this structure */ + struct mutex mtx; /* locks this structure */ }; static struct usb_pcwd_private *usb_pcwd_device; @@ -635,7 +635,7 @@ static int usb_pcwd_probe(struct usb_interface *interface, const struct usb_devi usb_pcwd_device = usb_pcwd; - init_MUTEX (&usb_pcwd->sem); + mutex_init(&usb_pcwd->mtx); usb_pcwd->udev = udev; usb_pcwd->interface = interface; usb_pcwd->interface_number = iface_desc->desc.bInterfaceNumber; @@ -763,7 +763,7 @@ static void usb_pcwd_disconnect(struct usb_interface *interface) usb_pcwd = usb_get_intfdata (interface); usb_set_intfdata (interface, NULL); - down (&usb_pcwd->sem); + mutex_lock(&usb_pcwd->mtx); /* Stop the timer before we leave */ if (!nowayout) @@ -777,7 +777,7 @@ static void usb_pcwd_disconnect(struct usb_interface *interface) misc_deregister(&usb_pcwd_temperature_miscdev); unregister_reboot_notifier(&usb_pcwd_notifier); - up (&usb_pcwd->sem); + mutex_unlock(&usb_pcwd->mtx); /* Delete the USB PCWD device */ usb_pcwd_delete(usb_pcwd); diff --git a/drivers/char/watchdog/s3c2410_wdt.c b/drivers/char/watchdog/s3c2410_wdt.c index dff6cb5dc9a7..20fa29ca7404 100644 --- a/drivers/char/watchdog/s3c2410_wdt.c +++ b/drivers/char/watchdog/s3c2410_wdt.c @@ -379,14 +379,14 @@ static int s3c2410wdt_probe(struct platform_device *pdev) DBG("probe: mapped wdt_base=%p\n", wdt_base); - res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (res == NULL) { + wdt_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (wdt_irq == NULL) { printk(KERN_INFO PFX "failed to get irq resource\n"); ret = -ENOENT; goto err_map; } - ret = request_irq(res->start, s3c2410wdt_irq, 0, pdev->name, pdev); + ret = request_irq(wdt_irq->start, s3c2410wdt_irq, 0, pdev->name, pdev); if (ret != 0) { printk(KERN_INFO PFX "failed to install irq (%d)\n", ret); goto err_map; diff --git a/drivers/char/watchdog/sbc8360.c b/drivers/char/watchdog/sbc8360.c index 67ae42685e75..285d85289532 100644 --- a/drivers/char/watchdog/sbc8360.c +++ b/drivers/char/watchdog/sbc8360.c @@ -333,18 +333,17 @@ static int __init sbc8360_init(void) int res; unsigned long int mseconds = 60000; - spin_lock_init(&sbc8360_lock); - res = misc_register(&sbc8360_miscdev); - if (res) { - printk(KERN_ERR PFX "failed to register misc device\n"); - goto out_nomisc; + if (timeout < 0 || timeout > 63) { + printk(KERN_ERR PFX "Invalid timeout index (must be 0-63).\n"); + res = -EINVAL; + goto out; } if (!request_region(SBC8360_ENABLE, 1, "SBC8360")) { printk(KERN_ERR PFX "ENABLE method I/O %X is not available.\n", SBC8360_ENABLE); res = -EIO; - goto out_noenablereg; + goto out; } if (!request_region(SBC8360_BASETIME, 1, "SBC8360")) { printk(KERN_ERR PFX @@ -360,10 +359,11 @@ static int __init sbc8360_init(void) goto out_noreboot; } - if (timeout < 0 || timeout > 63) { - printk(KERN_ERR PFX "Invalid timeout index (must be 0-63).\n"); - res = -EINVAL; - goto out_noreboot; + spin_lock_init(&sbc8360_lock); + res = misc_register(&sbc8360_miscdev); + if (res) { + printk(KERN_ERR PFX "failed to register misc device\n"); + goto out_nomisc; } wd_margin = wd_times[timeout][0]; @@ -383,13 +383,13 @@ static int __init sbc8360_init(void) return 0; + out_nomisc: + unregister_reboot_notifier(&sbc8360_notifier); out_noreboot: - release_region(SBC8360_ENABLE, 1); release_region(SBC8360_BASETIME, 1); - out_noenablereg: out_nobasetimereg: - misc_deregister(&sbc8360_miscdev); - out_nomisc: + release_region(SBC8360_ENABLE, 1); + out: return res; } diff --git a/drivers/char/watchdog/w83627hf_wdt.c b/drivers/char/watchdog/w83627hf_wdt.c index 337ee42c90dd..b46e7f47d705 100644 --- a/drivers/char/watchdog/w83627hf_wdt.c +++ b/drivers/char/watchdog/w83627hf_wdt.c @@ -1,5 +1,8 @@ /* - * w83627hf WDT driver + * w83627hf/thf WDT driver + * + * (c) Copyright 2007 Vlad Drukker <vlad@storewiz.com> + * added support for W83627THF. * * (c) Copyright 2003 Pádraig Brady <P@draigBrady.com> * @@ -39,7 +42,7 @@ #include <asm/uaccess.h> #include <asm/system.h> -#define WATCHDOG_NAME "w83627hf WDT" +#define WATCHDOG_NAME "w83627hf/thf WDT" #define PFX WATCHDOG_NAME ": " #define WATCHDOG_TIMEOUT 60 /* 60 sec default timeout */ @@ -50,7 +53,7 @@ static spinlock_t io_lock; /* You must set this - there is no sane way to probe for this board. */ static int wdt_io = 0x2E; module_param(wdt_io, int, 0); -MODULE_PARM_DESC(wdt_io, "w83627hf WDT io port (default 0x2E)"); +MODULE_PARM_DESC(wdt_io, "w83627hf/thf WDT io port (default 0x2E)"); static int timeout = WATCHDOG_TIMEOUT; /* in seconds */ module_param(timeout, int, 0); @@ -71,9 +74,19 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" _ static void w83627hf_select_wd_register(void) { + unsigned char c; outb_p(0x87, WDT_EFER); /* Enter extended function mode */ outb_p(0x87, WDT_EFER); /* Again according to manual */ + outb(0x20, WDT_EFER); /* check chip version */ + c = inb(WDT_EFDR); + if (c == 0x82) { /* W83627THF */ + outb_p(0x2b, WDT_EFER); /* select GPIO3 */ + c = ((inb_p(WDT_EFDR) & 0xf7) | 0x04); /* select WDT0 */ + outb_p(0x2b, WDT_EFER); + outb_p(c, WDT_EFDR); /* set GPIO3 to WDT0 */ + } + outb_p(0x07, WDT_EFER); /* point to logical device number reg */ outb_p(0x08, WDT_EFDR); /* select logical device 8 (GPIO2) */ outb_p(0x30, WDT_EFER); /* select CR30 */ @@ -311,7 +324,7 @@ wdt_init(void) spin_lock_init(&io_lock); - printk(KERN_INFO "WDT driver for the Winbond(TM) W83627HF Super I/O chip initialising.\n"); + printk(KERN_INFO "WDT driver for the Winbond(TM) W83627HF/THF Super I/O chip initialising.\n"); if (wdt_set_heartbeat(timeout)) { wdt_set_heartbeat(WATCHDOG_TIMEOUT); @@ -367,5 +380,5 @@ module_exit(wdt_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Pádraig Brady <P@draigBrady.com>"); -MODULE_DESCRIPTION("w83627hf WDT driver"); +MODULE_DESCRIPTION("w83627hf/thf WDT driver"); MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); |