module_param_named(aqmask, aqm_str, charp, 0440);
 MODULE_PARM_DESC(aqmask, "AP bus domain mask.");
 
+atomic_t ap_max_msg_size = ATOMIC_INIT(AP_DEFAULT_MAX_MSG_SIZE);
+EXPORT_SYMBOL(ap_max_msg_size);
+
 static struct device *ap_root_device;
 
 /* Hashtable of all queue devices on the AP bus */
  * Returns true if TAPQ succeeded and the info is filled or
  * false otherwise.
  */
-static bool ap_queue_info(ap_qid_t qid, int *q_type,
-                         unsigned int *q_fac, int *q_depth, bool *q_decfg)
+static bool ap_queue_info(ap_qid_t qid, int *q_type, unsigned int *q_fac,
+                         int *q_depth, int *q_ml, bool *q_decfg)
 {
        struct ap_queue_status status;
-       unsigned long info = 0;
+       union {
+               unsigned long value;
+               struct {
+                       unsigned int fac   : 32; /* facility bits */
+                       unsigned int at    :  8; /* ap type */
+                       unsigned int _res1 :  8;
+                       unsigned int _res2 :  4;
+                       unsigned int ml    :  4; /* apxl ml */
+                       unsigned int _res3 :  4;
+                       unsigned int qd    :  4; /* queue depth */
+               } tapq_gr2;
+       } tapq_info;
+
+       tapq_info.value = 0;
 
        /* make sure we don't run into a specifiation exception */
        if (AP_QID_CARD(qid) > ap_max_adapter_id ||
                return false;
 
        /* call TAPQ on this APQN */
-       status = ap_test_queue(qid, ap_apft_available(), &info);
+       status = ap_test_queue(qid, ap_apft_available(), &tapq_info.value);
        switch (status.response_code) {
        case AP_RESPONSE_NORMAL:
        case AP_RESPONSE_RESET_IN_PROGRESS:
                 * info should be filled. All bits 0 is not possible as
                 * there is at least one of the mode bits set.
                 */
-               if (WARN_ON_ONCE(!info))
+               if (WARN_ON_ONCE(!tapq_info.value))
                        return false;
-               *q_type = (int)((info >> 24) & 0xff);
-               *q_fac = (unsigned int)(info >> 32);
-               *q_depth = (int)(info & 0xff);
+               *q_type = tapq_info.tapq_gr2.at;
+               *q_fac = tapq_info.tapq_gr2.fac;
+               *q_depth = tapq_info.tapq_gr2.qd;
+               *q_ml = tapq_info.tapq_gr2.ml;
                *q_decfg = status.response_code == AP_RESPONSE_DECONFIGURED;
                switch (*q_type) {
                        /* For CEX2 and CEX3 the available functions
        unsigned int func;
        struct device *dev;
        struct ap_queue *aq;
-       int rc, dom, depth, type;
+       int rc, dom, depth, type, ml;
 
        /*
         * Go through the configuration for the domains and compare them
                        continue;
                }
                /* domain is valid, get info from this APQN */
-               if (!ap_queue_info(qid, &type, &func, &depth, &decfg)) {
+               if (!ap_queue_info(qid, &type, &func, &depth, &ml, &decfg)) {
                        if (aq) {
                                AP_DBF_INFO(
                                        "%s(%d,%d) ap_queue_info() not successful, rm queue device\n",
        unsigned int func;
        struct device *dev;
        struct ap_card *ac;
-       int rc, dom, depth, type, comp_type;
+       int rc, dom, depth, type, comp_type, ml;
 
        /* Is there currently a card device for this adapter ? */
        dev = bus_find_device(&ap_bus_type, NULL,
        for (dom = 0; dom <= ap_max_domain_id; dom++)
                if (ap_test_config_usage_domain(dom)) {
                        qid = AP_MKQID(ap, dom);
-                       if (ap_queue_info(qid, &type, &func, &depth, &decfg))
+                       if (ap_queue_info(qid, &type, &func,
+                                         &depth, &ml, &decfg))
                                break;
                }
        if (dom > ap_max_domain_id) {
                                    __func__, ap, type);
                        return;
                }
-               ac = ap_card_create(ap, depth, type, comp_type, func);
+               ac = ap_card_create(ap, depth, type, comp_type, func, ml);
                if (!ac) {
                        AP_DBF_WARN("%s(%d) ap_card_create() failed\n",
                                    __func__, ap);
                dev->bus = &ap_bus_type;
                dev->parent = ap_root_device;
                dev_set_name(dev, "card%02x", ap);
+               /* maybe enlarge ap_max_msg_size to support this card */
+               if (ac->maxmsgsize > atomic_read(&ap_max_msg_size)) {
+                       atomic_set(&ap_max_msg_size, ac->maxmsgsize);
+                       AP_DBF_INFO("%s(%d) ap_max_msg_size update to %d byte\n",
+                                   __func__, ap, atomic_read(&ap_max_msg_size));
+               }
                /* Register the new card device with AP bus */
                rc = device_register(dev);
                if (rc) {
 
 #define AP_RESET_TIMEOUT (HZ*0.7)      /* Time in ticks for reset timeouts. */
 #define AP_CONFIG_TIME 30      /* Time in seconds between AP bus rescans. */
 #define AP_POLL_TIME 1         /* Time in ticks between receive polls. */
+#define AP_DEFAULT_MAX_MSG_SIZE (12 * 1024)
+#define AP_TAPQ_ML_FIELD_CHUNK_SIZE (4096)
 
 extern int ap_domain_index;
+extern atomic_t ap_max_msg_size;
 
 extern DECLARE_HASHTABLE(ap_queues, 8);
 extern spinlock_t ap_queues_lock;
        unsigned int functions;         /* AP device function bitfield. */
        int queue_depth;                /* AP queue depth.*/
        int id;                         /* AP card number. */
+       unsigned int maxmsgsize;        /* AP msg limit for this card */
        bool config;                    /* configured state */
        atomic64_t total_request_count; /* # requests ever for this AP device.*/
 };
        struct list_head list;          /* Request queueing. */
        unsigned long long psmid;       /* Message id. */
        void *msg;                      /* Pointer to message buffer. */
-       unsigned int len;               /* Message length. */
+       unsigned int len;               /* actual msg len in msg buffer */
+       unsigned int bufsize;           /* allocated msg buffer size */
        u16 flags;                      /* Flags, see AP_MSG_FLAG_xxx */
        struct ap_fi fi;                /* Failure Injection cmd */
        int rc;                         /* Return code for this message */
 void ap_queue_remove(struct ap_queue *aq);
 void ap_queue_init_state(struct ap_queue *aq);
 
-struct ap_card *ap_card_create(int id, int queue_depth, int raw_device_type,
-                              int comp_device_type, unsigned int functions);
+struct ap_card *ap_card_create(int id, int queue_depth, int raw_type,
+                              int comp_type, unsigned int functions, int ml);
 
 struct ap_perms {
        unsigned long ioctlm[BITS_TO_LONGS(AP_IOCTLS)];
 
 
 static DEVICE_ATTR_RW(config);
 
+static ssize_t max_msg_size_show(struct device *dev,
+                                struct device_attribute *attr, char *buf)
+{
+       struct ap_card *ac = to_ap_card(dev);
+
+       return scnprintf(buf, PAGE_SIZE, "%u\n", ac->maxmsgsize);
+}
+
+static DEVICE_ATTR_RO(max_msg_size);
+
 static struct attribute *ap_card_dev_attrs[] = {
        &dev_attr_hwtype.attr,
        &dev_attr_raw_hwtype.attr,
        &dev_attr_pendingq_count.attr,
        &dev_attr_modalias.attr,
        &dev_attr_config.attr,
+       &dev_attr_max_msg_size.attr,
        NULL
 };
 
 }
 
 struct ap_card *ap_card_create(int id, int queue_depth, int raw_type,
-                              int comp_type, unsigned int functions)
+                              int comp_type, unsigned int functions, int ml)
 {
        struct ap_card *ac;
 
        ac->queue_depth = queue_depth;
        ac->functions = functions;
        ac->id = id;
+       ac->maxmsgsize = ml > 0 ?
+               ml * AP_TAPQ_ML_FIELD_CHUNK_SIZE : AP_DEFAULT_MAX_MSG_SIZE;
+
        return ac;
 }
 
        bool found = false;
 
        status = ap_dqap(aq->qid, &aq->reply->psmid,
-                        aq->reply->msg, aq->reply->len);
+                        aq->reply->msg, aq->reply->bufsize);
        switch (status.response_code) {
        case AP_RESPONSE_NORMAL:
                aq->queue_count = max_t(int, 0, aq->queue_count - 1);
 
                if (xcRB->user_defined != AUTOSELECT &&
                    xcRB->user_defined != zc->card->id)
                        continue;
+               /* check if request size exceeds card max msg size */
+               if (ap_msg.len > zc->card->maxmsgsize)
+                       continue;
                /* check if device node has admission for this card */
                if (!zcrypt_check_card(perms, zc->card->id))
                        continue;
                if (targets &&
                    !is_desired_ep11_card(zc->card->id, target_num, targets))
                        continue;
+               /* check if request size exceeds card max msg size */
+               if (ap_msg.len > zc->card->maxmsgsize)
+                       continue;
                /* check if device node has admission for this card */
                if (!zcrypt_check_card(perms, zc->card->id))
                        continue;
 
 #define CEX4C_MIN_MOD_SIZE      16     /*  256 bits    */
 #define CEX4C_MAX_MOD_SIZE     512     /* 4096 bits    */
 
-#define CEX4A_MAX_MESSAGE_SIZE MSGTYPE50_CRB3_MAX_MSG_SIZE
-#define CEX4C_MAX_MESSAGE_SIZE MSGTYPE06_MAX_MSG_SIZE
-
 /* Waiting time for requests to be processed.
  * Currently there are some types of request which are not deterministic.
  * But the maximum time limit managed by the stomper code is set to 60sec.
        int rc;
 
        if (ap_test_bit(&aq->card->functions, AP_FUNC_ACCEL)) {
-               zq = zcrypt_queue_alloc(CEX4A_MAX_MESSAGE_SIZE);
+               zq = zcrypt_queue_alloc(aq->card->maxmsgsize);
                if (!zq)
                        return -ENOMEM;
                zq->ops = zcrypt_msgtype(MSGTYPE50_NAME,
                                         MSGTYPE50_VARIANT_DEFAULT);
        } else if (ap_test_bit(&aq->card->functions, AP_FUNC_COPRO)) {
-               zq = zcrypt_queue_alloc(CEX4C_MAX_MESSAGE_SIZE);
+               zq = zcrypt_queue_alloc(aq->card->maxmsgsize);
                if (!zq)
                        return -ENOMEM;
                zq->ops = zcrypt_msgtype(MSGTYPE06_NAME,
                                         MSGTYPE06_VARIANT_DEFAULT);
        } else if (ap_test_bit(&aq->card->functions, AP_FUNC_EP11)) {
-               zq = zcrypt_queue_alloc(CEX4C_MAX_MESSAGE_SIZE);
+               zq = zcrypt_queue_alloc(aq->card->maxmsgsize);
                if (!zq)
                        return -ENOMEM;
                zq->ops = zcrypt_msgtype(MSGTYPE06_NAME,
 
                goto out;       /* ap_msg->rc indicates the error */
        t80h = reply->msg;
        if (t80h->type == TYPE80_RSP_CODE) {
-               if (aq->ap_dev.device_type == AP_DEVICE_TYPE_CEX2A)
-                       len = min_t(int, CEX2A_MAX_RESPONSE_SIZE, t80h->len);
-               else
-                       len = min_t(int, CEX3A_MAX_RESPONSE_SIZE, t80h->len);
-               memcpy(msg->msg, reply->msg, len);
+               len = t80h->len;
+               if (len > reply->bufsize || len > msg->bufsize) {
+                       msg->rc = -EMSGSIZE;
+               } else {
+                       memcpy(msg->msg, reply->msg, len);
+                       msg->len = len;
+               }
        } else
                memcpy(msg->msg, reply->msg, sizeof(error_reply));
 out:
        struct completion work;
        int rc;
 
-       if (zq->zcard->user_space_type == ZCRYPT_CEX2A)
-               ap_msg->msg = kmalloc(MSGTYPE50_CRB2_MAX_MSG_SIZE, GFP_KERNEL);
-       else
-               ap_msg->msg = kmalloc(MSGTYPE50_CRB3_MAX_MSG_SIZE, GFP_KERNEL);
+       ap_msg->bufsize = (zq->zcard->user_space_type == ZCRYPT_CEX2A) ?
+               MSGTYPE50_CRB2_MAX_MSG_SIZE : MSGTYPE50_CRB3_MAX_MSG_SIZE;
+       ap_msg->msg = kmalloc(ap_msg->bufsize, GFP_KERNEL);
        if (!ap_msg->msg)
                return -ENOMEM;
        ap_msg->receive = zcrypt_cex2a_receive;
        struct completion work;
        int rc;
 
-       if (zq->zcard->user_space_type == ZCRYPT_CEX2A)
-               ap_msg->msg = kmalloc(MSGTYPE50_CRB2_MAX_MSG_SIZE, GFP_KERNEL);
-       else
-               ap_msg->msg = kmalloc(MSGTYPE50_CRB3_MAX_MSG_SIZE, GFP_KERNEL);
+       ap_msg->bufsize = (zq->zcard->user_space_type == ZCRYPT_CEX2A) ?
+               MSGTYPE50_CRB2_MAX_MSG_SIZE : MSGTYPE50_CRB3_MAX_MSG_SIZE;
+       ap_msg->msg = kmalloc(ap_msg->bufsize, GFP_KERNEL);
        if (!ap_msg->msg)
                return -ENOMEM;
        ap_msg->receive = zcrypt_cex2a_receive;
 
        } __packed * msg = ap_msg->msg;
 
        int rcblen = CEIL4(xcRB->request_control_blk_length);
-       int replylen, req_sumlen, resp_sumlen;
+       int req_sumlen, resp_sumlen;
        char *req_data = ap_msg->msg + sizeof(struct type6_hdr) + rcblen;
        char *function_code;
 
        ap_msg->len = sizeof(struct type6_hdr) +
                CEIL4(xcRB->request_control_blk_length) +
                xcRB->request_data_length;
-       if (ap_msg->len > MSGTYPE06_MAX_MSG_SIZE)
+       if (ap_msg->len > ap_msg->bufsize)
                return -EINVAL;
 
        /*
                        xcRB->reply_control_blk_length)
                return -EINVAL; /* overflow after alignment*/
 
-       replylen = sizeof(struct type86_fmt2_msg) +
-               CEIL4(xcRB->reply_control_blk_length) +
-               xcRB->reply_data_length;
-       if (replylen > MSGTYPE06_MAX_MSG_SIZE)
-               return -EINVAL;
-
        /*
         * Overflow check
         * sum must be greater (or equal) than the largest operand
                return -EINVAL; /* overflow after alignment*/
 
        /* length checks */
-       ap_msg->len = sizeof(struct type6_hdr) + xcRB->req_len;
-       if (CEIL4(xcRB->req_len) > MSGTYPE06_MAX_MSG_SIZE -
-                                  (sizeof(struct type6_hdr)))
+       ap_msg->len = sizeof(struct type6_hdr) + CEIL4(xcRB->req_len);
+       if (ap_msg->len > ap_msg->bufsize)
                return -EINVAL;
 
        if (CEIL4(xcRB->resp_len) < xcRB->resp_len)
                return -EINVAL; /* overflow after alignment*/
 
-       if (CEIL4(xcRB->resp_len) > MSGTYPE06_MAX_MSG_SIZE -
-                                   (sizeof(struct type86_fmt2_msg)))
-               return -EINVAL;
-
        /* prepare type6 header */
        msg->hdr = static_type6_ep11_hdr;
        msg->hdr.ToCardLen1   = xcRB->req_len;
                switch (resp_type->type) {
                case CEXXC_RESPONSE_TYPE_ICA:
                        len = sizeof(struct type86x_reply) + t86r->length - 2;
-                       len = min_t(int, CEXXC_MAX_ICA_RESPONSE_SIZE, len);
-                       memcpy(msg->msg, reply->msg, len);
+                       if (len > reply->bufsize || len > msg->bufsize) {
+                               msg->rc = -EMSGSIZE;
+                       } else {
+                               memcpy(msg->msg, reply->msg, len);
+                               msg->len = len;
+                       }
                        break;
                case CEXXC_RESPONSE_TYPE_XCRB:
                        len = t86r->fmt2.offset2 + t86r->fmt2.count2;
-                       len = min_t(int, MSGTYPE06_MAX_MSG_SIZE, len);
-                       memcpy(msg->msg, reply->msg, len);
+                       if (len > reply->bufsize || len > msg->bufsize) {
+                               msg->rc = -EMSGSIZE;
+                       } else {
+                               memcpy(msg->msg, reply->msg, len);
+                               msg->len = len;
+                       }
                        break;
                default:
                        memcpy(msg->msg, &error_reply, sizeof(error_reply));
                switch (resp_type->type) {
                case CEXXC_RESPONSE_TYPE_EP11:
                        len = t86r->fmt2.offset1 + t86r->fmt2.count1;
-                       len = min_t(int, MSGTYPE06_MAX_MSG_SIZE, len);
-                       memcpy(msg->msg, reply->msg, len);
+                       if (len > reply->bufsize || len > msg->bufsize) {
+                               msg->rc = -EMSGSIZE;
+                       } else {
+                               memcpy(msg->msg, reply->msg, len);
+                               msg->len = len;
+                       }
                        break;
                default:
                        memcpy(msg->msg, &error_reply, sizeof(error_reply));
        ap_msg->msg = (void *) get_zeroed_page(GFP_KERNEL);
        if (!ap_msg->msg)
                return -ENOMEM;
+       ap_msg->bufsize = PAGE_SIZE;
        ap_msg->receive = zcrypt_msgtype6_receive;
        ap_msg->psmid = (((unsigned long long) current->pid) << 32) +
                atomic_inc_return(&zcrypt_step);
        ap_msg->msg = (void *) get_zeroed_page(GFP_KERNEL);
        if (!ap_msg->msg)
                return -ENOMEM;
+       ap_msg->bufsize = PAGE_SIZE;
        ap_msg->receive = zcrypt_msgtype6_receive;
        ap_msg->psmid = (((unsigned long long) current->pid) << 32) +
                atomic_inc_return(&zcrypt_step);
                .type = CEXXC_RESPONSE_TYPE_XCRB,
        };
 
-       ap_msg->msg = kmalloc(MSGTYPE06_MAX_MSG_SIZE, GFP_KERNEL);
+       ap_msg->bufsize = atomic_read(&ap_max_msg_size);
+       ap_msg->msg = kmalloc(ap_msg->bufsize, GFP_KERNEL);
        if (!ap_msg->msg)
                return -ENOMEM;
        ap_msg->receive = zcrypt_msgtype6_receive;
                .type = CEXXC_RESPONSE_TYPE_EP11,
        };
 
-       ap_msg->msg = kmalloc(MSGTYPE06_MAX_MSG_SIZE, GFP_KERNEL);
+       ap_msg->bufsize = atomic_read(&ap_max_msg_size);
+       ap_msg->msg = kmalloc(ap_msg->bufsize, GFP_KERNEL);
        if (!ap_msg->msg)
                return -ENOMEM;
        ap_msg->receive = zcrypt_msgtype6_receive_ep11;
                .type = CEXXC_RESPONSE_TYPE_XCRB,
        };
 
-       ap_msg->msg = kmalloc(MSGTYPE06_MAX_MSG_SIZE, GFP_KERNEL);
+       ap_msg->bufsize = AP_DEFAULT_MAX_MSG_SIZE;
+       ap_msg->msg = kmalloc(ap_msg->bufsize, GFP_KERNEL);
        if (!ap_msg->msg)
                return -ENOMEM;
        ap_msg->receive = zcrypt_msgtype6_receive;
 
 #define MSGTYPE06_VARIANT_NORNG                1
 #define MSGTYPE06_VARIANT_EP11         2
 
-#define MSGTYPE06_MAX_MSG_SIZE         (12*1024)
-
 /**
  * The type 6 message family is associated with CEXxC/CEXxP cards.
  *
 
        return false;
 }
 
-struct zcrypt_queue *zcrypt_queue_alloc(size_t max_response_size)
+struct zcrypt_queue *zcrypt_queue_alloc(size_t reply_buf_size)
 {
        struct zcrypt_queue *zq;
 
        zq = kzalloc(sizeof(struct zcrypt_queue), GFP_KERNEL);
        if (!zq)
                return NULL;
-       zq->reply.msg = kmalloc(max_response_size, GFP_KERNEL);
+       zq->reply.msg = kmalloc(reply_buf_size, GFP_KERNEL);
        if (!zq->reply.msg)
                goto out_free;
-       zq->reply.len = max_response_size;
+       zq->reply.bufsize = reply_buf_size;
        INIT_LIST_HEAD(&zq->list);
        kref_init(&zq->refcount);
        return zq;