struct qeth_ipa_cmd *cmd);
 static void qeth_l2_vnicc_set_defaults(struct qeth_card *card);
 static void qeth_l2_vnicc_init(struct qeth_card *card);
+static bool qeth_l2_vnicc_recover_timeout(struct qeth_card *card, u32 vnicc,
+                                         u32 *timeout);
 
 static int qeth_l2_verify_dev(struct net_device *dev)
 {
        u32 sub_cmd;
        struct {
                u32 vnic_char;
+               u32 timeout;
        } param;
        struct {
-               u32 *sup_cmds;
+               union{
+                       u32 *sup_cmds;
+                       u32 *timeout;
+               };
        } result;
 };
 
        if (cbctl->sub_cmd == IPA_VNICC_QUERY_CMDS)
                *cbctl->result.sup_cmds = rep->query_cmds.sup_cmds;
 
+       if (cbctl->sub_cmd == IPA_VNICC_GET_TIMEOUT)
+               *cbctl->result.timeout = rep->getset_timeout.timeout;
+
        return 0;
 }
 
                req->sub_hdr.data_length += sizeof(req->set_char);
                req->set_char.vnic_char = cbctl->param.vnic_char;
                break;
+       case IPA_VNICC_SET_TIMEOUT:
+               req->getset_timeout.timeout = cbctl->param.timeout;
+               /* fallthrough */
+       case IPA_VNICC_GET_TIMEOUT:
+               req->sub_hdr.data_length += sizeof(req->getset_timeout);
+               req->getset_timeout.vnic_char = cbctl->param.vnic_char;
+               break;
        default:
                qeth_release_buffer(iob->channel, iob);
                return -EOPNOTSUPP;
        return qeth_l2_vnicc_request(card, &cbctl);
 }
 
+/* VNICC get/set timeout for characteristic request */
+static int qeth_l2_vnicc_getset_timeout(struct qeth_card *card, u32 vnicc,
+                                       u32 cmd, u32 *timeout)
+{
+       struct _qeth_l2_vnicc_request_cbctl cbctl;
+
+       /* prepare callback control */
+       cbctl.sub_cmd = cmd;
+       cbctl.param.vnic_char = vnicc;
+       if (cmd == IPA_VNICC_SET_TIMEOUT)
+               cbctl.param.timeout = *timeout;
+       if (cmd == IPA_VNICC_GET_TIMEOUT)
+               cbctl.result.timeout = timeout;
+
+       QETH_CARD_TEXT(card, 2, "vniccgst");
+       return qeth_l2_vnicc_request(card, &cbctl);
+}
+
 /* set current VNICC flag state; called from sysfs store function */
 int qeth_l2_vnicc_set_state(struct qeth_card *card, u32 vnicc, bool state)
 {
        if (rc)
                card->options.vnicc.wanted_chars =
                        card->options.vnicc.cur_chars;
-       else if (state && vnicc == QETH_VNICC_RX_BCAST)
-               card->options.vnicc.rx_bcast_enabled = true;
+       else {
+               /* successful online VNICC change; handle special cases */
+               if (state && vnicc == QETH_VNICC_RX_BCAST)
+                       card->options.vnicc.rx_bcast_enabled = true;
+               if (!state && vnicc == QETH_VNICC_LEARNING)
+                       qeth_l2_vnicc_recover_timeout(card, vnicc,
+                                       &card->options.vnicc.learning_timeout);
+       }
 
        return rc;
 }
        return rc;
 }
 
+/* set VNICC timeout; called from sysfs store function. Currently, only learning
+ * supports timeout
+ */
+int qeth_l2_vnicc_set_timeout(struct qeth_card *card, u32 timeout)
+{
+       int rc = 0;
+
+       QETH_CARD_TEXT(card, 2, "vniccsto");
+
+       /* do not change anything if BridgePort is enabled */
+       if (qeth_bridgeport_is_in_use(card))
+               return -EBUSY;
+
+       /* check if characteristic and set_timeout are supported */
+       if (!(card->options.vnicc.sup_chars & QETH_VNICC_LEARNING) ||
+           !(card->options.vnicc.getset_timeout_sup & QETH_VNICC_LEARNING))
+               return -EOPNOTSUPP;
+
+       /* do we need to do anything? */
+       if (card->options.vnicc.learning_timeout == timeout)
+               return rc;
+
+       /* if card is not ready, simply store the value internally and return */
+       if (!qeth_card_hw_is_reachable(card)) {
+               card->options.vnicc.learning_timeout = timeout;
+               return rc;
+       }
+
+       /* send timeout value to card; if successful, store value internally */
+       rc = qeth_l2_vnicc_getset_timeout(card, QETH_VNICC_LEARNING,
+                                         IPA_VNICC_SET_TIMEOUT, &timeout);
+       if (!rc)
+               card->options.vnicc.learning_timeout = timeout;
+
+       return rc;
+}
+
+/* get current VNICC timeout; called from sysfs show function. Currently, only
+ * learning supports timeout
+ */
+int qeth_l2_vnicc_get_timeout(struct qeth_card *card, u32 *timeout)
+{
+       int rc = 0;
+
+       QETH_CARD_TEXT(card, 2, "vniccgto");
+
+       /* do not get anything if BridgePort is enabled */
+       if (qeth_bridgeport_is_in_use(card))
+               return -EBUSY;
+
+       /* check if characteristic and get_timeout are supported */
+       if (!(card->options.vnicc.sup_chars & QETH_VNICC_LEARNING) ||
+           !(card->options.vnicc.getset_timeout_sup & QETH_VNICC_LEARNING))
+               return -EOPNOTSUPP;
+       /* if card is ready, get timeout. Otherwise, just return stored value */
+       *timeout = card->options.vnicc.learning_timeout;
+       if (qeth_card_hw_is_reachable(card))
+               rc = qeth_l2_vnicc_getset_timeout(card, QETH_VNICC_LEARNING,
+                                                 IPA_VNICC_GET_TIMEOUT,
+                                                 timeout);
+
+       return rc;
+}
+
 /* check if VNICC is currently enabled */
 bool qeth_l2_vnicc_is_in_use(struct qeth_card *card)
 {
        return true;
 }
 
+/* recover user timeout setting */
+static bool qeth_l2_vnicc_recover_timeout(struct qeth_card *card, u32 vnicc,
+                                         u32 *timeout)
+{
+       if (card->options.vnicc.sup_chars & vnicc &&
+           card->options.vnicc.getset_timeout_sup & vnicc &&
+           !qeth_l2_vnicc_getset_timeout(card, vnicc, IPA_VNICC_SET_TIMEOUT,
+                                         timeout))
+               return false;
+       *timeout = QETH_VNICC_DEFAULT_TIMEOUT;
+       return true;
+}
+
 /* recover user characteristic setting */
 static bool qeth_l2_vnicc_recover_char(struct qeth_card *card, u32 vnicc,
                                       bool enable)
 /* (re-)initialize VNICC */
 static void qeth_l2_vnicc_init(struct qeth_card *card)
 {
+       u32 *timeout = &card->options.vnicc.learning_timeout;
        unsigned int chars_len, i;
        unsigned long chars_tmp;
        u32 sup_cmds, vnicc;
        card->options.vnicc.rx_bcast_enabled = 0;
        /* initial query and storage of VNIC characteristics */
        if (qeth_l2_vnicc_query_chars(card)) {
-               if (card->options.vnicc.wanted_chars != QETH_VNICC_DEFAULT)
+               if (card->options.vnicc.wanted_chars != QETH_VNICC_DEFAULT ||
+                   *timeout != QETH_VNICC_DEFAULT_TIMEOUT)
                        dev_err(&card->gdev->dev, "Configuring the VNIC characteristics failed\n");
                /* fail quietly if user didn't change the default config */
                card->options.vnicc.sup_chars = 0;
        for_each_set_bit(i, &chars_tmp, chars_len) {
                vnicc = BIT(i);
                qeth_l2_vnicc_query_cmds(card, vnicc, &sup_cmds);
+               if (!(sup_cmds & IPA_VNICC_SET_TIMEOUT) ||
+                   !(sup_cmds & IPA_VNICC_GET_TIMEOUT))
+                       card->options.vnicc.getset_timeout_sup &= ~vnicc;
                if (!(sup_cmds & IPA_VNICC_ENABLE) ||
                    !(sup_cmds & IPA_VNICC_DISABLE))
                        card->options.vnicc.set_char_sup &= ~vnicc;
        }
        /* enforce assumed default values and recover settings, if changed  */
-       error = false;
+       error = qeth_l2_vnicc_recover_timeout(card, QETH_VNICC_LEARNING,
+                                             timeout);
        chars_tmp = card->options.vnicc.wanted_chars ^ QETH_VNICC_DEFAULT;
        chars_tmp |= QETH_VNICC_BRIDGE_INVISIBLE;
        chars_len = sizeof(card->options.vnicc.wanted_chars) * BITS_PER_BYTE;
        /* characteristics values */
        card->options.vnicc.sup_chars = QETH_VNICC_ALL;
        card->options.vnicc.cur_chars = QETH_VNICC_DEFAULT;
+       card->options.vnicc.learning_timeout = QETH_VNICC_DEFAULT_TIMEOUT;
        /* supported commands */
        card->options.vnicc.set_char_sup = QETH_VNICC_ALL;
+       card->options.vnicc.getset_timeout_sup = QETH_VNICC_LEARNING;
        /* settings wanted by users */
        card->options.vnicc.wanted_chars = QETH_VNICC_DEFAULT;
 }
 
        return 0;
 }
 
+/* get current timeout setting */
+static ssize_t qeth_vnicc_timeout_show(struct device *dev,
+                                      struct device_attribute *attr, char *buf)
+{
+       struct qeth_card *card = dev_get_drvdata(dev);
+       u32 timeout;
+       int rc;
+
+       if (!card)
+               return -EINVAL;
+
+       rc = qeth_l2_vnicc_get_timeout(card, &timeout);
+       if (rc == -EBUSY)
+               return sprintf(buf, "n/a (BridgePort)\n");
+       if (rc == -EOPNOTSUPP)
+               return sprintf(buf, "n/a\n");
+       return rc ? rc : sprintf(buf, "%d\n", timeout);
+}
+
+/* change timeout setting */
+static ssize_t qeth_vnicc_timeout_store(struct device *dev,
+                                       struct device_attribute *attr,
+                                       const char *buf, size_t count)
+{
+       struct qeth_card *card = dev_get_drvdata(dev);
+       u32 timeout;
+       int rc;
+
+       if (!card)
+               return -EINVAL;
+
+       rc = kstrtou32(buf, 10, &timeout);
+       if (rc)
+               return rc;
+
+       mutex_lock(&card->conf_mutex);
+       rc = qeth_l2_vnicc_set_timeout(card, timeout);
+       mutex_unlock(&card->conf_mutex);
+       return rc ? rc : count;
+}
+
 /* get current setting of characteristic */
 static ssize_t qeth_vnicc_char_show(struct device *dev,
                                    struct device_attribute *attr, char *buf)
 static DEVICE_ATTR(mcast_flooding, 0644, qeth_vnicc_char_show,
                   qeth_vnicc_char_store);
 static DEVICE_ATTR(learning, 0644, qeth_vnicc_char_show, qeth_vnicc_char_store);
+static DEVICE_ATTR(learning_timeout, 0644, qeth_vnicc_timeout_show,
+                  qeth_vnicc_timeout_store);
 static DEVICE_ATTR(takeover_setvmac, 0644, qeth_vnicc_char_show,
                   qeth_vnicc_char_store);
 static DEVICE_ATTR(takeover_learning, 0644, qeth_vnicc_char_show,
        &dev_attr_flooding.attr,
        &dev_attr_mcast_flooding.attr,
        &dev_attr_learning.attr,
+       &dev_attr_learning_timeout.attr,
        &dev_attr_takeover_setvmac.attr,
        &dev_attr_takeover_learning.attr,
        &dev_attr_bridge_invisible.attr,