1
2
3
4
5
6
7
8
9#include <linux/kernel.h>
10#include <linux/of.h>
11#include <linux/of_address.h>
12#include <linux/of_device.h>
13#include <linux/of_platform.h>
14#include <linux/fs.h>
15#include <linux/module.h>
16#include <linux/cdev.h>
17#include <linux/list.h>
18#include <linux/mm.h>
19#include <linux/slab.h>
20#include <asm/io.h>
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42#define BSR_MAX_DEVS (32)
43
44struct bsr_dev {
45 u64 bsr_addr;
46 u64 bsr_len;
47 unsigned bsr_bytes;
48 unsigned bsr_stride;
49 unsigned bsr_type;
50 unsigned bsr_num;
51 int bsr_minor;
52
53 struct list_head bsr_list;
54
55 dev_t bsr_dev;
56 struct cdev bsr_cdev;
57 struct device *bsr_device;
58 char bsr_name[32];
59
60};
61
62static unsigned total_bsr_devs;
63static struct list_head bsr_devs = LIST_HEAD_INIT(bsr_devs);
64static struct class *bsr_class;
65static int bsr_major;
66
67enum {
68 BSR_8 = 0,
69 BSR_16 = 1,
70 BSR_64 = 2,
71 BSR_128 = 3,
72 BSR_4096 = 4,
73 BSR_UNKNOWN = 5,
74 BSR_MAX = 6,
75};
76
77static unsigned bsr_types[BSR_MAX];
78
79static ssize_t
80bsr_size_show(struct device *dev, struct device_attribute *attr, char *buf)
81{
82 struct bsr_dev *bsr_dev = dev_get_drvdata(dev);
83 return sprintf(buf, "%u\n", bsr_dev->bsr_bytes);
84}
85static DEVICE_ATTR_RO(bsr_size);
86
87static ssize_t
88bsr_stride_show(struct device *dev, struct device_attribute *attr, char *buf)
89{
90 struct bsr_dev *bsr_dev = dev_get_drvdata(dev);
91 return sprintf(buf, "%u\n", bsr_dev->bsr_stride);
92}
93static DEVICE_ATTR_RO(bsr_stride);
94
95static ssize_t
96bsr_length_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, "%llu\n", bsr_dev->bsr_len);
100}
101static DEVICE_ATTR_RO(bsr_length);
102
103static struct attribute *bsr_dev_attrs[] = {
104 &dev_attr_bsr_size.attr,
105 &dev_attr_bsr_stride.attr,
106 &dev_attr_bsr_length.attr,
107 NULL,
108};
109ATTRIBUTE_GROUPS(bsr_dev);
110
111static int bsr_mmap(struct file *filp, struct vm_area_struct *vma)
112{
113 unsigned long size = vma->vm_end - vma->vm_start;
114 struct bsr_dev *dev = filp->private_data;
115 int ret;
116
117 vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
118
119
120 if (dev->bsr_len < PAGE_SIZE && size == PAGE_SIZE)
121 ret = remap_4k_pfn(vma, vma->vm_start, dev->bsr_addr >> 12,
122 vma->vm_page_prot);
123 else if (size <= dev->bsr_len)
124 ret = io_remap_pfn_range(vma, vma->vm_start,
125 dev->bsr_addr >> PAGE_SHIFT,
126 size, vma->vm_page_prot);
127 else
128 return -EINVAL;
129
130 if (ret)
131 return -EAGAIN;
132
133 return 0;
134}
135
136static int bsr_open(struct inode *inode, struct file *filp)
137{
138 struct cdev *cdev = inode->i_cdev;
139 struct bsr_dev *dev = container_of(cdev, struct bsr_dev, bsr_cdev);
140
141 filp->private_data = dev;
142 return 0;
143}
144
145static const struct file_operations bsr_fops = {
146 .owner = THIS_MODULE,
147 .mmap = bsr_mmap,
148 .open = bsr_open,
149 .llseek = noop_llseek,
150};
151
152static void bsr_cleanup_devs(void)
153{
154 struct bsr_dev *cur, *n;
155
156 list_for_each_entry_safe(cur, n, &bsr_devs, bsr_list) {
157 if (cur->bsr_device) {
158 cdev_del(&cur->bsr_cdev);
159 device_del(cur->bsr_device);
160 }
161 list_del(&cur->bsr_list);
162 kfree(cur);
163 }
164}
165
166static int bsr_add_node(struct device_node *bn)
167{
168 int bsr_stride_len, bsr_bytes_len, num_bsr_devs;
169 const u32 *bsr_stride;
170 const u32 *bsr_bytes;
171 unsigned i;
172 int ret = -ENODEV;
173
174 bsr_stride = of_get_property(bn, "ibm,lock-stride", &bsr_stride_len);
175 bsr_bytes = of_get_property(bn, "ibm,#lock-bytes", &bsr_bytes_len);
176
177 if (!bsr_stride || !bsr_bytes ||
178 (bsr_stride_len != bsr_bytes_len)) {
179 printk(KERN_ERR "bsr of-node has missing/incorrect property\n");
180 return ret;
181 }
182
183 num_bsr_devs = bsr_bytes_len / sizeof(u32);
184
185 for (i = 0 ; i < num_bsr_devs; i++) {
186 struct bsr_dev *cur = kzalloc(sizeof(struct bsr_dev),
187 GFP_KERNEL);
188 struct resource res;
189 int result;
190
191 if (!cur) {
192 printk(KERN_ERR "Unable to alloc bsr dev\n");
193 ret = -ENOMEM;
194 goto out_err;
195 }
196
197 result = of_address_to_resource(bn, i, &res);
198 if (result < 0) {
199 printk(KERN_ERR "bsr of-node has invalid reg property, skipping\n");
200 kfree(cur);
201 continue;
202 }
203
204 cur->bsr_minor = i + total_bsr_devs;
205 cur->bsr_addr = res.start;
206 cur->bsr_len = resource_size(&res);
207 cur->bsr_bytes = bsr_bytes[i];
208 cur->bsr_stride = bsr_stride[i];
209 cur->bsr_dev = MKDEV(bsr_major, i + total_bsr_devs);
210
211
212
213 if (cur->bsr_len > 4096 && cur->bsr_len < PAGE_SIZE)
214 cur->bsr_len = 4096;
215
216 switch(cur->bsr_bytes) {
217 case 8:
218 cur->bsr_type = BSR_8;
219 break;
220 case 16:
221 cur->bsr_type = BSR_16;
222 break;
223 case 64:
224 cur->bsr_type = BSR_64;
225 break;
226 case 128:
227 cur->bsr_type = BSR_128;
228 break;
229 case 4096:
230 cur->bsr_type = BSR_4096;
231 break;
232 default:
233 cur->bsr_type = BSR_UNKNOWN;
234 }
235
236 cur->bsr_num = bsr_types[cur->bsr_type];
237 snprintf(cur->bsr_name, 32, "bsr%d_%d",
238 cur->bsr_bytes, cur->bsr_num);
239
240 cdev_init(&cur->bsr_cdev, &bsr_fops);
241 result = cdev_add(&cur->bsr_cdev, cur->bsr_dev, 1);
242 if (result) {
243 kfree(cur);
244 goto out_err;
245 }
246
247 cur->bsr_device = device_create(bsr_class, NULL, cur->bsr_dev,
248 cur, "%s", cur->bsr_name);
249 if (IS_ERR(cur->bsr_device)) {
250 printk(KERN_ERR "device_create failed for %s\n",
251 cur->bsr_name);
252 cdev_del(&cur->bsr_cdev);
253 kfree(cur);
254 goto out_err;
255 }
256
257 bsr_types[cur->bsr_type] = cur->bsr_num + 1;
258 list_add_tail(&cur->bsr_list, &bsr_devs);
259 }
260
261 total_bsr_devs += num_bsr_devs;
262
263 return 0;
264
265 out_err:
266
267 bsr_cleanup_devs();
268 return ret;
269}
270
271static int bsr_create_devs(struct device_node *bn)
272{
273 int ret;
274
275 while (bn) {
276 ret = bsr_add_node(bn);
277 if (ret) {
278 of_node_put(bn);
279 return ret;
280 }
281 bn = of_find_compatible_node(bn, NULL, "ibm,bsr");
282 }
283 return 0;
284}
285
286static int __init bsr_init(void)
287{
288 struct device_node *np;
289 dev_t bsr_dev;
290 int ret = -ENODEV;
291
292 np = of_find_compatible_node(NULL, NULL, "ibm,bsr");
293 if (!np)
294 goto out_err;
295
296 bsr_class = class_create(THIS_MODULE, "bsr");
297 if (IS_ERR(bsr_class)) {
298 printk(KERN_ERR "class_create() failed for bsr_class\n");
299 ret = PTR_ERR(bsr_class);
300 goto out_err_1;
301 }
302 bsr_class->dev_groups = bsr_dev_groups;
303
304 ret = alloc_chrdev_region(&bsr_dev, 0, BSR_MAX_DEVS, "bsr");
305 bsr_major = MAJOR(bsr_dev);
306 if (ret < 0) {
307 printk(KERN_ERR "alloc_chrdev_region() failed for bsr\n");
308 goto out_err_2;
309 }
310
311 ret = bsr_create_devs(np);
312 if (ret < 0) {
313 np = NULL;
314 goto out_err_3;
315 }
316
317 return 0;
318
319 out_err_3:
320 unregister_chrdev_region(bsr_dev, BSR_MAX_DEVS);
321
322 out_err_2:
323 class_destroy(bsr_class);
324
325 out_err_1:
326 of_node_put(np);
327
328 out_err:
329
330 return ret;
331}
332
333static void __exit bsr_exit(void)
334{
335
336 bsr_cleanup_devs();
337
338 if (bsr_class)
339 class_destroy(bsr_class);
340
341 if (bsr_major)
342 unregister_chrdev_region(MKDEV(bsr_major, 0), BSR_MAX_DEVS);
343}
344
345module_init(bsr_init);
346module_exit(bsr_exit);
347MODULE_LICENSE("GPL");
348MODULE_AUTHOR("Sonny Rao <sonnyrao@us.ibm.com>");
349