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