.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * Copyright (C) 2013-2015 Chelsio Communications. All rights reserved. |
---|
3 | | - * |
---|
4 | | - * This program is free software; you can redistribute it and/or modify it |
---|
5 | | - * under the terms and conditions of the GNU General Public License, |
---|
6 | | - * version 2, as published by the Free Software Foundation. |
---|
7 | | - * |
---|
8 | | - * This program is distributed in the hope it will be useful, but WITHOUT |
---|
9 | | - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
---|
10 | | - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
---|
11 | | - * more details. |
---|
12 | | - * |
---|
13 | | - * The full GNU General Public License is included in this distribution in |
---|
14 | | - * the file called "COPYING". |
---|
15 | | - * |
---|
16 | 4 | */ |
---|
17 | 5 | |
---|
18 | 6 | #include <linux/firmware.h> |
---|
.. | .. |
---|
22 | 10 | #include "t4_regs.h" |
---|
23 | 11 | #include "t4fw_api.h" |
---|
24 | 12 | #include "cxgb4_cudbg.h" |
---|
| 13 | +#include "cxgb4_filter.h" |
---|
| 14 | +#include "cxgb4_tc_flower.h" |
---|
25 | 15 | |
---|
26 | 16 | #define EEPROM_MAGIC 0x38E2F10C |
---|
27 | 17 | |
---|
.. | .. |
---|
34 | 24 | { |
---|
35 | 25 | netdev2adap(dev)->msg_enable = val; |
---|
36 | 26 | } |
---|
| 27 | + |
---|
| 28 | +enum cxgb4_ethtool_tests { |
---|
| 29 | + CXGB4_ETHTOOL_LB_TEST, |
---|
| 30 | + CXGB4_ETHTOOL_MAX_TEST, |
---|
| 31 | +}; |
---|
| 32 | + |
---|
| 33 | +static const char cxgb4_selftest_strings[CXGB4_ETHTOOL_MAX_TEST][ETH_GSTRING_LEN] = { |
---|
| 34 | + "Loop back test (offline)", |
---|
| 35 | +}; |
---|
| 36 | + |
---|
| 37 | +static const char * const flash_region_strings[] = { |
---|
| 38 | + "All", |
---|
| 39 | + "Firmware", |
---|
| 40 | + "PHY Firmware", |
---|
| 41 | + "Boot", |
---|
| 42 | + "Boot CFG", |
---|
| 43 | +}; |
---|
37 | 44 | |
---|
38 | 45 | static const char stats_strings[][ETH_GSTRING_LEN] = { |
---|
39 | 46 | "tx_octets_ok ", |
---|
.. | .. |
---|
103 | 110 | "rx_bg3_frames_trunc ", |
---|
104 | 111 | |
---|
105 | 112 | "tso ", |
---|
| 113 | + "uso ", |
---|
106 | 114 | "tx_csum_offload ", |
---|
107 | 115 | "rx_csum_good ", |
---|
108 | 116 | "vlan_extractions ", |
---|
109 | 117 | "vlan_insertions ", |
---|
110 | 118 | "gro_packets ", |
---|
111 | 119 | "gro_merged ", |
---|
| 120 | +#if IS_ENABLED(CONFIG_CHELSIO_TLS_DEVICE) |
---|
| 121 | + "tx_tls_encrypted_packets", |
---|
| 122 | + "tx_tls_encrypted_bytes ", |
---|
| 123 | + "tx_tls_ctx ", |
---|
| 124 | + "tx_tls_ooo ", |
---|
| 125 | + "tx_tls_skip_no_sync_data", |
---|
| 126 | + "tx_tls_drop_no_sync_data", |
---|
| 127 | + "tx_tls_drop_bypass_req ", |
---|
| 128 | +#endif |
---|
112 | 129 | }; |
---|
113 | 130 | |
---|
114 | 131 | static char adapter_stats_strings[][ETH_GSTRING_LEN] = { |
---|
.. | .. |
---|
158 | 175 | ARRAY_SIZE(loopback_stats_strings); |
---|
159 | 176 | case ETH_SS_PRIV_FLAGS: |
---|
160 | 177 | return ARRAY_SIZE(cxgb4_priv_flags_strings); |
---|
| 178 | + case ETH_SS_TEST: |
---|
| 179 | + return ARRAY_SIZE(cxgb4_selftest_strings); |
---|
161 | 180 | default: |
---|
162 | 181 | return -EOPNOTSUPP; |
---|
163 | 182 | } |
---|
.. | .. |
---|
181 | 200 | u32 exprom_vers; |
---|
182 | 201 | |
---|
183 | 202 | strlcpy(info->driver, cxgb4_driver_name, sizeof(info->driver)); |
---|
184 | | - strlcpy(info->version, cxgb4_driver_version, |
---|
185 | | - sizeof(info->version)); |
---|
186 | 203 | strlcpy(info->bus_info, pci_name(adapter->pdev), |
---|
187 | 204 | sizeof(info->bus_info)); |
---|
188 | 205 | info->regdump_len = get_regs_len(dev); |
---|
189 | 206 | |
---|
190 | | - if (!adapter->params.fw_vers) |
---|
191 | | - strcpy(info->fw_version, "N/A"); |
---|
192 | | - else |
---|
| 207 | + if (adapter->params.fw_vers) |
---|
193 | 208 | snprintf(info->fw_version, sizeof(info->fw_version), |
---|
194 | 209 | "%u.%u.%u.%u, TP %u.%u.%u.%u", |
---|
195 | 210 | FW_HDR_FW_VER_MAJOR_G(adapter->params.fw_vers), |
---|
.. | .. |
---|
224 | 239 | } else if (stringset == ETH_SS_PRIV_FLAGS) { |
---|
225 | 240 | memcpy(data, cxgb4_priv_flags_strings, |
---|
226 | 241 | sizeof(cxgb4_priv_flags_strings)); |
---|
| 242 | + } else if (stringset == ETH_SS_TEST) { |
---|
| 243 | + memcpy(data, cxgb4_selftest_strings, |
---|
| 244 | + sizeof(cxgb4_selftest_strings)); |
---|
227 | 245 | } |
---|
228 | 246 | } |
---|
229 | 247 | |
---|
.. | .. |
---|
232 | 250 | */ |
---|
233 | 251 | struct queue_port_stats { |
---|
234 | 252 | u64 tso; |
---|
| 253 | + u64 uso; |
---|
235 | 254 | u64 tx_csum; |
---|
236 | 255 | u64 rx_csum; |
---|
237 | 256 | u64 vlan_ex; |
---|
238 | 257 | u64 vlan_ins; |
---|
239 | 258 | u64 gro_pkts; |
---|
240 | 259 | u64 gro_merged; |
---|
| 260 | +#if IS_ENABLED(CONFIG_CHELSIO_TLS_DEVICE) |
---|
| 261 | + u64 tx_tls_encrypted_packets; |
---|
| 262 | + u64 tx_tls_encrypted_bytes; |
---|
| 263 | + u64 tx_tls_ctx; |
---|
| 264 | + u64 tx_tls_ooo; |
---|
| 265 | + u64 tx_tls_skip_no_sync_data; |
---|
| 266 | + u64 tx_tls_drop_no_sync_data; |
---|
| 267 | + u64 tx_tls_drop_bypass_req; |
---|
| 268 | +#endif |
---|
241 | 269 | }; |
---|
242 | 270 | |
---|
243 | 271 | struct adapter_stats { |
---|
.. | .. |
---|
252 | 280 | const struct port_info *p, |
---|
253 | 281 | struct queue_port_stats *s) |
---|
254 | 282 | { |
---|
255 | | - int i; |
---|
256 | 283 | const struct sge_eth_txq *tx = &adap->sge.ethtxq[p->first_qset]; |
---|
257 | 284 | const struct sge_eth_rxq *rx = &adap->sge.ethrxq[p->first_qset]; |
---|
| 285 | +#if IS_ENABLED(CONFIG_CHELSIO_TLS_DEVICE) |
---|
| 286 | + const struct ch_ktls_port_stats_debug *ktls_stats; |
---|
| 287 | +#endif |
---|
| 288 | + struct sge_eohw_txq *eohw_tx; |
---|
| 289 | + unsigned int i; |
---|
258 | 290 | |
---|
259 | 291 | memset(s, 0, sizeof(*s)); |
---|
260 | 292 | for (i = 0; i < p->nqsets; i++, rx++, tx++) { |
---|
261 | 293 | s->tso += tx->tso; |
---|
| 294 | + s->uso += tx->uso; |
---|
262 | 295 | s->tx_csum += tx->tx_cso; |
---|
263 | 296 | s->rx_csum += rx->stats.rx_cso; |
---|
264 | 297 | s->vlan_ex += rx->stats.vlan_ex; |
---|
.. | .. |
---|
266 | 299 | s->gro_pkts += rx->stats.lro_pkts; |
---|
267 | 300 | s->gro_merged += rx->stats.lro_merged; |
---|
268 | 301 | } |
---|
| 302 | + |
---|
| 303 | + if (adap->sge.eohw_txq) { |
---|
| 304 | + eohw_tx = &adap->sge.eohw_txq[p->first_qset]; |
---|
| 305 | + for (i = 0; i < p->nqsets; i++, eohw_tx++) { |
---|
| 306 | + s->tso += eohw_tx->tso; |
---|
| 307 | + s->uso += eohw_tx->uso; |
---|
| 308 | + s->tx_csum += eohw_tx->tx_cso; |
---|
| 309 | + s->vlan_ins += eohw_tx->vlan_ins; |
---|
| 310 | + } |
---|
| 311 | + } |
---|
| 312 | +#if IS_ENABLED(CONFIG_CHELSIO_TLS_DEVICE) |
---|
| 313 | + ktls_stats = &adap->ch_ktls_stats.ktls_port[p->port_id]; |
---|
| 314 | + s->tx_tls_encrypted_packets = |
---|
| 315 | + atomic64_read(&ktls_stats->ktls_tx_encrypted_packets); |
---|
| 316 | + s->tx_tls_encrypted_bytes = |
---|
| 317 | + atomic64_read(&ktls_stats->ktls_tx_encrypted_bytes); |
---|
| 318 | + s->tx_tls_ctx = atomic64_read(&ktls_stats->ktls_tx_ctx); |
---|
| 319 | + s->tx_tls_ooo = atomic64_read(&ktls_stats->ktls_tx_ooo); |
---|
| 320 | + s->tx_tls_skip_no_sync_data = |
---|
| 321 | + atomic64_read(&ktls_stats->ktls_tx_skip_no_sync_data); |
---|
| 322 | + s->tx_tls_drop_no_sync_data = |
---|
| 323 | + atomic64_read(&ktls_stats->ktls_tx_drop_no_sync_data); |
---|
| 324 | + s->tx_tls_drop_bypass_req = |
---|
| 325 | + atomic64_read(&ktls_stats->ktls_tx_drop_bypass_req); |
---|
| 326 | +#endif |
---|
269 | 327 | } |
---|
270 | 328 | |
---|
271 | 329 | static void collect_adapter_stats(struct adapter *adap, struct adapter_stats *s) |
---|
.. | .. |
---|
442 | 500 | * Link Mode Mask. |
---|
443 | 501 | */ |
---|
444 | 502 | static void fw_caps_to_lmm(enum fw_port_type port_type, |
---|
445 | | - unsigned int fw_caps, |
---|
| 503 | + fw_port_cap32_t fw_caps, |
---|
446 | 504 | unsigned long *link_mode_mask) |
---|
447 | 505 | { |
---|
448 | 506 | #define SET_LMM(__lmm_name) \ |
---|
449 | | - __set_bit(ETHTOOL_LINK_MODE_ ## __lmm_name ## _BIT, \ |
---|
450 | | - link_mode_mask) |
---|
| 507 | + do { \ |
---|
| 508 | + __set_bit(ETHTOOL_LINK_MODE_ ## __lmm_name ## _BIT, \ |
---|
| 509 | + link_mode_mask); \ |
---|
| 510 | + } while (0) |
---|
451 | 511 | |
---|
452 | 512 | #define FW_CAPS_TO_LMM(__fw_name, __lmm_name) \ |
---|
453 | 513 | do { \ |
---|
.. | .. |
---|
541 | 601 | case FW_PORT_TYPE_CR4_QSFP: |
---|
542 | 602 | SET_LMM(FIBRE); |
---|
543 | 603 | FW_CAPS_TO_LMM(SPEED_1G, 1000baseT_Full); |
---|
544 | | - FW_CAPS_TO_LMM(SPEED_10G, 10000baseSR_Full); |
---|
| 604 | + FW_CAPS_TO_LMM(SPEED_10G, 10000baseKR_Full); |
---|
545 | 605 | FW_CAPS_TO_LMM(SPEED_40G, 40000baseSR4_Full); |
---|
546 | 606 | FW_CAPS_TO_LMM(SPEED_25G, 25000baseCR_Full); |
---|
547 | 607 | FW_CAPS_TO_LMM(SPEED_50G, 50000baseCR2_Full); |
---|
.. | .. |
---|
550 | 610 | |
---|
551 | 611 | default: |
---|
552 | 612 | break; |
---|
| 613 | + } |
---|
| 614 | + |
---|
| 615 | + if (fw_caps & FW_PORT_CAP32_FEC_V(FW_PORT_CAP32_FEC_M)) { |
---|
| 616 | + FW_CAPS_TO_LMM(FEC_RS, FEC_RS); |
---|
| 617 | + FW_CAPS_TO_LMM(FEC_BASER_RS, FEC_BASER); |
---|
| 618 | + } else { |
---|
| 619 | + SET_LMM(FEC_NONE); |
---|
553 | 620 | } |
---|
554 | 621 | |
---|
555 | 622 | FW_CAPS_TO_LMM(ANEG, Autoneg); |
---|
.. | .. |
---|
563 | 630 | /** |
---|
564 | 631 | * lmm_to_fw_caps - translate ethtool Link Mode Mask to Firmware |
---|
565 | 632 | * capabilities |
---|
566 | | - * @et_lmm: ethtool Link Mode Mask |
---|
| 633 | + * @link_mode_mask: ethtool Link Mode Mask |
---|
567 | 634 | * |
---|
568 | 635 | * Translate ethtool Link Mode Mask into a Firmware Port capabilities |
---|
569 | 636 | * value. |
---|
.. | .. |
---|
623 | 690 | |
---|
624 | 691 | fw_caps_to_lmm(pi->port_type, pi->link_cfg.pcaps, |
---|
625 | 692 | link_ksettings->link_modes.supported); |
---|
626 | | - fw_caps_to_lmm(pi->port_type, pi->link_cfg.acaps, |
---|
| 693 | + fw_caps_to_lmm(pi->port_type, |
---|
| 694 | + t4_link_acaps(pi->adapter, |
---|
| 695 | + pi->lport, |
---|
| 696 | + &pi->link_cfg), |
---|
627 | 697 | link_ksettings->link_modes.advertising); |
---|
628 | 698 | fw_caps_to_lmm(pi->port_type, pi->link_cfg.lpacaps, |
---|
629 | 699 | link_ksettings->link_modes.lp_advertising); |
---|
.. | .. |
---|
632 | 702 | ? pi->link_cfg.speed |
---|
633 | 703 | : SPEED_UNKNOWN); |
---|
634 | 704 | base->duplex = DUPLEX_FULL; |
---|
635 | | - |
---|
636 | | - if (pi->link_cfg.fc & PAUSE_RX) { |
---|
637 | | - if (pi->link_cfg.fc & PAUSE_TX) { |
---|
638 | | - ethtool_link_ksettings_add_link_mode(link_ksettings, |
---|
639 | | - advertising, |
---|
640 | | - Pause); |
---|
641 | | - } else { |
---|
642 | | - ethtool_link_ksettings_add_link_mode(link_ksettings, |
---|
643 | | - advertising, |
---|
644 | | - Asym_Pause); |
---|
645 | | - } |
---|
646 | | - } else if (pi->link_cfg.fc & PAUSE_TX) { |
---|
647 | | - ethtool_link_ksettings_add_link_mode(link_ksettings, |
---|
648 | | - advertising, |
---|
649 | | - Asym_Pause); |
---|
650 | | - } |
---|
651 | 705 | |
---|
652 | 706 | base->autoneg = pi->link_cfg.autoneg; |
---|
653 | 707 | if (pi->link_cfg.pcaps & FW_PORT_CAP32_ANEG) |
---|
.. | .. |
---|
679 | 733 | base->autoneg == AUTONEG_DISABLE) { |
---|
680 | 734 | fw_caps = speed_to_fw_caps(base->speed); |
---|
681 | 735 | |
---|
682 | | - /* Must only specify a single speed which must be supported |
---|
683 | | - * as part of the Physical Port Capabilities. |
---|
684 | | - */ |
---|
685 | | - if ((fw_caps & (fw_caps - 1)) != 0 || |
---|
686 | | - !(lc->pcaps & fw_caps)) |
---|
| 736 | + /* Speed must be supported by Physical Port Capabilities. */ |
---|
| 737 | + if (!(lc->pcaps & fw_caps)) |
---|
687 | 738 | return -EINVAL; |
---|
688 | 739 | |
---|
689 | 740 | lc->speed_caps = fw_caps; |
---|
690 | 741 | lc->acaps = fw_caps; |
---|
691 | 742 | } else { |
---|
692 | 743 | fw_caps = |
---|
693 | | - lmm_to_fw_caps(link_ksettings->link_modes.advertising); |
---|
| 744 | + lmm_to_fw_caps(link_ksettings->link_modes.advertising); |
---|
694 | 745 | if (!(lc->pcaps & fw_caps)) |
---|
695 | 746 | return -EINVAL; |
---|
696 | 747 | lc->speed_caps = 0; |
---|
.. | .. |
---|
812 | 863 | struct port_info *p = netdev_priv(dev); |
---|
813 | 864 | |
---|
814 | 865 | epause->autoneg = (p->link_cfg.requested_fc & PAUSE_AUTONEG) != 0; |
---|
815 | | - epause->rx_pause = (p->link_cfg.fc & PAUSE_RX) != 0; |
---|
816 | | - epause->tx_pause = (p->link_cfg.fc & PAUSE_TX) != 0; |
---|
| 866 | + epause->rx_pause = (p->link_cfg.advertised_fc & PAUSE_RX) != 0; |
---|
| 867 | + epause->tx_pause = (p->link_cfg.advertised_fc & PAUSE_TX) != 0; |
---|
817 | 868 | } |
---|
818 | 869 | |
---|
819 | 870 | static int set_pauseparam(struct net_device *dev, |
---|
.. | .. |
---|
869 | 920 | e->rx_pending < MIN_FL_ENTRIES || e->tx_pending < MIN_TXQ_ENTRIES) |
---|
870 | 921 | return -EINVAL; |
---|
871 | 922 | |
---|
872 | | - if (adapter->flags & FULL_INIT_DONE) |
---|
| 923 | + if (adapter->flags & CXGB4_FULL_INIT_DONE) |
---|
873 | 924 | return -EBUSY; |
---|
874 | 925 | |
---|
875 | 926 | for (i = 0; i < pi->nqsets; ++i) { |
---|
.. | .. |
---|
926 | 977 | return q->rspq.adaptive_rx; |
---|
927 | 978 | } |
---|
928 | 979 | |
---|
929 | | -static int set_coalesce(struct net_device *dev, struct ethtool_coalesce *c) |
---|
| 980 | +/* Return the current global Adapter SGE Doorbell Queue Timer Tick for all |
---|
| 981 | + * Ethernet TX Queues. |
---|
| 982 | + */ |
---|
| 983 | +static int get_dbqtimer_tick(struct net_device *dev) |
---|
930 | 984 | { |
---|
931 | | - set_adaptive_rx_setting(dev, c->use_adaptive_rx_coalesce); |
---|
932 | | - return set_rx_intr_params(dev, c->rx_coalesce_usecs, |
---|
933 | | - c->rx_max_coalesced_frames); |
---|
| 985 | + struct port_info *pi = netdev_priv(dev); |
---|
| 986 | + struct adapter *adap = pi->adapter; |
---|
| 987 | + |
---|
| 988 | + if (!(adap->flags & CXGB4_SGE_DBQ_TIMER)) |
---|
| 989 | + return 0; |
---|
| 990 | + |
---|
| 991 | + return adap->sge.dbqtimer_tick; |
---|
| 992 | +} |
---|
| 993 | + |
---|
| 994 | +/* Return the SGE Doorbell Queue Timer Value for the Ethernet TX Queues |
---|
| 995 | + * associated with a Network Device. |
---|
| 996 | + */ |
---|
| 997 | +static int get_dbqtimer(struct net_device *dev) |
---|
| 998 | +{ |
---|
| 999 | + struct port_info *pi = netdev_priv(dev); |
---|
| 1000 | + struct adapter *adap = pi->adapter; |
---|
| 1001 | + struct sge_eth_txq *txq; |
---|
| 1002 | + |
---|
| 1003 | + txq = &adap->sge.ethtxq[pi->first_qset]; |
---|
| 1004 | + |
---|
| 1005 | + if (!(adap->flags & CXGB4_SGE_DBQ_TIMER)) |
---|
| 1006 | + return 0; |
---|
| 1007 | + |
---|
| 1008 | + /* all of the TX Queues use the same Timer Index */ |
---|
| 1009 | + return adap->sge.dbqtimer_val[txq->dbqtimerix]; |
---|
| 1010 | +} |
---|
| 1011 | + |
---|
| 1012 | +/* Set the global Adapter SGE Doorbell Queue Timer Tick for all Ethernet TX |
---|
| 1013 | + * Queues. This is the fundamental "Tick" that sets the scale of values which |
---|
| 1014 | + * can be used. Individual Ethernet TX Queues index into a relatively small |
---|
| 1015 | + * array of Tick Multipliers. Changing the base Tick will thus change all of |
---|
| 1016 | + * the resulting Timer Values associated with those multipliers for all |
---|
| 1017 | + * Ethernet TX Queues. |
---|
| 1018 | + */ |
---|
| 1019 | +static int set_dbqtimer_tick(struct net_device *dev, int usecs) |
---|
| 1020 | +{ |
---|
| 1021 | + struct port_info *pi = netdev_priv(dev); |
---|
| 1022 | + struct adapter *adap = pi->adapter; |
---|
| 1023 | + struct sge *s = &adap->sge; |
---|
| 1024 | + u32 param, val; |
---|
| 1025 | + int ret; |
---|
| 1026 | + |
---|
| 1027 | + if (!(adap->flags & CXGB4_SGE_DBQ_TIMER)) |
---|
| 1028 | + return 0; |
---|
| 1029 | + |
---|
| 1030 | + /* return early if it's the same Timer Tick we're already using */ |
---|
| 1031 | + if (s->dbqtimer_tick == usecs) |
---|
| 1032 | + return 0; |
---|
| 1033 | + |
---|
| 1034 | + /* attempt to set the new Timer Tick value */ |
---|
| 1035 | + param = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) | |
---|
| 1036 | + FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_DBQ_TIMERTICK)); |
---|
| 1037 | + val = usecs; |
---|
| 1038 | + ret = t4_set_params(adap, adap->mbox, adap->pf, 0, 1, ¶m, &val); |
---|
| 1039 | + if (ret) |
---|
| 1040 | + return ret; |
---|
| 1041 | + s->dbqtimer_tick = usecs; |
---|
| 1042 | + |
---|
| 1043 | + /* if successful, reread resulting dependent Timer values */ |
---|
| 1044 | + ret = t4_read_sge_dbqtimers(adap, ARRAY_SIZE(s->dbqtimer_val), |
---|
| 1045 | + s->dbqtimer_val); |
---|
| 1046 | + return ret; |
---|
| 1047 | +} |
---|
| 1048 | + |
---|
| 1049 | +/* Set the SGE Doorbell Queue Timer Value for the Ethernet TX Queues |
---|
| 1050 | + * associated with a Network Device. There is a relatively small array of |
---|
| 1051 | + * possible Timer Values so we need to pick the closest value available. |
---|
| 1052 | + */ |
---|
| 1053 | +static int set_dbqtimer(struct net_device *dev, int usecs) |
---|
| 1054 | +{ |
---|
| 1055 | + int qix, timerix, min_timerix, delta, min_delta; |
---|
| 1056 | + struct port_info *pi = netdev_priv(dev); |
---|
| 1057 | + struct adapter *adap = pi->adapter; |
---|
| 1058 | + struct sge *s = &adap->sge; |
---|
| 1059 | + struct sge_eth_txq *txq; |
---|
| 1060 | + u32 param, val; |
---|
| 1061 | + int ret; |
---|
| 1062 | + |
---|
| 1063 | + if (!(adap->flags & CXGB4_SGE_DBQ_TIMER)) |
---|
| 1064 | + return 0; |
---|
| 1065 | + |
---|
| 1066 | + /* Find the SGE Doorbell Timer Value that's closest to the requested |
---|
| 1067 | + * value. |
---|
| 1068 | + */ |
---|
| 1069 | + min_delta = INT_MAX; |
---|
| 1070 | + min_timerix = 0; |
---|
| 1071 | + for (timerix = 0; timerix < ARRAY_SIZE(s->dbqtimer_val); timerix++) { |
---|
| 1072 | + delta = s->dbqtimer_val[timerix] - usecs; |
---|
| 1073 | + if (delta < 0) |
---|
| 1074 | + delta = -delta; |
---|
| 1075 | + if (delta < min_delta) { |
---|
| 1076 | + min_delta = delta; |
---|
| 1077 | + min_timerix = timerix; |
---|
| 1078 | + } |
---|
| 1079 | + } |
---|
| 1080 | + |
---|
| 1081 | + /* Return early if it's the same Timer Index we're already using. |
---|
| 1082 | + * We use the same Timer Index for all of the TX Queues for an |
---|
| 1083 | + * interface so it's only necessary to check the first one. |
---|
| 1084 | + */ |
---|
| 1085 | + txq = &s->ethtxq[pi->first_qset]; |
---|
| 1086 | + if (txq->dbqtimerix == min_timerix) |
---|
| 1087 | + return 0; |
---|
| 1088 | + |
---|
| 1089 | + for (qix = 0; qix < pi->nqsets; qix++, txq++) { |
---|
| 1090 | + if (adap->flags & CXGB4_FULL_INIT_DONE) { |
---|
| 1091 | + param = |
---|
| 1092 | + (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DMAQ) | |
---|
| 1093 | + FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DMAQ_EQ_TIMERIX) | |
---|
| 1094 | + FW_PARAMS_PARAM_YZ_V(txq->q.cntxt_id)); |
---|
| 1095 | + val = min_timerix; |
---|
| 1096 | + ret = t4_set_params(adap, adap->mbox, adap->pf, 0, |
---|
| 1097 | + 1, ¶m, &val); |
---|
| 1098 | + if (ret) |
---|
| 1099 | + return ret; |
---|
| 1100 | + } |
---|
| 1101 | + txq->dbqtimerix = min_timerix; |
---|
| 1102 | + } |
---|
| 1103 | + return 0; |
---|
| 1104 | +} |
---|
| 1105 | + |
---|
| 1106 | +/* Set the global Adapter SGE Doorbell Queue Timer Tick for all Ethernet TX |
---|
| 1107 | + * Queues and the Timer Value for the Ethernet TX Queues associated with a |
---|
| 1108 | + * Network Device. Since changing the global Tick changes all of the |
---|
| 1109 | + * available Timer Values, we need to do this first before selecting the |
---|
| 1110 | + * resulting closest Timer Value. Moreover, since the Tick is global, |
---|
| 1111 | + * changing it affects the Timer Values for all Network Devices on the |
---|
| 1112 | + * adapter. So, before changing the Tick, we grab all of the current Timer |
---|
| 1113 | + * Values for other Network Devices on this Adapter and then attempt to select |
---|
| 1114 | + * new Timer Values which are close to the old values ... |
---|
| 1115 | + */ |
---|
| 1116 | +static int set_dbqtimer_tickval(struct net_device *dev, |
---|
| 1117 | + int tick_usecs, int timer_usecs) |
---|
| 1118 | +{ |
---|
| 1119 | + struct port_info *pi = netdev_priv(dev); |
---|
| 1120 | + struct adapter *adap = pi->adapter; |
---|
| 1121 | + int timer[MAX_NPORTS]; |
---|
| 1122 | + unsigned int port; |
---|
| 1123 | + int ret; |
---|
| 1124 | + |
---|
| 1125 | + /* Grab the other adapter Network Interface current timers and fill in |
---|
| 1126 | + * the new one for this Network Interface. |
---|
| 1127 | + */ |
---|
| 1128 | + for_each_port(adap, port) |
---|
| 1129 | + if (port == pi->port_id) |
---|
| 1130 | + timer[port] = timer_usecs; |
---|
| 1131 | + else |
---|
| 1132 | + timer[port] = get_dbqtimer(adap->port[port]); |
---|
| 1133 | + |
---|
| 1134 | + /* Change the global Tick first ... */ |
---|
| 1135 | + ret = set_dbqtimer_tick(dev, tick_usecs); |
---|
| 1136 | + if (ret) |
---|
| 1137 | + return ret; |
---|
| 1138 | + |
---|
| 1139 | + /* ... and then set all of the Network Interface Timer Values ... */ |
---|
| 1140 | + for_each_port(adap, port) { |
---|
| 1141 | + ret = set_dbqtimer(adap->port[port], timer[port]); |
---|
| 1142 | + if (ret) |
---|
| 1143 | + return ret; |
---|
| 1144 | + } |
---|
| 1145 | + |
---|
| 1146 | + return 0; |
---|
| 1147 | +} |
---|
| 1148 | + |
---|
| 1149 | +static int set_coalesce(struct net_device *dev, |
---|
| 1150 | + struct ethtool_coalesce *coalesce) |
---|
| 1151 | +{ |
---|
| 1152 | + int ret; |
---|
| 1153 | + |
---|
| 1154 | + set_adaptive_rx_setting(dev, coalesce->use_adaptive_rx_coalesce); |
---|
| 1155 | + |
---|
| 1156 | + ret = set_rx_intr_params(dev, coalesce->rx_coalesce_usecs, |
---|
| 1157 | + coalesce->rx_max_coalesced_frames); |
---|
| 1158 | + if (ret) |
---|
| 1159 | + return ret; |
---|
| 1160 | + |
---|
| 1161 | + return set_dbqtimer_tickval(dev, |
---|
| 1162 | + coalesce->tx_coalesce_usecs_irq, |
---|
| 1163 | + coalesce->tx_coalesce_usecs); |
---|
934 | 1164 | } |
---|
935 | 1165 | |
---|
936 | 1166 | static int get_coalesce(struct net_device *dev, struct ethtool_coalesce *c) |
---|
.. | .. |
---|
943 | 1173 | c->rx_max_coalesced_frames = (rq->intr_params & QINTR_CNT_EN_F) ? |
---|
944 | 1174 | adap->sge.counter_val[rq->pktcnt_idx] : 0; |
---|
945 | 1175 | c->use_adaptive_rx_coalesce = get_adaptive_rx_setting(dev); |
---|
| 1176 | + c->tx_coalesce_usecs_irq = get_dbqtimer_tick(dev); |
---|
| 1177 | + c->tx_coalesce_usecs = get_dbqtimer(dev); |
---|
946 | 1178 | return 0; |
---|
947 | 1179 | } |
---|
948 | 1180 | |
---|
.. | .. |
---|
1045 | 1277 | return err; |
---|
1046 | 1278 | } |
---|
1047 | 1279 | |
---|
1048 | | -static int set_flash(struct net_device *netdev, struct ethtool_flash *ef) |
---|
| 1280 | +static int cxgb4_ethtool_flash_bootcfg(struct net_device *netdev, |
---|
| 1281 | + const u8 *data, u32 size) |
---|
1049 | 1282 | { |
---|
| 1283 | + struct adapter *adap = netdev2adap(netdev); |
---|
1050 | 1284 | int ret; |
---|
1051 | | - const struct firmware *fw; |
---|
| 1285 | + |
---|
| 1286 | + ret = t4_load_bootcfg(adap, data, size); |
---|
| 1287 | + if (ret) |
---|
| 1288 | + dev_err(adap->pdev_dev, "Failed to load boot cfg image\n"); |
---|
| 1289 | + |
---|
| 1290 | + return ret; |
---|
| 1291 | +} |
---|
| 1292 | + |
---|
| 1293 | +static int cxgb4_ethtool_flash_boot(struct net_device *netdev, |
---|
| 1294 | + const u8 *bdata, u32 size) |
---|
| 1295 | +{ |
---|
| 1296 | + struct adapter *adap = netdev2adap(netdev); |
---|
| 1297 | + unsigned int offset; |
---|
| 1298 | + u8 *data; |
---|
| 1299 | + int ret; |
---|
| 1300 | + |
---|
| 1301 | + data = kmemdup(bdata, size, GFP_KERNEL); |
---|
| 1302 | + if (!data) |
---|
| 1303 | + return -ENOMEM; |
---|
| 1304 | + |
---|
| 1305 | + offset = OFFSET_G(t4_read_reg(adap, PF_REG(0, PCIE_PF_EXPROM_OFST_A))); |
---|
| 1306 | + |
---|
| 1307 | + ret = t4_load_boot(adap, data, offset, size); |
---|
| 1308 | + if (ret) |
---|
| 1309 | + dev_err(adap->pdev_dev, "Failed to load boot image\n"); |
---|
| 1310 | + |
---|
| 1311 | + kfree(data); |
---|
| 1312 | + return ret; |
---|
| 1313 | +} |
---|
| 1314 | + |
---|
| 1315 | +#define CXGB4_PHY_SIG 0x130000ea |
---|
| 1316 | + |
---|
| 1317 | +static int cxgb4_validate_phy_image(const u8 *data, u32 *size) |
---|
| 1318 | +{ |
---|
| 1319 | + struct cxgb4_fw_data *header; |
---|
| 1320 | + |
---|
| 1321 | + header = (struct cxgb4_fw_data *)data; |
---|
| 1322 | + if (be32_to_cpu(header->signature) != CXGB4_PHY_SIG) |
---|
| 1323 | + return -EINVAL; |
---|
| 1324 | + |
---|
| 1325 | + return 0; |
---|
| 1326 | +} |
---|
| 1327 | + |
---|
| 1328 | +static int cxgb4_ethtool_flash_phy(struct net_device *netdev, |
---|
| 1329 | + const u8 *data, u32 size) |
---|
| 1330 | +{ |
---|
| 1331 | + struct adapter *adap = netdev2adap(netdev); |
---|
| 1332 | + int ret; |
---|
| 1333 | + |
---|
| 1334 | + ret = cxgb4_validate_phy_image(data, NULL); |
---|
| 1335 | + if (ret) { |
---|
| 1336 | + dev_err(adap->pdev_dev, "PHY signature mismatch\n"); |
---|
| 1337 | + return ret; |
---|
| 1338 | + } |
---|
| 1339 | + |
---|
| 1340 | + /* We have to RESET the chip/firmware because we need the |
---|
| 1341 | + * chip in uninitialized state for loading new PHY image. |
---|
| 1342 | + * Otherwise, the running firmware will only store the PHY |
---|
| 1343 | + * image in local RAM which will be lost after next reset. |
---|
| 1344 | + */ |
---|
| 1345 | + ret = t4_fw_reset(adap, adap->mbox, PIORSTMODE_F | PIORST_F); |
---|
| 1346 | + if (ret < 0) { |
---|
| 1347 | + dev_err(adap->pdev_dev, |
---|
| 1348 | + "Set FW to RESET for flashing PHY FW failed. ret: %d\n", |
---|
| 1349 | + ret); |
---|
| 1350 | + return ret; |
---|
| 1351 | + } |
---|
| 1352 | + |
---|
| 1353 | + ret = t4_load_phy_fw(adap, MEMWIN_NIC, NULL, data, size); |
---|
| 1354 | + if (ret < 0) { |
---|
| 1355 | + dev_err(adap->pdev_dev, "Failed to load PHY FW. ret: %d\n", |
---|
| 1356 | + ret); |
---|
| 1357 | + return ret; |
---|
| 1358 | + } |
---|
| 1359 | + |
---|
| 1360 | + return 0; |
---|
| 1361 | +} |
---|
| 1362 | + |
---|
| 1363 | +static int cxgb4_ethtool_flash_fw(struct net_device *netdev, |
---|
| 1364 | + const u8 *data, u32 size) |
---|
| 1365 | +{ |
---|
1052 | 1366 | struct adapter *adap = netdev2adap(netdev); |
---|
1053 | 1367 | unsigned int mbox = PCIE_FW_MASTER_M + 1; |
---|
1054 | | - u32 pcie_fw; |
---|
| 1368 | + int ret; |
---|
| 1369 | + |
---|
| 1370 | + /* If the adapter has been fully initialized then we'll go ahead and |
---|
| 1371 | + * try to get the firmware's cooperation in upgrading to the new |
---|
| 1372 | + * firmware image otherwise we'll try to do the entire job from the |
---|
| 1373 | + * host ... and we always "force" the operation in this path. |
---|
| 1374 | + */ |
---|
| 1375 | + if (adap->flags & CXGB4_FULL_INIT_DONE) |
---|
| 1376 | + mbox = adap->mbox; |
---|
| 1377 | + |
---|
| 1378 | + ret = t4_fw_upgrade(adap, mbox, data, size, 1); |
---|
| 1379 | + if (ret) |
---|
| 1380 | + dev_err(adap->pdev_dev, |
---|
| 1381 | + "Failed to flash firmware\n"); |
---|
| 1382 | + |
---|
| 1383 | + return ret; |
---|
| 1384 | +} |
---|
| 1385 | + |
---|
| 1386 | +static int cxgb4_ethtool_flash_region(struct net_device *netdev, |
---|
| 1387 | + const u8 *data, u32 size, u32 region) |
---|
| 1388 | +{ |
---|
| 1389 | + struct adapter *adap = netdev2adap(netdev); |
---|
| 1390 | + int ret; |
---|
| 1391 | + |
---|
| 1392 | + switch (region) { |
---|
| 1393 | + case CXGB4_ETHTOOL_FLASH_FW: |
---|
| 1394 | + ret = cxgb4_ethtool_flash_fw(netdev, data, size); |
---|
| 1395 | + break; |
---|
| 1396 | + case CXGB4_ETHTOOL_FLASH_PHY: |
---|
| 1397 | + ret = cxgb4_ethtool_flash_phy(netdev, data, size); |
---|
| 1398 | + break; |
---|
| 1399 | + case CXGB4_ETHTOOL_FLASH_BOOT: |
---|
| 1400 | + ret = cxgb4_ethtool_flash_boot(netdev, data, size); |
---|
| 1401 | + break; |
---|
| 1402 | + case CXGB4_ETHTOOL_FLASH_BOOTCFG: |
---|
| 1403 | + ret = cxgb4_ethtool_flash_bootcfg(netdev, data, size); |
---|
| 1404 | + break; |
---|
| 1405 | + default: |
---|
| 1406 | + ret = -EOPNOTSUPP; |
---|
| 1407 | + break; |
---|
| 1408 | + } |
---|
| 1409 | + |
---|
| 1410 | + if (!ret) |
---|
| 1411 | + dev_info(adap->pdev_dev, |
---|
| 1412 | + "loading %s successful, reload cxgb4 driver\n", |
---|
| 1413 | + flash_region_strings[region]); |
---|
| 1414 | + return ret; |
---|
| 1415 | +} |
---|
| 1416 | + |
---|
| 1417 | +#define CXGB4_FW_SIG 0x4368656c |
---|
| 1418 | +#define CXGB4_FW_SIG_OFFSET 0x160 |
---|
| 1419 | + |
---|
| 1420 | +static int cxgb4_validate_fw_image(const u8 *data, u32 *size) |
---|
| 1421 | +{ |
---|
| 1422 | + struct cxgb4_fw_data *header; |
---|
| 1423 | + |
---|
| 1424 | + header = (struct cxgb4_fw_data *)&data[CXGB4_FW_SIG_OFFSET]; |
---|
| 1425 | + if (be32_to_cpu(header->signature) != CXGB4_FW_SIG) |
---|
| 1426 | + return -EINVAL; |
---|
| 1427 | + |
---|
| 1428 | + if (size) |
---|
| 1429 | + *size = be16_to_cpu(((struct fw_hdr *)data)->len512) * 512; |
---|
| 1430 | + |
---|
| 1431 | + return 0; |
---|
| 1432 | +} |
---|
| 1433 | + |
---|
| 1434 | +static int cxgb4_validate_bootcfg_image(const u8 *data, u32 *size) |
---|
| 1435 | +{ |
---|
| 1436 | + struct cxgb4_bootcfg_data *header; |
---|
| 1437 | + |
---|
| 1438 | + header = (struct cxgb4_bootcfg_data *)data; |
---|
| 1439 | + if (le16_to_cpu(header->signature) != BOOT_CFG_SIG) |
---|
| 1440 | + return -EINVAL; |
---|
| 1441 | + |
---|
| 1442 | + return 0; |
---|
| 1443 | +} |
---|
| 1444 | + |
---|
| 1445 | +static int cxgb4_validate_boot_image(const u8 *data, u32 *size) |
---|
| 1446 | +{ |
---|
| 1447 | + struct cxgb4_pci_exp_rom_header *exp_header; |
---|
| 1448 | + struct cxgb4_pcir_data *pcir_header; |
---|
| 1449 | + struct legacy_pci_rom_hdr *header; |
---|
| 1450 | + const u8 *cur_header = data; |
---|
| 1451 | + u16 pcir_offset; |
---|
| 1452 | + |
---|
| 1453 | + exp_header = (struct cxgb4_pci_exp_rom_header *)data; |
---|
| 1454 | + |
---|
| 1455 | + if (le16_to_cpu(exp_header->signature) != BOOT_SIGNATURE) |
---|
| 1456 | + return -EINVAL; |
---|
| 1457 | + |
---|
| 1458 | + if (size) { |
---|
| 1459 | + do { |
---|
| 1460 | + header = (struct legacy_pci_rom_hdr *)cur_header; |
---|
| 1461 | + pcir_offset = le16_to_cpu(header->pcir_offset); |
---|
| 1462 | + pcir_header = (struct cxgb4_pcir_data *)(cur_header + |
---|
| 1463 | + pcir_offset); |
---|
| 1464 | + |
---|
| 1465 | + *size += header->size512 * 512; |
---|
| 1466 | + cur_header += header->size512 * 512; |
---|
| 1467 | + } while (!(pcir_header->indicator & CXGB4_HDR_INDI)); |
---|
| 1468 | + } |
---|
| 1469 | + |
---|
| 1470 | + return 0; |
---|
| 1471 | +} |
---|
| 1472 | + |
---|
| 1473 | +static int cxgb4_ethtool_get_flash_region(const u8 *data, u32 *size) |
---|
| 1474 | +{ |
---|
| 1475 | + if (!cxgb4_validate_fw_image(data, size)) |
---|
| 1476 | + return CXGB4_ETHTOOL_FLASH_FW; |
---|
| 1477 | + if (!cxgb4_validate_boot_image(data, size)) |
---|
| 1478 | + return CXGB4_ETHTOOL_FLASH_BOOT; |
---|
| 1479 | + if (!cxgb4_validate_phy_image(data, size)) |
---|
| 1480 | + return CXGB4_ETHTOOL_FLASH_PHY; |
---|
| 1481 | + if (!cxgb4_validate_bootcfg_image(data, size)) |
---|
| 1482 | + return CXGB4_ETHTOOL_FLASH_BOOTCFG; |
---|
| 1483 | + |
---|
| 1484 | + return -EOPNOTSUPP; |
---|
| 1485 | +} |
---|
| 1486 | + |
---|
| 1487 | +static int set_flash(struct net_device *netdev, struct ethtool_flash *ef) |
---|
| 1488 | +{ |
---|
| 1489 | + struct adapter *adap = netdev2adap(netdev); |
---|
| 1490 | + const struct firmware *fw; |
---|
1055 | 1491 | unsigned int master; |
---|
1056 | 1492 | u8 master_vld = 0; |
---|
| 1493 | + const u8 *fw_data; |
---|
| 1494 | + size_t fw_size; |
---|
| 1495 | + u32 size = 0; |
---|
| 1496 | + u32 pcie_fw; |
---|
| 1497 | + int region; |
---|
| 1498 | + int ret; |
---|
1057 | 1499 | |
---|
1058 | 1500 | pcie_fw = t4_read_reg(adap, PCIE_FW_A); |
---|
1059 | 1501 | master = PCIE_FW_MASTER_G(pcie_fw); |
---|
.. | .. |
---|
1071 | 1513 | if (ret < 0) |
---|
1072 | 1514 | return ret; |
---|
1073 | 1515 | |
---|
1074 | | - /* If the adapter has been fully initialized then we'll go ahead and |
---|
1075 | | - * try to get the firmware's cooperation in upgrading to the new |
---|
1076 | | - * firmware image otherwise we'll try to do the entire job from the |
---|
1077 | | - * host ... and we always "force" the operation in this path. |
---|
1078 | | - */ |
---|
1079 | | - if (adap->flags & FULL_INIT_DONE) |
---|
1080 | | - mbox = adap->mbox; |
---|
| 1516 | + fw_data = fw->data; |
---|
| 1517 | + fw_size = fw->size; |
---|
| 1518 | + if (ef->region == ETHTOOL_FLASH_ALL_REGIONS) { |
---|
| 1519 | + while (fw_size > 0) { |
---|
| 1520 | + size = 0; |
---|
| 1521 | + region = cxgb4_ethtool_get_flash_region(fw_data, &size); |
---|
| 1522 | + if (region < 0 || !size) { |
---|
| 1523 | + ret = region; |
---|
| 1524 | + goto out_free_fw; |
---|
| 1525 | + } |
---|
1081 | 1526 | |
---|
1082 | | - ret = t4_fw_upgrade(adap, mbox, fw->data, fw->size, 1); |
---|
| 1527 | + ret = cxgb4_ethtool_flash_region(netdev, fw_data, size, |
---|
| 1528 | + region); |
---|
| 1529 | + if (ret) |
---|
| 1530 | + goto out_free_fw; |
---|
| 1531 | + |
---|
| 1532 | + fw_data += size; |
---|
| 1533 | + fw_size -= size; |
---|
| 1534 | + } |
---|
| 1535 | + } else { |
---|
| 1536 | + ret = cxgb4_ethtool_flash_region(netdev, fw_data, fw_size, |
---|
| 1537 | + ef->region); |
---|
| 1538 | + } |
---|
| 1539 | + |
---|
| 1540 | +out_free_fw: |
---|
1083 | 1541 | release_firmware(fw); |
---|
1084 | | - if (!ret) |
---|
1085 | | - dev_info(adap->pdev_dev, |
---|
1086 | | - "loaded firmware %s, reload cxgb4 driver\n", ef->data); |
---|
1087 | 1542 | return ret; |
---|
1088 | 1543 | } |
---|
1089 | 1544 | |
---|
.. | .. |
---|
1155 | 1610 | return 0; |
---|
1156 | 1611 | |
---|
1157 | 1612 | /* Interface must be brought up atleast once */ |
---|
1158 | | - if (pi->adapter->flags & FULL_INIT_DONE) { |
---|
| 1613 | + if (pi->adapter->flags & CXGB4_FULL_INIT_DONE) { |
---|
1159 | 1614 | for (i = 0; i < pi->rss_size; i++) |
---|
1160 | 1615 | pi->rss[i] = p[i]; |
---|
1161 | 1616 | |
---|
.. | .. |
---|
1165 | 1620 | return -EPERM; |
---|
1166 | 1621 | } |
---|
1167 | 1622 | |
---|
| 1623 | +static struct filter_entry *cxgb4_get_filter_entry(struct adapter *adap, |
---|
| 1624 | + u32 ftid) |
---|
| 1625 | +{ |
---|
| 1626 | + struct tid_info *t = &adap->tids; |
---|
| 1627 | + |
---|
| 1628 | + if (ftid >= t->hpftid_base && ftid < t->hpftid_base + t->nhpftids) |
---|
| 1629 | + return &t->hpftid_tab[ftid - t->hpftid_base]; |
---|
| 1630 | + |
---|
| 1631 | + if (ftid >= t->ftid_base && ftid < t->ftid_base + t->nftids) |
---|
| 1632 | + return &t->ftid_tab[ftid - t->ftid_base]; |
---|
| 1633 | + |
---|
| 1634 | + return lookup_tid(t, ftid); |
---|
| 1635 | +} |
---|
| 1636 | + |
---|
| 1637 | +static void cxgb4_fill_filter_rule(struct ethtool_rx_flow_spec *fs, |
---|
| 1638 | + struct ch_filter_specification *dfs) |
---|
| 1639 | +{ |
---|
| 1640 | + switch (dfs->val.proto) { |
---|
| 1641 | + case IPPROTO_TCP: |
---|
| 1642 | + if (dfs->type) |
---|
| 1643 | + fs->flow_type = TCP_V6_FLOW; |
---|
| 1644 | + else |
---|
| 1645 | + fs->flow_type = TCP_V4_FLOW; |
---|
| 1646 | + break; |
---|
| 1647 | + case IPPROTO_UDP: |
---|
| 1648 | + if (dfs->type) |
---|
| 1649 | + fs->flow_type = UDP_V6_FLOW; |
---|
| 1650 | + else |
---|
| 1651 | + fs->flow_type = UDP_V4_FLOW; |
---|
| 1652 | + break; |
---|
| 1653 | + } |
---|
| 1654 | + |
---|
| 1655 | + if (dfs->type) { |
---|
| 1656 | + fs->h_u.tcp_ip6_spec.psrc = cpu_to_be16(dfs->val.fport); |
---|
| 1657 | + fs->m_u.tcp_ip6_spec.psrc = cpu_to_be16(dfs->mask.fport); |
---|
| 1658 | + fs->h_u.tcp_ip6_spec.pdst = cpu_to_be16(dfs->val.lport); |
---|
| 1659 | + fs->m_u.tcp_ip6_spec.pdst = cpu_to_be16(dfs->mask.lport); |
---|
| 1660 | + memcpy(&fs->h_u.tcp_ip6_spec.ip6src, &dfs->val.fip[0], |
---|
| 1661 | + sizeof(fs->h_u.tcp_ip6_spec.ip6src)); |
---|
| 1662 | + memcpy(&fs->m_u.tcp_ip6_spec.ip6src, &dfs->mask.fip[0], |
---|
| 1663 | + sizeof(fs->m_u.tcp_ip6_spec.ip6src)); |
---|
| 1664 | + memcpy(&fs->h_u.tcp_ip6_spec.ip6dst, &dfs->val.lip[0], |
---|
| 1665 | + sizeof(fs->h_u.tcp_ip6_spec.ip6dst)); |
---|
| 1666 | + memcpy(&fs->m_u.tcp_ip6_spec.ip6dst, &dfs->mask.lip[0], |
---|
| 1667 | + sizeof(fs->m_u.tcp_ip6_spec.ip6dst)); |
---|
| 1668 | + fs->h_u.tcp_ip6_spec.tclass = dfs->val.tos; |
---|
| 1669 | + fs->m_u.tcp_ip6_spec.tclass = dfs->mask.tos; |
---|
| 1670 | + } else { |
---|
| 1671 | + fs->h_u.tcp_ip4_spec.psrc = cpu_to_be16(dfs->val.fport); |
---|
| 1672 | + fs->m_u.tcp_ip4_spec.psrc = cpu_to_be16(dfs->mask.fport); |
---|
| 1673 | + fs->h_u.tcp_ip4_spec.pdst = cpu_to_be16(dfs->val.lport); |
---|
| 1674 | + fs->m_u.tcp_ip4_spec.pdst = cpu_to_be16(dfs->mask.lport); |
---|
| 1675 | + memcpy(&fs->h_u.tcp_ip4_spec.ip4src, &dfs->val.fip[0], |
---|
| 1676 | + sizeof(fs->h_u.tcp_ip4_spec.ip4src)); |
---|
| 1677 | + memcpy(&fs->m_u.tcp_ip4_spec.ip4src, &dfs->mask.fip[0], |
---|
| 1678 | + sizeof(fs->m_u.tcp_ip4_spec.ip4src)); |
---|
| 1679 | + memcpy(&fs->h_u.tcp_ip4_spec.ip4dst, &dfs->val.lip[0], |
---|
| 1680 | + sizeof(fs->h_u.tcp_ip4_spec.ip4dst)); |
---|
| 1681 | + memcpy(&fs->m_u.tcp_ip4_spec.ip4dst, &dfs->mask.lip[0], |
---|
| 1682 | + sizeof(fs->m_u.tcp_ip4_spec.ip4dst)); |
---|
| 1683 | + fs->h_u.tcp_ip4_spec.tos = dfs->val.tos; |
---|
| 1684 | + fs->m_u.tcp_ip4_spec.tos = dfs->mask.tos; |
---|
| 1685 | + } |
---|
| 1686 | + fs->h_ext.vlan_tci = cpu_to_be16(dfs->val.ivlan); |
---|
| 1687 | + fs->m_ext.vlan_tci = cpu_to_be16(dfs->mask.ivlan); |
---|
| 1688 | + fs->flow_type |= FLOW_EXT; |
---|
| 1689 | + |
---|
| 1690 | + if (dfs->action == FILTER_DROP) |
---|
| 1691 | + fs->ring_cookie = RX_CLS_FLOW_DISC; |
---|
| 1692 | + else |
---|
| 1693 | + fs->ring_cookie = dfs->iq; |
---|
| 1694 | +} |
---|
| 1695 | + |
---|
| 1696 | +static int cxgb4_ntuple_get_filter(struct net_device *dev, |
---|
| 1697 | + struct ethtool_rxnfc *cmd, |
---|
| 1698 | + unsigned int loc) |
---|
| 1699 | +{ |
---|
| 1700 | + const struct port_info *pi = netdev_priv(dev); |
---|
| 1701 | + struct adapter *adap = netdev2adap(dev); |
---|
| 1702 | + struct filter_entry *f; |
---|
| 1703 | + int ftid; |
---|
| 1704 | + |
---|
| 1705 | + if (!(adap->flags & CXGB4_FULL_INIT_DONE)) |
---|
| 1706 | + return -EAGAIN; |
---|
| 1707 | + |
---|
| 1708 | + /* Check for maximum filter range */ |
---|
| 1709 | + if (!adap->ethtool_filters) |
---|
| 1710 | + return -EOPNOTSUPP; |
---|
| 1711 | + |
---|
| 1712 | + if (loc >= adap->ethtool_filters->nentries) |
---|
| 1713 | + return -ERANGE; |
---|
| 1714 | + |
---|
| 1715 | + if (!test_bit(loc, adap->ethtool_filters->port[pi->port_id].bmap)) |
---|
| 1716 | + return -ENOENT; |
---|
| 1717 | + |
---|
| 1718 | + ftid = adap->ethtool_filters->port[pi->port_id].loc_array[loc]; |
---|
| 1719 | + |
---|
| 1720 | + /* Fetch filter_entry */ |
---|
| 1721 | + f = cxgb4_get_filter_entry(adap, ftid); |
---|
| 1722 | + |
---|
| 1723 | + cxgb4_fill_filter_rule(&cmd->fs, &f->fs); |
---|
| 1724 | + |
---|
| 1725 | + return 0; |
---|
| 1726 | +} |
---|
| 1727 | + |
---|
1168 | 1728 | static int get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info, |
---|
1169 | 1729 | u32 *rules) |
---|
1170 | 1730 | { |
---|
1171 | 1731 | const struct port_info *pi = netdev_priv(dev); |
---|
| 1732 | + struct adapter *adap = netdev2adap(dev); |
---|
| 1733 | + unsigned int count = 0, index = 0; |
---|
| 1734 | + int ret = 0; |
---|
1172 | 1735 | |
---|
1173 | 1736 | switch (info->cmd) { |
---|
1174 | 1737 | case ETHTOOL_GRXFH: { |
---|
.. | .. |
---|
1224 | 1787 | case ETHTOOL_GRXRINGS: |
---|
1225 | 1788 | info->data = pi->nqsets; |
---|
1226 | 1789 | return 0; |
---|
| 1790 | + case ETHTOOL_GRXCLSRLCNT: |
---|
| 1791 | + info->rule_cnt = |
---|
| 1792 | + adap->ethtool_filters->port[pi->port_id].in_use; |
---|
| 1793 | + return 0; |
---|
| 1794 | + case ETHTOOL_GRXCLSRULE: |
---|
| 1795 | + return cxgb4_ntuple_get_filter(dev, info, info->fs.location); |
---|
| 1796 | + case ETHTOOL_GRXCLSRLALL: |
---|
| 1797 | + info->data = adap->ethtool_filters->nentries; |
---|
| 1798 | + while (count < info->rule_cnt) { |
---|
| 1799 | + ret = cxgb4_ntuple_get_filter(dev, info, index); |
---|
| 1800 | + if (!ret) |
---|
| 1801 | + rules[count++] = index; |
---|
| 1802 | + index++; |
---|
| 1803 | + } |
---|
| 1804 | + return 0; |
---|
1227 | 1805 | } |
---|
| 1806 | + |
---|
1228 | 1807 | return -EOPNOTSUPP; |
---|
| 1808 | +} |
---|
| 1809 | + |
---|
| 1810 | +static int cxgb4_ntuple_del_filter(struct net_device *dev, |
---|
| 1811 | + struct ethtool_rxnfc *cmd) |
---|
| 1812 | +{ |
---|
| 1813 | + struct cxgb4_ethtool_filter_info *filter_info; |
---|
| 1814 | + struct adapter *adapter = netdev2adap(dev); |
---|
| 1815 | + struct port_info *pi = netdev_priv(dev); |
---|
| 1816 | + struct filter_entry *f; |
---|
| 1817 | + u32 filter_id; |
---|
| 1818 | + int ret; |
---|
| 1819 | + |
---|
| 1820 | + if (!(adapter->flags & CXGB4_FULL_INIT_DONE)) |
---|
| 1821 | + return -EAGAIN; /* can still change nfilters */ |
---|
| 1822 | + |
---|
| 1823 | + if (!adapter->ethtool_filters) |
---|
| 1824 | + return -EOPNOTSUPP; |
---|
| 1825 | + |
---|
| 1826 | + if (cmd->fs.location >= adapter->ethtool_filters->nentries) { |
---|
| 1827 | + dev_err(adapter->pdev_dev, |
---|
| 1828 | + "Location must be < %u", |
---|
| 1829 | + adapter->ethtool_filters->nentries); |
---|
| 1830 | + return -ERANGE; |
---|
| 1831 | + } |
---|
| 1832 | + |
---|
| 1833 | + filter_info = &adapter->ethtool_filters->port[pi->port_id]; |
---|
| 1834 | + |
---|
| 1835 | + if (!test_bit(cmd->fs.location, filter_info->bmap)) |
---|
| 1836 | + return -ENOENT; |
---|
| 1837 | + |
---|
| 1838 | + filter_id = filter_info->loc_array[cmd->fs.location]; |
---|
| 1839 | + f = cxgb4_get_filter_entry(adapter, filter_id); |
---|
| 1840 | + |
---|
| 1841 | + if (f->fs.prio) |
---|
| 1842 | + filter_id -= adapter->tids.hpftid_base; |
---|
| 1843 | + else if (!f->fs.hash) |
---|
| 1844 | + filter_id -= (adapter->tids.ftid_base - adapter->tids.nhpftids); |
---|
| 1845 | + |
---|
| 1846 | + ret = cxgb4_flow_rule_destroy(dev, f->fs.tc_prio, &f->fs, filter_id); |
---|
| 1847 | + if (ret) |
---|
| 1848 | + goto err; |
---|
| 1849 | + |
---|
| 1850 | + clear_bit(cmd->fs.location, filter_info->bmap); |
---|
| 1851 | + filter_info->in_use--; |
---|
| 1852 | + |
---|
| 1853 | +err: |
---|
| 1854 | + return ret; |
---|
| 1855 | +} |
---|
| 1856 | + |
---|
| 1857 | +/* Add Ethtool n-tuple filters. */ |
---|
| 1858 | +static int cxgb4_ntuple_set_filter(struct net_device *netdev, |
---|
| 1859 | + struct ethtool_rxnfc *cmd) |
---|
| 1860 | +{ |
---|
| 1861 | + struct ethtool_rx_flow_spec_input input = {}; |
---|
| 1862 | + struct cxgb4_ethtool_filter_info *filter_info; |
---|
| 1863 | + struct adapter *adapter = netdev2adap(netdev); |
---|
| 1864 | + struct port_info *pi = netdev_priv(netdev); |
---|
| 1865 | + struct ch_filter_specification fs; |
---|
| 1866 | + struct ethtool_rx_flow_rule *flow; |
---|
| 1867 | + u32 tid; |
---|
| 1868 | + int ret; |
---|
| 1869 | + |
---|
| 1870 | + if (!(adapter->flags & CXGB4_FULL_INIT_DONE)) |
---|
| 1871 | + return -EAGAIN; /* can still change nfilters */ |
---|
| 1872 | + |
---|
| 1873 | + if (!adapter->ethtool_filters) |
---|
| 1874 | + return -EOPNOTSUPP; |
---|
| 1875 | + |
---|
| 1876 | + if (cmd->fs.location >= adapter->ethtool_filters->nentries) { |
---|
| 1877 | + dev_err(adapter->pdev_dev, |
---|
| 1878 | + "Location must be < %u", |
---|
| 1879 | + adapter->ethtool_filters->nentries); |
---|
| 1880 | + return -ERANGE; |
---|
| 1881 | + } |
---|
| 1882 | + |
---|
| 1883 | + if (test_bit(cmd->fs.location, |
---|
| 1884 | + adapter->ethtool_filters->port[pi->port_id].bmap)) |
---|
| 1885 | + return -EEXIST; |
---|
| 1886 | + |
---|
| 1887 | + memset(&fs, 0, sizeof(fs)); |
---|
| 1888 | + |
---|
| 1889 | + input.fs = &cmd->fs; |
---|
| 1890 | + flow = ethtool_rx_flow_rule_create(&input); |
---|
| 1891 | + if (IS_ERR(flow)) { |
---|
| 1892 | + ret = PTR_ERR(flow); |
---|
| 1893 | + goto exit; |
---|
| 1894 | + } |
---|
| 1895 | + |
---|
| 1896 | + fs.hitcnts = 1; |
---|
| 1897 | + |
---|
| 1898 | + ret = cxgb4_flow_rule_replace(netdev, flow->rule, cmd->fs.location, |
---|
| 1899 | + NULL, &fs, &tid); |
---|
| 1900 | + if (ret) |
---|
| 1901 | + goto free; |
---|
| 1902 | + |
---|
| 1903 | + filter_info = &adapter->ethtool_filters->port[pi->port_id]; |
---|
| 1904 | + |
---|
| 1905 | + if (fs.prio) |
---|
| 1906 | + tid += adapter->tids.hpftid_base; |
---|
| 1907 | + else if (!fs.hash) |
---|
| 1908 | + tid += (adapter->tids.ftid_base - adapter->tids.nhpftids); |
---|
| 1909 | + |
---|
| 1910 | + filter_info->loc_array[cmd->fs.location] = tid; |
---|
| 1911 | + set_bit(cmd->fs.location, filter_info->bmap); |
---|
| 1912 | + filter_info->in_use++; |
---|
| 1913 | + |
---|
| 1914 | +free: |
---|
| 1915 | + ethtool_rx_flow_rule_destroy(flow); |
---|
| 1916 | +exit: |
---|
| 1917 | + return ret; |
---|
| 1918 | +} |
---|
| 1919 | + |
---|
| 1920 | +static int set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd) |
---|
| 1921 | +{ |
---|
| 1922 | + int ret = -EOPNOTSUPP; |
---|
| 1923 | + |
---|
| 1924 | + switch (cmd->cmd) { |
---|
| 1925 | + case ETHTOOL_SRXCLSRLINS: |
---|
| 1926 | + ret = cxgb4_ntuple_set_filter(dev, cmd); |
---|
| 1927 | + break; |
---|
| 1928 | + case ETHTOOL_SRXCLSRLDEL: |
---|
| 1929 | + ret = cxgb4_ntuple_del_filter(dev, cmd); |
---|
| 1930 | + break; |
---|
| 1931 | + default: |
---|
| 1932 | + break; |
---|
| 1933 | + } |
---|
| 1934 | + |
---|
| 1935 | + return ret; |
---|
1229 | 1936 | } |
---|
1230 | 1937 | |
---|
1231 | 1938 | static int set_dump(struct net_device *dev, struct ethtool_dump *eth_dump) |
---|
.. | .. |
---|
1406 | 2113 | return 0; |
---|
1407 | 2114 | } |
---|
1408 | 2115 | |
---|
| 2116 | +static void cxgb4_lb_test(struct net_device *netdev, u64 *lb_status) |
---|
| 2117 | +{ |
---|
| 2118 | + int dev_state = netif_running(netdev); |
---|
| 2119 | + |
---|
| 2120 | + if (dev_state) { |
---|
| 2121 | + netif_tx_stop_all_queues(netdev); |
---|
| 2122 | + netif_carrier_off(netdev); |
---|
| 2123 | + } |
---|
| 2124 | + |
---|
| 2125 | + *lb_status = cxgb4_selftest_lb_pkt(netdev); |
---|
| 2126 | + |
---|
| 2127 | + if (dev_state) { |
---|
| 2128 | + netif_tx_start_all_queues(netdev); |
---|
| 2129 | + netif_carrier_on(netdev); |
---|
| 2130 | + } |
---|
| 2131 | +} |
---|
| 2132 | + |
---|
| 2133 | +static void cxgb4_self_test(struct net_device *netdev, |
---|
| 2134 | + struct ethtool_test *eth_test, u64 *data) |
---|
| 2135 | +{ |
---|
| 2136 | + struct port_info *pi = netdev_priv(netdev); |
---|
| 2137 | + struct adapter *adap = pi->adapter; |
---|
| 2138 | + |
---|
| 2139 | + memset(data, 0, sizeof(u64) * CXGB4_ETHTOOL_MAX_TEST); |
---|
| 2140 | + |
---|
| 2141 | + if (!(adap->flags & CXGB4_FULL_INIT_DONE) || |
---|
| 2142 | + !(adap->flags & CXGB4_FW_OK)) { |
---|
| 2143 | + eth_test->flags |= ETH_TEST_FL_FAILED; |
---|
| 2144 | + return; |
---|
| 2145 | + } |
---|
| 2146 | + |
---|
| 2147 | + if (eth_test->flags & ETH_TEST_FL_OFFLINE) |
---|
| 2148 | + cxgb4_lb_test(netdev, &data[CXGB4_ETHTOOL_LB_TEST]); |
---|
| 2149 | + |
---|
| 2150 | + if (data[CXGB4_ETHTOOL_LB_TEST]) |
---|
| 2151 | + eth_test->flags |= ETH_TEST_FL_FAILED; |
---|
| 2152 | +} |
---|
| 2153 | + |
---|
1409 | 2154 | static const struct ethtool_ops cxgb_ethtool_ops = { |
---|
| 2155 | + .supported_coalesce_params = ETHTOOL_COALESCE_USECS | |
---|
| 2156 | + ETHTOOL_COALESCE_RX_MAX_FRAMES | |
---|
| 2157 | + ETHTOOL_COALESCE_TX_USECS_IRQ | |
---|
| 2158 | + ETHTOOL_COALESCE_USE_ADAPTIVE_RX, |
---|
1410 | 2159 | .get_link_ksettings = get_link_ksettings, |
---|
1411 | 2160 | .set_link_ksettings = set_link_ksettings, |
---|
1412 | 2161 | .get_fecparam = get_fecparam, |
---|
.. | .. |
---|
1432 | 2181 | .get_regs_len = get_regs_len, |
---|
1433 | 2182 | .get_regs = get_regs, |
---|
1434 | 2183 | .get_rxnfc = get_rxnfc, |
---|
| 2184 | + .set_rxnfc = set_rxnfc, |
---|
1435 | 2185 | .get_rxfh_indir_size = get_rss_table_size, |
---|
1436 | 2186 | .get_rxfh = get_rss_table, |
---|
1437 | 2187 | .set_rxfh = set_rss_table, |
---|
| 2188 | + .self_test = cxgb4_self_test, |
---|
1438 | 2189 | .flash_device = set_flash, |
---|
1439 | 2190 | .get_ts_info = get_ts_info, |
---|
1440 | 2191 | .set_dump = set_dump, |
---|
.. | .. |
---|
1446 | 2197 | .set_priv_flags = cxgb4_set_priv_flags, |
---|
1447 | 2198 | }; |
---|
1448 | 2199 | |
---|
| 2200 | +void cxgb4_cleanup_ethtool_filters(struct adapter *adap) |
---|
| 2201 | +{ |
---|
| 2202 | + struct cxgb4_ethtool_filter_info *eth_filter_info; |
---|
| 2203 | + u8 i; |
---|
| 2204 | + |
---|
| 2205 | + if (!adap->ethtool_filters) |
---|
| 2206 | + return; |
---|
| 2207 | + |
---|
| 2208 | + eth_filter_info = adap->ethtool_filters->port; |
---|
| 2209 | + |
---|
| 2210 | + if (eth_filter_info) { |
---|
| 2211 | + for (i = 0; i < adap->params.nports; i++) { |
---|
| 2212 | + kvfree(eth_filter_info[i].loc_array); |
---|
| 2213 | + kfree(eth_filter_info[i].bmap); |
---|
| 2214 | + } |
---|
| 2215 | + kfree(eth_filter_info); |
---|
| 2216 | + } |
---|
| 2217 | + |
---|
| 2218 | + kfree(adap->ethtool_filters); |
---|
| 2219 | +} |
---|
| 2220 | + |
---|
| 2221 | +int cxgb4_init_ethtool_filters(struct adapter *adap) |
---|
| 2222 | +{ |
---|
| 2223 | + struct cxgb4_ethtool_filter_info *eth_filter_info; |
---|
| 2224 | + struct cxgb4_ethtool_filter *eth_filter; |
---|
| 2225 | + struct tid_info *tids = &adap->tids; |
---|
| 2226 | + u32 nentries, i; |
---|
| 2227 | + int ret; |
---|
| 2228 | + |
---|
| 2229 | + eth_filter = kzalloc(sizeof(*eth_filter), GFP_KERNEL); |
---|
| 2230 | + if (!eth_filter) |
---|
| 2231 | + return -ENOMEM; |
---|
| 2232 | + |
---|
| 2233 | + eth_filter_info = kcalloc(adap->params.nports, |
---|
| 2234 | + sizeof(*eth_filter_info), |
---|
| 2235 | + GFP_KERNEL); |
---|
| 2236 | + if (!eth_filter_info) { |
---|
| 2237 | + ret = -ENOMEM; |
---|
| 2238 | + goto free_eth_filter; |
---|
| 2239 | + } |
---|
| 2240 | + |
---|
| 2241 | + eth_filter->port = eth_filter_info; |
---|
| 2242 | + |
---|
| 2243 | + nentries = tids->nhpftids + tids->nftids; |
---|
| 2244 | + if (is_hashfilter(adap)) |
---|
| 2245 | + nentries += tids->nhash + |
---|
| 2246 | + (adap->tids.stid_base - adap->tids.tid_base); |
---|
| 2247 | + eth_filter->nentries = nentries; |
---|
| 2248 | + |
---|
| 2249 | + for (i = 0; i < adap->params.nports; i++) { |
---|
| 2250 | + eth_filter->port[i].loc_array = kvzalloc(nentries, GFP_KERNEL); |
---|
| 2251 | + if (!eth_filter->port[i].loc_array) { |
---|
| 2252 | + ret = -ENOMEM; |
---|
| 2253 | + goto free_eth_finfo; |
---|
| 2254 | + } |
---|
| 2255 | + |
---|
| 2256 | + eth_filter->port[i].bmap = kcalloc(BITS_TO_LONGS(nentries), |
---|
| 2257 | + sizeof(unsigned long), |
---|
| 2258 | + GFP_KERNEL); |
---|
| 2259 | + if (!eth_filter->port[i].bmap) { |
---|
| 2260 | + ret = -ENOMEM; |
---|
| 2261 | + goto free_eth_finfo; |
---|
| 2262 | + } |
---|
| 2263 | + } |
---|
| 2264 | + |
---|
| 2265 | + adap->ethtool_filters = eth_filter; |
---|
| 2266 | + return 0; |
---|
| 2267 | + |
---|
| 2268 | +free_eth_finfo: |
---|
| 2269 | + while (i-- > 0) { |
---|
| 2270 | + kfree(eth_filter->port[i].bmap); |
---|
| 2271 | + kvfree(eth_filter->port[i].loc_array); |
---|
| 2272 | + } |
---|
| 2273 | + kfree(eth_filter_info); |
---|
| 2274 | + |
---|
| 2275 | +free_eth_filter: |
---|
| 2276 | + kfree(eth_filter); |
---|
| 2277 | + |
---|
| 2278 | + return ret; |
---|
| 2279 | +} |
---|
| 2280 | + |
---|
1449 | 2281 | void cxgb4_set_ethtool_ops(struct net_device *netdev) |
---|
1450 | 2282 | { |
---|
1451 | 2283 | netdev->ethtool_ops = &cxgb_ethtool_ops; |
---|