提交 9fe3b64b 编写于 作者: L Linus Torvalds

Merge branch 'for-linus' of git://git390.osdl.marist.edu/pub/scm/linux-2.6

* 'for-linus' of git://git390.osdl.marist.edu/pub/scm/linux-2.6:
  [S390] qeth: avoid use of include/asm-s390
  [S390] dont use kthread for smp_rescan_cpus().
  [S390] virtio console: fix section mismatch warning.
  [S390] cio: Include linux/string.h in schid.h.
  [S390] qdio: fix section mismatch bug.
  [S390] stp: fix section mismatch warning.
  [S390] Remove diag 0x260 call from memory detection.
  [S390] qdio: make sure qdr is aligned to page size
  [S390] Add support for memory hot-remove.
  [S390] Wire up new syscalls.
  [S390] cio: Memory allocation for idset changed.
  [S390] qeth: preallocated qeth header for hiper socket
  [S390] Optimize storage key operations for anon pages
  [S390] nohz/sclp: disable timer on synchronous waits.
  [S390] ipl: Reboot from alternate device does not work when booting from file
  [S390] dasd: Add support for enhanced VM UID
  [S390] Remove last P390 trace.
...@@ -317,6 +317,9 @@ config ARCH_ENABLE_MEMORY_HOTPLUG ...@@ -317,6 +317,9 @@ config ARCH_ENABLE_MEMORY_HOTPLUG
def_bool y def_bool y
depends on SPARSEMEM depends on SPARSEMEM
config ARCH_ENABLE_MEMORY_HOTREMOVE
def_bool y
source "mm/Kconfig" source "mm/Kconfig"
comment "I/O subsystem configuration" comment "I/O subsystem configuration"
......
...@@ -1732,3 +1732,40 @@ compat_sys_timerfd_gettime_wrapper: ...@@ -1732,3 +1732,40 @@ compat_sys_timerfd_gettime_wrapper:
lgfr %r2,%r2 # int lgfr %r2,%r2 # int
llgtr %r3,%r3 # struct compat_itimerspec * llgtr %r3,%r3 # struct compat_itimerspec *
jg compat_sys_timerfd_gettime jg compat_sys_timerfd_gettime
.globl compat_sys_signalfd4_wrapper
compat_sys_signalfd4_wrapper:
lgfr %r2,%r2 # int
llgtr %r3,%r3 # compat_sigset_t *
llgfr %r4,%r4 # compat_size_t
lgfr %r5,%r5 # int
jg compat_sys_signalfd4
.globl sys_eventfd2_wrapper
sys_eventfd2_wrapper:
llgfr %r2,%r2 # unsigned int
lgfr %r3,%r3 # int
jg sys_eventfd2
.globl sys_inotify_init1_wrapper
sys_inotify_init1_wrapper:
lgfr %r2,%r2 # int
jg sys_inotify_init1
.globl sys_pipe2_wrapper
sys_pipe2_wrapper:
llgtr %r2,%r2 # u32 *
lgfr %r3,%r3 # int
jg sys_pipe2 # branch to system call
.globl sys_dup3_wrapper
sys_dup3_wrapper:
llgfr %r2,%r2 # unsigned int
llgfr %r3,%r3 # unsigned int
lgfr %r4,%r4 # int
jg sys_dup3 # branch to system call
.globl sys_epoll_create1_wrapper
sys_epoll_create1_wrapper:
lgfr %r2,%r2 # int
jg sys_epoll_create1 # branch to system call
...@@ -1705,7 +1705,10 @@ void __init setup_ipl(void) ...@@ -1705,7 +1705,10 @@ void __init setup_ipl(void)
void __init ipl_update_parameters(void) void __init ipl_update_parameters(void)
{ {
if (diag308(DIAG308_STORE, &ipl_block) == DIAG308_RC_OK) int rc;
rc = diag308(DIAG308_STORE, &ipl_block);
if ((rc == DIAG308_RC_OK) || (rc == DIAG308_RC_NOCONFIG))
diag308_set_works = 1; diag308_set_works = 1;
} }
......
...@@ -9,27 +9,6 @@ ...@@ -9,27 +9,6 @@
#include <asm/sclp.h> #include <asm/sclp.h>
#include <asm/setup.h> #include <asm/setup.h>
static int memory_fast_detect(struct mem_chunk *chunk)
{
unsigned long val0 = 0;
unsigned long val1 = 0xc;
int rc = -EOPNOTSUPP;
if (ipl_flags & IPL_NSS_VALID)
return -EOPNOTSUPP;
asm volatile(
" diag %1,%2,0x260\n"
"0: lhi %0,0\n"
"1:\n"
EX_TABLE(0b,1b)
: "+d" (rc), "+d" (val0), "+d" (val1) : : "cc");
if (rc || val0 != val1)
return -EOPNOTSUPP;
chunk->size = val0 + 1;
return 0;
}
static inline int tprot(unsigned long addr) static inline int tprot(unsigned long addr)
{ {
int rc = -EFAULT; int rc = -EFAULT;
...@@ -84,8 +63,6 @@ void detect_memory_layout(struct mem_chunk chunk[]) ...@@ -84,8 +63,6 @@ void detect_memory_layout(struct mem_chunk chunk[])
unsigned long flags, cr0; unsigned long flags, cr0;
memset(chunk, 0, MEMORY_CHUNKS * sizeof(struct mem_chunk)); memset(chunk, 0, MEMORY_CHUNKS * sizeof(struct mem_chunk));
if (memory_fast_detect(&chunk[0]) == 0)
return;
/* Disable IRQs, DAT and low address protection so tprot does the /* Disable IRQs, DAT and low address protection so tprot does the
* right thing and we don't get scheduled away with low address * right thing and we don't get scheduled away with low address
* protection disabled. * protection disabled.
......
...@@ -330,3 +330,9 @@ SYSCALL(sys_eventfd,sys_eventfd,sys_eventfd_wrapper) ...@@ -330,3 +330,9 @@ SYSCALL(sys_eventfd,sys_eventfd,sys_eventfd_wrapper)
SYSCALL(sys_timerfd_create,sys_timerfd_create,sys_timerfd_create_wrapper) SYSCALL(sys_timerfd_create,sys_timerfd_create,sys_timerfd_create_wrapper)
SYSCALL(sys_timerfd_settime,sys_timerfd_settime,compat_sys_timerfd_settime_wrapper) /* 320 */ SYSCALL(sys_timerfd_settime,sys_timerfd_settime,compat_sys_timerfd_settime_wrapper) /* 320 */
SYSCALL(sys_timerfd_gettime,sys_timerfd_gettime,compat_sys_timerfd_gettime_wrapper) SYSCALL(sys_timerfd_gettime,sys_timerfd_gettime,compat_sys_timerfd_gettime_wrapper)
SYSCALL(sys_signalfd4,sys_signalfd4,compat_sys_signalfd4_wrapper)
SYSCALL(sys_eventfd2,sys_eventfd2,sys_eventfd2_wrapper)
SYSCALL(sys_inotify_init1,sys_inotify_init1,sys_inotify_init1_wrapper)
SYSCALL(sys_pipe2,sys_pipe2,sys_pipe2_wrapper) /* 325 */
SYSCALL(sys_dup3,sys_dup3,sys_dup3_wrapper)
SYSCALL(sys_epoll_create1,sys_epoll_create1,sys_epoll_create1_wrapper)
...@@ -1348,7 +1348,7 @@ early_param("stp", early_parse_stp); ...@@ -1348,7 +1348,7 @@ early_param("stp", early_parse_stp);
/* /*
* Reset STP attachment. * Reset STP attachment.
*/ */
static void stp_reset(void) static void __init stp_reset(void)
{ {
int rc; int rc;
......
...@@ -43,7 +43,7 @@ void __udelay(unsigned long usecs) ...@@ -43,7 +43,7 @@ void __udelay(unsigned long usecs)
local_bh_disable(); local_bh_disable();
local_irq_save(flags); local_irq_save(flags);
if (raw_irqs_disabled_flags(flags)) { if (raw_irqs_disabled_flags(flags)) {
old_cc = S390_lowcore.clock_comparator; old_cc = local_tick_disable();
S390_lowcore.clock_comparator = -1ULL; S390_lowcore.clock_comparator = -1ULL;
__ctl_store(cr0, 0, 0); __ctl_store(cr0, 0, 0);
dummy = (cr0 & 0xffff00e0) | 0x00000800; dummy = (cr0 & 0xffff00e0) | 0x00000800;
...@@ -65,7 +65,7 @@ void __udelay(unsigned long usecs) ...@@ -65,7 +65,7 @@ void __udelay(unsigned long usecs)
if (raw_irqs_disabled_flags(flags)) { if (raw_irqs_disabled_flags(flags)) {
__ctl_load(cr0, 0, 0); __ctl_load(cr0, 0, 0);
S390_lowcore.clock_comparator = old_cc; local_tick_enable(old_cc);
} }
if (!irq_context) if (!irq_context)
_local_bh_enable(); _local_bh_enable();
......
...@@ -179,7 +179,7 @@ int arch_add_memory(int nid, u64 start, u64 size) ...@@ -179,7 +179,7 @@ int arch_add_memory(int nid, u64 start, u64 size)
int rc; int rc;
pgdat = NODE_DATA(nid); pgdat = NODE_DATA(nid);
zone = pgdat->node_zones + ZONE_NORMAL; zone = pgdat->node_zones + ZONE_MOVABLE;
rc = vmem_add_mapping(start, size); rc = vmem_add_mapping(start, size);
if (rc) if (rc)
return rc; return rc;
...@@ -189,3 +189,14 @@ int arch_add_memory(int nid, u64 start, u64 size) ...@@ -189,3 +189,14 @@ int arch_add_memory(int nid, u64 start, u64 size)
return rc; return rc;
} }
#endif /* CONFIG_MEMORY_HOTPLUG */ #endif /* CONFIG_MEMORY_HOTPLUG */
#ifdef CONFIG_MEMORY_HOTREMOVE
int remove_memory(u64 start, u64 size)
{
unsigned long start_pfn, end_pfn;
start_pfn = PFN_DOWN(start);
end_pfn = start_pfn + PFN_DOWN(size);
return offline_pages(start_pfn, end_pfn, 120 * HZ);
}
#endif /* CONFIG_MEMORY_HOTREMOVE */
...@@ -91,7 +91,8 @@ static struct alias_pav_group *_find_group(struct alias_lcu *lcu, ...@@ -91,7 +91,8 @@ static struct alias_pav_group *_find_group(struct alias_lcu *lcu,
else else
search_unit_addr = uid->base_unit_addr; search_unit_addr = uid->base_unit_addr;
list_for_each_entry(pos, &lcu->grouplist, group) { 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 pos;
}; };
return NULL; return NULL;
...@@ -332,6 +333,7 @@ static int _add_device_to_lcu(struct alias_lcu *lcu, ...@@ -332,6 +333,7 @@ static int _add_device_to_lcu(struct alias_lcu *lcu,
group->uid.base_unit_addr = uid->real_unit_addr; group->uid.base_unit_addr = uid->real_unit_addr;
else else
group->uid.base_unit_addr = uid->base_unit_addr; 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->group);
INIT_LIST_HEAD(&group->baselist); INIT_LIST_HEAD(&group->baselist);
INIT_LIST_HEAD(&group->aliaslist); INIT_LIST_HEAD(&group->aliaslist);
......
...@@ -913,7 +913,8 @@ dasd_vendor_show(struct device *dev, struct device_attribute *attr, char *buf) ...@@ -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); static DEVICE_ATTR(vendor, 0444, dasd_vendor_show, NULL);
#define UID_STRLEN ( /* vendor */ 3 + 1 + /* serial */ 14 + 1 +\ #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 static ssize_t
dasd_uid_show(struct device *dev, struct device_attribute *attr, char *buf) 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) ...@@ -945,8 +946,17 @@ dasd_uid_show(struct device *dev, struct device_attribute *attr, char *buf)
sprintf(ua_string, "%02x", uid->real_unit_addr); sprintf(ua_string, "%02x", uid->real_unit_addr);
break; break;
} }
snprintf(uid_string, sizeof(uid_string), "%s.%s.%04x.%s", if (strlen(uid->vduit) > 0)
uid->vendor, uid->serial, uid->ssid, ua_string); 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); spin_unlock(&dasd_devmap_lock);
return snprintf(buf, PAGE_SIZE, "%s\n", uid_string); return snprintf(buf, PAGE_SIZE, "%s\n", uid_string);
} }
......
...@@ -313,8 +313,8 @@ static int prefix(struct ccw1 *ccw, struct PFX_eckd_data *pfxdata, int trk, ...@@ -313,8 +313,8 @@ static int prefix(struct ccw1 *ccw, struct PFX_eckd_data *pfxdata, int trk,
memset(pfxdata, 0, sizeof(*pfxdata)); memset(pfxdata, 0, sizeof(*pfxdata));
/* prefix data */ /* prefix data */
pfxdata->format = 0; pfxdata->format = 0;
pfxdata->base_address = basepriv->conf_data.ned1.unit_addr; pfxdata->base_address = basepriv->ned->unit_addr;
pfxdata->base_lss = basepriv->conf_data.ned1.ID; pfxdata->base_lss = basepriv->ned->ID;
pfxdata->validity.define_extend = 1; pfxdata->validity.define_extend = 1;
/* private uid is kept up to date, conf_data may be outdated */ /* private uid is kept up to date, conf_data may be outdated */
...@@ -536,36 +536,40 @@ dasd_eckd_cdl_reclen(int recid) ...@@ -536,36 +536,40 @@ dasd_eckd_cdl_reclen(int recid)
/* /*
* Generate device unique id that specifies the physical device. * Generate device unique id that specifies the physical device.
*/ */
static int static int dasd_eckd_generate_uid(struct dasd_device *device,
dasd_eckd_generate_uid(struct dasd_device *device, struct dasd_uid *uid) struct dasd_uid *uid)
{ {
struct dasd_eckd_private *private; struct dasd_eckd_private *private;
struct dasd_eckd_confdata *confdata; int count;
private = (struct dasd_eckd_private *) device->private; private = (struct dasd_eckd_private *) device->private;
if (!private) if (!private)
return -ENODEV; return -ENODEV;
confdata = &private->conf_data; if (!private->ned || !private->gneq)
if (!confdata)
return -ENODEV; return -ENODEV;
memset(uid, 0, sizeof(struct dasd_uid)); 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); sizeof(uid->vendor) - 1);
EBCASC(uid->vendor, 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); sizeof(uid->serial) - 1);
EBCASC(uid->serial, sizeof(uid->serial) - 1); EBCASC(uid->serial, sizeof(uid->serial) - 1);
uid->ssid = confdata->neq.subsystemID; uid->ssid = private->gneq->subsystemID;
uid->real_unit_addr = confdata->ned1.unit_addr; uid->real_unit_addr = private->ned->unit_addr;;
if (confdata->ned2.sneq.flags == 0x40 && if (private->sneq) {
confdata->ned2.sneq.format == 0x0001) { uid->type = private->sneq->sua_flags;
uid->type = confdata->ned2.sneq.sua_flags;
if (uid->type == UA_BASE_PAV_ALIAS) 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 { } else {
uid->type = UA_BASE_DEVICE; 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; return 0;
} }
...@@ -623,6 +627,15 @@ static int dasd_eckd_read_conf_lpm(struct dasd_device *device, ...@@ -623,6 +627,15 @@ static int dasd_eckd_read_conf_lpm(struct dasd_device *device,
ret = -ENOMEM; ret = -ENOMEM;
goto out_error; 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); cqr = dasd_eckd_build_rcd_lpm(device, rcd_buf, ciw, lpm);
if (IS_ERR(cqr)) { if (IS_ERR(cqr)) {
ret = PTR_ERR(cqr); ret = PTR_ERR(cqr);
...@@ -646,8 +659,62 @@ static int dasd_eckd_read_conf_lpm(struct dasd_device *device, ...@@ -646,8 +659,62 @@ static int dasd_eckd_read_conf_lpm(struct dasd_device *device,
return ret; return ret;
} }
static int static int dasd_eckd_identify_conf_parts(struct dasd_eckd_private *private)
dasd_eckd_read_conf(struct dasd_device *device) {
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; void *conf_data;
int conf_len, conf_data_saved; int conf_len, conf_data_saved;
...@@ -661,7 +728,6 @@ dasd_eckd_read_conf(struct dasd_device *device) ...@@ -661,7 +728,6 @@ dasd_eckd_read_conf(struct dasd_device *device)
path_data->opm = ccw_device_get_path_mask(device->cdev); path_data->opm = ccw_device_get_path_mask(device->cdev);
lpm = 0x80; lpm = 0x80;
conf_data_saved = 0; conf_data_saved = 0;
/* get configuration data per operational path */ /* get configuration data per operational path */
for (lpm = 0x80; lpm; lpm>>= 1) { for (lpm = 0x80; lpm; lpm>>= 1) {
if (lpm & path_data->opm){ if (lpm & path_data->opm){
...@@ -678,22 +744,20 @@ dasd_eckd_read_conf(struct dasd_device *device) ...@@ -678,22 +744,20 @@ dasd_eckd_read_conf(struct dasd_device *device)
"data retrieved"); "data retrieved");
continue; /* no error */ 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 */ /* save first valid configuration data */
if (!conf_data_saved){ if (!conf_data_saved) {
memcpy(&private->conf_data, conf_data, kfree(private->conf_data);
sizeof(struct dasd_eckd_confdata)); 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++; conf_data_saved++;
} }
switch (((char *)conf_data)[242] & 0x07){ switch (dasd_eckd_path_access(conf_data, conf_len)) {
case 0x02: case 0x02:
path_data->npm |= lpm; path_data->npm |= lpm;
break; break;
...@@ -701,7 +765,8 @@ dasd_eckd_read_conf(struct dasd_device *device) ...@@ -701,7 +765,8 @@ dasd_eckd_read_conf(struct dasd_device *device)
path_data->ppm |= lpm; path_data->ppm |= lpm;
break; break;
} }
kfree(conf_data); if (conf_data != private->conf_data)
kfree(conf_data);
} }
} }
return 0; return 0;
...@@ -952,6 +1017,7 @@ dasd_eckd_check_characteristics(struct dasd_device *device) ...@@ -952,6 +1017,7 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
dasd_free_block(device->block); dasd_free_block(device->block);
device->block = NULL; device->block = NULL;
out_err1: out_err1:
kfree(private->conf_data);
kfree(device->private); kfree(device->private);
device->private = NULL; device->private = NULL;
return rc; return rc;
...@@ -959,7 +1025,17 @@ dasd_eckd_check_characteristics(struct dasd_device *device) ...@@ -959,7 +1025,17 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
static void dasd_eckd_uncheck_device(struct dasd_device *device) 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); 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 * static struct dasd_ccw_req *
...@@ -1746,9 +1822,10 @@ dasd_eckd_fill_info(struct dasd_device * device, ...@@ -1746,9 +1822,10 @@ dasd_eckd_fill_info(struct dasd_device * device,
info->characteristics_size = sizeof(struct dasd_eckd_characteristics); info->characteristics_size = sizeof(struct dasd_eckd_characteristics);
memcpy(info->characteristics, &private->rdc_data, memcpy(info->characteristics, &private->rdc_data,
sizeof(struct dasd_eckd_characteristics)); sizeof(struct dasd_eckd_characteristics));
info->confdata_size = sizeof(struct dasd_eckd_confdata); info->confdata_size = min((unsigned long)private->conf_len,
memcpy(info->configuration_data, &private->conf_data, sizeof(info->configuration_data));
sizeof(struct dasd_eckd_confdata)); memcpy(info->configuration_data, private->conf_data,
info->confdata_size);
return 0; return 0;
} }
......
...@@ -231,133 +231,62 @@ struct dasd_eckd_characteristics { ...@@ -231,133 +231,62 @@ struct dasd_eckd_characteristics {
__u8 reserved3[10]; __u8 reserved3[10];
} __attribute__ ((packed)); } __attribute__ ((packed));
struct dasd_eckd_confdata { /* elements of the configuration data */
struct dasd_ned {
struct { struct {
struct { __u8 identifier:2;
unsigned char identifier:2; __u8 token_id:1;
unsigned char token_id:1; __u8 sno_valid:1;
unsigned char sno_valid:1; __u8 subst_sno:1;
unsigned char subst_sno:1; __u8 recNED:1;
unsigned char recNED:1; __u8 emuNED:1;
unsigned char emuNED:1; __u8 reserved:1;
unsigned char reserved:1; } __attribute__ ((packed)) flags;
} __attribute__ ((packed)) flags; __u8 descriptor;
__u8 descriptor; __u8 dev_class;
__u8 dev_class; __u8 reserved;
__u8 reserved; __u8 dev_type[6];
unsigned char dev_type[6]; __u8 dev_model[3];
unsigned char dev_model[3]; __u8 HDA_manufacturer[3];
unsigned char HDA_manufacturer[3]; __u8 HDA_location[2];
unsigned char HDA_location[2]; __u8 HDA_seqno[12];
unsigned char HDA_seqno[12]; __u8 ID;
__u8 ID; __u8 unit_addr;
__u8 unit_addr; } __attribute__ ((packed));
} __attribute__ ((packed)) ned1;
union { 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 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;
struct { struct {
struct { __u8 identifier:2;
unsigned char identifier:2; __u8 reserved:6;
unsigned char token_id:1; } __attribute__ ((packed)) flags;
unsigned char sno_valid:1; __u8 res1;
unsigned char subst_sno:1; __u16 format;
unsigned char recNED:1; __u8 res2[4]; /* byte 4- 7 */
unsigned char emuNED:1; __u8 sua_flags; /* byte 8 */
unsigned char reserved:1; __u8 base_unit_addr; /* byte 9 */
} __attribute__ ((packed)) flags; __u8 res3[22]; /* byte 10-31 */
__u8 descriptor; } __attribute__ ((packed));
__u8 reserved[2];
unsigned char cont_type[6]; struct vd_sneq {
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;
struct { struct {
struct { __u8 identifier:2;
unsigned char identifier:2; __u8 reserved:6;
unsigned char token_id:1; } __attribute__ ((packed)) flags;
unsigned char sno_valid:1; __u8 res1;
unsigned char subst_sno:1; __u16 format;
unsigned char recNED:1; __u8 res2[4]; /* byte 4- 7 */
unsigned char emuNED:1; __u8 uit[16]; /* byte 8-23 */
unsigned char reserved:1; __u8 res3[8]; /* byte 24-31 */
} __attribute__ ((packed)) flags; } __attribute__ ((packed));
__u8 descriptor;
__u8 reserved[2]; struct dasd_gneq {
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];
struct { struct {
struct { __u8 identifier:2;
unsigned char identifier:2; __u8 reserved:6;
unsigned char reserved:6; } __attribute__ ((packed)) flags;
} __attribute__ ((packed)) flags; __u8 reserved[7];
__u8 selector; __u16 subsystemID;
__u16 interfaceID; __u8 reserved2[22];
__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;
} __attribute__ ((packed)); } __attribute__ ((packed));
struct dasd_eckd_path { struct dasd_eckd_path {
...@@ -463,7 +392,14 @@ struct alias_pav_group { ...@@ -463,7 +392,14 @@ struct alias_pav_group {
struct dasd_eckd_private { struct dasd_eckd_private {
struct dasd_eckd_characteristics rdc_data; 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 dasd_eckd_path path_data;
struct eckd_count count_area[5]; struct eckd_count count_area[5];
int init_cqr_status; int init_cqr_status;
......
...@@ -307,6 +307,7 @@ struct dasd_uid { ...@@ -307,6 +307,7 @@ struct dasd_uid {
__u16 ssid; __u16 ssid;
__u8 real_unit_addr; __u8 real_unit_addr;
__u8 base_unit_addr; __u8 base_unit_addr;
char vduit[33];
}; };
/* /*
......
...@@ -399,6 +399,7 @@ sclp_tod_from_jiffies(unsigned long jiffies) ...@@ -399,6 +399,7 @@ sclp_tod_from_jiffies(unsigned long jiffies)
void void
sclp_sync_wait(void) sclp_sync_wait(void)
{ {
unsigned long long old_tick;
unsigned long flags; unsigned long flags;
unsigned long cr0, cr0_sync; unsigned long cr0, cr0_sync;
u64 timeout; u64 timeout;
...@@ -419,11 +420,12 @@ sclp_sync_wait(void) ...@@ -419,11 +420,12 @@ sclp_sync_wait(void)
if (!irq_context) if (!irq_context)
local_bh_disable(); local_bh_disable();
/* Enable service-signal interruption, disable timer interrupts */ /* Enable service-signal interruption, disable timer interrupts */
old_tick = local_tick_disable();
trace_hardirqs_on(); trace_hardirqs_on();
__ctl_store(cr0, 0, 0); __ctl_store(cr0, 0, 0);
cr0_sync = cr0; cr0_sync = cr0;
cr0_sync &= 0xffff00a0;
cr0_sync |= 0x00000200; cr0_sync |= 0x00000200;
cr0_sync &= 0xFFFFF3AC;
__ctl_load(cr0_sync, 0, 0); __ctl_load(cr0_sync, 0, 0);
__raw_local_irq_stosm(0x01); __raw_local_irq_stosm(0x01);
/* Loop until driver state indicates finished request */ /* Loop until driver state indicates finished request */
...@@ -439,9 +441,9 @@ sclp_sync_wait(void) ...@@ -439,9 +441,9 @@ sclp_sync_wait(void)
__ctl_load(cr0, 0, 0); __ctl_load(cr0, 0, 0);
if (!irq_context) if (!irq_context)
_local_bh_enable(); _local_bh_enable();
local_tick_enable(old_tick);
local_irq_restore(flags); local_irq_restore(flags);
} }
EXPORT_SYMBOL(sclp_sync_wait); EXPORT_SYMBOL(sclp_sync_wait);
/* Dispatch changes in send and receive mask to registered listeners. */ /* Dispatch changes in send and receive mask to registered listeners. */
......
...@@ -427,6 +427,8 @@ static int sclp_mem_notifier(struct notifier_block *nb, ...@@ -427,6 +427,8 @@ static int sclp_mem_notifier(struct notifier_block *nb,
sclp_attach_storage(id); sclp_attach_storage(id);
switch (action) { switch (action) {
case MEM_ONLINE: case MEM_ONLINE:
case MEM_GOING_OFFLINE:
case MEM_CANCEL_OFFLINE:
break; break;
case MEM_GOING_ONLINE: case MEM_GOING_ONLINE:
rc = sclp_mem_change_state(start, size, 1); rc = sclp_mem_change_state(start, size, 1);
...@@ -434,6 +436,9 @@ static int sclp_mem_notifier(struct notifier_block *nb, ...@@ -434,6 +436,9 @@ static int sclp_mem_notifier(struct notifier_block *nb,
case MEM_CANCEL_ONLINE: case MEM_CANCEL_ONLINE:
sclp_mem_change_state(start, size, 0); sclp_mem_change_state(start, size, 0);
break; break;
case MEM_OFFLINE:
sclp_mem_change_state(start, size, 0);
break;
default: default:
rc = -EINVAL; rc = -EINVAL;
break; break;
......
...@@ -8,7 +8,6 @@ ...@@ -8,7 +8,6 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/cpu.h> #include <linux/cpu.h>
#include <linux/kthread.h>
#include <linux/sysdev.h> #include <linux/sysdev.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include <asm/smp.h> #include <asm/smp.h>
...@@ -41,19 +40,9 @@ static void sclp_cpu_capability_notify(struct work_struct *work) ...@@ -41,19 +40,9 @@ static void sclp_cpu_capability_notify(struct work_struct *work)
put_online_cpus(); 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) static void __ref sclp_cpu_change_notify(struct work_struct *work)
{ {
/* Can't call smp_rescan_cpus() from workqueue context since it may smp_rescan_cpus();
* 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");
} }
static void sclp_conf_receiver_fn(struct evbuf_header *evbuf) static void sclp_conf_receiver_fn(struct evbuf_header *evbuf)
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
* Author(s): Peter Oberparleiter <peter.oberparleiter@de.ibm.com> * Author(s): Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
*/ */
#include <linux/slab.h> #include <linux/vmalloc.h>
#include <linux/bitops.h> #include <linux/bitops.h>
#include "idset.h" #include "idset.h"
#include "css.h" #include "css.h"
...@@ -25,18 +25,18 @@ static struct idset *idset_new(int num_ssid, int num_id) ...@@ -25,18 +25,18 @@ static struct idset *idset_new(int num_ssid, int num_id)
{ {
struct idset *set; struct idset *set;
set = kzalloc(sizeof(struct idset) + bitmap_size(num_ssid, num_id), set = vmalloc(sizeof(struct idset) + bitmap_size(num_ssid, num_id));
GFP_KERNEL);
if (set) { if (set) {
set->num_ssid = num_ssid; set->num_ssid = num_ssid;
set->num_id = num_id; set->num_id = num_id;
memset(set->bitmap, 0, bitmap_size(num_ssid, num_id));
} }
return set; return set;
} }
void idset_free(struct idset *set) void idset_free(struct idset *set)
{ {
kfree(set); vfree(set);
} }
void idset_clear(struct idset *set) void idset_clear(struct idset *set)
......
...@@ -1355,7 +1355,7 @@ int qdio_allocate(struct qdio_initialize *init_data) ...@@ -1355,7 +1355,7 @@ int qdio_allocate(struct qdio_initialize *init_data)
goto out_rel; goto out_rel;
/* qdr is used in ccw1.cda which is u32 */ /* 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) if (!irq_ptr->qdr)
goto out_rel; goto out_rel;
WARN_ON((unsigned long)irq_ptr->qdr & 0xfff); WARN_ON((unsigned long)irq_ptr->qdr & 0xfff);
......
...@@ -142,7 +142,7 @@ int __init qdio_setup_perf_stats(void) ...@@ -142,7 +142,7 @@ int __init qdio_setup_perf_stats(void)
return 0; return 0;
} }
void __exit qdio_remove_perf_stats(void) void qdio_remove_perf_stats(void)
{ {
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
remove_proc_entry("qdio_perf", NULL); remove_proc_entry("qdio_perf", NULL);
......
...@@ -325,7 +325,7 @@ void qdio_release_memory(struct qdio_irq *irq_ptr) ...@@ -325,7 +325,7 @@ void qdio_release_memory(struct qdio_irq *irq_ptr)
kmem_cache_free(qdio_q_cache, q); 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(irq_ptr->chsc_page);
free_page((unsigned long) irq_ptr); free_page((unsigned long) irq_ptr);
} }
...@@ -515,7 +515,7 @@ int __init qdio_setup_init(void) ...@@ -515,7 +515,7 @@ int __init qdio_setup_init(void)
return 0; return 0;
} }
void __exit qdio_setup_exit(void) void qdio_setup_exit(void)
{ {
kmem_cache_destroy(qdio_q_cache); kmem_cache_destroy(qdio_q_cache);
} }
...@@ -352,7 +352,7 @@ static __init int early_put_chars(u32 vtermno, const char *buf, int count) ...@@ -352,7 +352,7 @@ static __init int early_put_chars(u32 vtermno, const char *buf, int count)
return len; return len;
} }
void s390_virtio_console_init(void) void __init s390_virtio_console_init(void)
{ {
virtio_cons_early_init(early_put_chars); virtio_cons_early_init(early_put_chars);
} }
......
...@@ -419,6 +419,7 @@ struct qeth_qdio_out_buffer { ...@@ -419,6 +419,7 @@ struct qeth_qdio_out_buffer {
int next_element_to_fill; int next_element_to_fill;
struct sk_buff_head skb_list; struct sk_buff_head skb_list;
struct list_head ctx_list; struct list_head ctx_list;
int is_header[16];
}; };
struct qeth_card; struct qeth_card;
...@@ -785,7 +786,7 @@ void qeth_core_remove_osn_attributes(struct device *); ...@@ -785,7 +786,7 @@ void qeth_core_remove_osn_attributes(struct device *);
/* exports for qeth discipline device drivers */ /* exports for qeth discipline device drivers */
extern struct qeth_card_list_struct qeth_core_card_list; 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]; extern struct qeth_dbf_info qeth_dbf[QETH_DBF_INFOS];
void qeth_set_allowed_threads(struct qeth_card *, unsigned long , int); 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); ...@@ -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_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 *, int qeth_do_send_packet_fast(struct qeth_card *, struct qeth_qdio_out_q *,
struct sk_buff *, struct qeth_hdr *, int, 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 *, int qeth_do_send_packet(struct qeth_card *, struct qeth_qdio_out_q *,
struct sk_buff *, struct qeth_hdr *, struct sk_buff *, struct qeth_hdr *,
int, struct qeth_eddp_context *); int, struct qeth_eddp_context *);
......
...@@ -19,8 +19,8 @@ ...@@ -19,8 +19,8 @@
#include <linux/mii.h> #include <linux/mii.h>
#include <linux/kthread.h> #include <linux/kthread.h>
#include <asm-s390/ebcdic.h> #include <asm/ebcdic.h>
#include <asm-s390/io.h> #include <asm/io.h>
#include <asm/s390_rdev.h> #include <asm/s390_rdev.h>
#include "qeth_core.h" #include "qeth_core.h"
...@@ -48,6 +48,8 @@ EXPORT_SYMBOL_GPL(qeth_dbf); ...@@ -48,6 +48,8 @@ EXPORT_SYMBOL_GPL(qeth_dbf);
struct qeth_card_list_struct qeth_core_card_list; struct qeth_card_list_struct qeth_core_card_list;
EXPORT_SYMBOL_GPL(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 struct device *qeth_core_root_dev;
static unsigned int known_devices[][10] = QETH_MODELLIST_ARRAY; 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, ...@@ -933,6 +935,10 @@ static void qeth_clear_output_buffer(struct qeth_qdio_out_q *queue,
} }
qeth_eddp_buf_release_contexts(buf); qeth_eddp_buf_release_contexts(buf);
for (i = 0; i < QETH_MAX_BUFFER_ELEMENTS(queue->card); ++i) { 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].length = 0;
buf->buffer->element[i].addr = NULL; buf->buffer->element[i].addr = NULL;
buf->buffer->element[i].flags = 0; buf->buffer->element[i].flags = 0;
...@@ -3002,8 +3008,8 @@ int qeth_get_elements_no(struct qeth_card *card, void *hdr, ...@@ -3002,8 +3008,8 @@ int qeth_get_elements_no(struct qeth_card *card, void *hdr,
if (skb_shinfo(skb)->nr_frags > 0) if (skb_shinfo(skb)->nr_frags > 0)
elements_needed = (skb_shinfo(skb)->nr_frags + 1); elements_needed = (skb_shinfo(skb)->nr_frags + 1);
if (elements_needed == 0) if (elements_needed == 0)
elements_needed = 1 + (((((unsigned long) hdr) % PAGE_SIZE) elements_needed = 1 + (((((unsigned long) skb->data) %
+ skb->len) >> PAGE_SHIFT); PAGE_SIZE) + skb->len) >> PAGE_SHIFT);
if ((elements_needed + elems) > QETH_MAX_BUFFER_ELEMENTS(card)) { if ((elements_needed + elems) > QETH_MAX_BUFFER_ELEMENTS(card)) {
QETH_DBF_MESSAGE(2, "Invalid size of IP packet " QETH_DBF_MESSAGE(2, "Invalid size of IP packet "
"(Number=%d / Length=%d). Discarded.\n", "(Number=%d / Length=%d). Discarded.\n",
...@@ -3015,7 +3021,8 @@ int qeth_get_elements_no(struct qeth_card *card, void *hdr, ...@@ -3015,7 +3021,8 @@ int qeth_get_elements_no(struct qeth_card *card, void *hdr,
EXPORT_SYMBOL_GPL(qeth_get_elements_no); EXPORT_SYMBOL_GPL(qeth_get_elements_no);
static inline void __qeth_fill_buffer(struct sk_buff *skb, 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 = skb->len;
int length_here; int length_here;
...@@ -3027,6 +3034,11 @@ static inline void __qeth_fill_buffer(struct sk_buff *skb, ...@@ -3027,6 +3034,11 @@ static inline void __qeth_fill_buffer(struct sk_buff *skb,
data = skb->data; data = skb->data;
first_lap = (is_tso == 0 ? 1 : 0); first_lap = (is_tso == 0 ? 1 : 0);
if (offset >= 0) {
data = skb->data + offset;
first_lap = 0;
}
while (length > 0) { while (length > 0) {
/* length_here is the remaining amount of data in this page */ /* length_here is the remaining amount of data in this page */
length_here = PAGE_SIZE - ((unsigned long) data % PAGE_SIZE); length_here = PAGE_SIZE - ((unsigned long) data % PAGE_SIZE);
...@@ -3058,22 +3070,22 @@ static inline void __qeth_fill_buffer(struct sk_buff *skb, ...@@ -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, 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 qdio_buffer *buffer;
struct qeth_hdr_tso *hdr;
int flush_cnt = 0, hdr_len, large_send = 0; int flush_cnt = 0, hdr_len, large_send = 0;
buffer = buf->buffer; buffer = buf->buffer;
atomic_inc(&skb->users); atomic_inc(&skb->users);
skb_queue_tail(&buf->skb_list, skb); skb_queue_tail(&buf->skb_list, skb);
hdr = (struct qeth_hdr_tso *) skb->data;
/*check first on TSO ....*/ /*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; 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 */ /*fill first buffer entry only with header information */
buffer->element[element].addr = skb->data; buffer->element[element].addr = skb->data;
buffer->element[element].length = hdr_len; buffer->element[element].length = hdr_len;
...@@ -3083,9 +3095,20 @@ static inline int qeth_fill_buffer(struct qeth_qdio_out_q *queue, ...@@ -3083,9 +3095,20 @@ static inline int qeth_fill_buffer(struct qeth_qdio_out_q *queue,
skb->len -= hdr_len; skb->len -= hdr_len;
large_send = 1; 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) if (skb_shinfo(skb)->nr_frags == 0)
__qeth_fill_buffer(skb, buffer, large_send, __qeth_fill_buffer(skb, buffer, large_send,
(int *)&buf->next_element_to_fill); (int *)&buf->next_element_to_fill, offset);
else else
__qeth_fill_buffer_frag(skb, buffer, large_send, __qeth_fill_buffer_frag(skb, buffer, large_send,
(int *)&buf->next_element_to_fill); (int *)&buf->next_element_to_fill);
...@@ -3115,7 +3138,7 @@ static inline int qeth_fill_buffer(struct qeth_qdio_out_q *queue, ...@@ -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, int qeth_do_send_packet_fast(struct qeth_card *card,
struct qeth_qdio_out_q *queue, struct sk_buff *skb, struct qeth_qdio_out_q *queue, struct sk_buff *skb,
struct qeth_hdr *hdr, int elements_needed, 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; struct qeth_qdio_out_buffer *buffer;
int buffers_needed = 0; int buffers_needed = 0;
...@@ -3148,7 +3171,7 @@ int qeth_do_send_packet_fast(struct qeth_card *card, ...@@ -3148,7 +3171,7 @@ int qeth_do_send_packet_fast(struct qeth_card *card,
} }
atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED); atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED);
if (ctx == NULL) { 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); qeth_flush_buffers(queue, index, 1);
} else { } else {
flush_cnt = qeth_eddp_fill_buffer(queue, ctx, index); 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, ...@@ -3224,7 +3247,7 @@ int qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue,
} }
} }
if (ctx == NULL) if (ctx == NULL)
tmp = qeth_fill_buffer(queue, buffer, skb); tmp = qeth_fill_buffer(queue, buffer, skb, hdr, -1, 0);
else { else {
tmp = qeth_eddp_fill_buffer(queue, ctx, tmp = qeth_eddp_fill_buffer(queue, ctx,
queue->next_buf_to_fill); queue->next_buf_to_fill);
...@@ -4443,8 +4466,17 @@ static int __init qeth_core_init(void) ...@@ -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; rc = IS_ERR(qeth_core_root_dev) ? PTR_ERR(qeth_core_root_dev) : 0;
if (rc) if (rc)
goto register_err; 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: register_err:
driver_remove_file(&qeth_core_ccwgroup_driver.driver, driver_remove_file(&qeth_core_ccwgroup_driver.driver,
&driver_attr_group); &driver_attr_group);
...@@ -4466,6 +4498,7 @@ static void __exit qeth_core_exit(void) ...@@ -4466,6 +4498,7 @@ static void __exit qeth_core_exit(void)
&driver_attr_group); &driver_attr_group);
ccwgroup_driver_unregister(&qeth_core_ccwgroup_driver); ccwgroup_driver_unregister(&qeth_core_ccwgroup_driver);
ccw_driver_unregister(&qeth_ccw_driver); ccw_driver_unregister(&qeth_ccw_driver);
kmem_cache_destroy(qeth_core_header_cache);
qeth_unregister_dbf_views(); qeth_unregister_dbf_views();
PRINT_INFO("core functions removed\n"); PRINT_INFO("core functions removed\n");
} }
......
...@@ -243,8 +243,7 @@ static void qeth_l2_get_packet_type(struct qeth_card *card, ...@@ -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, static void qeth_l2_fill_header(struct qeth_card *card, struct qeth_hdr *hdr,
struct sk_buff *skb, int ipv, int cast_type) struct sk_buff *skb, int ipv, int cast_type)
{ {
struct vlan_ethhdr *veth = (struct vlan_ethhdr *)((skb->data) + struct vlan_ethhdr *veth = (struct vlan_ethhdr *)skb_mac_header(skb);
QETH_HEADER_SIZE);
memset(hdr, 0, sizeof(struct qeth_hdr)); memset(hdr, 0, sizeof(struct qeth_hdr));
hdr->hdr.l2.id = QETH_HEADER_TYPE_LAYER2; 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) ...@@ -621,6 +620,9 @@ static int qeth_l2_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
int tx_bytes = skb->len; int tx_bytes = skb->len;
enum qeth_large_send_types large_send = QETH_LARGE_SEND_NO; enum qeth_large_send_types large_send = QETH_LARGE_SEND_NO;
struct qeth_eddp_context *ctx = NULL; 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) { if ((card->state != CARD_STATE_UP) || !card->lan_online) {
card->stats.tx_carrier_errors++; card->stats.tx_carrier_errors++;
...@@ -643,13 +645,32 @@ static int qeth_l2_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -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) if (card->info.type == QETH_CARD_TYPE_OSN)
hdr = (struct qeth_hdr *)skb->data; hdr = (struct qeth_hdr *)skb->data;
else { else {
/* create a clone with writeable headroom */ if ((card->info.type == QETH_CARD_TYPE_IQD) && (!large_send) &&
new_skb = skb_realloc_headroom(skb, sizeof(struct qeth_hdr)); (skb_shinfo(skb)->nr_frags == 0)) {
if (!new_skb) new_skb = skb;
goto tx_drop; data_offset = ETH_HLEN;
hdr = (struct qeth_hdr *)skb_push(new_skb, 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)); 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) { 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) ...@@ -660,9 +681,13 @@ static int qeth_l2_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
goto tx_drop; goto tx_drop;
} }
} else { } else {
elements = qeth_get_elements_no(card, (void *)hdr, new_skb, 0); elements = qeth_get_elements_no(card, (void *)hdr, new_skb,
if (!elements) elements_needed);
if (!elements) {
if (data_offset >= 0)
kmem_cache_free(qeth_core_header_cache, hdr);
goto tx_drop; goto tx_drop;
}
} }
if ((large_send == QETH_LARGE_SEND_NO) && 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) ...@@ -674,7 +699,7 @@ static int qeth_l2_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
elements, ctx); elements, ctx);
else else
rc = qeth_do_send_packet_fast(card, queue, new_skb, hdr, rc = qeth_do_send_packet_fast(card, queue, new_skb, hdr,
elements, ctx); elements, ctx, data_offset, hd_len);
if (!rc) { if (!rc) {
card->stats.tx_packets++; card->stats.tx_packets++;
card->stats.tx_bytes += tx_bytes; 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) ...@@ -701,6 +726,9 @@ static int qeth_l2_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (ctx != NULL) if (ctx != NULL)
qeth_eddp_put_context(ctx); qeth_eddp_put_context(ctx);
if (data_offset >= 0)
kmem_cache_free(qeth_core_header_cache, hdr);
if (rc == -EBUSY) { if (rc == -EBUSY) {
if (new_skb != skb) if (new_skb != skb)
dev_kfree_skb_any(new_skb); dev_kfree_skb_any(new_skb);
......
...@@ -2604,6 +2604,7 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -2604,6 +2604,7 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
int tx_bytes = skb->len; int tx_bytes = skb->len;
enum qeth_large_send_types large_send = QETH_LARGE_SEND_NO; enum qeth_large_send_types large_send = QETH_LARGE_SEND_NO;
struct qeth_eddp_context *ctx = NULL; struct qeth_eddp_context *ctx = NULL;
int data_offset = -1;
if ((card->info.type == QETH_CARD_TYPE_IQD) && if ((card->info.type == QETH_CARD_TYPE_IQD) &&
(skb->protocol != htons(ETH_P_IPV6)) && (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) ...@@ -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(); card->perf_stats.outbound_start_time = qeth_get_micros();
} }
/* create a clone with writeable headroom */ if (skb_is_gso(skb))
new_skb = skb_realloc_headroom(skb, sizeof(struct qeth_hdr_tso) + large_send = card->options.large_send;
VLAN_HLEN);
if (!new_skb) if ((card->info.type == QETH_CARD_TYPE_IQD) && (!large_send) &&
goto tx_drop; (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) { 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 { } else {
if (new_skb->protocol == htons(ETH_P_IP)) { if (new_skb->protocol == htons(ETH_P_IP)) {
if (card->dev->type == ARPHRD_IEEE802_TR) 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) ...@@ -2657,9 +2672,6 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
netif_stop_queue(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 /* fix hardware limitation: as long as we do not have sbal
* chaining we can not send long frag lists so we temporary * chaining we can not send long frag lists so we temporary
* switch to EDDP * switch to EDDP
...@@ -2677,9 +2689,16 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -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); qeth_tso_fill_header(card, hdr, new_skb);
elements_needed++; elements_needed++;
} else { } 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)); 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) { 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) ...@@ -2695,8 +2714,11 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
} else { } else {
int elems = qeth_get_elements_no(card, (void *)hdr, new_skb, int elems = qeth_get_elements_no(card, (void *)hdr, new_skb,
elements_needed); elements_needed);
if (!elems) if (!elems) {
if (data_offset >= 0)
kmem_cache_free(qeth_core_header_cache, hdr);
goto tx_drop; goto tx_drop;
}
elements_needed += elems; elements_needed += elems;
} }
...@@ -2709,7 +2731,7 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -2709,7 +2731,7 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
elements_needed, ctx); elements_needed, ctx);
else else
rc = qeth_do_send_packet_fast(card, queue, new_skb, hdr, rc = qeth_do_send_packet_fast(card, queue, new_skb, hdr,
elements_needed, ctx); elements_needed, ctx, data_offset, 0);
if (!rc) { if (!rc) {
card->stats.tx_packets++; card->stats.tx_packets++;
...@@ -2737,6 +2759,9 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -2737,6 +2759,9 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (ctx != NULL) if (ctx != NULL)
qeth_eddp_put_context(ctx); qeth_eddp_put_context(ctx);
if (data_offset >= 0)
kmem_cache_free(qeth_core_header_cache, hdr);
if (rc == -EBUSY) { if (rc == -EBUSY) {
if (new_skb != skb) if (new_skb != skb)
dev_kfree_skb_any(new_skb); dev_kfree_skb_any(new_skb);
......
...@@ -34,4 +34,18 @@ typedef struct { ...@@ -34,4 +34,18 @@ typedef struct {
void clock_comparator_work(void); void clock_comparator_work(void);
static inline unsigned long long local_tick_disable(void)
{
unsigned long long old;
old = S390_lowcore.clock_comparator;
S390_lowcore.clock_comparator = -1ULL;
return old;
}
static inline void local_tick_enable(unsigned long long comp)
{
S390_lowcore.clock_comparator = comp;
}
#endif /* __ASM_HARDIRQ_H */ #endif /* __ASM_HARDIRQ_H */
...@@ -159,7 +159,8 @@ enum diag308_vm_flags { ...@@ -159,7 +159,8 @@ enum diag308_vm_flags {
}; };
enum diag308_rc { enum diag308_rc {
DIAG308_RC_OK = 1, DIAG308_RC_OK = 0x0001,
DIAG308_RC_NOCONFIG = 0x0102,
}; };
extern int diag308(unsigned long subcode, void *addr); extern int diag308(unsigned long subcode, void *addr);
......
...@@ -11,6 +11,7 @@ struct subchannel_id { ...@@ -11,6 +11,7 @@ struct subchannel_id {
} __attribute__ ((packed, aligned(4))); } __attribute__ ((packed, aligned(4)));
#ifdef __KERNEL__ #ifdef __KERNEL__
#include <linux/string.h>
/* Helper function for sane state of pre-allocated subchannel_id. */ /* Helper function for sane state of pre-allocated subchannel_id. */
static inline void static inline void
......
...@@ -65,7 +65,6 @@ extern unsigned long machine_flags; ...@@ -65,7 +65,6 @@ extern unsigned long machine_flags;
#define MACHINE_FLAG_VM (1UL << 0) #define MACHINE_FLAG_VM (1UL << 0)
#define MACHINE_FLAG_IEEE (1UL << 1) #define MACHINE_FLAG_IEEE (1UL << 1)
#define MACHINE_FLAG_P390 (1UL << 2)
#define MACHINE_FLAG_CSP (1UL << 3) #define MACHINE_FLAG_CSP (1UL << 3)
#define MACHINE_FLAG_MVPG (1UL << 4) #define MACHINE_FLAG_MVPG (1UL << 4)
#define MACHINE_FLAG_DIAG44 (1UL << 5) #define MACHINE_FLAG_DIAG44 (1UL << 5)
......
...@@ -259,7 +259,13 @@ ...@@ -259,7 +259,13 @@
#define __NR_timerfd_create 319 #define __NR_timerfd_create 319
#define __NR_timerfd_settime 320 #define __NR_timerfd_settime 320
#define __NR_timerfd_gettime 321 #define __NR_timerfd_gettime 321
#define NR_syscalls 322 #define __NR_signalfd4 322
#define __NR_eventfd2 323
#define __NR_inotify_init1 324
#define __NR_pipe2 325
#define __NR_dup3 326
#define __NR_epoll_create1 327
#define NR_syscalls 328
/* /*
* There are some system calls that are not present on 64 bit, some * There are some system calls that are not present on 64 bit, some
......
...@@ -239,9 +239,6 @@ static inline void __SetPageUptodate(struct page *page) ...@@ -239,9 +239,6 @@ static inline void __SetPageUptodate(struct page *page)
{ {
smp_wmb(); smp_wmb();
__set_bit(PG_uptodate, &(page)->flags); __set_bit(PG_uptodate, &(page)->flags);
#ifdef CONFIG_S390
page_clear_dirty(page);
#endif
} }
static inline void SetPageUptodate(struct page *page) static inline void SetPageUptodate(struct page *page)
......
...@@ -667,7 +667,8 @@ void page_remove_rmap(struct page *page, struct vm_area_struct *vma) ...@@ -667,7 +667,8 @@ void page_remove_rmap(struct page *page, struct vm_area_struct *vma)
* Leaving it set also helps swapoff to reinstate ptes * Leaving it set also helps swapoff to reinstate ptes
* faster for those pages still in swapcache. * faster for those pages still in swapcache.
*/ */
if (page_test_dirty(page)) { if ((!PageAnon(page) || PageSwapCache(page)) &&
page_test_dirty(page)) {
page_clear_dirty(page); page_clear_dirty(page);
set_page_dirty(page); set_page_dirty(page);
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册