blob: 6ddd02308e143971f7ba4527cf0216707ddcbfdf [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Heiko Carstense018ba12006-02-01 03:06:31 -08002 * linux/drivers/s390/cio/cmf.c
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 *
4 * Linux on zSeries Channel Measurement Facility support
5 *
Cornelia Huck94bb0632006-06-29 15:08:41 +02006 * Copyright 2000,2006 IBM Corporation
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 *
Cornelia Huck94bb0632006-06-29 15:08:41 +02008 * Authors: Arnd Bergmann <arndb@de.ibm.com>
9 * Cornelia Huck <cornelia.huck@de.ibm.com>
Linus Torvalds1da177e2005-04-16 15:20:36 -070010 *
11 * original idea from Natarajan Krishnaswami <nkrishna@us.ibm.com>
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2, or (at your option)
16 * any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 */
27
28#include <linux/bootmem.h>
29#include <linux/device.h>
30#include <linux/init.h>
31#include <linux/list.h>
32#include <linux/module.h>
33#include <linux/moduleparam.h>
Tim Schmielau4e57b682005-10-30 15:03:48 -080034#include <linux/slab.h>
35#include <linux/timex.h> /* get_clock() */
Linus Torvalds1da177e2005-04-16 15:20:36 -070036
37#include <asm/ccwdev.h>
38#include <asm/cio.h>
39#include <asm/cmb.h>
Tim Schmielau4e57b682005-10-30 15:03:48 -080040#include <asm/div64.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070041
42#include "cio.h"
43#include "css.h"
44#include "device.h"
45#include "ioasm.h"
46#include "chsc.h"
47
Cornelia Huckfc5019c2007-10-12 16:11:15 +020048/*
49 * parameter to enable cmf during boot, possible uses are:
Linus Torvalds1da177e2005-04-16 15:20:36 -070050 * "s390cmf" -- enable cmf and allocate 2 MB of ram so measuring can be
51 * used on any subchannel
52 * "s390cmf=<num>" -- enable cmf and allocate enough memory to measure
53 * <num> subchannel, where <num> is an integer
54 * between 1 and 65535, default is 1024
55 */
56#define ARGSTRING "s390cmf"
57
58/* indices for READCMB */
59enum cmb_index {
60 /* basic and exended format: */
61 cmb_ssch_rsch_count,
62 cmb_sample_count,
63 cmb_device_connect_time,
64 cmb_function_pending_time,
65 cmb_device_disconnect_time,
66 cmb_control_unit_queuing_time,
67 cmb_device_active_only_time,
68 /* extended format only: */
69 cmb_device_busy_time,
70 cmb_initial_command_response_time,
71};
72
73/**
74 * enum cmb_format - types of supported measurement block formats
75 *
76 * @CMF_BASIC: traditional channel measurement blocks supported
Cornelia Huckc0208712007-10-12 16:11:16 +020077 * by all machines that we run on
Linus Torvalds1da177e2005-04-16 15:20:36 -070078 * @CMF_EXTENDED: improved format that was introduced with the z990
Cornelia Huckc0208712007-10-12 16:11:16 +020079 * machine
80 * @CMF_AUTODETECT: default: use extended format when running on a machine
81 * supporting extended format, otherwise fall back to
82 * basic format
83 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070084enum cmb_format {
85 CMF_BASIC,
86 CMF_EXTENDED,
87 CMF_AUTODETECT = -1,
88};
Cornelia Huckfc5019c2007-10-12 16:11:15 +020089
Cornelia Huckc0208712007-10-12 16:11:16 +020090/*
Linus Torvalds1da177e2005-04-16 15:20:36 -070091 * format - actual format for all measurement blocks
92 *
93 * The format module parameter can be set to a value of 0 (zero)
94 * or 1, indicating basic or extended format as described for
95 * enum cmb_format.
96 */
97static int format = CMF_AUTODETECT;
98module_param(format, bool, 0444);
99
100/**
101 * struct cmb_operations - functions to use depending on cmb_format
102 *
Cornelia Huck94bb0632006-06-29 15:08:41 +0200103 * Most of these functions operate on a struct ccw_device. There is only
104 * one instance of struct cmb_operations because the format of the measurement
105 * data is guaranteed to be the same for every ccw_device.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106 *
107 * @alloc: allocate memory for a channel measurement block,
108 * either with the help of a special pool or with kmalloc
109 * @free: free memory allocated with @alloc
110 * @set: enable or disable measurement
Cornelia Huckc0208712007-10-12 16:11:16 +0200111 * @read: read a measurement entry at an index
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112 * @readall: read a measurement block in a common format
113 * @reset: clear the data in the associated measurement block and
114 * reset its time stamp
Cornelia Huck94bb0632006-06-29 15:08:41 +0200115 * @align: align an allocated block so that the hardware can use it
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116 */
117struct cmb_operations {
Cornelia Huckfc5019c2007-10-12 16:11:15 +0200118 int (*alloc) (struct ccw_device *);
119 void (*free) (struct ccw_device *);
120 int (*set) (struct ccw_device *, u32);
121 u64 (*read) (struct ccw_device *, int);
122 int (*readall)(struct ccw_device *, struct cmbdata *);
123 void (*reset) (struct ccw_device *);
124 void *(*align) (void *);
Cornelia Huckc0208712007-10-12 16:11:16 +0200125/* private: */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126 struct attribute_group *attr_group;
127};
128static struct cmb_operations *cmbops;
129
Cornelia Huck94bb0632006-06-29 15:08:41 +0200130struct cmb_data {
131 void *hw_block; /* Pointer to block updated by hardware */
132 void *last_block; /* Last changed block copied from hardware block */
133 int size; /* Size of hw_block and last_block */
134 unsigned long long last_update; /* when last_block was updated */
135};
136
Cornelia Huckfc5019c2007-10-12 16:11:15 +0200137/*
138 * Our user interface is designed in terms of nanoseconds,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139 * while the hardware measures total times in its own
Cornelia Huckfc5019c2007-10-12 16:11:15 +0200140 * unit.
141 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142static inline u64 time_to_nsec(u32 value)
143{
144 return ((u64)value) * 128000ull;
145}
146
147/*
148 * Users are usually interested in average times,
149 * not accumulated time.
150 * This also helps us with atomicity problems
151 * when reading sinlge values.
152 */
153static inline u64 time_to_avg_nsec(u32 value, u32 count)
154{
155 u64 ret;
156
157 /* no samples yet, avoid division by 0 */
158 if (count == 0)
159 return 0;
160
Jan Engelhardt96de0e22007-10-19 23:21:04 +0200161 /* value comes in units of 128 µsec */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162 ret = time_to_nsec(value);
163 do_div(ret, count);
164
165 return ret;
166}
167
Cornelia Huckfc5019c2007-10-12 16:11:15 +0200168/*
169 * Activate or deactivate the channel monitor. When area is NULL,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170 * the monitor is deactivated. The channel monitor needs to
171 * be active in order to measure subchannels, which also need
Cornelia Huckfc5019c2007-10-12 16:11:15 +0200172 * to be enabled.
173 */
174static inline void cmf_activate(void *area, unsigned int onoff)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175{
176 register void * __gpr2 asm("2");
177 register long __gpr1 asm("1");
178
179 __gpr2 = area;
180 __gpr1 = onoff ? 2 : 0;
181 /* activate channel measurement */
182 asm("schm" : : "d" (__gpr2), "d" (__gpr1) );
183}
184
Cornelia Huckfc5019c2007-10-12 16:11:15 +0200185static int set_schib(struct ccw_device *cdev, u32 mme, int mbfc,
186 unsigned long address)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188 struct subchannel *sch;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189
190 sch = to_subchannel(cdev->dev.parent);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191
Sebastian Ott13952ec2008-12-25 13:39:13 +0100192 sch->config.mme = mme;
193 sch->config.mbfc = mbfc;
194 /* address can be either a block address or a block index */
195 if (mbfc)
196 sch->config.mba = address;
197 else
198 sch->config.mbi = address;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199
Sebastian Ott13952ec2008-12-25 13:39:13 +0100200 return cio_commit_config(sch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201}
202
203struct set_schib_struct {
204 u32 mme;
205 int mbfc;
206 unsigned long address;
207 wait_queue_head_t wait;
208 int ret;
Cornelia Huck94bb0632006-06-29 15:08:41 +0200209 struct kref kref;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210};
211
Cornelia Huck94bb0632006-06-29 15:08:41 +0200212static void cmf_set_schib_release(struct kref *kref)
213{
214 struct set_schib_struct *set_data;
215
216 set_data = container_of(kref, struct set_schib_struct, kref);
217 kfree(set_data);
218}
219
220#define CMF_PENDING 1
221
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222static int set_schib_wait(struct ccw_device *cdev, u32 mme,
223 int mbfc, unsigned long address)
224{
Cornelia Huck94bb0632006-06-29 15:08:41 +0200225 struct set_schib_struct *set_data;
226 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227
228 spin_lock_irq(cdev->ccwlock);
Cornelia Huck94bb0632006-06-29 15:08:41 +0200229 if (!cdev->private->cmb) {
230 ret = -ENODEV;
231 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232 }
Cornelia Huck94bb0632006-06-29 15:08:41 +0200233 set_data = kzalloc(sizeof(struct set_schib_struct), GFP_ATOMIC);
234 if (!set_data) {
235 ret = -ENOMEM;
236 goto out;
237 }
238 init_waitqueue_head(&set_data->wait);
239 kref_init(&set_data->kref);
240 set_data->mme = mme;
241 set_data->mbfc = mbfc;
242 set_data->address = address;
243
244 ret = set_schib(cdev, mme, mbfc, address);
245 if (ret != -EBUSY)
246 goto out_put;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247
248 if (cdev->private->state != DEV_STATE_ONLINE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249 /* if the device is not online, don't even try again */
Cornelia Huck94bb0632006-06-29 15:08:41 +0200250 ret = -EBUSY;
251 goto out_put;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252 }
Cornelia Huck94bb0632006-06-29 15:08:41 +0200253
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254 cdev->private->state = DEV_STATE_CMFCHANGE;
Cornelia Huck94bb0632006-06-29 15:08:41 +0200255 set_data->ret = CMF_PENDING;
256 cdev->private->cmb_wait = set_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257
258 spin_unlock_irq(cdev->ccwlock);
Cornelia Huck94bb0632006-06-29 15:08:41 +0200259 if (wait_event_interruptible(set_data->wait,
260 set_data->ret != CMF_PENDING)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261 spin_lock_irq(cdev->ccwlock);
Cornelia Huck94bb0632006-06-29 15:08:41 +0200262 if (set_data->ret == CMF_PENDING) {
263 set_data->ret = -ERESTARTSYS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264 if (cdev->private->state == DEV_STATE_CMFCHANGE)
265 cdev->private->state = DEV_STATE_ONLINE;
266 }
267 spin_unlock_irq(cdev->ccwlock);
268 }
Cornelia Huck94bb0632006-06-29 15:08:41 +0200269 spin_lock_irq(cdev->ccwlock);
270 cdev->private->cmb_wait = NULL;
271 ret = set_data->ret;
272out_put:
273 kref_put(&set_data->kref, cmf_set_schib_release);
274out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275 spin_unlock_irq(cdev->ccwlock);
Cornelia Huck94bb0632006-06-29 15:08:41 +0200276 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277}
278
279void retry_set_schib(struct ccw_device *cdev)
280{
Cornelia Huck94bb0632006-06-29 15:08:41 +0200281 struct set_schib_struct *set_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282
Cornelia Huck94bb0632006-06-29 15:08:41 +0200283 set_data = cdev->private->cmb_wait;
284 if (!set_data) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285 WARN_ON(1);
286 return;
287 }
Cornelia Huck94bb0632006-06-29 15:08:41 +0200288 kref_get(&set_data->kref);
289 set_data->ret = set_schib(cdev, set_data->mme, set_data->mbfc,
290 set_data->address);
291 wake_up(&set_data->wait);
292 kref_put(&set_data->kref, cmf_set_schib_release);
293}
294
295static int cmf_copy_block(struct ccw_device *cdev)
296{
297 struct subchannel *sch;
298 void *reference_buf;
299 void *hw_block;
300 struct cmb_data *cmb_data;
301
302 sch = to_subchannel(cdev->dev.parent);
303
Sebastian Ottcdb912a2008-12-25 13:39:12 +0100304 if (cio_update_schib(sch))
Cornelia Huck94bb0632006-06-29 15:08:41 +0200305 return -ENODEV;
306
Peter Oberparleiter23d805b2008-07-14 09:58:50 +0200307 if (scsw_fctl(&sch->schib.scsw) & SCSW_FCTL_START_FUNC) {
Cornelia Huck94bb0632006-06-29 15:08:41 +0200308 /* Don't copy if a start function is in progress. */
Peter Oberparleiter23d805b2008-07-14 09:58:50 +0200309 if ((!(scsw_actl(&sch->schib.scsw) & SCSW_ACTL_SUSPENDED)) &&
310 (scsw_actl(&sch->schib.scsw) &
Cornelia Huck94bb0632006-06-29 15:08:41 +0200311 (SCSW_ACTL_DEVACT | SCSW_ACTL_SCHACT)) &&
Peter Oberparleiter23d805b2008-07-14 09:58:50 +0200312 (!(scsw_stctl(&sch->schib.scsw) & SCSW_STCTL_SEC_STATUS)))
Cornelia Huck94bb0632006-06-29 15:08:41 +0200313 return -EBUSY;
314 }
315 cmb_data = cdev->private->cmb;
316 hw_block = cmbops->align(cmb_data->hw_block);
317 if (!memcmp(cmb_data->last_block, hw_block, cmb_data->size))
318 /* No need to copy. */
319 return 0;
320 reference_buf = kzalloc(cmb_data->size, GFP_ATOMIC);
321 if (!reference_buf)
322 return -ENOMEM;
323 /* Ensure consistency of block copied from hardware. */
324 do {
325 memcpy(cmb_data->last_block, hw_block, cmb_data->size);
326 memcpy(reference_buf, hw_block, cmb_data->size);
327 } while (memcmp(cmb_data->last_block, reference_buf, cmb_data->size));
328 cmb_data->last_update = get_clock();
329 kfree(reference_buf);
330 return 0;
331}
332
333struct copy_block_struct {
334 wait_queue_head_t wait;
335 int ret;
336 struct kref kref;
337};
338
339static void cmf_copy_block_release(struct kref *kref)
340{
341 struct copy_block_struct *copy_block;
342
343 copy_block = container_of(kref, struct copy_block_struct, kref);
344 kfree(copy_block);
345}
346
347static int cmf_cmb_copy_wait(struct ccw_device *cdev)
348{
349 struct copy_block_struct *copy_block;
350 int ret;
351 unsigned long flags;
352
353 spin_lock_irqsave(cdev->ccwlock, flags);
354 if (!cdev->private->cmb) {
355 ret = -ENODEV;
356 goto out;
357 }
358 copy_block = kzalloc(sizeof(struct copy_block_struct), GFP_ATOMIC);
359 if (!copy_block) {
360 ret = -ENOMEM;
361 goto out;
362 }
363 init_waitqueue_head(&copy_block->wait);
364 kref_init(&copy_block->kref);
365
366 ret = cmf_copy_block(cdev);
367 if (ret != -EBUSY)
368 goto out_put;
369
370 if (cdev->private->state != DEV_STATE_ONLINE) {
371 ret = -EBUSY;
372 goto out_put;
373 }
374
375 cdev->private->state = DEV_STATE_CMFUPDATE;
376 copy_block->ret = CMF_PENDING;
377 cdev->private->cmb_wait = copy_block;
378
379 spin_unlock_irqrestore(cdev->ccwlock, flags);
380 if (wait_event_interruptible(copy_block->wait,
381 copy_block->ret != CMF_PENDING)) {
382 spin_lock_irqsave(cdev->ccwlock, flags);
383 if (copy_block->ret == CMF_PENDING) {
384 copy_block->ret = -ERESTARTSYS;
385 if (cdev->private->state == DEV_STATE_CMFUPDATE)
386 cdev->private->state = DEV_STATE_ONLINE;
387 }
388 spin_unlock_irqrestore(cdev->ccwlock, flags);
389 }
390 spin_lock_irqsave(cdev->ccwlock, flags);
391 cdev->private->cmb_wait = NULL;
392 ret = copy_block->ret;
393out_put:
394 kref_put(&copy_block->kref, cmf_copy_block_release);
395out:
396 spin_unlock_irqrestore(cdev->ccwlock, flags);
397 return ret;
398}
399
400void cmf_retry_copy_block(struct ccw_device *cdev)
401{
402 struct copy_block_struct *copy_block;
403
404 copy_block = cdev->private->cmb_wait;
405 if (!copy_block) {
406 WARN_ON(1);
407 return;
408 }
409 kref_get(&copy_block->kref);
410 copy_block->ret = cmf_copy_block(cdev);
411 wake_up(&copy_block->wait);
412 kref_put(&copy_block->kref, cmf_copy_block_release);
413}
414
415static void cmf_generic_reset(struct ccw_device *cdev)
416{
417 struct cmb_data *cmb_data;
418
419 spin_lock_irq(cdev->ccwlock);
420 cmb_data = cdev->private->cmb;
421 if (cmb_data) {
422 memset(cmb_data->last_block, 0, cmb_data->size);
423 /*
424 * Need to reset hw block as well to make the hardware start
425 * from 0 again.
426 */
427 memset(cmbops->align(cmb_data->hw_block), 0, cmb_data->size);
428 cmb_data->last_update = 0;
429 }
430 cdev->private->cmb_start_time = get_clock();
431 spin_unlock_irq(cdev->ccwlock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432}
433
434/**
435 * struct cmb_area - container for global cmb data
436 *
437 * @mem: pointer to CMBs (only in basic measurement mode)
438 * @list: contains a linked list of all subchannels
Cornelia Huckc0208712007-10-12 16:11:16 +0200439 * @num_channels: number of channels to be measured
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440 * @lock: protect concurrent access to @mem and @list
441 */
442struct cmb_area {
443 struct cmb *mem;
444 struct list_head list;
445 int num_channels;
446 spinlock_t lock;
447};
448
449static struct cmb_area cmb_area = {
Milind Arun Choudharycb629a02007-04-27 16:02:01 +0200450 .lock = __SPIN_LOCK_UNLOCKED(cmb_area.lock),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451 .list = LIST_HEAD_INIT(cmb_area.list),
452 .num_channels = 1024,
453};
454
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455/* ****** old style CMB handling ********/
456
Cornelia Huckfc5019c2007-10-12 16:11:15 +0200457/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458 * Basic channel measurement blocks are allocated in one contiguous
459 * block of memory, which can not be moved as long as any channel
460 * is active. Therefore, a maximum number of subchannels needs to
461 * be defined somewhere. This is a module parameter, defaulting to
462 * a resonable value of 1024, or 32 kb of memory.
463 * Current kernels don't allow kmalloc with more than 128kb, so the
Cornelia Huckfc5019c2007-10-12 16:11:15 +0200464 * maximum is 4096.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465 */
466
467module_param_named(maxchannels, cmb_area.num_channels, uint, 0444);
468
469/**
470 * struct cmb - basic channel measurement block
Cornelia Huckc0208712007-10-12 16:11:16 +0200471 * @ssch_rsch_count: number of ssch and rsch
472 * @sample_count: number of samples
473 * @device_connect_time: time of device connect
474 * @function_pending_time: time of function pending
475 * @device_disconnect_time: time of device disconnect
476 * @control_unit_queuing_time: time of control unit queuing
477 * @device_active_only_time: time of device active only
478 * @reserved: unused in basic measurement mode
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479 *
Cornelia Huckc0208712007-10-12 16:11:16 +0200480 * The measurement block as used by the hardware. The fields are described
481 * further in z/Architecture Principles of Operation, chapter 17.
482 *
483 * The cmb area made up from these blocks must be a contiguous array and may
484 * not be reallocated or freed.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485 * Only one cmb area can be present in the system.
486 */
487struct cmb {
488 u16 ssch_rsch_count;
489 u16 sample_count;
490 u32 device_connect_time;
491 u32 function_pending_time;
492 u32 device_disconnect_time;
493 u32 control_unit_queuing_time;
494 u32 device_active_only_time;
495 u32 reserved[2];
496};
497
Cornelia Huckfc5019c2007-10-12 16:11:15 +0200498/*
499 * Insert a single device into the cmb_area list.
500 * Called with cmb_area.lock held from alloc_cmb.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501 */
Heiko Carstens4d284ca2007-02-05 21:18:53 +0100502static int alloc_cmb_single(struct ccw_device *cdev,
503 struct cmb_data *cmb_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504{
505 struct cmb *cmb;
506 struct ccw_device_private *node;
507 int ret;
508
509 spin_lock_irq(cdev->ccwlock);
510 if (!list_empty(&cdev->private->cmb_list)) {
511 ret = -EBUSY;
512 goto out;
513 }
514
Cornelia Huckfc5019c2007-10-12 16:11:15 +0200515 /*
516 * Find first unused cmb in cmb_area.mem.
517 * This is a little tricky: cmb_area.list
518 * remains sorted by ->cmb->hw_data pointers.
519 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520 cmb = cmb_area.mem;
521 list_for_each_entry(node, &cmb_area.list, cmb_list) {
Cornelia Huck94bb0632006-06-29 15:08:41 +0200522 struct cmb_data *data;
523 data = node->cmb;
524 if ((struct cmb*)data->hw_block > cmb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525 break;
526 cmb++;
527 }
528 if (cmb - cmb_area.mem >= cmb_area.num_channels) {
529 ret = -ENOMEM;
530 goto out;
531 }
532
533 /* insert new cmb */
534 list_add_tail(&cdev->private->cmb_list, &node->cmb_list);
Cornelia Huck94bb0632006-06-29 15:08:41 +0200535 cmb_data->hw_block = cmb;
536 cdev->private->cmb = cmb_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537 ret = 0;
538out:
539 spin_unlock_irq(cdev->ccwlock);
540 return ret;
541}
542
Cornelia Huckfc5019c2007-10-12 16:11:15 +0200543static int alloc_cmb(struct ccw_device *cdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544{
545 int ret;
546 struct cmb *mem;
547 ssize_t size;
Cornelia Huck94bb0632006-06-29 15:08:41 +0200548 struct cmb_data *cmb_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549
Cornelia Huck94bb0632006-06-29 15:08:41 +0200550 /* Allocate private cmb_data. */
551 cmb_data = kzalloc(sizeof(struct cmb_data), GFP_KERNEL);
552 if (!cmb_data)
553 return -ENOMEM;
554
555 cmb_data->last_block = kzalloc(sizeof(struct cmb), GFP_KERNEL);
556 if (!cmb_data->last_block) {
557 kfree(cmb_data);
558 return -ENOMEM;
559 }
560 cmb_data->size = sizeof(struct cmb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561 spin_lock(&cmb_area.lock);
562
563 if (!cmb_area.mem) {
564 /* there is no user yet, so we need a new area */
565 size = sizeof(struct cmb) * cmb_area.num_channels;
566 WARN_ON(!list_empty(&cmb_area.list));
567
568 spin_unlock(&cmb_area.lock);
569 mem = (void*)__get_free_pages(GFP_KERNEL | GFP_DMA,
570 get_order(size));
571 spin_lock(&cmb_area.lock);
572
573 if (cmb_area.mem) {
574 /* ok, another thread was faster */
575 free_pages((unsigned long)mem, get_order(size));
576 } else if (!mem) {
577 /* no luck */
578 ret = -ENOMEM;
579 goto out;
580 } else {
581 /* everything ok */
582 memset(mem, 0, size);
583 cmb_area.mem = mem;
584 cmf_activate(cmb_area.mem, 1);
585 }
586 }
587
588 /* do the actual allocation */
Cornelia Huck94bb0632006-06-29 15:08:41 +0200589 ret = alloc_cmb_single(cdev, cmb_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590out:
591 spin_unlock(&cmb_area.lock);
Cornelia Huck94bb0632006-06-29 15:08:41 +0200592 if (ret) {
593 kfree(cmb_data->last_block);
594 kfree(cmb_data);
595 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596 return ret;
597}
598
Cornelia Huck94bb0632006-06-29 15:08:41 +0200599static void free_cmb(struct ccw_device *cdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600{
601 struct ccw_device_private *priv;
Cornelia Huck94bb0632006-06-29 15:08:41 +0200602 struct cmb_data *cmb_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603
604 spin_lock(&cmb_area.lock);
605 spin_lock_irq(cdev->ccwlock);
606
Cornelia Huck94bb0632006-06-29 15:08:41 +0200607 priv = cdev->private;
608
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609 if (list_empty(&priv->cmb_list)) {
610 /* already freed */
611 goto out;
612 }
613
Cornelia Huck94bb0632006-06-29 15:08:41 +0200614 cmb_data = priv->cmb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615 priv->cmb = NULL;
Cornelia Huck94bb0632006-06-29 15:08:41 +0200616 if (cmb_data)
617 kfree(cmb_data->last_block);
618 kfree(cmb_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619 list_del_init(&priv->cmb_list);
620
621 if (list_empty(&cmb_area.list)) {
622 ssize_t size;
623 size = sizeof(struct cmb) * cmb_area.num_channels;
624 cmf_activate(NULL, 0);
625 free_pages((unsigned long)cmb_area.mem, get_order(size));
626 cmb_area.mem = NULL;
627 }
628out:
629 spin_unlock_irq(cdev->ccwlock);
630 spin_unlock(&cmb_area.lock);
631}
632
Cornelia Huck94bb0632006-06-29 15:08:41 +0200633static int set_cmb(struct ccw_device *cdev, u32 mme)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634{
635 u16 offset;
Cornelia Huck94bb0632006-06-29 15:08:41 +0200636 struct cmb_data *cmb_data;
637 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638
Cornelia Huck94bb0632006-06-29 15:08:41 +0200639 spin_lock_irqsave(cdev->ccwlock, flags);
640 if (!cdev->private->cmb) {
641 spin_unlock_irqrestore(cdev->ccwlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642 return -EINVAL;
Cornelia Huck94bb0632006-06-29 15:08:41 +0200643 }
644 cmb_data = cdev->private->cmb;
645 offset = mme ? (struct cmb *)cmb_data->hw_block - cmb_area.mem : 0;
646 spin_unlock_irqrestore(cdev->ccwlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647
648 return set_schib_wait(cdev, mme, 0, offset);
649}
650
Cornelia Huckfc5019c2007-10-12 16:11:15 +0200651static u64 read_cmb(struct ccw_device *cdev, int index)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652{
Cornelia Huck94bb0632006-06-29 15:08:41 +0200653 struct cmb *cmb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654 u32 val;
Cornelia Huck94bb0632006-06-29 15:08:41 +0200655 int ret;
656 unsigned long flags;
657
658 ret = cmf_cmb_copy_wait(cdev);
659 if (ret < 0)
660 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661
662 spin_lock_irqsave(cdev->ccwlock, flags);
663 if (!cdev->private->cmb) {
Cornelia Huck94bb0632006-06-29 15:08:41 +0200664 ret = 0;
665 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 }
Cornelia Huck94bb0632006-06-29 15:08:41 +0200667 cmb = ((struct cmb_data *)cdev->private->cmb)->last_block;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668
669 switch (index) {
670 case cmb_ssch_rsch_count:
Cornelia Huck94bb0632006-06-29 15:08:41 +0200671 ret = cmb->ssch_rsch_count;
672 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673 case cmb_sample_count:
Cornelia Huck94bb0632006-06-29 15:08:41 +0200674 ret = cmb->sample_count;
675 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 case cmb_device_connect_time:
Cornelia Huck94bb0632006-06-29 15:08:41 +0200677 val = cmb->device_connect_time;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678 break;
679 case cmb_function_pending_time:
Cornelia Huck94bb0632006-06-29 15:08:41 +0200680 val = cmb->function_pending_time;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 break;
682 case cmb_device_disconnect_time:
Cornelia Huck94bb0632006-06-29 15:08:41 +0200683 val = cmb->device_disconnect_time;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 break;
685 case cmb_control_unit_queuing_time:
Cornelia Huck94bb0632006-06-29 15:08:41 +0200686 val = cmb->control_unit_queuing_time;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687 break;
688 case cmb_device_active_only_time:
Cornelia Huck94bb0632006-06-29 15:08:41 +0200689 val = cmb->device_active_only_time;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 break;
691 default:
Cornelia Huck94bb0632006-06-29 15:08:41 +0200692 ret = 0;
693 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694 }
Cornelia Huck94bb0632006-06-29 15:08:41 +0200695 ret = time_to_avg_nsec(val, cmb->sample_count);
696out:
697 spin_unlock_irqrestore(cdev->ccwlock, flags);
698 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699}
700
Cornelia Huckfc5019c2007-10-12 16:11:15 +0200701static int readall_cmb(struct ccw_device *cdev, struct cmbdata *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702{
Cornelia Huck94bb0632006-06-29 15:08:41 +0200703 struct cmb *cmb;
704 struct cmb_data *cmb_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705 u64 time;
Cornelia Huck94bb0632006-06-29 15:08:41 +0200706 unsigned long flags;
707 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708
Cornelia Huck94bb0632006-06-29 15:08:41 +0200709 ret = cmf_cmb_copy_wait(cdev);
710 if (ret < 0)
711 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 spin_lock_irqsave(cdev->ccwlock, flags);
Cornelia Huck94bb0632006-06-29 15:08:41 +0200713 cmb_data = cdev->private->cmb;
714 if (!cmb_data) {
715 ret = -ENODEV;
716 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 }
Cornelia Huck94bb0632006-06-29 15:08:41 +0200718 if (cmb_data->last_update == 0) {
719 ret = -EAGAIN;
720 goto out;
721 }
722 cmb = cmb_data->last_block;
723 time = cmb_data->last_update - cdev->private->cmb_start_time;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724
725 memset(data, 0, sizeof(struct cmbdata));
726
727 /* we only know values before device_busy_time */
728 data->size = offsetof(struct cmbdata, device_busy_time);
729
730 /* convert to nanoseconds */
731 data->elapsed_time = (time * 1000) >> 12;
732
733 /* copy data to new structure */
Cornelia Huck94bb0632006-06-29 15:08:41 +0200734 data->ssch_rsch_count = cmb->ssch_rsch_count;
735 data->sample_count = cmb->sample_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736
737 /* time fields are converted to nanoseconds while copying */
Cornelia Huck94bb0632006-06-29 15:08:41 +0200738 data->device_connect_time = time_to_nsec(cmb->device_connect_time);
739 data->function_pending_time = time_to_nsec(cmb->function_pending_time);
740 data->device_disconnect_time =
741 time_to_nsec(cmb->device_disconnect_time);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742 data->control_unit_queuing_time
Cornelia Huck94bb0632006-06-29 15:08:41 +0200743 = time_to_nsec(cmb->control_unit_queuing_time);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 data->device_active_only_time
Cornelia Huck94bb0632006-06-29 15:08:41 +0200745 = time_to_nsec(cmb->device_active_only_time);
746 ret = 0;
747out:
748 spin_unlock_irqrestore(cdev->ccwlock, flags);
749 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750}
751
Cornelia Huck94bb0632006-06-29 15:08:41 +0200752static void reset_cmb(struct ccw_device *cdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753{
Cornelia Huck94bb0632006-06-29 15:08:41 +0200754 cmf_generic_reset(cdev);
755}
756
757static void * align_cmb(void *area)
758{
759 return area;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760}
761
762static struct attribute_group cmf_attr_group;
763
764static struct cmb_operations cmbops_basic = {
765 .alloc = alloc_cmb,
766 .free = free_cmb,
767 .set = set_cmb,
768 .read = read_cmb,
769 .readall = readall_cmb,
770 .reset = reset_cmb,
Cornelia Huck94bb0632006-06-29 15:08:41 +0200771 .align = align_cmb,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772 .attr_group = &cmf_attr_group,
773};
Heiko Carstens364c8552007-10-12 16:11:35 +0200774
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775/* ******** extended cmb handling ********/
776
777/**
778 * struct cmbe - extended channel measurement block
Cornelia Huckc0208712007-10-12 16:11:16 +0200779 * @ssch_rsch_count: number of ssch and rsch
780 * @sample_count: number of samples
781 * @device_connect_time: time of device connect
782 * @function_pending_time: time of function pending
783 * @device_disconnect_time: time of device disconnect
784 * @control_unit_queuing_time: time of control unit queuing
785 * @device_active_only_time: time of device active only
786 * @device_busy_time: time of device busy
787 * @initial_command_response_time: initial command response time
788 * @reserved: unused
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789 *
Cornelia Huckc0208712007-10-12 16:11:16 +0200790 * The measurement block as used by the hardware. May be in any 64 bit physical
791 * location.
792 * The fields are described further in z/Architecture Principles of Operation,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793 * third edition, chapter 17.
794 */
795struct cmbe {
796 u32 ssch_rsch_count;
797 u32 sample_count;
798 u32 device_connect_time;
799 u32 function_pending_time;
800 u32 device_disconnect_time;
801 u32 control_unit_queuing_time;
802 u32 device_active_only_time;
803 u32 device_busy_time;
804 u32 initial_command_response_time;
805 u32 reserved[7];
806};
807
Cornelia Huckfc5019c2007-10-12 16:11:15 +0200808/*
809 * kmalloc only guarantees 8 byte alignment, but we need cmbe
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810 * pointers to be naturally aligned. Make sure to allocate
Cornelia Huckfc5019c2007-10-12 16:11:15 +0200811 * enough space for two cmbes.
812 */
813static inline struct cmbe *cmbe_align(struct cmbe *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814{
815 unsigned long addr;
816 addr = ((unsigned long)c + sizeof (struct cmbe) - sizeof(long)) &
817 ~(sizeof (struct cmbe) - sizeof(long));
818 return (struct cmbe*)addr;
819}
820
Cornelia Huckfc5019c2007-10-12 16:11:15 +0200821static int alloc_cmbe(struct ccw_device *cdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822{
823 struct cmbe *cmbe;
Cornelia Huck94bb0632006-06-29 15:08:41 +0200824 struct cmb_data *cmb_data;
825 int ret;
826
827 cmbe = kzalloc (sizeof (*cmbe) * 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 if (!cmbe)
829 return -ENOMEM;
Cornelia Huck94bb0632006-06-29 15:08:41 +0200830 cmb_data = kzalloc(sizeof(struct cmb_data), GFP_KERNEL);
831 if (!cmb_data) {
832 ret = -ENOMEM;
833 goto out_free;
834 }
835 cmb_data->last_block = kzalloc(sizeof(struct cmbe), GFP_KERNEL);
836 if (!cmb_data->last_block) {
837 ret = -ENOMEM;
838 goto out_free;
839 }
840 cmb_data->size = sizeof(struct cmbe);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841 spin_lock_irq(cdev->ccwlock);
842 if (cdev->private->cmb) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843 spin_unlock_irq(cdev->ccwlock);
Cornelia Huck94bb0632006-06-29 15:08:41 +0200844 ret = -EBUSY;
845 goto out_free;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846 }
Cornelia Huck94bb0632006-06-29 15:08:41 +0200847 cmb_data->hw_block = cmbe;
848 cdev->private->cmb = cmb_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849 spin_unlock_irq(cdev->ccwlock);
850
851 /* activate global measurement if this is the first channel */
852 spin_lock(&cmb_area.lock);
853 if (list_empty(&cmb_area.list))
854 cmf_activate(NULL, 1);
855 list_add_tail(&cdev->private->cmb_list, &cmb_area.list);
856 spin_unlock(&cmb_area.lock);
857
858 return 0;
Cornelia Huck94bb0632006-06-29 15:08:41 +0200859out_free:
860 if (cmb_data)
861 kfree(cmb_data->last_block);
862 kfree(cmb_data);
863 kfree(cmbe);
864 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865}
866
Cornelia Huckfc5019c2007-10-12 16:11:15 +0200867static void free_cmbe(struct ccw_device *cdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868{
Cornelia Huck94bb0632006-06-29 15:08:41 +0200869 struct cmb_data *cmb_data;
870
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871 spin_lock_irq(cdev->ccwlock);
Cornelia Huck94bb0632006-06-29 15:08:41 +0200872 cmb_data = cdev->private->cmb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873 cdev->private->cmb = NULL;
Cornelia Huck94bb0632006-06-29 15:08:41 +0200874 if (cmb_data)
875 kfree(cmb_data->last_block);
876 kfree(cmb_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877 spin_unlock_irq(cdev->ccwlock);
878
879 /* deactivate global measurement if this is the last channel */
880 spin_lock(&cmb_area.lock);
881 list_del_init(&cdev->private->cmb_list);
882 if (list_empty(&cmb_area.list))
883 cmf_activate(NULL, 0);
884 spin_unlock(&cmb_area.lock);
885}
886
Cornelia Huck94bb0632006-06-29 15:08:41 +0200887static int set_cmbe(struct ccw_device *cdev, u32 mme)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888{
889 unsigned long mba;
Cornelia Huck94bb0632006-06-29 15:08:41 +0200890 struct cmb_data *cmb_data;
891 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892
Cornelia Huck94bb0632006-06-29 15:08:41 +0200893 spin_lock_irqsave(cdev->ccwlock, flags);
894 if (!cdev->private->cmb) {
895 spin_unlock_irqrestore(cdev->ccwlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896 return -EINVAL;
Cornelia Huck94bb0632006-06-29 15:08:41 +0200897 }
898 cmb_data = cdev->private->cmb;
899 mba = mme ? (unsigned long) cmbe_align(cmb_data->hw_block) : 0;
900 spin_unlock_irqrestore(cdev->ccwlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901
902 return set_schib_wait(cdev, mme, 1, mba);
903}
904
905
Cornelia Huckfc5019c2007-10-12 16:11:15 +0200906static u64 read_cmbe(struct ccw_device *cdev, int index)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907{
Cornelia Huck94bb0632006-06-29 15:08:41 +0200908 struct cmbe *cmb;
909 struct cmb_data *cmb_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910 u32 val;
Cornelia Huck94bb0632006-06-29 15:08:41 +0200911 int ret;
912 unsigned long flags;
913
914 ret = cmf_cmb_copy_wait(cdev);
915 if (ret < 0)
916 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917
918 spin_lock_irqsave(cdev->ccwlock, flags);
Cornelia Huck94bb0632006-06-29 15:08:41 +0200919 cmb_data = cdev->private->cmb;
920 if (!cmb_data) {
921 ret = 0;
922 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923 }
Cornelia Huck94bb0632006-06-29 15:08:41 +0200924 cmb = cmb_data->last_block;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925
926 switch (index) {
927 case cmb_ssch_rsch_count:
Cornelia Huck94bb0632006-06-29 15:08:41 +0200928 ret = cmb->ssch_rsch_count;
929 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930 case cmb_sample_count:
Cornelia Huck94bb0632006-06-29 15:08:41 +0200931 ret = cmb->sample_count;
932 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933 case cmb_device_connect_time:
Cornelia Huck94bb0632006-06-29 15:08:41 +0200934 val = cmb->device_connect_time;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935 break;
936 case cmb_function_pending_time:
Cornelia Huck94bb0632006-06-29 15:08:41 +0200937 val = cmb->function_pending_time;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938 break;
939 case cmb_device_disconnect_time:
Cornelia Huck94bb0632006-06-29 15:08:41 +0200940 val = cmb->device_disconnect_time;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941 break;
942 case cmb_control_unit_queuing_time:
Cornelia Huck94bb0632006-06-29 15:08:41 +0200943 val = cmb->control_unit_queuing_time;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944 break;
945 case cmb_device_active_only_time:
Cornelia Huck94bb0632006-06-29 15:08:41 +0200946 val = cmb->device_active_only_time;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947 break;
948 case cmb_device_busy_time:
Cornelia Huck94bb0632006-06-29 15:08:41 +0200949 val = cmb->device_busy_time;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950 break;
951 case cmb_initial_command_response_time:
Cornelia Huck94bb0632006-06-29 15:08:41 +0200952 val = cmb->initial_command_response_time;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953 break;
954 default:
Cornelia Huck94bb0632006-06-29 15:08:41 +0200955 ret = 0;
956 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957 }
Cornelia Huck94bb0632006-06-29 15:08:41 +0200958 ret = time_to_avg_nsec(val, cmb->sample_count);
959out:
960 spin_unlock_irqrestore(cdev->ccwlock, flags);
961 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962}
963
Cornelia Huckfc5019c2007-10-12 16:11:15 +0200964static int readall_cmbe(struct ccw_device *cdev, struct cmbdata *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965{
Cornelia Huck94bb0632006-06-29 15:08:41 +0200966 struct cmbe *cmb;
967 struct cmb_data *cmb_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968 u64 time;
Cornelia Huck94bb0632006-06-29 15:08:41 +0200969 unsigned long flags;
970 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971
Cornelia Huck94bb0632006-06-29 15:08:41 +0200972 ret = cmf_cmb_copy_wait(cdev);
973 if (ret < 0)
974 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975 spin_lock_irqsave(cdev->ccwlock, flags);
Cornelia Huck94bb0632006-06-29 15:08:41 +0200976 cmb_data = cdev->private->cmb;
977 if (!cmb_data) {
978 ret = -ENODEV;
979 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980 }
Cornelia Huck94bb0632006-06-29 15:08:41 +0200981 if (cmb_data->last_update == 0) {
982 ret = -EAGAIN;
983 goto out;
984 }
985 time = cmb_data->last_update - cdev->private->cmb_start_time;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986
987 memset (data, 0, sizeof(struct cmbdata));
988
989 /* we only know values before device_busy_time */
990 data->size = offsetof(struct cmbdata, device_busy_time);
991
992 /* conver to nanoseconds */
993 data->elapsed_time = (time * 1000) >> 12;
994
Cornelia Huck94bb0632006-06-29 15:08:41 +0200995 cmb = cmb_data->last_block;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996 /* copy data to new structure */
Cornelia Huck94bb0632006-06-29 15:08:41 +0200997 data->ssch_rsch_count = cmb->ssch_rsch_count;
998 data->sample_count = cmb->sample_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999
1000 /* time fields are converted to nanoseconds while copying */
Cornelia Huck94bb0632006-06-29 15:08:41 +02001001 data->device_connect_time = time_to_nsec(cmb->device_connect_time);
1002 data->function_pending_time = time_to_nsec(cmb->function_pending_time);
1003 data->device_disconnect_time =
1004 time_to_nsec(cmb->device_disconnect_time);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005 data->control_unit_queuing_time
Cornelia Huck94bb0632006-06-29 15:08:41 +02001006 = time_to_nsec(cmb->control_unit_queuing_time);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007 data->device_active_only_time
Cornelia Huck94bb0632006-06-29 15:08:41 +02001008 = time_to_nsec(cmb->device_active_only_time);
1009 data->device_busy_time = time_to_nsec(cmb->device_busy_time);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010 data->initial_command_response_time
Cornelia Huck94bb0632006-06-29 15:08:41 +02001011 = time_to_nsec(cmb->initial_command_response_time);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012
Cornelia Huck94bb0632006-06-29 15:08:41 +02001013 ret = 0;
1014out:
1015 spin_unlock_irqrestore(cdev->ccwlock, flags);
1016 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017}
1018
Cornelia Huck94bb0632006-06-29 15:08:41 +02001019static void reset_cmbe(struct ccw_device *cdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020{
Cornelia Huck94bb0632006-06-29 15:08:41 +02001021 cmf_generic_reset(cdev);
1022}
1023
1024static void * align_cmbe(void *area)
1025{
1026 return cmbe_align(area);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027}
1028
1029static struct attribute_group cmf_attr_group_ext;
1030
1031static struct cmb_operations cmbops_extended = {
1032 .alloc = alloc_cmbe,
1033 .free = free_cmbe,
1034 .set = set_cmbe,
1035 .read = read_cmbe,
1036 .readall = readall_cmbe,
1037 .reset = reset_cmbe,
Cornelia Huck94bb0632006-06-29 15:08:41 +02001038 .align = align_cmbe,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039 .attr_group = &cmf_attr_group_ext,
1040};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041
Cornelia Huckfc5019c2007-10-12 16:11:15 +02001042static ssize_t cmb_show_attr(struct device *dev, char *buf, enum cmb_index idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043{
1044 return sprintf(buf, "%lld\n",
1045 (unsigned long long) cmf_read(to_ccwdev(dev), idx));
1046}
1047
Cornelia Huckfc5019c2007-10-12 16:11:15 +02001048static ssize_t cmb_show_avg_sample_interval(struct device *dev,
1049 struct device_attribute *attr,
1050 char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051{
1052 struct ccw_device *cdev;
1053 long interval;
1054 unsigned long count;
Cornelia Huck94bb0632006-06-29 15:08:41 +02001055 struct cmb_data *cmb_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056
1057 cdev = to_ccwdev(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058 count = cmf_read(cdev, cmb_sample_count);
Cornelia Huck94bb0632006-06-29 15:08:41 +02001059 spin_lock_irq(cdev->ccwlock);
1060 cmb_data = cdev->private->cmb;
1061 if (count) {
1062 interval = cmb_data->last_update -
1063 cdev->private->cmb_start_time;
Cornelia Huck13ffa922006-07-17 16:09:28 +02001064 interval = (interval * 1000) >> 12;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065 interval /= count;
Cornelia Huck94bb0632006-06-29 15:08:41 +02001066 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067 interval = -1;
Cornelia Huck94bb0632006-06-29 15:08:41 +02001068 spin_unlock_irq(cdev->ccwlock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069 return sprintf(buf, "%ld\n", interval);
1070}
1071
Cornelia Huckfc5019c2007-10-12 16:11:15 +02001072static ssize_t cmb_show_avg_utilization(struct device *dev,
1073 struct device_attribute *attr,
1074 char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075{
1076 struct cmbdata data;
1077 u64 utilization;
1078 unsigned long t, u;
1079 int ret;
1080
1081 ret = cmf_readall(to_ccwdev(dev), &data);
Cornelia Huck94bb0632006-06-29 15:08:41 +02001082 if (ret == -EAGAIN || ret == -ENODEV)
1083 /* No data (yet/currently) available to use for calculation. */
1084 return sprintf(buf, "n/a\n");
1085 else if (ret)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086 return ret;
1087
1088 utilization = data.device_connect_time +
1089 data.function_pending_time +
1090 data.device_disconnect_time;
1091
1092 /* shift to avoid long long division */
1093 while (-1ul < (data.elapsed_time | utilization)) {
1094 utilization >>= 8;
1095 data.elapsed_time >>= 8;
1096 }
1097
1098 /* calculate value in 0.1 percent units */
1099 t = (unsigned long) data.elapsed_time / 1000;
1100 u = (unsigned long) utilization / t;
1101
1102 return sprintf(buf, "%02ld.%01ld%%\n", u/ 10, u - (u/ 10) * 10);
1103}
1104
1105#define cmf_attr(name) \
Cornelia Huckfc5019c2007-10-12 16:11:15 +02001106static ssize_t show_##name(struct device *dev, \
1107 struct device_attribute *attr, char *buf) \
1108{ return cmb_show_attr((dev), buf, cmb_##name); } \
1109static DEVICE_ATTR(name, 0444, show_##name, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110
1111#define cmf_attr_avg(name) \
Cornelia Huckfc5019c2007-10-12 16:11:15 +02001112static ssize_t show_avg_##name(struct device *dev, \
1113 struct device_attribute *attr, char *buf) \
1114{ return cmb_show_attr((dev), buf, cmb_##name); } \
1115static DEVICE_ATTR(avg_##name, 0444, show_avg_##name, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116
1117cmf_attr(ssch_rsch_count);
1118cmf_attr(sample_count);
1119cmf_attr_avg(device_connect_time);
1120cmf_attr_avg(function_pending_time);
1121cmf_attr_avg(device_disconnect_time);
1122cmf_attr_avg(control_unit_queuing_time);
1123cmf_attr_avg(device_active_only_time);
1124cmf_attr_avg(device_busy_time);
1125cmf_attr_avg(initial_command_response_time);
1126
Cornelia Huckfc5019c2007-10-12 16:11:15 +02001127static DEVICE_ATTR(avg_sample_interval, 0444, cmb_show_avg_sample_interval,
1128 NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129static DEVICE_ATTR(avg_utilization, 0444, cmb_show_avg_utilization, NULL);
1130
1131static struct attribute *cmf_attributes[] = {
1132 &dev_attr_avg_sample_interval.attr,
1133 &dev_attr_avg_utilization.attr,
1134 &dev_attr_ssch_rsch_count.attr,
1135 &dev_attr_sample_count.attr,
1136 &dev_attr_avg_device_connect_time.attr,
1137 &dev_attr_avg_function_pending_time.attr,
1138 &dev_attr_avg_device_disconnect_time.attr,
1139 &dev_attr_avg_control_unit_queuing_time.attr,
1140 &dev_attr_avg_device_active_only_time.attr,
Heiko Carstensd2c993d2006-07-12 16:41:55 +02001141 NULL,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142};
1143
1144static struct attribute_group cmf_attr_group = {
1145 .name = "cmf",
1146 .attrs = cmf_attributes,
1147};
1148
1149static struct attribute *cmf_attributes_ext[] = {
1150 &dev_attr_avg_sample_interval.attr,
1151 &dev_attr_avg_utilization.attr,
1152 &dev_attr_ssch_rsch_count.attr,
1153 &dev_attr_sample_count.attr,
1154 &dev_attr_avg_device_connect_time.attr,
1155 &dev_attr_avg_function_pending_time.attr,
1156 &dev_attr_avg_device_disconnect_time.attr,
1157 &dev_attr_avg_control_unit_queuing_time.attr,
1158 &dev_attr_avg_device_active_only_time.attr,
1159 &dev_attr_avg_device_busy_time.attr,
1160 &dev_attr_avg_initial_command_response_time.attr,
Heiko Carstensd2c993d2006-07-12 16:41:55 +02001161 NULL,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162};
1163
1164static struct attribute_group cmf_attr_group_ext = {
1165 .name = "cmf",
1166 .attrs = cmf_attributes_ext,
1167};
1168
Cornelia Huckfc5019c2007-10-12 16:11:15 +02001169static ssize_t cmb_enable_show(struct device *dev,
1170 struct device_attribute *attr,
1171 char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001172{
1173 return sprintf(buf, "%d\n", to_ccwdev(dev)->private->cmb ? 1 : 0);
1174}
1175
Cornelia Huckfc5019c2007-10-12 16:11:15 +02001176static ssize_t cmb_enable_store(struct device *dev,
1177 struct device_attribute *attr, const char *buf,
1178 size_t c)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179{
1180 struct ccw_device *cdev;
1181 int ret;
Cornelia Huck2f972202008-04-30 13:38:33 +02001182 unsigned long val;
1183
1184 ret = strict_strtoul(buf, 16, &val);
1185 if (ret)
1186 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001187
1188 cdev = to_ccwdev(dev);
1189
Cornelia Huck2f972202008-04-30 13:38:33 +02001190 switch (val) {
1191 case 0:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192 ret = disable_cmf(cdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001193 break;
Cornelia Huck2f972202008-04-30 13:38:33 +02001194 case 1:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195 ret = enable_cmf(cdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001196 break;
1197 }
1198
1199 return c;
1200}
1201
1202DEVICE_ATTR(cmb_enable, 0644, cmb_enable_show, cmb_enable_store);
1203
Cornelia Huckc0208712007-10-12 16:11:16 +02001204/**
1205 * enable_cmf() - switch on the channel measurement for a specific device
1206 * @cdev: The ccw device to be enabled
1207 *
1208 * Returns %0 for success or a negative error value.
1209 *
1210 * Context:
1211 * non-atomic
1212 */
Cornelia Huckfc5019c2007-10-12 16:11:15 +02001213int enable_cmf(struct ccw_device *cdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001214{
1215 int ret;
1216
1217 ret = cmbops->alloc(cdev);
1218 cmbops->reset(cdev);
1219 if (ret)
1220 return ret;
1221 ret = cmbops->set(cdev, 2);
1222 if (ret) {
1223 cmbops->free(cdev);
1224 return ret;
1225 }
1226 ret = sysfs_create_group(&cdev->dev.kobj, cmbops->attr_group);
1227 if (!ret)
1228 return 0;
1229 cmbops->set(cdev, 0); //FIXME: this can fail
1230 cmbops->free(cdev);
1231 return ret;
1232}
1233
Cornelia Huckc0208712007-10-12 16:11:16 +02001234/**
1235 * disable_cmf() - switch off the channel measurement for a specific device
1236 * @cdev: The ccw device to be disabled
1237 *
1238 * Returns %0 for success or a negative error value.
1239 *
1240 * Context:
1241 * non-atomic
1242 */
Cornelia Huckfc5019c2007-10-12 16:11:15 +02001243int disable_cmf(struct ccw_device *cdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244{
1245 int ret;
1246
1247 ret = cmbops->set(cdev, 0);
1248 if (ret)
1249 return ret;
1250 cmbops->free(cdev);
1251 sysfs_remove_group(&cdev->dev.kobj, cmbops->attr_group);
1252 return ret;
1253}
1254
Cornelia Huckc0208712007-10-12 16:11:16 +02001255/**
1256 * cmf_read() - read one value from the current channel measurement block
1257 * @cdev: the channel to be read
1258 * @index: the index of the value to be read
1259 *
1260 * Returns the value read or %0 if the value cannot be read.
1261 *
1262 * Context:
1263 * any
1264 */
Cornelia Huckfc5019c2007-10-12 16:11:15 +02001265u64 cmf_read(struct ccw_device *cdev, int index)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001266{
1267 return cmbops->read(cdev, index);
1268}
1269
Cornelia Huckc0208712007-10-12 16:11:16 +02001270/**
1271 * cmf_readall() - read the current channel measurement block
1272 * @cdev: the channel to be read
1273 * @data: a pointer to a data block that will be filled
1274 *
1275 * Returns %0 on success, a negative error value otherwise.
1276 *
1277 * Context:
1278 * any
1279 */
Cornelia Huckfc5019c2007-10-12 16:11:15 +02001280int cmf_readall(struct ccw_device *cdev, struct cmbdata *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001281{
1282 return cmbops->readall(cdev, data);
1283}
1284
Cornelia Huck94bb0632006-06-29 15:08:41 +02001285/* Reenable cmf when a disconnected device becomes available again. */
1286int cmf_reenable(struct ccw_device *cdev)
1287{
1288 cmbops->reset(cdev);
1289 return cmbops->set(cdev, 2);
1290}
1291
Cornelia Huckfc5019c2007-10-12 16:11:15 +02001292static int __init init_cmf(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001293{
1294 char *format_string;
1295 char *detect_string = "parameter";
1296
Cornelia Huckfc5019c2007-10-12 16:11:15 +02001297 /*
1298 * If the user did not give a parameter, see if we are running on a
1299 * machine supporting extended measurement blocks, otherwise fall back
1300 * to basic mode.
1301 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302 if (format == CMF_AUTODETECT) {
Cornelia Huck75784c02008-07-14 09:58:57 +02001303 if (!css_general_characteristics.ext_mb) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001304 format = CMF_BASIC;
1305 } else {
1306 format = CMF_EXTENDED;
1307 }
1308 detect_string = "autodetected";
1309 } else {
1310 detect_string = "parameter";
1311 }
1312
1313 switch (format) {
1314 case CMF_BASIC:
1315 format_string = "basic";
1316 cmbops = &cmbops_basic;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317 break;
1318 case CMF_EXTENDED:
Cornelia Huckfc5019c2007-10-12 16:11:15 +02001319 format_string = "extended";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320 cmbops = &cmbops_extended;
1321 break;
1322 default:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323 return 1;
1324 }
1325
Cornelia Hucke556bbb2007-07-27 12:29:19 +02001326 printk(KERN_INFO "cio: Channel measurement facility using %s "
1327 "format (%s)\n", format_string, detect_string);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328 return 0;
1329}
1330
1331module_init(init_cmf);
1332
1333
1334MODULE_AUTHOR("Arnd Bergmann <arndb@de.ibm.com>");
1335MODULE_LICENSE("GPL");
1336MODULE_DESCRIPTION("channel measurement facility base driver\n"
1337 "Copyright 2003 IBM Corporation\n");
1338
1339EXPORT_SYMBOL_GPL(enable_cmf);
1340EXPORT_SYMBOL_GPL(disable_cmf);
1341EXPORT_SYMBOL_GPL(cmf_read);
1342EXPORT_SYMBOL_GPL(cmf_readall);