summaryrefslogtreecommitdiff
path: root/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c')
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c140
1 files changed, 93 insertions, 47 deletions
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
index 4ccc806b1150..40beef5bca88 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
@@ -21,6 +21,7 @@
#include <linux/if_vlan.h>
#include <linux/interrupt.h>
#include <linux/ip.h>
+#include <linux/crash_dump.h>
#include <net/tcp.h>
#include <net/ipv6.h>
#include <net/ip6_checksum.h>
@@ -64,7 +65,7 @@ static int bnx2x_calc_num_queues(struct bnx2x *bp)
int nq = bnx2x_num_queues ? : netif_get_num_default_rss_queues();
/* Reduce memory usage in kdump environment by using only one queue */
- if (reset_devices)
+ if (is_kdump_kernel())
nq = 1;
nq = clamp(nq, 1, BNX2X_MAX_QUEUES(bp));
@@ -1063,6 +1064,11 @@ reuse_rx:
skb_record_rx_queue(skb, fp->rx_queue);
+ /* Check if this packet was timestamped */
+ if (unlikely(cqe->fast_path_cqe.type_error_flags &
+ (1 << ETH_FAST_PATH_RX_CQE_PTP_PKT_SHIFT)))
+ bnx2x_set_rx_ts(bp, skb);
+
if (le16_to_cpu(cqe_fp->pars_flags.flags) &
PARSING_FLAGS_VLAN)
__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q),
@@ -1932,7 +1938,7 @@ void bnx2x_set_num_queues(struct bnx2x *bp)
bp->num_ethernet_queues = bnx2x_calc_num_queues(bp);
/* override in STORAGE SD modes */
- if (IS_MF_STORAGE_SD(bp) || IS_MF_FCOE_AFEX(bp))
+ if (IS_MF_STORAGE_ONLY(bp))
bp->num_ethernet_queues = 1;
/* Add special queues */
@@ -2078,6 +2084,10 @@ int bnx2x_rss(struct bnx2x *bp, struct bnx2x_rss_config_obj *rss_obj,
__set_bit(BNX2X_RSS_IPV4_UDP, &params.rss_flags);
if (rss_obj->udp_rss_v6)
__set_bit(BNX2X_RSS_IPV6_UDP, &params.rss_flags);
+
+ if (!CHIP_IS_E1x(bp))
+ /* valid only for TUNN_MODE_GRE tunnel mode */
+ __set_bit(BNX2X_RSS_GRE_INNER_HDRS, &params.rss_flags);
} else {
__set_bit(BNX2X_RSS_MODE_DISABLED, &params.rss_flags);
}
@@ -2800,7 +2810,11 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
/* Initialize Rx filter. */
bnx2x_set_rx_mode_inner(bp);
- /* Start the Tx */
+ if (bp->flags & PTP_SUPPORTED) {
+ bnx2x_init_ptp(bp);
+ bnx2x_configure_ptp_filters(bp);
+ }
+ /* Start Tx */
switch (load_mode) {
case LOAD_NORMAL:
/* Tx queue should be only re-enabled */
@@ -3437,26 +3451,6 @@ exit_lbl:
}
#endif
-static void bnx2x_set_pbd_gso_e2(struct sk_buff *skb, u32 *parsing_data,
- u32 xmit_type)
-{
- struct ipv6hdr *ipv6;
-
- *parsing_data |= (skb_shinfo(skb)->gso_size <<
- ETH_TX_PARSE_BD_E2_LSO_MSS_SHIFT) &
- ETH_TX_PARSE_BD_E2_LSO_MSS;
-
- if (xmit_type & XMIT_GSO_ENC_V6)
- ipv6 = inner_ipv6_hdr(skb);
- else if (xmit_type & XMIT_GSO_V6)
- ipv6 = ipv6_hdr(skb);
- else
- ipv6 = NULL;
-
- if (ipv6 && ipv6->nexthdr == NEXTHDR_IPV6)
- *parsing_data |= ETH_TX_PARSE_BD_E2_IPV6_WITH_EXT_HDR;
-}
-
/**
* bnx2x_set_pbd_gso - update PBD in GSO case.
*
@@ -3466,7 +3460,6 @@ static void bnx2x_set_pbd_gso_e2(struct sk_buff *skb, u32 *parsing_data,
*/
static void bnx2x_set_pbd_gso(struct sk_buff *skb,
struct eth_tx_parse_bd_e1x *pbd,
- struct eth_tx_start_bd *tx_start_bd,
u32 xmit_type)
{
pbd->lso_mss = cpu_to_le16(skb_shinfo(skb)->gso_size);
@@ -3479,9 +3472,6 @@ static void bnx2x_set_pbd_gso(struct sk_buff *skb,
bswab16(~csum_tcpudp_magic(ip_hdr(skb)->saddr,
ip_hdr(skb)->daddr,
0, IPPROTO_TCP, 0));
-
- /* GSO on 57710/57711 needs FW to calculate IP checksum */
- tx_start_bd->bd_flags.as_bitfield |= ETH_TX_BD_FLAGS_IP_CSUM;
} else {
pbd->tcp_pseudo_csum =
bswab16(~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
@@ -3653,18 +3643,23 @@ static void bnx2x_update_pbds_gso_enc(struct sk_buff *skb,
(__force u32)iph->tot_len -
(__force u32)iph->frag_off;
+ outerip_len = iph->ihl << 1;
+
pbd2->fw_ip_csum_wo_len_flags_frag =
bswab16(csum_fold((__force __wsum)csum));
} else {
pbd2->fw_ip_hdr_to_payload_w =
hlen_w - ((sizeof(struct ipv6hdr)) >> 1);
+ pbd_e2->data.tunnel_data.flags |=
+ ETH_TUNNEL_DATA_IP_HDR_TYPE_OUTER;
}
pbd2->tcp_send_seq = bswab32(inner_tcp_hdr(skb)->seq);
pbd2->tcp_flags = pbd_tcp_flags(inner_tcp_hdr(skb));
- if (xmit_type & XMIT_GSO_V4) {
+ /* inner IP header info */
+ if (xmit_type & XMIT_CSUM_ENC_V4) {
pbd2->hw_ip_id = bswab16(inner_ip_hdr(skb)->id);
pbd_e2->data.tunnel_data.pseudo_csum =
@@ -3672,8 +3667,6 @@ static void bnx2x_update_pbds_gso_enc(struct sk_buff *skb,
inner_ip_hdr(skb)->saddr,
inner_ip_hdr(skb)->daddr,
0, IPPROTO_TCP, 0));
-
- outerip_len = ip_hdr(skb)->ihl << 1;
} else {
pbd_e2->data.tunnel_data.pseudo_csum =
bswab16(~csum_ipv6_magic(
@@ -3686,8 +3679,6 @@ static void bnx2x_update_pbds_gso_enc(struct sk_buff *skb,
*global_data |=
outerip_off |
- (!!(xmit_type & XMIT_CSUM_V6) <<
- ETH_TX_PARSE_2ND_BD_IP_HDR_TYPE_OUTER_SHIFT) |
(outerip_len <<
ETH_TX_PARSE_2ND_BD_IP_HDR_LEN_OUTER_W_SHIFT) |
((skb->protocol == cpu_to_be16(ETH_P_8021Q)) <<
@@ -3699,6 +3690,23 @@ static void bnx2x_update_pbds_gso_enc(struct sk_buff *skb,
}
}
+static inline void bnx2x_set_ipv6_ext_e2(struct sk_buff *skb, u32 *parsing_data,
+ u32 xmit_type)
+{
+ struct ipv6hdr *ipv6;
+
+ if (!(xmit_type & (XMIT_GSO_ENC_V6 | XMIT_GSO_V6)))
+ return;
+
+ if (xmit_type & XMIT_GSO_ENC_V6)
+ ipv6 = inner_ipv6_hdr(skb);
+ else /* XMIT_GSO_V6 */
+ ipv6 = ipv6_hdr(skb);
+
+ if (ipv6->nexthdr == NEXTHDR_IPV6)
+ *parsing_data |= ETH_TX_PARSE_BD_E2_IPV6_WITH_EXT_HDR;
+}
+
/* called with netif_tx_lock
* bnx2x_tx_int() runs without netif_tx_lock unless it needs to call
* netif_wake_queue()
@@ -3831,6 +3839,20 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
tx_start_bd->bd_flags.as_bitfield = ETH_TX_BD_FLAGS_START_BD;
+ if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) {
+ if (!(bp->flags & TX_TIMESTAMPING_EN)) {
+ BNX2X_ERR("Tx timestamping was not enabled, this packet will not be timestamped\n");
+ } else if (bp->ptp_tx_skb) {
+ BNX2X_ERR("The device supports only a single outstanding packet to timestamp, this packet will not be timestamped\n");
+ } else {
+ skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
+ /* schedule check for Tx timestamp */
+ bp->ptp_tx_skb = skb_get(skb);
+ bp->ptp_tx_start = jiffies;
+ schedule_work(&bp->ptp_task);
+ }
+ }
+
/* header nbd: indirectly zero other flags! */
tx_start_bd->general_data = 1 << ETH_TX_START_BD_HDR_NBDS_SHIFT;
@@ -3852,12 +3874,16 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* when transmitting in a vf, start bd must hold the ethertype
* for fw to enforce it
*/
+#ifndef BNX2X_STOP_ON_ERROR
if (IS_VF(bp))
+#endif
tx_start_bd->vlan_or_ethertype =
cpu_to_le16(ntohs(eth->h_proto));
+#ifndef BNX2X_STOP_ON_ERROR
else
/* used by FW for packet accounting */
tx_start_bd->vlan_or_ethertype = cpu_to_le16(pkt_prod);
+#endif
}
nbd = 2; /* start_bd + pbd + frags (updated when pages are mapped) */
@@ -3915,6 +3941,7 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
xmit_type);
}
+ bnx2x_set_ipv6_ext_e2(skb, &pbd_e2_parsing_data, xmit_type);
/* Add the macs to the parsing BD if this is a vf or if
* Tx Switching is enabled.
*/
@@ -3929,11 +3956,22 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
&pbd_e2->data.mac_addr.dst_mid,
&pbd_e2->data.mac_addr.dst_lo,
eth->h_dest);
- } else if (bp->flags & TX_SWITCHING) {
- bnx2x_set_fw_mac_addr(&pbd_e2->data.mac_addr.dst_hi,
- &pbd_e2->data.mac_addr.dst_mid,
- &pbd_e2->data.mac_addr.dst_lo,
- eth->h_dest);
+ } else {
+ if (bp->flags & TX_SWITCHING)
+ bnx2x_set_fw_mac_addr(
+ &pbd_e2->data.mac_addr.dst_hi,
+ &pbd_e2->data.mac_addr.dst_mid,
+ &pbd_e2->data.mac_addr.dst_lo,
+ eth->h_dest);
+#ifdef BNX2X_STOP_ON_ERROR
+ /* Enforce security is always set in Stop on Error -
+ * source mac should be present in the parsing BD
+ */
+ bnx2x_set_fw_mac_addr(&pbd_e2->data.mac_addr.src_hi,
+ &pbd_e2->data.mac_addr.src_mid,
+ &pbd_e2->data.mac_addr.src_lo,
+ eth->h_source);
+#endif
}
SET_FLAG(pbd_e2_parsing_data,
@@ -3980,10 +4018,12 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
bd_prod);
}
if (!CHIP_IS_E1x(bp))
- bnx2x_set_pbd_gso_e2(skb, &pbd_e2_parsing_data,
- xmit_type);
+ pbd_e2_parsing_data |=
+ (skb_shinfo(skb)->gso_size <<
+ ETH_TX_PARSE_BD_E2_LSO_MSS_SHIFT) &
+ ETH_TX_PARSE_BD_E2_LSO_MSS;
else
- bnx2x_set_pbd_gso(skb, pbd_e1x, first_bd, xmit_type);
+ bnx2x_set_pbd_gso(skb, pbd_e1x, xmit_type);
}
/* Set the PBD's parsing_data field if not zero
@@ -4191,14 +4231,13 @@ int bnx2x_change_mac_addr(struct net_device *dev, void *p)
struct bnx2x *bp = netdev_priv(dev);
int rc = 0;
- if (!bnx2x_is_valid_ether_addr(bp, addr->sa_data)) {
+ if (!is_valid_ether_addr(addr->sa_data)) {
BNX2X_ERR("Requested MAC address is not valid\n");
return -EINVAL;
}
- if ((IS_MF_STORAGE_SD(bp) || IS_MF_FCOE_AFEX(bp)) &&
- !is_zero_ether_addr(addr->sa_data)) {
- BNX2X_ERR("Can't configure non-zero address on iSCSI or FCoE functions in MF-SD mode\n");
+ if (IS_MF_STORAGE_ONLY(bp)) {
+ BNX2X_ERR("Can't change address on STORAGE ONLY function\n");
return -EINVAL;
}
@@ -4377,8 +4416,7 @@ static int bnx2x_alloc_fp_mem_at(struct bnx2x *bp, int index)
u8 cos;
int rx_ring_size = 0;
- if (!bp->rx_ring_size &&
- (IS_MF_STORAGE_SD(bp) || IS_MF_FCOE_AFEX(bp))) {
+ if (!bp->rx_ring_size && IS_MF_STORAGE_ONLY(bp)) {
rx_ring_size = MIN_RX_SIZE_NONTPA;
bp->rx_ring_size = rx_ring_size;
} else if (!bp->rx_ring_size) {
@@ -4771,11 +4809,15 @@ netdev_features_t bnx2x_fix_features(struct net_device *dev,
struct bnx2x *bp = netdev_priv(dev);
/* TPA requires Rx CSUM offloading */
- if (!(features & NETIF_F_RXCSUM) || bp->disable_tpa) {
+ if (!(features & NETIF_F_RXCSUM)) {
features &= ~NETIF_F_LRO;
features &= ~NETIF_F_GRO;
}
+ /* Note: do not disable SW GRO in kernel when HW GRO is off */
+ if (bp->disable_tpa)
+ features &= ~NETIF_F_LRO;
+
return features;
}
@@ -4814,6 +4856,10 @@ int bnx2x_set_features(struct net_device *dev, netdev_features_t features)
if ((changes & GRO_ENABLE_FLAG) && (flags & TPA_ENABLE_FLAG))
changes &= ~GRO_ENABLE_FLAG;
+ /* if GRO is changed while HW TPA is off, don't force a reload */
+ if ((changes & GRO_ENABLE_FLAG) && bp->disable_tpa)
+ changes &= ~GRO_ENABLE_FLAG;
+
if (changes)
bnx2x_reload = true;