diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/s390/cio/cmf.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/s390/cio/cmf.c')
-rw-r--r-- | drivers/s390/cio/cmf.c | 1042 |
1 files changed, 1042 insertions, 0 deletions
diff --git a/drivers/s390/cio/cmf.c b/drivers/s390/cio/cmf.c new file mode 100644 index 000000000000..49def26ba383 --- /dev/null +++ b/drivers/s390/cio/cmf.c | |||
@@ -0,0 +1,1042 @@ | |||
1 | /* | ||
2 | * linux/drivers/s390/cio/cmf.c ($Revision: 1.16 $) | ||
3 | * | ||
4 | * Linux on zSeries Channel Measurement Facility support | ||
5 | * | ||
6 | * Copyright 2000,2003 IBM Corporation | ||
7 | * | ||
8 | * Author: Arnd Bergmann <arndb@de.ibm.com> | ||
9 | * | ||
10 | * original idea from Natarajan Krishnaswami <nkrishna@us.ibm.com> | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2, or (at your option) | ||
15 | * any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | */ | ||
26 | |||
27 | #include <linux/bootmem.h> | ||
28 | #include <linux/device.h> | ||
29 | #include <linux/init.h> | ||
30 | #include <linux/list.h> | ||
31 | #include <linux/module.h> | ||
32 | #include <linux/moduleparam.h> | ||
33 | |||
34 | #include <asm/ccwdev.h> | ||
35 | #include <asm/cio.h> | ||
36 | #include <asm/cmb.h> | ||
37 | |||
38 | #include "cio.h" | ||
39 | #include "css.h" | ||
40 | #include "device.h" | ||
41 | #include "ioasm.h" | ||
42 | #include "chsc.h" | ||
43 | |||
44 | /* parameter to enable cmf during boot, possible uses are: | ||
45 | * "s390cmf" -- enable cmf and allocate 2 MB of ram so measuring can be | ||
46 | * used on any subchannel | ||
47 | * "s390cmf=<num>" -- enable cmf and allocate enough memory to measure | ||
48 | * <num> subchannel, where <num> is an integer | ||
49 | * between 1 and 65535, default is 1024 | ||
50 | */ | ||
51 | #define ARGSTRING "s390cmf" | ||
52 | |||
53 | /* indices for READCMB */ | ||
54 | enum cmb_index { | ||
55 | /* basic and exended format: */ | ||
56 | cmb_ssch_rsch_count, | ||
57 | cmb_sample_count, | ||
58 | cmb_device_connect_time, | ||
59 | cmb_function_pending_time, | ||
60 | cmb_device_disconnect_time, | ||
61 | cmb_control_unit_queuing_time, | ||
62 | cmb_device_active_only_time, | ||
63 | /* extended format only: */ | ||
64 | cmb_device_busy_time, | ||
65 | cmb_initial_command_response_time, | ||
66 | }; | ||
67 | |||
68 | /** | ||
69 | * enum cmb_format - types of supported measurement block formats | ||
70 | * | ||
71 | * @CMF_BASIC: traditional channel measurement blocks supported | ||
72 | * by all machines that we run on | ||
73 | * @CMF_EXTENDED: improved format that was introduced with the z990 | ||
74 | * machine | ||
75 | * @CMF_AUTODETECT: default: use extended format when running on a z990 | ||
76 | * or later machine, otherwise fall back to basic format | ||
77 | **/ | ||
78 | enum cmb_format { | ||
79 | CMF_BASIC, | ||
80 | CMF_EXTENDED, | ||
81 | CMF_AUTODETECT = -1, | ||
82 | }; | ||
83 | /** | ||
84 | * format - actual format for all measurement blocks | ||
85 | * | ||
86 | * The format module parameter can be set to a value of 0 (zero) | ||
87 | * or 1, indicating basic or extended format as described for | ||
88 | * enum cmb_format. | ||
89 | */ | ||
90 | static int format = CMF_AUTODETECT; | ||
91 | module_param(format, bool, 0444); | ||
92 | |||
93 | /** | ||
94 | * struct cmb_operations - functions to use depending on cmb_format | ||
95 | * | ||
96 | * all these functions operate on a struct cmf_device. There is only | ||
97 | * one instance of struct cmb_operations because all cmf_device | ||
98 | * objects are guaranteed to be of the same type. | ||
99 | * | ||
100 | * @alloc: allocate memory for a channel measurement block, | ||
101 | * either with the help of a special pool or with kmalloc | ||
102 | * @free: free memory allocated with @alloc | ||
103 | * @set: enable or disable measurement | ||
104 | * @readall: read a measurement block in a common format | ||
105 | * @reset: clear the data in the associated measurement block and | ||
106 | * reset its time stamp | ||
107 | */ | ||
108 | struct cmb_operations { | ||
109 | int (*alloc) (struct ccw_device*); | ||
110 | void(*free) (struct ccw_device*); | ||
111 | int (*set) (struct ccw_device*, u32); | ||
112 | u64 (*read) (struct ccw_device*, int); | ||
113 | int (*readall)(struct ccw_device*, struct cmbdata *); | ||
114 | void (*reset) (struct ccw_device*); | ||
115 | |||
116 | struct attribute_group *attr_group; | ||
117 | }; | ||
118 | static struct cmb_operations *cmbops; | ||
119 | |||
120 | /* our user interface is designed in terms of nanoseconds, | ||
121 | * while the hardware measures total times in its own | ||
122 | * unit.*/ | ||
123 | static inline u64 time_to_nsec(u32 value) | ||
124 | { | ||
125 | return ((u64)value) * 128000ull; | ||
126 | } | ||
127 | |||
128 | /* | ||
129 | * Users are usually interested in average times, | ||
130 | * not accumulated time. | ||
131 | * This also helps us with atomicity problems | ||
132 | * when reading sinlge values. | ||
133 | */ | ||
134 | static inline u64 time_to_avg_nsec(u32 value, u32 count) | ||
135 | { | ||
136 | u64 ret; | ||
137 | |||
138 | /* no samples yet, avoid division by 0 */ | ||
139 | if (count == 0) | ||
140 | return 0; | ||
141 | |||
142 | /* value comes in units of 128 µsec */ | ||
143 | ret = time_to_nsec(value); | ||
144 | do_div(ret, count); | ||
145 | |||
146 | return ret; | ||
147 | } | ||
148 | |||
149 | /* activate or deactivate the channel monitor. When area is NULL, | ||
150 | * the monitor is deactivated. The channel monitor needs to | ||
151 | * be active in order to measure subchannels, which also need | ||
152 | * to be enabled. */ | ||
153 | static inline void | ||
154 | cmf_activate(void *area, unsigned int onoff) | ||
155 | { | ||
156 | register void * __gpr2 asm("2"); | ||
157 | register long __gpr1 asm("1"); | ||
158 | |||
159 | __gpr2 = area; | ||
160 | __gpr1 = onoff ? 2 : 0; | ||
161 | /* activate channel measurement */ | ||
162 | asm("schm" : : "d" (__gpr2), "d" (__gpr1) ); | ||
163 | } | ||
164 | |||
165 | static int | ||
166 | set_schib(struct ccw_device *cdev, u32 mme, int mbfc, unsigned long address) | ||
167 | { | ||
168 | int ret; | ||
169 | int retry; | ||
170 | struct subchannel *sch; | ||
171 | struct schib *schib; | ||
172 | |||
173 | sch = to_subchannel(cdev->dev.parent); | ||
174 | schib = &sch->schib; | ||
175 | /* msch can silently fail, so do it again if necessary */ | ||
176 | for (retry = 0; retry < 3; retry++) { | ||
177 | /* prepare schib */ | ||
178 | stsch(sch->irq, schib); | ||
179 | schib->pmcw.mme = mme; | ||
180 | schib->pmcw.mbfc = mbfc; | ||
181 | /* address can be either a block address or a block index */ | ||
182 | if (mbfc) | ||
183 | schib->mba = address; | ||
184 | else | ||
185 | schib->pmcw.mbi = address; | ||
186 | |||
187 | /* try to submit it */ | ||
188 | switch(ret = msch_err(sch->irq, schib)) { | ||
189 | case 0: | ||
190 | break; | ||
191 | case 1: | ||
192 | case 2: /* in I/O or status pending */ | ||
193 | ret = -EBUSY; | ||
194 | break; | ||
195 | case 3: /* subchannel is no longer valid */ | ||
196 | ret = -ENODEV; | ||
197 | break; | ||
198 | default: /* msch caught an exception */ | ||
199 | ret = -EINVAL; | ||
200 | break; | ||
201 | } | ||
202 | stsch(sch->irq, schib); /* restore the schib */ | ||
203 | |||
204 | if (ret) | ||
205 | break; | ||
206 | |||
207 | /* check if it worked */ | ||
208 | if (schib->pmcw.mme == mme && | ||
209 | schib->pmcw.mbfc == mbfc && | ||
210 | (mbfc ? (schib->mba == address) | ||
211 | : (schib->pmcw.mbi == address))) | ||
212 | return 0; | ||
213 | |||
214 | ret = -EINVAL; | ||
215 | } | ||
216 | |||
217 | return ret; | ||
218 | } | ||
219 | |||
220 | struct set_schib_struct { | ||
221 | u32 mme; | ||
222 | int mbfc; | ||
223 | unsigned long address; | ||
224 | wait_queue_head_t wait; | ||
225 | int ret; | ||
226 | }; | ||
227 | |||
228 | static int set_schib_wait(struct ccw_device *cdev, u32 mme, | ||
229 | int mbfc, unsigned long address) | ||
230 | { | ||
231 | struct set_schib_struct s = { | ||
232 | .mme = mme, | ||
233 | .mbfc = mbfc, | ||
234 | .address = address, | ||
235 | .wait = __WAIT_QUEUE_HEAD_INITIALIZER(s.wait), | ||
236 | }; | ||
237 | |||
238 | spin_lock_irq(cdev->ccwlock); | ||
239 | s.ret = set_schib(cdev, mme, mbfc, address); | ||
240 | if (s.ret != -EBUSY) { | ||
241 | goto out_nowait; | ||
242 | } | ||
243 | |||
244 | if (cdev->private->state != DEV_STATE_ONLINE) { | ||
245 | s.ret = -EBUSY; | ||
246 | /* if the device is not online, don't even try again */ | ||
247 | goto out_nowait; | ||
248 | } | ||
249 | cdev->private->state = DEV_STATE_CMFCHANGE; | ||
250 | cdev->private->cmb_wait = &s; | ||
251 | s.ret = 1; | ||
252 | |||
253 | spin_unlock_irq(cdev->ccwlock); | ||
254 | if (wait_event_interruptible(s.wait, s.ret != 1)) { | ||
255 | spin_lock_irq(cdev->ccwlock); | ||
256 | if (s.ret == 1) { | ||
257 | s.ret = -ERESTARTSYS; | ||
258 | cdev->private->cmb_wait = 0; | ||
259 | if (cdev->private->state == DEV_STATE_CMFCHANGE) | ||
260 | cdev->private->state = DEV_STATE_ONLINE; | ||
261 | } | ||
262 | spin_unlock_irq(cdev->ccwlock); | ||
263 | } | ||
264 | return s.ret; | ||
265 | |||
266 | out_nowait: | ||
267 | spin_unlock_irq(cdev->ccwlock); | ||
268 | return s.ret; | ||
269 | } | ||
270 | |||
271 | void retry_set_schib(struct ccw_device *cdev) | ||
272 | { | ||
273 | struct set_schib_struct *s; | ||
274 | |||
275 | s = cdev->private->cmb_wait; | ||
276 | cdev->private->cmb_wait = 0; | ||
277 | if (!s) { | ||
278 | WARN_ON(1); | ||
279 | return; | ||
280 | } | ||
281 | s->ret = set_schib(cdev, s->mme, s->mbfc, s->address); | ||
282 | wake_up(&s->wait); | ||
283 | } | ||
284 | |||
285 | /** | ||
286 | * struct cmb_area - container for global cmb data | ||
287 | * | ||
288 | * @mem: pointer to CMBs (only in basic measurement mode) | ||
289 | * @list: contains a linked list of all subchannels | ||
290 | * @lock: protect concurrent access to @mem and @list | ||
291 | */ | ||
292 | struct cmb_area { | ||
293 | struct cmb *mem; | ||
294 | struct list_head list; | ||
295 | int num_channels; | ||
296 | spinlock_t lock; | ||
297 | }; | ||
298 | |||
299 | static struct cmb_area cmb_area = { | ||
300 | .lock = SPIN_LOCK_UNLOCKED, | ||
301 | .list = LIST_HEAD_INIT(cmb_area.list), | ||
302 | .num_channels = 1024, | ||
303 | }; | ||
304 | |||
305 | |||
306 | /* ****** old style CMB handling ********/ | ||
307 | |||
308 | /** int maxchannels | ||
309 | * | ||
310 | * Basic channel measurement blocks are allocated in one contiguous | ||
311 | * block of memory, which can not be moved as long as any channel | ||
312 | * is active. Therefore, a maximum number of subchannels needs to | ||
313 | * be defined somewhere. This is a module parameter, defaulting to | ||
314 | * a resonable value of 1024, or 32 kb of memory. | ||
315 | * Current kernels don't allow kmalloc with more than 128kb, so the | ||
316 | * maximum is 4096 | ||
317 | */ | ||
318 | |||
319 | module_param_named(maxchannels, cmb_area.num_channels, uint, 0444); | ||
320 | |||
321 | /** | ||
322 | * struct cmb - basic channel measurement block | ||
323 | * | ||
324 | * cmb as used by the hardware the fields are described in z/Architecture | ||
325 | * Principles of Operation, chapter 17. | ||
326 | * The area to be a contiguous array and may not be reallocated or freed. | ||
327 | * Only one cmb area can be present in the system. | ||
328 | */ | ||
329 | struct cmb { | ||
330 | u16 ssch_rsch_count; | ||
331 | u16 sample_count; | ||
332 | u32 device_connect_time; | ||
333 | u32 function_pending_time; | ||
334 | u32 device_disconnect_time; | ||
335 | u32 control_unit_queuing_time; | ||
336 | u32 device_active_only_time; | ||
337 | u32 reserved[2]; | ||
338 | }; | ||
339 | |||
340 | /* insert a single device into the cmb_area list | ||
341 | * called with cmb_area.lock held from alloc_cmb | ||
342 | */ | ||
343 | static inline int | ||
344 | alloc_cmb_single (struct ccw_device *cdev) | ||
345 | { | ||
346 | struct cmb *cmb; | ||
347 | struct ccw_device_private *node; | ||
348 | int ret; | ||
349 | |||
350 | spin_lock_irq(cdev->ccwlock); | ||
351 | if (!list_empty(&cdev->private->cmb_list)) { | ||
352 | ret = -EBUSY; | ||
353 | goto out; | ||
354 | } | ||
355 | |||
356 | /* find first unused cmb in cmb_area.mem. | ||
357 | * this is a little tricky: cmb_area.list | ||
358 | * remains sorted by ->cmb pointers */ | ||
359 | cmb = cmb_area.mem; | ||
360 | list_for_each_entry(node, &cmb_area.list, cmb_list) { | ||
361 | if ((struct cmb*)node->cmb > cmb) | ||
362 | break; | ||
363 | cmb++; | ||
364 | } | ||
365 | if (cmb - cmb_area.mem >= cmb_area.num_channels) { | ||
366 | ret = -ENOMEM; | ||
367 | goto out; | ||
368 | } | ||
369 | |||
370 | /* insert new cmb */ | ||
371 | list_add_tail(&cdev->private->cmb_list, &node->cmb_list); | ||
372 | cdev->private->cmb = cmb; | ||
373 | ret = 0; | ||
374 | out: | ||
375 | spin_unlock_irq(cdev->ccwlock); | ||
376 | return ret; | ||
377 | } | ||
378 | |||
379 | static int | ||
380 | alloc_cmb (struct ccw_device *cdev) | ||
381 | { | ||
382 | int ret; | ||
383 | struct cmb *mem; | ||
384 | ssize_t size; | ||
385 | |||
386 | spin_lock(&cmb_area.lock); | ||
387 | |||
388 | if (!cmb_area.mem) { | ||
389 | /* there is no user yet, so we need a new area */ | ||
390 | size = sizeof(struct cmb) * cmb_area.num_channels; | ||
391 | WARN_ON(!list_empty(&cmb_area.list)); | ||
392 | |||
393 | spin_unlock(&cmb_area.lock); | ||
394 | mem = (void*)__get_free_pages(GFP_KERNEL | GFP_DMA, | ||
395 | get_order(size)); | ||
396 | spin_lock(&cmb_area.lock); | ||
397 | |||
398 | if (cmb_area.mem) { | ||
399 | /* ok, another thread was faster */ | ||
400 | free_pages((unsigned long)mem, get_order(size)); | ||
401 | } else if (!mem) { | ||
402 | /* no luck */ | ||
403 | ret = -ENOMEM; | ||
404 | goto out; | ||
405 | } else { | ||
406 | /* everything ok */ | ||
407 | memset(mem, 0, size); | ||
408 | cmb_area.mem = mem; | ||
409 | cmf_activate(cmb_area.mem, 1); | ||
410 | } | ||
411 | } | ||
412 | |||
413 | /* do the actual allocation */ | ||
414 | ret = alloc_cmb_single(cdev); | ||
415 | out: | ||
416 | spin_unlock(&cmb_area.lock); | ||
417 | |||
418 | return ret; | ||
419 | } | ||
420 | |||
421 | static void | ||
422 | free_cmb(struct ccw_device *cdev) | ||
423 | { | ||
424 | struct ccw_device_private *priv; | ||
425 | |||
426 | priv = cdev->private; | ||
427 | |||
428 | spin_lock(&cmb_area.lock); | ||
429 | spin_lock_irq(cdev->ccwlock); | ||
430 | |||
431 | if (list_empty(&priv->cmb_list)) { | ||
432 | /* already freed */ | ||
433 | goto out; | ||
434 | } | ||
435 | |||
436 | priv->cmb = NULL; | ||
437 | list_del_init(&priv->cmb_list); | ||
438 | |||
439 | if (list_empty(&cmb_area.list)) { | ||
440 | ssize_t size; | ||
441 | size = sizeof(struct cmb) * cmb_area.num_channels; | ||
442 | cmf_activate(NULL, 0); | ||
443 | free_pages((unsigned long)cmb_area.mem, get_order(size)); | ||
444 | cmb_area.mem = NULL; | ||
445 | } | ||
446 | out: | ||
447 | spin_unlock_irq(cdev->ccwlock); | ||
448 | spin_unlock(&cmb_area.lock); | ||
449 | } | ||
450 | |||
451 | static int | ||
452 | set_cmb(struct ccw_device *cdev, u32 mme) | ||
453 | { | ||
454 | u16 offset; | ||
455 | |||
456 | if (!cdev->private->cmb) | ||
457 | return -EINVAL; | ||
458 | |||
459 | offset = mme ? (struct cmb *)cdev->private->cmb - cmb_area.mem : 0; | ||
460 | |||
461 | return set_schib_wait(cdev, mme, 0, offset); | ||
462 | } | ||
463 | |||
464 | static u64 | ||
465 | read_cmb (struct ccw_device *cdev, int index) | ||
466 | { | ||
467 | /* yes, we have to put it on the stack | ||
468 | * because the cmb must only be accessed | ||
469 | * atomically, e.g. with mvc */ | ||
470 | struct cmb cmb; | ||
471 | unsigned long flags; | ||
472 | u32 val; | ||
473 | |||
474 | spin_lock_irqsave(cdev->ccwlock, flags); | ||
475 | if (!cdev->private->cmb) { | ||
476 | spin_unlock_irqrestore(cdev->ccwlock, flags); | ||
477 | return 0; | ||
478 | } | ||
479 | |||
480 | cmb = *(struct cmb*)cdev->private->cmb; | ||
481 | spin_unlock_irqrestore(cdev->ccwlock, flags); | ||
482 | |||
483 | switch (index) { | ||
484 | case cmb_ssch_rsch_count: | ||
485 | return cmb.ssch_rsch_count; | ||
486 | case cmb_sample_count: | ||
487 | return cmb.sample_count; | ||
488 | case cmb_device_connect_time: | ||
489 | val = cmb.device_connect_time; | ||
490 | break; | ||
491 | case cmb_function_pending_time: | ||
492 | val = cmb.function_pending_time; | ||
493 | break; | ||
494 | case cmb_device_disconnect_time: | ||
495 | val = cmb.device_disconnect_time; | ||
496 | break; | ||
497 | case cmb_control_unit_queuing_time: | ||
498 | val = cmb.control_unit_queuing_time; | ||
499 | break; | ||
500 | case cmb_device_active_only_time: | ||
501 | val = cmb.device_active_only_time; | ||
502 | break; | ||
503 | default: | ||
504 | return 0; | ||
505 | } | ||
506 | return time_to_avg_nsec(val, cmb.sample_count); | ||
507 | } | ||
508 | |||
509 | static int | ||
510 | readall_cmb (struct ccw_device *cdev, struct cmbdata *data) | ||
511 | { | ||
512 | /* yes, we have to put it on the stack | ||
513 | * because the cmb must only be accessed | ||
514 | * atomically, e.g. with mvc */ | ||
515 | struct cmb cmb; | ||
516 | unsigned long flags; | ||
517 | u64 time; | ||
518 | |||
519 | spin_lock_irqsave(cdev->ccwlock, flags); | ||
520 | if (!cdev->private->cmb) { | ||
521 | spin_unlock_irqrestore(cdev->ccwlock, flags); | ||
522 | return -ENODEV; | ||
523 | } | ||
524 | |||
525 | cmb = *(struct cmb*)cdev->private->cmb; | ||
526 | time = get_clock() - cdev->private->cmb_start_time; | ||
527 | spin_unlock_irqrestore(cdev->ccwlock, flags); | ||
528 | |||
529 | memset(data, 0, sizeof(struct cmbdata)); | ||
530 | |||
531 | /* we only know values before device_busy_time */ | ||
532 | data->size = offsetof(struct cmbdata, device_busy_time); | ||
533 | |||
534 | /* convert to nanoseconds */ | ||
535 | data->elapsed_time = (time * 1000) >> 12; | ||
536 | |||
537 | /* copy data to new structure */ | ||
538 | data->ssch_rsch_count = cmb.ssch_rsch_count; | ||
539 | data->sample_count = cmb.sample_count; | ||
540 | |||
541 | /* time fields are converted to nanoseconds while copying */ | ||
542 | data->device_connect_time = time_to_nsec(cmb.device_connect_time); | ||
543 | data->function_pending_time = time_to_nsec(cmb.function_pending_time); | ||
544 | data->device_disconnect_time = time_to_nsec(cmb.device_disconnect_time); | ||
545 | data->control_unit_queuing_time | ||
546 | = time_to_nsec(cmb.control_unit_queuing_time); | ||
547 | data->device_active_only_time | ||
548 | = time_to_nsec(cmb.device_active_only_time); | ||
549 | |||
550 | return 0; | ||
551 | } | ||
552 | |||
553 | static void | ||
554 | reset_cmb(struct ccw_device *cdev) | ||
555 | { | ||
556 | struct cmb *cmb; | ||
557 | spin_lock_irq(cdev->ccwlock); | ||
558 | cmb = cdev->private->cmb; | ||
559 | if (cmb) | ||
560 | memset (cmb, 0, sizeof (*cmb)); | ||
561 | cdev->private->cmb_start_time = get_clock(); | ||
562 | spin_unlock_irq(cdev->ccwlock); | ||
563 | } | ||
564 | |||
565 | static struct attribute_group cmf_attr_group; | ||
566 | |||
567 | static struct cmb_operations cmbops_basic = { | ||
568 | .alloc = alloc_cmb, | ||
569 | .free = free_cmb, | ||
570 | .set = set_cmb, | ||
571 | .read = read_cmb, | ||
572 | .readall = readall_cmb, | ||
573 | .reset = reset_cmb, | ||
574 | .attr_group = &cmf_attr_group, | ||
575 | }; | ||
576 | |||
577 | /* ******** extended cmb handling ********/ | ||
578 | |||
579 | /** | ||
580 | * struct cmbe - extended channel measurement block | ||
581 | * | ||
582 | * cmb as used by the hardware, may be in any 64 bit physical location, | ||
583 | * the fields are described in z/Architecture Principles of Operation, | ||
584 | * third edition, chapter 17. | ||
585 | */ | ||
586 | struct cmbe { | ||
587 | u32 ssch_rsch_count; | ||
588 | u32 sample_count; | ||
589 | u32 device_connect_time; | ||
590 | u32 function_pending_time; | ||
591 | u32 device_disconnect_time; | ||
592 | u32 control_unit_queuing_time; | ||
593 | u32 device_active_only_time; | ||
594 | u32 device_busy_time; | ||
595 | u32 initial_command_response_time; | ||
596 | u32 reserved[7]; | ||
597 | }; | ||
598 | |||
599 | /* kmalloc only guarantees 8 byte alignment, but we need cmbe | ||
600 | * pointers to be naturally aligned. Make sure to allocate | ||
601 | * enough space for two cmbes */ | ||
602 | static inline struct cmbe* cmbe_align(struct cmbe *c) | ||
603 | { | ||
604 | unsigned long addr; | ||
605 | addr = ((unsigned long)c + sizeof (struct cmbe) - sizeof(long)) & | ||
606 | ~(sizeof (struct cmbe) - sizeof(long)); | ||
607 | return (struct cmbe*)addr; | ||
608 | } | ||
609 | |||
610 | static int | ||
611 | alloc_cmbe (struct ccw_device *cdev) | ||
612 | { | ||
613 | struct cmbe *cmbe; | ||
614 | cmbe = kmalloc (sizeof (*cmbe) * 2, GFP_KERNEL); | ||
615 | if (!cmbe) | ||
616 | return -ENOMEM; | ||
617 | |||
618 | spin_lock_irq(cdev->ccwlock); | ||
619 | if (cdev->private->cmb) { | ||
620 | kfree(cmbe); | ||
621 | spin_unlock_irq(cdev->ccwlock); | ||
622 | return -EBUSY; | ||
623 | } | ||
624 | |||
625 | cdev->private->cmb = cmbe; | ||
626 | spin_unlock_irq(cdev->ccwlock); | ||
627 | |||
628 | /* activate global measurement if this is the first channel */ | ||
629 | spin_lock(&cmb_area.lock); | ||
630 | if (list_empty(&cmb_area.list)) | ||
631 | cmf_activate(NULL, 1); | ||
632 | list_add_tail(&cdev->private->cmb_list, &cmb_area.list); | ||
633 | spin_unlock(&cmb_area.lock); | ||
634 | |||
635 | return 0; | ||
636 | } | ||
637 | |||
638 | static void | ||
639 | free_cmbe (struct ccw_device *cdev) | ||
640 | { | ||
641 | spin_lock_irq(cdev->ccwlock); | ||
642 | if (cdev->private->cmb) | ||
643 | kfree(cdev->private->cmb); | ||
644 | cdev->private->cmb = NULL; | ||
645 | spin_unlock_irq(cdev->ccwlock); | ||
646 | |||
647 | /* deactivate global measurement if this is the last channel */ | ||
648 | spin_lock(&cmb_area.lock); | ||
649 | list_del_init(&cdev->private->cmb_list); | ||
650 | if (list_empty(&cmb_area.list)) | ||
651 | cmf_activate(NULL, 0); | ||
652 | spin_unlock(&cmb_area.lock); | ||
653 | } | ||
654 | |||
655 | static int | ||
656 | set_cmbe(struct ccw_device *cdev, u32 mme) | ||
657 | { | ||
658 | unsigned long mba; | ||
659 | |||
660 | if (!cdev->private->cmb) | ||
661 | return -EINVAL; | ||
662 | mba = mme ? (unsigned long) cmbe_align(cdev->private->cmb) : 0; | ||
663 | |||
664 | return set_schib_wait(cdev, mme, 1, mba); | ||
665 | } | ||
666 | |||
667 | |||
668 | u64 | ||
669 | read_cmbe (struct ccw_device *cdev, int index) | ||
670 | { | ||
671 | /* yes, we have to put it on the stack | ||
672 | * because the cmb must only be accessed | ||
673 | * atomically, e.g. with mvc */ | ||
674 | struct cmbe cmb; | ||
675 | unsigned long flags; | ||
676 | u32 val; | ||
677 | |||
678 | spin_lock_irqsave(cdev->ccwlock, flags); | ||
679 | if (!cdev->private->cmb) { | ||
680 | spin_unlock_irqrestore(cdev->ccwlock, flags); | ||
681 | return 0; | ||
682 | } | ||
683 | |||
684 | cmb = *cmbe_align(cdev->private->cmb); | ||
685 | spin_unlock_irqrestore(cdev->ccwlock, flags); | ||
686 | |||
687 | switch (index) { | ||
688 | case cmb_ssch_rsch_count: | ||
689 | return cmb.ssch_rsch_count; | ||
690 | case cmb_sample_count: | ||
691 | return cmb.sample_count; | ||
692 | case cmb_device_connect_time: | ||
693 | val = cmb.device_connect_time; | ||
694 | break; | ||
695 | case cmb_function_pending_time: | ||
696 | val = cmb.function_pending_time; | ||
697 | break; | ||
698 | case cmb_device_disconnect_time: | ||
699 | val = cmb.device_disconnect_time; | ||
700 | break; | ||
701 | case cmb_control_unit_queuing_time: | ||
702 | val = cmb.control_unit_queuing_time; | ||
703 | break; | ||
704 | case cmb_device_active_only_time: | ||
705 | val = cmb.device_active_only_time; | ||
706 | break; | ||
707 | case cmb_device_busy_time: | ||
708 | val = cmb.device_busy_time; | ||
709 | break; | ||
710 | case cmb_initial_command_response_time: | ||
711 | val = cmb.initial_command_response_time; | ||
712 | break; | ||
713 | default: | ||
714 | return 0; | ||
715 | } | ||
716 | return time_to_avg_nsec(val, cmb.sample_count); | ||
717 | } | ||
718 | |||
719 | static int | ||
720 | readall_cmbe (struct ccw_device *cdev, struct cmbdata *data) | ||
721 | { | ||
722 | /* yes, we have to put it on the stack | ||
723 | * because the cmb must only be accessed | ||
724 | * atomically, e.g. with mvc */ | ||
725 | struct cmbe cmb; | ||
726 | unsigned long flags; | ||
727 | u64 time; | ||
728 | |||
729 | spin_lock_irqsave(cdev->ccwlock, flags); | ||
730 | if (!cdev->private->cmb) { | ||
731 | spin_unlock_irqrestore(cdev->ccwlock, flags); | ||
732 | return -ENODEV; | ||
733 | } | ||
734 | |||
735 | cmb = *cmbe_align(cdev->private->cmb); | ||
736 | time = get_clock() - cdev->private->cmb_start_time; | ||
737 | spin_unlock_irqrestore(cdev->ccwlock, flags); | ||
738 | |||
739 | memset (data, 0, sizeof(struct cmbdata)); | ||
740 | |||
741 | /* we only know values before device_busy_time */ | ||
742 | data->size = offsetof(struct cmbdata, device_busy_time); | ||
743 | |||
744 | /* conver to nanoseconds */ | ||
745 | data->elapsed_time = (time * 1000) >> 12; | ||
746 | |||
747 | /* copy data to new structure */ | ||
748 | data->ssch_rsch_count = cmb.ssch_rsch_count; | ||
749 | data->sample_count = cmb.sample_count; | ||
750 | |||
751 | /* time fields are converted to nanoseconds while copying */ | ||
752 | data->device_connect_time = time_to_nsec(cmb.device_connect_time); | ||
753 | data->function_pending_time = time_to_nsec(cmb.function_pending_time); | ||
754 | data->device_disconnect_time = time_to_nsec(cmb.device_disconnect_time); | ||
755 | data->control_unit_queuing_time | ||
756 | = time_to_nsec(cmb.control_unit_queuing_time); | ||
757 | data->device_active_only_time | ||
758 | = time_to_nsec(cmb.device_active_only_time); | ||
759 | data->device_busy_time = time_to_nsec(cmb.device_busy_time); | ||
760 | data->initial_command_response_time | ||
761 | = time_to_nsec(cmb.initial_command_response_time); | ||
762 | |||
763 | return 0; | ||
764 | } | ||
765 | |||
766 | static void | ||
767 | reset_cmbe(struct ccw_device *cdev) | ||
768 | { | ||
769 | struct cmbe *cmb; | ||
770 | spin_lock_irq(cdev->ccwlock); | ||
771 | cmb = cmbe_align(cdev->private->cmb); | ||
772 | if (cmb) | ||
773 | memset (cmb, 0, sizeof (*cmb)); | ||
774 | cdev->private->cmb_start_time = get_clock(); | ||
775 | spin_unlock_irq(cdev->ccwlock); | ||
776 | } | ||
777 | |||
778 | static struct attribute_group cmf_attr_group_ext; | ||
779 | |||
780 | static struct cmb_operations cmbops_extended = { | ||
781 | .alloc = alloc_cmbe, | ||
782 | .free = free_cmbe, | ||
783 | .set = set_cmbe, | ||
784 | .read = read_cmbe, | ||
785 | .readall = readall_cmbe, | ||
786 | .reset = reset_cmbe, | ||
787 | .attr_group = &cmf_attr_group_ext, | ||
788 | }; | ||
789 | |||
790 | |||
791 | static ssize_t | ||
792 | cmb_show_attr(struct device *dev, char *buf, enum cmb_index idx) | ||
793 | { | ||
794 | return sprintf(buf, "%lld\n", | ||
795 | (unsigned long long) cmf_read(to_ccwdev(dev), idx)); | ||
796 | } | ||
797 | |||
798 | static ssize_t | ||
799 | cmb_show_avg_sample_interval(struct device *dev, char *buf) | ||
800 | { | ||
801 | struct ccw_device *cdev; | ||
802 | long interval; | ||
803 | unsigned long count; | ||
804 | |||
805 | cdev = to_ccwdev(dev); | ||
806 | interval = get_clock() - cdev->private->cmb_start_time; | ||
807 | count = cmf_read(cdev, cmb_sample_count); | ||
808 | if (count) | ||
809 | interval /= count; | ||
810 | else | ||
811 | interval = -1; | ||
812 | return sprintf(buf, "%ld\n", interval); | ||
813 | } | ||
814 | |||
815 | static ssize_t | ||
816 | cmb_show_avg_utilization(struct device *dev, char *buf) | ||
817 | { | ||
818 | struct cmbdata data; | ||
819 | u64 utilization; | ||
820 | unsigned long t, u; | ||
821 | int ret; | ||
822 | |||
823 | ret = cmf_readall(to_ccwdev(dev), &data); | ||
824 | if (ret) | ||
825 | return ret; | ||
826 | |||
827 | utilization = data.device_connect_time + | ||
828 | data.function_pending_time + | ||
829 | data.device_disconnect_time; | ||
830 | |||
831 | /* shift to avoid long long division */ | ||
832 | while (-1ul < (data.elapsed_time | utilization)) { | ||
833 | utilization >>= 8; | ||
834 | data.elapsed_time >>= 8; | ||
835 | } | ||
836 | |||
837 | /* calculate value in 0.1 percent units */ | ||
838 | t = (unsigned long) data.elapsed_time / 1000; | ||
839 | u = (unsigned long) utilization / t; | ||
840 | |||
841 | return sprintf(buf, "%02ld.%01ld%%\n", u/ 10, u - (u/ 10) * 10); | ||
842 | } | ||
843 | |||
844 | #define cmf_attr(name) \ | ||
845 | static ssize_t show_ ## name (struct device * dev, char * buf) \ | ||
846 | { return cmb_show_attr((dev), buf, cmb_ ## name); } \ | ||
847 | static DEVICE_ATTR(name, 0444, show_ ## name, NULL); | ||
848 | |||
849 | #define cmf_attr_avg(name) \ | ||
850 | static ssize_t show_avg_ ## name (struct device * dev, char * buf) \ | ||
851 | { return cmb_show_attr((dev), buf, cmb_ ## name); } \ | ||
852 | static DEVICE_ATTR(avg_ ## name, 0444, show_avg_ ## name, NULL); | ||
853 | |||
854 | cmf_attr(ssch_rsch_count); | ||
855 | cmf_attr(sample_count); | ||
856 | cmf_attr_avg(device_connect_time); | ||
857 | cmf_attr_avg(function_pending_time); | ||
858 | cmf_attr_avg(device_disconnect_time); | ||
859 | cmf_attr_avg(control_unit_queuing_time); | ||
860 | cmf_attr_avg(device_active_only_time); | ||
861 | cmf_attr_avg(device_busy_time); | ||
862 | cmf_attr_avg(initial_command_response_time); | ||
863 | |||
864 | static DEVICE_ATTR(avg_sample_interval, 0444, cmb_show_avg_sample_interval, NULL); | ||
865 | static DEVICE_ATTR(avg_utilization, 0444, cmb_show_avg_utilization, NULL); | ||
866 | |||
867 | static struct attribute *cmf_attributes[] = { | ||
868 | &dev_attr_avg_sample_interval.attr, | ||
869 | &dev_attr_avg_utilization.attr, | ||
870 | &dev_attr_ssch_rsch_count.attr, | ||
871 | &dev_attr_sample_count.attr, | ||
872 | &dev_attr_avg_device_connect_time.attr, | ||
873 | &dev_attr_avg_function_pending_time.attr, | ||
874 | &dev_attr_avg_device_disconnect_time.attr, | ||
875 | &dev_attr_avg_control_unit_queuing_time.attr, | ||
876 | &dev_attr_avg_device_active_only_time.attr, | ||
877 | 0, | ||
878 | }; | ||
879 | |||
880 | static struct attribute_group cmf_attr_group = { | ||
881 | .name = "cmf", | ||
882 | .attrs = cmf_attributes, | ||
883 | }; | ||
884 | |||
885 | static struct attribute *cmf_attributes_ext[] = { | ||
886 | &dev_attr_avg_sample_interval.attr, | ||
887 | &dev_attr_avg_utilization.attr, | ||
888 | &dev_attr_ssch_rsch_count.attr, | ||
889 | &dev_attr_sample_count.attr, | ||
890 | &dev_attr_avg_device_connect_time.attr, | ||
891 | &dev_attr_avg_function_pending_time.attr, | ||
892 | &dev_attr_avg_device_disconnect_time.attr, | ||
893 | &dev_attr_avg_control_unit_queuing_time.attr, | ||
894 | &dev_attr_avg_device_active_only_time.attr, | ||
895 | &dev_attr_avg_device_busy_time.attr, | ||
896 | &dev_attr_avg_initial_command_response_time.attr, | ||
897 | 0, | ||
898 | }; | ||
899 | |||
900 | static struct attribute_group cmf_attr_group_ext = { | ||
901 | .name = "cmf", | ||
902 | .attrs = cmf_attributes_ext, | ||
903 | }; | ||
904 | |||
905 | static ssize_t cmb_enable_show(struct device *dev, char *buf) | ||
906 | { | ||
907 | return sprintf(buf, "%d\n", to_ccwdev(dev)->private->cmb ? 1 : 0); | ||
908 | } | ||
909 | |||
910 | static ssize_t cmb_enable_store(struct device *dev, const char *buf, size_t c) | ||
911 | { | ||
912 | struct ccw_device *cdev; | ||
913 | int ret; | ||
914 | |||
915 | cdev = to_ccwdev(dev); | ||
916 | |||
917 | switch (buf[0]) { | ||
918 | case '0': | ||
919 | ret = disable_cmf(cdev); | ||
920 | if (ret) | ||
921 | printk(KERN_INFO "disable_cmf failed (%d)\n", ret); | ||
922 | break; | ||
923 | case '1': | ||
924 | ret = enable_cmf(cdev); | ||
925 | if (ret && ret != -EBUSY) | ||
926 | printk(KERN_INFO "enable_cmf failed (%d)\n", ret); | ||
927 | break; | ||
928 | } | ||
929 | |||
930 | return c; | ||
931 | } | ||
932 | |||
933 | DEVICE_ATTR(cmb_enable, 0644, cmb_enable_show, cmb_enable_store); | ||
934 | |||
935 | /* enable_cmf/disable_cmf: module interface for cmf (de)activation */ | ||
936 | int | ||
937 | enable_cmf(struct ccw_device *cdev) | ||
938 | { | ||
939 | int ret; | ||
940 | |||
941 | ret = cmbops->alloc(cdev); | ||
942 | cmbops->reset(cdev); | ||
943 | if (ret) | ||
944 | return ret; | ||
945 | ret = cmbops->set(cdev, 2); | ||
946 | if (ret) { | ||
947 | cmbops->free(cdev); | ||
948 | return ret; | ||
949 | } | ||
950 | ret = sysfs_create_group(&cdev->dev.kobj, cmbops->attr_group); | ||
951 | if (!ret) | ||
952 | return 0; | ||
953 | cmbops->set(cdev, 0); //FIXME: this can fail | ||
954 | cmbops->free(cdev); | ||
955 | return ret; | ||
956 | } | ||
957 | |||
958 | int | ||
959 | disable_cmf(struct ccw_device *cdev) | ||
960 | { | ||
961 | int ret; | ||
962 | |||
963 | ret = cmbops->set(cdev, 0); | ||
964 | if (ret) | ||
965 | return ret; | ||
966 | cmbops->free(cdev); | ||
967 | sysfs_remove_group(&cdev->dev.kobj, cmbops->attr_group); | ||
968 | return ret; | ||
969 | } | ||
970 | |||
971 | u64 | ||
972 | cmf_read(struct ccw_device *cdev, int index) | ||
973 | { | ||
974 | return cmbops->read(cdev, index); | ||
975 | } | ||
976 | |||
977 | int | ||
978 | cmf_readall(struct ccw_device *cdev, struct cmbdata *data) | ||
979 | { | ||
980 | return cmbops->readall(cdev, data); | ||
981 | } | ||
982 | |||
983 | static int __init | ||
984 | init_cmf(void) | ||
985 | { | ||
986 | char *format_string; | ||
987 | char *detect_string = "parameter"; | ||
988 | |||
989 | /* We cannot really autoprobe this. If the user did not give a parameter, | ||
990 | see if we are running on z990 or up, otherwise fall back to basic mode. */ | ||
991 | |||
992 | if (format == CMF_AUTODETECT) { | ||
993 | if (!css_characteristics_avail || | ||
994 | !css_general_characteristics.ext_mb) { | ||
995 | format = CMF_BASIC; | ||
996 | } else { | ||
997 | format = CMF_EXTENDED; | ||
998 | } | ||
999 | detect_string = "autodetected"; | ||
1000 | } else { | ||
1001 | detect_string = "parameter"; | ||
1002 | } | ||
1003 | |||
1004 | switch (format) { | ||
1005 | case CMF_BASIC: | ||
1006 | format_string = "basic"; | ||
1007 | cmbops = &cmbops_basic; | ||
1008 | if (cmb_area.num_channels > 4096 || cmb_area.num_channels < 1) { | ||
1009 | printk(KERN_ERR "Basic channel measurement facility" | ||
1010 | " can only use 1 to 4096 devices\n" | ||
1011 | KERN_ERR "when the cmf driver is built" | ||
1012 | " as a loadable module\n"); | ||
1013 | return 1; | ||
1014 | } | ||
1015 | break; | ||
1016 | case CMF_EXTENDED: | ||
1017 | format_string = "extended"; | ||
1018 | cmbops = &cmbops_extended; | ||
1019 | break; | ||
1020 | default: | ||
1021 | printk(KERN_ERR "Invalid format %d for channel " | ||
1022 | "measurement facility\n", format); | ||
1023 | return 1; | ||
1024 | } | ||
1025 | |||
1026 | printk(KERN_INFO "Channel measurement facility using %s format (%s)\n", | ||
1027 | format_string, detect_string); | ||
1028 | return 0; | ||
1029 | } | ||
1030 | |||
1031 | module_init(init_cmf); | ||
1032 | |||
1033 | |||
1034 | MODULE_AUTHOR("Arnd Bergmann <arndb@de.ibm.com>"); | ||
1035 | MODULE_LICENSE("GPL"); | ||
1036 | MODULE_DESCRIPTION("channel measurement facility base driver\n" | ||
1037 | "Copyright 2003 IBM Corporation\n"); | ||
1038 | |||
1039 | EXPORT_SYMBOL_GPL(enable_cmf); | ||
1040 | EXPORT_SYMBOL_GPL(disable_cmf); | ||
1041 | EXPORT_SYMBOL_GPL(cmf_read); | ||
1042 | EXPORT_SYMBOL_GPL(cmf_readall); | ||