floppy: make controller const
[linux/fpc-iii.git] / drivers / char / bsr.c
blob89d871ef8c2f814dbaecc390bd47fa34ad14574c
1 /* IBM POWER Barrier Synchronization Register Driver
3 * Copyright IBM Corporation 2008
5 * Author: Sonny Rao <sonnyrao@us.ibm.com>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include <linux/kernel.h>
23 #include <linux/of.h>
24 #include <linux/of_device.h>
25 #include <linux/of_platform.h>
26 #include <linux/module.h>
27 #include <linux/cdev.h>
28 #include <linux/list.h>
29 #include <linux/mm.h>
30 #include <linux/slab.h>
31 #include <asm/pgtable.h>
32 #include <asm/io.h>
35 This driver exposes a special register which can be used for fast
36 synchronization across a large SMP machine. The hardware is exposed
37 as an array of bytes where each process will write to one of the bytes to
38 indicate it has finished the current stage and this update is broadcast to
39 all processors without having to bounce a cacheline between them. In
40 POWER5 and POWER6 there is one of these registers per SMP, but it is
41 presented in two forms; first, it is given as a whole and then as a number
42 of smaller registers which alias to parts of the single whole register.
43 This can potentially allow multiple groups of processes to each have their
44 own private synchronization device.
46 Note that this hardware *must* be written to using *only* single byte writes.
47 It may be read using 1, 2, 4, or 8 byte loads which must be aligned since
48 this region is treated as cache-inhibited processes should also use a
49 full sync before and after writing to the BSR to ensure all stores and
50 the BSR update have made it to all chips in the system
53 /* This is arbitrary number, up to Power6 it's been 17 or fewer */
54 #define BSR_MAX_DEVS (32)
56 struct bsr_dev {
57 u64 bsr_addr; /* Real address */
58 u64 bsr_len; /* length of mem region we can map */
59 unsigned bsr_bytes; /* size of the BSR reg itself */
60 unsigned bsr_stride; /* interval at which BSR repeats in the page */
61 unsigned bsr_type; /* maps to enum below */
62 unsigned bsr_num; /* bsr id number for its type */
63 int bsr_minor;
65 struct list_head bsr_list;
67 dev_t bsr_dev;
68 struct cdev bsr_cdev;
69 struct device *bsr_device;
70 char bsr_name[32];
74 static unsigned total_bsr_devs;
75 static struct list_head bsr_devs = LIST_HEAD_INIT(bsr_devs);
76 static struct class *bsr_class;
77 static int bsr_major;
79 enum {
80 BSR_8 = 0,
81 BSR_16 = 1,
82 BSR_64 = 2,
83 BSR_128 = 3,
84 BSR_4096 = 4,
85 BSR_UNKNOWN = 5,
86 BSR_MAX = 6,
89 static unsigned bsr_types[BSR_MAX];
91 static ssize_t
92 bsr_size_show(struct device *dev, struct device_attribute *attr, char *buf)
94 struct bsr_dev *bsr_dev = dev_get_drvdata(dev);
95 return sprintf(buf, "%u\n", bsr_dev->bsr_bytes);
98 static ssize_t
99 bsr_stride_show(struct device *dev, struct device_attribute *attr, char *buf)
101 struct bsr_dev *bsr_dev = dev_get_drvdata(dev);
102 return sprintf(buf, "%u\n", bsr_dev->bsr_stride);
105 static ssize_t
106 bsr_len_show(struct device *dev, struct device_attribute *attr, char *buf)
108 struct bsr_dev *bsr_dev = dev_get_drvdata(dev);
109 return sprintf(buf, "%llu\n", bsr_dev->bsr_len);
112 static struct device_attribute bsr_dev_attrs[] = {
113 __ATTR(bsr_size, S_IRUGO, bsr_size_show, NULL),
114 __ATTR(bsr_stride, S_IRUGO, bsr_stride_show, NULL),
115 __ATTR(bsr_length, S_IRUGO, bsr_len_show, NULL),
116 __ATTR_NULL
119 static int bsr_mmap(struct file *filp, struct vm_area_struct *vma)
121 unsigned long size = vma->vm_end - vma->vm_start;
122 struct bsr_dev *dev = filp->private_data;
123 int ret;
125 vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
127 /* check for the case of a small BSR device and map one 4k page for it*/
128 if (dev->bsr_len < PAGE_SIZE && size == PAGE_SIZE)
129 ret = remap_4k_pfn(vma, vma->vm_start, dev->bsr_addr >> 12,
130 vma->vm_page_prot);
131 else if (size <= dev->bsr_len)
132 ret = io_remap_pfn_range(vma, vma->vm_start,
133 dev->bsr_addr >> PAGE_SHIFT,
134 size, vma->vm_page_prot);
135 else
136 return -EINVAL;
138 if (ret)
139 return -EAGAIN;
141 return 0;
144 static int bsr_open(struct inode * inode, struct file * filp)
146 struct cdev *cdev = inode->i_cdev;
147 struct bsr_dev *dev = container_of(cdev, struct bsr_dev, bsr_cdev);
149 filp->private_data = dev;
150 return 0;
153 static const struct file_operations bsr_fops = {
154 .owner = THIS_MODULE,
155 .mmap = bsr_mmap,
156 .open = bsr_open,
159 static void bsr_cleanup_devs(void)
161 struct bsr_dev *cur, *n;
163 list_for_each_entry_safe(cur, n, &bsr_devs, bsr_list) {
164 if (cur->bsr_device) {
165 cdev_del(&cur->bsr_cdev);
166 device_del(cur->bsr_device);
168 list_del(&cur->bsr_list);
169 kfree(cur);
173 static int bsr_add_node(struct device_node *bn)
175 int bsr_stride_len, bsr_bytes_len, num_bsr_devs;
176 const u32 *bsr_stride;
177 const u32 *bsr_bytes;
178 unsigned i;
179 int ret = -ENODEV;
181 bsr_stride = of_get_property(bn, "ibm,lock-stride", &bsr_stride_len);
182 bsr_bytes = of_get_property(bn, "ibm,#lock-bytes", &bsr_bytes_len);
184 if (!bsr_stride || !bsr_bytes ||
185 (bsr_stride_len != bsr_bytes_len)) {
186 printk(KERN_ERR "bsr of-node has missing/incorrect property\n");
187 return ret;
190 num_bsr_devs = bsr_bytes_len / sizeof(u32);
192 for (i = 0 ; i < num_bsr_devs; i++) {
193 struct bsr_dev *cur = kzalloc(sizeof(struct bsr_dev),
194 GFP_KERNEL);
195 struct resource res;
196 int result;
198 if (!cur) {
199 printk(KERN_ERR "Unable to alloc bsr dev\n");
200 ret = -ENOMEM;
201 goto out_err;
204 result = of_address_to_resource(bn, i, &res);
205 if (result < 0) {
206 printk(KERN_ERR "bsr of-node has invalid reg property, skipping\n");
207 kfree(cur);
208 continue;
211 cur->bsr_minor = i + total_bsr_devs;
212 cur->bsr_addr = res.start;
213 cur->bsr_len = res.end - res.start + 1;
214 cur->bsr_bytes = bsr_bytes[i];
215 cur->bsr_stride = bsr_stride[i];
216 cur->bsr_dev = MKDEV(bsr_major, i + total_bsr_devs);
218 /* if we have a bsr_len of > 4k and less then PAGE_SIZE (64k pages) */
219 /* we can only map 4k of it, so only advertise the 4k in sysfs */
220 if (cur->bsr_len > 4096 && cur->bsr_len < PAGE_SIZE)
221 cur->bsr_len = 4096;
223 switch(cur->bsr_bytes) {
224 case 8:
225 cur->bsr_type = BSR_8;
226 break;
227 case 16:
228 cur->bsr_type = BSR_16;
229 break;
230 case 64:
231 cur->bsr_type = BSR_64;
232 break;
233 case 128:
234 cur->bsr_type = BSR_128;
235 break;
236 case 4096:
237 cur->bsr_type = BSR_4096;
238 break;
239 default:
240 cur->bsr_type = BSR_UNKNOWN;
243 cur->bsr_num = bsr_types[cur->bsr_type];
244 snprintf(cur->bsr_name, 32, "bsr%d_%d",
245 cur->bsr_bytes, cur->bsr_num);
247 cdev_init(&cur->bsr_cdev, &bsr_fops);
248 result = cdev_add(&cur->bsr_cdev, cur->bsr_dev, 1);
249 if (result) {
250 kfree(cur);
251 goto out_err;
254 cur->bsr_device = device_create(bsr_class, NULL, cur->bsr_dev,
255 cur, cur->bsr_name);
256 if (IS_ERR(cur->bsr_device)) {
257 printk(KERN_ERR "device_create failed for %s\n",
258 cur->bsr_name);
259 cdev_del(&cur->bsr_cdev);
260 kfree(cur);
261 goto out_err;
264 bsr_types[cur->bsr_type] = cur->bsr_num + 1;
265 list_add_tail(&cur->bsr_list, &bsr_devs);
268 total_bsr_devs += num_bsr_devs;
270 return 0;
272 out_err:
274 bsr_cleanup_devs();
275 return ret;
278 static int bsr_create_devs(struct device_node *bn)
280 int ret;
282 while (bn) {
283 ret = bsr_add_node(bn);
284 if (ret) {
285 of_node_put(bn);
286 return ret;
288 bn = of_find_compatible_node(bn, NULL, "ibm,bsr");
290 return 0;
293 static int __init bsr_init(void)
295 struct device_node *np;
296 dev_t bsr_dev = MKDEV(bsr_major, 0);
297 int ret = -ENODEV;
298 int result;
300 np = of_find_compatible_node(NULL, NULL, "ibm,bsr");
301 if (!np)
302 goto out_err;
304 bsr_class = class_create(THIS_MODULE, "bsr");
305 if (IS_ERR(bsr_class)) {
306 printk(KERN_ERR "class_create() failed for bsr_class\n");
307 goto out_err_1;
309 bsr_class->dev_attrs = bsr_dev_attrs;
311 result = alloc_chrdev_region(&bsr_dev, 0, BSR_MAX_DEVS, "bsr");
312 bsr_major = MAJOR(bsr_dev);
313 if (result < 0) {
314 printk(KERN_ERR "alloc_chrdev_region() failed for bsr\n");
315 goto out_err_2;
318 if ((ret = bsr_create_devs(np)) < 0) {
319 np = NULL;
320 goto out_err_3;
323 return 0;
325 out_err_3:
326 unregister_chrdev_region(bsr_dev, BSR_MAX_DEVS);
328 out_err_2:
329 class_destroy(bsr_class);
331 out_err_1:
332 of_node_put(np);
334 out_err:
336 return ret;
339 static void __exit bsr_exit(void)
342 bsr_cleanup_devs();
344 if (bsr_class)
345 class_destroy(bsr_class);
347 if (bsr_major)
348 unregister_chrdev_region(MKDEV(bsr_major, 0), BSR_MAX_DEVS);
351 module_init(bsr_init);
352 module_exit(bsr_exit);
353 MODULE_LICENSE("GPL");
354 MODULE_AUTHOR("Sonny Rao <sonnyrao@us.ibm.com>");