1 /* IBM POWER Barrier Synchronization Register Driver
3 * Copyright IBM Corporation 2008
5 * Author: Sonny Rao <sonnyrao@us.ibm.com>
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.
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.
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
22 #include <linux/kernel.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>
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.
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
51 /* This is arbitrary number, up to Power6 it's been 17 or fewer */
52 #define BSR_MAX_DEVS (32)
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 */
65 struct device
*bsr_device
;
70 static unsigned num_bsr_devs
;
71 static struct bsr_dev
*bsr_devs
;
72 static struct class *bsr_class
;
84 static unsigned bsr_types
[BSR_MAX
];
87 bsr_size_show(struct device
*dev
, struct device_attribute
*attr
, char *buf
)
89 struct bsr_dev
*bsr_dev
= dev_get_drvdata(dev
);
90 return sprintf(buf
, "%u\n", bsr_dev
->bsr_bytes
);
94 bsr_stride_show(struct device
*dev
, struct device_attribute
*attr
, char *buf
)
96 struct bsr_dev
*bsr_dev
= dev_get_drvdata(dev
);
97 return sprintf(buf
, "%u\n", bsr_dev
->bsr_stride
);
101 bsr_len_show(struct device
*dev
, struct device_attribute
*attr
, char *buf
)
103 struct bsr_dev
*bsr_dev
= dev_get_drvdata(dev
);
104 return sprintf(buf
, "%lu\n", bsr_dev
->bsr_len
);
107 static struct device_attribute bsr_dev_attrs
[] = {
108 __ATTR(bsr_size
, S_IRUGO
, bsr_size_show
, NULL
),
109 __ATTR(bsr_stride
, S_IRUGO
, bsr_stride_show
, NULL
),
110 __ATTR(bsr_length
, S_IRUGO
, bsr_len_show
, NULL
),
114 static int bsr_mmap(struct file
*filp
, struct vm_area_struct
*vma
)
116 unsigned long size
= vma
->vm_end
- vma
->vm_start
;
117 struct bsr_dev
*dev
= filp
->private_data
;
119 if (size
> dev
->bsr_len
|| (size
& (PAGE_SIZE
-1)))
122 vma
->vm_flags
|= (VM_IO
| VM_DONTEXPAND
);
123 vma
->vm_page_prot
= pgprot_noncached(vma
->vm_page_prot
);
125 if (io_remap_pfn_range(vma
, vma
->vm_start
, dev
->bsr_addr
>> PAGE_SHIFT
,
126 size
, vma
->vm_page_prot
))
132 static int bsr_open(struct inode
* inode
, struct file
* filp
)
134 struct cdev
*cdev
= inode
->i_cdev
;
135 struct bsr_dev
*dev
= container_of(cdev
, struct bsr_dev
, bsr_cdev
);
137 filp
->private_data
= dev
;
141 const static struct file_operations bsr_fops
= {
142 .owner
= THIS_MODULE
,
147 static void bsr_cleanup_devs(void)
150 for (i
=0 ; i
< num_bsr_devs
; i
++) {
151 struct bsr_dev
*cur
= bsr_devs
+ i
;
152 if (cur
->bsr_device
) {
153 cdev_del(&cur
->bsr_cdev
);
154 device_del(cur
->bsr_device
);
161 static int bsr_create_devs(struct device_node
*bn
)
163 int bsr_stride_len
, bsr_bytes_len
;
164 const u32
*bsr_stride
;
165 const u32
*bsr_bytes
;
168 bsr_stride
= of_get_property(bn
, "ibm,lock-stride", &bsr_stride_len
);
169 bsr_bytes
= of_get_property(bn
, "ibm,#lock-bytes", &bsr_bytes_len
);
171 if (!bsr_stride
|| !bsr_bytes
||
172 (bsr_stride_len
!= bsr_bytes_len
)) {
173 printk(KERN_ERR
"bsr of-node has missing/incorrect property\n");
177 num_bsr_devs
= bsr_bytes_len
/ sizeof(u32
);
179 /* only a warning, its informational since we'll fail and exit */
180 WARN_ON(num_bsr_devs
> BSR_MAX_DEVS
);
182 bsr_devs
= kzalloc(sizeof(struct bsr_dev
) * num_bsr_devs
, GFP_KERNEL
);
186 for (i
= 0 ; i
< num_bsr_devs
; i
++) {
187 struct bsr_dev
*cur
= bsr_devs
+ i
;
191 result
= of_address_to_resource(bn
, i
, &res
);
193 printk(KERN_ERR
"bsr of-node has invalid reg property\n");
198 cur
->bsr_addr
= res
.start
;
199 cur
->bsr_len
= res
.end
- res
.start
+ 1;
200 cur
->bsr_bytes
= bsr_bytes
[i
];
201 cur
->bsr_stride
= bsr_stride
[i
];
202 cur
->bsr_dev
= MKDEV(bsr_major
, i
);
204 switch(cur
->bsr_bytes
) {
206 cur
->bsr_type
= BSR_8
;
209 cur
->bsr_type
= BSR_16
;
212 cur
->bsr_type
= BSR_64
;
215 cur
->bsr_type
= BSR_128
;
218 cur
->bsr_type
= BSR_UNKNOWN
;
219 printk(KERN_INFO
"unknown BSR size %d\n",cur
->bsr_bytes
);
222 cur
->bsr_num
= bsr_types
[cur
->bsr_type
];
223 bsr_types
[cur
->bsr_type
] = cur
->bsr_num
+ 1;
224 snprintf(cur
->bsr_name
, 32, "bsr%d_%d",
225 cur
->bsr_bytes
, cur
->bsr_num
);
227 cdev_init(&cur
->bsr_cdev
, &bsr_fops
);
228 result
= cdev_add(&cur
->bsr_cdev
, cur
->bsr_dev
, 1);
232 cur
->bsr_device
= device_create_drvdata(bsr_class
, NULL
,
235 if (!cur
->bsr_device
) {
236 printk(KERN_ERR
"device_create failed for %s\n",
238 cdev_del(&cur
->bsr_cdev
);
251 static int __init
bsr_init(void)
253 struct device_node
*np
;
254 dev_t bsr_dev
= MKDEV(bsr_major
, 0);
258 np
= of_find_compatible_node(NULL
, "ibm,bsr", "ibm,bsr");
262 bsr_class
= class_create(THIS_MODULE
, "bsr");
263 if (IS_ERR(bsr_class
)) {
264 printk(KERN_ERR
"class_create() failed for bsr_class\n");
267 bsr_class
->dev_attrs
= bsr_dev_attrs
;
269 result
= alloc_chrdev_region(&bsr_dev
, 0, BSR_MAX_DEVS
, "bsr");
270 bsr_major
= MAJOR(bsr_dev
);
272 printk(KERN_ERR
"alloc_chrdev_region() failed for bsr\n");
276 if ((ret
= bsr_create_devs(np
)) < 0)
284 unregister_chrdev_region(bsr_dev
, BSR_MAX_DEVS
);
287 class_destroy(bsr_class
);
297 static void __exit
bsr_exit(void)
303 class_destroy(bsr_class
);
306 unregister_chrdev_region(MKDEV(bsr_major
, 0), BSR_MAX_DEVS
);
309 module_init(bsr_init
);
310 module_exit(bsr_exit
);
311 MODULE_LICENSE("GPL");
312 MODULE_AUTHOR("Sonny Rao <sonnyrao@us.ibm.com>");