diff options
Diffstat (limited to 'drivers/s390/net/qeth_core_main.c')
| -rw-r--r-- | drivers/s390/net/qeth_core_main.c | 166 |
1 files changed, 97 insertions, 69 deletions
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 8bd9fd51208c..1c80e8ca67b5 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -7,10 +7,9 @@ * Frank Blaschka <frank.blaschka@de.ibm.com> */ -#define KMSG_COMPONENT "qeth" -#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt +#define pr_fmt(fmt) "qeth: " fmt -#include <linux/compat.h> +#include <linux/export.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/string.h> @@ -364,30 +363,33 @@ out: return rc; } +static void qeth_free_cq(struct qeth_card *card) +{ + if (card->qdio.c_q) { + qeth_free_qdio_queue(card->qdio.c_q); + card->qdio.c_q = NULL; + } +} + static int qeth_alloc_cq(struct qeth_card *card) { if (card->options.cq == QETH_CQ_ENABLED) { QETH_CARD_TEXT(card, 2, "cqon"); - card->qdio.c_q = qeth_alloc_qdio_queue(); if (!card->qdio.c_q) { - dev_err(&card->gdev->dev, "Failed to create completion queue\n"); - return -ENOMEM; + card->qdio.c_q = qeth_alloc_qdio_queue(); + if (!card->qdio.c_q) { + dev_err(&card->gdev->dev, + "Failed to create completion queue\n"); + return -ENOMEM; + } } } else { QETH_CARD_TEXT(card, 2, "nocq"); - card->qdio.c_q = NULL; + qeth_free_cq(card); } return 0; } -static void qeth_free_cq(struct qeth_card *card) -{ - if (card->qdio.c_q) { - qeth_free_qdio_queue(card->qdio.c_q); - card->qdio.c_q = NULL; - } -} - static enum iucv_tx_notify qeth_compute_cq_notification(int sbalf15, int delayed) { @@ -426,7 +428,7 @@ static void qeth_setup_ccw(struct ccw1 *ccw, u8 cmd_code, u8 flags, u32 len, ccw->cmd_code = cmd_code; ccw->flags = flags | CCW_FLAG_SLI; ccw->count = len; - ccw->cda = (__u32)virt_to_phys(data); + ccw->cda = virt_to_dma32(data); } static int __qeth_issue_next_read(struct qeth_card *card) @@ -757,7 +759,7 @@ static void qeth_issue_ipa_msg(struct qeth_ipa_cmd *cmd, int rc, if (rc) QETH_DBF_MESSAGE(2, "IPA: %s(%#x) for device %x returned %#x \"%s\"\n", ipa_name, com, CARD_DEVID(card), rc, - qeth_get_ipa_msg(rc)); + qeth_get_ipa_msg(com, rc)); else QETH_DBF_MESSAGE(5, "IPA: %s(%#x) for device %x succeeded\n", ipa_name, com, CARD_DEVID(card)); @@ -1179,6 +1181,20 @@ static int qeth_check_irb_error(struct qeth_card *card, struct ccw_device *cdev, } } +/** + * qeth_irq() - qeth interrupt handler + * @cdev: ccw device + * @intparm: expect pointer to iob + * @irb: Interruption Response Block + * + * In the good path: + * corresponding qeth channel is locked with last used iob as active_cmd. + * But this function is also called for error interrupts. + * + * Caller ensures that: + * Interrupts are disabled; ccw device lock is held; + * + */ static void qeth_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb) { @@ -1220,11 +1236,10 @@ static void qeth_irq(struct ccw_device *cdev, unsigned long intparm, iob = (struct qeth_cmd_buffer *) (addr_t)intparm; } - qeth_unlock_channel(card, channel); - rc = qeth_check_irb_error(card, cdev, irb); if (rc) { /* IO was terminated, free its resources. */ + qeth_unlock_channel(card, channel); if (iob) qeth_cancel_cmd(iob, rc); return; @@ -1268,6 +1283,7 @@ static void qeth_irq(struct ccw_device *cdev, unsigned long intparm, rc = qeth_get_problem(card, cdev, irb); if (rc) { card->read_or_write_problem = 1; + qeth_unlock_channel(card, channel); if (iob) qeth_cancel_cmd(iob, rc); qeth_clear_ipacmd_list(card); @@ -1276,6 +1292,26 @@ static void qeth_irq(struct ccw_device *cdev, unsigned long intparm, } } + if (scsw_cmd_is_valid_cc(&irb->scsw) && irb->scsw.cmd.cc == 1 && iob) { + /* channel command hasn't started: retry. + * active_cmd is still set to last iob + */ + QETH_CARD_TEXT(card, 2, "irqcc1"); + rc = ccw_device_start_timeout(cdev, __ccw_from_cmd(iob), + (addr_t)iob, 0, 0, iob->timeout); + if (rc) { + QETH_DBF_MESSAGE(2, + "ccw retry on %x failed, rc = %i\n", + CARD_DEVID(card), rc); + QETH_CARD_TEXT_(card, 2, " err%d", rc); + qeth_unlock_channel(card, channel); + qeth_cancel_cmd(iob, rc); + } + return; + } + + qeth_unlock_channel(card, channel); + if (iob) { /* sanity check: */ if (irb->scsw.cmd.count > iob->length) { @@ -1359,7 +1395,7 @@ static void qeth_clear_output_buffer(struct qeth_qdio_out_q *queue, qeth_tx_complete_buf(queue, buf, error, budget); for (i = 0; i < queue->max_elements; ++i) { - void *data = phys_to_virt(buf->buffer->element[i].addr); + void *data = dma64_to_virt(buf->buffer->element[i].addr); if (__test_and_clear_bit(i, buf->from_kmem_cache) && data) kmem_cache_free(qeth_core_header_cache, data); @@ -1404,7 +1440,7 @@ static void qeth_tx_complete_pending_bufs(struct qeth_card *card, for (i = 0; i < aob->sb_count && i < queue->max_elements; i++) { - void *data = phys_to_virt(aob->sba[i]); + void *data = dma64_to_virt(aob->sba[i]); if (test_bit(i, buf->from_kmem_cache) && data) kmem_cache_free(qeth_core_header_cache, @@ -2582,7 +2618,8 @@ err_qdio_bufs: static void qeth_tx_completion_timer(struct timer_list *timer) { - struct qeth_qdio_out_q *queue = from_timer(queue, timer, timer); + struct qeth_qdio_out_q *queue = timer_container_of(queue, timer, + timer); napi_schedule(&queue->napi); QETH_TXQ_STAT_INC(queue, completion_timer); @@ -2594,6 +2631,10 @@ static int qeth_alloc_qdio_queues(struct qeth_card *card) QETH_CARD_TEXT(card, 2, "allcqdbf"); + /* completion */ + if (qeth_alloc_cq(card)) + goto out_err; + if (atomic_cmpxchg(&card->qdio.state, QETH_QDIO_UNINITIALIZED, QETH_QDIO_ALLOCATED) != QETH_QDIO_UNINITIALIZED) return 0; @@ -2629,10 +2670,6 @@ static int qeth_alloc_qdio_queues(struct qeth_card *card) queue->priority = QETH_QIB_PQUE_PRIO_DEFAULT; } - /* completion */ - if (qeth_alloc_cq(card)) - goto out_freeoutq; - return 0; out_freeoutq: @@ -2643,6 +2680,8 @@ out_freeoutq: qeth_free_buffer_pool(card); out_buffer_pool: atomic_set(&card->qdio.state, QETH_QDIO_UNINITIALIZED); + qeth_free_cq(card); +out_err: return -ENOMEM; } @@ -2650,11 +2689,12 @@ static void qeth_free_qdio_queues(struct qeth_card *card) { int i, j; + qeth_free_cq(card); + if (atomic_xchg(&card->qdio.state, QETH_QDIO_UNINITIALIZED) == QETH_QDIO_UNINITIALIZED) return; - qeth_free_cq(card); for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; ++j) { if (card->qdio.in_q->bufs[j].rx_skb) { consume_skb(card->qdio.in_q->bufs[j].rx_skb); @@ -2801,9 +2841,11 @@ static void qeth_print_status_message(struct qeth_card *card) * of the level OSA sets the first character to zero * */ if (!card->info.mcl_level[0]) { - sprintf(card->info.mcl_level, "%02x%02x", - card->info.mcl_level[2], - card->info.mcl_level[3]); + scnprintf(card->info.mcl_level, + sizeof(card->info.mcl_level), + "%02x%02x", + card->info.mcl_level[2], + card->info.mcl_level[3]); break; } fallthrough; @@ -2916,8 +2958,8 @@ static int qeth_init_input_buffer(struct qeth_card *card, */ for (i = 0; i < QETH_MAX_BUFFER_ELEMENTS(card); ++i) { buf->buffer->element[i].length = PAGE_SIZE; - buf->buffer->element[i].addr = - page_to_phys(pool_entry->elements[i]); + buf->buffer->element[i].addr = u64_to_dma64( + page_to_phys(pool_entry->elements[i])); if (i == QETH_MAX_BUFFER_ELEMENTS(card) - 1) buf->buffer->element[i].eflags = SBAL_EFLAGS_LAST_ENTRY; else @@ -3673,7 +3715,7 @@ static void qeth_flush_queue(struct qeth_qdio_out_q *queue) static void qeth_check_outbound_queue(struct qeth_qdio_out_q *queue) { /* - * check if weed have to switch to non-packing mode or if + * check if we have to switch to non-packing mode or if * we have to get a pci flag out on the queue */ if ((atomic_read(&queue->used_buffers) <= QETH_LOW_WATERMARK_PACK) || @@ -3706,24 +3748,11 @@ static void qeth_qdio_poll(struct ccw_device *cdev, unsigned long card_ptr) int qeth_configure_cq(struct qeth_card *card, enum qeth_cq cq) { - int rc; - - if (card->options.cq == QETH_CQ_NOTAVAILABLE) { - rc = -1; - goto out; - } else { - if (card->options.cq == cq) { - rc = 0; - goto out; - } - - qeth_free_qdio_queues(card); - card->options.cq = cq; - rc = 0; - } -out: - return rc; + if (card->options.cq == QETH_CQ_NOTAVAILABLE) + return -1; + card->options.cq = cq; + return 0; } EXPORT_SYMBOL_GPL(qeth_configure_cq); @@ -3763,9 +3792,9 @@ static void qeth_qdio_cq_handler(struct qeth_card *card, unsigned int qdio_err, while ((e < QDIO_MAX_ELEMENTS_PER_BUFFER) && buffer->element[e].addr) { - unsigned long phys_aob_addr = buffer->element[e].addr; + dma64_t phys_aob_addr = buffer->element[e].addr; - qeth_qdio_handle_aob(card, phys_to_virt(phys_aob_addr)); + qeth_qdio_handle_aob(card, dma64_to_virt(phys_aob_addr)); ++e; } qeth_scrub_qdio_buffer(buffer, QDIO_MAX_ELEMENTS_PER_BUFFER); @@ -4040,7 +4069,7 @@ static unsigned int qeth_fill_buffer(struct qeth_qdio_out_buffer *buf, if (hd_len) { is_first_elem = false; - buffer->element[element].addr = virt_to_phys(hdr); + buffer->element[element].addr = virt_to_dma64(hdr); buffer->element[element].length = hd_len; buffer->element[element].eflags = SBAL_EFLAGS_FIRST_FRAG; @@ -4061,7 +4090,7 @@ static unsigned int qeth_fill_buffer(struct qeth_qdio_out_buffer *buf, elem_length = min_t(unsigned int, length, PAGE_SIZE - offset_in_page(data)); - buffer->element[element].addr = virt_to_phys(data); + buffer->element[element].addr = virt_to_dma64(data); buffer->element[element].length = elem_length; length -= elem_length; if (is_first_elem) { @@ -4091,7 +4120,7 @@ static unsigned int qeth_fill_buffer(struct qeth_qdio_out_buffer *buf, elem_length = min_t(unsigned int, length, PAGE_SIZE - offset_in_page(data)); - buffer->element[element].addr = virt_to_phys(data); + buffer->element[element].addr = virt_to_dma64(data); buffer->element[element].length = elem_length; buffer->element[element].eflags = SBAL_EFLAGS_MIDDLE_FRAG; @@ -4774,8 +4803,7 @@ static int qeth_query_oat_command(struct qeth_card *card, char __user *udata) rc = qeth_send_ipa_cmd(card, iob, qeth_setadpparms_query_oat_cb, &priv); if (!rc) { - tmp = is_compat_task() ? compat_ptr(oat_data.ptr) : - u64_to_user_ptr(oat_data.ptr); + tmp = u64_to_user_ptr(oat_data.ptr); oat_data.response_len = priv.response_len; if (copy_to_user(tmp, priv.buffer, priv.response_len) || @@ -5371,8 +5399,6 @@ int qeth_set_offline(struct qeth_card *card, const struct qeth_discipline *disc, qeth_clear_ipacmd_list(card); rtnl_lock(); - card->info.open_when_online = card->dev->flags & IFF_UP; - dev_close(card->dev); netif_device_detach(card->dev); netif_carrier_off(card->dev); rtnl_unlock(); @@ -5569,7 +5595,7 @@ next_packet: offset = 0; } - hdr = phys_to_virt(element->addr) + offset; + hdr = dma64_to_virt(element->addr) + offset; offset += sizeof(*hdr); skb = NULL; @@ -5661,7 +5687,7 @@ use_skb: walk_packet: while (skb_len) { int data_len = min(skb_len, (int)(element->length - offset)); - char *data = phys_to_virt(element->addr) + offset; + char *data = dma64_to_virt(element->addr) + offset; skb_len -= data_len; offset += data_len; @@ -6090,7 +6116,7 @@ void qeth_dbf_longtext(debug_info_t *id, int level, char *fmt, ...) if (!debug_level_enabled(id, level)) return; va_start(args, fmt); - vsnprintf(dbf_txt_buf, sizeof(dbf_txt_buf), fmt, args); + vscnprintf(dbf_txt_buf, sizeof(dbf_txt_buf), fmt, args); va_end(args); debug_text_event(id, level, dbf_txt_buf); } @@ -6226,7 +6252,7 @@ static int qeth_add_dbf_entry(struct qeth_card *card, char *name) new_entry = kzalloc(sizeof(struct qeth_dbf_entry), GFP_KERNEL); if (!new_entry) goto err_dbg; - strncpy(new_entry->dbf_name, name, DBF_NAME_LEN); + strscpy(new_entry->dbf_name, name, sizeof(new_entry->dbf_name)); new_entry->dbf_info = card->debug; mutex_lock(&qeth_dbf_list_mutex); list_add(&new_entry->dbf_list, &qeth_dbf_list); @@ -6330,8 +6356,8 @@ static int qeth_core_probe_device(struct ccwgroup_device *gdev) goto err_dev; } - snprintf(dbf_name, sizeof(dbf_name), "qeth_card_%s", - dev_name(&gdev->dev)); + scnprintf(dbf_name, sizeof(dbf_name), "qeth_card_%s", + dev_name(&gdev->dev)); card->debug = qeth_get_dbf_entry(dbf_name); if (!card->debug) { rc = qeth_add_dbf_entry(card, dbf_name); @@ -7023,14 +7049,16 @@ int qeth_open(struct net_device *dev) card->data.state = CH_STATE_UP; netif_tx_start_all_queues(dev); - local_bh_disable(); qeth_for_each_output_queue(card, queue, i) { netif_napi_add_tx(dev, &queue->napi, qeth_tx_poll); napi_enable(&queue->napi); - napi_schedule(&queue->napi); } - napi_enable(&card->napi); + + local_bh_disable(); + qeth_for_each_output_queue(card, queue, i) { + napi_schedule(&queue->napi); + } napi_schedule(&card->napi); /* kick-start the NAPI softirq: */ local_bh_enable(); @@ -7059,7 +7087,7 @@ int qeth_stop(struct net_device *dev) netif_tx_disable(dev); qeth_for_each_output_queue(card, queue, i) { - del_timer_sync(&queue->timer); + timer_delete_sync(&queue->timer); /* Queues may get re-allocated, so remove the NAPIs. */ netif_napi_del(&queue->napi); } |
