diff options
Diffstat (limited to 'drivers/net/cxgbe/cxgbe_main.c')
-rw-r--r-- | drivers/net/cxgbe/cxgbe_main.c | 332 |
1 files changed, 235 insertions, 97 deletions
diff --git a/drivers/net/cxgbe/cxgbe_main.c b/drivers/net/cxgbe/cxgbe_main.c index 28db6c06..54eb23df 100644 --- a/drivers/net/cxgbe/cxgbe_main.c +++ b/drivers/net/cxgbe/cxgbe_main.c @@ -1,34 +1,6 @@ -/*- - * BSD LICENSE - * - * Copyright(c) 2014-2017 Chelsio Communications. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Chelsio Communications nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2014-2018 Chelsio Communications. + * All rights reserved. */ #include <sys/queue.h> @@ -57,9 +29,9 @@ #include <rte_ether.h> #include <rte_ethdev_driver.h> #include <rte_ethdev_pci.h> -#include <rte_malloc.h> #include <rte_random.h> #include <rte_dev.h> +#include <rte_kvargs.h> #include "common.h" #include "t4_regs.h" @@ -199,15 +171,16 @@ int cxgb4_set_rspq_intr_params(struct sge_rspq *q, unsigned int us, static inline bool is_x_1g_port(const struct link_config *lc) { - return (lc->supported & FW_PORT_CAP_SPEED_1G) != 0; + return (lc->pcaps & FW_PORT_CAP32_SPEED_1G) != 0; } static inline bool is_x_10g_port(const struct link_config *lc) { unsigned int speeds, high_speeds; - speeds = V_FW_PORT_CAP_SPEED(G_FW_PORT_CAP_SPEED(lc->supported)); - high_speeds = speeds & ~(FW_PORT_CAP_SPEED_100M | FW_PORT_CAP_SPEED_1G); + speeds = V_FW_PORT_CAP32_SPEED(G_FW_PORT_CAP32_SPEED(lc->pcaps)); + high_speeds = speeds & + ~(FW_PORT_CAP32_SPEED_100M | FW_PORT_CAP32_SPEED_1G); return high_speeds != 0; } @@ -345,14 +318,17 @@ static void setup_memwin(struct adapter *adap) MEMWIN_NIC)); } -static int init_rss(struct adapter *adap) +int init_rss(struct adapter *adap) { unsigned int i; - int err; - err = t4_init_rss_mode(adap, adap->mbox); - if (err) - return err; + if (is_pf4(adap)) { + int err; + + err = t4_init_rss_mode(adap, adap->mbox); + if (err) + return err; + } for_each_port(adap, i) { struct port_info *pi = adap2pinfo(adap, i); @@ -360,6 +336,8 @@ static int init_rss(struct adapter *adap) pi->rss = rte_zmalloc(NULL, pi->rss_size * sizeof(u16), 0); if (!pi->rss) return -ENOMEM; + + pi->rss_hf = CXGBE_RSS_HF_ALL; } return 0; } @@ -367,7 +345,7 @@ static int init_rss(struct adapter *adap) /** * Dump basic information about the adapter. */ -static void print_adapter_info(struct adapter *adap) +void print_adapter_info(struct adapter *adap) { /** * Hardware/Firmware/etc. Version/Revision IDs. @@ -375,27 +353,29 @@ static void print_adapter_info(struct adapter *adap) t4_dump_version_info(adap); } -static void print_port_info(struct adapter *adap) +void print_port_info(struct adapter *adap) { int i; char buf[80]; struct rte_pci_addr *loc = &adap->pdev->addr; for_each_port(adap, i) { - const struct port_info *pi = &adap->port[i]; + const struct port_info *pi = adap2pinfo(adap, i); char *bufp = buf; - if (pi->link_cfg.supported & FW_PORT_CAP_SPEED_100M) + if (pi->link_cfg.pcaps & FW_PORT_CAP32_SPEED_100M) bufp += sprintf(bufp, "100M/"); - if (pi->link_cfg.supported & FW_PORT_CAP_SPEED_1G) + if (pi->link_cfg.pcaps & FW_PORT_CAP32_SPEED_1G) bufp += sprintf(bufp, "1G/"); - if (pi->link_cfg.supported & FW_PORT_CAP_SPEED_10G) + if (pi->link_cfg.pcaps & FW_PORT_CAP32_SPEED_10G) bufp += sprintf(bufp, "10G/"); - if (pi->link_cfg.supported & FW_PORT_CAP_SPEED_25G) + if (pi->link_cfg.pcaps & FW_PORT_CAP32_SPEED_25G) bufp += sprintf(bufp, "25G/"); - if (pi->link_cfg.supported & FW_PORT_CAP_SPEED_40G) + if (pi->link_cfg.pcaps & FW_PORT_CAP32_SPEED_40G) bufp += sprintf(bufp, "40G/"); - if (pi->link_cfg.supported & FW_PORT_CAP_SPEED_100G) + if (pi->link_cfg.pcaps & FW_PORT_CAP32_SPEED_50G) + bufp += sprintf(bufp, "50G/"); + if (pi->link_cfg.pcaps & FW_PORT_CAP32_SPEED_100G) bufp += sprintf(bufp, "100G/"); if (bufp != buf) --bufp; @@ -412,6 +392,84 @@ static void print_port_info(struct adapter *adap) } } +static int +check_devargs_handler(__rte_unused const char *key, const char *value, + __rte_unused void *opaque) +{ + if (strcmp(value, "1")) + return -1; + + return 0; +} + +int cxgbe_get_devargs(struct rte_devargs *devargs, const char *key) +{ + struct rte_kvargs *kvlist; + + if (!devargs) + return 0; + + kvlist = rte_kvargs_parse(devargs->args, NULL); + if (!kvlist) + return 0; + + if (!rte_kvargs_count(kvlist, key)) { + rte_kvargs_free(kvlist); + return 0; + } + + if (rte_kvargs_process(kvlist, key, + check_devargs_handler, NULL) < 0) { + rte_kvargs_free(kvlist); + return 0; + } + rte_kvargs_free(kvlist); + + return 1; +} + +static void configure_vlan_types(struct adapter *adapter) +{ + struct rte_pci_device *pdev = adapter->pdev; + int i; + + for_each_port(adapter, i) { + /* OVLAN Type 0x88a8 */ + t4_set_reg_field(adapter, MPS_PORT_RX_OVLAN_REG(i, A_RX_OVLAN0), + V_OVLAN_MASK(M_OVLAN_MASK) | + V_OVLAN_ETYPE(M_OVLAN_ETYPE), + V_OVLAN_MASK(M_OVLAN_MASK) | + V_OVLAN_ETYPE(0x88a8)); + /* OVLAN Type 0x9100 */ + t4_set_reg_field(adapter, MPS_PORT_RX_OVLAN_REG(i, A_RX_OVLAN1), + V_OVLAN_MASK(M_OVLAN_MASK) | + V_OVLAN_ETYPE(M_OVLAN_ETYPE), + V_OVLAN_MASK(M_OVLAN_MASK) | + V_OVLAN_ETYPE(0x9100)); + /* OVLAN Type 0x8100 */ + t4_set_reg_field(adapter, MPS_PORT_RX_OVLAN_REG(i, A_RX_OVLAN2), + V_OVLAN_MASK(M_OVLAN_MASK) | + V_OVLAN_ETYPE(M_OVLAN_ETYPE), + V_OVLAN_MASK(M_OVLAN_MASK) | + V_OVLAN_ETYPE(0x8100)); + + /* IVLAN 0X8100 */ + t4_set_reg_field(adapter, MPS_PORT_RX_IVLAN(i), + V_IVLAN_ETYPE(M_IVLAN_ETYPE), + V_IVLAN_ETYPE(0x8100)); + + t4_set_reg_field(adapter, MPS_PORT_RX_CTL(i), + F_OVLAN_EN0 | F_OVLAN_EN1 | + F_OVLAN_EN2 | F_IVLAN_EN, + F_OVLAN_EN0 | F_OVLAN_EN1 | + F_OVLAN_EN2 | F_IVLAN_EN); + } + + if (cxgbe_get_devargs(pdev->device.devargs, CXGBE_DEVARG_KEEP_OVLAN)) + t4_tp_wr_bits_indirect(adapter, A_TP_INGRESS_CONFIG, + V_RM_OVLAN(1), V_RM_OVLAN(0)); +} + static void configure_pcie_ext_tag(struct adapter *adapter) { u16 v; @@ -828,6 +886,7 @@ static int adap_init0(struct adapter *adap) t4_init_sge_params(adap); t4_init_tp_params(adap); configure_pcie_ext_tag(adap); + configure_vlan_types(adap); adap->params.drv_memwin = MEMWIN_NIC; adap->flags |= FW_OK; @@ -860,7 +919,7 @@ void t4_os_portmod_changed(const struct adapter *adap, int port_id) NULL, "LR", "SR", "ER", "passive DA", "active DA", "LRM" }; - const struct port_info *pi = &adap->port[port_id]; + const struct port_info *pi = adap2pinfo(adap, port_id); if (pi->mod_type == FW_PORT_MOD_TYPE_NONE) dev_info(adap, "Port%d: port module unplugged\n", pi->port_id); @@ -881,6 +940,18 @@ void t4_os_portmod_changed(const struct adapter *adap, int port_id) pi->port_id, pi->mod_type); } +inline bool force_linkup(struct adapter *adap) +{ + struct rte_pci_device *pdev = adap->pdev; + + if (is_pf4(adap)) + return false; /* force_linkup not required for pf driver*/ + if (!cxgbe_get_devargs(pdev->device.devargs, + CXGBE_DEVARG_FORCE_LINK_UP)) + return false; + return true; +} + /** * link_start - enable a port * @dev: the port to enable @@ -912,7 +983,7 @@ int link_start(struct port_info *pi) ret = 0; } } - if (ret == 0) + if (ret == 0 && is_pf4(adapter)) ret = t4_link_l1cfg(adapter, adapter->mbox, pi->tx_chan, &pi->link_cfg); if (ret == 0) { @@ -926,18 +997,78 @@ int link_start(struct port_info *pi) ret = t4_enable_vi_params(adapter, adapter->mbox, pi->viid, true, true, false); } + + if (ret == 0 && force_linkup(adapter)) + pi->eth_dev->data->dev_link.link_status = ETH_LINK_UP; return ret; } /** - * cxgb4_write_rss - write the RSS table for a given port + * cxgbe_write_rss_conf - flash the RSS configuration for a given port + * @pi: the port + * @rss_hf: Hash configuration to apply + */ +int cxgbe_write_rss_conf(const struct port_info *pi, uint64_t rss_hf) +{ + struct adapter *adapter = pi->adapter; + const struct sge_eth_rxq *rxq; + u64 flags = 0; + u16 rss; + int err; + + /* Should never be called before setting up sge eth rx queues */ + if (!(adapter->flags & FULL_INIT_DONE)) { + dev_err(adap, "%s No RXQs available on port %d\n", + __func__, pi->port_id); + return -EINVAL; + } + + /* Don't allow unsupported hash functions */ + if (rss_hf & ~CXGBE_RSS_HF_ALL) + return -EINVAL; + + if (rss_hf & ETH_RSS_IPV4) + flags |= F_FW_RSS_VI_CONFIG_CMD_IP4TWOTUPEN; + + if (rss_hf & ETH_RSS_NONFRAG_IPV4_TCP) + flags |= F_FW_RSS_VI_CONFIG_CMD_IP4FOURTUPEN; + + if (rss_hf & ETH_RSS_NONFRAG_IPV4_UDP) + flags |= F_FW_RSS_VI_CONFIG_CMD_IP4FOURTUPEN | + F_FW_RSS_VI_CONFIG_CMD_UDPEN; + + if (rss_hf & ETH_RSS_IPV6) + flags |= F_FW_RSS_VI_CONFIG_CMD_IP6TWOTUPEN; + + if (rss_hf & ETH_RSS_NONFRAG_IPV6_TCP) + flags |= F_FW_RSS_VI_CONFIG_CMD_IP6FOURTUPEN; + + if (rss_hf & ETH_RSS_NONFRAG_IPV6_UDP) + flags |= F_FW_RSS_VI_CONFIG_CMD_IP6FOURTUPEN | + F_FW_RSS_VI_CONFIG_CMD_UDPEN; + + rxq = &adapter->sge.ethrxq[pi->first_qset]; + rss = rxq[0].rspq.abs_id; + + /* If Tunnel All Lookup isn't specified in the global RSS + * Configuration, then we need to specify a default Ingress + * Queue for any ingress packets which aren't hashed. We'll + * use our first ingress queue ... + */ + err = t4_config_vi_rss(adapter, adapter->mbox, pi->viid, + flags, rss); + return err; +} + +/** + * cxgbe_write_rss - write the RSS table for a given port * @pi: the port * @queues: array of queue indices for RSS * * Sets up the portion of the HW RSS table for the port's VI to distribute * packets to the Rx queues in @queues. */ -int cxgb4_write_rss(const struct port_info *pi, const u16 *queues) +int cxgbe_write_rss(const struct port_info *pi, const u16 *queues) { u16 *rss; int i, err; @@ -958,20 +1089,6 @@ int cxgb4_write_rss(const struct port_info *pi, const u16 *queues) err = t4_config_rss_range(adapter, adapter->pf, pi->viid, 0, pi->rss_size, rss, pi->rss_size); - /* - * If Tunnel All Lookup isn't specified in the global RSS - * Configuration, then we need to specify a default Ingress - * Queue for any ingress packets which aren't hashed. We'll - * use our first ingress queue ... - */ - if (!err) - err = t4_config_vi_rss(adapter, adapter->mbox, pi->viid, - F_FW_RSS_VI_CONFIG_CMD_IP6FOURTUPEN | - F_FW_RSS_VI_CONFIG_CMD_IP6TWOTUPEN | - F_FW_RSS_VI_CONFIG_CMD_IP4FOURTUPEN | - F_FW_RSS_VI_CONFIG_CMD_IP4TWOTUPEN | - F_FW_RSS_VI_CONFIG_CMD_UDPEN, - rss[0]); rte_free(rss); return err; } @@ -1001,7 +1118,11 @@ int setup_rss(struct port_info *pi) for (j = 0; j < pi->rss_size; j++) pi->rss[j] = j % pi->n_rx_qsets; - err = cxgb4_write_rss(pi, pi->rss); + err = cxgbe_write_rss(pi, pi->rss); + if (err) + return err; + + err = cxgbe_write_rss_conf(pi, pi->rss_hf); if (err) return err; pi->flags |= PORT_RSS_DONE; @@ -1016,7 +1137,8 @@ int setup_rss(struct port_info *pi) static void enable_rx(struct adapter *adap, struct sge_rspq *q) { /* 0-increment GTS to start the timer and enable interrupts */ - t4_write_reg(adap, MYPF_REG(A_SGE_PF_GTS), + t4_write_reg(adap, is_pf4(adap) ? MYPF_REG(A_SGE_PF_GTS) : + T4VF_SGE_BASE_ADDR + A_SGE_VF_GTS, V_SEINTARM(q->intr_params) | V_INGRESSQID(q->cntxt_id)); } @@ -1051,7 +1173,7 @@ static void fw_caps_to_speed_caps(enum fw_port_type port_type, #define FW_CAPS_TO_SPEED(__fw_name) \ do { \ - if (fw_caps & FW_PORT_CAP_ ## __fw_name) \ + if (fw_caps & FW_PORT_CAP32_ ## __fw_name) \ SET_SPEED(__fw_name); \ } while (0) @@ -1106,6 +1228,7 @@ static void fw_caps_to_speed_caps(enum fw_port_type port_type, case FW_PORT_TYPE_CR4_QSFP: FW_CAPS_TO_SPEED(SPEED_25G); FW_CAPS_TO_SPEED(SPEED_40G); + FW_CAPS_TO_SPEED(SPEED_50G); FW_CAPS_TO_SPEED(SPEED_100G); break; @@ -1128,10 +1251,10 @@ void cxgbe_get_speed_caps(struct port_info *pi, u32 *speed_caps) { *speed_caps = 0; - fw_caps_to_speed_caps(pi->port_type, pi->link_cfg.supported, + fw_caps_to_speed_caps(pi->port_type, pi->link_cfg.pcaps, speed_caps); - if (!(pi->link_cfg.supported & FW_PORT_CAP_ANEG)) + if (!(pi->link_cfg.pcaps & FW_PORT_CAP32_ANEG)) *speed_caps |= ETH_LINK_SPEED_FIXED; } @@ -1147,7 +1270,8 @@ int cxgbe_up(struct adapter *adap) { enable_rx(adap, &adap->sge.fw_evtq); t4_sge_tx_monitor_start(adap); - t4_intr_enable(adap); + if (is_pf4(adap)) + t4_intr_enable(adap); adap->flags |= FULL_INIT_DONE; /* TODO: deadman watchdog ?? */ @@ -1168,7 +1292,7 @@ int cxgbe_down(struct port_info *pi) return err; } - t4_reset_link_config(adapter, pi->port_id); + t4_reset_link_config(adapter, pi->pidx); return 0; } @@ -1181,7 +1305,8 @@ void cxgbe_close(struct adapter *adapter) int i; if (adapter->flags & FULL_INIT_DONE) { - t4_intr_disable(adapter); + if (is_pf4(adapter)) + t4_intr_disable(adapter); t4_sge_tx_monitor_stop(adapter); t4_free_sge_resources(adapter); for_each_port(adapter, i) { @@ -1190,11 +1315,16 @@ void cxgbe_close(struct adapter *adapter) t4_free_vi(adapter, adapter->mbox, adapter->pf, 0, pi->viid); rte_free(pi->eth_dev->data->mac_addrs); + /* Skip first port since it'll be freed by DPDK stack */ + if (i) { + rte_free(pi->eth_dev->data->dev_private); + rte_eth_dev_release_port(pi->eth_dev); + } } adapter->flags &= ~FULL_INIT_DONE; } - if (adapter->flags & FW_OK) + if (is_pf4(adapter) && (adapter->flags & FW_OK)) t4_fw_bye(adapter, adapter->mbox); } @@ -1265,21 +1395,16 @@ int cxgbe_probe(struct adapter *adapter) } for_each_port(adapter, i) { - char name[RTE_ETH_NAME_MAX_LEN]; - struct rte_eth_dev_data *data = NULL; const unsigned int numa_node = rte_socket_id(); + char name[RTE_ETH_NAME_MAX_LEN]; + struct rte_eth_dev *eth_dev; - pi = &adapter->port[i]; - pi->adapter = adapter; - pi->xact_addr_filt = -1; - pi->port_id = i; - - snprintf(name, sizeof(name), "cxgbe%d", - adapter->eth_dev->data->port_id + i); + snprintf(name, sizeof(name), "%s_%d", + adapter->pdev->device.name, i); if (i == 0) { /* First port is already allocated by DPDK */ - pi->eth_dev = adapter->eth_dev; + eth_dev = adapter->eth_dev; goto allocate_mac; } @@ -1289,21 +1414,26 @@ int cxgbe_probe(struct adapter *adapter) */ /* reserve an ethdev entry */ - pi->eth_dev = rte_eth_dev_allocate(name); - if (!pi->eth_dev) + eth_dev = rte_eth_dev_allocate(name); + if (!eth_dev) goto out_free; - data = rte_zmalloc_socket(name, sizeof(*data), 0, numa_node); - if (!data) + eth_dev->data->dev_private = + rte_zmalloc_socket(name, sizeof(struct port_info), + RTE_CACHE_LINE_SIZE, numa_node); + if (!eth_dev->data->dev_private) goto out_free; - data->port_id = adapter->eth_dev->data->port_id + i; - - pi->eth_dev->data = data; - allocate_mac: + pi = (struct port_info *)eth_dev->data->dev_private; + adapter->port[i] = pi; + pi->eth_dev = eth_dev; + pi->adapter = adapter; + pi->xact_addr_filt = -1; + pi->port_id = i; + pi->pidx = i; + pi->eth_dev->device = &adapter->pdev->device; - pi->eth_dev->data->dev_private = pi; pi->eth_dev->dev_ops = adapter->eth_dev->dev_ops; pi->eth_dev->tx_pkt_burst = adapter->eth_dev->tx_pkt_burst; pi->eth_dev->rx_pkt_burst = adapter->eth_dev->rx_pkt_burst; @@ -1318,6 +1448,11 @@ allocate_mac: err = -1; goto out_free; } + + if (i > 0) { + /* First port will be notified by upper layer */ + rte_eth_dev_probing_finish(eth_dev); + } } if (adapter->flags & FW_OK) { @@ -1349,8 +1484,11 @@ out_free: /* Skip first port since it'll be de-allocated by DPDK */ if (i == 0) continue; - if (pi->eth_dev->data) - rte_free(pi->eth_dev->data); + if (pi->eth_dev) { + if (pi->eth_dev->data->dev_private) + rte_free(pi->eth_dev->data->dev_private); + rte_eth_dev_release_port(pi->eth_dev); + } } if (adapter->flags & FW_OK) |