Commit | Line | Data |
---|---|---|
724117b7 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
1da177e4 | 2 | /* |
1da177e4 LT |
3 | * Linux on zSeries Channel Measurement Facility support |
4 | * | |
a53c8fab | 5 | * Copyright IBM Corp. 2000, 2006 |
1da177e4 | 6 | * |
94bb0633 CH |
7 | * Authors: Arnd Bergmann <arndb@de.ibm.com> |
8 | * Cornelia Huck <cornelia.huck@de.ibm.com> | |
1da177e4 LT |
9 | * |
10 | * original idea from Natarajan Krishnaswami <nkrishna@us.ibm.com> | |
1da177e4 LT |
11 | */ |
12 | ||
e6d5a428 ME |
13 | #define KMSG_COMPONENT "cio" |
14 | #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt | |
15 | ||
57c8a661 | 16 | #include <linux/memblock.h> |
1da177e4 LT |
17 | #include <linux/device.h> |
18 | #include <linux/init.h> | |
19 | #include <linux/list.h> | |
a00f761f | 20 | #include <linux/export.h> |
1da177e4 | 21 | #include <linux/moduleparam.h> |
4e57b681 | 22 | #include <linux/slab.h> |
1aae0560 | 23 | #include <linux/timex.h> /* get_tod_clock() */ |
1da177e4 LT |
24 | |
25 | #include <asm/ccwdev.h> | |
26 | #include <asm/cio.h> | |
27 | #include <asm/cmb.h> | |
4e57b681 | 28 | #include <asm/div64.h> |
1da177e4 LT |
29 | |
30 | #include "cio.h" | |
31 | #include "css.h" | |
32 | #include "device.h" | |
33 | #include "ioasm.h" | |
34 | #include "chsc.h" | |
35 | ||
fc5019c5 CH |
36 | /* |
37 | * parameter to enable cmf during boot, possible uses are: | |
1da177e4 LT |
38 | * "s390cmf" -- enable cmf and allocate 2 MB of ram so measuring can be |
39 | * used on any subchannel | |
40 | * "s390cmf=<num>" -- enable cmf and allocate enough memory to measure | |
41 | * <num> subchannel, where <num> is an integer | |
42 | * between 1 and 65535, default is 1024 | |
43 | */ | |
44 | #define ARGSTRING "s390cmf" | |
45 | ||
46 | /* indices for READCMB */ | |
47 | enum cmb_index { | |
cb09b356 | 48 | avg_utilization = -1, |
1da177e4 | 49 | /* basic and exended format: */ |
cb09b356 | 50 | cmb_ssch_rsch_count = 0, |
1da177e4 LT |
51 | cmb_sample_count, |
52 | cmb_device_connect_time, | |
53 | cmb_function_pending_time, | |
54 | cmb_device_disconnect_time, | |
55 | cmb_control_unit_queuing_time, | |
56 | cmb_device_active_only_time, | |
57 | /* extended format only: */ | |
58 | cmb_device_busy_time, | |
59 | cmb_initial_command_response_time, | |
60 | }; | |
61 | ||
62 | /** | |
63 | * enum cmb_format - types of supported measurement block formats | |
64 | * | |
65 | * @CMF_BASIC: traditional channel measurement blocks supported | |
c0208716 | 66 | * by all machines that we run on |
1da177e4 | 67 | * @CMF_EXTENDED: improved format that was introduced with the z990 |
c0208716 CH |
68 | * machine |
69 | * @CMF_AUTODETECT: default: use extended format when running on a machine | |
70 | * supporting extended format, otherwise fall back to | |
71 | * basic format | |
72 | */ | |
1da177e4 LT |
73 | enum cmb_format { |
74 | CMF_BASIC, | |
75 | CMF_EXTENDED, | |
76 | CMF_AUTODETECT = -1, | |
77 | }; | |
fc5019c5 | 78 | |
c0208716 | 79 | /* |
1da177e4 LT |
80 | * format - actual format for all measurement blocks |
81 | * | |
82 | * The format module parameter can be set to a value of 0 (zero) | |
83 | * or 1, indicating basic or extended format as described for | |
84 | * enum cmb_format. | |
85 | */ | |
86 | static int format = CMF_AUTODETECT; | |
69116f27 | 87 | module_param(format, bint, 0444); |
1da177e4 LT |
88 | |
89 | /** | |
90 | * struct cmb_operations - functions to use depending on cmb_format | |
91 | * | |
94bb0633 CH |
92 | * Most of these functions operate on a struct ccw_device. There is only |
93 | * one instance of struct cmb_operations because the format of the measurement | |
94 | * data is guaranteed to be the same for every ccw_device. | |
1da177e4 LT |
95 | * |
96 | * @alloc: allocate memory for a channel measurement block, | |
97 | * either with the help of a special pool or with kmalloc | |
98 | * @free: free memory allocated with @alloc | |
99 | * @set: enable or disable measurement | |
c0208716 | 100 | * @read: read a measurement entry at an index |
1da177e4 LT |
101 | * @readall: read a measurement block in a common format |
102 | * @reset: clear the data in the associated measurement block and | |
103 | * reset its time stamp | |
104 | */ | |
105 | struct cmb_operations { | |
fc5019c5 CH |
106 | int (*alloc) (struct ccw_device *); |
107 | void (*free) (struct ccw_device *); | |
108 | int (*set) (struct ccw_device *, u32); | |
109 | u64 (*read) (struct ccw_device *, int); | |
110 | int (*readall)(struct ccw_device *, struct cmbdata *); | |
111 | void (*reset) (struct ccw_device *); | |
c0208716 | 112 | /* private: */ |
1da177e4 LT |
113 | struct attribute_group *attr_group; |
114 | }; | |
115 | static struct cmb_operations *cmbops; | |
116 | ||
94bb0633 CH |
117 | struct cmb_data { |
118 | void *hw_block; /* Pointer to block updated by hardware */ | |
119 | void *last_block; /* Last changed block copied from hardware block */ | |
120 | int size; /* Size of hw_block and last_block */ | |
121 | unsigned long long last_update; /* when last_block was updated */ | |
122 | }; | |
123 | ||
fc5019c5 CH |
124 | /* |
125 | * Our user interface is designed in terms of nanoseconds, | |
1da177e4 | 126 | * while the hardware measures total times in its own |
fc5019c5 CH |
127 | * unit. |
128 | */ | |
1da177e4 LT |
129 | static inline u64 time_to_nsec(u32 value) |
130 | { | |
131 | return ((u64)value) * 128000ull; | |
132 | } | |
133 | ||
134 | /* | |
135 | * Users are usually interested in average times, | |
136 | * not accumulated time. | |
137 | * This also helps us with atomicity problems | |
138 | * when reading sinlge values. | |
139 | */ | |
140 | static inline u64 time_to_avg_nsec(u32 value, u32 count) | |
141 | { | |
142 | u64 ret; | |
143 | ||
144 | /* no samples yet, avoid division by 0 */ | |
145 | if (count == 0) | |
146 | return 0; | |
147 | ||
96de0e25 | 148 | /* value comes in units of 128 µsec */ |
1da177e4 LT |
149 | ret = time_to_nsec(value); |
150 | do_div(ret, count); | |
151 | ||
152 | return ret; | |
153 | } | |
154 | ||
7b4ff87c HC |
155 | #define CMF_OFF 0 |
156 | #define CMF_ON 2 | |
157 | ||
fc5019c5 CH |
158 | /* |
159 | * Activate or deactivate the channel monitor. When area is NULL, | |
1da177e4 LT |
160 | * the monitor is deactivated. The channel monitor needs to |
161 | * be active in order to measure subchannels, which also need | |
fc5019c5 CH |
162 | * to be enabled. |
163 | */ | |
164 | static inline void cmf_activate(void *area, unsigned int onoff) | |
1da177e4 | 165 | { |
1da177e4 | 166 | /* activate channel measurement */ |
6d7c628b HC |
167 | asm volatile( |
168 | " lgr 1,%[r1]\n" | |
169 | " lgr 2,%[mbo]\n" | |
170 | " schm\n" | |
171 | : | |
14edd0d7 HC |
172 | : [r1] "d" ((unsigned long)onoff), |
173 | [mbo] "d" (virt_to_phys(area)) | |
6d7c628b | 174 | : "1", "2"); |
1da177e4 LT |
175 | } |
176 | ||
fc5019c5 CH |
177 | static int set_schib(struct ccw_device *cdev, u32 mme, int mbfc, |
178 | unsigned long address) | |
1da177e4 | 179 | { |
a6ef1565 SO |
180 | struct subchannel *sch = to_subchannel(cdev->dev.parent); |
181 | int ret; | |
1da177e4 | 182 | |
13952ec1 SO |
183 | sch->config.mme = mme; |
184 | sch->config.mbfc = mbfc; | |
185 | /* address can be either a block address or a block index */ | |
186 | if (mbfc) | |
187 | sch->config.mba = address; | |
188 | else | |
189 | sch->config.mbi = address; | |
1da177e4 | 190 | |
a6ef1565 SO |
191 | ret = cio_commit_config(sch); |
192 | if (!mme && ret == -ENODEV) { | |
193 | /* | |
194 | * The task was to disable measurement block updates but | |
195 | * the subchannel is already gone. Report success. | |
196 | */ | |
197 | ret = 0; | |
198 | } | |
199 | return ret; | |
1da177e4 LT |
200 | } |
201 | ||
202 | struct set_schib_struct { | |
203 | u32 mme; | |
204 | int mbfc; | |
205 | unsigned long address; | |
206 | wait_queue_head_t wait; | |
207 | int ret; | |
208 | }; | |
209 | ||
94bb0633 | 210 | #define CMF_PENDING 1 |
adc69b4d | 211 | #define SET_SCHIB_TIMEOUT (10 * HZ) |
94bb0633 | 212 | |
1da177e4 | 213 | static int set_schib_wait(struct ccw_device *cdev, u32 mme, |
eeec1e43 | 214 | int mbfc, unsigned long address) |
1da177e4 | 215 | { |
eeec1e43 SO |
216 | struct set_schib_struct set_data; |
217 | int ret = -ENODEV; | |
1da177e4 LT |
218 | |
219 | spin_lock_irq(cdev->ccwlock); | |
eeec1e43 | 220 | if (!cdev->private->cmb) |
94bb0633 | 221 | goto out; |
94bb0633 CH |
222 | |
223 | ret = set_schib(cdev, mme, mbfc, address); | |
224 | if (ret != -EBUSY) | |
eeec1e43 | 225 | goto out; |
1da177e4 | 226 | |
eeec1e43 SO |
227 | /* if the device is not online, don't even try again */ |
228 | if (cdev->private->state != DEV_STATE_ONLINE) | |
229 | goto out; | |
230 | ||
231 | init_waitqueue_head(&set_data.wait); | |
232 | set_data.mme = mme; | |
233 | set_data.mbfc = mbfc; | |
234 | set_data.address = address; | |
235 | set_data.ret = CMF_PENDING; | |
94bb0633 | 236 | |
1da177e4 | 237 | cdev->private->state = DEV_STATE_CMFCHANGE; |
eeec1e43 | 238 | cdev->private->cmb_wait = &set_data; |
1da177e4 | 239 | spin_unlock_irq(cdev->ccwlock); |
adc69b4d | 240 | |
eeec1e43 SO |
241 | ret = wait_event_interruptible_timeout(set_data.wait, |
242 | set_data.ret != CMF_PENDING, | |
adc69b4d SO |
243 | SET_SCHIB_TIMEOUT); |
244 | spin_lock_irq(cdev->ccwlock); | |
245 | if (ret <= 0) { | |
eeec1e43 SO |
246 | if (set_data.ret == CMF_PENDING) { |
247 | set_data.ret = (ret == 0) ? -ETIME : ret; | |
1da177e4 LT |
248 | if (cdev->private->state == DEV_STATE_CMFCHANGE) |
249 | cdev->private->state = DEV_STATE_ONLINE; | |
250 | } | |
1da177e4 | 251 | } |
94bb0633 | 252 | cdev->private->cmb_wait = NULL; |
eeec1e43 | 253 | ret = set_data.ret; |
94bb0633 | 254 | out: |
1da177e4 | 255 | spin_unlock_irq(cdev->ccwlock); |
94bb0633 | 256 | return ret; |
1da177e4 LT |
257 | } |
258 | ||
259 | void retry_set_schib(struct ccw_device *cdev) | |
260 | { | |
eeec1e43 | 261 | struct set_schib_struct *set_data = cdev->private->cmb_wait; |
94bb0633 | 262 | |
eeec1e43 | 263 | if (!set_data) |
94bb0633 | 264 | return; |
eeec1e43 | 265 | |
94bb0633 CH |
266 | set_data->ret = set_schib(cdev, set_data->mme, set_data->mbfc, |
267 | set_data->address); | |
268 | wake_up(&set_data->wait); | |
94bb0633 CH |
269 | } |
270 | ||
271 | static int cmf_copy_block(struct ccw_device *cdev) | |
272 | { | |
81b050b5 | 273 | struct subchannel *sch = to_subchannel(cdev->dev.parent); |
94bb0633 | 274 | struct cmb_data *cmb_data; |
81b050b5 | 275 | void *hw_block; |
94bb0633 | 276 | |
cdb912a4 | 277 | if (cio_update_schib(sch)) |
94bb0633 CH |
278 | return -ENODEV; |
279 | ||
23d805b6 | 280 | if (scsw_fctl(&sch->schib.scsw) & SCSW_FCTL_START_FUNC) { |
94bb0633 | 281 | /* Don't copy if a start function is in progress. */ |
23d805b6 PO |
282 | if ((!(scsw_actl(&sch->schib.scsw) & SCSW_ACTL_SUSPENDED)) && |
283 | (scsw_actl(&sch->schib.scsw) & | |
94bb0633 | 284 | (SCSW_ACTL_DEVACT | SCSW_ACTL_SCHACT)) && |
23d805b6 | 285 | (!(scsw_stctl(&sch->schib.scsw) & SCSW_STCTL_SEC_STATUS))) |
94bb0633 CH |
286 | return -EBUSY; |
287 | } | |
288 | cmb_data = cdev->private->cmb; | |
45bf4b96 | 289 | hw_block = cmb_data->hw_block; |
81b050b5 | 290 | memcpy(cmb_data->last_block, hw_block, cmb_data->size); |
1aae0560 | 291 | cmb_data->last_update = get_tod_clock(); |
94bb0633 CH |
292 | return 0; |
293 | } | |
294 | ||
295 | struct copy_block_struct { | |
296 | wait_queue_head_t wait; | |
297 | int ret; | |
94bb0633 CH |
298 | }; |
299 | ||
94bb0633 CH |
300 | static int cmf_cmb_copy_wait(struct ccw_device *cdev) |
301 | { | |
60f3eac3 SO |
302 | struct copy_block_struct copy_block; |
303 | int ret = -ENODEV; | |
94bb0633 | 304 | |
60f3eac3 SO |
305 | spin_lock_irq(cdev->ccwlock); |
306 | if (!cdev->private->cmb) | |
94bb0633 | 307 | goto out; |
94bb0633 CH |
308 | |
309 | ret = cmf_copy_block(cdev); | |
310 | if (ret != -EBUSY) | |
60f3eac3 | 311 | goto out; |
94bb0633 | 312 | |
60f3eac3 SO |
313 | if (cdev->private->state != DEV_STATE_ONLINE) |
314 | goto out; | |
315 | ||
316 | init_waitqueue_head(©_block.wait); | |
317 | copy_block.ret = CMF_PENDING; | |
94bb0633 CH |
318 | |
319 | cdev->private->state = DEV_STATE_CMFUPDATE; | |
60f3eac3 SO |
320 | cdev->private->cmb_wait = ©_block; |
321 | spin_unlock_irq(cdev->ccwlock); | |
322 | ||
323 | ret = wait_event_interruptible(copy_block.wait, | |
324 | copy_block.ret != CMF_PENDING); | |
325 | spin_lock_irq(cdev->ccwlock); | |
326 | if (ret) { | |
327 | if (copy_block.ret == CMF_PENDING) { | |
328 | copy_block.ret = -ERESTARTSYS; | |
94bb0633 CH |
329 | if (cdev->private->state == DEV_STATE_CMFUPDATE) |
330 | cdev->private->state = DEV_STATE_ONLINE; | |
331 | } | |
94bb0633 | 332 | } |
94bb0633 | 333 | cdev->private->cmb_wait = NULL; |
60f3eac3 | 334 | ret = copy_block.ret; |
94bb0633 | 335 | out: |
60f3eac3 | 336 | spin_unlock_irq(cdev->ccwlock); |
94bb0633 CH |
337 | return ret; |
338 | } | |
339 | ||
340 | void cmf_retry_copy_block(struct ccw_device *cdev) | |
341 | { | |
60f3eac3 | 342 | struct copy_block_struct *copy_block = cdev->private->cmb_wait; |
1da177e4 | 343 | |
60f3eac3 | 344 | if (!copy_block) |
1da177e4 | 345 | return; |
60f3eac3 | 346 | |
94bb0633 CH |
347 | copy_block->ret = cmf_copy_block(cdev); |
348 | wake_up(©_block->wait); | |
94bb0633 CH |
349 | } |
350 | ||
351 | static void cmf_generic_reset(struct ccw_device *cdev) | |
352 | { | |
353 | struct cmb_data *cmb_data; | |
354 | ||
355 | spin_lock_irq(cdev->ccwlock); | |
356 | cmb_data = cdev->private->cmb; | |
357 | if (cmb_data) { | |
358 | memset(cmb_data->last_block, 0, cmb_data->size); | |
359 | /* | |
360 | * Need to reset hw block as well to make the hardware start | |
361 | * from 0 again. | |
362 | */ | |
45bf4b96 | 363 | memset(cmb_data->hw_block, 0, cmb_data->size); |
94bb0633 CH |
364 | cmb_data->last_update = 0; |
365 | } | |
1aae0560 | 366 | cdev->private->cmb_start_time = get_tod_clock(); |
94bb0633 | 367 | spin_unlock_irq(cdev->ccwlock); |
1da177e4 LT |
368 | } |
369 | ||
370 | /** | |
371 | * struct cmb_area - container for global cmb data | |
372 | * | |
373 | * @mem: pointer to CMBs (only in basic measurement mode) | |
374 | * @list: contains a linked list of all subchannels | |
c0208716 | 375 | * @num_channels: number of channels to be measured |
1da177e4 LT |
376 | * @lock: protect concurrent access to @mem and @list |
377 | */ | |
378 | struct cmb_area { | |
379 | struct cmb *mem; | |
380 | struct list_head list; | |
381 | int num_channels; | |
382 | spinlock_t lock; | |
383 | }; | |
384 | ||
385 | static struct cmb_area cmb_area = { | |
cb629a01 | 386 | .lock = __SPIN_LOCK_UNLOCKED(cmb_area.lock), |
1da177e4 LT |
387 | .list = LIST_HEAD_INIT(cmb_area.list), |
388 | .num_channels = 1024, | |
389 | }; | |
390 | ||
1da177e4 LT |
391 | /* ****** old style CMB handling ********/ |
392 | ||
fc5019c5 | 393 | /* |
1da177e4 LT |
394 | * Basic channel measurement blocks are allocated in one contiguous |
395 | * block of memory, which can not be moved as long as any channel | |
396 | * is active. Therefore, a maximum number of subchannels needs to | |
397 | * be defined somewhere. This is a module parameter, defaulting to | |
af901ca1 | 398 | * a reasonable value of 1024, or 32 kb of memory. |
1da177e4 | 399 | * Current kernels don't allow kmalloc with more than 128kb, so the |
fc5019c5 | 400 | * maximum is 4096. |
1da177e4 LT |
401 | */ |
402 | ||
403 | module_param_named(maxchannels, cmb_area.num_channels, uint, 0444); | |
404 | ||
405 | /** | |
406 | * struct cmb - basic channel measurement block | |
c0208716 CH |
407 | * @ssch_rsch_count: number of ssch and rsch |
408 | * @sample_count: number of samples | |
409 | * @device_connect_time: time of device connect | |
410 | * @function_pending_time: time of function pending | |
411 | * @device_disconnect_time: time of device disconnect | |
412 | * @control_unit_queuing_time: time of control unit queuing | |
413 | * @device_active_only_time: time of device active only | |
414 | * @reserved: unused in basic measurement mode | |
415 | * | |
416 | * The measurement block as used by the hardware. The fields are described | |
417 | * further in z/Architecture Principles of Operation, chapter 17. | |
1da177e4 | 418 | * |
c0208716 CH |
419 | * The cmb area made up from these blocks must be a contiguous array and may |
420 | * not be reallocated or freed. | |
1da177e4 LT |
421 | * Only one cmb area can be present in the system. |
422 | */ | |
423 | struct cmb { | |
424 | u16 ssch_rsch_count; | |
425 | u16 sample_count; | |
426 | u32 device_connect_time; | |
427 | u32 function_pending_time; | |
428 | u32 device_disconnect_time; | |
429 | u32 control_unit_queuing_time; | |
430 | u32 device_active_only_time; | |
431 | u32 reserved[2]; | |
432 | }; | |
433 | ||
fc5019c5 CH |
434 | /* |
435 | * Insert a single device into the cmb_area list. | |
436 | * Called with cmb_area.lock held from alloc_cmb. | |
1da177e4 | 437 | */ |
4d284cac HC |
438 | static int alloc_cmb_single(struct ccw_device *cdev, |
439 | struct cmb_data *cmb_data) | |
1da177e4 LT |
440 | { |
441 | struct cmb *cmb; | |
442 | struct ccw_device_private *node; | |
443 | int ret; | |
444 | ||
445 | spin_lock_irq(cdev->ccwlock); | |
446 | if (!list_empty(&cdev->private->cmb_list)) { | |
447 | ret = -EBUSY; | |
448 | goto out; | |
449 | } | |
450 | ||
fc5019c5 CH |
451 | /* |
452 | * Find first unused cmb in cmb_area.mem. | |
453 | * This is a little tricky: cmb_area.list | |
454 | * remains sorted by ->cmb->hw_data pointers. | |
455 | */ | |
1da177e4 LT |
456 | cmb = cmb_area.mem; |
457 | list_for_each_entry(node, &cmb_area.list, cmb_list) { | |
94bb0633 CH |
458 | struct cmb_data *data; |
459 | data = node->cmb; | |
460 | if ((struct cmb*)data->hw_block > cmb) | |
1da177e4 LT |
461 | break; |
462 | cmb++; | |
463 | } | |
464 | if (cmb - cmb_area.mem >= cmb_area.num_channels) { | |
465 | ret = -ENOMEM; | |
466 | goto out; | |
467 | } | |
468 | ||
469 | /* insert new cmb */ | |
470 | list_add_tail(&cdev->private->cmb_list, &node->cmb_list); | |
94bb0633 CH |
471 | cmb_data->hw_block = cmb; |
472 | cdev->private->cmb = cmb_data; | |
1da177e4 LT |
473 | ret = 0; |
474 | out: | |
475 | spin_unlock_irq(cdev->ccwlock); | |
476 | return ret; | |
477 | } | |
478 | ||
fc5019c5 | 479 | static int alloc_cmb(struct ccw_device *cdev) |
1da177e4 LT |
480 | { |
481 | int ret; | |
482 | struct cmb *mem; | |
483 | ssize_t size; | |
94bb0633 CH |
484 | struct cmb_data *cmb_data; |
485 | ||
486 | /* Allocate private cmb_data. */ | |
487 | cmb_data = kzalloc(sizeof(struct cmb_data), GFP_KERNEL); | |
488 | if (!cmb_data) | |
489 | return -ENOMEM; | |
1da177e4 | 490 | |
94bb0633 CH |
491 | cmb_data->last_block = kzalloc(sizeof(struct cmb), GFP_KERNEL); |
492 | if (!cmb_data->last_block) { | |
493 | kfree(cmb_data); | |
494 | return -ENOMEM; | |
495 | } | |
496 | cmb_data->size = sizeof(struct cmb); | |
1da177e4 LT |
497 | spin_lock(&cmb_area.lock); |
498 | ||
499 | if (!cmb_area.mem) { | |
500 | /* there is no user yet, so we need a new area */ | |
501 | size = sizeof(struct cmb) * cmb_area.num_channels; | |
502 | WARN_ON(!list_empty(&cmb_area.list)); | |
503 | ||
504 | spin_unlock(&cmb_area.lock); | |
343c8a56 | 505 | mem = (void *)__get_free_pages(GFP_KERNEL, get_order(size)); |
1da177e4 LT |
506 | spin_lock(&cmb_area.lock); |
507 | ||
508 | if (cmb_area.mem) { | |
509 | /* ok, another thread was faster */ | |
510 | free_pages((unsigned long)mem, get_order(size)); | |
511 | } else if (!mem) { | |
512 | /* no luck */ | |
513 | ret = -ENOMEM; | |
514 | goto out; | |
515 | } else { | |
516 | /* everything ok */ | |
517 | memset(mem, 0, size); | |
518 | cmb_area.mem = mem; | |
7b4ff87c | 519 | cmf_activate(cmb_area.mem, CMF_ON); |
1da177e4 LT |
520 | } |
521 | } | |
522 | ||
523 | /* do the actual allocation */ | |
94bb0633 | 524 | ret = alloc_cmb_single(cdev, cmb_data); |
1da177e4 LT |
525 | out: |
526 | spin_unlock(&cmb_area.lock); | |
94bb0633 CH |
527 | if (ret) { |
528 | kfree(cmb_data->last_block); | |
529 | kfree(cmb_data); | |
530 | } | |
1da177e4 LT |
531 | return ret; |
532 | } | |
533 | ||
94bb0633 | 534 | static void free_cmb(struct ccw_device *cdev) |
1da177e4 LT |
535 | { |
536 | struct ccw_device_private *priv; | |
94bb0633 | 537 | struct cmb_data *cmb_data; |
1da177e4 LT |
538 | |
539 | spin_lock(&cmb_area.lock); | |
540 | spin_lock_irq(cdev->ccwlock); | |
541 | ||
94bb0633 | 542 | priv = cdev->private; |
94bb0633 | 543 | cmb_data = priv->cmb; |
1da177e4 | 544 | priv->cmb = NULL; |
94bb0633 CH |
545 | if (cmb_data) |
546 | kfree(cmb_data->last_block); | |
547 | kfree(cmb_data); | |
1da177e4 LT |
548 | list_del_init(&priv->cmb_list); |
549 | ||
550 | if (list_empty(&cmb_area.list)) { | |
551 | ssize_t size; | |
552 | size = sizeof(struct cmb) * cmb_area.num_channels; | |
7b4ff87c | 553 | cmf_activate(NULL, CMF_OFF); |
1da177e4 LT |
554 | free_pages((unsigned long)cmb_area.mem, get_order(size)); |
555 | cmb_area.mem = NULL; | |
556 | } | |
1da177e4 LT |
557 | spin_unlock_irq(cdev->ccwlock); |
558 | spin_unlock(&cmb_area.lock); | |
559 | } | |
560 | ||
94bb0633 | 561 | static int set_cmb(struct ccw_device *cdev, u32 mme) |
1da177e4 LT |
562 | { |
563 | u16 offset; | |
94bb0633 CH |
564 | struct cmb_data *cmb_data; |
565 | unsigned long flags; | |
1da177e4 | 566 | |
94bb0633 CH |
567 | spin_lock_irqsave(cdev->ccwlock, flags); |
568 | if (!cdev->private->cmb) { | |
569 | spin_unlock_irqrestore(cdev->ccwlock, flags); | |
1da177e4 | 570 | return -EINVAL; |
94bb0633 CH |
571 | } |
572 | cmb_data = cdev->private->cmb; | |
573 | offset = mme ? (struct cmb *)cmb_data->hw_block - cmb_area.mem : 0; | |
574 | spin_unlock_irqrestore(cdev->ccwlock, flags); | |
1da177e4 LT |
575 | |
576 | return set_schib_wait(cdev, mme, 0, offset); | |
577 | } | |
578 | ||
cb09b356 SO |
579 | /* calculate utilization in 0.1 percent units */ |
580 | static u64 __cmb_utilization(u64 device_connect_time, u64 function_pending_time, | |
581 | u64 device_disconnect_time, u64 start_time) | |
582 | { | |
583 | u64 utilization, elapsed_time; | |
584 | ||
585 | utilization = time_to_nsec(device_connect_time + | |
586 | function_pending_time + | |
587 | device_disconnect_time); | |
588 | ||
589 | elapsed_time = get_tod_clock() - start_time; | |
590 | elapsed_time = tod_to_ns(elapsed_time); | |
591 | elapsed_time /= 1000; | |
592 | ||
593 | return elapsed_time ? (utilization / elapsed_time) : 0; | |
594 | } | |
595 | ||
fc5019c5 | 596 | static u64 read_cmb(struct ccw_device *cdev, int index) |
1da177e4 | 597 | { |
d4d287e8 SO |
598 | struct cmb_data *cmb_data; |
599 | unsigned long flags; | |
94bb0633 | 600 | struct cmb *cmb; |
cb09b356 | 601 | u64 ret = 0; |
1da177e4 LT |
602 | u32 val; |
603 | ||
604 | spin_lock_irqsave(cdev->ccwlock, flags); | |
d4d287e8 SO |
605 | cmb_data = cdev->private->cmb; |
606 | if (!cmb_data) | |
94bb0633 | 607 | goto out; |
1da177e4 | 608 | |
d4d287e8 | 609 | cmb = cmb_data->hw_block; |
1da177e4 | 610 | switch (index) { |
cb09b356 SO |
611 | case avg_utilization: |
612 | ret = __cmb_utilization(cmb->device_connect_time, | |
613 | cmb->function_pending_time, | |
614 | cmb->device_disconnect_time, | |
615 | cdev->private->cmb_start_time); | |
616 | goto out; | |
1da177e4 | 617 | case cmb_ssch_rsch_count: |
94bb0633 CH |
618 | ret = cmb->ssch_rsch_count; |
619 | goto out; | |
1da177e4 | 620 | case cmb_sample_count: |
94bb0633 CH |
621 | ret = cmb->sample_count; |
622 | goto out; | |
1da177e4 | 623 | case cmb_device_connect_time: |
94bb0633 | 624 | val = cmb->device_connect_time; |
1da177e4 LT |
625 | break; |
626 | case cmb_function_pending_time: | |
94bb0633 | 627 | val = cmb->function_pending_time; |
1da177e4 LT |
628 | break; |
629 | case cmb_device_disconnect_time: | |
94bb0633 | 630 | val = cmb->device_disconnect_time; |
1da177e4 LT |
631 | break; |
632 | case cmb_control_unit_queuing_time: | |
94bb0633 | 633 | val = cmb->control_unit_queuing_time; |
1da177e4 LT |
634 | break; |
635 | case cmb_device_active_only_time: | |
94bb0633 | 636 | val = cmb->device_active_only_time; |
1da177e4 LT |
637 | break; |
638 | default: | |
94bb0633 | 639 | goto out; |
1da177e4 | 640 | } |
94bb0633 CH |
641 | ret = time_to_avg_nsec(val, cmb->sample_count); |
642 | out: | |
643 | spin_unlock_irqrestore(cdev->ccwlock, flags); | |
644 | return ret; | |
1da177e4 LT |
645 | } |
646 | ||
fc5019c5 | 647 | static int readall_cmb(struct ccw_device *cdev, struct cmbdata *data) |
1da177e4 | 648 | { |
94bb0633 CH |
649 | struct cmb *cmb; |
650 | struct cmb_data *cmb_data; | |
1da177e4 | 651 | u64 time; |
94bb0633 CH |
652 | unsigned long flags; |
653 | int ret; | |
1da177e4 | 654 | |
94bb0633 CH |
655 | ret = cmf_cmb_copy_wait(cdev); |
656 | if (ret < 0) | |
657 | return ret; | |
1da177e4 | 658 | spin_lock_irqsave(cdev->ccwlock, flags); |
94bb0633 CH |
659 | cmb_data = cdev->private->cmb; |
660 | if (!cmb_data) { | |
661 | ret = -ENODEV; | |
662 | goto out; | |
1da177e4 | 663 | } |
94bb0633 CH |
664 | if (cmb_data->last_update == 0) { |
665 | ret = -EAGAIN; | |
666 | goto out; | |
667 | } | |
668 | cmb = cmb_data->last_block; | |
669 | time = cmb_data->last_update - cdev->private->cmb_start_time; | |
1da177e4 LT |
670 | |
671 | memset(data, 0, sizeof(struct cmbdata)); | |
672 | ||
673 | /* we only know values before device_busy_time */ | |
674 | data->size = offsetof(struct cmbdata, device_busy_time); | |
675 | ||
08c6df97 | 676 | data->elapsed_time = tod_to_ns(time); |
1da177e4 LT |
677 | |
678 | /* copy data to new structure */ | |
94bb0633 CH |
679 | data->ssch_rsch_count = cmb->ssch_rsch_count; |
680 | data->sample_count = cmb->sample_count; | |
1da177e4 LT |
681 | |
682 | /* time fields are converted to nanoseconds while copying */ | |
94bb0633 CH |
683 | data->device_connect_time = time_to_nsec(cmb->device_connect_time); |
684 | data->function_pending_time = time_to_nsec(cmb->function_pending_time); | |
685 | data->device_disconnect_time = | |
686 | time_to_nsec(cmb->device_disconnect_time); | |
1da177e4 | 687 | data->control_unit_queuing_time |
94bb0633 | 688 | = time_to_nsec(cmb->control_unit_queuing_time); |
1da177e4 | 689 | data->device_active_only_time |
94bb0633 CH |
690 | = time_to_nsec(cmb->device_active_only_time); |
691 | ret = 0; | |
692 | out: | |
693 | spin_unlock_irqrestore(cdev->ccwlock, flags); | |
694 | return ret; | |
695 | } | |
1da177e4 | 696 | |
94bb0633 CH |
697 | static void reset_cmb(struct ccw_device *cdev) |
698 | { | |
699 | cmf_generic_reset(cdev); | |
1da177e4 LT |
700 | } |
701 | ||
0f5d050c SO |
702 | static int cmf_enabled(struct ccw_device *cdev) |
703 | { | |
704 | int enabled; | |
705 | ||
706 | spin_lock_irq(cdev->ccwlock); | |
707 | enabled = !!cdev->private->cmb; | |
708 | spin_unlock_irq(cdev->ccwlock); | |
709 | ||
710 | return enabled; | |
711 | } | |
712 | ||
1da177e4 LT |
713 | static struct attribute_group cmf_attr_group; |
714 | ||
715 | static struct cmb_operations cmbops_basic = { | |
716 | .alloc = alloc_cmb, | |
717 | .free = free_cmb, | |
718 | .set = set_cmb, | |
719 | .read = read_cmb, | |
720 | .readall = readall_cmb, | |
721 | .reset = reset_cmb, | |
722 | .attr_group = &cmf_attr_group, | |
723 | }; | |
364c8558 | 724 | |
1da177e4 LT |
725 | /* ******** extended cmb handling ********/ |
726 | ||
727 | /** | |
728 | * struct cmbe - extended channel measurement block | |
c0208716 CH |
729 | * @ssch_rsch_count: number of ssch and rsch |
730 | * @sample_count: number of samples | |
731 | * @device_connect_time: time of device connect | |
732 | * @function_pending_time: time of function pending | |
733 | * @device_disconnect_time: time of device disconnect | |
734 | * @control_unit_queuing_time: time of control unit queuing | |
735 | * @device_active_only_time: time of device active only | |
736 | * @device_busy_time: time of device busy | |
737 | * @initial_command_response_time: initial command response time | |
738 | * @reserved: unused | |
1da177e4 | 739 | * |
c0208716 CH |
740 | * The measurement block as used by the hardware. May be in any 64 bit physical |
741 | * location. | |
742 | * The fields are described further in z/Architecture Principles of Operation, | |
1da177e4 LT |
743 | * third edition, chapter 17. |
744 | */ | |
745 | struct cmbe { | |
746 | u32 ssch_rsch_count; | |
747 | u32 sample_count; | |
748 | u32 device_connect_time; | |
749 | u32 function_pending_time; | |
750 | u32 device_disconnect_time; | |
751 | u32 control_unit_queuing_time; | |
752 | u32 device_active_only_time; | |
753 | u32 device_busy_time; | |
754 | u32 initial_command_response_time; | |
755 | u32 reserved[7]; | |
45bf4b96 | 756 | } __packed __aligned(64); |
1da177e4 | 757 | |
45bf4b96 | 758 | static struct kmem_cache *cmbe_cache; |
1da177e4 | 759 | |
fc5019c5 | 760 | static int alloc_cmbe(struct ccw_device *cdev) |
1da177e4 | 761 | { |
94bb0633 | 762 | struct cmb_data *cmb_data; |
616503d1 SO |
763 | struct cmbe *cmbe; |
764 | int ret = -ENOMEM; | |
94bb0633 | 765 | |
45bf4b96 | 766 | cmbe = kmem_cache_zalloc(cmbe_cache, GFP_KERNEL); |
1da177e4 | 767 | if (!cmbe) |
616503d1 SO |
768 | return ret; |
769 | ||
45bf4b96 | 770 | cmb_data = kzalloc(sizeof(*cmb_data), GFP_KERNEL); |
616503d1 | 771 | if (!cmb_data) |
94bb0633 | 772 | goto out_free; |
616503d1 | 773 | |
94bb0633 | 774 | cmb_data->last_block = kzalloc(sizeof(struct cmbe), GFP_KERNEL); |
616503d1 | 775 | if (!cmb_data->last_block) |
94bb0633 | 776 | goto out_free; |
616503d1 | 777 | |
45bf4b96 | 778 | cmb_data->size = sizeof(*cmbe); |
94bb0633 | 779 | cmb_data->hw_block = cmbe; |
616503d1 SO |
780 | |
781 | spin_lock(&cmb_area.lock); | |
782 | spin_lock_irq(cdev->ccwlock); | |
783 | if (cdev->private->cmb) | |
784 | goto out_unlock; | |
785 | ||
94bb0633 | 786 | cdev->private->cmb = cmb_data; |
1da177e4 LT |
787 | |
788 | /* activate global measurement if this is the first channel */ | |
1da177e4 | 789 | if (list_empty(&cmb_area.list)) |
7b4ff87c | 790 | cmf_activate(NULL, CMF_ON); |
1da177e4 | 791 | list_add_tail(&cdev->private->cmb_list, &cmb_area.list); |
1da177e4 | 792 | |
616503d1 SO |
793 | spin_unlock_irq(cdev->ccwlock); |
794 | spin_unlock(&cmb_area.lock); | |
1da177e4 | 795 | return 0; |
616503d1 SO |
796 | |
797 | out_unlock: | |
798 | spin_unlock_irq(cdev->ccwlock); | |
799 | spin_unlock(&cmb_area.lock); | |
800 | ret = -EBUSY; | |
94bb0633 CH |
801 | out_free: |
802 | if (cmb_data) | |
803 | kfree(cmb_data->last_block); | |
804 | kfree(cmb_data); | |
45bf4b96 SO |
805 | kmem_cache_free(cmbe_cache, cmbe); |
806 | ||
94bb0633 | 807 | return ret; |
1da177e4 LT |
808 | } |
809 | ||
fc5019c5 | 810 | static void free_cmbe(struct ccw_device *cdev) |
1da177e4 | 811 | { |
94bb0633 CH |
812 | struct cmb_data *cmb_data; |
813 | ||
616503d1 | 814 | spin_lock(&cmb_area.lock); |
1da177e4 | 815 | spin_lock_irq(cdev->ccwlock); |
94bb0633 | 816 | cmb_data = cdev->private->cmb; |
1da177e4 | 817 | cdev->private->cmb = NULL; |
a5e9ca57 | 818 | if (cmb_data) { |
94bb0633 | 819 | kfree(cmb_data->last_block); |
45bf4b96 | 820 | kmem_cache_free(cmbe_cache, cmb_data->hw_block); |
a5e9ca57 | 821 | } |
94bb0633 | 822 | kfree(cmb_data); |
1da177e4 LT |
823 | |
824 | /* deactivate global measurement if this is the last channel */ | |
1da177e4 LT |
825 | list_del_init(&cdev->private->cmb_list); |
826 | if (list_empty(&cmb_area.list)) | |
7b4ff87c | 827 | cmf_activate(NULL, CMF_OFF); |
616503d1 | 828 | spin_unlock_irq(cdev->ccwlock); |
1da177e4 LT |
829 | spin_unlock(&cmb_area.lock); |
830 | } | |
831 | ||
94bb0633 | 832 | static int set_cmbe(struct ccw_device *cdev, u32 mme) |
1da177e4 LT |
833 | { |
834 | unsigned long mba; | |
94bb0633 CH |
835 | struct cmb_data *cmb_data; |
836 | unsigned long flags; | |
1da177e4 | 837 | |
94bb0633 CH |
838 | spin_lock_irqsave(cdev->ccwlock, flags); |
839 | if (!cdev->private->cmb) { | |
840 | spin_unlock_irqrestore(cdev->ccwlock, flags); | |
1da177e4 | 841 | return -EINVAL; |
94bb0633 CH |
842 | } |
843 | cmb_data = cdev->private->cmb; | |
45bf4b96 | 844 | mba = mme ? (unsigned long) cmb_data->hw_block : 0; |
94bb0633 | 845 | spin_unlock_irqrestore(cdev->ccwlock, flags); |
1da177e4 LT |
846 | |
847 | return set_schib_wait(cdev, mme, 1, mba); | |
848 | } | |
849 | ||
fc5019c5 | 850 | static u64 read_cmbe(struct ccw_device *cdev, int index) |
1da177e4 | 851 | { |
94bb0633 | 852 | struct cmb_data *cmb_data; |
94bb0633 | 853 | unsigned long flags; |
d4d287e8 | 854 | struct cmbe *cmb; |
cb09b356 | 855 | u64 ret = 0; |
d4d287e8 | 856 | u32 val; |
1da177e4 | 857 | |
94bb0633 CH |
858 | spin_lock_irqsave(cdev->ccwlock, flags); |
859 | cmb_data = cdev->private->cmb; | |
d4d287e8 | 860 | if (!cmb_data) |
94bb0633 | 861 | goto out; |
1da177e4 | 862 | |
d4d287e8 | 863 | cmb = cmb_data->hw_block; |
1da177e4 | 864 | switch (index) { |
cb09b356 SO |
865 | case avg_utilization: |
866 | ret = __cmb_utilization(cmb->device_connect_time, | |
867 | cmb->function_pending_time, | |
868 | cmb->device_disconnect_time, | |
869 | cdev->private->cmb_start_time); | |
870 | goto out; | |
1da177e4 | 871 | case cmb_ssch_rsch_count: |
94bb0633 CH |
872 | ret = cmb->ssch_rsch_count; |
873 | goto out; | |
1da177e4 | 874 | case cmb_sample_count: |
94bb0633 CH |
875 | ret = cmb->sample_count; |
876 | goto out; | |
1da177e4 | 877 | case cmb_device_connect_time: |
94bb0633 | 878 | val = cmb->device_connect_time; |
1da177e4 LT |
879 | break; |
880 | case cmb_function_pending_time: | |
94bb0633 | 881 | val = cmb->function_pending_time; |
1da177e4 LT |
882 | break; |
883 | case cmb_device_disconnect_time: | |
94bb0633 | 884 | val = cmb->device_disconnect_time; |
1da177e4 LT |
885 | break; |
886 | case cmb_control_unit_queuing_time: | |
94bb0633 | 887 | val = cmb->control_unit_queuing_time; |
1da177e4 LT |
888 | break; |
889 | case cmb_device_active_only_time: | |
94bb0633 | 890 | val = cmb->device_active_only_time; |
1da177e4 LT |
891 | break; |
892 | case cmb_device_busy_time: | |
94bb0633 | 893 | val = cmb->device_busy_time; |
1da177e4 LT |
894 | break; |
895 | case cmb_initial_command_response_time: | |
94bb0633 | 896 | val = cmb->initial_command_response_time; |
1da177e4 LT |
897 | break; |
898 | default: | |
94bb0633 | 899 | goto out; |
1da177e4 | 900 | } |
94bb0633 CH |
901 | ret = time_to_avg_nsec(val, cmb->sample_count); |
902 | out: | |
903 | spin_unlock_irqrestore(cdev->ccwlock, flags); | |
904 | return ret; | |
1da177e4 LT |
905 | } |
906 | ||
fc5019c5 | 907 | static int readall_cmbe(struct ccw_device *cdev, struct cmbdata *data) |
1da177e4 | 908 | { |
94bb0633 CH |
909 | struct cmbe *cmb; |
910 | struct cmb_data *cmb_data; | |
1da177e4 | 911 | u64 time; |
94bb0633 CH |
912 | unsigned long flags; |
913 | int ret; | |
1da177e4 | 914 | |
94bb0633 CH |
915 | ret = cmf_cmb_copy_wait(cdev); |
916 | if (ret < 0) | |
917 | return ret; | |
1da177e4 | 918 | spin_lock_irqsave(cdev->ccwlock, flags); |
94bb0633 CH |
919 | cmb_data = cdev->private->cmb; |
920 | if (!cmb_data) { | |
921 | ret = -ENODEV; | |
922 | goto out; | |
1da177e4 | 923 | } |
94bb0633 CH |
924 | if (cmb_data->last_update == 0) { |
925 | ret = -EAGAIN; | |
926 | goto out; | |
927 | } | |
928 | time = cmb_data->last_update - cdev->private->cmb_start_time; | |
1da177e4 LT |
929 | |
930 | memset (data, 0, sizeof(struct cmbdata)); | |
931 | ||
932 | /* we only know values before device_busy_time */ | |
933 | data->size = offsetof(struct cmbdata, device_busy_time); | |
934 | ||
08c6df97 | 935 | data->elapsed_time = tod_to_ns(time); |
1da177e4 | 936 | |
94bb0633 | 937 | cmb = cmb_data->last_block; |
1da177e4 | 938 | /* copy data to new structure */ |
94bb0633 CH |
939 | data->ssch_rsch_count = cmb->ssch_rsch_count; |
940 | data->sample_count = cmb->sample_count; | |
1da177e4 LT |
941 | |
942 | /* time fields are converted to nanoseconds while copying */ | |
94bb0633 CH |
943 | data->device_connect_time = time_to_nsec(cmb->device_connect_time); |
944 | data->function_pending_time = time_to_nsec(cmb->function_pending_time); | |
945 | data->device_disconnect_time = | |
946 | time_to_nsec(cmb->device_disconnect_time); | |
1da177e4 | 947 | data->control_unit_queuing_time |
94bb0633 | 948 | = time_to_nsec(cmb->control_unit_queuing_time); |
1da177e4 | 949 | data->device_active_only_time |
94bb0633 CH |
950 | = time_to_nsec(cmb->device_active_only_time); |
951 | data->device_busy_time = time_to_nsec(cmb->device_busy_time); | |
1da177e4 | 952 | data->initial_command_response_time |
94bb0633 | 953 | = time_to_nsec(cmb->initial_command_response_time); |
1da177e4 | 954 | |
94bb0633 CH |
955 | ret = 0; |
956 | out: | |
957 | spin_unlock_irqrestore(cdev->ccwlock, flags); | |
958 | return ret; | |
1da177e4 LT |
959 | } |
960 | ||
94bb0633 | 961 | static void reset_cmbe(struct ccw_device *cdev) |
1da177e4 | 962 | { |
94bb0633 CH |
963 | cmf_generic_reset(cdev); |
964 | } | |
965 | ||
1da177e4 LT |
966 | static struct attribute_group cmf_attr_group_ext; |
967 | ||
968 | static struct cmb_operations cmbops_extended = { | |
969 | .alloc = alloc_cmbe, | |
970 | .free = free_cmbe, | |
971 | .set = set_cmbe, | |
972 | .read = read_cmbe, | |
973 | .readall = readall_cmbe, | |
974 | .reset = reset_cmbe, | |
975 | .attr_group = &cmf_attr_group_ext, | |
976 | }; | |
1da177e4 | 977 | |
fc5019c5 | 978 | static ssize_t cmb_show_attr(struct device *dev, char *buf, enum cmb_index idx) |
1da177e4 LT |
979 | { |
980 | return sprintf(buf, "%lld\n", | |
981 | (unsigned long long) cmf_read(to_ccwdev(dev), idx)); | |
982 | } | |
983 | ||
fc5019c5 CH |
984 | static ssize_t cmb_show_avg_sample_interval(struct device *dev, |
985 | struct device_attribute *attr, | |
986 | char *buf) | |
1da177e4 | 987 | { |
d4d287e8 | 988 | struct ccw_device *cdev = to_ccwdev(dev); |
1da177e4 | 989 | unsigned long count; |
d4d287e8 | 990 | long interval; |
1da177e4 | 991 | |
1da177e4 | 992 | count = cmf_read(cdev, cmb_sample_count); |
94bb0633 | 993 | spin_lock_irq(cdev->ccwlock); |
94bb0633 | 994 | if (count) { |
d4d287e8 | 995 | interval = get_tod_clock() - cdev->private->cmb_start_time; |
08c6df97 | 996 | interval = tod_to_ns(interval); |
1da177e4 | 997 | interval /= count; |
94bb0633 | 998 | } else |
1da177e4 | 999 | interval = -1; |
94bb0633 | 1000 | spin_unlock_irq(cdev->ccwlock); |
1da177e4 LT |
1001 | return sprintf(buf, "%ld\n", interval); |
1002 | } | |
1003 | ||
fc5019c5 CH |
1004 | static ssize_t cmb_show_avg_utilization(struct device *dev, |
1005 | struct device_attribute *attr, | |
1006 | char *buf) | |
1da177e4 | 1007 | { |
cb09b356 | 1008 | unsigned long u = cmf_read(to_ccwdev(dev), avg_utilization); |
1da177e4 | 1009 | |
cb09b356 | 1010 | return sprintf(buf, "%02lu.%01lu%%\n", u / 10, u % 10); |
1da177e4 LT |
1011 | } |
1012 | ||
1013 | #define cmf_attr(name) \ | |
fc5019c5 CH |
1014 | static ssize_t show_##name(struct device *dev, \ |
1015 | struct device_attribute *attr, char *buf) \ | |
1016 | { return cmb_show_attr((dev), buf, cmb_##name); } \ | |
1017 | static DEVICE_ATTR(name, 0444, show_##name, NULL); | |
1da177e4 LT |
1018 | |
1019 | #define cmf_attr_avg(name) \ | |
fc5019c5 CH |
1020 | static ssize_t show_avg_##name(struct device *dev, \ |
1021 | struct device_attribute *attr, char *buf) \ | |
1022 | { return cmb_show_attr((dev), buf, cmb_##name); } \ | |
1023 | static DEVICE_ATTR(avg_##name, 0444, show_avg_##name, NULL); | |
1da177e4 LT |
1024 | |
1025 | cmf_attr(ssch_rsch_count); | |
1026 | cmf_attr(sample_count); | |
1027 | cmf_attr_avg(device_connect_time); | |
1028 | cmf_attr_avg(function_pending_time); | |
1029 | cmf_attr_avg(device_disconnect_time); | |
1030 | cmf_attr_avg(control_unit_queuing_time); | |
1031 | cmf_attr_avg(device_active_only_time); | |
1032 | cmf_attr_avg(device_busy_time); | |
1033 | cmf_attr_avg(initial_command_response_time); | |
1034 | ||
fc5019c5 CH |
1035 | static DEVICE_ATTR(avg_sample_interval, 0444, cmb_show_avg_sample_interval, |
1036 | NULL); | |
1da177e4 LT |
1037 | static DEVICE_ATTR(avg_utilization, 0444, cmb_show_avg_utilization, NULL); |
1038 | ||
1039 | static struct attribute *cmf_attributes[] = { | |
1040 | &dev_attr_avg_sample_interval.attr, | |
1041 | &dev_attr_avg_utilization.attr, | |
1042 | &dev_attr_ssch_rsch_count.attr, | |
1043 | &dev_attr_sample_count.attr, | |
1044 | &dev_attr_avg_device_connect_time.attr, | |
1045 | &dev_attr_avg_function_pending_time.attr, | |
1046 | &dev_attr_avg_device_disconnect_time.attr, | |
1047 | &dev_attr_avg_control_unit_queuing_time.attr, | |
1048 | &dev_attr_avg_device_active_only_time.attr, | |
d2c993d8 | 1049 | NULL, |
1da177e4 LT |
1050 | }; |
1051 | ||
1052 | static struct attribute_group cmf_attr_group = { | |
1053 | .name = "cmf", | |
1054 | .attrs = cmf_attributes, | |
1055 | }; | |
1056 | ||
1057 | static struct attribute *cmf_attributes_ext[] = { | |
1058 | &dev_attr_avg_sample_interval.attr, | |
1059 | &dev_attr_avg_utilization.attr, | |
1060 | &dev_attr_ssch_rsch_count.attr, | |
1061 | &dev_attr_sample_count.attr, | |
1062 | &dev_attr_avg_device_connect_time.attr, | |
1063 | &dev_attr_avg_function_pending_time.attr, | |
1064 | &dev_attr_avg_device_disconnect_time.attr, | |
1065 | &dev_attr_avg_control_unit_queuing_time.attr, | |
1066 | &dev_attr_avg_device_active_only_time.attr, | |
1067 | &dev_attr_avg_device_busy_time.attr, | |
1068 | &dev_attr_avg_initial_command_response_time.attr, | |
d2c993d8 | 1069 | NULL, |
1da177e4 LT |
1070 | }; |
1071 | ||
1072 | static struct attribute_group cmf_attr_group_ext = { | |
1073 | .name = "cmf", | |
1074 | .attrs = cmf_attributes_ext, | |
1075 | }; | |
1076 | ||
fc5019c5 CH |
1077 | static ssize_t cmb_enable_show(struct device *dev, |
1078 | struct device_attribute *attr, | |
1079 | char *buf) | |
1da177e4 | 1080 | { |
279b8f9a | 1081 | struct ccw_device *cdev = to_ccwdev(dev); |
279b8f9a | 1082 | |
0f5d050c | 1083 | return sprintf(buf, "%d\n", cmf_enabled(cdev)); |
1da177e4 LT |
1084 | } |
1085 | ||
fc5019c5 CH |
1086 | static ssize_t cmb_enable_store(struct device *dev, |
1087 | struct device_attribute *attr, const char *buf, | |
1088 | size_t c) | |
1da177e4 | 1089 | { |
279b8f9a | 1090 | struct ccw_device *cdev = to_ccwdev(dev); |
2f972202 | 1091 | unsigned long val; |
279b8f9a | 1092 | int ret; |
2f972202 | 1093 | |
0178722b | 1094 | ret = kstrtoul(buf, 16, &val); |
2f972202 CH |
1095 | if (ret) |
1096 | return ret; | |
1da177e4 | 1097 | |
2f972202 CH |
1098 | switch (val) { |
1099 | case 0: | |
1da177e4 | 1100 | ret = disable_cmf(cdev); |
1da177e4 | 1101 | break; |
2f972202 | 1102 | case 1: |
1da177e4 | 1103 | ret = enable_cmf(cdev); |
1da177e4 | 1104 | break; |
279b8f9a SO |
1105 | default: |
1106 | ret = -EINVAL; | |
1da177e4 LT |
1107 | } |
1108 | ||
279b8f9a | 1109 | return ret ? ret : c; |
1da177e4 | 1110 | } |
279b8f9a | 1111 | DEVICE_ATTR_RW(cmb_enable); |
1da177e4 | 1112 | |
c0208716 CH |
1113 | /** |
1114 | * enable_cmf() - switch on the channel measurement for a specific device | |
1115 | * @cdev: The ccw device to be enabled | |
1116 | * | |
f3ea8419 CH |
1117 | * Enable channel measurements for @cdev. If this is called on a device |
1118 | * for which channel measurement is already enabled a reset of the | |
1119 | * measurement data is triggered. | |
1120 | * Returns: %0 for success or a negative error value. | |
c0208716 CH |
1121 | * Context: |
1122 | * non-atomic | |
1123 | */ | |
fc5019c5 | 1124 | int enable_cmf(struct ccw_device *cdev) |
1da177e4 | 1125 | { |
0f5d050c | 1126 | int ret = 0; |
1da177e4 | 1127 | |
1bc6664b | 1128 | device_lock(&cdev->dev); |
0f5d050c SO |
1129 | if (cmf_enabled(cdev)) { |
1130 | cmbops->reset(cdev); | |
1131 | goto out_unlock; | |
1132 | } | |
a6ef1565 | 1133 | get_device(&cdev->dev); |
1da177e4 | 1134 | ret = cmbops->alloc(cdev); |
1da177e4 | 1135 | if (ret) |
1bc6664b SO |
1136 | goto out; |
1137 | cmbops->reset(cdev); | |
1138 | ret = sysfs_create_group(&cdev->dev.kobj, cmbops->attr_group); | |
1139 | if (ret) { | |
1140 | cmbops->free(cdev); | |
1141 | goto out; | |
1142 | } | |
1da177e4 LT |
1143 | ret = cmbops->set(cdev, 2); |
1144 | if (ret) { | |
1bc6664b | 1145 | sysfs_remove_group(&cdev->dev.kobj, cmbops->attr_group); |
1da177e4 | 1146 | cmbops->free(cdev); |
1da177e4 | 1147 | } |
1bc6664b | 1148 | out: |
a6ef1565 SO |
1149 | if (ret) |
1150 | put_device(&cdev->dev); | |
0f5d050c | 1151 | out_unlock: |
1bc6664b | 1152 | device_unlock(&cdev->dev); |
1da177e4 LT |
1153 | return ret; |
1154 | } | |
1155 | ||
c0208716 | 1156 | /** |
1bc6664b | 1157 | * __disable_cmf() - switch off the channel measurement for a specific device |
c0208716 CH |
1158 | * @cdev: The ccw device to be disabled |
1159 | * | |
f3ea8419 | 1160 | * Returns: %0 for success or a negative error value. |
c0208716 CH |
1161 | * |
1162 | * Context: | |
1bc6664b | 1163 | * non-atomic, device_lock() held. |
c0208716 | 1164 | */ |
1bc6664b | 1165 | int __disable_cmf(struct ccw_device *cdev) |
1da177e4 LT |
1166 | { |
1167 | int ret; | |
1168 | ||
1169 | ret = cmbops->set(cdev, 0); | |
1170 | if (ret) | |
1171 | return ret; | |
1bc6664b | 1172 | |
1da177e4 | 1173 | sysfs_remove_group(&cdev->dev.kobj, cmbops->attr_group); |
1bc6664b | 1174 | cmbops->free(cdev); |
a6ef1565 | 1175 | put_device(&cdev->dev); |
1bc6664b SO |
1176 | |
1177 | return ret; | |
1178 | } | |
1179 | ||
1180 | /** | |
1181 | * disable_cmf() - switch off the channel measurement for a specific device | |
1182 | * @cdev: The ccw device to be disabled | |
1183 | * | |
f3ea8419 | 1184 | * Returns: %0 for success or a negative error value. |
1bc6664b SO |
1185 | * |
1186 | * Context: | |
1187 | * non-atomic | |
1188 | */ | |
1189 | int disable_cmf(struct ccw_device *cdev) | |
1190 | { | |
1191 | int ret; | |
1192 | ||
1193 | device_lock(&cdev->dev); | |
1194 | ret = __disable_cmf(cdev); | |
1195 | device_unlock(&cdev->dev); | |
1196 | ||
1da177e4 LT |
1197 | return ret; |
1198 | } | |
1199 | ||
c0208716 CH |
1200 | /** |
1201 | * cmf_read() - read one value from the current channel measurement block | |
1202 | * @cdev: the channel to be read | |
1203 | * @index: the index of the value to be read | |
1204 | * | |
f3ea8419 | 1205 | * Returns: The value read or %0 if the value cannot be read. |
c0208716 CH |
1206 | * |
1207 | * Context: | |
1208 | * any | |
1209 | */ | |
fc5019c5 | 1210 | u64 cmf_read(struct ccw_device *cdev, int index) |
1da177e4 LT |
1211 | { |
1212 | return cmbops->read(cdev, index); | |
1213 | } | |
1214 | ||
c0208716 CH |
1215 | /** |
1216 | * cmf_readall() - read the current channel measurement block | |
1217 | * @cdev: the channel to be read | |
1218 | * @data: a pointer to a data block that will be filled | |
1219 | * | |
f3ea8419 | 1220 | * Returns: %0 on success, a negative error value otherwise. |
c0208716 CH |
1221 | * |
1222 | * Context: | |
1223 | * any | |
1224 | */ | |
fc5019c5 | 1225 | int cmf_readall(struct ccw_device *cdev, struct cmbdata *data) |
1da177e4 LT |
1226 | { |
1227 | return cmbops->readall(cdev, data); | |
1228 | } | |
1229 | ||
94bb0633 CH |
1230 | /* Reenable cmf when a disconnected device becomes available again. */ |
1231 | int cmf_reenable(struct ccw_device *cdev) | |
1232 | { | |
1233 | cmbops->reset(cdev); | |
1234 | return cmbops->set(cdev, 2); | |
1235 | } | |
1236 | ||
ab97d211 SO |
1237 | /** |
1238 | * cmf_reactivate() - reactivate measurement block updates | |
1239 | * | |
1240 | * Use this during resume from hibernate. | |
1241 | */ | |
1242 | void cmf_reactivate(void) | |
1243 | { | |
1244 | spin_lock(&cmb_area.lock); | |
1245 | if (!list_empty(&cmb_area.list)) | |
7b4ff87c | 1246 | cmf_activate(cmb_area.mem, CMF_ON); |
ab97d211 SO |
1247 | spin_unlock(&cmb_area.lock); |
1248 | } | |
1249 | ||
45bf4b96 SO |
1250 | static int __init init_cmbe(void) |
1251 | { | |
1252 | cmbe_cache = kmem_cache_create("cmbe_cache", sizeof(struct cmbe), | |
1253 | __alignof__(struct cmbe), 0, NULL); | |
1254 | ||
1255 | return cmbe_cache ? 0 : -ENOMEM; | |
1256 | } | |
1257 | ||
fc5019c5 | 1258 | static int __init init_cmf(void) |
1da177e4 LT |
1259 | { |
1260 | char *format_string; | |
45bf4b96 SO |
1261 | char *detect_string; |
1262 | int ret; | |
1da177e4 | 1263 | |
fc5019c5 CH |
1264 | /* |
1265 | * If the user did not give a parameter, see if we are running on a | |
1266 | * machine supporting extended measurement blocks, otherwise fall back | |
1267 | * to basic mode. | |
1268 | */ | |
1da177e4 | 1269 | if (format == CMF_AUTODETECT) { |
75784c00 | 1270 | if (!css_general_characteristics.ext_mb) { |
1da177e4 LT |
1271 | format = CMF_BASIC; |
1272 | } else { | |
1273 | format = CMF_EXTENDED; | |
1274 | } | |
1275 | detect_string = "autodetected"; | |
1276 | } else { | |
1277 | detect_string = "parameter"; | |
1278 | } | |
1279 | ||
1280 | switch (format) { | |
1281 | case CMF_BASIC: | |
1282 | format_string = "basic"; | |
1283 | cmbops = &cmbops_basic; | |
1da177e4 LT |
1284 | break; |
1285 | case CMF_EXTENDED: | |
fc5019c5 | 1286 | format_string = "extended"; |
1da177e4 | 1287 | cmbops = &cmbops_extended; |
45bf4b96 SO |
1288 | |
1289 | ret = init_cmbe(); | |
1290 | if (ret) | |
1291 | return ret; | |
1da177e4 LT |
1292 | break; |
1293 | default: | |
45bf4b96 | 1294 | return -EINVAL; |
1da177e4 | 1295 | } |
e6d5a428 ME |
1296 | pr_info("Channel measurement facility initialized using format " |
1297 | "%s (mode %s)\n", format_string, detect_string); | |
1da177e4 LT |
1298 | return 0; |
1299 | } | |
a00f761f | 1300 | device_initcall(init_cmf); |
1da177e4 LT |
1301 | |
1302 | EXPORT_SYMBOL_GPL(enable_cmf); | |
1303 | EXPORT_SYMBOL_GPL(disable_cmf); | |
1304 | EXPORT_SYMBOL_GPL(cmf_read); | |
1305 | EXPORT_SYMBOL_GPL(cmf_readall); |