int __fbnic_open(struct fbnic_net *fbn)
{ struct fbnic_dev *fbd = fbn->fbd; int err;
err = fbnic_alloc_napi_vectors(fbn); if (err) return err;
err = fbnic_alloc_resources(fbn); if (err) goto free_napi_vectors;
err = fbnic_set_netif_queues(fbn); if (err) goto free_resources;
/* Send ownership message and flush to verify FW has seen it */
err = fbnic_fw_xmit_ownership_msg(fbd, true); if (err) {
dev_warn(fbd->dev, "Error %d sending host ownership message to the firmware\n",
err); goto err_reset_queues;
}
err = fbnic_time_start(fbn); if (err) goto release_ownership;
err = fbnic_fw_init_heartbeat(fbd, false); if (err) goto time_stop;
err = fbnic_pcs_request_irq(fbd); if (err) goto time_stop;
/* Pull the BMC config and initialize the RPC */
fbnic_bmc_rpc_init(fbd);
fbnic_rss_reinit(fbd, fbn);
if (WARN_ON(!is_valid_ether_addr(addr))) return -EADDRNOTAVAIL;
avail_addr = __fbnic_uc_sync(fbn->fbd, addr); if (!avail_addr) return -ENOSPC;
/* Add type flag indicating this address is in use by the host */
set_bit(FBNIC_MAC_ADDR_T_UNICAST, avail_addr->act_tcam);
return 0;
}
staticint fbnic_uc_unsync(struct net_device *netdev, constunsignedchar *addr)
{ struct fbnic_net *fbn = netdev_priv(netdev); struct fbnic_dev *fbd = fbn->fbd; int i, ret;
/* Scan from middle of list to bottom, filling bottom up. * Skip the first entry which is reserved for dev_addr and * leave the last entry to use for promiscuous filtering.
*/ for (i = fbd->mac_addr_boundary, ret = -ENOENT;
i < FBNIC_RPC_TCAM_MACDA_HOST_ADDR_IDX && ret; i++) { struct fbnic_mac_addr *mac_addr = &fbd->mac_addr[i];
if (!ether_addr_equal(mac_addr->value.addr8, addr)) continue;
if (WARN_ON(!is_multicast_ether_addr(addr))) return -EADDRNOTAVAIL;
avail_addr = __fbnic_mc_sync(fbn->fbd, addr); if (!avail_addr) return -ENOSPC;
/* Add type flag indicating this address is in use by the host */
set_bit(FBNIC_MAC_ADDR_T_MULTICAST, avail_addr->act_tcam);
return 0;
}
staticint fbnic_mc_unsync(struct net_device *netdev, constunsignedchar *addr)
{ struct fbnic_net *fbn = netdev_priv(netdev); struct fbnic_dev *fbd = fbn->fbd; int i, ret;
/* Scan from middle of list to top, filling top down. * Skip over the address reserved for the BMC MAC and * exclude index 0 as that belongs to the broadcast address
*/ for (i = fbd->mac_addr_boundary, ret = -ENOENT;
--i > FBNIC_RPC_TCAM_MACDA_BROADCAST_IDX && ret;) { struct fbnic_mac_addr *mac_addr = &fbd->mac_addr[i];
if (!ether_addr_equal(mac_addr->value.addr8, addr)) continue;
/* Populate last TCAM entry with promiscuous entry and 0/1 bit mask */
mac_addr = &fbd->mac_addr[FBNIC_RPC_TCAM_MACDA_PROMISC_IDX]; if (uc_promisc) { if (!is_zero_ether_addr(mac_addr->value.addr8) ||
mac_addr->state != FBNIC_TCAM_S_VALID) {
eth_zero_addr(mac_addr->value.addr8);
eth_broadcast_addr(mac_addr->mask.addr8);
clear_bit(FBNIC_MAC_ADDR_T_ALLMULTI,
mac_addr->act_tcam);
set_bit(FBNIC_MAC_ADDR_T_PROMISC,
mac_addr->act_tcam);
mac_addr->state = FBNIC_TCAM_S_ADD;
}
} elseif (mc_promisc &&
(!fbnic_bmc_present(fbd) || !fbd->fw_cap.all_multi)) { /* We have to add a special handler for multicast as the * BMC may have an all-multi rule already in place. As such * adding a rule ourselves won't do any good so we will have * to modify the rules for the ALL MULTI below if the BMC * already has the rule in place.
*/ if (!is_multicast_ether_addr(mac_addr->value.addr8) ||
mac_addr->state != FBNIC_TCAM_S_VALID) {
eth_zero_addr(mac_addr->value.addr8);
eth_broadcast_addr(mac_addr->mask.addr8);
mac_addr->value.addr8[0] ^= 1;
mac_addr->mask.addr8[0] ^= 1;
set_bit(FBNIC_MAC_ADDR_T_ALLMULTI,
mac_addr->act_tcam);
clear_bit(FBNIC_MAC_ADDR_T_PROMISC,
mac_addr->act_tcam);
mac_addr->state = FBNIC_TCAM_S_ADD;
}
} elseif (mac_addr->state == FBNIC_TCAM_S_VALID) { if (test_bit(FBNIC_MAC_ADDR_T_BMC, mac_addr->act_tcam)) {
clear_bit(FBNIC_MAC_ADDR_T_ALLMULTI,
mac_addr->act_tcam);
clear_bit(FBNIC_MAC_ADDR_T_PROMISC,
mac_addr->act_tcam);
} else {
mac_addr->state = FBNIC_TCAM_S_DELETE;
}
}
/* Add rules for BMC all multicast if it is enabled */
fbnic_bmc_rpc_all_multi_config(fbd, mc_promisc);
/* Sift out any unshared BMC rules and place them in BMC only section */
fbnic_sift_macda(fbd);
/* Write updates to hardware */
fbnic_write_rules(fbd);
fbnic_write_macda(fbd);
fbnic_write_tce_tcam(fbd);
}
staticvoid fbnic_set_rx_mode(struct net_device *netdev)
{ /* No need to update the hardware if we are not running */ if (netif_running(netdev))
__fbnic_set_rx_mode(netdev);
}
if (config->source != HWTSTAMP_SOURCE_NETDEV) return -EOPNOTSUPP;
if (!kernel_hwtstamp_config_changed(config, &fbn->hwtstamp_config)) return 0;
/* Upscale the filters */ switch (config->rx_filter) { case HWTSTAMP_FILTER_NONE: case HWTSTAMP_FILTER_ALL: case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: case HWTSTAMP_FILTER_PTP_V2_L2_EVENT: case HWTSTAMP_FILTER_PTP_V2_EVENT: break; case HWTSTAMP_FILTER_NTP_ALL:
config->rx_filter = HWTSTAMP_FILTER_ALL; break; case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
config->rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_EVENT; break; case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
config->rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_EVENT; break; case HWTSTAMP_FILTER_PTP_V2_L2_SYNC: case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
config->rx_filter = HWTSTAMP_FILTER_PTP_V2_L2_EVENT; break; case HWTSTAMP_FILTER_PTP_V2_SYNC: case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
config->rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT; break; default: return -ERANGE;
}
/* Save / report back filter configuration * Note that our filter configuration is inexact. Instead of * filtering for a specific UDP port or L2 Ethertype we are * filtering in all UDP or all non-IP packets for timestamping. So * if anything other than FILTER_ALL is requested we report * FILTER_SOME indicating that we will be timestamping a few * additional packets.
*/ if (config->rx_filter > HWTSTAMP_FILTER_ALL)
config->rx_filter = HWTSTAMP_FILTER_SOME;
spin_lock(&fbd->hw_stats_lock); /* Record drops for the host FIFOs. * 4: network to Host, 6: BMC to Host * Exclude the BMC and MC FIFOs as those stats may contain drops * due to unrelated items such as TCAM misses. They are still * accessible through the ethtool stats.
*/
i = FBNIC_RXB_FIFO_HOST;
rx_missed += fbd->hw_stats.rxb.fifo[i].drop.frames.value;
i = FBNIC_RXB_FIFO_BMC_TO_HOST;
rx_missed += fbd->hw_stats.rxb.fifo[i].drop.frames.value;
for (i = 0; i < fbd->max_num_queues; i++) { /* Report packets dropped due to CQ/BDQ being full/empty */
rx_over += fbd->hw_stats.hw_q[i].rde_pkt_cq_drop.value;
rx_over += fbd->hw_stats.hw_q[i].rde_pkt_bdq_drop.value;
/** * fbnic_netdev_free - Free the netdev associate with fbnic * @fbd: Driver specific structure to free netdev from * * Allocate and initialize the netdev and netdev private structure. Bind * together the hardware, netdev, and pci data structures.
**/ void fbnic_netdev_free(struct fbnic_dev *fbd)
{ struct fbnic_net *fbn = netdev_priv(fbd->netdev);
if (fbn->phylink)
phylink_destroy(fbn->phylink);
free_netdev(fbd->netdev);
fbd->netdev = NULL;
}
/** * fbnic_netdev_alloc - Allocate a netdev and associate with fbnic * @fbd: Driver specific structure to associate netdev with * * Allocate and initialize the netdev and netdev private structure. Bind * together the hardware, netdev, and pci data structures. * * Return: Pointer to net_device on success, NULL on failure
**/ struct net_device *fbnic_netdev_alloc(struct fbnic_dev *fbd)
{ struct net_device *netdev; struct fbnic_net *fbn; int default_queues;
netdev = alloc_etherdev_mq(sizeof(*fbn), FBNIC_MAX_RXQS); if (!netdev) return NULL;
/* TBD: This is workaround for BMC as phylink doesn't have support * for leavling the link enabled if a BMC is present.
*/
netdev->ethtool->wol_enabled = true;
netif_carrier_off(netdev);
netif_tx_stop_all_queues(netdev);
if (fbnic_phylink_init(netdev)) {
fbnic_netdev_free(fbd); return NULL;
}
/** * fbnic_netdev_register - Initialize general software structures * @netdev: Netdev containing structure to initialize and register * * Initialize the MAC address for the netdev and register it. * * Return: 0 on success, negative on failure
**/ int fbnic_netdev_register(struct net_device *netdev)
{ struct fbnic_net *fbn = netdev_priv(netdev); struct fbnic_dev *fbd = fbn->fbd;
u64 dsn = fbd->dsn;
u8 addr[ETH_ALEN]; int err;
err = fbnic_dsn_to_mac_addr(dsn, addr); if (!err) {
ether_addr_copy(netdev->perm_addr, addr);
eth_hw_addr_set(netdev, addr);
} else { /* A randomly assigned MAC address will cause provisioning * issues so instead just fail to spawn the netdev and * avoid any confusion.
*/
dev_err(fbd->dev, "MAC addr %pM invalid\n", addr); return err;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.