From 0462d115441d1619ba19313b8daaff679854cc49 Mon Sep 17 00:00:00 2001 From: Rahul Lakkireddy Date: Tue, 30 Jun 2015 04:58:38 +0530 Subject: [PATCH] cxgbe: add device related operations Adds dev_start(), dev_stop(), and dev_close() eth_dev_ops for cxgbe poll mode driver. Signed-off-by: Rahul Lakkireddy Signed-off-by: Kumar Sanghvi --- drivers/net/cxgbe/cxgbe.h | 4 + drivers/net/cxgbe/cxgbe_ethdev.c | 114 +++++++++++++++++++++++++ drivers/net/cxgbe/cxgbe_main.c | 139 +++++++++++++++++++++++++++++++ drivers/net/cxgbe/sge.c | 58 +++++++++++++ 4 files changed, 315 insertions(+) diff --git a/drivers/net/cxgbe/cxgbe.h b/drivers/net/cxgbe/cxgbe.h index 90d1db09a1..bf08baf5fb 100644 --- a/drivers/net/cxgbe/cxgbe.h +++ b/drivers/net/cxgbe/cxgbe.h @@ -44,6 +44,10 @@ #define CXGBE_DEFAULT_RX_DESC_SIZE 1024 /* Default RX ring size */ int cxgbe_probe(struct adapter *adapter); +int cxgbe_up(struct adapter *adap); +int cxgbe_down(struct port_info *pi); +void cxgbe_close(struct adapter *adapter); +int link_start(struct port_info *pi); void init_rspq(struct adapter *adap, struct sge_rspq *q, unsigned int us, unsigned int cnt, unsigned int size, unsigned int iqe_size); int setup_sge_fwevtq(struct adapter *adapter); diff --git a/drivers/net/cxgbe/cxgbe_ethdev.c b/drivers/net/cxgbe/cxgbe_ethdev.c index b6e17e444e..cb100fca18 100644 --- a/drivers/net/cxgbe/cxgbe_ethdev.c +++ b/drivers/net/cxgbe/cxgbe_ethdev.c @@ -171,6 +171,117 @@ static int cxgbe_dev_rx_queue_start(struct rte_eth_dev *eth_dev, static void cxgbe_dev_tx_queue_release(void *q); static void cxgbe_dev_rx_queue_release(void *q); +/* + * Stop device. + */ +static void cxgbe_dev_close(struct rte_eth_dev *eth_dev) +{ + struct port_info *pi = (struct port_info *)(eth_dev->data->dev_private); + struct adapter *adapter = pi->adapter; + int i, dev_down = 0; + + CXGBE_FUNC_TRACE(); + + if (!(adapter->flags & FULL_INIT_DONE)) + return; + + cxgbe_down(pi); + + /* + * We clear queues only if both tx and rx path of the port + * have been disabled + */ + t4_sge_eth_clear_queues(pi); + + /* See if all ports are down */ + for_each_port(adapter, i) { + pi = adap2pinfo(adapter, i); + /* + * Skip first port of the adapter since it will be closed + * by DPDK + */ + if (i == 0) + continue; + dev_down += (pi->eth_dev->data->dev_started == 0) ? 1 : 0; + } + + /* If rest of the ports are stopped, then free up resources */ + if (dev_down == (adapter->params.nports - 1)) + cxgbe_close(adapter); +} + +/* Start the device. + * It returns 0 on success. + */ +static int cxgbe_dev_start(struct rte_eth_dev *eth_dev) +{ + struct port_info *pi = (struct port_info *)(eth_dev->data->dev_private); + struct adapter *adapter = pi->adapter; + int err = 0, i; + + CXGBE_FUNC_TRACE(); + + /* + * If we don't have a connection to the firmware there's nothing we + * can do. + */ + if (!(adapter->flags & FW_OK)) { + err = -ENXIO; + goto out; + } + + if (!(adapter->flags & FULL_INIT_DONE)) { + err = cxgbe_up(adapter); + if (err < 0) + goto out; + } + + err = setup_rss(pi); + if (err) + goto out; + + for (i = 0; i < pi->n_tx_qsets; i++) { + err = cxgbe_dev_tx_queue_start(eth_dev, i); + if (err) + goto out; + } + + for (i = 0; i < pi->n_rx_qsets; i++) { + err = cxgbe_dev_rx_queue_start(eth_dev, i); + if (err) + goto out; + } + + err = link_start(pi); + if (err) + goto out; + +out: + return err; +} + +/* + * Stop device: disable rx and tx functions to allow for reconfiguring. + */ +static void cxgbe_dev_stop(struct rte_eth_dev *eth_dev) +{ + struct port_info *pi = (struct port_info *)(eth_dev->data->dev_private); + struct adapter *adapter = pi->adapter; + + CXGBE_FUNC_TRACE(); + + if (!(adapter->flags & FULL_INIT_DONE)) + return; + + cxgbe_down(pi); + + /* + * We clear queues only if both tx and rx path of the port + * have been disabled + */ + t4_sge_eth_clear_queues(pi); +} + static int cxgbe_dev_configure(struct rte_eth_dev *eth_dev) { struct port_info *pi = (struct port_info *)(eth_dev->data->dev_private); @@ -390,6 +501,9 @@ static void cxgbe_dev_rx_queue_release(void *q) } static struct eth_dev_ops cxgbe_eth_dev_ops = { + .dev_start = cxgbe_dev_start, + .dev_stop = cxgbe_dev_stop, + .dev_close = cxgbe_dev_close, .dev_configure = cxgbe_dev_configure, .dev_infos_get = cxgbe_dev_info_get, .tx_queue_setup = cxgbe_dev_tx_queue_setup, diff --git a/drivers/net/cxgbe/cxgbe_main.c b/drivers/net/cxgbe/cxgbe_main.c index 3029b57c69..7995d3ce3c 100644 --- a/drivers/net/cxgbe/cxgbe_main.c +++ b/drivers/net/cxgbe/cxgbe_main.c @@ -826,6 +826,50 @@ void t4_os_portmod_changed(const struct adapter *adap, int port_id) pi->port_id, pi->mod_type); } +/** + * link_start - enable a port + * @dev: the port to enable + * + * Performs the MAC and PHY actions needed to enable a port. + */ +int link_start(struct port_info *pi) +{ + struct adapter *adapter = pi->adapter; + int ret; + + /* + * We do not set address filters and promiscuity here, the stack does + * that step explicitly. + */ + ret = t4_set_rxmode(adapter, adapter->mbox, pi->viid, 1500, -1, -1, + -1, 1, true); + if (ret == 0) { + ret = t4_change_mac(adapter, adapter->mbox, pi->viid, + pi->xact_addr_filt, + (u8 *)&pi->eth_dev->data->mac_addrs[0], + true, true); + if (ret >= 0) { + pi->xact_addr_filt = ret; + ret = 0; + } + } + if (ret == 0) + ret = t4_link_l1cfg(adapter, adapter->mbox, pi->tx_chan, + &pi->link_cfg); + if (ret == 0) { + /* + * Enabling a Virtual Interface can result in an interrupt + * during the processing of the VI Enable command and, in some + * paths, result in an attempt to issue another command in the + * interrupt context. Thus, we disable interrupts during the + * course of the VI Enable command ... + */ + ret = t4_enable_vi_params(adapter, adapter->mbox, pi->viid, + true, true, false); + } + return ret; +} + /** * cxgb4_write_rss - write the RSS table for a given port * @pi: the port @@ -907,6 +951,101 @@ int setup_rss(struct port_info *pi) return 0; } +/* + * Enable NAPI scheduling and interrupt generation for all Rx queues. + */ +static void enable_rx(struct adapter *adap) +{ + struct sge *s = &adap->sge; + struct sge_rspq *q = &s->fw_evtq; + int i, j; + + /* 0-increment GTS to start the timer and enable interrupts */ + t4_write_reg(adap, MYPF_REG(A_SGE_PF_GTS), + V_SEINTARM(q->intr_params) | + V_INGRESSQID(q->cntxt_id)); + + for_each_port(adap, i) { + const struct port_info *pi = &adap->port[i]; + struct rte_eth_dev *eth_dev = pi->eth_dev; + + for (j = 0; j < eth_dev->data->nb_rx_queues; j++) { + q = eth_dev->data->rx_queues[j]; + + /* + * 0-increment GTS to start the timer and enable + * interrupts + */ + t4_write_reg(adap, MYPF_REG(A_SGE_PF_GTS), + V_SEINTARM(q->intr_params) | + V_INGRESSQID(q->cntxt_id)); + } + } +} + +/** + * cxgb_up - enable the adapter + * @adap: adapter being enabled + * + * Called when the first port is enabled, this function performs the + * actions necessary to make an adapter operational, such as completing + * the initialization of HW modules, and enabling interrupts. + */ +int cxgbe_up(struct adapter *adap) +{ + enable_rx(adap); + t4_sge_tx_monitor_start(adap); + t4_intr_enable(adap); + adap->flags |= FULL_INIT_DONE; + + /* TODO: deadman watchdog ?? */ + return 0; +} + +/* + * Close the port + */ +int cxgbe_down(struct port_info *pi) +{ + struct adapter *adapter = pi->adapter; + int err = 0; + + err = t4_enable_vi(adapter, adapter->mbox, pi->viid, false, false); + if (err) { + dev_err(adapter, "%s: disable_vi failed: %d\n", __func__, err); + return err; + } + + t4_reset_link_config(adapter, pi->port_id); + return 0; +} + +/* + * Release resources when all the ports have been stopped. + */ +void cxgbe_close(struct adapter *adapter) +{ + struct port_info *pi; + int i; + + if (adapter->flags & FULL_INIT_DONE) { + t4_intr_disable(adapter); + t4_sge_tx_monitor_stop(adapter); + t4_free_sge_resources(adapter); + for_each_port(adapter, i) { + pi = adap2pinfo(adapter, i); + if (pi->viid != 0) + t4_free_vi(adapter, adapter->mbox, + adapter->pf, 0, pi->viid); + rte_free(pi->eth_dev->data->mac_addrs); + } + adapter->flags &= ~FULL_INIT_DONE; + } + + if (adapter->flags & FW_OK) + t4_fw_bye(adapter, adapter->mbox); +} + int cxgbe_probe(struct adapter *adapter) { struct port_info *pi; diff --git a/drivers/net/cxgbe/sge.c b/drivers/net/cxgbe/sge.c index 4f4fdd6877..4da6320775 100644 --- a/drivers/net/cxgbe/sge.c +++ b/drivers/net/cxgbe/sge.c @@ -1959,6 +1959,35 @@ static void free_rspq_fl(struct adapter *adap, struct sge_rspq *rq, } } +/* + * Clear all queues of the port + * + * Note: This function must only be called after rx and tx path + * of the port have been disabled. + */ +void t4_sge_eth_clear_queues(struct port_info *pi) +{ + int i; + struct adapter *adap = pi->adapter; + struct sge_eth_rxq *rxq = &adap->sge.ethrxq[pi->first_qset]; + struct sge_eth_txq *txq = &adap->sge.ethtxq[pi->first_qset]; + + for (i = 0; i < pi->n_rx_qsets; i++, rxq++) { + if (rxq->rspq.desc) + t4_sge_eth_rxq_stop(adap, &rxq->rspq); + } + for (i = 0; i < pi->n_tx_qsets; i++, txq++) { + if (txq->q.desc) { + struct sge_txq *q = &txq->q; + + t4_sge_eth_txq_stop(txq); + reclaim_completed_tx(q); + free_tx_desc(q, q->size); + q->equeidx = q->pidx; + } + } +} + void t4_sge_eth_rxq_release(struct adapter *adap, struct sge_eth_rxq *rxq) { if (rxq->rspq.desc) { @@ -1989,6 +2018,35 @@ void t4_sge_tx_monitor_stop(struct adapter *adap) rte_eal_alarm_cancel(tx_timer_cb, (void *)adap); } +/** + * t4_free_sge_resources - free SGE resources + * @adap: the adapter + * + * Frees resources used by the SGE queue sets. + */ +void t4_free_sge_resources(struct adapter *adap) +{ + int i; + struct sge_eth_rxq *rxq = &adap->sge.ethrxq[0]; + struct sge_eth_txq *txq = &adap->sge.ethtxq[0]; + + /* clean up Ethernet Tx/Rx queues */ + for (i = 0; i < adap->sge.max_ethqsets; i++, rxq++, txq++) { + /* Free only the queues allocated */ + if (rxq->rspq.desc) { + t4_sge_eth_rxq_release(adap, rxq); + rxq->rspq.eth_dev = NULL; + } + if (txq->q.desc) { + t4_sge_eth_txq_release(adap, txq); + txq->eth_dev = NULL; + } + } + + if (adap->sge.fw_evtq.desc) + free_rspq_fl(adap, &adap->sge.fw_evtq, NULL); +} + /** * t4_sge_init - initialize SGE * @adap: the adapter