diff options
author | Andreas Herrmann <aherrman@de.ibm.com> | 2006-04-27 21:40:09 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-04-28 11:33:47 -0400 |
commit | a3ae39c060be57a4936d2c1d970e4d0c7d320d9c (patch) | |
tree | a8b0207d32f660fed21f55d0c4ab1c05f691ac39 /drivers | |
parent | 28f223782bca914ae65d08234c57c2175ecd7f5d (diff) |
[PATCH] s390: qdio memory allocations
Avoid memory allocation with GFP_KERNEL in qdio_establish/qdio_shutdown. Use
memory pool instead. (Otherwise this can lead to an I/O stall where qdio
waits for a free page and zfcp waits for end of error recovery in low memory
situations.)
Signed-off-by: Andreas Herrmann <aherrman@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/s390/cio/qdio.c | 30 |
1 files changed, 24 insertions, 6 deletions
diff --git a/drivers/s390/cio/qdio.c b/drivers/s390/cio/qdio.c index 814f9258ce00..a5bf272fe775 100644 --- a/drivers/s390/cio/qdio.c +++ b/drivers/s390/cio/qdio.c | |||
@@ -38,6 +38,7 @@ | |||
38 | #include <linux/kernel.h> | 38 | #include <linux/kernel.h> |
39 | #include <linux/proc_fs.h> | 39 | #include <linux/proc_fs.h> |
40 | #include <linux/timer.h> | 40 | #include <linux/timer.h> |
41 | #include <linux/mempool.h> | ||
41 | 42 | ||
42 | #include <asm/ccwdev.h> | 43 | #include <asm/ccwdev.h> |
43 | #include <asm/io.h> | 44 | #include <asm/io.h> |
@@ -80,6 +81,8 @@ static int indicator_used[INDICATORS_PER_CACHELINE]; | |||
80 | static __u32 * volatile indicators; | 81 | static __u32 * volatile indicators; |
81 | static __u32 volatile spare_indicator; | 82 | static __u32 volatile spare_indicator; |
82 | static atomic_t spare_indicator_usecount; | 83 | static atomic_t spare_indicator_usecount; |
84 | #define QDIO_MEMPOOL_SCSSC_ELEMENTS 2 | ||
85 | static mempool_t *qdio_mempool_scssc; | ||
83 | 86 | ||
84 | static debug_info_t *qdio_dbf_setup; | 87 | static debug_info_t *qdio_dbf_setup; |
85 | static debug_info_t *qdio_dbf_sbal; | 88 | static debug_info_t *qdio_dbf_sbal; |
@@ -2304,7 +2307,7 @@ qdio_get_ssqd_information(struct qdio_irq *irq_ptr) | |||
2304 | 2307 | ||
2305 | QDIO_DBF_TEXT0(0,setup,"getssqd"); | 2308 | QDIO_DBF_TEXT0(0,setup,"getssqd"); |
2306 | qdioac = 0; | 2309 | qdioac = 0; |
2307 | ssqd_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); | 2310 | ssqd_area = mempool_alloc(qdio_mempool_scssc, GFP_ATOMIC); |
2308 | if (!ssqd_area) { | 2311 | if (!ssqd_area) { |
2309 | QDIO_PRINT_WARN("Could not get memory for chsc. Using all " \ | 2312 | QDIO_PRINT_WARN("Could not get memory for chsc. Using all " \ |
2310 | "SIGAs for sch x%x.\n", irq_ptr->schid.sch_no); | 2313 | "SIGAs for sch x%x.\n", irq_ptr->schid.sch_no); |
@@ -2364,7 +2367,7 @@ qdio_get_ssqd_information(struct qdio_irq *irq_ptr) | |||
2364 | out: | 2367 | out: |
2365 | qdio_check_subchannel_qebsm(irq_ptr, qdioac, | 2368 | qdio_check_subchannel_qebsm(irq_ptr, qdioac, |
2366 | ssqd_area->sch_token); | 2369 | ssqd_area->sch_token); |
2367 | free_page ((unsigned long) ssqd_area); | 2370 | mempool_free(ssqd_area, qdio_mempool_scssc); |
2368 | irq_ptr->qdioac = qdioac; | 2371 | irq_ptr->qdioac = qdioac; |
2369 | } | 2372 | } |
2370 | 2373 | ||
@@ -2458,7 +2461,7 @@ tiqdio_set_subchannel_ind(struct qdio_irq *irq_ptr, int reset_to_zero) | |||
2458 | virt_to_phys((volatile void *)irq_ptr->dev_st_chg_ind); | 2461 | virt_to_phys((volatile void *)irq_ptr->dev_st_chg_ind); |
2459 | } | 2462 | } |
2460 | 2463 | ||
2461 | scssc_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); | 2464 | scssc_area = mempool_alloc(qdio_mempool_scssc, GFP_ATOMIC); |
2462 | if (!scssc_area) { | 2465 | if (!scssc_area) { |
2463 | QDIO_PRINT_WARN("No memory for setting indicators on " \ | 2466 | QDIO_PRINT_WARN("No memory for setting indicators on " \ |
2464 | "subchannel 0.%x.%x.\n", | 2467 | "subchannel 0.%x.%x.\n", |
@@ -2514,7 +2517,7 @@ tiqdio_set_subchannel_ind(struct qdio_irq *irq_ptr, int reset_to_zero) | |||
2514 | QDIO_DBF_HEX2(0,setup,&real_addr_dev_st_chg_ind,sizeof(unsigned long)); | 2517 | QDIO_DBF_HEX2(0,setup,&real_addr_dev_st_chg_ind,sizeof(unsigned long)); |
2515 | result = 0; | 2518 | result = 0; |
2516 | out: | 2519 | out: |
2517 | free_page ((unsigned long) scssc_area); | 2520 | mempool_free(scssc_area, qdio_mempool_scssc); |
2518 | return result; | 2521 | return result; |
2519 | 2522 | ||
2520 | } | 2523 | } |
@@ -2543,7 +2546,7 @@ tiqdio_set_delay_target(struct qdio_irq *irq_ptr, unsigned long delay_target) | |||
2543 | if (!irq_ptr->is_thinint_irq) | 2546 | if (!irq_ptr->is_thinint_irq) |
2544 | return -ENODEV; | 2547 | return -ENODEV; |
2545 | 2548 | ||
2546 | scsscf_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); | 2549 | scsscf_area = mempool_alloc(qdio_mempool_scssc, GFP_ATOMIC); |
2547 | if (!scsscf_area) { | 2550 | if (!scsscf_area) { |
2548 | QDIO_PRINT_WARN("No memory for setting delay target on " \ | 2551 | QDIO_PRINT_WARN("No memory for setting delay target on " \ |
2549 | "subchannel 0.%x.%x.\n", | 2552 | "subchannel 0.%x.%x.\n", |
@@ -2581,7 +2584,7 @@ tiqdio_set_delay_target(struct qdio_irq *irq_ptr, unsigned long delay_target) | |||
2581 | QDIO_DBF_HEX2(0,trace,&delay_target,sizeof(unsigned long)); | 2584 | QDIO_DBF_HEX2(0,trace,&delay_target,sizeof(unsigned long)); |
2582 | result = 0; /* not critical */ | 2585 | result = 0; /* not critical */ |
2583 | out: | 2586 | out: |
2584 | free_page ((unsigned long) scsscf_area); | 2587 | mempool_free(scsscf_area, qdio_mempool_scssc); |
2585 | return result; | 2588 | return result; |
2586 | } | 2589 | } |
2587 | 2590 | ||
@@ -3780,6 +3783,16 @@ oom: | |||
3780 | return -ENOMEM; | 3783 | return -ENOMEM; |
3781 | } | 3784 | } |
3782 | 3785 | ||
3786 | static void *qdio_mempool_alloc(gfp_t gfp_mask, void *size) | ||
3787 | { | ||
3788 | return (void *) get_zeroed_page(gfp_mask|GFP_DMA); | ||
3789 | } | ||
3790 | |||
3791 | static void qdio_mempool_free(void *element, void *size) | ||
3792 | { | ||
3793 | free_page((unsigned long) element); | ||
3794 | } | ||
3795 | |||
3783 | static int __init | 3796 | static int __init |
3784 | init_QDIO(void) | 3797 | init_QDIO(void) |
3785 | { | 3798 | { |
@@ -3809,6 +3822,10 @@ init_QDIO(void) | |||
3809 | 3822 | ||
3810 | qdio_add_procfs_entry(); | 3823 | qdio_add_procfs_entry(); |
3811 | 3824 | ||
3825 | qdio_mempool_scssc = mempool_create(QDIO_MEMPOOL_SCSSC_ELEMENTS, | ||
3826 | qdio_mempool_alloc, | ||
3827 | qdio_mempool_free, NULL); | ||
3828 | |||
3812 | if (tiqdio_check_chsc_availability()) | 3829 | if (tiqdio_check_chsc_availability()) |
3813 | QDIO_PRINT_ERR("Not all CHSCs supported. Continuing.\n"); | 3830 | QDIO_PRINT_ERR("Not all CHSCs supported. Continuing.\n"); |
3814 | 3831 | ||
@@ -3824,6 +3841,7 @@ cleanup_QDIO(void) | |||
3824 | qdio_remove_procfs_entry(); | 3841 | qdio_remove_procfs_entry(); |
3825 | qdio_release_qdio_memory(); | 3842 | qdio_release_qdio_memory(); |
3826 | qdio_unregister_dbf_views(); | 3843 | qdio_unregister_dbf_views(); |
3844 | mempool_destroy(qdio_mempool_scssc); | ||
3827 | 3845 | ||
3828 | printk("qdio: %s: module removed\n",version); | 3846 | printk("qdio: %s: module removed\n",version); |
3829 | } | 3847 | } |