Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux

Pull s390 updates from Martin Schwidefsky:
 "The first part of the s390 updates for 4.14:

   - Add machine type 0x3906 for IBM z14

   - Add IBM z14 TLB flushing improvements for KVM guests

   - Exploit the TOD clock epoch extension to provide a continuous TOD
     clock afer 2042/09/17

   - Add NIAI spinlock hints for IBM z14

   - Rework the vmcp driver and use CMA for the respone buffer of z/VM
     CP commands

   - Drop some s390 specific asm headers and use the generic version

   - Add block discard for DASD-FBA devices under z/VM

   - Add average request times to DASD statistics

   - A few of those constify patches which seem to be in vogue right now

   - Cleanup and bug fixes"

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux: (50 commits)
  s390/mm: avoid empty zero pages for KVM guests to avoid postcopy hangs
  s390/dasd: Add discard support for FBA devices
  s390/zcrypt: make CPRBX const
  s390/uaccess: avoid mvcos jump label
  s390/mm: use generic mm_hooks
  s390/facilities: fix typo
  s390/vmcp: simplify vmcp_response_free()
  s390/topology: Remove the unused parent_node() macro
  s390/dasd: Change unsigned long long to unsigned long
  s390/smp: convert cpuhp_setup_state() return code to zero on success
  s390: fix 'novx' early parameter handling
  s390/dasd: add average request times to dasd statistics
  s390/scm: use common completion path
  s390/pci: log changes to uid checking
  s390/vmcp: simplify vmcp_ioctl()
  s390/vmcp: return -ENOTTY for unknown ioctl commands
  s390/vmcp: split vmcp header file and move to uapi
  s390/vmcp: make use of contiguous memory allocator
  s390/cpcmd,vmcp: avoid GFP_DMA allocations
  s390/vmcp: fix uaccess check and avoid undefined behavior
  ...
This commit is contained in:
Linus Torvalds 2017-09-05 09:45:46 -07:00
commit 9e85ae6af6
87 changed files with 1405 additions and 694 deletions

View file

@ -801,11 +801,12 @@ static void dasd_profile_end(struct dasd_block *block,
struct dasd_ccw_req *cqr,
struct request *req)
{
long strtime, irqtime, endtime, tottime; /* in microseconds */
long tottimeps, sectors;
unsigned long strtime, irqtime, endtime, tottime;
unsigned long tottimeps, sectors;
struct dasd_device *device;
int sectors_ind, tottime_ind, tottimeps_ind, strtime_ind;
int irqtime_ind, irqtimeps_ind, endtime_ind;
struct dasd_profile_info *data;
device = cqr->startdev;
if (!(dasd_global_profile_level ||
@ -835,6 +836,11 @@ static void dasd_profile_end(struct dasd_block *block,
spin_lock(&dasd_global_profile.lock);
if (dasd_global_profile.data) {
data = dasd_global_profile.data;
data->dasd_sum_times += tottime;
data->dasd_sum_time_str += strtime;
data->dasd_sum_time_irq += irqtime;
data->dasd_sum_time_end += endtime;
dasd_profile_end_add_data(dasd_global_profile.data,
cqr->startdev != block->base,
cqr->cpmode == 1,
@ -847,7 +853,12 @@ static void dasd_profile_end(struct dasd_block *block,
spin_unlock(&dasd_global_profile.lock);
spin_lock(&block->profile.lock);
if (block->profile.data)
if (block->profile.data) {
data = block->profile.data;
data->dasd_sum_times += tottime;
data->dasd_sum_time_str += strtime;
data->dasd_sum_time_irq += irqtime;
data->dasd_sum_time_end += endtime;
dasd_profile_end_add_data(block->profile.data,
cqr->startdev != block->base,
cqr->cpmode == 1,
@ -856,10 +867,16 @@ static void dasd_profile_end(struct dasd_block *block,
tottimeps_ind, strtime_ind,
irqtime_ind, irqtimeps_ind,
endtime_ind);
}
spin_unlock(&block->profile.lock);
spin_lock(&device->profile.lock);
if (device->profile.data)
if (device->profile.data) {
data = device->profile.data;
data->dasd_sum_times += tottime;
data->dasd_sum_time_str += strtime;
data->dasd_sum_time_irq += irqtime;
data->dasd_sum_time_end += endtime;
dasd_profile_end_add_data(device->profile.data,
cqr->startdev != block->base,
cqr->cpmode == 1,
@ -868,6 +885,7 @@ static void dasd_profile_end(struct dasd_block *block,
tottimeps_ind, strtime_ind,
irqtime_ind, irqtimeps_ind,
endtime_ind);
}
spin_unlock(&device->profile.lock);
}
@ -989,6 +1007,14 @@ static void dasd_stats_seq_print(struct seq_file *m,
seq_printf(m, "total_sectors %u\n", data->dasd_io_sects);
seq_printf(m, "total_pav %u\n", data->dasd_io_alias);
seq_printf(m, "total_hpf %u\n", data->dasd_io_tpm);
seq_printf(m, "avg_total %lu\n", data->dasd_io_reqs ?
data->dasd_sum_times / data->dasd_io_reqs : 0UL);
seq_printf(m, "avg_build_to_ssch %lu\n", data->dasd_io_reqs ?
data->dasd_sum_time_str / data->dasd_io_reqs : 0UL);
seq_printf(m, "avg_ssch_to_irq %lu\n", data->dasd_io_reqs ?
data->dasd_sum_time_irq / data->dasd_io_reqs : 0UL);
seq_printf(m, "avg_irq_to_end %lu\n", data->dasd_io_reqs ?
data->dasd_sum_time_end / data->dasd_io_reqs : 0UL);
seq_puts(m, "histogram_sectors ");
dasd_stats_array(m, data->dasd_io_secs);
seq_puts(m, "histogram_io_times ");
@ -1639,7 +1665,7 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
{
struct dasd_ccw_req *cqr, *next;
struct dasd_device *device;
unsigned long long now;
unsigned long now;
int nrf_suppressed = 0;
int fp_suppressed = 0;
u8 *sense = NULL;
@ -3152,7 +3178,9 @@ static int dasd_alloc_queue(struct dasd_block *block)
*/
static void dasd_setup_queue(struct dasd_block *block)
{
unsigned int logical_block_size = block->bp_block;
struct request_queue *q = block->request_queue;
unsigned int max_bytes, max_discard_sectors;
int max;
if (block->base->features & DASD_FEATURE_USERAW) {
@ -3169,7 +3197,7 @@ static void dasd_setup_queue(struct dasd_block *block)
}
queue_flag_set_unlocked(QUEUE_FLAG_NONROT, q);
q->limits.max_dev_sectors = max;
blk_queue_logical_block_size(q, block->bp_block);
blk_queue_logical_block_size(q, logical_block_size);
blk_queue_max_hw_sectors(q, max);
blk_queue_max_segments(q, USHRT_MAX);
/* with page sized segments we can translate each segement into
@ -3177,6 +3205,21 @@ static void dasd_setup_queue(struct dasd_block *block)
*/
blk_queue_max_segment_size(q, PAGE_SIZE);
blk_queue_segment_boundary(q, PAGE_SIZE - 1);
/* Only activate blocklayer discard support for devices that support it */
if (block->base->features & DASD_FEATURE_DISCARD) {
q->limits.discard_granularity = logical_block_size;
q->limits.discard_alignment = PAGE_SIZE;
/* Calculate max_discard_sectors and make it PAGE aligned */
max_bytes = USHRT_MAX * logical_block_size;
max_bytes = ALIGN(max_bytes, PAGE_SIZE) - PAGE_SIZE;
max_discard_sectors = max_bytes / logical_block_size;
blk_queue_max_discard_sectors(q, max_discard_sectors);
blk_queue_max_write_zeroes_sectors(q, max_discard_sectors);
queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, q);
}
}
/*

View file

@ -2231,7 +2231,7 @@ static void dasd_3990_erp_account_error(struct dasd_ccw_req *erp)
struct dasd_device *device = erp->startdev;
__u8 lpum = erp->refers->irb.esw.esw1.lpum;
int pos = pathmask_to_pos(lpum);
unsigned long long clk;
unsigned long clk;
if (!device->path_thrhld)
return;

View file

@ -1634,7 +1634,7 @@ static struct attribute * dasd_attrs[] = {
NULL,
};
static struct attribute_group dasd_attr_group = {
static const struct attribute_group dasd_attr_group = {
.attrs = dasd_attrs,
};
@ -1676,6 +1676,7 @@ dasd_set_feature(struct ccw_device *cdev, int feature, int flag)
spin_unlock(&dasd_devmap_lock);
return 0;
}
EXPORT_SYMBOL(dasd_set_feature);
int

View file

@ -235,7 +235,7 @@ static void dasd_ext_handler(struct ext_code ext_code,
{
struct dasd_ccw_req *cqr, *next;
struct dasd_device *device;
unsigned long long expires;
unsigned long expires;
unsigned long flags;
addr_t ip;
int rc;

View file

@ -3254,11 +3254,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_track(
/* 1x prefix + one read/write ccw per track */
cplength = 1 + trkcount;
/* on 31-bit we need space for two 32 bit addresses per page
* on 64-bit one 64 bit address
*/
datasize = sizeof(struct PFX_eckd_data) +
cidaw * sizeof(unsigned long long);
datasize = sizeof(struct PFX_eckd_data) + cidaw * sizeof(unsigned long);
/* Allocate the ccw request. */
cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, cplength, datasize,
@ -3856,7 +3852,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_raw(struct dasd_device *startdev,
}
size = ALIGN(size, 8);
datasize = size + cidaw * sizeof(unsigned long long);
datasize = size + cidaw * sizeof(unsigned long);
/* Allocate the ccw request. */
cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, cplength,

View file

@ -165,7 +165,7 @@ struct DE_eckd_data {
__u8 ga_extended; /* Global Attributes Extended */
struct ch_t beg_ext;
struct ch_t end_ext;
unsigned long long ep_sys_time; /* Ext Parameter - System Time Stamp */
unsigned long ep_sys_time; /* Ext Parameter - System Time Stamp */
__u8 ep_format; /* Extended Parameter format byte */
__u8 ep_prio; /* Extended Parameter priority I/O byte */
__u8 ep_reserved1; /* Extended Parameter Reserved */

View file

@ -124,7 +124,7 @@ dasd_default_erp_action(struct dasd_ccw_req *cqr)
struct dasd_ccw_req *dasd_default_erp_postaction(struct dasd_ccw_req *cqr)
{
int success;
unsigned long long startclk, stopclk;
unsigned long startclk, stopclk;
struct dasd_device *startdev;
BUG_ON(cqr->refers == NULL || cqr->function == NULL);

View file

@ -174,6 +174,9 @@ dasd_fba_check_characteristics(struct dasd_device *device)
if (readonly)
set_bit(DASD_FLAG_DEVICE_RO, &device->flags);
/* FBA supports discard, set the according feature bit */
dasd_set_feature(cdev, DASD_FEATURE_DISCARD, 1);
dev_info(&device->cdev->dev,
"New FBA DASD %04X/%02X (CU %04X/%02X) with %d MB "
"and %d B/blk%s\n",
@ -247,9 +250,192 @@ static void dasd_fba_check_for_device_change(struct dasd_device *device,
dasd_generic_handle_state_change(device);
};
static struct dasd_ccw_req *dasd_fba_build_cp(struct dasd_device * memdev,
struct dasd_block *block,
struct request *req)
/*
* Builds a CCW with no data payload
*/
static void ccw_write_no_data(struct ccw1 *ccw)
{
ccw->cmd_code = DASD_FBA_CCW_WRITE;
ccw->flags |= CCW_FLAG_SLI;
ccw->count = 0;
}
/*
* Builds a CCW that writes only zeroes.
*/
static void ccw_write_zero(struct ccw1 *ccw, int count)
{
ccw->cmd_code = DASD_FBA_CCW_WRITE;
ccw->flags |= CCW_FLAG_SLI;
ccw->count = count;
ccw->cda = (__u32) (addr_t) page_to_phys(ZERO_PAGE(0));
}
/*
* Helper function to count the amount of necessary CCWs within a given range
* with 4k alignment and command chaining in mind.
*/
static int count_ccws(sector_t first_rec, sector_t last_rec,
unsigned int blocks_per_page)
{
sector_t wz_stop = 0, d_stop = 0;
int cur_pos = 0;
int count = 0;
if (first_rec % blocks_per_page != 0) {
wz_stop = first_rec + blocks_per_page -
(first_rec % blocks_per_page) - 1;
if (wz_stop > last_rec)
wz_stop = last_rec;
cur_pos = wz_stop - first_rec + 1;
count++;
}
if (last_rec - (first_rec + cur_pos) + 1 >= blocks_per_page) {
if ((last_rec - blocks_per_page + 1) % blocks_per_page != 0)
d_stop = last_rec - ((last_rec - blocks_per_page + 1) %
blocks_per_page);
else
d_stop = last_rec;
cur_pos += d_stop - (first_rec + cur_pos) + 1;
count++;
}
if (cur_pos == 0 || first_rec + cur_pos - 1 < last_rec)
count++;
return count;
}
/*
* This function builds a CCW request for block layer discard requests.
* Each page in the z/VM hypervisor that represents certain records of an FBA
* device will be padded with zeros. This is a special behaviour of the WRITE
* command which is triggered when no data payload is added to the CCW.
*
* Note: Due to issues in some z/VM versions, we can't fully utilise this
* special behaviour. We have to keep a 4k (or 8 block) alignment in mind to
* work around those issues and write actual zeroes to the unaligned parts in
* the request. This workaround might be removed in the future.
*/
static struct dasd_ccw_req *dasd_fba_build_cp_discard(
struct dasd_device *memdev,
struct dasd_block *block,
struct request *req)
{
struct LO_fba_data *LO_data;
struct dasd_ccw_req *cqr;
struct ccw1 *ccw;
sector_t wz_stop = 0, d_stop = 0;
sector_t first_rec, last_rec;
unsigned int blksize = block->bp_block;
unsigned int blocks_per_page;
int wz_count = 0;
int d_count = 0;
int cur_pos = 0; /* Current position within the extent */
int count = 0;
int cplength;
int datasize;
int nr_ccws;
first_rec = blk_rq_pos(req) >> block->s2b_shift;
last_rec =
(blk_rq_pos(req) + blk_rq_sectors(req) - 1) >> block->s2b_shift;
count = last_rec - first_rec + 1;
blocks_per_page = BLOCKS_PER_PAGE(blksize);
nr_ccws = count_ccws(first_rec, last_rec, blocks_per_page);
/* define extent + nr_ccws * locate record + nr_ccws * single CCW */
cplength = 1 + 2 * nr_ccws;
datasize = sizeof(struct DE_fba_data) +
nr_ccws * (sizeof(struct LO_fba_data) + sizeof(struct ccw1));
cqr = dasd_smalloc_request(DASD_FBA_MAGIC, cplength, datasize, memdev);
if (IS_ERR(cqr))
return cqr;
ccw = cqr->cpaddr;
define_extent(ccw++, cqr->data, WRITE, blksize, first_rec, count);
LO_data = cqr->data + sizeof(struct DE_fba_data);
/* First part is not aligned. Calculate range to write zeroes. */
if (first_rec % blocks_per_page != 0) {
wz_stop = first_rec + blocks_per_page -
(first_rec % blocks_per_page) - 1;
if (wz_stop > last_rec)
wz_stop = last_rec;
wz_count = wz_stop - first_rec + 1;
ccw[-1].flags |= CCW_FLAG_CC;
locate_record(ccw++, LO_data++, WRITE, cur_pos, wz_count);
ccw[-1].flags |= CCW_FLAG_CC;
ccw_write_zero(ccw++, wz_count * blksize);
cur_pos = wz_count;
}
/* We can do proper discard when we've got at least blocks_per_page blocks. */
if (last_rec - (first_rec + cur_pos) + 1 >= blocks_per_page) {
/* is last record at page boundary? */
if ((last_rec - blocks_per_page + 1) % blocks_per_page != 0)
d_stop = last_rec - ((last_rec - blocks_per_page + 1) %
blocks_per_page);
else
d_stop = last_rec;
d_count = d_stop - (first_rec + cur_pos) + 1;
ccw[-1].flags |= CCW_FLAG_CC;
locate_record(ccw++, LO_data++, WRITE, cur_pos, d_count);
ccw[-1].flags |= CCW_FLAG_CC;
ccw_write_no_data(ccw++);
cur_pos += d_count;
}
/* We might still have some bits left which need to be zeroed. */
if (cur_pos == 0 || first_rec + cur_pos - 1 < last_rec) {
if (d_stop != 0)
wz_count = last_rec - d_stop;
else if (wz_stop != 0)
wz_count = last_rec - wz_stop;
else
wz_count = count;
ccw[-1].flags |= CCW_FLAG_CC;
locate_record(ccw++, LO_data++, WRITE, cur_pos, wz_count);
ccw[-1].flags |= CCW_FLAG_CC;
ccw_write_zero(ccw++, wz_count * blksize);
}
if (blk_noretry_request(req) ||
block->base->features & DASD_FEATURE_FAILFAST)
set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
cqr->startdev = memdev;
cqr->memdev = memdev;
cqr->block = block;
cqr->expires = memdev->default_expires * HZ; /* default 5 minutes */
cqr->retries = memdev->default_retries;
cqr->buildclk = get_tod_clock();
cqr->status = DASD_CQR_FILLED;
return cqr;
}
static struct dasd_ccw_req *dasd_fba_build_cp_regular(
struct dasd_device *memdev,
struct dasd_block *block,
struct request *req)
{
struct dasd_fba_private *private = block->base->private;
unsigned long *idaws;
@ -372,6 +558,16 @@ static struct dasd_ccw_req *dasd_fba_build_cp(struct dasd_device * memdev,
return cqr;
}
static struct dasd_ccw_req *dasd_fba_build_cp(struct dasd_device *memdev,
struct dasd_block *block,
struct request *req)
{
if (req_op(req) == REQ_OP_DISCARD || req_op(req) == REQ_OP_WRITE_ZEROES)
return dasd_fba_build_cp_discard(memdev, block, req);
else
return dasd_fba_build_cp_regular(memdev, block, req);
}
static int
dasd_fba_free_cp(struct dasd_ccw_req *cqr, struct request *req)
{

View file

@ -167,6 +167,9 @@ do { \
printk(d_loglevel PRINTK_HEADER " " d_string "\n", d_args); \
} while(0)
/* Macro to calculate number of blocks per page */
#define BLOCKS_PER_PAGE(blksize) (PAGE_SIZE / blksize)
struct dasd_ccw_req {
unsigned int magic; /* Eye catcher */
struct list_head devlist; /* for dasd_device request queue */
@ -196,10 +199,10 @@ struct dasd_ccw_req {
void *function; /* originating ERP action */
/* these are for statistics only */
unsigned long long buildclk; /* TOD-clock of request generation */
unsigned long long startclk; /* TOD-clock of request start */
unsigned long long stopclk; /* TOD-clock of request interrupt */
unsigned long long endclk; /* TOD-clock of request termination */
unsigned long buildclk; /* TOD-clock of request generation */
unsigned long startclk; /* TOD-clock of request start */
unsigned long stopclk; /* TOD-clock of request interrupt */
unsigned long endclk; /* TOD-clock of request termination */
/* Callback that is called after reaching final status. */
void (*callback)(struct dasd_ccw_req *, void *data);
@ -423,7 +426,7 @@ struct dasd_path {
u8 chpid;
struct dasd_conf_data *conf_data;
atomic_t error_count;
unsigned long long errorclk;
unsigned long errorclk;
};
@ -454,6 +457,10 @@ struct dasd_profile_info {
unsigned int dasd_read_time2[32]; /* hist. of time from start to irq */
unsigned int dasd_read_time3[32]; /* hist. of time from irq to end */
unsigned int dasd_read_nr_req[32]; /* hist. of # of requests in chanq */
unsigned long dasd_sum_times; /* sum of request times */
unsigned long dasd_sum_time_str; /* sum of time from build to start */
unsigned long dasd_sum_time_irq; /* sum of time from start to irq */
unsigned long dasd_sum_time_end; /* sum of time from irq to end */
};
struct dasd_profile {
@ -535,7 +542,7 @@ struct dasd_block {
struct block_device *bdev;
atomic_t open_count;
unsigned long long blocks; /* size of volume in blocks */
unsigned long blocks; /* size of volume in blocks */
unsigned int bp_block; /* bytes per block */
unsigned int s2b_shift; /* log2 (bp_block/512) */

View file

@ -90,7 +90,7 @@ dasd_devices_show(struct seq_file *m, void *v)
seq_printf(m, "n/f ");
else
seq_printf(m,
"at blocksize: %d, %lld blocks, %lld MB",
"at blocksize: %u, %lu blocks, %lu MB",
block->bp_block, block->blocks,
((block->bp_block >> 9) *
block->blocks) >> 11);

View file

@ -249,13 +249,13 @@ static void scm_request_requeue(struct scm_request *scmrq)
static void scm_request_finish(struct scm_request *scmrq)
{
struct scm_blk_dev *bdev = scmrq->bdev;
int *error;
int i;
for (i = 0; i < nr_requests_per_io && scmrq->request[i]; i++) {
if (scmrq->error)
blk_mq_end_request(scmrq->request[i], scmrq->error);
else
blk_mq_complete_request(scmrq->request[i]);
error = blk_mq_rq_to_pdu(scmrq->request[i]);
*error = scmrq->error;
blk_mq_complete_request(scmrq->request[i]);
}
atomic_dec(&bdev->queued_reqs);
@ -415,7 +415,9 @@ void scm_blk_irq(struct scm_device *scmdev, void *data, blk_status_t error)
static void scm_blk_request_done(struct request *req)
{
blk_mq_end_request(req, 0);
int *error = blk_mq_rq_to_pdu(req);
blk_mq_end_request(req, *error);
}
static const struct block_device_operations scm_blk_devops = {
@ -448,6 +450,7 @@ int scm_blk_dev_setup(struct scm_blk_dev *bdev, struct scm_device *scmdev)
atomic_set(&bdev->queued_reqs, 0);
bdev->tag_set.ops = &scm_mq_ops;
bdev->tag_set.cmd_size = sizeof(int);
bdev->tag_set.nr_hw_queues = nr_requests;
bdev->tag_set.queue_depth = nr_requests_per_io * nr_requests;
bdev->tag_set.flags = BLK_MQ_F_SHOULD_MERGE;

View file

@ -169,10 +169,21 @@ config VMCP
def_bool y
prompt "Support for the z/VM CP interface"
depends on S390
select CMA
help
Select this option if you want to be able to interact with the control
program on z/VM
config VMCP_CMA_SIZE
int "Memory in MiB reserved for z/VM CP interface"
default "4"
depends on VMCP
help
Specify the default amount of memory in MiB reserved for the z/VM CP
interface. If needed this memory is used for large contiguous memory
allocations. The default can be changed with the kernel command line
parameter "vmcp_cma".
config MONREADER
def_tristate m
prompt "API for reading z/VM monitor service records"

View file

@ -1082,7 +1082,7 @@ static struct attribute * raw3270_attrs[] = {
NULL,
};
static struct attribute_group raw3270_attr_group = {
static const struct attribute_group raw3270_attr_group = {
.attrs = raw3270_attrs,
};

View file

@ -252,6 +252,7 @@ static int sclp_attach_storage(u8 id)
if (!sccb)
return -ENOMEM;
sccb->header.length = PAGE_SIZE;
sccb->header.function_code = 0x40;
rc = sclp_sync_request_timeout(0x00080001 | id << 8, sccb,
SCLP_QUEUE_INTERVAL);
if (rc)

View file

@ -135,7 +135,7 @@ static ssize_t sysfs_ofb_data_write(struct file *filp, struct kobject *kobj,
return rc ?: count;
}
static struct bin_attribute ofb_bin_attr = {
static const struct bin_attribute ofb_bin_attr = {
.attr = {
.name = "event_data",
.mode = S_IWUSR,

View file

@ -39,7 +39,7 @@ struct read_info_sccb {
u8 fac84; /* 84 */
u8 fac85; /* 85 */
u8 _pad_86[91 - 86]; /* 86-90 */
u8 flags; /* 91 */
u8 fac91; /* 91 */
u8 _pad_92[98 - 92]; /* 92-97 */
u8 fac98; /* 98 */
u8 hamaxpow; /* 99 */
@ -103,6 +103,8 @@ static void __init sclp_early_facilities_detect(struct read_info_sccb *sccb)
sclp.has_kss = !!(sccb->fac98 & 0x01);
if (sccb->fac85 & 0x02)
S390_lowcore.machine_flags |= MACHINE_FLAG_ESOP;
if (sccb->fac91 & 0x40)
S390_lowcore.machine_flags |= MACHINE_FLAG_TLB_GUEST;
sclp.rnmax = sccb->rnmax ? sccb->rnmax : sccb->rnmax2;
sclp.rzm = sccb->rnsize ? sccb->rnsize : sccb->rnsize2;
sclp.rzm <<= 20;
@ -139,7 +141,7 @@ static void __init sclp_early_facilities_detect(struct read_info_sccb *sccb)
/* Save IPL information */
sclp_ipl_info.is_valid = 1;
if (sccb->flags & 0x2)
if (sccb->fac91 & 0x2)
sclp_ipl_info.has_dump = 1;
memcpy(&sclp_ipl_info.loadparm, &sccb->loadparm, LOADPARM_LEN);

View file

@ -126,7 +126,7 @@ static struct attribute *ocf_attrs[] = {
NULL,
};
static struct attribute_group ocf_attr_group = {
static const struct attribute_group ocf_attr_group = {
.attrs = ocf_attrs,
};

View file

@ -175,7 +175,7 @@ static struct attribute *tape_attrs[] = {
NULL
};
static struct attribute_group tape_attr_group = {
static const struct attribute_group tape_attr_group = {
.attrs = tape_attrs,
};

View file

@ -17,15 +17,85 @@
#include <linux/kernel.h>
#include <linux/miscdevice.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/export.h>
#include <linux/mutex.h>
#include <linux/cma.h>
#include <linux/mm.h>
#include <asm/compat.h>
#include <asm/cpcmd.h>
#include <asm/debug.h>
#include <linux/uaccess.h>
#include "vmcp.h"
#include <asm/vmcp.h>
struct vmcp_session {
char *response;
unsigned int bufsize;
unsigned int cma_alloc : 1;
int resp_size;
int resp_code;
struct mutex mutex;
};
static debug_info_t *vmcp_debug;
static unsigned long vmcp_cma_size __initdata = CONFIG_VMCP_CMA_SIZE * 1024 * 1024;
static struct cma *vmcp_cma;
static int __init early_parse_vmcp_cma(char *p)
{
vmcp_cma_size = ALIGN(memparse(p, NULL), PAGE_SIZE);
return 0;
}
early_param("vmcp_cma", early_parse_vmcp_cma);
void __init vmcp_cma_reserve(void)
{
if (!MACHINE_IS_VM)
return;
cma_declare_contiguous(0, vmcp_cma_size, 0, 0, 0, false, "vmcp", &vmcp_cma);
}
static void vmcp_response_alloc(struct vmcp_session *session)
{
struct page *page = NULL;
int nr_pages, order;
order = get_order(session->bufsize);
nr_pages = ALIGN(session->bufsize, PAGE_SIZE) >> PAGE_SHIFT;
/*
* For anything below order 3 allocations rely on the buddy
* allocator. If such low-order allocations can't be handled
* anymore the system won't work anyway.
*/
if (order > 2)
page = cma_alloc(vmcp_cma, nr_pages, 0, GFP_KERNEL);
if (page) {
session->response = (char *)page_to_phys(page);
session->cma_alloc = 1;
return;
}
session->response = (char *)__get_free_pages(GFP_KERNEL | __GFP_RETRY_MAYFAIL, order);
}
static void vmcp_response_free(struct vmcp_session *session)
{
int nr_pages, order;
struct page *page;
if (!session->response)
return;
order = get_order(session->bufsize);
nr_pages = ALIGN(session->bufsize, PAGE_SIZE) >> PAGE_SHIFT;
if (session->cma_alloc) {
page = phys_to_page((unsigned long)session->response);
cma_release(vmcp_cma, page, nr_pages);
session->cma_alloc = 0;
} else {
free_pages((unsigned long)session->response, order);
}
session->response = NULL;
}
static int vmcp_open(struct inode *inode, struct file *file)
{
struct vmcp_session *session;
@ -51,7 +121,7 @@ static int vmcp_release(struct inode *inode, struct file *file)
session = file->private_data;
file->private_data = NULL;
free_pages((unsigned long)session->response, get_order(session->bufsize));
vmcp_response_free(session);
kfree(session);
return 0;
}
@ -97,9 +167,7 @@ vmcp_write(struct file *file, const char __user *buff, size_t count,
return -ERESTARTSYS;
}
if (!session->response)
session->response = (char *)__get_free_pages(GFP_KERNEL
| __GFP_RETRY_MAYFAIL | GFP_DMA,
get_order(session->bufsize));
vmcp_response_alloc(session);
if (!session->response) {
mutex_unlock(&session->mutex);
kfree(cmd);
@ -130,8 +198,8 @@ vmcp_write(struct file *file, const char __user *buff, size_t count,
static long vmcp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
struct vmcp_session *session;
int ret = -ENOTTY;
int __user *argp;
int temp;
session = file->private_data;
if (is_compat_task())
@ -142,28 +210,26 @@ static long vmcp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
return -ERESTARTSYS;
switch (cmd) {
case VMCP_GETCODE:
temp = session->resp_code;
mutex_unlock(&session->mutex);
return put_user(temp, argp);
ret = put_user(session->resp_code, argp);
break;
case VMCP_SETBUF:
free_pages((unsigned long)session->response,
get_order(session->bufsize));
session->response=NULL;
temp = get_user(session->bufsize, argp);
if (get_order(session->bufsize) > 8) {
vmcp_response_free(session);
ret = get_user(session->bufsize, argp);
if (ret)
session->bufsize = PAGE_SIZE;
temp = -EINVAL;
if (!session->bufsize || get_order(session->bufsize) > 8) {
session->bufsize = PAGE_SIZE;
ret = -EINVAL;
}
mutex_unlock(&session->mutex);
return temp;
break;
case VMCP_GETSIZE:
temp = session->resp_size;
mutex_unlock(&session->mutex);
return put_user(temp, argp);
ret = put_user(session->resp_size, argp);
break;
default:
mutex_unlock(&session->mutex);
return -ENOIOCTLCMD;
break;
}
mutex_unlock(&session->mutex);
return ret;
}
static const struct file_operations vmcp_fops = {

View file

@ -1,30 +0,0 @@
/*
* Copyright IBM Corp. 2004, 2005
* Interface implementation for communication with the z/VM control program
* Version 1.0
* Author(s): Christian Borntraeger <cborntra@de.ibm.com>
*
*
* z/VMs CP offers the possibility to issue commands via the diagnose code 8
* this driver implements a character device that issues these commands and
* returns the answer of CP.
*
* The idea of this driver is based on cpint from Neale Ferguson
*/
#include <linux/ioctl.h>
#include <linux/mutex.h>
#define VMCP_GETCODE _IOR(0x10, 1, int)
#define VMCP_SETBUF _IOW(0x10, 2, int)
#define VMCP_GETSIZE _IOR(0x10, 3, int)
struct vmcp_session {
unsigned int bufsize;
char *response;
int resp_size;
int resp_code;
/* As we use copy_from/to_user, which might *
* sleep and cannot use a spinlock */
struct mutex mutex;
};

View file

@ -143,7 +143,7 @@ static ssize_t chp_measurement_chars_read(struct file *filp,
sizeof(chp->cmg_chars));
}
static struct bin_attribute chp_measurement_chars_attr = {
static const struct bin_attribute chp_measurement_chars_attr = {
.attr = {
.name = "measurement_chars",
.mode = S_IRUSR,
@ -197,7 +197,7 @@ static ssize_t chp_measurement_read(struct file *filp, struct kobject *kobj,
return count;
}
static struct bin_attribute chp_measurement_attr = {
static const struct bin_attribute chp_measurement_attr = {
.attr = {
.name = "measurement",
.mode = S_IRUSR,

View file

@ -612,7 +612,7 @@ static struct attribute *io_subchannel_attrs[] = {
NULL,
};
static struct attribute_group io_subchannel_attr_group = {
static const struct attribute_group io_subchannel_attr_group = {
.attrs = io_subchannel_attrs,
};
@ -626,7 +626,7 @@ static struct attribute * ccwdev_attrs[] = {
NULL,
};
static struct attribute_group ccwdev_attr_group = {
static const struct attribute_group ccwdev_attr_group = {
.attrs = ccwdev_attrs,
};

View file

@ -98,7 +98,7 @@ static struct attribute *zcrypt_card_attrs[] = {
NULL,
};
static struct attribute_group zcrypt_card_attr_group = {
static const struct attribute_group zcrypt_card_attr_group = {
.attrs = zcrypt_card_attrs,
};

View file

@ -140,7 +140,7 @@ struct function_and_rules_block {
* + 0x000A 'MRP ' (MCL3 'PK' or CEX2C 'PK')
* - VUD block
*/
static struct CPRBX static_cprbx = {
static const struct CPRBX static_cprbx = {
.cprb_len = 0x00DC,
.cprb_ver_id = 0x02,
.func_id = {0x54, 0x32},

View file

@ -89,7 +89,7 @@ static struct attribute *zcrypt_queue_attrs[] = {
NULL,
};
static struct attribute_group zcrypt_queue_attr_group = {
static const struct attribute_group zcrypt_queue_attr_group = {
.attrs = zcrypt_queue_attrs,
};

View file

@ -350,7 +350,7 @@ static struct attribute *qeth_l3_device_attrs[] = {
NULL,
};
static struct attribute_group qeth_l3_device_attr_group = {
static const struct attribute_group qeth_l3_device_attr_group = {
.attrs = qeth_l3_device_attrs,
};
@ -680,7 +680,7 @@ static struct attribute *qeth_ipato_device_attrs[] = {
NULL,
};
static struct attribute_group qeth_device_ipato_group = {
static const struct attribute_group qeth_device_ipato_group = {
.name = "ipa_takeover",
.attrs = qeth_ipato_device_attrs,
};
@ -843,7 +843,7 @@ static struct attribute *qeth_vipa_device_attrs[] = {
NULL,
};
static struct attribute_group qeth_device_vipa_group = {
static const struct attribute_group qeth_device_vipa_group = {
.name = "vipa",
.attrs = qeth_vipa_device_attrs,
};
@ -1006,7 +1006,7 @@ static struct attribute *qeth_rxip_device_attrs[] = {
NULL,
};
static struct attribute_group qeth_device_rxip_group = {
static const struct attribute_group qeth_device_rxip_group = {
.name = "rxip",
.attrs = qeth_rxip_device_attrs,
};