diff options
Diffstat (limited to 'drivers/char')
| -rw-r--r-- | drivers/char/Kconfig | 10 | ||||
| -rw-r--r-- | drivers/char/Makefile | 1 | ||||
| -rw-r--r-- | drivers/char/hpet.c | 4 | ||||
| -rw-r--r-- | drivers/char/mem.c | 39 | ||||
| -rw-r--r-- | drivers/char/mspec.c | 421 | ||||
| -rw-r--r-- | drivers/char/rtc.c | 5 | ||||
| -rw-r--r-- | drivers/char/watchdog/Kconfig | 8 | ||||
| -rw-r--r-- | drivers/char/watchdog/shwdt.c | 110 |
8 files changed, 558 insertions, 40 deletions
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 52ea94b891f5..1b21c3a911d9 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig | |||
| @@ -439,6 +439,14 @@ config SGI_MBCS | |||
| 439 | If you have an SGI Altix with an attached SABrick | 439 | If you have an SGI Altix with an attached SABrick |
| 440 | say Y or M here, otherwise say N. | 440 | say Y or M here, otherwise say N. |
| 441 | 441 | ||
| 442 | config MSPEC | ||
| 443 | tristate "Memory special operations driver" | ||
| 444 | depends on IA64 | ||
| 445 | help | ||
| 446 | If you have an ia64 and you want to enable memory special | ||
| 447 | operations support (formerly known as fetchop), say Y here, | ||
| 448 | otherwise say N. | ||
| 449 | |||
| 442 | source "drivers/serial/Kconfig" | 450 | source "drivers/serial/Kconfig" |
| 443 | 451 | ||
| 444 | config UNIX98_PTYS | 452 | config UNIX98_PTYS |
| @@ -739,7 +747,7 @@ config NVRAM | |||
| 739 | 747 | ||
| 740 | config RTC | 748 | config RTC |
| 741 | tristate "Enhanced Real Time Clock Support" | 749 | tristate "Enhanced Real Time Clock Support" |
| 742 | depends on !PPC && !PARISC && !IA64 && !M68K && (!SPARC || PCI) && !FRV && !ARM | 750 | depends on !PPC && !PARISC && !IA64 && !M68K && (!SPARC || PCI) && !FRV && !ARM && !SUPERH |
| 743 | ---help--- | 751 | ---help--- |
| 744 | If you say Y here and create a character special file /dev/rtc with | 752 | If you say Y here and create a character special file /dev/rtc with |
| 745 | major number 10 and minor number 135 using mknod ("man mknod"), you | 753 | major number 10 and minor number 135 using mknod ("man mknod"), you |
diff --git a/drivers/char/Makefile b/drivers/char/Makefile index 8c6dfc621520..b583d0cd9fbe 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile | |||
| @@ -47,6 +47,7 @@ obj-$(CONFIG_HVC_RTAS) += hvc_rtas.o | |||
| 47 | obj-$(CONFIG_HVC_DRIVER) += hvc_console.o | 47 | obj-$(CONFIG_HVC_DRIVER) += hvc_console.o |
| 48 | obj-$(CONFIG_RAW_DRIVER) += raw.o | 48 | obj-$(CONFIG_RAW_DRIVER) += raw.o |
| 49 | obj-$(CONFIG_SGI_SNSC) += snsc.o snsc_event.o | 49 | obj-$(CONFIG_SGI_SNSC) += snsc.o snsc_event.o |
| 50 | obj-$(CONFIG_MSPEC) += mspec.o | ||
| 50 | obj-$(CONFIG_MMTIMER) += mmtimer.o | 51 | obj-$(CONFIG_MMTIMER) += mmtimer.o |
| 51 | obj-$(CONFIG_VIOCONS) += viocons.o | 52 | obj-$(CONFIG_VIOCONS) += viocons.o |
| 52 | obj-$(CONFIG_VIOTAPE) += viotape.o | 53 | obj-$(CONFIG_VIOTAPE) += viotape.o |
diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c index 8afba339f05a..58b0eb581114 100644 --- a/drivers/char/hpet.c +++ b/drivers/char/hpet.c | |||
| @@ -868,8 +868,8 @@ int hpet_alloc(struct hpet_data *hdp) | |||
| 868 | do_div(temp, period); | 868 | do_div(temp, period); |
| 869 | hpetp->hp_tick_freq = temp; /* ticks per second */ | 869 | hpetp->hp_tick_freq = temp; /* ticks per second */ |
| 870 | 870 | ||
| 871 | printk(KERN_INFO "hpet%d: at MMIO 0x%lx (virtual 0x%p), IRQ%s", | 871 | printk(KERN_INFO "hpet%d: at MMIO 0x%lx, IRQ%s", |
| 872 | hpetp->hp_which, hdp->hd_phys_address, hdp->hd_address, | 872 | hpetp->hp_which, hdp->hd_phys_address, |
| 873 | hpetp->hp_ntimer > 1 ? "s" : ""); | 873 | hpetp->hp_ntimer > 1 ? "s" : ""); |
| 874 | for (i = 0; i < hpetp->hp_ntimer; i++) | 874 | for (i = 0; i < hpetp->hp_ntimer; i++) |
| 875 | printk("%s %d", i > 0 ? "," : "", hdp->hd_irq[i]); | 875 | printk("%s %d", i > 0 ? "," : "", hdp->hd_irq[i]); |
diff --git a/drivers/char/mem.c b/drivers/char/mem.c index 917b20402664..4ac70ec697f0 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c | |||
| @@ -238,6 +238,32 @@ static pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn, | |||
| 238 | } | 238 | } |
| 239 | #endif | 239 | #endif |
| 240 | 240 | ||
| 241 | #ifndef CONFIG_MMU | ||
| 242 | static unsigned long get_unmapped_area_mem(struct file *file, | ||
| 243 | unsigned long addr, | ||
| 244 | unsigned long len, | ||
| 245 | unsigned long pgoff, | ||
| 246 | unsigned long flags) | ||
| 247 | { | ||
| 248 | if (!valid_mmap_phys_addr_range(pgoff, len)) | ||
| 249 | return (unsigned long) -EINVAL; | ||
| 250 | return pgoff; | ||
| 251 | } | ||
| 252 | |||
| 253 | /* can't do an in-place private mapping if there's no MMU */ | ||
| 254 | static inline int private_mapping_ok(struct vm_area_struct *vma) | ||
| 255 | { | ||
| 256 | return vma->vm_flags & VM_MAYSHARE; | ||
| 257 | } | ||
| 258 | #else | ||
| 259 | #define get_unmapped_area_mem NULL | ||
| 260 | |||
| 261 | static inline int private_mapping_ok(struct vm_area_struct *vma) | ||
| 262 | { | ||
| 263 | return 1; | ||
| 264 | } | ||
| 265 | #endif | ||
| 266 | |||
| 241 | static int mmap_mem(struct file * file, struct vm_area_struct * vma) | 267 | static int mmap_mem(struct file * file, struct vm_area_struct * vma) |
| 242 | { | 268 | { |
| 243 | size_t size = vma->vm_end - vma->vm_start; | 269 | size_t size = vma->vm_end - vma->vm_start; |
| @@ -245,6 +271,9 @@ static int mmap_mem(struct file * file, struct vm_area_struct * vma) | |||
| 245 | if (!valid_mmap_phys_addr_range(vma->vm_pgoff, size)) | 271 | if (!valid_mmap_phys_addr_range(vma->vm_pgoff, size)) |
| 246 | return -EINVAL; | 272 | return -EINVAL; |
| 247 | 273 | ||
| 274 | if (!private_mapping_ok(vma)) | ||
| 275 | return -ENOSYS; | ||
| 276 | |||
| 248 | vma->vm_page_prot = phys_mem_access_prot(file, vma->vm_pgoff, | 277 | vma->vm_page_prot = phys_mem_access_prot(file, vma->vm_pgoff, |
| 249 | size, | 278 | size, |
| 250 | vma->vm_page_prot); | 279 | vma->vm_page_prot); |
| @@ -782,6 +811,7 @@ static const struct file_operations mem_fops = { | |||
| 782 | .write = write_mem, | 811 | .write = write_mem, |
| 783 | .mmap = mmap_mem, | 812 | .mmap = mmap_mem, |
| 784 | .open = open_mem, | 813 | .open = open_mem, |
| 814 | .get_unmapped_area = get_unmapped_area_mem, | ||
| 785 | }; | 815 | }; |
| 786 | 816 | ||
| 787 | static const struct file_operations kmem_fops = { | 817 | static const struct file_operations kmem_fops = { |
| @@ -790,6 +820,7 @@ static const struct file_operations kmem_fops = { | |||
| 790 | .write = write_kmem, | 820 | .write = write_kmem, |
| 791 | .mmap = mmap_kmem, | 821 | .mmap = mmap_kmem, |
| 792 | .open = open_kmem, | 822 | .open = open_kmem, |
| 823 | .get_unmapped_area = get_unmapped_area_mem, | ||
| 793 | }; | 824 | }; |
| 794 | 825 | ||
| 795 | static const struct file_operations null_fops = { | 826 | static const struct file_operations null_fops = { |
| @@ -815,6 +846,10 @@ static const struct file_operations zero_fops = { | |||
| 815 | .mmap = mmap_zero, | 846 | .mmap = mmap_zero, |
| 816 | }; | 847 | }; |
| 817 | 848 | ||
| 849 | /* | ||
| 850 | * capabilities for /dev/zero | ||
| 851 | * - permits private mappings, "copies" are taken of the source of zeros | ||
| 852 | */ | ||
| 818 | static struct backing_dev_info zero_bdi = { | 853 | static struct backing_dev_info zero_bdi = { |
| 819 | .capabilities = BDI_CAP_MAP_COPY, | 854 | .capabilities = BDI_CAP_MAP_COPY, |
| 820 | }; | 855 | }; |
| @@ -862,9 +897,13 @@ static int memory_open(struct inode * inode, struct file * filp) | |||
| 862 | switch (iminor(inode)) { | 897 | switch (iminor(inode)) { |
| 863 | case 1: | 898 | case 1: |
| 864 | filp->f_op = &mem_fops; | 899 | filp->f_op = &mem_fops; |
| 900 | filp->f_mapping->backing_dev_info = | ||
| 901 | &directly_mappable_cdev_bdi; | ||
| 865 | break; | 902 | break; |
| 866 | case 2: | 903 | case 2: |
| 867 | filp->f_op = &kmem_fops; | 904 | filp->f_op = &kmem_fops; |
| 905 | filp->f_mapping->backing_dev_info = | ||
| 906 | &directly_mappable_cdev_bdi; | ||
| 868 | break; | 907 | break; |
| 869 | case 3: | 908 | case 3: |
| 870 | filp->f_op = &null_fops; | 909 | filp->f_op = &null_fops; |
diff --git a/drivers/char/mspec.c b/drivers/char/mspec.c new file mode 100644 index 000000000000..5426b1e5595f --- /dev/null +++ b/drivers/char/mspec.c | |||
| @@ -0,0 +1,421 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2001-2006 Silicon Graphics, Inc. All rights | ||
| 3 | * reserved. | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify it | ||
| 6 | * under the terms of version 2 of the GNU General Public License | ||
| 7 | * as published by the Free Software Foundation. | ||
| 8 | */ | ||
| 9 | |||
| 10 | /* | ||
| 11 | * SN Platform Special Memory (mspec) Support | ||
| 12 | * | ||
| 13 | * This driver exports the SN special memory (mspec) facility to user | ||
| 14 | * processes. | ||
| 15 | * There are three types of memory made available thru this driver: | ||
| 16 | * fetchops, uncached and cached. | ||
| 17 | * | ||
| 18 | * Fetchops are atomic memory operations that are implemented in the | ||
| 19 | * memory controller on SGI SN hardware. | ||
| 20 | * | ||
| 21 | * Uncached are used for memory write combining feature of the ia64 | ||
| 22 | * cpu. | ||
| 23 | * | ||
| 24 | * Cached are used for areas of memory that are used as cached addresses | ||
| 25 | * on our partition and used as uncached addresses from other partitions. | ||
| 26 | * Due to a design constraint of the SN2 Shub, you can not have processors | ||
| 27 | * on the same FSB perform both a cached and uncached reference to the | ||
| 28 | * same cache line. These special memory cached regions prevent the | ||
| 29 | * kernel from ever dropping in a TLB entry and therefore prevent the | ||
| 30 | * processor from ever speculating a cache line from this page. | ||
| 31 | */ | ||
| 32 | |||
| 33 | #include <linux/config.h> | ||
| 34 | #include <linux/types.h> | ||
| 35 | #include <linux/kernel.h> | ||
| 36 | #include <linux/module.h> | ||
| 37 | #include <linux/init.h> | ||
| 38 | #include <linux/errno.h> | ||
| 39 | #include <linux/miscdevice.h> | ||
| 40 | #include <linux/spinlock.h> | ||
| 41 | #include <linux/mm.h> | ||
| 42 | #include <linux/vmalloc.h> | ||
| 43 | #include <linux/string.h> | ||
| 44 | #include <linux/slab.h> | ||
| 45 | #include <linux/numa.h> | ||
| 46 | #include <asm/page.h> | ||
| 47 | #include <asm/system.h> | ||
| 48 | #include <asm/pgtable.h> | ||
| 49 | #include <asm/atomic.h> | ||
| 50 | #include <asm/tlbflush.h> | ||
| 51 | #include <asm/uncached.h> | ||
| 52 | #include <asm/sn/addrs.h> | ||
| 53 | #include <asm/sn/arch.h> | ||
| 54 | #include <asm/sn/mspec.h> | ||
| 55 | #include <asm/sn/sn_cpuid.h> | ||
| 56 | #include <asm/sn/io.h> | ||
| 57 | #include <asm/sn/bte.h> | ||
| 58 | #include <asm/sn/shubio.h> | ||
| 59 | |||
| 60 | |||
| 61 | #define FETCHOP_ID "SGI Fetchop," | ||
| 62 | #define CACHED_ID "Cached," | ||
| 63 | #define UNCACHED_ID "Uncached" | ||
| 64 | #define REVISION "4.0" | ||
| 65 | #define MSPEC_BASENAME "mspec" | ||
| 66 | |||
| 67 | /* | ||
| 68 | * Page types allocated by the device. | ||
| 69 | */ | ||
| 70 | enum { | ||
| 71 | MSPEC_FETCHOP = 1, | ||
| 72 | MSPEC_CACHED, | ||
| 73 | MSPEC_UNCACHED | ||
| 74 | }; | ||
| 75 | |||
| 76 | static int is_sn2; | ||
| 77 | |||
| 78 | /* | ||
| 79 | * One of these structures is allocated when an mspec region is mmaped. The | ||
| 80 | * structure is pointed to by the vma->vm_private_data field in the vma struct. | ||
| 81 | * This structure is used to record the addresses of the mspec pages. | ||
| 82 | */ | ||
| 83 | struct vma_data { | ||
| 84 | atomic_t refcnt; /* Number of vmas sharing the data. */ | ||
| 85 | spinlock_t lock; /* Serialize access to the vma. */ | ||
| 86 | int count; /* Number of pages allocated. */ | ||
| 87 | int type; /* Type of pages allocated. */ | ||
| 88 | unsigned long maddr[0]; /* Array of MSPEC addresses. */ | ||
| 89 | }; | ||
| 90 | |||
| 91 | /* used on shub2 to clear FOP cache in the HUB */ | ||
| 92 | static unsigned long scratch_page[MAX_NUMNODES]; | ||
| 93 | #define SH2_AMO_CACHE_ENTRIES 4 | ||
| 94 | |||
| 95 | static inline int | ||
| 96 | mspec_zero_block(unsigned long addr, int len) | ||
| 97 | { | ||
| 98 | int status; | ||
| 99 | |||
| 100 | if (is_sn2) { | ||
| 101 | if (is_shub2()) { | ||
| 102 | int nid; | ||
| 103 | void *p; | ||
| 104 | int i; | ||
| 105 | |||
| 106 | nid = nasid_to_cnodeid(get_node_number(__pa(addr))); | ||
| 107 | p = (void *)TO_AMO(scratch_page[nid]); | ||
| 108 | |||
| 109 | for (i=0; i < SH2_AMO_CACHE_ENTRIES; i++) { | ||
| 110 | FETCHOP_LOAD_OP(p, FETCHOP_LOAD); | ||
| 111 | p += FETCHOP_VAR_SIZE; | ||
| 112 | } | ||
| 113 | } | ||
| 114 | |||
| 115 | status = bte_copy(0, addr & ~__IA64_UNCACHED_OFFSET, len, | ||
| 116 | BTE_WACQUIRE | BTE_ZERO_FILL, NULL); | ||
| 117 | } else { | ||
| 118 | memset((char *) addr, 0, len); | ||
| 119 | status = 0; | ||
| 120 | } | ||
| 121 | return status; | ||
| 122 | } | ||
| 123 | |||
| 124 | /* | ||
| 125 | * mspec_open | ||
| 126 | * | ||
| 127 | * Called when a device mapping is created by a means other than mmap | ||
| 128 | * (via fork, etc.). Increments the reference count on the underlying | ||
| 129 | * mspec data so it is not freed prematurely. | ||
| 130 | */ | ||
| 131 | static void | ||
| 132 | mspec_open(struct vm_area_struct *vma) | ||
| 133 | { | ||
| 134 | struct vma_data *vdata; | ||
| 135 | |||
| 136 | vdata = vma->vm_private_data; | ||
| 137 | atomic_inc(&vdata->refcnt); | ||
| 138 | } | ||
| 139 | |||
| 140 | /* | ||
| 141 | * mspec_close | ||
| 142 | * | ||
| 143 | * Called when unmapping a device mapping. Frees all mspec pages | ||
| 144 | * belonging to the vma. | ||
| 145 | */ | ||
| 146 | static void | ||
| 147 | mspec_close(struct vm_area_struct *vma) | ||
| 148 | { | ||
| 149 | struct vma_data *vdata; | ||
| 150 | int i, pages, result, vdata_size; | ||
| 151 | |||
| 152 | vdata = vma->vm_private_data; | ||
| 153 | if (!atomic_dec_and_test(&vdata->refcnt)) | ||
| 154 | return; | ||
| 155 | |||
| 156 | pages = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT; | ||
| 157 | vdata_size = sizeof(struct vma_data) + pages * sizeof(long); | ||
| 158 | for (i = 0; i < pages; i++) { | ||
| 159 | if (vdata->maddr[i] == 0) | ||
| 160 | continue; | ||
| 161 | /* | ||
| 162 | * Clear the page before sticking it back | ||
| 163 | * into the pool. | ||
| 164 | */ | ||
| 165 | result = mspec_zero_block(vdata->maddr[i], PAGE_SIZE); | ||
| 166 | if (!result) | ||
| 167 | uncached_free_page(vdata->maddr[i]); | ||
| 168 | else | ||
| 169 | printk(KERN_WARNING "mspec_close(): " | ||
| 170 | "failed to zero page %i\n", | ||
| 171 | result); | ||
| 172 | } | ||
| 173 | |||
| 174 | if (vdata_size <= PAGE_SIZE) | ||
| 175 | kfree(vdata); | ||
| 176 | else | ||
| 177 | vfree(vdata); | ||
| 178 | } | ||
| 179 | |||
| 180 | |||
| 181 | /* | ||
| 182 | * mspec_nopfn | ||
| 183 | * | ||
| 184 | * Creates a mspec page and maps it to user space. | ||
| 185 | */ | ||
| 186 | static unsigned long | ||
| 187 | mspec_nopfn(struct vm_area_struct *vma, unsigned long address) | ||
| 188 | { | ||
| 189 | unsigned long paddr, maddr; | ||
| 190 | unsigned long pfn; | ||
| 191 | int index; | ||
| 192 | struct vma_data *vdata = vma->vm_private_data; | ||
| 193 | |||
| 194 | index = (address - vma->vm_start) >> PAGE_SHIFT; | ||
| 195 | maddr = (volatile unsigned long) vdata->maddr[index]; | ||
| 196 | if (maddr == 0) { | ||
| 197 | maddr = uncached_alloc_page(numa_node_id()); | ||
| 198 | if (maddr == 0) | ||
| 199 | return NOPFN_OOM; | ||
| 200 | |||
| 201 | spin_lock(&vdata->lock); | ||
| 202 | if (vdata->maddr[index] == 0) { | ||
| 203 | vdata->count++; | ||
| 204 | vdata->maddr[index] = maddr; | ||
| 205 | } else { | ||
| 206 | uncached_free_page(maddr); | ||
| 207 | maddr = vdata->maddr[index]; | ||
| 208 | } | ||
| 209 | spin_unlock(&vdata->lock); | ||
| 210 | } | ||
| 211 | |||
| 212 | if (vdata->type == MSPEC_FETCHOP) | ||
| 213 | paddr = TO_AMO(maddr); | ||
| 214 | else | ||
| 215 | paddr = __pa(TO_CAC(maddr)); | ||
| 216 | |||
| 217 | pfn = paddr >> PAGE_SHIFT; | ||
| 218 | |||
| 219 | return pfn; | ||
| 220 | } | ||
| 221 | |||
| 222 | static struct vm_operations_struct mspec_vm_ops = { | ||
| 223 | .open = mspec_open, | ||
| 224 | .close = mspec_close, | ||
| 225 | .nopfn = mspec_nopfn | ||
| 226 | }; | ||
| 227 | |||
| 228 | /* | ||
| 229 | * mspec_mmap | ||
| 230 | * | ||
| 231 | * Called when mmaping the device. Initializes the vma with a fault handler | ||
| 232 | * and private data structure necessary to allocate, track, and free the | ||
| 233 | * underlying pages. | ||
| 234 | */ | ||
| 235 | static int | ||
| 236 | mspec_mmap(struct file *file, struct vm_area_struct *vma, int type) | ||
| 237 | { | ||
| 238 | struct vma_data *vdata; | ||
| 239 | int pages, vdata_size; | ||
| 240 | |||
| 241 | if (vma->vm_pgoff != 0) | ||
| 242 | return -EINVAL; | ||
| 243 | |||
| 244 | if ((vma->vm_flags & VM_SHARED) == 0) | ||
| 245 | return -EINVAL; | ||
| 246 | |||
| 247 | if ((vma->vm_flags & VM_WRITE) == 0) | ||
| 248 | return -EPERM; | ||
| 249 | |||
| 250 | pages = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT; | ||
| 251 | vdata_size = sizeof(struct vma_data) + pages * sizeof(long); | ||
| 252 | if (vdata_size <= PAGE_SIZE) | ||
| 253 | vdata = kmalloc(vdata_size, GFP_KERNEL); | ||
| 254 | else | ||
| 255 | vdata = vmalloc(vdata_size); | ||
| 256 | if (!vdata) | ||
| 257 | return -ENOMEM; | ||
| 258 | memset(vdata, 0, vdata_size); | ||
| 259 | |||
| 260 | vdata->type = type; | ||
| 261 | spin_lock_init(&vdata->lock); | ||
| 262 | vdata->refcnt = ATOMIC_INIT(1); | ||
| 263 | vma->vm_private_data = vdata; | ||
| 264 | |||
| 265 | vma->vm_flags |= (VM_IO | VM_LOCKED | VM_RESERVED | VM_PFNMAP); | ||
| 266 | if (vdata->type == MSPEC_FETCHOP || vdata->type == MSPEC_UNCACHED) | ||
| 267 | vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); | ||
| 268 | vma->vm_ops = &mspec_vm_ops; | ||
| 269 | |||
| 270 | return 0; | ||
| 271 | } | ||
| 272 | |||
| 273 | static int | ||
| 274 | fetchop_mmap(struct file *file, struct vm_area_struct *vma) | ||
| 275 | { | ||
| 276 | return mspec_mmap(file, vma, MSPEC_FETCHOP); | ||
| 277 | } | ||
| 278 | |||
| 279 | static int | ||
| 280 | cached_mmap(struct file *file, struct vm_area_struct *vma) | ||
| 281 | { | ||
| 282 | return mspec_mmap(file, vma, MSPEC_CACHED); | ||
| 283 | } | ||
| 284 | |||
| 285 | static int | ||
| 286 | uncached_mmap(struct file *file, struct vm_area_struct *vma) | ||
| 287 | { | ||
| 288 | return mspec_mmap(file, vma, MSPEC_UNCACHED); | ||
| 289 | } | ||
| 290 | |||
| 291 | static struct file_operations fetchop_fops = { | ||
| 292 | .owner = THIS_MODULE, | ||
| 293 | .mmap = fetchop_mmap | ||
| 294 | }; | ||
| 295 | |||
| 296 | static struct miscdevice fetchop_miscdev = { | ||
| 297 | .minor = MISC_DYNAMIC_MINOR, | ||
| 298 | .name = "sgi_fetchop", | ||
| 299 | .fops = &fetchop_fops | ||
| 300 | }; | ||
| 301 | |||
| 302 | static struct file_operations cached_fops = { | ||
| 303 | .owner = THIS_MODULE, | ||
| 304 | .mmap = cached_mmap | ||
| 305 | }; | ||
| 306 | |||
| 307 | static struct miscdevice cached_miscdev = { | ||
| 308 | .minor = MISC_DYNAMIC_MINOR, | ||
| 309 | .name = "mspec_cached", | ||
| 310 | .fops = &cached_fops | ||
| 311 | }; | ||
| 312 | |||
| 313 | static struct file_operations uncached_fops = { | ||
| 314 | .owner = THIS_MODULE, | ||
| 315 | .mmap = uncached_mmap | ||
| 316 | }; | ||
| 317 | |||
| 318 | static struct miscdevice uncached_miscdev = { | ||
| 319 | .minor = MISC_DYNAMIC_MINOR, | ||
| 320 | .name = "mspec_uncached", | ||
| 321 | .fops = &uncached_fops | ||
| 322 | }; | ||
| 323 | |||
| 324 | /* | ||
| 325 | * mspec_init | ||
| 326 | * | ||
| 327 | * Called at boot time to initialize the mspec facility. | ||
| 328 | */ | ||
| 329 | static int __init | ||
| 330 | mspec_init(void) | ||
| 331 | { | ||
| 332 | int ret; | ||
| 333 | int nid; | ||
| 334 | |||
| 335 | /* | ||
| 336 | * The fetchop device only works on SN2 hardware, uncached and cached | ||
| 337 | * memory drivers should both be valid on all ia64 hardware | ||
| 338 | */ | ||
| 339 | if (ia64_platform_is("sn2")) { | ||
| 340 | is_sn2 = 1; | ||
| 341 | if (is_shub2()) { | ||
| 342 | ret = -ENOMEM; | ||
| 343 | for_each_online_node(nid) { | ||
| 344 | int actual_nid; | ||
| 345 | int nasid; | ||
| 346 | unsigned long phys; | ||
| 347 | |||
| 348 | scratch_page[nid] = uncached_alloc_page(nid); | ||
| 349 | if (scratch_page[nid] == 0) | ||
| 350 | goto free_scratch_pages; | ||
| 351 | phys = __pa(scratch_page[nid]); | ||
| 352 | nasid = get_node_number(phys); | ||
| 353 | actual_nid = nasid_to_cnodeid(nasid); | ||
| 354 | if (actual_nid != nid) | ||
| 355 | goto free_scratch_pages; | ||
| 356 | } | ||
| 357 | } | ||
| 358 | |||
| 359 | ret = misc_register(&fetchop_miscdev); | ||
| 360 | if (ret) { | ||
| 361 | printk(KERN_ERR | ||
| 362 | "%s: failed to register device %i\n", | ||
| 363 | FETCHOP_ID, ret); | ||
| 364 | goto free_scratch_pages; | ||
| 365 | } | ||
| 366 | } | ||
| 367 | ret = misc_register(&cached_miscdev); | ||
| 368 | if (ret) { | ||
| 369 | printk(KERN_ERR "%s: failed to register device %i\n", | ||
| 370 | CACHED_ID, ret); | ||
| 371 | if (is_sn2) | ||
| 372 | misc_deregister(&fetchop_miscdev); | ||
| 373 | goto free_scratch_pages; | ||
| 374 | } | ||
| 375 | ret = misc_register(&uncached_miscdev); | ||
| 376 | if (ret) { | ||
| 377 | printk(KERN_ERR "%s: failed to register device %i\n", | ||
| 378 | UNCACHED_ID, ret); | ||
| 379 | misc_deregister(&cached_miscdev); | ||
| 380 | if (is_sn2) | ||
| 381 | misc_deregister(&fetchop_miscdev); | ||
| 382 | goto free_scratch_pages; | ||
| 383 | } | ||
| 384 | |||
| 385 | printk(KERN_INFO "%s %s initialized devices: %s %s %s\n", | ||
| 386 | MSPEC_BASENAME, REVISION, is_sn2 ? FETCHOP_ID : "", | ||
| 387 | CACHED_ID, UNCACHED_ID); | ||
| 388 | |||
| 389 | return 0; | ||
| 390 | |||
| 391 | free_scratch_pages: | ||
| 392 | for_each_node(nid) { | ||
| 393 | if (scratch_page[nid] != 0) | ||
| 394 | uncached_free_page(scratch_page[nid]); | ||
| 395 | } | ||
| 396 | return ret; | ||
| 397 | } | ||
| 398 | |||
| 399 | static void __exit | ||
| 400 | mspec_exit(void) | ||
| 401 | { | ||
| 402 | int nid; | ||
| 403 | |||
| 404 | misc_deregister(&uncached_miscdev); | ||
| 405 | misc_deregister(&cached_miscdev); | ||
| 406 | if (is_sn2) { | ||
| 407 | misc_deregister(&fetchop_miscdev); | ||
| 408 | |||
| 409 | for_each_node(nid) { | ||
| 410 | if (scratch_page[nid] != 0) | ||
| 411 | uncached_free_page(scratch_page[nid]); | ||
| 412 | } | ||
| 413 | } | ||
| 414 | } | ||
| 415 | |||
| 416 | module_init(mspec_init); | ||
| 417 | module_exit(mspec_exit); | ||
| 418 | |||
| 419 | MODULE_AUTHOR("Silicon Graphics, Inc. <linux-altix@sgi.com>"); | ||
| 420 | MODULE_DESCRIPTION("Driver for SGI SN special memory operations"); | ||
| 421 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c index 6e6a7c7a7eff..ab6429b4a84e 100644 --- a/drivers/char/rtc.c +++ b/drivers/char/rtc.c | |||
| @@ -209,11 +209,12 @@ static const unsigned char days_in_mo[] = | |||
| 209 | */ | 209 | */ |
| 210 | static inline unsigned char rtc_is_updating(void) | 210 | static inline unsigned char rtc_is_updating(void) |
| 211 | { | 211 | { |
| 212 | unsigned long flags; | ||
| 212 | unsigned char uip; | 213 | unsigned char uip; |
| 213 | 214 | ||
| 214 | spin_lock_irq(&rtc_lock); | 215 | spin_lock_irqsave(&rtc_lock, flags); |
| 215 | uip = (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP); | 216 | uip = (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP); |
| 216 | spin_unlock_irq(&rtc_lock); | 217 | spin_unlock_irqrestore(&rtc_lock, flags); |
| 217 | return uip; | 218 | return uip; |
| 218 | } | 219 | } |
| 219 | 220 | ||
diff --git a/drivers/char/watchdog/Kconfig b/drivers/char/watchdog/Kconfig index fff89c2d88fd..f114d7b5bb2a 100644 --- a/drivers/char/watchdog/Kconfig +++ b/drivers/char/watchdog/Kconfig | |||
| @@ -510,6 +510,14 @@ config SH_WDT | |||
| 510 | To compile this driver as a module, choose M here: the | 510 | To compile this driver as a module, choose M here: the |
| 511 | module will be called shwdt. | 511 | module will be called shwdt. |
| 512 | 512 | ||
| 513 | config SH_WDT_MMAP | ||
| 514 | bool "Allow mmap of SH WDT" | ||
| 515 | default n | ||
| 516 | depends on SH_WDT | ||
| 517 | help | ||
| 518 | If you say Y here, user applications will be able to mmap the | ||
| 519 | WDT/CPG registers. | ||
| 520 | # | ||
| 513 | # SPARC64 Architecture | 521 | # SPARC64 Architecture |
| 514 | 522 | ||
| 515 | config WATCHDOG_CP1XXX | 523 | config WATCHDOG_CP1XXX |
diff --git a/drivers/char/watchdog/shwdt.c b/drivers/char/watchdog/shwdt.c index 1355038f1044..e5b8c64f1d65 100644 --- a/drivers/char/watchdog/shwdt.c +++ b/drivers/char/watchdog/shwdt.c | |||
| @@ -27,7 +27,7 @@ | |||
| 27 | #include <linux/notifier.h> | 27 | #include <linux/notifier.h> |
| 28 | #include <linux/ioport.h> | 28 | #include <linux/ioport.h> |
| 29 | #include <linux/fs.h> | 29 | #include <linux/fs.h> |
| 30 | 30 | #include <linux/mm.h> | |
| 31 | #include <asm/io.h> | 31 | #include <asm/io.h> |
| 32 | #include <asm/uaccess.h> | 32 | #include <asm/uaccess.h> |
| 33 | #include <asm/watchdog.h> | 33 | #include <asm/watchdog.h> |
| @@ -125,7 +125,6 @@ static void sh_wdt_start(void) | |||
| 125 | 125 | ||
| 126 | /** | 126 | /** |
| 127 | * sh_wdt_stop - Stop the Watchdog | 127 | * sh_wdt_stop - Stop the Watchdog |
| 128 | * | ||
| 129 | * Stops the watchdog. | 128 | * Stops the watchdog. |
| 130 | */ | 129 | */ |
| 131 | static void sh_wdt_stop(void) | 130 | static void sh_wdt_stop(void) |
| @@ -141,22 +140,20 @@ static void sh_wdt_stop(void) | |||
| 141 | 140 | ||
| 142 | /** | 141 | /** |
| 143 | * sh_wdt_keepalive - Keep the Userspace Watchdog Alive | 142 | * sh_wdt_keepalive - Keep the Userspace Watchdog Alive |
| 144 | * | ||
| 145 | * The Userspace watchdog got a KeepAlive: schedule the next heartbeat. | 143 | * The Userspace watchdog got a KeepAlive: schedule the next heartbeat. |
| 146 | */ | 144 | */ |
| 147 | static void sh_wdt_keepalive(void) | 145 | static inline void sh_wdt_keepalive(void) |
| 148 | { | 146 | { |
| 149 | next_heartbeat = jiffies + (heartbeat * HZ); | 147 | next_heartbeat = jiffies + (heartbeat * HZ); |
| 150 | } | 148 | } |
| 151 | 149 | ||
| 152 | /** | 150 | /** |
| 153 | * sh_wdt_set_heartbeat - Set the Userspace Watchdog heartbeat | 151 | * sh_wdt_set_heartbeat - Set the Userspace Watchdog heartbeat |
| 154 | * | ||
| 155 | * Set the Userspace Watchdog heartbeat | 152 | * Set the Userspace Watchdog heartbeat |
| 156 | */ | 153 | */ |
| 157 | static int sh_wdt_set_heartbeat(int t) | 154 | static int sh_wdt_set_heartbeat(int t) |
| 158 | { | 155 | { |
| 159 | if ((t < 1) || (t > 3600)) /* arbitrary upper limit */ | 156 | if (unlikely((t < 1) || (t > 3600))) /* arbitrary upper limit */ |
| 160 | return -EINVAL; | 157 | return -EINVAL; |
| 161 | 158 | ||
| 162 | heartbeat = t; | 159 | heartbeat = t; |
| @@ -165,7 +162,6 @@ static int sh_wdt_set_heartbeat(int t) | |||
| 165 | 162 | ||
| 166 | /** | 163 | /** |
| 167 | * sh_wdt_ping - Ping the Watchdog | 164 | * sh_wdt_ping - Ping the Watchdog |
| 168 | * | ||
| 169 | * @data: Unused | 165 | * @data: Unused |
| 170 | * | 166 | * |
| 171 | * Clears overflow bit, resets timer counter. | 167 | * Clears overflow bit, resets timer counter. |
| @@ -182,14 +178,13 @@ static void sh_wdt_ping(unsigned long data) | |||
| 182 | sh_wdt_write_cnt(0); | 178 | sh_wdt_write_cnt(0); |
| 183 | 179 | ||
| 184 | mod_timer(&timer, next_ping_period(clock_division_ratio)); | 180 | mod_timer(&timer, next_ping_period(clock_division_ratio)); |
| 185 | } else { | 181 | } else |
| 186 | printk(KERN_WARNING PFX "Heartbeat lost! Will not ping the watchdog\n"); | 182 | printk(KERN_WARNING PFX "Heartbeat lost! Will not ping " |
| 187 | } | 183 | "the watchdog\n"); |
| 188 | } | 184 | } |
| 189 | 185 | ||
| 190 | /** | 186 | /** |
| 191 | * sh_wdt_open - Open the Device | 187 | * sh_wdt_open - Open the Device |
| 192 | * | ||
| 193 | * @inode: inode of device | 188 | * @inode: inode of device |
| 194 | * @file: file handle of device | 189 | * @file: file handle of device |
| 195 | * | 190 | * |
| @@ -209,7 +204,6 @@ static int sh_wdt_open(struct inode *inode, struct file *file) | |||
| 209 | 204 | ||
| 210 | /** | 205 | /** |
| 211 | * sh_wdt_close - Close the Device | 206 | * sh_wdt_close - Close the Device |
| 212 | * | ||
| 213 | * @inode: inode of device | 207 | * @inode: inode of device |
| 214 | * @file: file handle of device | 208 | * @file: file handle of device |
| 215 | * | 209 | * |
| @@ -220,7 +214,8 @@ static int sh_wdt_close(struct inode *inode, struct file *file) | |||
| 220 | if (shwdt_expect_close == 42) { | 214 | if (shwdt_expect_close == 42) { |
| 221 | sh_wdt_stop(); | 215 | sh_wdt_stop(); |
| 222 | } else { | 216 | } else { |
| 223 | printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n"); | 217 | printk(KERN_CRIT PFX "Unexpected close, not " |
| 218 | "stopping watchdog!\n"); | ||
| 224 | sh_wdt_keepalive(); | 219 | sh_wdt_keepalive(); |
| 225 | } | 220 | } |
| 226 | 221 | ||
| @@ -232,7 +227,6 @@ static int sh_wdt_close(struct inode *inode, struct file *file) | |||
| 232 | 227 | ||
| 233 | /** | 228 | /** |
| 234 | * sh_wdt_write - Write to Device | 229 | * sh_wdt_write - Write to Device |
| 235 | * | ||
| 236 | * @file: file handle of device | 230 | * @file: file handle of device |
| 237 | * @buf: buffer to write | 231 | * @buf: buffer to write |
| 238 | * @count: length of buffer | 232 | * @count: length of buffer |
| @@ -264,8 +258,56 @@ static ssize_t sh_wdt_write(struct file *file, const char *buf, | |||
| 264 | } | 258 | } |
| 265 | 259 | ||
| 266 | /** | 260 | /** |
| 267 | * sh_wdt_ioctl - Query Device | 261 | * sh_wdt_mmap - map WDT/CPG registers into userspace |
| 262 | * @file: file structure for the device | ||
| 263 | * @vma: VMA to map the registers into | ||
| 264 | * | ||
| 265 | * A simple mmap() implementation for the corner cases where the counter | ||
| 266 | * needs to be mapped in userspace directly. Due to the relatively small | ||
| 267 | * size of the area, neighbouring registers not necessarily tied to the | ||
| 268 | * CPG will also be accessible through the register page, so this remains | ||
| 269 | * configurable for users that really know what they're doing. | ||
| 268 | * | 270 | * |
| 271 | * Additionaly, the register page maps in the CPG register base relative | ||
| 272 | * to the nearest page-aligned boundary, which requires that userspace do | ||
| 273 | * the appropriate CPU subtype math for calculating the page offset for | ||
| 274 | * the counter value. | ||
| 275 | */ | ||
| 276 | static int sh_wdt_mmap(struct file *file, struct vm_area_struct *vma) | ||
| 277 | { | ||
| 278 | int ret = -ENOSYS; | ||
| 279 | |||
| 280 | #ifdef CONFIG_SH_WDT_MMAP | ||
| 281 | unsigned long addr; | ||
| 282 | |||
| 283 | /* Only support the simple cases where we map in a register page. */ | ||
| 284 | if (((vma->vm_end - vma->vm_start) != PAGE_SIZE) || vma->vm_pgoff) | ||
| 285 | return -EINVAL; | ||
| 286 | |||
| 287 | /* | ||
| 288 | * Pick WTCNT as the start, it's usually the first register after the | ||
| 289 | * FRQCR, and neither one are generally page-aligned out of the box. | ||
| 290 | */ | ||
| 291 | addr = WTCNT & ~(PAGE_SIZE - 1); | ||
| 292 | |||
| 293 | vma->vm_flags |= VM_IO; | ||
| 294 | vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); | ||
| 295 | |||
| 296 | if (io_remap_pfn_range(vma, vma->vm_start, addr >> PAGE_SHIFT, | ||
| 297 | PAGE_SIZE, vma->vm_page_prot)) { | ||
| 298 | printk(KERN_ERR PFX "%s: io_remap_pfn_range failed\n", | ||
| 299 | __FUNCTION__); | ||
| 300 | return -EAGAIN; | ||
| 301 | } | ||
| 302 | |||
| 303 | ret = 0; | ||
| 304 | #endif | ||
| 305 | |||
| 306 | return ret; | ||
| 307 | } | ||
| 308 | |||
| 309 | /** | ||
| 310 | * sh_wdt_ioctl - Query Device | ||
| 269 | * @inode: inode of device | 311 | * @inode: inode of device |
| 270 | * @file: file handle of device | 312 | * @file: file handle of device |
| 271 | * @cmd: watchdog command | 313 | * @cmd: watchdog command |
| @@ -326,7 +368,6 @@ static int sh_wdt_ioctl(struct inode *inode, struct file *file, | |||
| 326 | 368 | ||
| 327 | /** | 369 | /** |
| 328 | * sh_wdt_notify_sys - Notifier Handler | 370 | * sh_wdt_notify_sys - Notifier Handler |
| 329 | * | ||
| 330 | * @this: notifier block | 371 | * @this: notifier block |
| 331 | * @code: notifier event | 372 | * @code: notifier event |
| 332 | * @unused: unused | 373 | * @unused: unused |
| @@ -337,9 +378,8 @@ static int sh_wdt_ioctl(struct inode *inode, struct file *file, | |||
| 337 | static int sh_wdt_notify_sys(struct notifier_block *this, | 378 | static int sh_wdt_notify_sys(struct notifier_block *this, |
| 338 | unsigned long code, void *unused) | 379 | unsigned long code, void *unused) |
| 339 | { | 380 | { |
| 340 | if (code == SYS_DOWN || code == SYS_HALT) { | 381 | if (code == SYS_DOWN || code == SYS_HALT) |
| 341 | sh_wdt_stop(); | 382 | sh_wdt_stop(); |
| 342 | } | ||
| 343 | 383 | ||
| 344 | return NOTIFY_DONE; | 384 | return NOTIFY_DONE; |
| 345 | } | 385 | } |
| @@ -351,10 +391,12 @@ static const struct file_operations sh_wdt_fops = { | |||
| 351 | .ioctl = sh_wdt_ioctl, | 391 | .ioctl = sh_wdt_ioctl, |
| 352 | .open = sh_wdt_open, | 392 | .open = sh_wdt_open, |
| 353 | .release = sh_wdt_close, | 393 | .release = sh_wdt_close, |
| 394 | .mmap = sh_wdt_mmap, | ||
| 354 | }; | 395 | }; |
| 355 | 396 | ||
| 356 | static struct watchdog_info sh_wdt_info = { | 397 | static struct watchdog_info sh_wdt_info = { |
| 357 | .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE, | 398 | .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | |
| 399 | WDIOF_MAGICCLOSE, | ||
| 358 | .firmware_version = 1, | 400 | .firmware_version = 1, |
| 359 | .identity = "SH WDT", | 401 | .identity = "SH WDT", |
| 360 | }; | 402 | }; |
| @@ -371,7 +413,6 @@ static struct miscdevice sh_wdt_miscdev = { | |||
| 371 | 413 | ||
| 372 | /** | 414 | /** |
| 373 | * sh_wdt_init - Initialize module | 415 | * sh_wdt_init - Initialize module |
| 374 | * | ||
| 375 | * Registers the device and notifier handler. Actual device | 416 | * Registers the device and notifier handler. Actual device |
| 376 | * initialization is handled by sh_wdt_open(). | 417 | * initialization is handled by sh_wdt_open(). |
| 377 | */ | 418 | */ |
| @@ -381,15 +422,15 @@ static int __init sh_wdt_init(void) | |||
| 381 | 422 | ||
| 382 | if ((clock_division_ratio < 0x5) || (clock_division_ratio > 0x7)) { | 423 | if ((clock_division_ratio < 0x5) || (clock_division_ratio > 0x7)) { |
| 383 | clock_division_ratio = WTCSR_CKS_4096; | 424 | clock_division_ratio = WTCSR_CKS_4096; |
| 384 | printk(KERN_INFO PFX "clock_division_ratio value must be 0x5<=x<=0x7, using %d\n", | 425 | printk(KERN_INFO PFX "clock_division_ratio value must " |
| 385 | clock_division_ratio); | 426 | "be 0x5<=x<=0x7, using %d\n", clock_division_ratio); |
| 386 | } | 427 | } |
| 387 | 428 | ||
| 388 | if (sh_wdt_set_heartbeat(heartbeat)) | 429 | rc = sh_wdt_set_heartbeat(heartbeat); |
| 389 | { | 430 | if (unlikely(rc)) { |
| 390 | heartbeat = WATCHDOG_HEARTBEAT; | 431 | heartbeat = WATCHDOG_HEARTBEAT; |
| 391 | printk(KERN_INFO PFX "heartbeat value must be 1<=x<=3600, using %d\n", | 432 | printk(KERN_INFO PFX "heartbeat value must " |
| 392 | heartbeat); | 433 | "be 1<=x<=3600, using %d\n", heartbeat); |
| 393 | } | 434 | } |
| 394 | 435 | ||
| 395 | init_timer(&timer); | 436 | init_timer(&timer); |
| @@ -397,15 +438,16 @@ static int __init sh_wdt_init(void) | |||
| 397 | timer.data = 0; | 438 | timer.data = 0; |
| 398 | 439 | ||
| 399 | rc = register_reboot_notifier(&sh_wdt_notifier); | 440 | rc = register_reboot_notifier(&sh_wdt_notifier); |
| 400 | if (rc) { | 441 | if (unlikely(rc)) { |
| 401 | printk(KERN_ERR PFX "Can't register reboot notifier (err=%d)\n", rc); | 442 | printk(KERN_ERR PFX "Can't register reboot notifier (err=%d)\n", |
| 443 | rc); | ||
| 402 | return rc; | 444 | return rc; |
| 403 | } | 445 | } |
| 404 | 446 | ||
| 405 | rc = misc_register(&sh_wdt_miscdev); | 447 | rc = misc_register(&sh_wdt_miscdev); |
| 406 | if (rc) { | 448 | if (unlikely(rc)) { |
| 407 | printk(KERN_ERR PFX "Can't register miscdev on minor=%d (err=%d)\n", | 449 | printk(KERN_ERR PFX "Can't register miscdev on " |
| 408 | sh_wdt_miscdev.minor, rc); | 450 | "minor=%d (err=%d)\n", sh_wdt_miscdev.minor, rc); |
| 409 | unregister_reboot_notifier(&sh_wdt_notifier); | 451 | unregister_reboot_notifier(&sh_wdt_notifier); |
| 410 | return rc; | 452 | return rc; |
| 411 | } | 453 | } |
| @@ -418,7 +460,6 @@ static int __init sh_wdt_init(void) | |||
| 418 | 460 | ||
| 419 | /** | 461 | /** |
| 420 | * sh_wdt_exit - Deinitialize module | 462 | * sh_wdt_exit - Deinitialize module |
| 421 | * | ||
| 422 | * Unregisters the device and notifier handler. Actual device | 463 | * Unregisters the device and notifier handler. Actual device |
| 423 | * deinitialization is handled by sh_wdt_close(). | 464 | * deinitialization is handled by sh_wdt_close(). |
| 424 | */ | 465 | */ |
| @@ -434,14 +475,13 @@ MODULE_LICENSE("GPL"); | |||
| 434 | MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); | 475 | MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); |
| 435 | 476 | ||
| 436 | module_param(clock_division_ratio, int, 0); | 477 | module_param(clock_division_ratio, int, 0); |
| 437 | MODULE_PARM_DESC(clock_division_ratio, "Clock division ratio. Valid ranges are from 0x5 (1.31ms) to 0x7 (5.25ms). Defaults to 0x7."); | 478 | MODULE_PARM_DESC(clock_division_ratio, "Clock division ratio. Valid ranges are from 0x5 (1.31ms) to 0x7 (5.25ms). (default=" __MODULE_STRING(clock_division_ratio) ")"); |
| 438 | 479 | ||
| 439 | module_param(heartbeat, int, 0); | 480 | module_param(heartbeat, int, 0); |
| 440 | MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (1<=heartbeat<=3600, default=" __MODULE_STRING(WATCHDOG_HEARTBEAT) ")"); | 481 | MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (1<=heartbeat<=3600, default=" __MODULE_STRING(WATCHDOG_HEARTBEAT) ")"); |
| 441 | 482 | ||
| 442 | module_param(nowayout, int, 0); | 483 | module_param(nowayout, int, 0); |
| 443 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); | 484 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); |
| 444 | 485 | ||
| 445 | module_init(sh_wdt_init); | 486 | module_init(sh_wdt_init); |
| 446 | module_exit(sh_wdt_exit); | 487 | module_exit(sh_wdt_exit); |
| 447 | |||
