summaryrefslogtreecommitdiffstats
path: root/drivers/s390
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/s390')
-rw-r--r--drivers/s390/block/dasd_alias.c4
-rw-r--r--drivers/s390/block/dasd_devmap.c16
-rw-r--r--drivers/s390/block/dasd_eckd.c147
-rw-r--r--drivers/s390/block/dasd_eckd.h184
-rw-r--r--drivers/s390/block/dasd_int.h1
-rw-r--r--drivers/s390/char/sclp.c6
-rw-r--r--drivers/s390/char/sclp_cmd.c5
-rw-r--r--drivers/s390/char/sclp_config.c13
-rw-r--r--drivers/s390/cio/idset.c8
-rw-r--r--drivers/s390/cio/qdio_main.c2
-rw-r--r--drivers/s390/cio/qdio_perf.c2
-rw-r--r--drivers/s390/cio/qdio_setup.c4
-rw-r--r--drivers/s390/kvm/kvm_virtio.c2
-rw-r--r--drivers/s390/net/qeth_core.h5
-rw-r--r--drivers/s390/net/qeth_core_main.c63
-rw-r--r--drivers/s390/net/qeth_l2_main.c50
-rw-r--r--drivers/s390/net/qeth_l3_main.c51
17 files changed, 336 insertions, 227 deletions
diff --git a/drivers/s390/block/dasd_alias.c b/drivers/s390/block/dasd_alias.c
index 2d8df0b30538..20676cdef4a5 100644
--- a/drivers/s390/block/dasd_alias.c
+++ b/drivers/s390/block/dasd_alias.c
@@ -91,7 +91,8 @@ static struct alias_pav_group *_find_group(struct alias_lcu *lcu,
else
search_unit_addr = uid->base_unit_addr;
list_for_each_entry(pos, &lcu->grouplist, group) {
- if (pos->uid.base_unit_addr == search_unit_addr)
+ if (pos->uid.base_unit_addr == search_unit_addr &&
+ !strncmp(pos->uid.vduit, uid->vduit, sizeof(uid->vduit)))
return pos;
};
return NULL;
@@ -332,6 +333,7 @@ static int _add_device_to_lcu(struct alias_lcu *lcu,
group->uid.base_unit_addr = uid->real_unit_addr;
else
group->uid.base_unit_addr = uid->base_unit_addr;
+ memcpy(group->uid.vduit, uid->vduit, sizeof(uid->vduit));
INIT_LIST_HEAD(&group->group);
INIT_LIST_HEAD(&group->baselist);
INIT_LIST_HEAD(&group->aliaslist);
diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c
index d774e79476fe..cd3335c1c307 100644
--- a/drivers/s390/block/dasd_devmap.c
+++ b/drivers/s390/block/dasd_devmap.c
@@ -913,7 +913,8 @@ dasd_vendor_show(struct device *dev, struct device_attribute *attr, char *buf)
static DEVICE_ATTR(vendor, 0444, dasd_vendor_show, NULL);
#define UID_STRLEN ( /* vendor */ 3 + 1 + /* serial */ 14 + 1 +\
- /* SSID */ 4 + 1 + /* unit addr */ 2 + 1)
+ /* SSID */ 4 + 1 + /* unit addr */ 2 + 1 +\
+ /* vduit */ 32 + 1)
static ssize_t
dasd_uid_show(struct device *dev, struct device_attribute *attr, char *buf)
@@ -945,8 +946,17 @@ dasd_uid_show(struct device *dev, struct device_attribute *attr, char *buf)
sprintf(ua_string, "%02x", uid->real_unit_addr);
break;
}
- snprintf(uid_string, sizeof(uid_string), "%s.%s.%04x.%s",
- uid->vendor, uid->serial, uid->ssid, ua_string);
+ if (strlen(uid->vduit) > 0)
+ snprintf(uid_string, sizeof(uid_string),
+ "%s.%s.%04x.%s.%s",
+ uid->vendor, uid->serial,
+ uid->ssid, ua_string,
+ uid->vduit);
+ else
+ snprintf(uid_string, sizeof(uid_string),
+ "%s.%s.%04x.%s",
+ uid->vendor, uid->serial,
+ uid->ssid, ua_string);
spin_unlock(&dasd_devmap_lock);
return snprintf(buf, PAGE_SIZE, "%s\n", uid_string);
}
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
index 3590fdb5b2fd..773b3fe275b2 100644
--- a/drivers/s390/block/dasd_eckd.c
+++ b/drivers/s390/block/dasd_eckd.c
@@ -313,8 +313,8 @@ static int prefix(struct ccw1 *ccw, struct PFX_eckd_data *pfxdata, int trk,
memset(pfxdata, 0, sizeof(*pfxdata));
/* prefix data */
pfxdata->format = 0;
- pfxdata->base_address = basepriv->conf_data.ned1.unit_addr;
- pfxdata->base_lss = basepriv->conf_data.ned1.ID;
+ pfxdata->base_address = basepriv->ned->unit_addr;
+ pfxdata->base_lss = basepriv->ned->ID;
pfxdata->validity.define_extend = 1;
/* private uid is kept up to date, conf_data may be outdated */
@@ -536,36 +536,40 @@ dasd_eckd_cdl_reclen(int recid)
/*
* Generate device unique id that specifies the physical device.
*/
-static int
-dasd_eckd_generate_uid(struct dasd_device *device, struct dasd_uid *uid)
+static int dasd_eckd_generate_uid(struct dasd_device *device,
+ struct dasd_uid *uid)
{
struct dasd_eckd_private *private;
- struct dasd_eckd_confdata *confdata;
+ int count;
private = (struct dasd_eckd_private *) device->private;
if (!private)
return -ENODEV;
- confdata = &private->conf_data;
- if (!confdata)
+ if (!private->ned || !private->gneq)
return -ENODEV;
memset(uid, 0, sizeof(struct dasd_uid));
- memcpy(uid->vendor, confdata->ned1.HDA_manufacturer,
+ memcpy(uid->vendor, private->ned->HDA_manufacturer,
sizeof(uid->vendor) - 1);
EBCASC(uid->vendor, sizeof(uid->vendor) - 1);
- memcpy(uid->serial, confdata->ned1.HDA_location,
+ memcpy(uid->serial, private->ned->HDA_location,
sizeof(uid->serial) - 1);
EBCASC(uid->serial, sizeof(uid->serial) - 1);
- uid->ssid = confdata->neq.subsystemID;
- uid->real_unit_addr = confdata->ned1.unit_addr;
- if (confdata->ned2.sneq.flags == 0x40 &&
- confdata->ned2.sneq.format == 0x0001) {
- uid->type = confdata->ned2.sneq.sua_flags;
+ uid->ssid = private->gneq->subsystemID;
+ uid->real_unit_addr = private->ned->unit_addr;;
+ if (private->sneq) {
+ uid->type = private->sneq->sua_flags;
if (uid->type == UA_BASE_PAV_ALIAS)
- uid->base_unit_addr = confdata->ned2.sneq.base_unit_addr;
+ uid->base_unit_addr = private->sneq->base_unit_addr;
} else {
uid->type = UA_BASE_DEVICE;
}
+ if (private->vdsneq) {
+ for (count = 0; count < 16; count++) {
+ sprintf(uid->vduit+2*count, "%02x",
+ private->vdsneq->uit[count]);
+ }
+ }
return 0;
}
@@ -623,6 +627,15 @@ static int dasd_eckd_read_conf_lpm(struct dasd_device *device,
ret = -ENOMEM;
goto out_error;
}
+
+ /*
+ * buffer has to start with EBCDIC "V1.0" to show
+ * support for virtual device SNEQ
+ */
+ rcd_buf[0] = 0xE5;
+ rcd_buf[1] = 0xF1;
+ rcd_buf[2] = 0x4B;
+ rcd_buf[3] = 0xF0;
cqr = dasd_eckd_build_rcd_lpm(device, rcd_buf, ciw, lpm);
if (IS_ERR(cqr)) {
ret = PTR_ERR(cqr);
@@ -646,8 +659,62 @@ out_error:
return ret;
}
-static int
-dasd_eckd_read_conf(struct dasd_device *device)
+static int dasd_eckd_identify_conf_parts(struct dasd_eckd_private *private)
+{
+
+ struct dasd_sneq *sneq;
+ int i, count;
+
+ private->ned = NULL;
+ private->sneq = NULL;
+ private->vdsneq = NULL;
+ private->gneq = NULL;
+ count = private->conf_len / sizeof(struct dasd_sneq);
+ sneq = (struct dasd_sneq *)private->conf_data;
+ for (i = 0; i < count; ++i) {
+ if (sneq->flags.identifier == 1 && sneq->format == 1)
+ private->sneq = sneq;
+ else if (sneq->flags.identifier == 1 && sneq->format == 4)
+ private->vdsneq = (struct vd_sneq *)sneq;
+ else if (sneq->flags.identifier == 2)
+ private->gneq = (struct dasd_gneq *)sneq;
+ else if (sneq->flags.identifier == 3 && sneq->res1 == 1)
+ private->ned = (struct dasd_ned *)sneq;
+ sneq++;
+ }
+ if (!private->ned || !private->gneq) {
+ private->ned = NULL;
+ private->sneq = NULL;
+ private->vdsneq = NULL;
+ private->gneq = NULL;
+ return -EINVAL;
+ }
+ return 0;
+
+};
+
+static unsigned char dasd_eckd_path_access(void *conf_data, int conf_len)
+{
+ struct dasd_gneq *gneq;
+ int i, count, found;
+
+ count = conf_len / sizeof(*gneq);
+ gneq = (struct dasd_gneq *)conf_data;
+ found = 0;
+ for (i = 0; i < count; ++i) {
+ if (gneq->flags.identifier == 2) {
+ found = 1;
+ break;
+ }
+ gneq++;
+ }
+ if (found)
+ return ((char *)gneq)[18] & 0x07;
+ else
+ return 0;
+}
+
+static int dasd_eckd_read_conf(struct dasd_device *device)
{
void *conf_data;
int conf_len, conf_data_saved;
@@ -661,7 +728,6 @@ dasd_eckd_read_conf(struct dasd_device *device)
path_data->opm = ccw_device_get_path_mask(device->cdev);
lpm = 0x80;
conf_data_saved = 0;
-
/* get configuration data per operational path */
for (lpm = 0x80; lpm; lpm>>= 1) {
if (lpm & path_data->opm){
@@ -678,22 +744,20 @@ dasd_eckd_read_conf(struct dasd_device *device)
"data retrieved");
continue; /* no error */
}
- if (conf_len != sizeof(struct dasd_eckd_confdata)) {
- MESSAGE(KERN_WARNING,
- "sizes of configuration data mismatch"
- "%d (read) vs %ld (expected)",
- conf_len,
- sizeof(struct dasd_eckd_confdata));
- kfree(conf_data);
- continue; /* no error */
- }
/* save first valid configuration data */
- if (!conf_data_saved){
- memcpy(&private->conf_data, conf_data,
- sizeof(struct dasd_eckd_confdata));
+ if (!conf_data_saved) {
+ kfree(private->conf_data);
+ private->conf_data = conf_data;
+ private->conf_len = conf_len;
+ if (dasd_eckd_identify_conf_parts(private)) {
+ private->conf_data = NULL;
+ private->conf_len = 0;
+ kfree(conf_data);
+ continue;
+ }
conf_data_saved++;
}
- switch (((char *)conf_data)[242] & 0x07){
+ switch (dasd_eckd_path_access(conf_data, conf_len)) {
case 0x02:
path_data->npm |= lpm;
break;
@@ -701,7 +765,8 @@ dasd_eckd_read_conf(struct dasd_device *device)
path_data->ppm |= lpm;
break;
}
- kfree(conf_data);
+ if (conf_data != private->conf_data)
+ kfree(conf_data);
}
}
return 0;
@@ -952,6 +1017,7 @@ out_err2:
dasd_free_block(device->block);
device->block = NULL;
out_err1:
+ kfree(private->conf_data);
kfree(device->private);
device->private = NULL;
return rc;
@@ -959,7 +1025,17 @@ out_err1:
static void dasd_eckd_uncheck_device(struct dasd_device *device)
{
+ struct dasd_eckd_private *private;
+
+ private = (struct dasd_eckd_private *) device->private;
dasd_alias_disconnect_device_from_lcu(device);
+ private->ned = NULL;
+ private->sneq = NULL;
+ private->vdsneq = NULL;
+ private->gneq = NULL;
+ private->conf_len = 0;
+ kfree(private->conf_data);
+ private->conf_data = NULL;
}
static struct dasd_ccw_req *
@@ -1746,9 +1822,10 @@ dasd_eckd_fill_info(struct dasd_device * device,
info->characteristics_size = sizeof(struct dasd_eckd_characteristics);
memcpy(info->characteristics, &private->rdc_data,
sizeof(struct dasd_eckd_characteristics));
- info->confdata_size = sizeof(struct dasd_eckd_confdata);
- memcpy(info->configuration_data, &private->conf_data,
- sizeof(struct dasd_eckd_confdata));
+ info->confdata_size = min((unsigned long)private->conf_len,
+ sizeof(info->configuration_data));
+ memcpy(info->configuration_data, private->conf_data,
+ info->confdata_size);
return 0;
}
diff --git a/drivers/s390/block/dasd_eckd.h b/drivers/s390/block/dasd_eckd.h
index fc2509c939bc..4bf0aa5112c1 100644
--- a/drivers/s390/block/dasd_eckd.h
+++ b/drivers/s390/block/dasd_eckd.h
@@ -231,133 +231,62 @@ struct dasd_eckd_characteristics {
__u8 reserved3[10];
} __attribute__ ((packed));
-struct dasd_eckd_confdata {
+/* elements of the configuration data */
+struct dasd_ned {
struct {
- struct {
- unsigned char identifier:2;
- unsigned char token_id:1;
- unsigned char sno_valid:1;
- unsigned char subst_sno:1;
- unsigned char recNED:1;
- unsigned char emuNED:1;
- unsigned char reserved:1;
- } __attribute__ ((packed)) flags;
- __u8 descriptor;
- __u8 dev_class;
- __u8 reserved;
- unsigned char dev_type[6];
- unsigned char dev_model[3];
- unsigned char HDA_manufacturer[3];
- unsigned char HDA_location[2];
- unsigned char HDA_seqno[12];
- __u8 ID;
- __u8 unit_addr;
- } __attribute__ ((packed)) ned1;
- union {
- struct {
- struct {
- unsigned char identifier:2;
- unsigned char token_id:1;
- unsigned char sno_valid:1;
- unsigned char subst_sno:1;
- unsigned char recNED:1;
- unsigned char emuNED:1;
- unsigned char reserved:1;
- } __attribute__ ((packed)) flags;
- __u8 descriptor;
- __u8 reserved[2];
- unsigned char dev_type[6];
- unsigned char dev_model[3];
- unsigned char DASD_manufacturer[3];
- unsigned char DASD_location[2];
- unsigned char DASD_seqno[12];
- __u16 ID;
- } __attribute__ ((packed)) ned;
- struct {
- unsigned char flags; /* byte 0 */
- unsigned char res1; /* byte 1 */
- __u16 format; /* byte 2-3 */
- unsigned char res2[4]; /* byte 4-7 */
- unsigned char sua_flags; /* byte 8 */
- __u8 base_unit_addr; /* byte 9 */
- unsigned char res3[22]; /* byte 10-31 */
- } __attribute__ ((packed)) sneq;
- } __attribute__ ((packed)) ned2;
+ __u8 identifier:2;
+ __u8 token_id:1;
+ __u8 sno_valid:1;
+ __u8 subst_sno:1;
+ __u8 recNED:1;
+ __u8 emuNED:1;
+ __u8 reserved:1;
+ } __attribute__ ((packed)) flags;
+ __u8 descriptor;
+ __u8 dev_class;
+ __u8 reserved;
+ __u8 dev_type[6];
+ __u8 dev_model[3];
+ __u8 HDA_manufacturer[3];
+ __u8 HDA_location[2];
+ __u8 HDA_seqno[12];
+ __u8 ID;
+ __u8 unit_addr;
+} __attribute__ ((packed));
+
+struct dasd_sneq {
struct {
- struct {
- unsigned char identifier:2;
- unsigned char token_id:1;
- unsigned char sno_valid:1;
- unsigned char subst_sno:1;
- unsigned char recNED:1;
- unsigned char emuNED:1;
- unsigned char reserved:1;
- } __attribute__ ((packed)) flags;
- __u8 descriptor;
- __u8 reserved[2];
- unsigned char cont_type[6];
- unsigned char cont_model[3];
- unsigned char cont_manufacturer[3];
- unsigned char cont_location[2];
- unsigned char cont_seqno[12];
- __u16 ID;
- } __attribute__ ((packed)) ned3;
+ __u8 identifier:2;
+ __u8 reserved:6;
+ } __attribute__ ((packed)) flags;
+ __u8 res1;
+ __u16 format;
+ __u8 res2[4]; /* byte 4- 7 */
+ __u8 sua_flags; /* byte 8 */
+ __u8 base_unit_addr; /* byte 9 */
+ __u8 res3[22]; /* byte 10-31 */
+} __attribute__ ((packed));
+
+struct vd_sneq {
struct {
- struct {
- unsigned char identifier:2;
- unsigned char token_id:1;
- unsigned char sno_valid:1;
- unsigned char subst_sno:1;
- unsigned char recNED:1;
- unsigned char emuNED:1;
- unsigned char reserved:1;
- } __attribute__ ((packed)) flags;
- __u8 descriptor;
- __u8 reserved[2];
- unsigned char cont_type[6];
- unsigned char empty[3];
- unsigned char cont_manufacturer[3];
- unsigned char cont_location[2];
- unsigned char cont_seqno[12];
- __u16 ID;
- } __attribute__ ((packed)) ned4;
- unsigned char ned5[32];
- unsigned char ned6[32];
- unsigned char ned7[32];
+ __u8 identifier:2;
+ __u8 reserved:6;
+ } __attribute__ ((packed)) flags;
+ __u8 res1;
+ __u16 format;
+ __u8 res2[4]; /* byte 4- 7 */
+ __u8 uit[16]; /* byte 8-23 */
+ __u8 res3[8]; /* byte 24-31 */
+} __attribute__ ((packed));
+
+struct dasd_gneq {
struct {
- struct {
- unsigned char identifier:2;
- unsigned char reserved:6;
- } __attribute__ ((packed)) flags;
- __u8 selector;
- __u16 interfaceID;
- __u32 reserved;
- __u16 subsystemID;
- struct {
- unsigned char sp0:1;
- unsigned char sp1:1;
- unsigned char reserved:5;
- unsigned char scluster:1;
- } __attribute__ ((packed)) spathID;
- __u8 unit_address;
- __u8 dev_ID;
- __u8 dev_address;
- __u8 adapterID;
- __u16 link_address;
- struct {
- unsigned char parallel:1;
- unsigned char escon:1;
- unsigned char reserved:1;
- unsigned char ficon:1;
- unsigned char reserved2:4;
- } __attribute__ ((packed)) protocol_type;
- struct {
- unsigned char PID_in_236:1;
- unsigned char reserved:7;
- } __attribute__ ((packed)) format_flags;
- __u8 log_dev_address;
- unsigned char reserved2[12];
- } __attribute__ ((packed)) neq;
+ __u8 identifier:2;
+ __u8 reserved:6;
+ } __attribute__ ((packed)) flags;
+ __u8 reserved[7];
+ __u16 subsystemID;
+ __u8 reserved2[22];
} __attribute__ ((packed));
struct dasd_eckd_path {
@@ -463,7 +392,14 @@ struct alias_pav_group {
struct dasd_eckd_private {
struct dasd_eckd_characteristics rdc_data;
- struct dasd_eckd_confdata conf_data;
+ u8 *conf_data;
+ int conf_len;
+ /* pointers to specific parts in the conf_data */
+ struct dasd_ned *ned;
+ struct dasd_sneq *sneq;
+ struct vd_sneq *vdsneq;
+ struct dasd_gneq *gneq;
+
struct dasd_eckd_path path_data;
struct eckd_count count_area[5];
int init_cqr_status;
diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h
index fb2f931cf844..31ecaa4a40e4 100644
--- a/drivers/s390/block/dasd_int.h
+++ b/drivers/s390/block/dasd_int.h
@@ -307,6 +307,7 @@ struct dasd_uid {
__u16 ssid;
__u8 real_unit_addr;
__u8 base_unit_addr;
+ char vduit[33];
};
/*
diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c
index 3c8b25e6c345..1fd8f2193ed8 100644
--- a/drivers/s390/char/sclp.c
+++ b/drivers/s390/char/sclp.c
@@ -399,6 +399,7 @@ sclp_tod_from_jiffies(unsigned long jiffies)
void
sclp_sync_wait(void)
{
+ unsigned long long old_tick;
unsigned long flags;
unsigned long cr0, cr0_sync;
u64 timeout;
@@ -419,11 +420,12 @@ sclp_sync_wait(void)
if (!irq_context)
local_bh_disable();
/* Enable service-signal interruption, disable timer interrupts */
+ old_tick = local_tick_disable();
trace_hardirqs_on();
__ctl_store(cr0, 0, 0);
cr0_sync = cr0;
+ cr0_sync &= 0xffff00a0;
cr0_sync |= 0x00000200;
- cr0_sync &= 0xFFFFF3AC;
__ctl_load(cr0_sync, 0, 0);
__raw_local_irq_stosm(0x01);
/* Loop until driver state indicates finished request */
@@ -439,9 +441,9 @@ sclp_sync_wait(void)
__ctl_load(cr0, 0, 0);
if (!irq_context)
_local_bh_enable();
+ local_tick_enable(old_tick);
local_irq_restore(flags);
}
-
EXPORT_SYMBOL(sclp_sync_wait);
/* Dispatch changes in send and receive mask to registered listeners. */
diff --git a/drivers/s390/char/sclp_cmd.c b/drivers/s390/char/sclp_cmd.c
index 0c2b77493db4..eb5f1b8bc57f 100644
--- a/drivers/s390/char/sclp_cmd.c
+++ b/drivers/s390/char/sclp_cmd.c
@@ -427,6 +427,8 @@ static int sclp_mem_notifier(struct notifier_block *nb,
sclp_attach_storage(id);
switch (action) {
case MEM_ONLINE:
+ case MEM_GOING_OFFLINE:
+ case MEM_CANCEL_OFFLINE:
break;
case MEM_GOING_ONLINE:
rc = sclp_mem_change_state(start, size, 1);
@@ -434,6 +436,9 @@ static int sclp_mem_notifier(struct notifier_block *nb,
case MEM_CANCEL_ONLINE:
sclp_mem_change_state(start, size, 0);
break;
+ case MEM_OFFLINE:
+ sclp_mem_change_state(start, size, 0);
+ break;
default:
rc = -EINVAL;
break;
diff --git a/drivers/s390/char/sclp_config.c b/drivers/s390/char/sclp_config.c
index fff4ff485d9b..4cebd6ee6d27 100644
--- a/drivers/s390/char/sclp_config.c
+++ b/drivers/s390/char/sclp_config.c
@@ -8,7 +8,6 @@
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/cpu.h>
-#include <linux/kthread.h>
#include <linux/sysdev.h>
#include <linux/workqueue.h>
#include <asm/smp.h>
@@ -41,19 +40,9 @@ static void sclp_cpu_capability_notify(struct work_struct *work)
put_online_cpus();
}
-static int sclp_cpu_kthread(void *data)
-{
- smp_rescan_cpus();
- return 0;
-}
-
static void __ref sclp_cpu_change_notify(struct work_struct *work)
{
- /* Can't call smp_rescan_cpus() from workqueue context since it may
- * deadlock in case of cpu hotplug. So we have to create a kernel
- * thread in order to call it.
- */
- kthread_run(sclp_cpu_kthread, NULL, "cpu_rescan");
+ smp_rescan_cpus();
}
static void sclp_conf_receiver_fn(struct evbuf_header *evbuf)
diff --git a/drivers/s390/cio/idset.c b/drivers/s390/cio/idset.c
index ef7bc0a125ef..cf8f24a4b5eb 100644
--- a/drivers/s390/cio/idset.c
+++ b/drivers/s390/cio/idset.c
@@ -5,7 +5,7 @@
* Author(s): Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
*/
-#include <linux/slab.h>
+#include <linux/vmalloc.h>
#include <linux/bitops.h>
#include "idset.h"
#include "css.h"
@@ -25,18 +25,18 @@ static struct idset *idset_new(int num_ssid, int num_id)
{
struct idset *set;
- set = kzalloc(sizeof(struct idset) + bitmap_size(num_ssid, num_id),
- GFP_KERNEL);
+ set = vmalloc(sizeof(struct idset) + bitmap_size(num_ssid, num_id));
if (set) {
set->num_ssid = num_ssid;
set->num_id = num_id;
+ memset(set->bitmap, 0, bitmap_size(num_ssid, num_id));
}
return set;
}
void idset_free(struct idset *set)
{
- kfree(set);
+ vfree(set);
}
void idset_clear(struct idset *set)
diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c
index d10c73cc1688..d15648514a0f 100644
--- a/drivers/s390/cio/qdio_main.c
+++ b/drivers/s390/cio/qdio_main.c
@@ -1355,7 +1355,7 @@ int qdio_allocate(struct qdio_initialize *init_data)
goto out_rel;
/* qdr is used in ccw1.cda which is u32 */
- irq_ptr->qdr = kzalloc(sizeof(struct qdr), GFP_KERNEL | GFP_DMA);
+ irq_ptr->qdr = (struct qdr *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
if (!irq_ptr->qdr)
goto out_rel;
WARN_ON((unsigned long)irq_ptr->qdr & 0xfff);
diff --git a/drivers/s390/cio/qdio_perf.c b/drivers/s390/cio/qdio_perf.c
index ea01b85b1cc9..ec5c4a414235 100644
--- a/drivers/s390/cio/qdio_perf.c
+++ b/drivers/s390/cio/qdio_perf.c
@@ -142,7 +142,7 @@ int __init qdio_setup_perf_stats(void)
return 0;
}
-void __exit qdio_remove_perf_stats(void)
+void qdio_remove_perf_stats(void)
{
#ifdef CONFIG_PROC_FS
remove_proc_entry("qdio_perf", NULL);
diff --git a/drivers/s390/cio/qdio_setup.c b/drivers/s390/cio/qdio_setup.c
index f0923a8aceda..1bd2a208db28 100644
--- a/drivers/s390/cio/qdio_setup.c
+++ b/drivers/s390/cio/qdio_setup.c
@@ -325,7 +325,7 @@ void qdio_release_memory(struct qdio_irq *irq_ptr)
kmem_cache_free(qdio_q_cache, q);
}
}
- kfree(irq_ptr->qdr);
+ free_page((unsigned long) irq_ptr->qdr);
free_page(irq_ptr->chsc_page);
free_page((unsigned long) irq_ptr);
}
@@ -515,7 +515,7 @@ int __init qdio_setup_init(void)
return 0;
}
-void __exit qdio_setup_exit(void)
+void qdio_setup_exit(void)
{
kmem_cache_destroy(qdio_q_cache);
}
diff --git a/drivers/s390/kvm/kvm_virtio.c b/drivers/s390/kvm/kvm_virtio.c
index 79954bd6bfa5..292b60da6dc7 100644
--- a/drivers/s390/kvm/kvm_virtio.c
+++ b/drivers/s390/kvm/kvm_virtio.c
@@ -352,7 +352,7 @@ static __init int early_put_chars(u32 vtermno, const char *buf, int count)
return len;
}
-void s390_virtio_console_init(void)
+void __init s390_virtio_console_init(void)
{
virtio_cons_early_init(early_put_chars);
}
diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h
index 1895dbb553cd..80971c21ea1a 100644
--- a/drivers/s390/net/qeth_core.h
+++ b/drivers/s390/net/qeth_core.h
@@ -419,6 +419,7 @@ struct qeth_qdio_out_buffer {
int next_element_to_fill;
struct sk_buff_head skb_list;
struct list_head ctx_list;
+ int is_header[16];
};
struct qeth_card;
@@ -785,7 +786,7 @@ void qeth_core_remove_osn_attributes(struct device *);
/* exports for qeth discipline device drivers */
extern struct qeth_card_list_struct qeth_core_card_list;
-
+extern struct kmem_cache *qeth_core_header_cache;
extern struct qeth_dbf_info qeth_dbf[QETH_DBF_INFOS];
void qeth_set_allowed_threads(struct qeth_card *, unsigned long , int);
@@ -843,7 +844,7 @@ int qeth_get_priority_queue(struct qeth_card *, struct sk_buff *, int, int);
int qeth_get_elements_no(struct qeth_card *, void *, struct sk_buff *, int);
int qeth_do_send_packet_fast(struct qeth_card *, struct qeth_qdio_out_q *,
struct sk_buff *, struct qeth_hdr *, int,
- struct qeth_eddp_context *);
+ struct qeth_eddp_context *, int, int);
int qeth_do_send_packet(struct qeth_card *, struct qeth_qdio_out_q *,
struct sk_buff *, struct qeth_hdr *,
int, struct qeth_eddp_context *);
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c
index cebb25e36e82..bd420d1b9a0d 100644
--- a/drivers/s390/net/qeth_core_main.c
+++ b/drivers/s390/net/qeth_core_main.c
@@ -19,8 +19,8 @@
#include <linux/mii.h>
#include <linux/kthread.h>
-#include <asm-s390/ebcdic.h>
-#include <asm-s390/io.h>
+#include <asm/ebcdic.h>
+#include <asm/io.h>
#include <asm/s390_rdev.h>
#include "qeth_core.h"
@@ -48,6 +48,8 @@ EXPORT_SYMBOL_GPL(qeth_dbf);
struct qeth_card_list_struct qeth_core_card_list;
EXPORT_SYMBOL_GPL(qeth_core_card_list);
+struct kmem_cache *qeth_core_header_cache;
+EXPORT_SYMBOL_GPL(qeth_core_header_cache);
static struct device *qeth_core_root_dev;
static unsigned int known_devices[][10] = QETH_MODELLIST_ARRAY;
@@ -933,6 +935,10 @@ static void qeth_clear_output_buffer(struct qeth_qdio_out_q *queue,
}
qeth_eddp_buf_release_contexts(buf);
for (i = 0; i < QETH_MAX_BUFFER_ELEMENTS(queue->card); ++i) {
+ if (buf->buffer->element[i].addr && buf->is_header[i])
+ kmem_cache_free(qeth_core_header_cache,
+ buf->buffer->element[i].addr);
+ buf->is_header[i] = 0;
buf->buffer->element[i].length = 0;
buf->buffer->element[i].addr = NULL;
buf->buffer->element[i].flags = 0;
@@ -3002,8 +3008,8 @@ int qeth_get_elements_no(struct qeth_card *card, void *hdr,
if (skb_shinfo(skb)->nr_frags > 0)
elements_needed = (skb_shinfo(skb)->nr_frags + 1);
if (elements_needed == 0)
- elements_needed = 1 + (((((unsigned long) hdr) % PAGE_SIZE)
- + skb->len) >> PAGE_SHIFT);
+ elements_needed = 1 + (((((unsigned long) skb->data) %
+ PAGE_SIZE) + skb->len) >> PAGE_SHIFT);
if ((elements_needed + elems) > QETH_MAX_BUFFER_ELEMENTS(card)) {
QETH_DBF_MESSAGE(2, "Invalid size of IP packet "
"(Number=%d / Length=%d). Discarded.\n",
@@ -3015,7 +3021,8 @@ int qeth_get_elements_no(struct qeth_card *card, void *hdr,
EXPORT_SYMBOL_GPL(qeth_get_elements_no);
static inline void __qeth_fill_buffer(struct sk_buff *skb,
- struct qdio_buffer *buffer, int is_tso, int *next_element_to_fill)
+ struct qdio_buffer *buffer, int is_tso, int *next_element_to_fill,
+ int offset)
{
int length = skb->len;
int length_here;
@@ -3027,6 +3034,11 @@ static inline void __qeth_fill_buffer(struct sk_buff *skb,
data = skb->data;
first_lap = (is_tso == 0 ? 1 : 0);
+ if (offset >= 0) {
+ data = skb->data + offset;
+ first_lap = 0;
+ }
+
while (length > 0) {
/* length_here is the remaining amount of data in this page */
length_here = PAGE_SIZE - ((unsigned long) data % PAGE_SIZE);
@@ -3058,22 +3070,22 @@ static inline void __qeth_fill_buffer(struct sk_buff *skb,
}
static inline int qeth_fill_buffer(struct qeth_qdio_out_q *queue,
- struct qeth_qdio_out_buffer *buf, struct sk_buff *skb)
+ struct qeth_qdio_out_buffer *buf, struct sk_buff *skb,
+ struct qeth_hdr *hdr, int offset, int hd_len)
{
struct qdio_buffer *buffer;
- struct qeth_hdr_tso *hdr;
int flush_cnt = 0, hdr_len, large_send = 0;
buffer = buf->buffer;
atomic_inc(&skb->users);
skb_queue_tail(&buf->skb_list, skb);
- hdr = (struct qeth_hdr_tso *) skb->data;
/*check first on TSO ....*/
- if (hdr->hdr.hdr.l3.id == QETH_HEADER_TYPE_TSO) {
+ if (hdr->hdr.l3.id == QETH_HEADER_TYPE_TSO) {
int element = buf->next_element_to_fill;
- hdr_len = sizeof(struct qeth_hdr_tso) + hdr->ext.dg_hdr_len;
+ hdr_len = sizeof(struct qeth_hdr_tso) +
+ ((struct qeth_hdr_tso *)hdr)->ext.dg_hdr_len;
/*fill first buffer entry only with header information */
buffer->element[element].addr = skb->data;
buffer->element[element].length = hdr_len;
@@ -3083,9 +3095,20 @@ static inline int qeth_fill_buffer(struct qeth_qdio_out_q *queue,
skb->len -= hdr_len;
large_send = 1;
}
+
+ if (offset >= 0) {
+ int element = buf->next_element_to_fill;
+ buffer->element[element].addr = hdr;
+ buffer->element[element].length = sizeof(struct qeth_hdr) +
+ hd_len;
+ buffer->element[element].flags = SBAL_FLAGS_FIRST_FRAG;
+ buf->is_header[element] = 1;
+ buf->next_element_to_fill++;
+ }
+
if (skb_shinfo(skb)->nr_frags == 0)
__qeth_fill_buffer(skb, buffer, large_send,
- (int *)&buf->next_element_to_fill);
+ (int *)&buf->next_element_to_fill, offset);
else
__qeth_fill_buffer_frag(skb, buffer, large_send,
(int *)&buf->next_element_to_fill);
@@ -3115,7 +3138,7 @@ static inline int qeth_fill_buffer(struct qeth_qdio_out_q *queue,
int qeth_do_send_packet_fast(struct qeth_card *card,
struct qeth_qdio_out_q *queue, struct sk_buff *skb,
struct qeth_hdr *hdr, int elements_needed,
- struct qeth_eddp_context *ctx)
+ struct qeth_eddp_context *ctx, int offset, int hd_len)
{
struct qeth_qdio_out_buffer *buffer;
int buffers_needed = 0;
@@ -3148,7 +3171,7 @@ int qeth_do_send_packet_fast(struct qeth_card *card,
}
atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED);
if (ctx == NULL) {
- qeth_fill_buffer(queue, buffer, skb);
+ qeth_fill_buffer(queue, buffer, skb, hdr, offset, hd_len);
qeth_flush_buffers(queue, index, 1);
} else {
flush_cnt = qeth_eddp_fill_buffer(queue, ctx, index);
@@ -3224,7 +3247,7 @@ int qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue,
}
}
if (ctx == NULL)
- tmp = qeth_fill_buffer(queue, buffer, skb);
+ tmp = qeth_fill_buffer(queue, buffer, skb, hdr, -1, 0);
else {
tmp = qeth_eddp_fill_buffer(queue, ctx,
queue->next_buf_to_fill);
@@ -4443,8 +4466,17 @@ static int __init qeth_core_init(void)
rc = IS_ERR(qeth_core_root_dev) ? PTR_ERR(qeth_core_root_dev) : 0;
if (rc)
goto register_err;
- return 0;
+ qeth_core_header_cache = kmem_cache_create("qeth_hdr",
+ sizeof(struct qeth_hdr) + ETH_HLEN, 64, 0, NULL);
+ if (!qeth_core_header_cache) {
+ rc = -ENOMEM;
+ goto slab_err;
+ }
+
+ return 0;
+slab_err:
+ s390_root_dev_unregister(qeth_core_root_dev);
register_err:
driver_remove_file(&qeth_core_ccwgroup_driver.driver,
&driver_attr_group);
@@ -4466,6 +4498,7 @@ static void __exit qeth_core_exit(void)
&driver_attr_group);
ccwgroup_driver_unregister(&qeth_core_ccwgroup_driver);
ccw_driver_unregister(&qeth_ccw_driver);
+ kmem_cache_destroy(qeth_core_header_cache);
qeth_unregister_dbf_views();
PRINT_INFO("core functions removed\n");
}
diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c
index a8b069cd9a4c..b3cee032f578 100644
--- a/drivers/s390/net/qeth_l2_main.c
+++ b/drivers/s390/net/qeth_l2_main.c
@@ -243,8 +243,7 @@ static void qeth_l2_get_packet_type(struct qeth_card *card,
static void qeth_l2_fill_header(struct qeth_card *card, struct qeth_hdr *hdr,
struct sk_buff *skb, int ipv, int cast_type)
{
- struct vlan_ethhdr *veth = (struct vlan_ethhdr *)((skb->data) +
- QETH_HEADER_SIZE);
+ struct vlan_ethhdr *veth = (struct vlan_ethhdr *)skb_mac_header(skb);
memset(hdr, 0, sizeof(struct qeth_hdr));
hdr->hdr.l2.id = QETH_HEADER_TYPE_LAYER2;
@@ -621,6 +620,9 @@ static int qeth_l2_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
int tx_bytes = skb->len;
enum qeth_large_send_types large_send = QETH_LARGE_SEND_NO;
struct qeth_eddp_context *ctx = NULL;
+ int data_offset = -1;
+ int elements_needed = 0;
+ int hd_len = 0;
if ((card->state != CARD_STATE_UP) || !card->lan_online) {
card->stats.tx_carrier_errors++;
@@ -643,13 +645,32 @@ static int qeth_l2_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (card->info.type == QETH_CARD_TYPE_OSN)
hdr = (struct qeth_hdr *)skb->data;
else {
- /* create a clone with writeable headroom */
- new_skb = skb_realloc_headroom(skb, sizeof(struct qeth_hdr));
- if (!new_skb)
- goto tx_drop;
- hdr = (struct qeth_hdr *)skb_push(new_skb,
+ if ((card->info.type == QETH_CARD_TYPE_IQD) && (!large_send) &&
+ (skb_shinfo(skb)->nr_frags == 0)) {
+ new_skb = skb;
+ data_offset = ETH_HLEN;
+ hd_len = ETH_HLEN;
+ hdr = kmem_cache_alloc(qeth_core_header_cache,
+ GFP_ATOMIC);
+ if (!hdr)
+ goto tx_drop;
+ elements_needed++;
+ skb_reset_mac_header(new_skb);
+ qeth_l2_fill_header(card, hdr, new_skb, ipv, cast_type);
+ hdr->hdr.l2.pkt_length = new_skb->len;
+ memcpy(((char *)hdr) + sizeof(struct qeth_hdr),
+ skb_mac_header(new_skb), ETH_HLEN);
+ } else {
+ /* create a clone with writeable headroom */
+ new_skb = skb_realloc_headroom(skb,
+ sizeof(struct qeth_hdr));
+ if (!new_skb)
+ goto tx_drop;
+ hdr = (struct qeth_hdr *)skb_push(new_skb,
sizeof(struct qeth_hdr));
- qeth_l2_fill_header(card, hdr, new_skb, ipv, cast_type);
+ skb_set_mac_header(new_skb, sizeof(struct qeth_hdr));
+ qeth_l2_fill_header(card, hdr, new_skb, ipv, cast_type);
+ }
}
if (large_send == QETH_LARGE_SEND_EDDP) {
@@ -660,9 +681,13 @@ static int qeth_l2_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
goto tx_drop;
}
} else {
- elements = qeth_get_elements_no(card, (void *)hdr, new_skb, 0);
- if (!elements)
+ elements = qeth_get_elements_no(card, (void *)hdr, new_skb,
+ elements_needed);
+ if (!elements) {
+ if (data_offset >= 0)
+ kmem_cache_free(qeth_core_header_cache, hdr);
goto tx_drop;
+ }
}
if ((large_send == QETH_LARGE_SEND_NO) &&
@@ -674,7 +699,7 @@ static int qeth_l2_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
elements, ctx);
else
rc = qeth_do_send_packet_fast(card, queue, new_skb, hdr,
- elements, ctx);
+ elements, ctx, data_offset, hd_len);
if (!rc) {
card->stats.tx_packets++;
card->stats.tx_bytes += tx_bytes;
@@ -701,6 +726,9 @@ static int qeth_l2_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (ctx != NULL)
qeth_eddp_put_context(ctx);
+ if (data_offset >= 0)
+ kmem_cache_free(qeth_core_header_cache, hdr);
+
if (rc == -EBUSY) {
if (new_skb != skb)
dev_kfree_skb_any(new_skb);
diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c
index 3e1d13857350..dd72c3c20165 100644
--- a/drivers/s390/net/qeth_l3_main.c
+++ b/drivers/s390/net/qeth_l3_main.c
@@ -2604,6 +2604,7 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
int tx_bytes = skb->len;
enum qeth_large_send_types large_send = QETH_LARGE_SEND_NO;
struct qeth_eddp_context *ctx = NULL;
+ int data_offset = -1;
if ((card->info.type == QETH_CARD_TYPE_IQD) &&
(skb->protocol != htons(ETH_P_IPV6)) &&
@@ -2624,14 +2625,28 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
card->perf_stats.outbound_start_time = qeth_get_micros();
}
- /* create a clone with writeable headroom */
- new_skb = skb_realloc_headroom(skb, sizeof(struct qeth_hdr_tso) +
- VLAN_HLEN);
- if (!new_skb)
- goto tx_drop;
+ if (skb_is_gso(skb))
+ large_send = card->options.large_send;
+
+ if ((card->info.type == QETH_CARD_TYPE_IQD) && (!large_send) &&
+ (skb_shinfo(skb)->nr_frags == 0)) {
+ new_skb = skb;
+ data_offset = ETH_HLEN;
+ hdr = kmem_cache_alloc(qeth_core_header_cache, GFP_ATOMIC);
+ if (!hdr)
+ goto tx_drop;
+ elements_needed++;
+ } else {
+ /* create a clone with writeable headroom */
+ new_skb = skb_realloc_headroom(skb, sizeof(struct qeth_hdr_tso)
+ + VLAN_HLEN);
+ if (!new_skb)
+ goto tx_drop;
+ }
if (card->info.type == QETH_CARD_TYPE_IQD) {
- skb_pull(new_skb, ETH_HLEN);
+ if (data_offset < 0)
+ skb_pull(new_skb, ETH_HLEN);
} else {
if (new_skb->protocol == htons(ETH_P_IP)) {
if (card->dev->type == ARPHRD_IEEE802_TR)
@@ -2657,9 +2672,6 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
netif_stop_queue(dev);
- if (skb_is_gso(new_skb))
- large_send = card->options.large_send;
-
/* fix hardware limitation: as long as we do not have sbal
* chaining we can not send long frag lists so we temporary
* switch to EDDP
@@ -2677,9 +2689,16 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
qeth_tso_fill_header(card, hdr, new_skb);
elements_needed++;
} else {
- hdr = (struct qeth_hdr *)skb_push(new_skb,
+ if (data_offset < 0) {
+ hdr = (struct qeth_hdr *)skb_push(new_skb,
sizeof(struct qeth_hdr));
- qeth_l3_fill_header(card, hdr, new_skb, ipv, cast_type);
+ qeth_l3_fill_header(card, hdr, new_skb, ipv,
+ cast_type);
+ } else {
+ qeth_l3_fill_header(card, hdr, new_skb, ipv,
+ cast_type);
+ hdr->hdr.l3.length = new_skb->len - data_offset;
+ }
}
if (large_send == QETH_LARGE_SEND_EDDP) {
@@ -2695,8 +2714,11 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
} else {
int elems = qeth_get_elements_no(card, (void *)hdr, new_skb,
elements_needed);
- if (!elems)
+ if (!elems) {
+ if (data_offset >= 0)
+ kmem_cache_free(qeth_core_header_cache, hdr);
goto tx_drop;
+ }
elements_needed += elems;
}
@@ -2709,7 +2731,7 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
elements_needed, ctx);
else
rc = qeth_do_send_packet_fast(card, queue, new_skb, hdr,
- elements_needed, ctx);
+ elements_needed, ctx, data_offset, 0);
if (!rc) {
card->stats.tx_packets++;
@@ -2737,6 +2759,9 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (ctx != NULL)
qeth_eddp_put_context(ctx);
+ if (data_offset >= 0)
+ kmem_cache_free(qeth_core_header_cache, hdr);
+
if (rc == -EBUSY) {
if (new_skb != skb)
dev_kfree_skb_any(new_skb);