X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=drivers%2Fnet%2Fngbe%2Fngbe_ethdev.c;h=775789f59607ed3625ec4a1c3f3f3f5008789e2c;hb=891f8260dd49d4bc683cffaca79b7f7d5247b968;hp=42d8c1e0951d8667549360f9f36d1ee3973f5954;hpb=e2a289a788c0a128a15bc0f1099af7c031201ac5;p=dpdk.git diff --git a/drivers/net/ngbe/ngbe_ethdev.c b/drivers/net/ngbe/ngbe_ethdev.c index 42d8c1e095..775789f596 100644 --- a/drivers/net/ngbe/ngbe_ethdev.c +++ b/drivers/net/ngbe/ngbe_ethdev.c @@ -13,6 +13,67 @@ #include "ngbe.h" #include "ngbe_ethdev.h" #include "ngbe_rxtx.h" +#include "ngbe_regs_group.h" + +static const struct reg_info ngbe_regs_general[] = { + {NGBE_RST, 1, 1, "NGBE_RST"}, + {NGBE_STAT, 1, 1, "NGBE_STAT"}, + {NGBE_PORTCTL, 1, 1, "NGBE_PORTCTL"}, + {NGBE_GPIODATA, 1, 1, "NGBE_GPIODATA"}, + {NGBE_GPIOCTL, 1, 1, "NGBE_GPIOCTL"}, + {NGBE_LEDCTL, 1, 1, "NGBE_LEDCTL"}, + {0, 0, 0, ""} +}; + +static const struct reg_info ngbe_regs_nvm[] = { + {0, 0, 0, ""} +}; + +static const struct reg_info ngbe_regs_interrupt[] = { + {0, 0, 0, ""} +}; + +static const struct reg_info ngbe_regs_fctl_others[] = { + {0, 0, 0, ""} +}; + +static const struct reg_info ngbe_regs_rxdma[] = { + {0, 0, 0, ""} +}; + +static const struct reg_info ngbe_regs_rx[] = { + {0, 0, 0, ""} +}; + +static struct reg_info ngbe_regs_tx[] = { + {0, 0, 0, ""} +}; + +static const struct reg_info ngbe_regs_wakeup[] = { + {0, 0, 0, ""} +}; + +static const struct reg_info ngbe_regs_mac[] = { + {0, 0, 0, ""} +}; + +static const struct reg_info ngbe_regs_diagnostic[] = { + {0, 0, 0, ""}, +}; + +/* PF registers */ +static const struct reg_info *ngbe_regs_others[] = { + ngbe_regs_general, + ngbe_regs_nvm, + ngbe_regs_interrupt, + ngbe_regs_fctl_others, + ngbe_regs_rxdma, + ngbe_regs_rx, + ngbe_regs_tx, + ngbe_regs_wakeup, + ngbe_regs_mac, + ngbe_regs_diagnostic, + NULL}; static int ngbe_dev_close(struct rte_eth_dev *dev); static int ngbe_dev_link_update(struct rte_eth_dev *dev, @@ -259,6 +320,9 @@ eth_ngbe_dev_init(struct rte_eth_dev *eth_dev, void *init_params __rte_unused) PMD_INIT_FUNC_TRACE(); eth_dev->dev_ops = &ngbe_eth_dev_ops; + eth_dev->rx_queue_count = ngbe_dev_rx_queue_count; + eth_dev->rx_descriptor_status = ngbe_dev_rx_descriptor_status; + eth_dev->tx_descriptor_status = ngbe_dev_tx_descriptor_status; eth_dev->rx_pkt_burst = &ngbe_recv_pkts; eth_dev->tx_pkt_burst = &ngbe_xmit_pkts; eth_dev->tx_pkt_prepare = &ngbe_prep_pkts; @@ -317,6 +381,14 @@ eth_ngbe_dev_init(struct rte_eth_dev *eth_dev, void *init_params __rte_unused) /* Unlock any pending hardware semaphore */ ngbe_swfw_lock_reset(hw); + /* Get Hardware Flow Control setting */ + hw->fc.requested_mode = ngbe_fc_full; + hw->fc.current_mode = ngbe_fc_full; + hw->fc.pause_time = NGBE_FC_PAUSE_TIME; + hw->fc.low_water = NGBE_FC_XON_LOTH; + hw->fc.high_water = NGBE_FC_XOFF_HITH; + hw->fc.send_xon = 1; + err = hw->rom.init_params(hw); if (err != 0) { PMD_INIT_LOG(ERR, "The EEPROM init failed: %d", err); @@ -2175,6 +2247,121 @@ ngbe_dev_interrupt_handler(void *param) ngbe_dev_interrupt_action(dev); } +static int +ngbe_dev_led_on(struct rte_eth_dev *dev) +{ + struct ngbe_hw *hw = ngbe_dev_hw(dev); + return hw->mac.led_on(hw, 0) == 0 ? 0 : -ENOTSUP; +} + +static int +ngbe_dev_led_off(struct rte_eth_dev *dev) +{ + struct ngbe_hw *hw = ngbe_dev_hw(dev); + return hw->mac.led_off(hw, 0) == 0 ? 0 : -ENOTSUP; +} + +static int +ngbe_flow_ctrl_get(struct rte_eth_dev *dev, struct rte_eth_fc_conf *fc_conf) +{ + struct ngbe_hw *hw = ngbe_dev_hw(dev); + uint32_t mflcn_reg; + uint32_t fccfg_reg; + int rx_pause; + int tx_pause; + + fc_conf->pause_time = hw->fc.pause_time; + fc_conf->high_water = hw->fc.high_water; + fc_conf->low_water = hw->fc.low_water; + fc_conf->send_xon = hw->fc.send_xon; + fc_conf->autoneg = !hw->fc.disable_fc_autoneg; + + /* + * Return rx_pause status according to actual setting of + * RXFCCFG register. + */ + mflcn_reg = rd32(hw, NGBE_RXFCCFG); + if (mflcn_reg & NGBE_RXFCCFG_FC) + rx_pause = 1; + else + rx_pause = 0; + + /* + * Return tx_pause status according to actual setting of + * TXFCCFG register. + */ + fccfg_reg = rd32(hw, NGBE_TXFCCFG); + if (fccfg_reg & NGBE_TXFCCFG_FC) + tx_pause = 1; + else + tx_pause = 0; + + if (rx_pause && tx_pause) + fc_conf->mode = RTE_ETH_FC_FULL; + else if (rx_pause) + fc_conf->mode = RTE_ETH_FC_RX_PAUSE; + else if (tx_pause) + fc_conf->mode = RTE_ETH_FC_TX_PAUSE; + else + fc_conf->mode = RTE_ETH_FC_NONE; + + return 0; +} + +static int +ngbe_flow_ctrl_set(struct rte_eth_dev *dev, struct rte_eth_fc_conf *fc_conf) +{ + struct ngbe_hw *hw = ngbe_dev_hw(dev); + int err; + uint32_t rx_buf_size; + uint32_t max_high_water; + enum ngbe_fc_mode rte_fcmode_2_ngbe_fcmode[] = { + ngbe_fc_none, + ngbe_fc_rx_pause, + ngbe_fc_tx_pause, + ngbe_fc_full + }; + + PMD_INIT_FUNC_TRACE(); + + rx_buf_size = rd32(hw, NGBE_PBRXSIZE); + PMD_INIT_LOG(DEBUG, "Rx packet buffer size = 0x%x", rx_buf_size); + + /* + * At least reserve one Ethernet frame for watermark + * high_water/low_water in kilo bytes for ngbe + */ + max_high_water = (rx_buf_size - RTE_ETHER_MAX_LEN) >> 10; + if (fc_conf->high_water > max_high_water || + fc_conf->high_water < fc_conf->low_water) { + PMD_INIT_LOG(ERR, "Invalid high/low water setup value in KB"); + PMD_INIT_LOG(ERR, "High_water must <= 0x%x", max_high_water); + return -EINVAL; + } + + hw->fc.requested_mode = rte_fcmode_2_ngbe_fcmode[fc_conf->mode]; + hw->fc.pause_time = fc_conf->pause_time; + hw->fc.high_water = fc_conf->high_water; + hw->fc.low_water = fc_conf->low_water; + hw->fc.send_xon = fc_conf->send_xon; + hw->fc.disable_fc_autoneg = !fc_conf->autoneg; + + err = hw->mac.fc_enable(hw); + + /* Not negotiated is not an error case */ + if (err == 0 || err == NGBE_ERR_FC_NOT_NEGOTIATED) { + wr32m(hw, NGBE_MACRXFLT, NGBE_MACRXFLT_CTL_MASK, + (fc_conf->mac_ctrl_frame_fwd + ? NGBE_MACRXFLT_CTL_NOPS : NGBE_MACRXFLT_CTL_DROP)); + ngbe_flush(hw); + + return 0; + } + + PMD_INIT_LOG(ERR, "ngbe_fc_enable = 0x%x", err); + return -EIO; +} + int ngbe_dev_rss_reta_update(struct rte_eth_dev *dev, struct rte_eth_rss_reta_entry64 *reta_conf, @@ -2546,6 +2733,310 @@ ngbe_dev_set_mc_addr_list(struct rte_eth_dev *dev, ngbe_dev_addr_list_itr, TRUE); } +static uint64_t +ngbe_read_systime_cyclecounter(struct rte_eth_dev *dev) +{ + struct ngbe_hw *hw = ngbe_dev_hw(dev); + uint64_t systime_cycles; + + systime_cycles = (uint64_t)rd32(hw, NGBE_TSTIMEL); + systime_cycles |= (uint64_t)rd32(hw, NGBE_TSTIMEH) << 32; + + return systime_cycles; +} + +static uint64_t +ngbe_read_rx_tstamp_cyclecounter(struct rte_eth_dev *dev) +{ + struct ngbe_hw *hw = ngbe_dev_hw(dev); + uint64_t rx_tstamp_cycles; + + /* TSRXSTMPL stores ns and TSRXSTMPH stores seconds. */ + rx_tstamp_cycles = (uint64_t)rd32(hw, NGBE_TSRXSTMPL); + rx_tstamp_cycles |= (uint64_t)rd32(hw, NGBE_TSRXSTMPH) << 32; + + return rx_tstamp_cycles; +} + +static uint64_t +ngbe_read_tx_tstamp_cyclecounter(struct rte_eth_dev *dev) +{ + struct ngbe_hw *hw = ngbe_dev_hw(dev); + uint64_t tx_tstamp_cycles; + + /* TSTXSTMPL stores ns and TSTXSTMPH stores seconds. */ + tx_tstamp_cycles = (uint64_t)rd32(hw, NGBE_TSTXSTMPL); + tx_tstamp_cycles |= (uint64_t)rd32(hw, NGBE_TSTXSTMPH) << 32; + + return tx_tstamp_cycles; +} + +static void +ngbe_start_timecounters(struct rte_eth_dev *dev) +{ + struct ngbe_hw *hw = ngbe_dev_hw(dev); + struct ngbe_adapter *adapter = ngbe_dev_adapter(dev); + uint32_t incval = 0; + uint32_t shift = 0; + + incval = NGBE_INCVAL_1GB; + shift = NGBE_INCVAL_SHIFT_1GB; + + wr32(hw, NGBE_TSTIMEINC, NGBE_TSTIMEINC_IV(incval)); + + memset(&adapter->systime_tc, 0, sizeof(struct rte_timecounter)); + memset(&adapter->rx_tstamp_tc, 0, sizeof(struct rte_timecounter)); + memset(&adapter->tx_tstamp_tc, 0, sizeof(struct rte_timecounter)); + + adapter->systime_tc.cc_mask = NGBE_CYCLECOUNTER_MASK; + adapter->systime_tc.cc_shift = shift; + adapter->systime_tc.nsec_mask = (1ULL << shift) - 1; + + adapter->rx_tstamp_tc.cc_mask = NGBE_CYCLECOUNTER_MASK; + adapter->rx_tstamp_tc.cc_shift = shift; + adapter->rx_tstamp_tc.nsec_mask = (1ULL << shift) - 1; + + adapter->tx_tstamp_tc.cc_mask = NGBE_CYCLECOUNTER_MASK; + adapter->tx_tstamp_tc.cc_shift = shift; + adapter->tx_tstamp_tc.nsec_mask = (1ULL << shift) - 1; +} + +static int +ngbe_timesync_adjust_time(struct rte_eth_dev *dev, int64_t delta) +{ + struct ngbe_adapter *adapter = ngbe_dev_adapter(dev); + + adapter->systime_tc.nsec += delta; + adapter->rx_tstamp_tc.nsec += delta; + adapter->tx_tstamp_tc.nsec += delta; + + return 0; +} + +static int +ngbe_timesync_write_time(struct rte_eth_dev *dev, const struct timespec *ts) +{ + uint64_t ns; + struct ngbe_adapter *adapter = ngbe_dev_adapter(dev); + + ns = rte_timespec_to_ns(ts); + /* Set the timecounters to a new value. */ + adapter->systime_tc.nsec = ns; + adapter->rx_tstamp_tc.nsec = ns; + adapter->tx_tstamp_tc.nsec = ns; + + return 0; +} + +static int +ngbe_timesync_read_time(struct rte_eth_dev *dev, struct timespec *ts) +{ + uint64_t ns, systime_cycles; + struct ngbe_adapter *adapter = ngbe_dev_adapter(dev); + + systime_cycles = ngbe_read_systime_cyclecounter(dev); + ns = rte_timecounter_update(&adapter->systime_tc, systime_cycles); + *ts = rte_ns_to_timespec(ns); + + return 0; +} + +static int +ngbe_timesync_enable(struct rte_eth_dev *dev) +{ + struct ngbe_hw *hw = ngbe_dev_hw(dev); + uint32_t tsync_ctl; + + /* Stop the timesync system time. */ + wr32(hw, NGBE_TSTIMEINC, 0x0); + /* Reset the timesync system time value. */ + wr32(hw, NGBE_TSTIMEL, 0x0); + wr32(hw, NGBE_TSTIMEH, 0x0); + + ngbe_start_timecounters(dev); + + /* Enable L2 filtering of IEEE1588/802.1AS Ethernet frame types. */ + wr32(hw, NGBE_ETFLT(NGBE_ETF_ID_1588), + RTE_ETHER_TYPE_1588 | NGBE_ETFLT_ENA | NGBE_ETFLT_1588); + + /* Enable timestamping of received PTP packets. */ + tsync_ctl = rd32(hw, NGBE_TSRXCTL); + tsync_ctl |= NGBE_TSRXCTL_ENA; + wr32(hw, NGBE_TSRXCTL, tsync_ctl); + + /* Enable timestamping of transmitted PTP packets. */ + tsync_ctl = rd32(hw, NGBE_TSTXCTL); + tsync_ctl |= NGBE_TSTXCTL_ENA; + wr32(hw, NGBE_TSTXCTL, tsync_ctl); + + ngbe_flush(hw); + + return 0; +} + +static int +ngbe_timesync_disable(struct rte_eth_dev *dev) +{ + struct ngbe_hw *hw = ngbe_dev_hw(dev); + uint32_t tsync_ctl; + + /* Disable timestamping of transmitted PTP packets. */ + tsync_ctl = rd32(hw, NGBE_TSTXCTL); + tsync_ctl &= ~NGBE_TSTXCTL_ENA; + wr32(hw, NGBE_TSTXCTL, tsync_ctl); + + /* Disable timestamping of received PTP packets. */ + tsync_ctl = rd32(hw, NGBE_TSRXCTL); + tsync_ctl &= ~NGBE_TSRXCTL_ENA; + wr32(hw, NGBE_TSRXCTL, tsync_ctl); + + /* Disable L2 filtering of IEEE1588/802.1AS Ethernet frame types. */ + wr32(hw, NGBE_ETFLT(NGBE_ETF_ID_1588), 0); + + /* Stop incrementating the System Time registers. */ + wr32(hw, NGBE_TSTIMEINC, 0); + + return 0; +} + +static int +ngbe_timesync_read_rx_timestamp(struct rte_eth_dev *dev, + struct timespec *timestamp, + uint32_t flags __rte_unused) +{ + struct ngbe_hw *hw = ngbe_dev_hw(dev); + struct ngbe_adapter *adapter = ngbe_dev_adapter(dev); + uint32_t tsync_rxctl; + uint64_t rx_tstamp_cycles; + uint64_t ns; + + tsync_rxctl = rd32(hw, NGBE_TSRXCTL); + if ((tsync_rxctl & NGBE_TSRXCTL_VLD) == 0) + return -EINVAL; + + rx_tstamp_cycles = ngbe_read_rx_tstamp_cyclecounter(dev); + ns = rte_timecounter_update(&adapter->rx_tstamp_tc, rx_tstamp_cycles); + *timestamp = rte_ns_to_timespec(ns); + + return 0; +} + +static int +ngbe_timesync_read_tx_timestamp(struct rte_eth_dev *dev, + struct timespec *timestamp) +{ + struct ngbe_hw *hw = ngbe_dev_hw(dev); + struct ngbe_adapter *adapter = ngbe_dev_adapter(dev); + uint32_t tsync_txctl; + uint64_t tx_tstamp_cycles; + uint64_t ns; + + tsync_txctl = rd32(hw, NGBE_TSTXCTL); + if ((tsync_txctl & NGBE_TSTXCTL_VLD) == 0) + return -EINVAL; + + tx_tstamp_cycles = ngbe_read_tx_tstamp_cyclecounter(dev); + ns = rte_timecounter_update(&adapter->tx_tstamp_tc, tx_tstamp_cycles); + *timestamp = rte_ns_to_timespec(ns); + + return 0; +} + +static int +ngbe_get_reg_length(struct rte_eth_dev *dev __rte_unused) +{ + int count = 0; + int g_ind = 0; + const struct reg_info *reg_group; + const struct reg_info **reg_set = ngbe_regs_others; + + while ((reg_group = reg_set[g_ind++])) + count += ngbe_regs_group_count(reg_group); + + return count; +} + +static int +ngbe_get_regs(struct rte_eth_dev *dev, + struct rte_dev_reg_info *regs) +{ + struct ngbe_hw *hw = ngbe_dev_hw(dev); + uint32_t *data = regs->data; + int g_ind = 0; + int count = 0; + const struct reg_info *reg_group; + const struct reg_info **reg_set = ngbe_regs_others; + + if (data == NULL) { + regs->length = ngbe_get_reg_length(dev); + regs->width = sizeof(uint32_t); + return 0; + } + + /* Support only full register dump */ + if (regs->length == 0 || + regs->length == (uint32_t)ngbe_get_reg_length(dev)) { + regs->version = hw->mac.type << 24 | + hw->revision_id << 16 | + hw->device_id; + while ((reg_group = reg_set[g_ind++])) + count += ngbe_read_regs_group(dev, &data[count], + reg_group); + return 0; + } + + return -ENOTSUP; +} + +static int +ngbe_get_eeprom_length(struct rte_eth_dev *dev) +{ + struct ngbe_hw *hw = ngbe_dev_hw(dev); + + /* Return unit is byte count */ + return hw->rom.word_size * 2; +} + +static int +ngbe_get_eeprom(struct rte_eth_dev *dev, + struct rte_dev_eeprom_info *in_eeprom) +{ + struct ngbe_hw *hw = ngbe_dev_hw(dev); + struct ngbe_rom_info *eeprom = &hw->rom; + uint16_t *data = in_eeprom->data; + int first, length; + + first = in_eeprom->offset >> 1; + length = in_eeprom->length >> 1; + if (first > hw->rom.word_size || + ((first + length) > hw->rom.word_size)) + return -EINVAL; + + in_eeprom->magic = hw->vendor_id | (hw->device_id << 16); + + return eeprom->readw_buffer(hw, first, length, data); +} + +static int +ngbe_set_eeprom(struct rte_eth_dev *dev, + struct rte_dev_eeprom_info *in_eeprom) +{ + struct ngbe_hw *hw = ngbe_dev_hw(dev); + struct ngbe_rom_info *eeprom = &hw->rom; + uint16_t *data = in_eeprom->data; + int first, length; + + first = in_eeprom->offset >> 1; + length = in_eeprom->length >> 1; + if (first > hw->rom.word_size || + ((first + length) > hw->rom.word_size)) + return -EINVAL; + + in_eeprom->magic = hw->vendor_id | (hw->device_id << 16); + + return eeprom->writew_buffer(hw, first, length, data); +} + static const struct eth_dev_ops ngbe_eth_dev_ops = { .dev_configure = ngbe_dev_configure, .dev_infos_get = ngbe_dev_info_get, @@ -2580,6 +3071,10 @@ static const struct eth_dev_ops ngbe_eth_dev_ops = { .rx_queue_release = ngbe_dev_rx_queue_release, .tx_queue_setup = ngbe_dev_tx_queue_setup, .tx_queue_release = ngbe_dev_tx_queue_release, + .dev_led_on = ngbe_dev_led_on, + .dev_led_off = ngbe_dev_led_off, + .flow_ctrl_get = ngbe_flow_ctrl_get, + .flow_ctrl_set = ngbe_flow_ctrl_set, .mac_addr_add = ngbe_add_rar, .mac_addr_remove = ngbe_remove_rar, .mac_addr_set = ngbe_set_default_mac_addr, @@ -2590,8 +3085,22 @@ static const struct eth_dev_ops ngbe_eth_dev_ops = { .rss_hash_update = ngbe_dev_rss_hash_update, .rss_hash_conf_get = ngbe_dev_rss_hash_conf_get, .set_mc_addr_list = ngbe_dev_set_mc_addr_list, + .rxq_info_get = ngbe_rxq_info_get, + .txq_info_get = ngbe_txq_info_get, .rx_burst_mode_get = ngbe_rx_burst_mode_get, .tx_burst_mode_get = ngbe_tx_burst_mode_get, + .timesync_enable = ngbe_timesync_enable, + .timesync_disable = ngbe_timesync_disable, + .timesync_read_rx_timestamp = ngbe_timesync_read_rx_timestamp, + .timesync_read_tx_timestamp = ngbe_timesync_read_tx_timestamp, + .get_reg = ngbe_get_regs, + .get_eeprom_length = ngbe_get_eeprom_length, + .get_eeprom = ngbe_get_eeprom, + .set_eeprom = ngbe_set_eeprom, + .timesync_adjust_time = ngbe_timesync_adjust_time, + .timesync_read_time = ngbe_timesync_read_time, + .timesync_write_time = ngbe_timesync_write_time, + .tx_done_cleanup = ngbe_dev_tx_done_cleanup, }; RTE_PMD_REGISTER_PCI(net_ngbe, rte_ngbe_pmd);