xref: /OK3568_Linux_fs/kernel/drivers/s390/cio/cmf.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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(&copy_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 = &copy_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(&copy_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