X-Git-Url: http://git.cascardo.info/?a=blobdiff_plain;f=drivers%2Fnet%2Fethernet%2Femulex%2Fbenet%2Fbe_main.c;h=5ba1ea5ec43df3f26609d8f5b96ebfa703b47ee5;hb=ecf1f6e1df385d17b9cdebd06edf4d1f00d217a7;hp=45662af28928619090eee250731c30a032cdd202;hpb=c502224efb2eaec47f16da39235079598a0f3ed2;p=cascardo%2Flinux.git diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 45662af28928..5ba1ea5ec43d 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005 - 2013 Emulex + * Copyright (C) 2005 - 2014 Emulex * All rights reserved. * * This program is free software; you can redistribute it and/or @@ -913,24 +913,14 @@ static int be_ipv6_tx_stall_chk(struct be_adapter *adapter, return BE3_chip(adapter) && be_ipv6_exthdr_check(skb); } -static struct sk_buff *be_xmit_workarounds(struct be_adapter *adapter, - struct sk_buff *skb, - bool *skip_hw_vlan) +static struct sk_buff *be_lancer_xmit_workarounds(struct be_adapter *adapter, + struct sk_buff *skb, + bool *skip_hw_vlan) { struct vlan_ethhdr *veh = (struct vlan_ethhdr *)skb->data; unsigned int eth_hdr_len; struct iphdr *ip; - /* Lancer, SH-R ASICs have a bug wherein Packets that are 32 bytes or less - * may cause a transmit stall on that port. So the work-around is to - * pad short packets (<= 32 bytes) to a 36-byte length. - */ - if (unlikely(!BEx_chip(adapter) && skb->len <= 32)) { - if (skb_padto(skb, 36)) - goto tx_drop; - skb->len = 36; - } - /* For padded packets, BE HW modifies tot_len field in IP header * incorrecly when VLAN tag is inserted by HW. * For padded packets, Lancer computes incorrect checksum. @@ -945,9 +935,9 @@ static struct sk_buff *be_xmit_workarounds(struct be_adapter *adapter, } /* If vlan tag is already inlined in the packet, skip HW VLAN - * tagging in UMC mode + * tagging in pvid-tagging mode */ - if ((adapter->function_mode & UMC_ENABLED) && + if (be_pvid_tagging_enabled(adapter) && veh->h_vlan_proto == htons(ETH_P_8021Q)) *skip_hw_vlan = true; @@ -959,7 +949,7 @@ static struct sk_buff *be_xmit_workarounds(struct be_adapter *adapter, vlan_tx_tag_present(skb)) { skb = be_insert_vlan_in_pkt(adapter, skb, skip_hw_vlan); if (unlikely(!skb)) - goto tx_drop; + goto err; } /* HW may lockup when VLAN HW tagging is requested on @@ -981,15 +971,39 @@ static struct sk_buff *be_xmit_workarounds(struct be_adapter *adapter, be_vlan_tag_tx_chk(adapter, skb)) { skb = be_insert_vlan_in_pkt(adapter, skb, skip_hw_vlan); if (unlikely(!skb)) - goto tx_drop; + goto err; } return skb; tx_drop: dev_kfree_skb_any(skb); +err: return NULL; } +static struct sk_buff *be_xmit_workarounds(struct be_adapter *adapter, + struct sk_buff *skb, + bool *skip_hw_vlan) +{ + /* Lancer, SH-R ASICs have a bug wherein Packets that are 32 bytes or + * less may cause a transmit stall on that port. So the work-around is + * to pad short packets (<= 32 bytes) to a 36-byte length. + */ + if (unlikely(!BEx_chip(adapter) && skb->len <= 32)) { + if (skb_padto(skb, 36)) + return NULL; + skb->len = 36; + } + + if (BEx_chip(adapter) || lancer_chip(adapter)) { + skb = be_lancer_xmit_workarounds(adapter, skb, skip_hw_vlan); + if (!skb) + return NULL; + } + + return skb; +} + static netdev_tx_t be_xmit(struct sk_buff *skb, struct net_device *netdev) { struct be_adapter *adapter = netdev_priv(netdev); @@ -1157,6 +1171,14 @@ ret: return status; } +static void be_clear_promisc(struct be_adapter *adapter) +{ + adapter->promiscuous = false; + adapter->flags &= ~BE_FLAGS_VLAN_PROMISC; + + be_cmd_rx_filter(adapter, IFF_PROMISC, OFF); +} + static void be_set_rx_mode(struct net_device *netdev) { struct be_adapter *adapter = netdev_priv(netdev); @@ -1170,9 +1192,7 @@ static void be_set_rx_mode(struct net_device *netdev) /* BE was previously in promiscuous mode; disable it */ if (adapter->promiscuous) { - adapter->promiscuous = false; - be_cmd_rx_filter(adapter, IFF_PROMISC, OFF); - + be_clear_promisc(adapter); if (adapter->vlans_added) be_vid_config(adapter); } @@ -1444,11 +1464,15 @@ static struct be_rx_page_info *get_rx_page_info(struct be_rx_obj *rxo) rx_page_info = &rxo->page_info_tbl[frag_idx]; BUG_ON(!rx_page_info->page); - if (rx_page_info->last_page_user) { + if (rx_page_info->last_frag) { dma_unmap_page(&adapter->pdev->dev, dma_unmap_addr(rx_page_info, bus), adapter->big_page_size, DMA_FROM_DEVICE); - rx_page_info->last_page_user = false; + rx_page_info->last_frag = false; + } else { + dma_sync_single_for_cpu(&adapter->pdev->dev, + dma_unmap_addr(rx_page_info, bus), + rx_frag_size, DMA_FROM_DEVICE); } queue_tail_inc(rxq); @@ -1656,7 +1680,7 @@ static void be_parse_rx_compl_v1(struct be_eth_rx_compl *compl, rxcp->rss_hash = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, rsshash, compl); if (rxcp->vlanf) { - rxcp->vtm = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, vtm, + rxcp->qnq = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, qnq, compl); rxcp->vlan_tag = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, vlan_tag, compl); @@ -1686,7 +1710,7 @@ static void be_parse_rx_compl_v0(struct be_eth_rx_compl *compl, rxcp->rss_hash = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, rsshash, compl); if (rxcp->vlanf) { - rxcp->vtm = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, vtm, + rxcp->qnq = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, qnq, compl); rxcp->vlan_tag = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, vlan_tag, compl); @@ -1719,9 +1743,11 @@ static struct be_rx_compl_info *be_rx_compl_get(struct be_rx_obj *rxo) rxcp->l4_csum = 0; if (rxcp->vlanf) { - /* vlanf could be wrongly set in some cards. - * ignore if vtm is not set */ - if ((adapter->function_mode & FLEX10_MODE) && !rxcp->vtm) + /* In QNQ modes, if qnq bit is not set, then the packet was + * tagged only with the transparent outer vlan-tag and must + * not be treated as a vlan packet by host + */ + if (be_is_qnq_mode(adapter) && !rxcp->qnq) rxcp->vlanf = 0; if (!lancer_chip(adapter)) @@ -1780,17 +1806,16 @@ static void be_post_rx_frags(struct be_rx_obj *rxo, gfp_t gfp) rx_stats(rxo)->rx_post_fail++; break; } - page_info->page_offset = 0; + page_offset = 0; } else { get_page(pagep); - page_info->page_offset = page_offset + rx_frag_size; + page_offset += rx_frag_size; } - page_offset = page_info->page_offset; + page_info->page_offset = page_offset; page_info->page = pagep; - dma_unmap_addr_set(page_info, bus, page_dmaaddr); - frag_dmaaddr = page_dmaaddr + page_info->page_offset; rxd = queue_head_node(rxq); + frag_dmaaddr = page_dmaaddr + page_info->page_offset; rxd->fragpa_lo = cpu_to_le32(frag_dmaaddr & 0xFFFFFFFF); rxd->fragpa_hi = cpu_to_le32(upper_32_bits(frag_dmaaddr)); @@ -1798,15 +1823,24 @@ static void be_post_rx_frags(struct be_rx_obj *rxo, gfp_t gfp) if ((page_offset + rx_frag_size + rx_frag_size) > adapter->big_page_size) { pagep = NULL; - page_info->last_page_user = true; + page_info->last_frag = true; + dma_unmap_addr_set(page_info, bus, page_dmaaddr); + } else { + dma_unmap_addr_set(page_info, bus, frag_dmaaddr); } prev_page_info = page_info; queue_head_inc(rxq); page_info = &rxo->page_info_tbl[rxq->head]; } - if (pagep) - prev_page_info->last_page_user = true; + + /* Mark the last frag of a page when we break out of the above loop + * with no more slots available in the RXQ + */ + if (pagep) { + prev_page_info->last_frag = true; + dma_unmap_addr_set(prev_page_info, bus, page_dmaaddr); + } if (posted) { atomic_add(posted, &rxq->used); @@ -2419,6 +2453,9 @@ void be_detect_error(struct be_adapter *adapter) u32 ue_lo = 0, ue_hi = 0, ue_lo_mask = 0, ue_hi_mask = 0; u32 sliport_status = 0, sliport_err1 = 0, sliport_err2 = 0; u32 i; + bool error_detected = false; + struct device *dev = &adapter->pdev->dev; + struct net_device *netdev = adapter->netdev; if (be_hw_error(adapter)) return; @@ -2430,6 +2467,21 @@ void be_detect_error(struct be_adapter *adapter) SLIPORT_ERROR1_OFFSET); sliport_err2 = ioread32(adapter->db + SLIPORT_ERROR2_OFFSET); + adapter->hw_error = true; + /* Do not log error messages if its a FW reset */ + if (sliport_err1 == SLIPORT_ERROR_FW_RESET1 && + sliport_err2 == SLIPORT_ERROR_FW_RESET2) { + dev_info(dev, "Firmware update in progress\n"); + } else { + error_detected = true; + dev_err(dev, "Error detected in the card\n"); + dev_err(dev, "ERR: sliport status 0x%x\n", + sliport_status); + dev_err(dev, "ERR: sliport error1 0x%x\n", + sliport_err1); + dev_err(dev, "ERR: sliport error2 0x%x\n", + sliport_err2); + } } } else { pci_read_config_dword(adapter->pdev, @@ -2443,51 +2495,33 @@ void be_detect_error(struct be_adapter *adapter) ue_lo = (ue_lo & ~ue_lo_mask); ue_hi = (ue_hi & ~ue_hi_mask); - } - - /* On certain platforms BE hardware can indicate spurious UEs. - * Allow the h/w to stop working completely in case of a real UE. - * Hence not setting the hw_error for UE detection. - */ - if (sliport_status & SLIPORT_STATUS_ERR_MASK) { - adapter->hw_error = true; - /* Do not log error messages if its a FW reset */ - if (sliport_err1 == SLIPORT_ERROR_FW_RESET1 && - sliport_err2 == SLIPORT_ERROR_FW_RESET2) { - dev_info(&adapter->pdev->dev, - "Firmware update in progress\n"); - return; - } else { - dev_err(&adapter->pdev->dev, - "Error detected in the card\n"); - } - } - if (sliport_status & SLIPORT_STATUS_ERR_MASK) { - dev_err(&adapter->pdev->dev, - "ERR: sliport status 0x%x\n", sliport_status); - dev_err(&adapter->pdev->dev, - "ERR: sliport error1 0x%x\n", sliport_err1); - dev_err(&adapter->pdev->dev, - "ERR: sliport error2 0x%x\n", sliport_err2); - } - - if (ue_lo) { - for (i = 0; ue_lo; ue_lo >>= 1, i++) { - if (ue_lo & 1) - dev_err(&adapter->pdev->dev, - "UE: %s bit set\n", ue_status_low_desc[i]); - } - } + /* On certain platforms BE hardware can indicate spurious UEs. + * Allow HW to stop working completely in case of a real UE. + * Hence not setting the hw_error for UE detection. + */ - if (ue_hi) { - for (i = 0; ue_hi; ue_hi >>= 1, i++) { - if (ue_hi & 1) - dev_err(&adapter->pdev->dev, - "UE: %s bit set\n", ue_status_hi_desc[i]); + if (ue_lo || ue_hi) { + error_detected = true; + dev_err(dev, + "Unrecoverable Error detected in the adapter"); + dev_err(dev, "Please reboot server to recover"); + if (skyhawk_chip(adapter)) + adapter->hw_error = true; + for (i = 0; ue_lo; ue_lo >>= 1, i++) { + if (ue_lo & 1) + dev_err(dev, "UE: %s bit set\n", + ue_status_low_desc[i]); + } + for (i = 0; ue_hi; ue_hi >>= 1, i++) { + if (ue_hi & 1) + dev_err(dev, "UE: %s bit set\n", + ue_status_hi_desc[i]); + } } } - + if (error_detected) + netif_carrier_off(netdev); } static void be_msix_disable(struct be_adapter *adapter) @@ -2501,7 +2535,7 @@ static void be_msix_disable(struct be_adapter *adapter) static int be_msix_enable(struct be_adapter *adapter) { - int i, status, num_vec; + int i, num_vec; struct device *dev = &adapter->pdev->dev; /* If RoCE is supported, program the max number of NIC vectors that @@ -2517,24 +2551,11 @@ static int be_msix_enable(struct be_adapter *adapter) for (i = 0; i < num_vec; i++) adapter->msix_entries[i].entry = i; - status = pci_enable_msix(adapter->pdev, adapter->msix_entries, num_vec); - if (status == 0) { - goto done; - } else if (status >= MIN_MSIX_VECTORS) { - num_vec = status; - status = pci_enable_msix(adapter->pdev, adapter->msix_entries, - num_vec); - if (!status) - goto done; - } - - dev_warn(dev, "MSIx enable failed\n"); + num_vec = pci_enable_msix_range(adapter->pdev, adapter->msix_entries, + MIN_MSIX_VECTORS, num_vec); + if (num_vec < 0) + goto fail; - /* INTx is not supported in VFs, so fail probe if enable_msix fails */ - if (!be_physfn(adapter)) - return status; - return 0; -done: if (be_roce_supported(adapter) && num_vec > MIN_MSIX_VECTORS) { adapter->num_msix_roce_vec = num_vec / 2; dev_info(dev, "enabled %d MSI-x vector(s) for RoCE\n", @@ -2546,6 +2567,14 @@ done: dev_info(dev, "enabled %d MSI-x vector(s) for NIC\n", adapter->num_msix_vec); return 0; + +fail: + dev_warn(dev, "MSIx enable failed\n"); + + /* INTx is not supported in VFs, so fail probe if enable_msix fails */ + if (!be_physfn(adapter)) + return num_vec; + return 0; } static inline int be_msix_vec_get(struct be_adapter *adapter, @@ -3099,19 +3128,38 @@ err: return status; } +/* Converting function_mode bits on BE3 to SH mc_type enums */ + +static u8 be_convert_mc_type(u32 function_mode) +{ + if (function_mode & VNIC_MODE && function_mode & FLEX10_MODE) + return vNIC1; + else if (function_mode & FLEX10_MODE) + return FLEX10; + else if (function_mode & VNIC_MODE) + return vNIC2; + else if (function_mode & UMC_ENABLED) + return UMC; + else + return MC_NONE; +} + /* On BE2/BE3 FW does not suggest the supported limits */ static void BEx_get_resources(struct be_adapter *adapter, struct be_resources *res) { struct pci_dev *pdev = adapter->pdev; bool use_sriov = false; - int max_vfs; - - max_vfs = pci_sriov_get_totalvfs(pdev); - - if (BE3_chip(adapter) && sriov_want(adapter)) { - res->max_vfs = max_vfs > 0 ? min(MAX_VFS, max_vfs) : 0; - use_sriov = res->max_vfs; + int max_vfs = 0; + + if (be_physfn(adapter) && BE3_chip(adapter)) { + be_cmd_get_profile_config(adapter, res, 0); + /* Some old versions of BE3 FW don't report max_vfs value */ + if (res->max_vfs == 0) { + max_vfs = pci_sriov_get_totalvfs(pdev); + res->max_vfs = max_vfs > 0 ? min(MAX_VFS, max_vfs) : 0; + } + use_sriov = res->max_vfs && sriov_want(adapter); } if (be_physfn(adapter)) @@ -3119,12 +3167,23 @@ static void BEx_get_resources(struct be_adapter *adapter, else res->max_uc_mac = BE_VF_UC_PMAC_COUNT; - if (adapter->function_mode & FLEX10_MODE) - res->max_vlans = BE_NUM_VLANS_SUPPORTED/8; - else if (adapter->function_mode & UMC_ENABLED) - res->max_vlans = BE_UMC_NUM_VLANS_SUPPORTED; - else + adapter->mc_type = be_convert_mc_type(adapter->function_mode); + + if (be_is_mc(adapter)) { + /* Assuming that there are 4 channels per port, + * when multi-channel is enabled + */ + if (be_is_qnq_mode(adapter)) + res->max_vlans = BE_NUM_VLANS_SUPPORTED/8; + else + /* In a non-qnq multichannel mode, the pvid + * takes up one vlan entry + */ + res->max_vlans = (BE_NUM_VLANS_SUPPORTED / 4) - 1; + } else { res->max_vlans = BE_NUM_VLANS_SUPPORTED; + } + res->max_mcast_mac = BE_MAX_MC; /* For BE3 1Gb ports, F/W does not properly support multiple TXQs */ @@ -3141,7 +3200,7 @@ static void BEx_get_resources(struct be_adapter *adapter, res->max_rx_qs = res->max_rss_qs + 1; if (be_physfn(adapter)) - res->max_evt_qs = (max_vfs > 0) ? + res->max_evt_qs = (res->max_vfs > 0) ? BE3_SRIOV_MAX_EVT_QS : BE3_MAX_EVT_QS; else res->max_evt_qs = 1; @@ -4407,14 +4466,32 @@ static bool be_reset_required(struct be_adapter *adapter) static char *mc_name(struct be_adapter *adapter) { - if (adapter->function_mode & FLEX10_MODE) - return "FLEX10"; - else if (adapter->function_mode & VNIC_MODE) - return "vNIC"; - else if (adapter->function_mode & UMC_ENABLED) - return "UMC"; - else - return ""; + char *str = ""; /* default */ + + switch (adapter->mc_type) { + case UMC: + str = "UMC"; + break; + case FLEX10: + str = "FLEX10"; + break; + case vNIC1: + str = "vNIC-1"; + break; + case nPAR: + str = "nPAR"; + break; + case UFP: + str = "UFP"; + break; + case vNIC2: + str = "vNIC-2"; + break; + default: + str = ""; + } + + return str; } static inline char *func_name(struct be_adapter *adapter)