mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-28 18:51:56 -04:00
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:
commit
9e85ae6af6
87 changed files with 1405 additions and 694 deletions
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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) */
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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 = {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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},
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in a new issue