X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=drivers%2Fnet%2Fcxgbe%2Fcxgbe_ethdev.c;h=bb134e504f71d3c22da2a71c1772bf08972d868c;hb=e274f5732225;hp=600a16ce41ff0a86b016fb0010d55586e332fae0;hpb=856505d303f40c3ed11210a7f74f8ae0755ea539;p=dpdk.git diff --git a/drivers/net/cxgbe/cxgbe_ethdev.c b/drivers/net/cxgbe/cxgbe_ethdev.c index 600a16ce41..bb134e504f 100644 --- a/drivers/net/cxgbe/cxgbe_ethdev.c +++ b/drivers/net/cxgbe/cxgbe_ethdev.c @@ -1,7 +1,7 @@ /*- * BSD LICENSE * - * Copyright(c) 2014-2015 Chelsio Communications. + * Copyright(c) 2014-2016 Chelsio Communications. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -141,8 +141,14 @@ static void cxgbe_dev_info_get(struct rte_eth_dev *eth_dev, struct adapter *adapter = pi->adapter; int max_queues = adapter->sge.max_ethqsets / adapter->params.nports; - device_info->min_rx_bufsize = 68; /* XXX: Smallest pkt size */ - device_info->max_rx_pktlen = 1500; /* XXX: For now we support mtu */ + static const struct rte_eth_desc_lim cxgbe_desc_lim = { + .nb_max = CXGBE_MAX_RING_DESC_SIZE, + .nb_min = CXGBE_MIN_RING_DESC_SIZE, + .nb_align = 1, + }; + + device_info->min_rx_bufsize = CXGBE_MIN_RX_BUFSIZE; + device_info->max_rx_pktlen = CXGBE_MAX_RX_PKTLEN; device_info->max_rx_queues = max_queues; device_info->max_tx_queues = max_queues; device_info->max_mac_addrs = 1; @@ -162,6 +168,99 @@ static void cxgbe_dev_info_get(struct rte_eth_dev *eth_dev, DEV_TX_OFFLOAD_TCP_TSO; device_info->reta_size = pi->rss_size; + + device_info->rx_desc_lim = cxgbe_desc_lim; + device_info->tx_desc_lim = cxgbe_desc_lim; + device_info->speed_capa = ETH_LINK_SPEED_10G | ETH_LINK_SPEED_40G; +} + +static void cxgbe_dev_promiscuous_enable(struct rte_eth_dev *eth_dev) +{ + struct port_info *pi = (struct port_info *)(eth_dev->data->dev_private); + struct adapter *adapter = pi->adapter; + + t4_set_rxmode(adapter, adapter->mbox, pi->viid, -1, + 1, -1, 1, -1, false); +} + +static void cxgbe_dev_promiscuous_disable(struct rte_eth_dev *eth_dev) +{ + struct port_info *pi = (struct port_info *)(eth_dev->data->dev_private); + struct adapter *adapter = pi->adapter; + + t4_set_rxmode(adapter, adapter->mbox, pi->viid, -1, + 0, -1, 1, -1, false); +} + +static void cxgbe_dev_allmulticast_enable(struct rte_eth_dev *eth_dev) +{ + struct port_info *pi = (struct port_info *)(eth_dev->data->dev_private); + struct adapter *adapter = pi->adapter; + + /* TODO: address filters ?? */ + + t4_set_rxmode(adapter, adapter->mbox, pi->viid, -1, + -1, 1, 1, -1, false); +} + +static void cxgbe_dev_allmulticast_disable(struct rte_eth_dev *eth_dev) +{ + struct port_info *pi = (struct port_info *)(eth_dev->data->dev_private); + struct adapter *adapter = pi->adapter; + + /* TODO: address filters ?? */ + + t4_set_rxmode(adapter, adapter->mbox, pi->viid, -1, + -1, 0, 1, -1, false); +} + +static int cxgbe_dev_link_update(struct rte_eth_dev *eth_dev, + __rte_unused int wait_to_complete) +{ + struct port_info *pi = (struct port_info *)(eth_dev->data->dev_private); + struct adapter *adapter = pi->adapter; + struct sge *s = &adapter->sge; + struct rte_eth_link *old_link = ð_dev->data->dev_link; + unsigned int work_done, budget = 4; + + cxgbe_poll(&s->fw_evtq, NULL, budget, &work_done); + if (old_link->link_status == pi->link_cfg.link_ok) + return -1; /* link not changed */ + + eth_dev->data->dev_link.link_status = pi->link_cfg.link_ok; + eth_dev->data->dev_link.link_duplex = ETH_LINK_FULL_DUPLEX; + eth_dev->data->dev_link.link_speed = pi->link_cfg.speed; + + /* link has changed */ + return 0; +} + +static int cxgbe_dev_mtu_set(struct rte_eth_dev *eth_dev, uint16_t mtu) +{ + struct port_info *pi = (struct port_info *)(eth_dev->data->dev_private); + struct adapter *adapter = pi->adapter; + struct rte_eth_dev_info dev_info; + int err; + uint16_t new_mtu = mtu + ETHER_HDR_LEN + ETHER_CRC_LEN; + + cxgbe_dev_info_get(eth_dev, &dev_info); + + /* Must accommodate at least ETHER_MIN_MTU */ + if ((new_mtu < ETHER_MIN_MTU) || (new_mtu > dev_info.max_rx_pktlen)) + return -EINVAL; + + /* set to jumbo mode if needed */ + if (new_mtu > ETHER_MAX_LEN) + eth_dev->data->dev_conf.rxmode.jumbo_frame = 1; + else + eth_dev->data->dev_conf.rxmode.jumbo_frame = 0; + + err = t4_set_rxmode(adapter, adapter->mbox, pi->viid, new_mtu, -1, -1, + -1, -1, true); + if (!err) + eth_dev->data->dev_conf.rxmode.max_rx_pkt_len = new_mtu; + + return err; } static int cxgbe_dev_tx_queue_start(struct rte_eth_dev *eth_dev, @@ -307,23 +406,33 @@ static int cxgbe_dev_configure(struct rte_eth_dev *eth_dev) static int cxgbe_dev_tx_queue_start(struct rte_eth_dev *eth_dev, uint16_t tx_queue_id) { + int ret; struct sge_eth_txq *txq = (struct sge_eth_txq *) (eth_dev->data->tx_queues[tx_queue_id]); dev_debug(NULL, "%s: tx_queue_id = %d\n", __func__, tx_queue_id); - return t4_sge_eth_txq_start(txq); + ret = t4_sge_eth_txq_start(txq); + if (ret == 0) + eth_dev->data->tx_queue_state[tx_queue_id] = RTE_ETH_QUEUE_STATE_STARTED; + + return ret; } static int cxgbe_dev_tx_queue_stop(struct rte_eth_dev *eth_dev, uint16_t tx_queue_id) { + int ret; struct sge_eth_txq *txq = (struct sge_eth_txq *) (eth_dev->data->tx_queues[tx_queue_id]); dev_debug(NULL, "%s: tx_queue_id = %d\n", __func__, tx_queue_id); - return t4_sge_eth_txq_stop(txq); + ret = t4_sge_eth_txq_stop(txq); + if (ret == 0) + eth_dev->data->tx_queue_state[tx_queue_id] = RTE_ETH_QUEUE_STATE_STOPPED; + + return ret; } static int cxgbe_dev_tx_queue_setup(struct rte_eth_dev *eth_dev, @@ -399,6 +508,7 @@ static void cxgbe_dev_tx_queue_release(void *q) static int cxgbe_dev_rx_queue_start(struct rte_eth_dev *eth_dev, uint16_t rx_queue_id) { + int ret; struct port_info *pi = (struct port_info *)(eth_dev->data->dev_private); struct adapter *adap = pi->adapter; struct sge_rspq *q; @@ -407,12 +517,18 @@ static int cxgbe_dev_rx_queue_start(struct rte_eth_dev *eth_dev, __func__, pi->port_id, rx_queue_id); q = eth_dev->data->rx_queues[rx_queue_id]; - return t4_sge_eth_rxq_start(adap, q); + + ret = t4_sge_eth_rxq_start(adap, q); + if (ret == 0) + eth_dev->data->rx_queue_state[rx_queue_id] = RTE_ETH_QUEUE_STATE_STARTED; + + return ret; } static int cxgbe_dev_rx_queue_stop(struct rte_eth_dev *eth_dev, uint16_t rx_queue_id) { + int ret; struct port_info *pi = (struct port_info *)(eth_dev->data->dev_private); struct adapter *adap = pi->adapter; struct sge_rspq *q; @@ -421,7 +537,11 @@ static int cxgbe_dev_rx_queue_stop(struct rte_eth_dev *eth_dev, __func__, pi->port_id, rx_queue_id); q = eth_dev->data->rx_queues[rx_queue_id]; - return t4_sge_eth_rxq_stop(adap, q); + ret = t4_sge_eth_rxq_stop(adap, q); + if (ret == 0) + eth_dev->data->rx_queue_state[rx_queue_id] = RTE_ETH_QUEUE_STATE_STOPPED; + + return ret; } static int cxgbe_dev_rx_queue_setup(struct rte_eth_dev *eth_dev, @@ -437,6 +557,8 @@ static int cxgbe_dev_rx_queue_setup(struct rte_eth_dev *eth_dev, int err = 0; int msi_idx = 0; unsigned int temp_nb_desc; + struct rte_eth_dev_info dev_info; + unsigned int pkt_len = eth_dev->data->dev_conf.rxmode.max_rx_pkt_len; RTE_SET_USED(rx_conf); @@ -444,6 +566,17 @@ static int cxgbe_dev_rx_queue_setup(struct rte_eth_dev *eth_dev, __func__, eth_dev->data->nb_rx_queues, queue_idx, nb_desc, socket_id, mp); + cxgbe_dev_info_get(eth_dev, &dev_info); + + /* Must accommodate at least ETHER_MIN_MTU */ + if ((pkt_len < dev_info.min_rx_bufsize) || + (pkt_len > dev_info.max_rx_pktlen)) { + dev_err(adap, "%s: max pkt len must be > %d and <= %d\n", + __func__, dev_info.min_rx_bufsize, + dev_info.max_rx_pktlen); + return -EINVAL; + } + /* Free up the existing queue */ if (eth_dev->data->rx_queues[queue_idx]) { cxgbe_dev_rx_queue_release(eth_dev->data->rx_queues[queue_idx]); @@ -473,6 +606,12 @@ static int cxgbe_dev_rx_queue_setup(struct rte_eth_dev *eth_dev, if ((&rxq->fl) != NULL) rxq->fl.size = temp_nb_desc; + /* Set to jumbo mode if necessary */ + if (pkt_len > ETHER_MAX_LEN) + eth_dev->data->dev_conf.rxmode.jumbo_frame = 1; + else + eth_dev->data->dev_conf.rxmode.jumbo_frame = 0; + err = t4_sge_alloc_rxq(adapter, &rxq->rspq, false, eth_dev, msi_idx, &rxq->fl, t4_ethrx_handler, t4_get_mps_bg_map(adapter, pi->tx_chan), mp, @@ -522,18 +661,14 @@ static void cxgbe_dev_stats_get(struct rte_eth_dev *eth_dev, ps.rx_ovflow2 + ps.rx_ovflow3 + ps.rx_trunc0 + ps.rx_trunc1 + ps.rx_trunc2 + ps.rx_trunc3; - eth_stats->ibadcrc = ps.rx_fcs_err; - eth_stats->ibadlen = ps.rx_jabber + ps.rx_too_long + ps.rx_runt; - eth_stats->ierrors = ps.rx_symbol_err + eth_stats->ibadcrc + - eth_stats->ibadlen + ps.rx_len_err + - eth_stats->imissed; - eth_stats->rx_pause_xon = ps.rx_pause; + eth_stats->ierrors = ps.rx_symbol_err + ps.rx_fcs_err + + ps.rx_jabber + ps.rx_too_long + ps.rx_runt + + ps.rx_len_err; /* TX Stats */ eth_stats->opackets = ps.tx_frames; eth_stats->obytes = ps.tx_octets; eth_stats->oerrors = ps.tx_error_frames; - eth_stats->tx_pause_xon = ps.tx_pause; for (i = 0; i < pi->n_rx_qsets; i++) { struct sge_eth_rxq *rxq = @@ -581,12 +716,85 @@ static void cxgbe_dev_stats_reset(struct rte_eth_dev *eth_dev) } } -static struct eth_dev_ops cxgbe_eth_dev_ops = { +static int cxgbe_flow_ctrl_get(struct rte_eth_dev *eth_dev, + struct rte_eth_fc_conf *fc_conf) +{ + struct port_info *pi = (struct port_info *)(eth_dev->data->dev_private); + struct link_config *lc = &pi->link_cfg; + int rx_pause, tx_pause; + + fc_conf->autoneg = lc->fc & PAUSE_AUTONEG; + rx_pause = lc->fc & PAUSE_RX; + tx_pause = lc->fc & PAUSE_TX; + + if (rx_pause && tx_pause) + fc_conf->mode = RTE_FC_FULL; + else if (rx_pause) + fc_conf->mode = RTE_FC_RX_PAUSE; + else if (tx_pause) + fc_conf->mode = RTE_FC_TX_PAUSE; + else + fc_conf->mode = RTE_FC_NONE; + return 0; +} + +static int cxgbe_flow_ctrl_set(struct rte_eth_dev *eth_dev, + struct rte_eth_fc_conf *fc_conf) +{ + struct port_info *pi = (struct port_info *)(eth_dev->data->dev_private); + struct adapter *adapter = pi->adapter; + struct link_config *lc = &pi->link_cfg; + + if (lc->supported & FW_PORT_CAP_ANEG) { + if (fc_conf->autoneg) + lc->requested_fc |= PAUSE_AUTONEG; + else + lc->requested_fc &= ~PAUSE_AUTONEG; + } + + if (((fc_conf->mode & RTE_FC_FULL) == RTE_FC_FULL) || + (fc_conf->mode & RTE_FC_RX_PAUSE)) + lc->requested_fc |= PAUSE_RX; + else + lc->requested_fc &= ~PAUSE_RX; + + if (((fc_conf->mode & RTE_FC_FULL) == RTE_FC_FULL) || + (fc_conf->mode & RTE_FC_TX_PAUSE)) + lc->requested_fc |= PAUSE_TX; + else + lc->requested_fc &= ~PAUSE_TX; + + return t4_link_l1cfg(adapter, adapter->mbox, pi->tx_chan, + &pi->link_cfg); +} + +static const uint32_t * +cxgbe_dev_supported_ptypes_get(struct rte_eth_dev *eth_dev) +{ + static const uint32_t ptypes[] = { + RTE_PTYPE_L3_IPV4, + RTE_PTYPE_L3_IPV6, + RTE_PTYPE_UNKNOWN + }; + + if (eth_dev->rx_pkt_burst == cxgbe_recv_pkts) + return ptypes; + return NULL; +} + +static const struct eth_dev_ops cxgbe_eth_dev_ops = { .dev_start = cxgbe_dev_start, .dev_stop = cxgbe_dev_stop, .dev_close = cxgbe_dev_close, + .promiscuous_enable = cxgbe_dev_promiscuous_enable, + .promiscuous_disable = cxgbe_dev_promiscuous_disable, + .allmulticast_enable = cxgbe_dev_allmulticast_enable, + .allmulticast_disable = cxgbe_dev_allmulticast_disable, .dev_configure = cxgbe_dev_configure, .dev_infos_get = cxgbe_dev_info_get, + .dev_supported_ptypes_get = cxgbe_dev_supported_ptypes_get, + .link_update = cxgbe_dev_link_update, + .mtu_set = cxgbe_dev_mtu_set, .tx_queue_setup = cxgbe_dev_tx_queue_setup, .tx_queue_start = cxgbe_dev_tx_queue_start, .tx_queue_stop = cxgbe_dev_tx_queue_stop, @@ -597,6 +805,8 @@ static struct eth_dev_ops cxgbe_eth_dev_ops = { .rx_queue_release = cxgbe_dev_rx_queue_release, .stats_get = cxgbe_dev_stats_get, .stats_reset = cxgbe_dev_stats_reset, + .flow_ctrl_get = cxgbe_flow_ctrl_get, + .flow_ctrl_set = cxgbe_flow_ctrl_set, }; /* @@ -624,6 +834,7 @@ static int eth_cxgbe_dev_init(struct rte_eth_dev *eth_dev) return 0; pci_dev = eth_dev->pci_dev; + snprintf(name, sizeof(name), "cxgbeadapter%d", eth_dev->data->port_id); adapter = rte_zmalloc(name, sizeof(*adapter), 0); if (!adapter) @@ -641,16 +852,21 @@ static int eth_cxgbe_dev_init(struct rte_eth_dev *eth_dev) pi->adapter = adapter; err = cxgbe_probe(adapter); - if (err) + if (err) { dev_err(adapter, "%s: cxgbe probe failed with err %d\n", __func__, err); + goto out_free_adapter; + } + + return 0; out_free_adapter: + rte_free(adapter); return err; } static struct eth_driver rte_cxgbe_pmd = { - { + .pci_drv = { .name = "rte_cxgbe_pmd", .id_table = cxgb4_pci_tbl, .drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC,