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