/*
* linux/drivers/s390/cio/cmf.c
*
* Linux on zSeries Channel Measurement Facility support
*
* Copyright 2000,2006 IBM Corporation
*
* Authors: Arnd Bergmann <arndb@de.ibm.com>
* Cornelia Huck <cornelia.huck@de.ibm.com>
*
* original idea from Natarajan Krishnaswami <nkrishna@us.ibm.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#define KMSG_COMPONENT "cio"
#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
#include <linux/bootmem.h>
#include <linux/device.h>
#include <linux/init.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <linux/timex.h> /* get_clock() */
#include <asm/ccwdev.h>
#include <asm/cio.h>
#include <asm/cmb.h>
#include <asm/div64.h>
#include "cio.h"
#include "css.h"
#include "device.h"
#include "ioasm.h"
#include "chsc.h"
/*
* parameter to enable cmf during boot, possible uses are:
* "s390cmf" -- enable cmf and allocate 2 MB of ram so measuring can be
* used on any subchannel
* "s390cmf=<num>" -- enable cmf and allocate enough memory to measure
* <num> subchannel, where <num> is an integer
* between 1 and 65535, default is 1024
*/
#define ARGSTRING "s390cmf"
/* indices for READCMB */
enum cmb_index {
/* basic and exended format: */
cmb_ssch_rsch_count,
cmb_sample_count,
cmb_device_connect_time,
cmb_function_pending_time,
cmb_device_disconnect_time,
cmb_control_unit_queuing_time,
cmb_device_active_only_time,
/* extended format only: */
cmb_device_busy_time,
cmb_initial_command_response_time,
};
/**
* enum cmb_format - types of supported measurement block formats
*
* @CMF_BASIC: traditional channel measurement blocks supported
* by all machines that we run on
* @CMF_EXTENDED: improved format that was introduced with the z990
* machine
* @CMF_AUTODETECT: default: use extended format when running on a machine
* supporting extended format, otherwise fall back to
* basic format
*/
enum cmb_format {
CMF_BASIC,
CMF_EXTENDED,
CMF_AUTODETECT = -1,
};
/*
* format - actual format for all measurement blocks
*
* The format module parameter can be set to a value of 0 (zero)
* or 1, indicating basic or extended format as described for
* enum cmb_format.
*/
static int format = CMF_AUTODETECT;
module_param(format, bint, 0444);
/**
* struct cmb_operations - functions to use depending on cmb_format
*
* Most of these functions operate on a struct ccw_device. There is only
* one instance of struct cmb_operations because the format of the measurement
* data is guaranteed to be the same for every ccw_device.
*
* @alloc: allocate memory for a channel measurement block,
* either with the help of a special pool or with kmalloc
* @free: free memory allocated with @alloc
* @set: enable or disable measurement
* @read: read a measurement entry at an index
* @readall: read a measurement block in a common format
* @reset: clear the data in the associated measurement block and
* reset its time stamp
* @align: align an allocated block so that the hardware can use it
*/
struct cmb_operations {
int (*alloc) (struct ccw_device *);
void (*free) (struct ccw_device *);
int (*set) (struct ccw_device *, u32);
u64 (*