diff options
| -rw-r--r-- | net/iucv/iucv.c | 107 |
1 files changed, 61 insertions, 46 deletions
diff --git a/net/iucv/iucv.c b/net/iucv/iucv.c index a2f5a6ea3895..7698f6c459d6 100644 --- a/net/iucv/iucv.c +++ b/net/iucv/iucv.c | |||
| @@ -97,7 +97,7 @@ struct iucv_irq_list { | |||
| 97 | struct iucv_irq_data data; | 97 | struct iucv_irq_data data; |
| 98 | }; | 98 | }; |
| 99 | 99 | ||
| 100 | static struct iucv_irq_data *iucv_irq_data; | 100 | static struct iucv_irq_data *iucv_irq_data[NR_CPUS]; |
| 101 | static cpumask_t iucv_buffer_cpumask = CPU_MASK_NONE; | 101 | static cpumask_t iucv_buffer_cpumask = CPU_MASK_NONE; |
| 102 | static cpumask_t iucv_irq_cpumask = CPU_MASK_NONE; | 102 | static cpumask_t iucv_irq_cpumask = CPU_MASK_NONE; |
| 103 | 103 | ||
| @@ -277,7 +277,7 @@ union iucv_param { | |||
| 277 | /* | 277 | /* |
| 278 | * Anchor for per-cpu IUCV command parameter block. | 278 | * Anchor for per-cpu IUCV command parameter block. |
| 279 | */ | 279 | */ |
| 280 | static union iucv_param *iucv_param; | 280 | static union iucv_param *iucv_param[NR_CPUS]; |
| 281 | 281 | ||
| 282 | /** | 282 | /** |
| 283 | * iucv_call_b2f0 | 283 | * iucv_call_b2f0 |
| @@ -356,7 +356,7 @@ static void iucv_allow_cpu(void *data) | |||
| 356 | * 0x10 - Flag to allow priority message completion interrupts | 356 | * 0x10 - Flag to allow priority message completion interrupts |
| 357 | * 0x08 - Flag to allow IUCV control interrupts | 357 | * 0x08 - Flag to allow IUCV control interrupts |
| 358 | */ | 358 | */ |
| 359 | parm = percpu_ptr(iucv_param, smp_processor_id()); | 359 | parm = iucv_param[cpu]; |
| 360 | memset(parm, 0, sizeof(union iucv_param)); | 360 | memset(parm, 0, sizeof(union iucv_param)); |
| 361 | parm->set_mask.ipmask = 0xf8; | 361 | parm->set_mask.ipmask = 0xf8; |
| 362 | iucv_call_b2f0(IUCV_SETMASK, parm); | 362 | iucv_call_b2f0(IUCV_SETMASK, parm); |
| @@ -377,7 +377,7 @@ static void iucv_block_cpu(void *data) | |||
| 377 | union iucv_param *parm; | 377 | union iucv_param *parm; |
| 378 | 378 | ||
| 379 | /* Disable all iucv interrupts. */ | 379 | /* Disable all iucv interrupts. */ |
| 380 | parm = percpu_ptr(iucv_param, smp_processor_id()); | 380 | parm = iucv_param[cpu]; |
| 381 | memset(parm, 0, sizeof(union iucv_param)); | 381 | memset(parm, 0, sizeof(union iucv_param)); |
| 382 | iucv_call_b2f0(IUCV_SETMASK, parm); | 382 | iucv_call_b2f0(IUCV_SETMASK, parm); |
| 383 | 383 | ||
| @@ -401,9 +401,9 @@ static void iucv_declare_cpu(void *data) | |||
| 401 | return; | 401 | return; |
| 402 | 402 | ||
| 403 | /* Declare interrupt buffer. */ | 403 | /* Declare interrupt buffer. */ |
| 404 | parm = percpu_ptr(iucv_param, cpu); | 404 | parm = iucv_param[cpu]; |
| 405 | memset(parm, 0, sizeof(union iucv_param)); | 405 | memset(parm, 0, sizeof(union iucv_param)); |
| 406 | parm->db.ipbfadr1 = virt_to_phys(percpu_ptr(iucv_irq_data, cpu)); | 406 | parm->db.ipbfadr1 = virt_to_phys(iucv_irq_data[cpu]); |
| 407 | rc = iucv_call_b2f0(IUCV_DECLARE_BUFFER, parm); | 407 | rc = iucv_call_b2f0(IUCV_DECLARE_BUFFER, parm); |
| 408 | if (rc) { | 408 | if (rc) { |
| 409 | char *err = "Unknown"; | 409 | char *err = "Unknown"; |
| @@ -458,7 +458,7 @@ static void iucv_retrieve_cpu(void *data) | |||
| 458 | iucv_block_cpu(NULL); | 458 | iucv_block_cpu(NULL); |
| 459 | 459 | ||
| 460 | /* Retrieve interrupt buffer. */ | 460 | /* Retrieve interrupt buffer. */ |
| 461 | parm = percpu_ptr(iucv_param, cpu); | 461 | parm = iucv_param[cpu]; |
| 462 | iucv_call_b2f0(IUCV_RETRIEVE_BUFFER, parm); | 462 | iucv_call_b2f0(IUCV_RETRIEVE_BUFFER, parm); |
| 463 | 463 | ||
| 464 | /* Clear indication that an iucv buffer exists for this cpu. */ | 464 | /* Clear indication that an iucv buffer exists for this cpu. */ |
| @@ -558,22 +558,23 @@ static int __cpuinit iucv_cpu_notify(struct notifier_block *self, | |||
| 558 | switch (action) { | 558 | switch (action) { |
| 559 | case CPU_UP_PREPARE: | 559 | case CPU_UP_PREPARE: |
| 560 | case CPU_UP_PREPARE_FROZEN: | 560 | case CPU_UP_PREPARE_FROZEN: |
| 561 | if (!percpu_populate(iucv_irq_data, | 561 | iucv_irq_data[cpu] = kmalloc_node(sizeof(struct iucv_irq_data), |
| 562 | sizeof(struct iucv_irq_data), | 562 | GFP_KERNEL|GFP_DMA, cpu_to_node(cpu)); |
| 563 | GFP_KERNEL|GFP_DMA, cpu)) | 563 | if (!iucv_irq_data[cpu]) |
| 564 | return NOTIFY_BAD; | 564 | return NOTIFY_BAD; |
| 565 | if (!percpu_populate(iucv_param, sizeof(union iucv_param), | 565 | iucv_param[cpu] = kmalloc_node(sizeof(union iucv_param), |
| 566 | GFP_KERNEL|GFP_DMA, cpu)) { | 566 | GFP_KERNEL|GFP_DMA, cpu_to_node(cpu)); |
| 567 | percpu_depopulate(iucv_irq_data, cpu); | 567 | if (!iucv_param[cpu]) |
| 568 | return NOTIFY_BAD; | 568 | return NOTIFY_BAD; |
| 569 | } | ||
| 570 | break; | 569 | break; |
| 571 | case CPU_UP_CANCELED: | 570 | case CPU_UP_CANCELED: |
| 572 | case CPU_UP_CANCELED_FROZEN: | 571 | case CPU_UP_CANCELED_FROZEN: |
| 573 | case CPU_DEAD: | 572 | case CPU_DEAD: |
| 574 | case CPU_DEAD_FROZEN: | 573 | case CPU_DEAD_FROZEN: |
| 575 | percpu_depopulate(iucv_param, cpu); | 574 | kfree(iucv_param[cpu]); |
| 576 | percpu_depopulate(iucv_irq_data, cpu); | 575 | iucv_param[cpu] = NULL; |
| 576 | kfree(iucv_irq_data[cpu]); | ||
| 577 | iucv_irq_data[cpu] = NULL; | ||
| 577 | break; | 578 | break; |
| 578 | case CPU_ONLINE: | 579 | case CPU_ONLINE: |
| 579 | case CPU_ONLINE_FROZEN: | 580 | case CPU_ONLINE_FROZEN: |
| @@ -612,7 +613,7 @@ static int iucv_sever_pathid(u16 pathid, u8 userdata[16]) | |||
| 612 | { | 613 | { |
| 613 | union iucv_param *parm; | 614 | union iucv_param *parm; |
| 614 | 615 | ||
| 615 | parm = percpu_ptr(iucv_param, smp_processor_id()); | 616 | parm = iucv_param[smp_processor_id()]; |
| 616 | memset(parm, 0, sizeof(union iucv_param)); | 617 | memset(parm, 0, sizeof(union iucv_param)); |
| 617 | if (userdata) | 618 | if (userdata) |
| 618 | memcpy(parm->ctrl.ipuser, userdata, sizeof(parm->ctrl.ipuser)); | 619 | memcpy(parm->ctrl.ipuser, userdata, sizeof(parm->ctrl.ipuser)); |
| @@ -755,7 +756,7 @@ int iucv_path_accept(struct iucv_path *path, struct iucv_handler *handler, | |||
| 755 | 756 | ||
| 756 | local_bh_disable(); | 757 | local_bh_disable(); |
| 757 | /* Prepare parameter block. */ | 758 | /* Prepare parameter block. */ |
| 758 | parm = percpu_ptr(iucv_param, smp_processor_id()); | 759 | parm = iucv_param[smp_processor_id()]; |
| 759 | memset(parm, 0, sizeof(union iucv_param)); | 760 | memset(parm, 0, sizeof(union iucv_param)); |
| 760 | parm->ctrl.ippathid = path->pathid; | 761 | parm->ctrl.ippathid = path->pathid; |
| 761 | parm->ctrl.ipmsglim = path->msglim; | 762 | parm->ctrl.ipmsglim = path->msglim; |
| @@ -799,7 +800,7 @@ int iucv_path_connect(struct iucv_path *path, struct iucv_handler *handler, | |||
| 799 | BUG_ON(in_atomic()); | 800 | BUG_ON(in_atomic()); |
| 800 | spin_lock_bh(&iucv_table_lock); | 801 | spin_lock_bh(&iucv_table_lock); |
| 801 | iucv_cleanup_queue(); | 802 | iucv_cleanup_queue(); |
| 802 | parm = percpu_ptr(iucv_param, smp_processor_id()); | 803 | parm = iucv_param[smp_processor_id()]; |
| 803 | memset(parm, 0, sizeof(union iucv_param)); | 804 | memset(parm, 0, sizeof(union iucv_param)); |
| 804 | parm->ctrl.ipmsglim = path->msglim; | 805 | parm->ctrl.ipmsglim = path->msglim; |
| 805 | parm->ctrl.ipflags1 = path->flags; | 806 | parm->ctrl.ipflags1 = path->flags; |
| @@ -854,7 +855,7 @@ int iucv_path_quiesce(struct iucv_path *path, u8 userdata[16]) | |||
| 854 | int rc; | 855 | int rc; |
| 855 | 856 | ||
| 856 | local_bh_disable(); | 857 | local_bh_disable(); |
| 857 | parm = percpu_ptr(iucv_param, smp_processor_id()); | 858 | parm = iucv_param[smp_processor_id()]; |
| 858 | memset(parm, 0, sizeof(union iucv_param)); | 859 | memset(parm, 0, sizeof(union iucv_param)); |
| 859 | if (userdata) | 860 | if (userdata) |
| 860 | memcpy(parm->ctrl.ipuser, userdata, sizeof(parm->ctrl.ipuser)); | 861 | memcpy(parm->ctrl.ipuser, userdata, sizeof(parm->ctrl.ipuser)); |
| @@ -881,7 +882,7 @@ int iucv_path_resume(struct iucv_path *path, u8 userdata[16]) | |||
| 881 | int rc; | 882 | int rc; |
| 882 | 883 | ||
| 883 | local_bh_disable(); | 884 | local_bh_disable(); |
| 884 | parm = percpu_ptr(iucv_param, smp_processor_id()); | 885 | parm = iucv_param[smp_processor_id()]; |
| 885 | memset(parm, 0, sizeof(union iucv_param)); | 886 | memset(parm, 0, sizeof(union iucv_param)); |
| 886 | if (userdata) | 887 | if (userdata) |
| 887 | memcpy(parm->ctrl.ipuser, userdata, sizeof(parm->ctrl.ipuser)); | 888 | memcpy(parm->ctrl.ipuser, userdata, sizeof(parm->ctrl.ipuser)); |
| @@ -936,7 +937,7 @@ int iucv_message_purge(struct iucv_path *path, struct iucv_message *msg, | |||
| 936 | int rc; | 937 | int rc; |
| 937 | 938 | ||
| 938 | local_bh_disable(); | 939 | local_bh_disable(); |
| 939 | parm = percpu_ptr(iucv_param, smp_processor_id()); | 940 | parm = iucv_param[smp_processor_id()]; |
| 940 | memset(parm, 0, sizeof(union iucv_param)); | 941 | memset(parm, 0, sizeof(union iucv_param)); |
| 941 | parm->purge.ippathid = path->pathid; | 942 | parm->purge.ippathid = path->pathid; |
| 942 | parm->purge.ipmsgid = msg->id; | 943 | parm->purge.ipmsgid = msg->id; |
| @@ -1003,7 +1004,7 @@ int iucv_message_receive(struct iucv_path *path, struct iucv_message *msg, | |||
| 1003 | } | 1004 | } |
| 1004 | 1005 | ||
| 1005 | local_bh_disable(); | 1006 | local_bh_disable(); |
| 1006 | parm = percpu_ptr(iucv_param, smp_processor_id()); | 1007 | parm = iucv_param[smp_processor_id()]; |
| 1007 | memset(parm, 0, sizeof(union iucv_param)); | 1008 | memset(parm, 0, sizeof(union iucv_param)); |
| 1008 | parm->db.ipbfadr1 = (u32)(addr_t) buffer; | 1009 | parm->db.ipbfadr1 = (u32)(addr_t) buffer; |
| 1009 | parm->db.ipbfln1f = (u32) size; | 1010 | parm->db.ipbfln1f = (u32) size; |
| @@ -1040,7 +1041,7 @@ int iucv_message_reject(struct iucv_path *path, struct iucv_message *msg) | |||
| 1040 | int rc; | 1041 | int rc; |
| 1041 | 1042 | ||
| 1042 | local_bh_disable(); | 1043 | local_bh_disable(); |
| 1043 | parm = percpu_ptr(iucv_param, smp_processor_id()); | 1044 | parm = iucv_param[smp_processor_id()]; |
| 1044 | memset(parm, 0, sizeof(union iucv_param)); | 1045 | memset(parm, 0, sizeof(union iucv_param)); |
| 1045 | parm->db.ippathid = path->pathid; | 1046 | parm->db.ippathid = path->pathid; |
| 1046 | parm->db.ipmsgid = msg->id; | 1047 | parm->db.ipmsgid = msg->id; |
| @@ -1074,7 +1075,7 @@ int iucv_message_reply(struct iucv_path *path, struct iucv_message *msg, | |||
| 1074 | int rc; | 1075 | int rc; |
| 1075 | 1076 | ||
| 1076 | local_bh_disable(); | 1077 | local_bh_disable(); |
| 1077 | parm = percpu_ptr(iucv_param, smp_processor_id()); | 1078 | parm = iucv_param[smp_processor_id()]; |
| 1078 | memset(parm, 0, sizeof(union iucv_param)); | 1079 | memset(parm, 0, sizeof(union iucv_param)); |
| 1079 | if (flags & IUCV_IPRMDATA) { | 1080 | if (flags & IUCV_IPRMDATA) { |
| 1080 | parm->dpl.ippathid = path->pathid; | 1081 | parm->dpl.ippathid = path->pathid; |
| @@ -1118,7 +1119,7 @@ int iucv_message_send(struct iucv_path *path, struct iucv_message *msg, | |||
| 1118 | int rc; | 1119 | int rc; |
| 1119 | 1120 | ||
| 1120 | local_bh_disable(); | 1121 | local_bh_disable(); |
| 1121 | parm = percpu_ptr(iucv_param, smp_processor_id()); | 1122 | parm = iucv_param[smp_processor_id()]; |
| 1122 | memset(parm, 0, sizeof(union iucv_param)); | 1123 | memset(parm, 0, sizeof(union iucv_param)); |
| 1123 | if (flags & IUCV_IPRMDATA) { | 1124 | if (flags & IUCV_IPRMDATA) { |
| 1124 | /* Message of 8 bytes can be placed into the parameter list. */ | 1125 | /* Message of 8 bytes can be placed into the parameter list. */ |
| @@ -1172,7 +1173,7 @@ int iucv_message_send2way(struct iucv_path *path, struct iucv_message *msg, | |||
| 1172 | int rc; | 1173 | int rc; |
| 1173 | 1174 | ||
| 1174 | local_bh_disable(); | 1175 | local_bh_disable(); |
| 1175 | parm = percpu_ptr(iucv_param, smp_processor_id()); | 1176 | parm = iucv_param[smp_processor_id()]; |
| 1176 | memset(parm, 0, sizeof(union iucv_param)); | 1177 | memset(parm, 0, sizeof(union iucv_param)); |
| 1177 | if (flags & IUCV_IPRMDATA) { | 1178 | if (flags & IUCV_IPRMDATA) { |
| 1178 | parm->dpl.ippathid = path->pathid; | 1179 | parm->dpl.ippathid = path->pathid; |
| @@ -1559,7 +1560,7 @@ static void iucv_external_interrupt(u16 code) | |||
| 1559 | struct iucv_irq_data *p; | 1560 | struct iucv_irq_data *p; |
| 1560 | struct iucv_irq_list *work; | 1561 | struct iucv_irq_list *work; |
| 1561 | 1562 | ||
| 1562 | p = percpu_ptr(iucv_irq_data, smp_processor_id()); | 1563 | p = iucv_irq_data[smp_processor_id()]; |
| 1563 | if (p->ippathid >= iucv_max_pathid) { | 1564 | if (p->ippathid >= iucv_max_pathid) { |
| 1564 | printk(KERN_WARNING "iucv_do_int: Got interrupt with " | 1565 | printk(KERN_WARNING "iucv_do_int: Got interrupt with " |
| 1565 | "pathid %d > max_connections (%ld)\n", | 1566 | "pathid %d > max_connections (%ld)\n", |
| @@ -1598,6 +1599,7 @@ static void iucv_external_interrupt(u16 code) | |||
| 1598 | static int __init iucv_init(void) | 1599 | static int __init iucv_init(void) |
| 1599 | { | 1600 | { |
| 1600 | int rc; | 1601 | int rc; |
| 1602 | int cpu; | ||
| 1601 | 1603 | ||
| 1602 | if (!MACHINE_IS_VM) { | 1604 | if (!MACHINE_IS_VM) { |
| 1603 | rc = -EPROTONOSUPPORT; | 1605 | rc = -EPROTONOSUPPORT; |
| @@ -1617,19 +1619,23 @@ static int __init iucv_init(void) | |||
| 1617 | rc = PTR_ERR(iucv_root); | 1619 | rc = PTR_ERR(iucv_root); |
| 1618 | goto out_bus; | 1620 | goto out_bus; |
| 1619 | } | 1621 | } |
| 1620 | /* Note: GFP_DMA used to get memory below 2G */ | 1622 | |
| 1621 | iucv_irq_data = percpu_alloc(sizeof(struct iucv_irq_data), | 1623 | for_each_online_cpu(cpu) { |
| 1622 | GFP_KERNEL|GFP_DMA); | 1624 | /* Note: GFP_DMA used to get memory below 2G */ |
| 1623 | if (!iucv_irq_data) { | 1625 | iucv_irq_data[cpu] = kmalloc_node(sizeof(struct iucv_irq_data), |
| 1624 | rc = -ENOMEM; | 1626 | GFP_KERNEL|GFP_DMA, cpu_to_node(cpu)); |
| 1625 | goto out_root; | 1627 | if (!iucv_irq_data[cpu]) { |
| 1626 | } | 1628 | rc = -ENOMEM; |
| 1627 | /* Allocate parameter blocks. */ | 1629 | goto out_free; |
| 1628 | iucv_param = percpu_alloc(sizeof(union iucv_param), | 1630 | } |
| 1629 | GFP_KERNEL|GFP_DMA); | 1631 | |
| 1630 | if (!iucv_param) { | 1632 | /* Allocate parameter blocks. */ |
| 1631 | rc = -ENOMEM; | 1633 | iucv_param[cpu] = kmalloc_node(sizeof(union iucv_param), |
| 1632 | goto out_extint; | 1634 | GFP_KERNEL|GFP_DMA, cpu_to_node(cpu)); |
| 1635 | if (!iucv_param[cpu]) { | ||
| 1636 | rc = -ENOMEM; | ||
| 1637 | goto out_free; | ||
| 1638 | } | ||
| 1633 | } | 1639 | } |
| 1634 | register_hotcpu_notifier(&iucv_cpu_notifier); | 1640 | register_hotcpu_notifier(&iucv_cpu_notifier); |
| 1635 | ASCEBC(iucv_error_no_listener, 16); | 1641 | ASCEBC(iucv_error_no_listener, 16); |
| @@ -1638,9 +1644,13 @@ static int __init iucv_init(void) | |||
| 1638 | iucv_available = 1; | 1644 | iucv_available = 1; |
| 1639 | return 0; | 1645 | return 0; |
| 1640 | 1646 | ||
| 1641 | out_extint: | 1647 | out_free: |
| 1642 | percpu_free(iucv_irq_data); | 1648 | for_each_possible_cpu(cpu) { |
| 1643 | out_root: | 1649 | kfree(iucv_param[cpu]); |
| 1650 | iucv_param[cpu] = NULL; | ||
| 1651 | kfree(iucv_irq_data[cpu]); | ||
| 1652 | iucv_irq_data[cpu] = NULL; | ||
| 1653 | } | ||
| 1644 | s390_root_dev_unregister(iucv_root); | 1654 | s390_root_dev_unregister(iucv_root); |
| 1645 | out_bus: | 1655 | out_bus: |
| 1646 | bus_unregister(&iucv_bus); | 1656 | bus_unregister(&iucv_bus); |
| @@ -1658,6 +1668,7 @@ out: | |||
| 1658 | static void __exit iucv_exit(void) | 1668 | static void __exit iucv_exit(void) |
| 1659 | { | 1669 | { |
| 1660 | struct iucv_irq_list *p, *n; | 1670 | struct iucv_irq_list *p, *n; |
| 1671 | int cpu; | ||
| 1661 | 1672 | ||
| 1662 | spin_lock_irq(&iucv_queue_lock); | 1673 | spin_lock_irq(&iucv_queue_lock); |
| 1663 | list_for_each_entry_safe(p, n, &iucv_task_queue, list) | 1674 | list_for_each_entry_safe(p, n, &iucv_task_queue, list) |
| @@ -1666,8 +1677,12 @@ static void __exit iucv_exit(void) | |||
| 1666 | kfree(p); | 1677 | kfree(p); |
| 1667 | spin_unlock_irq(&iucv_queue_lock); | 1678 | spin_unlock_irq(&iucv_queue_lock); |
| 1668 | unregister_hotcpu_notifier(&iucv_cpu_notifier); | 1679 | unregister_hotcpu_notifier(&iucv_cpu_notifier); |
| 1669 | percpu_free(iucv_param); | 1680 | for_each_possible_cpu(cpu) { |
| 1670 | percpu_free(iucv_irq_data); | 1681 | kfree(iucv_param[cpu]); |
| 1682 | iucv_param[cpu] = NULL; | ||
| 1683 | kfree(iucv_irq_data[cpu]); | ||
| 1684 | iucv_irq_data[cpu] = NULL; | ||
| 1685 | } | ||
| 1671 | s390_root_dev_unregister(iucv_root); | 1686 | s390_root_dev_unregister(iucv_root); |
| 1672 | bus_unregister(&iucv_bus); | 1687 | bus_unregister(&iucv_bus); |
| 1673 | unregister_external_interrupt(0x4000, iucv_external_interrupt); | 1688 | unregister_external_interrupt(0x4000, iucv_external_interrupt); |
