]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/blobdiff - drivers/s390/cio/qdio.c
[PATCH] s390: qdio memory allocations
[mirror_ubuntu-zesty-kernel.git] / drivers / s390 / cio / qdio.c
index 30a836ffc31fc51fe4b95513c093bee1ec5f78ee..a5bf272fe775155b87dcd2c87b96a3e312bdf8b3 100644 (file)
@@ -7,7 +7,7 @@
  *
  * Copyright 2000,2002 IBM Corporation
  * Author(s):             Utz Bacher <utz.bacher@de.ibm.com>
- * 2.6 cio integration by Cornelia Huck <cohuck@de.ibm.com>
+ * 2.6 cio integration by Cornelia Huck <cornelia.huck@de.ibm.com>
  *
  * Restriction: only 63 iqdio subchannels would have its own indicator,
  * after that, subsequent subchannels share one indicator
@@ -38,6 +38,7 @@
 #include <linux/kernel.h>
 #include <linux/proc_fs.h>
 #include <linux/timer.h>
+#include <linux/mempool.h>
 
 #include <asm/ccwdev.h>
 #include <asm/io.h>
@@ -56,8 +57,6 @@
 #include "ioasm.h"
 #include "chsc.h"
 
-#define VERSION_QDIO_C "$Revision: 1.114 $"
-
 /****************** MODULE PARAMETER VARIABLES ********************/
 MODULE_AUTHOR("Utz Bacher <utz.bacher@de.ibm.com>");
 MODULE_DESCRIPTION("QDIO base support version 2, " \
@@ -66,8 +65,7 @@ MODULE_LICENSE("GPL");
 
 /******************** HERE WE GO ***********************************/
 
-static const char version[] = "QDIO base support version 2 ("
-       VERSION_QDIO_C "/" VERSION_QDIO_H  "/" VERSION_CIO_QDIO_H ")";
+static const char version[] = "QDIO base support version 2";
 
 #ifdef QDIO_PERFORMANCE_STATS
 static int proc_perf_file_registration;
@@ -83,6 +81,8 @@ static int indicator_used[INDICATORS_PER_CACHELINE];
 static __u32 * volatile indicators;
 static __u32 volatile spare_indicator;
 static atomic_t spare_indicator_usecount;
+#define QDIO_MEMPOOL_SCSSC_ELEMENTS 2
+static mempool_t *qdio_mempool_scssc;
 
 static debug_info_t *qdio_dbf_setup;
 static debug_info_t *qdio_dbf_sbal;
@@ -168,8 +168,13 @@ qdio_do_eqbs(struct qdio_q *q, unsigned char *state,
        q_no = q->q_no;
        if(!q->is_input_q)
                q_no += irq->no_input_qs;
+again:
        ccq = do_eqbs(irq->sch_token, state, q_no, start, cnt);
        rc = qdio_check_ccq(q, ccq);
+       if (rc == 1) {
+               QDIO_DBF_TEXT5(1,trace,"eqAGAIN");
+               goto again;
+       }
        if (rc < 0) {
                 QDIO_DBF_TEXT2(1,trace,"eqberr");
                 sprintf(dbf_text,"%2x,%2x,%d,%d",tmp_cnt, *cnt, ccq, q_no);
@@ -198,8 +203,13 @@ qdio_do_sqbs(struct qdio_q *q, unsigned char state,
        q_no = q->q_no;
        if(!q->is_input_q)
                q_no += irq->no_input_qs;
+again:
        ccq = do_sqbs(irq->sch_token, state, q_no, start, cnt);
        rc = qdio_check_ccq(q, ccq);
+       if (rc == 1) {
+               QDIO_DBF_TEXT5(1,trace,"sqAGAIN");
+               goto again;
+       }
        if (rc < 0) {
                 QDIO_DBF_TEXT3(1,trace,"sqberr");
                 sprintf(dbf_text,"%2x,%2x,%d,%d",tmp_cnt,*cnt,ccq,q_no);
@@ -1190,8 +1200,7 @@ tiqdio_is_inbound_q_done(struct qdio_q *q)
 
        if (!no_used)
                return 1;
-
-       if (!q->siga_sync)
+       if (!q->siga_sync && !irq->is_qebsm)
                /* we'll check for more primed buffers in qeth_stop_polling */
                return 0;
        if (irq->is_qebsm) {
@@ -1680,16 +1689,14 @@ qdio_alloc_qs(struct qdio_irq *irq_ptr,
        int result=-ENOMEM;
 
        for (i=0;i<no_input_qs;i++) {
-               q=kmalloc(sizeof(struct qdio_q),GFP_KERNEL);
+               q = kzalloc(sizeof(struct qdio_q), GFP_KERNEL);
 
                if (!q) {
                        QDIO_PRINT_ERR("kmalloc of q failed!\n");
                        goto out;
                }
 
-               memset(q,0,sizeof(struct qdio_q));
-
-               q->slib=kmalloc(PAGE_SIZE,GFP_KERNEL);
+               q->slib = kmalloc(PAGE_SIZE, GFP_KERNEL);
                if (!q->slib) {
                        QDIO_PRINT_ERR("kmalloc of slib failed!\n");
                        goto out;
@@ -1699,14 +1706,12 @@ qdio_alloc_qs(struct qdio_irq *irq_ptr,
        }
 
        for (i=0;i<no_output_qs;i++) {
-               q=kmalloc(sizeof(struct qdio_q),GFP_KERNEL);
+               q = kzalloc(sizeof(struct qdio_q), GFP_KERNEL);
 
                if (!q) {
                        goto out;
                }
 
-               memset(q,0,sizeof(struct qdio_q));
-
                q->slib=kmalloc(PAGE_SIZE,GFP_KERNEL);
                if (!q->slib) {
                        QDIO_PRINT_ERR("kmalloc of slib failed!\n");
@@ -2302,7 +2307,7 @@ qdio_get_ssqd_information(struct qdio_irq *irq_ptr)
 
        QDIO_DBF_TEXT0(0,setup,"getssqd");
        qdioac = 0;
-       ssqd_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
+       ssqd_area = mempool_alloc(qdio_mempool_scssc, GFP_ATOMIC);
        if (!ssqd_area) {
                QDIO_PRINT_WARN("Could not get memory for chsc. Using all " \
                                "SIGAs for sch x%x.\n", irq_ptr->schid.sch_no);
@@ -2362,7 +2367,7 @@ qdio_get_ssqd_information(struct qdio_irq *irq_ptr)
 out:
        qdio_check_subchannel_qebsm(irq_ptr, qdioac,
                                    ssqd_area->sch_token);
-       free_page ((unsigned long) ssqd_area);
+       mempool_free(ssqd_area, qdio_mempool_scssc);
        irq_ptr->qdioac = qdioac;
 }
 
@@ -2456,7 +2461,7 @@ tiqdio_set_subchannel_ind(struct qdio_irq *irq_ptr, int reset_to_zero)
                        virt_to_phys((volatile void *)irq_ptr->dev_st_chg_ind);
        }
 
-       scssc_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
+       scssc_area = mempool_alloc(qdio_mempool_scssc, GFP_ATOMIC);
        if (!scssc_area) {
                QDIO_PRINT_WARN("No memory for setting indicators on " \
                                "subchannel 0.%x.%x.\n",
@@ -2512,7 +2517,7 @@ tiqdio_set_subchannel_ind(struct qdio_irq *irq_ptr, int reset_to_zero)
        QDIO_DBF_HEX2(0,setup,&real_addr_dev_st_chg_ind,sizeof(unsigned long));
        result = 0;
 out:
-       free_page ((unsigned long) scssc_area);
+       mempool_free(scssc_area, qdio_mempool_scssc);
        return result;
 
 }
@@ -2541,7 +2546,7 @@ tiqdio_set_delay_target(struct qdio_irq *irq_ptr, unsigned long delay_target)
        if (!irq_ptr->is_thinint_irq)
                return -ENODEV;
 
-       scsscf_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
+       scsscf_area = mempool_alloc(qdio_mempool_scssc, GFP_ATOMIC);
        if (!scsscf_area) {
                QDIO_PRINT_WARN("No memory for setting delay target on " \
                                "subchannel 0.%x.%x.\n",
@@ -2579,7 +2584,7 @@ tiqdio_set_delay_target(struct qdio_irq *irq_ptr, unsigned long delay_target)
        QDIO_DBF_HEX2(0,trace,&delay_target,sizeof(unsigned long));
        result = 0; /* not critical */
 out:
-       free_page ((unsigned long) scsscf_area);
+       mempool_free(scsscf_area, qdio_mempool_scssc);
        return result;
 }
 
@@ -2978,7 +2983,7 @@ qdio_allocate(struct qdio_initialize *init_data)
        qdio_allocate_do_dbf(init_data);
 
        /* create irq */
-       irq_ptr=kmalloc(sizeof(struct qdio_irq), GFP_KERNEL | GFP_DMA);
+       irq_ptr = kzalloc(sizeof(struct qdio_irq), GFP_KERNEL | GFP_DMA);
 
        QDIO_DBF_TEXT0(0,setup,"irq_ptr:");
        QDIO_DBF_HEX0(0,setup,&irq_ptr,sizeof(void*));
@@ -2988,8 +2993,6 @@ qdio_allocate(struct qdio_initialize *init_data)
                return -ENOMEM;
        }
 
-       memset(irq_ptr,0,sizeof(struct qdio_irq));
-
        init_MUTEX(&irq_ptr->setting_up_sema);
 
        /* QDR must be in DMA area since CCW data address is only 32 bit */
@@ -3680,10 +3683,10 @@ qdio_get_qdio_memory(void)
 
        for (i=1;i<INDICATORS_PER_CACHELINE;i++)
                indicator_used[i]=0;
-       indicators=(__u32*)kmalloc(sizeof(__u32)*(INDICATORS_PER_CACHELINE),
+       indicators = kzalloc(sizeof(__u32)*(INDICATORS_PER_CACHELINE),
                                   GFP_KERNEL);
-               if (!indicators) return -ENOMEM;
-       memset(indicators,0,sizeof(__u32)*(INDICATORS_PER_CACHELINE));
+               if (!indicators)
+               return -ENOMEM;
        return 0;
 }
 
@@ -3780,6 +3783,16 @@ oom:
        return -ENOMEM;
 }
 
+static void *qdio_mempool_alloc(gfp_t gfp_mask, void *size)
+{
+       return (void *) get_zeroed_page(gfp_mask|GFP_DMA);
+}
+
+static void qdio_mempool_free(void *element, void *size)
+{
+       free_page((unsigned long) element);
+}
+
 static int __init
 init_QDIO(void)
 {
@@ -3809,6 +3822,10 @@ init_QDIO(void)
 
        qdio_add_procfs_entry();
 
+       qdio_mempool_scssc = mempool_create(QDIO_MEMPOOL_SCSSC_ELEMENTS,
+                                           qdio_mempool_alloc,
+                                           qdio_mempool_free, NULL);
+
        if (tiqdio_check_chsc_availability())
                QDIO_PRINT_ERR("Not all CHSCs supported. Continuing.\n");
 
@@ -3824,6 +3841,7 @@ cleanup_QDIO(void)
        qdio_remove_procfs_entry();
        qdio_release_qdio_memory();
        qdio_unregister_dbf_views();
+       mempool_destroy(qdio_mempool_scssc);
 
        printk("qdio: %s: module removed\n",version);
 }