xref: /openbmc/linux/drivers/char/bsr.c (revision b627b4ed)
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>");
338