| .. | .. |
|---|
| 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; |
|---|