--- zzzz-none-000/linux-3.10.107/drivers/net/ethernet/brocade/bna/bnad.c 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/drivers/net/ethernet/brocade/bna/bnad.c 2021-02-04 17:41:59.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Linux network driver for Brocade Converged Network Adapter. + * Linux network driver for QLogic BR-series Converged Network Adapter. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License (GPL) Version 2 as @@ -11,9 +11,10 @@ * General Public License for more details. */ /* - * Copyright (c) 2005-2010 Brocade Communications Systems, Inc. + * Copyright (c) 2005-2014 Brocade Communications Systems, Inc. + * Copyright (c) 2014-2015 QLogic Corporation * All rights reserved - * www.brocade.com + * www.qlogic.com */ #include #include @@ -52,11 +53,12 @@ /* * Global variables */ -u32 bnad_rxqs_per_cq = 2; +static u32 bnad_rxqs_per_cq = 2; static u32 bna_id; static struct mutex bnad_list_mutex; static LIST_HEAD(bnad_list); -static const u8 bnad_bcast_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const u8 bnad_bcast_addr[] __aligned(2) = + { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; /* * Local MACROS @@ -142,7 +144,8 @@ dma_unmap_page(&bnad->pcidev->dev, dma_unmap_addr(&unmap->vectors[vector], dma_addr), - skb_shinfo(skb)->frags[nvecs].size, DMA_TO_DEVICE); + dma_unmap_len(&unmap->vectors[vector], dma_len), + DMA_TO_DEVICE); dma_unmap_addr_set(&unmap->vectors[vector], dma_addr, 0); nvecs--; } @@ -193,7 +196,6 @@ return 0; hw_cons = *(tcb->hw_consumer_index); - rmb(); cons = tcb->consumer_index; q_depth = tcb->q_depth; @@ -249,7 +251,7 @@ if (likely(test_bit(BNAD_TXQ_TX_STARTED, &tcb->flags))) bna_ib_ack(tcb->i_dbell, sent); - smp_mb__before_clear_bit(); + smp_mb__before_atomic(); clear_bit(BNAD_TXQ_FREE_SENT, &tcb->flags); return sent; @@ -283,26 +285,31 @@ bnad_rxq_alloc_init(struct bnad *bnad, struct bna_rcb *rcb) { struct bnad_rx_unmap_q *unmap_q = rcb->unmap_q; - int mtu, order; + int order; bnad_rxq_alloc_uninit(bnad, rcb); - mtu = bna_enet_mtu_get(&bnad->bna.enet); - order = get_order(mtu); + order = get_order(rcb->rxq->buffer_size); + + unmap_q->type = BNAD_RXBUF_PAGE; if (bna_is_small_rxq(rcb->id)) { unmap_q->alloc_order = 0; unmap_q->map_size = rcb->rxq->buffer_size; } else { - unmap_q->alloc_order = order; - unmap_q->map_size = - (rcb->rxq->buffer_size > 2048) ? - PAGE_SIZE << order : 2048; + if (rcb->rxq->multi_buffer) { + unmap_q->alloc_order = 0; + unmap_q->map_size = rcb->rxq->buffer_size; + unmap_q->type = BNAD_RXBUF_MULTI_BUFF; + } else { + unmap_q->alloc_order = order; + unmap_q->map_size = + (rcb->rxq->buffer_size > 2048) ? + PAGE_SIZE << order : 2048; + } } - BUG_ON(((PAGE_SIZE << order) % unmap_q->map_size)); - - unmap_q->type = BNAD_RXBUF_PAGE; + BUG_ON((PAGE_SIZE << order) % unmap_q->map_size); return 0; } @@ -346,10 +353,10 @@ for (i = 0; i < rcb->q_depth; i++) { struct bnad_rx_unmap *unmap = &unmap_q->unmap[i]; - if (BNAD_RXBUF_IS_PAGE(unmap_q->type)) - bnad_rxq_cleanup_page(bnad, unmap); - else + if (BNAD_RXBUF_IS_SK_BUFF(unmap_q->type)) bnad_rxq_cleanup_skb(bnad, unmap); + else + bnad_rxq_cleanup_page(bnad, unmap); } bnad_rxq_alloc_uninit(bnad, rcb); } @@ -392,7 +399,13 @@ } dma_addr = dma_map_page(&bnad->pcidev->dev, page, page_offset, - unmap_q->map_size, DMA_FROM_DEVICE); + unmap_q->map_size, DMA_FROM_DEVICE); + if (dma_mapping_error(&bnad->pcidev->dev, dma_addr)) { + put_page(page); + BNAD_UPDATE_CTR(bnad, rxbuf_map_failed); + rcb->rxq->rxbuf_map_failed++; + goto finishing; + } unmap->page = page; unmap->page_offset = page_offset; @@ -447,8 +460,15 @@ rcb->rxq->rxbuf_alloc_failed++; goto finishing; } + dma_addr = dma_map_single(&bnad->pcidev->dev, skb->data, buff_sz, DMA_FROM_DEVICE); + if (dma_mapping_error(&bnad->pcidev->dev, dma_addr)) { + dev_kfree_skb_any(skb); + BNAD_UPDATE_CTR(bnad, rxbuf_map_failed); + rcb->rxq->rxbuf_map_failed++; + goto finishing; + } unmap->skb = skb; dma_unmap_addr_set(&unmap->vector, dma_addr, dma_addr); @@ -481,10 +501,10 @@ if (!(to_alloc >> BNAD_RXQ_REFILL_THRESHOLD_SHIFT)) return; - if (BNAD_RXBUF_IS_PAGE(unmap_q->type)) - bnad_rxq_refill_page(bnad, rcb, to_alloc); - else + if (BNAD_RXBUF_IS_SK_BUFF(unmap_q->type)) bnad_rxq_refill_skb(bnad, rcb, to_alloc); + else + bnad_rxq_refill_page(bnad, rcb, to_alloc); } #define flags_cksum_prot_mask (BNA_CQ_EF_IPV4 | BNA_CQ_EF_L3_CKSUM_OK | \ @@ -501,72 +521,114 @@ #define flags_udp6 (BNA_CQ_EF_IPV6 | \ BNA_CQ_EF_UDP | BNA_CQ_EF_L4_CKSUM_OK) -static inline struct sk_buff * -bnad_cq_prepare_skb(struct bnad_rx_ctrl *rx_ctrl, - struct bnad_rx_unmap_q *unmap_q, - struct bnad_rx_unmap *unmap, - u32 length, u32 flags) +static void +bnad_cq_drop_packet(struct bnad *bnad, struct bna_rcb *rcb, + u32 sop_ci, u32 nvecs) { - struct bnad *bnad = rx_ctrl->bnad; - struct sk_buff *skb; + struct bnad_rx_unmap_q *unmap_q; + struct bnad_rx_unmap *unmap; + u32 ci, vec; + + unmap_q = rcb->unmap_q; + for (vec = 0, ci = sop_ci; vec < nvecs; vec++) { + unmap = &unmap_q->unmap[ci]; + BNA_QE_INDX_INC(ci, rcb->q_depth); + + if (BNAD_RXBUF_IS_SK_BUFF(unmap_q->type)) + bnad_rxq_cleanup_skb(bnad, unmap); + else + bnad_rxq_cleanup_page(bnad, unmap); + } +} + +static void +bnad_cq_setup_skb_frags(struct bna_rcb *rcb, struct sk_buff *skb, + u32 sop_ci, u32 nvecs, u32 last_fraglen) +{ + struct bnad *bnad; + u32 ci, vec, len, totlen = 0; + struct bnad_rx_unmap_q *unmap_q; + struct bnad_rx_unmap *unmap; - if (BNAD_RXBUF_IS_PAGE(unmap_q->type)) { - skb = napi_get_frags(&rx_ctrl->napi); - if (unlikely(!skb)) - return NULL; + unmap_q = rcb->unmap_q; + bnad = rcb->bnad; + + /* prefetch header */ + prefetch(page_address(unmap_q->unmap[sop_ci].page) + + unmap_q->unmap[sop_ci].page_offset); + + for (vec = 1, ci = sop_ci; vec <= nvecs; vec++) { + unmap = &unmap_q->unmap[ci]; + BNA_QE_INDX_INC(ci, rcb->q_depth); dma_unmap_page(&bnad->pcidev->dev, dma_unmap_addr(&unmap->vector, dma_addr), unmap->vector.len, DMA_FROM_DEVICE); + + len = (vec == nvecs) ? + last_fraglen : unmap->vector.len; + skb->truesize += unmap->vector.len; + totlen += len; + skb_fill_page_desc(skb, skb_shinfo(skb)->nr_frags, - unmap->page, unmap->page_offset, length); - skb->len += length; - skb->data_len += length; - skb->truesize += length; + unmap->page, unmap->page_offset, len); unmap->page = NULL; unmap->vector.len = 0; - - return skb; } - skb = unmap->skb; - BUG_ON(!skb); + skb->len += totlen; + skb->data_len += totlen; +} + +static inline void +bnad_cq_setup_skb(struct bnad *bnad, struct sk_buff *skb, + struct bnad_rx_unmap *unmap, u32 len) +{ + prefetch(skb->data); dma_unmap_single(&bnad->pcidev->dev, dma_unmap_addr(&unmap->vector, dma_addr), unmap->vector.len, DMA_FROM_DEVICE); - skb_put(skb, length); - + skb_put(skb, len); skb->protocol = eth_type_trans(skb, bnad->netdev); unmap->skb = NULL; unmap->vector.len = 0; - return skb; } static u32 bnad_cq_process(struct bnad *bnad, struct bna_ccb *ccb, int budget) { - struct bna_cq_entry *cq, *cmpl; + struct bna_cq_entry *cq, *cmpl, *next_cmpl; struct bna_rcb *rcb = NULL; struct bnad_rx_unmap_q *unmap_q; - struct bnad_rx_unmap *unmap; - struct sk_buff *skb; + struct bnad_rx_unmap *unmap = NULL; + struct sk_buff *skb = NULL; struct bna_pkt_rate *pkt_rt = &ccb->pkt_rate; struct bnad_rx_ctrl *rx_ctrl = ccb->ctrl; - u32 packets = 0, length = 0, flags, masked_flags; + u32 packets = 0, len = 0, totlen = 0; + u32 pi, vec, sop_ci = 0, nvecs = 0; + u32 flags, masked_flags; prefetch(bnad->netdev); cq = ccb->sw_q; - cmpl = &cq[ccb->producer_index]; - while (cmpl->valid && (packets < budget)) { - packets++; - flags = ntohl(cmpl->flags); - length = ntohs(cmpl->length); + while (packets < budget) { + cmpl = &cq[ccb->producer_index]; + if (!cmpl->valid) + break; + /* The 'valid' field is set by the adapter, only after writing + * the other fields of completion entry. Hence, do not load + * other fields of completion entry *before* the 'valid' is + * loaded. Adding the rmb() here prevents the compiler and/or + * CPU from reordering the reads which would potentially result + * in reading stale values in completion entry. + */ + rmb(); + BNA_UPDATE_PKT_CNT(pkt_rt, ntohs(cmpl->length)); if (bna_is_small_rxq(cmpl->rxq_id)) @@ -575,25 +637,78 @@ rcb = ccb->rcb[0]; unmap_q = rcb->unmap_q; - unmap = &unmap_q->unmap[rcb->consumer_index]; - if (unlikely(flags & (BNA_CQ_EF_MAC_ERROR | - BNA_CQ_EF_FCS_ERROR | - BNA_CQ_EF_TOO_LONG))) { - if (BNAD_RXBUF_IS_PAGE(unmap_q->type)) - bnad_rxq_cleanup_page(bnad, unmap); - else - bnad_rxq_cleanup_skb(bnad, unmap); + /* start of packet ci */ + sop_ci = rcb->consumer_index; + if (BNAD_RXBUF_IS_SK_BUFF(unmap_q->type)) { + unmap = &unmap_q->unmap[sop_ci]; + skb = unmap->skb; + } else { + skb = napi_get_frags(&rx_ctrl->napi); + if (unlikely(!skb)) + break; + } + prefetch(skb); + + flags = ntohl(cmpl->flags); + len = ntohs(cmpl->length); + totlen = len; + nvecs = 1; + + /* Check all the completions for this frame. + * busy-wait doesn't help much, break here. + */ + if (BNAD_RXBUF_IS_MULTI_BUFF(unmap_q->type) && + (flags & BNA_CQ_EF_EOP) == 0) { + pi = ccb->producer_index; + do { + BNA_QE_INDX_INC(pi, ccb->q_depth); + next_cmpl = &cq[pi]; + + if (!next_cmpl->valid) + break; + /* The 'valid' field is set by the adapter, only + * after writing the other fields of completion + * entry. Hence, do not load other fields of + * completion entry *before* the 'valid' is + * loaded. Adding the rmb() here prevents the + * compiler and/or CPU from reordering the reads + * which would potentially result in reading + * stale values in completion entry. + */ + rmb(); + + len = ntohs(next_cmpl->length); + flags = ntohl(next_cmpl->flags); + + nvecs++; + totlen += len; + } while ((flags & BNA_CQ_EF_EOP) == 0); + + if (!next_cmpl->valid) + break; + } + packets++; + + /* TODO: BNA_CQ_EF_LOCAL ? */ + if (unlikely(flags & (BNA_CQ_EF_MAC_ERROR | + BNA_CQ_EF_FCS_ERROR | + BNA_CQ_EF_TOO_LONG))) { + bnad_cq_drop_packet(bnad, rcb, sop_ci, nvecs); rcb->rxq->rx_packets_with_error++; + goto next; } - skb = bnad_cq_prepare_skb(ccb->ctrl, unmap_q, unmap, - length, flags); + if (BNAD_RXBUF_IS_SK_BUFF(unmap_q->type)) + bnad_cq_setup_skb(bnad, skb, unmap, len); + else + bnad_cq_setup_skb_frags(rcb, skb, sop_ci, nvecs, len); - if (unlikely(!skb)) - break; + rcb->rxq->rx_packets++; + rcb->rxq->rx_bytes += totlen; + ccb->bytes_per_intr += totlen; masked_flags = flags & flags_cksum_prot_mask; @@ -607,22 +722,22 @@ else skb_checksum_none_assert(skb); - rcb->rxq->rx_packets++; - rcb->rxq->rx_bytes += length; - - if (flags & BNA_CQ_EF_VLAN) + if ((flags & BNA_CQ_EF_VLAN) && + (bnad->netdev->features & NETIF_F_HW_VLAN_CTAG_RX)) __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), ntohs(cmpl->vlan_tag)); - if (BNAD_RXBUF_IS_PAGE(unmap_q->type)) - napi_gro_frags(&rx_ctrl->napi); - else + if (BNAD_RXBUF_IS_SK_BUFF(unmap_q->type)) netif_receive_skb(skb); + else + napi_gro_frags(&rx_ctrl->napi); next: - cmpl->valid = 0; - BNA_QE_INDX_INC(rcb->consumer_index, rcb->q_depth); - BNA_QE_INDX_INC(ccb->producer_index, ccb->q_depth); - cmpl = &cq[ccb->producer_index]; + BNA_QE_INDX_ADD(rcb->consumer_index, nvecs, rcb->q_depth); + for (vec = 0; vec < nvecs; vec++) { + cmpl = &cq[ccb->producer_index]; + cmpl->valid = 0; + BNA_QE_INDX_INC(ccb->producer_index, ccb->q_depth); + } } napi_gro_flush(&rx_ctrl->napi, false); @@ -655,7 +770,7 @@ struct bna_ccb *ccb = (struct bna_ccb *)data; if (ccb) { - ((struct bnad_rx_ctrl *)(ccb->ctrl))->rx_intr_ctr++; + ((struct bnad_rx_ctrl *)ccb->ctrl)->rx_intr_ctr++; bnad_netif_rx_schedule_poll(ccb->bnad, ccb); } @@ -773,9 +888,9 @@ { struct net_device *netdev = bnad->netdev; - memcpy(netdev->perm_addr, &bnad->perm_addr, netdev->addr_len); + ether_addr_copy(netdev->perm_addr, bnad->perm_addr); if (is_zero_ether_addr(netdev->dev_addr)) - memcpy(netdev->dev_addr, &bnad->perm_addr, netdev->addr_len); + ether_addr_copy(netdev->dev_addr, bnad->perm_addr); } /* Control Path Handlers */ @@ -844,8 +959,7 @@ if (link_up) { if (!netif_carrier_ok(bnad->netdev)) { uint tx_id, tcb_id; - printk(KERN_WARNING "bna: %s link up\n", - bnad->netdev->name); + netdev_info(bnad->netdev, "link up\n"); netif_carrier_on(bnad->netdev); BNAD_UPDATE_CTR(bnad, link_toggle); for (tx_id = 0; tx_id < bnad->num_tx; tx_id++) { @@ -864,10 +978,6 @@ /* * Force an immediate * Transmit Schedule */ - printk(KERN_INFO "bna: %s %d " - "TXQ_STARTED\n", - bnad->netdev->name, - txq_id); netif_wake_subqueue( bnad->netdev, txq_id); @@ -885,8 +995,7 @@ } } else { if (netif_carrier_ok(bnad->netdev)) { - printk(KERN_WARNING "bna: %s link down\n", - bnad->netdev->name); + netdev_info(bnad->netdev, "link down\n"); netif_carrier_off(bnad->netdev); BNAD_UPDATE_CTR(bnad, link_toggle); } @@ -956,8 +1065,6 @@ txq_id = tcb->id; clear_bit(BNAD_TXQ_TX_STARTED, &tcb->flags); netif_stop_subqueue(bnad->netdev, txq_id); - printk(KERN_INFO "bna: %s %d TXQ_STOPPED\n", - bnad->netdev->name, txq_id); } } @@ -980,8 +1087,6 @@ BUG_ON(*(tcb->hw_consumer_index) != 0); if (netif_carrier_ok(bnad->netdev)) { - printk(KERN_INFO "bna: %s %d TXQ_STARTED\n", - bnad->netdev->name, txq_id); netif_wake_subqueue(bnad->netdev, txq_id); BNAD_UPDATE_CTR(bnad, netif_queue_wakeup); } @@ -992,8 +1097,8 @@ * get a 0 MAC address. We try to get the MAC address * again here. */ - if (is_zero_ether_addr(&bnad->perm_addr.mac[0])) { - bna_enet_perm_mac_get(&bnad->bna.enet, &bnad->perm_addr); + if (is_zero_ether_addr(bnad->perm_addr)) { + bna_enet_perm_mac_get(&bnad->bna.enet, bnad->perm_addr); bnad_set_netdev_perm_addr(bnad); } } @@ -1025,7 +1130,7 @@ bnad_txq_cleanup(bnad, tcb); - smp_mb__before_clear_bit(); + smp_mb__before_atomic(); clear_bit(BNAD_TXQ_FREE_SENT, &tcb->flags); } @@ -1601,7 +1706,7 @@ unsigned long flags; spin_lock_irqsave(&bnad->bna_lock, flags); - bfa_nw_ioc_timeout((void *) &bnad->bna.ioceth.ioc); + bfa_nw_ioc_timeout(&bnad->bna.ioceth.ioc); spin_unlock_irqrestore(&bnad->bna_lock, flags); } @@ -1612,7 +1717,7 @@ unsigned long flags; spin_lock_irqsave(&bnad->bna_lock, flags); - bfa_nw_ioc_hb_check((void *) &bnad->bna.ioceth.ioc); + bfa_nw_ioc_hb_check(&bnad->bna.ioceth.ioc); spin_unlock_irqrestore(&bnad->bna_lock, flags); } @@ -1623,7 +1728,7 @@ unsigned long flags; spin_lock_irqsave(&bnad->bna_lock, flags); - bfa_nw_iocpf_timeout((void *) &bnad->bna.ioceth.ioc); + bfa_nw_iocpf_timeout(&bnad->bna.ioceth.ioc); spin_unlock_irqrestore(&bnad->bna_lock, flags); } @@ -1634,7 +1739,7 @@ unsigned long flags; spin_lock_irqsave(&bnad->bna_lock, flags); - bfa_nw_iocpf_sem_timeout((void *) &bnad->bna.ioceth.ioc); + bfa_nw_iocpf_sem_timeout(&bnad->bna.ioceth.ioc); spin_unlock_irqrestore(&bnad->bna_lock, flags); } @@ -1760,8 +1865,7 @@ struct netdev_hw_addr *mc_addr; netdev_for_each_mc_addr(mc_addr, netdev) { - memcpy(&mc_list[i * ETH_ALEN], &mc_addr->addr[0], - ETH_ALEN); + ether_addr_copy(&mc_list[i * ETH_ALEN], &mc_addr->addr[0]); i++; } } @@ -1900,8 +2004,10 @@ tx = bna_tx_create(&bnad->bna, bnad, tx_config, &tx_cbfn, res_info, tx_info); spin_unlock_irqrestore(&bnad->bna_lock, flags); - if (!tx) + if (!tx) { + err = -ENOMEM; goto err_return; + } tx_info->tx = tx; INIT_DELAYED_WORK(&tx_info->tx_cleanup_work, @@ -1912,7 +2018,7 @@ err = bnad_tx_msix_register(bnad, tx_info, tx_id, bnad->num_txq_per_tx); if (err) - goto err_return; + goto cleanup_tx; } spin_lock_irqsave(&bnad->bna_lock, flags); @@ -1921,6 +2027,12 @@ return 0; +cleanup_tx: + spin_lock_irqsave(&bnad->bna_lock, flags); + bna_tx_destroy(tx_info->tx); + spin_unlock_irqrestore(&bnad->bna_lock, flags); + tx_info->tx = NULL; + tx_info->tx_id = 0; err_return: bnad_tx_res_free(bnad, res_info); return err; @@ -1931,6 +2043,7 @@ static void bnad_init_rx_config(struct bnad *bnad, struct bna_rx_config *rx_config) { + memset(rx_config, 0, sizeof(*rx_config)); rx_config->rx_type = BNA_RX_T_REGULAR; rx_config->num_paths = bnad->num_rxp_per_rx; rx_config->coalescing_timeo = bnad->rx_coalescing_timeo; @@ -1944,19 +2057,50 @@ BFI_ENET_RSS_IPV4_TCP); rx_config->rss_config.hash_mask = bnad->num_rxp_per_rx - 1; - get_random_bytes(rx_config->rss_config.toeplitz_hash_key, + netdev_rss_key_fill(rx_config->rss_config.toeplitz_hash_key, sizeof(rx_config->rss_config.toeplitz_hash_key)); } else { rx_config->rss_status = BNA_STATUS_T_DISABLED; memset(&rx_config->rss_config, 0, sizeof(rx_config->rss_config)); } + + rx_config->frame_size = BNAD_FRAME_SIZE(bnad->netdev->mtu); + rx_config->q0_multi_buf = BNA_STATUS_T_DISABLED; + + /* BNA_RXP_SINGLE - one data-buffer queue + * BNA_RXP_SLR - one small-buffer and one large-buffer queues + * BNA_RXP_HDS - one header-buffer and one data-buffer queues + */ + /* TODO: configurable param for queue type */ rx_config->rxp_type = BNA_RXP_SLR; - rx_config->q_depth = bnad->rxq_depth; - rx_config->small_buff_size = BFI_SMALL_RXBUF_SIZE; + if (BNAD_PCI_DEV_IS_CAT2(bnad) && + rx_config->frame_size > 4096) { + /* though size_routing_enable is set in SLR, + * small packets may get routed to same rxq. + * set buf_size to 2048 instead of PAGE_SIZE. + */ + rx_config->q0_buf_size = 2048; + /* this should be in multiples of 2 */ + rx_config->q0_num_vecs = 4; + rx_config->q0_depth = bnad->rxq_depth * rx_config->q0_num_vecs; + rx_config->q0_multi_buf = BNA_STATUS_T_ENABLED; + } else { + rx_config->q0_buf_size = rx_config->frame_size; + rx_config->q0_num_vecs = 1; + rx_config->q0_depth = bnad->rxq_depth; + } + + /* initialize for q1 for BNA_RXP_SLR/BNA_RXP_HDS */ + if (rx_config->rxp_type == BNA_RXP_SLR) { + rx_config->q1_depth = bnad->rxq_depth; + rx_config->q1_buf_size = BFI_SMALL_RXBUF_SIZE; + } - rx_config->vlan_strip_status = BNA_STATUS_T_ENABLED; + rx_config->vlan_strip_status = + (bnad->netdev->features & NETIF_F_HW_VLAN_CTAG_RX) ? + BNA_STATUS_T_ENABLED : BNA_STATUS_T_DISABLED; } static void @@ -1970,6 +2114,49 @@ } /* Called with mutex_lock(&bnad->conf_mutex) held */ +static u32 +bnad_reinit_rx(struct bnad *bnad) +{ + struct net_device *netdev = bnad->netdev; + u32 err = 0, current_err = 0; + u32 rx_id = 0, count = 0; + unsigned long flags; + + /* destroy and create new rx objects */ + for (rx_id = 0; rx_id < bnad->num_rx; rx_id++) { + if (!bnad->rx_info[rx_id].rx) + continue; + bnad_destroy_rx(bnad, rx_id); + } + + spin_lock_irqsave(&bnad->bna_lock, flags); + bna_enet_mtu_set(&bnad->bna.enet, + BNAD_FRAME_SIZE(bnad->netdev->mtu), NULL); + spin_unlock_irqrestore(&bnad->bna_lock, flags); + + for (rx_id = 0; rx_id < bnad->num_rx; rx_id++) { + count++; + current_err = bnad_setup_rx(bnad, rx_id); + if (current_err && !err) { + err = current_err; + netdev_err(netdev, "RXQ:%u setup failed\n", rx_id); + } + } + + /* restore rx configuration */ + if (bnad->rx_info[0].rx && !err) { + bnad_restore_vlans(bnad, 0); + bnad_enable_default_bcast(bnad); + spin_lock_irqsave(&bnad->bna_lock, flags); + bnad_mac_addr_set_locked(bnad, netdev->dev_addr); + spin_unlock_irqrestore(&bnad->bna_lock, flags); + bnad_set_rx_mode(netdev); + } + + return count; +} + +/* Called with bnad_conf_lock() held */ void bnad_destroy_rx(struct bnad *bnad, u32 rx_id) { @@ -2048,13 +2235,19 @@ spin_unlock_irqrestore(&bnad->bna_lock, flags); /* Fill Unmap Q memory requirements */ - BNAD_FILL_UNMAPQ_MEM_REQ(&res_info[BNA_RX_RES_MEM_T_UNMAPQ], - rx_config->num_paths + - ((rx_config->rxp_type == BNA_RXP_SINGLE) ? - 0 : rx_config->num_paths), - ((bnad->rxq_depth * sizeof(struct bnad_rx_unmap)) + - sizeof(struct bnad_rx_unmap_q))); - + BNAD_FILL_UNMAPQ_MEM_REQ(&res_info[BNA_RX_RES_MEM_T_UNMAPDQ], + rx_config->num_paths, + (rx_config->q0_depth * + sizeof(struct bnad_rx_unmap)) + + sizeof(struct bnad_rx_unmap_q)); + + if (rx_config->rxp_type != BNA_RXP_SINGLE) { + BNAD_FILL_UNMAPQ_MEM_REQ(&res_info[BNA_RX_RES_MEM_T_UNMAPHQ], + rx_config->num_paths, + (rx_config->q1_depth * + sizeof(struct bnad_rx_unmap) + + sizeof(struct bnad_rx_unmap_q))); + } /* Allocate resource */ err = bnad_rx_res_alloc(bnad, res_info, rx_id); if (err) @@ -2147,7 +2340,7 @@ * Called with bnad->bna_lock held */ int -bnad_mac_addr_set_locked(struct bnad *bnad, u8 *mac_addr) +bnad_mac_addr_set_locked(struct bnad *bnad, const u8 *mac_addr) { int ret; @@ -2158,7 +2351,7 @@ if (!bnad->rx_info[0].rx) return 0; - ret = bna_rx_ucast_set(bnad->rx_info[0].rx, mac_addr, NULL); + ret = bna_rx_ucast_set(bnad->rx_info[0].rx, mac_addr); if (ret != BNA_CB_SUCCESS) return -EADDRNOTAVAIL; @@ -2176,8 +2369,8 @@ init_completion(&bnad->bnad_completions.mcast_comp); spin_lock_irqsave(&bnad->bna_lock, flags); - ret = bna_rx_mcast_add(rx_info->rx, (u8 *)bnad_bcast_addr, - bnad_cb_rx_mcast_add); + ret = bna_rx_mcast_add(rx_info->rx, bnad_bcast_addr, + bnad_cb_rx_mcast_add); spin_unlock_irqrestore(&bnad->bna_lock, flags); if (ret == BNA_CB_SUCCESS) @@ -2306,19 +2499,17 @@ { int err; - if (skb_header_cloned(skb)) { - err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC); - if (err) { - BNAD_UPDATE_CTR(bnad, tso_err); - return err; - } + err = skb_cow_head(skb, 0); + if (err < 0) { + BNAD_UPDATE_CTR(bnad, tso_err); + return err; } /* * For TSO, the TCP checksum field is seeded with pseudo-header sum * excluding the length field. */ - if (skb->protocol == htons(ETH_P_IP)) { + if (vlan_get_protocol(skb) == htons(ETH_P_IP)) { struct iphdr *iph = ip_hdr(skb); /* Do we really need these? */ @@ -2479,11 +2670,14 @@ for (i = 0; i < bnad->msix_num; i++) bnad->msix_table[i].entry = i; - ret = pci_enable_msix(bnad->pcidev, bnad->msix_table, bnad->msix_num); - if (ret > 0) { - /* Not enough MSI-X vectors. */ - pr_warn("BNA: %d MSI-X vectors allocated < %d requested\n", - ret, bnad->msix_num); + ret = pci_enable_msix_range(bnad->pcidev, bnad->msix_table, + 1, bnad->msix_num); + if (ret < 0) { + goto intx_mode; + } else if (ret < bnad->msix_num) { + dev_warn(&bnad->pcidev->dev, + "%d MSI-X vectors allocated < %d requested\n", + ret, bnad->msix_num); spin_lock_irqsave(&bnad->bna_lock, flags); /* ret = #of vectors that we got */ @@ -2494,25 +2688,19 @@ bnad->msix_num = BNAD_NUM_TXQ + BNAD_NUM_RXP + BNAD_MAILBOX_MSIX_VECTORS; - if (bnad->msix_num > ret) + if (bnad->msix_num > ret) { + pci_disable_msix(bnad->pcidev); goto intx_mode; - - /* Try once more with adjusted numbers */ - /* If this fails, fall back to INTx */ - ret = pci_enable_msix(bnad->pcidev, bnad->msix_table, - bnad->msix_num); - if (ret) - goto intx_mode; - - } else if (ret < 0) - goto intx_mode; + } + } pci_intx(bnad->pcidev, 0); return; intx_mode: - pr_warn("BNA: MSI-X enable failed - operating in INTx mode\n"); + dev_warn(&bnad->pcidev->dev, + "MSI-X enable failed - operating in INTx mode\n"); kfree(bnad->msix_table); bnad->msix_table = NULL; @@ -2549,7 +2737,6 @@ int err; struct bnad *bnad = netdev_priv(netdev); struct bna_pause_config pause_config; - int mtu; unsigned long flags; mutex_lock(&bnad->conf_mutex); @@ -2568,11 +2755,10 @@ pause_config.tx_pause = 0; pause_config.rx_pause = 0; - mtu = ETH_HLEN + VLAN_HLEN + bnad->netdev->mtu + ETH_FCS_LEN; - spin_lock_irqsave(&bnad->bna_lock, flags); - bna_enet_mtu_set(&bnad->bna.enet, mtu, NULL); - bna_enet_pause_config(&bnad->bna.enet, &pause_config, NULL); + bna_enet_mtu_set(&bnad->bna.enet, + BNAD_FRAME_SIZE(bnad->netdev->mtu), NULL); + bna_enet_pause_config(&bnad->bna.enet, &pause_config); bna_enet_enable(&bnad->bna.enet); spin_unlock_irqrestore(&bnad->bna_lock, flags); @@ -2643,8 +2829,8 @@ u32 gso_size; u16 vlan_tag = 0; - if (vlan_tx_tag_present(skb)) { - vlan_tag = (u16)vlan_tx_tag_get(skb); + if (skb_vlan_tag_present(skb)) { + vlan_tag = (u16)skb_vlan_tag_get(skb); flags |= (BNA_TXQ_WI_CF_INS_PRIO | BNA_TXQ_WI_CF_INS_VLAN); } if (test_bit(BNAD_RF_CEE_RUNNING, &bnad->run_flags)) { @@ -2662,13 +2848,11 @@ } if (unlikely((gso_size + skb_transport_offset(skb) + tcp_hdrlen(skb)) >= skb->len)) { - txqent->hdr.wi.opcode = - __constant_htons(BNA_TXQ_WI_SEND); + txqent->hdr.wi.opcode = htons(BNA_TXQ_WI_SEND); txqent->hdr.wi.lso_mss = 0; BNAD_UPDATE_CTR(bnad, tx_skb_tso_too_short); } else { - txqent->hdr.wi.opcode = - __constant_htons(BNA_TXQ_WI_SEND_LSO); + txqent->hdr.wi.opcode = htons(BNA_TXQ_WI_SEND_LSO); txqent->hdr.wi.lso_mss = htons(gso_size); } @@ -2682,22 +2866,22 @@ htons(BNA_TXQ_WI_L4_HDR_N_OFFSET( tcp_hdrlen(skb) >> 2, skb_transport_offset(skb))); } else { - txqent->hdr.wi.opcode = __constant_htons(BNA_TXQ_WI_SEND); + txqent->hdr.wi.opcode = htons(BNA_TXQ_WI_SEND); txqent->hdr.wi.lso_mss = 0; - if (unlikely(skb->len > (bnad->netdev->mtu + ETH_HLEN))) { + if (unlikely(skb->len > (bnad->netdev->mtu + VLAN_ETH_HLEN))) { BNAD_UPDATE_CTR(bnad, tx_skb_non_tso_too_long); return -EINVAL; } if (skb->ip_summed == CHECKSUM_PARTIAL) { + __be16 net_proto = vlan_get_protocol(skb); u8 proto = 0; - if (skb->protocol == __constant_htons(ETH_P_IP)) + if (net_proto == htons(ETH_P_IP)) proto = ip_hdr(skb)->protocol; #ifdef NETIF_F_IPV6_CSUM - else if (skb->protocol == - __constant_htons(ETH_P_IPV6)) { + else if (net_proto == htons(ETH_P_IPV6)) { /* nexthdr may not be TCP immediately. */ proto = ipv6_hdr(skb)->nexthdr; } @@ -2766,42 +2950,42 @@ /* Sanity checks for the skb */ if (unlikely(skb->len <= ETH_HLEN)) { - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); BNAD_UPDATE_CTR(bnad, tx_skb_too_short); return NETDEV_TX_OK; } if (unlikely(len > BFI_TX_MAX_DATA_PER_VECTOR)) { - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); BNAD_UPDATE_CTR(bnad, tx_skb_headlen_zero); return NETDEV_TX_OK; } if (unlikely(len == 0)) { - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); BNAD_UPDATE_CTR(bnad, tx_skb_headlen_zero); return NETDEV_TX_OK; } tcb = bnad->tx_info[0].tcb[txq_id]; - q_depth = tcb->q_depth; - prod = tcb->producer_index; - - unmap_q = tcb->unmap_q; /* * Takes care of the Tx that is scheduled between clearing the flag * and the netif_tx_stop_all_queues() call. */ - if (unlikely(!test_bit(BNAD_TXQ_TX_STARTED, &tcb->flags))) { - dev_kfree_skb(skb); + if (unlikely(!tcb || !test_bit(BNAD_TXQ_TX_STARTED, &tcb->flags))) { + dev_kfree_skb_any(skb); BNAD_UPDATE_CTR(bnad, tx_skb_stopping); return NETDEV_TX_OK; } + q_depth = tcb->q_depth; + prod = tcb->producer_index; + unmap_q = tcb->unmap_q; + vectors = 1 + skb_shinfo(skb)->nr_frags; wis = BNA_TXQ_WI_NEEDED(vectors); /* 4 vectors per work item */ if (unlikely(vectors > BFI_TX_MAX_VECTORS_PER_PKT)) { - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); BNAD_UPDATE_CTR(bnad, tx_skb_max_vectors); return NETDEV_TX_OK; } @@ -2814,7 +2998,7 @@ sent = bnad_txcmpl_process(bnad, tcb); if (likely(test_bit(BNAD_TXQ_TX_STARTED, &tcb->flags))) bna_ib_ack(tcb->i_dbell, sent); - smp_mb__before_clear_bit(); + smp_mb__before_atomic(); clear_bit(BNAD_TXQ_FREE_SENT, &tcb->flags); } else { netif_stop_queue(netdev); @@ -2841,7 +3025,7 @@ /* Program the opcode, flags, frame_len, num_vectors in WI */ if (bnad_txq_wi_prepare(bnad, tcb, skb, txqent)) { - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); return NETDEV_TX_OK; } txqent->hdr.wi.reserved = 0; @@ -2854,6 +3038,11 @@ unmap = head_unmap; dma_addr = dma_map_single(&bnad->pcidev->dev, skb->data, len, DMA_TO_DEVICE); + if (dma_mapping_error(&bnad->pcidev->dev, dma_addr)) { + dev_kfree_skb_any(skb); + BNAD_UPDATE_CTR(bnad, tx_skb_map_failed); + return NETDEV_TX_OK; + } BNA_SET_DMA_ADDR(dma_addr, &txqent->vector[0].host_addr); txqent->vector[0].length = htons(len); dma_unmap_addr_set(&unmap->vectors[0], dma_addr, dma_addr); @@ -2861,13 +3050,13 @@ for (i = 0, vect_id = 0; i < vectors - 1; i++) { const struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[i]; - u16 size = skb_frag_size(frag); + u32 size = skb_frag_size(frag); if (unlikely(size == 0)) { /* Undo the changes starting at tcb->producer_index */ bnad_tx_buff_unmap(bnad, unmap_q, q_depth, tcb->producer_index); - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); BNAD_UPDATE_CTR(bnad, tx_skb_frag_zero); return NETDEV_TX_OK; } @@ -2879,24 +3068,33 @@ vect_id = 0; BNA_QE_INDX_INC(prod, q_depth); txqent = &((struct bna_txq_entry *)tcb->sw_q)[prod]; - txqent->hdr.wi_ext.opcode = - __constant_htons(BNA_TXQ_WI_EXTENSION); + txqent->hdr.wi_ext.opcode = htons(BNA_TXQ_WI_EXTENSION); unmap = &unmap_q[prod]; } dma_addr = skb_frag_dma_map(&bnad->pcidev->dev, frag, 0, size, DMA_TO_DEVICE); + if (dma_mapping_error(&bnad->pcidev->dev, dma_addr)) { + /* Undo the changes starting at tcb->producer_index */ + bnad_tx_buff_unmap(bnad, unmap_q, q_depth, + tcb->producer_index); + dev_kfree_skb_any(skb); + BNAD_UPDATE_CTR(bnad, tx_skb_map_failed); + return NETDEV_TX_OK; + } + + dma_unmap_len_set(&unmap->vectors[vect_id], dma_len, size); BNA_SET_DMA_ADDR(dma_addr, &txqent->vector[vect_id].host_addr); txqent->vector[vect_id].length = htons(size); dma_unmap_addr_set(&unmap->vectors[vect_id], dma_addr, - dma_addr); + dma_addr); head_unmap->nvecs++; } if (unlikely(len != skb->len)) { /* Undo the changes starting at tcb->producer_index */ bnad_tx_buff_unmap(bnad, unmap_q, q_depth, tcb->producer_index); - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); BNAD_UPDATE_CTR(bnad, tx_skb_len_mismatch); return NETDEV_TX_OK; } @@ -2904,12 +3102,15 @@ BNA_QE_INDX_INC(prod, q_depth); tcb->producer_index = prod; - wmb(); + smp_mb(); if (unlikely(!test_bit(BNAD_TXQ_TX_STARTED, &tcb->flags))) return NETDEV_TX_OK; + skb_tx_timestamp(skb); + bna_txq_prod_indx_doorbell(tcb); + smp_mb(); return NETDEV_TX_OK; } @@ -2934,73 +3135,125 @@ return stats; } +static void +bnad_set_rx_ucast_fltr(struct bnad *bnad) +{ + struct net_device *netdev = bnad->netdev; + int uc_count = netdev_uc_count(netdev); + enum bna_cb_status ret; + u8 *mac_list; + struct netdev_hw_addr *ha; + int entry; + + if (netdev_uc_empty(bnad->netdev)) { + bna_rx_ucast_listset(bnad->rx_info[0].rx, 0, NULL); + return; + } + + if (uc_count > bna_attr(&bnad->bna)->num_ucmac) + goto mode_default; + + mac_list = kzalloc(uc_count * ETH_ALEN, GFP_ATOMIC); + if (mac_list == NULL) + goto mode_default; + + entry = 0; + netdev_for_each_uc_addr(ha, netdev) { + ether_addr_copy(&mac_list[entry * ETH_ALEN], &ha->addr[0]); + entry++; + } + + ret = bna_rx_ucast_listset(bnad->rx_info[0].rx, entry, mac_list); + kfree(mac_list); + + if (ret != BNA_CB_SUCCESS) + goto mode_default; + + return; + + /* ucast packets not in UCAM are routed to default function */ +mode_default: + bnad->cfg_flags |= BNAD_CF_DEFAULT; + bna_rx_ucast_listset(bnad->rx_info[0].rx, 0, NULL); +} + +static void +bnad_set_rx_mcast_fltr(struct bnad *bnad) +{ + struct net_device *netdev = bnad->netdev; + int mc_count = netdev_mc_count(netdev); + enum bna_cb_status ret; + u8 *mac_list; + + if (netdev->flags & IFF_ALLMULTI) + goto mode_allmulti; + + if (netdev_mc_empty(netdev)) + return; + + if (mc_count > bna_attr(&bnad->bna)->num_mcmac) + goto mode_allmulti; + + mac_list = kzalloc((mc_count + 1) * ETH_ALEN, GFP_ATOMIC); + + if (mac_list == NULL) + goto mode_allmulti; + + ether_addr_copy(&mac_list[0], &bnad_bcast_addr[0]); + + /* copy rest of the MCAST addresses */ + bnad_netdev_mc_list_get(netdev, mac_list); + ret = bna_rx_mcast_listset(bnad->rx_info[0].rx, mc_count + 1, mac_list); + kfree(mac_list); + + if (ret != BNA_CB_SUCCESS) + goto mode_allmulti; + + return; + +mode_allmulti: + bnad->cfg_flags |= BNAD_CF_ALLMULTI; + bna_rx_mcast_delall(bnad->rx_info[0].rx); +} + void bnad_set_rx_mode(struct net_device *netdev) { struct bnad *bnad = netdev_priv(netdev); - u32 new_mask, valid_mask; + enum bna_rxmode new_mode, mode_mask; unsigned long flags; spin_lock_irqsave(&bnad->bna_lock, flags); - new_mask = valid_mask = 0; - - if (netdev->flags & IFF_PROMISC) { - if (!(bnad->cfg_flags & BNAD_CF_PROMISC)) { - new_mask = BNAD_RXMODE_PROMISC_DEFAULT; - valid_mask = BNAD_RXMODE_PROMISC_DEFAULT; - bnad->cfg_flags |= BNAD_CF_PROMISC; - } - } else { - if (bnad->cfg_flags & BNAD_CF_PROMISC) { - new_mask = ~BNAD_RXMODE_PROMISC_DEFAULT; - valid_mask = BNAD_RXMODE_PROMISC_DEFAULT; - bnad->cfg_flags &= ~BNAD_CF_PROMISC; - } - } - - if (netdev->flags & IFF_ALLMULTI) { - if (!(bnad->cfg_flags & BNAD_CF_ALLMULTI)) { - new_mask |= BNA_RXMODE_ALLMULTI; - valid_mask |= BNA_RXMODE_ALLMULTI; - bnad->cfg_flags |= BNAD_CF_ALLMULTI; - } - } else { - if (bnad->cfg_flags & BNAD_CF_ALLMULTI) { - new_mask &= ~BNA_RXMODE_ALLMULTI; - valid_mask |= BNA_RXMODE_ALLMULTI; - bnad->cfg_flags &= ~BNAD_CF_ALLMULTI; - } + if (bnad->rx_info[0].rx == NULL) { + spin_unlock_irqrestore(&bnad->bna_lock, flags); + return; } - if (bnad->rx_info[0].rx == NULL) - goto unlock; - - bna_rx_mode_set(bnad->rx_info[0].rx, new_mask, valid_mask, NULL); + /* clear bnad flags to update it with new settings */ + bnad->cfg_flags &= ~(BNAD_CF_PROMISC | BNAD_CF_DEFAULT | + BNAD_CF_ALLMULTI); - if (!netdev_mc_empty(netdev)) { - u8 *mcaddr_list; - int mc_count = netdev_mc_count(netdev); + new_mode = 0; + if (netdev->flags & IFF_PROMISC) { + new_mode |= BNAD_RXMODE_PROMISC_DEFAULT; + bnad->cfg_flags |= BNAD_CF_PROMISC; + } else { + bnad_set_rx_mcast_fltr(bnad); - /* Index 0 holds the broadcast address */ - mcaddr_list = - kzalloc((mc_count + 1) * ETH_ALEN, - GFP_ATOMIC); - if (!mcaddr_list) - goto unlock; + if (bnad->cfg_flags & BNAD_CF_ALLMULTI) + new_mode |= BNA_RXMODE_ALLMULTI; - memcpy(&mcaddr_list[0], &bnad_bcast_addr[0], ETH_ALEN); + bnad_set_rx_ucast_fltr(bnad); - /* Copy rest of the MC addresses */ - bnad_netdev_mc_list_get(netdev, mcaddr_list); + if (bnad->cfg_flags & BNAD_CF_DEFAULT) + new_mode |= BNA_RXMODE_DEFAULT; + } - bna_rx_mcast_listset(bnad->rx_info[0].rx, mc_count + 1, - mcaddr_list, NULL); + mode_mask = BNA_RXMODE_PROMISC | BNA_RXMODE_DEFAULT | + BNA_RXMODE_ALLMULTI; + bna_rx_mode_set(bnad->rx_info[0].rx, new_mode, mode_mask); - /* Should we enable BNAD_CF_ALLMULTI for err != 0 ? */ - kfree(mcaddr_list); - } -unlock: spin_unlock_irqrestore(&bnad->bna_lock, flags); } @@ -3010,19 +3263,18 @@ * in a non-blocking context. */ static int -bnad_set_mac_address(struct net_device *netdev, void *mac_addr) +bnad_set_mac_address(struct net_device *netdev, void *addr) { int err; struct bnad *bnad = netdev_priv(netdev); - struct sockaddr *sa = (struct sockaddr *)mac_addr; + struct sockaddr *sa = (struct sockaddr *)addr; unsigned long flags; spin_lock_irqsave(&bnad->bna_lock, flags); err = bnad_mac_addr_set_locked(bnad, sa->sa_data); - if (!err) - memcpy(netdev->dev_addr, sa->sa_data, netdev->addr_len); + ether_addr_copy(netdev->dev_addr, sa->sa_data); spin_unlock_irqrestore(&bnad->bna_lock, flags); @@ -3030,14 +3282,14 @@ } static int -bnad_mtu_set(struct bnad *bnad, int mtu) +bnad_mtu_set(struct bnad *bnad, int frame_size) { unsigned long flags; init_completion(&bnad->bnad_completions.mtu_comp); spin_lock_irqsave(&bnad->bna_lock, flags); - bna_enet_mtu_set(&bnad->bna.enet, mtu, bnad_cb_enet_mtu_set); + bna_enet_mtu_set(&bnad->bna.enet, frame_size, bnad_cb_enet_mtu_set); spin_unlock_irqrestore(&bnad->bna_lock, flags); wait_for_completion(&bnad->bnad_completions.mtu_comp); @@ -3048,18 +3300,34 @@ static int bnad_change_mtu(struct net_device *netdev, int new_mtu) { - int err, mtu = netdev->mtu; + int err, mtu; struct bnad *bnad = netdev_priv(netdev); + u32 rx_count = 0, frame, new_frame; if (new_mtu + ETH_HLEN < ETH_ZLEN || new_mtu > BNAD_JUMBO_MTU) return -EINVAL; mutex_lock(&bnad->conf_mutex); + mtu = netdev->mtu; netdev->mtu = new_mtu; - mtu = ETH_HLEN + VLAN_HLEN + new_mtu + ETH_FCS_LEN; - err = bnad_mtu_set(bnad, mtu); + frame = BNAD_FRAME_SIZE(mtu); + new_frame = BNAD_FRAME_SIZE(new_mtu); + + /* check if multi-buffer needs to be enabled */ + if (BNAD_PCI_DEV_IS_CAT2(bnad) && + netif_running(bnad->netdev)) { + /* only when transition is over 4K */ + if ((frame <= 4096 && new_frame > 4096) || + (frame > 4096 && new_frame <= 4096)) + rx_count = bnad_reinit_rx(bnad); + } + + /* rx_count > 0 - new rx created + * - Linux set err = 0 and return + */ + err = bnad_mtu_set(bnad, new_frame); if (err) err = -EBUSY; @@ -3109,6 +3377,27 @@ return 0; } +static int bnad_set_features(struct net_device *dev, netdev_features_t features) +{ + struct bnad *bnad = netdev_priv(dev); + netdev_features_t changed = features ^ dev->features; + + if ((changed & NETIF_F_HW_VLAN_CTAG_RX) && netif_running(dev)) { + unsigned long flags; + + spin_lock_irqsave(&bnad->bna_lock, flags); + + if (features & NETIF_F_HW_VLAN_CTAG_RX) + bna_rx_vlan_strip_enable(bnad->rx_info[0].rx); + else + bna_rx_vlan_strip_disable(bnad->rx_info[0].rx); + + spin_unlock_irqrestore(&bnad->bna_lock, flags); + } + + return 0; +} + #ifdef CONFIG_NET_POLL_CONTROLLER static void bnad_netpoll(struct net_device *netdev) @@ -3156,6 +3445,7 @@ .ndo_change_mtu = bnad_change_mtu, .ndo_vlan_rx_add_vid = bnad_vlan_rx_add_vid, .ndo_vlan_rx_kill_vid = bnad_vlan_rx_kill_vid, + .ndo_set_features = bnad_set_features, #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = bnad_netpoll #endif @@ -3168,14 +3458,14 @@ netdev->hw_features = NETIF_F_SG | NETIF_F_RXCSUM | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | - NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_HW_VLAN_CTAG_TX; + NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_HW_VLAN_CTAG_TX | + NETIF_F_HW_VLAN_CTAG_RX; netdev->vlan_features = NETIF_F_SG | NETIF_F_HIGHDMA | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_TSO | NETIF_F_TSO6; - netdev->features |= netdev->hw_features | - NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_CTAG_FILTER; + netdev->features |= netdev->hw_features | NETIF_F_HW_VLAN_CTAG_FILTER; if (using_dac) netdev->features |= NETIF_F_HIGHDMA; @@ -3209,11 +3499,10 @@ bnad->bar0 = ioremap_nocache(bnad->mmio_start, bnad->mmio_len); if (!bnad->bar0) { dev_err(&pdev->dev, "ioremap for bar0 failed\n"); - pci_set_drvdata(pdev, NULL); return -ENOMEM; } - pr_info("bar0 mapped to %p, len %llu\n", bnad->bar0, - (unsigned long long) bnad->mmio_len); + dev_info(&pdev->dev, "bar0 mapped to %p, len %llu\n", bnad->bar0, + (unsigned long long) bnad->mmio_len); spin_lock_irqsave(&bnad->bna_lock, flags); if (!bnad_msix_disable) @@ -3260,7 +3549,6 @@ if (bnad->bar0) iounmap(bnad->bar0); - pci_set_drvdata(bnad->pcidev, NULL); } /* @@ -3297,17 +3585,12 @@ err = pci_request_regions(pdev, BNAD_NAME); if (err) goto disable_device; - if (!dma_set_mask(&pdev->dev, DMA_BIT_MASK(64)) && - !dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64))) { + if (!dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64))) { *using_dac = true; } else { - err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); - if (err) { - err = dma_set_coherent_mask(&pdev->dev, - DMA_BIT_MASK(32)); - if (err) - goto release_regions; - } + err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); + if (err) + goto release_regions; *using_dac = false; } pci_set_master(pdev); @@ -3340,13 +3623,10 @@ struct bfa_pcidev pcidev_info; unsigned long flags; - pr_info("bnad_pci_probe : (0x%p, 0x%p) PCI Func : (%d)\n", - pdev, pcidev_id, PCI_FUNC(pdev->devfn)); - mutex_lock(&bnad_fwimg_mutex); if (!cna_get_firmware_buf(pdev)) { mutex_unlock(&bnad_fwimg_mutex); - pr_warn("Failed to load Firmware Image!\n"); + dev_err(&pdev->dev, "failed to load firmware image!\n"); return -ENODEV; } mutex_unlock(&bnad_fwimg_mutex); @@ -3424,17 +3704,13 @@ /* Set up timers */ setup_timer(&bnad->bna.ioceth.ioc.ioc_timer, bnad_ioc_timeout, - ((unsigned long)bnad)); + (unsigned long)bnad); setup_timer(&bnad->bna.ioceth.ioc.hb_timer, bnad_ioc_hb_check, - ((unsigned long)bnad)); + (unsigned long)bnad); setup_timer(&bnad->bna.ioceth.ioc.iocpf_timer, bnad_iocpf_timeout, - ((unsigned long)bnad)); + (unsigned long)bnad); setup_timer(&bnad->bna.ioceth.ioc.sem_timer, bnad_iocpf_sem_timeout, - ((unsigned long)bnad)); - - /* Now start the timer before calling IOC */ - mod_timer(&bnad->bna.ioceth.ioc.iocpf_timer, - jiffies + msecs_to_jiffies(BNA_IOC_TIMER_FREQ)); + (unsigned long)bnad); /* * Start the chip @@ -3443,8 +3719,7 @@ */ err = bnad_ioceth_enable(bnad); if (err) { - pr_err("BNA: Initialization failed err=%d\n", - err); + dev_err(&pdev->dev, "initialization failed err=%d\n", err); goto probe_success; } @@ -3477,7 +3752,7 @@ /* Get the burnt-in mac */ spin_lock_irqsave(&bnad->bna_lock, flags); - bna_enet_perm_mac_get(&bna->enet, &bnad->perm_addr); + bna_enet_perm_mac_get(&bna->enet, bnad->perm_addr); bnad_set_netdev_perm_addr(bnad); spin_unlock_irqrestore(&bnad->bna_lock, flags); @@ -3486,7 +3761,7 @@ /* Finally, reguister with net_device layer */ err = register_netdev(netdev); if (err) { - pr_err("BNA : Registering with netdev failed\n"); + dev_err(&pdev->dev, "registering net device failed\n"); goto probe_uninit; } set_bit(BNAD_RF_NETDEV_REGISTERED, &bnad->run_flags); @@ -3538,7 +3813,6 @@ if (!netdev) return; - pr_info("%s bnad_pci_remove\n", netdev->name); bnad = netdev_priv(netdev); bna = &bnad->bna; @@ -3569,7 +3843,7 @@ free_netdev(netdev); } -static DEFINE_PCI_DEVICE_TABLE(bnad_pci_id_table) = { +static const struct pci_device_id bnad_pci_id_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_BROCADE, PCI_DEVICE_ID_BROCADE_CT), @@ -3599,15 +3873,14 @@ { int err; - pr_info("Brocade 10G Ethernet driver - version: %s\n", - BNAD_VERSION); + pr_info("bna: QLogic BR-series 10G Ethernet driver - version: %s\n", + BNAD_VERSION); bfa_nw_ioc_auto_recover(bnad_ioc_auto_recover); err = pci_register_driver(&bnad_pci_driver); if (err < 0) { - pr_err("bna : PCI registration failed in module init " - "(%d)\n", err); + pr_err("bna: PCI driver registration failed err=%d\n", err); return err; } @@ -3626,7 +3899,7 @@ MODULE_AUTHOR("Brocade"); MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Brocade 10G PCIe Ethernet driver"); +MODULE_DESCRIPTION("QLogic BR-series 10G PCIe Ethernet driver"); MODULE_VERSION(BNAD_VERSION); MODULE_FIRMWARE(CNA_FW_FILE_CT); MODULE_FIRMWARE(CNA_FW_FILE_CT2);