diff options
Diffstat (limited to 'drivers/s390/net/qeth_core_main.c')
-rw-r--r-- | drivers/s390/net/qeth_core_main.c | 269 |
1 files changed, 124 insertions, 145 deletions
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 88e998de2d03..bba1b54b8aa3 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -204,12 +204,17 @@ EXPORT_SYMBOL_GPL(qeth_threads_running); void qeth_clear_working_pool_list(struct qeth_card *card) { struct qeth_buffer_pool_entry *pool_entry, *tmp; + struct qeth_qdio_q *queue = card->qdio.in_q; + unsigned int i; QETH_CARD_TEXT(card, 5, "clwrklst"); list_for_each_entry_safe(pool_entry, tmp, &card->qdio.in_buf_pool.entry_list, list){ list_del(&pool_entry->list); } + + for (i = 0; i < ARRAY_SIZE(queue->bufs); i++) + queue->bufs[i].pool_entry = NULL; } EXPORT_SYMBOL_GPL(qeth_clear_working_pool_list); @@ -969,7 +974,7 @@ void qeth_clear_ipacmd_list(struct qeth_card *card) spin_lock_irqsave(&card->lock, flags); list_for_each_entry(iob, &card->cmd_waiter_list, list) - qeth_notify_cmd(iob, -EIO); + qeth_notify_cmd(iob, -ECANCELED); spin_unlock_irqrestore(&card->lock, flags); } EXPORT_SYMBOL_GPL(qeth_clear_ipacmd_list); @@ -1647,6 +1652,7 @@ static void qeth_setup_card(struct qeth_card *card) qeth_init_qdio_info(card); INIT_DELAYED_WORK(&card->buffer_reclaim_work, qeth_buffer_reclaim_work); INIT_WORK(&card->close_dev_work, qeth_close_dev_handler); + hash_init(card->rx_mode_addrs); hash_init(card->local_addrs4); hash_init(card->local_addrs6); spin_lock_init(&card->local_addrs4_lock); @@ -2025,7 +2031,7 @@ static bool qeth_mpc_match_reply(struct qeth_cmd_buffer *iob, } static struct qeth_cmd_buffer *qeth_mpc_alloc_cmd(struct qeth_card *card, - void *data, + const void *data, unsigned int data_length) { struct qeth_cmd_buffer *iob; @@ -2436,6 +2442,17 @@ static int qeth_cm_setup(struct qeth_card *card) return qeth_send_control_data(card, iob, qeth_cm_setup_cb, NULL); } +static bool qeth_is_supported_link_type(struct qeth_card *card, u8 link_type) +{ + if (link_type == QETH_LINK_TYPE_LANE_TR || + link_type == QETH_LINK_TYPE_HSTR) { + dev_err(&card->gdev->dev, "Unsupported Token Ring device\n"); + return false; + } + + return true; +} + static int qeth_update_max_mtu(struct qeth_card *card, unsigned int max_mtu) { struct net_device *dev = card->dev; @@ -2495,8 +2512,8 @@ static int qeth_ulp_enable_cb(struct qeth_card *card, struct qeth_reply *reply, { __u16 mtu, framesize; __u16 len; - __u8 link_type; struct qeth_cmd_buffer *iob; + u8 link_type = 0; QETH_CARD_TEXT(card, 2, "ulpenacb"); @@ -2516,9 +2533,11 @@ static int qeth_ulp_enable_cb(struct qeth_card *card, struct qeth_reply *reply, if (len >= QETH_MPC_DIFINFO_LEN_INDICATES_LINK_TYPE) { memcpy(&link_type, QETH_ULP_ENABLE_RESP_LINK_TYPE(iob->data), 1); - card->info.link_type = link_type; - } else - card->info.link_type = 0; + if (!qeth_is_supported_link_type(card, link_type)) + return -EPROTONOSUPPORT; + } + + card->info.link_type = link_type; QETH_CARD_TEXT_(card, 2, "link%d", card->info.link_type); return 0; } @@ -2951,7 +2970,7 @@ static struct qeth_buffer_pool_entry *qeth_find_free_buffer_pool_entry( static int qeth_init_input_buffer(struct qeth_card *card, struct qeth_qdio_buffer *buf) { - struct qeth_buffer_pool_entry *pool_entry; + struct qeth_buffer_pool_entry *pool_entry = buf->pool_entry; int i; if ((card->options.cq == QETH_CQ_ENABLED) && (!buf->rx_skb)) { @@ -2962,9 +2981,13 @@ static int qeth_init_input_buffer(struct qeth_card *card, return -ENOMEM; } - pool_entry = qeth_find_free_buffer_pool_entry(card); - if (!pool_entry) - return -ENOBUFS; + if (!pool_entry) { + pool_entry = qeth_find_free_buffer_pool_entry(card); + if (!pool_entry) + return -ENOBUFS; + + buf->pool_entry = pool_entry; + } /* * since the buffer is accessed only from the input_tasklet @@ -2972,8 +2995,6 @@ static int qeth_init_input_buffer(struct qeth_card *card, * the QETH_IN_BUF_REQUEUE_THRESHOLD we should never run out off * buffers */ - - buf->pool_entry = pool_entry; for (i = 0; i < QETH_MAX_BUFFER_ELEMENTS(card); ++i) { buf->buffer->element[i].length = PAGE_SIZE; buf->buffer->element[i].addr = @@ -3001,6 +3022,7 @@ static unsigned int qeth_tx_select_bulk_max(struct qeth_card *card, static int qeth_init_qdio_queues(struct qeth_card *card) { + unsigned int rx_bufs = card->qdio.in_buf_pool.buf_count; unsigned int i; int rc; @@ -3012,16 +3034,14 @@ static int qeth_init_qdio_queues(struct qeth_card *card) qeth_initialize_working_pool_list(card); /*give only as many buffers to hardware as we have buffer pool entries*/ - for (i = 0; i < card->qdio.in_buf_pool.buf_count - 1; i++) { + for (i = 0; i < rx_bufs; i++) { rc = qeth_init_input_buffer(card, &card->qdio.in_q->bufs[i]); if (rc) return rc; } - card->qdio.in_q->next_buf_to_init = - card->qdio.in_buf_pool.buf_count - 1; - rc = do_QDIO(CARD_DDEV(card), QDIO_FLAG_SYNC_INPUT, 0, 0, - card->qdio.in_buf_pool.buf_count - 1); + card->qdio.in_q->next_buf_to_init = QDIO_BUFNR(rx_bufs); + rc = do_QDIO(CARD_DDEV(card), QDIO_FLAG_SYNC_INPUT, 0, 0, rx_bufs); if (rc) { QETH_CARD_TEXT_(card, 2, "1err%d", rc); return rc; @@ -3100,7 +3120,6 @@ struct qeth_cmd_buffer *qeth_ipa_alloc_cmd(struct qeth_card *card, enum qeth_prot_versions prot, unsigned int data_length) { - enum qeth_link_types link_type = card->info.link_type; struct qeth_cmd_buffer *iob; struct qeth_ipacmd_hdr *hdr; @@ -3116,7 +3135,7 @@ struct qeth_cmd_buffer *qeth_ipa_alloc_cmd(struct qeth_card *card, hdr->command = cmd_code; hdr->initiator = IPA_CMD_INITIATOR_HOST; /* hdr->seqno is set by qeth_send_control_data() */ - hdr->adapter_type = (link_type == QETH_LINK_TYPE_HSTR) ? 2 : 1; + hdr->adapter_type = QETH_LINK_TYPE_FAST_ETH; hdr->rel_adapter_no = (u8) card->dev->dev_port; hdr->prim_version_no = IS_LAYER2(card) ? 2 : 1; hdr->param_count = 1; @@ -3199,18 +3218,22 @@ static int qeth_query_setadapterparms_cb(struct qeth_card *card, struct qeth_reply *reply, unsigned long data) { struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *) data; + struct qeth_query_cmds_supp *query_cmd; QETH_CARD_TEXT(card, 3, "quyadpcb"); if (qeth_setadpparms_inspect_rc(cmd)) return -EIO; - if (cmd->data.setadapterparms.data.query_cmds_supp.lan_type & 0x7f) { - card->info.link_type = - cmd->data.setadapterparms.data.query_cmds_supp.lan_type; + query_cmd = &cmd->data.setadapterparms.data.query_cmds_supp; + if (query_cmd->lan_type & 0x7f) { + if (!qeth_is_supported_link_type(card, query_cmd->lan_type)) + return -EPROTONOSUPPORT; + + card->info.link_type = query_cmd->lan_type; QETH_CARD_TEXT_(card, 2, "lnk %d", card->info.link_type); } - card->options.adp.supported = - cmd->data.setadapterparms.data.query_cmds_supp.supported_cmds; + + card->options.adp.supported = query_cmd->supported_cmds; return 0; } @@ -3468,20 +3491,15 @@ static int qeth_check_qdio_errors(struct qeth_card *card, return 0; } -static void qeth_queue_input_buffer(struct qeth_card *card, int index) +static unsigned int qeth_rx_refill_queue(struct qeth_card *card, + unsigned int count) { struct qeth_qdio_q *queue = card->qdio.in_q; struct list_head *lh; - int count; int i; int rc; int newcount = 0; - count = (index < queue->next_buf_to_init)? - card->qdio.in_buf_pool.buf_count - - (queue->next_buf_to_init - index) : - card->qdio.in_buf_pool.buf_count - - (queue->next_buf_to_init + QDIO_MAX_BUFFERS_PER_Q - index); /* only requeue at a certain threshold to avoid SIGAs */ if (count >= QETH_IN_BUF_REQUEUE_THRESHOLD(card)) { for (i = queue->next_buf_to_init; @@ -3509,21 +3527,13 @@ static void qeth_queue_input_buffer(struct qeth_card *card, int index) i++; if (i == card->qdio.in_buf_pool.buf_count) { QETH_CARD_TEXT(card, 2, "qsarbw"); - card->reclaim_index = index; schedule_delayed_work( &card->buffer_reclaim_work, QETH_RECLAIM_WORK_TIME); } - return; + return 0; } - /* - * according to old code it should be avoided to requeue all - * 128 buffers in order to benefit from PCI avoidance. - * this function keeps at least one buffer (the buffer at - * 'index') un-requeued -> this buffer is the first buffer that - * will be requeued the next time - */ rc = do_QDIO(CARD_DDEV(card), QDIO_FLAG_SYNC_INPUT, 0, queue->next_buf_to_init, count); if (rc) { @@ -3531,7 +3541,10 @@ static void qeth_queue_input_buffer(struct qeth_card *card, int index) } queue->next_buf_to_init = QDIO_BUFNR(queue->next_buf_to_init + count); + return count; } + + return 0; } static void qeth_buffer_reclaim_work(struct work_struct *work) @@ -3539,8 +3552,10 @@ static void qeth_buffer_reclaim_work(struct work_struct *work) struct qeth_card *card = container_of(work, struct qeth_card, buffer_reclaim_work.work); - QETH_CARD_TEXT_(card, 2, "brw:%x", card->reclaim_index); - qeth_queue_input_buffer(card, card->reclaim_index); + local_bh_disable(); + napi_schedule(&card->napi); + /* kick-start the NAPI softirq: */ + local_bh_enable(); } static void qeth_handle_send_error(struct qeth_card *card, @@ -4541,7 +4556,6 @@ static int qeth_setadpparms_set_access_ctrl_cb(struct qeth_card *card, { struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *) data; struct qeth_set_access_ctrl *access_ctrl_req; - int fallback = *(int *)reply->param; QETH_CARD_TEXT(card, 4, "setaccb"); @@ -4555,70 +4569,54 @@ static int qeth_setadpparms_set_access_ctrl_cb(struct qeth_card *card, cmd->data.setadapterparms.hdr.return_code); switch (qeth_setadpparms_inspect_rc(cmd)) { case SET_ACCESS_CTRL_RC_SUCCESS: - if (card->options.isolation == ISOLATION_MODE_NONE) { + if (access_ctrl_req->subcmd_code == ISOLATION_MODE_NONE) dev_info(&card->gdev->dev, "QDIO data connection isolation is deactivated\n"); - } else { + else dev_info(&card->gdev->dev, "QDIO data connection isolation is activated\n"); - } - break; + return 0; case SET_ACCESS_CTRL_RC_ALREADY_NOT_ISOLATED: QETH_DBF_MESSAGE(2, "QDIO data connection isolation on device %x already deactivated\n", CARD_DEVID(card)); - if (fallback) - card->options.isolation = card->options.prev_isolation; - break; + return 0; case SET_ACCESS_CTRL_RC_ALREADY_ISOLATED: QETH_DBF_MESSAGE(2, "QDIO data connection isolation on device %x already activated\n", CARD_DEVID(card)); - if (fallback) - card->options.isolation = card->options.prev_isolation; - break; + return 0; case SET_ACCESS_CTRL_RC_NOT_SUPPORTED: dev_err(&card->gdev->dev, "Adapter does not " "support QDIO data connection isolation\n"); - break; + return -EOPNOTSUPP; case SET_ACCESS_CTRL_RC_NONE_SHARED_ADAPTER: dev_err(&card->gdev->dev, "Adapter is dedicated. " "QDIO data connection isolation not supported\n"); - if (fallback) - card->options.isolation = card->options.prev_isolation; - break; + return -EOPNOTSUPP; case SET_ACCESS_CTRL_RC_ACTIVE_CHECKSUM_OFF: dev_err(&card->gdev->dev, "TSO does not permit QDIO data connection isolation\n"); - if (fallback) - card->options.isolation = card->options.prev_isolation; - break; + return -EPERM; case SET_ACCESS_CTRL_RC_REFLREL_UNSUPPORTED: dev_err(&card->gdev->dev, "The adjacent switch port does not " "support reflective relay mode\n"); - if (fallback) - card->options.isolation = card->options.prev_isolation; - break; + return -EOPNOTSUPP; case SET_ACCESS_CTRL_RC_REFLREL_FAILED: dev_err(&card->gdev->dev, "The reflective relay mode cannot be " "enabled at the adjacent switch port"); - if (fallback) - card->options.isolation = card->options.prev_isolation; - break; + return -EREMOTEIO; case SET_ACCESS_CTRL_RC_REFLREL_DEACT_FAILED: dev_warn(&card->gdev->dev, "Turning off reflective relay mode " "at the adjacent switch failed\n"); - break; + /* benign error while disabling ISOLATION_MODE_FWD */ + return 0; default: - /* this should never happen */ - if (fallback) - card->options.isolation = card->options.prev_isolation; - break; + return -EIO; } - return (cmd->hdr.return_code) ? -EIO : 0; } -static int qeth_setadpparms_set_access_ctrl(struct qeth_card *card, - enum qeth_ipa_isolation_modes isolation, int fallback) +int qeth_setadpparms_set_access_ctrl(struct qeth_card *card, + enum qeth_ipa_isolation_modes mode) { int rc; struct qeth_cmd_buffer *iob; @@ -4627,42 +4625,28 @@ static int qeth_setadpparms_set_access_ctrl(struct qeth_card *card, QETH_CARD_TEXT(card, 4, "setacctl"); + if (!qeth_adp_supported(card, IPA_SETADP_SET_ACCESS_CONTROL)) { + dev_err(&card->gdev->dev, + "Adapter does not support QDIO data connection isolation\n"); + return -EOPNOTSUPP; + } + iob = qeth_get_adapter_cmd(card, IPA_SETADP_SET_ACCESS_CONTROL, SETADP_DATA_SIZEOF(set_access_ctrl)); if (!iob) return -ENOMEM; cmd = __ipa_cmd(iob); access_ctrl_req = &cmd->data.setadapterparms.data.set_access_ctrl; - access_ctrl_req->subcmd_code = isolation; + access_ctrl_req->subcmd_code = mode; rc = qeth_send_ipa_cmd(card, iob, qeth_setadpparms_set_access_ctrl_cb, - &fallback); - QETH_CARD_TEXT_(card, 2, "rc=%d", rc); - return rc; -} - -int qeth_set_access_ctrl_online(struct qeth_card *card, int fallback) -{ - int rc = 0; - - QETH_CARD_TEXT(card, 4, "setactlo"); - - if ((IS_OSD(card) || IS_OSX(card)) && - qeth_adp_supported(card, IPA_SETADP_SET_ACCESS_CONTROL)) { - rc = qeth_setadpparms_set_access_ctrl(card, - card->options.isolation, fallback); - if (rc) { - QETH_DBF_MESSAGE(3, "IPA(SET_ACCESS_CTRL(%d) on device %x: sent failed\n", - rc, CARD_DEVID(card)); - rc = -EOPNOTSUPP; - } - } else if (card->options.isolation != ISOLATION_MODE_NONE) { - card->options.isolation = ISOLATION_MODE_NONE; - - dev_err(&card->gdev->dev, "Adapter does not " - "support QDIO data connection isolation\n"); - rc = -EOPNOTSUPP; + NULL); + if (rc) { + QETH_CARD_TEXT_(card, 2, "rc=%d", rc); + QETH_DBF_MESSAGE(3, "IPA(SET_ACCESS_CTRL(%d) on device %x: sent failed\n", + rc, CARD_DEVID(card)); } + return rc; } @@ -4850,26 +4834,24 @@ static int qeth_snmp_command(struct qeth_card *card, char __user *udata) } static int qeth_setadpparms_query_oat_cb(struct qeth_card *card, - struct qeth_reply *reply, unsigned long data) + struct qeth_reply *reply, + unsigned long data) { struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *)data; - struct qeth_qoat_priv *priv; - char *resdata; + struct qeth_qoat_priv *priv = reply->param; int resdatalen; QETH_CARD_TEXT(card, 3, "qoatcb"); if (qeth_setadpparms_inspect_rc(cmd)) return -EIO; - priv = (struct qeth_qoat_priv *)reply->param; resdatalen = cmd->data.setadapterparms.hdr.cmdlength; - resdata = (char *)data + 28; if (resdatalen > (priv->buffer_len - priv->response_len)) return -ENOSPC; - memcpy((priv->buffer + priv->response_len), resdata, - resdatalen); + memcpy(priv->buffer + priv->response_len, + &cmd->data.setadapterparms.hdr, resdatalen); priv->response_len += resdatalen; if (cmd->data.setadapterparms.hdr.seq_no < @@ -4890,24 +4872,17 @@ static int qeth_query_oat_command(struct qeth_card *card, char __user *udata) QETH_CARD_TEXT(card, 3, "qoatcmd"); - if (!qeth_adp_supported(card, IPA_SETADP_QUERY_OAT)) { - rc = -EOPNOTSUPP; - goto out; - } + if (!qeth_adp_supported(card, IPA_SETADP_QUERY_OAT)) + return -EOPNOTSUPP; - if (copy_from_user(&oat_data, udata, - sizeof(struct qeth_query_oat_data))) { - rc = -EFAULT; - goto out; - } + if (copy_from_user(&oat_data, udata, sizeof(oat_data))) + return -EFAULT; priv.buffer_len = oat_data.buffer_len; priv.response_len = 0; priv.buffer = vzalloc(oat_data.buffer_len); - if (!priv.buffer) { - rc = -ENOMEM; - goto out; - } + if (!priv.buffer) + return -ENOMEM; iob = qeth_get_adapter_cmd(card, IPA_SETADP_QUERY_OAT, SETADP_DATA_SIZEOF(query_oat)); @@ -4919,30 +4894,19 @@ static int qeth_query_oat_command(struct qeth_card *card, char __user *udata) oat_req = &cmd->data.setadapterparms.data.query_oat; oat_req->subcmd_code = oat_data.command; - rc = qeth_send_ipa_cmd(card, iob, qeth_setadpparms_query_oat_cb, - &priv); + rc = qeth_send_ipa_cmd(card, iob, qeth_setadpparms_query_oat_cb, &priv); if (!rc) { - if (is_compat_task()) - tmp = compat_ptr(oat_data.ptr); - else - tmp = (void __user *)(unsigned long)oat_data.ptr; - - if (copy_to_user(tmp, priv.buffer, - priv.response_len)) { - rc = -EFAULT; - goto out_free; - } - + tmp = is_compat_task() ? compat_ptr(oat_data.ptr) : + u64_to_user_ptr(oat_data.ptr); oat_data.response_len = priv.response_len; - if (copy_to_user(udata, &oat_data, - sizeof(struct qeth_query_oat_data))) + if (copy_to_user(tmp, priv.buffer, priv.response_len) || + copy_to_user(udata, &oat_data, sizeof(oat_data))) rc = -EFAULT; } out_free: vfree(priv.buffer); -out: return rc; } @@ -5331,9 +5295,12 @@ retriable: (card->info.hwtrap && qeth_hw_trap(card, QETH_DIAGS_TRAP_ARM))) card->info.hwtrap = 0; - rc = qeth_set_access_ctrl_online(card, 0); - if (rc) - goto out; + if (card->options.isolation != ISOLATION_MODE_NONE) { + rc = qeth_setadpparms_set_access_ctrl(card, + card->options.isolation); + if (rc) + goto out; + } rc = qeth_init_qdio_queues(card); if (rc) { @@ -5767,6 +5734,7 @@ static unsigned int qeth_extract_skbs(struct qeth_card *card, int budget, static unsigned int qeth_rx_poll(struct qeth_card *card, int budget) { + struct qeth_rx *ctx = &card->rx; unsigned int work_done = 0; while (budget > 0) { @@ -5802,8 +5770,11 @@ static unsigned int qeth_rx_poll(struct qeth_card *card, int budget) if (done) { QETH_CARD_STAT_INC(card, rx_bufs); qeth_put_buffer_pool_entry(card, buffer->pool_entry); - qeth_queue_input_buffer(card, card->rx.b_index); + buffer->pool_entry = NULL; card->rx.b_count--; + ctx->bufs_refill++; + ctx->bufs_refill -= qeth_rx_refill_queue(card, + ctx->bufs_refill); /* Step forward to next buffer: */ card->rx.b_index = QDIO_BUFNR(card->rx.b_index + 1); @@ -5843,9 +5814,16 @@ int qeth_poll(struct napi_struct *napi, int budget) if (card->options.cq == QETH_CQ_ENABLED) qeth_cq_poll(card); - /* Exhausted the RX budget. Keep IRQ disabled, we get called again. */ - if (budget && work_done >= budget) - return work_done; + if (budget) { + struct qeth_rx *ctx = &card->rx; + + /* Process any substantial refill backlog: */ + ctx->bufs_refill -= qeth_rx_refill_queue(card, ctx->bufs_refill); + + /* Exhausted the RX budget. Keep IRQ disabled, we get called again. */ + if (work_done >= budget) + return work_done; + } if (napi_complete_done(napi, work_done) && qdio_start_irq(CARD_DDEV(card))) @@ -6841,7 +6819,7 @@ netdev_features_t qeth_features_check(struct sk_buff *skb, /* Traffic with local next-hop is not eligible for some offloads: */ if (skb->ip_summed == CHECKSUM_PARTIAL && - card->options.isolation != ISOLATION_MODE_FWD) { + READ_ONCE(card->options.isolation) != ISOLATION_MODE_FWD) { netdev_features_t restricted = 0; if (skb_is_gso(skb) && !netif_needs_gso(skb, features)) @@ -7032,6 +7010,7 @@ int qeth_stop(struct net_device *dev) } napi_disable(&card->napi); + cancel_delayed_work_sync(&card->buffer_reclaim_work); qdio_stop_irq(CARD_DDEV(card)); return 0; |