Merge branch 'urgent' of git://git.kernel.org/pub/scm/linux/kernel/git/brodo/pcmcia-2.6
[sfrench/cifs-2.6.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/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>
33
34 /*
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.
45
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
51 */
52
53 /* This is arbitrary number, up to Power6 it's been 17 or fewer  */
54 #define BSR_MAX_DEVS (32)
55
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;
64
65         struct list_head bsr_list;
66
67         dev_t    bsr_dev;
68         struct cdev bsr_cdev;
69         struct device *bsr_device;
70         char     bsr_name[32];
71
72 };
73
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;
78
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,
87 };
88
89 static unsigned bsr_types[BSR_MAX];
90
91 static ssize_t
92 bsr_size_show(struct device *dev, struct device_attribute *attr, char *buf)
93 {
94         struct bsr_dev *bsr_dev = dev_get_drvdata(dev);
95         return sprintf(buf, "%u\n", bsr_dev->bsr_bytes);
96 }
97
98 static ssize_t
99 bsr_stride_show(struct device *dev, struct device_attribute *attr, char *buf)
100 {
101         struct bsr_dev *bsr_dev = dev_get_drvdata(dev);
102         return sprintf(buf, "%u\n", bsr_dev->bsr_stride);
103 }
104
105 static ssize_t
106 bsr_len_show(struct device *dev, struct device_attribute *attr, char *buf)
107 {
108         struct bsr_dev *bsr_dev = dev_get_drvdata(dev);
109         return sprintf(buf, "%llu\n", bsr_dev->bsr_len);
110 }
111
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
117 };
118
119 static int bsr_mmap(struct file *filp, struct vm_area_struct *vma)
120 {
121         unsigned long size   = vma->vm_end - vma->vm_start;
122         struct bsr_dev *dev = filp->private_data;
123         int ret;
124
125         vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
126
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;
137
138         if (ret)
139                 return -EAGAIN;
140
141         return 0;
142 }
143
144 static int bsr_open(struct inode * inode, struct file * filp)
145 {
146         struct cdev *cdev = inode->i_cdev;
147         struct bsr_dev *dev = container_of(cdev, struct bsr_dev, bsr_cdev);
148
149         filp->private_data = dev;
150         return 0;
151 }
152
153 static const struct file_operations bsr_fops = {
154         .owner = THIS_MODULE,
155         .mmap  = bsr_mmap,
156         .open  = bsr_open,
157 };
158
159 static void bsr_cleanup_devs(void)
160 {
161         struct bsr_dev *cur, *n;
162
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);
167                 }
168                 list_del(&cur->bsr_list);
169                 kfree(cur);
170         }
171 }
172
173 static int bsr_add_node(struct device_node *bn)
174 {
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;
180
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);
183
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;
188         }
189
190         num_bsr_devs = bsr_bytes_len / sizeof(u32);
191
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;
197
198                 if (!cur) {
199                         printk(KERN_ERR "Unable to alloc bsr dev\n");
200                         ret = -ENOMEM;
201                         goto out_err;
202                 }
203
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;
209                 }
210
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);
217
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;
222
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;
241                 }
242
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);
246
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;
252                 }
253
254                 cur->bsr_device = device_create(bsr_class, NULL, cur->bsr_dev,
255                                                 cur, cur->bsr_name);
256                 if (!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;
262                 }
263
264                 bsr_types[cur->bsr_type] = cur->bsr_num + 1;
265                 list_add_tail(&cur->bsr_list, &bsr_devs);
266         }
267
268         total_bsr_devs += num_bsr_devs;
269
270         return 0;
271
272  out_err:
273
274         bsr_cleanup_devs();
275         return ret;
276 }
277
278 static int bsr_create_devs(struct device_node *bn)
279 {
280         int ret;
281
282         while (bn) {
283                 ret = bsr_add_node(bn);
284                 if (ret) {
285                         of_node_put(bn);
286                         return ret;
287                 }
288                 bn = of_find_compatible_node(bn, NULL, "ibm,bsr");
289         }
290         return 0;
291 }
292
293 static int __init bsr_init(void)
294 {
295         struct device_node *np;
296         dev_t bsr_dev = MKDEV(bsr_major, 0);
297         int ret = -ENODEV;
298         int result;
299
300         np = of_find_compatible_node(NULL, NULL, "ibm,bsr");
301         if (!np)
302                 goto out_err;
303
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;
308         }
309         bsr_class->dev_attrs = bsr_dev_attrs;
310
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;
316         }
317
318         if ((ret = bsr_create_devs(np)) < 0) {
319                 np = NULL;
320                 goto out_err_3;
321         }
322
323         return 0;
324
325  out_err_3:
326         unregister_chrdev_region(bsr_dev, BSR_MAX_DEVS);
327
328  out_err_2:
329         class_destroy(bsr_class);
330
331  out_err_1:
332         of_node_put(np);
333
334  out_err:
335
336         return ret;
337 }
338
339 static void __exit  bsr_exit(void)
340 {
341
342         bsr_cleanup_devs();
343
344         if (bsr_class)
345                 class_destroy(bsr_class);
346
347         if (bsr_major)
348                 unregister_chrdev_region(MKDEV(bsr_major, 0), BSR_MAX_DEVS);
349 }
350
351 module_init(bsr_init);
352 module_exit(bsr_exit);
353 MODULE_LICENSE("GPL");
354 MODULE_AUTHOR("Sonny Rao <sonnyrao@us.ibm.com>");