Avoid ICE in get_random_int() with gcc-3.4.5
[linux-2.6] / drivers / char / bsr.c
1 /* IBM POWER Barrier Synchronization Register Driver
2  *
3  * Copyright IBM Corporation 2008
4  *
5  * Author: Sonny Rao <sonnyrao@us.ibm.com>
6  *
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.
11  *
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.
16  *
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
20  */
21
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 <asm/io.h>
31
32 /*
33  This driver exposes a special register which can be used for fast
34  synchronization across a large SMP machine.  The hardware is exposed
35  as an array of bytes where each process will write to one of the bytes to
36  indicate it has finished the current stage and this update is broadcast to
37  all processors without having to bounce a cacheline between them. In
38  POWER5 and POWER6 there is one of these registers per SMP,  but it is
39  presented in two forms; first, it is given as a whole and then as a number
40  of smaller registers which alias to parts of the single whole register.
41  This can potentially allow multiple groups of processes to each have their
42  own private synchronization device.
43
44  Note that this hardware *must* be written to using *only* single byte writes.
45  It may be read using 1, 2, 4, or 8 byte loads which must be aligned since
46  this region is treated as cache-inhibited  processes should also use a
47  full sync before and after writing to the BSR to ensure all stores and
48  the BSR update have made it to all chips in the system
49 */
50
51 /* This is arbitrary number, up to Power6 it's been 17 or fewer  */
52 #define BSR_MAX_DEVS (32)
53
54 struct bsr_dev {
55         u64      bsr_addr;     /* Real address */
56         u64      bsr_len;      /* length of mem region we can map */
57         unsigned bsr_bytes;    /* size of the BSR reg itself */
58         unsigned bsr_stride;   /* interval at which BSR repeats in the page */
59         unsigned bsr_type;     /* maps to enum below */
60         unsigned bsr_num;      /* bsr id number for its type */
61         int      bsr_minor;
62
63         struct list_head bsr_list;
64
65         dev_t    bsr_dev;
66         struct cdev bsr_cdev;
67         struct device *bsr_device;
68         char     bsr_name[32];
69
70 };
71
72 static unsigned total_bsr_devs;
73 static struct list_head bsr_devs = LIST_HEAD_INIT(bsr_devs);
74 static struct class *bsr_class;
75 static int bsr_major;
76
77 enum {
78         BSR_8   = 0,
79         BSR_16  = 1,
80         BSR_64  = 2,
81         BSR_128 = 3,
82         BSR_UNKNOWN = 4,
83         BSR_MAX = 5,
84 };
85
86 static unsigned bsr_types[BSR_MAX];
87
88 static ssize_t
89 bsr_size_show(struct device *dev, struct device_attribute *attr, char *buf)
90 {
91         struct bsr_dev *bsr_dev = dev_get_drvdata(dev);
92         return sprintf(buf, "%u\n", bsr_dev->bsr_bytes);
93 }
94
95 static ssize_t
96 bsr_stride_show(struct device *dev, struct device_attribute *attr, char *buf)
97 {
98         struct bsr_dev *bsr_dev = dev_get_drvdata(dev);
99         return sprintf(buf, "%u\n", bsr_dev->bsr_stride);
100 }
101
102 static ssize_t
103 bsr_len_show(struct device *dev, struct device_attribute *attr, char *buf)
104 {
105         struct bsr_dev *bsr_dev = dev_get_drvdata(dev);
106         return sprintf(buf, "%llu\n", bsr_dev->bsr_len);
107 }
108
109 static struct device_attribute bsr_dev_attrs[] = {
110         __ATTR(bsr_size, S_IRUGO, bsr_size_show, NULL),
111         __ATTR(bsr_stride, S_IRUGO, bsr_stride_show, NULL),
112         __ATTR(bsr_length, S_IRUGO, bsr_len_show, NULL),
113         __ATTR_NULL
114 };
115
116 static int bsr_mmap(struct file *filp, struct vm_area_struct *vma)
117 {
118         unsigned long size   = vma->vm_end - vma->vm_start;
119         struct bsr_dev *dev = filp->private_data;
120
121         if (size > dev->bsr_len || (size & (PAGE_SIZE-1)))
122                 return -EINVAL;
123
124         vma->vm_flags |= (VM_IO | VM_DONTEXPAND);
125         vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
126
127         if (io_remap_pfn_range(vma, vma->vm_start, dev->bsr_addr >> PAGE_SHIFT,
128                                size, vma->vm_page_prot))
129                 return -EAGAIN;
130
131         return 0;
132 }
133
134 static int bsr_open(struct inode * inode, struct file * filp)
135 {
136         struct cdev *cdev = inode->i_cdev;
137         struct bsr_dev *dev = container_of(cdev, struct bsr_dev, bsr_cdev);
138
139         filp->private_data = dev;
140         return 0;
141 }
142
143 static const struct file_operations bsr_fops = {
144         .owner = THIS_MODULE,
145         .mmap  = bsr_mmap,
146         .open  = bsr_open,
147 };
148
149 static void bsr_cleanup_devs(void)
150 {
151         struct bsr_dev *cur, *n;
152
153         list_for_each_entry_safe(cur, n, &bsr_devs, bsr_list) {
154                 if (cur->bsr_device) {
155                         cdev_del(&cur->bsr_cdev);
156                         device_del(cur->bsr_device);
157                 }
158                 list_del(&cur->bsr_list);
159                 kfree(cur);
160         }
161 }
162
163 static int bsr_add_node(struct device_node *bn)
164 {
165         int bsr_stride_len, bsr_bytes_len, num_bsr_devs;
166         const u32 *bsr_stride;
167         const u32 *bsr_bytes;
168         unsigned i;
169         int ret = -ENODEV;
170
171         bsr_stride = of_get_property(bn, "ibm,lock-stride", &bsr_stride_len);
172         bsr_bytes  = of_get_property(bn, "ibm,#lock-bytes", &bsr_bytes_len);
173
174         if (!bsr_stride || !bsr_bytes ||
175             (bsr_stride_len != bsr_bytes_len)) {
176                 printk(KERN_ERR "bsr of-node has missing/incorrect property\n");
177                 return ret;
178         }
179
180         num_bsr_devs = bsr_bytes_len / sizeof(u32);
181
182         for (i = 0 ; i < num_bsr_devs; i++) {
183                 struct bsr_dev *cur = kzalloc(sizeof(struct bsr_dev),
184                                               GFP_KERNEL);
185                 struct resource res;
186                 int result;
187
188                 if (!cur) {
189                         printk(KERN_ERR "Unable to alloc bsr dev\n");
190                         ret = -ENOMEM;
191                         goto out_err;
192                 }
193
194                 result = of_address_to_resource(bn, i, &res);
195                 if (result < 0) {
196                         printk(KERN_ERR "bsr of-node has invalid reg property, skipping\n");
197                         kfree(cur);
198                         continue;
199                 }
200
201                 cur->bsr_minor  = i + total_bsr_devs;
202                 cur->bsr_addr   = res.start;
203                 cur->bsr_len    = res.end - res.start + 1;
204                 cur->bsr_bytes  = bsr_bytes[i];
205                 cur->bsr_stride = bsr_stride[i];
206                 cur->bsr_dev    = MKDEV(bsr_major, i + total_bsr_devs);
207
208                 switch(cur->bsr_bytes) {
209                 case 8:
210                         cur->bsr_type = BSR_8;
211                         break;
212                 case 16:
213                         cur->bsr_type = BSR_16;
214                         break;
215                 case 64:
216                         cur->bsr_type = BSR_64;
217                         break;
218                 case 128:
219                         cur->bsr_type = BSR_128;
220                         break;
221                 default:
222                         cur->bsr_type = BSR_UNKNOWN;
223                         printk(KERN_INFO "unknown BSR size %d\n",cur->bsr_bytes);
224                 }
225
226                 cur->bsr_num = bsr_types[cur->bsr_type];
227                 snprintf(cur->bsr_name, 32, "bsr%d_%d",
228                          cur->bsr_bytes, cur->bsr_num);
229
230                 cdev_init(&cur->bsr_cdev, &bsr_fops);
231                 result = cdev_add(&cur->bsr_cdev, cur->bsr_dev, 1);
232                 if (result) {
233                         kfree(cur);
234                         goto out_err;
235                 }
236
237                 cur->bsr_device = device_create(bsr_class, NULL, cur->bsr_dev,
238                                                 cur, cur->bsr_name);
239                 if (!cur->bsr_device) {
240                         printk(KERN_ERR "device_create failed for %s\n",
241                                cur->bsr_name);
242                         cdev_del(&cur->bsr_cdev);
243                         kfree(cur);
244                         goto out_err;
245                 }
246
247                 bsr_types[cur->bsr_type] = cur->bsr_num + 1;
248                 list_add_tail(&cur->bsr_list, &bsr_devs);
249         }
250
251         total_bsr_devs += num_bsr_devs;
252
253         return 0;
254
255  out_err:
256
257         bsr_cleanup_devs();
258         return ret;
259 }
260
261 static int bsr_create_devs(struct device_node *bn)
262 {
263         int ret;
264
265         while (bn) {
266                 ret = bsr_add_node(bn);
267                 if (ret) {
268                         of_node_put(bn);
269                         return ret;
270                 }
271                 bn = of_find_compatible_node(bn, NULL, "ibm,bsr");
272         }
273         return 0;
274 }
275
276 static int __init bsr_init(void)
277 {
278         struct device_node *np;
279         dev_t bsr_dev = MKDEV(bsr_major, 0);
280         int ret = -ENODEV;
281         int result;
282
283         np = of_find_compatible_node(NULL, NULL, "ibm,bsr");
284         if (!np)
285                 goto out_err;
286
287         bsr_class = class_create(THIS_MODULE, "bsr");
288         if (IS_ERR(bsr_class)) {
289                 printk(KERN_ERR "class_create() failed for bsr_class\n");
290                 goto out_err_1;
291         }
292         bsr_class->dev_attrs = bsr_dev_attrs;
293
294         result = alloc_chrdev_region(&bsr_dev, 0, BSR_MAX_DEVS, "bsr");
295         bsr_major = MAJOR(bsr_dev);
296         if (result < 0) {
297                 printk(KERN_ERR "alloc_chrdev_region() failed for bsr\n");
298                 goto out_err_2;
299         }
300
301         if ((ret = bsr_create_devs(np)) < 0) {
302                 np = NULL;
303                 goto out_err_3;
304         }
305
306         return 0;
307
308  out_err_3:
309         unregister_chrdev_region(bsr_dev, BSR_MAX_DEVS);
310
311  out_err_2:
312         class_destroy(bsr_class);
313
314  out_err_1:
315         of_node_put(np);
316
317  out_err:
318
319         return ret;
320 }
321
322 static void __exit  bsr_exit(void)
323 {
324
325         bsr_cleanup_devs();
326
327         if (bsr_class)
328                 class_destroy(bsr_class);
329
330         if (bsr_major)
331                 unregister_chrdev_region(MKDEV(bsr_major, 0), BSR_MAX_DEVS);
332 }
333
334 module_init(bsr_init);
335 module_exit(bsr_exit);
336 MODULE_LICENSE("GPL");
337 MODULE_AUTHOR("Sonny Rao <sonnyrao@us.ibm.com>");