diff options
Diffstat (limited to 'drivers/net/ethernet/chelsio')
-rw-r--r-- | drivers/net/ethernet/chelsio/cxgb/sge.c | 3 | ||||
-rw-r--r-- | drivers/net/ethernet/chelsio/cxgb4/clip_tbl.c | 3 | ||||
-rw-r--r-- | drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 3 | ||||
-rw-r--r-- | drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c | 24 | ||||
-rw-r--r-- | drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 74 | ||||
-rw-r--r-- | drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c | 450 | ||||
-rw-r--r-- | drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_u32.c | 3 | ||||
-rw-r--r-- | drivers/net/ethernet/chelsio/cxgb4/l2t.c | 2 | ||||
-rw-r--r-- | drivers/net/ethernet/chelsio/cxgb4/sched.c | 2 | ||||
-rw-r--r-- | drivers/net/ethernet/chelsio/cxgb4/smt.c | 3 | ||||
-rw-r--r-- | drivers/net/ethernet/chelsio/cxgb4/t4_hw.c | 47 | ||||
-rw-r--r-- | drivers/net/ethernet/chelsio/cxgb4/t4_pci_id_tbl.h | 1 | ||||
-rw-r--r-- | drivers/net/ethernet/chelsio/cxgb4/t4fw_version.h | 12 | ||||
-rw-r--r-- | drivers/net/ethernet/chelsio/cxgb4vf/adapter.h | 3 | ||||
-rw-r--r-- | drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c | 106 | ||||
-rw-r--r-- | drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c | 6 |
16 files changed, 430 insertions, 312 deletions
diff --git a/drivers/net/ethernet/chelsio/cxgb/sge.c b/drivers/net/ethernet/chelsio/cxgb/sge.c index 30de26ef3da4..47b5c8e2104b 100644 --- a/drivers/net/ethernet/chelsio/cxgb/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb/sge.c @@ -585,8 +585,7 @@ static int alloc_rx_resources(struct sge *sge, struct sge_params *p) sizeof(struct cpl_rx_data) + sge->freelQ[!sge->jumbo_fl].dma_offset; - size = (16 * 1024) - - SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); + size = (16 * 1024) - SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); sge->freelQ[sge->jumbo_fl].rx_buffer_size = size; diff --git a/drivers/net/ethernet/chelsio/cxgb4/clip_tbl.c b/drivers/net/ethernet/chelsio/cxgb4/clip_tbl.c index 5701272aa7f7..ce28820c57c9 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/clip_tbl.c +++ b/drivers/net/ethernet/chelsio/cxgb4/clip_tbl.c @@ -289,8 +289,7 @@ struct clip_tbl *t4_init_clip_tbl(unsigned int clipt_start, if (clipt_size < CLIPT_MIN_HASH_BUCKETS) return NULL; - ctbl = kvzalloc(sizeof(*ctbl) + - clipt_size*sizeof(struct list_head), GFP_KERNEL); + ctbl = kvzalloc(struct_size(ctbl, hash_list, clipt_size), GFP_KERNEL); if (!ctbl) return NULL; diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h index 2d1ca920601e..568715a13b5c 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h @@ -568,7 +568,7 @@ struct sge_rspq; struct port_info { struct adapter *adapter; u16 viid; - s16 xact_addr_filt; /* index of exact MAC address filter */ + int xact_addr_filt; /* index of exact MAC address filter */ u16 rss_size; /* size of VI's RSS table slice */ s8 mdio_addr; enum fw_port_type port_type; @@ -860,6 +860,7 @@ struct doorbell_stats { struct hash_mac_addr { struct list_head list; u8 addr[ETH_ALEN]; + unsigned int iface_mac; }; struct uld_msix_bmap { diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c index d07230c892a5..796043544fc3 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c @@ -446,8 +446,10 @@ static void fw_caps_to_lmm(enum fw_port_type port_type, unsigned long *link_mode_mask) { #define SET_LMM(__lmm_name) \ - __set_bit(ETHTOOL_LINK_MODE_ ## __lmm_name ## _BIT, \ - link_mode_mask) + do { \ + __set_bit(ETHTOOL_LINK_MODE_ ## __lmm_name ## _BIT, \ + link_mode_mask); \ + } while (0) #define FW_CAPS_TO_LMM(__fw_name, __lmm_name) \ do { \ @@ -541,7 +543,7 @@ static void fw_caps_to_lmm(enum fw_port_type port_type, case FW_PORT_TYPE_CR4_QSFP: SET_LMM(FIBRE); FW_CAPS_TO_LMM(SPEED_1G, 1000baseT_Full); - FW_CAPS_TO_LMM(SPEED_10G, 10000baseSR_Full); + FW_CAPS_TO_LMM(SPEED_10G, 10000baseKR_Full); FW_CAPS_TO_LMM(SPEED_40G, 40000baseSR4_Full); FW_CAPS_TO_LMM(SPEED_25G, 25000baseCR_Full); FW_CAPS_TO_LMM(SPEED_50G, 50000baseCR2_Full); @@ -552,6 +554,13 @@ static void fw_caps_to_lmm(enum fw_port_type port_type, break; } + if (fw_caps & FW_PORT_CAP32_FEC_V(FW_PORT_CAP32_FEC_M)) { + FW_CAPS_TO_LMM(FEC_RS, FEC_RS); + FW_CAPS_TO_LMM(FEC_BASER_RS, FEC_BASER); + } else { + SET_LMM(FEC_NONE); + } + FW_CAPS_TO_LMM(ANEG, Autoneg); FW_CAPS_TO_LMM(802_3_PAUSE, Pause); FW_CAPS_TO_LMM(802_3_ASM_DIR, Asym_Pause); @@ -679,18 +688,15 @@ static int set_link_ksettings(struct net_device *dev, base->autoneg == AUTONEG_DISABLE) { fw_caps = speed_to_fw_caps(base->speed); - /* Must only specify a single speed which must be supported - * as part of the Physical Port Capabilities. - */ - if ((fw_caps & (fw_caps - 1)) != 0 || - !(lc->pcaps & fw_caps)) + /* Speed must be supported by Physical Port Capabilities. */ + if (!(lc->pcaps & fw_caps)) return -EINVAL; lc->speed_caps = fw_caps; lc->acaps = fw_caps; } else { fw_caps = - lmm_to_fw_caps(link_ksettings->link_modes.advertising); + lmm_to_fw_caps(link_ksettings->link_modes.advertising); if (!(lc->pcaps & fw_caps)) return -EINVAL; lc->speed_caps = 0; diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index 6ba9099ca7fe..adf75d16e6d3 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -433,6 +433,60 @@ static int set_rxmode(struct net_device *dev, int mtu, bool sleep_ok) } /** + * cxgb4_change_mac - Update match filter for a MAC address. + * @pi: the port_info + * @viid: the VI id + * @tcam_idx: TCAM index of existing filter for old value of MAC address, + * or -1 + * @addr: the new MAC address value + * @persist: whether a new MAC allocation should be persistent + * @add_smt: if true also add the address to the HW SMT + * + * Modifies an MPS filter and sets it to the new MAC address if + * @tcam_idx >= 0, or adds the MAC address to a new filter if + * @tcam_idx < 0. In the latter case the address is added persistently + * if @persist is %true. + * Addresses are programmed to hash region, if tcam runs out of entries. + * + */ +static int cxgb4_change_mac(struct port_info *pi, unsigned int viid, + int *tcam_idx, const u8 *addr, bool persist, + u8 *smt_idx) +{ + struct adapter *adapter = pi->adapter; + struct hash_mac_addr *entry, *new_entry; + int ret; + + ret = t4_change_mac(adapter, adapter->mbox, viid, + *tcam_idx, addr, persist, smt_idx); + /* We ran out of TCAM entries. try programming hash region. */ + if (ret == -ENOMEM) { + /* If the MAC address to be updated is in the hash addr + * list, update it from the list + */ + list_for_each_entry(entry, &adapter->mac_hlist, list) { + if (entry->iface_mac) { + ether_addr_copy(entry->addr, addr); + goto set_hash; + } + } + new_entry = kzalloc(sizeof(*new_entry), GFP_KERNEL); + if (!new_entry) + return -ENOMEM; + ether_addr_copy(new_entry->addr, addr); + new_entry->iface_mac = true; + list_add_tail(&new_entry->list, &adapter->mac_hlist); +set_hash: + ret = cxgb4_set_addr_hash(pi); + } else if (ret >= 0) { + *tcam_idx = ret; + ret = 0; + } + + return ret; +} + +/* * link_start - enable a port * @dev: the port to enable * @@ -450,15 +504,9 @@ static int link_start(struct net_device *dev) */ ret = t4_set_rxmode(pi->adapter, mb, pi->viid, dev->mtu, -1, -1, -1, !!(dev->features & NETIF_F_HW_VLAN_CTAG_RX), true); - if (ret == 0) { - ret = t4_change_mac(pi->adapter, mb, pi->viid, - pi->xact_addr_filt, dev->dev_addr, true, - &pi->smt_idx); - if (ret >= 0) { - pi->xact_addr_filt = ret; - ret = 0; - } - } + if (ret == 0) + ret = cxgb4_change_mac(pi, pi->viid, &pi->xact_addr_filt, + dev->dev_addr, true, &pi->smt_idx); if (ret == 0) ret = t4_link_l1cfg(pi->adapter, mb, pi->tx_chan, &pi->link_cfg); @@ -2839,9 +2887,8 @@ static int cxgb_set_mac_addr(struct net_device *dev, void *p) if (!is_valid_ether_addr(addr->sa_data)) return -EADDRNOTAVAIL; - ret = t4_change_mac(pi->adapter, pi->adapter->pf, pi->viid, - pi->xact_addr_filt, addr->sa_data, true, - &pi->smt_idx); + ret = cxgb4_change_mac(pi, pi->viid, &pi->xact_addr_filt, + addr->sa_data, true, &pi->smt_idx); if (ret < 0) return ret; @@ -5653,7 +5700,8 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent) NETIF_F_GSO_UDP_TUNNEL | NETIF_F_TSO | NETIF_F_TSO6; - netdev->hw_features |= NETIF_F_GSO_UDP_TUNNEL; + netdev->hw_features |= NETIF_F_GSO_UDP_TUNNEL | + NETIF_F_HW_TLS_RECORD; } if (highdma) diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c index c116f96956fe..82a8d1970060 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c @@ -83,28 +83,23 @@ static void cxgb4_process_flow_match(struct net_device *dev, struct tc_cls_flower_offload *cls, struct ch_filter_specification *fs) { + struct flow_rule *rule = tc_cls_flower_offload_flow_rule(cls); u16 addr_type = 0; - if (dissector_uses_key(cls->dissector, FLOW_DISSECTOR_KEY_CONTROL)) { - struct flow_dissector_key_control *key = - skb_flow_dissector_target(cls->dissector, - FLOW_DISSECTOR_KEY_CONTROL, - cls->key); + if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_CONTROL)) { + struct flow_match_control match; - addr_type = key->addr_type; + flow_rule_match_control(rule, &match); + addr_type = match.key->addr_type; } - if (dissector_uses_key(cls->dissector, FLOW_DISSECTOR_KEY_BASIC)) { - struct flow_dissector_key_basic *key = - skb_flow_dissector_target(cls->dissector, - FLOW_DISSECTOR_KEY_BASIC, - cls->key); - struct flow_dissector_key_basic *mask = - skb_flow_dissector_target(cls->dissector, - FLOW_DISSECTOR_KEY_BASIC, - cls->mask); - u16 ethtype_key = ntohs(key->n_proto); - u16 ethtype_mask = ntohs(mask->n_proto); + if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_BASIC)) { + struct flow_match_basic match; + u16 ethtype_key, ethtype_mask; + + flow_rule_match_basic(rule, &match); + ethtype_key = ntohs(match.key->n_proto); + ethtype_mask = ntohs(match.mask->n_proto); if (ethtype_key == ETH_P_ALL) { ethtype_key = 0; @@ -116,115 +111,89 @@ static void cxgb4_process_flow_match(struct net_device *dev, fs->val.ethtype = ethtype_key; fs->mask.ethtype = ethtype_mask; - fs->val.proto = key->ip_proto; - fs->mask.proto = mask->ip_proto; + fs->val.proto = match.key->ip_proto; + fs->mask.proto = match.mask->ip_proto; } if (addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS) { - struct flow_dissector_key_ipv4_addrs *key = - skb_flow_dissector_target(cls->dissector, - FLOW_DISSECTOR_KEY_IPV4_ADDRS, - cls->key); - struct flow_dissector_key_ipv4_addrs *mask = - skb_flow_dissector_target(cls->dissector, - FLOW_DISSECTOR_KEY_IPV4_ADDRS, - cls->mask); + struct flow_match_ipv4_addrs match; + + flow_rule_match_ipv4_addrs(rule, &match); fs->type = 0; - memcpy(&fs->val.lip[0], &key->dst, sizeof(key->dst)); - memcpy(&fs->val.fip[0], &key->src, sizeof(key->src)); - memcpy(&fs->mask.lip[0], &mask->dst, sizeof(mask->dst)); - memcpy(&fs->mask.fip[0], &mask->src, sizeof(mask->src)); + memcpy(&fs->val.lip[0], &match.key->dst, sizeof(match.key->dst)); + memcpy(&fs->val.fip[0], &match.key->src, sizeof(match.key->src)); + memcpy(&fs->mask.lip[0], &match.mask->dst, sizeof(match.mask->dst)); + memcpy(&fs->mask.fip[0], &match.mask->src, sizeof(match.mask->src)); /* also initialize nat_lip/fip to same values */ - memcpy(&fs->nat_lip[0], &key->dst, sizeof(key->dst)); - memcpy(&fs->nat_fip[0], &key->src, sizeof(key->src)); - + memcpy(&fs->nat_lip[0], &match.key->dst, sizeof(match.key->dst)); + memcpy(&fs->nat_fip[0], &match.key->src, sizeof(match.key->src)); } if (addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS) { - struct flow_dissector_key_ipv6_addrs *key = - skb_flow_dissector_target(cls->dissector, - FLOW_DISSECTOR_KEY_IPV6_ADDRS, - cls->key); - struct flow_dissector_key_ipv6_addrs *mask = - skb_flow_dissector_target(cls->dissector, - FLOW_DISSECTOR_KEY_IPV6_ADDRS, - cls->mask); + struct flow_match_ipv6_addrs match; + flow_rule_match_ipv6_addrs(rule, &match); fs->type = 1; - memcpy(&fs->val.lip[0], key->dst.s6_addr, sizeof(key->dst)); - memcpy(&fs->val.fip[0], key->src.s6_addr, sizeof(key->src)); - memcpy(&fs->mask.lip[0], mask->dst.s6_addr, sizeof(mask->dst)); - memcpy(&fs->mask.fip[0], mask->src.s6_addr, sizeof(mask->src)); + memcpy(&fs->val.lip[0], match.key->dst.s6_addr, + sizeof(match.key->dst)); + memcpy(&fs->val.fip[0], match.key->src.s6_addr, + sizeof(match.key->src)); + memcpy(&fs->mask.lip[0], match.mask->dst.s6_addr, + sizeof(match.mask->dst)); + memcpy(&fs->mask.fip[0], match.mask->src.s6_addr, + sizeof(match.mask->src)); /* also initialize nat_lip/fip to same values */ - memcpy(&fs->nat_lip[0], key->dst.s6_addr, sizeof(key->dst)); - memcpy(&fs->nat_fip[0], key->src.s6_addr, sizeof(key->src)); + memcpy(&fs->nat_lip[0], match.key->dst.s6_addr, + sizeof(match.key->dst)); + memcpy(&fs->nat_fip[0], match.key->src.s6_addr, + sizeof(match.key->src)); } - if (dissector_uses_key(cls->dissector, FLOW_DISSECTOR_KEY_PORTS)) { - struct flow_dissector_key_ports *key, *mask; + if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_PORTS)) { + struct flow_match_ports match; - key = skb_flow_dissector_target(cls->dissector, - FLOW_DISSECTOR_KEY_PORTS, - cls->key); - mask = skb_flow_dissector_target(cls->dissector, - FLOW_DISSECTOR_KEY_PORTS, - cls->mask); - fs->val.lport = cpu_to_be16(key->dst); - fs->mask.lport = cpu_to_be16(mask->dst); - fs->val.fport = cpu_to_be16(key->src); - fs->mask.fport = cpu_to_be16(mask->src); + flow_rule_match_ports(rule, &match); + fs->val.lport = cpu_to_be16(match.key->dst); + fs->mask.lport = cpu_to_be16(match.mask->dst); + fs->val.fport = cpu_to_be16(match.key->src); + fs->mask.fport = cpu_to_be16(match.mask->src); /* also initialize nat_lport/fport to same values */ - fs->nat_lport = cpu_to_be16(key->dst); - fs->nat_fport = cpu_to_be16(key->src); + fs->nat_lport = cpu_to_be16(match.key->dst); + fs->nat_fport = cpu_to_be16(match.key->src); } - if (dissector_uses_key(cls->dissector, FLOW_DISSECTOR_KEY_IP)) { - struct flow_dissector_key_ip *key, *mask; - - key = skb_flow_dissector_target(cls->dissector, - FLOW_DISSECTOR_KEY_IP, - cls->key); - mask = skb_flow_dissector_target(cls->dissector, - FLOW_DISSECTOR_KEY_IP, - cls->mask); - fs->val.tos = key->tos; - fs->mask.tos = mask->tos; + if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IP)) { + struct flow_match_ip match; + + flow_rule_match_ip(rule, &match); + fs->val.tos = match.key->tos; + fs->mask.tos = match.mask->tos; } - if (dissector_uses_key(cls->dissector, FLOW_DISSECTOR_KEY_ENC_KEYID)) { - struct flow_dissector_key_keyid *key, *mask; - - key = skb_flow_dissector_target(cls->dissector, - FLOW_DISSECTOR_KEY_ENC_KEYID, - cls->key); - mask = skb_flow_dissector_target(cls->dissector, - FLOW_DISSECTOR_KEY_ENC_KEYID, - cls->mask); - fs->val.vni = be32_to_cpu(key->keyid); - fs->mask.vni = be32_to_cpu(mask->keyid); + if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_KEYID)) { + struct flow_match_enc_keyid match; + + flow_rule_match_enc_keyid(rule, &match); + fs->val.vni = be32_to_cpu(match.key->keyid); + fs->mask.vni = be32_to_cpu(match.mask->keyid); if (fs->mask.vni) { fs->val.encap_vld = 1; fs->mask.encap_vld = 1; } } - if (dissector_uses_key(cls->dissector, FLOW_DISSECTOR_KEY_VLAN)) { - struct flow_dissector_key_vlan *key, *mask; + if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_VLAN)) { + struct flow_match_vlan match; u16 vlan_tci, vlan_tci_mask; - key = skb_flow_dissector_target(cls->dissector, - FLOW_DISSECTOR_KEY_VLAN, - cls->key); - mask = skb_flow_dissector_target(cls->dissector, - FLOW_DISSECTOR_KEY_VLAN, - cls->mask); - vlan_tci = key->vlan_id | (key->vlan_priority << - VLAN_PRIO_SHIFT); - vlan_tci_mask = mask->vlan_id | (mask->vlan_priority << - VLAN_PRIO_SHIFT); + flow_rule_match_vlan(rule, &match); + vlan_tci = match.key->vlan_id | (match.key->vlan_priority << + VLAN_PRIO_SHIFT); + vlan_tci_mask = match.mask->vlan_id | (match.mask->vlan_priority << + VLAN_PRIO_SHIFT); fs->val.ivlan = vlan_tci; fs->mask.ivlan = vlan_tci_mask; @@ -255,10 +224,12 @@ static void cxgb4_process_flow_match(struct net_device *dev, static int cxgb4_validate_flow_match(struct net_device *dev, struct tc_cls_flower_offload *cls) { + struct flow_rule *rule = tc_cls_flower_offload_flow_rule(cls); + struct flow_dissector *dissector = rule->match.dissector; u16 ethtype_mask = 0; u16 ethtype_key = 0; - if (cls->dissector->used_keys & + if (dissector->used_keys & ~(BIT(FLOW_DISSECTOR_KEY_CONTROL) | BIT(FLOW_DISSECTOR_KEY_BASIC) | BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) | @@ -268,36 +239,29 @@ static int cxgb4_validate_flow_match(struct net_device *dev, BIT(FLOW_DISSECTOR_KEY_VLAN) | BIT(FLOW_DISSECTOR_KEY_IP))) { netdev_warn(dev, "Unsupported key used: 0x%x\n", - cls->dissector->used_keys); + dissector->used_keys); return -EOPNOTSUPP; } - if (dissector_uses_key(cls->dissector, FLOW_DISSECTOR_KEY_BASIC)) { - struct flow_dissector_key_basic *key = - skb_flow_dissector_target(cls->dissector, - FLOW_DISSECTOR_KEY_BASIC, - cls->key); - struct flow_dissector_key_basic *mask = - skb_flow_dissector_target(cls->dissector, - FLOW_DISSECTOR_KEY_BASIC, - cls->mask); - ethtype_key = ntohs(key->n_proto); - ethtype_mask = ntohs(mask->n_proto); + if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_BASIC)) { + struct flow_match_basic match; + + flow_rule_match_basic(rule, &match); + ethtype_key = ntohs(match.key->n_proto); + ethtype_mask = ntohs(match.mask->n_proto); } - if (dissector_uses_key(cls->dissector, FLOW_DISSECTOR_KEY_IP)) { + if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IP)) { u16 eth_ip_type = ethtype_key & ethtype_mask; - struct flow_dissector_key_ip *mask; + struct flow_match_ip match; if (eth_ip_type != ETH_P_IP && eth_ip_type != ETH_P_IPV6) { netdev_err(dev, "IP Key supported only with IPv4/v6"); return -EINVAL; } - mask = skb_flow_dissector_target(cls->dissector, - FLOW_DISSECTOR_KEY_IP, - cls->mask); - if (mask->ttl) { + flow_rule_match_ip(rule, &match); + if (match.mask->ttl) { netdev_warn(dev, "ttl match unsupported for offload"); return -EOPNOTSUPP; } @@ -328,7 +292,7 @@ static void process_pedit_field(struct ch_filter_specification *fs, u32 val, u32 mask, u32 offset, u8 htype) { switch (htype) { - case TCA_PEDIT_KEY_EX_HDR_TYPE_ETH: + case FLOW_ACT_MANGLE_HDR_TYPE_ETH: switch (offset) { case PEDIT_ETH_DMAC_31_0: fs->newdmac = 1; @@ -346,7 +310,7 @@ static void process_pedit_field(struct ch_filter_specification *fs, u32 val, offload_pedit(fs, val, mask, ETH_SMAC_47_16); } break; - case TCA_PEDIT_KEY_EX_HDR_TYPE_IP4: + case FLOW_ACT_MANGLE_HDR_TYPE_IP4: switch (offset) { case PEDIT_IP4_SRC: offload_pedit(fs, val, mask, IP4_SRC); @@ -356,7 +320,7 @@ static void process_pedit_field(struct ch_filter_specification *fs, u32 val, } fs->nat_mode = NAT_MODE_ALL; break; - case TCA_PEDIT_KEY_EX_HDR_TYPE_IP6: + case FLOW_ACT_MANGLE_HDR_TYPE_IP6: switch (offset) { case PEDIT_IP6_SRC_31_0: offload_pedit(fs, val, mask, IP6_SRC_31_0); @@ -384,7 +348,7 @@ static void process_pedit_field(struct ch_filter_specification *fs, u32 val, } fs->nat_mode = NAT_MODE_ALL; break; - case TCA_PEDIT_KEY_EX_HDR_TYPE_TCP: + case FLOW_ACT_MANGLE_HDR_TYPE_TCP: switch (offset) { case PEDIT_TCP_SPORT_DPORT: if (~mask & PEDIT_TCP_UDP_SPORT_MASK) @@ -397,7 +361,7 @@ static void process_pedit_field(struct ch_filter_specification *fs, u32 val, } fs->nat_mode = NAT_MODE_ALL; break; - case TCA_PEDIT_KEY_EX_HDR_TYPE_UDP: + case FLOW_ACT_MANGLE_HDR_TYPE_UDP: switch (offset) { case PEDIT_UDP_SPORT_DPORT: if (~mask & PEDIT_TCP_UDP_SPORT_MASK) @@ -416,56 +380,63 @@ static void cxgb4_process_flow_actions(struct net_device *in, struct tc_cls_flower_offload *cls, struct ch_filter_specification *fs) { - const struct tc_action *a; + struct flow_rule *rule = tc_cls_flower_offload_flow_rule(cls); + struct flow_action_entry *act; int i; - tcf_exts_for_each_action(i, a, cls->exts) { - if (is_tcf_gact_ok(a)) { + flow_action_for_each(i, act, &rule->action) { + switch (act->id) { + case FLOW_ACTION_ACCEPT: fs->action = FILTER_PASS; - } else if (is_tcf_gact_shot(a)) { + break; + case FLOW_ACTION_DROP: fs->action = FILTER_DROP; - } else if (is_tcf_mirred_egress_redirect(a)) { - struct net_device *out = tcf_mirred_dev(a); + break; + case FLOW_ACTION_REDIRECT: { + struct net_device *out = act->dev; struct port_info *pi = netdev_priv(out); fs->action = FILTER_SWITCH; fs->eport = pi->port_id; - } else if (is_tcf_vlan(a)) { - u32 vlan_action = tcf_vlan_action(a); - u8 prio = tcf_vlan_push_prio(a); - u16 vid = tcf_vlan_push_vid(a); + } + break; + case FLOW_ACTION_VLAN_POP: + case FLOW_ACTION_VLAN_PUSH: + case FLOW_ACTION_VLAN_MANGLE: { + u8 prio = act->vlan.prio; + u16 vid = act->vlan.vid; u16 vlan_tci = (prio << VLAN_PRIO_SHIFT) | vid; - - switch (vlan_action) { - case TCA_VLAN_ACT_POP: + switch (act->id) { + case FLOW_ACTION_VLAN_POP: fs->newvlan |= VLAN_REMOVE; break; - case TCA_VLAN_ACT_PUSH: + case FLOW_ACTION_VLAN_PUSH: fs->newvlan |= VLAN_INSERT; fs->vlan = vlan_tci; break; - case TCA_VLAN_ACT_MODIFY: + case FLOW_ACTION_VLAN_MANGLE: fs->newvlan |= VLAN_REWRITE; fs->vlan = vlan_tci; break; default: break; } - } else if (is_tcf_pedit(a)) { + } + break; + case FLOW_ACTION_MANGLE: { u32 mask, val, offset; - int nkeys, i; u8 htype; - nkeys = tcf_pedit_nkeys(a); - for (i = 0; i < nkeys; i++) { - htype = tcf_pedit_htype(a, i); - mask = tcf_pedit_mask(a, i); - val = tcf_pedit_val(a, i); - offset = tcf_pedit_offset(a, i); + htype = act->mangle.htype; + mask = act->mangle.mask; + val = act->mangle.val; + offset = act->mangle.offset; - process_pedit_field(fs, val, mask, offset, - htype); + process_pedit_field(fs, val, mask, offset, htype); } + break; + default: + break; } } } @@ -484,101 +455,89 @@ static bool valid_l4_mask(u32 mask) } static bool valid_pedit_action(struct net_device *dev, - const struct tc_action *a) + const struct flow_action_entry *act) { u32 mask, offset; - u8 cmd, htype; - int nkeys, i; - - nkeys = tcf_pedit_nkeys(a); - for (i = 0; i < nkeys; i++) { - htype = tcf_pedit_htype(a, i); - cmd = tcf_pedit_cmd(a, i); - mask = tcf_pedit_mask(a, i); - offset = tcf_pedit_offset(a, i); - - if (cmd != TCA_PEDIT_KEY_EX_CMD_SET) { - netdev_err(dev, "%s: Unsupported pedit cmd\n", + u8 htype; + + htype = act->mangle.htype; + mask = act->mangle.mask; + offset = act->mangle.offset; + + switch (htype) { + case FLOW_ACT_MANGLE_HDR_TYPE_ETH: + switch (offset) { + case PEDIT_ETH_DMAC_31_0: + case PEDIT_ETH_DMAC_47_32_SMAC_15_0: + case PEDIT_ETH_SMAC_47_16: + break; + default: + netdev_err(dev, "%s: Unsupported pedit field\n", __func__); return false; } - - switch (htype) { - case TCA_PEDIT_KEY_EX_HDR_TYPE_ETH: - switch (offset) { - case PEDIT_ETH_DMAC_31_0: - case PEDIT_ETH_DMAC_47_32_SMAC_15_0: - case PEDIT_ETH_SMAC_47_16: - break; - default: - netdev_err(dev, "%s: Unsupported pedit field\n", - __func__); - return false; - } - break; - case TCA_PEDIT_KEY_EX_HDR_TYPE_IP4: - switch (offset) { - case PEDIT_IP4_SRC: - case PEDIT_IP4_DST: - break; - default: - netdev_err(dev, "%s: Unsupported pedit field\n", - __func__); - return false; - } + break; + case FLOW_ACT_MANGLE_HDR_TYPE_IP4: + switch (offset) { + case PEDIT_IP4_SRC: + case PEDIT_IP4_DST: break; - case TCA_PEDIT_KEY_EX_HDR_TYPE_IP6: - switch (offset) { - case PEDIT_IP6_SRC_31_0: - case PEDIT_IP6_SRC_63_32: - case PEDIT_IP6_SRC_95_64: - case PEDIT_IP6_SRC_127_96: - case PEDIT_IP6_DST_31_0: - case PEDIT_IP6_DST_63_32: - case PEDIT_IP6_DST_95_64: - case PEDIT_IP6_DST_127_96: - break; - default: - netdev_err(dev, "%s: Unsupported pedit field\n", - __func__); - return false; - } + default: + netdev_err(dev, "%s: Unsupported pedit field\n", + __func__); + return false; + } + break; + case FLOW_ACT_MANGLE_HDR_TYPE_IP6: + switch (offset) { + case PEDIT_IP6_SRC_31_0: + case PEDIT_IP6_SRC_63_32: + case PEDIT_IP6_SRC_95_64: + case PEDIT_IP6_SRC_127_96: + case PEDIT_IP6_DST_31_0: + case PEDIT_IP6_DST_63_32: + case PEDIT_IP6_DST_95_64: + case PEDIT_IP6_DST_127_96: break; - case TCA_PEDIT_KEY_EX_HDR_TYPE_TCP: - switch (offset) { - case PEDIT_TCP_SPORT_DPORT: - if (!valid_l4_mask(~mask)) { - netdev_err(dev, "%s: Unsupported mask for TCP L4 ports\n", - __func__); - return false; - } - break; - default: - netdev_err(dev, "%s: Unsupported pedit field\n", + default: + netdev_err(dev, "%s: Unsupported pedit field\n", + __func__); + return false; + } + break; + case FLOW_ACT_MANGLE_HDR_TYPE_TCP: + switch (offset) { + case PEDIT_TCP_SPORT_DPORT: + if (!valid_l4_mask(~mask)) { + netdev_err(dev, "%s: Unsupported mask for TCP L4 ports\n", __func__); return false; } break; - case TCA_PEDIT_KEY_EX_HDR_TYPE_UDP: - switch (offset) { - case PEDIT_UDP_SPORT_DPORT: - if (!valid_l4_mask(~mask)) { - netdev_err(dev, "%s: Unsupported mask for UDP L4 ports\n", - __func__); - return false; - } - break; - default: - netdev_err(dev, "%s: Unsupported pedit field\n", + default: + netdev_err(dev, "%s: Unsupported pedit field\n", + __func__); + return false; + } + break; + case FLOW_ACT_MANGLE_HDR_TYPE_UDP: + switch (offset) { + case PEDIT_UDP_SPORT_DPORT: + if (!valid_l4_mask(~mask)) { + netdev_err(dev, "%s: Unsupported mask for UDP L4 ports\n", __func__); return false; } break; default: - netdev_err(dev, "%s: Unsupported pedit type\n", + netdev_err(dev, "%s: Unsupported pedit field\n", __func__); return false; } + break; + default: + netdev_err(dev, "%s: Unsupported pedit type\n", __func__); + return false; } return true; } @@ -586,24 +545,26 @@ static bool valid_pedit_action(struct net_device *dev, static int cxgb4_validate_flow_actions(struct net_device *dev, struct tc_cls_flower_offload *cls) { - const struct tc_action *a; + struct flow_rule *rule = tc_cls_flower_offload_flow_rule(cls); + struct flow_action_entry *act; bool act_redir = false; bool act_pedit = false; bool act_vlan = false; int i; - tcf_exts_for_each_action(i, a, cls->exts) { - if (is_tcf_gact_ok(a)) { - /* Do nothing */ - } else if (is_tcf_gact_shot(a)) { + flow_action_for_each(i, act, &rule->action) { + switch (act->id) { + case FLOW_ACTION_ACCEPT: + case FLOW_ACTION_DROP: /* Do nothing */ - } else if (is_tcf_mirred_egress_redirect(a)) { + break; + case FLOW_ACTION_REDIRECT: { struct adapter *adap = netdev2adap(dev); struct net_device *n_dev, *target_dev; unsigned int i; bool found = false; - target_dev = tcf_mirred_dev(a); + target_dev = act->dev; for_each_port(adap, i) { n_dev = adap->port[i]; if (target_dev == n_dev) { @@ -621,15 +582,18 @@ static int cxgb4_validate_flow_actions(struct net_device *dev, return -EINVAL; } act_redir = true; - } else if (is_tcf_vlan(a)) { - u16 proto = be16_to_cpu(tcf_vlan_push_proto(a)); - u32 vlan_action = tcf_vlan_action(a); + } + break; + case FLOW_ACTION_VLAN_POP: + case FLOW_ACTION_VLAN_PUSH: + case FLOW_ACTION_VLAN_MANGLE: { + u16 proto = be16_to_cpu(act->vlan.proto); - switch (vlan_action) { - case TCA_VLAN_ACT_POP: + switch (act->id) { + case FLOW_ACTION_VLAN_POP: break; - case TCA_VLAN_ACT_PUSH: - case TCA_VLAN_ACT_MODIFY: + case FLOW_ACTION_VLAN_PUSH: + case FLOW_ACTION_VLAN_MANGLE: if (proto != ETH_P_8021Q) { netdev_err(dev, "%s: Unsupported vlan proto\n", __func__); @@ -642,13 +606,17 @@ static int cxgb4_validate_flow_actions(struct net_device *dev, return -EOPNOTSUPP; } act_vlan = true; - } else if (is_tcf_pedit(a)) { - bool pedit_valid = valid_pedit_action(dev, a); + } + break; + case FLOW_ACTION_MANGLE: { + bool pedit_valid = valid_pedit_action(dev, act); if (!pedit_valid) return -EOPNOTSUPP; act_pedit = true; - } else { + } + break; + default: netdev_err(dev, "%s: Unsupported action\n", __func__); return -EOPNOTSUPP; } @@ -843,9 +811,9 @@ int cxgb4_tc_flower_stats(struct net_device *dev, if (ofld_stats->packet_count != packets) { if (ofld_stats->prev_packet_count != packets) ofld_stats->last_used = jiffies; - tcf_exts_stats_update(cls->exts, bytes - ofld_stats->byte_count, - packets - ofld_stats->packet_count, - ofld_stats->last_used); + flow_stats_update(&cls->stats, bytes - ofld_stats->byte_count, + packets - ofld_stats->packet_count, + ofld_stats->last_used); ofld_stats->packet_count = packets; ofld_stats->byte_count = bytes; diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_u32.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_u32.c index c7d2b4dc7568..02fc63fa7f25 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_u32.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_u32.c @@ -444,8 +444,7 @@ struct cxgb4_tc_u32_table *cxgb4_init_tc_u32(struct adapter *adap) if (!max_tids) return NULL; - t = kvzalloc(sizeof(*t) + - (max_tids * sizeof(struct cxgb4_link)), GFP_KERNEL); + t = kvzalloc(struct_size(t, table, max_tids), GFP_KERNEL); if (!t) return NULL; diff --git a/drivers/net/ethernet/chelsio/cxgb4/l2t.c b/drivers/net/ethernet/chelsio/cxgb4/l2t.c index 4852febbfec3..1a407d3c1d67 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/l2t.c +++ b/drivers/net/ethernet/chelsio/cxgb4/l2t.c @@ -646,7 +646,7 @@ struct l2t_data *t4_init_l2t(unsigned int l2t_start, unsigned int l2t_end) if (l2t_size < L2T_MIN_HASH_BUCKETS) return NULL; - d = kvzalloc(sizeof(*d) + l2t_size * sizeof(struct l2t_entry), GFP_KERNEL); + d = kvzalloc(struct_size(d, l2tab, l2t_size), GFP_KERNEL); if (!d) return NULL; diff --git a/drivers/net/ethernet/chelsio/cxgb4/sched.c b/drivers/net/ethernet/chelsio/cxgb4/sched.c index 52edb688942b..ba6c153ee45c 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/sched.c +++ b/drivers/net/ethernet/chelsio/cxgb4/sched.c @@ -478,7 +478,7 @@ struct sched_table *t4_init_sched(unsigned int sched_size) struct sched_table *s; unsigned int i; - s = kvzalloc(sizeof(*s) + sched_size * sizeof(struct sched_class), GFP_KERNEL); + s = kvzalloc(struct_size(s, tab, sched_size), GFP_KERNEL); if (!s) return NULL; diff --git a/drivers/net/ethernet/chelsio/cxgb4/smt.c b/drivers/net/ethernet/chelsio/cxgb4/smt.c index 7b2207a2a130..eaf1fb74689c 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/smt.c +++ b/drivers/net/ethernet/chelsio/cxgb4/smt.c @@ -47,8 +47,7 @@ struct smt_data *t4_init_smt(void) smt_size = SMT_SIZE; - s = kvzalloc(sizeof(*s) + smt_size * sizeof(struct smt_entry), - GFP_KERNEL); + s = kvzalloc(struct_size(s, smtab, smt_size), GFP_KERNEL); if (!s) return NULL; s->smt_size = smt_size; diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c index 2b03f6187a24..c5e5466ee38b 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c @@ -4105,6 +4105,9 @@ static inline fw_port_cap32_t cc_to_fwcap_fec(enum cc_fec cc_fec) * @mbox: the Firmware Mailbox to use * @port: the Port ID * @lc: the Port's Link Configuration + * @sleep_ok: if true we may sleep while awaiting command completion + * @timeout: time to wait for command to finish before timing out + * (negative implies @sleep_ok=false) * * Set up a port's MAC and PHY according to a desired link configuration. * - If the PHY can auto-negotiate first decide what to advertise, then @@ -4124,6 +4127,7 @@ int t4_link_l1cfg_core(struct adapter *adapter, unsigned int mbox, int ret; fw_mdi = (FW_PORT_CAP32_MDI_V(FW_PORT_CAP32_MDI_AUTO) & lc->pcaps); + /* Convert driver coding of Pause Frame Flow Control settings into the * Firmware's API. */ @@ -4143,8 +4147,13 @@ int t4_link_l1cfg_core(struct adapter *adapter, unsigned int mbox, fw_fec = cc_to_fwcap_fec(cc_fec); /* Figure out what our Requested Port Capabilities are going to be. + * Note parallel structure in t4_handle_get_port_info() and + * init_link_config(). */ if (!(lc->pcaps & FW_PORT_CAP32_ANEG)) { + if (lc->autoneg == AUTONEG_ENABLE) + return -EINVAL; + rcap = lc->acaps | fw_fc | fw_fec; lc->fc = lc->requested_fc & ~PAUSE_AUTONEG; lc->fec = cc_fec; @@ -4156,7 +4165,11 @@ int t4_link_l1cfg_core(struct adapter *adapter, unsigned int mbox, rcap = lc->acaps | fw_fc | fw_fec | fw_mdi; } - /* Note that older Firmware doesn't have FW_PORT_CAP32_FORCE_PAUSE, so + /* Some Requested Port Capabilities are trivially wrong if they exceed + * the Physical Port Capabilities. We can check that here and provide + * moderately useful feedback in the system log. + * + * Note that older Firmware doesn't have FW_PORT_CAP32_FORCE_PAUSE, so * we need to exclude this from this check in order to maintain * compatibility ... */ @@ -4185,6 +4198,13 @@ int t4_link_l1cfg_core(struct adapter *adapter, unsigned int mbox, ret = t4_wr_mbox_meat_timeout(adapter, mbox, &cmd, sizeof(cmd), NULL, sleep_ok, timeout); + + /* Unfortunately, even if the Requested Port Capabilities "fit" within + * the Physical Port Capabilities, some combinations of features may + * still not be leagal. For example, 40Gb/s and Reed-Solomon Forward + * Error Correction. So if the Firmware rejects the L1 Configure + * request, flag that here. + */ if (ret) { dev_err(adapter->pdev_dev, "Requested Port Capabilities %#x rejected, error %d\n", @@ -8461,6 +8481,10 @@ void t4_handle_get_port_info(struct port_info *pi, const __be64 *rpl) fc = fwcap_to_cc_pause(linkattr); speed = fwcap_to_speed(linkattr); + /* Reset state for communicating new Transceiver Module status and + * whether the OS-dependent layer wants us to redo the current + * "sticky" L1 Configure Link Parameters. + */ lc->new_module = false; lc->redo_l1cfg = false; @@ -8497,9 +8521,15 @@ void t4_handle_get_port_info(struct port_info *pi, const __be64 *rpl) */ pi->port_type = port_type; + /* Record new Module Type information. + */ pi->mod_type = mod_type; + /* Let the OS-dependent layer know if we have a new + * Transceiver Module inserted. + */ lc->new_module = t4_is_inserted_mod_type(mod_type); + t4_os_portmod_changed(adapter, pi->port_id); } @@ -8507,8 +8537,10 @@ void t4_handle_get_port_info(struct port_info *pi, const __be64 *rpl) fc != lc->fc || fec != lc->fec) { /* something changed */ if (!link_ok && lc->link_ok) { lc->link_down_rc = linkdnrc; - dev_warn(adapter->pdev_dev, "Port %d link down, reason: %s\n", - pi->tx_chan, t4_link_down_rc_str(linkdnrc)); + dev_warn_ratelimited(adapter->pdev_dev, + "Port %d link down, reason: %s\n", + pi->tx_chan, + t4_link_down_rc_str(linkdnrc)); } lc->link_ok = link_ok; lc->speed = speed; @@ -8518,6 +8550,11 @@ void t4_handle_get_port_info(struct port_info *pi, const __be64 *rpl) lc->lpacaps = lpacaps; lc->acaps = acaps & ADVERT_MASK; + /* If we're not physically capable of Auto-Negotiation, note + * this as Auto-Negotiation disabled. Otherwise, we track + * what Auto-Negotiation settings we have. Note parallel + * structure in t4_link_l1cfg_core() and init_link_config(). + */ if (!(lc->acaps & FW_PORT_CAP32_ANEG)) { lc->autoneg = AUTONEG_DISABLE; } else if (lc->acaps & FW_PORT_CAP32_ANEG) { @@ -8535,6 +8572,10 @@ void t4_handle_get_port_info(struct port_info *pi, const __be64 *rpl) t4_os_link_changed(adapter, pi->port_id, link_ok); } + /* If we have a new Transceiver Module and the OS-dependent code has + * told us that it wants us to redo whatever "sticky" L1 Configuration + * Link Parameters are set, do that now. + */ if (lc->new_module && lc->redo_l1cfg) { struct link_config old_lc; int ret; diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_pci_id_tbl.h b/drivers/net/ethernet/chelsio/cxgb4/t4_pci_id_tbl.h index bf7325f6d553..0c5373462ced 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_pci_id_tbl.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_pci_id_tbl.h @@ -218,6 +218,7 @@ CH_PCI_DEVICE_ID_TABLE_DEFINE_BEGIN CH_PCI_ID_TABLE_FENTRY(0x6088), /* Custom T62100-CR */ CH_PCI_ID_TABLE_FENTRY(0x6089), /* Custom T62100-KR */ CH_PCI_ID_TABLE_FENTRY(0x608a), /* Custom T62100-CR */ + CH_PCI_ID_TABLE_FENTRY(0x608b), /* Custom T6225-CR */ CH_PCI_DEVICE_ID_TABLE_DEFINE_END; #endif /* __T4_PCI_ID_TBL_H__ */ diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4fw_version.h b/drivers/net/ethernet/chelsio/cxgb4/t4fw_version.h index a844296135b4..9125ddd89dd1 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4fw_version.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4fw_version.h @@ -36,8 +36,8 @@ #define __T4FW_VERSION_H__ #define T4FW_VERSION_MAJOR 0x01 -#define T4FW_VERSION_MINOR 0x14 -#define T4FW_VERSION_MICRO 0x08 +#define T4FW_VERSION_MINOR 0x16 +#define T4FW_VERSION_MICRO 0x09 #define T4FW_VERSION_BUILD 0x00 #define T4FW_MIN_VERSION_MAJOR 0x01 @@ -45,8 +45,8 @@ #define T4FW_MIN_VERSION_MICRO 0x00 #define T5FW_VERSION_MAJOR 0x01 -#define T5FW_VERSION_MINOR 0x14 -#define T5FW_VERSION_MICRO 0x08 +#define T5FW_VERSION_MINOR 0x16 +#define T5FW_VERSION_MICRO 0x09 #define T5FW_VERSION_BUILD 0x00 #define T5FW_MIN_VERSION_MAJOR 0x00 @@ -54,8 +54,8 @@ #define T5FW_MIN_VERSION_MICRO 0x00 #define T6FW_VERSION_MAJOR 0x01 -#define T6FW_VERSION_MINOR 0x14 -#define T6FW_VERSION_MICRO 0x08 +#define T6FW_VERSION_MINOR 0x16 +#define T6FW_VERSION_MICRO 0x09 #define T6FW_VERSION_BUILD 0x00 #define T6FW_MIN_VERSION_MAJOR 0x00 diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/adapter.h b/drivers/net/ethernet/chelsio/cxgb4vf/adapter.h index 5883f09e3804..26f48a14d2f9 100644 --- a/drivers/net/ethernet/chelsio/cxgb4vf/adapter.h +++ b/drivers/net/ethernet/chelsio/cxgb4vf/adapter.h @@ -94,7 +94,7 @@ struct port_info { struct adapter *adapter; /* our adapter */ u32 vlan_id; /* vlan id for VST */ u16 viid; /* virtual interface ID */ - s16 xact_addr_filt; /* index of our MAC address filter */ + int xact_addr_filt; /* index of our MAC address filter */ u16 rss_size; /* size of VI's RSS table slice */ u8 pidx; /* index into adapter port[] */ s8 mdio_addr; @@ -352,6 +352,7 @@ struct sge { struct hash_mac_addr { struct list_head list; u8 addr[ETH_ALEN]; + unsigned int iface_mac; }; struct mbox_list { diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c b/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c index 2fab87e86561..84be3313fede 100644 --- a/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c @@ -236,6 +236,73 @@ void t4vf_os_portmod_changed(struct adapter *adapter, int pidx) "inserted\n", dev->name, pi->mod_type); } +static int cxgb4vf_set_addr_hash(struct port_info *pi) +{ + struct adapter *adapter = pi->adapter; + u64 vec = 0; + bool ucast = false; + struct hash_mac_addr *entry; + + /* Calculate the hash vector for the updated list and program it */ + list_for_each_entry(entry, &adapter->mac_hlist, list) { + ucast |= is_unicast_ether_addr(entry->addr); + vec |= (1ULL << hash_mac_addr(entry->addr)); + } + return t4vf_set_addr_hash(adapter, pi->viid, ucast, vec, false); +} + +/** + * cxgb4vf_change_mac - Update match filter for a MAC address. + * @pi: the port_info + * @viid: the VI id + * @tcam_idx: TCAM index of existing filter for old value of MAC address, + * or -1 + * @addr: the new MAC address value + * @persist: whether a new MAC allocation should be persistent + * @add_smt: if true also add the address to the HW SMT + * + * Modifies an MPS filter and sets it to the new MAC address if + * @tcam_idx >= 0, or adds the MAC address to a new filter if + * @tcam_idx < 0. In the latter case the address is added persistently + * if @persist is %true. + * Addresses are programmed to hash region, if tcam runs out of entries. + * + */ +static int cxgb4vf_change_mac(struct port_info *pi, unsigned int viid, + int *tcam_idx, const u8 *addr, bool persistent) +{ + struct hash_mac_addr *new_entry, *entry; + struct adapter *adapter = pi->adapter; + int ret; + + ret = t4vf_change_mac(adapter, viid, *tcam_idx, addr, persistent); + /* We ran out of TCAM entries. try programming hash region. */ + if (ret == -ENOMEM) { + /* If the MAC address to be updated is in the hash addr + * list, update it from the list + */ + list_for_each_entry(entry, &adapter->mac_hlist, list) { + if (entry->iface_mac) { + ether_addr_copy(entry->addr, addr); + goto set_hash; + } + } + new_entry = kzalloc(sizeof(*new_entry), GFP_KERNEL); + if (!new_entry) + return -ENOMEM; + ether_addr_copy(new_entry->addr, addr); + new_entry->iface_mac = true; + list_add_tail(&new_entry->list, &adapter->mac_hlist); +set_hash: + ret = cxgb4vf_set_addr_hash(pi); + } else if (ret >= 0) { + *tcam_idx = ret; + ret = 0; + } + + return ret; +} + /* * Net device operations. * ====================== @@ -259,14 +326,10 @@ static int link_start(struct net_device *dev) */ ret = t4vf_set_rxmode(pi->adapter, pi->viid, dev->mtu, -1, -1, -1, 1, true); - if (ret == 0) { - ret = t4vf_change_mac(pi->adapter, pi->viid, - pi->xact_addr_filt, dev->dev_addr, true); - if (ret >= 0) { - pi->xact_addr_filt = ret; - ret = 0; - } - } + if (ret == 0) + ret = cxgb4vf_change_mac(pi, pi->viid, + &pi->xact_addr_filt, + dev->dev_addr, true); /* * We don't need to actually "start the link" itself since the @@ -791,6 +854,13 @@ static int cxgb4vf_open(struct net_device *dev) return err; } + /* It's possible that the basic port information could have + * changed since we first read it. + */ + err = t4vf_update_port_info(pi); + if (err < 0) + return err; + /* * Note that this interface is up and start everything up ... */ @@ -863,21 +933,6 @@ static struct net_device_stats *cxgb4vf_get_stats(struct net_device *dev) return ns; } -static inline int cxgb4vf_set_addr_hash(struct port_info *pi) -{ - struct adapter *adapter = pi->adapter; - u64 vec = 0; - bool ucast = false; - struct hash_mac_addr *entry; - - /* Calculate the hash vector for the updated list and program it */ - list_for_each_entry(entry, &adapter->mac_hlist, list) { - ucast |= is_unicast_ether_addr(entry->addr); - vec |= (1ULL << hash_mac_addr(entry->addr)); - } - return t4vf_set_addr_hash(adapter, pi->viid, ucast, vec, false); -} - static int cxgb4vf_mac_sync(struct net_device *netdev, const u8 *mac_addr) { struct port_info *pi = netdev_priv(netdev); @@ -1159,13 +1214,12 @@ static int cxgb4vf_set_mac_addr(struct net_device *dev, void *_addr) if (!is_valid_ether_addr(addr->sa_data)) return -EADDRNOTAVAIL; - ret = t4vf_change_mac(pi->adapter, pi->viid, pi->xact_addr_filt, - addr->sa_data, true); + ret = cxgb4vf_change_mac(pi, pi->viid, &pi->xact_addr_filt, + addr->sa_data, true); if (ret < 0) return ret; memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); - pi->xact_addr_filt = ret; return 0; } diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c b/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c index 5b8c08cf523f..84dff74ca9cd 100644 --- a/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c @@ -2005,8 +2005,10 @@ static void t4vf_handle_get_port_info(struct port_info *pi, fc != lc->fc || fec != lc->fec) { /* something changed */ if (!link_ok && lc->link_ok) { lc->link_down_rc = linkdnrc; - dev_warn(adapter->pdev_dev, "Port %d link down, reason: %s\n", - pi->port_id, t4vf_link_down_rc_str(linkdnrc)); + dev_warn_ratelimited(adapter->pdev_dev, + "Port %d link down, reason: %s\n", + pi->port_id, + t4vf_link_down_rc_str(linkdnrc)); } lc->link_ok = link_ok; lc->speed = speed; |