blob: 7d59230e88bb3a2452e8e4eaf667f25659d3d13d [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 * Linux on zSeries Channel Measurement Facility support
3 *
Heiko Carstensa53c8fa2012-07-20 11:15:04 +02004 * Copyright IBM Corp. 2000, 2006
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 *
Cornelia Huck94bb0632006-06-29 15:08:41 +02006 * Authors: Arnd Bergmann <arndb@de.ibm.com>
7 * Cornelia Huck <cornelia.huck@de.ibm.com>
Linus Torvalds1da177e2005-04-16 15:20:36 -07008 *
9 * original idea from Natarajan Krishnaswami <nkrishna@us.ibm.com>
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2, or (at your option)
14 * any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 */
25
Michael Ernste6d5a422008-12-25 13:39:36 +010026#define KMSG_COMPONENT "cio"
27#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
28
Linus Torvalds1da177e2005-04-16 15:20:36 -070029#include <linux/bootmem.h>
30#include <linux/device.h>
31#include <linux/init.h>
32#include <linux/list.h>
Paul Gortmakera00f7612016-10-30 16:37:24 -040033#include <linux/export.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070034#include <linux/moduleparam.h>
Tim Schmielau4e57b682005-10-30 15:03:48 -080035#include <linux/slab.h>
Heiko Carstens1aae0562013-01-30 09:49:40 +010036#include <linux/timex.h> /* get_tod_clock() */
Linus Torvalds1da177e2005-04-16 15:20:36 -070037
38#include <asm/ccwdev.h>
39#include <asm/cio.h>
40#include <asm/cmb.h>
Tim Schmielau4e57b682005-10-30 15:03:48 -080041#include <asm/div64.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070042
43#include "cio.h"
44#include "css.h"
45#include "device.h"
46#include "ioasm.h"
47#include "chsc.h"
48
Cornelia Huckfc5019c2007-10-12 16:11:15 +020049/*
50 * parameter to enable cmf during boot, possible uses are:
Linus Torvalds1da177e2005-04-16 15:20:36 -070051 * "s390cmf" -- enable cmf and allocate 2 MB of ram so measuring can be
52 * used on any subchannel
53 * "s390cmf=<num>" -- enable cmf and allocate enough memory to measure
54 * <num> subchannel, where <num> is an integer
55 * between 1 and 65535, default is 1024
56 */
57#define ARGSTRING "s390cmf"
58
59/* indices for READCMB */
60enum cmb_index {
Sebastian Ottcb09b352017-09-08 21:01:38 +020061 avg_utilization = -1,
Linus Torvalds1da177e2005-04-16 15:20:36 -070062 /* basic and exended format: */
Sebastian Ottcb09b352017-09-08 21:01:38 +020063 cmb_ssch_rsch_count = 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -070064 cmb_sample_count,
65 cmb_device_connect_time,
66 cmb_function_pending_time,
67 cmb_device_disconnect_time,
68 cmb_control_unit_queuing_time,
69 cmb_device_active_only_time,
70 /* extended format only: */
71 cmb_device_busy_time,
72 cmb_initial_command_response_time,
73};
74
75/**
76 * enum cmb_format - types of supported measurement block formats
77 *
78 * @CMF_BASIC: traditional channel measurement blocks supported
Cornelia Huckc0208712007-10-12 16:11:16 +020079 * by all machines that we run on
Linus Torvalds1da177e2005-04-16 15:20:36 -070080 * @CMF_EXTENDED: improved format that was introduced with the z990
Cornelia Huckc0208712007-10-12 16:11:16 +020081 * machine
82 * @CMF_AUTODETECT: default: use extended format when running on a machine
83 * supporting extended format, otherwise fall back to
84 * basic format
85 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070086enum cmb_format {
87 CMF_BASIC,
88 CMF_EXTENDED,
89 CMF_AUTODETECT = -1,
90};
Cornelia Huckfc5019c2007-10-12 16:11:15 +020091
Cornelia Huckc0208712007-10-12 16:11:16 +020092/*
Linus Torvalds1da177e2005-04-16 15:20:36 -070093 * format - actual format for all measurement blocks
94 *
95 * The format module parameter can be set to a value of 0 (zero)
96 * or 1, indicating basic or extended format as described for
97 * enum cmb_format.
98 */
99static int format = CMF_AUTODETECT;
Rusty Russell69116f22012-01-13 09:32:17 +1030100module_param(format, bint, 0444);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101
102/**
103 * struct cmb_operations - functions to use depending on cmb_format
104 *
Cornelia Huck94bb0632006-06-29 15:08:41 +0200105 * Most of these functions operate on a struct ccw_device. There is only
106 * one instance of struct cmb_operations because the format of the measurement
107 * data is guaranteed to be the same for every ccw_device.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108 *
109 * @alloc: allocate memory for a channel measurement block,
110 * either with the help of a special pool or with kmalloc
111 * @free: free memory allocated with @alloc
112 * @set: enable or disable measurement
Cornelia Huckc0208712007-10-12 16:11:16 +0200113 * @read: read a measurement entry at an index
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114 * @readall: read a measurement block in a common format
115 * @reset: clear the data in the associated measurement block and
116 * reset its time stamp
117 */
118struct cmb_operations {
Cornelia Huckfc5019c2007-10-12 16:11:15 +0200119 int (*alloc) (struct ccw_device *);
120 void (*free) (struct ccw_device *);
121 int (*set) (struct ccw_device *, u32);
122 u64 (*read) (struct ccw_device *, int);
123 int (*readall)(struct ccw_device *, struct cmbdata *);
124 void (*reset) (struct ccw_device *);
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
Heiko Carstens7b4ff872016-06-20 14:03:38 +0200168#define CMF_OFF 0
169#define CMF_ON 2
170
Cornelia Huckfc5019c2007-10-12 16:11:15 +0200171/*
172 * Activate or deactivate the channel monitor. When area is NULL,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173 * the monitor is deactivated. The channel monitor needs to
174 * be active in order to measure subchannels, which also need
Cornelia Huckfc5019c2007-10-12 16:11:15 +0200175 * to be enabled.
176 */
177static inline void cmf_activate(void *area, unsigned int onoff)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178{
179 register void * __gpr2 asm("2");
180 register long __gpr1 asm("1");
181
182 __gpr2 = area;
Heiko Carstens7b4ff872016-06-20 14:03:38 +0200183 __gpr1 = onoff;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184 /* activate channel measurement */
185 asm("schm" : : "d" (__gpr2), "d" (__gpr1) );
186}
187
Cornelia Huckfc5019c2007-10-12 16:11:15 +0200188static int set_schib(struct ccw_device *cdev, u32 mme, int mbfc,
189 unsigned long address)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190{
Sebastian Otta6ef1562015-09-07 19:51:39 +0200191 struct subchannel *sch = to_subchannel(cdev->dev.parent);
192 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193
Sebastian Ott13952ec2008-12-25 13:39:13 +0100194 sch->config.mme = mme;
195 sch->config.mbfc = mbfc;
196 /* address can be either a block address or a block index */
197 if (mbfc)
198 sch->config.mba = address;
199 else
200 sch->config.mbi = address;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201
Sebastian Otta6ef1562015-09-07 19:51:39 +0200202 ret = cio_commit_config(sch);
203 if (!mme && ret == -ENODEV) {
204 /*
205 * The task was to disable measurement block updates but
206 * the subchannel is already gone. Report success.
207 */
208 ret = 0;
209 }
210 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211}
212
213struct set_schib_struct {
214 u32 mme;
215 int mbfc;
216 unsigned long address;
217 wait_queue_head_t wait;
218 int ret;
219};
220
Cornelia Huck94bb0632006-06-29 15:08:41 +0200221#define CMF_PENDING 1
Sebastian Ottadc69b42017-09-05 14:22:48 +0200222#define SET_SCHIB_TIMEOUT (10 * HZ)
Cornelia Huck94bb0632006-06-29 15:08:41 +0200223
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224static int set_schib_wait(struct ccw_device *cdev, u32 mme,
Sebastian Otteeec1e42017-09-06 13:43:20 +0200225 int mbfc, unsigned long address)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226{
Sebastian Otteeec1e42017-09-06 13:43:20 +0200227 struct set_schib_struct set_data;
228 int ret = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229
230 spin_lock_irq(cdev->ccwlock);
Sebastian Otteeec1e42017-09-06 13:43:20 +0200231 if (!cdev->private->cmb)
Cornelia Huck94bb0632006-06-29 15:08:41 +0200232 goto out;
Cornelia Huck94bb0632006-06-29 15:08:41 +0200233
234 ret = set_schib(cdev, mme, mbfc, address);
235 if (ret != -EBUSY)
Sebastian Otteeec1e42017-09-06 13:43:20 +0200236 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237
Sebastian Otteeec1e42017-09-06 13:43:20 +0200238 /* if the device is not online, don't even try again */
239 if (cdev->private->state != DEV_STATE_ONLINE)
240 goto out;
241
242 init_waitqueue_head(&set_data.wait);
243 set_data.mme = mme;
244 set_data.mbfc = mbfc;
245 set_data.address = address;
246 set_data.ret = CMF_PENDING;
Cornelia Huck94bb0632006-06-29 15:08:41 +0200247
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248 cdev->private->state = DEV_STATE_CMFCHANGE;
Sebastian Otteeec1e42017-09-06 13:43:20 +0200249 cdev->private->cmb_wait = &set_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250 spin_unlock_irq(cdev->ccwlock);
Sebastian Ottadc69b42017-09-05 14:22:48 +0200251
Sebastian Otteeec1e42017-09-06 13:43:20 +0200252 ret = wait_event_interruptible_timeout(set_data.wait,
253 set_data.ret != CMF_PENDING,
Sebastian Ottadc69b42017-09-05 14:22:48 +0200254 SET_SCHIB_TIMEOUT);
255 spin_lock_irq(cdev->ccwlock);
256 if (ret <= 0) {
Sebastian Otteeec1e42017-09-06 13:43:20 +0200257 if (set_data.ret == CMF_PENDING) {
258 set_data.ret = (ret == 0) ? -ETIME : ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259 if (cdev->private->state == DEV_STATE_CMFCHANGE)
260 cdev->private->state = DEV_STATE_ONLINE;
261 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262 }
Cornelia Huck94bb0632006-06-29 15:08:41 +0200263 cdev->private->cmb_wait = NULL;
Sebastian Otteeec1e42017-09-06 13:43:20 +0200264 ret = set_data.ret;
Cornelia Huck94bb0632006-06-29 15:08:41 +0200265out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266 spin_unlock_irq(cdev->ccwlock);
Cornelia Huck94bb0632006-06-29 15:08:41 +0200267 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268}
269
270void retry_set_schib(struct ccw_device *cdev)
271{
Sebastian Otteeec1e42017-09-06 13:43:20 +0200272 struct set_schib_struct *set_data = cdev->private->cmb_wait;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273
Sebastian Otteeec1e42017-09-06 13:43:20 +0200274 if (!set_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275 return;
Sebastian Otteeec1e42017-09-06 13:43:20 +0200276
Cornelia Huck94bb0632006-06-29 15:08:41 +0200277 set_data->ret = set_schib(cdev, set_data->mme, set_data->mbfc,
278 set_data->address);
279 wake_up(&set_data->wait);
Cornelia Huck94bb0632006-06-29 15:08:41 +0200280}
281
282static int cmf_copy_block(struct ccw_device *cdev)
283{
Sebastian Ott81b050b2017-09-06 10:44:23 +0200284 struct subchannel *sch = to_subchannel(cdev->dev.parent);
Cornelia Huck94bb0632006-06-29 15:08:41 +0200285 struct cmb_data *cmb_data;
Sebastian Ott81b050b2017-09-06 10:44:23 +0200286 void *hw_block;
Cornelia Huck94bb0632006-06-29 15:08:41 +0200287
Sebastian Ottcdb912a2008-12-25 13:39:12 +0100288 if (cio_update_schib(sch))
Cornelia Huck94bb0632006-06-29 15:08:41 +0200289 return -ENODEV;
290
Peter Oberparleiter23d805b2008-07-14 09:58:50 +0200291 if (scsw_fctl(&sch->schib.scsw) & SCSW_FCTL_START_FUNC) {
Cornelia Huck94bb0632006-06-29 15:08:41 +0200292 /* Don't copy if a start function is in progress. */
Peter Oberparleiter23d805b2008-07-14 09:58:50 +0200293 if ((!(scsw_actl(&sch->schib.scsw) & SCSW_ACTL_SUSPENDED)) &&
294 (scsw_actl(&sch->schib.scsw) &
Cornelia Huck94bb0632006-06-29 15:08:41 +0200295 (SCSW_ACTL_DEVACT | SCSW_ACTL_SCHACT)) &&
Peter Oberparleiter23d805b2008-07-14 09:58:50 +0200296 (!(scsw_stctl(&sch->schib.scsw) & SCSW_STCTL_SEC_STATUS)))
Cornelia Huck94bb0632006-06-29 15:08:41 +0200297 return -EBUSY;
298 }
299 cmb_data = cdev->private->cmb;
Sebastian Ott45bf4b92015-09-07 19:53:01 +0200300 hw_block = cmb_data->hw_block;
Sebastian Ott81b050b2017-09-06 10:44:23 +0200301 memcpy(cmb_data->last_block, hw_block, cmb_data->size);
Heiko Carstens1aae0562013-01-30 09:49:40 +0100302 cmb_data->last_update = get_tod_clock();
Cornelia Huck94bb0632006-06-29 15:08:41 +0200303 return 0;
304}
305
306struct copy_block_struct {
307 wait_queue_head_t wait;
308 int ret;
Cornelia Huck94bb0632006-06-29 15:08:41 +0200309};
310
Cornelia Huck94bb0632006-06-29 15:08:41 +0200311static int cmf_cmb_copy_wait(struct ccw_device *cdev)
312{
Sebastian Ott60f3eac2017-09-06 19:05:29 +0200313 struct copy_block_struct copy_block;
314 int ret = -ENODEV;
Cornelia Huck94bb0632006-06-29 15:08:41 +0200315
Sebastian Ott60f3eac2017-09-06 19:05:29 +0200316 spin_lock_irq(cdev->ccwlock);
317 if (!cdev->private->cmb)
Cornelia Huck94bb0632006-06-29 15:08:41 +0200318 goto out;
Cornelia Huck94bb0632006-06-29 15:08:41 +0200319
320 ret = cmf_copy_block(cdev);
321 if (ret != -EBUSY)
Sebastian Ott60f3eac2017-09-06 19:05:29 +0200322 goto out;
Cornelia Huck94bb0632006-06-29 15:08:41 +0200323
Sebastian Ott60f3eac2017-09-06 19:05:29 +0200324 if (cdev->private->state != DEV_STATE_ONLINE)
325 goto out;
326
327 init_waitqueue_head(&copy_block.wait);
328 copy_block.ret = CMF_PENDING;
Cornelia Huck94bb0632006-06-29 15:08:41 +0200329
330 cdev->private->state = DEV_STATE_CMFUPDATE;
Sebastian Ott60f3eac2017-09-06 19:05:29 +0200331 cdev->private->cmb_wait = &copy_block;
332 spin_unlock_irq(cdev->ccwlock);
Cornelia Huck94bb0632006-06-29 15:08:41 +0200333
Sebastian Ott60f3eac2017-09-06 19:05:29 +0200334 ret = wait_event_interruptible(copy_block.wait,
335 copy_block.ret != CMF_PENDING);
336 spin_lock_irq(cdev->ccwlock);
337 if (ret) {
338 if (copy_block.ret == CMF_PENDING) {
339 copy_block.ret = -ERESTARTSYS;
Cornelia Huck94bb0632006-06-29 15:08:41 +0200340 if (cdev->private->state == DEV_STATE_CMFUPDATE)
341 cdev->private->state = DEV_STATE_ONLINE;
342 }
Cornelia Huck94bb0632006-06-29 15:08:41 +0200343 }
Cornelia Huck94bb0632006-06-29 15:08:41 +0200344 cdev->private->cmb_wait = NULL;
Sebastian Ott60f3eac2017-09-06 19:05:29 +0200345 ret = copy_block.ret;
Cornelia Huck94bb0632006-06-29 15:08:41 +0200346out:
Sebastian Ott60f3eac2017-09-06 19:05:29 +0200347 spin_unlock_irq(cdev->ccwlock);
Cornelia Huck94bb0632006-06-29 15:08:41 +0200348 return ret;
349}
350
351void cmf_retry_copy_block(struct ccw_device *cdev)
352{
Sebastian Ott60f3eac2017-09-06 19:05:29 +0200353 struct copy_block_struct *copy_block = cdev->private->cmb_wait;
Cornelia Huck94bb0632006-06-29 15:08:41 +0200354
Sebastian Ott60f3eac2017-09-06 19:05:29 +0200355 if (!copy_block)
Cornelia Huck94bb0632006-06-29 15:08:41 +0200356 return;
Sebastian Ott60f3eac2017-09-06 19:05:29 +0200357
Cornelia Huck94bb0632006-06-29 15:08:41 +0200358 copy_block->ret = cmf_copy_block(cdev);
359 wake_up(&copy_block->wait);
Cornelia Huck94bb0632006-06-29 15:08:41 +0200360}
361
362static void cmf_generic_reset(struct ccw_device *cdev)
363{
364 struct cmb_data *cmb_data;
365
366 spin_lock_irq(cdev->ccwlock);
367 cmb_data = cdev->private->cmb;
368 if (cmb_data) {
369 memset(cmb_data->last_block, 0, cmb_data->size);
370 /*
371 * Need to reset hw block as well to make the hardware start
372 * from 0 again.
373 */
Sebastian Ott45bf4b92015-09-07 19:53:01 +0200374 memset(cmb_data->hw_block, 0, cmb_data->size);
Cornelia Huck94bb0632006-06-29 15:08:41 +0200375 cmb_data->last_update = 0;
376 }
Heiko Carstens1aae0562013-01-30 09:49:40 +0100377 cdev->private->cmb_start_time = get_tod_clock();
Cornelia Huck94bb0632006-06-29 15:08:41 +0200378 spin_unlock_irq(cdev->ccwlock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379}
380
381/**
382 * struct cmb_area - container for global cmb data
383 *
384 * @mem: pointer to CMBs (only in basic measurement mode)
385 * @list: contains a linked list of all subchannels
Cornelia Huckc0208712007-10-12 16:11:16 +0200386 * @num_channels: number of channels to be measured
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387 * @lock: protect concurrent access to @mem and @list
388 */
389struct cmb_area {
390 struct cmb *mem;
391 struct list_head list;
392 int num_channels;
393 spinlock_t lock;
394};
395
396static struct cmb_area cmb_area = {
Milind Arun Choudharycb629a02007-04-27 16:02:01 +0200397 .lock = __SPIN_LOCK_UNLOCKED(cmb_area.lock),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 .list = LIST_HEAD_INIT(cmb_area.list),
399 .num_channels = 1024,
400};
401
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402/* ****** old style CMB handling ********/
403
Cornelia Huckfc5019c2007-10-12 16:11:15 +0200404/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405 * Basic channel measurement blocks are allocated in one contiguous
406 * block of memory, which can not be moved as long as any channel
407 * is active. Therefore, a maximum number of subchannels needs to
408 * be defined somewhere. This is a module parameter, defaulting to
André Goddard Rosaaf901ca2009-11-14 13:09:05 -0200409 * a reasonable value of 1024, or 32 kb of memory.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 * Current kernels don't allow kmalloc with more than 128kb, so the
Cornelia Huckfc5019c2007-10-12 16:11:15 +0200411 * maximum is 4096.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412 */
413
414module_param_named(maxchannels, cmb_area.num_channels, uint, 0444);
415
416/**
417 * struct cmb - basic channel measurement block
Cornelia Huckc0208712007-10-12 16:11:16 +0200418 * @ssch_rsch_count: number of ssch and rsch
419 * @sample_count: number of samples
420 * @device_connect_time: time of device connect
421 * @function_pending_time: time of function pending
422 * @device_disconnect_time: time of device disconnect
423 * @control_unit_queuing_time: time of control unit queuing
424 * @device_active_only_time: time of device active only
425 * @reserved: unused in basic measurement mode
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426 *
Cornelia Huckc0208712007-10-12 16:11:16 +0200427 * The measurement block as used by the hardware. The fields are described
428 * further in z/Architecture Principles of Operation, chapter 17.
429 *
430 * The cmb area made up from these blocks must be a contiguous array and may
431 * not be reallocated or freed.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432 * Only one cmb area can be present in the system.
433 */
434struct cmb {
435 u16 ssch_rsch_count;
436 u16 sample_count;
437 u32 device_connect_time;
438 u32 function_pending_time;
439 u32 device_disconnect_time;
440 u32 control_unit_queuing_time;
441 u32 device_active_only_time;
442 u32 reserved[2];
443};
444
Cornelia Huckfc5019c2007-10-12 16:11:15 +0200445/*
446 * Insert a single device into the cmb_area list.
447 * Called with cmb_area.lock held from alloc_cmb.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448 */
Heiko Carstens4d284ca2007-02-05 21:18:53 +0100449static int alloc_cmb_single(struct ccw_device *cdev,
450 struct cmb_data *cmb_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451{
452 struct cmb *cmb;
453 struct ccw_device_private *node;
454 int ret;
455
456 spin_lock_irq(cdev->ccwlock);
457 if (!list_empty(&cdev->private->cmb_list)) {
458 ret = -EBUSY;
459 goto out;
460 }
461
Cornelia Huckfc5019c2007-10-12 16:11:15 +0200462 /*
463 * Find first unused cmb in cmb_area.mem.
464 * This is a little tricky: cmb_area.list
465 * remains sorted by ->cmb->hw_data pointers.
466 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467 cmb = cmb_area.mem;
468 list_for_each_entry(node, &cmb_area.list, cmb_list) {
Cornelia Huck94bb0632006-06-29 15:08:41 +0200469 struct cmb_data *data;
470 data = node->cmb;
471 if ((struct cmb*)data->hw_block > cmb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472 break;
473 cmb++;
474 }
475 if (cmb - cmb_area.mem >= cmb_area.num_channels) {
476 ret = -ENOMEM;
477 goto out;
478 }
479
480 /* insert new cmb */
481 list_add_tail(&cdev->private->cmb_list, &node->cmb_list);
Cornelia Huck94bb0632006-06-29 15:08:41 +0200482 cmb_data->hw_block = cmb;
483 cdev->private->cmb = cmb_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484 ret = 0;
485out:
486 spin_unlock_irq(cdev->ccwlock);
487 return ret;
488}
489
Cornelia Huckfc5019c2007-10-12 16:11:15 +0200490static int alloc_cmb(struct ccw_device *cdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491{
492 int ret;
493 struct cmb *mem;
494 ssize_t size;
Cornelia Huck94bb0632006-06-29 15:08:41 +0200495 struct cmb_data *cmb_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496
Cornelia Huck94bb0632006-06-29 15:08:41 +0200497 /* Allocate private cmb_data. */
498 cmb_data = kzalloc(sizeof(struct cmb_data), GFP_KERNEL);
499 if (!cmb_data)
500 return -ENOMEM;
501
502 cmb_data->last_block = kzalloc(sizeof(struct cmb), GFP_KERNEL);
503 if (!cmb_data->last_block) {
504 kfree(cmb_data);
505 return -ENOMEM;
506 }
507 cmb_data->size = sizeof(struct cmb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508 spin_lock(&cmb_area.lock);
509
510 if (!cmb_area.mem) {
511 /* there is no user yet, so we need a new area */
512 size = sizeof(struct cmb) * cmb_area.num_channels;
513 WARN_ON(!list_empty(&cmb_area.list));
514
515 spin_unlock(&cmb_area.lock);
516 mem = (void*)__get_free_pages(GFP_KERNEL | GFP_DMA,
517 get_order(size));
518 spin_lock(&cmb_area.lock);
519
520 if (cmb_area.mem) {
521 /* ok, another thread was faster */
522 free_pages((unsigned long)mem, get_order(size));
523 } else if (!mem) {
524 /* no luck */
525 ret = -ENOMEM;
526 goto out;
527 } else {
528 /* everything ok */
529 memset(mem, 0, size);
530 cmb_area.mem = mem;
Heiko Carstens7b4ff872016-06-20 14:03:38 +0200531 cmf_activate(cmb_area.mem, CMF_ON);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532 }
533 }
534
535 /* do the actual allocation */
Cornelia Huck94bb0632006-06-29 15:08:41 +0200536 ret = alloc_cmb_single(cdev, cmb_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537out:
538 spin_unlock(&cmb_area.lock);
Cornelia Huck94bb0632006-06-29 15:08:41 +0200539 if (ret) {
540 kfree(cmb_data->last_block);
541 kfree(cmb_data);
542 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543 return ret;
544}
545
Cornelia Huck94bb0632006-06-29 15:08:41 +0200546static void free_cmb(struct ccw_device *cdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547{
548 struct ccw_device_private *priv;
Cornelia Huck94bb0632006-06-29 15:08:41 +0200549 struct cmb_data *cmb_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550
551 spin_lock(&cmb_area.lock);
552 spin_lock_irq(cdev->ccwlock);
553
Cornelia Huck94bb0632006-06-29 15:08:41 +0200554 priv = cdev->private;
Cornelia Huck94bb0632006-06-29 15:08:41 +0200555 cmb_data = priv->cmb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556 priv->cmb = NULL;
Cornelia Huck94bb0632006-06-29 15:08:41 +0200557 if (cmb_data)
558 kfree(cmb_data->last_block);
559 kfree(cmb_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560 list_del_init(&priv->cmb_list);
561
562 if (list_empty(&cmb_area.list)) {
563 ssize_t size;
564 size = sizeof(struct cmb) * cmb_area.num_channels;
Heiko Carstens7b4ff872016-06-20 14:03:38 +0200565 cmf_activate(NULL, CMF_OFF);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566 free_pages((unsigned long)cmb_area.mem, get_order(size));
567 cmb_area.mem = NULL;
568 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569 spin_unlock_irq(cdev->ccwlock);
570 spin_unlock(&cmb_area.lock);
571}
572
Cornelia Huck94bb0632006-06-29 15:08:41 +0200573static int set_cmb(struct ccw_device *cdev, u32 mme)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574{
575 u16 offset;
Cornelia Huck94bb0632006-06-29 15:08:41 +0200576 struct cmb_data *cmb_data;
577 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578
Cornelia Huck94bb0632006-06-29 15:08:41 +0200579 spin_lock_irqsave(cdev->ccwlock, flags);
580 if (!cdev->private->cmb) {
581 spin_unlock_irqrestore(cdev->ccwlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582 return -EINVAL;
Cornelia Huck94bb0632006-06-29 15:08:41 +0200583 }
584 cmb_data = cdev->private->cmb;
585 offset = mme ? (struct cmb *)cmb_data->hw_block - cmb_area.mem : 0;
586 spin_unlock_irqrestore(cdev->ccwlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587
588 return set_schib_wait(cdev, mme, 0, offset);
589}
590
Sebastian Ottcb09b352017-09-08 21:01:38 +0200591/* calculate utilization in 0.1 percent units */
592static u64 __cmb_utilization(u64 device_connect_time, u64 function_pending_time,
593 u64 device_disconnect_time, u64 start_time)
594{
595 u64 utilization, elapsed_time;
596
597 utilization = time_to_nsec(device_connect_time +
598 function_pending_time +
599 device_disconnect_time);
600
601 elapsed_time = get_tod_clock() - start_time;
602 elapsed_time = tod_to_ns(elapsed_time);
603 elapsed_time /= 1000;
604
605 return elapsed_time ? (utilization / elapsed_time) : 0;
606}
607
Cornelia Huckfc5019c2007-10-12 16:11:15 +0200608static u64 read_cmb(struct ccw_device *cdev, int index)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609{
Sebastian Ottd4d287e2017-09-07 13:18:40 +0200610 struct cmb_data *cmb_data;
Cornelia Huck94bb0632006-06-29 15:08:41 +0200611 unsigned long flags;
Sebastian Ottd4d287e2017-09-07 13:18:40 +0200612 struct cmb *cmb;
Sebastian Ottcb09b352017-09-08 21:01:38 +0200613 u64 ret = 0;
Sebastian Ottd4d287e2017-09-07 13:18:40 +0200614 u32 val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615
616 spin_lock_irqsave(cdev->ccwlock, flags);
Sebastian Ottd4d287e2017-09-07 13:18:40 +0200617 cmb_data = cdev->private->cmb;
618 if (!cmb_data)
Cornelia Huck94bb0632006-06-29 15:08:41 +0200619 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620
Sebastian Ottd4d287e2017-09-07 13:18:40 +0200621 cmb = cmb_data->hw_block;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622 switch (index) {
Sebastian Ottcb09b352017-09-08 21:01:38 +0200623 case avg_utilization:
624 ret = __cmb_utilization(cmb->device_connect_time,
625 cmb->function_pending_time,
626 cmb->device_disconnect_time,
627 cdev->private->cmb_start_time);
628 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629 case cmb_ssch_rsch_count:
Cornelia Huck94bb0632006-06-29 15:08:41 +0200630 ret = cmb->ssch_rsch_count;
631 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632 case cmb_sample_count:
Cornelia Huck94bb0632006-06-29 15:08:41 +0200633 ret = cmb->sample_count;
634 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635 case cmb_device_connect_time:
Cornelia Huck94bb0632006-06-29 15:08:41 +0200636 val = cmb->device_connect_time;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637 break;
638 case cmb_function_pending_time:
Cornelia Huck94bb0632006-06-29 15:08:41 +0200639 val = cmb->function_pending_time;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640 break;
641 case cmb_device_disconnect_time:
Cornelia Huck94bb0632006-06-29 15:08:41 +0200642 val = cmb->device_disconnect_time;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643 break;
644 case cmb_control_unit_queuing_time:
Cornelia Huck94bb0632006-06-29 15:08:41 +0200645 val = cmb->control_unit_queuing_time;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646 break;
647 case cmb_device_active_only_time:
Cornelia Huck94bb0632006-06-29 15:08:41 +0200648 val = cmb->device_active_only_time;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649 break;
650 default:
Cornelia Huck94bb0632006-06-29 15:08:41 +0200651 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 }
Cornelia Huck94bb0632006-06-29 15:08:41 +0200653 ret = time_to_avg_nsec(val, cmb->sample_count);
654out:
655 spin_unlock_irqrestore(cdev->ccwlock, flags);
656 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657}
658
Cornelia Huckfc5019c2007-10-12 16:11:15 +0200659static int readall_cmb(struct ccw_device *cdev, struct cmbdata *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660{
Cornelia Huck94bb0632006-06-29 15:08:41 +0200661 struct cmb *cmb;
662 struct cmb_data *cmb_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663 u64 time;
Cornelia Huck94bb0632006-06-29 15:08:41 +0200664 unsigned long flags;
665 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666
Cornelia Huck94bb0632006-06-29 15:08:41 +0200667 ret = cmf_cmb_copy_wait(cdev);
668 if (ret < 0)
669 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 spin_lock_irqsave(cdev->ccwlock, flags);
Cornelia Huck94bb0632006-06-29 15:08:41 +0200671 cmb_data = cdev->private->cmb;
672 if (!cmb_data) {
673 ret = -ENODEV;
674 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675 }
Cornelia Huck94bb0632006-06-29 15:08:41 +0200676 if (cmb_data->last_update == 0) {
677 ret = -EAGAIN;
678 goto out;
679 }
680 cmb = cmb_data->last_block;
681 time = cmb_data->last_update - cdev->private->cmb_start_time;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682
683 memset(data, 0, sizeof(struct cmbdata));
684
685 /* we only know values before device_busy_time */
686 data->size = offsetof(struct cmbdata, device_busy_time);
687
Sebastian Ott08c6df92017-09-12 11:21:00 +0200688 data->elapsed_time = tod_to_ns(time);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689
690 /* copy data to new structure */
Cornelia Huck94bb0632006-06-29 15:08:41 +0200691 data->ssch_rsch_count = cmb->ssch_rsch_count;
692 data->sample_count = cmb->sample_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693
694 /* time fields are converted to nanoseconds while copying */
Cornelia Huck94bb0632006-06-29 15:08:41 +0200695 data->device_connect_time = time_to_nsec(cmb->device_connect_time);
696 data->function_pending_time = time_to_nsec(cmb->function_pending_time);
697 data->device_disconnect_time =
698 time_to_nsec(cmb->device_disconnect_time);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699 data->control_unit_queuing_time
Cornelia Huck94bb0632006-06-29 15:08:41 +0200700 = time_to_nsec(cmb->control_unit_queuing_time);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701 data->device_active_only_time
Cornelia Huck94bb0632006-06-29 15:08:41 +0200702 = time_to_nsec(cmb->device_active_only_time);
703 ret = 0;
704out:
705 spin_unlock_irqrestore(cdev->ccwlock, flags);
706 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707}
708
Cornelia Huck94bb0632006-06-29 15:08:41 +0200709static void reset_cmb(struct ccw_device *cdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710{
Cornelia Huck94bb0632006-06-29 15:08:41 +0200711 cmf_generic_reset(cdev);
712}
713
Sebastian Ott0f5d0502016-07-12 19:57:57 +0200714static int cmf_enabled(struct ccw_device *cdev)
715{
716 int enabled;
717
718 spin_lock_irq(cdev->ccwlock);
719 enabled = !!cdev->private->cmb;
720 spin_unlock_irq(cdev->ccwlock);
721
722 return enabled;
723}
724
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725static struct attribute_group cmf_attr_group;
726
727static struct cmb_operations cmbops_basic = {
728 .alloc = alloc_cmb,
729 .free = free_cmb,
730 .set = set_cmb,
731 .read = read_cmb,
732 .readall = readall_cmb,
733 .reset = reset_cmb,
734 .attr_group = &cmf_attr_group,
735};
Heiko Carstens364c8552007-10-12 16:11:35 +0200736
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737/* ******** extended cmb handling ********/
738
739/**
740 * struct cmbe - extended channel measurement block
Cornelia Huckc0208712007-10-12 16:11:16 +0200741 * @ssch_rsch_count: number of ssch and rsch
742 * @sample_count: number of samples
743 * @device_connect_time: time of device connect
744 * @function_pending_time: time of function pending
745 * @device_disconnect_time: time of device disconnect
746 * @control_unit_queuing_time: time of control unit queuing
747 * @device_active_only_time: time of device active only
748 * @device_busy_time: time of device busy
749 * @initial_command_response_time: initial command response time
750 * @reserved: unused
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751 *
Cornelia Huckc0208712007-10-12 16:11:16 +0200752 * The measurement block as used by the hardware. May be in any 64 bit physical
753 * location.
754 * The fields are described further in z/Architecture Principles of Operation,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755 * third edition, chapter 17.
756 */
757struct cmbe {
758 u32 ssch_rsch_count;
759 u32 sample_count;
760 u32 device_connect_time;
761 u32 function_pending_time;
762 u32 device_disconnect_time;
763 u32 control_unit_queuing_time;
764 u32 device_active_only_time;
765 u32 device_busy_time;
766 u32 initial_command_response_time;
767 u32 reserved[7];
Sebastian Ott45bf4b92015-09-07 19:53:01 +0200768} __packed __aligned(64);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769
Sebastian Ott45bf4b92015-09-07 19:53:01 +0200770static struct kmem_cache *cmbe_cache;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771
Cornelia Huckfc5019c2007-10-12 16:11:15 +0200772static int alloc_cmbe(struct ccw_device *cdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773{
Cornelia Huck94bb0632006-06-29 15:08:41 +0200774 struct cmb_data *cmb_data;
Sebastian Ott616503d2015-09-07 19:52:06 +0200775 struct cmbe *cmbe;
776 int ret = -ENOMEM;
Cornelia Huck94bb0632006-06-29 15:08:41 +0200777
Sebastian Ott45bf4b92015-09-07 19:53:01 +0200778 cmbe = kmem_cache_zalloc(cmbe_cache, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 if (!cmbe)
Sebastian Ott616503d2015-09-07 19:52:06 +0200780 return ret;
781
Sebastian Ott45bf4b92015-09-07 19:53:01 +0200782 cmb_data = kzalloc(sizeof(*cmb_data), GFP_KERNEL);
Sebastian Ott616503d2015-09-07 19:52:06 +0200783 if (!cmb_data)
Cornelia Huck94bb0632006-06-29 15:08:41 +0200784 goto out_free;
Sebastian Ott616503d2015-09-07 19:52:06 +0200785
Cornelia Huck94bb0632006-06-29 15:08:41 +0200786 cmb_data->last_block = kzalloc(sizeof(struct cmbe), GFP_KERNEL);
Sebastian Ott616503d2015-09-07 19:52:06 +0200787 if (!cmb_data->last_block)
Cornelia Huck94bb0632006-06-29 15:08:41 +0200788 goto out_free;
Sebastian Ott616503d2015-09-07 19:52:06 +0200789
Sebastian Ott45bf4b92015-09-07 19:53:01 +0200790 cmb_data->size = sizeof(*cmbe);
Cornelia Huck94bb0632006-06-29 15:08:41 +0200791 cmb_data->hw_block = cmbe;
Sebastian Ott616503d2015-09-07 19:52:06 +0200792
793 spin_lock(&cmb_area.lock);
794 spin_lock_irq(cdev->ccwlock);
795 if (cdev->private->cmb)
796 goto out_unlock;
797
Cornelia Huck94bb0632006-06-29 15:08:41 +0200798 cdev->private->cmb = cmb_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799
800 /* activate global measurement if this is the first channel */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801 if (list_empty(&cmb_area.list))
Heiko Carstens7b4ff872016-06-20 14:03:38 +0200802 cmf_activate(NULL, CMF_ON);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 list_add_tail(&cdev->private->cmb_list, &cmb_area.list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804
Sebastian Ott616503d2015-09-07 19:52:06 +0200805 spin_unlock_irq(cdev->ccwlock);
806 spin_unlock(&cmb_area.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807 return 0;
Sebastian Ott616503d2015-09-07 19:52:06 +0200808
809out_unlock:
810 spin_unlock_irq(cdev->ccwlock);
811 spin_unlock(&cmb_area.lock);
812 ret = -EBUSY;
Cornelia Huck94bb0632006-06-29 15:08:41 +0200813out_free:
814 if (cmb_data)
815 kfree(cmb_data->last_block);
816 kfree(cmb_data);
Sebastian Ott45bf4b92015-09-07 19:53:01 +0200817 kmem_cache_free(cmbe_cache, cmbe);
818
Cornelia Huck94bb0632006-06-29 15:08:41 +0200819 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820}
821
Cornelia Huckfc5019c2007-10-12 16:11:15 +0200822static void free_cmbe(struct ccw_device *cdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823{
Cornelia Huck94bb0632006-06-29 15:08:41 +0200824 struct cmb_data *cmb_data;
825
Sebastian Ott616503d2015-09-07 19:52:06 +0200826 spin_lock(&cmb_area.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827 spin_lock_irq(cdev->ccwlock);
Cornelia Huck94bb0632006-06-29 15:08:41 +0200828 cmb_data = cdev->private->cmb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829 cdev->private->cmb = NULL;
Sebastian Otta5e9ca52015-09-07 19:52:31 +0200830 if (cmb_data) {
Cornelia Huck94bb0632006-06-29 15:08:41 +0200831 kfree(cmb_data->last_block);
Sebastian Ott45bf4b92015-09-07 19:53:01 +0200832 kmem_cache_free(cmbe_cache, cmb_data->hw_block);
Sebastian Otta5e9ca52015-09-07 19:52:31 +0200833 }
Cornelia Huck94bb0632006-06-29 15:08:41 +0200834 kfree(cmb_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835
836 /* deactivate global measurement if this is the last channel */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 list_del_init(&cdev->private->cmb_list);
838 if (list_empty(&cmb_area.list))
Heiko Carstens7b4ff872016-06-20 14:03:38 +0200839 cmf_activate(NULL, CMF_OFF);
Sebastian Ott616503d2015-09-07 19:52:06 +0200840 spin_unlock_irq(cdev->ccwlock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841 spin_unlock(&cmb_area.lock);
842}
843
Cornelia Huck94bb0632006-06-29 15:08:41 +0200844static int set_cmbe(struct ccw_device *cdev, u32 mme)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845{
846 unsigned long mba;
Cornelia Huck94bb0632006-06-29 15:08:41 +0200847 struct cmb_data *cmb_data;
848 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849
Cornelia Huck94bb0632006-06-29 15:08:41 +0200850 spin_lock_irqsave(cdev->ccwlock, flags);
851 if (!cdev->private->cmb) {
852 spin_unlock_irqrestore(cdev->ccwlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853 return -EINVAL;
Cornelia Huck94bb0632006-06-29 15:08:41 +0200854 }
855 cmb_data = cdev->private->cmb;
Sebastian Ott45bf4b92015-09-07 19:53:01 +0200856 mba = mme ? (unsigned long) cmb_data->hw_block : 0;
Cornelia Huck94bb0632006-06-29 15:08:41 +0200857 spin_unlock_irqrestore(cdev->ccwlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858
859 return set_schib_wait(cdev, mme, 1, mba);
860}
861
Cornelia Huckfc5019c2007-10-12 16:11:15 +0200862static u64 read_cmbe(struct ccw_device *cdev, int index)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863{
Cornelia Huck94bb0632006-06-29 15:08:41 +0200864 struct cmb_data *cmb_data;
Cornelia Huck94bb0632006-06-29 15:08:41 +0200865 unsigned long flags;
Sebastian Ottd4d287e2017-09-07 13:18:40 +0200866 struct cmbe *cmb;
Sebastian Ottcb09b352017-09-08 21:01:38 +0200867 u64 ret = 0;
Sebastian Ottd4d287e2017-09-07 13:18:40 +0200868 u32 val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869
870 spin_lock_irqsave(cdev->ccwlock, flags);
Cornelia Huck94bb0632006-06-29 15:08:41 +0200871 cmb_data = cdev->private->cmb;
Sebastian Ottd4d287e2017-09-07 13:18:40 +0200872 if (!cmb_data)
Cornelia Huck94bb0632006-06-29 15:08:41 +0200873 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874
Sebastian Ottd4d287e2017-09-07 13:18:40 +0200875 cmb = cmb_data->hw_block;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876 switch (index) {
Sebastian Ottcb09b352017-09-08 21:01:38 +0200877 case avg_utilization:
878 ret = __cmb_utilization(cmb->device_connect_time,
879 cmb->function_pending_time,
880 cmb->device_disconnect_time,
881 cdev->private->cmb_start_time);
882 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883 case cmb_ssch_rsch_count:
Cornelia Huck94bb0632006-06-29 15:08:41 +0200884 ret = cmb->ssch_rsch_count;
885 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886 case cmb_sample_count:
Cornelia Huck94bb0632006-06-29 15:08:41 +0200887 ret = cmb->sample_count;
888 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 case cmb_device_connect_time:
Cornelia Huck94bb0632006-06-29 15:08:41 +0200890 val = cmb->device_connect_time;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891 break;
892 case cmb_function_pending_time:
Cornelia Huck94bb0632006-06-29 15:08:41 +0200893 val = cmb->function_pending_time;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894 break;
895 case cmb_device_disconnect_time:
Cornelia Huck94bb0632006-06-29 15:08:41 +0200896 val = cmb->device_disconnect_time;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897 break;
898 case cmb_control_unit_queuing_time:
Cornelia Huck94bb0632006-06-29 15:08:41 +0200899 val = cmb->control_unit_queuing_time;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900 break;
901 case cmb_device_active_only_time:
Cornelia Huck94bb0632006-06-29 15:08:41 +0200902 val = cmb->device_active_only_time;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903 break;
904 case cmb_device_busy_time:
Cornelia Huck94bb0632006-06-29 15:08:41 +0200905 val = cmb->device_busy_time;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906 break;
907 case cmb_initial_command_response_time:
Cornelia Huck94bb0632006-06-29 15:08:41 +0200908 val = cmb->initial_command_response_time;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 break;
910 default:
Cornelia Huck94bb0632006-06-29 15:08:41 +0200911 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912 }
Cornelia Huck94bb0632006-06-29 15:08:41 +0200913 ret = time_to_avg_nsec(val, cmb->sample_count);
914out:
915 spin_unlock_irqrestore(cdev->ccwlock, flags);
916 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917}
918
Cornelia Huckfc5019c2007-10-12 16:11:15 +0200919static int readall_cmbe(struct ccw_device *cdev, struct cmbdata *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920{
Cornelia Huck94bb0632006-06-29 15:08:41 +0200921 struct cmbe *cmb;
922 struct cmb_data *cmb_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923 u64 time;
Cornelia Huck94bb0632006-06-29 15:08:41 +0200924 unsigned long flags;
925 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926
Cornelia Huck94bb0632006-06-29 15:08:41 +0200927 ret = cmf_cmb_copy_wait(cdev);
928 if (ret < 0)
929 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930 spin_lock_irqsave(cdev->ccwlock, flags);
Cornelia Huck94bb0632006-06-29 15:08:41 +0200931 cmb_data = cdev->private->cmb;
932 if (!cmb_data) {
933 ret = -ENODEV;
934 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935 }
Cornelia Huck94bb0632006-06-29 15:08:41 +0200936 if (cmb_data->last_update == 0) {
937 ret = -EAGAIN;
938 goto out;
939 }
940 time = cmb_data->last_update - cdev->private->cmb_start_time;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941
942 memset (data, 0, sizeof(struct cmbdata));
943
944 /* we only know values before device_busy_time */
945 data->size = offsetof(struct cmbdata, device_busy_time);
946
Sebastian Ott08c6df92017-09-12 11:21:00 +0200947 data->elapsed_time = tod_to_ns(time);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948
Cornelia Huck94bb0632006-06-29 15:08:41 +0200949 cmb = cmb_data->last_block;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950 /* copy data to new structure */
Cornelia Huck94bb0632006-06-29 15:08:41 +0200951 data->ssch_rsch_count = cmb->ssch_rsch_count;
952 data->sample_count = cmb->sample_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953
954 /* time fields are converted to nanoseconds while copying */
Cornelia Huck94bb0632006-06-29 15:08:41 +0200955 data->device_connect_time = time_to_nsec(cmb->device_connect_time);
956 data->function_pending_time = time_to_nsec(cmb->function_pending_time);
957 data->device_disconnect_time =
958 time_to_nsec(cmb->device_disconnect_time);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959 data->control_unit_queuing_time
Cornelia Huck94bb0632006-06-29 15:08:41 +0200960 = time_to_nsec(cmb->control_unit_queuing_time);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961 data->device_active_only_time
Cornelia Huck94bb0632006-06-29 15:08:41 +0200962 = time_to_nsec(cmb->device_active_only_time);
963 data->device_busy_time = time_to_nsec(cmb->device_busy_time);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964 data->initial_command_response_time
Cornelia Huck94bb0632006-06-29 15:08:41 +0200965 = time_to_nsec(cmb->initial_command_response_time);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966
Cornelia Huck94bb0632006-06-29 15:08:41 +0200967 ret = 0;
968out:
969 spin_unlock_irqrestore(cdev->ccwlock, flags);
970 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971}
972
Cornelia Huck94bb0632006-06-29 15:08:41 +0200973static void reset_cmbe(struct ccw_device *cdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974{
Cornelia Huck94bb0632006-06-29 15:08:41 +0200975 cmf_generic_reset(cdev);
976}
977
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978static struct attribute_group cmf_attr_group_ext;
979
980static struct cmb_operations cmbops_extended = {
981 .alloc = alloc_cmbe,
982 .free = free_cmbe,
983 .set = set_cmbe,
984 .read = read_cmbe,
985 .readall = readall_cmbe,
986 .reset = reset_cmbe,
987 .attr_group = &cmf_attr_group_ext,
988};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989
Cornelia Huckfc5019c2007-10-12 16:11:15 +0200990static ssize_t cmb_show_attr(struct device *dev, char *buf, enum cmb_index idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991{
992 return sprintf(buf, "%lld\n",
993 (unsigned long long) cmf_read(to_ccwdev(dev), idx));
994}
995
Cornelia Huckfc5019c2007-10-12 16:11:15 +0200996static ssize_t cmb_show_avg_sample_interval(struct device *dev,
997 struct device_attribute *attr,
998 char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999{
Sebastian Ottd4d287e2017-09-07 13:18:40 +02001000 struct ccw_device *cdev = to_ccwdev(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001 unsigned long count;
Sebastian Ottd4d287e2017-09-07 13:18:40 +02001002 long interval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004 count = cmf_read(cdev, cmb_sample_count);
Cornelia Huck94bb0632006-06-29 15:08:41 +02001005 spin_lock_irq(cdev->ccwlock);
Cornelia Huck94bb0632006-06-29 15:08:41 +02001006 if (count) {
Sebastian Ottd4d287e2017-09-07 13:18:40 +02001007 interval = get_tod_clock() - cdev->private->cmb_start_time;
Sebastian Ott08c6df92017-09-12 11:21:00 +02001008 interval = tod_to_ns(interval);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009 interval /= count;
Cornelia Huck94bb0632006-06-29 15:08:41 +02001010 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011 interval = -1;
Cornelia Huck94bb0632006-06-29 15:08:41 +02001012 spin_unlock_irq(cdev->ccwlock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013 return sprintf(buf, "%ld\n", interval);
1014}
1015
Cornelia Huckfc5019c2007-10-12 16:11:15 +02001016static ssize_t cmb_show_avg_utilization(struct device *dev,
1017 struct device_attribute *attr,
1018 char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019{
Sebastian Ottcb09b352017-09-08 21:01:38 +02001020 unsigned long u = cmf_read(to_ccwdev(dev), avg_utilization);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021
Sebastian Ottcb09b352017-09-08 21:01:38 +02001022 return sprintf(buf, "%02lu.%01lu%%\n", u / 10, u % 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023}
1024
1025#define cmf_attr(name) \
Cornelia Huckfc5019c2007-10-12 16:11:15 +02001026static ssize_t show_##name(struct device *dev, \
1027 struct device_attribute *attr, char *buf) \
1028{ return cmb_show_attr((dev), buf, cmb_##name); } \
1029static DEVICE_ATTR(name, 0444, show_##name, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001030
1031#define cmf_attr_avg(name) \
Cornelia Huckfc5019c2007-10-12 16:11:15 +02001032static ssize_t show_avg_##name(struct device *dev, \
1033 struct device_attribute *attr, char *buf) \
1034{ return cmb_show_attr((dev), buf, cmb_##name); } \
1035static DEVICE_ATTR(avg_##name, 0444, show_avg_##name, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036
1037cmf_attr(ssch_rsch_count);
1038cmf_attr(sample_count);
1039cmf_attr_avg(device_connect_time);
1040cmf_attr_avg(function_pending_time);
1041cmf_attr_avg(device_disconnect_time);
1042cmf_attr_avg(control_unit_queuing_time);
1043cmf_attr_avg(device_active_only_time);
1044cmf_attr_avg(device_busy_time);
1045cmf_attr_avg(initial_command_response_time);
1046
Cornelia Huckfc5019c2007-10-12 16:11:15 +02001047static DEVICE_ATTR(avg_sample_interval, 0444, cmb_show_avg_sample_interval,
1048 NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049static DEVICE_ATTR(avg_utilization, 0444, cmb_show_avg_utilization, NULL);
1050
1051static struct attribute *cmf_attributes[] = {
1052 &dev_attr_avg_sample_interval.attr,
1053 &dev_attr_avg_utilization.attr,
1054 &dev_attr_ssch_rsch_count.attr,
1055 &dev_attr_sample_count.attr,
1056 &dev_attr_avg_device_connect_time.attr,
1057 &dev_attr_avg_function_pending_time.attr,
1058 &dev_attr_avg_device_disconnect_time.attr,
1059 &dev_attr_avg_control_unit_queuing_time.attr,
1060 &dev_attr_avg_device_active_only_time.attr,
Heiko Carstensd2c993d2006-07-12 16:41:55 +02001061 NULL,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062};
1063
1064static struct attribute_group cmf_attr_group = {
1065 .name = "cmf",
1066 .attrs = cmf_attributes,
1067};
1068
1069static struct attribute *cmf_attributes_ext[] = {
1070 &dev_attr_avg_sample_interval.attr,
1071 &dev_attr_avg_utilization.attr,
1072 &dev_attr_ssch_rsch_count.attr,
1073 &dev_attr_sample_count.attr,
1074 &dev_attr_avg_device_connect_time.attr,
1075 &dev_attr_avg_function_pending_time.attr,
1076 &dev_attr_avg_device_disconnect_time.attr,
1077 &dev_attr_avg_control_unit_queuing_time.attr,
1078 &dev_attr_avg_device_active_only_time.attr,
1079 &dev_attr_avg_device_busy_time.attr,
1080 &dev_attr_avg_initial_command_response_time.attr,
Heiko Carstensd2c993d2006-07-12 16:41:55 +02001081 NULL,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082};
1083
1084static struct attribute_group cmf_attr_group_ext = {
1085 .name = "cmf",
1086 .attrs = cmf_attributes_ext,
1087};
1088
Cornelia Huckfc5019c2007-10-12 16:11:15 +02001089static ssize_t cmb_enable_show(struct device *dev,
1090 struct device_attribute *attr,
1091 char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092{
Sebastian Ott279b8f92015-09-07 19:50:25 +02001093 struct ccw_device *cdev = to_ccwdev(dev);
Sebastian Ott279b8f92015-09-07 19:50:25 +02001094
Sebastian Ott0f5d0502016-07-12 19:57:57 +02001095 return sprintf(buf, "%d\n", cmf_enabled(cdev));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096}
1097
Cornelia Huckfc5019c2007-10-12 16:11:15 +02001098static ssize_t cmb_enable_store(struct device *dev,
1099 struct device_attribute *attr, const char *buf,
1100 size_t c)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101{
Sebastian Ott279b8f92015-09-07 19:50:25 +02001102 struct ccw_device *cdev = to_ccwdev(dev);
Cornelia Huck2f972202008-04-30 13:38:33 +02001103 unsigned long val;
Sebastian Ott279b8f92015-09-07 19:50:25 +02001104 int ret;
Cornelia Huck2f972202008-04-30 13:38:33 +02001105
Jingoo Han01787222013-07-22 10:18:15 +09001106 ret = kstrtoul(buf, 16, &val);
Cornelia Huck2f972202008-04-30 13:38:33 +02001107 if (ret)
1108 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109
Cornelia Huck2f972202008-04-30 13:38:33 +02001110 switch (val) {
1111 case 0:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112 ret = disable_cmf(cdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113 break;
Cornelia Huck2f972202008-04-30 13:38:33 +02001114 case 1:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115 ret = enable_cmf(cdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116 break;
Sebastian Ott279b8f92015-09-07 19:50:25 +02001117 default:
1118 ret = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119 }
1120
Sebastian Ott279b8f92015-09-07 19:50:25 +02001121 return ret ? ret : c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122}
Sebastian Ott279b8f92015-09-07 19:50:25 +02001123DEVICE_ATTR_RW(cmb_enable);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124
Sebastian Ott823d4942009-06-16 10:30:20 +02001125int ccw_set_cmf(struct ccw_device *cdev, int enable)
1126{
1127 return cmbops->set(cdev, enable ? 2 : 0);
1128}
1129
Cornelia Huckc0208712007-10-12 16:11:16 +02001130/**
1131 * enable_cmf() - switch on the channel measurement for a specific device
1132 * @cdev: The ccw device to be enabled
1133 *
1134 * Returns %0 for success or a negative error value.
Sebastian Ott0f5d0502016-07-12 19:57:57 +02001135 * Note: If this is called on a device for which channel measurement is already
1136 * enabled a reset of the measurement data is triggered.
Cornelia Huckc0208712007-10-12 16:11:16 +02001137 * Context:
1138 * non-atomic
1139 */
Cornelia Huckfc5019c2007-10-12 16:11:15 +02001140int enable_cmf(struct ccw_device *cdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141{
Sebastian Ott0f5d0502016-07-12 19:57:57 +02001142 int ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143
Sebastian Ott1bc66642015-09-15 13:11:42 +02001144 device_lock(&cdev->dev);
Sebastian Ott0f5d0502016-07-12 19:57:57 +02001145 if (cmf_enabled(cdev)) {
1146 cmbops->reset(cdev);
1147 goto out_unlock;
1148 }
Sebastian Otta6ef1562015-09-07 19:51:39 +02001149 get_device(&cdev->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150 ret = cmbops->alloc(cdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151 if (ret)
Sebastian Ott1bc66642015-09-15 13:11:42 +02001152 goto out;
1153 cmbops->reset(cdev);
1154 ret = sysfs_create_group(&cdev->dev.kobj, cmbops->attr_group);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155 if (ret) {
1156 cmbops->free(cdev);
Sebastian Ott1bc66642015-09-15 13:11:42 +02001157 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158 }
Sebastian Ott1bc66642015-09-15 13:11:42 +02001159 ret = cmbops->set(cdev, 2);
1160 if (ret) {
1161 sysfs_remove_group(&cdev->dev.kobj, cmbops->attr_group);
1162 cmbops->free(cdev);
1163 }
1164out:
Sebastian Otta6ef1562015-09-07 19:51:39 +02001165 if (ret)
1166 put_device(&cdev->dev);
Sebastian Ott0f5d0502016-07-12 19:57:57 +02001167out_unlock:
Sebastian Ott1bc66642015-09-15 13:11:42 +02001168 device_unlock(&cdev->dev);
1169 return ret;
1170}
1171
1172/**
1173 * __disable_cmf() - switch off the channel measurement for a specific device
1174 * @cdev: The ccw device to be disabled
1175 *
1176 * Returns %0 for success or a negative error value.
1177 *
1178 * Context:
1179 * non-atomic, device_lock() held.
1180 */
1181int __disable_cmf(struct ccw_device *cdev)
1182{
1183 int ret;
1184
1185 ret = cmbops->set(cdev, 0);
1186 if (ret)
1187 return ret;
1188
1189 sysfs_remove_group(&cdev->dev.kobj, cmbops->attr_group);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001190 cmbops->free(cdev);
Sebastian Otta6ef1562015-09-07 19:51:39 +02001191 put_device(&cdev->dev);
Sebastian Ott1bc66642015-09-15 13:11:42 +02001192
Linus Torvalds1da177e2005-04-16 15:20:36 -07001193 return ret;
1194}
1195
Cornelia Huckc0208712007-10-12 16:11:16 +02001196/**
1197 * disable_cmf() - switch off the channel measurement for a specific device
1198 * @cdev: The ccw device to be disabled
1199 *
1200 * Returns %0 for success or a negative error value.
1201 *
1202 * Context:
1203 * non-atomic
1204 */
Cornelia Huckfc5019c2007-10-12 16:11:15 +02001205int disable_cmf(struct ccw_device *cdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206{
1207 int ret;
1208
Sebastian Ott1bc66642015-09-15 13:11:42 +02001209 device_lock(&cdev->dev);
1210 ret = __disable_cmf(cdev);
1211 device_unlock(&cdev->dev);
1212
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213 return ret;
1214}
1215
Cornelia Huckc0208712007-10-12 16:11:16 +02001216/**
1217 * cmf_read() - read one value from the current channel measurement block
1218 * @cdev: the channel to be read
1219 * @index: the index of the value to be read
1220 *
1221 * Returns the value read or %0 if the value cannot be read.
1222 *
1223 * Context:
1224 * any
1225 */
Cornelia Huckfc5019c2007-10-12 16:11:15 +02001226u64 cmf_read(struct ccw_device *cdev, int index)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001227{
1228 return cmbops->read(cdev, index);
1229}
1230
Cornelia Huckc0208712007-10-12 16:11:16 +02001231/**
1232 * cmf_readall() - read the current channel measurement block
1233 * @cdev: the channel to be read
1234 * @data: a pointer to a data block that will be filled
1235 *
1236 * Returns %0 on success, a negative error value otherwise.
1237 *
1238 * Context:
1239 * any
1240 */
Cornelia Huckfc5019c2007-10-12 16:11:15 +02001241int cmf_readall(struct ccw_device *cdev, struct cmbdata *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242{
1243 return cmbops->readall(cdev, data);
1244}
1245
Cornelia Huck94bb0632006-06-29 15:08:41 +02001246/* Reenable cmf when a disconnected device becomes available again. */
1247int cmf_reenable(struct ccw_device *cdev)
1248{
1249 cmbops->reset(cdev);
1250 return cmbops->set(cdev, 2);
1251}
1252
Sebastian Ottab97d212015-09-09 10:29:59 +02001253/**
1254 * cmf_reactivate() - reactivate measurement block updates
1255 *
1256 * Use this during resume from hibernate.
1257 */
1258void cmf_reactivate(void)
1259{
1260 spin_lock(&cmb_area.lock);
1261 if (!list_empty(&cmb_area.list))
Heiko Carstens7b4ff872016-06-20 14:03:38 +02001262 cmf_activate(cmb_area.mem, CMF_ON);
Sebastian Ottab97d212015-09-09 10:29:59 +02001263 spin_unlock(&cmb_area.lock);
1264}
1265
Sebastian Ott45bf4b92015-09-07 19:53:01 +02001266static int __init init_cmbe(void)
1267{
1268 cmbe_cache = kmem_cache_create("cmbe_cache", sizeof(struct cmbe),
1269 __alignof__(struct cmbe), 0, NULL);
1270
1271 return cmbe_cache ? 0 : -ENOMEM;
1272}
1273
Cornelia Huckfc5019c2007-10-12 16:11:15 +02001274static int __init init_cmf(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001275{
1276 char *format_string;
Sebastian Ott45bf4b92015-09-07 19:53:01 +02001277 char *detect_string;
1278 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279
Cornelia Huckfc5019c2007-10-12 16:11:15 +02001280 /*
1281 * If the user did not give a parameter, see if we are running on a
1282 * machine supporting extended measurement blocks, otherwise fall back
1283 * to basic mode.
1284 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001285 if (format == CMF_AUTODETECT) {
Cornelia Huck75784c02008-07-14 09:58:57 +02001286 if (!css_general_characteristics.ext_mb) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001287 format = CMF_BASIC;
1288 } else {
1289 format = CMF_EXTENDED;
1290 }
1291 detect_string = "autodetected";
1292 } else {
1293 detect_string = "parameter";
1294 }
1295
1296 switch (format) {
1297 case CMF_BASIC:
1298 format_string = "basic";
1299 cmbops = &cmbops_basic;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300 break;
1301 case CMF_EXTENDED:
Cornelia Huckfc5019c2007-10-12 16:11:15 +02001302 format_string = "extended";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001303 cmbops = &cmbops_extended;
Sebastian Ott45bf4b92015-09-07 19:53:01 +02001304
1305 ret = init_cmbe();
1306 if (ret)
1307 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308 break;
1309 default:
Sebastian Ott45bf4b92015-09-07 19:53:01 +02001310 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311 }
Michael Ernste6d5a422008-12-25 13:39:36 +01001312 pr_info("Channel measurement facility initialized using format "
1313 "%s (mode %s)\n", format_string, detect_string);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314 return 0;
1315}
Paul Gortmakera00f7612016-10-30 16:37:24 -04001316device_initcall(init_cmf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317
1318EXPORT_SYMBOL_GPL(enable_cmf);
1319EXPORT_SYMBOL_GPL(disable_cmf);
1320EXPORT_SYMBOL_GPL(cmf_read);
1321EXPORT_SYMBOL_GPL(cmf_readall);