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