diff options
32 files changed, 427 insertions, 262 deletions
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 2ed88122be93..8d41908e2513 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig | |||
@@ -317,6 +317,9 @@ config ARCH_ENABLE_MEMORY_HOTPLUG | |||
317 | def_bool y | 317 | def_bool y |
318 | depends on SPARSEMEM | 318 | depends on SPARSEMEM |
319 | 319 | ||
320 | config ARCH_ENABLE_MEMORY_HOTREMOVE | ||
321 | def_bool y | ||
322 | |||
320 | source "mm/Kconfig" | 323 | source "mm/Kconfig" |
321 | 324 | ||
322 | comment "I/O subsystem configuration" | 325 | comment "I/O subsystem configuration" |
diff --git a/arch/s390/kernel/compat_wrapper.S b/arch/s390/kernel/compat_wrapper.S index d003a6e16afb..328a20e880b5 100644 --- a/arch/s390/kernel/compat_wrapper.S +++ b/arch/s390/kernel/compat_wrapper.S | |||
@@ -1732,3 +1732,40 @@ compat_sys_timerfd_gettime_wrapper: | |||
1732 | lgfr %r2,%r2 # int | 1732 | lgfr %r2,%r2 # int |
1733 | llgtr %r3,%r3 # struct compat_itimerspec * | 1733 | llgtr %r3,%r3 # struct compat_itimerspec * |
1734 | jg compat_sys_timerfd_gettime | 1734 | jg compat_sys_timerfd_gettime |
1735 | |||
1736 | .globl compat_sys_signalfd4_wrapper | ||
1737 | compat_sys_signalfd4_wrapper: | ||
1738 | lgfr %r2,%r2 # int | ||
1739 | llgtr %r3,%r3 # compat_sigset_t * | ||
1740 | llgfr %r4,%r4 # compat_size_t | ||
1741 | lgfr %r5,%r5 # int | ||
1742 | jg compat_sys_signalfd4 | ||
1743 | |||
1744 | .globl sys_eventfd2_wrapper | ||
1745 | sys_eventfd2_wrapper: | ||
1746 | llgfr %r2,%r2 # unsigned int | ||
1747 | lgfr %r3,%r3 # int | ||
1748 | jg sys_eventfd2 | ||
1749 | |||
1750 | .globl sys_inotify_init1_wrapper | ||
1751 | sys_inotify_init1_wrapper: | ||
1752 | lgfr %r2,%r2 # int | ||
1753 | jg sys_inotify_init1 | ||
1754 | |||
1755 | .globl sys_pipe2_wrapper | ||
1756 | sys_pipe2_wrapper: | ||
1757 | llgtr %r2,%r2 # u32 * | ||
1758 | lgfr %r3,%r3 # int | ||
1759 | jg sys_pipe2 # branch to system call | ||
1760 | |||
1761 | .globl sys_dup3_wrapper | ||
1762 | sys_dup3_wrapper: | ||
1763 | llgfr %r2,%r2 # unsigned int | ||
1764 | llgfr %r3,%r3 # unsigned int | ||
1765 | lgfr %r4,%r4 # int | ||
1766 | jg sys_dup3 # branch to system call | ||
1767 | |||
1768 | .globl sys_epoll_create1_wrapper | ||
1769 | sys_epoll_create1_wrapper: | ||
1770 | lgfr %r2,%r2 # int | ||
1771 | jg sys_epoll_create1 # branch to system call | ||
diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c index 54b2779b5e2f..2dcf590faba6 100644 --- a/arch/s390/kernel/ipl.c +++ b/arch/s390/kernel/ipl.c | |||
@@ -1705,7 +1705,10 @@ void __init setup_ipl(void) | |||
1705 | 1705 | ||
1706 | void __init ipl_update_parameters(void) | 1706 | void __init ipl_update_parameters(void) |
1707 | { | 1707 | { |
1708 | if (diag308(DIAG308_STORE, &ipl_block) == DIAG308_RC_OK) | 1708 | int rc; |
1709 | |||
1710 | rc = diag308(DIAG308_STORE, &ipl_block); | ||
1711 | if ((rc == DIAG308_RC_OK) || (rc == DIAG308_RC_NOCONFIG)) | ||
1709 | diag308_set_works = 1; | 1712 | diag308_set_works = 1; |
1710 | } | 1713 | } |
1711 | 1714 | ||
diff --git a/arch/s390/kernel/mem_detect.c b/arch/s390/kernel/mem_detect.c index 18ed7abe16c5..9872999c66d1 100644 --- a/arch/s390/kernel/mem_detect.c +++ b/arch/s390/kernel/mem_detect.c | |||
@@ -9,27 +9,6 @@ | |||
9 | #include <asm/sclp.h> | 9 | #include <asm/sclp.h> |
10 | #include <asm/setup.h> | 10 | #include <asm/setup.h> |
11 | 11 | ||
12 | static int memory_fast_detect(struct mem_chunk *chunk) | ||
13 | { | ||
14 | unsigned long val0 = 0; | ||
15 | unsigned long val1 = 0xc; | ||
16 | int rc = -EOPNOTSUPP; | ||
17 | |||
18 | if (ipl_flags & IPL_NSS_VALID) | ||
19 | return -EOPNOTSUPP; | ||
20 | asm volatile( | ||
21 | " diag %1,%2,0x260\n" | ||
22 | "0: lhi %0,0\n" | ||
23 | "1:\n" | ||
24 | EX_TABLE(0b,1b) | ||
25 | : "+d" (rc), "+d" (val0), "+d" (val1) : : "cc"); | ||
26 | |||
27 | if (rc || val0 != val1) | ||
28 | return -EOPNOTSUPP; | ||
29 | chunk->size = val0 + 1; | ||
30 | return 0; | ||
31 | } | ||
32 | |||
33 | static inline int tprot(unsigned long addr) | 12 | static inline int tprot(unsigned long addr) |
34 | { | 13 | { |
35 | int rc = -EFAULT; | 14 | int rc = -EFAULT; |
@@ -84,8 +63,6 @@ void detect_memory_layout(struct mem_chunk chunk[]) | |||
84 | unsigned long flags, cr0; | 63 | unsigned long flags, cr0; |
85 | 64 | ||
86 | memset(chunk, 0, MEMORY_CHUNKS * sizeof(struct mem_chunk)); | 65 | memset(chunk, 0, MEMORY_CHUNKS * sizeof(struct mem_chunk)); |
87 | if (memory_fast_detect(&chunk[0]) == 0) | ||
88 | return; | ||
89 | /* Disable IRQs, DAT and low address protection so tprot does the | 66 | /* Disable IRQs, DAT and low address protection so tprot does the |
90 | * right thing and we don't get scheduled away with low address | 67 | * right thing and we don't get scheduled away with low address |
91 | * protection disabled. | 68 | * protection disabled. |
diff --git a/arch/s390/kernel/syscalls.S b/arch/s390/kernel/syscalls.S index c87ec687d4c6..c66d35e55142 100644 --- a/arch/s390/kernel/syscalls.S +++ b/arch/s390/kernel/syscalls.S | |||
@@ -330,3 +330,9 @@ SYSCALL(sys_eventfd,sys_eventfd,sys_eventfd_wrapper) | |||
330 | SYSCALL(sys_timerfd_create,sys_timerfd_create,sys_timerfd_create_wrapper) | 330 | SYSCALL(sys_timerfd_create,sys_timerfd_create,sys_timerfd_create_wrapper) |
331 | SYSCALL(sys_timerfd_settime,sys_timerfd_settime,compat_sys_timerfd_settime_wrapper) /* 320 */ | 331 | SYSCALL(sys_timerfd_settime,sys_timerfd_settime,compat_sys_timerfd_settime_wrapper) /* 320 */ |
332 | SYSCALL(sys_timerfd_gettime,sys_timerfd_gettime,compat_sys_timerfd_gettime_wrapper) | 332 | SYSCALL(sys_timerfd_gettime,sys_timerfd_gettime,compat_sys_timerfd_gettime_wrapper) |
333 | SYSCALL(sys_signalfd4,sys_signalfd4,compat_sys_signalfd4_wrapper) | ||
334 | SYSCALL(sys_eventfd2,sys_eventfd2,sys_eventfd2_wrapper) | ||
335 | SYSCALL(sys_inotify_init1,sys_inotify_init1,sys_inotify_init1_wrapper) | ||
336 | SYSCALL(sys_pipe2,sys_pipe2,sys_pipe2_wrapper) /* 325 */ | ||
337 | SYSCALL(sys_dup3,sys_dup3,sys_dup3_wrapper) | ||
338 | SYSCALL(sys_epoll_create1,sys_epoll_create1,sys_epoll_create1_wrapper) | ||
diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c index ab70d9bd9261..ca114fe46ffb 100644 --- a/arch/s390/kernel/time.c +++ b/arch/s390/kernel/time.c | |||
@@ -1348,7 +1348,7 @@ early_param("stp", early_parse_stp); | |||
1348 | /* | 1348 | /* |
1349 | * Reset STP attachment. | 1349 | * Reset STP attachment. |
1350 | */ | 1350 | */ |
1351 | static void stp_reset(void) | 1351 | static void __init stp_reset(void) |
1352 | { | 1352 | { |
1353 | int rc; | 1353 | int rc; |
1354 | 1354 | ||
diff --git a/arch/s390/lib/delay.c b/arch/s390/lib/delay.c index eae21a8ac72d..fc6ab6094df8 100644 --- a/arch/s390/lib/delay.c +++ b/arch/s390/lib/delay.c | |||
@@ -43,7 +43,7 @@ void __udelay(unsigned long usecs) | |||
43 | local_bh_disable(); | 43 | local_bh_disable(); |
44 | local_irq_save(flags); | 44 | local_irq_save(flags); |
45 | if (raw_irqs_disabled_flags(flags)) { | 45 | if (raw_irqs_disabled_flags(flags)) { |
46 | old_cc = S390_lowcore.clock_comparator; | 46 | old_cc = local_tick_disable(); |
47 | S390_lowcore.clock_comparator = -1ULL; | 47 | S390_lowcore.clock_comparator = -1ULL; |
48 | __ctl_store(cr0, 0, 0); | 48 | __ctl_store(cr0, 0, 0); |
49 | dummy = (cr0 & 0xffff00e0) | 0x00000800; | 49 | dummy = (cr0 & 0xffff00e0) | 0x00000800; |
@@ -65,7 +65,7 @@ void __udelay(unsigned long usecs) | |||
65 | 65 | ||
66 | if (raw_irqs_disabled_flags(flags)) { | 66 | if (raw_irqs_disabled_flags(flags)) { |
67 | __ctl_load(cr0, 0, 0); | 67 | __ctl_load(cr0, 0, 0); |
68 | S390_lowcore.clock_comparator = old_cc; | 68 | local_tick_enable(old_cc); |
69 | } | 69 | } |
70 | if (!irq_context) | 70 | if (!irq_context) |
71 | _local_bh_enable(); | 71 | _local_bh_enable(); |
diff --git a/arch/s390/mm/init.c b/arch/s390/mm/init.c index 4993b0f594eb..1169130a97ef 100644 --- a/arch/s390/mm/init.c +++ b/arch/s390/mm/init.c | |||
@@ -179,7 +179,7 @@ int arch_add_memory(int nid, u64 start, u64 size) | |||
179 | int rc; | 179 | int rc; |
180 | 180 | ||
181 | pgdat = NODE_DATA(nid); | 181 | pgdat = NODE_DATA(nid); |
182 | zone = pgdat->node_zones + ZONE_NORMAL; | 182 | zone = pgdat->node_zones + ZONE_MOVABLE; |
183 | rc = vmem_add_mapping(start, size); | 183 | rc = vmem_add_mapping(start, size); |
184 | if (rc) | 184 | if (rc) |
185 | return rc; | 185 | return rc; |
@@ -189,3 +189,14 @@ int arch_add_memory(int nid, u64 start, u64 size) | |||
189 | return rc; | 189 | return rc; |
190 | } | 190 | } |
191 | #endif /* CONFIG_MEMORY_HOTPLUG */ | 191 | #endif /* CONFIG_MEMORY_HOTPLUG */ |
192 | |||
193 | #ifdef CONFIG_MEMORY_HOTREMOVE | ||
194 | int remove_memory(u64 start, u64 size) | ||
195 | { | ||
196 | unsigned long start_pfn, end_pfn; | ||
197 | |||
198 | start_pfn = PFN_DOWN(start); | ||
199 | end_pfn = start_pfn + PFN_DOWN(size); | ||
200 | return offline_pages(start_pfn, end_pfn, 120 * HZ); | ||
201 | } | ||
202 | #endif /* CONFIG_MEMORY_HOTREMOVE */ | ||
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, | |||
91 | else | 91 | else |
92 | search_unit_addr = uid->base_unit_addr; | 92 | search_unit_addr = uid->base_unit_addr; |
93 | list_for_each_entry(pos, &lcu->grouplist, group) { | 93 | list_for_each_entry(pos, &lcu->grouplist, group) { |
94 | if (pos->uid.base_unit_addr == search_unit_addr) | 94 | if (pos->uid.base_unit_addr == search_unit_addr && |
95 | !strncmp(pos->uid.vduit, uid->vduit, sizeof(uid->vduit))) | ||
95 | return pos; | 96 | return pos; |
96 | }; | 97 | }; |
97 | return NULL; | 98 | return NULL; |
@@ -332,6 +333,7 @@ static int _add_device_to_lcu(struct alias_lcu *lcu, | |||
332 | group->uid.base_unit_addr = uid->real_unit_addr; | 333 | group->uid.base_unit_addr = uid->real_unit_addr; |
333 | else | 334 | else |
334 | group->uid.base_unit_addr = uid->base_unit_addr; | 335 | group->uid.base_unit_addr = uid->base_unit_addr; |
336 | memcpy(group->uid.vduit, uid->vduit, sizeof(uid->vduit)); | ||
335 | INIT_LIST_HEAD(&group->group); | 337 | INIT_LIST_HEAD(&group->group); |
336 | INIT_LIST_HEAD(&group->baselist); | 338 | INIT_LIST_HEAD(&group->baselist); |
337 | INIT_LIST_HEAD(&group->aliaslist); | 339 | 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) | |||
913 | static DEVICE_ATTR(vendor, 0444, dasd_vendor_show, NULL); | 913 | static DEVICE_ATTR(vendor, 0444, dasd_vendor_show, NULL); |
914 | 914 | ||
915 | #define UID_STRLEN ( /* vendor */ 3 + 1 + /* serial */ 14 + 1 +\ | 915 | #define UID_STRLEN ( /* vendor */ 3 + 1 + /* serial */ 14 + 1 +\ |
916 | /* SSID */ 4 + 1 + /* unit addr */ 2 + 1) | 916 | /* SSID */ 4 + 1 + /* unit addr */ 2 + 1 +\ |
917 | /* vduit */ 32 + 1) | ||
917 | 918 | ||
918 | static ssize_t | 919 | static ssize_t |
919 | dasd_uid_show(struct device *dev, struct device_attribute *attr, char *buf) | 920 | 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 | sprintf(ua_string, "%02x", uid->real_unit_addr); | 946 | sprintf(ua_string, "%02x", uid->real_unit_addr); |
946 | break; | 947 | break; |
947 | } | 948 | } |
948 | snprintf(uid_string, sizeof(uid_string), "%s.%s.%04x.%s", | 949 | if (strlen(uid->vduit) > 0) |
949 | uid->vendor, uid->serial, uid->ssid, ua_string); | 950 | snprintf(uid_string, sizeof(uid_string), |
951 | "%s.%s.%04x.%s.%s", | ||
952 | uid->vendor, uid->serial, | ||
953 | uid->ssid, ua_string, | ||
954 | uid->vduit); | ||
955 | else | ||
956 | snprintf(uid_string, sizeof(uid_string), | ||
957 | "%s.%s.%04x.%s", | ||
958 | uid->vendor, uid->serial, | ||
959 | uid->ssid, ua_string); | ||
950 | spin_unlock(&dasd_devmap_lock); | 960 | spin_unlock(&dasd_devmap_lock); |
951 | return snprintf(buf, PAGE_SIZE, "%s\n", uid_string); | 961 | return snprintf(buf, PAGE_SIZE, "%s\n", uid_string); |
952 | } | 962 | } |
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, | |||
313 | memset(pfxdata, 0, sizeof(*pfxdata)); | 313 | memset(pfxdata, 0, sizeof(*pfxdata)); |
314 | /* prefix data */ | 314 | /* prefix data */ |
315 | pfxdata->format = 0; | 315 | pfxdata->format = 0; |
316 | pfxdata->base_address = basepriv->conf_data.ned1.unit_addr; | 316 | pfxdata->base_address = basepriv->ned->unit_addr; |
317 | pfxdata->base_lss = basepriv->conf_data.ned1.ID; | 317 | pfxdata->base_lss = basepriv->ned->ID; |
318 | pfxdata->validity.define_extend = 1; | 318 | pfxdata->validity.define_extend = 1; |
319 | 319 | ||
320 | /* private uid is kept up to date, conf_data may be outdated */ | 320 | /* private uid is kept up to date, conf_data may be outdated */ |
@@ -536,36 +536,40 @@ dasd_eckd_cdl_reclen(int recid) | |||
536 | /* | 536 | /* |
537 | * Generate device unique id that specifies the physical device. | 537 | * Generate device unique id that specifies the physical device. |
538 | */ | 538 | */ |
539 | static int | 539 | static int dasd_eckd_generate_uid(struct dasd_device *device, |
540 | dasd_eckd_generate_uid(struct dasd_device *device, struct dasd_uid *uid) | 540 | struct dasd_uid *uid) |
541 | { | 541 | { |
542 | struct dasd_eckd_private *private; | 542 | struct dasd_eckd_private *private; |
543 | struct dasd_eckd_confdata *confdata; | 543 | int count; |
544 | 544 | ||
545 | private = (struct dasd_eckd_private *) device->private; | 545 | private = (struct dasd_eckd_private *) device->private; |
546 | if (!private) | 546 | if (!private) |
547 | return -ENODEV; | 547 | return -ENODEV; |
548 | confdata = &private->conf_data; | 548 | if (!private->ned || !private->gneq) |
549 | if (!confdata) | ||
550 | return -ENODEV; | 549 | return -ENODEV; |
551 | 550 | ||
552 | memset(uid, 0, sizeof(struct dasd_uid)); | 551 | memset(uid, 0, sizeof(struct dasd_uid)); |
553 | memcpy(uid->vendor, confdata->ned1.HDA_manufacturer, | 552 | memcpy(uid->vendor, private->ned->HDA_manufacturer, |
554 | sizeof(uid->vendor) - 1); | 553 | sizeof(uid->vendor) - 1); |
555 | EBCASC(uid->vendor, sizeof(uid->vendor) - 1); | 554 | EBCASC(uid->vendor, sizeof(uid->vendor) - 1); |
556 | memcpy(uid->serial, confdata->ned1.HDA_location, | 555 | memcpy(uid->serial, private->ned->HDA_location, |
557 | sizeof(uid->serial) - 1); | 556 | sizeof(uid->serial) - 1); |
558 | EBCASC(uid->serial, sizeof(uid->serial) - 1); | 557 | EBCASC(uid->serial, sizeof(uid->serial) - 1); |
559 | uid->ssid = confdata->neq.subsystemID; | 558 | uid->ssid = private->gneq->subsystemID; |
560 | uid->real_unit_addr = confdata->ned1.unit_addr; | 559 | uid->real_unit_addr = private->ned->unit_addr;; |
561 | if (confdata->ned2.sneq.flags == 0x40 && | 560 | if (private->sneq) { |
562 | confdata->ned2.sneq.format == 0x0001) { | 561 | uid->type = private->sneq->sua_flags; |
563 | uid->type = confdata->ned2.sneq.sua_flags; | ||
564 | if (uid->type == UA_BASE_PAV_ALIAS) | 562 | if (uid->type == UA_BASE_PAV_ALIAS) |
565 | uid->base_unit_addr = confdata->ned2.sneq.base_unit_addr; | 563 | uid->base_unit_addr = private->sneq->base_unit_addr; |
566 | } else { | 564 | } else { |
567 | uid->type = UA_BASE_DEVICE; | 565 | uid->type = UA_BASE_DEVICE; |
568 | } | 566 | } |
567 | if (private->vdsneq) { | ||
568 | for (count = 0; count < 16; count++) { | ||
569 | sprintf(uid->vduit+2*count, "%02x", | ||
570 | private->vdsneq->uit[count]); | ||
571 | } | ||
572 | } | ||
569 | return 0; | 573 | return 0; |
570 | } | 574 | } |
571 | 575 | ||
@@ -623,6 +627,15 @@ static int dasd_eckd_read_conf_lpm(struct dasd_device *device, | |||
623 | ret = -ENOMEM; | 627 | ret = -ENOMEM; |
624 | goto out_error; | 628 | goto out_error; |
625 | } | 629 | } |
630 | |||
631 | /* | ||
632 | * buffer has to start with EBCDIC "V1.0" to show | ||
633 | * support for virtual device SNEQ | ||
634 | */ | ||
635 | rcd_buf[0] = 0xE5; | ||
636 | rcd_buf[1] = 0xF1; | ||
637 | rcd_buf[2] = 0x4B; | ||
638 | rcd_buf[3] = 0xF0; | ||
626 | cqr = dasd_eckd_build_rcd_lpm(device, rcd_buf, ciw, lpm); | 639 | cqr = dasd_eckd_build_rcd_lpm(device, rcd_buf, ciw, lpm); |
627 | if (IS_ERR(cqr)) { | 640 | if (IS_ERR(cqr)) { |
628 | ret = PTR_ERR(cqr); | 641 | ret = PTR_ERR(cqr); |
@@ -646,8 +659,62 @@ out_error: | |||
646 | return ret; | 659 | return ret; |
647 | } | 660 | } |
648 | 661 | ||
649 | static int | 662 | static int dasd_eckd_identify_conf_parts(struct dasd_eckd_private *private) |
650 | dasd_eckd_read_conf(struct dasd_device *device) | 663 | { |
664 | |||
665 | struct dasd_sneq *sneq; | ||
666 | int i, count; | ||
667 | |||
668 | private->ned = NULL; | ||
669 | private->sneq = NULL; | ||
670 | private->vdsneq = NULL; | ||
671 | private->gneq = NULL; | ||
672 | count = private->conf_len / sizeof(struct dasd_sneq); | ||
673 | sneq = (struct dasd_sneq *)private->conf_data; | ||
674 | for (i = 0; i < count; ++i) { | ||
675 | if (sneq->flags.identifier == 1 && sneq->format == 1) | ||
676 | private->sneq = sneq; | ||
677 | else if (sneq->flags.identifier == 1 && sneq->format == 4) | ||
678 | private->vdsneq = (struct vd_sneq *)sneq; | ||
679 | else if (sneq->flags.identifier == 2) | ||
680 | private->gneq = (struct dasd_gneq *)sneq; | ||
681 | else if (sneq->flags.identifier == 3 && sneq->res1 == 1) | ||
682 | private->ned = (struct dasd_ned *)sneq; | ||
683 | sneq++; | ||
684 | } | ||
685 | if (!private->ned || !private->gneq) { | ||
686 | private->ned = NULL; | ||
687 | private->sneq = NULL; | ||
688 | private->vdsneq = NULL; | ||
689 | private->gneq = NULL; | ||
690 | return -EINVAL; | ||
691 | } | ||
692 | return 0; | ||
693 | |||
694 | }; | ||
695 | |||
696 | static unsigned char dasd_eckd_path_access(void *conf_data, int conf_len) | ||
697 | { | ||
698 | struct dasd_gneq *gneq; | ||
699 | int i, count, found; | ||
700 | |||
701 | count = conf_len / sizeof(*gneq); | ||
702 | gneq = (struct dasd_gneq *)conf_data; | ||
703 | found = 0; | ||
704 | for (i = 0; i < count; ++i) { | ||
705 | if (gneq->flags.identifier == 2) { | ||
706 | found = 1; | ||
707 | break; | ||
708 | } | ||
709 | gneq++; | ||
710 | } | ||
711 | if (found) | ||
712 | return ((char *)gneq)[18] & 0x07; | ||
713 | else | ||
714 | return 0; | ||
715 | } | ||
716 | |||
717 | static int dasd_eckd_read_conf(struct dasd_device *device) | ||
651 | { | 718 | { |
652 | void *conf_data; | 719 | void *conf_data; |
653 | int conf_len, conf_data_saved; | 720 | int conf_len, conf_data_saved; |
@@ -661,7 +728,6 @@ dasd_eckd_read_conf(struct dasd_device *device) | |||
661 | path_data->opm = ccw_device_get_path_mask(device->cdev); | 728 | path_data->opm = ccw_device_get_path_mask(device->cdev); |
662 | lpm = 0x80; | 729 | lpm = 0x80; |
663 | conf_data_saved = 0; | 730 | conf_data_saved = 0; |
664 | |||
665 | /* get configuration data per operational path */ | 731 | /* get configuration data per operational path */ |
666 | for (lpm = 0x80; lpm; lpm>>= 1) { | 732 | for (lpm = 0x80; lpm; lpm>>= 1) { |
667 | if (lpm & path_data->opm){ | 733 | if (lpm & path_data->opm){ |
@@ -678,22 +744,20 @@ dasd_eckd_read_conf(struct dasd_device *device) | |||
678 | "data retrieved"); | 744 | "data retrieved"); |
679 | continue; /* no error */ | 745 | continue; /* no error */ |
680 | } | 746 | } |
681 | if (conf_len != sizeof(struct dasd_eckd_confdata)) { | ||
682 | MESSAGE(KERN_WARNING, | ||
683 | "sizes of configuration data mismatch" | ||
684 | "%d (read) vs %ld (expected)", | ||
685 | conf_len, | ||
686 | sizeof(struct dasd_eckd_confdata)); | ||
687 | kfree(conf_data); | ||
688 | continue; /* no error */ | ||
689 | } | ||
690 | /* save first valid configuration data */ | 747 | /* save first valid configuration data */ |
691 | if (!conf_data_saved){ | 748 | if (!conf_data_saved) { |
692 | memcpy(&private->conf_data, conf_data, | 749 | kfree(private->conf_data); |
693 | sizeof(struct dasd_eckd_confdata)); | 750 | private->conf_data = conf_data; |
751 | private->conf_len = conf_len; | ||
752 | if (dasd_eckd_identify_conf_parts(private)) { | ||
753 | private->conf_data = NULL; | ||
754 | private->conf_len = 0; | ||
755 | kfree(conf_data); | ||
756 | continue; | ||
757 | } | ||
694 | conf_data_saved++; | 758 | conf_data_saved++; |
695 | } | 759 | } |
696 | switch (((char *)conf_data)[242] & 0x07){ | 760 | switch (dasd_eckd_path_access(conf_data, conf_len)) { |
697 | case 0x02: | 761 | case 0x02: |
698 | path_data->npm |= lpm; | 762 | path_data->npm |= lpm; |
699 | break; | 763 | break; |
@@ -701,7 +765,8 @@ dasd_eckd_read_conf(struct dasd_device *device) | |||
701 | path_data->ppm |= lpm; | 765 | path_data->ppm |= lpm; |
702 | break; | 766 | break; |
703 | } | 767 | } |
704 | kfree(conf_data); | 768 | if (conf_data != private->conf_data) |
769 | kfree(conf_data); | ||
705 | } | 770 | } |
706 | } | 771 | } |
707 | return 0; | 772 | return 0; |
@@ -952,6 +1017,7 @@ out_err2: | |||
952 | dasd_free_block(device->block); | 1017 | dasd_free_block(device->block); |
953 | device->block = NULL; | 1018 | device->block = NULL; |
954 | out_err1: | 1019 | out_err1: |
1020 | kfree(private->conf_data); | ||
955 | kfree(device->private); | 1021 | kfree(device->private); |
956 | device->private = NULL; | 1022 | device->private = NULL; |
957 | return rc; | 1023 | return rc; |
@@ -959,7 +1025,17 @@ out_err1: | |||
959 | 1025 | ||
960 | static void dasd_eckd_uncheck_device(struct dasd_device *device) | 1026 | static void dasd_eckd_uncheck_device(struct dasd_device *device) |
961 | { | 1027 | { |
1028 | struct dasd_eckd_private *private; | ||
1029 | |||
1030 | private = (struct dasd_eckd_private *) device->private; | ||
962 | dasd_alias_disconnect_device_from_lcu(device); | 1031 | dasd_alias_disconnect_device_from_lcu(device); |
1032 | private->ned = NULL; | ||
1033 | private->sneq = NULL; | ||
1034 | private->vdsneq = NULL; | ||
1035 | private->gneq = NULL; | ||
1036 | private->conf_len = 0; | ||
1037 | kfree(private->conf_data); | ||
1038 | private->conf_data = NULL; | ||
963 | } | 1039 | } |
964 | 1040 | ||
965 | static struct dasd_ccw_req * | 1041 | static struct dasd_ccw_req * |
@@ -1746,9 +1822,10 @@ dasd_eckd_fill_info(struct dasd_device * device, | |||
1746 | info->characteristics_size = sizeof(struct dasd_eckd_characteristics); | 1822 | info->characteristics_size = sizeof(struct dasd_eckd_characteristics); |
1747 | memcpy(info->characteristics, &private->rdc_data, | 1823 | memcpy(info->characteristics, &private->rdc_data, |
1748 | sizeof(struct dasd_eckd_characteristics)); | 1824 | sizeof(struct dasd_eckd_characteristics)); |
1749 | info->confdata_size = sizeof(struct dasd_eckd_confdata); | 1825 | info->confdata_size = min((unsigned long)private->conf_len, |
1750 | memcpy(info->configuration_data, &private->conf_data, | 1826 | sizeof(info->configuration_data)); |
1751 | sizeof(struct dasd_eckd_confdata)); | 1827 | memcpy(info->configuration_data, private->conf_data, |
1828 | info->confdata_size); | ||
1752 | return 0; | 1829 | return 0; |
1753 | } | 1830 | } |
1754 | 1831 | ||
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 { | |||
231 | __u8 reserved3[10]; | 231 | __u8 reserved3[10]; |
232 | } __attribute__ ((packed)); | 232 | } __attribute__ ((packed)); |
233 | 233 | ||
234 | struct dasd_eckd_confdata { | 234 | /* elements of the configuration data */ |
235 | struct dasd_ned { | ||
235 | struct { | 236 | struct { |
236 | struct { | 237 | __u8 identifier:2; |
237 | unsigned char identifier:2; | 238 | __u8 token_id:1; |
238 | unsigned char token_id:1; | 239 | __u8 sno_valid:1; |
239 | unsigned char sno_valid:1; | 240 | __u8 subst_sno:1; |
240 | unsigned char subst_sno:1; | 241 | __u8 recNED:1; |
241 | unsigned char recNED:1; | 242 | __u8 emuNED:1; |
242 | unsigned char emuNED:1; | 243 | __u8 reserved:1; |
243 | unsigned char reserved:1; | 244 | } __attribute__ ((packed)) flags; |
244 | } __attribute__ ((packed)) flags; | 245 | __u8 descriptor; |
245 | __u8 descriptor; | 246 | __u8 dev_class; |
246 | __u8 dev_class; | 247 | __u8 reserved; |
247 | __u8 reserved; | 248 | __u8 dev_type[6]; |
248 | unsigned char dev_type[6]; | 249 | __u8 dev_model[3]; |
249 | unsigned char dev_model[3]; | 250 | __u8 HDA_manufacturer[3]; |
250 | unsigned char HDA_manufacturer[3]; | 251 | __u8 HDA_location[2]; |
251 | unsigned char HDA_location[2]; | 252 | __u8 HDA_seqno[12]; |
252 | unsigned char HDA_seqno[12]; | 253 | __u8 ID; |
253 | __u8 ID; | 254 | __u8 unit_addr; |
254 | __u8 unit_addr; | 255 | } __attribute__ ((packed)); |
255 | } __attribute__ ((packed)) ned1; | 256 | |
256 | union { | 257 | struct dasd_sneq { |
257 | struct { | ||
258 | struct { | ||
259 | unsigned char identifier:2; | ||
260 | unsigned char token_id:1; | ||
261 | unsigned char sno_valid:1; | ||
262 | unsigned char subst_sno:1; | ||
263 | unsigned char recNED:1; | ||
264 | unsigned char emuNED:1; | ||
265 | unsigned char reserved:1; | ||
266 | } __attribute__ ((packed)) flags; | ||
267 | __u8 descriptor; | ||
268 | __u8 reserved[2]; | ||
269 | unsigned char dev_type[6]; | ||
270 | unsigned char dev_model[3]; | ||
271 | unsigned char DASD_manufacturer[3]; | ||
272 | unsigned char DASD_location[2]; | ||
273 | unsigned char DASD_seqno[12]; | ||
274 | __u16 ID; | ||
275 | } __attribute__ ((packed)) ned; | ||
276 | struct { | ||
277 | unsigned char flags; /* byte 0 */ | ||
278 | unsigned char res1; /* byte 1 */ | ||
279 | __u16 format; /* byte 2-3 */ | ||
280 | unsigned char res2[4]; /* byte 4-7 */ | ||
281 | unsigned char sua_flags; /* byte 8 */ | ||
282 | __u8 base_unit_addr; /* byte 9 */ | ||
283 | unsigned char res3[22]; /* byte 10-31 */ | ||
284 | } __attribute__ ((packed)) sneq; | ||
285 | } __attribute__ ((packed)) ned2; | ||
286 | struct { | 258 | struct { |
287 | struct { | 259 | __u8 identifier:2; |
288 | unsigned char identifier:2; | 260 | __u8 reserved:6; |
289 | unsigned char token_id:1; | 261 | } __attribute__ ((packed)) flags; |
290 | unsigned char sno_valid:1; | 262 | __u8 res1; |
291 | unsigned char subst_sno:1; | 263 | __u16 format; |
292 | unsigned char recNED:1; | 264 | __u8 res2[4]; /* byte 4- 7 */ |
293 | unsigned char emuNED:1; | 265 | __u8 sua_flags; /* byte 8 */ |
294 | unsigned char reserved:1; | 266 | __u8 base_unit_addr; /* byte 9 */ |
295 | } __attribute__ ((packed)) flags; | 267 | __u8 res3[22]; /* byte 10-31 */ |
296 | __u8 descriptor; | 268 | } __attribute__ ((packed)); |
297 | __u8 reserved[2]; | 269 | |
298 | unsigned char cont_type[6]; | 270 | struct vd_sneq { |
299 | unsigned char cont_model[3]; | ||
300 | unsigned char cont_manufacturer[3]; | ||
301 | unsigned char cont_location[2]; | ||
302 | unsigned char cont_seqno[12]; | ||
303 | __u16 ID; | ||
304 | } __attribute__ ((packed)) ned3; | ||
305 | struct { | 271 | struct { |
306 | struct { | 272 | __u8 identifier:2; |
307 | unsigned char identifier:2; | 273 | __u8 reserved:6; |
308 | unsigned char token_id:1; | 274 | } __attribute__ ((packed)) flags; |
309 | unsigned char sno_valid:1; | 275 | __u8 res1; |
310 | unsigned char subst_sno:1; | 276 | __u16 format; |
311 | unsigned char recNED:1; | 277 | __u8 res2[4]; /* byte 4- 7 */ |
312 | unsigned char emuNED:1; | 278 | __u8 uit[16]; /* byte 8-23 */ |
313 | unsigned char reserved:1; | 279 | __u8 res3[8]; /* byte 24-31 */ |
314 | } __attribute__ ((packed)) flags; | 280 | } __attribute__ ((packed)); |
315 | __u8 descriptor; | 281 | |
316 | __u8 reserved[2]; | 282 | struct dasd_gneq { |
317 | unsigned char cont_type[6]; | ||
318 | unsigned char empty[3]; | ||
319 | unsigned char cont_manufacturer[3]; | ||
320 | unsigned char cont_location[2]; | ||
321 | unsigned char cont_seqno[12]; | ||
322 | __u16 ID; | ||
323 | } __attribute__ ((packed)) ned4; | ||
324 | unsigned char ned5[32]; | ||
325 | unsigned char ned6[32]; | ||
326 | unsigned char ned7[32]; | ||
327 | struct { | 283 | struct { |
328 | struct { | 284 | __u8 identifier:2; |
329 | unsigned char identifier:2; | 285 | __u8 reserved:6; |
330 | unsigned char reserved:6; | 286 | } __attribute__ ((packed)) flags; |
331 | } __attribute__ ((packed)) flags; | 287 | __u8 reserved[7]; |
332 | __u8 selector; | 288 | __u16 subsystemID; |
333 | __u16 interfaceID; | 289 | __u8 reserved2[22]; |
334 | __u32 reserved; | ||
335 | __u16 subsystemID; | ||
336 | struct { | ||
337 | unsigned char sp0:1; | ||
338 | unsigned char sp1:1; | ||
339 | unsigned char reserved:5; | ||
340 | unsigned char scluster:1; | ||
341 | } __attribute__ ((packed)) spathID; | ||
342 | __u8 unit_address; | ||
343 | __u8 dev_ID; | ||
344 | __u8 dev_address; | ||
345 | __u8 adapterID; | ||
346 | __u16 link_address; | ||
347 | struct { | ||
348 | unsigned char parallel:1; | ||
349 | unsigned char escon:1; | ||
350 | unsigned char reserved:1; | ||
351 | unsigned char ficon:1; | ||
352 | unsigned char reserved2:4; | ||
353 | } __attribute__ ((packed)) protocol_type; | ||
354 | struct { | ||
355 | unsigned char PID_in_236:1; | ||
356 | unsigned char reserved:7; | ||
357 | } __attribute__ ((packed)) format_flags; | ||
358 | __u8 log_dev_address; | ||
359 | unsigned char reserved2[12]; | ||
360 | } __attribute__ ((packed)) neq; | ||
361 | } __attribute__ ((packed)); | 290 | } __attribute__ ((packed)); |
362 | 291 | ||
363 | struct dasd_eckd_path { | 292 | struct dasd_eckd_path { |
@@ -463,7 +392,14 @@ struct alias_pav_group { | |||
463 | 392 | ||
464 | struct dasd_eckd_private { | 393 | struct dasd_eckd_private { |
465 | struct dasd_eckd_characteristics rdc_data; | 394 | struct dasd_eckd_characteristics rdc_data; |
466 | struct dasd_eckd_confdata conf_data; | 395 | u8 *conf_data; |
396 | int conf_len; | ||
397 | /* pointers to specific parts in the conf_data */ | ||
398 | struct dasd_ned *ned; | ||
399 | struct dasd_sneq *sneq; | ||
400 | struct vd_sneq *vdsneq; | ||
401 | struct dasd_gneq *gneq; | ||
402 | |||
467 | struct dasd_eckd_path path_data; | 403 | struct dasd_eckd_path path_data; |
468 | struct eckd_count count_area[5]; | 404 | struct eckd_count count_area[5]; |
469 | int init_cqr_status; | 405 | 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 { | |||
307 | __u16 ssid; | 307 | __u16 ssid; |
308 | __u8 real_unit_addr; | 308 | __u8 real_unit_addr; |
309 | __u8 base_unit_addr; | 309 | __u8 base_unit_addr; |
310 | char vduit[33]; | ||
310 | }; | 311 | }; |
311 | 312 | ||
312 | /* | 313 | /* |
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) | |||
399 | void | 399 | void |
400 | sclp_sync_wait(void) | 400 | sclp_sync_wait(void) |
401 | { | 401 | { |
402 | unsigned long long old_tick; | ||
402 | unsigned long flags; | 403 | unsigned long flags; |
403 | unsigned long cr0, cr0_sync; | 404 | unsigned long cr0, cr0_sync; |
404 | u64 timeout; | 405 | u64 timeout; |
@@ -419,11 +420,12 @@ sclp_sync_wait(void) | |||
419 | if (!irq_context) | 420 | if (!irq_context) |
420 | local_bh_disable(); | 421 | local_bh_disable(); |
421 | /* Enable service-signal interruption, disable timer interrupts */ | 422 | /* Enable service-signal interruption, disable timer interrupts */ |
423 | old_tick = local_tick_disable(); | ||
422 | trace_hardirqs_on(); | 424 | trace_hardirqs_on(); |
423 | __ctl_store(cr0, 0, 0); | 425 | __ctl_store(cr0, 0, 0); |
424 | cr0_sync = cr0; | 426 | cr0_sync = cr0; |
427 | cr0_sync &= 0xffff00a0; | ||
425 | cr0_sync |= 0x00000200; | 428 | cr0_sync |= 0x00000200; |
426 | cr0_sync &= 0xFFFFF3AC; | ||
427 | __ctl_load(cr0_sync, 0, 0); | 429 | __ctl_load(cr0_sync, 0, 0); |
428 | __raw_local_irq_stosm(0x01); | 430 | __raw_local_irq_stosm(0x01); |
429 | /* Loop until driver state indicates finished request */ | 431 | /* Loop until driver state indicates finished request */ |
@@ -439,9 +441,9 @@ sclp_sync_wait(void) | |||
439 | __ctl_load(cr0, 0, 0); | 441 | __ctl_load(cr0, 0, 0); |
440 | if (!irq_context) | 442 | if (!irq_context) |
441 | _local_bh_enable(); | 443 | _local_bh_enable(); |
444 | local_tick_enable(old_tick); | ||
442 | local_irq_restore(flags); | 445 | local_irq_restore(flags); |
443 | } | 446 | } |
444 | |||
445 | EXPORT_SYMBOL(sclp_sync_wait); | 447 | EXPORT_SYMBOL(sclp_sync_wait); |
446 | 448 | ||
447 | /* Dispatch changes in send and receive mask to registered listeners. */ | 449 | /* 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, | |||
427 | sclp_attach_storage(id); | 427 | sclp_attach_storage(id); |
428 | switch (action) { | 428 | switch (action) { |
429 | case MEM_ONLINE: | 429 | case MEM_ONLINE: |
430 | case MEM_GOING_OFFLINE: | ||
431 | case MEM_CANCEL_OFFLINE: | ||
430 | break; | 432 | break; |
431 | case MEM_GOING_ONLINE: | 433 | case MEM_GOING_ONLINE: |
432 | rc = sclp_mem_change_state(start, size, 1); | 434 | rc = sclp_mem_change_state(start, size, 1); |
@@ -434,6 +436,9 @@ static int sclp_mem_notifier(struct notifier_block *nb, | |||
434 | case MEM_CANCEL_ONLINE: | 436 | case MEM_CANCEL_ONLINE: |
435 | sclp_mem_change_state(start, size, 0); | 437 | sclp_mem_change_state(start, size, 0); |
436 | break; | 438 | break; |
439 | case MEM_OFFLINE: | ||
440 | sclp_mem_change_state(start, size, 0); | ||
441 | break; | ||
437 | default: | 442 | default: |
438 | rc = -EINVAL; | 443 | rc = -EINVAL; |
439 | break; | 444 | 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 @@ | |||
8 | #include <linux/init.h> | 8 | #include <linux/init.h> |
9 | #include <linux/errno.h> | 9 | #include <linux/errno.h> |
10 | #include <linux/cpu.h> | 10 | #include <linux/cpu.h> |
11 | #include <linux/kthread.h> | ||
12 | #include <linux/sysdev.h> | 11 | #include <linux/sysdev.h> |
13 | #include <linux/workqueue.h> | 12 | #include <linux/workqueue.h> |
14 | #include <asm/smp.h> | 13 | #include <asm/smp.h> |
@@ -41,19 +40,9 @@ static void sclp_cpu_capability_notify(struct work_struct *work) | |||
41 | put_online_cpus(); | 40 | put_online_cpus(); |
42 | } | 41 | } |
43 | 42 | ||
44 | static int sclp_cpu_kthread(void *data) | ||
45 | { | ||
46 | smp_rescan_cpus(); | ||
47 | return 0; | ||
48 | } | ||
49 | |||
50 | static void __ref sclp_cpu_change_notify(struct work_struct *work) | 43 | static void __ref sclp_cpu_change_notify(struct work_struct *work) |
51 | { | 44 | { |
52 | /* Can't call smp_rescan_cpus() from workqueue context since it may | 45 | smp_rescan_cpus(); |
53 | * deadlock in case of cpu hotplug. So we have to create a kernel | ||
54 | * thread in order to call it. | ||
55 | */ | ||
56 | kthread_run(sclp_cpu_kthread, NULL, "cpu_rescan"); | ||
57 | } | 46 | } |
58 | 47 | ||
59 | static void sclp_conf_receiver_fn(struct evbuf_header *evbuf) | 48 | 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 @@ | |||
5 | * Author(s): Peter Oberparleiter <peter.oberparleiter@de.ibm.com> | 5 | * Author(s): Peter Oberparleiter <peter.oberparleiter@de.ibm.com> |
6 | */ | 6 | */ |
7 | 7 | ||
8 | #include <linux/slab.h> | 8 | #include <linux/vmalloc.h> |
9 | #include <linux/bitops.h> | 9 | #include <linux/bitops.h> |
10 | #include "idset.h" | 10 | #include "idset.h" |
11 | #include "css.h" | 11 | #include "css.h" |
@@ -25,18 +25,18 @@ static struct idset *idset_new(int num_ssid, int num_id) | |||
25 | { | 25 | { |
26 | struct idset *set; | 26 | struct idset *set; |
27 | 27 | ||
28 | set = kzalloc(sizeof(struct idset) + bitmap_size(num_ssid, num_id), | 28 | set = vmalloc(sizeof(struct idset) + bitmap_size(num_ssid, num_id)); |
29 | GFP_KERNEL); | ||
30 | if (set) { | 29 | if (set) { |
31 | set->num_ssid = num_ssid; | 30 | set->num_ssid = num_ssid; |
32 | set->num_id = num_id; | 31 | set->num_id = num_id; |
32 | memset(set->bitmap, 0, bitmap_size(num_ssid, num_id)); | ||
33 | } | 33 | } |
34 | return set; | 34 | return set; |
35 | } | 35 | } |
36 | 36 | ||
37 | void idset_free(struct idset *set) | 37 | void idset_free(struct idset *set) |
38 | { | 38 | { |
39 | kfree(set); | 39 | vfree(set); |
40 | } | 40 | } |
41 | 41 | ||
42 | void idset_clear(struct idset *set) | 42 | 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) | |||
1355 | goto out_rel; | 1355 | goto out_rel; |
1356 | 1356 | ||
1357 | /* qdr is used in ccw1.cda which is u32 */ | 1357 | /* qdr is used in ccw1.cda which is u32 */ |
1358 | irq_ptr->qdr = kzalloc(sizeof(struct qdr), GFP_KERNEL | GFP_DMA); | 1358 | irq_ptr->qdr = (struct qdr *) get_zeroed_page(GFP_KERNEL | GFP_DMA); |
1359 | if (!irq_ptr->qdr) | 1359 | if (!irq_ptr->qdr) |
1360 | goto out_rel; | 1360 | goto out_rel; |
1361 | WARN_ON((unsigned long)irq_ptr->qdr & 0xfff); | 1361 | 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) | |||
142 | return 0; | 142 | return 0; |
143 | } | 143 | } |
144 | 144 | ||
145 | void __exit qdio_remove_perf_stats(void) | 145 | void qdio_remove_perf_stats(void) |
146 | { | 146 | { |
147 | #ifdef CONFIG_PROC_FS | 147 | #ifdef CONFIG_PROC_FS |
148 | remove_proc_entry("qdio_perf", NULL); | 148 | 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) | |||
325 | kmem_cache_free(qdio_q_cache, q); | 325 | kmem_cache_free(qdio_q_cache, q); |
326 | } | 326 | } |
327 | } | 327 | } |
328 | kfree(irq_ptr->qdr); | 328 | free_page((unsigned long) irq_ptr->qdr); |
329 | free_page(irq_ptr->chsc_page); | 329 | free_page(irq_ptr->chsc_page); |
330 | free_page((unsigned long) irq_ptr); | 330 | free_page((unsigned long) irq_ptr); |
331 | } | 331 | } |
@@ -515,7 +515,7 @@ int __init qdio_setup_init(void) | |||
515 | return 0; | 515 | return 0; |
516 | } | 516 | } |
517 | 517 | ||
518 | void __exit qdio_setup_exit(void) | 518 | void qdio_setup_exit(void) |
519 | { | 519 | { |
520 | kmem_cache_destroy(qdio_q_cache); | 520 | kmem_cache_destroy(qdio_q_cache); |
521 | } | 521 | } |
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) | |||
352 | return len; | 352 | return len; |
353 | } | 353 | } |
354 | 354 | ||
355 | void s390_virtio_console_init(void) | 355 | void __init s390_virtio_console_init(void) |
356 | { | 356 | { |
357 | virtio_cons_early_init(early_put_chars); | 357 | virtio_cons_early_init(early_put_chars); |
358 | } | 358 | } |
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 { | |||
419 | int next_element_to_fill; | 419 | int next_element_to_fill; |
420 | struct sk_buff_head skb_list; | 420 | struct sk_buff_head skb_list; |
421 | struct list_head ctx_list; | 421 | struct list_head ctx_list; |
422 | int is_header[16]; | ||
422 | }; | 423 | }; |
423 | 424 | ||
424 | struct qeth_card; | 425 | struct qeth_card; |
@@ -785,7 +786,7 @@ void qeth_core_remove_osn_attributes(struct device *); | |||
785 | 786 | ||
786 | /* exports for qeth discipline device drivers */ | 787 | /* exports for qeth discipline device drivers */ |
787 | extern struct qeth_card_list_struct qeth_core_card_list; | 788 | extern struct qeth_card_list_struct qeth_core_card_list; |
788 | 789 | extern struct kmem_cache *qeth_core_header_cache; | |
789 | extern struct qeth_dbf_info qeth_dbf[QETH_DBF_INFOS]; | 790 | extern struct qeth_dbf_info qeth_dbf[QETH_DBF_INFOS]; |
790 | 791 | ||
791 | void qeth_set_allowed_threads(struct qeth_card *, unsigned long , int); | 792 | 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 | int qeth_get_elements_no(struct qeth_card *, void *, struct sk_buff *, int); | 844 | int qeth_get_elements_no(struct qeth_card *, void *, struct sk_buff *, int); |
844 | int qeth_do_send_packet_fast(struct qeth_card *, struct qeth_qdio_out_q *, | 845 | int qeth_do_send_packet_fast(struct qeth_card *, struct qeth_qdio_out_q *, |
845 | struct sk_buff *, struct qeth_hdr *, int, | 846 | struct sk_buff *, struct qeth_hdr *, int, |
846 | struct qeth_eddp_context *); | 847 | struct qeth_eddp_context *, int, int); |
847 | int qeth_do_send_packet(struct qeth_card *, struct qeth_qdio_out_q *, | 848 | int qeth_do_send_packet(struct qeth_card *, struct qeth_qdio_out_q *, |
848 | struct sk_buff *, struct qeth_hdr *, | 849 | struct sk_buff *, struct qeth_hdr *, |
849 | int, struct qeth_eddp_context *); | 850 | 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 @@ | |||
19 | #include <linux/mii.h> | 19 | #include <linux/mii.h> |
20 | #include <linux/kthread.h> | 20 | #include <linux/kthread.h> |
21 | 21 | ||
22 | #include <asm-s390/ebcdic.h> | 22 | #include <asm/ebcdic.h> |
23 | #include <asm-s390/io.h> | 23 | #include <asm/io.h> |
24 | #include <asm/s390_rdev.h> | 24 | #include <asm/s390_rdev.h> |
25 | 25 | ||
26 | #include "qeth_core.h" | 26 | #include "qeth_core.h" |
@@ -48,6 +48,8 @@ EXPORT_SYMBOL_GPL(qeth_dbf); | |||
48 | 48 | ||
49 | struct qeth_card_list_struct qeth_core_card_list; | 49 | struct qeth_card_list_struct qeth_core_card_list; |
50 | EXPORT_SYMBOL_GPL(qeth_core_card_list); | 50 | EXPORT_SYMBOL_GPL(qeth_core_card_list); |
51 | struct kmem_cache *qeth_core_header_cache; | ||
52 | EXPORT_SYMBOL_GPL(qeth_core_header_cache); | ||
51 | 53 | ||
52 | static struct device *qeth_core_root_dev; | 54 | static struct device *qeth_core_root_dev; |
53 | static unsigned int known_devices[][10] = QETH_MODELLIST_ARRAY; | 55 | 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 | } | 935 | } |
934 | qeth_eddp_buf_release_contexts(buf); | 936 | qeth_eddp_buf_release_contexts(buf); |
935 | for (i = 0; i < QETH_MAX_BUFFER_ELEMENTS(queue->card); ++i) { | 937 | for (i = 0; i < QETH_MAX_BUFFER_ELEMENTS(queue->card); ++i) { |
938 | if (buf->buffer->element[i].addr && buf->is_header[i]) | ||
939 | kmem_cache_free(qeth_core_header_cache, | ||
940 | buf->buffer->element[i].addr); | ||
941 | buf->is_header[i] = 0; | ||
936 | buf->buffer->element[i].length = 0; | 942 | buf->buffer->element[i].length = 0; |
937 | buf->buffer->element[i].addr = NULL; | 943 | buf->buffer->element[i].addr = NULL; |
938 | buf->buffer->element[i].flags = 0; | 944 | buf->buffer->element[i].flags = 0; |
@@ -3002,8 +3008,8 @@ int qeth_get_elements_no(struct qeth_card *card, void *hdr, | |||
3002 | if (skb_shinfo(skb)->nr_frags > 0) | 3008 | if (skb_shinfo(skb)->nr_frags > 0) |
3003 | elements_needed = (skb_shinfo(skb)->nr_frags + 1); | 3009 | elements_needed = (skb_shinfo(skb)->nr_frags + 1); |
3004 | if (elements_needed == 0) | 3010 | if (elements_needed == 0) |
3005 | elements_needed = 1 + (((((unsigned long) hdr) % PAGE_SIZE) | 3011 | elements_needed = 1 + (((((unsigned long) skb->data) % |
3006 | + skb->len) >> PAGE_SHIFT); | 3012 | PAGE_SIZE) + skb->len) >> PAGE_SHIFT); |
3007 | if ((elements_needed + elems) > QETH_MAX_BUFFER_ELEMENTS(card)) { | 3013 | if ((elements_needed + elems) > QETH_MAX_BUFFER_ELEMENTS(card)) { |
3008 | QETH_DBF_MESSAGE(2, "Invalid size of IP packet " | 3014 | QETH_DBF_MESSAGE(2, "Invalid size of IP packet " |
3009 | "(Number=%d / Length=%d). Discarded.\n", | 3015 | "(Number=%d / Length=%d). Discarded.\n", |
@@ -3015,7 +3021,8 @@ int qeth_get_elements_no(struct qeth_card *card, void *hdr, | |||
3015 | EXPORT_SYMBOL_GPL(qeth_get_elements_no); | 3021 | EXPORT_SYMBOL_GPL(qeth_get_elements_no); |
3016 | 3022 | ||
3017 | static inline void __qeth_fill_buffer(struct sk_buff *skb, | 3023 | static inline void __qeth_fill_buffer(struct sk_buff *skb, |
3018 | struct qdio_buffer *buffer, int is_tso, int *next_element_to_fill) | 3024 | struct qdio_buffer *buffer, int is_tso, int *next_element_to_fill, |
3025 | int offset) | ||
3019 | { | 3026 | { |
3020 | int length = skb->len; | 3027 | int length = skb->len; |
3021 | int length_here; | 3028 | int length_here; |
@@ -3027,6 +3034,11 @@ static inline void __qeth_fill_buffer(struct sk_buff *skb, | |||
3027 | data = skb->data; | 3034 | data = skb->data; |
3028 | first_lap = (is_tso == 0 ? 1 : 0); | 3035 | first_lap = (is_tso == 0 ? 1 : 0); |
3029 | 3036 | ||
3037 | if (offset >= 0) { | ||
3038 | data = skb->data + offset; | ||
3039 | first_lap = 0; | ||
3040 | } | ||
3041 | |||
3030 | while (length > 0) { | 3042 | while (length > 0) { |
3031 | /* length_here is the remaining amount of data in this page */ | 3043 | /* length_here is the remaining amount of data in this page */ |
3032 | length_here = PAGE_SIZE - ((unsigned long) data % PAGE_SIZE); | 3044 | length_here = PAGE_SIZE - ((unsigned long) data % PAGE_SIZE); |
@@ -3058,22 +3070,22 @@ static inline void __qeth_fill_buffer(struct sk_buff *skb, | |||
3058 | } | 3070 | } |
3059 | 3071 | ||
3060 | static inline int qeth_fill_buffer(struct qeth_qdio_out_q *queue, | 3072 | static inline int qeth_fill_buffer(struct qeth_qdio_out_q *queue, |
3061 | struct qeth_qdio_out_buffer *buf, struct sk_buff *skb) | 3073 | struct qeth_qdio_out_buffer *buf, struct sk_buff *skb, |
3074 | struct qeth_hdr *hdr, int offset, int hd_len) | ||
3062 | { | 3075 | { |
3063 | struct qdio_buffer *buffer; | 3076 | struct qdio_buffer *buffer; |
3064 | struct qeth_hdr_tso *hdr; | ||
3065 | int flush_cnt = 0, hdr_len, large_send = 0; | 3077 | int flush_cnt = 0, hdr_len, large_send = 0; |
3066 | 3078 | ||
3067 | buffer = buf->buffer; | 3079 | buffer = buf->buffer; |
3068 | atomic_inc(&skb->users); | 3080 | atomic_inc(&skb->users); |
3069 | skb_queue_tail(&buf->skb_list, skb); | 3081 | skb_queue_tail(&buf->skb_list, skb); |
3070 | 3082 | ||
3071 | hdr = (struct qeth_hdr_tso *) skb->data; | ||
3072 | /*check first on TSO ....*/ | 3083 | /*check first on TSO ....*/ |
3073 | if (hdr->hdr.hdr.l3.id == QETH_HEADER_TYPE_TSO) { | 3084 | if (hdr->hdr.l3.id == QETH_HEADER_TYPE_TSO) { |
3074 | int element = buf->next_element_to_fill; | 3085 | int element = buf->next_element_to_fill; |
3075 | 3086 | ||
3076 | hdr_len = sizeof(struct qeth_hdr_tso) + hdr->ext.dg_hdr_len; | 3087 | hdr_len = sizeof(struct qeth_hdr_tso) + |
3088 | ((struct qeth_hdr_tso *)hdr)->ext.dg_hdr_len; | ||
3077 | /*fill first buffer entry only with header information */ | 3089 | /*fill first buffer entry only with header information */ |
3078 | buffer->element[element].addr = skb->data; | 3090 | buffer->element[element].addr = skb->data; |
3079 | buffer->element[element].length = hdr_len; | 3091 | buffer->element[element].length = hdr_len; |
@@ -3083,9 +3095,20 @@ static inline int qeth_fill_buffer(struct qeth_qdio_out_q *queue, | |||
3083 | skb->len -= hdr_len; | 3095 | skb->len -= hdr_len; |
3084 | large_send = 1; | 3096 | large_send = 1; |
3085 | } | 3097 | } |
3098 | |||
3099 | if (offset >= 0) { | ||
3100 | int element = buf->next_element_to_fill; | ||
3101 | buffer->element[element].addr = hdr; | ||
3102 | buffer->element[element].length = sizeof(struct qeth_hdr) + | ||
3103 | hd_len; | ||
3104 | buffer->element[element].flags = SBAL_FLAGS_FIRST_FRAG; | ||
3105 | buf->is_header[element] = 1; | ||
3106 | buf->next_element_to_fill++; | ||
3107 | } | ||
3108 | |||
3086 | if (skb_shinfo(skb)->nr_frags == 0) | 3109 | if (skb_shinfo(skb)->nr_frags == 0) |
3087 | __qeth_fill_buffer(skb, buffer, large_send, | 3110 | __qeth_fill_buffer(skb, buffer, large_send, |
3088 | (int *)&buf->next_element_to_fill); | 3111 | (int *)&buf->next_element_to_fill, offset); |
3089 | else | 3112 | else |
3090 | __qeth_fill_buffer_frag(skb, buffer, large_send, | 3113 | __qeth_fill_buffer_frag(skb, buffer, large_send, |
3091 | (int *)&buf->next_element_to_fill); | 3114 | (int *)&buf->next_element_to_fill); |
@@ -3115,7 +3138,7 @@ static inline int qeth_fill_buffer(struct qeth_qdio_out_q *queue, | |||
3115 | int qeth_do_send_packet_fast(struct qeth_card *card, | 3138 | int qeth_do_send_packet_fast(struct qeth_card *card, |
3116 | struct qeth_qdio_out_q *queue, struct sk_buff *skb, | 3139 | struct qeth_qdio_out_q *queue, struct sk_buff *skb, |
3117 | struct qeth_hdr *hdr, int elements_needed, | 3140 | struct qeth_hdr *hdr, int elements_needed, |
3118 | struct qeth_eddp_context *ctx) | 3141 | struct qeth_eddp_context *ctx, int offset, int hd_len) |
3119 | { | 3142 | { |
3120 | struct qeth_qdio_out_buffer *buffer; | 3143 | struct qeth_qdio_out_buffer *buffer; |
3121 | int buffers_needed = 0; | 3144 | int buffers_needed = 0; |
@@ -3148,7 +3171,7 @@ int qeth_do_send_packet_fast(struct qeth_card *card, | |||
3148 | } | 3171 | } |
3149 | atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED); | 3172 | atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED); |
3150 | if (ctx == NULL) { | 3173 | if (ctx == NULL) { |
3151 | qeth_fill_buffer(queue, buffer, skb); | 3174 | qeth_fill_buffer(queue, buffer, skb, hdr, offset, hd_len); |
3152 | qeth_flush_buffers(queue, index, 1); | 3175 | qeth_flush_buffers(queue, index, 1); |
3153 | } else { | 3176 | } else { |
3154 | flush_cnt = qeth_eddp_fill_buffer(queue, ctx, index); | 3177 | 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 | } | 3247 | } |
3225 | } | 3248 | } |
3226 | if (ctx == NULL) | 3249 | if (ctx == NULL) |
3227 | tmp = qeth_fill_buffer(queue, buffer, skb); | 3250 | tmp = qeth_fill_buffer(queue, buffer, skb, hdr, -1, 0); |
3228 | else { | 3251 | else { |
3229 | tmp = qeth_eddp_fill_buffer(queue, ctx, | 3252 | tmp = qeth_eddp_fill_buffer(queue, ctx, |
3230 | queue->next_buf_to_fill); | 3253 | queue->next_buf_to_fill); |
@@ -4443,8 +4466,17 @@ static int __init qeth_core_init(void) | |||
4443 | rc = IS_ERR(qeth_core_root_dev) ? PTR_ERR(qeth_core_root_dev) : 0; | 4466 | rc = IS_ERR(qeth_core_root_dev) ? PTR_ERR(qeth_core_root_dev) : 0; |
4444 | if (rc) | 4467 | if (rc) |
4445 | goto register_err; | 4468 | goto register_err; |
4446 | return 0; | ||
4447 | 4469 | ||
4470 | qeth_core_header_cache = kmem_cache_create("qeth_hdr", | ||
4471 | sizeof(struct qeth_hdr) + ETH_HLEN, 64, 0, NULL); | ||
4472 | if (!qeth_core_header_cache) { | ||
4473 | rc = -ENOMEM; | ||
4474 | goto slab_err; | ||
4475 | } | ||
4476 | |||
4477 | return 0; | ||
4478 | slab_err: | ||
4479 | s390_root_dev_unregister(qeth_core_root_dev); | ||
4448 | register_err: | 4480 | register_err: |
4449 | driver_remove_file(&qeth_core_ccwgroup_driver.driver, | 4481 | driver_remove_file(&qeth_core_ccwgroup_driver.driver, |
4450 | &driver_attr_group); | 4482 | &driver_attr_group); |
@@ -4466,6 +4498,7 @@ static void __exit qeth_core_exit(void) | |||
4466 | &driver_attr_group); | 4498 | &driver_attr_group); |
4467 | ccwgroup_driver_unregister(&qeth_core_ccwgroup_driver); | 4499 | ccwgroup_driver_unregister(&qeth_core_ccwgroup_driver); |
4468 | ccw_driver_unregister(&qeth_ccw_driver); | 4500 | ccw_driver_unregister(&qeth_ccw_driver); |
4501 | kmem_cache_destroy(qeth_core_header_cache); | ||
4469 | qeth_unregister_dbf_views(); | 4502 | qeth_unregister_dbf_views(); |
4470 | PRINT_INFO("core functions removed\n"); | 4503 | PRINT_INFO("core functions removed\n"); |
4471 | } | 4504 | } |
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, | |||
243 | static void qeth_l2_fill_header(struct qeth_card *card, struct qeth_hdr *hdr, | 243 | static void qeth_l2_fill_header(struct qeth_card *card, struct qeth_hdr *hdr, |
244 | struct sk_buff *skb, int ipv, int cast_type) | 244 | struct sk_buff *skb, int ipv, int cast_type) |
245 | { | 245 | { |
246 | struct vlan_ethhdr *veth = (struct vlan_ethhdr *)((skb->data) + | 246 | struct vlan_ethhdr *veth = (struct vlan_ethhdr *)skb_mac_header(skb); |
247 | QETH_HEADER_SIZE); | ||
248 | 247 | ||
249 | memset(hdr, 0, sizeof(struct qeth_hdr)); | 248 | memset(hdr, 0, sizeof(struct qeth_hdr)); |
250 | hdr->hdr.l2.id = QETH_HEADER_TYPE_LAYER2; | 249 | 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 | int tx_bytes = skb->len; | 620 | int tx_bytes = skb->len; |
622 | enum qeth_large_send_types large_send = QETH_LARGE_SEND_NO; | 621 | enum qeth_large_send_types large_send = QETH_LARGE_SEND_NO; |
623 | struct qeth_eddp_context *ctx = NULL; | 622 | struct qeth_eddp_context *ctx = NULL; |
623 | int data_offset = -1; | ||
624 | int elements_needed = 0; | ||
625 | int hd_len = 0; | ||
624 | 626 | ||
625 | if ((card->state != CARD_STATE_UP) || !card->lan_online) { | 627 | if ((card->state != CARD_STATE_UP) || !card->lan_online) { |
626 | card->stats.tx_carrier_errors++; | 628 | 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 | if (card->info.type == QETH_CARD_TYPE_OSN) | 645 | if (card->info.type == QETH_CARD_TYPE_OSN) |
644 | hdr = (struct qeth_hdr *)skb->data; | 646 | hdr = (struct qeth_hdr *)skb->data; |
645 | else { | 647 | else { |
646 | /* create a clone with writeable headroom */ | 648 | if ((card->info.type == QETH_CARD_TYPE_IQD) && (!large_send) && |
647 | new_skb = skb_realloc_headroom(skb, sizeof(struct qeth_hdr)); | 649 | (skb_shinfo(skb)->nr_frags == 0)) { |
648 | if (!new_skb) | 650 | new_skb = skb; |
649 | goto tx_drop; | 651 | data_offset = ETH_HLEN; |
650 | hdr = (struct qeth_hdr *)skb_push(new_skb, | 652 | hd_len = ETH_HLEN; |
653 | hdr = kmem_cache_alloc(qeth_core_header_cache, | ||
654 | GFP_ATOMIC); | ||
655 | if (!hdr) | ||
656 | goto tx_drop; | ||
657 | elements_needed++; | ||
658 | skb_reset_mac_header(new_skb); | ||
659 | qeth_l2_fill_header(card, hdr, new_skb, ipv, cast_type); | ||
660 | hdr->hdr.l2.pkt_length = new_skb->len; | ||
661 | memcpy(((char *)hdr) + sizeof(struct qeth_hdr), | ||
662 | skb_mac_header(new_skb), ETH_HLEN); | ||
663 | } else { | ||
664 | /* create a clone with writeable headroom */ | ||
665 | new_skb = skb_realloc_headroom(skb, | ||
666 | sizeof(struct qeth_hdr)); | ||
667 | if (!new_skb) | ||
668 | goto tx_drop; | ||
669 | hdr = (struct qeth_hdr *)skb_push(new_skb, | ||
651 | sizeof(struct qeth_hdr)); | 670 | sizeof(struct qeth_hdr)); |
652 | qeth_l2_fill_header(card, hdr, new_skb, ipv, cast_type); | 671 | skb_set_mac_header(new_skb, sizeof(struct qeth_hdr)); |
672 | qeth_l2_fill_header(card, hdr, new_skb, ipv, cast_type); | ||
673 | } | ||
653 | } | 674 | } |
654 | 675 | ||
655 | if (large_send == QETH_LARGE_SEND_EDDP) { | 676 | 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 | goto tx_drop; | 681 | goto tx_drop; |
661 | } | 682 | } |
662 | } else { | 683 | } else { |
663 | elements = qeth_get_elements_no(card, (void *)hdr, new_skb, 0); | 684 | elements = qeth_get_elements_no(card, (void *)hdr, new_skb, |
664 | if (!elements) | 685 | elements_needed); |
686 | if (!elements) { | ||
687 | if (data_offset >= 0) | ||
688 | kmem_cache_free(qeth_core_header_cache, hdr); | ||
665 | goto tx_drop; | 689 | goto tx_drop; |
690 | } | ||
666 | } | 691 | } |
667 | 692 | ||
668 | if ((large_send == QETH_LARGE_SEND_NO) && | 693 | 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 | elements, ctx); | 699 | elements, ctx); |
675 | else | 700 | else |
676 | rc = qeth_do_send_packet_fast(card, queue, new_skb, hdr, | 701 | rc = qeth_do_send_packet_fast(card, queue, new_skb, hdr, |
677 | elements, ctx); | 702 | elements, ctx, data_offset, hd_len); |
678 | if (!rc) { | 703 | if (!rc) { |
679 | card->stats.tx_packets++; | 704 | card->stats.tx_packets++; |
680 | card->stats.tx_bytes += tx_bytes; | 705 | 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 | if (ctx != NULL) | 726 | if (ctx != NULL) |
702 | qeth_eddp_put_context(ctx); | 727 | qeth_eddp_put_context(ctx); |
703 | 728 | ||
729 | if (data_offset >= 0) | ||
730 | kmem_cache_free(qeth_core_header_cache, hdr); | ||
731 | |||
704 | if (rc == -EBUSY) { | 732 | if (rc == -EBUSY) { |
705 | if (new_skb != skb) | 733 | if (new_skb != skb) |
706 | dev_kfree_skb_any(new_skb); | 734 | 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) | |||
2604 | int tx_bytes = skb->len; | 2604 | int tx_bytes = skb->len; |
2605 | enum qeth_large_send_types large_send = QETH_LARGE_SEND_NO; | 2605 | enum qeth_large_send_types large_send = QETH_LARGE_SEND_NO; |
2606 | struct qeth_eddp_context *ctx = NULL; | 2606 | struct qeth_eddp_context *ctx = NULL; |
2607 | int data_offset = -1; | ||
2607 | 2608 | ||
2608 | if ((card->info.type == QETH_CARD_TYPE_IQD) && | 2609 | if ((card->info.type == QETH_CARD_TYPE_IQD) && |
2609 | (skb->protocol != htons(ETH_P_IPV6)) && | 2610 | (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 | card->perf_stats.outbound_start_time = qeth_get_micros(); | 2625 | card->perf_stats.outbound_start_time = qeth_get_micros(); |
2625 | } | 2626 | } |
2626 | 2627 | ||
2627 | /* create a clone with writeable headroom */ | 2628 | if (skb_is_gso(skb)) |
2628 | new_skb = skb_realloc_headroom(skb, sizeof(struct qeth_hdr_tso) + | 2629 | large_send = card->options.large_send; |
2629 | VLAN_HLEN); | 2630 | |
2630 | if (!new_skb) | 2631 | if ((card->info.type == QETH_CARD_TYPE_IQD) && (!large_send) && |
2631 | goto tx_drop; | 2632 | (skb_shinfo(skb)->nr_frags == 0)) { |
2633 | new_skb = skb; | ||
2634 | data_offset = ETH_HLEN; | ||
2635 | hdr = kmem_cache_alloc(qeth_core_header_cache, GFP_ATOMIC); | ||
2636 | if (!hdr) | ||
2637 | goto tx_drop; | ||
2638 | elements_needed++; | ||
2639 | } else { | ||
2640 | /* create a clone with writeable headroom */ | ||
2641 | new_skb = skb_realloc_headroom(skb, sizeof(struct qeth_hdr_tso) | ||
2642 | + VLAN_HLEN); | ||
2643 | if (!new_skb) | ||
2644 | goto tx_drop; | ||
2645 | } | ||
2632 | 2646 | ||
2633 | if (card->info.type == QETH_CARD_TYPE_IQD) { | 2647 | if (card->info.type == QETH_CARD_TYPE_IQD) { |
2634 | skb_pull(new_skb, ETH_HLEN); | 2648 | if (data_offset < 0) |
2649 | skb_pull(new_skb, ETH_HLEN); | ||
2635 | } else { | 2650 | } else { |
2636 | if (new_skb->protocol == htons(ETH_P_IP)) { | 2651 | if (new_skb->protocol == htons(ETH_P_IP)) { |
2637 | if (card->dev->type == ARPHRD_IEEE802_TR) | 2652 | 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 | 2672 | ||
2658 | netif_stop_queue(dev); | 2673 | netif_stop_queue(dev); |
2659 | 2674 | ||
2660 | if (skb_is_gso(new_skb)) | ||
2661 | large_send = card->options.large_send; | ||
2662 | |||
2663 | /* fix hardware limitation: as long as we do not have sbal | 2675 | /* fix hardware limitation: as long as we do not have sbal |
2664 | * chaining we can not send long frag lists so we temporary | 2676 | * chaining we can not send long frag lists so we temporary |
2665 | * switch to EDDP | 2677 | * switch to EDDP |
@@ -2677,9 +2689,16 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
2677 | qeth_tso_fill_header(card, hdr, new_skb); | 2689 | qeth_tso_fill_header(card, hdr, new_skb); |
2678 | elements_needed++; | 2690 | elements_needed++; |
2679 | } else { | 2691 | } else { |
2680 | hdr = (struct qeth_hdr *)skb_push(new_skb, | 2692 | if (data_offset < 0) { |
2693 | hdr = (struct qeth_hdr *)skb_push(new_skb, | ||
2681 | sizeof(struct qeth_hdr)); | 2694 | sizeof(struct qeth_hdr)); |
2682 | qeth_l3_fill_header(card, hdr, new_skb, ipv, cast_type); | 2695 | qeth_l3_fill_header(card, hdr, new_skb, ipv, |
2696 | cast_type); | ||
2697 | } else { | ||
2698 | qeth_l3_fill_header(card, hdr, new_skb, ipv, | ||
2699 | cast_type); | ||
2700 | hdr->hdr.l3.length = new_skb->len - data_offset; | ||
2701 | } | ||
2683 | } | 2702 | } |
2684 | 2703 | ||
2685 | if (large_send == QETH_LARGE_SEND_EDDP) { | 2704 | 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 | } else { | 2714 | } else { |
2696 | int elems = qeth_get_elements_no(card, (void *)hdr, new_skb, | 2715 | int elems = qeth_get_elements_no(card, (void *)hdr, new_skb, |
2697 | elements_needed); | 2716 | elements_needed); |
2698 | if (!elems) | 2717 | if (!elems) { |
2718 | if (data_offset >= 0) | ||
2719 | kmem_cache_free(qeth_core_header_cache, hdr); | ||
2699 | goto tx_drop; | 2720 | goto tx_drop; |
2721 | } | ||
2700 | elements_needed += elems; | 2722 | elements_needed += elems; |
2701 | } | 2723 | } |
2702 | 2724 | ||
@@ -2709,7 +2731,7 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
2709 | elements_needed, ctx); | 2731 | elements_needed, ctx); |
2710 | else | 2732 | else |
2711 | rc = qeth_do_send_packet_fast(card, queue, new_skb, hdr, | 2733 | rc = qeth_do_send_packet_fast(card, queue, new_skb, hdr, |
2712 | elements_needed, ctx); | 2734 | elements_needed, ctx, data_offset, 0); |
2713 | 2735 | ||
2714 | if (!rc) { | 2736 | if (!rc) { |
2715 | card->stats.tx_packets++; | 2737 | card->stats.tx_packets++; |
@@ -2737,6 +2759,9 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
2737 | if (ctx != NULL) | 2759 | if (ctx != NULL) |
2738 | qeth_eddp_put_context(ctx); | 2760 | qeth_eddp_put_context(ctx); |
2739 | 2761 | ||
2762 | if (data_offset >= 0) | ||
2763 | kmem_cache_free(qeth_core_header_cache, hdr); | ||
2764 | |||
2740 | if (rc == -EBUSY) { | 2765 | if (rc == -EBUSY) { |
2741 | if (new_skb != skb) | 2766 | if (new_skb != skb) |
2742 | dev_kfree_skb_any(new_skb); | 2767 | dev_kfree_skb_any(new_skb); |
diff --git a/include/asm-s390/hardirq.h b/include/asm-s390/hardirq.h index 4b7cb964ff35..89ec7056da28 100644 --- a/include/asm-s390/hardirq.h +++ b/include/asm-s390/hardirq.h | |||
@@ -34,4 +34,18 @@ typedef struct { | |||
34 | 34 | ||
35 | void clock_comparator_work(void); | 35 | void clock_comparator_work(void); |
36 | 36 | ||
37 | static inline unsigned long long local_tick_disable(void) | ||
38 | { | ||
39 | unsigned long long old; | ||
40 | |||
41 | old = S390_lowcore.clock_comparator; | ||
42 | S390_lowcore.clock_comparator = -1ULL; | ||
43 | return old; | ||
44 | } | ||
45 | |||
46 | static inline void local_tick_enable(unsigned long long comp) | ||
47 | { | ||
48 | S390_lowcore.clock_comparator = comp; | ||
49 | } | ||
50 | |||
37 | #endif /* __ASM_HARDIRQ_H */ | 51 | #endif /* __ASM_HARDIRQ_H */ |
diff --git a/include/asm-s390/ipl.h b/include/asm-s390/ipl.h index eaca6dff5405..1171e6d144a3 100644 --- a/include/asm-s390/ipl.h +++ b/include/asm-s390/ipl.h | |||
@@ -159,7 +159,8 @@ enum diag308_vm_flags { | |||
159 | }; | 159 | }; |
160 | 160 | ||
161 | enum diag308_rc { | 161 | enum diag308_rc { |
162 | DIAG308_RC_OK = 1, | 162 | DIAG308_RC_OK = 0x0001, |
163 | DIAG308_RC_NOCONFIG = 0x0102, | ||
163 | }; | 164 | }; |
164 | 165 | ||
165 | extern int diag308(unsigned long subcode, void *addr); | 166 | extern int diag308(unsigned long subcode, void *addr); |
diff --git a/include/asm-s390/schid.h b/include/asm-s390/schid.h index 7bdc0fe15691..825503cf3dc2 100644 --- a/include/asm-s390/schid.h +++ b/include/asm-s390/schid.h | |||
@@ -11,6 +11,7 @@ struct subchannel_id { | |||
11 | } __attribute__ ((packed, aligned(4))); | 11 | } __attribute__ ((packed, aligned(4))); |
12 | 12 | ||
13 | #ifdef __KERNEL__ | 13 | #ifdef __KERNEL__ |
14 | #include <linux/string.h> | ||
14 | 15 | ||
15 | /* Helper function for sane state of pre-allocated subchannel_id. */ | 16 | /* Helper function for sane state of pre-allocated subchannel_id. */ |
16 | static inline void | 17 | static inline void |
diff --git a/include/asm-s390/setup.h b/include/asm-s390/setup.h index 4ba14e463e83..2bd9faeb3919 100644 --- a/include/asm-s390/setup.h +++ b/include/asm-s390/setup.h | |||
@@ -65,7 +65,6 @@ extern unsigned long machine_flags; | |||
65 | 65 | ||
66 | #define MACHINE_FLAG_VM (1UL << 0) | 66 | #define MACHINE_FLAG_VM (1UL << 0) |
67 | #define MACHINE_FLAG_IEEE (1UL << 1) | 67 | #define MACHINE_FLAG_IEEE (1UL << 1) |
68 | #define MACHINE_FLAG_P390 (1UL << 2) | ||
69 | #define MACHINE_FLAG_CSP (1UL << 3) | 68 | #define MACHINE_FLAG_CSP (1UL << 3) |
70 | #define MACHINE_FLAG_MVPG (1UL << 4) | 69 | #define MACHINE_FLAG_MVPG (1UL << 4) |
71 | #define MACHINE_FLAG_DIAG44 (1UL << 5) | 70 | #define MACHINE_FLAG_DIAG44 (1UL << 5) |
diff --git a/include/asm-s390/unistd.h b/include/asm-s390/unistd.h index 583da807ea97..c8ad350d1444 100644 --- a/include/asm-s390/unistd.h +++ b/include/asm-s390/unistd.h | |||
@@ -259,7 +259,13 @@ | |||
259 | #define __NR_timerfd_create 319 | 259 | #define __NR_timerfd_create 319 |
260 | #define __NR_timerfd_settime 320 | 260 | #define __NR_timerfd_settime 320 |
261 | #define __NR_timerfd_gettime 321 | 261 | #define __NR_timerfd_gettime 321 |
262 | #define NR_syscalls 322 | 262 | #define __NR_signalfd4 322 |
263 | #define __NR_eventfd2 323 | ||
264 | #define __NR_inotify_init1 324 | ||
265 | #define __NR_pipe2 325 | ||
266 | #define __NR_dup3 326 | ||
267 | #define __NR_epoll_create1 327 | ||
268 | #define NR_syscalls 328 | ||
263 | 269 | ||
264 | /* | 270 | /* |
265 | * There are some system calls that are not present on 64 bit, some | 271 | * There are some system calls that are not present on 64 bit, some |
diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h index 54590a9a103e..25aaccdb2f26 100644 --- a/include/linux/page-flags.h +++ b/include/linux/page-flags.h | |||
@@ -239,9 +239,6 @@ static inline void __SetPageUptodate(struct page *page) | |||
239 | { | 239 | { |
240 | smp_wmb(); | 240 | smp_wmb(); |
241 | __set_bit(PG_uptodate, &(page)->flags); | 241 | __set_bit(PG_uptodate, &(page)->flags); |
242 | #ifdef CONFIG_S390 | ||
243 | page_clear_dirty(page); | ||
244 | #endif | ||
245 | } | 242 | } |
246 | 243 | ||
247 | static inline void SetPageUptodate(struct page *page) | 244 | static inline void SetPageUptodate(struct page *page) |
@@ -667,7 +667,8 @@ void page_remove_rmap(struct page *page, struct vm_area_struct *vma) | |||
667 | * Leaving it set also helps swapoff to reinstate ptes | 667 | * Leaving it set also helps swapoff to reinstate ptes |
668 | * faster for those pages still in swapcache. | 668 | * faster for those pages still in swapcache. |
669 | */ | 669 | */ |
670 | if (page_test_dirty(page)) { | 670 | if ((!PageAnon(page) || PageSwapCache(page)) && |
671 | page_test_dirty(page)) { | ||
671 | page_clear_dirty(page); | 672 | page_clear_dirty(page); |
672 | set_page_dirty(page); | 673 | set_page_dirty(page); |
673 | } | 674 | } |