sfxge: add 7xxx NICs family support

Support 7xxx adapters including firmware-assisted TSO and VLAN tagging:

  - Solarflare Flareon Ultra 7000 series 10/40G adapters:
    - Solarflare SFN7042Q QSFP+ Server Adapter
    - Solarflare SFN7142Q QSFP+ Server Adapter

  - Solarflare Flareon Ultra 7000 series 10G adapters:
    - Solarflare SFN7022F SFP+ Server Adapter
    - Solarflare SFN7122F SFP+ Server Adapter
    - Solarflare SFN7322F Precision Time Synchronization Server Adapter

  - Solarflare Flareon 7000 series 10G adapters:
    - Solarflare SFN7002F SFP+ Server Adapter

Support utilities to configure adapters and update firmware.

The work is done by Solarflare developers
(Andy Moreton, Andrew Lee and many others),
Artem V. Andreev <Artem.Andreev at oktetlabs.ru> and me.

Sponsored by:   Solarflare Communications, Inc.
MFC after:      2 weeks
Causually read by: gnn
Differential Revision: https://reviews.freebsd.org/D2618
This commit is contained in:
Andrew Rybchenko 2015-05-25 08:34:55 +00:00
parent d0f6fcd886
commit 3c838a9f51
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=283514
73 changed files with 32828 additions and 6519 deletions

View File

@ -1,26 +1,30 @@
.\" Copyright (c) 2011 Solarflare Communications, Inc.
.\" Copyright (c) 2011-2015 Solarflare Communications Inc.
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\" modification, are permitted provided that the following conditions are met:
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\" 1. Redistributions of source code must retain the above copyright notice,
.\" this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright notice,
.\" this list of conditions and the following disclaimer in the documentation
.\" and/or other materials provided with the distribution.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
.\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
.\" THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
.\" CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
.\" EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
.\" PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
.\" OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
.\" WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
.\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
.\" EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
.\" The views and conclusions contained in the software and documentation are
.\" those of the authors and should not be interpreted as representing official
.\" policies, either expressed or implied, of the FreeBSD Project.
.\"
.\" $FreeBSD$
.\"
@ -116,6 +120,9 @@ If a packet is dropped, the
.Va tx_put_overflow
counter is incremented and the local sender receives ENOBUFS.
The value must be greater than or equal to 0.
.It Va hw.sfxge.tso_fw_assisted
Enable/disable usage of FW-assisted TSO if supported by NIC firmware.
Enabled by default.
.It Va hw.sfxge.N.max_rss_channels
The maximum number of allocated RSS channels for the Nth adapter.
If set to 0 or unset, the number of channels is determined by the number

View File

@ -2156,37 +2156,6 @@ dev/sdhci/sdhci.c optional sdhci
dev/sdhci/sdhci_if.m optional sdhci
dev/sdhci/sdhci_pci.c optional sdhci pci
dev/sf/if_sf.c optional sf pci
dev/sfxge/common/efx_bootcfg.c optional sfxge pci
dev/sfxge/common/efx_ev.c optional sfxge pci
dev/sfxge/common/efx_filter.c optional sfxge pci
dev/sfxge/common/efx_intr.c optional sfxge pci
dev/sfxge/common/efx_mac.c optional sfxge pci
dev/sfxge/common/efx_mcdi.c optional sfxge pci
dev/sfxge/common/efx_mon.c optional sfxge pci
dev/sfxge/common/efx_nic.c optional sfxge pci
dev/sfxge/common/efx_nvram.c optional sfxge pci
dev/sfxge/common/efx_phy.c optional sfxge pci
dev/sfxge/common/efx_port.c optional sfxge pci
dev/sfxge/common/efx_rx.c optional sfxge pci
dev/sfxge/common/efx_sram.c optional sfxge pci
dev/sfxge/common/efx_tx.c optional sfxge pci
dev/sfxge/common/efx_vpd.c optional sfxge pci
dev/sfxge/common/efx_wol.c optional sfxge pci
dev/sfxge/common/siena_mac.c optional sfxge pci
dev/sfxge/common/siena_mon.c optional sfxge pci
dev/sfxge/common/siena_nic.c optional sfxge pci
dev/sfxge/common/siena_nvram.c optional sfxge pci
dev/sfxge/common/siena_phy.c optional sfxge pci
dev/sfxge/common/siena_sram.c optional sfxge pci
dev/sfxge/common/siena_vpd.c optional sfxge pci
dev/sfxge/sfxge.c optional sfxge pci
dev/sfxge/sfxge_dma.c optional sfxge pci
dev/sfxge/sfxge_ev.c optional sfxge pci
dev/sfxge/sfxge_intr.c optional sfxge pci
dev/sfxge/sfxge_mcdi.c optional sfxge pci
dev/sfxge/sfxge_port.c optional sfxge pci
dev/sfxge/sfxge_rx.c optional sfxge pci
dev/sfxge/sfxge_tx.c optional sfxge pci
dev/sge/if_sge.c optional sge pci
dev/si/si.c optional si
dev/si/si2_z280.c optional si

View File

@ -304,37 +304,52 @@ dev/qlxgbe/ql_isr.c optional qlxgbe pci
dev/qlxgbe/ql_misc.c optional qlxgbe pci
dev/qlxgbe/ql_os.c optional qlxgbe pci
dev/qlxgbe/ql_reset.c optional qlxgbe pci
dev/sfxge/common/efx_bootcfg.c optional sfxge inet pci
dev/sfxge/common/efx_ev.c optional sfxge inet pci
dev/sfxge/common/efx_filter.c optional sfxge inet pci
dev/sfxge/common/efx_intr.c optional sfxge inet pci
dev/sfxge/common/efx_mac.c optional sfxge inet pci
dev/sfxge/common/efx_mcdi.c optional sfxge inet pci
dev/sfxge/common/efx_mon.c optional sfxge inet pci
dev/sfxge/common/efx_nic.c optional sfxge inet pci
dev/sfxge/common/efx_nvram.c optional sfxge inet pci
dev/sfxge/common/efx_phy.c optional sfxge inet pci
dev/sfxge/common/efx_port.c optional sfxge inet pci
dev/sfxge/common/efx_rx.c optional sfxge inet pci
dev/sfxge/common/efx_sram.c optional sfxge inet pci
dev/sfxge/common/efx_tx.c optional sfxge inet pci
dev/sfxge/common/efx_vpd.c optional sfxge inet pci
dev/sfxge/common/efx_wol.c optional sfxge inet pci
dev/sfxge/common/siena_mac.c optional sfxge inet pci
dev/sfxge/common/siena_mon.c optional sfxge inet pci
dev/sfxge/common/siena_nic.c optional sfxge inet pci
dev/sfxge/common/siena_nvram.c optional sfxge inet pci
dev/sfxge/common/siena_phy.c optional sfxge inet pci
dev/sfxge/common/siena_sram.c optional sfxge inet pci
dev/sfxge/common/siena_vpd.c optional sfxge inet pci
dev/sfxge/sfxge.c optional sfxge inet pci
dev/sfxge/sfxge_dma.c optional sfxge inet pci
dev/sfxge/sfxge_ev.c optional sfxge inet pci
dev/sfxge/sfxge_intr.c optional sfxge inet pci
dev/sfxge/sfxge_mcdi.c optional sfxge inet pci
dev/sfxge/sfxge_port.c optional sfxge inet pci
dev/sfxge/sfxge_rx.c optional sfxge inet pci
dev/sfxge/sfxge_tx.c optional sfxge inet pci
dev/sfxge/common/efx_bootcfg.c optional sfxge pci
dev/sfxge/common/efx_crc32.c optional sfxge pci
dev/sfxge/common/efx_ev.c optional sfxge pci
dev/sfxge/common/efx_filter.c optional sfxge pci
dev/sfxge/common/efx_hash.c optional sfxge pci
dev/sfxge/common/efx_intr.c optional sfxge pci
dev/sfxge/common/efx_mac.c optional sfxge pci
dev/sfxge/common/efx_mcdi.c optional sfxge pci
dev/sfxge/common/efx_mon.c optional sfxge pci
dev/sfxge/common/efx_nic.c optional sfxge pci
dev/sfxge/common/efx_nvram.c optional sfxge pci
dev/sfxge/common/efx_phy.c optional sfxge pci
dev/sfxge/common/efx_port.c optional sfxge pci
dev/sfxge/common/efx_rx.c optional sfxge pci
dev/sfxge/common/efx_sram.c optional sfxge pci
dev/sfxge/common/efx_tx.c optional sfxge pci
dev/sfxge/common/efx_vpd.c optional sfxge pci
dev/sfxge/common/efx_wol.c optional sfxge pci
dev/sfxge/common/hunt_ev.c optional sfxge pci
dev/sfxge/common/hunt_filter.c optional sfxge pci
dev/sfxge/common/hunt_intr.c optional sfxge pci
dev/sfxge/common/hunt_mac.c optional sfxge pci
dev/sfxge/common/hunt_mcdi.c optional sfxge pci
dev/sfxge/common/hunt_nic.c optional sfxge pci
dev/sfxge/common/hunt_nvram.c optional sfxge pci
dev/sfxge/common/hunt_phy.c optional sfxge pci
dev/sfxge/common/hunt_rx.c optional sfxge pci
dev/sfxge/common/hunt_sram.c optional sfxge pci
dev/sfxge/common/hunt_tx.c optional sfxge pci
dev/sfxge/common/hunt_vpd.c optional sfxge pci
dev/sfxge/common/siena_mac.c optional sfxge pci
dev/sfxge/common/siena_mcdi.c optional sfxge pci
dev/sfxge/common/siena_nic.c optional sfxge pci
dev/sfxge/common/siena_nvram.c optional sfxge pci
dev/sfxge/common/siena_phy.c optional sfxge pci
dev/sfxge/common/siena_sram.c optional sfxge pci
dev/sfxge/common/siena_vpd.c optional sfxge pci
dev/sfxge/sfxge.c optional sfxge pci
dev/sfxge/sfxge_dma.c optional sfxge pci
dev/sfxge/sfxge_ev.c optional sfxge pci
dev/sfxge/sfxge_intr.c optional sfxge pci
dev/sfxge/sfxge_mcdi.c optional sfxge pci
dev/sfxge/sfxge_nvram.c optional sfxge pci
dev/sfxge/sfxge_port.c optional sfxge pci
dev/sfxge/sfxge_rx.c optional sfxge pci
dev/sfxge/sfxge_tx.c optional sfxge pci
dev/sio/sio.c optional sio
dev/sio/sio_isa.c optional sio isa
dev/sio/sio_pccard.c optional sio pccard

View File

@ -0,0 +1,691 @@
/*-
* Copyright (c) 2012-2015 Solarflare Communications Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the FreeBSD Project.
*
* $FreeBSD$
*/
/* These structures define the layouts for the TLV items stored in static and
* dynamic configuration partitions in NVRAM for EF10 (Huntington etc.).
*
* They contain the same sort of information that was kept in the
* siena_mc_static_config_hdr_t and siena_mc_dynamic_config_hdr_t structures
* (defined in <ci/mgmt/mc_flash_layout.h> and <ci/mgmt/mc_dynamic_cfg.h>) for
* Siena.
*
* These are used directly by the MC and should also be usable directly on host
* systems which are little-endian and do not do strange things with structure
* padding. (Big-endian host systems will require some byte-swapping.)
*
* -----
*
* Please refer to SF-108797-SW for a general overview of the TLV partition
* format.
*
* -----
*
* The current tag IDs have a general structure: with the exception of the
* special values defined in the document, they are of the form 0xLTTTNNNN,
* where:
*
* - L is a location, indicating where this tag is expected to be found:
* 0 for static configuration, or 1 for dynamic configuration. Other
* values are reserved.
*
* - TTT is a type, which is just a unique value. The same type value
* might appear in both locations, indicating a relationship between
* the items (e.g. static and dynamic VPD below).
*
* - NNNN is an index of some form. Some item types are per-port, some
* are per-PF, some are per-partition-type.
*
* -----
*
* As with the previous Siena structures, each structure here is laid out
* carefully: values are aligned to their natural boundary, with explicit
* padding fields added where necessary. (No, technically this does not
* absolutely guarantee portability. But, in practice, compilers are generally
* sensible enough not to introduce completely pointless padding, and it works
* well enough.)
*/
#ifndef CI_MGMT_TLV_LAYOUT_H
#define CI_MGMT_TLV_LAYOUT_H
/* ----------------------------------------------------------------------------
* General structure (defined by SF-108797-SW)
* ----------------------------------------------------------------------------
*/
/* The "end" tag.
*
* (Note that this is *not* followed by length or value fields: anything after
* the tag itself is irrelevant.)
*/
#define TLV_TAG_END (0xEEEEEEEE)
/* Other special reserved tag values.
*/
#define TLV_TAG_SKIP (0x00000000)
#define TLV_TAG_INVALID (0xFFFFFFFF)
/* TLV partition header.
*
* In a TLV partition, this must be the first item in the sequence, at offset
* 0.
*/
#define TLV_TAG_PARTITION_HEADER (0xEF10DA7A)
struct tlv_partition_header {
uint32_t tag;
uint32_t length;
uint16_t type_id;
uint16_t reserved;
uint32_t generation;
uint32_t total_length;
};
/* TLV partition trailer.
*
* In a TLV partition, this must be the last item in the sequence, immediately
* preceding the TLV_TAG_END word.
*/
#define TLV_TAG_PARTITION_TRAILER (0xEF101A57)
struct tlv_partition_trailer {
uint32_t tag;
uint32_t length;
uint32_t generation;
uint32_t checksum;
};
/* Appendable TLV partition header.
*
* In an appendable TLV partition, this must be the first item in the sequence,
* at offset 0. (Note that, unlike the configuration partitions, there is no
* trailer before the TLV_TAG_END word.)
*/
#define TLV_TAG_APPENDABLE_PARTITION_HEADER (0xEF10ADA7)
struct tlv_appendable_partition_header {
uint32_t tag;
uint32_t length;
uint16_t type_id;
uint16_t reserved;
};
/* ----------------------------------------------------------------------------
* Configuration items
* ----------------------------------------------------------------------------
*/
/* NIC global capabilities.
*/
#define TLV_TAG_GLOBAL_CAPABILITIES (0x00010000)
struct tlv_global_capabilities {
uint32_t tag;
uint32_t length;
uint32_t flags;
};
/* Siena-style per-port MAC address allocation.
*
* There are <count> addresses, starting at <base_address> and incrementing
* by adding <stride> to the low-order byte(s).
*
* (See also TLV_TAG_GLOBAL_MAC for an alternative, specifying a global pool
* of contiguous MAC addresses for the firmware to allocate as it sees fit.)
*/
#define TLV_TAG_PORT_MAC(port) (0x00020000 + (port))
struct tlv_port_mac {
uint32_t tag;
uint32_t length;
uint8_t base_address[6];
uint16_t reserved;
uint16_t count;
uint16_t stride;
};
/* Static VPD.
*
* This is the portion of VPD which is set at manufacturing time and not
* expected to change. It is formatted as a standard PCI VPD block.
*/
#define TLV_TAG_PF_STATIC_VPD(pf) (0x00030000 + (pf))
struct tlv_pf_static_vpd {
uint32_t tag;
uint32_t length;
uint8_t bytes[];
};
/* Dynamic VPD.
*
* This is the portion of VPD which may be changed (e.g. by firmware updates).
* It is formatted as a standard PCI VPD block.
*/
#define TLV_TAG_PF_DYNAMIC_VPD(pf) (0x10030000 + (pf))
struct tlv_pf_dynamic_vpd {
uint32_t tag;
uint32_t length;
uint8_t bytes[];
};
/* "DBI" PCI config space changes.
*
* This is a set of edits made to the default PCI config space values before
* the device is allowed to enumerate.
*/
#define TLV_TAG_PF_DBI(pf) (0x00040000 + (pf))
struct tlv_pf_dbi {
uint32_t tag;
uint32_t length;
struct {
uint16_t addr;
uint16_t byte_enables;
uint32_t value;
} items[];
};
/* Partition subtype codes.
*
* A subtype may optionally be stored for each type of partition present in
* the NVRAM. For example, this may be used to allow a generic firmware update
* utility to select a specific variant of firmware for a specific variant of
* board.
*
* The description[] field is an optional string which is returned in the
* MC_CMD_NVRAM_METADATA response if present.
*/
#define TLV_TAG_PARTITION_SUBTYPE(type) (0x00050000 + (type))
struct tlv_partition_subtype {
uint32_t tag;
uint32_t length;
uint32_t subtype;
uint8_t description[];
};
/* Partition version codes.
*
* A version may optionally be stored for each type of partition present in
* the NVRAM. This provides a standard way of tracking the currently stored
* version of each of the various component images.
*/
#define TLV_TAG_PARTITION_VERSION(type) (0x10060000 + (type))
struct tlv_partition_version {
uint32_t tag;
uint32_t length;
uint16_t version_w;
uint16_t version_x;
uint16_t version_y;
uint16_t version_z;
};
/* Global PCIe configuration */
#define TLV_TAG_GLOBAL_PCIE_CONFIG (0x10070000)
struct tlv_pcie_config {
uint32_t tag;
uint32_t length;
int16_t max_pf_number; /**< Largest PF RID (lower PFs may be hidden) */
uint16_t pf_aper; /**< BIU aperture for PF BAR2 */
uint16_t vf_aper; /**< BIU aperture for VF BAR0 */
uint16_t int_aper; /**< BIU aperture for PF BAR4 and VF BAR2 */
#define TLV_MAX_PF_DEFAULT (-1) /* Use FW default for largest PF RID */
#define TLV_APER_DEFAULT (0xFFFF) /* Use FW default for a given aperture */
};
/* Per-PF configuration. Note that not all these fields are necessarily useful
* as the apertures are constrained by the BIU settings (the one case we do
* use is to make BAR2 bigger than the BIU thinks to reserve space), but we can
* tidy things up later */
#define TLV_TAG_PF_PCIE_CONFIG(pf) (0x10080000 + (pf))
struct tlv_per_pf_pcie_config {
uint32_t tag;
uint32_t length;
uint8_t vfs_total;
uint8_t port_allocation;
uint16_t vectors_per_pf;
uint16_t vectors_per_vf;
uint8_t pf_bar0_aperture;
uint8_t pf_bar2_aperture;
uint8_t vf_bar0_aperture;
uint8_t vf_base;
uint16_t supp_pagesz;
uint16_t msix_vec_base;
};
/* Development ONLY. This is a single TLV tag for all the gubbins
* that can be set through the MC command-line other than the PCIe
* settings. This is a temporary measure. */
#define TLV_TAG_TMP_GUBBINS (0x10090000)
struct tlv_tmp_gubbins {
uint32_t tag;
uint32_t length;
/* Consumed by dpcpu.c */
uint64_t tx0_tags; /* Bitmap */
uint64_t tx1_tags; /* Bitmap */
uint64_t dl_tags; /* Bitmap */
uint32_t flags;
#define TLV_DPCPU_TX_STRIPE (1) /* TX striping is on */
#define TLV_DPCPU_BIU_TAGS (2) /* Use BIU tag manager */
#define TLV_DPCPU_TX0_TAGS (4) /* tx0_tags is valid */
#define TLV_DPCPU_TX1_TAGS (8) /* tx1_tags is valid */
#define TLV_DPCPU_DL_TAGS (16) /* dl_tags is valid */
/* Consumed by features.c */
uint32_t dut_features; /* All 1s -> leave alone */
int8_t with_rmon; /* 0 -> off, 1 -> on, -1 -> leave alone */
/* Consumed by clocks_hunt.c */
int8_t clk_mode; /* 0 -> off, 1 -> on, -1 -> leave alone */
/* Consumed by sram.c */
int8_t rx_dc_size; /* -1 -> leave alone */
int8_t tx_dc_size;
int16_t num_q_allocs;
};
/* Global port configuration
*
* This is now deprecated in favour of a platform-provided default
* and dynamic config override via tlv_global_port_options.
*/
#define TLV_TAG_GLOBAL_PORT_CONFIG (0x000a0000)
struct tlv_global_port_config {
uint32_t tag;
uint32_t length;
uint32_t ports_per_core;
uint32_t max_port_speed;
};
/* Firmware options.
*
* This is intended for user-configurable selection of optional firmware
* features and variants.
*
* Initially, this consists only of the satellite CPU firmware variant
* selection, but this tag could be extended in the future (using the
* tag length to determine whether additional fields are present).
*/
#define TLV_TAG_FIRMWARE_OPTIONS (0x100b0000)
struct tlv_firmware_options {
uint32_t tag;
uint32_t length;
uint32_t firmware_variant;
#define TLV_FIRMWARE_VARIANT_DRIVER_SELECTED (0xffffffff)
/* These are the values for overriding the driver's choice; the definitions
* are taken from MCDI so that they don't get out of step. Include
* <ci/mgmt/mc_driver_pcol.h> or the equivalent from your driver's tree if
* you need to use these constants.
*/
#define TLV_FIRMWARE_VARIANT_FULL_FEATURED MC_CMD_FW_FULL_FEATURED
#define TLV_FIRMWARE_VARIANT_LOW_LATENCY MC_CMD_FW_LOW_LATENCY
#define TLV_FIRMWARE_VARIANT_PACKED_STREAM MC_CMD_FW_PACKED_STREAM
#define TLV_FIRMWARE_VARIANT_HIGH_TX_RATE MC_CMD_FW_HIGH_TX_RATE
#define TLV_FIRMWARE_VARIANT_PACKED_STREAM_HASH_MODE_1 \
MC_CMD_FW_PACKED_STREAM_HASH_MODE_1
};
/* Voltage settings
*
* Intended for boards with A0 silicon where the core voltage may
* need tweaking. Most likely set once when the pass voltage is
* determined. */
#define TLV_TAG_0V9_SETTINGS (0x000c0000)
struct tlv_0v9_settings {
uint32_t tag;
uint32_t length;
uint16_t flags; /* Boards with high 0v9 settings may need active cooling */
#define TLV_TAG_0V9_REQUIRES_FAN (1)
uint16_t target_voltage; /* In millivolts */
/* Since the limits are meant to be centred to the target (and must at least
* contain it) they need setting as well. */
uint16_t warn_low; /* In millivolts */
uint16_t warn_high; /* In millivolts */
uint16_t panic_low; /* In millivolts */
uint16_t panic_high; /* In millivolts */
};
/* Clock configuration */
#define TLV_TAG_CLOCK_CONFIG (0x000d0000)
struct tlv_clock_config {
uint32_t tag;
uint32_t length;
uint16_t clk_sys; /* MHz */
uint16_t clk_dpcpu; /* MHz */
uint16_t clk_icore; /* MHz */
uint16_t clk_pcs; /* MHz */
};
#define TLV_TAG_CLOCK_CONFIG_MEDFORD (0x00100000)
struct tlv_clock_config_medford {
uint32_t tag;
uint32_t length;
uint16_t clk_sys; /* MHz */
uint16_t clk_mc; /* MHz */
uint16_t clk_rmon; /* MHz */
uint16_t clk_vswitch; /* MHz */
uint16_t clk_dpcpu; /* MHz */
uint16_t clk_pcs; /* MHz */
};
/* EF10-style global pool of MAC addresses.
*
* There are <count> addresses, starting at <base_address>, which are
* contiguous. Firmware is responsible for allocating addresses from this
* pool to ports / PFs as appropriate.
*/
#define TLV_TAG_GLOBAL_MAC (0x000e0000)
struct tlv_global_mac {
uint32_t tag;
uint32_t length;
uint8_t base_address[6];
uint16_t reserved1;
uint16_t count;
uint16_t reserved2;
};
#define TLV_TAG_ATB_0V9_TARGET (0x000f0000)
/* The target value for the 0v9 power rail measured on-chip at the
* analogue test bus */
struct tlv_0v9_atb_target {
uint32_t tag;
uint32_t length;
uint16_t millivolts;
uint16_t reserved;
};
/* Global PCIe configuration, second revision. This represents the visible PFs
* by a bitmap rather than having the number of the highest visible one. As such
* it can (for a 16-PF chip) represent a superset of what TLV_TAG_GLOBAL_PCIE_CONFIG
* can and it should be used in place of that tag in future (but compatibility with
* the old tag will be left in the firmware indefinitely). */
#define TLV_TAG_GLOBAL_PCIE_CONFIG_R2 (0x10100000)
struct tlv_pcie_config_r2 {
uint32_t tag;
uint32_t length;
uint16_t visible_pfs; /**< Bitmap of visible PFs */
uint16_t pf_aper; /**< BIU aperture for PF BAR2 */
uint16_t vf_aper; /**< BIU aperture for VF BAR0 */
uint16_t int_aper; /**< BIU aperture for PF BAR4 and VF BAR2 */
};
/* Dynamic port mode.
*
* Allows selecting alternate port configuration for platforms that support it
* (e.g. 1x40G vs 2x10G on Milano, 1x40G vs 4x10G on Medford). This affects the
* number of externally visible ports (and, hence, PF to port mapping), so must
* be done at boot time.
*
* This tag supercedes tlv_global_port_config.
*/
#define TLV_TAG_GLOBAL_PORT_MODE (0x10110000)
struct tlv_global_port_mode {
uint32_t tag;
uint32_t length;
uint32_t port_mode;
#define TLV_PORT_MODE_DEFAULT (0xffffffff) /* Default for given platform */
#define TLV_PORT_MODE_10G (0) /* 10G, single SFP/10G-KR */
#define TLV_PORT_MODE_40G (1) /* 40G, single QSFP/40G-KR */
#define TLV_PORT_MODE_10G_10G (2) /* 2x10G, dual SFP/10G-KR or single QSFP */
#define TLV_PORT_MODE_40G_40G (3) /* 40G + 40G, dual QSFP/40G-KR (Greenport, Medford) */
#define TLV_PORT_MODE_10G_10G_10G_10G (4) /* 2x10G + 2x10G, quad SFP/10G-KR or dual QSFP (Greenport, Medford) */
#define TLV_PORT_MODE_10G_10G_10G_10G_Q (5) /* 4x10G, single QSFP, cage 0 (Medford) */
#define TLV_PORT_MODE_40G_10G_10G (6) /* 1x40G + 2x10G, dual QSFP (Greenport, Medford) */
#define TLV_PORT_MODE_10G_10G_40G (7) /* 2x10G + 1x40G, dual QSFP (Greenport, Medford) */
#define TLV_PORT_MODE_10G_10G_10G_10G_Q2 (8) /* 4x10G, single QSFP, cage 1 (Medford) */
#define TLV_PORT_MODE_MAX TLV_PORT_MODE_10G_10G_10G_10G_Q2
};
/* Type of the v-switch created implicitly by the firmware */
#define TLV_TAG_VSWITCH_TYPE(port) (0x10120000 + (port))
struct tlv_vswitch_type {
uint32_t tag;
uint32_t length;
uint32_t vswitch_type;
#define TLV_VSWITCH_TYPE_DEFAULT (0xffffffff) /* Firmware default; equivalent to no TLV present for a given port */
#define TLV_VSWITCH_TYPE_NONE (0)
#define TLV_VSWITCH_TYPE_VLAN (1)
#define TLV_VSWITCH_TYPE_VEB (2)
#define TLV_VSWITCH_TYPE_VEPA (3)
#define TLV_VSWITCH_TYPE_MUX (4)
#define TLV_VSWITCH_TYPE_TEST (5)
};
/* A VLAN tag for the v-port created implicitly by the firmware */
#define TLV_TAG_VPORT_VLAN_TAG(pf) (0x10130000 + (pf))
struct tlv_vport_vlan_tag {
uint32_t tag;
uint32_t length;
uint32_t vlan_tag;
#define TLV_VPORT_NO_VLAN_TAG (0xFFFFFFFF) /* Default in the absence of TLV for a given PF */
};
/* Offset to be applied to the 0v9 setting, wherever it came from */
#define TLV_TAG_ATB_0V9_OFFSET (0x10140000)
struct tlv_0v9_atb_offset {
uint32_t tag;
uint32_t length;
int16_t offset_millivolts;
uint16_t reserved;
};
/* A privilege mask given on reset to all non-admin PCIe functions (that is other than first-PF-per-port).
* The meaning of particular bits is defined in mcdi_ef10.yml under MC_CMD_PRIVILEGE_MASK, see also bug 44583.
* TLV_TAG_PRIVILEGE_MASK_ADD specifies bits that should be added (ORed) to firmware default while
* TLV_TAG_PRIVILEGE_MASK_REM specifies bits that should be removed (ANDed) from firmware default:
* Initial_privilege_mask = (firmware_default_mask | privilege_mask_add) & ~privilege_mask_rem */
#define TLV_TAG_PRIVILEGE_MASK (0x10150000) /* legacy symbol - do not use */
struct tlv_privilege_mask { /* legacy structure - do not use */
uint32_t tag;
uint32_t length;
uint32_t privilege_mask;
};
#define TLV_TAG_PRIVILEGE_MASK_ADD (0x10150000)
struct tlv_privilege_mask_add {
uint32_t tag;
uint32_t length;
uint32_t privilege_mask_add;
};
#define TLV_TAG_PRIVILEGE_MASK_REM (0x10160000)
struct tlv_privilege_mask_rem {
uint32_t tag;
uint32_t length;
uint32_t privilege_mask_rem;
};
/* Additional privileges given to all PFs.
* This tag takes precedence over TLV_TAG_PRIVILEGE_MASK_REM. */
#define TLV_TAG_PRIVILEGE_MASK_ADD_ALL_PFS (0x10190000)
struct tlv_privilege_mask_add_all_pfs {
uint32_t tag;
uint32_t length;
uint32_t privilege_mask_add;
};
/* Additional privileges given to a selected PF.
* This tag takes precedence over TLV_TAG_PRIVILEGE_MASK_REM. */
#define TLV_TAG_PRIVILEGE_MASK_ADD_SINGLE_PF(pf) (0x101A0000 + (pf))
struct tlv_privilege_mask_add_single_pf {
uint32_t tag;
uint32_t length;
uint32_t privilege_mask_add;
};
/* Turning on/off the PFIOV mode.
* This tag only takes effect if TLV_TAG_VSWITCH_TYPE is missing or set to DEFAULT. */
#define TLV_TAG_PFIOV(port) (0x10170000 + (port))
struct tlv_pfiov {
uint32_t tag;
uint32_t length;
uint32_t pfiov;
#define TLV_PFIOV_OFF (0) /* Default */
#define TLV_PFIOV_ON (1)
};
/* Multicast filter chaining mode selection.
*
* When enabled, multicast packets are delivered to all recipients of all
* matching multicast filters, with the exception that IP multicast filters
* will steal traffic from MAC multicast filters on a per-function basis.
* (New behaviour.)
*
* When disabled, multicast packets will always be delivered only to the
* recipients of the highest priority matching multicast filter.
* (Legacy behaviour.)
*
* The DEFAULT mode (which is the same as the tag not being present at all)
* is equivalent to ENABLED in production builds, and DISABLED in eftest
* builds.
*
* This option is intended to provide run-time control over this feature
* while it is being stabilised and may be withdrawn at some point in the
* future; the new behaviour is intended to become the standard behaviour.
*/
#define TLV_TAG_MCAST_FILTER_CHAINING (0x10180000)
struct tlv_mcast_filter_chaining {
uint32_t tag;
uint32_t length;
uint32_t mode;
#define TLV_MCAST_FILTER_CHAINING_DEFAULT (0xffffffff)
#define TLV_MCAST_FILTER_CHAINING_DISABLED (0)
#define TLV_MCAST_FILTER_CHAINING_ENABLED (1)
};
/* Pacer rate limit per PF */
#define TLV_TAG_RATE_LIMIT(pf) (0x101b0000 + (pf))
struct tlv_rate_limit {
uint32_t tag;
uint32_t length;
uint32_t rate_mbps;
};
/* OCSD Enable/Disable
*
* This setting allows OCSD to be disabled. This is a requirement for HP
* servers to support PCI passthrough for virtualization.
*
* The DEFAULT mode (which is the same as the tag not being present) is
* equivalent to ENABLED.
*
* This option is not used by the MCFW, and is entirely handled by the various
* drivers that support OCSD, by reading the setting before they attempt
* to enable OCSD.
*
* bit0: OCSD Disabled/Enabled
*/
#define TLV_TAG_OCSD (0x101C0000)
struct tlv_ocsd {
uint32_t tag;
uint32_t length;
uint32_t mode;
#define TLV_OCSD_DISABLED 0
#define TLV_OCSD_ENABLED 1 /* Default */
};
#endif /* CI_MGMT_TLV_LAYOUT_H */

View File

@ -1,30 +1,34 @@
/*-
* Copyright (c) 2010-2011 Solarflare Communications, Inc.
* Copyright (c) 2010-2015 Solarflare Communications Inc.
* All rights reserved.
*
* This software was developed in part by Philip Paeps under contract for
* Solarflare Communications, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* modification, are permitted provided that the following conditions are met:
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the FreeBSD Project.
*
* $FreeBSD$
*/
@ -56,6 +60,7 @@ extern "C" {
#else
#define EFSYS_USE_UINT64 0
#endif
#define EFSYS_HAS_SSE2_M128 0
#if _BYTE_ORDER == _BIG_ENDIAN
#define EFSYS_IS_BIG_ENDIAN 1
#define EFSYS_IS_LITTLE_ENDIAN 0
@ -90,6 +95,10 @@ extern "C" {
#define P2ROUNDUP(x, align) (-(-(x) & -(align)))
#endif
#ifndef P2ALIGN
#define P2ALIGN(_x, _a) ((_x) & -(_a))
#endif
#ifndef IS2P
#define ISP2(x) (((x) & ((x) - 1)) == 0)
#endif
@ -176,7 +185,7 @@ prefetch_read_once(void *addr)
#endif
static __inline void
sfxge_map_mbuf_fast(bus_dma_tag_t tag, bus_dmamap_t map,
struct mbuf *m, bus_dma_segment_t *seg)
struct mbuf *m, bus_dma_segment_t *seg)
{
#if defined(__i386__) || defined(__amd64__)
seg->ds_addr = pmap_kextract(mtod(m, vm_offset_t));
@ -188,10 +197,6 @@ sfxge_map_mbuf_fast(bus_dma_tag_t tag, bus_dmamap_t map,
#endif
}
/* Modifiers used for DOS builds */
#define __cs
#define __far
/* Modifiers used for Windows builds */
#define __in
#define __in_opt
@ -231,6 +236,7 @@ sfxge_map_mbuf_fast(bus_dma_tag_t tag, bus_dmamap_t map,
#define EFSYS_OPT_FALCON 0
#define EFSYS_OPT_FALCON_NIC_CFG_OVERRIDE 0
#define EFSYS_OPT_SIENA 1
#define EFSYS_OPT_HUNTINGTON 1
#ifdef DEBUG
#define EFSYS_OPT_CHECK_REG 1
#else
@ -248,19 +254,19 @@ sfxge_map_mbuf_fast(bus_dma_tag_t tag, bus_dmamap_t map,
#define EFSYS_OPT_MON_NULL 0
#define EFSYS_OPT_MON_LM87 0
#define EFSYS_OPT_MON_MAX6647 0
#define EFSYS_OPT_MON_SIENA 0
#define EFSYS_OPT_MON_MCDI 0
#define EFSYS_OPT_MON_STATS 0
#define EFSYS_OPT_PHY_NULL 0
#define EFSYS_OPT_PHY_QT2022C2 0
#define EFSYS_OPT_PHY_SFX7101 0
#define EFSYS_OPT_PHY_TXC43128 0
#define EFSYS_OPT_PHY_PM8358 0
#define EFSYS_OPT_PHY_SFT9001 0
#define EFSYS_OPT_PHY_QT2025C 0
#define EFSYS_OPT_PHY_STATS 1
#define EFSYS_OPT_PHY_PROPS 0
#define EFSYS_OPT_PHY_BIST 1
#define EFSYS_OPT_PHY_BIST 0
#define EFSYS_OPT_BIST 1
#define EFSYS_OPT_PHY_LED_CONTROL 1
#define EFSYS_OPT_PHY_FLAGS 0
@ -276,7 +282,8 @@ sfxge_map_mbuf_fast(bus_dma_tag_t tag, bus_dmamap_t map,
#define EFSYS_OPT_WOL 1
#define EFSYS_OPT_RX_SCALE 1
#define EFSYS_OPT_QSTATS 1
#define EFSYS_OPT_FILTER 0
#define EFSYS_OPT_FILTER 1
#define EFSYS_OPT_MCAST_FILTER_LIST 1
#define EFSYS_OPT_RX_SCATTER 0
#define EFSYS_OPT_RX_HDR_SPLIT 0
@ -618,6 +625,9 @@ typedef struct efsys_mem_s {
#define EFSYS_MEM_ADDR(_esmp) \
((_esmp)->esm_addr)
#define EFSYS_MEM_IS_NULL(_esmp) \
((_esmp)->esm_base == NULL)
/* BAR */
#define SFXGE_LOCK_NAME_MAX 16
@ -880,6 +890,24 @@ typedef struct efsys_bar_s {
} while (B_FALSE)
#endif
/*
* Guarantees 64bit aligned 64bit writes to write combined BAR mapping
* (required by PIO hardware)
*/
#define EFSYS_BAR_WC_WRITEQ(_esbp, _offset, _eqp) \
do { \
_NOTE(CONSTANTCONDITION) \
KASSERT(IS_P2ALIGNED(_offset, sizeof (efx_qword_t)), \
("not power of 2 aligned")); \
\
(void) (_esbp); \
\
/* FIXME: Perform a 64-bit write */ \
KASSERT(0, ("not implemented")); \
\
_NOTE(CONSTANTCONDITION) \
} while (B_FALSE)
#if defined(SFXGE_USE_BUS_SPACE_8)
#define EFSYS_BAR_WRITEO(_esbp, _offset, _eop, _lock) \
do { \
@ -979,6 +1007,13 @@ typedef struct efsys_bar_s {
} while (B_FALSE)
#endif
/* Use the standard octo-word write for doorbell writes */
#define EFSYS_BAR_DOORBELL_WRITEO(_esbp, _offset, _eop) \
do { \
EFSYS_BAR_WRITEO((_esbp), (_offset), (_eop), B_FALSE); \
_NOTE(CONSTANTCONDITION) \
} while (B_FALSE)
/* SPIN */
#define EFSYS_SPIN(_us) \
@ -994,6 +1029,23 @@ typedef struct efsys_bar_s {
#define EFSYS_MEM_READ_BARRIER() rmb()
#define EFSYS_PIO_WRITE_BARRIER()
/* DMA SYNC */
#define EFSYS_DMA_SYNC_FOR_KERNEL(_esmp, _offset, _size) \
do { \
bus_dmamap_sync((_esmp)->esm_tag, \
(_esmp)->esm_map, \
BUS_DMASYNC_POSTREAD); \
_NOTE(CONSTANTCONDITION) \
} while (B_FALSE)
#define EFSYS_DMA_SYNC_FOR_DEVICE(_esmp, _offset, _size) \
do { \
bus_dmamap_sync((_esmp)->esm_tag, \
(_esmp)->esm_map, \
BUS_DMASYNC_PREWRITE); \
_NOTE(CONSTANTCONDITION) \
} while (B_FALSE)
/* TIMESTAMP */
typedef clock_t efsys_timestamp_t;
@ -1150,7 +1202,7 @@ extern void sfxge_err(efsys_identifier_t *, unsigned int,
#define EFSYS_ASSERT(_exp) do { \
if (!(_exp)) \
panic(#_exp); \
panic("%s", #_exp); \
} while (0)
#define EFSYS_ASSERT3(_x, _op, _y, _t) do { \
@ -1164,6 +1216,10 @@ extern void sfxge_err(efsys_identifier_t *, unsigned int,
#define EFSYS_ASSERT3S(_x, _op, _y) EFSYS_ASSERT3(_x, _op, _y, int64_t)
#define EFSYS_ASSERT3P(_x, _op, _y) EFSYS_ASSERT3(_x, _op, _y, uintptr_t)
/* ROTATE */
#define EFSYS_HAS_ROTL_DWORD 0
#ifdef __cplusplus
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,26 +1,31 @@
/*-
* Copyright 2009 Solarflare Communications Inc. All rights reserved.
* Copyright (c) 2009-2015 Solarflare Communications Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* modification, are permitted provided that the following conditions are met:
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the FreeBSD Project.
*/
#include <sys/cdefs.h>
@ -64,7 +69,7 @@ efx_bootcfg_verify(
__in efx_nic_t *enp,
__in_bcount(size) caddr_t data,
__in size_t size,
__out size_t *usedp)
__out_opt size_t *usedp)
{
size_t offset = 0;
size_t used = 0;

View File

@ -0,0 +1,388 @@
/*-
* Copyright (c) 2012-2015 Solarflare Communications Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the FreeBSD Project.
*
* $FreeBSD$
*/
#ifndef _SYS_EFX_CHECK_H
#define _SYS_EFX_CHECK_H
#include "efsys.h"
/*
* Check that the efsys.h header in client code has a valid combination of
* EFSYS_OPT_xxx options.
*
* NOTE: Keep checks for obsolete options here to ensure that they are removed
* from client code (and do not reappear in merges from other branches).
*/
/* Support NVRAM based boot config */
#if EFSYS_OPT_BOOTCFG
# if !EFSYS_OPT_NVRAM
# error "BOOTCFG requires NVRAM"
# endif
#endif /* EFSYS_OPT_BOOTCFG */
/* Verify chip implements accessed registers */
#if EFSYS_OPT_CHECK_REG
# if !(EFSYS_OPT_FALCON || EFSYS_OPT_SIENA || EFSYS_OPT_HUNTINGTON)
# error "CHECK_REG requires FALCON or SIENA or HUNTINGTON"
# endif
#endif /* EFSYS_OPT_CHECK_REG */
/* Decode fatal errors */
#if EFSYS_OPT_DECODE_INTR_FATAL
# if !(EFSYS_OPT_FALCON || EFSYS_OPT_SIENA)
# if EFSYS_OPT_HUNTINGTON
# error "INTR_FATAL not supported on HUNTINGTON"
# endif
# error "INTR_FATAL requires FALCON or SIENA"
# endif
#endif /* EFSYS_OPT_DECODE_INTR_FATAL */
/* Support diagnostic hardware tests */
#if EFSYS_OPT_DIAG
# if !(EFSYS_OPT_FALCON || EFSYS_OPT_SIENA || EFSYS_OPT_HUNTINGTON)
# error "DIAG requires FALCON or SIENA or HUNTINGTON"
# endif
#endif /* EFSYS_OPT_DIAG */
/* Support optimized EVQ data access */
#if EFSYS_OPT_EV_PREFETCH
# if !(EFSYS_OPT_FALCON || EFSYS_OPT_SIENA || EFSYS_OPT_HUNTINGTON)
# error "EV_PREFETCH requires FALCON or SIENA or HUNTINGTON"
# endif
#endif /* EFSYS_OPT_EV_PREFETCH */
/* Support overriding the NVRAM and VPD configuration */
#if EFSYS_OPT_FALCON_NIC_CFG_OVERRIDE
# if !EFSYS_OPT_FALCON
# error "FALCON_NIC_CFG_OVERRIDE requires FALCON"
# endif
#endif /* EFSYS_OPT_FALCON_NIC_CFG_OVERRIDE */
/* Support hardware packet filters */
#if EFSYS_OPT_FILTER
# if !(EFSYS_OPT_FALCON || EFSYS_OPT_SIENA || EFSYS_OPT_HUNTINGTON)
# error "FILTER requires FALCON or SIENA or HUNTINGTON"
# endif
#endif /* EFSYS_OPT_FILTER */
#if EFSYS_OPT_HUNTINGTON
# if !EFSYS_OPT_FILTER
# error "HUNTINGTON requires FILTER"
# endif
#endif /* EFSYS_OPT_HUNTINGTON */
/* Support hardware loopback modes */
#if EFSYS_OPT_LOOPBACK
# if !(EFSYS_OPT_FALCON || EFSYS_OPT_SIENA || EFSYS_OPT_HUNTINGTON)
# error "LOOPBACK requires FALCON or SIENA or HUNTINGTON"
# endif
#endif /* EFSYS_OPT_LOOPBACK */
/* Support Falcon GMAC */
#if EFSYS_OPT_MAC_FALCON_GMAC
# if !EFSYS_OPT_FALCON
# error "MAC_FALCON_GMAC requires FALCON"
# endif
#endif /* EFSYS_OPT_MAC_FALCON_GMAC */
/* Support Falcon XMAC */
#if EFSYS_OPT_MAC_FALCON_XMAC
# if !EFSYS_OPT_FALCON
# error "MAC_FALCON_XMAC requires FALCON"
# endif
#endif /* EFSYS_OPT_MAC_FALCON_XMAC */
/* Support MAC statistics */
#if EFSYS_OPT_MAC_STATS
# if !(EFSYS_OPT_FALCON || EFSYS_OPT_SIENA || EFSYS_OPT_HUNTINGTON)
# error "MAC_STATS requires FALCON or SIENA or HUNTINGTON"
# endif
#endif /* EFSYS_OPT_MAC_STATS */
/* Support management controller messages */
#if EFSYS_OPT_MCDI
# if !(EFSYS_OPT_SIENA || EFSYS_OPT_HUNTINGTON)
# if EFSYS_OPT_FALCON
# error "MCDI not supported on FALCON"
# endif
# error "MCDI requires SIENA or HUNTINGTON"
# endif
#endif /* EFSYS_OPT_MCDI */
#if EFSYS_OPT_SIENA && !EFSYS_OPT_MCDI
# error "SIENA requires MCDI"
#endif
#if EFSYS_OPT_HUNTINGTON && !EFSYS_OPT_MCDI
# error "HUNTINGTON requires MCDI"
#endif
/* Support LM87 monitor */
#if EFSYS_OPT_MON_LM87
# if !EFSYS_OPT_FALCON
# error "MON_LM87 requires FALCON"
# endif
#endif /* EFSYS_OPT_MON_LM87 */
/* Support MAX6647 monitor */
#if EFSYS_OPT_MON_MAX6647
# if !EFSYS_OPT_FALCON
# error "MON_MAX6647 requires FALCON"
# endif
#endif /* EFSYS_OPT_MON_MAX6647 */
/* Support null monitor */
#if EFSYS_OPT_MON_NULL
# if !EFSYS_OPT_FALCON
# error "MON_NULL requires FALCON"
# endif
#endif /* EFSYS_OPT_MON_NULL */
/* Support Siena monitor */
#ifdef EFSYS_OPT_MON_SIENA
# error "MON_SIENA is obsolete use MON_MCDI"
#endif /* EFSYS_OPT_MON_SIENA*/
/* Support Huntington monitor */
#ifdef EFSYS_OPT_MON_HUNTINGTON
# error "MON_HUNTINGTON is obsolete use MON_MCDI"
#endif /* EFSYS_OPT_MON_HUNTINGTON*/
/* Support monitor statistics (voltage/temperature) */
#if EFSYS_OPT_MON_STATS
# if !(EFSYS_OPT_FALCON || EFSYS_OPT_SIENA || EFSYS_OPT_HUNTINGTON)
# error "MON_STATS requires FALCON or SIENA or HUNTINGTON"
# endif
#endif /* EFSYS_OPT_MON_STATS */
/* Support Monitor via mcdi */
#if EFSYS_OPT_MON_MCDI
# if !(EFSYS_OPT_SIENA || EFSYS_OPT_HUNTINGTON)
# error "MON_MCDI requires SIENA or HUNTINGTON"
# endif
#endif /* EFSYS_OPT_MON_MCDI*/
/* Support printable names for statistics */
#if EFSYS_OPT_NAMES
# if !(EFSYS_OPT_LOOPBACK || EFSYS_OPT_MAC_STATS || EFSYS_OPT_MCDI || \
EFSYS_MON_STATS || EFSYS_OPT_PHY_PROPS || EFSYS_OPT_PHY_STATS || \
EFSYS_OPT_QSTATS)
# error "NAMES requires LOOPBACK or xxxSTATS or MCDI or PHY_PROPS"
# endif
#endif /* EFSYS_OPT_NAMES */
/* Support non volatile configuration */
#if EFSYS_OPT_NVRAM
# if !(EFSYS_OPT_FALCON || EFSYS_OPT_SIENA || EFSYS_OPT_HUNTINGTON)
# error "NVRAM requires FALCON or SIENA or HUNTINGTON"
# endif
#endif /* EFSYS_OPT_NVRAM */
/* Support Falcon bootrom */
#if EFSYS_OPT_NVRAM_FALCON_BOOTROM
# if !EFSYS_OPT_NVRAM
# error "NVRAM_FALCON_BOOTROM requires NVRAM"
# endif
# if !EFSYS_OPT_FALCON
# error "NVRAM_FALCON_BOOTROM requires FALCON"
# endif
#endif /* EFSYS_OPT_NVRAM_FALCON_BOOTROM */
/* Support NVRAM config for SFT9001 */
#if EFSYS_OPT_NVRAM_SFT9001
# if !EFSYS_OPT_NVRAM
# error "NVRAM_SFT9001 requires NVRAM"
# endif
# if !EFSYS_OPT_FALCON
# error "NVRAM_SFT9001 requires FALCON"
# endif
#endif /* EFSYS_OPT_NVRAM_SFT9001 */
/* Support NVRAM config for SFX7101 */
#if EFSYS_OPT_NVRAM_SFX7101
# if !EFSYS_OPT_NVRAM
# error "NVRAM_SFX7101 requires NVRAM"
# endif
# if !EFSYS_OPT_FALCON
# error "NVRAM_SFX7101 requires FALCON"
# endif
#endif /* EFSYS_OPT_NVRAM_SFX7101 */
/* Support PCIe interface tuning */
#if EFSYS_OPT_PCIE_TUNE
# if !(EFSYS_OPT_FALCON || EFSYS_OPT_SIENA)
# error "PCIE_TUNE requires FALCON or SIENA"
# endif
#endif /* EFSYS_OPT_PCIE_TUNE */
/* Support PHY BIST diagnostics */
#if EFSYS_OPT_PHY_BIST
# error "PHY_BIST is obsolete. It has been replaced by the BIST option."
#endif /* EFSYS_OPT_PHY_BIST */
/* Support PHY flags */
#if EFSYS_OPT_PHY_FLAGS
# if !(EFSYS_OPT_FALCON || EFSYS_OPT_SIENA)
# error "PHY_FLAGS requires FALCON or SIENA"
# endif
#endif /* EFSYS_OPT_PHY_FLAGS */
/* Support for PHY LED control */
#if EFSYS_OPT_PHY_LED_CONTROL
# if !(EFSYS_OPT_FALCON || EFSYS_OPT_SIENA)
# error "PHY_LED_CONTROL requires FALCON or SIENA"
# endif
#endif /* EFSYS_OPT_PHY_LED_CONTROL */
/* Support NULL PHY */
#if EFSYS_OPT_PHY_NULL
# if !EFSYS_OPT_FALCON
# error "PHY_NULL requires FALCON"
# endif
#endif /* EFSYS_OPT_PHY_NULL */
/* Obsolete option */
#ifdef EFSYS_OPT_PHY_PM8358
# error "EFSYS_OPT_PHY_PM8358 is obsolete and is not supported."
#endif
/* Support PHY properties */
#if EFSYS_OPT_PHY_PROPS
# if !(EFSYS_OPT_FALCON || EFSYS_OPT_SIENA)
# error "PHY_PROPS requires FALCON or SIENA"
# endif
#endif /* EFSYS_OPT_PHY_PROPS */
/* Support QT2022C2 PHY */
#if EFSYS_OPT_PHY_QT2022C2
# if !EFSYS_OPT_FALCON
# error "PHY_QT2022C2 requires FALCON"
# endif
#endif /* EFSYS_OPT_PHY_QT2022C2 */
/* Support QT2025C PHY (Wakefield NIC) */
#if EFSYS_OPT_PHY_QT2025C
# if !EFSYS_OPT_FALCON
# error "PHY_QT2025C requires FALCON"
# endif
#endif /* EFSYS_OPT_PHY_QT2025C */
/* Support SFT9001 PHY (Starbolt NIC) */
#if EFSYS_OPT_PHY_SFT9001
# if !EFSYS_OPT_FALCON
# error "PHY_SFT9001 requires FALCON"
# endif
#endif /* EFSYS_OPT_PHY_SFT9001 */
/* Support SFX7101 PHY (SFE4001 NIC) */
#if EFSYS_OPT_PHY_SFX7101
# if !EFSYS_OPT_FALCON
# error "PHY_SFX7101 requires FALCON"
# endif
#endif /* EFSYS_OPT_PHY_SFX7101 */
/* Support PHY statistics */
#if EFSYS_OPT_PHY_STATS
# if !(EFSYS_OPT_FALCON || EFSYS_OPT_SIENA)
# error "PHY_STATS requires FALCON or SIENA"
# endif
#endif /* EFSYS_OPT_PHY_STATS */
/* Support TXC43128 PHY (SFE4003 NIC) */
#if EFSYS_OPT_PHY_TXC43128
# if !EFSYS_OPT_FALCON
# error "PHY_TXC43128 requires FALCON"
# endif
#endif /* EFSYS_OPT_PHY_TXC43128 */
/* Support EVQ/RXQ/TXQ statistics */
#if EFSYS_OPT_QSTATS
# if !(EFSYS_OPT_FALCON || EFSYS_OPT_SIENA || EFSYS_OPT_HUNTINGTON)
# error "QSTATS requires FALCON or SIENA or HUNTINGTON"
# endif
#endif /* EFSYS_OPT_QSTATS */
/* Support receive header split */
#if EFSYS_OPT_RX_HDR_SPLIT
# if !(EFSYS_OPT_FALCON || EFSYS_OPT_SIENA || EFSYS_OPT_HUNTINGTON)
# error "RX_HDR_SPLIT requires FALCON or SIENA or HUNTINGTON"
# endif
#endif /* EFSYS_OPT_RX_HDR_SPLIT */
/* Support receive scaling (RSS) */
#if EFSYS_OPT_RX_SCALE
# if !(EFSYS_OPT_FALCON || EFSYS_OPT_SIENA || EFSYS_OPT_HUNTINGTON)
# error "RX_SCALE requires FALCON or SIENA or HUNTINGTON"
# endif
#endif /* EFSYS_OPT_RX_SCALE */
/* Support receive scatter DMA */
#if EFSYS_OPT_RX_SCATTER
# if !(EFSYS_OPT_FALCON || EFSYS_OPT_SIENA || EFSYS_OPT_HUNTINGTON)
# error "RX_SCATTER requires FALCON or SIENA or HUNTINGTON"
# endif
#endif /* EFSYS_OPT_RX_SCATTER */
/* Obsolete option */
#ifdef EFSYS_OPT_STAT_NAME
# error "EFSYS_OPT_STAT_NAME is obsolete (replaced by EFSYS_OPT_NAMES)."
#endif
/* Support PCI Vital Product Data (VPD) */
#if EFSYS_OPT_VPD
# if !(EFSYS_OPT_FALCON || EFSYS_OPT_SIENA || EFSYS_OPT_HUNTINGTON)
# error "VPD requires FALCON or SIENA or HUNTINGTON"
# endif
#endif /* EFSYS_OPT_VPD */
/* Support Wake on LAN */
#if EFSYS_OPT_WOL
# if !EFSYS_OPT_SIENA
# error "WOL requires SIENA"
# endif
#endif /* EFSYS_OPT_WOL */
/* Support calculating multicast pktfilter in common code */
#if EFSYS_OPT_MCAST_FILTER_LIST
# if !(EFSYS_OPT_FALCON || EFSYS_OPT_SIENA || EFSYS_OPT_HUNTINGTON)
# error "MCAST_FILTER_LIST requires FALCON or SIENA or HUNTINGTON"
# endif
#endif /* EFSYS_OPT_MCAST_FILTER_LIST */
/* Support BIST */
#if EFSYS_OPT_BIST
# if !(EFSYS_OPT_FALCON || EFSYS_OPT_SIENA || EFSYS_OPT_HUNTINGTON)
# error "BIST requires FALCON or SIENA or HUNTINGTON"
# endif
#endif /* EFSYS_OPT_BIST */
#endif /* _SYS_EFX_CHECK_H */

View File

@ -0,0 +1,127 @@
/*-
* Copyright (c) 2013-2015 Solarflare Communications Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the FreeBSD Project.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "efsys.h"
#include "efx.h"
#include "efx_types.h"
#include "efx_impl.h"
/*
* Precomputed table for computing IEEE 802.3 CRC32
* with polynomial 0x04c11db7 (bit-reversed 0xedb88320)
*/
static const uint32_t crc32_table[256] = {
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
};
/* Calculate the IEEE 802.3 CRC32 of a MAC addr */
__checkReturn uint32_t
efx_crc32_calculate(
__in uint32_t crc_init,
__in_ecount(length) uint8_t const *input,
__in int length)
{
int index;
uint32_t crc = crc_init;
for (index = 0; index < length; index++) {
uint32_t data = *(input++);
crc = (crc >> 8) ^ crc32_table[(crc ^ data) & 0xff];
}
return (crc);
}

View File

@ -1,26 +1,31 @@
/*-
* Copyright 2007-2009 Solarflare Communications Inc. All rights reserved.
* Copyright (c) 2007-2015 Solarflare Communications Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* modification, are permitted provided that the following conditions are met:
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the FreeBSD Project.
*/
#include <sys/cdefs.h>
@ -31,6 +36,7 @@ __FBSDID("$FreeBSD$");
#include "efx_types.h"
#include "efx_regs.h"
#include "efx_impl.h"
#include "mcdi_mon.h"
#if EFSYS_OPT_QSTATS
#define EFX_EV_QSTAT_INCR(_eep, _stat) \
@ -42,11 +48,118 @@ __FBSDID("$FreeBSD$");
#define EFX_EV_QSTAT_INCR(_eep, _stat)
#endif
#define EFX_EV_PRESENT(_qword) \
(EFX_QWORD_FIELD((_qword), EFX_DWORD_0) != 0xffffffff && \
EFX_QWORD_FIELD((_qword), EFX_DWORD_1) != 0xffffffff)
#if EFSYS_OPT_FALCON || EFSYS_OPT_SIENA
static __checkReturn int
falconsiena_ev_init(
__in efx_nic_t *enp);
static void
falconsiena_ev_fini(
__in efx_nic_t *enp);
static __checkReturn int
falconsiena_ev_qcreate(
__in efx_nic_t *enp,
__in unsigned int index,
__in efsys_mem_t *esmp,
__in size_t n,
__in uint32_t id,
__in efx_evq_t *eep);
static void
falconsiena_ev_qdestroy(
__in efx_evq_t *eep);
static __checkReturn int
falconsiena_ev_qprime(
__in efx_evq_t *eep,
__in unsigned int count);
static void
falconsiena_ev_qpoll(
__in efx_evq_t *eep,
__inout unsigned int *countp,
__in const efx_ev_callbacks_t *eecp,
__in_opt void *arg);
static void
falconsiena_ev_qpost(
__in efx_evq_t *eep,
__in uint16_t data);
static __checkReturn int
falconsiena_ev_qmoderate(
__in efx_evq_t *eep,
__in unsigned int us);
#if EFSYS_OPT_QSTATS
static void
falconsiena_ev_qstats_update(
__in efx_evq_t *eep,
__inout_ecount(EV_NQSTATS) efsys_stat_t *stat);
#endif
#endif /* EFSYS_OPT_FALCON || EFSYS_OPT_SIENA */
#if EFSYS_OPT_FALCON
static efx_ev_ops_t __efx_ev_falcon_ops = {
falconsiena_ev_init, /* eevo_init */
falconsiena_ev_fini, /* eevo_fini */
falconsiena_ev_qcreate, /* eevo_qcreate */
falconsiena_ev_qdestroy, /* eevo_qdestroy */
falconsiena_ev_qprime, /* eevo_qprime */
falconsiena_ev_qpost, /* eevo_qpost */
falconsiena_ev_qmoderate, /* eevo_qmoderate */
#if EFSYS_OPT_QSTATS
falconsiena_ev_qstats_update, /* eevo_qstats_update */
#endif
};
#endif /* EFSYS_OPT_FALCON */
#if EFSYS_OPT_SIENA
static efx_ev_ops_t __efx_ev_siena_ops = {
falconsiena_ev_init, /* eevo_init */
falconsiena_ev_fini, /* eevo_fini */
falconsiena_ev_qcreate, /* eevo_qcreate */
falconsiena_ev_qdestroy, /* eevo_qdestroy */
falconsiena_ev_qprime, /* eevo_qprime */
falconsiena_ev_qpost, /* eevo_qpost */
falconsiena_ev_qmoderate, /* eevo_qmoderate */
#if EFSYS_OPT_QSTATS
falconsiena_ev_qstats_update, /* eevo_qstats_update */
#endif
};
#endif /* EFSYS_OPT_SIENA */
#if EFSYS_OPT_HUNTINGTON
static efx_ev_ops_t __efx_ev_hunt_ops = {
hunt_ev_init, /* eevo_init */
hunt_ev_fini, /* eevo_fini */
hunt_ev_qcreate, /* eevo_qcreate */
hunt_ev_qdestroy, /* eevo_qdestroy */
hunt_ev_qprime, /* eevo_qprime */
hunt_ev_qpost, /* eevo_qpost */
hunt_ev_qmoderate, /* eevo_qmoderate */
#if EFSYS_OPT_QSTATS
hunt_ev_qstats_update, /* eevo_qstats_update */
#endif
};
#endif /* EFSYS_OPT_HUNTINGTON */
__checkReturn int
efx_ev_init(
__in efx_nic_t *enp)
{
efx_oword_t oword;
efx_ev_ops_t *eevop;
int rc;
EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
@ -57,8 +170,290 @@ efx_ev_init(
goto fail1;
}
switch (enp->en_family) {
#if EFSYS_OPT_FALCON
case EFX_FAMILY_FALCON:
eevop = (efx_ev_ops_t *)&__efx_ev_falcon_ops;
break;
#endif /* EFSYS_OPT_FALCON */
#if EFSYS_OPT_SIENA
case EFX_FAMILY_SIENA:
eevop = (efx_ev_ops_t *)&__efx_ev_siena_ops;
break;
#endif /* EFSYS_OPT_SIENA */
#if EFSYS_OPT_HUNTINGTON
case EFX_FAMILY_HUNTINGTON:
eevop = (efx_ev_ops_t *)&__efx_ev_hunt_ops;
break;
#endif /* EFSYS_OPT_HUNTINGTON */
default:
EFSYS_ASSERT(0);
rc = ENOTSUP;
goto fail1;
}
EFSYS_ASSERT3U(enp->en_ev_qcount, ==, 0);
if ((rc = eevop->eevo_init(enp)) != 0)
goto fail2;
enp->en_eevop = eevop;
enp->en_mod_flags |= EFX_MOD_EV;
return (0);
fail2:
EFSYS_PROBE(fail2);
fail1:
EFSYS_PROBE1(fail1, int, rc);
enp->en_eevop = NULL;
enp->en_mod_flags &= ~EFX_MOD_EV;
return (rc);
}
void
efx_ev_fini(
__in efx_nic_t *enp)
{
efx_ev_ops_t *eevop = enp->en_eevop;
EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_EV);
EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_RX));
EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_TX));
EFSYS_ASSERT3U(enp->en_ev_qcount, ==, 0);
eevop->eevo_fini(enp);
enp->en_eevop = NULL;
enp->en_mod_flags &= ~EFX_MOD_EV;
}
__checkReturn int
efx_ev_qcreate(
__in efx_nic_t *enp,
__in unsigned int index,
__in efsys_mem_t *esmp,
__in size_t n,
__in uint32_t id,
__deref_out efx_evq_t **eepp)
{
efx_ev_ops_t *eevop = enp->en_eevop;
efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
efx_evq_t *eep;
int rc;
EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_EV);
EFSYS_ASSERT3U(enp->en_ev_qcount + 1, <, encp->enc_evq_limit);
/* Allocate an EVQ object */
EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (efx_evq_t), eep);
if (eep == NULL) {
rc = ENOMEM;
goto fail1;
}
eep->ee_magic = EFX_EVQ_MAGIC;
eep->ee_enp = enp;
eep->ee_index = index;
eep->ee_mask = n - 1;
eep->ee_esmp = esmp;
if ((rc = eevop->eevo_qcreate(enp, index, esmp, n, id, eep)) != 0)
goto fail2;
enp->en_ev_qcount++;
*eepp = eep;
return (0);
fail2:
EFSYS_PROBE(fail2);
EFSYS_KMEM_FREE(enp->en_esip, sizeof (efx_evq_t), eep);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
void
efx_ev_qdestroy(
__in efx_evq_t *eep)
{
efx_nic_t *enp = eep->ee_enp;
efx_ev_ops_t *eevop = enp->en_eevop;
EFSYS_ASSERT3U(eep->ee_magic, ==, EFX_EVQ_MAGIC);
EFSYS_ASSERT(enp->en_ev_qcount != 0);
--enp->en_ev_qcount;
eevop->eevo_qdestroy(eep);
/* Free the EVQ object */
EFSYS_KMEM_FREE(enp->en_esip, sizeof (efx_evq_t), eep);
}
__checkReturn int
efx_ev_qprime(
__in efx_evq_t *eep,
__in unsigned int count)
{
efx_nic_t *enp = eep->ee_enp;
efx_ev_ops_t *eevop = enp->en_eevop;
int rc;
EFSYS_ASSERT3U(eep->ee_magic, ==, EFX_EVQ_MAGIC);
if (!(enp->en_mod_flags & EFX_MOD_INTR)) {
rc = EINVAL;
goto fail1;
}
if ((rc = eevop->eevo_qprime(eep, count)) != 0)
goto fail2;
return (0);
fail2:
EFSYS_PROBE(fail2);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
__checkReturn boolean_t
efx_ev_qpending(
__in efx_evq_t *eep,
__in unsigned int count)
{
size_t offset;
efx_qword_t qword;
EFSYS_ASSERT3U(eep->ee_magic, ==, EFX_EVQ_MAGIC);
offset = (count & eep->ee_mask) * sizeof (efx_qword_t);
EFSYS_MEM_READQ(eep->ee_esmp, offset, &qword);
return (EFX_EV_PRESENT(qword));
}
#if EFSYS_OPT_EV_PREFETCH
void
efx_ev_qprefetch(
__in efx_evq_t *eep,
__in unsigned int count)
{
efx_nic_t *enp = eep->ee_enp;
unsigned int offset;
EFSYS_ASSERT3U(eep->ee_magic, ==, EFX_EVQ_MAGIC);
offset = (count & eep->ee_mask) * sizeof (efx_qword_t);
EFSYS_MEM_PREFETCH(eep->ee_esmp, offset);
}
#endif /* EFSYS_OPT_EV_PREFETCH */
void
efx_ev_qpoll(
__in efx_evq_t *eep,
__inout unsigned int *countp,
__in const efx_ev_callbacks_t *eecp,
__in_opt void *arg)
{
EFSYS_ASSERT3U(eep->ee_magic, ==, EFX_EVQ_MAGIC);
/*
* FIXME: Huntington will require support for hardware event batching
* and merging, which will need a different ev_qpoll implementation.
*
* Without those features the Falcon/Siena code can be used unchanged.
*/
EFX_STATIC_ASSERT(ESF_DZ_EV_CODE_LBN == FSF_AZ_EV_CODE_LBN);
EFX_STATIC_ASSERT(ESF_DZ_EV_CODE_WIDTH == FSF_AZ_EV_CODE_WIDTH);
EFX_STATIC_ASSERT(ESE_DZ_EV_CODE_RX_EV == FSE_AZ_EV_CODE_RX_EV);
EFX_STATIC_ASSERT(ESE_DZ_EV_CODE_TX_EV == FSE_AZ_EV_CODE_TX_EV);
EFX_STATIC_ASSERT(ESE_DZ_EV_CODE_DRIVER_EV == FSE_AZ_EV_CODE_DRIVER_EV);
EFX_STATIC_ASSERT(ESE_DZ_EV_CODE_DRV_GEN_EV ==
FSE_AZ_EV_CODE_DRV_GEN_EV);
#if EFSYS_OPT_MCDI
EFX_STATIC_ASSERT(ESE_DZ_EV_CODE_MCDI_EV ==
FSE_AZ_EV_CODE_MCDI_EVRESPONSE);
#endif
falconsiena_ev_qpoll(eep, countp, eecp, arg);
}
void
efx_ev_qpost(
__in efx_evq_t *eep,
__in uint16_t data)
{
efx_nic_t *enp = eep->ee_enp;
efx_ev_ops_t *eevop = enp->en_eevop;
EFSYS_ASSERT3U(eep->ee_magic, ==, EFX_EVQ_MAGIC);
EFSYS_ASSERT(eevop != NULL &&
eevop->eevo_qpost != NULL);
eevop->eevo_qpost(eep, data);
}
__checkReturn int
efx_ev_qmoderate(
__in efx_evq_t *eep,
__in unsigned int us)
{
efx_nic_t *enp = eep->ee_enp;
efx_ev_ops_t *eevop = enp->en_eevop;
int rc;
EFSYS_ASSERT3U(eep->ee_magic, ==, EFX_EVQ_MAGIC);
if ((rc = eevop->eevo_qmoderate(eep, us)) != 0)
goto fail1;
return (0);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
#if EFSYS_OPT_QSTATS
void
efx_ev_qstats_update(
__in efx_evq_t *eep,
__inout_ecount(EV_NQSTATS) efsys_stat_t *stat)
{ efx_nic_t *enp = eep->ee_enp;
efx_ev_ops_t *eevop = enp->en_eevop;
EFSYS_ASSERT3U(eep->ee_magic, ==, EFX_EVQ_MAGIC);
eevop->eevo_qstats_update(eep, stat);
}
#endif /* EFSYS_OPT_QSTATS */
#if EFSYS_OPT_FALCON || EFSYS_OPT_SIENA
static __checkReturn int
falconsiena_ev_init(
__in efx_nic_t *enp)
{
efx_oword_t oword;
/*
* Program the event queue for receive and transmit queue
* flush events.
@ -67,17 +462,12 @@ efx_ev_init(
EFX_SET_OWORD_FIELD(oword, FRF_AZ_FLS_EVQ_ID, 0);
EFX_BAR_WRITEO(enp, FR_AZ_DP_CTRL_REG, &oword);
enp->en_mod_flags |= EFX_MOD_EV;
return (0);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
static __checkReturn boolean_t
efx_ev_rx_not_ok(
falconsiena_ev_rx_not_ok(
__in efx_evq_t *eep,
__in efx_qword_t *eqp,
__in uint32_t label,
@ -167,7 +557,7 @@ efx_ev_rx_not_ok(
}
static __checkReturn boolean_t
efx_ev_rx(
falconsiena_ev_rx(
__in efx_evq_t *eep,
__in efx_qword_t *eqp,
__in const efx_ev_callbacks_t *eecp,
@ -264,7 +654,7 @@ efx_ev_rx(
/* Detect errors included in the FSF_AZ_RX_EV_PKT_OK indication */
if (!ok) {
ignore = efx_ev_rx_not_ok(eep, eqp, label, id, &flags);
ignore = falconsiena_ev_rx_not_ok(eep, eqp, label, id, &flags);
if (ignore) {
EFSYS_PROBE4(rx_complete, uint32_t, label, uint32_t, id,
uint32_t, size, uint16_t, flags);
@ -323,7 +713,7 @@ efx_ev_rx(
}
static __checkReturn boolean_t
efx_ev_tx(
falconsiena_ev_tx(
__in efx_evq_t *eep,
__in efx_qword_t *eqp,
__in const efx_ev_callbacks_t *eecp,
@ -370,7 +760,7 @@ efx_ev_tx(
}
static __checkReturn boolean_t
efx_ev_global(
falconsiena_ev_global(
__in efx_evq_t *eep,
__in efx_qword_t *eqp,
__in const efx_ev_callbacks_t *eecp,
@ -396,7 +786,7 @@ efx_ev_global(
}
static __checkReturn boolean_t
efx_ev_driver(
falconsiena_ev_driver(
__in efx_evq_t *eep,
__in efx_qword_t *eqp,
__in const efx_ev_callbacks_t *eecp,
@ -437,7 +827,8 @@ efx_ev_driver(
EFSYS_PROBE1(rx_descq_fls_failed, uint32_t, rxq_index);
should_abort = eecp->eec_rxq_flush_failed(arg, rxq_index);
should_abort = eecp->eec_rxq_flush_failed(arg,
rxq_index);
} else {
EFX_EV_QSTAT_INCR(eep, EV_DRIVER_RX_DESCQ_FLS_DONE);
@ -524,7 +915,7 @@ efx_ev_driver(
}
static __checkReturn boolean_t
efx_ev_drv_gen(
falconsiena_ev_drv_gen(
__in efx_evq_t *eep,
__in efx_qword_t *eqp,
__in const efx_ev_callbacks_t *eecp,
@ -552,7 +943,7 @@ efx_ev_drv_gen(
#if EFSYS_OPT_MCDI
static __checkReturn boolean_t
efx_ev_mcdi(
falconsiena_ev_mcdi(
__in efx_evq_t *eep,
__in efx_qword_t *eqp,
__in const efx_ev_callbacks_t *eecp,
@ -583,9 +974,9 @@ efx_ev_mcdi(
case MCDI_EVENT_CODE_CMDDONE:
efx_mcdi_ev_cpl(enp,
MCDI_EV_FIELD(eqp, CMDDONE_SEQ),
MCDI_EV_FIELD(eqp, CMDDONE_DATALEN),
MCDI_EV_FIELD(eqp, CMDDONE_ERRNO));
MCDI_EV_FIELD(eqp, CMDDONE_SEQ),
MCDI_EV_FIELD(eqp, CMDDONE_DATALEN),
MCDI_EV_FIELD(eqp, CMDDONE_ERRNO));
break;
case MCDI_EVENT_CODE_LINKCHANGE: {
@ -601,7 +992,7 @@ efx_ev_mcdi(
efx_mon_stat_value_t value;
int rc;
if ((rc = siena_mon_ev(enp, eqp, &id, &value)) == 0)
if ((rc = mcdi_mon_ev(enp, eqp, &id, &value)) == 0)
should_abort = eecp->eec_monitor(arg, id, value);
else if (rc == ENOTSUP) {
should_abort = eecp->eec_exception(arg,
@ -656,22 +1047,14 @@ efx_ev_mcdi(
#endif /* EFSYS_OPT_MCDI */
__checkReturn int
efx_ev_qprime(
static __checkReturn int
falconsiena_ev_qprime(
__in efx_evq_t *eep,
__in unsigned int count)
{
efx_nic_t *enp = eep->ee_enp;
uint32_t rptr;
efx_dword_t dword;
int rc;
EFSYS_ASSERT3U(eep->ee_magic, ==, EFX_EVQ_MAGIC);
if (!(enp->en_mod_flags & EFX_MOD_INTR)) {
rc = EINVAL;
goto fail1;
}
rptr = count & eep->ee_mask;
@ -681,55 +1064,12 @@ efx_ev_qprime(
&dword, B_FALSE);
return (0);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
__checkReturn boolean_t
efx_ev_qpending(
__in efx_evq_t *eep,
__in unsigned int count)
{
size_t offset;
efx_qword_t qword;
EFSYS_ASSERT3U(eep->ee_magic, ==, EFX_EVQ_MAGIC);
offset = (count & eep->ee_mask) * sizeof (efx_qword_t);
EFSYS_MEM_READQ(eep->ee_esmp, offset, &qword);
return (EFX_QWORD_FIELD(qword, EFX_DWORD_0) != 0xffffffff &&
EFX_QWORD_FIELD(qword, EFX_DWORD_1) != 0xffffffff);
}
#if EFSYS_OPT_EV_PREFETCH
void
efx_ev_qprefetch(
__in efx_evq_t *eep,
__in unsigned int count)
{
unsigned int offset;
EFSYS_ASSERT3U(eep->ee_magic, ==, EFX_EVQ_MAGIC);
offset = (count & eep->ee_mask) * sizeof (efx_qword_t);
EFSYS_MEM_PREFETCH(eep->ee_esmp, offset);
}
#endif /* EFSYS_OPT_EV_PREFETCH */
#define EFX_EV_BATCH 8
#define EFX_EV_PRESENT(_qword) \
(EFX_QWORD_FIELD((_qword), EFX_DWORD_0) != 0xffffffff && \
EFX_QWORD_FIELD((_qword), EFX_DWORD_1) != 0xffffffff)
void
efx_ev_qpoll(
static void
falconsiena_ev_qpoll(
__in efx_evq_t *eep,
__inout unsigned int *countp,
__in const efx_ev_callbacks_t *eecp,
@ -742,7 +1082,6 @@ efx_ev_qpoll(
unsigned int index;
size_t offset;
EFSYS_ASSERT3U(eep->ee_magic, ==, EFX_EVQ_MAGIC);
EFSYS_ASSERT(countp != NULL);
EFSYS_ASSERT(eecp != NULL);
@ -778,7 +1117,6 @@ efx_ev_qpoll(
for (index = 0; index < total; ++index) {
boolean_t should_abort;
uint32_t code;
efx_ev_handler_t handler;
#if EFSYS_OPT_EV_PREFETCH
/* Prefetch if we've now reached the batch period */
@ -794,9 +1132,49 @@ efx_ev_qpoll(
EFX_EV_QSTAT_INCR(eep, EV_ALL);
code = EFX_QWORD_FIELD(ev[index], FSF_AZ_EV_CODE);
handler = eep->ee_handler[code];
EFSYS_ASSERT(handler != NULL);
should_abort = handler(eep, &(ev[index]), eecp, arg);
switch (code) {
case FSE_AZ_EV_CODE_RX_EV:
should_abort = eep->ee_rx(eep,
&(ev[index]), eecp, arg);
break;
case FSE_AZ_EV_CODE_TX_EV:
should_abort = eep->ee_tx(eep,
&(ev[index]), eecp, arg);
break;
case FSE_AZ_EV_CODE_DRIVER_EV:
should_abort = eep->ee_driver(eep,
&(ev[index]), eecp, arg);
break;
case FSE_AZ_EV_CODE_DRV_GEN_EV:
should_abort = eep->ee_drv_gen(eep,
&(ev[index]), eecp, arg);
break;
#if EFSYS_OPT_MCDI
case FSE_AZ_EV_CODE_MCDI_EVRESPONSE:
should_abort = eep->ee_mcdi(eep,
&(ev[index]), eecp, arg);
break;
#endif
case FSE_AZ_EV_CODE_GLOBAL_EV:
if (eep->ee_global) {
should_abort = eep->ee_global(eep,
&(ev[index]), eecp, arg);
break;
}
/* else fallthrough */
default:
EFSYS_PROBE3(bad_event,
unsigned int, eep->ee_index,
uint32_t,
EFX_QWORD_FIELD(ev[index], EFX_DWORD_1),
uint32_t,
EFX_QWORD_FIELD(ev[index], EFX_DWORD_0));
EFSYS_ASSERT(eecp->eec_exception != NULL);
(void) eecp->eec_exception(arg,
EFX_EXCEPTION_EV_ERROR, code);
should_abort = B_TRUE;
}
if (should_abort) {
/* Ignore subsequent events */
total = index + 1;
@ -823,8 +1201,8 @@ efx_ev_qpoll(
*countp = count;
}
void
efx_ev_qpost(
static void
falconsiena_ev_qpost(
__in efx_evq_t *eep,
__in uint16_t data)
{
@ -832,8 +1210,6 @@ efx_ev_qpost(
efx_qword_t ev;
efx_oword_t oword;
EFSYS_ASSERT3U(eep->ee_magic, ==, EFX_EVQ_MAGIC);
EFX_POPULATE_QWORD_2(ev, FSF_AZ_EV_CODE, FSE_AZ_EV_CODE_DRV_GEN_EV,
FSF_AZ_EV_DATA_DW0, (uint32_t)data);
@ -844,8 +1220,8 @@ efx_ev_qpost(
EFX_BAR_WRITEO(enp, FR_AZ_DRV_EV_REG, &oword);
}
__checkReturn int
efx_ev_qmoderate(
static __checkReturn int
falconsiena_ev_qmoderate(
__in efx_evq_t *eep,
__in unsigned int us)
{
@ -855,8 +1231,6 @@ efx_ev_qmoderate(
efx_dword_t dword;
int rc;
EFSYS_ASSERT3U(eep->ee_magic, ==, EFX_EVQ_MAGIC);
if (us > encp->enc_evq_timer_max_us) {
rc = EINVAL;
goto fail1;
@ -905,27 +1279,24 @@ efx_ev_qmoderate(
return (rc);
}
__checkReturn int
efx_ev_qcreate(
static __checkReturn int
falconsiena_ev_qcreate(
__in efx_nic_t *enp,
__in unsigned int index,
__in efsys_mem_t *esmp,
__in size_t n,
__in uint32_t id,
__deref_out efx_evq_t **eepp)
__in efx_evq_t *eep)
{
efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
uint32_t size;
efx_evq_t *eep;
efx_oword_t oword;
int rc;
EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_EV);
EFX_STATIC_ASSERT(ISP2(EFX_EVQ_MAXNEVS));
EFX_STATIC_ASSERT(ISP2(EFX_EVQ_MINNEVS));
EFSYS_ASSERT3U(enp->en_ev_qcount + 1, <, encp->enc_evq_limit);
if (!ISP2(n) || !(n & EFX_EVQ_NEVS_MASK)) {
if (!ISP2(n) || (n < EFX_EVQ_MINNEVS) || (n > EFX_EVQ_MAXNEVS)) {
rc = EINVAL;
goto fail1;
}
@ -949,46 +1320,29 @@ efx_ev_qcreate(
goto fail4;
}
/* Allocate an EVQ object */
EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (efx_evq_t), eep);
if (eep == NULL) {
rc = ENOMEM;
goto fail5;
}
eep->ee_magic = EFX_EVQ_MAGIC;
eep->ee_enp = enp;
eep->ee_index = index;
eep->ee_mask = n - 1;
eep->ee_esmp = esmp;
/* Set up the handler table */
eep->ee_handler[FSE_AZ_EV_CODE_RX_EV] = efx_ev_rx;
eep->ee_handler[FSE_AZ_EV_CODE_TX_EV] = efx_ev_tx;
eep->ee_handler[FSE_AZ_EV_CODE_DRIVER_EV] = efx_ev_driver;
eep->ee_handler[FSE_AZ_EV_CODE_GLOBAL_EV] = efx_ev_global;
eep->ee_handler[FSE_AZ_EV_CODE_DRV_GEN_EV] = efx_ev_drv_gen;
eep->ee_rx = falconsiena_ev_rx;
eep->ee_tx = falconsiena_ev_tx;
eep->ee_driver = falconsiena_ev_driver;
eep->ee_global = falconsiena_ev_global;
eep->ee_drv_gen = falconsiena_ev_drv_gen;
#if EFSYS_OPT_MCDI
eep->ee_handler[FSE_AZ_EV_CODE_MCDI_EVRESPONSE] = efx_ev_mcdi;
eep->ee_mcdi = falconsiena_ev_mcdi;
#endif /* EFSYS_OPT_MCDI */
/* Set up the new event queue */
if (enp->en_family != EFX_FAMILY_FALCON) {
EFX_POPULATE_OWORD_1(oword, FRF_CZ_TIMER_Q_EN, 1);
EFX_BAR_TBL_WRITEO(enp, FR_AZ_TIMER_TBL, index, &oword);
EFX_BAR_TBL_WRITEO(enp, FR_AZ_TIMER_TBL, index, &oword, B_TRUE);
}
EFX_POPULATE_OWORD_3(oword, FRF_AZ_EVQ_EN, 1, FRF_AZ_EVQ_SIZE, size,
FRF_AZ_EVQ_BUF_BASE_ID, id);
EFX_BAR_TBL_WRITEO(enp, FR_AZ_EVQ_PTR_TBL, index, &oword);
EFX_BAR_TBL_WRITEO(enp, FR_AZ_EVQ_PTR_TBL, index, &oword, B_TRUE);
enp->en_ev_qcount++;
*eepp = eep;
return (0);
fail5:
EFSYS_PROBE(fail5);
fail4:
EFSYS_PROBE(fail4);
#if EFSYS_OPT_RX_SCALE
@ -1003,14 +1357,15 @@ efx_ev_qcreate(
return (rc);
}
#endif /* EFSYS_OPT_FALCON || EFSYS_OPT_SIENA */
#if EFSYS_OPT_QSTATS
#if EFSYS_OPT_NAMES
/* START MKCONFIG GENERATED EfxEventQueueStatNamesBlock 67e9bdcd920059bd */
static const char __cs * __cs __efx_ev_qstat_name[] = {
/* START MKCONFIG GENERATED EfxEventQueueStatNamesBlock b693ddf85aee1bfd */
static const char *__efx_ev_qstat_name[] = {
"all",
"rx",
"rx_ok",
"rx_recovery",
"rx_frm_trunc",
"rx_tobe_disc",
"rx_pause_frm_err",
@ -1028,16 +1383,14 @@ static const char __cs * __cs __efx_ev_qstat_name[] = {
"rx_other_ipv4",
"rx_other_ipv6",
"rx_non_ip",
"rx_overrun",
"rx_batch",
"tx",
"tx_wq_ff_full",
"tx_pkt_err",
"tx_pkt_too_big",
"tx_unexpected",
"global",
"global_phy",
"global_mnt",
"global_rx_recovery",
"driver",
"driver_srm_upd_done",
"driver_tx_descq_fls_done",
@ -1050,7 +1403,7 @@ static const char __cs * __cs __efx_ev_qstat_name[] = {
};
/* END MKCONFIG GENERATED EfxEventQueueStatNamesBlock */
const char __cs *
const char *
efx_ev_qstat_name(
__in efx_nic_t *enp,
__in unsigned int id)
@ -1063,16 +1416,16 @@ efx_ev_qstat_name(
#endif /* EFSYS_OPT_NAMES */
#endif /* EFSYS_OPT_QSTATS */
#if EFSYS_OPT_FALCON || EFSYS_OPT_SIENA
#if EFSYS_OPT_QSTATS
void
efx_ev_qstats_update(
static void
falconsiena_ev_qstats_update(
__in efx_evq_t *eep,
__inout_ecount(EV_NQSTATS) efsys_stat_t *stat)
{
unsigned int id;
EFSYS_ASSERT3U(eep->ee_magic, ==, EFX_EVQ_MAGIC);
for (id = 0; id < EV_NQSTATS; id++) {
efsys_stat_t *essp = &stat[id];
@ -1082,44 +1435,31 @@ efx_ev_qstats_update(
}
#endif /* EFSYS_OPT_QSTATS */
void
efx_ev_qdestroy(
static void
falconsiena_ev_qdestroy(
__in efx_evq_t *eep)
{
efx_nic_t *enp = eep->ee_enp;
efx_oword_t oword;
EFSYS_ASSERT3U(eep->ee_magic, ==, EFX_EVQ_MAGIC);
EFSYS_ASSERT(enp->en_ev_qcount != 0);
--enp->en_ev_qcount;
/* Purge event queue */
EFX_ZERO_OWORD(oword);
EFX_BAR_TBL_WRITEO(enp, FR_AZ_EVQ_PTR_TBL,
eep->ee_index, &oword);
eep->ee_index, &oword, B_TRUE);
if (enp->en_family != EFX_FAMILY_FALCON) {
EFX_ZERO_OWORD(oword);
EFX_BAR_TBL_WRITEO(enp, FR_AZ_TIMER_TBL,
eep->ee_index, &oword);
eep->ee_index, &oword, B_TRUE);
}
/* Free the EVQ object */
EFSYS_KMEM_FREE(enp->en_esip, sizeof (efx_evq_t), eep);
}
void
efx_ev_fini(
static void
falconsiena_ev_fini(
__in efx_nic_t *enp)
{
EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_EV);
EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_RX));
EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_TX));
EFSYS_ASSERT3U(enp->en_ev_qcount, ==, 0);
enp->en_mod_flags &= ~EFX_MOD_EV;
_NOTE(ARGUNUSED(enp))
}
#endif /* EFSYS_OPT_FALCON || EFSYS_OPT_SIENA */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,333 @@
/*-
* Copyright 2006 Bob Jenkins
*
* Derived from public domain source, see
* <http://burtleburtle.net/bob/c/lookup3.c>:
*
* "lookup3.c, by Bob Jenkins, May 2006, Public Domain.
*
* These are functions for producing 32-bit hashes for hash table lookup...
* ...You can use this free for any purpose. It's in the public domain.
* It has no warranty."
*
* Copyright (c) 2014-2015 Solarflare Communications Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the FreeBSD Project.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "efsys.h"
#include "efx.h"
#include "efx_types.h"
#include "efx_impl.h"
/* Hash initial value */
#define EFX_HASH_INITIAL_VALUE 0xdeadbeef
/*
* Rotate a 32-bit value left
*
* Allow platform to provide an intrinsic or optimised routine and
* fall-back to a simple shift based implementation.
*/
#if EFSYS_HAS_ROTL_DWORD
#define EFX_HASH_ROTATE(_value, _shift) \
EFSYS_ROTL_DWORD(_value, _shift)
#else
#define EFX_HASH_ROTATE(_value, _shift) \
(((_value) << (_shift)) | ((_value) >> (32 - (_shift))))
#endif
/* Mix three 32-bit values reversibly */
#define EFX_HASH_MIX(_a, _b, _c) \
do { \
_a -= _c; \
_a ^= EFX_HASH_ROTATE(_c, 4); \
_c += _b; \
_b -= _a; \
_b ^= EFX_HASH_ROTATE(_a, 6); \
_a += _c; \
_c -= _b; \
_c ^= EFX_HASH_ROTATE(_b, 8); \
_b += _a; \
_a -= _c; \
_a ^= EFX_HASH_ROTATE(_c, 16); \
_c += _b; \
_b -= _a; \
_b ^= EFX_HASH_ROTATE(_a, 19); \
_a += _c; \
_c -= _b; \
_c ^= EFX_HASH_ROTATE(_b, 4); \
_b += _a; \
_NOTE(CONSTANTCONDITION) \
} while (B_FALSE)
/* Final mixing of three 32-bit values into one (_c) */
#define EFX_HASH_FINALISE(_a, _b, _c) \
do { \
_c ^= _b; \
_c -= EFX_HASH_ROTATE(_b, 14); \
_a ^= _c; \
_a -= EFX_HASH_ROTATE(_c, 11); \
_b ^= _a; \
_b -= EFX_HASH_ROTATE(_a, 25); \
_c ^= _b; \
_c -= EFX_HASH_ROTATE(_b, 16); \
_a ^= _c; \
_a -= EFX_HASH_ROTATE(_c, 4); \
_b ^= _a; \
_b -= EFX_HASH_ROTATE(_a, 14); \
_c ^= _b; \
_c -= EFX_HASH_ROTATE(_b, 24); \
_NOTE(CONSTANTCONDITION) \
} while (B_FALSE)
/* Produce a 32-bit hash from 32-bit aligned input */
__checkReturn uint32_t
efx_hash_dwords(
__in_ecount(count) uint32_t const *input,
__in size_t count,
__in uint32_t init)
{
uint32_t a;
uint32_t b;
uint32_t c;
/* Set up the initial internal state */
a = b = c = EFX_HASH_INITIAL_VALUE +
(((uint32_t)count) * sizeof (uint32_t)) + init;
/* Handle all but the last three dwords of the input */
while (count > 3) {
a += input[0];
b += input[1];
c += input[2];
EFX_HASH_MIX(a, b, c);
count -= 3;
input += 3;
}
/* Handle the left-overs */
switch (count) {
case 3:
c += input[2];
/* Fall-through */
case 2:
b += input[1];
/* Fall-through */
case 1:
a += input[0];
EFX_HASH_FINALISE(a, b, c);
break;
case 0:
/* Should only get here if count parameter was zero */
break;
}
return (c);
}
#if EFSYS_IS_BIG_ENDIAN
/* Produce a 32-bit hash from arbitrarily aligned input */
__checkReturn uint32_t
efx_hash_bytes(
__in_ecount(length) uint8_t const *input,
__in size_t length,
__in uint32_t init)
{
uint32_t a;
uint32_t b;
uint32_t c;
/* Set up the initial internal state */
a = b = c = EFX_HASH_INITIAL_VALUE + (uint32_t)length + init;
/* Handle all but the last twelve bytes of the input */
while (length > 12) {
a += ((uint32_t)input[0]) << 24;
a += ((uint32_t)input[1]) << 16;
a += ((uint32_t)input[2]) << 8;
a += ((uint32_t)input[3]);
b += ((uint32_t)input[4]) << 24;
b += ((uint32_t)input[5]) << 16;
b += ((uint32_t)input[6]) << 8;
b += ((uint32_t)input[7]);
c += ((uint32_t)input[8]) << 24;
c += ((uint32_t)input[9]) << 16;
c += ((uint32_t)input[10]) << 8;
c += ((uint32_t)input[11]);
EFX_HASH_MIX(a, b, c);
length -= 12;
input += 12;
}
/* Handle the left-overs */
switch (length) {
case 12:
c += ((uint32_t)input[11]);
/* Fall-through */
case 11:
c += ((uint32_t)input[10]) << 8;
/* Fall-through */
case 10:
c += ((uint32_t)input[9]) << 16;
/* Fall-through */
case 9:
c += ((uint32_t)input[8]) << 24;
/* Fall-through */
case 8:
b += ((uint32_t)input[7]);
/* Fall-through */
case 7:
b += ((uint32_t)input[6]) << 8;
/* Fall-through */
case 6:
b += ((uint32_t)input[5]) << 16;
/* Fall-through */
case 5:
b += ((uint32_t)input[4]) << 24;
/* Fall-through */
case 4:
a += ((uint32_t)input[3]);
/* Fall-through */
case 3:
a += ((uint32_t)input[2]) << 8;
/* Fall-through */
case 2:
a += ((uint32_t)input[1]) << 16;
/* Fall-through */
case 1:
a += ((uint32_t)input[0]) << 24;
EFX_HASH_FINALISE(a, b, c);
break;
case 0:
/* Should only get here if length parameter was zero */
break;
}
return (c);
}
#elif EFSYS_IS_LITTLE_ENDIAN
/* Produce a 32-bit hash from arbitrarily aligned input */
__checkReturn uint32_t
efx_hash_bytes(
__in_ecount(length) uint8_t const *input,
__in size_t length,
__in uint32_t init)
{
uint32_t a;
uint32_t b;
uint32_t c;
/* Set up the initial internal state */
a = b = c = EFX_HASH_INITIAL_VALUE + (uint32_t)length + init;
/* Handle all but the last twelve bytes of the input */
while (length > 12) {
a += ((uint32_t)input[0]);
a += ((uint32_t)input[1]) << 8;
a += ((uint32_t)input[2]) << 16;
a += ((uint32_t)input[3]) << 24;
b += ((uint32_t)input[4]);
b += ((uint32_t)input[5]) << 8;
b += ((uint32_t)input[6]) << 16;
b += ((uint32_t)input[7]) << 24;
c += ((uint32_t)input[8]);
c += ((uint32_t)input[9]) << 8;
c += ((uint32_t)input[10]) << 16;
c += ((uint32_t)input[11]) << 24;
EFX_HASH_MIX(a, b, c);
length -= 12;
input += 12;
}
/* Handle the left-overs */
switch (length) {
case 12:
c += ((uint32_t)input[11]) << 24;
/* Fall-through */
case 11:
c += ((uint32_t)input[10]) << 16;
/* Fall-through */
case 10:
c += ((uint32_t)input[9]) << 8;
/* Fall-through */
case 9:
c += ((uint32_t)input[8]);
/* Fall-through */
case 8:
b += ((uint32_t)input[7]) << 24;
/* Fall-through */
case 7:
b += ((uint32_t)input[6]) << 16;
/* Fall-through */
case 6:
b += ((uint32_t)input[5]) << 8;
/* Fall-through */
case 5:
b += ((uint32_t)input[4]);
/* Fall-through */
case 4:
a += ((uint32_t)input[3]) << 24;
/* Fall-through */
case 3:
a += ((uint32_t)input[2]) << 16;
/* Fall-through */
case 2:
a += ((uint32_t)input[1]) << 8;
/* Fall-through */
case 1:
a += ((uint32_t)input[0]);
EFX_HASH_FINALISE(a, b, c);
break;
case 0:
/* Should only get here if length parameter was zero */
break;
}
return (c);
}
#else
#error "Neither of EFSYS_IS_{BIG,LITTLE}_ENDIAN is set"
#endif

View File

@ -1,26 +1,31 @@
/*-
* Copyright 2007-2009 Solarflare Communications Inc. All rights reserved.
* Copyright (c) 2007-2015 Solarflare Communications Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* modification, are permitted provided that the following conditions are met:
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the FreeBSD Project.
*
* $FreeBSD$
*/
@ -31,6 +36,15 @@
#include "efsys.h"
#include "efx.h"
#include "efx_regs.h"
#include "efx_regs_ef10.h"
/* FIXME: Add definition for driver generated software events */
#ifndef ESE_DZ_EV_CODE_DRV_GEN_EV
#define ESE_DZ_EV_CODE_DRV_GEN_EV FSE_AZ_EV_CODE_DRV_GEN_EV
#endif
#include "efx_check.h"
#if EFSYS_OPT_FALCON
#include "falcon_impl.h"
@ -40,40 +54,138 @@
#include "siena_impl.h"
#endif /* EFSYS_OPT_SIENA */
#if EFSYS_OPT_HUNTINGTON
#include "hunt_impl.h"
#endif /* EFSYS_OPT_HUNTINGTON */
#ifdef __cplusplus
extern "C" {
#endif
#define EFX_MOD_MCDI 0x00000001
#define EFX_MOD_PROBE 0x00000002
#define EFX_MOD_NVRAM 0x00000004
#define EFX_MOD_VPD 0x00000008
#define EFX_MOD_NIC 0x00000010
#define EFX_MOD_INTR 0x00000020
#define EFX_MOD_EV 0x00000040
#define EFX_MOD_RX 0x00000080
#define EFX_MOD_TX 0x00000100
#define EFX_MOD_PORT 0x00000200
#define EFX_MOD_MON 0x00000400
#define EFX_MOD_WOL 0x00000800
#define EFX_MOD_FILTER 0x00001000
#define EFX_MOD_MCDI 0x00000001
#define EFX_MOD_PROBE 0x00000002
#define EFX_MOD_NVRAM 0x00000004
#define EFX_MOD_VPD 0x00000008
#define EFX_MOD_NIC 0x00000010
#define EFX_MOD_INTR 0x00000020
#define EFX_MOD_EV 0x00000040
#define EFX_MOD_RX 0x00000080
#define EFX_MOD_TX 0x00000100
#define EFX_MOD_PORT 0x00000200
#define EFX_MOD_MON 0x00000400
#define EFX_MOD_WOL 0x00000800
#define EFX_MOD_FILTER 0x00001000
#define EFX_MOD_PKTFILTER 0x00002000
#define EFX_RESET_MAC 0x00000001
#define EFX_RESET_PHY 0x00000002
#define EFX_RESET_MAC 0x00000001
#define EFX_RESET_PHY 0x00000002
#define EFX_RESET_RXQ_ERR 0x00000004
#define EFX_RESET_TXQ_ERR 0x00000008
typedef enum efx_mac_type_e {
EFX_MAC_INVALID = 0,
EFX_MAC_FALCON_GMAC,
EFX_MAC_FALCON_XMAC,
EFX_MAC_SIENA,
EFX_MAC_HUNTINGTON,
EFX_MAC_NTYPES
} efx_mac_type_t;
typedef struct efx_ev_ops_s {
int (*eevo_init)(efx_nic_t *);
void (*eevo_fini)(efx_nic_t *);
int (*eevo_qcreate)(efx_nic_t *, unsigned int,
efsys_mem_t *, size_t, uint32_t,
efx_evq_t *);
void (*eevo_qdestroy)(efx_evq_t *);
int (*eevo_qprime)(efx_evq_t *, unsigned int);
void (*eevo_qpost)(efx_evq_t *, uint16_t);
int (*eevo_qmoderate)(efx_evq_t *, unsigned int);
#if EFSYS_OPT_QSTATS
void (*eevo_qstats_update)(efx_evq_t *, efsys_stat_t *);
#endif
} efx_ev_ops_t;
typedef struct efx_tx_ops_s {
int (*etxo_init)(efx_nic_t *);
void (*etxo_fini)(efx_nic_t *);
int (*etxo_qcreate)(efx_nic_t *,
unsigned int, unsigned int,
efsys_mem_t *, size_t,
uint32_t, uint16_t,
efx_evq_t *, efx_txq_t *,
unsigned int *);
void (*etxo_qdestroy)(efx_txq_t *);
int (*etxo_qpost)(efx_txq_t *, efx_buffer_t *,
unsigned int, unsigned int,
unsigned int *);
void (*etxo_qpush)(efx_txq_t *, unsigned int, unsigned int);
int (*etxo_qpace)(efx_txq_t *, unsigned int);
int (*etxo_qflush)(efx_txq_t *);
void (*etxo_qenable)(efx_txq_t *);
int (*etxo_qpio_enable)(efx_txq_t *);
void (*etxo_qpio_disable)(efx_txq_t *);
int (*etxo_qpio_write)(efx_txq_t *,uint8_t *, size_t,
size_t);
int (*etxo_qpio_post)(efx_txq_t *, size_t, unsigned int,
unsigned int *);
int (*etxo_qdesc_post)(efx_txq_t *, efx_desc_t *,
unsigned int, unsigned int,
unsigned int *);
void (*etxo_qdesc_dma_create)(efx_txq_t *, efsys_dma_addr_t,
size_t, boolean_t,
efx_desc_t *);
void (*etxo_qdesc_tso_create)(efx_txq_t *, uint16_t,
uint32_t, uint8_t,
efx_desc_t *);
void (*etxo_qdesc_vlantci_create)(efx_txq_t *, uint16_t,
efx_desc_t *);
#if EFSYS_OPT_QSTATS
void (*etxo_qstats_update)(efx_txq_t *,
efsys_stat_t *);
#endif
} efx_tx_ops_t;
typedef struct efx_rx_ops_s {
int (*erxo_init)(efx_nic_t *);
void (*erxo_fini)(efx_nic_t *);
#if EFSYS_OPT_RX_HDR_SPLIT
int (*erxo_hdr_split_enable)(efx_nic_t *, unsigned int,
unsigned int);
#endif
#if EFSYS_OPT_RX_SCATTER
int (*erxo_scatter_enable)(efx_nic_t *, unsigned int);
#endif
#if EFSYS_OPT_RX_SCALE
int (*erxo_scale_mode_set)(efx_nic_t *, efx_rx_hash_alg_t,
efx_rx_hash_type_t, boolean_t);
int (*erxo_scale_key_set)(efx_nic_t *, uint8_t *, size_t);
int (*erxo_scale_tbl_set)(efx_nic_t *, unsigned int *,
size_t);
#endif
void (*erxo_qpost)(efx_rxq_t *, efsys_dma_addr_t *, size_t,
unsigned int, unsigned int,
unsigned int);
void (*erxo_qpush)(efx_rxq_t *, unsigned int, unsigned int *);
int (*erxo_qflush)(efx_rxq_t *);
void (*erxo_qenable)(efx_rxq_t *);
int (*erxo_qcreate)(efx_nic_t *enp, unsigned int,
unsigned int, efx_rxq_type_t,
efsys_mem_t *, size_t, uint32_t,
efx_evq_t *, efx_rxq_t *);
void (*erxo_qdestroy)(efx_rxq_t *);
} efx_rx_ops_t;
typedef struct efx_mac_ops_s {
int (*emo_reset)(efx_nic_t *); /* optional */
int (*emo_poll)(efx_nic_t *, efx_link_mode_t *);
int (*emo_up)(efx_nic_t *, boolean_t *);
int (*emo_addr_set)(efx_nic_t *);
int (*emo_reconfigure)(efx_nic_t *);
int (*emo_multicast_list_set)(efx_nic_t *);
int (*emo_filter_default_rxq_set)(efx_nic_t *,
efx_rxq_t *, boolean_t);
void (*emo_filter_default_rxq_clear)(efx_nic_t *);
#if EFSYS_OPT_LOOPBACK
int (*emo_loopback_set)(efx_nic_t *, efx_link_mode_t,
efx_loopback_type_t);
@ -103,21 +215,59 @@ typedef struct efx_phy_ops_s {
#endif /* EFSYS_OPT_PHY_STATS */
#if EFSYS_OPT_PHY_PROPS
#if EFSYS_OPT_NAMES
const char __cs *(*epo_prop_name)(efx_nic_t *, unsigned int);
const char *(*epo_prop_name)(efx_nic_t *, unsigned int);
#endif /* EFSYS_OPT_PHY_PROPS */
int (*epo_prop_get)(efx_nic_t *, unsigned int, uint32_t,
uint32_t *);
int (*epo_prop_set)(efx_nic_t *, unsigned int, uint32_t);
#endif /* EFSYS_OPT_PHY_PROPS */
#if EFSYS_OPT_PHY_BIST
int (*epo_bist_start)(efx_nic_t *, efx_phy_bist_type_t);
int (*epo_bist_poll)(efx_nic_t *, efx_phy_bist_type_t,
efx_phy_bist_result_t *, uint32_t *,
#if EFSYS_OPT_BIST
int (*epo_bist_enable_offline)(efx_nic_t *);
int (*epo_bist_start)(efx_nic_t *, efx_bist_type_t);
int (*epo_bist_poll)(efx_nic_t *, efx_bist_type_t,
efx_bist_result_t *, uint32_t *,
unsigned long *, size_t);
void (*epo_bist_stop)(efx_nic_t *, efx_phy_bist_type_t);
#endif /* EFSYS_OPT_PHY_BIST */
void (*epo_bist_stop)(efx_nic_t *, efx_bist_type_t);
#endif /* EFSYS_OPT_BIST */
} efx_phy_ops_t;
#if EFSYS_OPT_FILTER
typedef struct efx_filter_ops_s {
int (*efo_init)(efx_nic_t *);
void (*efo_fini)(efx_nic_t *);
int (*efo_restore)(efx_nic_t *);
int (*efo_add)(efx_nic_t *, efx_filter_spec_t *,
boolean_t may_replace);
int (*efo_delete)(efx_nic_t *, efx_filter_spec_t *);
int (*efo_supported_filters)(efx_nic_t *, uint32_t *, size_t *);
int (*efo_reconfigure)(efx_nic_t *, uint8_t const *, boolean_t,
boolean_t, boolean_t, boolean_t,
uint8_t const *, int);
} efx_filter_ops_t;
extern __checkReturn int
efx_filter_reconfigure(
__in efx_nic_t *enp,
__in_ecount(6) uint8_t const *mac_addr,
__in boolean_t all_unicst,
__in boolean_t mulcst,
__in boolean_t all_mulcst,
__in boolean_t brdcst,
__in_ecount(6*count) uint8_t const *addrs,
__in int count);
#endif /* EFSYS_OPT_FILTER */
typedef struct efx_pktfilter_ops_s {
int (*epfo_set)(efx_nic_t *,
boolean_t unicst,
boolean_t brdcast);
#if EFSYS_OPT_MCAST_FILTER_LIST
int (*epfo_mcast_list_set)(efx_nic_t *, uint8_t const *addrs, int count);
#endif /* EFSYS_OPT_MCAST_FILTER_LIST */
int (*epfo_mcast_all)(efx_nic_t *);
} efx_pktfilter_ops_t;
typedef struct efx_port_s {
efx_mac_type_t ep_mac_type;
uint32_t ep_phy_type;
@ -125,11 +275,16 @@ typedef struct efx_port_s {
uint32_t ep_mac_pdu;
uint8_t ep_mac_addr[6];
efx_link_mode_t ep_link_mode;
boolean_t ep_unicst;
boolean_t ep_all_unicst;
boolean_t ep_mulcst;
boolean_t ep_all_mulcst;
boolean_t ep_brdcst;
unsigned int ep_fcntl;
boolean_t ep_fcntl_autoneg;
efx_oword_t ep_multicst_hash[2];
uint8_t ep_mulcst_addr_list[EFX_MAC_ADDR_LEN *
EFX_MAC_MULTICAST_LIST_MAX];
uint32_t ep_mulcst_addr_count;
#if EFSYS_OPT_LOOPBACK
efx_loopback_type_t ep_loopback_type;
efx_link_mode_t ep_loopback_link_mode;
@ -161,8 +316,8 @@ typedef struct efx_port_s {
uint32_t ep_fwver; /* falcon only */
boolean_t ep_mac_drain;
boolean_t ep_mac_stats_pending;
#if EFSYS_OPT_PHY_BIST
efx_phy_bist_type_t ep_current_bist;
#if EFSYS_OPT_BIST
efx_bist_type_t ep_current_bist;
#endif
efx_mac_ops_t *ep_emop;
efx_phy_ops_t *ep_epop;
@ -182,16 +337,30 @@ typedef struct efx_mon_s {
efx_mon_ops_t *em_emop;
} efx_mon_t;
typedef struct efx_intr_ops_s {
int (*eio_init)(efx_nic_t *, efx_intr_type_t, efsys_mem_t *);
void (*eio_enable)(efx_nic_t *);
void (*eio_disable)(efx_nic_t *);
void (*eio_disable_unlocked)(efx_nic_t *);
int (*eio_trigger)(efx_nic_t *, unsigned int);
void (*eio_fini)(efx_nic_t *);
} efx_intr_ops_t;
typedef struct efx_intr_s {
efx_intr_type_t ei_type;
efx_intr_ops_t *ei_eiop;
efsys_mem_t *ei_esmp;
efx_intr_type_t ei_type;
unsigned int ei_level;
} efx_intr_t;
typedef struct efx_nic_ops_s {
int (*eno_probe)(efx_nic_t *);
int (*eno_set_drv_limits)(efx_nic_t *, efx_drv_limits_t*);
int (*eno_reset)(efx_nic_t *);
int (*eno_init)(efx_nic_t *);
int (*eno_get_vi_pool)(efx_nic_t *, uint32_t *);
int (*eno_get_bar_region)(efx_nic_t *, efx_nic_region_t,
uint32_t *, size_t *);
#if EFSYS_OPT_DIAG
int (*eno_sram_test)(efx_nic_t *, efx_sram_pattern_fn_t);
int (*eno_register_test)(efx_nic_t *);
@ -201,94 +370,107 @@ typedef struct efx_nic_ops_s {
} efx_nic_ops_t;
#ifndef EFX_TXQ_LIMIT_TARGET
# define EFX_TXQ_LIMIT_TARGET 259
#define EFX_TXQ_LIMIT_TARGET 259
#endif
#ifndef EFX_RXQ_LIMIT_TARGET
# define EFX_RXQ_LIMIT_TARGET 512
#define EFX_RXQ_LIMIT_TARGET 512
#endif
#ifndef EFX_TXQ_DC_SIZE
#define EFX_TXQ_DC_SIZE 1 /* 16 descriptors */
#define EFX_TXQ_DC_SIZE 1 /* 16 descriptors */
#endif
#ifndef EFX_RXQ_DC_SIZE
#define EFX_RXQ_DC_SIZE 3 /* 64 descriptors */
#define EFX_RXQ_DC_SIZE 3 /* 64 descriptors */
#endif
#if EFSYS_OPT_FILTER
typedef enum efx_filter_type_e {
EFX_FILTER_RX_TCP_FULL, /* TCP/IPv4 4-tuple {dIP,dTCP,sIP,sTCP} */
EFX_FILTER_RX_TCP_WILD, /* TCP/IPv4 dest {dIP,dTCP, -, -} */
EFX_FILTER_RX_UDP_FULL, /* UDP/IPv4 4-tuple {dIP,dUDP,sIP,sUDP} */
EFX_FILTER_RX_UDP_WILD, /* UDP/IPv4 dest {dIP,dUDP, -, -} */
typedef struct falconsiena_filter_spec_s {
uint8_t fsfs_type;
uint32_t fsfs_flags;
uint32_t fsfs_dmaq_id;
uint32_t fsfs_dword[3];
} falconsiena_filter_spec_t;
typedef enum falconsiena_filter_type_e {
EFX_FS_FILTER_RX_TCP_FULL, /* TCP/IPv4 4-tuple {dIP,dTCP,sIP,sTCP} */
EFX_FS_FILTER_RX_TCP_WILD, /* TCP/IPv4 dest {dIP,dTCP, -, -} */
EFX_FS_FILTER_RX_UDP_FULL, /* UDP/IPv4 4-tuple {dIP,dUDP,sIP,sUDP} */
EFX_FS_FILTER_RX_UDP_WILD, /* UDP/IPv4 dest {dIP,dUDP, -, -} */
#if EFSYS_OPT_SIENA
EFX_FILTER_RX_MAC_FULL, /* Ethernet {dMAC,VLAN} */
EFX_FILTER_RX_MAC_WILD, /* Ethernet {dMAC, -} */
EFX_FS_FILTER_RX_MAC_FULL, /* Ethernet {dMAC,VLAN} */
EFX_FS_FILTER_RX_MAC_WILD, /* Ethernet {dMAC, -} */
EFX_FILTER_TX_TCP_FULL, /* TCP/IPv4 {dIP,dTCP,sIP,sTCP} */
EFX_FILTER_TX_TCP_WILD, /* TCP/IPv4 { -, -,sIP,sTCP} */
EFX_FILTER_TX_UDP_FULL, /* UDP/IPv4 {dIP,dTCP,sIP,sTCP} */
EFX_FILTER_TX_UDP_WILD, /* UDP/IPv4 source (host, port) */
EFX_FS_FILTER_TX_TCP_FULL, /* TCP/IPv4 {dIP,dTCP,sIP,sTCP} */
EFX_FS_FILTER_TX_TCP_WILD, /* TCP/IPv4 { -, -,sIP,sTCP} */
EFX_FS_FILTER_TX_UDP_FULL, /* UDP/IPv4 {dIP,dTCP,sIP,sTCP} */
EFX_FS_FILTER_TX_UDP_WILD, /* UDP/IPv4 source (host, port) */
EFX_FILTER_TX_MAC_FULL, /* Ethernet source (MAC address, VLAN ID) */
EFX_FILTER_TX_MAC_WILD, /* Ethernet source (MAC address) */
EFX_FS_FILTER_TX_MAC_FULL, /* Ethernet source (MAC address, VLAN ID) */
EFX_FS_FILTER_TX_MAC_WILD, /* Ethernet source (MAC address) */
#endif /* EFSYS_OPT_SIENA */
EFX_FILTER_NTYPES
} efx_filter_type_t;
EFX_FS_FILTER_NTYPES
} falconsiena_filter_type_t;
typedef enum efx_filter_tbl_id_e {
EFX_FILTER_TBL_RX_IP = 0,
EFX_FILTER_TBL_RX_MAC,
EFX_FILTER_TBL_TX_IP,
EFX_FILTER_TBL_TX_MAC,
EFX_FILTER_NTBLS
} efx_filter_tbl_id_t;
typedef enum falconsiena_filter_tbl_id_e {
EFX_FS_FILTER_TBL_RX_IP = 0,
EFX_FS_FILTER_TBL_RX_MAC,
EFX_FS_FILTER_TBL_TX_IP,
EFX_FS_FILTER_TBL_TX_MAC,
EFX_FS_FILTER_NTBLS
} falconsiena_filter_tbl_id_t;
typedef struct efx_filter_tbl_s {
int eft_size; /* number of entries */
int eft_used; /* active count */
uint32_t *eft_bitmap; /* active bitmap */
efx_filter_spec_t *eft_spec; /* array of saved specs */
} efx_filter_tbl_t;
typedef struct falconsiena_filter_tbl_s {
int fsft_size; /* number of entries */
int fsft_used; /* active count */
uint32_t *fsft_bitmap; /* active bitmap */
falconsiena_filter_spec_t *fsft_spec; /* array of saved specs */
} falconsiena_filter_tbl_t;
typedef struct falconsiena_filter_s {
falconsiena_filter_tbl_t fsf_tbl[EFX_FS_FILTER_NTBLS];
unsigned int fsf_depth[EFX_FS_FILTER_NTYPES];
} falconsiena_filter_t;
typedef struct efx_filter_s {
efx_filter_tbl_t ef_tbl[EFX_FILTER_NTBLS];
unsigned int ef_depth[EFX_FILTER_NTYPES];
#if EFSYS_OPT_FALCON || EFSYS_OPT_SIENA
falconsiena_filter_t *ef_falconsiena_filter;
#endif /* EFSYS_OPT_FALCON || EFSYS_OPT_SIENA */
#if EFSYS_OPT_HUNTINGTON
hunt_filter_table_t *ef_hunt_filter_table;
#endif /* EFSYS_OPT_HUNTINGTON */
} efx_filter_t;
extern __checkReturn int
efx_filter_insert_filter(
__in efx_nic_t *enp,
__in efx_filter_spec_t *spec,
__in boolean_t replace);
extern __checkReturn int
efx_filter_remove_filter(
__in efx_nic_t *enp,
__in efx_filter_spec_t *spec);
extern void
efx_filter_remove_index(
__inout efx_nic_t *enp,
__in efx_filter_type_t type,
__in int filter_idx);
extern void
efx_filter_redirect_index(
__inout efx_nic_t *enp,
__in efx_filter_type_t type,
__in int filter_index,
__in int rxq_index);
extern __checkReturn int
efx_filter_clear_tbl(
falconsiena_filter_tbl_clear(
__in efx_nic_t *enp,
__in efx_filter_tbl_id_t tbl);
__in falconsiena_filter_tbl_id_t tbl);
#endif /* EFSYS_OPT_FILTER */
#if EFSYS_OPT_MCDI
typedef struct efx_mcdi_ops_s {
int (*emco_init)(efx_nic_t *, const efx_mcdi_transport_t *);
void (*emco_request_copyin)(efx_nic_t *, efx_mcdi_req_t *,
unsigned int, boolean_t, boolean_t);
boolean_t (*emco_request_poll)(efx_nic_t *);
void (*emco_request_copyout)(efx_nic_t *, efx_mcdi_req_t *);
int (*emco_poll_reboot)(efx_nic_t *);
void (*emco_fini)(efx_nic_t *);
int (*emco_fw_update_supported)(efx_nic_t *, boolean_t *);
int (*emco_macaddr_change_supported)(efx_nic_t *, boolean_t *);
} efx_mcdi_ops_t;
typedef struct efx_mcdi_s {
efx_mcdi_ops_t *em_emcop;
const efx_mcdi_transport_t *em_emtp;
efx_mcdi_iface_t em_emip;
} efx_mcdi_t;
#endif /* EFSYS_OPT_MCDI */
#if EFSYS_OPT_NVRAM
typedef struct efx_nvram_ops_s {
#if EFSYS_OPT_DIAG
@ -325,6 +507,85 @@ typedef struct efx_vpd_ops_s {
} efx_vpd_ops_t;
#endif /* EFSYS_OPT_VPD */
#if EFSYS_OPT_VPD || EFSYS_OPT_NVRAM
__checkReturn int
efx_mcdi_nvram_partitions(
__in efx_nic_t *enp,
__out_bcount(size) caddr_t data,
__in size_t size,
__out unsigned int *npartnp);
__checkReturn int
efx_mcdi_nvram_metadata(
__in efx_nic_t *enp,
__in uint32_t partn,
__out uint32_t *subtypep,
__out_ecount(4) uint16_t version[4],
__out_bcount_opt(size) char *descp,
__in size_t size);
__checkReturn int
efx_mcdi_nvram_info(
__in efx_nic_t *enp,
__in uint32_t partn,
__out_opt size_t *sizep,
__out_opt uint32_t *addressp,
__out_opt uint32_t *erase_sizep);
__checkReturn int
efx_mcdi_nvram_update_start(
__in efx_nic_t *enp,
__in uint32_t partn);
__checkReturn int
efx_mcdi_nvram_read(
__in efx_nic_t *enp,
__in uint32_t partn,
__in uint32_t offset,
__out_bcount(size) caddr_t data,
__in size_t size);
__checkReturn int
efx_mcdi_nvram_erase(
__in efx_nic_t *enp,
__in uint32_t partn,
__in uint32_t offset,
__in size_t size);
__checkReturn int
efx_mcdi_nvram_write(
__in efx_nic_t *enp,
__in uint32_t partn,
__in uint32_t offset,
__out_bcount(size) caddr_t data,
__in size_t size);
__checkReturn int
efx_mcdi_nvram_update_finish(
__in efx_nic_t *enp,
__in uint32_t partn,
__in boolean_t reboot);
#if EFSYS_OPT_DIAG
__checkReturn int
efx_mcdi_nvram_test(
__in efx_nic_t *enp,
__in uint32_t partn);
#endif /* EFSYS_OPT_DIAG */
#endif /* EFSYS_OPT_VPD || EFSYS_OPT_NVRAM */
typedef struct efx_drv_cfg_s {
uint32_t edc_min_vi_count;
uint32_t edc_max_vi_count;
uint32_t edc_max_piobuf_count;
uint32_t edc_pio_alloc_size;
} efx_drv_cfg_t;
struct efx_nic_s {
uint32_t en_magic;
efx_family_t en_family;
@ -335,6 +596,7 @@ struct efx_nic_s {
unsigned int en_mod_flags;
unsigned int en_reset_flags;
efx_nic_cfg_t en_nic_cfg;
efx_drv_cfg_t en_drv_cfg;
efx_port_t en_port;
efx_mon_t en_mon;
efx_intr_t en_intr;
@ -342,9 +604,17 @@ struct efx_nic_s {
uint32_t en_rx_qcount;
uint32_t en_tx_qcount;
efx_nic_ops_t *en_enop;
efx_ev_ops_t *en_eevop;
efx_tx_ops_t *en_etxop;
efx_rx_ops_t *en_erxop;
#if EFSYS_OPT_FILTER
efx_filter_t en_filter;
efx_filter_ops_t *en_efop;
#endif /* EFSYS_OPT_FILTER */
efx_pktfilter_ops_t *en_epfop;
#if EFSYS_OPT_MCDI
efx_mcdi_t en_mcdi;
#endif /* EFSYS_OPT_MCDI */
#if EFSYS_OPT_NVRAM
efx_nvram_type_t en_nvram_locked;
efx_nvram_ops_t *en_envop;
@ -352,6 +622,12 @@ struct efx_nic_s {
#if EFSYS_OPT_VPD
efx_vpd_ops_t *en_evpdop;
#endif /* EFSYS_OPT_VPD */
#if EFSYS_OPT_RX_SCALE
efx_rx_hash_support_t en_hash_support;
efx_rx_scale_support_t en_rss_support;
uint32_t en_rss_context;
#endif /* EFSYS_OPT_RX_SCALE */
uint32_t en_vport_id;
union {
#if EFSYS_OPT_FALCON
struct {
@ -373,9 +649,6 @@ struct efx_nic_s {
#endif /* EFSYS_OPT_FALCON */
#if EFSYS_OPT_SIENA
struct {
#if EFSYS_OPT_MCDI
efx_mcdi_iface_t enu_mip;
#endif /* EFSYS_OPT_MCDI */
#if EFSYS_OPT_NVRAM || EFSYS_OPT_VPD
unsigned int enu_partn_mask;
#endif /* EFSYS_OPT_NVRAM || EFSYS_OPT_VPD */
@ -383,8 +656,28 @@ struct efx_nic_s {
caddr_t enu_svpd;
size_t enu_svpd_length;
#endif /* EFSYS_OPT_VPD */
int enu_unused;
} siena;
#endif /* EFSYS_OPT_SIENA */
#if EFSYS_OPT_HUNTINGTON
struct {
int enu_vi_base;
int enu_vi_count;
#if EFSYS_OPT_VPD
caddr_t enu_svpd;
size_t enu_svpd_length;
#endif /* EFSYS_OPT_VPD */
efx_piobuf_handle_t enu_piobuf_handle[HUNT_PIOBUF_NBUFS];
uint32_t enu_piobuf_count;
uint32_t enu_pio_alloc_map[HUNT_PIOBUF_NBUFS];
uint32_t enu_pio_write_vi_base;
/* Memory BAR mapping regions */
uint32_t enu_uc_mem_map_offset;
size_t enu_uc_mem_map_size;
uint32_t enu_wc_mem_map_offset;
size_t enu_wc_mem_map_size;
} hunt;
#endif /* EFSYS_OPT_HUNTINGTON */
} en_u;
};
@ -394,6 +687,11 @@ struct efx_nic_s {
typedef boolean_t (*efx_ev_handler_t)(efx_evq_t *, efx_qword_t *,
const efx_ev_callbacks_t *, void *);
typedef struct efx_evq_rxq_state_s {
unsigned int eers_rx_read_ptr;
unsigned int eers_rx_mask;
} efx_evq_rxq_state_t;
struct efx_evq_s {
uint32_t ee_magic;
efx_nic_t *ee_enp;
@ -403,7 +701,17 @@ struct efx_evq_s {
#if EFSYS_OPT_QSTATS
uint32_t ee_stat[EV_NQSTATS];
#endif /* EFSYS_OPT_QSTATS */
efx_ev_handler_t ee_handler[1 << FSF_AZ_EV_CODE_WIDTH];
efx_ev_handler_t ee_rx;
efx_ev_handler_t ee_tx;
efx_ev_handler_t ee_driver;
efx_ev_handler_t ee_global;
efx_ev_handler_t ee_drv_gen;
#if EFSYS_OPT_MCDI
efx_ev_handler_t ee_mcdi;
#endif /* EFSYS_OPT_MCDI */
efx_evq_rxq_state_t ee_rxq_state[EFX_EV_RX_NLABELS];
};
#define EFX_EVQ_MAGIC 0x08081997
@ -414,7 +722,9 @@ struct efx_evq_s {
struct efx_rxq_s {
uint32_t er_magic;
efx_nic_t *er_enp;
efx_evq_t *er_eep;
unsigned int er_index;
unsigned int er_label;
unsigned int er_mask;
efsys_mem_t *er_esmp;
};
@ -427,6 +737,13 @@ struct efx_txq_s {
unsigned int et_index;
unsigned int et_mask;
efsys_mem_t *et_esmp;
#if EFSYS_OPT_HUNTINGTON
uint32_t et_pio_bufnum;
uint32_t et_pio_blknum;
uint32_t et_pio_write_offset;
uint32_t et_pio_offset;
size_t et_pio_size;
#endif
#if EFSYS_OPT_QSTATS
uint32_t et_stat[TX_NQSTATS];
#endif /* EFSYS_OPT_QSTATS */
@ -445,10 +762,19 @@ struct efx_txq_s {
_NOTE(CONSTANTCONDITION) \
} while (B_FALSE)
#define EFX_MAC_BROADCAST_ADDR_SET(_dst) \
do { \
uint16_t *_d = (uint16_t *)(_dst); \
_d[0] = 0xffff; \
_d[1] = 0xffff; \
_d[2] = 0xffff; \
_NOTE(CONSTANTCONDITION) \
} while (B_FALSE)
#if EFSYS_OPT_CHECK_REG
#define EFX_CHECK_REG(_enp, _reg) \
do { \
const char __cs *name = #_reg; \
const char *name = #_reg; \
char min = name[4]; \
char max = name[5]; \
char rev; \
@ -462,6 +788,10 @@ struct efx_txq_s {
rev = 'C'; \
break; \
\
case EFX_FAMILY_HUNTINGTON: \
rev = 'D'; \
break; \
\
default: \
rev = '?'; \
break; \
@ -578,6 +908,21 @@ struct efx_txq_s {
_NOTE(CONSTANTCONDITION) \
} while (B_FALSE)
#define EFX_BAR_TBL_WRITED2(_enp, _reg, _index, _edp, _lock) \
do { \
EFX_CHECK_REG((_enp), (_reg)); \
EFSYS_PROBE4(efx_bar_tbl_writed, const char *, #_reg, \
uint32_t, (_index), \
uint32_t, _reg ## _OFST, \
uint32_t, (_edp)->ed_u32[0]); \
EFSYS_BAR_WRITED((_enp)->en_esbp, \
(_reg ## _OFST + \
(2 * sizeof (efx_dword_t)) + \
((_index) * _reg ## _STEP)), \
(_edp), (_lock)); \
_NOTE(CONSTANTCONDITION) \
} while (B_FALSE)
#define EFX_BAR_TBL_WRITED3(_enp, _reg, _index, _edp, _lock) \
do { \
EFX_CHECK_REG((_enp), (_reg)); \
@ -621,12 +966,12 @@ struct efx_txq_s {
_NOTE(CONSTANTCONDITION) \
} while (B_FALSE)
#define EFX_BAR_TBL_READO(_enp, _reg, _index, _eop) \
#define EFX_BAR_TBL_READO(_enp, _reg, _index, _eop, _lock) \
do { \
EFX_CHECK_REG((_enp), (_reg)); \
EFSYS_BAR_READO((_enp)->en_esbp, \
(_reg ## _OFST + ((_index) * _reg ## _STEP)), \
(_eop), B_TRUE); \
(_eop), (_lock)); \
EFSYS_PROBE7(efx_bar_tbl_reado, const char *, #_reg, \
uint32_t, (_index), \
uint32_t, _reg ## _OFST, \
@ -637,7 +982,7 @@ struct efx_txq_s {
_NOTE(CONSTANTCONDITION) \
} while (B_FALSE)
#define EFX_BAR_TBL_WRITEO(_enp, _reg, _index, _eop) \
#define EFX_BAR_TBL_WRITEO(_enp, _reg, _index, _eop, _lock) \
do { \
EFX_CHECK_REG((_enp), (_reg)); \
EFSYS_PROBE7(efx_bar_tbl_writeo, const char *, #_reg, \
@ -649,14 +994,71 @@ struct efx_txq_s {
uint32_t, (_eop)->eo_u32[0]); \
EFSYS_BAR_WRITEO((_enp)->en_esbp, \
(_reg ## _OFST + ((_index) * _reg ## _STEP)), \
(_eop), B_TRUE); \
(_eop), (_lock)); \
_NOTE(CONSTANTCONDITION) \
} while (B_FALSE)
/*
* Allow drivers to perform optimised 128-bit doorbell writes.
* The DMA descriptor pointers (RX_DESC_UPD and TX_DESC_UPD) are
* special-cased in the BIU on the Falcon/Siena and EF10 architectures to avoid
* the need for locking in the host, and are the only ones known to be safe to
* use 128-bites write with.
*/
#define EFX_BAR_TBL_DOORBELL_WRITEO(_enp, _reg, _index, _eop) \
do { \
EFX_CHECK_REG((_enp), (_reg)); \
EFSYS_PROBE7(efx_bar_tbl_doorbell_writeo, \
const char *, \
#_reg, \
uint32_t, (_index), \
uint32_t, _reg ## _OFST, \
uint32_t, (_eop)->eo_u32[3], \
uint32_t, (_eop)->eo_u32[2], \
uint32_t, (_eop)->eo_u32[1], \
uint32_t, (_eop)->eo_u32[0]); \
EFSYS_BAR_DOORBELL_WRITEO((_enp)->en_esbp, \
(_reg ## _OFST + ((_index) * _reg ## _STEP)), \
(_eop)); \
_NOTE(CONSTANTCONDITION) \
} while (B_FALSE)
#define EFX_DMA_SYNC_QUEUE_FOR_DEVICE(_esmp, _entries, _wptr, _owptr) \
do { \
unsigned int _new = (_wptr); \
unsigned int _old = (_owptr); \
\
if ((_new) >= (_old)) \
EFSYS_DMA_SYNC_FOR_DEVICE((_esmp), \
(_old) * sizeof (efx_desc_t), \
((_new) - (_old)) * sizeof (efx_desc_t)); \
else \
/* \
* It is cheaper to sync entire map than sync \
* two parts especially when offset/size are \
* ignored and entire map is synced in any case.\
*/ \
EFSYS_DMA_SYNC_FOR_DEVICE((_esmp), \
0, \
(_entries) * sizeof (efx_desc_t)); \
_NOTE(CONSTANTCONDITION) \
} while (B_FALSE)
extern __checkReturn int
efx_nic_biu_test(
__in efx_nic_t *enp);
extern __checkReturn int
efx_mac_select(
__in efx_nic_t *enp);
extern void
efx_mac_multicast_hash_compute(
__in_ecount(6*count) uint8_t const *addrs,
__in int count,
__out efx_oword_t *hash_low,
__out efx_oword_t *hash_high);
extern __checkReturn int
efx_phy_probe(
__in efx_nic_t *enp);
@ -683,7 +1085,7 @@ efx_vpd_hunk_verify(
extern __checkReturn int
efx_vpd_hunk_reinit(
__in caddr_t data,
__in_bcount(size) caddr_t data,
__in size_t size,
__in boolean_t wantpid);
@ -716,7 +1118,7 @@ efx_vpd_hunk_set(
#if EFSYS_OPT_DIAG
extern efx_sram_pattern_fn_t __cs __efx_sram_pattern_fns[];
extern efx_sram_pattern_fn_t __efx_sram_pattern_fns[];
typedef struct efx_register_set_s {
unsigned int address;
@ -740,6 +1142,23 @@ efx_nic_test_tables(
#endif /* EFSYS_OPT_DIAG */
#if EFSYS_OPT_MCDI
extern __checkReturn int
efx_mcdi_set_workaround(
__in efx_nic_t *enp,
__in uint32_t type,
__in boolean_t enabled,
__out_opt uint32_t *flagsp);
extern __checkReturn int
efx_mcdi_get_workarounds(
__in efx_nic_t *enp,
__out_opt uint32_t *implementedp,
__out_opt uint32_t *enabledp);
#endif /* EFSYS_OPT_MCDI */
#ifdef __cplusplus
}
#endif

View File

@ -1,26 +1,31 @@
/*-
* Copyright 2007-2009 Solarflare Communications Inc. All rights reserved.
* Copyright (c) 2007-2015 Solarflare Communications Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* modification, are permitted provided that the following conditions are met:
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the FreeBSD Project.
*/
#include <sys/cdefs.h>
@ -32,6 +37,82 @@ __FBSDID("$FreeBSD$");
#include "efx_regs.h"
#include "efx_impl.h"
#if EFSYS_OPT_FALCON || EFSYS_OPT_SIENA
static __checkReturn int
falconsiena_intr_init(
__in efx_nic_t *enp,
__in efx_intr_type_t type,
__in efsys_mem_t *esmp);
static void
falconsiena_intr_enable(
__in efx_nic_t *enp);
static void
falconsiena_intr_disable(
__in efx_nic_t *enp);
static void
falconsiena_intr_disable_unlocked(
__in efx_nic_t *enp);
static __checkReturn int
falconsiena_intr_trigger(
__in efx_nic_t *enp,
__in unsigned int level);
static void
falconsiena_intr_fini(
__in efx_nic_t *enp);
static __checkReturn boolean_t
falconsiena_intr_check_fatal(
__in efx_nic_t *enp);
static void
falconsiena_intr_fatal(
__in efx_nic_t *enp);
#endif /* EFSYS_OPT_FALCON || EFSYS_OPT_SIENA */
#if EFSYS_OPT_FALCON
static efx_intr_ops_t __efx_intr_falcon_ops = {
falconsiena_intr_init, /* eio_init */
falconsiena_intr_enable, /* eio_enable */
falconsiena_intr_disable, /* eio_disable */
falconsiena_intr_disable_unlocked, /* eio_disable_unlocked */
falconsiena_intr_trigger, /* eio_trigger */
falconsiena_intr_fini, /* eio_fini */
};
#endif /* EFSYS_OPT_FALCON */
#if EFSYS_OPT_SIENA
static efx_intr_ops_t __efx_intr_siena_ops = {
falconsiena_intr_init, /* eio_init */
falconsiena_intr_enable, /* eio_enable */
falconsiena_intr_disable, /* eio_disable */
falconsiena_intr_disable_unlocked, /* eio_disable_unlocked */
falconsiena_intr_trigger, /* eio_trigger */
falconsiena_intr_fini, /* eio_fini */
};
#endif /* EFSYS_OPT_SIENA */
#if EFSYS_OPT_HUNTINGTON
static efx_intr_ops_t __efx_intr_hunt_ops = {
hunt_intr_init, /* eio_init */
hunt_intr_enable, /* eio_enable */
hunt_intr_disable, /* eio_disable */
hunt_intr_disable_unlocked, /* eio_disable_unlocked */
hunt_intr_trigger, /* eio_trigger */
hunt_intr_fini, /* eio_fini */
};
#endif /* EFSYS_OPT_HUNTINGTON */
__checkReturn int
efx_intr_init(
__in efx_nic_t *enp,
@ -39,7 +120,7 @@ efx_intr_init(
__in efsys_mem_t *esmp)
{
efx_intr_t *eip = &(enp->en_intr);
efx_oword_t oword;
efx_intr_ops_t *eiop;
int rc;
EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
@ -50,10 +131,219 @@ efx_intr_init(
goto fail1;
}
eip->ei_esmp = esmp;
eip->ei_type = type;
eip->ei_level = 0;
enp->en_mod_flags |= EFX_MOD_INTR;
eip->ei_type = type;
eip->ei_esmp = esmp;
switch (enp->en_family) {
#if EFSYS_OPT_FALCON
case EFX_FAMILY_FALCON:
eiop = (efx_intr_ops_t *)&__efx_intr_falcon_ops;
break;
#endif /* EFSYS_OPT_FALCON */
#if EFSYS_OPT_SIENA
case EFX_FAMILY_SIENA:
eiop = (efx_intr_ops_t *)&__efx_intr_siena_ops;
break;
#endif /* EFSYS_OPT_SIENA */
#if EFSYS_OPT_HUNTINGTON
case EFX_FAMILY_HUNTINGTON:
eiop = (efx_intr_ops_t *)&__efx_intr_hunt_ops;
break;
#endif /* EFSYS_OPT_HUNTINGTON */
default:
EFSYS_ASSERT(B_FALSE);
rc = ENOTSUP;
goto fail2;
}
if ((rc = eiop->eio_init(enp, type, esmp)) != 0)
goto fail3;
eip->ei_eiop = eiop;
return (0);
fail3:
EFSYS_PROBE(fail3);
fail2:
EFSYS_PROBE(fail2);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
void
efx_intr_fini(
__in efx_nic_t *enp)
{
efx_intr_t *eip = &(enp->en_intr);
efx_intr_ops_t *eiop = eip->ei_eiop;
EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC);
EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
eiop->eio_fini(enp);
enp->en_mod_flags &= ~EFX_MOD_INTR;
}
void
efx_intr_enable(
__in efx_nic_t *enp)
{
efx_intr_t *eip = &(enp->en_intr);
efx_intr_ops_t *eiop = eip->ei_eiop;
EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
eiop->eio_enable(enp);
}
void
efx_intr_disable(
__in efx_nic_t *enp)
{
efx_intr_t *eip = &(enp->en_intr);
efx_intr_ops_t *eiop = eip->ei_eiop;
EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
eiop->eio_disable(enp);
}
void
efx_intr_disable_unlocked(
__in efx_nic_t *enp)
{
efx_intr_t *eip = &(enp->en_intr);
efx_intr_ops_t *eiop = eip->ei_eiop;
EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
eiop->eio_disable_unlocked(enp);
}
__checkReturn int
efx_intr_trigger(
__in efx_nic_t *enp,
__in unsigned int level)
{
efx_intr_t *eip = &(enp->en_intr);
efx_intr_ops_t *eiop = eip->ei_eiop;
EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
return (eiop->eio_trigger(enp, level));
}
void
efx_intr_status_line(
__in efx_nic_t *enp,
__out boolean_t *fatalp,
__out uint32_t *qmaskp)
{
efx_intr_t *eip = &(enp->en_intr);
efx_dword_t dword;
EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
/* Ensure Huntington and Falcon/Siena ISR at same location */
EFX_STATIC_ASSERT(FR_BZ_INT_ISR0_REG_OFST ==
ER_DZ_BIU_INT_ISR_REG_OFST);
/*
* Read the queue mask and implicitly acknowledge the
* interrupt.
*/
EFX_BAR_READD(enp, FR_BZ_INT_ISR0_REG, &dword, B_FALSE);
*qmaskp = EFX_DWORD_FIELD(dword, EFX_DWORD_0);
EFSYS_PROBE1(qmask, uint32_t, *qmaskp);
#if EFSYS_OPT_HUNTINGTON
if (enp->en_family == EFX_FAMILY_HUNTINGTON) {
/* Huntington reports fatal errors via events */
*fatalp = B_FALSE;
return;
}
#endif
if (*qmaskp & (1U << eip->ei_level))
*fatalp = falconsiena_intr_check_fatal(enp);
else
*fatalp = B_FALSE;
}
void
efx_intr_status_message(
__in efx_nic_t *enp,
__in unsigned int message,
__out boolean_t *fatalp)
{
efx_intr_t *eip = &(enp->en_intr);
EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
#if EFSYS_OPT_HUNTINGTON
if (enp->en_family == EFX_FAMILY_HUNTINGTON) {
/* Huntington reports fatal errors via events */
*fatalp = B_FALSE;
return;
}
#endif
if (message == eip->ei_level)
*fatalp = falconsiena_intr_check_fatal(enp);
else
*fatalp = B_FALSE;
}
void
efx_intr_fatal(
__in efx_nic_t *enp)
{
EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
#if EFSYS_OPT_HUNTINGTON
if (enp->en_family == EFX_FAMILY_HUNTINGTON) {
/* Huntington reports fatal errors via events */
return;
}
#endif
#if EFSYS_OPT_FALCON || EFSYS_OPT_SIENA
falconsiena_intr_fatal(enp);
#endif
}
/* ************************************************************************* */
/* ************************************************************************* */
/* ************************************************************************* */
#if EFSYS_OPT_FALCON || EFSYS_OPT_SIENA
static __checkReturn int
falconsiena_intr_init(
__in efx_nic_t *enp,
__in efx_intr_type_t type,
__in efsys_mem_t *esmp)
{
efx_intr_t *eip = &(enp->en_intr);
efx_oword_t oword;
/*
* bug17213 workaround.
@ -85,23 +375,15 @@ efx_intr_init(
EFX_BAR_WRITEO(enp, FR_AZ_INT_ADR_REG_KER, &oword);
return (0);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
void
efx_intr_enable(
static void
falconsiena_intr_enable(
__in efx_nic_t *enp)
{
efx_intr_t *eip = &(enp->en_intr);
efx_oword_t oword;
EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
EFX_BAR_READO(enp, FR_AZ_INT_EN_REG_KER, &oword);
EFX_SET_OWORD_FIELD(oword, FRF_AZ_KER_INT_LEVE_SEL, eip->ei_level);
@ -109,15 +391,12 @@ efx_intr_enable(
EFX_BAR_WRITEO(enp, FR_AZ_INT_EN_REG_KER, &oword);
}
void
efx_intr_disable(
static void
falconsiena_intr_disable(
__in efx_nic_t *enp)
{
efx_oword_t oword;
EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
EFX_BAR_READO(enp, FR_AZ_INT_EN_REG_KER, &oword);
EFX_SET_OWORD_FIELD(oword, FRF_AZ_DRV_INT_EN_KER, 0);
EFX_BAR_WRITEO(enp, FR_AZ_INT_EN_REG_KER, &oword);
@ -125,15 +404,12 @@ efx_intr_disable(
EFSYS_SPIN(10);
}
void
efx_intr_disable_unlocked(
static void
falconsiena_intr_disable_unlocked(
__in efx_nic_t *enp)
{
efx_oword_t oword;
EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
EFSYS_BAR_READO(enp->en_esbp, FR_AZ_INT_EN_REG_KER_OFST,
&oword, B_FALSE);
EFX_SET_OWORD_FIELD(oword, FRF_AZ_DRV_INT_EN_KER, 0);
@ -141,8 +417,8 @@ efx_intr_disable_unlocked(
&oword, B_FALSE);
}
__checkReturn int
efx_intr_trigger(
static __checkReturn int
falconsiena_intr_trigger(
__in efx_nic_t *enp,
__in unsigned int level)
{
@ -152,22 +428,19 @@ efx_intr_trigger(
uint32_t sel;
int rc;
EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
/* bug16757: No event queues can be initialized */
EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_EV));
switch (enp->en_family) {
case EFX_FAMILY_FALCON:
if (level > EFX_NINTR_FALCON) {
if (level >= EFX_NINTR_FALCON) {
rc = EINVAL;
goto fail1;
}
break;
case EFX_FAMILY_SIENA:
if (level > EFX_NINTR_SIENA) {
if (level >= EFX_NINTR_SIENA) {
rc = EINVAL;
goto fail1;
}
@ -213,7 +486,7 @@ efx_intr_trigger(
}
static __checkReturn boolean_t
efx_intr_check_fatal(
falconsiena_intr_check_fatal(
__in efx_nic_t *enp)
{
efx_intr_t *eip = &(enp->en_intr);
@ -236,61 +509,14 @@ efx_intr_check_fatal(
return (B_FALSE);
}
void
efx_intr_status_line(
__in efx_nic_t *enp,
__out boolean_t *fatalp,
__out uint32_t *qmaskp)
{
efx_intr_t *eip = &(enp->en_intr);
efx_dword_t dword;
EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
/*
* Read the queue mask and implicitly acknowledge the
* interrupt.
*/
EFX_BAR_READD(enp, FR_BZ_INT_ISR0_REG, &dword, B_FALSE);
*qmaskp = EFX_DWORD_FIELD(dword, EFX_DWORD_0);
EFSYS_PROBE1(qmask, uint32_t, *qmaskp);
if (*qmaskp & (1U << eip->ei_level))
*fatalp = efx_intr_check_fatal(enp);
else
*fatalp = B_FALSE;
}
void
efx_intr_status_message(
__in efx_nic_t *enp,
__in unsigned int message,
__out boolean_t *fatalp)
{
efx_intr_t *eip = &(enp->en_intr);
EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
if (message == eip->ei_level)
*fatalp = efx_intr_check_fatal(enp);
else
*fatalp = B_FALSE;
}
void
efx_intr_fatal(
static void
falconsiena_intr_fatal(
__in efx_nic_t *enp)
{
#if EFSYS_OPT_DECODE_INTR_FATAL
efx_oword_t fatal;
efx_oword_t mem_per;
EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
EFX_BAR_READO(enp, FR_AZ_FATAL_INTR_REG_KER, &fatal);
EFX_ZERO_OWORD(mem_per);
@ -339,19 +565,15 @@ efx_intr_fatal(
#endif
}
void
efx_intr_fini(
static void
falconsiena_intr_fini(
__in efx_nic_t *enp)
{
efx_oword_t oword;
EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC);
EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
/* Clear the interrupt address register */
EFX_ZERO_OWORD(oword);
EFX_BAR_WRITEO(enp, FR_AZ_INT_ADR_REG_KER, &oword);
enp->en_mod_flags &= ~EFX_MOD_INTR;
}
#endif /* EFSYS_OPT_FALCON || EFSYS_OPT_SIENA */

View File

@ -1,26 +1,31 @@
/*-
* Copyright 2007-2009 Solarflare Communications Inc. All rights reserved.
* Copyright (c) 2007-2015 Solarflare Communications Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* modification, are permitted provided that the following conditions are met:
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the FreeBSD Project.
*/
#include <sys/cdefs.h>
@ -39,74 +44,126 @@ __FBSDID("$FreeBSD$");
#include "falcon_xmac.h"
#endif
#if EFSYS_OPT_FALCON || EFSYS_OPT_SIENA
static __checkReturn int
falconsiena_mac_multicast_list_set(
__in efx_nic_t *enp);
#endif /* EFSYS_OPT_FALCON || EFSYS_OPT_SIENA */
#if EFSYS_OPT_MAC_FALCON_GMAC
static efx_mac_ops_t __cs __efx_falcon_gmac_ops = {
falcon_gmac_reset, /* emo_reset */
falcon_mac_poll, /* emo_poll */
falcon_mac_up, /* emo_up */
falcon_gmac_reconfigure, /* emo_reconfigure */
static efx_mac_ops_t __efx_falcon_gmac_ops = {
falcon_gmac_reset, /* emo_reset */
falcon_mac_poll, /* emo_poll */
falcon_mac_up, /* emo_up */
falcon_gmac_reconfigure, /* emo_addr_set */
falcon_gmac_reconfigure, /* emo_reconfigure */
falconsiena_mac_multicast_list_set, /* emo_multicast_list_set */
NULL, /* emo_filter_set_default_rxq */
NULL, /* emo_filter_default_rxq_clear */
#if EFSYS_OPT_LOOPBACK
falcon_mac_loopback_set, /* emo_loopback_set */
falcon_mac_loopback_set, /* emo_loopback_set */
#endif /* EFSYS_OPT_LOOPBACK */
#if EFSYS_OPT_MAC_STATS
falcon_mac_stats_upload, /* emo_stats_upload */
NULL, /* emo_stats_periodic */
falcon_gmac_stats_update /* emo_stats_update */
falcon_mac_stats_upload, /* emo_stats_upload */
NULL, /* emo_stats_periodic */
falcon_gmac_stats_update /* emo_stats_update */
#endif /* EFSYS_OPT_MAC_STATS */
};
#endif /* EFSYS_OPT_MAC_FALCON_GMAC */
#if EFSYS_OPT_MAC_FALCON_XMAC
static efx_mac_ops_t __cs __efx_falcon_xmac_ops = {
falcon_xmac_reset, /* emo_reset */
falcon_mac_poll, /* emo_poll */
falcon_mac_up, /* emo_up */
falcon_xmac_reconfigure, /* emo_reconfigure */
static efx_mac_ops_t __efx_falcon_xmac_ops = {
falcon_xmac_reset, /* emo_reset */
falcon_mac_poll, /* emo_poll */
falcon_mac_up, /* emo_up */
falcon_xmac_reconfigure, /* emo_addr_set */
falcon_xmac_reconfigure, /* emo_reconfigure */
falconsiena_mac_multicast_list_set, /* emo_multicast_list_set */
NULL, /* emo_filter_set_default_rxq */
NULL, /* emo_filter_default_rxq_clear */
#if EFSYS_OPT_LOOPBACK
falcon_mac_loopback_set, /* emo_loopback_set */
falcon_mac_loopback_set, /* emo_loopback_set */
#endif /* EFSYS_OPT_LOOPBACK */
#if EFSYS_OPT_MAC_STATS
falcon_mac_stats_upload, /* emo_stats_upload */
NULL, /* emo_stats_periodic */
falcon_xmac_stats_update /* emo_stats_update */
falcon_mac_stats_upload, /* emo_stats_upload */
NULL, /* emo_stats_periodic */
falcon_xmac_stats_update /* emo_stats_update */
#endif /* EFSYS_OPT_MAC_STATS */
};
#endif /* EFSYS_OPT_MAC_FALCON_XMAC */
#if EFSYS_OPT_SIENA
static efx_mac_ops_t __cs __efx_siena_mac_ops = {
NULL, /* emo_reset */
siena_mac_poll, /* emo_poll */
siena_mac_up, /* emo_up */
siena_mac_reconfigure, /* emo_reconfigure */
static efx_mac_ops_t __efx_siena_mac_ops = {
NULL, /* emo_reset */
siena_mac_poll, /* emo_poll */
siena_mac_up, /* emo_up */
siena_mac_reconfigure, /* emo_addr_set */
siena_mac_reconfigure, /* emo_reconfigure */
falconsiena_mac_multicast_list_set, /* emo_multicast_list_set */
NULL, /* emo_filter_set_default_rxq */
NULL, /* emo_filter_default_rxq_clear */
#if EFSYS_OPT_LOOPBACK
siena_mac_loopback_set, /* emo_loopback_set */
siena_mac_loopback_set, /* emo_loopback_set */
#endif /* EFSYS_OPT_LOOPBACK */
#if EFSYS_OPT_MAC_STATS
siena_mac_stats_upload, /* emo_stats_upload */
siena_mac_stats_periodic, /* emo_stats_periodic */
siena_mac_stats_update /* emo_stats_update */
efx_mcdi_mac_stats_upload, /* emo_stats_upload */
efx_mcdi_mac_stats_periodic, /* emo_stats_periodic */
siena_mac_stats_update /* emo_stats_update */
#endif /* EFSYS_OPT_MAC_STATS */
};
#endif /* EFSYS_OPT_SIENA */
static efx_mac_ops_t __cs * __cs __efx_mac_ops[] = {
#if EFSYS_OPT_HUNTINGTON
static efx_mac_ops_t __efx_hunt_mac_ops = {
NULL, /* emo_reset */
hunt_mac_poll, /* emo_poll */
hunt_mac_up, /* emo_up */
hunt_mac_addr_set, /* emo_addr_set */
hunt_mac_reconfigure, /* emo_reconfigure */
hunt_mac_multicast_list_set, /* emo_multicast_list_set */
hunt_mac_filter_default_rxq_set, /* emo_filter_default_rxq_set */
hunt_mac_filter_default_rxq_clear,
/* emo_filter_default_rxq_clear */
#if EFSYS_OPT_LOOPBACK
hunt_mac_loopback_set, /* emo_loopback_set */
#endif /* EFSYS_OPT_LOOPBACK */
#if EFSYS_OPT_MAC_STATS
efx_mcdi_mac_stats_upload, /* emo_stats_upload */
efx_mcdi_mac_stats_periodic, /* emo_stats_periodic */
hunt_mac_stats_update /* emo_stats_update */
#endif /* EFSYS_OPT_MAC_STATS */
};
#endif /* EFSYS_OPT_HUNTINGTON */
static efx_mac_ops_t *__efx_mac_ops[] = {
/* [EFX_MAC_INVALID] */
NULL,
/* [EFX_MAC_FALCON_GMAC] */
#if EFSYS_OPT_MAC_FALCON_GMAC
&__efx_falcon_gmac_ops,
#else
NULL,
#endif /* EFSYS_OPT_MAC_FALCON_GMAC */
#endif
/* [EFX_MAC_FALCON_XMAC] */
#if EFSYS_OPT_MAC_FALCON_XMAC
&__efx_falcon_xmac_ops,
#else
NULL,
#endif /* EFSYS_OPT_MAC_FALCON_XMAC */
#endif
/* [EFX_MAC_SIENA] */
#if EFSYS_OPT_SIENA
&__efx_siena_mac_ops,
#else
NULL,
#endif /* EFSYS_OPT_SIENA */
#endif
/* [EFX_MAC_HUNTINGTON] */
#if EFSYS_OPT_HUNTINGTON
&__efx_hunt_mac_ops,
#else
NULL,
#endif
};
__checkReturn int
@ -167,7 +224,7 @@ efx_mac_addr_set(
EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
if (addr[0] & 0x01) {
if (EFX_MAC_ADDR_IS_MULTICAST(addr)) {
rc = EINVAL;
goto fail1;
}
@ -180,7 +237,7 @@ efx_mac_addr_set(
EFX_MAC_ADDR_COPY(old_addr, epp->ep_mac_addr);
EFX_MAC_ADDR_COPY(epp->ep_mac_addr, addr);
if ((rc = emop->emo_reconfigure(enp)) != 0)
if ((rc = emop->emo_addr_set(enp)) != 0)
goto fail3;
return (0);
@ -201,22 +258,30 @@ efx_mac_addr_set(
__checkReturn int
efx_mac_filter_set(
__in efx_nic_t *enp,
__in boolean_t unicst,
__in boolean_t all_unicst,
__in boolean_t mulcst,
__in boolean_t all_mulcst,
__in boolean_t brdcst)
{
efx_port_t *epp = &(enp->en_port);
efx_mac_ops_t *emop = epp->ep_emop;
boolean_t old_unicst;
boolean_t old_all_unicst;
boolean_t old_mulcst;
boolean_t old_all_mulcst;
boolean_t old_brdcst;
int rc;
EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
old_unicst = unicst;
old_brdcst = brdcst;
old_all_unicst = epp->ep_all_unicst;
old_mulcst = epp->ep_mulcst;
old_all_mulcst = epp->ep_all_mulcst;
old_brdcst = epp->ep_brdcst;
epp->ep_unicst = unicst;
epp->ep_all_unicst = all_unicst;
epp->ep_mulcst = mulcst;
epp->ep_all_mulcst = all_mulcst;
epp->ep_brdcst = brdcst;
if ((rc = emop->emo_reconfigure(enp)) != 0)
@ -227,7 +292,9 @@ efx_mac_filter_set(
fail1:
EFSYS_PROBE1(fail1, int, rc);
epp->ep_unicst = old_unicst;
epp->ep_all_unicst = old_all_unicst;
epp->ep_mulcst = old_mulcst;
epp->ep_all_mulcst = old_all_mulcst;
epp->ep_brdcst = old_brdcst;
return (rc);
@ -318,45 +385,45 @@ efx_mac_fcntl_set(
}
/*
* Ignore a request to set flow control autonegotiation
* Ignore a request to set flow control auto-negotiation
* if the PHY doesn't support it.
*/
if (~epp->ep_phy_cap_mask & (1 << EFX_PHY_CAP_AN))
autoneg = B_FALSE;
old_fcntl = epp->ep_fcntl;
old_autoneg = autoneg;
old_autoneg = epp->ep_fcntl_autoneg;
old_adv_cap = epp->ep_adv_cap_mask;
epp->ep_fcntl = fcntl;
epp->ep_fcntl_autoneg = autoneg;
/*
* If the PHY supports autonegotiation, then encode the flow control
* settings in the advertised capabilities, and restart AN. Otherwise,
* just push the new settings directly to the MAC.
* Always encode the flow control settings in the advertised
* capabilities even if we are not trying to auto-negotiate
* them and reconfigure both the PHY and the MAC.
*/
if (epp->ep_phy_cap_mask & (1 << EFX_PHY_CAP_AN)) {
if (fcntl & EFX_FCNTL_RESPOND)
epp->ep_adv_cap_mask |= (1 << EFX_PHY_CAP_PAUSE |
1 << EFX_PHY_CAP_ASYM);
else
epp->ep_adv_cap_mask &= ~(1 << EFX_PHY_CAP_PAUSE |
1 << EFX_PHY_CAP_ASYM);
if (fcntl & EFX_FCNTL_RESPOND)
epp->ep_adv_cap_mask |= (1 << EFX_PHY_CAP_PAUSE |
1 << EFX_PHY_CAP_ASYM);
else
epp->ep_adv_cap_mask &= ~(1 << EFX_PHY_CAP_PAUSE |
1 << EFX_PHY_CAP_ASYM);
if (fcntl & EFX_FCNTL_GENERATE)
epp->ep_adv_cap_mask ^= (1 << EFX_PHY_CAP_ASYM);
if (fcntl & EFX_FCNTL_GENERATE)
epp->ep_adv_cap_mask ^= (1 << EFX_PHY_CAP_ASYM);
if ((rc = epop->epo_reconfigure(enp)) != 0)
goto fail2;
if ((rc = epop->epo_reconfigure(enp)) != 0)
goto fail2;
} else {
if ((rc = emop->emo_reconfigure(enp)) != 0)
goto fail2;
}
if ((rc = emop->emo_reconfigure(enp)) != 0)
goto fail3;
return (0);
fail3:
EFSYS_PROBE(fail3);
fail2:
EFSYS_PROBE(fail2);
@ -377,29 +444,30 @@ efx_mac_fcntl_get(
__out unsigned int *fcntl_linkp)
{
efx_port_t *epp = &(enp->en_port);
unsigned int wanted;
unsigned int wanted = 0;
EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
/*
* If the PHY supports auto negotiation, then the requested flow
* control settings are encoded in the advertised capabilities.
* Decode the requested flow control settings from the PHY
* advertised capabilities.
*/
if (epp->ep_phy_cap_mask & (1 << EFX_PHY_CAP_AN)) {
wanted = 0;
if (epp->ep_adv_cap_mask & (1 << EFX_PHY_CAP_PAUSE))
wanted = EFX_FCNTL_RESPOND | EFX_FCNTL_GENERATE;
if (epp->ep_adv_cap_mask & (1 << EFX_PHY_CAP_ASYM))
wanted ^= EFX_FCNTL_GENERATE;
} else
wanted = epp->ep_fcntl;
if (epp->ep_adv_cap_mask & (1 << EFX_PHY_CAP_PAUSE))
wanted = EFX_FCNTL_RESPOND | EFX_FCNTL_GENERATE;
if (epp->ep_adv_cap_mask & (1 << EFX_PHY_CAP_ASYM))
wanted ^= EFX_FCNTL_GENERATE;
*fcntl_linkp = epp->ep_fcntl;
*fcntl_wantedp = wanted;
}
/*
* FIXME: efx_mac_hash_set() should be deleted once all its callers have been
* updated to use efx_mac_multicast_list_set().
* Then efx_port_t.ep_multicst_hash could be made Falcon/Siena specific as
* well.
*/
__checkReturn int
efx_mac_hash_set(
__in efx_nic_t *enp,
@ -443,12 +511,130 @@ efx_mac_hash_set(
return (rc);
}
__checkReturn int
efx_mac_multicast_list_set(
__in efx_nic_t *enp,
__in_ecount(6*count) uint8_t const *addrs,
__in int count)
{
efx_port_t *epp = &(enp->en_port);
efx_mac_ops_t *emop = epp->ep_emop;
uint8_t *old_mulcst_addr_list = NULL;
uint32_t old_mulcst_addr_count;
int rc;
EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
if (count > EFX_MAC_MULTICAST_LIST_MAX) {
rc = EINVAL;
goto fail1;
}
old_mulcst_addr_count = epp->ep_mulcst_addr_count;
if (old_mulcst_addr_count > 0) {
/* Allocate memory to store old list (instead of using stack) */
EFSYS_KMEM_ALLOC(enp->en_esip,
old_mulcst_addr_count * EFX_MAC_ADDR_LEN,
old_mulcst_addr_list);
if (old_mulcst_addr_list == NULL) {
rc = ENOMEM;
goto fail2;
}
/* Save the old list in case we need to rollback */
memcpy(old_mulcst_addr_list, epp->ep_mulcst_addr_list,
old_mulcst_addr_count * EFX_MAC_ADDR_LEN);
}
/* Store the new list */
memcpy(epp->ep_mulcst_addr_list, addrs,
count * EFX_MAC_ADDR_LEN);
epp->ep_mulcst_addr_count = count;
if ((rc = emop->emo_multicast_list_set(enp)) != 0)
goto fail3;
if (old_mulcst_addr_count > 0) {
EFSYS_KMEM_FREE(enp->en_esip,
old_mulcst_addr_count * EFX_MAC_ADDR_LEN,
old_mulcst_addr_list);
}
return (0);
fail3:
EFSYS_PROBE(fail3);
/* Restore original list on failure */
epp->ep_mulcst_addr_count = old_mulcst_addr_count;
if (old_mulcst_addr_count > 0) {
memcpy(epp->ep_mulcst_addr_list, old_mulcst_addr_list,
old_mulcst_addr_count * EFX_MAC_ADDR_LEN);
EFSYS_KMEM_FREE(enp->en_esip,
old_mulcst_addr_count * EFX_MAC_ADDR_LEN,
old_mulcst_addr_list);
}
fail2:
EFSYS_PROBE(fail2);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
__checkReturn int
efx_mac_filter_default_rxq_set(
__in efx_nic_t *enp,
__in efx_rxq_t *erp,
__in boolean_t using_rss)
{
efx_port_t *epp = &(enp->en_port);
efx_mac_ops_t *emop = epp->ep_emop;
int rc;
EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
if (emop->emo_filter_default_rxq_set != NULL) {
rc = emop->emo_filter_default_rxq_set(enp, erp, using_rss);
if (rc != 0)
goto fail1;
}
return (0);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
void
efx_mac_filter_default_rxq_clear(
__in efx_nic_t *enp)
{
efx_port_t *epp = &(enp->en_port);
efx_mac_ops_t *emop = epp->ep_emop;
EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
if (emop->emo_filter_default_rxq_clear != NULL)
emop->emo_filter_default_rxq_clear(enp);
}
#if EFSYS_OPT_MAC_STATS
#if EFSYS_OPT_NAMES
/* START MKCONFIG GENERATED EfxMacStatNamesBlock adf707adba80813e */
static const char __cs * __cs __efx_mac_stat_name[] = {
/* START MKCONFIG GENERATED EfxMacStatNamesBlock 054d43a31d2d7a45 */
static const char *__efx_mac_stat_name[] = {
"rx_octets",
"rx_pkts",
"rx_unicst_pkts",
@ -500,10 +686,40 @@ static const char __cs * __cs __efx_mac_stat_name[] = {
"tx_late_col_pkts",
"tx_def_pkts",
"tx_ex_def_pkts",
"pm_trunc_bb_overflow",
"pm_discard_bb_overflow",
"pm_trunc_vfifo_full",
"pm_discard_vfifo_full",
"pm_trunc_qbb",
"pm_discard_qbb",
"pm_discard_mapping",
"rxdp_q_disabled_pkts",
"rxdp_di_dropped_pkts",
"rxdp_streaming_pkts",
"rxdp_hlb_fetch",
"rxdp_hlb_wait",
"vadapter_rx_unicast_packets",
"vadapter_rx_unicast_bytes",
"vadapter_rx_multicast_packets",
"vadapter_rx_multicast_bytes",
"vadapter_rx_broadcast_packets",
"vadapter_rx_broadcast_bytes",
"vadapter_rx_bad_packets",
"vadapter_rx_bad_bytes",
"vadapter_rx_overflow",
"vadapter_tx_unicast_packets",
"vadapter_tx_unicast_bytes",
"vadapter_tx_multicast_packets",
"vadapter_tx_multicast_bytes",
"vadapter_tx_broadcast_packets",
"vadapter_tx_broadcast_bytes",
"vadapter_tx_bad_packets",
"vadapter_tx_bad_bytes",
"vadapter_tx_overflow",
};
/* END MKCONFIG GENERATED EfxMacStatNamesBlock */
__checkReturn const char __cs *
__checkReturn const char *
efx_mac_stat_name(
__in efx_nic_t *enp,
__in unsigned int id)
@ -515,7 +731,7 @@ efx_mac_stat_name(
return (__efx_mac_stat_name[id]);
}
#endif /* EFSYS_OPT_STAT_NAME */
#endif /* EFSYS_OPT_NAMES */
__checkReturn int
efx_mac_stats_upload(
@ -588,7 +804,7 @@ efx_mac_stats_update(
__in efx_nic_t *enp,
__in efsys_mem_t *esmp,
__inout_ecount(EFX_MAC_NSTATS) efsys_stat_t *essp,
__in uint32_t *generationp)
__out_opt uint32_t *generationp)
{
efx_port_t *epp = &(enp->en_port);
efx_mac_ops_t *emop = epp->ep_emop;
@ -616,6 +832,13 @@ efx_mac_select(
efx_mac_ops_t *emop;
int rc = EINVAL;
#if EFSYS_OPT_HUNTINGTON
if (enp->en_family == EFX_FAMILY_HUNTINGTON) {
type = EFX_MAC_HUNTINGTON;
goto chosen;
}
#endif
#if EFSYS_OPT_SIENA
if (enp->en_family == EFX_FAMILY_SIENA) {
type = EFX_MAC_SIENA;
@ -685,3 +908,71 @@ efx_mac_select(
return (rc);
}
#if EFSYS_OPT_FALCON || EFSYS_OPT_SIENA
/* Compute the multicast hash as used on Falcon and Siena. */
static void
falconsiena_mac_multicast_hash_compute(
__in_ecount(6*count) uint8_t const *addrs,
__in int count,
__out efx_oword_t *hash_low,
__out efx_oword_t *hash_high)
{
uint32_t crc, index;
int i;
EFSYS_ASSERT(hash_low != NULL);
EFSYS_ASSERT(hash_high != NULL);
EFX_ZERO_OWORD(*hash_low);
EFX_ZERO_OWORD(*hash_high);
for (i = 0; i < count; i++) {
/* Calculate hash bucket (IEEE 802.3 CRC32 of the MAC addr) */
crc = efx_crc32_calculate(0xffffffff, addrs, EFX_MAC_ADDR_LEN);
index = crc % EFX_MAC_HASH_BITS;
if (index < 128) {
EFX_SET_OWORD_BIT(*hash_low, index);
} else {
EFX_SET_OWORD_BIT(*hash_high, index - 128);
}
addrs += EFX_MAC_ADDR_LEN;
}
}
static __checkReturn int
falconsiena_mac_multicast_list_set(
__in efx_nic_t *enp)
{
efx_port_t *epp = &(enp->en_port);
efx_mac_ops_t *emop = epp->ep_emop;
efx_oword_t old_hash[2];
int rc;
EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
memcpy(old_hash, epp->ep_multicst_hash, sizeof (old_hash));
falconsiena_mac_multicast_hash_compute(epp->ep_mulcst_addr_list,
epp->ep_mulcst_addr_count,
&epp->ep_multicst_hash[0],
&epp->ep_multicst_hash[1]);
if ((rc = emop->emo_reconfigure(enp)) != 0)
goto fail1;
return (0);
fail1:
EFSYS_PROBE1(fail1, int, rc);
memcpy(epp->ep_multicst_hash, old_hash, sizeof (old_hash));
return (rc);
}
#endif /* EFSYS_OPT_FALCON || EFSYS_OPT_SIENA */

File diff suppressed because it is too large Load Diff

View File

@ -1,26 +1,31 @@
/*-
* Copyright 2009 Solarflare Communications Inc. All rights reserved.
* Copyright (c) 2009-2015 Solarflare Communications Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* modification, are permitted provided that the following conditions are met:
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the FreeBSD Project.
*
* $FreeBSD$
*/
@ -36,10 +41,15 @@
extern "C" {
#endif
/* Number of retries attempted for init code */
#define EFX_MCDI_REQ_RETRY_INIT 2
/*
* A reboot/assertion causes the MCDI status word to be set after the
* command word is set or a REBOOT event is sent. If we notice a reboot
* via these mechanisms then wait 10ms for the status word to be set.
*/
#define EFX_MCDI_STATUS_SLEEP_US 10000
struct efx_mcdi_req_s {
boolean_t emr_quiet;
/* Inputs: Command #, input buffer and length */
unsigned int emr_cmd;
uint8_t *emr_in_buf;
@ -52,19 +62,25 @@ struct efx_mcdi_req_s {
};
typedef struct efx_mcdi_iface_s {
const efx_mcdi_transport_t *emi_mtp;
unsigned int emi_port;
unsigned int emi_seq;
efx_mcdi_req_t *emi_pending_req;
boolean_t emi_ev_cpl;
boolean_t emi_new_epoch;
int emi_aborted;
uint32_t emi_poll_cnt;
uint32_t emi_mc_reboot_status;
} efx_mcdi_iface_t;
extern void
efx_mcdi_execute(
__in efx_nic_t *enp,
__in efx_mcdi_req_t *emrp);
__inout efx_mcdi_req_t *emrp);
extern void
efx_mcdi_execute_quiet(
__in efx_nic_t *enp,
__inout efx_mcdi_req_t *emrp);
extern void
efx_mcdi_ev_cpl(
@ -78,6 +94,16 @@ efx_mcdi_ev_death(
__in efx_nic_t *enp,
__in int rc);
extern __checkReturn int
efx_mcdi_request_errcode(
__in unsigned int err);
extern void
efx_mcdi_raise_exception(
__in efx_nic_t *enp,
__in_opt efx_mcdi_req_t *emrp,
__in int rc);
typedef enum efx_mcdi_boot_e {
EFX_MCDI_BOOT_PRIMARY,
EFX_MCDI_BOOT_SECONDARY,
@ -91,6 +117,86 @@ efx_mcdi_version(
__out_opt uint32_t *buildp,
__out_opt efx_mcdi_boot_t *statusp);
extern __checkReturn int
efx_mcdi_read_assertion(
__in efx_nic_t *enp);
extern __checkReturn int
efx_mcdi_exit_assertion_handler(
__in efx_nic_t *enp);
extern __checkReturn int
efx_mcdi_drv_attach(
__in efx_nic_t *enp,
__in boolean_t attach);
extern __checkReturn int
efx_mcdi_get_board_cfg(
__in efx_nic_t *enp,
__out_opt uint32_t *board_typep,
__out_opt efx_dword_t *capabilitiesp,
__out_ecount_opt(6) uint8_t mac_addrp[6]);
extern __checkReturn int
efx_mcdi_get_phy_cfg(
__in efx_nic_t *enp);
extern __checkReturn int
efx_mcdi_firmware_update_supported(
__in efx_nic_t *enp,
__out boolean_t *supportedp);
extern __checkReturn int
efx_mcdi_macaddr_change_supported(
__in efx_nic_t *enp,
__out boolean_t *supportedp);
#if EFSYS_OPT_BIST
#if EFSYS_OPT_HUNTINGTON
extern __checkReturn int
efx_mcdi_bist_enable_offline(
__in efx_nic_t *enp);
#endif /* EFSYS_OPT_HUNTINGTON */
extern __checkReturn int
efx_mcdi_bist_start(
__in efx_nic_t *enp,
__in efx_bist_type_t type);
#endif /* EFSYS_OPT_BIST */
extern __checkReturn int
efx_mcdi_get_resource_limits(
__in efx_nic_t *enp,
__out_opt uint32_t *nevqp,
__out_opt uint32_t *nrxqp,
__out_opt uint32_t *ntxqp);
extern __checkReturn int
efx_mcdi_log_ctrl(
__in efx_nic_t *enp);
extern __checkReturn int
efx_mcdi_mac_stats_clear(
__in efx_nic_t *enp);
extern __checkReturn int
efx_mcdi_mac_stats_upload(
__in efx_nic_t *enp,
__in efsys_mem_t *esmp);
extern __checkReturn int
efx_mcdi_mac_stats_periodic(
__in efx_nic_t *enp,
__in efsys_mem_t *esmp,
__in uint16_t period,
__in boolean_t events);
#if EFSYS_OPT_LOOPBACK
extern __checkReturn int
efx_mcdi_get_loopback_modes(
__in efx_nic_t *enp);
#endif /* EFSYS_OPT_LOOPBACK */
#define MCDI_IN(_emr, _type, _ofst) \
((_type *)((_emr).emr_in_buf + (_ofst)))
@ -101,10 +207,18 @@ efx_mcdi_version(
EFX_POPULATE_BYTE_1(*MCDI_IN2(_emr, efx_byte_t, _ofst), \
EFX_BYTE_0, _value)
#define MCDI_IN_SET_WORD(_emr, _ofst, _value) \
EFX_POPULATE_WORD_1(*MCDI_IN2(_emr, efx_word_t, _ofst), \
EFX_WORD_0, _value)
#define MCDI_IN_SET_DWORD(_emr, _ofst, _value) \
EFX_POPULATE_DWORD_1(*MCDI_IN2(_emr, efx_dword_t, _ofst), \
EFX_DWORD_0, _value)
#define MCDI_IN_SET_DWORD_FIELD(_emr, _ofst, _field, _value) \
EFX_SET_DWORD_FIELD(*MCDI_IN2(_emr, efx_dword_t, _ofst), \
MC_CMD_ ## _field, _value)
#define MCDI_IN_POPULATE_DWORD_1(_emr, _ofst, _field1, _value1) \
EFX_POPULATE_DWORD_1(*MCDI_IN2(_emr, efx_dword_t, _ofst), \
MC_CMD_ ## _field1, _value1)
@ -154,7 +268,7 @@ efx_mcdi_version(
#define MCDI_IN_POPULATE_DWORD_7(_emr, _ofst, _field1, _value1, \
_field2, _value2, _field3, _value3, _field4, _value4, \
_field5, _value5, _field6, _value6, _field7, _value7) \
EFX_POPULATE_DWORD_7(MCDI_IN2(_emr, efx_dword_t, _ofst), \
EFX_POPULATE_DWORD_7(*MCDI_IN2(_emr, efx_dword_t, _ofst), \
MC_CMD_ ## _field1, _value1, \
MC_CMD_ ## _field2, _value2, \
MC_CMD_ ## _field3, _value3, \
@ -233,7 +347,7 @@ efx_mcdi_version(
#define MCDI_EV_FIELD(_eqp, _field) \
EFX_QWORD_FIELD(*_eqp, MCDI_EVENT_ ## _field)
#define MCDI_CMD_DWORD_FIELD(_edp, _field) \
#define MCDI_CMD_DWORD_FIELD(_edp, _field) \
EFX_DWORD_FIELD(*_edp, MC_CMD_ ## _field)
#ifdef __cplusplus

View File

@ -1,26 +1,31 @@
/*-
* Copyright 2007-2009 Solarflare Communications Inc. All rights reserved.
* Copyright (c) 2007-2015 Solarflare Communications Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* modification, are permitted provided that the following conditions are met:
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the FreeBSD Project.
*/
#include <sys/cdefs.h>
@ -44,17 +49,22 @@ __FBSDID("$FreeBSD$");
#include "max6647.h"
#endif
#if EFSYS_OPT_MON_MCDI
#include "mcdi_mon.h"
#endif
#if EFSYS_OPT_NAMES
static const char __cs * __cs __efx_mon_name[] = {
static const char *__efx_mon_name[] = {
"",
"nullmon",
"lm87",
"max6647",
"sfx90x0"
"sfx90x0",
"sfx91x0"
};
const char __cs *
const char *
efx_mon_name(
__in efx_nic_t *enp)
{
@ -70,47 +80,46 @@ efx_mon_name(
#endif /* EFSYS_OPT_NAMES */
#if EFSYS_OPT_MON_NULL
static efx_mon_ops_t __cs __efx_mon_null_ops = {
static efx_mon_ops_t __efx_mon_null_ops = {
nullmon_reset, /* emo_reset */
nullmon_reconfigure, /* emo_reconfigure */
#if EFSYS_OPT_MON_STATS
nullmon_stats_update /* emo_stat_update */
nullmon_stats_update /* emo_stats_update */
#endif /* EFSYS_OPT_MON_STATS */
};
#endif
#if EFSYS_OPT_MON_LM87
static efx_mon_ops_t __cs __efx_mon_lm87_ops = {
static efx_mon_ops_t __efx_mon_lm87_ops = {
lm87_reset, /* emo_reset */
lm87_reconfigure, /* emo_reconfigure */
#if EFSYS_OPT_MON_STATS
lm87_stats_update /* emo_stat_update */
lm87_stats_update /* emo_stats_update */
#endif /* EFSYS_OPT_MON_STATS */
};
#endif
#if EFSYS_OPT_MON_MAX6647
static efx_mon_ops_t __cs __efx_mon_max6647_ops = {
static efx_mon_ops_t __efx_mon_max6647_ops = {
max6647_reset, /* emo_reset */
max6647_reconfigure, /* emo_reconfigure */
#if EFSYS_OPT_MON_STATS
max6647_stats_update /* emo_stat_update */
max6647_stats_update /* emo_stats_update */
#endif /* EFSYS_OPT_MON_STATS */
};
#endif
#if EFSYS_OPT_MON_SIENA
static efx_mon_ops_t __cs __efx_mon_siena_ops = {
siena_mon_reset, /* emo_reset */
siena_mon_reconfigure, /* emo_reconfigure */
#if EFSYS_OPT_MON_MCDI
static efx_mon_ops_t __efx_mon_mcdi_ops = {
NULL, /* emo_reset */
NULL, /* emo_reconfigure */
#if EFSYS_OPT_MON_STATS
siena_mon_stats_update /* emo_stat_update */
mcdi_mon_stats_update /* emo_stats_update */
#endif /* EFSYS_OPT_MON_STATS */
};
#endif
static efx_mon_ops_t __cs * __cs __efx_mon_ops[] = {
static efx_mon_ops_t *__efx_mon_ops[] = {
NULL,
#if EFSYS_OPT_MON_NULL
&__efx_mon_null_ops,
@ -127,8 +136,13 @@ static efx_mon_ops_t __cs * __cs __efx_mon_ops[] = {
#else
NULL,
#endif
#if EFSYS_OPT_MON_SIENA
&__efx_mon_siena_ops
#if EFSYS_OPT_MON_MCDI
&__efx_mon_mcdi_ops,
#else
NULL,
#endif
#if EFSYS_OPT_MON_MCDI
&__efx_mon_mcdi_ops
#else
NULL
#endif
@ -162,11 +176,15 @@ efx_mon_init(
goto fail2;
}
if ((rc = emop->emo_reset(enp)) != 0)
goto fail3;
if (emop->emo_reset != NULL) {
if ((rc = emop->emo_reset(enp)) != 0)
goto fail3;
}
if ((rc = emop->emo_reconfigure(enp)) != 0)
goto fail4;
if (emop->emo_reconfigure != NULL) {
if ((rc = emop->emo_reconfigure(enp)) != 0)
goto fail4;
}
emp->em_emop = emop;
return (0);
@ -174,7 +192,8 @@ efx_mon_init(
fail4:
EFSYS_PROBE(fail5);
(void) emop->emo_reset(enp);
if (emop->emo_reset != NULL)
(void) emop->emo_reset(enp);
fail3:
EFSYS_PROBE(fail4);
@ -195,8 +214,8 @@ efx_mon_init(
#if EFSYS_OPT_NAMES
/* START MKCONFIG GENERATED MonitorStatNamesBlock 89ff37f1d74ad8b3 */
static const char __cs * __cs __mon_stat_name[] = {
/* START MKCONFIG GENERATED MonitorStatNamesBlock b9328f15438c4d01 */
static const char *__mon_stat_name[] = {
"value_2_5v",
"value_vccp1",
"value_vcc",
@ -227,11 +246,50 @@ static const char __cs * __cs __mon_stat_name[] = {
"vaoe_in",
"iaoe",
"iaoe_in",
"nic_power",
"0_9v",
"i0_9v",
"i1_2v",
"0_9v_adc",
"controller_temperature2",
"vreg_temperature",
"vreg_0_9v_temperature",
"vreg_1_2v_temperature",
"int_vptat",
"controller_internal_adc_temperature",
"ext_vptat",
"controller_external_adc_temperature",
"ambient_temperature",
"airflow",
"vdd08d_vss08d_csr",
"vdd08d_vss08d_csr_extadc",
"hotpoint_temperature",
"phy_power_switch_port0",
"phy_power_switch_port1",
"mum_vcc",
"0v9_a",
"i0v9_a",
"0v9_a_temp",
"0v9_b",
"i0v9_b",
"0v9_b_temp",
"ccom_avreg_1v2_supply",
"ccom_avreg_1v2_supply_ext_adc",
"ccom_avreg_1v8_supply",
"ccom_avreg_1v8_supply_ext_adc",
"controller_master_vptat",
"controller_master_internal_temp",
"controller_master_vptat_ext_adc",
"controller_master_internal_temp_ext_adc",
"controller_slave_vptat",
"controller_slave_internal_temp",
"controller_slave_vptat_ext_adc",
"controller_slave_internal_temp_ext_adc",
};
/* END MKCONFIG GENERATED MonitorStatNamesBlock */
extern const char __cs *
extern const char *
efx_mon_stat_name(
__in efx_nic_t *enp,
__in efx_mon_stat_t id)
@ -276,9 +334,11 @@ efx_mon_fini(
emp->em_emop = NULL;
rc = emop->emo_reset(enp);
if (rc != 0)
EFSYS_PROBE1(fail1, int, rc);
if (emop->emo_reset != NULL) {
rc = emop->emo_reset(enp);
if (rc != 0)
EFSYS_PROBE1(fail1, int, rc);
}
emp->em_type = EFX_MON_INVALID;

View File

@ -1,26 +1,31 @@
/*-
* Copyright 2007-2009 Solarflare Communications Inc. All rights reserved.
* Copyright (c) 2007-2015 Solarflare Communications Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* modification, are permitted provided that the following conditions are met:
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the FreeBSD Project.
*/
#include <sys/cdefs.h>
@ -38,27 +43,55 @@ efx_family(
__in uint16_t devid,
__out efx_family_t *efp)
{
if (venid == EFX_PCI_VENID_SFC) {
switch (devid) {
#if EFSYS_OPT_FALCON
if (venid == EFX_PCI_VENID_SFC && devid == EFX_PCI_DEVID_FALCON) {
*efp = EFX_FAMILY_FALCON;
return (0);
}
case EFX_PCI_DEVID_FALCON:
*efp = EFX_FAMILY_FALCON;
return (0);
#endif
#if EFSYS_OPT_SIENA
if (venid == EFX_PCI_VENID_SFC && devid == EFX_PCI_DEVID_BETHPAGE) {
*efp = EFX_FAMILY_SIENA;
return (0);
}
if (venid == EFX_PCI_VENID_SFC && devid == EFX_PCI_DEVID_SIENA) {
*efp = EFX_FAMILY_SIENA;
return (0);
}
if (venid == EFX_PCI_VENID_SFC &&
devid == EFX_PCI_DEVID_SIENA_F1_UNINIT) {
*efp = EFX_FAMILY_SIENA;
return (0);
}
case EFX_PCI_DEVID_SIENA_F1_UNINIT:
/*
* Hardware default for PF0 of uninitialised Siena.
* manftest must be able to cope with this device id.
*/
*efp = EFX_FAMILY_SIENA;
return (0);
case EFX_PCI_DEVID_BETHPAGE:
case EFX_PCI_DEVID_SIENA:
*efp = EFX_FAMILY_SIENA;
return (0);
#endif
#if EFSYS_OPT_HUNTINGTON
case EFX_PCI_DEVID_HUNTINGTON_PF_UNINIT:
/*
* Hardware default for PF0 of uninitialised Huntington.
* manftest must be able to cope with this device id.
*/
*efp = EFX_FAMILY_HUNTINGTON;
return (0);
case EFX_PCI_DEVID_FARMINGDALE:
case EFX_PCI_DEVID_GREENPORT:
case EFX_PCI_DEVID_HUNTINGTON:
*efp = EFX_FAMILY_HUNTINGTON;
return (0);
case EFX_PCI_DEVID_FARMINGDALE_VF:
case EFX_PCI_DEVID_GREENPORT_VF:
case EFX_PCI_DEVID_HUNTINGTON_VF:
*efp = EFX_FAMILY_HUNTINGTON;
return (0);
#endif
default:
break;
}
}
*efp = EFX_FAMILY_INVALID;
return (ENOTSUP);
}
@ -80,11 +113,28 @@ efx_infer_family(
EFSYS_BAR_READO(esbp, FR_AZ_CS_DEBUG_REG_OFST, &oword, B_TRUE);
portnum = EFX_OWORD_FIELD(oword, FRF_CZ_CS_PORT_NUM);
switch (portnum) {
#if EFSYS_OPT_FALCON
case 0:
family = EFX_FAMILY_FALCON;
break;
case 0: {
efx_dword_t dword;
uint32_t hw_rev;
EFSYS_BAR_READD(esbp, ER_DZ_BIU_HW_REV_ID_REG_OFST, &dword,
B_TRUE);
hw_rev = EFX_DWORD_FIELD(dword, ERF_DZ_HW_REV_ID);
if (hw_rev == ER_DZ_BIU_HW_REV_ID_REG_RESET) {
#if EFSYS_OPT_HUNTINGTON
family = EFX_FAMILY_HUNTINGTON;
break;
#endif
} else {
#if EFSYS_OPT_FALCON
family = EFX_FAMILY_FALCON;
break;
#endif
}
rc = ENOTSUP;
goto fail1;
}
#if EFSYS_OPT_SIENA
case 1:
case 2:
@ -106,15 +156,10 @@ efx_infer_family(
return (rc);
}
/*
* The built-in default value device id for port 1 of Siena is 0x0810.
* manftest needs to be able to cope with that.
*/
#define EFX_BIU_MAGIC0 0x01234567
#define EFX_BIU_MAGIC1 0xfedcba98
static __checkReturn int
__checkReturn int
efx_nic_biu_test(
__in efx_nic_t *enp)
{
@ -128,18 +173,18 @@ efx_nic_biu_test(
* back the cached value that was last written.
*/
EFX_POPULATE_OWORD_1(oword, FRF_AZ_DRIVER_DW0, EFX_BIU_MAGIC0);
EFX_BAR_TBL_WRITEO(enp, FR_AZ_DRIVER_REG, 0, &oword);
EFX_BAR_TBL_WRITEO(enp, FR_AZ_DRIVER_REG, 0, &oword, B_TRUE);
EFX_POPULATE_OWORD_1(oword, FRF_AZ_DRIVER_DW0, EFX_BIU_MAGIC1);
EFX_BAR_TBL_WRITEO(enp, FR_AZ_DRIVER_REG, 1, &oword);
EFX_BAR_TBL_WRITEO(enp, FR_AZ_DRIVER_REG, 1, &oword, B_TRUE);
EFX_BAR_TBL_READO(enp, FR_AZ_DRIVER_REG, 0, &oword);
EFX_BAR_TBL_READO(enp, FR_AZ_DRIVER_REG, 0, &oword, B_TRUE);
if (EFX_OWORD_FIELD(oword, FRF_AZ_DRIVER_DW0) != EFX_BIU_MAGIC0) {
rc = EIO;
goto fail1;
}
EFX_BAR_TBL_READO(enp, FR_AZ_DRIVER_REG, 1, &oword);
EFX_BAR_TBL_READO(enp, FR_AZ_DRIVER_REG, 1, &oword, B_TRUE);
if (EFX_OWORD_FIELD(oword, FRF_AZ_DRIVER_DW0) != EFX_BIU_MAGIC1) {
rc = EIO;
goto fail2;
@ -151,18 +196,18 @@ efx_nic_biu_test(
* values already written into the scratch registers.
*/
EFX_POPULATE_OWORD_1(oword, FRF_AZ_DRIVER_DW0, EFX_BIU_MAGIC1);
EFX_BAR_TBL_WRITEO(enp, FR_AZ_DRIVER_REG, 0, &oword);
EFX_BAR_TBL_WRITEO(enp, FR_AZ_DRIVER_REG, 0, &oword, B_TRUE);
EFX_POPULATE_OWORD_1(oword, FRF_AZ_DRIVER_DW0, EFX_BIU_MAGIC0);
EFX_BAR_TBL_WRITEO(enp, FR_AZ_DRIVER_REG, 1, &oword);
EFX_BAR_TBL_WRITEO(enp, FR_AZ_DRIVER_REG, 1, &oword, B_TRUE);
EFX_BAR_TBL_READO(enp, FR_AZ_DRIVER_REG, 0, &oword);
EFX_BAR_TBL_READO(enp, FR_AZ_DRIVER_REG, 0, &oword, B_TRUE);
if (EFX_OWORD_FIELD(oword, FRF_AZ_DRIVER_DW0) != EFX_BIU_MAGIC1) {
rc = EIO;
goto fail3;
}
EFX_BAR_TBL_READO(enp, FR_AZ_DRIVER_REG, 1, &oword);
EFX_BAR_TBL_READO(enp, FR_AZ_DRIVER_REG, 1, &oword, B_TRUE);
if (EFX_OWORD_FIELD(oword, FRF_AZ_DRIVER_DW0) != EFX_BIU_MAGIC0) {
rc = EIO;
goto fail4;
@ -184,10 +229,13 @@ efx_nic_biu_test(
#if EFSYS_OPT_FALCON
static efx_nic_ops_t __cs __efx_nic_falcon_ops = {
static efx_nic_ops_t __efx_nic_falcon_ops = {
falcon_nic_probe, /* eno_probe */
NULL, /* eno_set_drv_limits */
falcon_nic_reset, /* eno_reset */
falcon_nic_init, /* eno_init */
NULL, /* eno_get_vi_pool */
NULL, /* eno_get_bar_region */
#if EFSYS_OPT_DIAG
falcon_sram_test, /* eno_sram_test */
falcon_nic_register_test, /* eno_register_test */
@ -200,10 +248,13 @@ static efx_nic_ops_t __cs __efx_nic_falcon_ops = {
#if EFSYS_OPT_SIENA
static efx_nic_ops_t __cs __efx_nic_siena_ops = {
static efx_nic_ops_t __efx_nic_siena_ops = {
siena_nic_probe, /* eno_probe */
NULL, /* eno_set_drv_limits */
siena_nic_reset, /* eno_reset */
siena_nic_init, /* eno_init */
NULL, /* eno_get_vi_pool */
NULL, /* eno_get_bar_region */
#if EFSYS_OPT_DIAG
siena_sram_test, /* eno_sram_test */
siena_nic_register_test, /* eno_register_test */
@ -214,6 +265,25 @@ static efx_nic_ops_t __cs __efx_nic_siena_ops = {
#endif /* EFSYS_OPT_SIENA */
#if EFSYS_OPT_HUNTINGTON
static efx_nic_ops_t __efx_nic_hunt_ops = {
hunt_nic_probe, /* eno_probe */
hunt_nic_set_drv_limits, /* eno_set_drv_limits */
hunt_nic_reset, /* eno_reset */
hunt_nic_init, /* eno_init */
hunt_nic_get_vi_pool, /* eno_get_vi_pool */
hunt_nic_get_bar_region, /* eno_get_bar_region */
#if EFSYS_OPT_DIAG
hunt_sram_test, /* eno_sram_test */
hunt_nic_register_test, /* eno_register_test */
#endif /* EFSYS_OPT_DIAG */
hunt_nic_fini, /* eno_fini */
hunt_nic_unprobe, /* eno_unprobe */
};
#endif /* EFSYS_OPT_HUNTINGTON */
__checkReturn int
efx_nic_create(
__in efx_family_t family,
@ -257,10 +327,27 @@ efx_nic_create(
EFX_FEATURE_WOL |
EFX_FEATURE_MCDI |
EFX_FEATURE_LOOKAHEAD_SPLIT |
EFX_FEATURE_MAC_HEADER_FILTERS;
EFX_FEATURE_MAC_HEADER_FILTERS |
EFX_FEATURE_TX_SRC_FILTERS;
break;
#endif /* EFSYS_OPT_SIENA */
#if EFSYS_OPT_HUNTINGTON
case EFX_FAMILY_HUNTINGTON:
enp->en_enop = (efx_nic_ops_t *)&__efx_nic_hunt_ops;
/* FIXME: Add WOL support */
enp->en_features =
EFX_FEATURE_IPV6 |
EFX_FEATURE_LINK_EVENTS |
EFX_FEATURE_PERIODIC_MAC_STATS |
EFX_FEATURE_MCDI |
EFX_FEATURE_MAC_HEADER_FILTERS |
EFX_FEATURE_MCDI_DMA |
EFX_FEATURE_PIO_BUFFERS |
EFX_FEATURE_FW_ASSISTED_TSO;
break;
#endif /* EFSYS_OPT_HUNTINGTON */
default:
rc = ENOTSUP;
goto fail2;
@ -276,7 +363,7 @@ efx_nic_create(
return (0);
fail2:
EFSYS_PROBE(fail3);
EFSYS_PROBE(fail2);
enp->en_magic = 0;
@ -294,7 +381,6 @@ efx_nic_probe(
__in efx_nic_t *enp)
{
efx_nic_ops_t *enop;
efx_oword_t oword;
int rc;
EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
@ -303,36 +389,22 @@ efx_nic_probe(
#endif /* EFSYS_OPT_MCDI */
EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_PROBE));
/* Test BIU */
if ((rc = efx_nic_biu_test(enp)) != 0)
goto fail1;
/* Clear the region register */
EFX_POPULATE_OWORD_4(oword,
FRF_AZ_ADR_REGION0, 0,
FRF_AZ_ADR_REGION1, (1 << 16),
FRF_AZ_ADR_REGION2, (2 << 16),
FRF_AZ_ADR_REGION3, (3 << 16));
EFX_BAR_WRITEO(enp, FR_AZ_ADR_REGION_REG, &oword);
enop = enp->en_enop;
if ((rc = enop->eno_probe(enp)) != 0)
goto fail2;
goto fail1;
if ((rc = efx_phy_probe(enp)) != 0)
goto fail3;
goto fail2;
enp->en_mod_flags |= EFX_MOD_PROBE;
return (0);
fail3:
EFSYS_PROBE(fail3);
fail2:
EFSYS_PROBE(fail2);
enop->eno_unprobe(enp);
fail2:
EFSYS_PROBE(fail2);
fail1:
EFSYS_PROBE1(fail1, int, rc);
@ -375,6 +447,105 @@ efx_nic_pcie_extended_sync(
#endif /* EFSYS_OPT_PCIE_TUNE */
__checkReturn int
efx_nic_set_drv_limits(
__inout efx_nic_t *enp,
__in efx_drv_limits_t *edlp)
{
efx_nic_ops_t *enop = enp->en_enop;
int rc;
EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
if (enop->eno_set_drv_limits != NULL) {
if ((rc = enop->eno_set_drv_limits(enp, edlp)) != 0)
goto fail1;
}
return (0);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
__checkReturn int
efx_nic_get_bar_region(
__in efx_nic_t *enp,
__in efx_nic_region_t region,
__out uint32_t *offsetp,
__out size_t *sizep)
{
efx_nic_ops_t *enop = enp->en_enop;
int rc;
EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC);
if (enop->eno_get_bar_region == NULL) {
rc = ENOTSUP;
goto fail1;
}
if ((rc = (enop->eno_get_bar_region)(enp,
region, offsetp, sizep)) != 0) {
goto fail2;
}
return (0);
fail2:
EFSYS_PROBE(fail2);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
__checkReturn int
efx_nic_get_vi_pool(
__in efx_nic_t *enp,
__out uint32_t *evq_countp,
__out uint32_t *rxq_countp,
__out uint32_t *txq_countp)
{
efx_nic_ops_t *enop = enp->en_enop;
efx_nic_cfg_t *encp = &enp->en_nic_cfg;
int rc;
EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC);
if (enop->eno_get_vi_pool != NULL) {
uint32_t vi_count = 0;
if ((rc = (enop->eno_get_vi_pool)(enp, &vi_count)) != 0)
goto fail1;
*evq_countp = vi_count;
*rxq_countp = vi_count;
*txq_countp = vi_count;
} else {
/* Use NIC limits as default value */
*evq_countp = encp->enc_evq_limit;
*rxq_countp = encp->enc_rxq_limit;
*txq_countp = encp->enc_txq_limit;
}
return (0);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
__checkReturn int
efx_nic_init(
__in efx_nic_t *enp)
@ -679,3 +850,191 @@ efx_nic_test_tables(
}
#endif /* EFSYS_OPT_DIAG */
#if EFSYS_OPT_LOOPBACK
extern void
efx_loopback_mask(
__in efx_loopback_kind_t loopback_kind,
__out efx_qword_t *maskp)
{
efx_qword_t mask;
EFSYS_ASSERT3U(loopback_kind, <, EFX_LOOPBACK_NKINDS);
EFSYS_ASSERT(maskp != NULL);
/* Assert the MC_CMD_LOOPBACK and EFX_LOOPBACK namespace agree */
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_NONE == EFX_LOOPBACK_OFF);
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_DATA == EFX_LOOPBACK_DATA);
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMAC == EFX_LOOPBACK_GMAC);
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGMII == EFX_LOOPBACK_XGMII);
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGXS == EFX_LOOPBACK_XGXS);
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI == EFX_LOOPBACK_XAUI);
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMII == EFX_LOOPBACK_GMII);
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SGMII == EFX_LOOPBACK_SGMII);
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGBR == EFX_LOOPBACK_XGBR);
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI == EFX_LOOPBACK_XFI);
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI_FAR == EFX_LOOPBACK_XAUI_FAR);
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMII_FAR == EFX_LOOPBACK_GMII_FAR);
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SGMII_FAR == EFX_LOOPBACK_SGMII_FAR);
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI_FAR == EFX_LOOPBACK_XFI_FAR);
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GPHY == EFX_LOOPBACK_GPHY);
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PHYXS == EFX_LOOPBACK_PHY_XS);
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PCS == EFX_LOOPBACK_PCS);
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PMAPMD == EFX_LOOPBACK_PMA_PMD);
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XPORT == EFX_LOOPBACK_XPORT);
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGMII_WS == EFX_LOOPBACK_XGMII_WS);
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI_WS == EFX_LOOPBACK_XAUI_WS);
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI_WS_FAR ==
EFX_LOOPBACK_XAUI_WS_FAR);
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI_WS_NEAR ==
EFX_LOOPBACK_XAUI_WS_NEAR);
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMII_WS == EFX_LOOPBACK_GMII_WS);
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI_WS == EFX_LOOPBACK_XFI_WS);
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI_WS_FAR ==
EFX_LOOPBACK_XFI_WS_FAR);
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PHYXS_WS == EFX_LOOPBACK_PHYXS_WS);
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PMA_INT == EFX_LOOPBACK_PMA_INT);
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_NEAR == EFX_LOOPBACK_SD_NEAR);
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_FAR == EFX_LOOPBACK_SD_FAR);
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PMA_INT_WS ==
EFX_LOOPBACK_PMA_INT_WS);
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_FEP2_WS ==
EFX_LOOPBACK_SD_FEP2_WS);
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_FEP1_5_WS ==
EFX_LOOPBACK_SD_FEP1_5_WS);
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_FEP_WS == EFX_LOOPBACK_SD_FEP_WS);
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_FES_WS == EFX_LOOPBACK_SD_FES_WS);
/* Build bitmask of possible loopback types */
EFX_ZERO_QWORD(mask);
if ((loopback_kind == EFX_LOOPBACK_KIND_OFF) ||
(loopback_kind == EFX_LOOPBACK_KIND_ALL)) {
EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_OFF);
}
if ((loopback_kind == EFX_LOOPBACK_KIND_MAC) ||
(loopback_kind == EFX_LOOPBACK_KIND_ALL)) {
/*
* The "MAC" grouping has historically been used by drivers to
* mean loopbacks supported by on-chip hardware. Keep that
* meaning here, and include on-chip PHY layer loopbacks.
*/
EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_DATA);
EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_GMAC);
EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XGMII);
EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XGXS);
EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XAUI);
EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_GMII);
EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_SGMII);
EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XGBR);
EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XFI);
EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XAUI_FAR);
EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_GMII_FAR);
EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_SGMII_FAR);
EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XFI_FAR);
EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_PMA_INT);
EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_SD_NEAR);
EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_SD_FAR);
}
if ((loopback_kind == EFX_LOOPBACK_KIND_PHY) ||
(loopback_kind == EFX_LOOPBACK_KIND_ALL)) {
/*
* The "PHY" grouping has historically been used by drivers to
* mean loopbacks supported by off-chip hardware. Keep that
* meaning here.
*/
EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_GPHY);
EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_PHY_XS);
EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_PCS);
EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_PMA_PMD);
}
*maskp = mask;
}
__checkReturn int
efx_mcdi_get_loopback_modes(
__in efx_nic_t *enp)
{
efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
efx_mcdi_req_t req;
uint8_t payload[MAX(MC_CMD_GET_LOOPBACK_MODES_IN_LEN,
MC_CMD_GET_LOOPBACK_MODES_OUT_LEN)];
efx_qword_t mask;
efx_qword_t modes;
int rc;
(void) memset(payload, 0, sizeof (payload));
req.emr_cmd = MC_CMD_GET_LOOPBACK_MODES;
req.emr_in_buf = payload;
req.emr_in_length = MC_CMD_GET_LOOPBACK_MODES_IN_LEN;
req.emr_out_buf = payload;
req.emr_out_length = MC_CMD_GET_LOOPBACK_MODES_OUT_LEN;
efx_mcdi_execute(enp, &req);
if (req.emr_rc != 0) {
rc = req.emr_rc;
goto fail1;
}
if (req.emr_out_length_used <
MC_CMD_GET_LOOPBACK_MODES_OUT_SUGGESTED_OFST +
MC_CMD_GET_LOOPBACK_MODES_OUT_SUGGESTED_LEN) {
rc = EMSGSIZE;
goto fail2;
}
/*
* We assert the MC_CMD_LOOPBACK and EFX_LOOPBACK namespaces agree
* in efx_loopback_mask() and in siena_phy.c:siena_phy_get_link().
*/
efx_loopback_mask(EFX_LOOPBACK_KIND_ALL, &mask);
EFX_AND_QWORD(mask,
*MCDI_OUT2(req, efx_qword_t, GET_LOOPBACK_MODES_OUT_SUGGESTED));
modes = *MCDI_OUT2(req, efx_qword_t, GET_LOOPBACK_MODES_OUT_100M);
EFX_AND_QWORD(modes, mask);
encp->enc_loopback_types[EFX_LINK_100FDX] = modes;
modes = *MCDI_OUT2(req, efx_qword_t, GET_LOOPBACK_MODES_OUT_1G);
EFX_AND_QWORD(modes, mask);
encp->enc_loopback_types[EFX_LINK_1000FDX] = modes;
modes = *MCDI_OUT2(req, efx_qword_t, GET_LOOPBACK_MODES_OUT_10G);
EFX_AND_QWORD(modes, mask);
encp->enc_loopback_types[EFX_LINK_10000FDX] = modes;
if (req.emr_out_length_used >=
MC_CMD_GET_LOOPBACK_MODES_OUT_40G_OFST +
MC_CMD_GET_LOOPBACK_MODES_OUT_40G_LEN) {
/* Response includes 40G loopback modes */
modes =
*MCDI_OUT2(req, efx_qword_t, GET_LOOPBACK_MODES_OUT_40G);
EFX_AND_QWORD(modes, mask);
encp->enc_loopback_types[EFX_LINK_40000FDX] = modes;
}
EFX_ZERO_QWORD(modes);
EFX_SET_QWORD_BIT(modes, EFX_LOOPBACK_OFF);
EFX_OR_QWORD(modes, encp->enc_loopback_types[EFX_LINK_100FDX]);
EFX_OR_QWORD(modes, encp->enc_loopback_types[EFX_LINK_1000FDX]);
EFX_OR_QWORD(modes, encp->enc_loopback_types[EFX_LINK_10000FDX]);
EFX_OR_QWORD(modes, encp->enc_loopback_types[EFX_LINK_40000FDX]);
encp->enc_loopback_types[EFX_LINK_UNKNOWN] = modes;
return (0);
fail2:
EFSYS_PROBE(fail2);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
#endif /* EFSYS_OPT_LOOPBACK */

View File

@ -1,26 +1,31 @@
/*-
* Copyright 2009 Solarflare Communications Inc. All rights reserved.
* Copyright (c) 2009-2015 Solarflare Communications Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* modification, are permitted provided that the following conditions are met:
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the FreeBSD Project.
*/
#include <sys/cdefs.h>
@ -36,7 +41,7 @@ __FBSDID("$FreeBSD$");
#if EFSYS_OPT_FALCON
static efx_nvram_ops_t __cs __efx_nvram_falcon_ops = {
static efx_nvram_ops_t __efx_nvram_falcon_ops = {
#if EFSYS_OPT_DIAG
falcon_nvram_test, /* envo_test */
#endif /* EFSYS_OPT_DIAG */
@ -54,7 +59,7 @@ static efx_nvram_ops_t __cs __efx_nvram_falcon_ops = {
#if EFSYS_OPT_SIENA
static efx_nvram_ops_t __cs __efx_nvram_siena_ops = {
static efx_nvram_ops_t __efx_nvram_siena_ops = {
#if EFSYS_OPT_DIAG
siena_nvram_test, /* envo_test */
#endif /* EFSYS_OPT_DIAG */
@ -70,6 +75,24 @@ static efx_nvram_ops_t __cs __efx_nvram_siena_ops = {
#endif /* EFSYS_OPT_SIENA */
#if EFSYS_OPT_HUNTINGTON
static efx_nvram_ops_t __efx_nvram_hunt_ops = {
#if EFSYS_OPT_DIAG
hunt_nvram_test, /* envo_test */
#endif /* EFSYS_OPT_DIAG */
hunt_nvram_size, /* envo_size */
hunt_nvram_get_version, /* envo_get_version */
hunt_nvram_rw_start, /* envo_rw_start */
hunt_nvram_read_chunk, /* envo_read_chunk */
hunt_nvram_erase, /* envo_erase */
hunt_nvram_write_chunk, /* envo_write_chunk */
hunt_nvram_rw_finish, /* envo_rw_finish */
hunt_nvram_set_version, /* envo_set_version */
};
#endif /* EFSYS_OPT_HUNTINGTON */
__checkReturn int
efx_nvram_init(
__in efx_nic_t *enp)
@ -94,6 +117,12 @@ efx_nvram_init(
break;
#endif /* EFSYS_OPT_SIENA */
#if EFSYS_OPT_HUNTINGTON
case EFX_FAMILY_HUNTINGTON:
envop = (efx_nvram_ops_t *)&__efx_nvram_hunt_ops;
break;
#endif /* EFSYS_OPT_HUNTINGTON */
default:
EFSYS_ASSERT(0);
rc = ENOTSUP;
@ -329,7 +358,7 @@ efx_nvram_rw_finish(
efx_nvram_set_version(
__in efx_nic_t *enp,
__in efx_nvram_type_t type,
__out uint16_t version[4])
__in_ecount(4) uint16_t version[4])
{
efx_nvram_ops_t *envop = enp->en_envop;
int rc;
@ -373,3 +402,486 @@ efx_nvram_fini(
}
#endif /* EFSYS_OPT_NVRAM */
#if EFSYS_OPT_NVRAM || EFSYS_OPT_VPD
/*
* Internal MCDI request handling
*/
__checkReturn int
efx_mcdi_nvram_partitions(
__in efx_nic_t *enp,
__out_bcount(size) caddr_t data,
__in size_t size,
__out unsigned int *npartnp)
{
efx_mcdi_req_t req;
uint8_t payload[MAX(MC_CMD_NVRAM_PARTITIONS_IN_LEN,
MC_CMD_NVRAM_PARTITIONS_OUT_LENMAX)];
unsigned int npartn;
int rc;
(void) memset(payload, 0, sizeof (payload));
req.emr_cmd = MC_CMD_NVRAM_PARTITIONS;
req.emr_in_buf = payload;
req.emr_in_length = MC_CMD_NVRAM_PARTITIONS_IN_LEN;
req.emr_out_buf = payload;
req.emr_out_length = MC_CMD_NVRAM_PARTITIONS_OUT_LENMAX;
efx_mcdi_execute(enp, &req);
if (req.emr_rc != 0) {
rc = req.emr_rc;
goto fail1;
}
if (req.emr_out_length_used < MC_CMD_NVRAM_PARTITIONS_OUT_LENMIN) {
rc = EMSGSIZE;
goto fail2;
}
npartn = MCDI_OUT_DWORD(req, NVRAM_PARTITIONS_OUT_NUM_PARTITIONS);
if (req.emr_out_length_used < MC_CMD_NVRAM_PARTITIONS_OUT_LEN(npartn)) {
rc = ENOENT;
goto fail3;
}
if (size < npartn * sizeof (uint32_t)) {
rc = ENOSPC;
goto fail3;
}
*npartnp = npartn;
memcpy(data,
MCDI_OUT2(req, uint32_t, NVRAM_PARTITIONS_OUT_TYPE_ID),
(npartn * sizeof (uint32_t)));
return (0);
fail3:
EFSYS_PROBE(fail3);
fail2:
EFSYS_PROBE(fail2);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
__checkReturn int
efx_mcdi_nvram_metadata(
__in efx_nic_t *enp,
__in uint32_t partn,
__out uint32_t *subtypep,
__out_ecount(4) uint16_t version[4],
__out_bcount_opt(size) char *descp,
__in size_t size)
{
efx_mcdi_req_t req;
uint8_t payload[MAX(MC_CMD_NVRAM_METADATA_IN_LEN,
MC_CMD_NVRAM_METADATA_OUT_LENMAX)];
int rc;
(void) memset(payload, 0, sizeof (payload));
req.emr_cmd = MC_CMD_NVRAM_METADATA;
req.emr_in_buf = payload;
req.emr_in_length = MC_CMD_NVRAM_METADATA_IN_LEN;
req.emr_out_buf = payload;
req.emr_out_length = MC_CMD_NVRAM_METADATA_OUT_LENMAX;
MCDI_IN_SET_DWORD(req, NVRAM_METADATA_IN_TYPE, partn);
efx_mcdi_execute(enp, &req);
if (req.emr_rc != 0) {
rc = req.emr_rc;
goto fail1;
}
if (req.emr_out_length_used < MC_CMD_NVRAM_METADATA_OUT_LENMIN) {
rc = EMSGSIZE;
goto fail2;
}
if (MCDI_OUT_DWORD_FIELD(req, NVRAM_METADATA_OUT_FLAGS,
NVRAM_METADATA_OUT_SUBTYPE_VALID)) {
*subtypep = MCDI_OUT_DWORD(req, NVRAM_METADATA_OUT_SUBTYPE);
} else {
*subtypep = 0;
}
if (MCDI_OUT_DWORD_FIELD(req, NVRAM_METADATA_OUT_FLAGS,
NVRAM_METADATA_OUT_VERSION_VALID)) {
version[0] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_W);
version[1] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_X);
version[2] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_Y);
version[3] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_Z);
} else {
version[0] = version[1] = version[2] = version[3] = 0;
}
if (MCDI_OUT_DWORD_FIELD(req, NVRAM_METADATA_OUT_FLAGS,
NVRAM_METADATA_OUT_DESCRIPTION_VALID)) {
/* Return optional descrition string */
if ((descp != NULL) && (size > 0)) {
size_t desclen;
descp[0] = '\0';
desclen = (req.emr_out_length_used
- MC_CMD_NVRAM_METADATA_OUT_LEN(0));
EFSYS_ASSERT3U(desclen, <=,
MC_CMD_NVRAM_METADATA_OUT_DESCRIPTION_MAXNUM);
if (size < desclen) {
rc = ENOSPC;
goto fail3;
}
memcpy(descp, MCDI_OUT2(req, char,
NVRAM_METADATA_OUT_DESCRIPTION),
desclen);
/* Ensure string is NUL terminated */
descp[desclen] = '\0';
}
}
return (0);
fail3:
EFSYS_PROBE(fail3);
fail2:
EFSYS_PROBE(fail2);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
__checkReturn int
efx_mcdi_nvram_info(
__in efx_nic_t *enp,
__in uint32_t partn,
__out_opt size_t *sizep,
__out_opt uint32_t *addressp,
__out_opt uint32_t *erase_sizep)
{
uint8_t payload[MAX(MC_CMD_NVRAM_INFO_IN_LEN,
MC_CMD_NVRAM_INFO_OUT_LEN)];
efx_mcdi_req_t req;
int rc;
(void) memset(payload, 0, sizeof (payload));
req.emr_cmd = MC_CMD_NVRAM_INFO;
req.emr_in_buf = payload;
req.emr_in_length = MC_CMD_NVRAM_INFO_IN_LEN;
req.emr_out_buf = payload;
req.emr_out_length = MC_CMD_NVRAM_INFO_OUT_LEN;
MCDI_IN_SET_DWORD(req, NVRAM_INFO_IN_TYPE, partn);
efx_mcdi_execute_quiet(enp, &req);
if (req.emr_rc != 0) {
rc = req.emr_rc;
goto fail1;
}
if (req.emr_out_length_used < MC_CMD_NVRAM_INFO_OUT_LEN) {
rc = EMSGSIZE;
goto fail2;
}
if (sizep)
*sizep = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_SIZE);
if (addressp)
*addressp = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_PHYSADDR);
if (erase_sizep)
*erase_sizep = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_ERASESIZE);
return (0);
fail2:
EFSYS_PROBE(fail2);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
__checkReturn int
efx_mcdi_nvram_update_start(
__in efx_nic_t *enp,
__in uint32_t partn)
{
uint8_t payload[MAX(MC_CMD_NVRAM_UPDATE_START_IN_LEN,
MC_CMD_NVRAM_UPDATE_START_OUT_LEN)];
efx_mcdi_req_t req;
int rc;
(void) memset(payload, 0, sizeof (payload));
req.emr_cmd = MC_CMD_NVRAM_UPDATE_START;
req.emr_in_buf = payload;
req.emr_in_length = MC_CMD_NVRAM_UPDATE_START_IN_LEN;
req.emr_out_buf = payload;
req.emr_out_length = MC_CMD_NVRAM_UPDATE_START_OUT_LEN;
MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_START_IN_TYPE, partn);
efx_mcdi_execute(enp, &req);
if (req.emr_rc != 0) {
rc = req.emr_rc;
goto fail1;
}
return (0);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
__checkReturn int
efx_mcdi_nvram_read(
__in efx_nic_t *enp,
__in uint32_t partn,
__in uint32_t offset,
__out_bcount(size) caddr_t data,
__in size_t size)
{
efx_mcdi_req_t req;
uint8_t payload[MAX(MC_CMD_NVRAM_READ_IN_LEN,
MC_CMD_NVRAM_READ_OUT_LENMAX)];
int rc;
if (size > MC_CMD_NVRAM_READ_OUT_LENMAX) {
rc = EINVAL;
goto fail1;
}
(void) memset(payload, 0, sizeof (payload));
req.emr_cmd = MC_CMD_NVRAM_READ;
req.emr_in_buf = payload;
req.emr_in_length = MC_CMD_NVRAM_READ_IN_LEN;
req.emr_out_buf = payload;
req.emr_out_length = MC_CMD_NVRAM_READ_OUT_LENMAX;
MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_TYPE, partn);
MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_OFFSET, offset);
MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_LENGTH, size);
efx_mcdi_execute(enp, &req);
if (req.emr_rc != 0) {
rc = req.emr_rc;
goto fail1;
}
if (req.emr_out_length_used < MC_CMD_NVRAM_READ_OUT_LEN(size)) {
rc = EMSGSIZE;
goto fail2;
}
memcpy(data,
MCDI_OUT2(req, uint8_t, NVRAM_READ_OUT_READ_BUFFER),
size);
return (0);
fail2:
EFSYS_PROBE(fail2);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
__checkReturn int
efx_mcdi_nvram_erase(
__in efx_nic_t *enp,
__in uint32_t partn,
__in uint32_t offset,
__in size_t size)
{
efx_mcdi_req_t req;
uint8_t payload[MAX(MC_CMD_NVRAM_ERASE_IN_LEN,
MC_CMD_NVRAM_ERASE_OUT_LEN)];
int rc;
(void) memset(payload, 0, sizeof (payload));
req.emr_cmd = MC_CMD_NVRAM_ERASE;
req.emr_in_buf = payload;
req.emr_in_length = MC_CMD_NVRAM_ERASE_IN_LEN;
req.emr_out_buf = payload;
req.emr_out_length = MC_CMD_NVRAM_ERASE_OUT_LEN;
MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_TYPE, partn);
MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_OFFSET, offset);
MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_LENGTH, size);
efx_mcdi_execute(enp, &req);
if (req.emr_rc != 0) {
rc = req.emr_rc;
goto fail1;
}
return (0);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
__checkReturn int
efx_mcdi_nvram_write(
__in efx_nic_t *enp,
__in uint32_t partn,
__in uint32_t offset,
__out_bcount(size) caddr_t data,
__in size_t size)
{
efx_mcdi_req_t req;
uint8_t payload[MAX(MC_CMD_NVRAM_WRITE_IN_LENMAX,
MC_CMD_NVRAM_WRITE_OUT_LEN)];
int rc;
if (size > MC_CMD_NVRAM_WRITE_IN_LENMAX) {
rc = EINVAL;
goto fail1;
}
(void) memset(payload, 0, sizeof (payload));
req.emr_cmd = MC_CMD_NVRAM_WRITE;
req.emr_in_buf = payload;
req.emr_in_length = MC_CMD_NVRAM_WRITE_IN_LEN(size);
req.emr_out_buf = payload;
req.emr_out_length = MC_CMD_NVRAM_WRITE_OUT_LEN;
MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_TYPE, partn);
MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_OFFSET, offset);
MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_LENGTH, size);
memcpy(MCDI_IN2(req, uint8_t, NVRAM_WRITE_IN_WRITE_BUFFER),
data, size);
efx_mcdi_execute(enp, &req);
if (req.emr_rc != 0) {
rc = req.emr_rc;
goto fail2;
}
return (0);
fail2:
EFSYS_PROBE(fail2);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
__checkReturn int
efx_mcdi_nvram_update_finish(
__in efx_nic_t *enp,
__in uint32_t partn,
__in boolean_t reboot)
{
efx_mcdi_req_t req;
uint8_t payload[MAX(MC_CMD_NVRAM_UPDATE_FINISH_IN_LEN,
MC_CMD_NVRAM_UPDATE_FINISH_OUT_LEN)];
int rc;
(void) memset(payload, 0, sizeof (payload));
req.emr_cmd = MC_CMD_NVRAM_UPDATE_FINISH;
req.emr_in_buf = payload;
req.emr_in_length = MC_CMD_NVRAM_UPDATE_FINISH_IN_LEN;
req.emr_out_buf = payload;
req.emr_out_length = MC_CMD_NVRAM_UPDATE_FINISH_OUT_LEN;
MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_FINISH_IN_TYPE, partn);
MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_FINISH_IN_REBOOT, reboot);
efx_mcdi_execute(enp, &req);
if (req.emr_rc != 0) {
rc = req.emr_rc;
goto fail1;
}
return (0);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
#if EFSYS_OPT_DIAG
__checkReturn int
efx_mcdi_nvram_test(
__in efx_nic_t *enp,
__in uint32_t partn)
{
efx_mcdi_req_t req;
uint8_t payload[MAX(MC_CMD_NVRAM_TEST_IN_LEN,
MC_CMD_NVRAM_TEST_OUT_LEN)];
int result;
int rc;
(void) memset(payload, 0, sizeof (payload));
req.emr_cmd = MC_CMD_NVRAM_TEST;
req.emr_in_buf = payload;
req.emr_in_length = MC_CMD_NVRAM_TEST_IN_LEN;
req.emr_out_buf = payload;
req.emr_out_length = MC_CMD_NVRAM_TEST_OUT_LEN;
MCDI_IN_SET_DWORD(req, NVRAM_TEST_IN_TYPE, partn);
efx_mcdi_execute(enp, &req);
if (req.emr_rc != 0) {
rc = req.emr_rc;
goto fail1;
}
if (req.emr_out_length_used < MC_CMD_NVRAM_TEST_OUT_LEN) {
rc = EMSGSIZE;
goto fail2;
}
result = MCDI_OUT_DWORD(req, NVRAM_TEST_OUT_RESULT);
if (result == MC_CMD_NVRAM_TEST_FAIL) {
EFSYS_PROBE1(nvram_test_failure, int, partn);
rc = (EINVAL);
goto fail3;
}
return (0);
fail3:
EFSYS_PROBE(fail3);
fail2:
EFSYS_PROBE(fail2);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
#endif /* EFSYS_OPT_DIAG */
#endif /* EFSYS_OPT_NVRAM || EFSYS_OPT_VPD */

View File

@ -1,26 +1,31 @@
/*-
* Copyright 2007-2009 Solarflare Communications Inc. All rights reserved.
* Copyright (c) 2007-2015 Solarflare Communications Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* modification, are permitted provided that the following conditions are met:
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the FreeBSD Project.
*/
#include <sys/cdefs.h>
@ -68,7 +73,7 @@ __FBSDID("$FreeBSD$");
#endif
#if EFSYS_OPT_PHY_NULL
static efx_phy_ops_t __cs __efx_phy_null_ops = {
static efx_phy_ops_t __efx_phy_null_ops = {
NULL, /* epo_power */
nullphy_reset, /* epo_reset */
nullphy_reconfigure, /* epo_reconfigure */
@ -86,16 +91,17 @@ static efx_phy_ops_t __cs __efx_phy_null_ops = {
nullphy_prop_get, /* epo_prop_get */
nullphy_prop_set, /* epo_prop_set */
#endif /* EFSYS_OPT_PHY_PROPS */
#if EFSYS_OPT_PHY_BIST
#if EFSYS_OPT_BIST
NULL, /* epo_bist_enable_offline */
NULL, /* epo_bist_start */
NULL, /* epo_bist_poll */
NULL, /* epo_bist_stop */
#endif /* EFSYS_OPT_PHY_BIST */
#endif /* EFSYS_OPT_BIST */
};
#endif /* EFSYS_OPT_PHY_NULL */
#if EFSYS_OPT_PHY_QT2022C2
static efx_phy_ops_t __cs __efx_phy_qt2022c2_ops = {
static efx_phy_ops_t __efx_phy_qt2022c2_ops = {
NULL, /* epo_power */
qt2022c2_reset, /* epo_reset */
qt2022c2_reconfigure, /* epo_reconfigure */
@ -113,16 +119,17 @@ static efx_phy_ops_t __cs __efx_phy_qt2022c2_ops = {
qt2022c2_prop_get, /* epo_prop_get */
qt2022c2_prop_set, /* epo_prop_set */
#endif /* EFSYS_OPT_PHY_PROPS */
#if EFSYS_OPT_PHY_BIST
#if EFSYS_OPT_BIST
NULL, /* epo_bist_enable_offline */
NULL, /* epo_bist_start */
NULL, /* epo_bist_poll */
NULL, /* epo_bist_stop */
#endif /* EFSYS_OPT_PHY_BIST */
#endif /* EFSYS_OPT_BIST */
};
#endif /* EFSYS_OPT_PHY_QT2022C2 */
#if EFSYS_OPT_PHY_SFX7101
static efx_phy_ops_t __cs __efx_phy_sfx7101_ops = {
static efx_phy_ops_t __efx_phy_sfx7101_ops = {
sfx7101_power, /* epo_power */
sfx7101_reset, /* epo_reset */
sfx7101_reconfigure, /* epo_reconfigure */
@ -140,16 +147,17 @@ static efx_phy_ops_t __cs __efx_phy_sfx7101_ops = {
sfx7101_prop_get, /* epo_prop_get */
sfx7101_prop_set, /* epo_prop_set */
#endif /* EFSYS_OPT_PHY_PROPS */
#if EFSYS_OPT_PHY_BIST
#if EFSYS_OPT_BIST
NULL, /* epo_bist_enable_offline */
NULL, /* epo_bist_start */
NULL, /* epo_bist_poll */
NULL, /* epo_bist_stop */
#endif /* EFSYS_OPT_PHY_BIST */
#endif /* EFSYS_OPT_BIST */
};
#endif /* EFSYS_OPT_PHY_SFX7101 */
#if EFSYS_OPT_PHY_TXC43128
static efx_phy_ops_t __cs __efx_phy_txc43128_ops = {
static efx_phy_ops_t __efx_phy_txc43128_ops = {
NULL, /* epo_power */
txc43128_reset, /* epo_reset */
txc43128_reconfigure, /* epo_reconfigure */
@ -167,16 +175,17 @@ static efx_phy_ops_t __cs __efx_phy_txc43128_ops = {
txc43128_prop_get, /* epo_prop_get */
txc43128_prop_set, /* epo_prop_set */
#endif /* EFSYS_OPT_PHY_PROPS */
#if EFSYS_OPT_PHY_BIST
#if EFSYS_OPT_BIST
NULL, /* epo_bist_enable_offline */
NULL, /* epo_bist_start */
NULL, /* epo_bist_poll */
NULL, /* epo_bist_stop */
#endif /* EFSYS_OPT_PHY_BIST */
#endif /* EFSYS_OPT_BIST */
};
#endif /* EFSYS_OPT_PHY_TXC43128 */
#if EFSYS_OPT_PHY_SFT9001
static efx_phy_ops_t __cs __efx_phy_sft9001_ops = {
static efx_phy_ops_t __efx_phy_sft9001_ops = {
NULL, /* epo_power */
sft9001_reset, /* epo_reset */
sft9001_reconfigure, /* epo_reconfigure */
@ -194,16 +203,17 @@ static efx_phy_ops_t __cs __efx_phy_sft9001_ops = {
sft9001_prop_get, /* epo_prop_get */
sft9001_prop_set, /* epo_prop_set */
#endif /* EFSYS_OPT_PHY_PROPS */
#if EFSYS_OPT_PHY_BIST
#if EFSYS_OPT_BIST
NULL, /* epo_bist_enable_offline */
sft9001_bist_start, /* epo_bist_start */
sft9001_bist_poll, /* epo_bist_poll */
sft9001_bist_stop, /* epo_bist_stop */
#endif /* EFSYS_OPT_PHY_BIST */
#endif /* EFSYS_OPT_BIST */
};
#endif /* EFSYS_OPT_PHY_SFT9001 */
#if EFSYS_OPT_PHY_QT2025C
static efx_phy_ops_t __cs __efx_phy_qt2025c_ops = {
static efx_phy_ops_t __efx_phy_qt2025c_ops = {
NULL, /* epo_power */
qt2025c_reset, /* epo_reset */
qt2025c_reconfigure, /* epo_reconfigure */
@ -221,16 +231,17 @@ static efx_phy_ops_t __cs __efx_phy_qt2025c_ops = {
qt2025c_prop_get, /* epo_prop_get */
qt2025c_prop_set, /* epo_prop_set */
#endif /* EFSYS_OPT_PHY_PROPS */
#if EFSYS_OPT_PHY_BIST
#if EFSYS_OPT_BIST
NULL, /* epo_bist_enable_offline */
NULL, /* epo_bist_start */
NULL, /* epo_bist_poll */
NULL, /* epo_bist_stop */
#endif /* EFSYS_OPT_PHY_BIST */
#endif /* EFSYS_OPT_BIST */
};
#endif /* EFSYS_OPT_PHY_QT2025C */
#if EFSYS_OPT_SIENA
static efx_phy_ops_t __cs __efx_phy_siena_ops = {
static efx_phy_ops_t __efx_phy_siena_ops = {
siena_phy_power, /* epo_power */
NULL, /* epo_reset */
siena_phy_reconfigure, /* epo_reconfigure */
@ -248,14 +259,43 @@ static efx_phy_ops_t __cs __efx_phy_siena_ops = {
siena_phy_prop_get, /* epo_prop_get */
siena_phy_prop_set, /* epo_prop_set */
#endif /* EFSYS_OPT_PHY_PROPS */
#if EFSYS_OPT_PHY_BIST
#if EFSYS_OPT_BIST
NULL, /* epo_bist_enable_offline */
siena_phy_bist_start, /* epo_bist_start */
siena_phy_bist_poll, /* epo_bist_poll */
siena_phy_bist_stop, /* epo_bist_stop */
#endif /* EFSYS_OPT_PHY_BIST */
#endif /* EFSYS_OPT_BIST */
};
#endif /* EFSYS_OPT_SIENA */
#if EFSYS_OPT_HUNTINGTON
static efx_phy_ops_t __efx_phy_hunt_ops = {
hunt_phy_power, /* epo_power */
NULL, /* epo_reset */
hunt_phy_reconfigure, /* epo_reconfigure */
hunt_phy_verify, /* epo_verify */
NULL, /* epo_uplink_check */
NULL, /* epo_downlink_check */
hunt_phy_oui_get, /* epo_oui_get */
#if EFSYS_OPT_PHY_STATS
hunt_phy_stats_update, /* epo_stats_update */
#endif /* EFSYS_OPT_PHY_STATS */
#if EFSYS_OPT_PHY_PROPS
#if EFSYS_OPT_NAMES
hunt_phy_prop_name, /* epo_prop_name */
#endif
hunt_phy_prop_get, /* epo_prop_get */
hunt_phy_prop_set, /* epo_prop_set */
#endif /* EFSYS_OPT_PHY_PROPS */
#if EFSYS_OPT_BIST
hunt_bist_enable_offline, /* epo_bist_enable_offline */
hunt_bist_start, /* epo_bist_start */
hunt_bist_poll, /* epo_bist_poll */
hunt_bist_stop, /* epo_bist_stop */
#endif /* EFSYS_OPT_BIST */
};
#endif /* EFSYS_OPT_HUNTINGTON */
__checkReturn int
efx_phy_probe(
__in efx_nic_t *enp)
@ -317,6 +357,11 @@ efx_phy_probe(
epop = (efx_phy_ops_t *)&__efx_phy_siena_ops;
break;
#endif /* EFSYS_OPT_SIENA */
#if EFSYS_OPT_HUNTINGTON
case EFX_FAMILY_HUNTINGTON:
epop = (efx_phy_ops_t *)&__efx_phy_hunt_ops;
break;
#endif /* EFSYS_OPT_HUNTINGTON */
default:
rc = ENOTSUP;
goto fail1;
@ -516,8 +561,8 @@ efx_phy_media_type_get(
#if EFSYS_OPT_NAMES
/* START MKCONFIG GENERATED PhyStatNamesBlock 271268f3da0e804f */
static const char __cs * __cs __efx_phy_stat_name[] = {
/* START MKCONFIG GENERATED PhyStatNamesBlock d5f79b4bc2c050fe */
static const char *__efx_phy_stat_name[] = {
"oui",
"pma_pmd_link_up",
"pma_pmd_rx_fault",
@ -568,7 +613,7 @@ static const char __cs * __cs __efx_phy_stat_name[] = {
/* END MKCONFIG GENERATED PhyStatNamesBlock */
const char __cs *
const char *
efx_phy_stat_name(
__in efx_nic_t *enp,
__in efx_phy_stat_t type)
@ -602,7 +647,7 @@ efx_phy_stats_update(
#if EFSYS_OPT_PHY_PROPS
#if EFSYS_OPT_NAMES
const char __cs *
const char *
efx_phy_prop_name(
__in efx_nic_t *enp,
__in unsigned int id)
@ -649,23 +694,51 @@ efx_phy_prop_set(
}
#endif /* EFSYS_OPT_PHY_STATS */
#if EFSYS_OPT_PHY_BIST
#if EFSYS_OPT_BIST
__checkReturn int
efx_phy_bist_start(
__in efx_nic_t *enp,
__in efx_phy_bist_type_t type)
efx_bist_enable_offline(
__in efx_nic_t *enp)
{
efx_port_t *epp = &(enp->en_port);
efx_phy_ops_t *epop = epp->ep_epop;
int rc;
EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
EFSYS_ASSERT3U(type, !=, EFX_PHY_BIST_TYPE_UNKNOWN);
EFSYS_ASSERT3U(type, <, EFX_PHY_BIST_TYPE_NTYPES);
EFSYS_ASSERT3U(epp->ep_current_bist, ==, EFX_PHY_BIST_TYPE_UNKNOWN);
if (epop->epo_bist_enable_offline == NULL) {
rc = ENOTSUP;
goto fail1;
}
if ((rc = epop->epo_bist_enable_offline(enp)) != 0)
goto fail2;
return (0);
fail2:
EFSYS_PROBE(fail2);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
__checkReturn int
efx_bist_start(
__in efx_nic_t *enp,
__in efx_bist_type_t type)
{
efx_port_t *epp = &(enp->en_port);
efx_phy_ops_t *epop = epp->ep_epop;
int rc;
EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
EFSYS_ASSERT3U(type, !=, EFX_BIST_TYPE_UNKNOWN);
EFSYS_ASSERT3U(type, <, EFX_BIST_TYPE_NTYPES);
EFSYS_ASSERT3U(epp->ep_current_bist, ==, EFX_BIST_TYPE_UNKNOWN);
if (epop->epo_bist_start == NULL) {
rc = ENOTSUP;
@ -688,10 +761,10 @@ efx_phy_bist_start(
}
__checkReturn int
efx_phy_bist_poll(
efx_bist_poll(
__in efx_nic_t *enp,
__in efx_phy_bist_type_t type,
__out efx_phy_bist_result_t *resultp,
__in efx_bist_type_t type,
__out efx_bist_result_t *resultp,
__out_opt uint32_t *value_maskp,
__out_ecount_opt(count) unsigned long *valuesp,
__in size_t count)
@ -701,10 +774,9 @@ efx_phy_bist_poll(
int rc;
EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
EFSYS_ASSERT3U(type, !=, EFX_PHY_BIST_TYPE_UNKNOWN);
EFSYS_ASSERT3U(type, <, EFX_PHY_BIST_TYPE_NTYPES);
EFSYS_ASSERT3U(type, !=, EFX_BIST_TYPE_UNKNOWN);
EFSYS_ASSERT3U(type, <, EFX_BIST_TYPE_NTYPES);
EFSYS_ASSERT3U(epp->ep_current_bist, ==, type);
EFSYS_ASSERT(epop->epo_bist_poll != NULL);
@ -728,18 +800,17 @@ efx_phy_bist_poll(
}
void
efx_phy_bist_stop(
efx_bist_stop(
__in efx_nic_t *enp,
__in efx_phy_bist_type_t type)
__in efx_bist_type_t type)
{
efx_port_t *epp = &(enp->en_port);
efx_phy_ops_t *epop = epp->ep_epop;
EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
EFSYS_ASSERT3U(type, !=, EFX_PHY_BIST_TYPE_UNKNOWN);
EFSYS_ASSERT3U(type, <, EFX_PHY_BIST_TYPE_NTYPES);
EFSYS_ASSERT3U(type, !=, EFX_BIST_TYPE_UNKNOWN);
EFSYS_ASSERT3U(type, <, EFX_BIST_TYPE_NTYPES);
EFSYS_ASSERT3U(epp->ep_current_bist, ==, type);
EFSYS_ASSERT(epop->epo_bist_stop != NULL);
@ -747,10 +818,10 @@ efx_phy_bist_stop(
if (epop->epo_bist_stop != NULL)
epop->epo_bist_stop(enp, type);
epp->ep_current_bist = EFX_PHY_BIST_TYPE_UNKNOWN;
epp->ep_current_bist = EFX_BIST_TYPE_UNKNOWN;
}
#endif /* EFSYS_OPT_PHY_BIST */
#endif /* EFSYS_OPT_BIST */
void
efx_phy_unprobe(
__in efx_nic_t *enp)

View File

@ -0,0 +1,53 @@
/*-
* Copyright (c) 2013-2015 Solarflare Communications Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the FreeBSD Project.
*
* $FreeBSD$
*/
#ifndef _SYS_EFX_PHY_IDS_H
#define _SYS_EFX_PHY_IDS_H
#define EFX_PHY_NULL 0
typedef enum efx_phy_type_e { /* GENERATED BY scripts/genfwdef */
EFX_PHY_TXC43128 = 1,
EFX_PHY_SFX7101 = 3,
EFX_PHY_QT2022C2 = 4,
EFX_PHY_PM8358 = 6,
EFX_PHY_SFT9001A = 8,
EFX_PHY_QT2025C = 9,
EFX_PHY_SFT9001B = 10,
EFX_PHY_QLX111V = 12,
EFX_PHY_QT2025_KR = 17,
EFX_PHY_AEL3020 = 18,
EFX_PHY_XFI_FARMI = 19,
} efx_phy_type_t;
#endif /* _SYS_EFX_PHY_IDS_H */

View File

@ -1,26 +1,31 @@
/*-
* Copyright 2009 Solarflare Communications Inc. All rights reserved.
* Copyright (c) 2009-2015 Solarflare Communications Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* modification, are permitted provided that the following conditions are met:
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the FreeBSD Project.
*/
#include <sys/cdefs.h>
@ -61,6 +66,9 @@ efx_port_init(
epp->ep_emop->emo_reconfigure(enp);
/* Pick up current phy capababilities */
efx_port_poll(enp, NULL);
/*
* Turn on the PHY if available, otherwise reset it, and
* reconfigure it with the current configuration.
@ -96,7 +104,7 @@ efx_port_init(
__checkReturn int
efx_port_poll(
__in efx_nic_t *enp,
__out efx_link_mode_t *link_modep)
__out_opt efx_link_mode_t *link_modep)
{
efx_port_t *epp = &(enp->en_port);
efx_mac_ops_t *emop = epp->ep_emop;
@ -141,7 +149,9 @@ efx_port_loopback_set(
EFSYS_ASSERT(emop != NULL);
EFSYS_ASSERT(link_mode < EFX_LINK_NMODES);
if ((1 << loopback_type) & ~encp->enc_loopback_types[link_mode]) {
if (EFX_TEST_QWORD_BIT(encp->enc_loopback_types[link_mode],
loopback_type) == 0) {
rc = ENOTSUP;
goto fail1;
}
@ -165,7 +175,7 @@ efx_port_loopback_set(
#if EFSYS_OPT_NAMES
static const char __cs * __cs __efx_loopback_type_name[] = {
static const char *__efx_loopback_type_name[] = {
"OFF",
"DATA",
"GMAC",
@ -184,13 +194,33 @@ static const char __cs * __cs __efx_loopback_type_name[] = {
"PHY_XS",
"PCS",
"PMA_PMD",
"XPORT",
"XGMII_WS",
"XAUI_WS",
"XAUI_WS_FAR",
"XAUI_WS_NEAR",
"GMII_WS",
"XFI_WS",
"XFI_WS_FAR",
"PHYXS_WS",
"PMA_INT",
"SD_NEAR",
"SD_FAR",
"PMA_INT_WS",
"SD_FEP2_WS",
"SD_FEP1_5_WS",
"SD_FEP_WS",
"SD_FES_WS",
};
__checkReturn const char __cs *
__checkReturn const char *
efx_loopback_type_name(
__in efx_nic_t *enp,
__in efx_loopback_type_t type)
{
EFX_STATIC_ASSERT(EFX_ARRAY_SIZE(__efx_loopback_type_name) ==
EFX_LOOPBACK_NTYPES);
_NOTE(ARGUNUSED(enp))
EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
EFSYS_ASSERT3U(type, <, EFX_LOOPBACK_NTYPES);

View File

@ -1,26 +1,31 @@
/*-
* Copyright 2007-2009 Solarflare Communications Inc. All rights reserved.
* Copyright (c) 2007-2015 Solarflare Communications Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* modification, are permitted provided that the following conditions are met:
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the FreeBSD Project.
*
* $FreeBSD$
*/
@ -3854,7 +3859,7 @@ extern "C" {
*/
#define FR_AZ_TX_PACE_TBL_OFST FR_BZ_TX_PACE_TBL_OFST
#define FR_AZ_TX_PACE_TBL_OFST FR_BZ_TX_PACE_TBL_OFST
#ifdef __cplusplus

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,26 +1,31 @@
/*-
* Copyright 2007-2009 Solarflare Communications Inc. All rights reserved.
* Copyright (c) 2007-2015 Solarflare Communications Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* modification, are permitted provided that the following conditions are met:
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the FreeBSD Project.
*/
#include <sys/cdefs.h>
@ -50,6 +55,21 @@ efx_sram_buf_tbl_set(
EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC);
#if EFSYS_OPT_HUNTINGTON
if (enp->en_family == EFX_FAMILY_HUNTINGTON) {
/*
* FIXME: the efx_sram_buf_tbl_*() functionality needs to be
* pulled inside the Falcon/Siena queue create/destroy code,
* and then the original functions can be removed (see bug30834
* comment #1). But, for now, we just ensure that they are
* no-ops for Huntington, to allow bringing up existing drivers
* without modification.
*/
return (0);
}
#endif /* EFSYS_OPT_HUNTINGTON */
if (stop >= EFX_BUF_TBL_SIZE) {
rc = EFBIG;
goto fail1;
@ -156,6 +176,21 @@ efx_sram_buf_tbl_clear(
EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC);
#if EFSYS_OPT_HUNTINGTON
if (enp->en_family == EFX_FAMILY_HUNTINGTON) {
/*
* FIXME: the efx_sram_buf_tbl_*() functionality needs to be
* pulled inside the Falcon/Siena queue create/destroy code,
* and then the original functions can be removed (see bug30834
* comment #1). But, for now, we just ensure that they are
* no-ops for Huntington, to allow bringing up existing drivers
* without modification.
*/
return;
}
#endif /* EFSYS_OPT_HUNTINGTON */
EFSYS_ASSERT3U(stop, <, EFX_BUF_TBL_SIZE);
EFSYS_PROBE2(buf, uint32_t, start, uint32_t, stop - 1);
@ -262,7 +297,7 @@ efx_sram_bit_sweep_set(
}
}
efx_sram_pattern_fn_t __cs __efx_sram_pattern_fns[] = {
efx_sram_pattern_fn_t __efx_sram_pattern_fns[] = {
efx_sram_byte_increment_set,
efx_sram_all_the_same_set,
efx_sram_bit_alternate_set,

File diff suppressed because it is too large Load Diff

View File

@ -1,26 +1,31 @@
/*-
* Copyright 2007-2009 Solarflare Communications Inc. All rights reserved.
* Copyright (c) 2007-2015 Solarflare Communications Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* modification, are permitted provided that the following conditions are met:
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the FreeBSD Project.
*
* Ackowledgement to Fen Systems Ltd.
*
@ -113,11 +118,10 @@ extern "C" {
#define EFX_DWORD_3_LBN 96
#define EFX_DWORD_3_WIDTH 32
#define EFX_QWORD_0_LBN 0
#define EFX_QWORD_0_WIDTH 64
#define EFX_QWORD_1_LBN 64
#define EFX_QWORD_1_WIDTH 64
/* There are intentionally no EFX_QWORD_0 or EFX_QWORD_1 field definitions
* here as the implementaion of EFX_QWORD_FIELD and EFX_OWORD_FIELD do not
* support field widths larger than 32 bits.
*/
/* Specified attribute (i.e. LBN ow WIDTH) of the specified field */
#define EFX_VAL(_field, _attribute) \
@ -229,6 +233,9 @@ typedef union efx_oword_u {
efx_word_t eo_word[8];
efx_dword_t eo_dword[4];
efx_qword_t eo_qword[2];
#if EFSYS_HAS_SSE2_M128
__m128i eo_u128[1];
#endif
#if EFSYS_HAS_UINT64
uint64_t eo_u64[2];
#endif
@ -891,11 +898,7 @@ extern int fix_lint;
#define EFX_ZERO_OWORD(_oword) \
EFX_POPULATE_OWORD_1(_oword, EFX_DUMMY_FIELD, 0)
#define EFX_SET_OWORD64(_oword) \
EFX_POPULATE_OWORD_2(_oword, \
EFX_QWORD_0, (uint64_t)-1, EFX_QWORD_1, (uint64_t)-1)
#define EFX_SET_OWORD32(_oword) \
#define EFX_SET_OWORD(_oword) \
EFX_POPULATE_OWORD_4(_oword, \
EFX_DWORD_0, 0xffffffff, EFX_DWORD_1, 0xffffffff, \
EFX_DWORD_2, 0xffffffff, EFX_DWORD_3, 0xffffffff)
@ -969,11 +972,7 @@ extern int fix_lint;
#define EFX_ZERO_QWORD(_qword) \
EFX_POPULATE_QWORD_1(_qword, EFX_DUMMY_FIELD, 0)
#define EFX_SET_QWORD64(_qword) \
EFX_POPULATE_QWORD_1(_qword, \
EFX_QWORD_0, (uint64_t)-1)
#define EFX_SET_QWORD32(_qword) \
#define EFX_SET_QWORD(_qword) \
EFX_POPULATE_QWORD_2(_qword, \
EFX_DWORD_0, 0xffffffff, EFX_DWORD_1, 0xffffffff)
@ -1380,6 +1379,23 @@ extern int fix_lint;
_NOTE(CONSTANTCONDITION) \
} while (B_FALSE)
#define EFX_TEST_OWORD_BIT64(_oword, _bit) \
(((_oword).eo_u64[0] & \
__CPU_TO_LE_64(EFX_SHIFT64(_bit, FIX_LINT(0)))) || \
((_oword).eo_u64[1] & \
__CPU_TO_LE_64(EFX_SHIFT64(_bit, FIX_LINT(64)))))
#define EFX_TEST_OWORD_BIT32(_oword, _bit) \
(((_oword).eo_u32[0] & \
__CPU_TO_LE_32(EFX_SHIFT32(_bit, FIX_LINT(0)))) || \
((_oword).eo_u32[1] & \
__CPU_TO_LE_32(EFX_SHIFT32(_bit, FIX_LINT(32)))) || \
((_oword).eo_u32[2] & \
__CPU_TO_LE_32(EFX_SHIFT32(_bit, FIX_LINT(64)))) || \
((_oword).eo_u32[3] & \
__CPU_TO_LE_32(EFX_SHIFT32(_bit, FIX_LINT(96)))))
#define EFX_SET_QWORD_BIT64(_qword, _bit) \
do { \
_NOTE(CONSTANTCONDITION) \
@ -1416,6 +1432,17 @@ extern int fix_lint;
_NOTE(CONSTANTCONDITION) \
} while (B_FALSE)
#define EFX_TEST_QWORD_BIT64(_qword, _bit) \
(((_qword).eq_u64[0] & \
__CPU_TO_LE_64(EFX_SHIFT64(_bit, FIX_LINT(0)))) != 0)
#define EFX_TEST_QWORD_BIT32(_qword, _bit) \
(((_qword).eq_u32[0] & \
__CPU_TO_LE_32(EFX_SHIFT32(_bit, FIX_LINT(0)))) || \
((_qword).eq_u32[1] & \
__CPU_TO_LE_32(EFX_SHIFT32(_bit, FIX_LINT(32)))))
#define EFX_SET_DWORD_BIT(_dword, _bit) \
do { \
(_dword).ed_u32[0] |= \
@ -1430,6 +1457,11 @@ extern int fix_lint;
_NOTE(CONSTANTCONDITION) \
} while (B_FALSE)
#define EFX_TEST_DWORD_BIT(_dword, _bit) \
(((_dword).ed_u32[0] & \
__CPU_TO_LE_32(EFX_SHIFT32(_bit, FIX_LINT(0)))) != 0)
#define EFX_SET_WORD_BIT(_word, _bit) \
do { \
(_word).ew_u16[0] |= \
@ -1444,6 +1476,11 @@ extern int fix_lint;
_NOTE(CONSTANTCONDITION) \
} while (B_FALSE)
#define EFX_TEST_WORD_BIT(_word, _bit) \
(((_word).ew_u16[0] & \
__CPU_TO_LE_16(EFX_SHIFT16(_bit, FIX_LINT(0)))) != 0)
#define EFX_SET_BYTE_BIT(_byte, _bit) \
do { \
(_byte).eb_u8[0] |= \
@ -1458,6 +1495,11 @@ extern int fix_lint;
_NOTE(CONSTANTCONDITION) \
} while (B_FALSE)
#define EFX_TEST_BYTE_BIT(_byte, _bit) \
(((_byte).eb_u8[0] & \
__NATIVE_8(EFX_SHIFT8(_bit, FIX_LINT(0)))) != 0)
#define EFX_OR_OWORD64(_oword1, _oword2) \
do { \
(_oword1).eo_u64[0] |= (_oword2).eo_u64[0]; \
@ -1563,18 +1605,18 @@ extern int fix_lint;
#define EFX_QWORD_IS_SET EFX_QWORD_IS_SET64
#define EFX_POPULATE_OWORD EFX_POPULATE_OWORD64
#define EFX_POPULATE_QWORD EFX_POPULATE_QWORD64
#define EFX_SET_OWORD EFX_SET_OWORD64
#define EFX_SET_QWORD EFX_SET_QWORD64
#define EFX_SET_OWORD_FIELD EFX_SET_OWORD_FIELD64
#define EFX_SET_QWORD_FIELD EFX_SET_QWORD_FIELD64
#define EFX_SET_OWORD_BIT EFX_SET_OWORD_BIT64
#define EFX_CLEAR_OWORD_BIT EFX_CLEAR_OWORD_BIT64
#define EFX_TEST_OWORD_BIT EFX_TEST_OWORD_BIT64
#define EFX_SET_QWORD_BIT EFX_SET_QWORD_BIT64
#define EFX_CLEAR_QWORD_BIT EFX_CLEAR_QWORD_BIT64
#define EFX_TEST_QWORD_BIT EFX_TEST_QWORD_BIT64
#define EFX_OR_OWORD EFX_OR_OWORD64
#define EFX_AND_OWORD EFX_AND_OWORD64
#define EFX_OR_QWORD EFX_OR_QWORD64
#define EFX_AND_QWORD EFX_OR_QWORD64
#define EFX_AND_QWORD EFX_AND_QWORD64
#else
#define EFX_OWORD_FIELD EFX_OWORD_FIELD32
#define EFX_QWORD_FIELD EFX_QWORD_FIELD32
@ -1586,18 +1628,18 @@ extern int fix_lint;
#define EFX_QWORD_IS_SET EFX_QWORD_IS_SET32
#define EFX_POPULATE_OWORD EFX_POPULATE_OWORD32
#define EFX_POPULATE_QWORD EFX_POPULATE_QWORD32
#define EFX_SET_OWORD EFX_SET_OWORD32
#define EFX_SET_QWORD EFX_SET_QWORD32
#define EFX_SET_OWORD_FIELD EFX_SET_OWORD_FIELD32
#define EFX_SET_QWORD_FIELD EFX_SET_QWORD_FIELD32
#define EFX_SET_OWORD_BIT EFX_SET_OWORD_BIT32
#define EFX_CLEAR_OWORD_BIT EFX_CLEAR_OWORD_BIT32
#define EFX_TEST_OWORD_BIT EFX_TEST_OWORD_BIT32
#define EFX_SET_QWORD_BIT EFX_SET_QWORD_BIT32
#define EFX_CLEAR_QWORD_BIT EFX_CLEAR_QWORD_BIT32
#define EFX_TEST_QWORD_BIT EFX_TEST_QWORD_BIT32
#define EFX_OR_OWORD EFX_OR_OWORD32
#define EFX_AND_OWORD EFX_AND_OWORD32
#define EFX_OR_QWORD EFX_OR_QWORD32
#define EFX_AND_QWORD EFX_OR_QWORD32
#define EFX_AND_QWORD EFX_AND_QWORD32
#endif
#ifdef __cplusplus

View File

@ -1,26 +1,31 @@
/*-
* Copyright 2009 Solarflare Communications Inc. All rights reserved.
* Copyright (c) 2009-2015 Solarflare Communications Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* modification, are permitted provided that the following conditions are met:
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the FreeBSD Project.
*/
#include <sys/cdefs.h>
@ -54,7 +59,7 @@ __FBSDID("$FreeBSD$");
#if EFSYS_OPT_FALCON
static efx_vpd_ops_t __cs __efx_vpd_falcon_ops = {
static efx_vpd_ops_t __efx_vpd_falcon_ops = {
NULL, /* evpdo_init */
falcon_vpd_size, /* evpdo_size */
falcon_vpd_read, /* evpdo_read */
@ -71,7 +76,7 @@ static efx_vpd_ops_t __cs __efx_vpd_falcon_ops = {
#if EFSYS_OPT_SIENA
static efx_vpd_ops_t __cs __efx_vpd_siena_ops = {
static efx_vpd_ops_t __efx_vpd_siena_ops = {
siena_vpd_init, /* evpdo_init */
siena_vpd_size, /* evpdo_size */
siena_vpd_read, /* evpdo_read */
@ -86,6 +91,23 @@ static efx_vpd_ops_t __cs __efx_vpd_siena_ops = {
#endif /* EFSYS_OPT_SIENA */
#if EFSYS_OPT_HUNTINGTON
static efx_vpd_ops_t __efx_vpd_hunt_ops = {
hunt_vpd_init, /* evpdo_init */
hunt_vpd_size, /* evpdo_size */
hunt_vpd_read, /* evpdo_read */
hunt_vpd_verify, /* evpdo_verify */
hunt_vpd_reinit, /* evpdo_reinit */
hunt_vpd_get, /* evpdo_get */
hunt_vpd_set, /* evpdo_set */
hunt_vpd_next, /* evpdo_next */
hunt_vpd_write, /* evpdo_write */
hunt_vpd_fini, /* evpdo_fini */
};
#endif /* EFSYS_OPT_HUNTINGTON */
__checkReturn int
efx_vpd_init(
__in efx_nic_t *enp)
@ -110,6 +132,12 @@ efx_vpd_init(
break;
#endif /* EFSYS_OPT_SIENA */
#if EFSYS_OPT_HUNTINGTON
case EFX_FAMILY_HUNTINGTON:
evpdop = (efx_vpd_ops_t *)&__efx_vpd_hunt_ops;
break;
#endif /* EFSYS_OPT_HUNTINGTON */
default:
EFSYS_ASSERT(0);
rc = ENOTSUP;
@ -566,14 +594,14 @@ efx_vpd_hunk_verify(
return (rc);
}
static uint8_t __cs __efx_vpd_blank_pid[] = {
static uint8_t __efx_vpd_blank_pid[] = {
/* Large resource type ID length 1 */
0x82, 0x01, 0x00,
/* Product name ' ' */
0x32,
};
static uint8_t __cs __efx_vpd_blank_r[] = {
static uint8_t __efx_vpd_blank_r[] = {
/* Large resource type VPD-R length 4 */
0x90, 0x04, 0x00,
/* RV keyword length 1 */
@ -584,7 +612,7 @@ static uint8_t __cs __efx_vpd_blank_r[] = {
__checkReturn int
efx_vpd_hunk_reinit(
__in caddr_t data,
__in_bcount(size) caddr_t data,
__in size_t size,
__in boolean_t wantpid)
{

View File

@ -1,26 +1,31 @@
/*-
* Copyright 2009 Solarflare Communications Inc. All rights reserved.
* Copyright (c) 2009-2015 Solarflare Communications Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* modification, are permitted provided that the following conditions are met:
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the FreeBSD Project.
*/
#include <sys/cdefs.h>
@ -67,17 +72,19 @@ efx_wol_filter_clear(
__in efx_nic_t *enp)
{
efx_mcdi_req_t req;
uint8_t payload[MC_CMD_WOL_FILTER_RESET_IN_LEN];
uint8_t payload[MAX(MC_CMD_WOL_FILTER_RESET_IN_LEN,
MC_CMD_WOL_FILTER_RESET_OUT_LEN)];
int rc;
EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_WOL);
(void) memset(payload, 0, sizeof (payload));
req.emr_cmd = MC_CMD_WOL_FILTER_RESET;
req.emr_in_buf = payload;
req.emr_in_length = MC_CMD_WOL_FILTER_RESET_IN_LEN;
req.emr_out_buf = NULL;
req.emr_out_length = 0;
req.emr_out_buf = payload;
req.emr_out_length = MC_CMD_WOL_FILTER_RESET_OUT_LEN;
MCDI_IN_SET_DWORD(req, WOL_FILTER_RESET_IN_MASK,
MC_CMD_WOL_FILTER_RESET_IN_WAKE_FILTERS |
@ -114,8 +121,8 @@ efx_wol_filter_add(
EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_WOL);
(void) memset(payload, 0, sizeof (payload));
req.emr_cmd = MC_CMD_WOL_FILTER_SET;
(void) memset(payload, '\0', sizeof (payload));
req.emr_in_buf = payload;
req.emr_in_length = MC_CMD_WOL_FILTER_SET_IN_LEN;
req.emr_out_buf = payload;
@ -226,18 +233,19 @@ efx_wol_filter_remove(
__in uint32_t filter_id)
{
efx_mcdi_req_t req;
uint8_t payload[MC_CMD_WOL_FILTER_REMOVE_IN_LEN];
uint8_t payload[MAX(MC_CMD_WOL_FILTER_REMOVE_IN_LEN,
MC_CMD_WOL_FILTER_REMOVE_OUT_LEN)];
int rc;
EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_WOL);
(void) memset(payload, 0, sizeof (payload));
req.emr_cmd = MC_CMD_WOL_FILTER_REMOVE;
req.emr_in_buf = payload;
req.emr_in_length = MC_CMD_WOL_FILTER_REMOVE_IN_LEN;
EFX_STATIC_ASSERT(MC_CMD_WOL_FILTER_REMOVE_OUT_LEN == 0);
req.emr_out_buf = NULL;
req.emr_out_length = 0;
req.emr_out_buf = payload;
req.emr_out_length = MC_CMD_WOL_FILTER_REMOVE_OUT_LEN;
MCDI_IN_SET_DWORD(req, WOL_FILTER_REMOVE_IN_FILTER_ID, filter_id);
@ -273,6 +281,7 @@ efx_lightsout_offload_add(
EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_WOL);
(void) memset(payload, 0, sizeof (payload));
req.emr_cmd = MC_CMD_ADD_LIGHTSOUT_OFFLOAD;
req.emr_in_buf = payload;
req.emr_in_length = sizeof (type);
@ -282,6 +291,7 @@ efx_lightsout_offload_add(
switch (type) {
case EFX_LIGHTSOUT_OFFLOAD_TYPE_ARP:
req.emr_in_length = MC_CMD_ADD_LIGHTSOUT_OFFLOAD_IN_ARP_LEN;
MCDI_IN_SET_DWORD(req, ADD_LIGHTSOUT_OFFLOAD_IN_PROTOCOL,
MC_CMD_LIGHTSOUT_OFFLOAD_PROTOCOL_ARP);
EFX_MAC_ADDR_COPY(MCDI_IN2(req, uint8_t,
@ -292,6 +302,7 @@ efx_lightsout_offload_add(
break;
case EFX_LIGHTSOUT_OFFLOAD_TYPE_NS:
req.emr_in_length = MC_CMD_ADD_LIGHTSOUT_OFFLOAD_IN_NS_LEN;
MCDI_IN_SET_DWORD(req, ADD_LIGHTSOUT_OFFLOAD_IN_PROTOCOL,
MC_CMD_LIGHTSOUT_OFFLOAD_PROTOCOL_NS);
EFX_MAC_ADDR_COPY(MCDI_IN2(req, uint8_t,
@ -305,25 +316,28 @@ efx_lightsout_offload_add(
paramp->elop_ns.ip, sizeof (paramp->elop_ns.ip));
break;
default:
EFSYS_ASSERT3U(type, !=, type);
rc = EINVAL;
goto fail1;
}
efx_mcdi_execute(enp, &req);
if (req.emr_rc != 0) {
rc = req.emr_rc;
goto fail1;
goto fail2;
}
if (req.emr_out_length_used < MC_CMD_ADD_LIGHTSOUT_OFFLOAD_OUT_LEN) {
rc = EMSGSIZE;
goto fail2;
goto fail3;
}
*filter_idp = MCDI_OUT_DWORD(req, ADD_LIGHTSOUT_OFFLOAD_OUT_FILTER_ID);
return (0);
fail3:
EFSYS_PROBE(fail3);
fail2:
EFSYS_PROBE(fail2);
fail1:
@ -340,18 +354,19 @@ efx_lightsout_offload_remove(
__in uint32_t filter_id)
{
efx_mcdi_req_t req;
uint8_t payload[MC_CMD_REMOVE_LIGHTSOUT_OFFLOAD_IN_LEN];
uint8_t payload[MAX(MC_CMD_REMOVE_LIGHTSOUT_OFFLOAD_IN_LEN,
MC_CMD_REMOVE_LIGHTSOUT_OFFLOAD_OUT_LEN)];
int rc;
EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_WOL);
(void) memset(payload, 0, sizeof (payload));
req.emr_cmd = MC_CMD_REMOVE_LIGHTSOUT_OFFLOAD;
req.emr_in_buf = payload;
req.emr_in_length = sizeof (payload);
EFX_STATIC_ASSERT(MC_CMD_REMOVE_LIGHTSOUT_OFFLOAD_OUT_LEN == 0);
req.emr_out_buf = NULL;
req.emr_out_length = 0;
req.emr_in_length = MC_CMD_REMOVE_LIGHTSOUT_OFFLOAD_IN_LEN;
req.emr_out_buf = payload;
req.emr_out_length = MC_CMD_REMOVE_LIGHTSOUT_OFFLOAD_OUT_LEN;
switch (type) {
case EFX_LIGHTSOUT_OFFLOAD_TYPE_ARP:
@ -363,7 +378,8 @@ efx_lightsout_offload_remove(
MC_CMD_LIGHTSOUT_OFFLOAD_PROTOCOL_NS);
break;
default:
EFSYS_ASSERT3U(type, !=, type);
rc = EINVAL;
goto fail1;
}
MCDI_IN_SET_DWORD(req, REMOVE_LIGHTSOUT_OFFLOAD_IN_FILTER_ID,
@ -373,11 +389,13 @@ efx_lightsout_offload_remove(
if (req.emr_rc != 0) {
rc = req.emr_rc;
goto fail1;
goto fail2;
}
return (0);
fail2:
EFSYS_PROBE(fail2);
fail1:
EFSYS_PROBE1(fail1, int, rc);

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,155 @@
/*-
* Copyright (c) 2012-2015 Solarflare Communications Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the FreeBSD Project.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "efsys.h"
#include "efx.h"
#include "efx_impl.h"
#if EFSYS_OPT_HUNTINGTON
__checkReturn int
hunt_intr_init(
__in efx_nic_t *enp,
__in efx_intr_type_t type,
__in efsys_mem_t *esmp)
{
_NOTE(ARGUNUSED(enp, type, esmp))
return (0);
}
void
hunt_intr_enable(
__in efx_nic_t *enp)
{
_NOTE(ARGUNUSED(enp))
}
void
hunt_intr_disable(
__in efx_nic_t *enp)
{
_NOTE(ARGUNUSED(enp))
}
void
hunt_intr_disable_unlocked(
__in efx_nic_t *enp)
{
_NOTE(ARGUNUSED(enp))
}
static __checkReturn int
efx_mcdi_trigger_interrupt(
__in efx_nic_t *enp,
__in unsigned int level)
{
efx_mcdi_req_t req;
uint8_t payload[MAX(MC_CMD_TRIGGER_INTERRUPT_IN_LEN,
MC_CMD_TRIGGER_INTERRUPT_OUT_LEN)];
int rc;
EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON);
if (level >= enp->en_nic_cfg.enc_intr_limit) {
rc = EINVAL;
goto fail1;
}
(void) memset(payload, 0, sizeof (payload));
req.emr_cmd = MC_CMD_TRIGGER_INTERRUPT;
req.emr_in_buf = payload;
req.emr_in_length = MC_CMD_TRIGGER_INTERRUPT_IN_LEN;
req.emr_out_buf = payload;
req.emr_out_length = MC_CMD_TRIGGER_INTERRUPT_OUT_LEN;
MCDI_IN_SET_DWORD(req, TRIGGER_INTERRUPT_IN_INTR_LEVEL, level);
efx_mcdi_execute(enp, &req);
if (req.emr_rc != 0) {
rc = req.emr_rc;
goto fail2;
}
return (0);
fail2:
EFSYS_PROBE(fail2);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
__checkReturn int
hunt_intr_trigger(
__in efx_nic_t *enp,
__in unsigned int level)
{
efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
int rc;
if (encp->enc_bug41750_workaround) {
/* bug 41750: Test interrupts don't work on Greenport */
rc = ENOTSUP;
goto fail1;
}
if ((rc = efx_mcdi_trigger_interrupt(enp, level)) != 0)
goto fail2;
return (0);
fail2:
EFSYS_PROBE(fail2);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
void
hunt_intr_fini(
__in efx_nic_t *enp)
{
_NOTE(ARGUNUSED(enp))
}
#endif /* EFSYS_OPT_HUNTINGTON */

View File

@ -0,0 +1,685 @@
/*-
* Copyright (c) 2012-2015 Solarflare Communications Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the FreeBSD Project.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "efsys.h"
#include "efx.h"
#include "efx_impl.h"
#if EFSYS_OPT_HUNTINGTON
__checkReturn int
hunt_mac_poll(
__in efx_nic_t *enp,
__out efx_link_mode_t *link_modep)
{
/*
* TBD: Consider a common Siena/Huntington function. The code is
* essentially identical.
*/
efx_port_t *epp = &(enp->en_port);
hunt_link_state_t hls;
int rc;
if ((rc = hunt_phy_get_link(enp, &hls)) != 0)
goto fail1;
epp->ep_adv_cap_mask = hls.hls_adv_cap_mask;
epp->ep_fcntl = hls.hls_fcntl;
*link_modep = hls.hls_link_mode;
return (0);
fail1:
EFSYS_PROBE1(fail1, int, rc);
*link_modep = EFX_LINK_UNKNOWN;
return (rc);
}
__checkReturn int
hunt_mac_up(
__in efx_nic_t *enp,
__out boolean_t *mac_upp)
{
/*
* TBD: Consider a common Siena/Huntington function. The code is
* essentially identical.
*/
hunt_link_state_t hls;
int rc;
/*
* Because Huntington doesn't *require* polling, we can't rely on
* hunt_mac_poll() being executed to populate epp->ep_mac_up.
*/
if ((rc = hunt_phy_get_link(enp, &hls)) != 0)
goto fail1;
*mac_upp = hls.hls_mac_up;
return (0);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
/*
* Huntington uses MC_CMD_VADAPTOR_SET_MAC to set the
* MAC address; the address field in MC_CMD_SET_MAC has no
* effect.
* MC_CMD_VADAPTOR_SET_MAC requires mac-spoofing privilege and
* the port to have no filters or queues active.
*/
static __checkReturn int
efx_mcdi_vadapter_set_mac(
__in efx_nic_t *enp)
{
efx_port_t *epp = &(enp->en_port);
efx_mcdi_req_t req;
uint8_t payload[MAX(MC_CMD_VADAPTOR_SET_MAC_IN_LEN,
MC_CMD_VADAPTOR_SET_MAC_OUT_LEN)];
int rc;
(void) memset(payload, 0, sizeof (payload));
req.emr_cmd = MC_CMD_VADAPTOR_SET_MAC;
req.emr_in_buf = payload;
req.emr_in_length = MC_CMD_VADAPTOR_SET_MAC_IN_LEN;
req.emr_out_buf = payload;
req.emr_out_length = MC_CMD_VADAPTOR_SET_MAC_OUT_LEN;
MCDI_IN_SET_DWORD(req, VADAPTOR_SET_MAC_IN_UPSTREAM_PORT_ID,
enp->en_vport_id);
EFX_MAC_ADDR_COPY(MCDI_IN2(req, uint8_t, VADAPTOR_SET_MAC_IN_MACADDR),
epp->ep_mac_addr);
efx_mcdi_execute(enp, &req);
if (req.emr_rc != 0) {
rc = req.emr_rc;
goto fail1;
}
return (0);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
__checkReturn int
hunt_mac_addr_set(
__in efx_nic_t *enp)
{
int rc;
if ((rc = efx_mcdi_vadapter_set_mac(enp)) != 0)
goto fail1;
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
__checkReturn int
hunt_mac_reconfigure(
__in efx_nic_t *enp)
{
efx_port_t *epp = &(enp->en_port);
efx_mcdi_req_t req;
uint8_t payload[MAX(MC_CMD_SET_MAC_IN_LEN,
MC_CMD_SET_MAC_OUT_LEN)];
int rc;
(void) memset(payload, 0, sizeof (payload));
req.emr_cmd = MC_CMD_SET_MAC;
req.emr_in_buf = payload;
req.emr_in_length = MC_CMD_SET_MAC_IN_LEN;
req.emr_out_buf = payload;
req.emr_out_length = MC_CMD_SET_MAC_OUT_LEN;
MCDI_IN_SET_DWORD(req, SET_MAC_IN_MTU, epp->ep_mac_pdu);
MCDI_IN_SET_DWORD(req, SET_MAC_IN_DRAIN, epp->ep_mac_drain ? 1 : 0);
EFX_MAC_ADDR_COPY(MCDI_IN2(req, uint8_t, SET_MAC_IN_ADDR),
epp->ep_mac_addr);
/*
* Note: The Huntington MAC does not support REJECT_BRDCST.
* The REJECT_UNCST flag will also prevent multicast traffic
* from reaching the filters. As Huntington filters drop any
* traffic that does not match a filter it is ok to leave the
* MAC running in promiscuous mode. See bug41141.
*/
MCDI_IN_POPULATE_DWORD_2(req, SET_MAC_IN_REJECT,
SET_MAC_IN_REJECT_UNCST, 0,
SET_MAC_IN_REJECT_BRDCST, 0);
/*
* Flow control, whether it is auto-negotiated or not,
* is set via the PHY advertised capabilities. When set to
* automatic the MAC will use the PHY settings to determine
* the flow control settings.
*/
MCDI_IN_SET_DWORD(req, SET_MAC_IN_FCNTL, MC_CMD_FCNTL_AUTO);
/* Do not include the Ethernet frame checksum in RX packets */
MCDI_IN_POPULATE_DWORD_1(req, SET_MAC_IN_FLAGS,
SET_MAC_IN_FLAG_INCLUDE_FCS, 0);
efx_mcdi_execute_quiet(enp, &req);
if (req.emr_rc != 0) {
/*
* Unprivileged functions cannot control link state,
* but still need to configure filters.
*/
if (req.emr_rc != EACCES) {
rc = req.emr_rc;
goto fail1;
}
}
/*
* Apply the filters for the MAC configuration.
* If the NIC isn't ready to accept filters this may
* return success without setting anything.
*/
rc = efx_filter_reconfigure(enp, epp->ep_mac_addr,
epp->ep_all_unicst, epp->ep_mulcst,
epp->ep_all_mulcst, epp->ep_brdcst,
epp->ep_mulcst_addr_list,
epp->ep_mulcst_addr_count);
return (0);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
__checkReturn int
hunt_mac_multicast_list_set(
__in efx_nic_t *enp)
{
efx_port_t *epp = &(enp->en_port);
efx_mac_ops_t *emop = epp->ep_emop;
int rc;
EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON);
/* FIXME: Insert filters for multicast list */
if ((rc = emop->emo_reconfigure(enp)) != 0)
goto fail1;
return (0);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
__checkReturn int
hunt_mac_filter_default_rxq_set(
__in efx_nic_t *enp,
__in efx_rxq_t *erp,
__in boolean_t using_rss)
{
efx_port_t *epp = &(enp->en_port);
efx_rxq_t *old_rxq;
boolean_t old_using_rss;
int rc;
hunt_filter_get_default_rxq(enp, &old_rxq, &old_using_rss);
hunt_filter_default_rxq_set(enp, erp, using_rss);
rc = efx_filter_reconfigure(enp, epp->ep_mac_addr,
epp->ep_all_unicst, epp->ep_mulcst,
epp->ep_all_mulcst, epp->ep_brdcst,
epp->ep_mulcst_addr_list,
epp->ep_mulcst_addr_count);
if (rc != 0)
goto fail1;
return (0);
fail1:
EFSYS_PROBE1(fail1, int, rc);
hunt_filter_default_rxq_set(enp, old_rxq, old_using_rss);
return (rc);
}
void
hunt_mac_filter_default_rxq_clear(
__in efx_nic_t *enp)
{
efx_port_t *epp = &(enp->en_port);
hunt_filter_default_rxq_clear(enp);
efx_filter_reconfigure(enp, epp->ep_mac_addr,
epp->ep_all_unicst, epp->ep_mulcst,
epp->ep_all_mulcst, epp->ep_brdcst,
epp->ep_mulcst_addr_list,
epp->ep_mulcst_addr_count);
}
#if EFSYS_OPT_LOOPBACK
__checkReturn int
hunt_mac_loopback_set(
__in efx_nic_t *enp,
__in efx_link_mode_t link_mode,
__in efx_loopback_type_t loopback_type)
{
/*
* TBD: Consider a common Siena/Huntington function. The code is
* essentially identical.
*/
efx_port_t *epp = &(enp->en_port);
efx_phy_ops_t *epop = epp->ep_epop;
efx_loopback_type_t old_loopback_type;
efx_link_mode_t old_loopback_link_mode;
int rc;
/* The PHY object handles this on Huntington */
old_loopback_type = epp->ep_loopback_type;
old_loopback_link_mode = epp->ep_loopback_link_mode;
epp->ep_loopback_type = loopback_type;
epp->ep_loopback_link_mode = link_mode;
if ((rc = epop->epo_reconfigure(enp)) != 0)
goto fail1;
return (0);
fail1:
EFSYS_PROBE(fail2);
epp->ep_loopback_type = old_loopback_type;
epp->ep_loopback_link_mode = old_loopback_link_mode;
return (rc);
}
#endif /* EFSYS_OPT_LOOPBACK */
#if EFSYS_OPT_MAC_STATS
#define HUNT_MAC_STAT_READ(_esmp, _field, _eqp) \
EFSYS_MEM_READQ((_esmp), (_field) * sizeof (efx_qword_t), _eqp)
__checkReturn int
hunt_mac_stats_update(
__in efx_nic_t *enp,
__in efsys_mem_t *esmp,
__out_ecount(EFX_MAC_NSTATS) efsys_stat_t *stat,
__out_opt uint32_t *generationp)
{
efx_qword_t value;
efx_qword_t generation_start;
efx_qword_t generation_end;
_NOTE(ARGUNUSED(enp))
/* Read END first so we don't race with the MC */
EFSYS_DMA_SYNC_FOR_KERNEL(esmp, 0, EFX_MAC_STATS_SIZE);
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_GENERATION_END,
&generation_end);
EFSYS_MEM_READ_BARRIER();
/* TX */
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_PKTS, &value);
EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_PKTS]), &value);
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_CONTROL_PKTS, &value);
EFSYS_STAT_SUBR_QWORD(&(stat[EFX_MAC_TX_PKTS]), &value);
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_PAUSE_PKTS, &value);
EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_PAUSE_PKTS]), &value);
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_UNICAST_PKTS, &value);
EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_UNICST_PKTS]), &value);
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_MULTICAST_PKTS, &value);
EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_MULTICST_PKTS]), &value);
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_BROADCAST_PKTS, &value);
EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_BRDCST_PKTS]), &value);
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_BYTES, &value);
EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_OCTETS]), &value);
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_LT64_PKTS, &value);
EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_LE_64_PKTS]), &value);
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_64_PKTS, &value);
EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_LE_64_PKTS]), &value);
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_65_TO_127_PKTS, &value);
EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_65_TO_127_PKTS]), &value);
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_128_TO_255_PKTS, &value);
EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_128_TO_255_PKTS]), &value);
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_256_TO_511_PKTS, &value);
EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_256_TO_511_PKTS]), &value);
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_512_TO_1023_PKTS, &value);
EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_512_TO_1023_PKTS]), &value);
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_1024_TO_15XX_PKTS, &value);
EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_1024_TO_15XX_PKTS]), &value);
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_15XX_TO_JUMBO_PKTS, &value);
EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_GE_15XX_PKTS]), &value);
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_GTJUMBO_PKTS, &value);
EFSYS_STAT_INCR_QWORD(&(stat[EFX_MAC_TX_GE_15XX_PKTS]), &value);
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_BAD_FCS_PKTS, &value);
EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_ERRORS]), &value);
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_SINGLE_COLLISION_PKTS, &value);
EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_SGL_COL_PKTS]), &value);
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_MULTIPLE_COLLISION_PKTS,
&value);
EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_MULT_COL_PKTS]), &value);
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_EXCESSIVE_COLLISION_PKTS,
&value);
EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_EX_COL_PKTS]), &value);
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_LATE_COLLISION_PKTS, &value);
EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_LATE_COL_PKTS]), &value);
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_DEFERRED_PKTS, &value);
EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_DEF_PKTS]), &value);
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_EXCESSIVE_DEFERRED_PKTS,
&value);
EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_EX_DEF_PKTS]), &value);
/* RX */
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_BYTES, &value);
EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_OCTETS]), &value);
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_PKTS, &value);
EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_PKTS]), &value);
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_UNICAST_PKTS, &value);
EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_UNICST_PKTS]), &value);
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_MULTICAST_PKTS, &value);
EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_MULTICST_PKTS]), &value);
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_BROADCAST_PKTS, &value);
EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_BRDCST_PKTS]), &value);
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_PAUSE_PKTS, &value);
EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_PAUSE_PKTS]), &value);
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_UNDERSIZE_PKTS, &value);
EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_LE_64_PKTS]), &value);
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_64_PKTS, &value);
EFSYS_STAT_INCR_QWORD(&(stat[EFX_MAC_RX_LE_64_PKTS]), &value);
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_65_TO_127_PKTS, &value);
EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_65_TO_127_PKTS]), &value);
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_128_TO_255_PKTS, &value);
EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_128_TO_255_PKTS]), &value);
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_256_TO_511_PKTS, &value);
EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_256_TO_511_PKTS]), &value);
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_512_TO_1023_PKTS, &value);
EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_512_TO_1023_PKTS]), &value);
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_1024_TO_15XX_PKTS, &value);
EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_1024_TO_15XX_PKTS]), &value);
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_15XX_TO_JUMBO_PKTS, &value);
EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_GE_15XX_PKTS]), &value);
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_GTJUMBO_PKTS, &value);
EFSYS_STAT_INCR_QWORD(&(stat[EFX_MAC_RX_GE_15XX_PKTS]), &value);
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_BAD_FCS_PKTS, &value);
EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_FCS_ERRORS]), &value);
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_OVERFLOW_PKTS, &value);
EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_DROP_EVENTS]), &value);
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_FALSE_CARRIER_PKTS, &value);
EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_FALSE_CARRIER_ERRORS]), &value);
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_SYMBOL_ERROR_PKTS, &value);
EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_SYMBOL_ERRORS]), &value);
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_ALIGN_ERROR_PKTS, &value);
EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_ALIGN_ERRORS]), &value);
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_INTERNAL_ERROR_PKTS, &value);
EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_INTERNAL_ERRORS]), &value);
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_JABBER_PKTS, &value);
EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_JABBER_PKTS]), &value);
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_LANES01_CHAR_ERR, &value);
EFSYS_STAT_SET_DWORD(&(stat[EFX_MAC_RX_LANE0_CHAR_ERR]),
&(value.eq_dword[0]));
EFSYS_STAT_SET_DWORD(&(stat[EFX_MAC_RX_LANE1_CHAR_ERR]),
&(value.eq_dword[1]));
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_LANES23_CHAR_ERR, &value);
EFSYS_STAT_SET_DWORD(&(stat[EFX_MAC_RX_LANE2_CHAR_ERR]),
&(value.eq_dword[0]));
EFSYS_STAT_SET_DWORD(&(stat[EFX_MAC_RX_LANE3_CHAR_ERR]),
&(value.eq_dword[1]));
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_LANES01_DISP_ERR, &value);
EFSYS_STAT_SET_DWORD(&(stat[EFX_MAC_RX_LANE0_DISP_ERR]),
&(value.eq_dword[0]));
EFSYS_STAT_SET_DWORD(&(stat[EFX_MAC_RX_LANE1_DISP_ERR]),
&(value.eq_dword[1]));
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_LANES23_DISP_ERR, &value);
EFSYS_STAT_SET_DWORD(&(stat[EFX_MAC_RX_LANE2_DISP_ERR]),
&(value.eq_dword[0]));
EFSYS_STAT_SET_DWORD(&(stat[EFX_MAC_RX_LANE3_DISP_ERR]),
&(value.eq_dword[1]));
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_MATCH_FAULT, &value);
EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_MATCH_FAULT]), &value);
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_NODESC_DROPS, &value);
EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_NODESC_DROP_CNT]), &value);
/* Packet memory (EF10 only) */
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_PM_TRUNC_BB_OVERFLOW, &value);
EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_PM_TRUNC_BB_OVERFLOW]), &value);
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_PM_DISCARD_BB_OVERFLOW, &value);
EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_PM_DISCARD_BB_OVERFLOW]), &value);
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_PM_TRUNC_VFIFO_FULL, &value);
EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_PM_TRUNC_VFIFO_FULL]), &value);
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_PM_DISCARD_VFIFO_FULL, &value);
EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_PM_DISCARD_VFIFO_FULL]), &value);
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_PM_TRUNC_QBB, &value);
EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_PM_TRUNC_QBB]), &value);
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_PM_DISCARD_QBB, &value);
EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_PM_DISCARD_QBB]), &value);
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_PM_DISCARD_MAPPING, &value);
EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_PM_DISCARD_MAPPING]), &value);
/* RX datapath */
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_RXDP_Q_DISABLED_PKTS, &value);
EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RXDP_Q_DISABLED_PKTS]), &value);
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_RXDP_DI_DROPPED_PKTS, &value);
EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RXDP_DI_DROPPED_PKTS]), &value);
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_RXDP_STREAMING_PKTS, &value);
EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RXDP_STREAMING_PKTS]), &value);
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_RXDP_HLB_FETCH_CONDITIONS, &value);
EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RXDP_HLB_FETCH]), &value);
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_RXDP_HLB_WAIT_CONDITIONS, &value);
EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RXDP_HLB_WAIT]), &value);
/* VADAPTER RX */
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_VADAPTER_RX_UNICAST_PACKETS,
&value);
EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_VADAPTER_RX_UNICAST_PACKETS]),
&value);
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_VADAPTER_RX_UNICAST_BYTES,
&value);
EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_VADAPTER_RX_UNICAST_BYTES]),
&value);
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_VADAPTER_RX_MULTICAST_PACKETS,
&value);
EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_VADAPTER_RX_MULTICAST_PACKETS]),
&value);
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_VADAPTER_RX_MULTICAST_BYTES,
&value);
EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_VADAPTER_RX_MULTICAST_BYTES]),
&value);
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_VADAPTER_RX_BROADCAST_PACKETS,
&value);
EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_VADAPTER_RX_BROADCAST_PACKETS]),
&value);
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_VADAPTER_RX_BROADCAST_BYTES,
&value);
EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_VADAPTER_RX_BROADCAST_BYTES]),
&value);
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_VADAPTER_RX_BAD_PACKETS,
&value);
EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_VADAPTER_RX_BAD_PACKETS]),
&value);
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_VADAPTER_RX_BAD_BYTES, &value);
EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_VADAPTER_RX_BAD_BYTES]), &value);
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_VADAPTER_RX_OVERFLOW, &value);
EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_VADAPTER_RX_OVERFLOW]), &value);
/* VADAPTER TX */
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_VADAPTER_TX_UNICAST_PACKETS,
&value);
EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_VADAPTER_TX_UNICAST_PACKETS]),
&value);
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_VADAPTER_TX_UNICAST_BYTES,
&value);
EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_VADAPTER_TX_UNICAST_BYTES]),
&value);
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_VADAPTER_TX_MULTICAST_PACKETS,
&value);
EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_VADAPTER_TX_MULTICAST_PACKETS]),
&value);
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_VADAPTER_TX_MULTICAST_BYTES,
&value);
EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_VADAPTER_TX_MULTICAST_BYTES]),
&value);
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_VADAPTER_TX_BROADCAST_PACKETS,
&value);
EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_VADAPTER_TX_BROADCAST_PACKETS]),
&value);
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_VADAPTER_TX_BROADCAST_BYTES,
&value);
EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_VADAPTER_TX_BROADCAST_BYTES]),
&value);
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_VADAPTER_TX_BAD_PACKETS, &value);
EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_VADAPTER_TX_BAD_PACKETS]), &value);
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_VADAPTER_TX_BAD_BYTES, &value);
EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_VADAPTER_TX_BAD_BYTES]), &value);
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_VADAPTER_TX_OVERFLOW, &value);
EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_VADAPTER_TX_OVERFLOW]), &value);
EFSYS_DMA_SYNC_FOR_KERNEL(esmp, 0, EFX_MAC_STATS_SIZE);
EFSYS_MEM_READ_BARRIER();
HUNT_MAC_STAT_READ(esmp, MC_CMD_MAC_GENERATION_START,
&generation_start);
/* Check that we didn't read the stats in the middle of a DMA */
/* Not a good enough check ? */
if (memcmp(&generation_start, &generation_end,
sizeof (generation_start)))
return (EAGAIN);
if (generationp)
*generationp = EFX_QWORD_FIELD(generation_start, EFX_DWORD_0);
return (0);
}
#endif /* EFSYS_OPT_MAC_STATS */
#endif /* EFSYS_OPT_HUNTINGTON */

View File

@ -0,0 +1,465 @@
/*-
* Copyright (c) 2012-2015 Solarflare Communications Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the FreeBSD Project.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "efsys.h"
#include "efx.h"
#include "efx_impl.h"
#if EFSYS_OPT_HUNTINGTON
#if EFSYS_OPT_MCDI
#ifndef WITH_MCDI_V2
#error "WITH_MCDI_V2 required for Huntington MCDIv2 commands."
#endif
typedef enum efx_mcdi_header_type_e {
EFX_MCDI_HEADER_TYPE_V1, /* MCDIv0 (BootROM), MCDIv1 commands */
EFX_MCDI_HEADER_TYPE_V2, /* MCDIv2 commands */
} efx_mcdi_header_type_t;
/*
* Return the header format to use for sending an MCDI request.
*
* An MCDIv1 (Siena compatible) command should use MCDIv2 encapsulation if the
* request input buffer or response output buffer are too large for the MCDIv1
* format. An MCDIv2 command must always be sent using MCDIv2 encapsulation.
*/
#define EFX_MCDI_HEADER_TYPE(_cmd, _length) \
((((_cmd) & ~EFX_MASK32(MCDI_HEADER_CODE)) || \
((_length) & ~EFX_MASK32(MCDI_HEADER_DATALEN))) ? \
EFX_MCDI_HEADER_TYPE_V2 : EFX_MCDI_HEADER_TYPE_V1)
/*
* MCDI Header NOT_EPOCH flag
* ==========================
* A new epoch begins at initial startup or after an MC reboot, and defines when
* the MC should reject stale MCDI requests.
*
* The first MCDI request sent by the host should contain NOT_EPOCH=0, and all
* subsequent requests (until the next MC reboot) should contain NOT_EPOCH=1.
*
* After rebooting the MC will fail all requests with NOT_EPOCH=1 by writing a
* response with ERROR=1 and DATALEN=0 until a request is seen with NOT_EPOCH=0.
*/
__checkReturn int
hunt_mcdi_init(
__in efx_nic_t *enp,
__in const efx_mcdi_transport_t *emtp)
{
efsys_mem_t *esmp = emtp->emt_dma_mem;
efx_dword_t dword;
int rc;
EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON);
EFSYS_ASSERT(enp->en_features & EFX_FEATURE_MCDI_DMA);
/* A host DMA buffer is required for Huntington MCDI */
if (esmp == NULL) {
rc = EINVAL;
goto fail1;
}
/*
* Ensure that the MC doorbell is in a known state before issuing MCDI
* commands. The recovery algorithm requires that the MC command buffer
* must be 256 byte aligned. See bug24769.
*/
if ((EFSYS_MEM_ADDR(esmp) & 0xFF) != 0) {
rc = EINVAL;
goto fail2;
}
EFX_POPULATE_DWORD_1(dword, EFX_DWORD_0, 1);
EFX_BAR_WRITED(enp, ER_DZ_MC_DB_HWRD_REG, &dword, B_FALSE);
/* Save initial MC reboot status */
(void) hunt_mcdi_poll_reboot(enp);
/* Start a new epoch (allow fresh MCDI requests to succeed) */
efx_mcdi_new_epoch(enp);
return (0);
fail2:
EFSYS_PROBE(fail2);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
void
hunt_mcdi_fini(
__in efx_nic_t *enp)
{
efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
emip->emi_new_epoch = B_FALSE;
}
void
hunt_mcdi_request_copyin(
__in efx_nic_t *enp,
__in efx_mcdi_req_t *emrp,
__in unsigned int seq,
__in boolean_t ev_cpl,
__in boolean_t new_epoch)
{
const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
efsys_mem_t *esmp = emtp->emt_dma_mem;
efx_mcdi_header_type_t hdr_type;
efx_dword_t dword;
unsigned int xflags;
unsigned int pos;
size_t offset;
EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_HUNTINGTON);
xflags = 0;
if (ev_cpl)
xflags |= MCDI_HEADER_XFLAGS_EVREQ;
offset = 0;
hdr_type = EFX_MCDI_HEADER_TYPE(emrp->emr_cmd,
MAX(emrp->emr_in_length, emrp->emr_out_length));
if (hdr_type == EFX_MCDI_HEADER_TYPE_V2) {
/* Construct MCDI v2 header */
EFX_POPULATE_DWORD_8(dword,
MCDI_HEADER_CODE, MC_CMD_V2_EXTN,
MCDI_HEADER_RESYNC, 1,
MCDI_HEADER_DATALEN, 0,
MCDI_HEADER_SEQ, seq,
MCDI_HEADER_NOT_EPOCH, new_epoch ? 0 : 1,
MCDI_HEADER_ERROR, 0,
MCDI_HEADER_RESPONSE, 0,
MCDI_HEADER_XFLAGS, xflags);
EFSYS_MEM_WRITED(esmp, offset, &dword);
offset += sizeof (dword);
EFX_POPULATE_DWORD_2(dword,
MC_CMD_V2_EXTN_IN_EXTENDED_CMD, emrp->emr_cmd,
MC_CMD_V2_EXTN_IN_ACTUAL_LEN, emrp->emr_in_length);
EFSYS_MEM_WRITED(esmp, offset, &dword);
offset += sizeof (dword);
} else {
/* Construct MCDI v1 header */
EFX_POPULATE_DWORD_8(dword,
MCDI_HEADER_CODE, emrp->emr_cmd,
MCDI_HEADER_RESYNC, 1,
MCDI_HEADER_DATALEN, emrp->emr_in_length,
MCDI_HEADER_SEQ, seq,
MCDI_HEADER_NOT_EPOCH, new_epoch ? 0 : 1,
MCDI_HEADER_ERROR, 0,
MCDI_HEADER_RESPONSE, 0,
MCDI_HEADER_XFLAGS, xflags);
EFSYS_MEM_WRITED(esmp, offset, &dword);
offset += sizeof (dword);
}
/* Construct the payload */
for (pos = 0; pos < emrp->emr_in_length; pos += sizeof (efx_dword_t)) {
memcpy(&dword, MCDI_IN(*emrp, efx_dword_t, pos),
MIN(sizeof (dword), emrp->emr_in_length - pos));
EFSYS_MEM_WRITED(esmp, offset + pos, &dword);
}
/* Ring the doorbell to post the command DMA address to the MC */
EFSYS_ASSERT((EFSYS_MEM_ADDR(esmp) & 0xFF) == 0);
/* Guarantee ordering of memory (MCDI request) and PIO (MC doorbell) */
EFSYS_DMA_SYNC_FOR_DEVICE(esmp, 0, offset + emrp->emr_in_length);
EFSYS_PIO_WRITE_BARRIER();
EFX_POPULATE_DWORD_1(dword,
EFX_DWORD_0, EFSYS_MEM_ADDR(esmp) >> 32);
EFX_BAR_WRITED(enp, ER_DZ_MC_DB_LWRD_REG, &dword, B_FALSE);
EFX_POPULATE_DWORD_1(dword,
EFX_DWORD_0, EFSYS_MEM_ADDR(esmp) & 0xffffffff);
EFX_BAR_WRITED(enp, ER_DZ_MC_DB_HWRD_REG, &dword, B_FALSE);
}
void
hunt_mcdi_request_copyout(
__in efx_nic_t *enp,
__in efx_mcdi_req_t *emrp)
{
const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
efsys_mem_t *esmp = emtp->emt_dma_mem;
unsigned int pos;
unsigned int offset;
efx_dword_t hdr;
efx_dword_t hdr2;
efx_dword_t data;
size_t bytes;
if (emrp->emr_out_buf == NULL)
return;
/* Read the command header to detect MCDI response format */
EFSYS_MEM_READD(esmp, 0, &hdr);
if (EFX_DWORD_FIELD(hdr, MCDI_HEADER_CODE) == MC_CMD_V2_EXTN) {
offset = 2 * sizeof (efx_dword_t);
/*
* Read the actual payload length. The length given in the event
* is only correct for responses with the V1 format.
*/
EFSYS_MEM_READD(esmp, sizeof (efx_dword_t), &hdr2);
emrp->emr_out_length_used = EFX_DWORD_FIELD(hdr2,
MC_CMD_V2_EXTN_IN_ACTUAL_LEN);
} else {
offset = sizeof (efx_dword_t);
}
/* Copy payload out into caller supplied buffer */
bytes = MIN(emrp->emr_out_length_used, emrp->emr_out_length);
for (pos = 0; pos < bytes; pos += sizeof (efx_dword_t)) {
EFSYS_MEM_READD(esmp, offset + pos, &data);
memcpy(MCDI_OUT(*emrp, efx_dword_t, pos), &data,
MIN(sizeof (data), bytes - pos));
}
}
__checkReturn boolean_t
hunt_mcdi_request_poll(
__in efx_nic_t *enp)
{
efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
efsys_mem_t *esmp = emtp->emt_dma_mem;
efx_mcdi_req_t *emrp;
efx_dword_t dword;
unsigned int seq;
unsigned int cmd;
unsigned int length;
size_t offset;
int state;
int rc;
EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_HUNTINGTON);
/* Serialise against post-watchdog efx_mcdi_ev* */
EFSYS_LOCK(enp->en_eslp, state);
EFSYS_ASSERT(emip->emi_pending_req != NULL);
EFSYS_ASSERT(!emip->emi_ev_cpl);
emrp = emip->emi_pending_req;
offset = 0;
/* Read the command header */
EFSYS_MEM_READD(esmp, offset, &dword);
offset += sizeof (efx_dword_t);
if (EFX_DWORD_FIELD(dword, MCDI_HEADER_RESPONSE) == 0) {
EFSYS_UNLOCK(enp->en_eslp, state);
return (B_FALSE);
}
if (EFX_DWORD_FIELD(dword, MCDI_HEADER_CODE) == MC_CMD_V2_EXTN) {
efx_dword_t dword2;
EFSYS_MEM_READD(esmp, offset, &dword2);
offset += sizeof (efx_dword_t);
cmd = EFX_DWORD_FIELD(dword2, MC_CMD_V2_EXTN_IN_EXTENDED_CMD);
length = EFX_DWORD_FIELD(dword2, MC_CMD_V2_EXTN_IN_ACTUAL_LEN);
} else {
cmd = EFX_DWORD_FIELD(dword, MCDI_HEADER_CODE);
length = EFX_DWORD_FIELD(dword, MCDI_HEADER_DATALEN);
}
/* Request complete */
emip->emi_pending_req = NULL;
seq = (emip->emi_seq - 1) & EFX_MASK32(MCDI_HEADER_SEQ);
/* Check for synchronous reboot */
if (EFX_DWORD_FIELD(dword, MCDI_HEADER_ERROR) != 0 && length == 0) {
/* The MC has rebooted since the request was sent. */
EFSYS_SPIN(EFX_MCDI_STATUS_SLEEP_US);
hunt_mcdi_poll_reboot(enp);
EFSYS_UNLOCK(enp->en_eslp, state);
rc = EIO;
goto fail1;
}
/* Ensure stale MCDI requests fail after an MC reboot. */
emip->emi_new_epoch = B_FALSE;
EFSYS_UNLOCK(enp->en_eslp, state);
/* Check that the returned data is consistent */
if (cmd != emrp->emr_cmd ||
EFX_DWORD_FIELD(dword, MCDI_HEADER_SEQ) != seq) {
/* Response is for a different request */
rc = EIO;
goto fail2;
}
if (EFX_DWORD_FIELD(dword, MCDI_HEADER_ERROR)) {
efx_dword_t errdword;
int errcode;
int argnum;
/* Read error code (and arg num for MCDI v2 commands) */
EFSYS_MEM_READD(esmp, offset + MC_CMD_ERR_CODE_OFST, &errdword);
errcode = EFX_DWORD_FIELD(errdword, EFX_DWORD_0);
EFSYS_MEM_READD(esmp, offset + MC_CMD_ERR_ARG_OFST, &errdword);
argnum = EFX_DWORD_FIELD(errdword, EFX_DWORD_0);
rc = efx_mcdi_request_errcode(errcode);
if (!emrp->emr_quiet) {
EFSYS_PROBE3(mcdi_err_arg, int, emrp->emr_cmd,
int, errcode, int, argnum);
}
goto fail3;
} else {
emrp->emr_out_length_used = length;
emrp->emr_rc = 0;
hunt_mcdi_request_copyout(enp, emrp);
}
goto out;
fail3:
if (!emrp->emr_quiet)
EFSYS_PROBE(fail3);
fail2:
if (!emrp->emr_quiet)
EFSYS_PROBE(fail2);
fail1:
if (!emrp->emr_quiet)
EFSYS_PROBE1(fail1, int, rc);
/* Fill out error state */
emrp->emr_rc = rc;
emrp->emr_out_length_used = 0;
/* Reboot/Assertion */
if (rc == EIO || rc == EINTR)
efx_mcdi_raise_exception(enp, emrp, rc);
out:
return (B_TRUE);
}
int
hunt_mcdi_poll_reboot(
__in efx_nic_t *enp)
{
efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
efx_dword_t dword;
uint32_t old_status;
uint32_t new_status;
int rc;
old_status = emip->emi_mc_reboot_status;
/* Update MC reboot status word */
EFX_BAR_TBL_READD(enp, ER_DZ_BIU_MC_SFT_STATUS_REG, 0, &dword, B_FALSE);
new_status = dword.ed_u32[0];
/* MC has rebooted if the value has changed */
if (new_status != old_status) {
emip->emi_mc_reboot_status = new_status;
/*
* FIXME: Ignore detected MC REBOOT for now.
*
* The Siena support for checking for MC reboot from status
* flags is broken - see comments in siena_mcdi_poll_reboot().
* As the generic MCDI code is shared the Huntington reboot
* detection suffers similar problems.
*
* Do not report an error when the boot status changes until
* this can be handled by common code drivers (and reworked to
* support Siena too).
*/
if (B_FALSE) {
rc = EIO;
goto fail1;
}
}
return (0);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
__checkReturn int
hunt_mcdi_fw_update_supported(
__in efx_nic_t *enp,
__out boolean_t *supportedp)
{
efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_HUNTINGTON);
/* use privilege mask state at MCDI attach */
*supportedp = (encp->enc_privilege_mask &
MC_CMD_PRIVILEGE_MASK_IN_GRP_ADMIN)
== MC_CMD_PRIVILEGE_MASK_IN_GRP_ADMIN;
return (0);
}
__checkReturn int
hunt_mcdi_macaddr_change_supported(
__in efx_nic_t *enp,
__out boolean_t *supportedp)
{
efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_HUNTINGTON);
/* use privilege mask state at MCDI attach */
*supportedp = (encp->enc_privilege_mask &
MC_CMD_PRIVILEGE_MASK_IN_GRP_MAC_SPOOFING)
== MC_CMD_PRIVILEGE_MASK_IN_GRP_MAC_SPOOFING;
return (0);
}
#endif /* EFSYS_OPT_MCDI */
#endif /* EFSYS_OPT_HUNTINGTON */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,701 @@
/*-
* Copyright (c) 2012-2015 Solarflare Communications Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the FreeBSD Project.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "efsys.h"
#include "efx.h"
#include "efx_impl.h"
#if EFSYS_OPT_HUNTINGTON
static void
hunt_phy_decode_cap(
__in uint32_t mcdi_cap,
__out uint32_t *maskp)
{
/*
* TBD: consider common Siena/Hunt function: Hunt is a superset of
* Siena here (adds 40G)
*/
uint32_t mask;
mask = 0;
if (mcdi_cap & (1 << MC_CMD_PHY_CAP_10HDX_LBN))
mask |= (1 << EFX_PHY_CAP_10HDX);
if (mcdi_cap & (1 << MC_CMD_PHY_CAP_10FDX_LBN))
mask |= (1 << EFX_PHY_CAP_10FDX);
if (mcdi_cap & (1 << MC_CMD_PHY_CAP_100HDX_LBN))
mask |= (1 << EFX_PHY_CAP_100HDX);
if (mcdi_cap & (1 << MC_CMD_PHY_CAP_100FDX_LBN))
mask |= (1 << EFX_PHY_CAP_100FDX);
if (mcdi_cap & (1 << MC_CMD_PHY_CAP_1000HDX_LBN))
mask |= (1 << EFX_PHY_CAP_1000HDX);
if (mcdi_cap & (1 << MC_CMD_PHY_CAP_1000FDX_LBN))
mask |= (1 << EFX_PHY_CAP_1000FDX);
if (mcdi_cap & (1 << MC_CMD_PHY_CAP_10000FDX_LBN))
mask |= (1 << EFX_PHY_CAP_10000FDX);
if (mcdi_cap & (1 << MC_CMD_PHY_CAP_40000FDX_LBN))
mask |= (1 << EFX_PHY_CAP_40000FDX);
if (mcdi_cap & (1 << MC_CMD_PHY_CAP_PAUSE_LBN))
mask |= (1 << EFX_PHY_CAP_PAUSE);
if (mcdi_cap & (1 << MC_CMD_PHY_CAP_ASYM_LBN))
mask |= (1 << EFX_PHY_CAP_ASYM);
if (mcdi_cap & (1 << MC_CMD_PHY_CAP_AN_LBN))
mask |= (1 << EFX_PHY_CAP_AN);
*maskp = mask;
}
static void
hunt_phy_decode_link_mode(
__in efx_nic_t *enp,
__in uint32_t link_flags,
__in unsigned int speed,
__in unsigned int fcntl,
__out efx_link_mode_t *link_modep,
__out unsigned int *fcntlp)
{
/*
* TBD: consider common Siena/Hunt function: Hunt is a superset of
* Siena here (adds 40G and generate-only flow control)
*/
boolean_t fd = !!(link_flags &
(1 << MC_CMD_GET_LINK_OUT_FULL_DUPLEX_LBN));
boolean_t up = !!(link_flags &
(1 << MC_CMD_GET_LINK_OUT_LINK_UP_LBN));
_NOTE(ARGUNUSED(enp))
if (!up)
*link_modep = EFX_LINK_DOWN;
else if (speed == 40000 && fd)
*link_modep = EFX_LINK_40000FDX;
else if (speed == 10000 && fd)
*link_modep = EFX_LINK_10000FDX;
else if (speed == 1000)
*link_modep = fd ? EFX_LINK_1000FDX : EFX_LINK_1000HDX;
else if (speed == 100)
*link_modep = fd ? EFX_LINK_100FDX : EFX_LINK_100HDX;
else if (speed == 10)
*link_modep = fd ? EFX_LINK_10FDX : EFX_LINK_10HDX;
else
*link_modep = EFX_LINK_UNKNOWN;
if (fcntl == MC_CMD_FCNTL_OFF)
*fcntlp = 0;
else if (fcntl == MC_CMD_FCNTL_RESPOND)
*fcntlp = EFX_FCNTL_RESPOND;
else if (fcntl == MC_CMD_FCNTL_GENERATE)
*fcntlp = EFX_FCNTL_GENERATE;
else if (fcntl == MC_CMD_FCNTL_BIDIR)
*fcntlp = EFX_FCNTL_RESPOND | EFX_FCNTL_GENERATE;
else {
EFSYS_PROBE1(mc_pcol_error, int, fcntl);
*fcntlp = 0;
}
}
void
hunt_phy_link_ev(
__in efx_nic_t *enp,
__in efx_qword_t *eqp,
__out efx_link_mode_t *link_modep)
{
/*
* TBD: consider common Siena/Hunt function: Hunt is a superset of
* Siena here (adds 40G)
*/
efx_port_t *epp = &(enp->en_port);
unsigned int link_flags;
unsigned int speed;
unsigned int fcntl;
efx_link_mode_t link_mode;
uint32_t lp_cap_mask;
/*
* Convert the LINKCHANGE speed enumeration into mbit/s, in the
* same way as GET_LINK encodes the speed
*/
switch (MCDI_EV_FIELD(eqp, LINKCHANGE_SPEED)) {
case MCDI_EVENT_LINKCHANGE_SPEED_100M:
speed = 100;
break;
case MCDI_EVENT_LINKCHANGE_SPEED_1G:
speed = 1000;
break;
case MCDI_EVENT_LINKCHANGE_SPEED_10G:
speed = 10000;
break;
case MCDI_EVENT_LINKCHANGE_SPEED_40G:
speed = 40000;
break;
default:
speed = 0;
break;
}
link_flags = MCDI_EV_FIELD(eqp, LINKCHANGE_LINK_FLAGS);
hunt_phy_decode_link_mode(enp, link_flags, speed,
MCDI_EV_FIELD(eqp, LINKCHANGE_FCNTL),
&link_mode, &fcntl);
hunt_phy_decode_cap(MCDI_EV_FIELD(eqp, LINKCHANGE_LP_CAP),
&lp_cap_mask);
/*
* It's safe to update ep_lp_cap_mask without the driver's port lock
* because presumably any concurrently running efx_port_poll() is
* only going to arrive at the same value.
*
* ep_fcntl has two meanings. It's either the link common fcntl
* (if the PHY supports AN), or it's the forced link state. If
* the former, it's safe to update the value for the same reason as
* for ep_lp_cap_mask. If the latter, then just ignore the value,
* because we can race with efx_mac_fcntl_set().
*/
epp->ep_lp_cap_mask = lp_cap_mask;
epp->ep_fcntl = fcntl;
*link_modep = link_mode;
}
__checkReturn int
hunt_phy_power(
__in efx_nic_t *enp,
__in boolean_t power)
{
/* TBD: consider common Siena/Hunt function: essentially identical */
int rc;
if (!power)
return (0);
/* Check if the PHY is a zombie */
if ((rc = hunt_phy_verify(enp)) != 0)
goto fail1;
enp->en_reset_flags |= EFX_RESET_PHY;
return (0);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
__checkReturn int
hunt_phy_get_link(
__in efx_nic_t *enp,
__out hunt_link_state_t *hlsp)
{
/*
* TBD: consider common Siena/Hunt function: Hunt is very similar
* (at least for now; not clear that the loopbacks should necessarily
* be quite the same...)
*/
efx_mcdi_req_t req;
uint8_t payload[MAX(MC_CMD_GET_LINK_IN_LEN,
MC_CMD_GET_LINK_OUT_LEN)];
int rc;
(void) memset(payload, 0, sizeof (payload));
req.emr_cmd = MC_CMD_GET_LINK;
req.emr_in_buf = payload;
req.emr_in_length = MC_CMD_GET_LINK_IN_LEN;
req.emr_out_buf = payload;
req.emr_out_length = MC_CMD_GET_LINK_OUT_LEN;
efx_mcdi_execute(enp, &req);
if (req.emr_rc != 0) {
rc = req.emr_rc;
goto fail1;
}
if (req.emr_out_length_used < MC_CMD_GET_LINK_OUT_LEN) {
rc = EMSGSIZE;
goto fail2;
}
hunt_phy_decode_cap(MCDI_OUT_DWORD(req, GET_LINK_OUT_CAP),
&hlsp->hls_adv_cap_mask);
hunt_phy_decode_cap(MCDI_OUT_DWORD(req, GET_LINK_OUT_LP_CAP),
&hlsp->hls_lp_cap_mask);
hunt_phy_decode_link_mode(enp, MCDI_OUT_DWORD(req, GET_LINK_OUT_FLAGS),
MCDI_OUT_DWORD(req, GET_LINK_OUT_LINK_SPEED),
MCDI_OUT_DWORD(req, GET_LINK_OUT_FCNTL),
&hlsp->hls_link_mode, &hlsp->hls_fcntl);
#if EFSYS_OPT_LOOPBACK
/* Assert the MC_CMD_LOOPBACK and EFX_LOOPBACK namespace agree */
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_NONE == EFX_LOOPBACK_OFF);
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_DATA == EFX_LOOPBACK_DATA);
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMAC == EFX_LOOPBACK_GMAC);
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGMII == EFX_LOOPBACK_XGMII);
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGXS == EFX_LOOPBACK_XGXS);
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI == EFX_LOOPBACK_XAUI);
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMII == EFX_LOOPBACK_GMII);
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SGMII == EFX_LOOPBACK_SGMII);
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGBR == EFX_LOOPBACK_XGBR);
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI == EFX_LOOPBACK_XFI);
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI_FAR == EFX_LOOPBACK_XAUI_FAR);
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMII_FAR == EFX_LOOPBACK_GMII_FAR);
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SGMII_FAR == EFX_LOOPBACK_SGMII_FAR);
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI_FAR == EFX_LOOPBACK_XFI_FAR);
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GPHY == EFX_LOOPBACK_GPHY);
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PHYXS == EFX_LOOPBACK_PHY_XS);
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PCS == EFX_LOOPBACK_PCS);
EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PMAPMD == EFX_LOOPBACK_PMA_PMD);
hlsp->hls_loopback = MCDI_OUT_DWORD(req, GET_LINK_OUT_LOOPBACK_MODE);
#endif /* EFSYS_OPT_LOOPBACK */
hlsp->hls_mac_up = MCDI_OUT_DWORD(req, GET_LINK_OUT_MAC_FAULT) == 0;
return (0);
fail2:
EFSYS_PROBE(fail2);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
__checkReturn int
hunt_phy_reconfigure(
__in efx_nic_t *enp)
{
/*
* TBD: this is a little different for now (no LED support for Hunt
* yet), but ultimately should consider common Siena/Hunt function:
* Hunt should be a superset of Siena here (adds 40G)
*/
efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
efx_port_t *epp = &(enp->en_port);
efx_mcdi_req_t req;
uint8_t payload[MAX(MC_CMD_SET_LINK_IN_LEN,
MC_CMD_SET_LINK_OUT_LEN)];
uint32_t cap_mask;
unsigned int led_mode;
unsigned int speed;
int rc;
if (~encp->enc_func_flags & EFX_NIC_FUNC_LINKCTRL)
goto out;
(void) memset(payload, 0, sizeof (payload));
req.emr_cmd = MC_CMD_SET_LINK;
req.emr_in_buf = payload;
req.emr_in_length = MC_CMD_SET_LINK_IN_LEN;
req.emr_out_buf = payload;
req.emr_out_length = MC_CMD_SET_LINK_OUT_LEN;
cap_mask = epp->ep_adv_cap_mask;
MCDI_IN_POPULATE_DWORD_10(req, SET_LINK_IN_CAP,
PHY_CAP_10HDX, (cap_mask >> EFX_PHY_CAP_10HDX) & 0x1,
PHY_CAP_10FDX, (cap_mask >> EFX_PHY_CAP_10FDX) & 0x1,
PHY_CAP_100HDX, (cap_mask >> EFX_PHY_CAP_100HDX) & 0x1,
PHY_CAP_100FDX, (cap_mask >> EFX_PHY_CAP_100FDX) & 0x1,
PHY_CAP_1000HDX, (cap_mask >> EFX_PHY_CAP_1000HDX) & 0x1,
PHY_CAP_1000FDX, (cap_mask >> EFX_PHY_CAP_1000FDX) & 0x1,
PHY_CAP_10000FDX, (cap_mask >> EFX_PHY_CAP_10000FDX) & 0x1,
PHY_CAP_PAUSE, (cap_mask >> EFX_PHY_CAP_PAUSE) & 0x1,
PHY_CAP_ASYM, (cap_mask >> EFX_PHY_CAP_ASYM) & 0x1,
PHY_CAP_AN, (cap_mask >> EFX_PHY_CAP_AN) & 0x1);
/* Too many fields for for POPULATE macros, so insert this afterwards */
MCDI_IN_SET_DWORD_FIELD(req, SET_LINK_IN_CAP,
PHY_CAP_40000FDX, (cap_mask >> EFX_PHY_CAP_40000FDX) & 0x1);
#if EFSYS_OPT_LOOPBACK
MCDI_IN_SET_DWORD(req, SET_LINK_IN_LOOPBACK_MODE,
epp->ep_loopback_type);
switch (epp->ep_loopback_link_mode) {
case EFX_LINK_100FDX:
speed = 100;
break;
case EFX_LINK_1000FDX:
speed = 1000;
break;
case EFX_LINK_10000FDX:
speed = 10000;
break;
case EFX_LINK_40000FDX:
speed = 40000;
break;
default:
speed = 0;
}
#else
MCDI_IN_SET_DWORD(req, SET_LINK_IN_LOOPBACK_MODE, MC_CMD_LOOPBACK_NONE);
speed = 0;
#endif /* EFSYS_OPT_LOOPBACK */
MCDI_IN_SET_DWORD(req, SET_LINK_IN_LOOPBACK_SPEED, speed);
#if EFSYS_OPT_PHY_FLAGS
MCDI_IN_SET_DWORD(req, SET_LINK_IN_FLAGS, epp->ep_phy_flags);
#else
MCDI_IN_SET_DWORD(req, SET_LINK_IN_FLAGS, 0);
#endif /* EFSYS_OPT_PHY_FLAGS */
efx_mcdi_execute(enp, &req);
if (req.emr_rc != 0) {
rc = req.emr_rc;
goto fail1;
}
/* And set the blink mode */
(void) memset(payload, 0, sizeof (payload));
req.emr_cmd = MC_CMD_SET_ID_LED;
req.emr_in_buf = payload;
req.emr_in_length = MC_CMD_SET_ID_LED_IN_LEN;
req.emr_out_buf = payload;
req.emr_out_length = MC_CMD_SET_ID_LED_OUT_LEN;
#if EFSYS_OPT_PHY_LED_CONTROL
switch (epp->ep_phy_led_mode) {
case EFX_PHY_LED_DEFAULT:
led_mode = MC_CMD_LED_DEFAULT;
break;
case EFX_PHY_LED_OFF:
led_mode = MC_CMD_LED_OFF;
break;
case EFX_PHY_LED_ON:
led_mode = MC_CMD_LED_ON;
break;
default:
EFSYS_ASSERT(0);
led_mode = MC_CMD_LED_DEFAULT;
}
MCDI_IN_SET_DWORD(req, SET_ID_LED_IN_STATE, led_mode);
#else
MCDI_IN_SET_DWORD(req, SET_ID_LED_IN_STATE, MC_CMD_LED_DEFAULT);
#endif /* EFSYS_OPT_PHY_LED_CONTROL */
efx_mcdi_execute(enp, &req);
if (req.emr_rc != 0) {
rc = req.emr_rc;
goto fail2;
}
out:
return (0);
fail2:
EFSYS_PROBE(fail2);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
__checkReturn int
hunt_phy_verify(
__in efx_nic_t *enp)
{
/* TBD: consider common Siena/Hunt function: essentially identical */
efx_mcdi_req_t req;
uint8_t payload[MAX(MC_CMD_GET_PHY_STATE_IN_LEN,
MC_CMD_GET_PHY_STATE_OUT_LEN)];
uint32_t state;
int rc;
(void) memset(payload, 0, sizeof (payload));
req.emr_cmd = MC_CMD_GET_PHY_STATE;
req.emr_in_buf = payload;
req.emr_in_length = MC_CMD_GET_PHY_STATE_IN_LEN;
req.emr_out_buf = payload;
req.emr_out_length = MC_CMD_GET_PHY_STATE_OUT_LEN;
efx_mcdi_execute(enp, &req);
if (req.emr_rc != 0) {
rc = req.emr_rc;
goto fail1;
}
if (req.emr_out_length_used < MC_CMD_GET_PHY_STATE_OUT_LEN) {
rc = EMSGSIZE;
goto fail2;
}
state = MCDI_OUT_DWORD(req, GET_PHY_STATE_OUT_STATE);
if (state != MC_CMD_PHY_STATE_OK) {
if (state != MC_CMD_PHY_STATE_ZOMBIE)
EFSYS_PROBE1(mc_pcol_error, int, state);
rc = ENOTACTIVE;
goto fail3;
}
return (0);
fail3:
EFSYS_PROBE(fail3);
fail2:
EFSYS_PROBE(fail2);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
__checkReturn int
hunt_phy_oui_get(
__in efx_nic_t *enp,
__out uint32_t *ouip)
{
_NOTE(ARGUNUSED(enp, ouip))
return (ENOTSUP);
}
#if EFSYS_OPT_PHY_STATS
__checkReturn int
hunt_phy_stats_update(
__in efx_nic_t *enp,
__in efsys_mem_t *esmp,
__out_ecount(EFX_PHY_NSTATS) uint32_t *stat)
{
/* TBD: no stats support in firmware yet */
_NOTE(ARGUNUSED(enp, esmp))
memset(stat, 0, EFX_PHY_NSTATS * sizeof (*stat));
return (0);
}
#endif /* EFSYS_OPT_PHY_STATS */
#if EFSYS_OPT_PHY_PROPS
#if EFSYS_OPT_NAMES
extern const char *
hunt_phy_prop_name(
__in efx_nic_t *enp,
__in unsigned int id)
{
_NOTE(ARGUNUSED(enp, id))
return (NULL);
}
#endif /* EFSYS_OPT_NAMES */
extern __checkReturn int
hunt_phy_prop_get(
__in efx_nic_t *enp,
__in unsigned int id,
__in uint32_t flags,
__out uint32_t *valp)
{
_NOTE(ARGUNUSED(enp, id, flags, valp))
return (ENOTSUP);
}
extern __checkReturn int
hunt_phy_prop_set(
__in efx_nic_t *enp,
__in unsigned int id,
__in uint32_t val)
{
_NOTE(ARGUNUSED(enp, id, val))
return (ENOTSUP);
}
#endif /* EFSYS_OPT_PHY_PROPS */
#if EFSYS_OPT_BIST
__checkReturn int
hunt_bist_enable_offline(
__in efx_nic_t *enp)
{
int rc;
if ((rc = efx_mcdi_bist_enable_offline(enp)) != 0)
goto fail1;
return (0);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
__checkReturn int
hunt_bist_start(
__in efx_nic_t *enp,
__in efx_bist_type_t type)
{
int rc;
if ((rc = efx_mcdi_bist_start(enp, type)) != 0)
goto fail1;
return (0);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
__checkReturn int
hunt_bist_poll(
__in efx_nic_t *enp,
__in efx_bist_type_t type,
__out efx_bist_result_t *resultp,
__out_opt __drv_when(count > 0, __notnull)
uint32_t *value_maskp,
__out_ecount_opt(count) __drv_when(count > 0, __notnull)
unsigned long *valuesp,
__in size_t count)
{
efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
efx_mcdi_req_t req;
uint8_t payload[MAX(MC_CMD_POLL_BIST_IN_LEN,
MCDI_CTL_SDU_LEN_MAX)];
uint32_t value_mask = 0;
uint32_t result;
int rc;
(void) memset(payload, 0, sizeof (payload));
req.emr_cmd = MC_CMD_POLL_BIST;
req.emr_in_buf = payload;
req.emr_in_length = MC_CMD_POLL_BIST_IN_LEN;
req.emr_out_buf = payload;
req.emr_out_length = MCDI_CTL_SDU_LEN_MAX;
efx_mcdi_execute(enp, &req);
if (req.emr_rc != 0) {
rc = req.emr_rc;
goto fail1;
}
if (req.emr_out_length_used < MC_CMD_POLL_BIST_OUT_RESULT_OFST + 4) {
rc = EMSGSIZE;
goto fail2;
}
if (count > 0)
(void) memset(valuesp, '\0', count * sizeof (unsigned long));
result = MCDI_OUT_DWORD(req, POLL_BIST_OUT_RESULT);
if (result == MC_CMD_POLL_BIST_FAILED &&
req.emr_out_length >= MC_CMD_POLL_BIST_OUT_MEM_LEN &&
count > EFX_BIST_MEM_ECC_FATAL) {
if (valuesp != NULL) {
valuesp[EFX_BIST_MEM_TEST] =
MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_TEST);
valuesp[EFX_BIST_MEM_ADDR] =
MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_ADDR);
valuesp[EFX_BIST_MEM_BUS] =
MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_BUS);
valuesp[EFX_BIST_MEM_EXPECT] =
MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_EXPECT);
valuesp[EFX_BIST_MEM_ACTUAL] =
MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_ACTUAL);
valuesp[EFX_BIST_MEM_ECC] =
MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_ECC);
valuesp[EFX_BIST_MEM_ECC_PARITY] =
MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_ECC_PARITY);
valuesp[EFX_BIST_MEM_ECC_FATAL] =
MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_ECC_FATAL);
}
value_mask |= (1 << EFX_BIST_MEM_TEST) |
(1 << EFX_BIST_MEM_ADDR) |
(1 << EFX_BIST_MEM_BUS) |
(1 << EFX_BIST_MEM_EXPECT) |
(1 << EFX_BIST_MEM_ACTUAL) |
(1 << EFX_BIST_MEM_ECC) |
(1 << EFX_BIST_MEM_ECC_PARITY) |
(1 << EFX_BIST_MEM_ECC_FATAL);
} else if (result == MC_CMD_POLL_BIST_FAILED &&
encp->enc_phy_type == EFX_PHY_XFI_FARMI &&
req.emr_out_length >= MC_CMD_POLL_BIST_OUT_MRSFP_LEN &&
count > EFX_BIST_FAULT_CODE) {
if (valuesp != NULL)
valuesp[EFX_BIST_FAULT_CODE] =
MCDI_OUT_DWORD(req, POLL_BIST_OUT_MRSFP_TEST);
value_mask |= 1 << EFX_BIST_FAULT_CODE;
}
if (value_maskp != NULL)
*value_maskp = value_mask;
EFSYS_ASSERT(resultp != NULL);
if (result == MC_CMD_POLL_BIST_RUNNING)
*resultp = EFX_BIST_RESULT_RUNNING;
else if (result == MC_CMD_POLL_BIST_PASSED)
*resultp = EFX_BIST_RESULT_PASSED;
else
*resultp = EFX_BIST_RESULT_FAILED;
return (0);
fail2:
EFSYS_PROBE(fail2);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
void
hunt_bist_stop(
__in efx_nic_t *enp,
__in efx_bist_type_t type)
{
/* There is no way to stop BIST on Huntinton. */
_NOTE(ARGUNUSED(enp, type))
}
#endif /* EFSYS_OPT_BIST */
#endif /* EFSYS_OPT_HUNTINGTON */

View File

@ -0,0 +1,765 @@
/*-
* Copyright (c) 2012-2015 Solarflare Communications Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the FreeBSD Project.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "efsys.h"
#include "efx.h"
#include "efx_impl.h"
#if EFSYS_OPT_HUNTINGTON
static __checkReturn int
efx_mcdi_init_rxq(
__in efx_nic_t *enp,
__in uint32_t size,
__in uint32_t target_evq,
__in uint32_t label,
__in uint32_t instance,
__in efsys_mem_t *esmp)
{
efx_mcdi_req_t req;
uint8_t payload[
MAX(MC_CMD_INIT_RXQ_IN_LEN(EFX_RXQ_NBUFS(EFX_RXQ_MAXNDESCS)),
MC_CMD_INIT_RXQ_OUT_LEN)];
int npages = EFX_RXQ_NBUFS(size);
int i;
efx_qword_t *dma_addr;
uint64_t addr;
int rc;
EFSYS_ASSERT3U(size, <=, EFX_RXQ_MAXNDESCS);
(void) memset(payload, 0, sizeof (payload));
req.emr_cmd = MC_CMD_INIT_RXQ;
req.emr_in_buf = payload;
req.emr_in_length = MC_CMD_INIT_RXQ_IN_LEN(npages);
req.emr_out_buf = payload;
req.emr_out_length = MC_CMD_INIT_RXQ_OUT_LEN;
MCDI_IN_SET_DWORD(req, INIT_RXQ_IN_SIZE, size);
MCDI_IN_SET_DWORD(req, INIT_RXQ_IN_TARGET_EVQ, target_evq);
MCDI_IN_SET_DWORD(req, INIT_RXQ_IN_LABEL, label);
MCDI_IN_SET_DWORD(req, INIT_RXQ_IN_INSTANCE, instance);
MCDI_IN_POPULATE_DWORD_5(req, INIT_RXQ_IN_FLAGS,
INIT_RXQ_IN_FLAG_BUFF_MODE, 0,
INIT_RXQ_IN_FLAG_HDR_SPLIT, 0,
INIT_RXQ_IN_FLAG_TIMESTAMP, 0,
INIT_RXQ_IN_CRC_MODE, 0,
INIT_RXQ_IN_FLAG_PREFIX, 1);
MCDI_IN_SET_DWORD(req, INIT_RXQ_IN_OWNER_ID, 0);
MCDI_IN_SET_DWORD(req, INIT_RXQ_IN_PORT_ID, EVB_PORT_ID_ASSIGNED);
dma_addr = MCDI_IN2(req, efx_qword_t, INIT_RXQ_IN_DMA_ADDR);
addr = EFSYS_MEM_ADDR(esmp);
for (i = 0; i < npages; i++) {
EFX_POPULATE_QWORD_2(*dma_addr,
EFX_DWORD_1, (uint32_t)(addr >> 32),
EFX_DWORD_0, (uint32_t)(addr & 0xffffffff));
dma_addr++;
addr += EFX_BUF_SIZE;
}
efx_mcdi_execute(enp, &req);
if (req.emr_rc != 0) {
rc = req.emr_rc;
goto fail1;
}
return (0);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
static __checkReturn int
efx_mcdi_fini_rxq(
__in efx_nic_t *enp,
__in uint32_t instance)
{
efx_mcdi_req_t req;
uint8_t payload[MAX(MC_CMD_FINI_RXQ_IN_LEN,
MC_CMD_FINI_RXQ_OUT_LEN)];
int rc;
(void) memset(payload, 0, sizeof (payload));
req.emr_cmd = MC_CMD_FINI_RXQ;
req.emr_in_buf = payload;
req.emr_in_length = MC_CMD_FINI_RXQ_IN_LEN;
req.emr_out_buf = payload;
req.emr_out_length = MC_CMD_FINI_RXQ_OUT_LEN;
MCDI_IN_SET_DWORD(req, FINI_RXQ_IN_INSTANCE, instance);
efx_mcdi_execute(enp, &req);
if ((req.emr_rc != 0) && (req.emr_rc != MC_CMD_ERR_EALREADY)) {
rc = req.emr_rc;
goto fail1;
}
return (0);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
#if EFSYS_OPT_RX_SCALE
static __checkReturn int
efx_mcdi_rss_context_alloc(
__in efx_nic_t *enp,
__out uint32_t *rss_contextp)
{
efx_mcdi_req_t req;
uint8_t payload[MAX(MC_CMD_RSS_CONTEXT_ALLOC_IN_LEN,
MC_CMD_RSS_CONTEXT_ALLOC_OUT_LEN)];
uint32_t rss_context;
int rc;
(void) memset(payload, 0, sizeof (payload));
req.emr_cmd = MC_CMD_RSS_CONTEXT_ALLOC;
req.emr_in_buf = payload;
req.emr_in_length = MC_CMD_RSS_CONTEXT_ALLOC_IN_LEN;
req.emr_out_buf = payload;
req.emr_out_length = MC_CMD_RSS_CONTEXT_ALLOC_OUT_LEN;
MCDI_IN_SET_DWORD(req, RSS_CONTEXT_ALLOC_IN_UPSTREAM_PORT_ID,
EVB_PORT_ID_ASSIGNED);
MCDI_IN_SET_DWORD(req, RSS_CONTEXT_ALLOC_IN_TYPE,
MC_CMD_RSS_CONTEXT_ALLOC_IN_TYPE_EXCLUSIVE);
/* NUM_QUEUES is only used to validate indirection table offsets */
MCDI_IN_SET_DWORD(req, RSS_CONTEXT_ALLOC_IN_NUM_QUEUES, 64);
efx_mcdi_execute(enp, &req);
if (req.emr_rc != 0) {
rc = req.emr_rc;
goto fail1;
}
if (req.emr_out_length_used < MC_CMD_RSS_CONTEXT_ALLOC_OUT_LEN) {
rc = EMSGSIZE;
goto fail2;
}
rss_context = MCDI_OUT_DWORD(req, RSS_CONTEXT_ALLOC_OUT_RSS_CONTEXT_ID);
if (rss_context == HUNTINGTON_RSS_CONTEXT_INVALID) {
rc = ENOENT;
goto fail3;
}
*rss_contextp = rss_context;
return (0);
fail3:
EFSYS_PROBE(fail3);
fail2:
EFSYS_PROBE(fail2);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
#endif /* EFSYS_OPT_RX_SCALE */
#if EFSYS_OPT_RX_SCALE
static int
efx_mcdi_rss_context_free(
__in efx_nic_t *enp,
__in uint32_t rss_context)
{
efx_mcdi_req_t req;
uint8_t payload[MAX(MC_CMD_RSS_CONTEXT_FREE_IN_LEN,
MC_CMD_RSS_CONTEXT_FREE_OUT_LEN)];
int rc;
if (rss_context == HUNTINGTON_RSS_CONTEXT_INVALID) {
rc = EINVAL;
goto fail1;
}
(void) memset(payload, 0, sizeof (payload));
req.emr_cmd = MC_CMD_RSS_CONTEXT_FREE;
req.emr_in_buf = payload;
req.emr_in_length = MC_CMD_RSS_CONTEXT_FREE_IN_LEN;
req.emr_out_buf = payload;
req.emr_out_length = MC_CMD_RSS_CONTEXT_FREE_OUT_LEN;
MCDI_IN_SET_DWORD(req, RSS_CONTEXT_FREE_IN_RSS_CONTEXT_ID, rss_context);
efx_mcdi_execute(enp, &req);
if (req.emr_rc != 0) {
rc = req.emr_rc;
goto fail2;
}
return (0);
fail2:
EFSYS_PROBE(fail2);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
#endif /* EFSYS_OPT_RX_SCALE */
#if EFSYS_OPT_RX_SCALE
static int
efx_mcdi_rss_context_set_flags(
__in efx_nic_t *enp,
__in uint32_t rss_context,
__in efx_rx_hash_type_t type)
{
efx_mcdi_req_t req;
uint8_t payload[MAX(MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_LEN,
MC_CMD_RSS_CONTEXT_SET_FLAGS_OUT_LEN)];
int rc;
if (rss_context == HUNTINGTON_RSS_CONTEXT_INVALID) {
rc = EINVAL;
goto fail1;
}
(void) memset(payload, 0, sizeof (payload));
req.emr_cmd = MC_CMD_RSS_CONTEXT_SET_FLAGS;
req.emr_in_buf = payload;
req.emr_in_length = MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_LEN;
req.emr_out_buf = payload;
req.emr_out_length = MC_CMD_RSS_CONTEXT_SET_FLAGS_OUT_LEN;
MCDI_IN_SET_DWORD(req, RSS_CONTEXT_SET_FLAGS_IN_RSS_CONTEXT_ID,
rss_context);
MCDI_IN_POPULATE_DWORD_4(req, RSS_CONTEXT_SET_FLAGS_IN_FLAGS,
RSS_CONTEXT_SET_FLAGS_IN_TOEPLITZ_IPV4_EN,
(type & (1U << EFX_RX_HASH_IPV4)) ? 1 : 0,
RSS_CONTEXT_SET_FLAGS_IN_TOEPLITZ_TCPV4_EN,
(type & (1U << EFX_RX_HASH_TCPIPV4)) ? 1 : 0,
RSS_CONTEXT_SET_FLAGS_IN_TOEPLITZ_IPV6_EN,
(type & (1U << EFX_RX_HASH_IPV6)) ? 1 : 0,
RSS_CONTEXT_SET_FLAGS_IN_TOEPLITZ_TCPV6_EN,
(type & (1U << EFX_RX_HASH_TCPIPV6)) ? 1 : 0);
efx_mcdi_execute(enp, &req);
if (req.emr_rc != 0) {
rc = req.emr_rc;
goto fail2;
}
return (0);
fail2:
EFSYS_PROBE(fail2);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
#endif /* EFSYS_OPT_RX_SCALE */
#if EFSYS_OPT_RX_SCALE
static int
efx_mcdi_rss_context_set_key(
__in efx_nic_t *enp,
__in uint32_t rss_context,
__in_ecount(n) uint8_t *key,
__in size_t n)
{
efx_mcdi_req_t req;
uint8_t payload[MAX(MC_CMD_RSS_CONTEXT_SET_KEY_IN_LEN,
MC_CMD_RSS_CONTEXT_SET_KEY_OUT_LEN)];
int rc;
if (rss_context == HUNTINGTON_RSS_CONTEXT_INVALID) {
rc = EINVAL;
goto fail1;
}
(void) memset(payload, 0, sizeof (payload));
req.emr_cmd = MC_CMD_RSS_CONTEXT_SET_KEY;
req.emr_in_buf = payload;
req.emr_in_length = MC_CMD_RSS_CONTEXT_SET_KEY_IN_LEN;
req.emr_out_buf = payload;
req.emr_out_length = MC_CMD_RSS_CONTEXT_SET_KEY_OUT_LEN;
MCDI_IN_SET_DWORD(req, RSS_CONTEXT_SET_KEY_IN_RSS_CONTEXT_ID,
rss_context);
EFSYS_ASSERT3U(n, ==, MC_CMD_RSS_CONTEXT_SET_KEY_IN_TOEPLITZ_KEY_LEN);
if (n != MC_CMD_RSS_CONTEXT_SET_KEY_IN_TOEPLITZ_KEY_LEN) {
rc = EINVAL;
goto fail2;
}
memcpy(MCDI_IN2(req, uint8_t, RSS_CONTEXT_SET_KEY_IN_TOEPLITZ_KEY),
key, n);
efx_mcdi_execute(enp, &req);
if (req.emr_rc != 0) {
rc = req.emr_rc;
goto fail3;
}
return (0);
fail3:
EFSYS_PROBE(fail3);
fail2:
EFSYS_PROBE(fail2);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
#endif /* EFSYS_OPT_RX_SCALE */
#if EFSYS_OPT_RX_SCALE
static int
efx_mcdi_rss_context_set_table(
__in efx_nic_t *enp,
__in uint32_t rss_context,
__in_ecount(n) unsigned int *table,
__in size_t n)
{
efx_mcdi_req_t req;
uint8_t payload[MAX(MC_CMD_RSS_CONTEXT_SET_TABLE_IN_LEN,
MC_CMD_RSS_CONTEXT_SET_TABLE_OUT_LEN)];
uint8_t *req_table;
int i, rc;
if (rss_context == HUNTINGTON_RSS_CONTEXT_INVALID) {
rc = EINVAL;
goto fail1;
}
(void) memset(payload, 0, sizeof (payload));
req.emr_cmd = MC_CMD_RSS_CONTEXT_SET_TABLE;
req.emr_in_buf = payload;
req.emr_in_length = MC_CMD_RSS_CONTEXT_SET_TABLE_IN_LEN;
req.emr_out_buf = payload;
req.emr_out_length = MC_CMD_RSS_CONTEXT_SET_TABLE_OUT_LEN;
MCDI_IN_SET_DWORD(req, RSS_CONTEXT_SET_TABLE_IN_RSS_CONTEXT_ID,
rss_context);
req_table =
MCDI_IN2(req, uint8_t, RSS_CONTEXT_SET_TABLE_IN_INDIRECTION_TABLE);
for (i = 0;
i < MC_CMD_RSS_CONTEXT_SET_TABLE_IN_INDIRECTION_TABLE_LEN;
i++) {
req_table[i] = (n > 0) ? (uint8_t)table[i % n] : 0;
}
efx_mcdi_execute(enp, &req);
if (req.emr_rc != 0) {
rc = req.emr_rc;
goto fail2;
}
return (0);
fail2:
EFSYS_PROBE(fail2);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
#endif /* EFSYS_OPT_RX_SCALE */
__checkReturn int
hunt_rx_init(
__in efx_nic_t *enp)
{
#if EFSYS_OPT_RX_SCALE
if (efx_mcdi_rss_context_alloc(enp, &enp->en_rss_context) == 0) {
/*
* Allocated an exclusive RSS context, which allows both the
* indirection table and key to be modified.
*/
enp->en_rss_support = EFX_RX_SCALE_EXCLUSIVE;
enp->en_hash_support = EFX_RX_HASH_AVAILABLE;
} else {
/*
* Failed to allocate an exclusive RSS context. Continue
* operation without support for RSS. The pseudo-header in
* received packets will not contain a Toeplitz hash value.
*/
enp->en_rss_support = EFX_RX_SCALE_UNAVAILABLE;
enp->en_hash_support = EFX_RX_HASH_UNAVAILABLE;
}
#endif /* EFSYS_OPT_RX_SCALE */
return (0);
}
#if EFSYS_OPT_RX_HDR_SPLIT
__checkReturn int
hunt_rx_hdr_split_enable(
__in efx_nic_t *enp,
__in unsigned int hdr_buf_size,
__in unsigned int pld_buf_size)
{
int rc;
/* FIXME */
_NOTE(ARGUNUSED(enp, hdr_buf_size, pld_buf_size))
if (B_FALSE) {
rc = ENOTSUP;
goto fail1;
}
/* FIXME */
return (0);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
#endif /* EFSYS_OPT_RX_HDR_SPLIT */
#if EFSYS_OPT_RX_SCATTER
__checkReturn int
hunt_rx_scatter_enable(
__in efx_nic_t *enp,
__in unsigned int buf_size)
{
_NOTE(ARGUNUSED(enp, buf_size))
return (0);
}
#endif /* EFSYS_OPT_RX_SCATTER */
#if EFSYS_OPT_RX_SCALE
__checkReturn int
hunt_rx_scale_mode_set(
__in efx_nic_t *enp,
__in efx_rx_hash_alg_t alg,
__in efx_rx_hash_type_t type,
__in boolean_t insert)
{
int rc;
EFSYS_ASSERT3U(alg, ==, EFX_RX_HASHALG_TOEPLITZ);
EFSYS_ASSERT3U(insert, ==, B_TRUE);
if ((alg != EFX_RX_HASHALG_TOEPLITZ) || (insert == B_FALSE)) {
rc = EINVAL;
goto fail1;
}
if (enp->en_rss_support == EFX_RX_SCALE_UNAVAILABLE) {
rc = ENOTSUP;
goto fail2;
}
if ((rc = efx_mcdi_rss_context_set_flags(enp,
enp->en_rss_context, type)) != 0)
goto fail3;
return (0);
fail3:
EFSYS_PROBE(fail3);
fail2:
EFSYS_PROBE(fail2);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
#endif /* EFSYS_OPT_RX_SCALE */
#if EFSYS_OPT_RX_SCALE
__checkReturn int
hunt_rx_scale_key_set(
__in efx_nic_t *enp,
__in_ecount(n) uint8_t *key,
__in size_t n)
{
int rc;
if (enp->en_rss_support == EFX_RX_SCALE_UNAVAILABLE) {
rc = ENOTSUP;
goto fail1;
}
if ((rc = efx_mcdi_rss_context_set_key(enp,
enp->en_rss_context, key, n)) != 0)
goto fail2;
return (0);
fail2:
EFSYS_PROBE(fail2);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
#endif /* EFSYS_OPT_RX_SCALE */
#if EFSYS_OPT_RX_SCALE
__checkReturn int
hunt_rx_scale_tbl_set(
__in efx_nic_t *enp,
__in_ecount(n) unsigned int *table,
__in size_t n)
{
int rc;
if (enp->en_rss_support == EFX_RX_SCALE_UNAVAILABLE) {
rc = ENOTSUP;
goto fail1;
}
if ((rc = efx_mcdi_rss_context_set_table(enp,
enp->en_rss_context, table, n)) != 0)
goto fail2;
return (0);
fail2:
EFSYS_PROBE(fail2);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
#endif /* EFSYS_OPT_RX_SCALE */
void
hunt_rx_qpost(
__in efx_rxq_t *erp,
__in_ecount(n) efsys_dma_addr_t *addrp,
__in size_t size,
__in unsigned int n,
__in unsigned int completed,
__in unsigned int added)
{
efx_qword_t qword;
unsigned int i;
unsigned int offset;
unsigned int id;
/* The client driver must not overfill the queue */
EFSYS_ASSERT3U(added - completed + n, <=,
EFX_RXQ_LIMIT(erp->er_mask + 1));
id = added & (erp->er_mask);
for (i = 0; i < n; i++) {
EFSYS_PROBE4(rx_post, unsigned int, erp->er_index,
unsigned int, id, efsys_dma_addr_t, addrp[i],
size_t, size);
EFX_POPULATE_QWORD_3(qword,
ESF_DZ_RX_KER_BYTE_CNT, (uint32_t)(size),
ESF_DZ_RX_KER_BUF_ADDR_DW0,
(uint32_t)(addrp[i] & 0xffffffff),
ESF_DZ_RX_KER_BUF_ADDR_DW1,
(uint32_t)(addrp[i] >> 32));
offset = id * sizeof (efx_qword_t);
EFSYS_MEM_WRITEQ(erp->er_esmp, offset, &qword);
id = (id + 1) & (erp->er_mask);
}
}
void
hunt_rx_qpush(
__in efx_rxq_t *erp,
__in unsigned int added,
__inout unsigned int *pushedp)
{
efx_nic_t *enp = erp->er_enp;
unsigned int pushed = *pushedp;
uint32_t wptr;
efx_dword_t dword;
/* Hardware has alignment restriction for WPTR */
wptr = P2ALIGN(added, HUNTINGTON_RX_WPTR_ALIGN);
if (pushed == wptr)
return;
*pushedp = wptr;
/* Push the populated descriptors out */
wptr &= erp->er_mask;
EFX_POPULATE_DWORD_1(dword, ERF_DZ_RX_DESC_WPTR, wptr);
/* Guarantee ordering of memory (descriptors) and PIO (doorbell) */
EFX_DMA_SYNC_QUEUE_FOR_DEVICE(erp->er_esmp, erp->er_mask + 1,
wptr, pushed & erp->er_mask);
EFSYS_PIO_WRITE_BARRIER();
EFX_BAR_TBL_WRITED(enp, ER_DZ_RX_DESC_UPD_REG,
erp->er_index, &dword, B_FALSE);
}
__checkReturn int
hunt_rx_qflush(
__in efx_rxq_t *erp)
{
efx_nic_t *enp = erp->er_enp;
int rc;
if ((rc = efx_mcdi_fini_rxq(enp, erp->er_index)) != 0)
goto fail1;
return (0);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
void
hunt_rx_qenable(
__in efx_rxq_t *erp)
{
/* FIXME */
_NOTE(ARGUNUSED(erp))
/* FIXME */
}
__checkReturn int
hunt_rx_qcreate(
__in efx_nic_t *enp,
__in unsigned int index,
__in unsigned int label,
__in efx_rxq_type_t type,
__in efsys_mem_t *esmp,
__in size_t n,
__in uint32_t id,
__in efx_evq_t *eep,
__in efx_rxq_t *erp)
{
efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
int rc;
_NOTE(ARGUNUSED(erp))
EFX_STATIC_ASSERT(EFX_EV_RX_NLABELS == (1 << ESF_DZ_RX_QLABEL_WIDTH));
EFSYS_ASSERT3U(label, <, EFX_EV_RX_NLABELS);
EFSYS_ASSERT3U(enp->en_rx_qcount + 1, <, encp->enc_rxq_limit);
EFX_STATIC_ASSERT(ISP2(EFX_RXQ_MAXNDESCS));
EFX_STATIC_ASSERT(ISP2(EFX_RXQ_MINNDESCS));
if (!ISP2(n) || (n < EFX_RXQ_MINNDESCS) || (n > EFX_RXQ_MAXNDESCS)) {
rc = EINVAL;
goto fail1;
}
if (index >= encp->enc_rxq_limit) {
rc = EINVAL;
goto fail2;
}
/*
* FIXME: Siena code handles different queue types (default, header
* split, scatter); we'll need to do something more here later, but
* all that stuff is TBD for now.
*/
if ((rc = efx_mcdi_init_rxq(enp, n, eep->ee_index, label, index,
esmp)) != 0)
goto fail3;
erp->er_eep = eep;
erp->er_label = label;
hunt_ev_rxlabel_init(eep, erp, label);
return (0);
fail3:
EFSYS_PROBE(fail3);
fail2:
EFSYS_PROBE(fail2);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
void
hunt_rx_qdestroy(
__in efx_rxq_t *erp)
{
efx_nic_t *enp = erp->er_enp;
efx_evq_t *eep = erp->er_eep;
unsigned int label = erp->er_label;
hunt_ev_rxlabel_fini(eep, label);
EFSYS_ASSERT(enp->en_rx_qcount != 0);
--enp->en_rx_qcount;
EFSYS_KMEM_FREE(enp->en_esip, sizeof (efx_rxq_t), erp);
}
void
hunt_rx_fini(
__in efx_nic_t *enp)
{
#if EFSYS_OPT_RX_SCALE
if (enp->en_rss_support != EFX_RX_SCALE_UNAVAILABLE) {
(void) efx_mcdi_rss_context_free(enp, enp->en_rss_context);
}
enp->en_rss_context = 0;
enp->en_rss_support = EFX_RX_SCALE_UNAVAILABLE;
#else
_NOTE(ARGUNUSED(enp))
#endif /* EFSYS_OPT_RX_SCALE */
}
#endif /* EFSYS_OPT_HUNTINGTON */

View File

@ -0,0 +1,69 @@
/*-
* Copyright (c) 2012-2015 Solarflare Communications Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the FreeBSD Project.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "efsys.h"
#include "efx.h"
#include "efx_impl.h"
#if EFSYS_OPT_HUNTINGTON
#if EFSYS_OPT_DIAG
__checkReturn int
hunt_sram_test(
__in efx_nic_t *enp,
__in efx_sram_pattern_fn_t func)
{
int rc;
/* FIXME */
_NOTE(ARGUNUSED(enp))
_NOTE(ARGUNUSED(func))
if (B_FALSE) {
rc = ENOTSUP;
goto fail1;
}
/* FIXME */
return (0);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
#endif /* EFSYS_OPT_DIAG */
#endif /* EFSYS_OPT_HUNTINGTON */

679
sys/dev/sfxge/common/hunt_tx.c Executable file
View File

@ -0,0 +1,679 @@
/*-
* Copyright (c) 2012-2015 Solarflare Communications Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the FreeBSD Project.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "efsys.h"
#include "efx.h"
#include "efx_impl.h"
#if EFSYS_OPT_HUNTINGTON
#if EFSYS_OPT_QSTATS
#define EFX_TX_QSTAT_INCR(_etp, _stat) \
do { \
(_etp)->et_stat[_stat]++; \
_NOTE(CONSTANTCONDITION) \
} while (B_FALSE)
#else
#define EFX_TX_QSTAT_INCR(_etp, _stat)
#endif
static __checkReturn int
efx_mcdi_init_txq(
__in efx_nic_t *enp,
__in uint32_t size,
__in uint32_t target_evq,
__in uint32_t label,
__in uint32_t instance,
__in uint16_t flags,
__in efsys_mem_t *esmp)
{
efx_mcdi_req_t req;
uint8_t payload[MAX(MC_CMD_INIT_TXQ_IN_LEN(EFX_TXQ_MAX_BUFS),
MC_CMD_INIT_TXQ_OUT_LEN)];
efx_qword_t *dma_addr;
uint64_t addr;
int npages;
int i;
int rc;
EFSYS_ASSERT(EFX_TXQ_MAX_BUFS >=
EFX_TXQ_NBUFS(EFX_TXQ_MAXNDESCS(&enp->en_nic_cfg)));
npages = EFX_TXQ_NBUFS(size);
if (npages > MC_CMD_INIT_TXQ_IN_DMA_ADDR_MAXNUM) {
rc = EINVAL;
goto fail1;
}
(void) memset(payload, 0, sizeof (payload));
req.emr_cmd = MC_CMD_INIT_TXQ;
req.emr_in_buf = payload;
req.emr_in_length = MC_CMD_INIT_TXQ_IN_LEN(npages);
req.emr_out_buf = payload;
req.emr_out_length = MC_CMD_INIT_TXQ_OUT_LEN;
MCDI_IN_SET_DWORD(req, INIT_TXQ_IN_SIZE, size);
MCDI_IN_SET_DWORD(req, INIT_TXQ_IN_TARGET_EVQ, target_evq);
MCDI_IN_SET_DWORD(req, INIT_TXQ_IN_LABEL, label);
MCDI_IN_SET_DWORD(req, INIT_TXQ_IN_INSTANCE, instance);
MCDI_IN_POPULATE_DWORD_6(req, INIT_TXQ_IN_FLAGS,
INIT_TXQ_IN_FLAG_BUFF_MODE, 0,
INIT_TXQ_IN_FLAG_IP_CSUM_DIS, (flags & EFX_CKSUM_IPV4) ? 0 : 1,
INIT_TXQ_IN_FLAG_TCP_CSUM_DIS, (flags & EFX_CKSUM_TCPUDP) ? 0 : 1,
INIT_TXQ_IN_FLAG_TCP_UDP_ONLY, 0,
INIT_TXQ_IN_CRC_MODE, 0,
INIT_TXQ_IN_FLAG_TIMESTAMP, 0);
MCDI_IN_SET_DWORD(req, INIT_TXQ_IN_OWNER_ID, 0);
MCDI_IN_SET_DWORD(req, INIT_TXQ_IN_PORT_ID, EVB_PORT_ID_ASSIGNED);
dma_addr = MCDI_IN2(req, efx_qword_t, INIT_TXQ_IN_DMA_ADDR);
addr = EFSYS_MEM_ADDR(esmp);
for (i = 0; i < npages; i++) {
EFX_POPULATE_QWORD_2(*dma_addr,
EFX_DWORD_1, (uint32_t)(addr >> 32),
EFX_DWORD_0, (uint32_t)(addr & 0xffffffff));
dma_addr++;
addr += EFX_BUF_SIZE;
}
efx_mcdi_execute(enp, &req);
if (req.emr_rc != 0) {
rc = req.emr_rc;
goto fail2;
}
return (0);
fail2:
EFSYS_PROBE(fail2);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
static __checkReturn int
efx_mcdi_fini_txq(
__in efx_nic_t *enp,
__in uint32_t instance)
{
efx_mcdi_req_t req;
uint8_t payload[MAX(MC_CMD_FINI_TXQ_IN_LEN,
MC_CMD_FINI_TXQ_OUT_LEN)];
int rc;
(void) memset(payload, 0, sizeof (payload));
req.emr_cmd = MC_CMD_FINI_TXQ;
req.emr_in_buf = payload;
req.emr_in_length = MC_CMD_FINI_TXQ_IN_LEN;
req.emr_out_buf = payload;
req.emr_out_length = MC_CMD_FINI_TXQ_OUT_LEN;
MCDI_IN_SET_DWORD(req, FINI_TXQ_IN_INSTANCE, instance);
efx_mcdi_execute(enp, &req);
if ((req.emr_rc != 0) && (req.emr_rc != MC_CMD_ERR_EALREADY)) {
rc = req.emr_rc;
goto fail1;
}
return (0);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
__checkReturn int
hunt_tx_init(
__in efx_nic_t *enp)
{
_NOTE(ARGUNUSED(enp))
return (0);
}
void
hunt_tx_fini(
__in efx_nic_t *enp)
{
_NOTE(ARGUNUSED(enp))
}
__checkReturn int
hunt_tx_qcreate(
__in efx_nic_t *enp,
__in unsigned int index,
__in unsigned int label,
__in efsys_mem_t *esmp,
__in size_t n,
__in uint32_t id,
__in uint16_t flags,
__in efx_evq_t *eep,
__in efx_txq_t *etp,
__out unsigned int *addedp)
{
efx_qword_t desc;
int rc;
if ((rc = efx_mcdi_init_txq(enp, n, eep->ee_index, label, index, flags,
esmp)) != 0)
goto fail1;
/*
* A previous user of this TX queue may have written a descriptor to the
* TX push collector, but not pushed the doorbell (e.g. after a crash).
* The next doorbell write would then push the stale descriptor.
*
* Ensure the (per network port) TX push collector is cleared by writing
* a no-op TX option descriptor. See bug29981 for details.
*/
*addedp = 1;
EFX_POPULATE_QWORD_4(desc,
ESF_DZ_TX_DESC_IS_OPT, 1,
ESF_DZ_TX_OPTION_TYPE, ESE_DZ_TX_OPTION_DESC_CRC_CSUM,
ESF_DZ_TX_OPTION_UDP_TCP_CSUM, (flags & EFX_CKSUM_TCPUDP) ? 1 : 0,
ESF_DZ_TX_OPTION_IP_CSUM, (flags & EFX_CKSUM_IPV4) ? 1 : 0);
EFSYS_MEM_WRITEQ(etp->et_esmp, 0, &desc);
hunt_tx_qpush(etp, *addedp, 0);
return (0);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
void
hunt_tx_qdestroy(
__in efx_txq_t *etp)
{
/* FIXME */
_NOTE(ARGUNUSED(etp))
/* FIXME */
}
__checkReturn int
hunt_tx_qpio_enable(
__in efx_txq_t *etp)
{
efx_nic_t *enp = etp->et_enp;
efx_piobuf_handle_t handle;
int rc;
if (etp->et_pio_size != 0) {
rc = EALREADY;
goto fail1;
}
/* Sub-allocate a PIO block from a piobuf */
if ((rc = hunt_nic_pio_alloc(enp,
&etp->et_pio_bufnum,
&handle,
&etp->et_pio_blknum,
&etp->et_pio_offset,
&etp->et_pio_size)) != 0) {
goto fail2;
}
EFSYS_ASSERT3U(etp->et_pio_size, !=, 0);
/* Link the piobuf to this TXQ */
if ((rc = hunt_nic_pio_link(enp, etp->et_index, handle)) != 0) {
goto fail3;
}
/*
* et_pio_offset is the offset of the sub-allocated block within the
* hardware PIO buffer. It is used as the buffer address in the PIO
* option descriptor.
*
* et_pio_write_offset is the offset of the sub-allocated block from the
* start of the write-combined memory mapping, and is used for writing
* data into the PIO buffer.
*/
etp->et_pio_write_offset =
(etp->et_pio_bufnum * ER_DZ_TX_PIOBUF_STEP) +
ER_DZ_TX_PIOBUF_OFST + etp->et_pio_offset;
return (0);
fail3:
EFSYS_PROBE(fail3);
hunt_nic_pio_free(enp, etp->et_pio_bufnum, etp->et_pio_blknum);
etp->et_pio_size = 0;
fail2:
EFSYS_PROBE(fail2);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
void
hunt_tx_qpio_disable(
__in efx_txq_t *etp)
{
efx_nic_t *enp = etp->et_enp;
if (etp->et_pio_size != 0) {
/* Unlink the piobuf from this TXQ */
hunt_nic_pio_unlink(enp, etp->et_index);
/* Free the sub-allocated PIO block */
hunt_nic_pio_free(enp, etp->et_pio_bufnum, etp->et_pio_blknum);
etp->et_pio_size = 0;
etp->et_pio_write_offset = 0;
}
}
__checkReturn int
hunt_tx_qpio_write(
__in efx_txq_t *etp,
__in_ecount(length) uint8_t *buffer,
__in size_t length,
__in size_t offset)
{
efx_nic_t *enp = etp->et_enp;
efsys_bar_t *esbp = enp->en_esbp;
uint32_t write_offset;
uint32_t write_offset_limit;
efx_qword_t *eqp;
int rc;
EFSYS_ASSERT(length % sizeof (efx_qword_t) == 0);
if (etp->et_pio_size == 0) {
rc = ENOENT;
goto fail1;
}
if (offset + length > etp->et_pio_size) {
rc = ENOSPC;
goto fail2;
}
/*
* Writes to PIO buffers must be 64 bit aligned, and multiples of
* 64 bits.
*/
write_offset = etp->et_pio_write_offset + offset;
write_offset_limit = write_offset + length;
eqp = (efx_qword_t *)buffer;
while (write_offset < write_offset_limit) {
EFSYS_BAR_WC_WRITEQ(esbp, write_offset, eqp);
eqp++;
write_offset += sizeof (efx_qword_t);
}
return (0);
fail2:
EFSYS_PROBE(fail2);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
__checkReturn int
hunt_tx_qpio_post(
__in efx_txq_t *etp,
__in size_t pkt_length,
__in unsigned int completed,
__inout unsigned int *addedp)
{
efx_qword_t pio_desc;
unsigned int id;
size_t offset;
unsigned int added = *addedp;
int rc;
if (added - completed + 1 > EFX_TXQ_LIMIT(etp->et_mask + 1)) {
rc = ENOSPC;
goto fail1;
}
if (etp->et_pio_size == 0) {
rc = ENOENT;
goto fail2;
}
id = added++ & etp->et_mask;
offset = id * sizeof (efx_qword_t);
EFSYS_PROBE4(tx_pio_post, unsigned int, etp->et_index,
unsigned int, id, uint32_t, etp->et_pio_offset,
size_t, pkt_length);
EFX_POPULATE_QWORD_5(pio_desc,
ESF_DZ_TX_DESC_IS_OPT, 1,
ESF_DZ_TX_OPTION_TYPE, 1,
ESF_DZ_TX_PIO_CONT, 0,
ESF_DZ_TX_PIO_BYTE_CNT, pkt_length,
ESF_DZ_TX_PIO_BUF_ADDR, etp->et_pio_offset);
EFSYS_MEM_WRITEQ(etp->et_esmp, offset, &pio_desc);
EFX_TX_QSTAT_INCR(etp, TX_POST_PIO);
*addedp = added;
return (0);
fail2:
EFSYS_PROBE(fail2);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
__checkReturn int
hunt_tx_qpost(
__in efx_txq_t *etp,
__in_ecount(n) efx_buffer_t *eb,
__in unsigned int n,
__in unsigned int completed,
__inout unsigned int *addedp)
{
unsigned int added = *addedp;
unsigned int i;
int rc;
if (added - completed + n > EFX_TXQ_LIMIT(etp->et_mask + 1)) {
rc = ENOSPC;
goto fail1;
}
for (i = 0; i < n; i++) {
efx_buffer_t *ebp = &eb[i];
efsys_dma_addr_t addr = ebp->eb_addr;
size_t size = ebp->eb_size;
boolean_t eop = ebp->eb_eop;
unsigned int id;
size_t offset;
efx_qword_t qword;
/* Fragments must not span 4k boundaries. */
EFSYS_ASSERT(P2ROUNDUP(addr + 1, 4096) >= (addr + size));
id = added++ & etp->et_mask;
offset = id * sizeof (efx_qword_t);
EFSYS_PROBE5(tx_post, unsigned int, etp->et_index,
unsigned int, id, efsys_dma_addr_t, addr,
size_t, size, boolean_t, eop);
EFX_POPULATE_QWORD_5(qword,
ESF_DZ_TX_KER_TYPE, 0,
ESF_DZ_TX_KER_CONT, (eop) ? 0 : 1,
ESF_DZ_TX_KER_BYTE_CNT, (uint32_t)(size),
ESF_DZ_TX_KER_BUF_ADDR_DW0, (uint32_t)(addr & 0xffffffff),
ESF_DZ_TX_KER_BUF_ADDR_DW1, (uint32_t)(addr >> 32));
EFSYS_MEM_WRITEQ(etp->et_esmp, offset, &qword);
}
EFX_TX_QSTAT_INCR(etp, TX_POST);
*addedp = added;
return (0);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
/*
* This improves performance by pushing a TX descriptor at the same time as the
* doorbell. The descriptor must be added to the TXQ, so that can be used if the
* hardware decides not to use the pushed descriptor.
*/
void
hunt_tx_qpush(
__in efx_txq_t *etp,
__in unsigned int added,
__in unsigned int pushed)
{
efx_nic_t *enp = etp->et_enp;
unsigned int wptr;
unsigned int id;
size_t offset;
efx_qword_t desc;
efx_oword_t oword;
wptr = added & etp->et_mask;
id = pushed & etp->et_mask;
offset = id * sizeof (efx_qword_t);
EFSYS_MEM_READQ(etp->et_esmp, offset, &desc);
EFX_POPULATE_OWORD_3(oword,
ERF_DZ_TX_DESC_WPTR, wptr,
ERF_DZ_TX_DESC_HWORD, EFX_QWORD_FIELD(desc, EFX_DWORD_1),
ERF_DZ_TX_DESC_LWORD, EFX_QWORD_FIELD(desc, EFX_DWORD_0));
/* Guarantee ordering of memory (descriptors) and PIO (doorbell) */
EFX_DMA_SYNC_QUEUE_FOR_DEVICE(etp->et_esmp, etp->et_mask + 1, wptr, id);
EFSYS_PIO_WRITE_BARRIER();
EFX_BAR_TBL_DOORBELL_WRITEO(enp, ER_DZ_TX_DESC_UPD_REG, etp->et_index,
&oword);
}
__checkReturn int
hunt_tx_qdesc_post(
__in efx_txq_t *etp,
__in_ecount(n) efx_desc_t *ed,
__in unsigned int n,
__in unsigned int completed,
__inout unsigned int *addedp)
{
unsigned int added = *addedp;
unsigned int i;
int rc;
if (added - completed + n > EFX_TXQ_LIMIT(etp->et_mask + 1)) {
rc = ENOSPC;
goto fail1;
}
for (i = 0; i < n; i++) {
efx_desc_t *edp = &ed[i];
unsigned int id;
size_t offset;
id = added++ & etp->et_mask;
offset = id * sizeof (efx_desc_t);
EFSYS_MEM_WRITEQ(etp->et_esmp, offset, &edp->ed_eq);
}
EFSYS_PROBE3(tx_desc_post, unsigned int, etp->et_index,
unsigned int, added, unsigned int, n);
EFX_TX_QSTAT_INCR(etp, TX_POST);
*addedp = added;
return (0);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
void
hunt_tx_qdesc_dma_create(
__in efx_txq_t *etp,
__in efsys_dma_addr_t addr,
__in size_t size,
__in boolean_t eop,
__out efx_desc_t *edp)
{
/* Fragments must not span 4k boundaries. */
EFSYS_ASSERT(P2ROUNDUP(addr + 1, 4096) >= addr + size);
EFSYS_PROBE4(tx_desc_dma_create, unsigned int, etp->et_index,
efsys_dma_addr_t, addr,
size_t, size, boolean_t, eop);
EFX_POPULATE_QWORD_5(edp->ed_eq,
ESF_DZ_TX_KER_TYPE, 0,
ESF_DZ_TX_KER_CONT, (eop) ? 0 : 1,
ESF_DZ_TX_KER_BYTE_CNT, (uint32_t)(size),
ESF_DZ_TX_KER_BUF_ADDR_DW0, (uint32_t)(addr & 0xffffffff),
ESF_DZ_TX_KER_BUF_ADDR_DW1, (uint32_t)(addr >> 32));
}
void
hunt_tx_qdesc_tso_create(
__in efx_txq_t *etp,
__in uint16_t ipv4_id,
__in uint32_t tcp_seq,
__in uint8_t tcp_flags,
__out efx_desc_t *edp)
{
EFSYS_PROBE4(tx_desc_tso_create, unsigned int, etp->et_index,
uint16_t, ipv4_id, uint32_t, tcp_seq,
uint8_t, tcp_flags);
EFX_POPULATE_QWORD_5(edp->ed_eq,
ESF_DZ_TX_DESC_IS_OPT, 1,
ESF_DZ_TX_OPTION_TYPE,
ESE_DZ_TX_OPTION_DESC_TSO,
ESF_DZ_TX_TSO_TCP_FLAGS, tcp_flags,
ESF_DZ_TX_TSO_IP_ID, ipv4_id,
ESF_DZ_TX_TSO_TCP_SEQNO, tcp_seq);
}
void
hunt_tx_qdesc_vlantci_create(
__in efx_txq_t *etp,
__in uint16_t tci,
__out efx_desc_t *edp)
{
EFSYS_PROBE2(tx_desc_vlantci_create, unsigned int, etp->et_index,
uint16_t, tci);
EFX_POPULATE_QWORD_4(edp->ed_eq,
ESF_DZ_TX_DESC_IS_OPT, 1,
ESF_DZ_TX_OPTION_TYPE,
ESE_DZ_TX_OPTION_DESC_VLAN,
ESF_DZ_TX_VLAN_OP, tci ? 1 : 0,
ESF_DZ_TX_VLAN_TAG1, tci);
}
__checkReturn int
hunt_tx_qpace(
__in efx_txq_t *etp,
__in unsigned int ns)
{
int rc;
/* FIXME */
_NOTE(ARGUNUSED(etp, ns))
if (B_FALSE) {
rc = ENOTSUP;
goto fail1;
}
/* FIXME */
return (0);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
__checkReturn int
hunt_tx_qflush(
__in efx_txq_t *etp)
{
efx_nic_t *enp = etp->et_enp;
int rc;
if ((rc = efx_mcdi_fini_txq(enp, etp->et_index)) != 0)
goto fail1;
return (0);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
void
hunt_tx_qenable(
__in efx_txq_t *etp)
{
/* FIXME */
_NOTE(ARGUNUSED(etp))
/* FIXME */
}
#if EFSYS_OPT_QSTATS
void
hunt_tx_qstats_update(
__in efx_txq_t *etp,
__inout_ecount(TX_NQSTATS) efsys_stat_t *stat)
{
/*
* TBD: Consider a common Siena/Huntington function. The code is
* essentially identical.
*/
unsigned int id;
for (id = 0; id < TX_NQSTATS; id++) {
efsys_stat_t *essp = &stat[id];
EFSYS_STAT_INCR(essp, etp->et_stat[id]);
etp->et_stat[id] = 0;
}
}
#endif /* EFSYS_OPT_QSTATS */
#endif /* EFSYS_OPT_HUNTINGTON */

View File

@ -0,0 +1,435 @@
/*-
* Copyright (c) 2009-2015 Solarflare Communications Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the FreeBSD Project.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "efsys.h"
#include "efx.h"
#include "efx_types.h"
#include "efx_regs.h"
#include "efx_impl.h"
#if EFSYS_OPT_VPD
#if EFSYS_OPT_HUNTINGTON
#include "ef10_tlv_layout.h"
__checkReturn int
hunt_vpd_init(
__in efx_nic_t *enp)
{
caddr_t svpd;
size_t svpd_size;
uint32_t pci_pf;
int rc;
EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON);
pci_pf = enp->en_nic_cfg.enc_pf;
/*
* The VPD interface exposes VPD resources from the combined static and
* dynamic VPD storage. As the static VPD configuration should *never*
* change, we can cache it.
*/
svpd = NULL;
svpd_size = 0;
rc = hunt_nvram_partn_read_tlv(enp,
NVRAM_PARTITION_TYPE_STATIC_CONFIG,
TLV_TAG_PF_STATIC_VPD(pci_pf),
&svpd, &svpd_size);
if (rc != 0) {
if (rc == EACCES) {
/* Unpriviledged functions cannot access VPD */
goto out;
}
goto fail1;
}
if (svpd != NULL && svpd_size > 0) {
if ((rc = efx_vpd_hunk_verify(svpd, svpd_size, NULL)) != 0)
goto fail2;
}
enp->en_u.hunt.enu_svpd = svpd;
enp->en_u.hunt.enu_svpd_length = svpd_size;
out:
return (0);
fail2:
EFSYS_PROBE(fail2);
EFSYS_KMEM_FREE(enp->en_esip, svpd_size, svpd);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
__checkReturn int
hunt_vpd_size(
__in efx_nic_t *enp,
__out size_t *sizep)
{
int rc;
EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON);
/*
* This function returns the total size the user should allocate
* for all VPD operations. We've already cached the static vpd,
* so we just need to return an upper bound on the dynamic vpd,
* which is the size of the DYNAMIC_CONFIG partition.
*/
if ((rc = efx_mcdi_nvram_info(enp, NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG,
sizep, NULL, NULL)) != 0)
goto fail1;
return (0);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
__checkReturn int
hunt_vpd_read(
__in efx_nic_t *enp,
__out_bcount(size) caddr_t data,
__in size_t size)
{
caddr_t dvpd;
size_t dvpd_size;
uint32_t pci_pf;
int rc;
EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON);
pci_pf = enp->en_nic_cfg.enc_pf;
if ((rc = hunt_nvram_partn_read_tlv(enp,
NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG,
TLV_TAG_PF_DYNAMIC_VPD(pci_pf),
&dvpd, &dvpd_size)) != 0)
goto fail1;
if (dvpd_size > size) {
rc = ENOSPC;
goto fail2;
}
memcpy(data, dvpd, dvpd_size);
/* Pad data with all-1s, consistent with update operations */
memset(data + dvpd_size, 0xff, size - dvpd_size);
EFSYS_KMEM_FREE(enp->en_esip, dvpd_size, dvpd);
return (0);
fail2:
EFSYS_PROBE(fail2);
EFSYS_KMEM_FREE(enp->en_esip, dvpd_size, dvpd);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
__checkReturn int
hunt_vpd_verify(
__in efx_nic_t *enp,
__in_bcount(size) caddr_t data,
__in size_t size)
{
efx_vpd_tag_t stag;
efx_vpd_tag_t dtag;
efx_vpd_keyword_t skey;
efx_vpd_keyword_t dkey;
unsigned int scont;
unsigned int dcont;
int rc;
EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON);
/*
* Strictly you could take the view that dynamic vpd is optional.
* Instead, to conform more closely to the read/verify/reinit()
* paradigm, we require dynamic vpd. hunt_vpd_reinit() will
* reinitialize it as required.
*/
if ((rc = efx_vpd_hunk_verify(data, size, NULL)) != 0)
goto fail1;
/*
* Verify that there is no duplication between the static and
* dynamic cfg sectors.
*/
if (enp->en_u.hunt.enu_svpd_length == 0)
goto done;
dcont = 0;
_NOTE(CONSTANTCONDITION)
while (1) {
if ((rc = efx_vpd_hunk_next(data, size, &dtag,
&dkey, NULL, NULL, &dcont)) != 0)
goto fail2;
if (dcont == 0)
break;
scont = 0;
_NOTE(CONSTANTCONDITION)
while (1) {
if ((rc = efx_vpd_hunk_next(
enp->en_u.hunt.enu_svpd,
enp->en_u.hunt.enu_svpd_length, &stag, &skey,
NULL, NULL, &scont)) != 0)
goto fail3;
if (scont == 0)
break;
if (stag == dtag && skey == dkey) {
rc = EEXIST;
goto fail4;
}
}
}
done:
return (0);
fail4:
EFSYS_PROBE(fail4);
fail3:
EFSYS_PROBE(fail3);
fail2:
EFSYS_PROBE(fail2);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
__checkReturn int
hunt_vpd_reinit(
__in efx_nic_t *enp,
__in_bcount(size) caddr_t data,
__in size_t size)
{
boolean_t wantpid;
int rc;
/*
* Only create an ID string if the dynamic cfg doesn't have one
*/
if (enp->en_u.hunt.enu_svpd_length == 0)
wantpid = B_TRUE;
else {
unsigned int offset;
uint8_t length;
rc = efx_vpd_hunk_get(enp->en_u.hunt.enu_svpd,
enp->en_u.hunt.enu_svpd_length,
EFX_VPD_ID, 0, &offset, &length);
if (rc == 0)
wantpid = B_FALSE;
else if (rc == ENOENT)
wantpid = B_TRUE;
else
goto fail1;
}
if ((rc = efx_vpd_hunk_reinit(data, size, wantpid)) != 0)
goto fail2;
return (0);
fail2:
EFSYS_PROBE(fail2);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
__checkReturn int
hunt_vpd_get(
__in efx_nic_t *enp,
__in_bcount(size) caddr_t data,
__in size_t size,
__inout efx_vpd_value_t *evvp)
{
unsigned int offset;
uint8_t length;
int rc;
EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON);
/* Attempt to satisfy the request from svpd first */
if (enp->en_u.hunt.enu_svpd_length > 0) {
if ((rc = efx_vpd_hunk_get(enp->en_u.hunt.enu_svpd,
enp->en_u.hunt.enu_svpd_length, evvp->evv_tag,
evvp->evv_keyword, &offset, &length)) == 0) {
evvp->evv_length = length;
memcpy(evvp->evv_value,
enp->en_u.hunt.enu_svpd + offset, length);
return (0);
} else if (rc != ENOENT)
goto fail1;
}
/* And then from the provided data buffer */
if ((rc = efx_vpd_hunk_get(data, size, evvp->evv_tag,
evvp->evv_keyword, &offset, &length)) != 0)
goto fail2;
evvp->evv_length = length;
memcpy(evvp->evv_value, data + offset, length);
return (0);
fail2:
EFSYS_PROBE(fail2);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
__checkReturn int
hunt_vpd_set(
__in efx_nic_t *enp,
__in_bcount(size) caddr_t data,
__in size_t size,
__in efx_vpd_value_t *evvp)
{
int rc;
EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON);
/* If the provided (tag,keyword) exists in svpd, then it is readonly */
if (enp->en_u.hunt.enu_svpd_length > 0) {
unsigned int offset;
uint8_t length;
if ((rc = efx_vpd_hunk_get(enp->en_u.hunt.enu_svpd,
enp->en_u.hunt.enu_svpd_length, evvp->evv_tag,
evvp->evv_keyword, &offset, &length)) == 0) {
rc = EACCES;
goto fail1;
}
}
if ((rc = efx_vpd_hunk_set(data, size, evvp)) != 0)
goto fail2;
return (0);
fail2:
EFSYS_PROBE(fail2);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
__checkReturn int
hunt_vpd_next(
__in efx_nic_t *enp,
__in_bcount(size) caddr_t data,
__in size_t size,
__out efx_vpd_value_t *evvp,
__inout unsigned int *contp)
{
_NOTE(ARGUNUSED(enp, data, size, evvp, contp))
return (ENOTSUP);
}
__checkReturn int
hunt_vpd_write(
__in efx_nic_t *enp,
__in_bcount(size) caddr_t data,
__in size_t size)
{
size_t vpd_length;
uint32_t pci_pf;
int rc;
EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON);
pci_pf = enp->en_nic_cfg.enc_pf;
/* Determine total length of new dynamic VPD */
if ((rc = efx_vpd_hunk_length(data, size, &vpd_length)) != 0)
goto fail1;
/* Store new dynamic VPD in DYNAMIC_CONFIG partition */
if ((rc = hunt_nvram_partn_write_tlv(enp,
NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG,
TLV_TAG_PF_DYNAMIC_VPD(pci_pf),
data, vpd_length)) != 0) {
goto fail2;
}
return (0);
fail2:
EFSYS_PROBE(fail2);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
void
hunt_vpd_fini(
__in efx_nic_t *enp)
{
EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON);
if (enp->en_u.hunt.enu_svpd_length > 0) {
EFSYS_KMEM_FREE(enp->en_esip, enp->en_u.hunt.enu_svpd_length,
enp->en_u.hunt.enu_svpd);
enp->en_u.hunt.enu_svpd = NULL;
enp->en_u.hunt.enu_svpd_length = 0;
}
}
#endif /* EFSYS_OPT_HUNTINGTON */
#endif /* EFSYS_OPT_VPD */

View File

@ -0,0 +1,552 @@
/*-
* Copyright (c) 2009-2015 Solarflare Communications Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the FreeBSD Project.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "efsys.h"
#include "efx.h"
#include "efx_impl.h"
#if EFSYS_OPT_MON_MCDI
#if EFSYS_OPT_MON_STATS
#define MCDI_MON_NEXT_PAGE (uint16_t)0xfffe
#define MCDI_MON_INVALID_SENSOR (uint16_t)0xfffd
#define MCDI_MON_PAGE_SIZE 0x20
/* Bitmasks of valid port(s) for each sensor */
#define MCDI_MON_PORT_NONE (0x00)
#define MCDI_MON_PORT_P1 (0x01)
#define MCDI_MON_PORT_P2 (0x02)
#define MCDI_MON_PORT_P3 (0x04)
#define MCDI_MON_PORT_P4 (0x08)
#define MCDI_MON_PORT_Px (0xFFFF)
/* Entry for MCDI sensor in sensor map */
#define STAT(portmask, stat) \
{ (MCDI_MON_PORT_##portmask), (EFX_MON_STAT_##stat) }
/* Entry for sensor next page flag in sensor map */
#define STAT_NEXT_PAGE() \
{ MCDI_MON_PORT_NONE, MCDI_MON_NEXT_PAGE }
/* Placeholder for gaps in the array */
#define STAT_NO_SENSOR() \
{ MCDI_MON_PORT_NONE, MCDI_MON_INVALID_SENSOR }
/* Map from MC sensors to monitor statistics */
static const struct mcdi_sensor_map_s {
uint16_t msm_port_mask;
uint16_t msm_stat;
} mcdi_sensor_map[] = {
/* Sensor page 0 MC_CMD_SENSOR_xxx */
STAT(Px, INT_TEMP), /* 0x00 CONTROLLER_TEMP */
STAT(Px, EXT_TEMP), /* 0x01 PHY_COMMON_TEMP */
STAT(Px, INT_COOLING), /* 0x02 CONTROLLER_COOLING */
STAT(P1, EXT_TEMP), /* 0x03 PHY0_TEMP */
STAT(P1, EXT_COOLING), /* 0x04 PHY0_COOLING */
STAT(P2, EXT_TEMP), /* 0x05 PHY1_TEMP */
STAT(P2, EXT_COOLING), /* 0x06 PHY1_COOLING */
STAT(Px, 1V), /* 0x07 IN_1V0 */
STAT(Px, 1_2V), /* 0x08 IN_1V2 */
STAT(Px, 1_8V), /* 0x09 IN_1V8 */
STAT(Px, 2_5V), /* 0x0a IN_2V5 */
STAT(Px, 3_3V), /* 0x0b IN_3V3 */
STAT(Px, 12V), /* 0x0c IN_12V0 */
STAT(Px, 1_2VA), /* 0x0d IN_1V2A */
STAT(Px, VREF), /* 0x0e IN_VREF */
STAT(Px, VAOE), /* 0x0f OUT_VAOE */
STAT(Px, AOE_TEMP), /* 0x10 AOE_TEMP */
STAT(Px, PSU_AOE_TEMP), /* 0x11 PSU_AOE_TEMP */
STAT(Px, PSU_TEMP), /* 0x12 PSU_TEMP */
STAT(Px, FAN0), /* 0x13 FAN_0 */
STAT(Px, FAN1), /* 0x14 FAN_1 */
STAT(Px, FAN2), /* 0x15 FAN_2 */
STAT(Px, FAN3), /* 0x16 FAN_3 */
STAT(Px, FAN4), /* 0x17 FAN_4 */
STAT(Px, VAOE_IN), /* 0x18 IN_VAOE */
STAT(Px, IAOE), /* 0x19 OUT_IAOE */
STAT(Px, IAOE_IN), /* 0x1a IN_IAOE */
STAT(Px, NIC_POWER), /* 0x1b NIC_POWER */
STAT(Px, 0_9V), /* 0x1c IN_0V9 */
STAT(Px, I0_9V), /* 0x1d IN_I0V9 */
STAT(Px, I1_2V), /* 0x1e IN_I1V2 */
STAT_NEXT_PAGE(), /* 0x1f Next page flag (not a sensor) */
/* Sensor page 1 MC_CMD_SENSOR_xxx */
STAT(Px, 0_9V_ADC), /* 0x20 IN_0V9_ADC */
STAT(Px, INT_TEMP2), /* 0x21 CONTROLLER_2_TEMP */
STAT(Px, VREG_TEMP), /* 0x22 VREG_INTERNAL_TEMP */
STAT(Px, VREG_0_9V_TEMP), /* 0x23 VREG_0V9_TEMP */
STAT(Px, VREG_1_2V_TEMP), /* 0x24 VREG_1V2_TEMP */
STAT(Px, INT_VPTAT), /* 0x25 CTRLR. VPTAT */
STAT(Px, INT_ADC_TEMP), /* 0x26 CTRLR. INTERNAL_TEMP */
STAT(Px, EXT_VPTAT), /* 0x27 CTRLR. VPTAT_EXTADC */
STAT(Px, EXT_ADC_TEMP), /* 0x28 CTRLR. INTERNAL_TEMP_EXTADC */
STAT(Px, AMBIENT_TEMP), /* 0x29 AMBIENT_TEMP */
STAT(Px, AIRFLOW), /* 0x2a AIRFLOW */
STAT(Px, VDD08D_VSS08D_CSR), /* 0x2b VDD08D_VSS08D_CSR */
STAT(Px, VDD08D_VSS08D_CSR_EXTADC), /* 0x2c VDD08D_VSS08D_CSR_EXTADC */
STAT(Px, HOTPOINT_TEMP), /* 0x2d HOTPOINT_TEMP */
STAT(P1, PHY_POWER_SWITCH_PORT0), /* 0x2e PHY_POWER_SWITCH_PORT0 */
STAT(P2, PHY_POWER_SWITCH_PORT1), /* 0x2f PHY_POWER_SWITCH_PORT1 */
STAT(Px, MUM_VCC), /* 0x30 MUM_VCC */
STAT(Px, 0V9_A), /* 0x31 0V9_A */
STAT(Px, I0V9_A), /* 0x32 I0V9_A */
STAT(Px, 0V9_A_TEMP), /* 0x33 0V9_A_TEMP */
STAT(Px, 0V9_B), /* 0x34 0V9_B */
STAT(Px, I0V9_B), /* 0x35 I0V9_B */
STAT(Px, 0V9_B_TEMP), /* 0x36 0V9_B_TEMP */
STAT(Px, CCOM_AVREG_1V2_SUPPLY), /* 0x37 CCOM_AVREG_1V2_SUPPLY */
STAT(Px, CCOM_AVREG_1V2_SUPPLY_EXT_ADC),
/* 0x38 CCOM_AVREG_1V2_SUPPLY_EXT_ADC */
STAT(Px, CCOM_AVREG_1V8_SUPPLY), /* 0x39 CCOM_AVREG_1V8_SUPPLY */
STAT(Px, CCOM_AVREG_1V8_SUPPLY_EXT_ADC),
/* 0x3a CCOM_AVREG_1V8_SUPPLY_EXT_ADC */
STAT_NO_SENSOR(), /* 0x3b (no sensor) */
STAT_NO_SENSOR(), /* 0x3c (no sensor) */
STAT_NO_SENSOR(), /* 0x3d (no sensor) */
STAT_NO_SENSOR(), /* 0x3e (no sensor) */
STAT_NEXT_PAGE(), /* 0x3f Next page flag (not a sensor) */
/* Sensor page 2 MC_CMD_SENSOR_xxx */
STAT(Px, CONTROLLER_MASTER_VPTAT), /* 0x40 MASTER_VPTAT */
STAT(Px, CONTROLLER_MASTER_INTERNAL_TEMP), /* 0x41 MASTER_INT_TEMP */
STAT(Px, CONTROLLER_MASTER_VPTAT_EXT_ADC), /* 0x42 MAST_VPTAT_EXT_ADC */
STAT(Px, CONTROLLER_MASTER_INTERNAL_TEMP_EXT_ADC),
/* 0x43 MASTER_INTERNAL_TEMP_EXT_ADC */
STAT(Px, CONTROLLER_SLAVE_VPTAT), /* 0x44 SLAVE_VPTAT */
STAT(Px, CONTROLLER_SLAVE_INTERNAL_TEMP), /* 0x45 SLAVE_INTERNAL_TEMP */
STAT(Px, CONTROLLER_SLAVE_VPTAT_EXT_ADC), /* 0x46 SLAVE_VPTAT_EXT_ADC */
STAT(Px, CONTROLLER_SLAVE_INTERNAL_TEMP_EXT_ADC),
/* 0x47 SLAVE_INTERNAL_TEMP_EXT_ADC */
};
#define MCDI_STATIC_SENSOR_ASSERT(_field) \
EFX_STATIC_ASSERT(MC_CMD_SENSOR_STATE_ ## _field \
== EFX_MON_STAT_STATE_ ## _field)
static void
mcdi_mon_decode_stats(
__in efx_nic_t *enp,
__in_ecount(sensor_mask_size) uint32_t *sensor_mask,
__in size_t sensor_mask_size,
__in_opt efsys_mem_t *esmp,
__out_ecount_opt(sensor_mask_size) uint32_t *stat_maskp,
__out_ecount_opt(EFX_MON_NSTATS) efx_mon_stat_value_t *stat)
{
efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
uint16_t port_mask;
uint16_t sensor;
size_t sensor_max;
uint32_t stat_mask[(EFX_ARRAY_SIZE(mcdi_sensor_map) + 31) / 32];
uint32_t idx = 0;
uint32_t page = 0;
/* Assert the MC_CMD_SENSOR and EFX_MON_STATE namespaces agree */
MCDI_STATIC_SENSOR_ASSERT(OK);
MCDI_STATIC_SENSOR_ASSERT(WARNING);
MCDI_STATIC_SENSOR_ASSERT(FATAL);
MCDI_STATIC_SENSOR_ASSERT(BROKEN);
MCDI_STATIC_SENSOR_ASSERT(NO_READING);
EFX_STATIC_ASSERT(sizeof (stat_mask[0]) * 8 ==
EFX_MON_MASK_ELEMENT_SIZE);
sensor_max =
MIN((8 * sensor_mask_size), EFX_ARRAY_SIZE(mcdi_sensor_map));
port_mask = 1U << emip->emi_port;
memset(stat_mask, 0, sizeof (stat_mask));
/*
* The MCDI sensor readings in the DMA buffer are a packed array of
* MC_CMD_SENSOR_VALUE_ENTRY structures, which only includes entries for
* supported sensors (bit set in sensor_mask). The sensor_mask and
* sensor readings do not include entries for the per-page NEXT_PAGE
* flag.
*
* sensor_mask may legitimately contain MCDI sensors that the driver
* does not understand.
*/
for (sensor = 0; sensor < sensor_max; ++sensor) {
efx_mon_stat_t id = mcdi_sensor_map[sensor].msm_stat;
if ((sensor % MCDI_MON_PAGE_SIZE) == MC_CMD_SENSOR_PAGE0_NEXT) {
EFSYS_ASSERT3U(id, ==, MCDI_MON_NEXT_PAGE);
page++;
continue;
}
if (~(sensor_mask[page]) & (1U << sensor))
continue;
idx++;
if ((port_mask & mcdi_sensor_map[sensor].msm_port_mask) == 0)
continue;
EFSYS_ASSERT(id < EFX_MON_NSTATS);
/*
* stat_mask is a bitmask indexed by EFX_MON_* monitor statistic
* identifiers from efx_mon_stat_t (without NEXT_PAGE bits).
*
* If there is an entry in the MCDI sensor to monitor statistic
* map then the sensor reading is used for the value of the
* monitor statistic.
*/
stat_mask[id / EFX_MON_MASK_ELEMENT_SIZE] |=
(1U << (id % EFX_MON_MASK_ELEMENT_SIZE));
if (stat != NULL && esmp != NULL && !EFSYS_MEM_IS_NULL(esmp)) {
efx_dword_t dword;
/* Get MCDI sensor reading from DMA buffer */
EFSYS_MEM_READD(esmp, 4 * (idx - 1), &dword);
/* Update EFX monitor stat from MCDI sensor reading */
stat[id].emsv_value = (uint16_t)EFX_DWORD_FIELD(dword,
MC_CMD_SENSOR_VALUE_ENTRY_TYPEDEF_VALUE);
stat[id].emsv_state = (uint16_t)EFX_DWORD_FIELD(dword,
MC_CMD_SENSOR_VALUE_ENTRY_TYPEDEF_STATE);
}
}
if (stat_maskp != NULL) {
memcpy(stat_maskp, stat_mask, sizeof (stat_mask));
}
}
__checkReturn int
mcdi_mon_ev(
__in efx_nic_t *enp,
__in efx_qword_t *eqp,
__out efx_mon_stat_t *idp,
__out efx_mon_stat_value_t *valuep)
{
efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
uint16_t port_mask;
uint16_t sensor;
uint16_t state;
uint16_t value;
efx_mon_stat_t id;
int rc;
port_mask = (emip->emi_port == 1)
? MCDI_MON_PORT_P1
: MCDI_MON_PORT_P2;
sensor = (uint16_t)MCDI_EV_FIELD(eqp, SENSOREVT_MONITOR);
state = (uint16_t)MCDI_EV_FIELD(eqp, SENSOREVT_STATE);
value = (uint16_t)MCDI_EV_FIELD(eqp, SENSOREVT_VALUE);
/* Hardware must support this MCDI sensor */
EFSYS_ASSERT3U(sensor, <, (8 * encp->enc_mcdi_sensor_mask_size));
EFSYS_ASSERT((sensor % MCDI_MON_PAGE_SIZE) != MC_CMD_SENSOR_PAGE0_NEXT);
EFSYS_ASSERT(encp->enc_mcdi_sensor_maskp != NULL);
EFSYS_ASSERT((encp->enc_mcdi_sensor_maskp[sensor / MCDI_MON_PAGE_SIZE] &
(1U << (sensor % MCDI_MON_PAGE_SIZE))) != 0);
/* But we don't have to understand it */
if (sensor >= EFX_ARRAY_SIZE(mcdi_sensor_map)) {
rc = ENOTSUP;
goto fail1;
}
id = mcdi_sensor_map[sensor].msm_stat;
if ((port_mask & mcdi_sensor_map[sensor].msm_port_mask) == 0)
return (ENODEV);
EFSYS_ASSERT(id < EFX_MON_NSTATS);
*idp = id;
valuep->emsv_value = value;
valuep->emsv_state = state;
return (0);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
static __checkReturn int
efx_mcdi_read_sensors(
__in efx_nic_t *enp,
__in efsys_mem_t *esmp,
__in uint32_t size)
{
efx_mcdi_req_t req;
uint8_t payload[MAX(MC_CMD_READ_SENSORS_EXT_IN_LEN,
MC_CMD_READ_SENSORS_EXT_OUT_LEN)];
uint32_t addr_lo, addr_hi;
req.emr_cmd = MC_CMD_READ_SENSORS;
req.emr_in_buf = payload;
req.emr_in_length = MC_CMD_READ_SENSORS_EXT_IN_LEN;
req.emr_out_buf = payload;
req.emr_out_length = MC_CMD_READ_SENSORS_EXT_OUT_LEN;
addr_lo = (uint32_t)(EFSYS_MEM_ADDR(esmp) & 0xffffffff);
addr_hi = (uint32_t)(EFSYS_MEM_ADDR(esmp) >> 32);
MCDI_IN_SET_DWORD(req, READ_SENSORS_EXT_IN_DMA_ADDR_LO, addr_lo);
MCDI_IN_SET_DWORD(req, READ_SENSORS_EXT_IN_DMA_ADDR_HI, addr_hi);
MCDI_IN_SET_DWORD(req, READ_SENSORS_EXT_IN_LENGTH, size);
efx_mcdi_execute(enp, &req);
return (req.emr_rc);
}
static __checkReturn int
efx_mcdi_sensor_info_npages(
__in efx_nic_t *enp,
__out uint32_t *npagesp)
{
efx_mcdi_req_t req;
uint8_t payload[MAX(MC_CMD_SENSOR_INFO_EXT_IN_LEN,
MC_CMD_SENSOR_INFO_OUT_LENMAX)];
int page;
int rc;
EFSYS_ASSERT(npagesp != NULL);
page = 0;
do {
(void) memset(payload, 0, sizeof (payload));
req.emr_cmd = MC_CMD_SENSOR_INFO;
req.emr_in_buf = payload;
req.emr_in_length = MC_CMD_SENSOR_INFO_EXT_IN_LEN;
req.emr_out_buf = payload;
req.emr_out_length = MC_CMD_SENSOR_INFO_OUT_LENMAX;
MCDI_IN_SET_DWORD(req, SENSOR_INFO_EXT_IN_PAGE, page++);
efx_mcdi_execute_quiet(enp, &req);
if (req.emr_rc != 0) {
rc = req.emr_rc;
goto fail1;
}
} while (MCDI_OUT_DWORD(req, SENSOR_INFO_OUT_MASK) &
(1 << MC_CMD_SENSOR_PAGE0_NEXT));
*npagesp = page;
return (0);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
static __checkReturn int
efx_mcdi_sensor_info(
__in efx_nic_t *enp,
__out_ecount(npages) uint32_t *sensor_maskp,
__in size_t npages)
{
efx_mcdi_req_t req;
uint8_t payload[MAX(MC_CMD_SENSOR_INFO_EXT_IN_LEN,
MC_CMD_SENSOR_INFO_OUT_LENMAX)];
uint32_t page;
int rc;
EFSYS_ASSERT(sensor_maskp != NULL);
for (page = 0; page < npages; page++) {
uint32_t mask;
(void) memset(payload, 0, sizeof (payload));
req.emr_cmd = MC_CMD_SENSOR_INFO;
req.emr_in_buf = payload;
req.emr_in_length = MC_CMD_SENSOR_INFO_EXT_IN_LEN;
req.emr_out_buf = payload;
req.emr_out_length = MC_CMD_SENSOR_INFO_OUT_LENMAX;
MCDI_IN_SET_DWORD(req, SENSOR_INFO_EXT_IN_PAGE, page);
efx_mcdi_execute(enp, &req);
if (req.emr_rc != 0) {
rc = req.emr_rc;
goto fail1;
}
mask = MCDI_OUT_DWORD(req, SENSOR_INFO_OUT_MASK);
if ((page != (npages - 1)) &&
((mask & (1U << MC_CMD_SENSOR_PAGE0_NEXT)) == 0)) {
rc = EINVAL;
goto fail2;
}
sensor_maskp[page] = mask;
}
if (sensor_maskp[npages - 1] & (1U << MC_CMD_SENSOR_PAGE0_NEXT)) {
rc = EINVAL;
goto fail3;
}
return (0);
fail3:
EFSYS_PROBE(fail3);
fail2:
EFSYS_PROBE(fail2);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
__checkReturn int
mcdi_mon_stats_update(
__in efx_nic_t *enp,
__in efsys_mem_t *esmp,
__out_ecount(EFX_MON_NSTATS) efx_mon_stat_value_t *values)
{
efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
uint32_t size = encp->enc_mon_stat_dma_buf_size;
int rc;
if ((rc = efx_mcdi_read_sensors(enp, esmp, size)) != 0)
goto fail1;
EFSYS_DMA_SYNC_FOR_KERNEL(esmp, 0, size);
mcdi_mon_decode_stats(enp,
encp->enc_mcdi_sensor_maskp,
encp->enc_mcdi_sensor_mask_size,
esmp, NULL, values);
return (0);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
__checkReturn int
mcdi_mon_cfg_build(
__in efx_nic_t *enp)
{
efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
uint32_t npages;
int rc;
switch (enp->en_family) {
#if EFSYS_OPT_SIENA
case EFX_FAMILY_SIENA:
encp->enc_mon_type = EFX_MON_SFC90X0;
break;
#endif
#if EFSYS_OPT_HUNTINGTON
case EFX_FAMILY_HUNTINGTON:
encp->enc_mon_type = EFX_MON_SFC91X0;
break;
#endif
default:
rc = EINVAL;
goto fail1;
}
/* Get mc sensor mask size */
npages = 0;
if ((rc = efx_mcdi_sensor_info_npages(enp, &npages)) != 0)
goto fail2;
encp->enc_mon_stat_dma_buf_size = npages * EFX_MON_STATS_PAGE_SIZE;
encp->enc_mcdi_sensor_mask_size = npages * sizeof (uint32_t);
/* Allocate mc sensor mask */
EFSYS_KMEM_ALLOC(enp->en_esip,
encp->enc_mcdi_sensor_mask_size,
encp->enc_mcdi_sensor_maskp);
if (encp->enc_mcdi_sensor_maskp == NULL) {
rc = ENOMEM;
goto fail3;
}
/* Read mc sensor mask */
if ((rc = efx_mcdi_sensor_info(enp,
encp->enc_mcdi_sensor_maskp,
npages)) != 0)
goto fail4;
/* Build monitor statistics mask */
mcdi_mon_decode_stats(enp,
encp->enc_mcdi_sensor_maskp,
encp->enc_mcdi_sensor_mask_size,
NULL, encp->enc_mon_stat_mask, NULL);
return (0);
fail4:
EFSYS_PROBE(fail4);
EFSYS_KMEM_FREE(enp->en_esip,
encp->enc_mcdi_sensor_mask_size,
encp->enc_mcdi_sensor_maskp);
fail3:
EFSYS_PROBE(fail3);
fail2:
EFSYS_PROBE(fail2);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
void
mcdi_mon_cfg_free(
__in efx_nic_t *enp)
{
efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
if (encp->enc_mcdi_sensor_maskp != NULL) {
EFSYS_KMEM_FREE(enp->en_esip,
encp->enc_mcdi_sensor_mask_size,
encp->enc_mcdi_sensor_maskp);
}
}
#endif /* EFSYS_OPT_MON_STATS */
#endif /* EFSYS_OPT_MON_MCDI */

View File

@ -0,0 +1,76 @@
/*-
* Copyright (c) 2009-2015 Solarflare Communications Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the FreeBSD Project.
*
* $FreeBSD$
*/
#ifndef _SYS_MCDI_MON_H
#define _SYS_MCDI_MON_H
#include "efx.h"
#ifdef __cplusplus
extern "C" {
#endif
#if EFSYS_OPT_MON_MCDI
#if EFSYS_OPT_MON_STATS
__checkReturn int
mcdi_mon_cfg_build(
__in efx_nic_t *enp);
void
mcdi_mon_cfg_free(
__in efx_nic_t *enp);
extern __checkReturn int
mcdi_mon_ev(
__in efx_nic_t *enp,
__in efx_qword_t *eqp,
__out efx_mon_stat_t *idp,
__out efx_mon_stat_value_t *valuep);
extern __checkReturn int
mcdi_mon_stats_update(
__in efx_nic_t *enp,
__in efsys_mem_t *esmp,
__out_ecount(EFX_MON_NSTATS) efx_mon_stat_value_t *values);
#endif /* EFSYS_OPT_MON_STATS */
#endif /* EFSYS_OPT_MON_MCDI */
#ifdef __cplusplus
}
#endif
#endif /* _SYS_MCDI_MON_H */

View File

@ -1,26 +1,31 @@
/*-
* Copyright 2007-2009 Solarflare Communications Inc. All rights reserved.
* Copyright (c) 2007-2015 Solarflare Communications Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* modification, are permitted provided that the following conditions are met:
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the FreeBSD Project.
*
* $FreeBSD$
*/
@ -48,6 +53,45 @@
#define SIENA_MC_BOOT_MAGIC (0x51E4A001)
#define SIENA_MC_BOOT_VERSION (1)
/*Structures supporting an arbitrary number of binary blobs in the flash image
intended to house code and tables for the satellite cpus*/
/*thanks to random.org for:*/
#define BLOBS_HEADER_MAGIC (0xBDA3BBD4)
#define BLOB_HEADER_MAGIC (0xA1478A91)
typedef struct blobs_hdr_s { /* GENERATED BY scripts/genfwdef */
efx_dword_t magic;
efx_dword_t no_of_blobs;
} blobs_hdr_t;
typedef struct blob_hdr_s { /* GENERATED BY scripts/genfwdef */
efx_dword_t magic;
efx_dword_t cpu_type;
efx_dword_t build_variant;
efx_dword_t offset;
efx_dword_t length;
efx_dword_t checksum;
} blob_hdr_t;
#define BLOB_CPU_TYPE_TXDI_TEXT (0)
#define BLOB_CPU_TYPE_RXDI_TEXT (1)
#define BLOB_CPU_TYPE_TXDP_TEXT (2)
#define BLOB_CPU_TYPE_RXDP_TEXT (3)
#define BLOB_CPU_TYPE_RXHRSL_HR_LUT (4)
#define BLOB_CPU_TYPE_RXHRSL_HR_LUT_CFG (5)
#define BLOB_CPU_TYPE_TXHRSL_HR_LUT (6)
#define BLOB_CPU_TYPE_TXHRSL_HR_LUT_CFG (7)
#define BLOB_CPU_TYPE_RXHRSL_HR_PGM (8)
#define BLOB_CPU_TYPE_RXHRSL_SL_PGM (9)
#define BLOB_CPU_TYPE_TXHRSL_HR_PGM (10)
#define BLOB_CPU_TYPE_TXHRSL_SL_PGM (11)
#define BLOB_CPU_TYPE_RXDI_VTBL0 (12)
#define BLOB_CPU_TYPE_TXDI_VTBL0 (13)
#define BLOB_CPU_TYPE_RXDI_VTBL1 (14)
#define BLOB_CPU_TYPE_TXDI_VTBL1 (15)
#define BLOB_CPU_TYPE_DUMPSPEC (32)
typedef struct siena_mc_boot_hdr_s { /* GENERATED BY scripts/genfwdef */
efx_dword_t magic; /* = SIENA_MC_BOOT_MAGIC */
efx_word_t hdr_version; /* this structure definition is version 1 */
@ -57,14 +101,21 @@ typedef struct siena_mc_boot_hdr_s { /* GENERATED BY scripts/genfwdef */
efx_byte_t firmware_version_c;
efx_word_t checksum; /* of whole header area + firmware image */
efx_word_t firmware_version_d;
efx_word_t reserved_a[1]; /* (set to 0) */
efx_byte_t mcfw_subtype;
efx_byte_t reserved_a[1]; /* (set to 0) */
efx_dword_t firmware_text_offset; /* offset to firmware .text */
efx_dword_t firmware_text_size; /* length of firmware .text, in bytes */
efx_dword_t firmware_data_offset; /* offset to firmware .data */
efx_dword_t firmware_data_size; /* length of firmware .data, in bytes */
efx_dword_t reserved_b[8]; /* (set to 0) */
efx_byte_t spi_rate; /* SPI rate for reading image, 0 is BootROM default */
efx_byte_t spi_phase_adj; /* SPI SDO/SCL phase adjustment, 0 is default (no adj) */
efx_word_t reserved_b[1]; /* (set to 0) */
efx_dword_t reserved_c[7]; /* (set to 0) */
} siena_mc_boot_hdr_t;
#define SIENA_MC_BOOT_HDR_PADDING \
(SIENA_MC_BOOT_HDR_LEN - sizeof(siena_mc_boot_hdr_t))
#define SIENA_MC_STATIC_CONFIG_MAGIC (0xBDCF5555)
#define SIENA_MC_STATIC_CONFIG_VERSION (0)
@ -81,8 +132,8 @@ typedef struct siena_mc_static_config_hdr_s { /* GENERATED BY scripts/genfwdef *
efx_byte_t green_mode_valid; /* Whether cal holds a valid value */
efx_word_t mac_addr_count;
efx_word_t mac_addr_stride;
efx_word_t calibrated_vref;
efx_word_t adc_vref;
efx_word_t calibrated_vref; /* Vref as measured during production */
efx_word_t adc_vref; /* Vref as read by ADC */
efx_dword_t reserved2[1]; /* (write as zero) */
efx_dword_t num_dbi_items;
struct {
@ -117,17 +168,32 @@ typedef struct siena_mc_dynamic_config_hdr_s { /* GENERATED BY scripts/genfwdef
#define SIENA_MC_EXPROM_SINGLE_MAGIC (0xAA55) /* little-endian uint16_t */
#define SIENA_MC_EXPROM_COMBO_MAGIC (0xB0070102) /* little-endian uint32_t */
#define SIENA_MC_EXPROM_COMBO_V2_MAGIC (0xB0070103) /* little-endian uint32_t */
typedef struct siena_mc_combo_rom_hdr_s { /* GENERATED BY scripts/genfwdef */
efx_dword_t magic; /* = SIENA_MC_EXPROM_COMBO_MAGIC */
efx_dword_t len1; /* length of first image */
efx_dword_t len2; /* length of second image */
efx_dword_t off1; /* offset of first byte to edit to combine images */
efx_dword_t off2; /* offset of second byte to edit to combine images */
efx_word_t infoblk0_off; /* infoblk offset */
efx_word_t infoblk1_off; /* infoblk offset */
efx_byte_t infoblk_len; /* length of space reserved for infoblk structures */
efx_byte_t reserved[7]; /* (set to 0) */
efx_dword_t magic; /* = SIENA_MC_EXPROM_COMBO_MAGIC or SIENA_MC_EXPROM_COMBO_V2_MAGIC */
union {
struct {
efx_dword_t len1; /* length of first image */
efx_dword_t len2; /* length of second image */
efx_dword_t off1; /* offset of first byte to edit to combine images */
efx_dword_t off2; /* offset of second byte to edit to combine images */
efx_word_t infoblk0_off;/* infoblk offset */
efx_word_t infoblk1_off;/* infoblk offset */
efx_byte_t infoblk_len;/* length of space reserved for one infoblk structure */
efx_byte_t reserved[7];/* (set to 0) */
} v1;
struct {
efx_dword_t len1; /* length of first image */
efx_dword_t len2; /* length of second image */
efx_dword_t off1; /* offset of first byte to edit to combine images */
efx_dword_t off2; /* offset of second byte to edit to combine images */
efx_word_t infoblk_off;/* infoblk start offset */
efx_word_t infoblk_count;/* infoblk count */
efx_byte_t infoblk_len;/* length of space reserved for one infoblk structure */
efx_byte_t reserved[7];/* (set to 0) */
} v2;
};
} siena_mc_combo_rom_hdr_t;
#pragma pack()

View File

@ -1,26 +1,31 @@
/*-
* Copyright 2009 Solarflare Communications Inc. All rights reserved.
* Copyright (c) 2009-2015 Solarflare Communications Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* modification, are permitted provided that the following conditions are met:
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the FreeBSD Project.
*
* $FreeBSD$
*/
@ -101,6 +106,49 @@ siena_sram_test(
#endif /* EFSYS_OPT_DIAG */
#if EFSYS_OPT_MCDI
extern __checkReturn int
siena_mcdi_init(
__in efx_nic_t *enp,
__in const efx_mcdi_transport_t *mtp);
extern void
siena_mcdi_request_copyin(
__in efx_nic_t *enp,
__in efx_mcdi_req_t *emrp,
__in unsigned int seq,
__in boolean_t ev_cpl,
__in boolean_t new_epoch);
extern __checkReturn boolean_t
siena_mcdi_request_poll(
__in efx_nic_t *enp);
extern void
siena_mcdi_request_copyout(
__in efx_nic_t *enp,
__in efx_mcdi_req_t *emrp);
extern int
siena_mcdi_poll_reboot(
__in efx_nic_t *enp);
extern void
siena_mcdi_fini(
__in efx_nic_t *enp);
extern __checkReturn int
siena_mcdi_fw_update_supported(
__in efx_nic_t *enp,
__out boolean_t *supportedp);
extern __checkReturn int
siena_mcdi_macaddr_change_supported(
__in efx_nic_t *enp,
__out boolean_t *supportedp);
#endif /* EFSYS_OPT_MCDI */
#if EFSYS_OPT_NVRAM || EFSYS_OPT_VPD
@ -169,6 +217,12 @@ siena_nvram_size(
__in efx_nvram_type_t type,
__out size_t *sizep);
extern __checkReturn int
siena_nvram_get_subtype(
__in efx_nic_t *enp,
__in unsigned int partn,
__out uint32_t *subtypep);
extern __checkReturn int
siena_nvram_get_version(
__in efx_nic_t *enp,
@ -212,7 +266,7 @@ extern __checkReturn int
siena_nvram_set_version(
__in efx_nic_t *enp,
__in efx_nvram_type_t type,
__out uint16_t version[4]);
__in_ecount(4) uint16_t version[4]);
#endif /* EFSYS_OPT_NVRAM */
@ -341,7 +395,7 @@ siena_phy_stats_update(
#if EFSYS_OPT_NAMES
extern const char __cs *
extern const char *
siena_phy_prop_name(
__in efx_nic_t *enp,
__in unsigned int id);
@ -363,18 +417,18 @@ siena_phy_prop_set(
#endif /* EFSYS_OPT_PHY_PROPS */
#if EFSYS_OPT_PHY_BIST
#if EFSYS_OPT_BIST
extern __checkReturn int
siena_phy_bist_start(
__in efx_nic_t *enp,
__in efx_phy_bist_type_t type);
__in efx_bist_type_t type);
extern __checkReturn int
siena_phy_bist_poll(
__in efx_nic_t *enp,
__in efx_phy_bist_type_t type,
__out efx_phy_bist_result_t *resultp,
__in efx_bist_type_t type,
__out efx_bist_result_t *resultp,
__out_opt __drv_when(count > 0, __notnull)
uint32_t *value_maskp,
__out_ecount_opt(count) __drv_when(count > 0, __notnull)
@ -384,9 +438,9 @@ siena_phy_bist_poll(
extern void
siena_phy_bist_stop(
__in efx_nic_t *enp,
__in efx_phy_bist_type_t type);
__in efx_bist_type_t type);
#endif /* EFSYS_OPT_PHY_BIST */
#endif /* EFSYS_OPT_BIST */
extern __checkReturn int
siena_mac_poll(
@ -414,22 +468,6 @@ siena_mac_loopback_set(
#if EFSYS_OPT_MAC_STATS
extern __checkReturn int
siena_mac_stats_clear(
__in efx_nic_t *enp);
extern __checkReturn int
siena_mac_stats_upload(
__in efx_nic_t *enp,
__in efsys_mem_t *esmp);
extern __checkReturn int
siena_mac_stats_periodic(
__in efx_nic_t *enp,
__in efsys_mem_t *esmp,
__in uint16_t period_ms,
__in boolean_t events);
extern __checkReturn int
siena_mac_stats_update(
__in efx_nic_t *enp,
@ -439,39 +477,6 @@ siena_mac_stats_update(
#endif /* EFSYS_OPT_MAC_STATS */
extern __checkReturn int
siena_mon_reset(
__in efx_nic_t *enp);
extern __checkReturn int
siena_mon_reconfigure(
__in efx_nic_t *enp);
#if EFSYS_OPT_MON_STATS
extern void
siena_mon_decode_stats(
__in efx_nic_t *enp,
__in uint32_t dmask,
__in_opt efsys_mem_t *esmp,
__out_opt uint32_t *vmaskp,
__out_ecount_opt(EFX_MON_NSTATS) efx_mon_stat_value_t *value);
extern __checkReturn int
siena_mon_ev(
__in efx_nic_t *enp,
__in efx_qword_t *eqp,
__out efx_mon_stat_t *idp,
__out efx_mon_stat_value_t *valuep);
extern __checkReturn int
siena_mon_stats_update(
__in efx_nic_t *enp,
__in efsys_mem_t *esmp,
__out_ecount(EFX_MON_NSTATS) efx_mon_stat_value_t *values);
#endif /* EFSYS_OPT_MON_STATS */
#ifdef __cplusplus
}
#endif

View File

@ -1,26 +1,31 @@
/*-
* Copyright 2009 Solarflare Communications Inc. All rights reserved.
* Copyright (c) 2009-2015 Solarflare Communications Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* modification, are permitted provided that the following conditions are met:
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the FreeBSD Project.
*/
#include <sys/cdefs.h>
@ -89,26 +94,29 @@ siena_mac_reconfigure(
__in efx_nic_t *enp)
{
efx_port_t *epp = &(enp->en_port);
uint8_t payload[MAX(MC_CMD_SET_MAC_IN_LEN,
MC_CMD_SET_MCAST_HASH_IN_LEN)];
efx_oword_t multicast_hash[2];
efx_mcdi_req_t req;
uint8_t payload[MAX(MAX(MC_CMD_SET_MAC_IN_LEN,
MC_CMD_SET_MAC_OUT_LEN),
MAX(MC_CMD_SET_MCAST_HASH_IN_LEN,
MC_CMD_SET_MCAST_HASH_OUT_LEN))];
unsigned int fcntl;
int rc;
(void) memset(payload, 0, sizeof (payload));
req.emr_cmd = MC_CMD_SET_MAC;
req.emr_in_buf = payload;
req.emr_in_length = MC_CMD_SET_MAC_IN_LEN;
EFX_STATIC_ASSERT(MC_CMD_SET_MAC_OUT_LEN == 0);
req.emr_out_buf = NULL;
req.emr_out_length = 0;
req.emr_out_buf = payload;
req.emr_out_length = MC_CMD_SET_MAC_OUT_LEN;
MCDI_IN_SET_DWORD(req, SET_MAC_IN_MTU, epp->ep_mac_pdu);
MCDI_IN_SET_DWORD(req, SET_MAC_IN_DRAIN, epp->ep_mac_drain ? 1 : 0);
EFX_MAC_ADDR_COPY(MCDI_IN2(req, uint8_t, SET_MAC_IN_ADDR),
epp->ep_mac_addr);
MCDI_IN_POPULATE_DWORD_2(req, SET_MAC_IN_REJECT,
SET_MAC_IN_REJECT_UNCST, !epp->ep_unicst,
SET_MAC_IN_REJECT_BRDCST, !epp->ep_brdcst);
SET_MAC_IN_REJECT_UNCST, !epp->ep_all_unicst,
SET_MAC_IN_REJECT_BRDCST, !epp->ep_brdcst);
if (epp->ep_fcntl_autoneg)
/* efx_fcntl_set() has already set the phy capabilities */
@ -129,19 +137,40 @@ siena_mac_reconfigure(
goto fail1;
}
/* Push multicast hash. Set the broadcast bit (0xff) appropriately */
/* Push multicast hash */
if (epp->ep_all_mulcst) {
/* A hash matching all multicast is all 1s */
EFX_SET_OWORD(multicast_hash[0]);
EFX_SET_OWORD(multicast_hash[1]);
} else if (epp->ep_mulcst) {
/* Use the hash set by the multicast list */
multicast_hash[0] = epp->ep_multicst_hash[0];
multicast_hash[1] = epp->ep_multicst_hash[1];
} else {
/* A hash matching no traffic is simply 0 */
EFX_ZERO_OWORD(multicast_hash[0]);
EFX_ZERO_OWORD(multicast_hash[1]);
}
/*
* Broadcast packets go through the multicast hash filter.
* The IEEE 802.3 CRC32 of the broadcast address is 0xbe2612ff
* so we always add bit 0xff to the mask (bit 0x7f in the
* second octword).
*/
if (epp->ep_brdcst)
EFX_SET_OWORD_BIT(multicast_hash[1], 0x7f);
(void) memset(payload, 0, sizeof (payload));
req.emr_cmd = MC_CMD_SET_MCAST_HASH;
req.emr_in_buf = payload;
req.emr_in_length = MC_CMD_SET_MCAST_HASH_IN_LEN;
EFX_STATIC_ASSERT(MC_CMD_SET_MCAST_HASH_OUT_LEN == 0);
req.emr_out_buf = NULL;
req.emr_out_length = 0;
req.emr_out_buf = payload;
req.emr_out_length = MC_CMD_SET_MCAST_HASH_OUT_LEN;
memcpy(MCDI_IN2(req, uint8_t, SET_MCAST_HASH_IN_HASH0),
epp->ep_multicst_hash, sizeof (epp->ep_multicst_hash));
if (epp->ep_brdcst)
EFX_SET_OWORD_BIT(*MCDI_IN2(req, efx_oword_t,
SET_MCAST_HASH_IN_HASH1), 0x7f);
multicast_hash, sizeof (multicast_hash));
efx_mcdi_execute(enp, &req);
@ -198,150 +227,6 @@ siena_mac_loopback_set(
#if EFSYS_OPT_MAC_STATS
__checkReturn int
siena_mac_stats_clear(
__in efx_nic_t *enp)
{
uint8_t payload[MC_CMD_MAC_STATS_IN_LEN];
efx_mcdi_req_t req;
int rc;
req.emr_cmd = MC_CMD_MAC_STATS;
req.emr_in_buf = payload;
req.emr_in_length = sizeof (payload);
EFX_STATIC_ASSERT(MC_CMD_MAC_STATS_OUT_DMA_LEN == 0);
req.emr_out_buf = NULL;
req.emr_out_length = 0;
MCDI_IN_POPULATE_DWORD_3(req, MAC_STATS_IN_CMD,
MAC_STATS_IN_DMA, 0,
MAC_STATS_IN_CLEAR, 1,
MAC_STATS_IN_PERIODIC_CHANGE, 0);
efx_mcdi_execute(enp, &req);
if (req.emr_rc != 0) {
rc = req.emr_rc;
goto fail1;
}
return (0);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
__checkReturn int
siena_mac_stats_upload(
__in efx_nic_t *enp,
__in efsys_mem_t *esmp)
{
uint8_t payload[MC_CMD_MAC_STATS_IN_LEN];
efx_mcdi_req_t req;
size_t bytes;
int rc;
EFX_STATIC_ASSERT(MC_CMD_MAC_NSTATS * sizeof (uint64_t) <=
EFX_MAC_STATS_SIZE);
bytes = MC_CMD_MAC_NSTATS * sizeof (uint64_t);
req.emr_cmd = MC_CMD_MAC_STATS;
req.emr_in_buf = payload;
req.emr_in_length = sizeof (payload);
EFX_STATIC_ASSERT(MC_CMD_MAC_STATS_OUT_DMA_LEN == 0);
req.emr_out_buf = NULL;
req.emr_out_length = 0;
MCDI_IN_SET_DWORD(req, MAC_STATS_IN_DMA_ADDR_LO,
EFSYS_MEM_ADDR(esmp) & 0xffffffff);
MCDI_IN_SET_DWORD(req, MAC_STATS_IN_DMA_ADDR_HI,
EFSYS_MEM_ADDR(esmp) >> 32);
MCDI_IN_SET_DWORD(req, MAC_STATS_IN_DMA_LEN, bytes);
/*
* The MC DMAs aggregate statistics for our convinience, so we can
* avoid having to pull the statistics buffer into the cache to
* maintain cumulative statistics.
*/
MCDI_IN_POPULATE_DWORD_3(req, MAC_STATS_IN_CMD,
MAC_STATS_IN_DMA, 1,
MAC_STATS_IN_CLEAR, 0,
MAC_STATS_IN_PERIODIC_CHANGE, 0);
efx_mcdi_execute(enp, &req);
if (req.emr_rc != 0) {
rc = req.emr_rc;
goto fail1;
}
return (0);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
__checkReturn int
siena_mac_stats_periodic(
__in efx_nic_t *enp,
__in efsys_mem_t *esmp,
__in uint16_t period,
__in boolean_t events)
{
uint8_t payload[MC_CMD_MAC_STATS_IN_LEN];
efx_mcdi_req_t req;
size_t bytes;
int rc;
bytes = MC_CMD_MAC_NSTATS * sizeof (uint64_t);
req.emr_cmd = MC_CMD_MAC_STATS;
req.emr_in_buf = payload;
req.emr_in_length = sizeof (payload);
EFX_STATIC_ASSERT(MC_CMD_MAC_STATS_OUT_DMA_LEN == 0);
req.emr_out_buf = NULL;
req.emr_out_length = 0;
MCDI_IN_SET_DWORD(req, MAC_STATS_IN_DMA_ADDR_LO,
EFSYS_MEM_ADDR(esmp) & 0xffffffff);
MCDI_IN_SET_DWORD(req, MAC_STATS_IN_DMA_ADDR_HI,
EFSYS_MEM_ADDR(esmp) >> 32);
MCDI_IN_SET_DWORD(req, MAC_STATS_IN_DMA_LEN, bytes);
/*
* The MC DMAs aggregate statistics for our convinience, so we can
* avoid having to pull the statistics buffer into the cache to
* maintain cumulative statistics.
*/
MCDI_IN_POPULATE_DWORD_6(req, MAC_STATS_IN_CMD,
MAC_STATS_IN_DMA, 0,
MAC_STATS_IN_CLEAR, 0,
MAC_STATS_IN_PERIODIC_CHANGE, 1,
MAC_STATS_IN_PERIODIC_ENABLE, period ? 1 : 0,
MAC_STATS_IN_PERIODIC_NOEVENT, events ? 0 : 1,
MAC_STATS_IN_PERIOD_MS, period);
efx_mcdi_execute(enp, &req);
if (req.emr_rc != 0) {
rc = req.emr_rc;
goto fail1;
}
return (0);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
#define SIENA_MAC_STAT_READ(_esmp, _field, _eqp) \
EFSYS_MEM_READQ((_esmp), (_field) * sizeof (efx_qword_t), _eqp)
@ -352,7 +237,6 @@ siena_mac_stats_update(
__out_ecount(EFX_MAC_NSTATS) efsys_stat_t *stat,
__out_opt uint32_t *generationp)
{
efx_qword_t rx_pkts;
efx_qword_t value;
efx_qword_t generation_start;
efx_qword_t generation_end;
@ -360,6 +244,7 @@ siena_mac_stats_update(
_NOTE(ARGUNUSED(enp))
/* Read END first so we don't race with the MC */
EFSYS_DMA_SYNC_FOR_KERNEL(esmp, 0, EFX_MAC_STATS_SIZE);
SIENA_MAC_STAT_READ(esmp, MC_CMD_MAC_GENERATION_END,
&generation_end);
EFSYS_MEM_READ_BARRIER();
@ -388,7 +273,7 @@ siena_mac_stats_update(
SIENA_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_LT64_PKTS, &value);
EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_LE_64_PKTS]), &value);
SIENA_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_64_PKTS, &value);
EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_LE_64_PKTS]), &value);
EFSYS_STAT_INCR_QWORD(&(stat[EFX_MAC_TX_LE_64_PKTS]), &value);
SIENA_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_65_TO_127_PKTS, &value);
EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_65_TO_127_PKTS]), &value);
@ -435,8 +320,8 @@ siena_mac_stats_update(
EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_EX_DEF_PKTS]), &value);
/* RX */
SIENA_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_BYTES, &rx_pkts);
EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_OCTETS]), &rx_pkts);
SIENA_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_BYTES, &value);
EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_OCTETS]), &value);
SIENA_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_PKTS, &value);
EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_PKTS]), &value);
@ -529,6 +414,7 @@ siena_mac_stats_update(
SIENA_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_NODESC_DROPS, &value);
EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_NODESC_DROP_CNT]), &value);
EFSYS_DMA_SYNC_FOR_KERNEL(esmp, 0, EFX_MAC_STATS_SIZE);
EFSYS_MEM_READ_BARRIER();
SIENA_MAC_STAT_READ(esmp, MC_CMD_MAC_GENERATION_START,
&generation_start);

View File

@ -0,0 +1,354 @@
/*-
* Copyright (c) 2012-2015 Solarflare Communications Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the FreeBSD Project.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "efsys.h"
#include "efx.h"
#include "efx_impl.h"
#if EFSYS_OPT_SIENA && EFSYS_OPT_MCDI
#define SIENA_MCDI_PDU(_emip) \
(((emip)->emi_port == 1) \
? MC_SMEM_P0_PDU_OFST >> 2 \
: MC_SMEM_P1_PDU_OFST >> 2)
#define SIENA_MCDI_DOORBELL(_emip) \
(((emip)->emi_port == 1) \
? MC_SMEM_P0_DOORBELL_OFST >> 2 \
: MC_SMEM_P1_DOORBELL_OFST >> 2)
#define SIENA_MCDI_STATUS(_emip) \
(((emip)->emi_port == 1) \
? MC_SMEM_P0_STATUS_OFST >> 2 \
: MC_SMEM_P1_STATUS_OFST >> 2)
void
siena_mcdi_request_copyin(
__in efx_nic_t *enp,
__in efx_mcdi_req_t *emrp,
__in unsigned int seq,
__in boolean_t ev_cpl,
__in boolean_t new_epoch)
{
efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
efx_dword_t dword;
unsigned int xflags;
unsigned int pdur;
unsigned int dbr;
unsigned int pos;
EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
_NOTE(ARGUNUSED(new_epoch))
EFSYS_ASSERT(emip->emi_port == 1 || emip->emi_port == 2);
pdur = SIENA_MCDI_PDU(emip);
dbr = SIENA_MCDI_DOORBELL(emip);
xflags = 0;
if (ev_cpl)
xflags |= MCDI_HEADER_XFLAGS_EVREQ;
/* Construct the header in shared memory */
EFX_POPULATE_DWORD_6(dword,
MCDI_HEADER_CODE, emrp->emr_cmd,
MCDI_HEADER_RESYNC, 1,
MCDI_HEADER_DATALEN, emrp->emr_in_length,
MCDI_HEADER_SEQ, seq,
MCDI_HEADER_RESPONSE, 0,
MCDI_HEADER_XFLAGS, xflags);
EFX_BAR_TBL_WRITED(enp, FR_CZ_MC_TREG_SMEM, pdur, &dword, B_TRUE);
for (pos = 0; pos < emrp->emr_in_length; pos += sizeof (efx_dword_t)) {
memcpy(&dword, MCDI_IN(*emrp, efx_dword_t, pos),
MIN(sizeof (dword), emrp->emr_in_length - pos));
EFX_BAR_TBL_WRITED(enp, FR_CZ_MC_TREG_SMEM,
pdur + 1 + (pos >> 2), &dword, B_FALSE);
}
/* Ring the doorbell */
EFX_POPULATE_DWORD_1(dword, EFX_DWORD_0, 0xd004be11);
EFX_BAR_TBL_WRITED(enp, FR_CZ_MC_TREG_SMEM, dbr, &dword, B_FALSE);
}
void
siena_mcdi_request_copyout(
__in efx_nic_t *enp,
__in efx_mcdi_req_t *emrp)
{
efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
unsigned int pos;
unsigned int pdur;
efx_dword_t data;
pdur = SIENA_MCDI_PDU(emip);
/* Copy payload out if caller supplied buffer */
if (emrp->emr_out_buf != NULL) {
size_t bytes = MIN(emrp->emr_out_length_used,
emrp->emr_out_length);
for (pos = 0; pos < bytes; pos += sizeof (efx_dword_t)) {
EFX_BAR_TBL_READD(enp, FR_CZ_MC_TREG_SMEM,
pdur + 1 + (pos >> 2), &data, B_FALSE);
memcpy(MCDI_OUT(*emrp, efx_dword_t, pos), &data,
MIN(sizeof (data), bytes - pos));
}
}
}
int
siena_mcdi_poll_reboot(
__in efx_nic_t *enp)
{
#ifndef EFX_GRACEFUL_MC_REBOOT
/*
* This function is not being used properly.
* Until its callers are fixed, it should always return 0.
*/
_NOTE(ARGUNUSED(enp))
return (0);
#else
efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
unsigned int rebootr;
efx_dword_t dword;
uint32_t value;
EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
EFSYS_ASSERT(emip->emi_port == 1 || emip->emi_port == 2);
rebootr = SIENA_MCDI_STATUS(emip);
EFX_BAR_TBL_READD(enp, FR_CZ_MC_TREG_SMEM, rebootr, &dword, B_FALSE);
value = EFX_DWORD_FIELD(dword, EFX_DWORD_0);
if (value == 0)
return (0);
EFX_ZERO_DWORD(dword);
EFX_BAR_TBL_WRITED(enp, FR_CZ_MC_TREG_SMEM, rebootr, &dword, B_FALSE);
if (value == MC_STATUS_DWORD_ASSERT)
return (EINTR);
else
return (EIO);
#endif
}
__checkReturn boolean_t
siena_mcdi_request_poll(
__in efx_nic_t *enp)
{
efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
efx_mcdi_req_t *emrp;
efx_dword_t dword;
unsigned int pdur;
unsigned int seq;
unsigned int length;
int state;
int rc;
EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_SIENA);
/* Serialise against post-watchdog efx_mcdi_ev* */
EFSYS_LOCK(enp->en_eslp, state);
EFSYS_ASSERT(emip->emi_pending_req != NULL);
EFSYS_ASSERT(!emip->emi_ev_cpl);
emrp = emip->emi_pending_req;
/* Check for reboot atomically w.r.t efx_mcdi_request_start */
if (emip->emi_poll_cnt++ == 0) {
if ((rc = siena_mcdi_poll_reboot(enp)) != 0) {
emip->emi_pending_req = NULL;
EFSYS_UNLOCK(enp->en_eslp, state);
goto fail1;
}
}
EFSYS_ASSERT(emip->emi_port == 1 || emip->emi_port == 2);
pdur = SIENA_MCDI_PDU(emip);
/* Read the command header */
EFX_BAR_TBL_READD(enp, FR_CZ_MC_TREG_SMEM, pdur, &dword, B_FALSE);
if (EFX_DWORD_FIELD(dword, MCDI_HEADER_RESPONSE) == 0) {
EFSYS_UNLOCK(enp->en_eslp, state);
return (B_FALSE);
}
/* Request complete */
emip->emi_pending_req = NULL;
seq = (emip->emi_seq - 1) & EFX_MASK32(MCDI_HEADER_SEQ);
/* Check for synchronous reboot */
if (EFX_DWORD_FIELD(dword, MCDI_HEADER_ERROR) != 0 &&
EFX_DWORD_FIELD(dword, MCDI_HEADER_DATALEN) == 0) {
/* Consume status word */
EFSYS_SPIN(EFX_MCDI_STATUS_SLEEP_US);
siena_mcdi_poll_reboot(enp);
EFSYS_UNLOCK(enp->en_eslp, state);
rc = EIO;
goto fail2;
}
EFSYS_UNLOCK(enp->en_eslp, state);
/* Check that the returned data is consistent */
if (EFX_DWORD_FIELD(dword, MCDI_HEADER_CODE) != emrp->emr_cmd ||
EFX_DWORD_FIELD(dword, MCDI_HEADER_SEQ) != seq) {
/* Response is for a different request */
rc = EIO;
goto fail3;
}
length = EFX_DWORD_FIELD(dword, MCDI_HEADER_DATALEN);
if (EFX_DWORD_FIELD(dword, MCDI_HEADER_ERROR)) {
efx_dword_t errdword;
int errcode;
EFSYS_ASSERT3U(length, ==, 4);
EFX_BAR_TBL_READD(enp, FR_CZ_MC_TREG_SMEM,
pdur + 1 + (MC_CMD_ERR_CODE_OFST >> 2),
&errdword, B_FALSE);
errcode = EFX_DWORD_FIELD(errdword, EFX_DWORD_0);
rc = efx_mcdi_request_errcode(errcode);
if (!emrp->emr_quiet) {
EFSYS_PROBE2(mcdi_err, int, emrp->emr_cmd,
int, errcode);
}
goto fail4;
} else {
emrp->emr_out_length_used = length;
emrp->emr_rc = 0;
siena_mcdi_request_copyout(enp, emrp);
}
goto out;
fail4:
if (!emrp->emr_quiet)
EFSYS_PROBE(fail4);
fail3:
if (!emrp->emr_quiet)
EFSYS_PROBE(fail3);
fail2:
if (!emrp->emr_quiet)
EFSYS_PROBE(fail2);
fail1:
if (!emrp->emr_quiet)
EFSYS_PROBE1(fail1, int, rc);
/* Fill out error state */
emrp->emr_rc = rc;
emrp->emr_out_length_used = 0;
/* Reboot/Assertion */
if (rc == EIO || rc == EINTR)
efx_mcdi_raise_exception(enp, emrp, rc);
out:
return (B_TRUE);
}
__checkReturn int
siena_mcdi_init(
__in efx_nic_t *enp,
__in const efx_mcdi_transport_t *mtp)
{
efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
efx_oword_t oword;
unsigned int portnum;
int rc;
EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
/* Determine the port number to use for MCDI */
EFX_BAR_READO(enp, FR_AZ_CS_DEBUG_REG, &oword);
portnum = EFX_OWORD_FIELD(oword, FRF_CZ_CS_PORT_NUM);
if (portnum == 0) {
/* Presumably booted from ROM; only MCDI port 1 will work */
emip->emi_port = 1;
} else if (portnum <= 2) {
emip->emi_port = portnum;
} else {
rc = EINVAL;
goto fail1;
}
/*
* Wipe the atomic reboot status so subsequent MCDI requests succeed.
* BOOT_STATUS is preserved so eno_nic_probe() can boot out of the
* assertion handler.
*/
(void) siena_mcdi_poll_reboot(enp);
return (0);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
void
siena_mcdi_fini(
__in efx_nic_t *enp)
{
}
__checkReturn int
siena_mcdi_fw_update_supported(
__in efx_nic_t *enp,
__out boolean_t *supportedp)
{
EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_SIENA);
*supportedp = B_TRUE;
return (0);
}
__checkReturn int
siena_mcdi_macaddr_change_supported(
__in efx_nic_t *enp,
__out boolean_t *supportedp)
{
EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_SIENA);
*supportedp = B_TRUE;
return (0);
}
#endif /* EFSYS_OPT_SIENA && EFSYS_OPT_MCDI */

View File

@ -1,284 +0,0 @@
/*-
* Copyright 2009 Solarflare Communications Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "efsys.h"
#include "efx.h"
#include "efx_impl.h"
#if EFSYS_OPT_MON_SIENA
__checkReturn int
siena_mon_reset(
__in efx_nic_t *enp)
{
_NOTE(ARGUNUSED(enp))
EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
return (0);
}
__checkReturn int
siena_mon_reconfigure(
__in efx_nic_t *enp)
{
_NOTE(ARGUNUSED(enp))
EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
return (0);
}
#if EFSYS_OPT_MON_STATS
#define SIENA_MON_WRONG_PORT (uint16_t)0xffff
static __cs uint16_t __siena_mon_port0_map[] = {
EFX_MON_STAT_INT_TEMP, /* MC_CMD_SENSOR_CONTROLLER_TEMP */
EFX_MON_STAT_EXT_TEMP, /* MC_CMD_SENSOR_PHY_COMMON_TEMP */
EFX_MON_STAT_INT_COOLING, /* MC_CMD_SENSOR_CONTROLLER_COOLING */
EFX_MON_STAT_EXT_TEMP, /* MC_CMD_SENSOR_PHY0_TEMP */
EFX_MON_STAT_EXT_COOLING, /* MC_CMD_SENSOR_PHY0_COOLING */
SIENA_MON_WRONG_PORT, /* MC_CMD_SENSOR_PHY1_TEMP */
SIENA_MON_WRONG_PORT, /* MC_CMD_SENSOR_PHY1_COOLING */
EFX_MON_STAT_1V, /* MC_CMD_SENSOR_IN_1V0 */
EFX_MON_STAT_1_2V, /* MC_CMD_SENSOR_IN_1V2 */
EFX_MON_STAT_1_8V, /* MC_CMD_SENSOR_IN_1V8 */
EFX_MON_STAT_2_5V, /* MC_CMD_SENSOR_IN_2V5 */
EFX_MON_STAT_3_3V, /* MC_CMD_SENSOR_IN_3V3 */
EFX_MON_STAT_12V, /* MC_CMD_SENSOR_IN_12V0 */
EFX_MON_STAT_1_2VA, /* MC_CMD_SENSOR_IN_1V2A */
EFX_MON_STAT_VREF, /* MC_CMD_SENSOR_IN_VREF */
EFX_MON_STAT_VAOE, /* MC_CMD_SENSOR_OUT_VAOE */
EFX_MON_STAT_AOE_TEMP, /* MC_CMD_SENSOR_AOE_TEMP */
EFX_MON_STAT_PSU_AOE_TEMP, /* MC_CMD_SENSOR_PSU_AOE_TEMP */
EFX_MON_STAT_PSU_TEMP, /* MC_CMD_SENSOR_PSE_TEMP */
EFX_MON_STAT_FAN0, /* MC_CMD_SENSOR_FAN_0 */
EFX_MON_STAT_FAN1, /* MC_CMD_SENSOR_FAN_1 */
EFX_MON_STAT_FAN2, /* MC_CMD_SENSOR_FAN_2 */
EFX_MON_STAT_FAN3, /* MC_CMD_SENSOR_FAN_3 */
EFX_MON_STAT_FAN4, /* MC_CMD_SENSOR_FAN_4 */
EFX_MON_STAT_VAOE_IN, /* MC_CMD_SENSOR_IN_VAOE */
EFX_MON_STAT_IAOE, /* MC_CMD_SENSOR_OUT_IAOE */
EFX_MON_STAT_IAOE_IN, /* MC_CMD_SENSOR_IN_IAOE */
};
static __cs uint16_t __siena_mon_port1_map[] = {
EFX_MON_STAT_INT_TEMP, /* MC_CMD_SENSOR_CONTROLLER_TEMP */
EFX_MON_STAT_EXT_TEMP, /* MC_CMD_SENSOR_PHY_COMMON_TEMP */
EFX_MON_STAT_INT_COOLING, /* MC_CMD_SENSOR_CONTROLLER_COOLING */
SIENA_MON_WRONG_PORT, /* MC_CMD_SENSOR_PHY0_TEMP */
SIENA_MON_WRONG_PORT, /* MC_CMD_SENSOR_PHY0_COOLING */
EFX_MON_STAT_EXT_TEMP, /* MC_CMD_SENSOR_PHY1_TEMP */
EFX_MON_STAT_EXT_COOLING, /* MC_CMD_SENSOR_PHY1_COOLING */
EFX_MON_STAT_1V, /* MC_CMD_SENSOR_IN_1V0 */
EFX_MON_STAT_1_2V, /* MC_CMD_SENSOR_IN_1V2 */
EFX_MON_STAT_1_8V, /* MC_CMD_SENSOR_IN_1V8 */
EFX_MON_STAT_2_5V, /* MC_CMD_SENSOR_IN_2V5 */
EFX_MON_STAT_3_3V, /* MC_CMD_SENSOR_IN_3V3 */
EFX_MON_STAT_12V, /* MC_CMD_SENSOR_IN_12V0 */
EFX_MON_STAT_1_2VA, /* MC_CMD_SENSOR_IN_1V2A */
EFX_MON_STAT_VREF, /* MC_CMD_SENSOR_IN_VREF */
EFX_MON_STAT_VAOE, /* MC_CMD_SENSOR_OUT_VAOE */
EFX_MON_STAT_AOE_TEMP, /* MC_CMD_SENSOR_AOE_TEMP */
EFX_MON_STAT_PSU_AOE_TEMP, /* MC_CMD_SENSOR_PSU_AOE_TEMP */
EFX_MON_STAT_PSU_TEMP, /* MC_CMD_SENSOR_PSE_TEMP */
EFX_MON_STAT_FAN0, /* MC_CMD_SENSOR_FAN_0 */
EFX_MON_STAT_FAN1, /* MC_CMD_SENSOR_FAN_1 */
EFX_MON_STAT_FAN2, /* MC_CMD_SENSOR_FAN_2 */
EFX_MON_STAT_FAN3, /* MC_CMD_SENSOR_FAN_3 */
EFX_MON_STAT_FAN4, /* MC_CMD_SENSOR_FAN_4 */
EFX_MON_STAT_VAOE_IN, /* MC_CMD_SENSOR_IN_VAOE */
EFX_MON_STAT_IAOE, /* MC_CMD_SENSOR_OUT_IAOE */
EFX_MON_STAT_IAOE_IN, /* MC_CMD_SENSOR_IN_IAOE */
};
#define SIENA_STATIC_SENSOR_ASSERT(_field) \
EFX_STATIC_ASSERT(MC_CMD_SENSOR_STATE_ ## _field \
== EFX_MON_STAT_STATE_ ## _field)
void
siena_mon_decode_stats(
__in efx_nic_t *enp,
__in uint32_t dmask,
__in_opt efsys_mem_t *esmp,
__out_opt uint32_t *vmaskp,
__out_ecount_opt(EFX_MON_NSTATS) efx_mon_stat_value_t *value)
{
efx_mcdi_iface_t *emip = &(enp->en_u.siena.enu_mip);
uint16_t *sensor_map;
uint16_t mc_sensor;
size_t mc_sensor_max;
uint32_t vmask = 0;
uint32_t idx = 0;
/* Assert the MC_CMD_SENSOR and EFX_MON_STATE namespaces agree */
SIENA_STATIC_SENSOR_ASSERT(OK);
SIENA_STATIC_SENSOR_ASSERT(WARNING);
SIENA_STATIC_SENSOR_ASSERT(FATAL);
SIENA_STATIC_SENSOR_ASSERT(BROKEN);
EFX_STATIC_ASSERT(sizeof (__siena_mon_port1_map)
== sizeof (__siena_mon_port0_map));
mc_sensor_max = EFX_ARRAY_SIZE(__siena_mon_port0_map);
sensor_map = (emip->emi_port == 1)
? __siena_mon_port0_map
: __siena_mon_port1_map;
/*
* dmask may legitimately contain sensors not understood by the driver
*/
for (mc_sensor = 0; mc_sensor < mc_sensor_max; ++mc_sensor) {
uint16_t efx_sensor = sensor_map[mc_sensor];
if (~dmask & (1 << mc_sensor))
continue;
idx++;
if (efx_sensor == SIENA_MON_WRONG_PORT)
continue;
EFSYS_ASSERT(efx_sensor < EFX_MON_NSTATS);
vmask |= (1 << efx_sensor);
if (value != NULL && esmp != NULL && !EFSYS_MEM_IS_NULL(esmp)) {
efx_mon_stat_value_t *emsvp = value + efx_sensor;
efx_dword_t dword;
EFSYS_MEM_READD(esmp, 4 * (idx - 1), &dword);
emsvp->emsv_value =
(uint16_t)EFX_DWORD_FIELD(
dword,
MC_CMD_SENSOR_VALUE_ENTRY_TYPEDEF_VALUE);
emsvp->emsv_state =
(uint16_t)EFX_DWORD_FIELD(
dword,
MC_CMD_SENSOR_VALUE_ENTRY_TYPEDEF_STATE);
}
}
if (vmaskp != NULL)
*vmaskp = vmask;
}
__checkReturn int
siena_mon_ev(
__in efx_nic_t *enp,
__in efx_qword_t *eqp,
__out efx_mon_stat_t *idp,
__out efx_mon_stat_value_t *valuep)
{
efx_mcdi_iface_t *emip = &(enp->en_u.siena.enu_mip);
efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
uint16_t ev_monitor;
uint16_t ev_state;
uint16_t ev_value;
uint16_t *sensor_map;
efx_mon_stat_t id;
int rc;
sensor_map = (emip->emi_port == 1)
? __siena_mon_port0_map
: __siena_mon_port1_map;
ev_monitor = (uint16_t)MCDI_EV_FIELD(eqp, SENSOREVT_MONITOR);
ev_state = (uint16_t)MCDI_EV_FIELD(eqp, SENSOREVT_STATE);
ev_value = (uint16_t)MCDI_EV_FIELD(eqp, SENSOREVT_VALUE);
/* Hardware must support this statistic */
EFSYS_ASSERT((1 << ev_monitor) & encp->enc_siena_mon_stat_mask);
/* But we don't have to understand it */
if (ev_monitor >= EFX_ARRAY_SIZE(__siena_mon_port0_map)) {
rc = ENOTSUP;
goto fail1;
}
id = sensor_map[ev_monitor];
if (id == SIENA_MON_WRONG_PORT)
return (ENODEV);
EFSYS_ASSERT(id < EFX_MON_NSTATS);
*idp = id;
valuep->emsv_value = ev_value;
valuep->emsv_state = ev_state;
return (0);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
__checkReturn int
siena_mon_stats_update(
__in efx_nic_t *enp,
__in efsys_mem_t *esmp,
__out_ecount(EFX_MON_NSTATS) efx_mon_stat_value_t *values)
{
efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
uint32_t dmask = encp->enc_siena_mon_stat_mask;
uint32_t vmask;
uint8_t payload[MC_CMD_READ_SENSORS_IN_LEN];
efx_mcdi_req_t req;
int rc;
EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
req.emr_cmd = MC_CMD_READ_SENSORS;
req.emr_in_buf = payload;
req.emr_in_length = sizeof (payload);
EFX_STATIC_ASSERT(MC_CMD_READ_SENSORS_OUT_LEN == 0);
req.emr_out_buf = NULL;
req.emr_out_length = 0;
MCDI_IN_SET_DWORD(req, READ_SENSORS_IN_DMA_ADDR_LO,
EFSYS_MEM_ADDR(esmp) & 0xffffffff);
MCDI_IN_SET_DWORD(req, READ_SENSORS_IN_DMA_ADDR_HI,
EFSYS_MEM_ADDR(esmp) >> 32);
efx_mcdi_execute(enp, &req);
if (req.emr_rc != 0) {
rc = req.emr_rc;
goto fail1;
}
siena_mon_decode_stats(enp, dmask, esmp, &vmask, values);
EFSYS_ASSERT(vmask == encp->enc_mon_stat_mask);
return (0);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
#endif /* EFSYS_OPT_MON_STATS */
#endif /* EFSYS_OPT_MON_SIENA */

View File

@ -1,26 +1,31 @@
/*-
* Copyright 2009 Solarflare Communications Inc. All rights reserved.
* Copyright (c) 2009-2015 Solarflare Communications Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* modification, are permitted provided that the following conditions are met:
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the FreeBSD Project.
*/
#include <sys/cdefs.h>
@ -29,6 +34,7 @@ __FBSDID("$FreeBSD$");
#include "efsys.h"
#include "efx.h"
#include "efx_impl.h"
#include "mcdi_mon.h"
#if EFSYS_OPT_SIENA
@ -38,15 +44,16 @@ siena_nic_get_partn_mask(
__out unsigned int *maskp)
{
efx_mcdi_req_t req;
uint8_t outbuf[MC_CMD_NVRAM_TYPES_OUT_LEN];
uint8_t payload[MAX(MC_CMD_NVRAM_TYPES_IN_LEN,
MC_CMD_NVRAM_TYPES_OUT_LEN)];
int rc;
(void) memset(payload, 0, sizeof (payload));
req.emr_cmd = MC_CMD_NVRAM_TYPES;
EFX_STATIC_ASSERT(MC_CMD_NVRAM_TYPES_IN_LEN == 0);
req.emr_in_buf = NULL;
req.emr_in_length = 0;
req.emr_out_buf = outbuf;
req.emr_out_length = sizeof (outbuf);
req.emr_in_buf = payload;
req.emr_in_length = MC_CMD_NVRAM_TYPES_IN_LEN;
req.emr_out_buf = payload;
req.emr_out_length = MC_CMD_NVRAM_TYPES_OUT_LEN;
efx_mcdi_execute(enp, &req);
@ -72,193 +79,17 @@ siena_nic_get_partn_mask(
return (rc);
}
static __checkReturn int
siena_nic_exit_assertion_handler(
__in efx_nic_t *enp)
{
efx_mcdi_req_t req;
uint8_t payload[MC_CMD_REBOOT_IN_LEN];
int rc;
req.emr_cmd = MC_CMD_REBOOT;
req.emr_in_buf = payload;
req.emr_in_length = MC_CMD_REBOOT_IN_LEN;
EFX_STATIC_ASSERT(MC_CMD_REBOOT_OUT_LEN == 0);
req.emr_out_buf = NULL;
req.emr_out_length = 0;
MCDI_IN_SET_DWORD(req, REBOOT_IN_FLAGS,
MC_CMD_REBOOT_FLAGS_AFTER_ASSERTION);
efx_mcdi_execute(enp, &req);
if (req.emr_rc != 0 && req.emr_rc != EIO) {
rc = req.emr_rc;
goto fail1;
}
return (0);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
static __checkReturn int
siena_nic_read_assertion(
__in efx_nic_t *enp)
{
efx_mcdi_req_t req;
uint8_t payload[MAX(MC_CMD_GET_ASSERTS_IN_LEN,
MC_CMD_GET_ASSERTS_OUT_LEN)];
const char *reason;
unsigned int flags;
unsigned int index;
unsigned int ofst;
int retry;
int rc;
/*
* Before we attempt to chat to the MC, we should verify that the MC
* isn't in it's assertion handler, either due to a previous reboot,
* or because we're reinitializing due to an eec_exception().
*
* Use GET_ASSERTS to read any assertion state that may be present.
* Retry this command twice. Once because a boot-time assertion failure
* might cause the 1st MCDI request to fail. And once again because
* we might race with siena_nic_exit_assertion_handler() running on the
* other port.
*/
retry = 2;
do {
req.emr_cmd = MC_CMD_GET_ASSERTS;
req.emr_in_buf = payload;
req.emr_in_length = MC_CMD_GET_ASSERTS_IN_LEN;
req.emr_out_buf = payload;
req.emr_out_length = MC_CMD_GET_ASSERTS_OUT_LEN;
MCDI_IN_SET_DWORD(req, GET_ASSERTS_IN_CLEAR, 1);
efx_mcdi_execute(enp, &req);
} while ((req.emr_rc == EINTR || req.emr_rc == EIO) && retry-- > 0);
if (req.emr_rc != 0) {
rc = req.emr_rc;
goto fail1;
}
if (req.emr_out_length_used < MC_CMD_GET_ASSERTS_OUT_LEN) {
rc = EMSGSIZE;
goto fail2;
}
/* Print out any assertion state recorded */
flags = MCDI_OUT_DWORD(req, GET_ASSERTS_OUT_GLOBAL_FLAGS);
if (flags == MC_CMD_GET_ASSERTS_FLAGS_NO_FAILS)
return (0);
reason = (flags == MC_CMD_GET_ASSERTS_FLAGS_SYS_FAIL)
? "system-level assertion"
: (flags == MC_CMD_GET_ASSERTS_FLAGS_THR_FAIL)
? "thread-level assertion"
: (flags == MC_CMD_GET_ASSERTS_FLAGS_WDOG_FIRED)
? "watchdog reset"
: "unknown assertion";
EFSYS_PROBE3(mcpu_assertion,
const char *, reason, unsigned int,
MCDI_OUT_DWORD(req, GET_ASSERTS_OUT_SAVED_PC_OFFS),
unsigned int,
MCDI_OUT_DWORD(req, GET_ASSERTS_OUT_THREAD_OFFS));
/* Print out the registers */
ofst = MC_CMD_GET_ASSERTS_OUT_GP_REGS_OFFS_OFST;
for (index = 1; index < 32; index++) {
EFSYS_PROBE2(mcpu_register, unsigned int, index, unsigned int,
EFX_DWORD_FIELD(*MCDI_OUT(req, efx_dword_t, ofst),
EFX_DWORD_0));
ofst += sizeof (efx_dword_t);
}
EFSYS_ASSERT(ofst <= MC_CMD_GET_ASSERTS_OUT_LEN);
return (0);
fail2:
EFSYS_PROBE(fail2);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
static __checkReturn int
siena_nic_attach(
__in efx_nic_t *enp,
__in boolean_t attach)
{
efx_mcdi_req_t req;
uint8_t payload[MC_CMD_DRV_ATTACH_IN_LEN];
int rc;
req.emr_cmd = MC_CMD_DRV_ATTACH;
req.emr_in_buf = payload;
req.emr_in_length = MC_CMD_DRV_ATTACH_IN_LEN;
req.emr_out_buf = NULL;
req.emr_out_length = 0;
MCDI_IN_SET_DWORD(req, DRV_ATTACH_IN_NEW_STATE, attach ? 1 : 0);
MCDI_IN_SET_DWORD(req, DRV_ATTACH_IN_UPDATE, 1);
efx_mcdi_execute(enp, &req);
if (req.emr_rc != 0) {
rc = req.emr_rc;
goto fail1;
}
if (req.emr_out_length_used < MC_CMD_DRV_ATTACH_OUT_LEN) {
rc = EMSGSIZE;
goto fail2;
}
return (0);
fail2:
EFSYS_PROBE(fail2);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
#if EFSYS_OPT_PCIE_TUNE
__checkReturn int
siena_nic_pcie_extended_sync(
__in efx_nic_t *enp)
{
uint8_t inbuf[MC_CMD_WORKAROUND_IN_LEN];
efx_mcdi_req_t req;
int rc;
EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_SIENA);
req.emr_cmd = MC_CMD_WORKAROUND;
req.emr_in_buf = inbuf;
req.emr_in_length = sizeof (inbuf);
EFX_STATIC_ASSERT(MC_CMD_WORKAROUND_OUT_LEN == 0);
req.emr_out_buf = NULL;
req.emr_out_length = 0;
MCDI_IN_SET_DWORD(req, WORKAROUND_IN_TYPE, MC_CMD_WORKAROUND_BUG17230);
MCDI_IN_SET_DWORD(req, WORKAROUND_IN_ENABLED, 1);
efx_mcdi_execute(enp, &req);
if (req.emr_rc != 0) {
rc = req.emr_rc;
if ((rc = efx_mcdi_set_workaround(enp, MC_CMD_WORKAROUND_BUG17230,
B_TRUE, NULL) != 0))
goto fail1;
}
return (0);
@ -275,58 +106,33 @@ siena_board_cfg(
__in efx_nic_t *enp)
{
efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
efx_mcdi_iface_t *emip = &(enp->en_u.siena.enu_mip);
uint8_t outbuf[MAX(MC_CMD_GET_BOARD_CFG_OUT_LENMIN,
MC_CMD_GET_RESOURCE_LIMITS_OUT_LEN)];
efx_mcdi_req_t req;
uint8_t *mac_addr;
efx_dword_t *capabilities;
uint8_t mac_addr[6];
efx_dword_t capabilities;
uint32_t board_type;
uint32_t nevq, nrxq, ntxq;
int rc;
/* External port identifier using one-based port numbering */
encp->enc_external_port = (uint8_t)enp->en_mcdi.em_emip.emi_port;
/* Board configuration */
req.emr_cmd = MC_CMD_GET_BOARD_CFG;
EFX_STATIC_ASSERT(MC_CMD_GET_BOARD_CFG_IN_LEN == 0);
req.emr_in_buf = NULL;
req.emr_in_length = 0;
req.emr_out_buf = outbuf;
req.emr_out_length = MC_CMD_GET_BOARD_CFG_OUT_LENMIN;
efx_mcdi_execute(enp, &req);
if (req.emr_rc != 0) {
rc = req.emr_rc;
if ((rc = efx_mcdi_get_board_cfg(enp, &board_type,
&capabilities, mac_addr)) != 0)
goto fail1;
}
if (req.emr_out_length_used < MC_CMD_GET_BOARD_CFG_OUT_LENMIN) {
rc = EMSGSIZE;
goto fail2;
}
if (emip->emi_port == 1) {
mac_addr = MCDI_OUT2(req, uint8_t,
GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT0);
capabilities = MCDI_OUT2(req, efx_dword_t,
GET_BOARD_CFG_OUT_CAPABILITIES_PORT0);
} else {
mac_addr = MCDI_OUT2(req, uint8_t,
GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT1);
capabilities = MCDI_OUT2(req, efx_dword_t,
GET_BOARD_CFG_OUT_CAPABILITIES_PORT1);
}
EFX_MAC_ADDR_COPY(encp->enc_mac_addr, mac_addr);
encp->enc_board_type = MCDI_OUT_DWORD(req,
GET_BOARD_CFG_OUT_BOARD_TYPE);
encp->enc_board_type = board_type;
/* Additional capabilities */
encp->enc_clk_mult = 1;
if (MCDI_CMD_DWORD_FIELD(capabilities, CAPABILITIES_TURBO)) {
if (EFX_DWORD_FIELD(capabilities, MC_CMD_CAPABILITIES_TURBO)) {
enp->en_features |= EFX_FEATURE_TURBO;
if (MCDI_CMD_DWORD_FIELD(capabilities,
CAPABILITIES_TURBO_ACTIVE))
if (EFX_DWORD_FIELD(capabilities,
MC_CMD_CAPABILITIES_TURBO_ACTIVE)) {
encp->enc_clk_mult = 2;
}
}
encp->enc_evq_timer_quantum_ns =
@ -334,48 +140,39 @@ siena_board_cfg(
encp->enc_evq_timer_max_us = (encp->enc_evq_timer_quantum_ns <<
FRF_CZ_TC_TIMER_VAL_WIDTH) / 1000;
/* When hash header insertion is enabled, Siena inserts 16 bytes */
encp->enc_rx_prefix_size = 16;
/* Alignment for receive packet DMA buffers */
encp->enc_rx_buf_align_start = 1;
encp->enc_rx_buf_align_end = 1;
/* Alignment for WPTR updates */
encp->enc_rx_push_align = 1;
/* Resource limits */
req.emr_cmd = MC_CMD_GET_RESOURCE_LIMITS;
EFX_STATIC_ASSERT(MC_CMD_GET_RESOURCE_LIMITS_IN_LEN == 0);
req.emr_in_buf = NULL;
req.emr_in_length = 0;
req.emr_out_buf = outbuf;
req.emr_out_length = MC_CMD_GET_RESOURCE_LIMITS_OUT_LEN;
rc = efx_mcdi_get_resource_limits(enp, &nevq, &nrxq, &ntxq);
if (rc != 0) {
if (rc != ENOTSUP)
goto fail2;
efx_mcdi_execute(enp, &req);
if (req.emr_rc == 0) {
if (req.emr_out_length_used <
MC_CMD_GET_RESOURCE_LIMITS_OUT_LEN) {
rc = EMSGSIZE;
goto fail3;
}
encp->enc_evq_limit = MCDI_OUT_DWORD(req,
GET_RESOURCE_LIMITS_OUT_EVQ);
encp->enc_txq_limit = MIN(EFX_TXQ_LIMIT_TARGET,
MCDI_OUT_DWORD(req, GET_RESOURCE_LIMITS_OUT_TXQ));
encp->enc_rxq_limit = MIN(EFX_RXQ_LIMIT_TARGET,
MCDI_OUT_DWORD(req, GET_RESOURCE_LIMITS_OUT_RXQ));
} else if (req.emr_rc == ENOTSUP) {
encp->enc_evq_limit = 1024;
encp->enc_txq_limit = EFX_TXQ_LIMIT_TARGET;
encp->enc_rxq_limit = EFX_RXQ_LIMIT_TARGET;
} else {
rc = req.emr_rc;
goto fail4;
nevq = 1024;
nrxq = EFX_RXQ_LIMIT_TARGET;
ntxq = EFX_TXQ_LIMIT_TARGET;
}
encp->enc_evq_limit = nevq;
encp->enc_rxq_limit = MIN(EFX_RXQ_LIMIT_TARGET, nrxq);
encp->enc_txq_limit = MIN(EFX_TXQ_LIMIT_TARGET, ntxq);
encp->enc_buftbl_limit = SIENA_SRAM_ROWS -
(encp->enc_txq_limit * EFX_TXQ_DC_NDESCS(EFX_TXQ_DC_SIZE)) -
(encp->enc_rxq_limit * EFX_RXQ_DC_NDESCS(EFX_RXQ_DC_SIZE));
encp->enc_hw_tx_insert_vlan_enabled = B_FALSE;
encp->enc_fw_assisted_tso_enabled = B_FALSE;
return (0);
fail4:
EFSYS_PROBE(fail4);
fail3:
EFSYS_PROBE(fail3);
fail2:
EFSYS_PROBE(fail2);
fail1:
@ -388,220 +185,27 @@ static __checkReturn int
siena_phy_cfg(
__in efx_nic_t *enp)
{
efx_port_t *epp = &(enp->en_port);
efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
efx_mcdi_req_t req;
uint8_t outbuf[MC_CMD_GET_PHY_CFG_OUT_LEN];
int rc;
req.emr_cmd = MC_CMD_GET_PHY_CFG;
EFX_STATIC_ASSERT(MC_CMD_GET_PHY_CFG_IN_LEN == 0);
req.emr_in_buf = NULL;
req.emr_in_length = 0;
req.emr_out_buf = outbuf;
req.emr_out_length = sizeof (outbuf);
efx_mcdi_execute(enp, &req);
if (req.emr_rc != 0) {
rc = req.emr_rc;
/* Fill out fields in enp->en_port and enp->en_nic_cfg from MCDI */
if ((rc = efx_mcdi_get_phy_cfg(enp)) != 0)
goto fail1;
}
if (req.emr_out_length_used < MC_CMD_GET_PHY_CFG_OUT_LEN) {
rc = EMSGSIZE;
goto fail2;
}
encp->enc_phy_type = MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_TYPE);
#if EFSYS_OPT_NAMES
(void) strncpy(encp->enc_phy_name,
MCDI_OUT2(req, char, GET_PHY_CFG_OUT_NAME),
MIN(sizeof (encp->enc_phy_name) - 1,
MC_CMD_GET_PHY_CFG_OUT_NAME_LEN));
#endif /* EFSYS_OPT_NAMES */
(void) memset(encp->enc_phy_revision, 0,
sizeof (encp->enc_phy_revision));
memcpy(encp->enc_phy_revision,
MCDI_OUT2(req, char, GET_PHY_CFG_OUT_REVISION),
MIN(sizeof (encp->enc_phy_revision) - 1,
MC_CMD_GET_PHY_CFG_OUT_REVISION_LEN));
#if EFSYS_OPT_PHY_LED_CONTROL
encp->enc_led_mask = ((1 << EFX_PHY_LED_DEFAULT) |
(1 << EFX_PHY_LED_OFF) |
(1 << EFX_PHY_LED_ON));
#endif /* EFSYS_OPT_PHY_LED_CONTROL */
#if EFSYS_OPT_PHY_PROPS
encp->enc_phy_nprops = 0;
#endif /* EFSYS_OPT_PHY_PROPS */
/* Get the media type of the fixed port, if recognised. */
EFX_STATIC_ASSERT(MC_CMD_MEDIA_XAUI == EFX_PHY_MEDIA_XAUI);
EFX_STATIC_ASSERT(MC_CMD_MEDIA_CX4 == EFX_PHY_MEDIA_CX4);
EFX_STATIC_ASSERT(MC_CMD_MEDIA_KX4 == EFX_PHY_MEDIA_KX4);
EFX_STATIC_ASSERT(MC_CMD_MEDIA_XFP == EFX_PHY_MEDIA_XFP);
EFX_STATIC_ASSERT(MC_CMD_MEDIA_SFP_PLUS == EFX_PHY_MEDIA_SFP_PLUS);
EFX_STATIC_ASSERT(MC_CMD_MEDIA_BASE_T == EFX_PHY_MEDIA_BASE_T);
epp->ep_fixed_port_type =
MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_MEDIA_TYPE);
if (epp->ep_fixed_port_type >= EFX_PHY_MEDIA_NTYPES)
epp->ep_fixed_port_type = EFX_PHY_MEDIA_INVALID;
epp->ep_phy_cap_mask =
MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_SUPPORTED_CAP);
#if EFSYS_OPT_PHY_FLAGS
encp->enc_phy_flags_mask = MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_FLAGS);
#endif /* EFSYS_OPT_PHY_FLAGS */
encp->enc_port = (uint8_t)MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_PRT);
/* Populate internal state */
encp->enc_siena_channel =
(uint8_t)MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_CHANNEL);
#if EFSYS_OPT_PHY_STATS
encp->enc_siena_phy_stat_mask =
MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_STATS_MASK);
/* Convert the MCDI statistic mask into the EFX_PHY_STAT mask */
siena_phy_decode_stats(enp, encp->enc_siena_phy_stat_mask,
siena_phy_decode_stats(enp, encp->enc_mcdi_phy_stat_mask,
NULL, &encp->enc_phy_stat_mask, NULL);
#endif /* EFSYS_OPT_PHY_STATS */
#if EFSYS_OPT_PHY_BIST
encp->enc_bist_mask = 0;
if (MCDI_OUT_DWORD_FIELD(req, GET_PHY_CFG_OUT_FLAGS,
GET_PHY_CFG_OUT_BIST_CABLE_SHORT))
encp->enc_bist_mask |= (1 << EFX_PHY_BIST_TYPE_CABLE_SHORT);
if (MCDI_OUT_DWORD_FIELD(req, GET_PHY_CFG_OUT_FLAGS,
GET_PHY_CFG_OUT_BIST_CABLE_LONG))
encp->enc_bist_mask |= (1 << EFX_PHY_BIST_TYPE_CABLE_LONG);
if (MCDI_OUT_DWORD_FIELD(req, GET_PHY_CFG_OUT_FLAGS,
GET_PHY_CFG_OUT_BIST))
encp->enc_bist_mask |= (1 << EFX_PHY_BIST_TYPE_NORMAL);
#endif /* EFSYS_OPT_PHY_BIST */
return (0);
fail2:
EFSYS_PROBE(fail2);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
#if EFSYS_OPT_LOOPBACK
static __checkReturn int
siena_loopback_cfg(
__in efx_nic_t *enp)
{
efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
efx_mcdi_req_t req;
uint8_t outbuf[MC_CMD_GET_LOOPBACK_MODES_OUT_LEN];
int rc;
req.emr_cmd = MC_CMD_GET_LOOPBACK_MODES;
EFX_STATIC_ASSERT(MC_CMD_GET_LOOPBACK_MODES_IN_LEN == 0);
req.emr_in_buf = NULL;
req.emr_in_length = 0;
req.emr_out_buf = outbuf;
req.emr_out_length = sizeof (outbuf);
efx_mcdi_execute(enp, &req);
if (req.emr_rc != 0) {
rc = req.emr_rc;
goto fail1;
}
if (req.emr_out_length_used < MC_CMD_GET_LOOPBACK_MODES_OUT_LEN) {
rc = EMSGSIZE;
goto fail2;
}
/*
* We assert the MC_CMD_LOOPBACK and EFX_LOOPBACK namespaces agree
* in siena_phy.c:siena_phy_get_link()
*/
encp->enc_loopback_types[EFX_LINK_100FDX] = EFX_LOOPBACK_MASK &
MCDI_OUT_DWORD(req, GET_LOOPBACK_MODES_OUT_100M) &
MCDI_OUT_DWORD(req, GET_LOOPBACK_MODES_OUT_SUGGESTED);
encp->enc_loopback_types[EFX_LINK_1000FDX] = EFX_LOOPBACK_MASK &
MCDI_OUT_DWORD(req, GET_LOOPBACK_MODES_OUT_1G) &
MCDI_OUT_DWORD(req, GET_LOOPBACK_MODES_OUT_SUGGESTED);
encp->enc_loopback_types[EFX_LINK_10000FDX] = EFX_LOOPBACK_MASK &
MCDI_OUT_DWORD(req, GET_LOOPBACK_MODES_OUT_10G) &
MCDI_OUT_DWORD(req, GET_LOOPBACK_MODES_OUT_SUGGESTED);
encp->enc_loopback_types[EFX_LINK_UNKNOWN] =
(1 << EFX_LOOPBACK_OFF) |
encp->enc_loopback_types[EFX_LINK_100FDX] |
encp->enc_loopback_types[EFX_LINK_1000FDX] |
encp->enc_loopback_types[EFX_LINK_10000FDX];
return (0);
fail2:
EFSYS_PROBE(fail2);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
#endif /* EFSYS_OPT_LOOPBACK */
#if EFSYS_OPT_MON_STATS
static __checkReturn int
siena_monitor_cfg(
__in efx_nic_t *enp)
{
efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
efx_mcdi_req_t req;
uint8_t outbuf[MCDI_CTL_SDU_LEN_MAX];
int rc;
req.emr_cmd = MC_CMD_SENSOR_INFO;
EFX_STATIC_ASSERT(MC_CMD_SENSOR_INFO_IN_LEN == 0);
req.emr_in_buf = NULL;
req.emr_in_length = 0;
req.emr_out_buf = outbuf;
req.emr_out_length = sizeof (outbuf);
efx_mcdi_execute(enp, &req);
if (req.emr_rc != 0) {
rc = req.emr_rc;
goto fail1;
}
if (req.emr_out_length_used < MC_CMD_SENSOR_INFO_OUT_MASK_OFST + 4) {
rc = EMSGSIZE;
goto fail2;
}
encp->enc_siena_mon_stat_mask =
MCDI_OUT_DWORD(req, SENSOR_INFO_OUT_MASK);
encp->enc_mon_type = EFX_MON_SFC90X0;
siena_mon_decode_stats(enp, encp->enc_siena_mon_stat_mask,
NULL, &(encp->enc_mon_stat_mask), NULL);
return (0);
fail2:
EFSYS_PROBE(fail2);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
#endif /* EFSYS_OPT_MON_STATS */
__checkReturn int
siena_nic_probe(
__in efx_nic_t *enp)
@ -610,78 +214,93 @@ siena_nic_probe(
efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
siena_link_state_t sls;
unsigned int mask;
efx_oword_t oword;
int rc;
EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_SIENA);
/* Read clear any assertion state */
if ((rc = siena_nic_read_assertion(enp)) != 0)
/* Test BIU */
if ((rc = efx_nic_biu_test(enp)) != 0)
goto fail1;
/* Exit the assertion handler */
if ((rc = siena_nic_exit_assertion_handler(enp)) != 0)
/* Clear the region register */
EFX_POPULATE_OWORD_4(oword,
FRF_AZ_ADR_REGION0, 0,
FRF_AZ_ADR_REGION1, (1 << 16),
FRF_AZ_ADR_REGION2, (2 << 16),
FRF_AZ_ADR_REGION3, (3 << 16));
EFX_BAR_WRITEO(enp, FR_AZ_ADR_REGION_REG, &oword);
/* Read clear any assertion state */
if ((rc = efx_mcdi_read_assertion(enp)) != 0)
goto fail2;
/* Wrestle control from the BMC */
if ((rc = siena_nic_attach(enp, B_TRUE)) != 0)
/* Exit the assertion handler */
if ((rc = efx_mcdi_exit_assertion_handler(enp)) != 0)
goto fail3;
if ((rc = siena_board_cfg(enp)) != 0)
/* Wrestle control from the BMC */
if ((rc = efx_mcdi_drv_attach(enp, B_TRUE)) != 0)
goto fail4;
if ((rc = siena_phy_cfg(enp)) != 0)
if ((rc = siena_board_cfg(enp)) != 0)
goto fail5;
if ((rc = siena_phy_cfg(enp)) != 0)
goto fail6;
/* Obtain the default PHY advertised capabilities */
if ((rc = siena_nic_reset(enp)) != 0)
goto fail6;
if ((rc = siena_phy_get_link(enp, &sls)) != 0)
goto fail7;
if ((rc = siena_phy_get_link(enp, &sls)) != 0)
goto fail8;
epp->ep_default_adv_cap_mask = sls.sls_adv_cap_mask;
epp->ep_adv_cap_mask = sls.sls_adv_cap_mask;
#if EFSYS_OPT_VPD || EFSYS_OPT_NVRAM
if ((rc = siena_nic_get_partn_mask(enp, &mask)) != 0)
goto fail8;
goto fail9;
enp->en_u.siena.enu_partn_mask = mask;
#endif
#if EFSYS_OPT_MAC_STATS
/* Wipe the MAC statistics */
if ((rc = siena_mac_stats_clear(enp)) != 0)
goto fail9;
#endif
#if EFSYS_OPT_LOOPBACK
if ((rc = siena_loopback_cfg(enp)) != 0)
if ((rc = efx_mcdi_mac_stats_clear(enp)) != 0)
goto fail10;
#endif
#if EFSYS_OPT_MON_STATS
if ((rc = siena_monitor_cfg(enp)) != 0)
#if EFSYS_OPT_LOOPBACK
if ((rc = efx_mcdi_get_loopback_modes(enp)) != 0)
goto fail11;
#endif
#if EFSYS_OPT_MON_STATS
if ((rc = mcdi_mon_cfg_build(enp)) != 0)
goto fail12;
#endif
encp->enc_features = enp->en_features;
return (0);
#if EFSYS_OPT_MON_STATS
fail12:
EFSYS_PROBE(fail12);
#endif
#if EFSYS_OPT_LOOPBACK
fail11:
EFSYS_PROBE(fail11);
#endif
#if EFSYS_OPT_LOOPBACK
#if EFSYS_OPT_MAC_STATS
fail10:
EFSYS_PROBE(fail10);
#endif
#if EFSYS_OPT_MAC_STATS
#if EFSYS_OPT_VPD || EFSYS_OPT_NVRAM
fail9:
EFSYS_PROBE(fail9);
#endif
#if EFSYS_OPT_VPD || EFSYS_OPT_NVRAM
fail8:
EFSYS_PROBE(fail8);
#endif
fail7:
EFSYS_PROBE(fail7);
fail6:
@ -710,16 +329,20 @@ siena_nic_reset(
EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_SIENA);
/* siena_nic_reset() is called to recover from BADASSERT failures. */
if ((rc = siena_nic_read_assertion(enp)) != 0)
if ((rc = efx_mcdi_read_assertion(enp)) != 0)
goto fail1;
if ((rc = siena_nic_exit_assertion_handler(enp)) != 0)
if ((rc = efx_mcdi_exit_assertion_handler(enp)) != 0)
goto fail2;
req.emr_cmd = MC_CMD_PORT_RESET;
EFX_STATIC_ASSERT(MC_CMD_PORT_RESET_IN_LEN == 0);
/*
* Bug24908: ENTITY_RESET_IN_LEN is non zero but zero may be supplied
* for backwards compatibility with PORT_RESET_IN_LEN.
*/
EFX_STATIC_ASSERT(MC_CMD_ENTITY_RESET_OUT_LEN == 0);
req.emr_cmd = MC_CMD_ENTITY_RESET;
req.emr_in_buf = NULL;
req.emr_in_length = 0;
EFX_STATIC_ASSERT(MC_CMD_PORT_RESET_OUT_LEN == 0);
req.emr_out_buf = NULL;
req.emr_out_length = 0;
@ -742,40 +365,6 @@ siena_nic_reset(
return (0);
}
static __checkReturn int
siena_nic_logging(
__in efx_nic_t *enp)
{
efx_mcdi_req_t req;
uint8_t payload[MC_CMD_LOG_CTRL_IN_LEN];
int rc;
req.emr_cmd = MC_CMD_LOG_CTRL;
req.emr_in_buf = payload;
req.emr_in_length = MC_CMD_LOG_CTRL_IN_LEN;
EFX_STATIC_ASSERT(MC_CMD_LOG_CTRL_OUT_LEN == 0);
req.emr_out_buf = NULL;
req.emr_out_length = 0;
MCDI_IN_SET_DWORD(req, LOG_CTRL_IN_LOG_DEST,
MC_CMD_LOG_CTRL_IN_LOG_DEST_EVQ);
MCDI_IN_SET_DWORD(req, LOG_CTRL_IN_LOG_DEST_EVQ, 0);
efx_mcdi_execute(enp, &req);
if (req.emr_rc != 0) {
rc = req.emr_rc;
goto fail1;
}
return (0);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
static void
siena_nic_rx_cfg(
__in efx_nic_t *enp)
@ -814,7 +403,8 @@ siena_nic_init(
EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_SIENA);
if ((rc = siena_nic_logging(enp)) != 0)
/* Enable reporting of some events (e.g. link change) */
if ((rc = efx_mcdi_log_ctrl(enp)) != 0)
goto fail1;
siena_sram_init(enp);
@ -850,12 +440,15 @@ siena_nic_fini(
siena_nic_unprobe(
__in efx_nic_t *enp)
{
(void) siena_nic_attach(enp, B_FALSE);
#if EFSYS_OPT_MON_STATS
mcdi_mon_cfg_free(enp);
#endif /* EFSYS_OPT_MON_STATS */
(void) efx_mcdi_drv_attach(enp, B_FALSE);
}
#if EFSYS_OPT_DIAG
static efx_register_set_t __cs __siena_registers[] = {
static efx_register_set_t __siena_registers[] = {
{ FR_AZ_ADR_REGION_REG_OFST, 0, 1 },
{ FR_CZ_USR_EV_CFG_OFST, 0, 1 },
{ FR_AZ_RX_CFG_REG_OFST, 0, 1 },
@ -871,7 +464,7 @@ static efx_register_set_t __cs __siena_registers[] = {
{ FR_CZ_RX_RSS_IPV6_REG3_OFST, 0, 1}
};
static const uint32_t __cs __siena_register_masks[] = {
static const uint32_t __siena_register_masks[] = {
0x0003FFFF, 0x0003FFFF, 0x0003FFFF, 0x0003FFFF,
0x000103FF, 0x00000000, 0x00000000, 0x00000000,
0xFFFFFFFE, 0xFFFFFFFF, 0x0003FFFF, 0x00000000,
@ -887,7 +480,7 @@ static const uint32_t __cs __siena_register_masks[] = {
0xFFFFFFFF, 0xFFFFFFFF, 0x00000007, 0x00000000
};
static efx_register_set_t __cs __siena_tables[] = {
static efx_register_set_t __siena_tables[] = {
{ FR_AZ_RX_FILTER_TBL0_OFST, FR_AZ_RX_FILTER_TBL0_STEP,
FR_AZ_RX_FILTER_TBL0_ROWS },
{ FR_CZ_RX_MAC_FILTER_TBL0_OFST, FR_CZ_RX_MAC_FILTER_TBL0_STEP,
@ -903,7 +496,7 @@ static efx_register_set_t __cs __siena_tables[] = {
FR_CZ_TX_MAC_FILTER_TBL0_STEP, FR_CZ_TX_MAC_FILTER_TBL0_ROWS }
};
static const uint32_t __cs __siena_table_masks[] = {
static const uint32_t __siena_table_masks[] = {
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x000003FF,
0xFFFF0FFF, 0xFFFFFFFF, 0x00000E7F, 0x00000000,
0xFFFFFFFE, 0x0FFFFFFF, 0x01800000, 0x00000000,

View File

@ -1,26 +1,31 @@
/*-
* Copyright 2009 Solarflare Communications Inc. All rights reserved.
* Copyright (c) 2009-2015 Solarflare Communications Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* modification, are permitted provided that the following conditions are met:
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the FreeBSD Project.
*/
#include <sys/cdefs.h>
@ -42,9 +47,6 @@ siena_nvram_partn_size(
__in unsigned int partn,
__out size_t *sizep)
{
efx_mcdi_req_t req;
uint8_t payload[MAX(MC_CMD_NVRAM_INFO_IN_LEN,
MC_CMD_NVRAM_INFO_OUT_LEN)];
int rc;
if ((1 << partn) & ~enp->en_u.siena.enu_partn_mask) {
@ -52,32 +54,12 @@ siena_nvram_partn_size(
goto fail1;
}
req.emr_cmd = MC_CMD_NVRAM_INFO;
req.emr_in_buf = payload;
req.emr_in_length = MC_CMD_NVRAM_INFO_IN_LEN;
req.emr_out_buf = payload;
req.emr_out_length = MC_CMD_NVRAM_INFO_OUT_LEN;
MCDI_IN_SET_DWORD(req, NVRAM_INFO_IN_TYPE, partn);
efx_mcdi_execute(enp, &req);
if (req.emr_rc != 0) {
rc = req.emr_rc;
if ((rc = efx_mcdi_nvram_info(enp, partn, sizep, NULL, NULL)) != 0) {
goto fail2;
}
if (req.emr_out_length_used < MC_CMD_NVRAM_INFO_OUT_LEN) {
rc = EMSGSIZE;
goto fail3;
}
*sizep = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_SIZE);
return (0);
fail3:
EFSYS_PROBE(fail3);
fail2:
EFSYS_PROBE(fail2);
fail1:
@ -91,23 +73,9 @@ siena_nvram_partn_lock(
__in efx_nic_t *enp,
__in unsigned int partn)
{
efx_mcdi_req_t req;
uint8_t payload[MC_CMD_NVRAM_UPDATE_START_IN_LEN];
int rc;
req.emr_cmd = MC_CMD_NVRAM_UPDATE_START;
req.emr_in_buf = payload;
req.emr_in_length = MC_CMD_NVRAM_UPDATE_START_IN_LEN;
EFX_STATIC_ASSERT(MC_CMD_NVRAM_UPDATE_START_OUT_LEN == 0);
req.emr_out_buf = NULL;
req.emr_out_length = 0;
MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_START_IN_TYPE, partn);
efx_mcdi_execute(enp, &req);
if (req.emr_rc != 0) {
rc = req.emr_rc;
if ((rc = efx_mcdi_nvram_update_start(enp, partn)) != 0) {
goto fail1;
}
@ -127,43 +95,17 @@ siena_nvram_partn_read(
__out_bcount(size) caddr_t data,
__in size_t size)
{
efx_mcdi_req_t req;
uint8_t payload[MAX(MC_CMD_NVRAM_READ_IN_LEN,
MC_CMD_NVRAM_READ_OUT_LEN(SIENA_NVRAM_CHUNK))];
size_t chunk;
int rc;
while (size > 0) {
chunk = MIN(size, SIENA_NVRAM_CHUNK);
req.emr_cmd = MC_CMD_NVRAM_READ;
req.emr_in_buf = payload;
req.emr_in_length = MC_CMD_NVRAM_READ_IN_LEN;
req.emr_out_buf = payload;
req.emr_out_length =
MC_CMD_NVRAM_READ_OUT_LEN(SIENA_NVRAM_CHUNK);
MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_TYPE, partn);
MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_OFFSET, offset);
MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_LENGTH, chunk);
efx_mcdi_execute(enp, &req);
if (req.emr_rc != 0) {
rc = req.emr_rc;
if ((rc = efx_mcdi_nvram_read(enp, partn, offset,
data, chunk)) != 0) {
goto fail1;
}
if (req.emr_out_length_used <
MC_CMD_NVRAM_READ_OUT_LEN(chunk)) {
rc = EMSGSIZE;
goto fail2;
}
memcpy(data,
MCDI_OUT2(req, uint8_t, NVRAM_READ_OUT_READ_BUFFER),
chunk);
size -= chunk;
data += chunk;
offset += chunk;
@ -171,8 +113,6 @@ siena_nvram_partn_read(
return (0);
fail2:
EFSYS_PROBE(fail2);
fail1:
EFSYS_PROBE1(fail1, int, rc);
@ -186,25 +126,9 @@ siena_nvram_partn_erase(
__in unsigned int offset,
__in size_t size)
{
efx_mcdi_req_t req;
uint8_t payload[MC_CMD_NVRAM_ERASE_IN_LEN];
int rc;
req.emr_cmd = MC_CMD_NVRAM_ERASE;
req.emr_in_buf = payload;
req.emr_in_length = MC_CMD_NVRAM_ERASE_IN_LEN;
EFX_STATIC_ASSERT(MC_CMD_NVRAM_ERASE_OUT_LEN == 0);
req.emr_out_buf = NULL;
req.emr_out_length = 0;
MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_TYPE, partn);
MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_OFFSET, offset);
MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_LENGTH, size);
efx_mcdi_execute(enp, &req);
if (req.emr_rc != 0) {
rc = req.emr_rc;
if ((rc = efx_mcdi_nvram_erase(enp, partn, offset, size)) != 0) {
goto fail1;
}
@ -224,32 +148,14 @@ siena_nvram_partn_write(
__out_bcount(size) caddr_t data,
__in size_t size)
{
efx_mcdi_req_t req;
uint8_t payload[MC_CMD_NVRAM_WRITE_IN_LEN(SIENA_NVRAM_CHUNK)];
size_t chunk;
int rc;
while (size > 0) {
chunk = MIN(size, SIENA_NVRAM_CHUNK);
req.emr_cmd = MC_CMD_NVRAM_WRITE;
req.emr_in_buf = payload;
req.emr_in_length = MC_CMD_NVRAM_WRITE_IN_LEN(chunk);
EFX_STATIC_ASSERT(MC_CMD_NVRAM_WRITE_OUT_LEN == 0);
req.emr_out_buf = NULL;
req.emr_out_length = 0;
MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_TYPE, partn);
MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_OFFSET, offset);
MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_LENGTH, chunk);
memcpy(MCDI_IN2(req, uint8_t, NVRAM_WRITE_IN_WRITE_BUFFER),
data, chunk);
efx_mcdi_execute(enp, &req);
if (req.emr_rc != 0) {
rc = req.emr_rc;
if ((rc = efx_mcdi_nvram_write(enp, partn, offset,
data, chunk)) != 0) {
goto fail1;
}
@ -271,18 +177,9 @@ siena_nvram_partn_unlock(
__in efx_nic_t *enp,
__in unsigned int partn)
{
efx_mcdi_req_t req;
uint8_t payload[MC_CMD_NVRAM_UPDATE_FINISH_IN_LEN];
uint32_t reboot;
boolean_t reboot;
int rc;
req.emr_cmd = MC_CMD_NVRAM_UPDATE_FINISH;
req.emr_in_buf = payload;
req.emr_in_length = MC_CMD_NVRAM_UPDATE_FINISH_IN_LEN;
EFX_STATIC_ASSERT(MC_CMD_NVRAM_UPDATE_FINISH_OUT_LEN == 0);
req.emr_out_buf = NULL;
req.emr_out_length = 0;
/*
* Reboot into the new image only for PHYs. The driver has to
* explicitly cope with an MC reboot after a firmware update.
@ -291,13 +188,7 @@ siena_nvram_partn_unlock(
partn == MC_CMD_NVRAM_TYPE_PHY_PORT1 ||
partn == MC_CMD_NVRAM_TYPE_DISABLED_CALLISTO);
MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_FINISH_IN_TYPE, partn);
MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_FINISH_IN_REBOOT, reboot);
efx_mcdi_execute(enp, &req);
if (req.emr_rc != 0) {
rc = req.emr_rc;
if ((rc = efx_mcdi_nvram_update_finish(enp, partn, reboot)) != 0) {
goto fail1;
}
@ -338,7 +229,6 @@ static siena_parttbl_entry_t siena_parttbl[] = {
{MC_CMD_NVRAM_TYPE_FC_FW, 2, EFX_NVRAM_FCFW},
{MC_CMD_NVRAM_TYPE_CPLD, 1, EFX_NVRAM_CPLD},
{MC_CMD_NVRAM_TYPE_CPLD, 2, EFX_NVRAM_CPLD},
{0, 0, 0},
};
static __checkReturn siena_parttbl_entry_t *
@ -346,12 +236,15 @@ siena_parttbl_entry(
__in efx_nic_t *enp,
__in efx_nvram_type_t type)
{
efx_mcdi_iface_t *emip = &(enp->en_u.siena.enu_mip);
efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
siena_parttbl_entry_t *entry;
unsigned int i;
EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
for (entry = siena_parttbl; entry->port > 0; ++entry) {
for (i = 0; i < EFX_ARRAY_SIZE(siena_parttbl); i++) {
entry = &siena_parttbl[i];
if (entry->port == emip->emi_port && entry->nvtype == type)
return (entry);
}
@ -365,59 +258,29 @@ siena_parttbl_entry(
siena_nvram_test(
__in efx_nic_t *enp)
{
efx_mcdi_iface_t *emip = &(enp->en_u.siena.enu_mip);
efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
siena_parttbl_entry_t *entry;
efx_mcdi_req_t req;
uint8_t payload[MAX(MC_CMD_NVRAM_TEST_IN_LEN,
MC_CMD_NVRAM_TEST_OUT_LEN)];
int result;
unsigned int i;
int rc;
req.emr_cmd = MC_CMD_NVRAM_TEST;
req.emr_in_buf = payload;
req.emr_in_length = MC_CMD_NVRAM_TEST_IN_LEN;
req.emr_out_buf = payload;
req.emr_out_length = MC_CMD_NVRAM_TEST_OUT_LEN;
/*
* Iterate over the list of supported partition types
* applicable to *this* port
*/
for (entry = siena_parttbl; entry->port > 0; ++entry) {
for (i = 0; i < EFX_ARRAY_SIZE(siena_parttbl); i++) {
entry = &siena_parttbl[i];
if (entry->port != emip->emi_port ||
!(enp->en_u.siena.enu_partn_mask & (1 << entry->partn)))
continue;
MCDI_IN_SET_DWORD(req, NVRAM_TEST_IN_TYPE, entry->partn);
efx_mcdi_execute(enp, &req);
if (req.emr_rc != 0) {
rc = req.emr_rc;
if ((rc = efx_mcdi_nvram_test(enp, entry->partn)) != 0) {
goto fail1;
}
if (req.emr_out_length_used < MC_CMD_NVRAM_TEST_OUT_LEN) {
rc = EMSGSIZE;
goto fail2;
}
result = MCDI_OUT_DWORD(req, NVRAM_TEST_OUT_RESULT);
if (result == MC_CMD_NVRAM_TEST_FAIL) {
EFSYS_PROBE1(nvram_test_failure, int, entry->partn);
rc = (EINVAL);
goto fail3;
}
}
return (0);
fail3:
EFSYS_PROBE(fail3);
fail2:
EFSYS_PROBE(fail2);
fail1:
EFSYS_PROBE1(fail1, int, rc);
@ -467,7 +330,7 @@ siena_nvram_get_dynamic_cfg(
__out siena_mc_dynamic_config_hdr_t **dcfgp,
__out size_t *sizep)
{
siena_mc_dynamic_config_hdr_t *dcfg;
siena_mc_dynamic_config_hdr_t *dcfg = NULL;
size_t size;
uint8_t cksum;
unsigned int vpd_offset;
@ -577,34 +440,35 @@ siena_nvram_get_dynamic_cfg(
EFSYS_PROBE(fail4);
fail3:
EFSYS_PROBE(fail3);
fail2:
EFSYS_PROBE(fail2);
EFSYS_KMEM_FREE(enp->en_esip, size, dcfg);
fail2:
EFSYS_PROBE(fail2);
fail1:
EFSYS_PROBE1(fail1, int, rc);
return (rc);
}
static __checkReturn int
__checkReturn int
siena_nvram_get_subtype(
__in efx_nic_t *enp,
__in unsigned int partn,
__out uint32_t *subtypep)
{
efx_mcdi_req_t req;
uint8_t outbuf[MC_CMD_GET_BOARD_CFG_OUT_LENMAX];
uint8_t payload[MAX(MC_CMD_GET_BOARD_CFG_IN_LEN,
MC_CMD_GET_BOARD_CFG_OUT_LENMAX)];
efx_word_t *fw_list;
int rc;
(void) memset(payload, 0, sizeof (payload));
req.emr_cmd = MC_CMD_GET_BOARD_CFG;
EFX_STATIC_ASSERT(MC_CMD_GET_BOARD_CFG_IN_LEN == 0);
req.emr_in_buf = NULL;
req.emr_in_length = 0;
req.emr_out_buf = outbuf;
req.emr_out_length = sizeof (outbuf);
req.emr_in_buf = payload;
req.emr_in_length = MC_CMD_GET_BOARD_CFG_IN_LEN;
req.emr_out_buf = payload;
req.emr_out_length = MC_CMD_GET_BOARD_CFG_OUT_LENMAX;
efx_mcdi_execute(enp, &req);
@ -652,6 +516,7 @@ siena_nvram_get_version(
siena_parttbl_entry_t *entry;
unsigned int dcfg_partn;
unsigned int partn;
unsigned int i;
int rc;
if ((entry = siena_parttbl_entry(enp, type)) == NULL) {
@ -674,11 +539,12 @@ siena_nvram_get_version(
* that have access to this partition.
*/
version[0] = version[1] = version[2] = version[3] = 0;
for (entry = siena_parttbl; entry->port > 0; ++entry) {
for (i = 0; i < EFX_ARRAY_SIZE(siena_parttbl); i++) {
unsigned int nitems;
uint16_t temp[4];
size_t length;
entry = &siena_parttbl[i];
if (entry->partn != partn)
continue;
@ -869,7 +735,7 @@ siena_nvram_rw_finish(
siena_nvram_set_version(
__in efx_nic_t *enp,
__in efx_nvram_type_t type,
__out uint16_t version[4])
__in_ecount(4) uint16_t version[4])
{
siena_mc_dynamic_config_hdr_t *dcfg = NULL;
siena_parttbl_entry_t *entry;

View File

@ -1,26 +1,31 @@
/*-
* Copyright 2009 Solarflare Communications Inc. All rights reserved.
* Copyright (c) 2009-2015 Solarflare Communications Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* modification, are permitted provided that the following conditions are met:
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the FreeBSD Project.
*/
#include <sys/cdefs.h>
@ -192,15 +197,16 @@ siena_phy_get_link(
__out siena_link_state_t *slsp)
{
efx_mcdi_req_t req;
uint8_t outbuf[MC_CMD_GET_LINK_OUT_LEN];
uint8_t payload[MAX(MC_CMD_GET_LINK_IN_LEN,
MC_CMD_GET_LINK_OUT_LEN)];
int rc;
(void) memset(payload, 0, sizeof (payload));
req.emr_cmd = MC_CMD_GET_LINK;
EFX_STATIC_ASSERT(MC_CMD_GET_LINK_IN_LEN == 0);
req.emr_in_buf = NULL;
req.emr_in_length = 0;
req.emr_out_buf = outbuf;
req.emr_out_length = sizeof (outbuf);
req.emr_in_buf = payload;
req.emr_in_length = MC_CMD_GET_LINK_IN_LEN;
req.emr_out_buf = payload;
req.emr_out_length = MC_CMD_GET_LINK_OUT_LEN;
efx_mcdi_execute(enp, &req);
@ -266,19 +272,21 @@ siena_phy_reconfigure(
{
efx_port_t *epp = &(enp->en_port);
efx_mcdi_req_t req;
uint8_t payload[MAX(MC_CMD_SET_ID_LED_IN_LEN,
MC_CMD_SET_LINK_IN_LEN)];
uint8_t payload[MAX(MAX(MC_CMD_SET_ID_LED_IN_LEN,
MC_CMD_SET_ID_LED_OUT_LEN),
MAX(MC_CMD_SET_LINK_IN_LEN,
MC_CMD_SET_LINK_OUT_LEN))];
uint32_t cap_mask;
unsigned int led_mode;
unsigned int speed;
int rc;
(void) memset(payload, 0, sizeof (payload));
req.emr_cmd = MC_CMD_SET_LINK;
req.emr_in_buf = payload;
req.emr_in_length = MC_CMD_SET_LINK_IN_LEN;
EFX_STATIC_ASSERT(MC_CMD_SET_LINK_OUT_LEN == 0);
req.emr_out_buf = NULL;
req.emr_out_length = 0;
req.emr_out_buf = payload;
req.emr_out_length = MC_CMD_SET_LINK_OUT_LEN;
cap_mask = epp->ep_adv_cap_mask;
MCDI_IN_POPULATE_DWORD_10(req, SET_LINK_IN_CAP,
@ -329,12 +337,12 @@ siena_phy_reconfigure(
}
/* And set the blink mode */
(void) memset(payload, 0, sizeof (payload));
req.emr_cmd = MC_CMD_SET_ID_LED;
req.emr_in_buf = payload;
req.emr_in_length = MC_CMD_SET_ID_LED_IN_LEN;
EFX_STATIC_ASSERT(MC_CMD_SET_ID_LED_OUT_LEN == 0);
req.emr_out_buf = NULL;
req.emr_out_length = 0;
req.emr_out_buf = payload;
req.emr_out_length = MC_CMD_SET_ID_LED_OUT_LEN;
#if EFSYS_OPT_PHY_LED_CONTROL
switch (epp->ep_phy_led_mode) {
@ -379,16 +387,17 @@ siena_phy_verify(
__in efx_nic_t *enp)
{
efx_mcdi_req_t req;
uint8_t outbuf[MC_CMD_GET_PHY_STATE_OUT_LEN];
uint8_t payload[MAX(MC_CMD_GET_PHY_STATE_IN_LEN,
MC_CMD_GET_PHY_STATE_OUT_LEN)];
uint32_t state;
int rc;
(void) memset(payload, 0, sizeof (payload));
req.emr_cmd = MC_CMD_GET_PHY_STATE;
EFX_STATIC_ASSERT(MC_CMD_GET_PHY_STATE_IN_LEN == 0);
req.emr_in_buf = NULL;
req.emr_in_length = 0;
req.emr_out_buf = outbuf;
req.emr_out_length = sizeof (outbuf);
req.emr_in_buf = payload;
req.emr_in_length = MC_CMD_GET_PHY_STATE_IN_LEN;
req.emr_out_buf = payload;
req.emr_out_length = MC_CMD_GET_PHY_STATE_OUT_LEN;
efx_mcdi_execute(enp, &req);
@ -544,18 +553,19 @@ siena_phy_stats_update(
__out_ecount(EFX_PHY_NSTATS) uint32_t *stat)
{
efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
uint32_t vmask = encp->enc_siena_phy_stat_mask;
uint8_t payload[MC_CMD_PHY_STATS_IN_LEN];
uint32_t vmask = encp->enc_mcdi_phy_stat_mask;
uint64_t smask;
efx_mcdi_req_t req;
uint8_t payload[MAX(MC_CMD_PHY_STATS_IN_LEN,
MC_CMD_PHY_STATS_OUT_DMA_LEN)];
int rc;
(void) memset(payload, 0, sizeof (payload));
req.emr_cmd = MC_CMD_PHY_STATS;
req.emr_in_buf = payload;
req.emr_in_length = sizeof (payload);
EFX_STATIC_ASSERT(MC_CMD_PHY_STATS_OUT_DMA_LEN == 0);
req.emr_out_buf = NULL;
req.emr_out_length = 0;
req.emr_in_length = MC_CMD_PHY_STATS_IN_LEN;
req.emr_out_buf = payload;
req.emr_out_length = MC_CMD_PHY_STATS_OUT_DMA_LEN;
MCDI_IN_SET_DWORD(req, PHY_STATS_IN_DMA_ADDR_LO,
EFSYS_MEM_ADDR(esmp) & 0xffffffff);
@ -587,7 +597,7 @@ siena_phy_stats_update(
#if EFSYS_OPT_NAMES
extern const char __cs *
extern const char *
siena_phy_prop_name(
__in efx_nic_t *enp,
__in unsigned int id)
@ -624,46 +634,17 @@ siena_phy_prop_set(
#endif /* EFSYS_OPT_PHY_PROPS */
#if EFSYS_OPT_PHY_BIST
#if EFSYS_OPT_BIST
__checkReturn int
siena_phy_bist_start(
__in efx_nic_t *enp,
__in efx_phy_bist_type_t type)
__in efx_bist_type_t type)
{
uint8_t payload[MC_CMD_START_BIST_IN_LEN];
efx_mcdi_req_t req;
int rc;
req.emr_cmd = MC_CMD_START_BIST;
req.emr_in_buf = payload;
req.emr_in_length = sizeof (payload);
EFX_STATIC_ASSERT(MC_CMD_START_BIST_OUT_LEN == 0);
req.emr_out_buf = NULL;
req.emr_out_length = 0;
switch (type) {
case EFX_PHY_BIST_TYPE_NORMAL:
MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE, MC_CMD_PHY_BIST);
break;
case EFX_PHY_BIST_TYPE_CABLE_SHORT:
MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE,
MC_CMD_PHY_BIST_CABLE_SHORT);
break;
case EFX_PHY_BIST_TYPE_CABLE_LONG:
MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE,
MC_CMD_PHY_BIST_CABLE_LONG);
break;
default:
EFSYS_ASSERT(0);
}
efx_mcdi_execute(enp, &req);
if (req.emr_rc != 0) {
rc = req.emr_rc;
if ((rc = efx_mcdi_bist_start(enp, type)) != 0)
goto fail1;
}
return (0);
@ -696,8 +677,8 @@ siena_phy_sft9001_bist_status(
__checkReturn int
siena_phy_bist_poll(
__in efx_nic_t *enp,
__in efx_phy_bist_type_t type,
__out efx_phy_bist_result_t *resultp,
__in efx_bist_type_t type,
__out efx_bist_result_t *resultp,
__out_opt __drv_when(count > 0, __notnull)
uint32_t *value_maskp,
__out_ecount_opt(count) __drv_when(count > 0, __notnull)
@ -705,19 +686,19 @@ siena_phy_bist_poll(
__in size_t count)
{
efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
uint8_t payload[MCDI_CTL_SDU_LEN_MAX];
uint8_t payload[MAX(MC_CMD_POLL_BIST_IN_LEN,
MCDI_CTL_SDU_LEN_MAX)];
uint32_t value_mask = 0;
efx_mcdi_req_t req;
uint32_t result;
int rc;
(void) memset(payload, 0, sizeof (payload));
req.emr_cmd = MC_CMD_POLL_BIST;
_NOTE(CONSTANTCONDITION)
EFSYS_ASSERT(MC_CMD_POLL_BIST_IN_LEN == 0);
req.emr_in_buf = NULL;
req.emr_in_length = 0;
req.emr_in_buf = payload;
req.emr_in_length = MC_CMD_POLL_BIST_IN_LEN;
req.emr_out_buf = payload;
req.emr_out_length = sizeof (payload);
req.emr_out_length = MCDI_CTL_SDU_LEN_MAX;
efx_mcdi_execute(enp, &req);
@ -740,90 +721,90 @@ siena_phy_bist_poll(
if (result == MC_CMD_POLL_BIST_PASSED &&
encp->enc_phy_type == EFX_PHY_SFT9001B &&
req.emr_out_length_used >= MC_CMD_POLL_BIST_OUT_SFT9001_LEN &&
(type == EFX_PHY_BIST_TYPE_CABLE_SHORT ||
type == EFX_PHY_BIST_TYPE_CABLE_LONG)) {
(type == EFX_BIST_TYPE_PHY_CABLE_SHORT ||
type == EFX_BIST_TYPE_PHY_CABLE_LONG)) {
uint16_t word;
if (count > EFX_PHY_BIST_CABLE_LENGTH_A) {
if (count > EFX_BIST_PHY_CABLE_LENGTH_A) {
if (valuesp != NULL)
valuesp[EFX_PHY_BIST_CABLE_LENGTH_A] =
valuesp[EFX_BIST_PHY_CABLE_LENGTH_A] =
MCDI_OUT_DWORD(req,
POLL_BIST_OUT_SFT9001_CABLE_LENGTH_A);
value_mask |= (1 << EFX_PHY_BIST_CABLE_LENGTH_A);
value_mask |= (1 << EFX_BIST_PHY_CABLE_LENGTH_A);
}
if (count > EFX_PHY_BIST_CABLE_LENGTH_B) {
if (count > EFX_BIST_PHY_CABLE_LENGTH_B) {
if (valuesp != NULL)
valuesp[EFX_PHY_BIST_CABLE_LENGTH_B] =
valuesp[EFX_BIST_PHY_CABLE_LENGTH_B] =
MCDI_OUT_DWORD(req,
POLL_BIST_OUT_SFT9001_CABLE_LENGTH_B);
value_mask |= (1 << EFX_PHY_BIST_CABLE_LENGTH_B);
value_mask |= (1 << EFX_BIST_PHY_CABLE_LENGTH_B);
}
if (count > EFX_PHY_BIST_CABLE_LENGTH_C) {
if (count > EFX_BIST_PHY_CABLE_LENGTH_C) {
if (valuesp != NULL)
valuesp[EFX_PHY_BIST_CABLE_LENGTH_C] =
valuesp[EFX_BIST_PHY_CABLE_LENGTH_C] =
MCDI_OUT_DWORD(req,
POLL_BIST_OUT_SFT9001_CABLE_LENGTH_C);
value_mask |= (1 << EFX_PHY_BIST_CABLE_LENGTH_C);
value_mask |= (1 << EFX_BIST_PHY_CABLE_LENGTH_C);
}
if (count > EFX_PHY_BIST_CABLE_LENGTH_D) {
if (count > EFX_BIST_PHY_CABLE_LENGTH_D) {
if (valuesp != NULL)
valuesp[EFX_PHY_BIST_CABLE_LENGTH_D] =
valuesp[EFX_BIST_PHY_CABLE_LENGTH_D] =
MCDI_OUT_DWORD(req,
POLL_BIST_OUT_SFT9001_CABLE_LENGTH_D);
value_mask |= (1 << EFX_PHY_BIST_CABLE_LENGTH_D);
value_mask |= (1 << EFX_BIST_PHY_CABLE_LENGTH_D);
}
if (count > EFX_PHY_BIST_CABLE_STATUS_A) {
if (count > EFX_BIST_PHY_CABLE_STATUS_A) {
if (valuesp != NULL) {
word = MCDI_OUT_WORD(req,
POLL_BIST_OUT_SFT9001_CABLE_STATUS_A);
valuesp[EFX_PHY_BIST_CABLE_STATUS_A] =
valuesp[EFX_BIST_PHY_CABLE_STATUS_A] =
siena_phy_sft9001_bist_status(word);
}
value_mask |= (1 << EFX_PHY_BIST_CABLE_STATUS_A);
value_mask |= (1 << EFX_BIST_PHY_CABLE_STATUS_A);
}
if (count > EFX_PHY_BIST_CABLE_STATUS_B) {
if (count > EFX_BIST_PHY_CABLE_STATUS_B) {
if (valuesp != NULL) {
word = MCDI_OUT_WORD(req,
POLL_BIST_OUT_SFT9001_CABLE_STATUS_B);
valuesp[EFX_PHY_BIST_CABLE_STATUS_B] =
valuesp[EFX_BIST_PHY_CABLE_STATUS_B] =
siena_phy_sft9001_bist_status(word);
}
value_mask |= (1 << EFX_PHY_BIST_CABLE_STATUS_B);
value_mask |= (1 << EFX_BIST_PHY_CABLE_STATUS_B);
}
if (count > EFX_PHY_BIST_CABLE_STATUS_C) {
if (count > EFX_BIST_PHY_CABLE_STATUS_C) {
if (valuesp != NULL) {
word = MCDI_OUT_WORD(req,
POLL_BIST_OUT_SFT9001_CABLE_STATUS_C);
valuesp[EFX_PHY_BIST_CABLE_STATUS_C] =
valuesp[EFX_BIST_PHY_CABLE_STATUS_C] =
siena_phy_sft9001_bist_status(word);
}
value_mask |= (1 << EFX_PHY_BIST_CABLE_STATUS_C);
value_mask |= (1 << EFX_BIST_PHY_CABLE_STATUS_C);
}
if (count > EFX_PHY_BIST_CABLE_STATUS_D) {
if (count > EFX_BIST_PHY_CABLE_STATUS_D) {
if (valuesp != NULL) {
word = MCDI_OUT_WORD(req,
POLL_BIST_OUT_SFT9001_CABLE_STATUS_D);
valuesp[EFX_PHY_BIST_CABLE_STATUS_D] =
valuesp[EFX_BIST_PHY_CABLE_STATUS_D] =
siena_phy_sft9001_bist_status(word);
}
value_mask |= (1 << EFX_PHY_BIST_CABLE_STATUS_D);
value_mask |= (1 << EFX_BIST_PHY_CABLE_STATUS_D);
}
} else if (result == MC_CMD_POLL_BIST_FAILED &&
encp->enc_phy_type == EFX_PHY_QLX111V &&
req.emr_out_length >= MC_CMD_POLL_BIST_OUT_MRSFP_LEN &&
count > EFX_PHY_BIST_FAULT_CODE) {
count > EFX_BIST_FAULT_CODE) {
if (valuesp != NULL)
valuesp[EFX_PHY_BIST_FAULT_CODE] =
valuesp[EFX_BIST_FAULT_CODE] =
MCDI_OUT_DWORD(req, POLL_BIST_OUT_MRSFP_TEST);
value_mask |= 1 << EFX_PHY_BIST_FAULT_CODE;
value_mask |= 1 << EFX_BIST_FAULT_CODE;
}
if (value_maskp != NULL)
@ -831,11 +812,11 @@ siena_phy_bist_poll(
EFSYS_ASSERT(resultp != NULL);
if (result == MC_CMD_POLL_BIST_RUNNING)
*resultp = EFX_PHY_BIST_RESULT_RUNNING;
*resultp = EFX_BIST_RESULT_RUNNING;
else if (result == MC_CMD_POLL_BIST_PASSED)
*resultp = EFX_PHY_BIST_RESULT_PASSED;
*resultp = EFX_BIST_RESULT_PASSED;
else
*resultp = EFX_PHY_BIST_RESULT_FAILED;
*resultp = EFX_BIST_RESULT_FAILED;
return (0);
@ -850,12 +831,12 @@ siena_phy_bist_poll(
void
siena_phy_bist_stop(
__in efx_nic_t *enp,
__in efx_phy_bist_type_t type)
__in efx_bist_type_t type)
{
/* There is no way to stop BIST on Siena */
_NOTE(ARGUNUSED(enp, type))
}
#endif /* EFSYS_OPT_PHY_BIST */
#endif /* EFSYS_OPT_BIST */
#endif /* EFSYS_OPT_SIENA */

View File

@ -1,26 +1,31 @@
/*-
* Copyright 2009 Solarflare Communications Inc. All rights reserved.
* Copyright (c) 2009-2015 Solarflare Communications Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* modification, are permitted provided that the following conditions are met:
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the FreeBSD Project.
*/
#include <sys/cdefs.h>

View File

@ -1,26 +1,31 @@
/*-
* Copyright 2009 Solarflare Communications Inc. All rights reserved.
* Copyright (c) 2009-2015 Solarflare Communications Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* modification, are permitted provided that the following conditions are met:
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the FreeBSD Project.
*/
#include <sys/cdefs.h>
@ -141,11 +146,11 @@ siena_vpd_get_static(
EFSYS_PROBE(fail4);
fail3:
EFSYS_PROBE(fail3);
fail2:
EFSYS_PROBE(fail2);
EFSYS_KMEM_FREE(enp->en_esip, size, scfg);
fail2:
EFSYS_PROBE(fail2);
fail1:
EFSYS_PROBE1(fail1, int, rc);
@ -156,7 +161,7 @@ siena_vpd_get_static(
siena_vpd_init(
__in efx_nic_t *enp)
{
efx_mcdi_iface_t *emip = &(enp->en_u.siena.enu_mip);
efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
caddr_t svpd = NULL;
unsigned partn;
size_t size = 0;
@ -201,7 +206,7 @@ siena_vpd_size(
__in efx_nic_t *enp,
__out size_t *sizep)
{
efx_mcdi_iface_t *emip = &(enp->en_u.siena.enu_mip);
efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
unsigned int partn;
int rc;
@ -236,8 +241,8 @@ siena_vpd_read(
__out_bcount(size) caddr_t data,
__in size_t size)
{
efx_mcdi_iface_t *emip = &(enp->en_u.siena.enu_mip);
siena_mc_dynamic_config_hdr_t *dcfg;
efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
siena_mc_dynamic_config_hdr_t *dcfg = NULL;
unsigned int vpd_length;
unsigned int vpd_offset;
unsigned int dcfg_partn;
@ -499,8 +504,8 @@ siena_vpd_write(
__in_bcount(size) caddr_t data,
__in size_t size)
{
efx_mcdi_iface_t *emip = &(enp->en_u.siena.enu_mip);
siena_mc_dynamic_config_hdr_t *dcfg;
efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
siena_mc_dynamic_config_hdr_t *dcfg = NULL;
unsigned int vpd_offset;
unsigned int dcfg_partn;
unsigned int hdr_length;
@ -525,18 +530,18 @@ siena_vpd_write(
goto fail2;
if ((rc = siena_nvram_partn_lock(enp, dcfg_partn)) != 0)
goto fail2;
goto fail3;
if ((rc = siena_nvram_get_dynamic_cfg(enp, dcfg_partn,
B_FALSE, &dcfg, &dcfg_size)) != 0)
goto fail3;
goto fail4;
hdr_length = EFX_WORD_FIELD(dcfg->length, EFX_WORD_0);
/* Allocated memory should have room for the new VPD */
if (hdr_length + vpd_length > dcfg_size) {
rc = ENOSPC;
goto fail3;
goto fail5;
}
/* Copy in new vpd and update header */
@ -553,12 +558,12 @@ siena_vpd_write(
/* Erase and write the new sector */
if ((rc = siena_nvram_partn_erase(enp, dcfg_partn, 0, partn_size)) != 0)
goto fail4;
goto fail6;
/* Write out the new structure to nvram */
if ((rc = siena_nvram_partn_write(enp, dcfg_partn, 0, (caddr_t)dcfg,
vpd_offset + vpd_length)) != 0)
goto fail5;
goto fail7;
EFSYS_KMEM_FREE(enp->en_esip, dcfg_size, dcfg);
@ -566,18 +571,22 @@ siena_vpd_write(
return (0);
fail7:
EFSYS_PROBE(fail7);
fail6:
EFSYS_PROBE(fail6);
fail5:
EFSYS_PROBE(fail5);
fail4:
EFSYS_PROBE(fail4);
fail3:
EFSYS_PROBE(fail3);
EFSYS_KMEM_FREE(enp->en_esip, dcfg_size, dcfg);
fail2:
EFSYS_PROBE(fail2);
fail4:
EFSYS_PROBE(fail4);
siena_nvram_partn_unlock(enp, dcfg_partn);
fail3:
EFSYS_PROBE(fail3);
fail2:
EFSYS_PROBE(fail2);
fail1:
EFSYS_PROBE1(fail1, int, rc);

View File

@ -1,30 +1,34 @@
/*-
* Copyright (c) 2010-2011 Solarflare Communications, Inc.
* Copyright (c) 2010-2015 Solarflare Communications Inc.
* All rights reserved.
*
* This software was developed in part by Philip Paeps under contract for
* Solarflare Communications, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* modification, are permitted provided that the following conditions are met:
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the FreeBSD Project.
*/
#include <sys/cdefs.h>
@ -42,6 +46,7 @@ __FBSDID("$FreeBSD$");
#include <sys/taskqueue.h>
#include <sys/sockio.h>
#include <sys/sysctl.h>
#include <sys/priv.h>
#include <sys/syslog.h>
#include <dev/pci/pcireg.h>
@ -57,6 +62,7 @@ __FBSDID("$FreeBSD$");
#include "sfxge.h"
#include "sfxge_rx.h"
#include "sfxge_ioc.h"
#include "sfxge_version.h"
#define SFXGE_CAP (IFCAP_VLAN_MTU | IFCAP_VLAN_HWCSUM | \
@ -92,6 +98,83 @@ SYSCTL_INT(_hw_sfxge, OID_AUTO, tx_ring, CTLFLAG_RDTUN,
static void
sfxge_reset(void *arg, int npending);
static int
sfxge_estimate_rsrc_limits(struct sfxge_softc *sc)
{
efx_drv_limits_t limits;
int rc;
unsigned int evq_max;
uint32_t evq_allocated;
uint32_t rxq_allocated;
uint32_t txq_allocated;
/*
* Limit the number of event queues to:
* - number of CPUs
* - hardwire maximum RSS channels
* - administratively specified maximum RSS channels
*/
evq_max = MIN(mp_ncpus, EFX_MAXRSS);
if (sc->max_rss_channels > 0)
evq_max = MIN(evq_max, sc->max_rss_channels);
memset(&limits, 0, sizeof(limits));
limits.edl_min_evq_count = 1;
limits.edl_max_evq_count = evq_max;
limits.edl_min_txq_count = SFXGE_TXQ_NTYPES;
limits.edl_max_txq_count = evq_max + SFXGE_TXQ_NTYPES - 1;
limits.edl_min_rxq_count = 1;
limits.edl_max_rxq_count = evq_max;
efx_nic_set_drv_limits(sc->enp, &limits);
if ((rc = efx_nic_init(sc->enp)) != 0)
return (rc);
rc = efx_nic_get_vi_pool(sc->enp, &evq_allocated, &rxq_allocated,
&txq_allocated);
if (rc != 0) {
efx_nic_fini(sc->enp);
return (rc);
}
KASSERT(txq_allocated >= SFXGE_TXQ_NTYPES,
("txq_allocated < SFXGE_TXQ_NTYPES"));
sc->evq_max = MIN(evq_allocated, evq_max);
sc->evq_max = MIN(rxq_allocated, sc->evq_max);
sc->evq_max = MIN(txq_allocated - (SFXGE_TXQ_NTYPES - 1),
sc->evq_max);
KASSERT(sc->evq_max <= evq_max,
("allocated more than maximum requested"));
/*
* NIC is kept initialized in the case of success to be able to
* initialize port to find out media types.
*/
return (0);
}
static int
sfxge_set_drv_limits(struct sfxge_softc *sc)
{
efx_drv_limits_t limits;
memset(&limits, 0, sizeof(limits));
/* Limits are strict since take into account initial estimation */
limits.edl_min_evq_count = limits.edl_max_evq_count =
sc->intr.n_alloc;
limits.edl_min_txq_count = limits.edl_max_txq_count =
sc->intr.n_alloc + SFXGE_TXQ_NTYPES - 1;
limits.edl_min_rxq_count = limits.edl_max_rxq_count =
sc->intr.n_alloc;
return (efx_nic_set_drv_limits(sc->enp, &limits));
}
static int
sfxge_start(struct sfxge_softc *sc)
{
@ -107,6 +190,10 @@ sfxge_start(struct sfxge_softc *sc)
goto fail;
}
/* Set required resource limits */
if ((rc = sfxge_set_drv_limits(sc)) != 0)
goto fail;
if ((rc = efx_nic_init(sc->enp)) != 0)
goto fail;
@ -118,16 +205,16 @@ sfxge_start(struct sfxge_softc *sc)
if ((rc = sfxge_ev_start(sc)) != 0)
goto fail3;
/* Fire up the port. */
if ((rc = sfxge_port_start(sc)) != 0)
goto fail4;
/* Start the receiver side. */
if ((rc = sfxge_rx_start(sc)) != 0)
goto fail4;
goto fail5;
/* Start the transmitter side. */
if ((rc = sfxge_tx_start(sc)) != 0)
goto fail5;
/* Fire up the port. */
if ((rc = sfxge_port_start(sc)) != 0)
goto fail6;
sc->init_state = SFXGE_STARTED;
@ -139,10 +226,10 @@ sfxge_start(struct sfxge_softc *sc)
return (0);
fail6:
sfxge_tx_stop(sc);
sfxge_rx_stop(sc);
fail5:
sfxge_rx_stop(sc);
sfxge_port_stop(sc);
fail4:
sfxge_ev_stop(sc);
@ -181,15 +268,15 @@ sfxge_stop(struct sfxge_softc *sc)
sc->init_state = SFXGE_REGISTERED;
/* Stop the port. */
sfxge_port_stop(sc);
/* Stop the transmitter. */
sfxge_tx_stop(sc);
/* Stop the receiver. */
sfxge_rx_stop(sc);
/* Stop the port. */
sfxge_port_stop(sc);
/* Stop processing events. */
sfxge_ev_stop(sc);
@ -201,11 +288,73 @@ sfxge_stop(struct sfxge_softc *sc)
sc->ifnet->if_drv_flags &= ~IFF_DRV_RUNNING;
}
static int
sfxge_vpd_ioctl(struct sfxge_softc *sc, sfxge_ioc_t *ioc)
{
efx_vpd_value_t value;
int rc = 0;
switch (ioc->u.vpd.op) {
case SFXGE_VPD_OP_GET_KEYWORD:
value.evv_tag = ioc->u.vpd.tag;
value.evv_keyword = ioc->u.vpd.keyword;
rc = efx_vpd_get(sc->enp, sc->vpd_data, sc->vpd_size, &value);
if (rc != 0)
break;
ioc->u.vpd.len = MIN(ioc->u.vpd.len, value.evv_length);
if (ioc->u.vpd.payload != 0) {
rc = copyout(value.evv_value, ioc->u.vpd.payload,
ioc->u.vpd.len);
}
break;
case SFXGE_VPD_OP_SET_KEYWORD:
if (ioc->u.vpd.len > sizeof(value.evv_value))
return (EINVAL);
value.evv_tag = ioc->u.vpd.tag;
value.evv_keyword = ioc->u.vpd.keyword;
value.evv_length = ioc->u.vpd.len;
rc = copyin(ioc->u.vpd.payload, value.evv_value, value.evv_length);
if (rc != 0)
break;
rc = efx_vpd_set(sc->enp, sc->vpd_data, sc->vpd_size, &value);
if (rc != 0)
break;
rc = efx_vpd_verify(sc->enp, sc->vpd_data, sc->vpd_size);
if (rc != 0)
break;
rc = efx_vpd_write(sc->enp, sc->vpd_data, sc->vpd_size);
break;
default:
rc = EOPNOTSUPP;
break;
}
return (rc);
}
static int
sfxge_private_ioctl(struct sfxge_softc *sc, sfxge_ioc_t *ioc)
{
switch (ioc->op) {
case SFXGE_MCDI_IOC:
return (sfxge_mcdi_ioctl(sc, ioc));
case SFXGE_NVRAM_IOC:
return (sfxge_nvram_ioctl(sc, ioc));
case SFXGE_VPD_IOC:
return (sfxge_vpd_ioctl(sc, ioc));
default:
return (EOPNOTSUPP);
}
}
static int
sfxge_if_ioctl(struct ifnet *ifp, unsigned long command, caddr_t data)
{
struct sfxge_softc *sc;
struct ifreq *ifr;
sfxge_ioc_t ioc;
int error;
ifr = (struct ifreq *)data;
@ -274,7 +423,8 @@ sfxge_if_ioctl(struct ifnet *ifp, unsigned long command, caddr_t data)
* can't (yet) disable.
*/
KASSERT((reqcap & ~ifp->if_capabilities) == 0,
("Unsupported capabilities %x requested %x vs %x",
("Unsupported capabilities 0x%x requested 0x%x vs "
"supported 0x%x",
reqcap & ~ifp->if_capabilities,
reqcap , ifp->if_capabilities));
if (capchg_mask & SFXGE_CAP_FIXED) {
@ -337,6 +487,18 @@ sfxge_if_ioctl(struct ifnet *ifp, unsigned long command, caddr_t data)
case SIOCGIFMEDIA:
error = ifmedia_ioctl(ifp, ifr, &sc->media, command);
break;
case SIOCGPRIVATE_0:
error = priv_check(curthread, PRIV_DRIVER);
if (error != 0)
break;
error = copyin(ifr->ifr_data, &ioc, sizeof(ioc));
if (error != 0)
return (error);
error = sfxge_private_ioctl(sc, &ioc);
if (error == 0) {
error = copyout(&ioc, ifr->ifr_data, sizeof(ioc));
}
break;
default:
error = ether_ioctl(ifp, command, data);
}
@ -382,6 +544,10 @@ sfxge_ifnet_init(struct ifnet *ifp, struct sfxge_softc *sc)
ifp->if_capenable |= IFCAP_LRO;
#endif
if (encp->enc_hw_tx_insert_vlan_enabled) {
ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING;
ifp->if_capenable |= IFCAP_VLAN_HWTAGGING;
}
ifp->if_hwassist = CSUM_TCP | CSUM_UDP | CSUM_IP | CSUM_TSO |
CSUM_TCP_IPV6 | CSUM_UDP_IPV6;
@ -392,6 +558,7 @@ sfxge_ifnet_init(struct ifnet *ifp, struct sfxge_softc *sc)
ifp->if_get_counter = sfxge_get_counter;
DBGPRINT(sc->dev, "ifmedia_init");
if ((rc = sfxge_port_ifmedia_init(sc)) != 0)
goto fail;
@ -475,10 +642,12 @@ sfxge_create(struct sfxge_softc *sc)
(void) pci_enable_busmaster(dev);
/* Initialize DMA mappings. */
DBGPRINT(sc->dev, "dma_init...");
if ((error = sfxge_dma_init(sc)) != 0)
goto fail;
/* Map the device registers. */
DBGPRINT(sc->dev, "bar_init...");
if ((error = sfxge_bar_init(sc)) != 0)
goto fail;
@ -486,6 +655,8 @@ sfxge_create(struct sfxge_softc *sc)
&sc->family);
KASSERT(error == 0, ("Family should be filtered by sfxge_probe()"));
DBGPRINT(sc->dev, "nic_create...");
/* Create the common code nic object. */
SFXGE_EFSYS_LOCK_INIT(&sc->enp_lock,
device_get_nameunit(sc->dev), "nic");
@ -495,7 +666,8 @@ sfxge_create(struct sfxge_softc *sc)
sc->enp = enp;
if (!ISP2(sfxge_rx_ring_entries) ||
!(sfxge_rx_ring_entries & EFX_RXQ_NDESCS_MASK)) {
(sfxge_rx_ring_entries < EFX_RXQ_MINNDESCS) ||
(sfxge_rx_ring_entries > EFX_RXQ_MAXNDESCS)) {
log(LOG_ERR, "%s=%d must be power of 2 from %u to %u",
SFXGE_PARAM_RX_RING, sfxge_rx_ring_entries,
EFX_RXQ_MINNDESCS, EFX_RXQ_MAXNDESCS);
@ -505,20 +677,23 @@ sfxge_create(struct sfxge_softc *sc)
sc->rxq_entries = sfxge_rx_ring_entries;
if (!ISP2(sfxge_tx_ring_entries) ||
!(sfxge_tx_ring_entries & EFX_TXQ_NDESCS_MASK)) {
(sfxge_tx_ring_entries < EFX_TXQ_MINNDESCS) ||
(sfxge_tx_ring_entries > EFX_TXQ_MAXNDESCS(efx_nic_cfg_get(enp)))) {
log(LOG_ERR, "%s=%d must be power of 2 from %u to %u",
SFXGE_PARAM_TX_RING, sfxge_tx_ring_entries,
EFX_TXQ_MINNDESCS, EFX_TXQ_MAXNDESCS);
EFX_TXQ_MINNDESCS, EFX_TXQ_MAXNDESCS(efx_nic_cfg_get(enp)));
error = EINVAL;
goto fail_tx_ring_entries;
}
sc->txq_entries = sfxge_tx_ring_entries;
/* Initialize MCDI to talk to the microcontroller. */
DBGPRINT(sc->dev, "mcdi_init...");
if ((error = sfxge_mcdi_init(sc)) != 0)
goto fail4;
/* Probe the NIC and build the configuration data area. */
DBGPRINT(sc->dev, "nic_probe...");
if ((error = efx_nic_probe(enp)) != 0)
goto fail5;
@ -528,50 +703,75 @@ sfxge_create(struct sfxge_softc *sc)
SFXGE_VERSION_STRING, 0,
"Driver version");
SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
OID_AUTO, "phy_type", CTLFLAG_RD,
NULL, efx_nic_cfg_get(enp)->enc_phy_type,
"PHY type");
/* Initialize the NVRAM. */
DBGPRINT(sc->dev, "nvram_init...");
if ((error = efx_nvram_init(enp)) != 0)
goto fail6;
/* Initialize the VPD. */
DBGPRINT(sc->dev, "vpd_init...");
if ((error = efx_vpd_init(enp)) != 0)
goto fail7;
efx_mcdi_new_epoch(enp);
/* Reset the NIC. */
DBGPRINT(sc->dev, "nic_reset...");
if ((error = efx_nic_reset(enp)) != 0)
goto fail8;
/* Initialize buffer table allocation. */
sc->buffer_table_next = 0;
/* Set up interrupts. */
if ((error = sfxge_intr_init(sc)) != 0)
/*
* Guarantee minimum and estimate maximum number of event queues
* to take it into account when MSI-X interrupts are allocated.
* It initializes NIC and keeps it initialized on success.
*/
if ((error = sfxge_estimate_rsrc_limits(sc)) != 0)
goto fail8;
/* Set up interrupts. */
DBGPRINT(sc->dev, "intr_init...");
if ((error = sfxge_intr_init(sc)) != 0)
goto fail9;
/* Initialize event processing state. */
DBGPRINT(sc->dev, "ev_init...");
if ((error = sfxge_ev_init(sc)) != 0)
goto fail11;
/* Initialize receive state. */
if ((error = sfxge_rx_init(sc)) != 0)
/* Initialize port state. */
DBGPRINT(sc->dev, "port_init...");
if ((error = sfxge_port_init(sc)) != 0)
goto fail12;
/* Initialize transmit state. */
if ((error = sfxge_tx_init(sc)) != 0)
/* Initialize receive state. */
DBGPRINT(sc->dev, "rx_init...");
if ((error = sfxge_rx_init(sc)) != 0)
goto fail13;
/* Initialize port state. */
if ((error = sfxge_port_init(sc)) != 0)
/* Initialize transmit state. */
DBGPRINT(sc->dev, "tx_init...");
if ((error = sfxge_tx_init(sc)) != 0)
goto fail14;
sc->init_state = SFXGE_INITIALIZED;
DBGPRINT(sc->dev, "success");
return (0);
fail14:
sfxge_tx_fini(sc);
sfxge_rx_fini(sc);
fail13:
sfxge_rx_fini(sc);
sfxge_port_fini(sc);
fail12:
sfxge_ev_fini(sc);
@ -579,6 +779,9 @@ sfxge_create(struct sfxge_softc *sc)
fail11:
sfxge_intr_fini(sc);
fail9:
efx_nic_fini(sc->enp);
fail8:
efx_vpd_fini(enp);
@ -603,6 +806,7 @@ sfxge_create(struct sfxge_softc *sc)
(void) pci_disable_busmaster(sc->dev);
fail:
DBGPRINT(sc->dev, "failed %d", error);
sc->dev = NULL;
SFXGE_ADAPTER_LOCK_DESTROY(sc);
return (error);
@ -613,15 +817,15 @@ sfxge_destroy(struct sfxge_softc *sc)
{
efx_nic_t *enp;
/* Clean up port state. */
sfxge_port_fini(sc);
/* Clean up transmit state. */
sfxge_tx_fini(sc);
/* Clean up receive state. */
sfxge_rx_fini(sc);
/* Clean up port state. */
sfxge_port_fini(sc);
/* Clean up event processing state. */
sfxge_ev_fini(sc);
@ -750,6 +954,7 @@ sfxge_reset(void *arg, int npending)
{
struct sfxge_softc *sc;
int rc;
unsigned attempt;
(void)npending;
@ -762,10 +967,15 @@ sfxge_reset(void *arg, int npending)
sfxge_stop(sc);
efx_nic_reset(sc->enp);
if ((rc = sfxge_start(sc)) != 0)
device_printf(sc->dev,
"reset failed (%d); interface is now stopped\n",
rc);
for (attempt = 0; attempt < 3; ++attempt) {
if ((rc = sfxge_start(sc)) == 0)
goto done;
device_printf(sc->dev, "start on reset failed (%d)\n", rc);
DELAY(100000);
}
device_printf(sc->dev, "reset failed; interface is now stopped\n");
done:
SFXGE_ADAPTER_UNLOCK(sc);
@ -797,29 +1007,42 @@ sfxge_attach(device_t dev)
sc->ifnet = ifp;
/* Initialize hardware. */
DBGPRINT(sc->dev, "create nic");
if ((error = sfxge_create(sc)) != 0)
goto fail2;
/* Create the ifnet for the port. */
DBGPRINT(sc->dev, "init ifnet");
if ((error = sfxge_ifnet_init(ifp, sc)) != 0)
goto fail3;
DBGPRINT(sc->dev, "init vpd");
if ((error = sfxge_vpd_init(sc)) != 0)
goto fail4;
/*
* NIC is initialized inside sfxge_create() and kept inialized
* to be able to initialize port to discover media types in
* sfxge_ifnet_init().
*/
efx_nic_fini(sc->enp);
sc->init_state = SFXGE_REGISTERED;
DBGPRINT(sc->dev, "success");
return (0);
fail4:
sfxge_ifnet_fini(ifp);
fail3:
efx_nic_fini(sc->enp);
sfxge_destroy(sc);
fail2:
if_free(sc->ifnet);
fail:
DBGPRINT(sc->dev, "failed %d", error);
return (error);
}
@ -852,13 +1075,25 @@ sfxge_probe(device_t dev)
pci_vendor_id = pci_get_vendor(dev);
pci_device_id = pci_get_device(dev);
DBGPRINT(dev, "PCI ID %04x:%04x", pci_vendor_id, pci_device_id);
rc = efx_family(pci_vendor_id, pci_device_id, &family);
if (rc != 0)
if (rc != 0) {
DBGPRINT(dev, "efx_family fail %d", rc);
return (ENXIO);
}
KASSERT(family == EFX_FAMILY_SIENA, ("impossible controller family"));
device_set_desc(dev, "Solarflare SFC9000 family");
return (0);
if (family == EFX_FAMILY_SIENA) {
device_set_desc(dev, "Solarflare SFC9000 family");
return (0);
}
if (family == EFX_FAMILY_HUNTINGTON) {
device_set_desc(dev, "Solarflare SFC9100 family");
return (0);
}
DBGPRINT(dev, "impossible controller family %d", family);
return (ENXIO);
}
static device_method_t sfxge_methods[] = {

View File

@ -1,30 +1,34 @@
/*-
* Copyright (c) 2010-2011 Solarflare Communications, Inc.
* Copyright (c) 2010-2015 Solarflare Communications Inc.
* All rights reserved.
*
* This software was developed in part by Philip Paeps under contract for
* Solarflare Communications, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* modification, are permitted provided that the following conditions are met:
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the FreeBSD Project.
*
* $FreeBSD$
*/
@ -34,7 +38,6 @@
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/condvar.h>
#include <sys/socket.h>
#include <sys/sysctl.h>
#include <sys/sx.h>
@ -46,6 +49,18 @@
#include <net/if_media.h>
#include <net/if_types.h>
#include "sfxge_ioc.h"
/*
* Debugging
*/
#if 0
#define DBGPRINT(dev, fmt, args...) \
device_printf(dev, "%s: " fmt "\n", __func__, ## args)
#else
#define DBGPRINT(dev, fmt, args...)
#endif
/*
* Backward-compatibility
*/
@ -72,6 +87,10 @@
#define IFM_10G_KX4 IFM_10G_CX4
#endif
#ifndef IFM_40G_CR4
#define IFM_40G_CR4 IFM_UNKNOWN
#endif
#if (__FreeBSD_version >= 800501 && __FreeBSD_version < 900000) || \
__FreeBSD_version >= 900003
#define SFXGE_HAVE_DESCRIBE_INTR
@ -161,7 +180,7 @@ enum sfxge_mcdi_state {
struct sfxge_mcdi {
struct mtx lock;
struct cv cv;
efsys_mem_t mem;
enum sfxge_mcdi_state state;
efx_mcdi_transport_t transport;
@ -191,6 +210,9 @@ struct sfxge_port {
struct sfxge_hw_stats phy_stats;
struct sfxge_hw_stats mac_stats;
efx_link_mode_t link_mode;
uint8_t mcast_addrs[EFX_MAC_MULTICAST_LIST_MAX *
EFX_MAC_ADDR_LEN];
unsigned int mcast_count;
/* Only used in debugging output */
char lock_name[SFXGE_LOCK_NAME_MAX];
@ -250,11 +272,15 @@ struct sfxge_softc {
size_t rx_prefix_size;
size_t rx_buffer_size;
size_t rx_buffer_align;
uma_zone_t rx_buffer_zone;
unsigned int evq_max;
unsigned int evq_count;
unsigned int rxq_count;
unsigned int txq_count;
int tso_fw_assisted;
};
#define SFXGE_LINK_UP(sc) ((sc)->port.link_mode != EFX_LINK_DOWN)
@ -277,10 +303,12 @@ extern void sfxge_sram_buf_tbl_alloc(struct sfxge_softc *sc, size_t n,
extern int sfxge_dma_init(struct sfxge_softc *sc);
extern void sfxge_dma_fini(struct sfxge_softc *sc);
extern int sfxge_dma_alloc(struct sfxge_softc *sc, bus_size_t len,
efsys_mem_t *esmp);
efsys_mem_t *esmp);
extern void sfxge_dma_free(efsys_mem_t *esmp);
extern int sfxge_dma_map_sg_collapse(bus_dma_tag_t tag, bus_dmamap_t map,
struct mbuf **mp, bus_dma_segment_t *segs, int *nsegs, int maxsegs);
struct mbuf **mp,
bus_dma_segment_t *segs,
int *nsegs, int maxsegs);
/*
* From sfxge_ev.c.
@ -304,6 +332,12 @@ extern void sfxge_intr_stop(struct sfxge_softc *sc);
*/
extern int sfxge_mcdi_init(struct sfxge_softc *sc);
extern void sfxge_mcdi_fini(struct sfxge_softc *sc);
extern int sfxge_mcdi_ioctl(struct sfxge_softc *sc, sfxge_ioc_t *ip);
/*
* From sfxge_nvram.c.
*/
extern int sfxge_nvram_ioctl(struct sfxge_softc *sc, sfxge_ioc_t *ip);
/*
* From sfxge_port.c.
@ -313,7 +347,7 @@ extern void sfxge_port_fini(struct sfxge_softc *sc);
extern int sfxge_port_start(struct sfxge_softc *sc);
extern void sfxge_port_stop(struct sfxge_softc *sc);
extern void sfxge_mac_link_update(struct sfxge_softc *sc,
efx_link_mode_t mode);
efx_link_mode_t mode);
extern int sfxge_mac_filter_set(struct sfxge_softc *sc);
extern int sfxge_port_ifmedia_init(struct sfxge_softc *sc);
extern uint64_t sfxge_get_counter(struct ifnet *ifp, ift_counter c);

View File

@ -1,30 +1,34 @@
/*-
* Copyright (c) 2010-2011 Solarflare Communications, Inc.
* Copyright (c) 2010-2015 Solarflare Communications Inc.
* All rights reserved.
*
* This software was developed in part by Philip Paeps under contract for
* Solarflare Communications, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* modification, are permitted provided that the following conditions are met:
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the FreeBSD Project.
*/
#include <sys/cdefs.h>
@ -60,7 +64,8 @@ sfxge_dma_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
int
sfxge_dma_map_sg_collapse(bus_dma_tag_t tag, bus_dmamap_t map,
struct mbuf **mp, bus_dma_segment_t *segs, int *nsegs, int maxsegs)
struct mbuf **mp, bus_dma_segment_t *segs,
int *nsegs, int maxsegs)
{
bus_dma_segment_t *psegs;
struct mbuf *m;

View File

@ -1,30 +1,34 @@
/*-
* Copyright (c) 2010-2011 Solarflare Communications, Inc.
* Copyright (c) 2010-2015 Solarflare Communications Inc.
* All rights reserved.
*
* This software was developed in part by Philip Paeps under contract for
* Solarflare Communications, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* modification, are permitted provided that the following conditions are met:
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the FreeBSD Project.
*/
#include <sys/cdefs.h>
@ -82,12 +86,13 @@ sfxge_ev_qcomplete(struct sfxge_evq *evq, boolean_t eop)
static boolean_t
sfxge_ev_rx(void *arg, uint32_t label, uint32_t id, uint32_t size,
uint16_t flags)
uint16_t flags)
{
struct sfxge_evq *evq;
struct sfxge_softc *sc;
struct sfxge_rxq *rxq;
unsigned int expected;
unsigned int stop;
unsigned int delta;
struct sfxge_rx_sw_desc *rx_desc;
evq = arg;
@ -106,28 +111,40 @@ sfxge_ev_rx(void *arg, uint32_t label, uint32_t id, uint32_t size,
if (__predict_false(rxq->init_state != SFXGE_RXQ_STARTED))
goto done;
expected = rxq->pending++ & rxq->ptr_mask;
if (id != expected) {
evq->exception = B_TRUE;
stop = (id + 1) & rxq->ptr_mask;
id = rxq->pending & rxq->ptr_mask;
delta = (stop >= id) ? (stop - id) : (rxq->entries - id + stop);
rxq->pending += delta;
device_printf(sc->dev, "RX completion out of order"
" (id=%#x expected=%#x flags=%#x); resetting\n",
id, expected, flags);
sfxge_schedule_reset(sc);
if (delta != 1) {
if ((!efx_nic_cfg_get(sc->enp)->enc_rx_batching_enabled) ||
(delta <= 0) ||
(delta > efx_nic_cfg_get(sc->enp)->enc_rx_batch_max)) {
evq->exception = B_TRUE;
goto done;
device_printf(sc->dev, "RX completion out of order"
" (id=%#x delta=%u flags=%#x); resetting\n",
id, delta, flags);
sfxge_schedule_reset(sc);
goto done;
}
}
rx_desc = &rxq->queue[id];
KASSERT(rx_desc->flags == EFX_DISCARD,
("rx_desc->flags != EFX_DISCARD"));
rx_desc->flags = flags;
KASSERT(size < (1 << 16), ("size > (1 << 16)"));
rx_desc->size = (uint16_t)size;
prefetch_read_many(rx_desc->mbuf);
for (; id != stop; id = (id + 1) & rxq->ptr_mask) {
rx_desc = &rxq->queue[id];
KASSERT(rx_desc->flags == EFX_DISCARD,
("rx_desc->flags != EFX_DISCARD"));
rx_desc->flags = flags;
KASSERT(size < (1 << 16), ("size > (1 << 16)"));
rx_desc->size = (uint16_t)size;
}
evq->rx_done++;
if (rxq->pending - rxq->completed >= SFXGE_RX_BATCH)
@ -148,6 +165,18 @@ sfxge_ev_exception(void *arg, uint32_t code, uint32_t data)
sc = evq->sc;
DBGPRINT(sc->dev, "[%d] %s", evq->index,
(code == EFX_EXCEPTION_RX_RECOVERY) ? "RX_RECOVERY" :
(code == EFX_EXCEPTION_RX_DSC_ERROR) ? "RX_DSC_ERROR" :
(code == EFX_EXCEPTION_TX_DSC_ERROR) ? "TX_DSC_ERROR" :
(code == EFX_EXCEPTION_UNKNOWN_SENSOREVT) ? "UNKNOWN_SENSOREVT" :
(code == EFX_EXCEPTION_FWALERT_SRAM) ? "FWALERT_SRAM" :
(code == EFX_EXCEPTION_UNKNOWN_FWALERT) ? "UNKNOWN_FWALERT" :
(code == EFX_EXCEPTION_RX_ERROR) ? "RX_ERROR" :
(code == EFX_EXCEPTION_TX_ERROR) ? "TX_ERROR" :
(code == EFX_EXCEPTION_EV_ERROR) ? "EV_ERROR" :
"UNKNOWN");
evq->exception = B_TRUE;
if (code != EFX_EXCEPTION_UNKNOWN_SENSOREVT) {
@ -180,6 +209,11 @@ sfxge_ev_rxq_flush_done(void *arg, uint32_t rxq_index)
/* Resend a software event on the correct queue */
index = rxq->index;
if (index == evq->index) {
sfxge_rx_qflush_done(rxq);
return (B_FALSE);
}
evq = sc->evq[index];
label = rxq_index;
@ -299,6 +333,11 @@ sfxge_ev_txq_flush_done(void *arg, uint32_t txq_index)
KASSERT(txq->init_state == SFXGE_TXQ_INITIALIZED,
("txq not initialized"));
if (txq->evq_index == evq->index) {
sfxge_tx_qflush_done(txq);
return (B_FALSE);
}
/* Resend a software event on the correct queue */
evq = sc->evq[txq->evq_index];
@ -551,7 +590,9 @@ sfxge_ev_initialized(void *arg)
evq = (struct sfxge_evq *)arg;
SFXGE_EVQ_LOCK_ASSERT_OWNED(evq);
KASSERT(evq->init_state == SFXGE_EVQ_STARTING,
/* Init done events may be duplicated on 7xxx */
KASSERT(evq->init_state == SFXGE_EVQ_STARTING ||
evq->init_state == SFXGE_EVQ_STARTED,
("evq not starting"));
evq->init_state = SFXGE_EVQ_STARTED;

View File

@ -1,30 +1,34 @@
/*-
* Copyright (c) 2010-2011 Solarflare Communications, Inc.
* Copyright (c) 2010-2015 Solarflare Communications Inc.
* All rights reserved.
*
* This software was developed in part by Philip Paeps under contract for
* Solarflare Communications, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* modification, are permitted provided that the following conditions are met:
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the FreeBSD Project.
*/
#include <sys/cdefs.h>
@ -36,7 +40,6 @@ __FBSDID("$FreeBSD$");
#include <sys/malloc.h>
#include <sys/queue.h>
#include <sys/rman.h>
#include <sys/smp.h>
#include <sys/syslog.h>
#include <sys/taskqueue.h>
@ -294,16 +297,9 @@ sfxge_intr_setup_msix(struct sfxge_softc *sc)
if (count == 0)
return (EINVAL);
/* Limit the number of interrupts to the number of CPUs. */
if (count > mp_ncpus)
count = mp_ncpus;
/* Not very likely these days... */
if (count > EFX_MAXRSS)
count = EFX_MAXRSS;
if (sc->max_rss_channels > 0 && count > sc->max_rss_channels)
count = sc->max_rss_channels;
/* Do not try to allocate more than already estimated EVQ maximum */
KASSERT(sc->evq_max > 0, ("evq_max is zero"));
count = MIN(count, sc->evq_max);
rid = PCIR_BAR(4);
resp = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
@ -412,7 +408,7 @@ static const char *const __sfxge_err[] = {
void
sfxge_err(efsys_identifier_t *arg, unsigned int code, uint32_t dword0,
uint32_t dword1)
uint32_t dword1)
{
struct sfxge_softc *sc = (struct sfxge_softc *)arg;
device_t dev = sc->dev;

112
sys/dev/sfxge/sfxge_ioc.h Normal file
View File

@ -0,0 +1,112 @@
/*-
* Copyright (c) 2014-2015 Solarflare Communications Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the FreeBSD Project.
*
* $FreeBSD$
*/
#ifndef _SYS_SFXGE_IOC_H
#define _SYS_SFXGE_IOC_H
#ifdef __cplusplus
extern "C" {
#endif
#include <sys/types.h>
/* More codes may be added if necessary */
enum sfxge_ioc_codes {
SFXGE_MCDI_IOC,
SFXGE_NVRAM_IOC,
SFXGE_VPD_IOC
};
enum sfxge_nvram_ops {
SFXGE_NVRAM_OP_SIZE,
SFXGE_NVRAM_OP_READ,
SFXGE_NVRAM_OP_WRITE,
SFXGE_NVRAM_OP_ERASE,
SFXGE_NVRAM_OP_GET_VER,
SFXGE_NVRAM_OP_SET_VER
};
enum sfxge_nvram_types {
SFXGE_NVRAM_TYPE_BOOTROM,
SFXGE_NVRAM_TYPE_BOOTROM_CFG,
SFXGE_NVRAM_TYPE_MC,
SFXGE_NVRAM_TYPE_MC_GOLDEN,
SFXGE_NVRAM_TYPE_PHY,
SFXGE_NVRAM_TYPE_NULL_PHY,
SFXGE_NVRAM_TYPE_FPGA,
SFXGE_NVRAM_TYPE_FCFW,
SFXGE_NVRAM_TYPE_CPLD,
SFXGE_NVRAM_TYPE_FPGA_BACKUP,
SFXGE_NVRAM_TYPE_DYNAMIC_CFG
};
enum sfxge_vpd_ops {
SFXGE_VPD_OP_GET_KEYWORD,
SFXGE_VPD_OP_SET_KEYWORD
};
#define SFXGE_MCDI_MAX_PAYLOAD 0x400
#define SFXGE_VPD_MAX_PAYLOAD 0x100
typedef struct sfxge_ioc_s {
uint32_t op;
union {
struct {
caddr_t payload;
uint32_t cmd;
size_t len; /* In and out */
uint32_t rc;
} mcdi;
struct {
uint32_t op;
uint32_t type;
uint32_t offset;
uint32_t size;
uint32_t subtype;
uint16_t version[4]; /* get/set_ver */
caddr_t data;
} nvram;
struct {
uint8_t op;
uint8_t tag;
uint16_t keyword;
uint16_t len; /* In or out */
caddr_t payload;
} vpd;
} u;
} __packed sfxge_ioc_t;
#ifdef __cplusplus
}
#endif
#endif /* _SYS_SFXGE_IOC_H */

View File

@ -1,30 +1,34 @@
/*-
* Copyright (c) 2010-2011 Solarflare Communications, Inc.
* Copyright (c) 2010-2015 Solarflare Communications Inc.
* All rights reserved.
*
* This software was developed in part by Philip Paeps under contract for
* Solarflare Communications, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* modification, are permitted provided that the following conditions are met:
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the FreeBSD Project.
*/
#include <sys/cdefs.h>
@ -37,6 +41,7 @@ __FBSDID("$FreeBSD$");
#include <sys/proc.h>
#include <sys/syslog.h>
#include <sys/taskqueue.h>
#include <sys/malloc.h>
#include "common/efx.h"
#include "common/efx_mcdi.h"
@ -48,36 +53,6 @@ __FBSDID("$FreeBSD$");
#define SFXGE_MCDI_POLL_INTERVAL_MAX 100000 /* 100ms in 1us units */
#define SFXGE_MCDI_WATCHDOG_INTERVAL 10000000 /* 10s in 1us units */
/* Acquire exclusive access to MCDI for the duration of a request. */
static void
sfxge_mcdi_acquire(struct sfxge_mcdi *mcdi)
{
SFXGE_MCDI_LOCK(mcdi);
KASSERT(mcdi->state != SFXGE_MCDI_UNINITIALIZED,
("MCDI not initialized"));
while (mcdi->state != SFXGE_MCDI_INITIALIZED)
(void)cv_wait_sig(&mcdi->cv, &mcdi->lock);
mcdi->state = SFXGE_MCDI_BUSY;
SFXGE_MCDI_UNLOCK(mcdi);
}
/* Release ownership of MCDI on request completion. */
static void
sfxge_mcdi_release(struct sfxge_mcdi *mcdi)
{
SFXGE_MCDI_LOCK(mcdi);
KASSERT((mcdi->state == SFXGE_MCDI_BUSY ||
mcdi->state == SFXGE_MCDI_COMPLETED),
("MCDI not busy or task not completed"));
mcdi->state = SFXGE_MCDI_INITIALIZED;
cv_broadcast(&mcdi->cv);
SFXGE_MCDI_UNLOCK(mcdi);
}
static void
sfxge_mcdi_timeout(struct sfxge_softc *sc)
{
@ -140,13 +115,16 @@ sfxge_mcdi_execute(void *arg, efx_mcdi_req_t *emrp)
sc = (struct sfxge_softc *)arg;
mcdi = &sc->mcdi;
sfxge_mcdi_acquire(mcdi);
SFXGE_MCDI_LOCK(mcdi);
KASSERT(mcdi->state == SFXGE_MCDI_INITIALIZED,
("MCDI not initialized"));
/* Issue request and poll for completion. */
efx_mcdi_request_start(sc->enp, emrp, B_FALSE);
sfxge_mcdi_poll(sc);
sfxge_mcdi_release(mcdi);
SFXGE_MCDI_UNLOCK(mcdi);
}
static void
@ -158,11 +136,10 @@ sfxge_mcdi_ev_cpl(void *arg)
sc = (struct sfxge_softc *)arg;
mcdi = &sc->mcdi;
SFXGE_MCDI_LOCK(mcdi);
KASSERT(mcdi->state == SFXGE_MCDI_BUSY, ("MCDI not busy"));
mcdi->state = SFXGE_MCDI_COMPLETED;
cv_broadcast(&mcdi->cv);
SFXGE_MCDI_UNLOCK(mcdi);
KASSERT(mcdi->state == SFXGE_MCDI_INITIALIZED,
("MCDI not initialized"));
/* We do not use MCDI completion, MCDI is simply polled */
}
static void
@ -186,17 +163,96 @@ sfxge_mcdi_exception(void *arg, efx_mcdi_exception_t eme)
sfxge_schedule_reset(sc);
}
int
sfxge_mcdi_ioctl(struct sfxge_softc *sc, sfxge_ioc_t *ip)
{
const efx_nic_cfg_t *encp = efx_nic_cfg_get(sc->enp);
struct sfxge_mcdi *mp = &(sc->mcdi);
efx_mcdi_req_t emr;
uint8_t *mcdibuf;
int rc;
if (mp->state == SFXGE_MCDI_UNINITIALIZED) {
rc = ENODEV;
goto fail1;
}
if (!(encp->enc_features & EFX_FEATURE_MCDI)) {
rc = ENOTSUP;
goto fail2;
}
if (ip->u.mcdi.len > SFXGE_MCDI_MAX_PAYLOAD) {
rc = EINVAL;
goto fail3;
}
mcdibuf = malloc(SFXGE_MCDI_MAX_PAYLOAD, M_TEMP, M_WAITOK | M_ZERO);
if (mcdibuf == NULL) {
rc = ENOMEM;
goto fail4;
}
if ((rc = copyin(ip->u.mcdi.payload, mcdibuf, ip->u.mcdi.len)) != 0) {
goto fail5;
}
emr.emr_cmd = ip->u.mcdi.cmd;
emr.emr_in_buf = mcdibuf;
emr.emr_in_length = ip->u.mcdi.len;
emr.emr_out_buf = mcdibuf;
emr.emr_out_length = SFXGE_MCDI_MAX_PAYLOAD;
sfxge_mcdi_execute(sc, &emr);
ip->u.mcdi.rc = emr.emr_rc;
ip->u.mcdi.cmd = emr.emr_cmd;
ip->u.mcdi.len = emr.emr_out_length_used;
if ((rc = copyout(mcdibuf, ip->u.mcdi.payload, ip->u.mcdi.len)) != 0) {
goto fail6;
}
/*
* Helpfully trigger a device reset in response to an MCDI_CMD_REBOOT
* Both ports will see ->emt_exception callbacks on the next MCDI poll
*/
if (ip->u.mcdi.cmd == MC_CMD_REBOOT) {
EFSYS_PROBE(mcdi_ioctl_mc_reboot);
/* sfxge_t->s_state_lock held */
(void) sfxge_schedule_reset(sc);
}
free(mcdibuf, M_TEMP);
return (0);
fail6:
fail5:
free(mcdibuf, M_TEMP);
fail4:
fail3:
fail2:
fail1:
return (rc);
}
int
sfxge_mcdi_init(struct sfxge_softc *sc)
{
efx_nic_t *enp;
struct sfxge_mcdi *mcdi;
efx_mcdi_transport_t *emtp;
efsys_mem_t *esmp;
int max_msg_size;
int rc;
enp = sc->enp;
mcdi = &sc->mcdi;
emtp = &mcdi->transport;
esmp = &mcdi->mem;
max_msg_size = sizeof (uint32_t) + MCDI_CTL_SDU_LEN_MAX_V2;
KASSERT(mcdi->state == SFXGE_MCDI_UNINITIALIZED,
("MCDI already initialized"));
@ -205,13 +261,15 @@ sfxge_mcdi_init(struct sfxge_softc *sc)
mcdi->state = SFXGE_MCDI_INITIALIZED;
if ((rc = sfxge_dma_alloc(sc, max_msg_size, esmp)) != 0)
goto fail;
emtp->emt_context = sc;
emtp->emt_dma_mem = esmp;
emtp->emt_execute = sfxge_mcdi_execute;
emtp->emt_ev_cpl = sfxge_mcdi_ev_cpl;
emtp->emt_exception = sfxge_mcdi_exception;
cv_init(&mcdi->cv, "sfxge_mcdi");
if ((rc = efx_mcdi_init(enp, emtp)) != 0)
goto fail;
@ -229,10 +287,12 @@ sfxge_mcdi_fini(struct sfxge_softc *sc)
struct sfxge_mcdi *mcdi;
efx_nic_t *enp;
efx_mcdi_transport_t *emtp;
efsys_mem_t *esmp;
enp = sc->enp;
mcdi = &sc->mcdi;
emtp = &mcdi->transport;
esmp = &mcdi->mem;
SFXGE_MCDI_LOCK(mcdi);
KASSERT(mcdi->state == SFXGE_MCDI_INITIALIZED,
@ -241,8 +301,9 @@ sfxge_mcdi_fini(struct sfxge_softc *sc)
efx_mcdi_fini(enp);
bzero(emtp, sizeof(*emtp));
cv_destroy(&mcdi->cv);
SFXGE_MCDI_UNLOCK(mcdi);
sfxge_dma_free(esmp);
SFXGE_MCDI_LOCK_DESTROY(mcdi);
}

203
sys/dev/sfxge/sfxge_nvram.c Normal file
View File

@ -0,0 +1,203 @@
/*-
* Copyright (c) 2010-2015 Solarflare Communications, Inc.
* All rights reserved.
*
* This software was developed in part by OKTET Labs Ltd. under contract for
* Solarflare Communications, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/types.h>
#include <sys/malloc.h>
#include "common/efx.h"
#include "sfxge.h"
/* These data make no real sense, they are here just to make sfupdate happy.
* Any code that would rely on it is broken.
*/
static const uint8_t fake_dynamic_cfg_nvram[] = {
0x7a, 0xda, 0x10, 0xef, 0x0c, 0x00, 0x00, 0x00,
0x00, 0x05, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x10,
0x08, 0x00, 0x00, 0x00, 0x90, 0x04, 0x00, 0x52,
0x56, 0x01, 0xc3, 0x78, 0x01, 0x00, 0x03, 0x10,
0x08, 0x00, 0x00, 0x00, 0x90, 0x04, 0x00, 0x52,
0x56, 0x01, 0xc3, 0x78, 0x57, 0x1a, 0x10, 0xef,
0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x02, 0x0b, 0x64, 0x7d, 0xee, 0xee, 0xee, 0xee
};
static int
sfxge_nvram_rw(struct sfxge_softc *sc, sfxge_ioc_t *ip, efx_nvram_type_t type,
boolean_t write)
{
efx_nic_t *enp = sc->enp;
size_t total_size = ip->u.nvram.size;
size_t chunk_size;
off_t off;
int rc = 0;
uint8_t *buf;
if (type == EFX_NVRAM_DYNAMIC_CFG && sc->family == EFX_FAMILY_SIENA) {
if (write)
return (0);
rc = copyout(fake_dynamic_cfg_nvram, ip->u.nvram.data,
MIN(total_size, sizeof(fake_dynamic_cfg_nvram)));
return (rc);
}
if ((rc = efx_nvram_rw_start(enp, type, &chunk_size)) != 0)
goto fail1;
buf = malloc(chunk_size, M_TEMP, M_WAITOK);
if (buf == NULL) {
rc = ENOMEM;
goto fail2;
}
off = 0;
while (total_size) {
size_t len = MIN(chunk_size, total_size);
if (write) {
rc = copyin(ip->u.nvram.data + off, buf, len);
if (rc != 0)
goto fail3;
rc = efx_nvram_write_chunk(enp, type,
ip->u.nvram.offset + off, buf, len);
if (rc != 0)
goto fail3;
} else {
rc = efx_nvram_read_chunk(enp, type,
ip->u.nvram.offset + off, buf, len);
if (rc != 0)
goto fail3;
rc = copyout(buf, ip->u.nvram.data + off, len);
if (rc != 0)
goto fail3;
}
total_size -= len;
off += len;
}
fail3:
free(buf, M_TEMP);
fail2:
efx_nvram_rw_finish(enp, type);
fail1:
return (rc);
}
static int
sfxge_nvram_erase(struct sfxge_softc *sc, efx_nvram_type_t type)
{
efx_nic_t *enp = sc->enp;
size_t chunk_size;
int rc = 0;
if (type == EFX_NVRAM_DYNAMIC_CFG && sc->family == EFX_FAMILY_SIENA)
return (0);
if ((rc = efx_nvram_rw_start(enp, type, &chunk_size)) != 0)
return (rc);
rc = efx_nvram_erase(enp, type);
efx_nvram_rw_finish(enp, type);
return (rc);
}
int
sfxge_nvram_ioctl(struct sfxge_softc *sc, sfxge_ioc_t *ip)
{
static const efx_nvram_type_t nvram_types[] = {
[SFXGE_NVRAM_TYPE_BOOTROM] = EFX_NVRAM_BOOTROM,
[SFXGE_NVRAM_TYPE_BOOTROM_CFG] = EFX_NVRAM_BOOTROM_CFG,
[SFXGE_NVRAM_TYPE_MC] = EFX_NVRAM_MC_FIRMWARE,
[SFXGE_NVRAM_TYPE_MC_GOLDEN] = EFX_NVRAM_MC_GOLDEN,
[SFXGE_NVRAM_TYPE_PHY] = EFX_NVRAM_PHY,
[SFXGE_NVRAM_TYPE_NULL_PHY] = EFX_NVRAM_NULLPHY,
[SFXGE_NVRAM_TYPE_FPGA] = EFX_NVRAM_FPGA,
[SFXGE_NVRAM_TYPE_FCFW] = EFX_NVRAM_FCFW,
[SFXGE_NVRAM_TYPE_CPLD] = EFX_NVRAM_CPLD,
[SFXGE_NVRAM_TYPE_FPGA_BACKUP] = EFX_NVRAM_FPGA_BACKUP,
[SFXGE_NVRAM_TYPE_DYNAMIC_CFG] = EFX_NVRAM_DYNAMIC_CFG,
};
efx_nic_t *enp = sc->enp;
efx_nvram_type_t type;
int rc = 0;
if (ip->u.nvram.type > SFXGE_NVRAM_TYPE_DYNAMIC_CFG)
return (EINVAL);
type = nvram_types[ip->u.nvram.type];
if (type == EFX_NVRAM_MC_GOLDEN &&
(ip->u.nvram.op == SFXGE_NVRAM_OP_WRITE ||
ip->u.nvram.op == SFXGE_NVRAM_OP_ERASE ||
ip->u.nvram.op == SFXGE_NVRAM_OP_SET_VER))
return (EOPNOTSUPP);
switch (ip->u.nvram.op) {
case SFXGE_NVRAM_OP_SIZE:
{
size_t size;
if (type == EFX_NVRAM_DYNAMIC_CFG && sc->family == EFX_FAMILY_SIENA) {
ip->u.nvram.size = sizeof(fake_dynamic_cfg_nvram);
} else {
if ((rc = efx_nvram_size(enp, type, &size)) != 0)
return (rc);
ip->u.nvram.size = size;
}
break;
}
case SFXGE_NVRAM_OP_READ:
rc = sfxge_nvram_rw(sc, ip, type, B_FALSE);
break;
case SFXGE_NVRAM_OP_WRITE:
rc = sfxge_nvram_rw(sc, ip, type, B_TRUE);
break;
case SFXGE_NVRAM_OP_ERASE:
rc = sfxge_nvram_erase(sc, type);
break;
case SFXGE_NVRAM_OP_GET_VER:
rc = efx_nvram_get_version(enp, type, &ip->u.nvram.subtype,
&ip->u.nvram.version[0]);
break;
case SFXGE_NVRAM_OP_SET_VER:
rc = efx_nvram_set_version(enp, type, &ip->u.nvram.version[0]);
break;
default:
rc = EOPNOTSUPP;
break;
}
return (rc);
}

View File

@ -1,30 +1,34 @@
/*-
* Copyright (c) 2010-2011 Solarflare Communications, Inc.
* Copyright (c) 2010-2015 Solarflare Communications Inc.
* All rights reserved.
*
* This software was developed in part by Philip Paeps under contract for
* Solarflare Communications, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* modification, are permitted provided that the following conditions are met:
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the FreeBSD Project.
*/
#include <sys/cdefs.h>
@ -70,10 +74,6 @@ sfxge_mac_stat_update(struct sfxge_softc *sc)
for (count = 0; count < 100; ++count) {
EFSYS_PROBE1(wait, unsigned int, count);
/* Synchronize the DMA memory for reading */
bus_dmamap_sync(esmp->esm_tag, esmp->esm_map,
BUS_DMASYNC_POSTREAD);
/* Try to update the cached counters */
if ((rc = efx_mac_stats_update(sc->enp, esmp,
port->mac_stats.decode_buf, NULL)) != EAGAIN)
@ -294,6 +294,7 @@ static const uint64_t sfxge_link_baudrate[EFX_LINK_NMODES] = {
[EFX_LINK_1000HDX] = IF_Gbps(1),
[EFX_LINK_1000FDX] = IF_Gbps(1),
[EFX_LINK_10000FDX] = IF_Gbps(10),
[EFX_LINK_40000FDX] = IF_Gbps(40),
};
void
@ -342,42 +343,68 @@ sfxge_mac_poll_work(void *arg, int npending)
}
static int
sfxge_mac_filter_set_locked(struct sfxge_softc *sc)
sfxge_mac_multicast_list_set(struct sfxge_softc *sc)
{
unsigned int bucket[EFX_MAC_HASH_BITS];
struct ifnet *ifp = sc->ifnet;
struct sfxge_port *port = &sc->port;
uint8_t *mcast_addr = port->mcast_addrs;
struct ifmultiaddr *ifma;
struct sockaddr_dl *sa;
efx_nic_t *enp = sc->enp;
unsigned int index;
int rc = 0;
mtx_assert(&port->lock, MA_OWNED);
port->mcast_count = 0;
if_maddr_rlock(ifp);
TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
if (ifma->ifma_addr->sa_family == AF_LINK) {
if (port->mcast_count == EFX_MAC_MULTICAST_LIST_MAX) {
device_printf(sc->dev,
"Too many multicast addresses\n");
rc = EINVAL;
break;
}
sa = (struct sockaddr_dl *)ifma->ifma_addr;
memcpy(mcast_addr, LLADDR(sa), EFX_MAC_ADDR_LEN);
mcast_addr += EFX_MAC_ADDR_LEN;
++port->mcast_count;
}
}
if_maddr_runlock(ifp);
if (rc == 0) {
rc = efx_mac_multicast_list_set(sc->enp, port->mcast_addrs,
port->mcast_count);
if (rc != 0)
device_printf(sc->dev,
"Cannot set multicast address list\n");
}
return (rc);
}
static int
sfxge_mac_filter_set_locked(struct sfxge_softc *sc)
{
struct ifnet *ifp = sc->ifnet;
struct sfxge_port *port = &sc->port;
boolean_t all_mulcst;
int rc;
/* Set promisc-unicast and broadcast filter bits */
if ((rc = efx_mac_filter_set(enp, !!(ifp->if_flags & IFF_PROMISC),
B_TRUE)) != 0)
return (rc);
mtx_assert(&port->lock, MA_OWNED);
/* Set multicast hash filter */
if (ifp->if_flags & (IFF_PROMISC | IFF_ALLMULTI)) {
for (index = 0; index < EFX_MAC_HASH_BITS; index++)
bucket[index] = 1;
} else {
/* Broadcast frames also go through the multicast
* filter, and the broadcast address hashes to
* 0xff. */
bucket[0xff] = 1;
all_mulcst = !!(ifp->if_flags & (IFF_PROMISC | IFF_ALLMULTI));
if_maddr_rlock(ifp);
TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
if (ifma->ifma_addr->sa_family == AF_LINK) {
sa = (struct sockaddr_dl *)ifma->ifma_addr;
index = ether_crc32_le(LLADDR(sa), 6) & 0xff;
bucket[index] = 1;
}
}
if_maddr_runlock(ifp);
}
return (efx_mac_hash_set(enp, bucket));
rc = sfxge_mac_multicast_list_set(sc);
/* Fallback to all multicast if cannot set multicast list */
if (rc != 0)
all_mulcst = B_TRUE;
rc = efx_mac_filter_set(sc->enp, !!(ifp->if_flags & IFF_PROMISC),
(port->mcast_count > 0), all_mulcst, B_TRUE);
return (rc);
}
int
@ -431,7 +458,9 @@ sfxge_port_stop(struct sfxge_softc *sc)
port->link_mode = EFX_LINK_UNKNOWN;
/* Destroy the common code port object. */
efx_port_fini(sc->enp);
efx_port_fini(enp);
efx_filter_fini(enp);
SFXGE_PORT_UNLOCK(port);
}
@ -455,6 +484,10 @@ sfxge_port_start(struct sfxge_softc *sc)
KASSERT(port->init_state == SFXGE_PORT_INITIALIZED,
("port not initialized"));
/* Initialise the required filtering */
if ((rc = efx_filter_init(enp)) != 0)
goto fail_filter_init;
/* Initialize the port object in the common code. */
if ((rc = efx_port_init(sc->enp)) != 0)
goto fail;
@ -466,7 +499,7 @@ sfxge_port_start(struct sfxge_softc *sc)
if ((rc = efx_mac_fcntl_set(enp, sfxge_port_wanted_fc(sc), B_TRUE))
!= 0)
goto fail2;
goto fail3;
/* Set the unicast address */
if_addr_rlock(ifp);
@ -474,24 +507,24 @@ sfxge_port_start(struct sfxge_softc *sc)
mac_addr, sizeof(mac_addr));
if_addr_runlock(ifp);
if ((rc = efx_mac_addr_set(enp, mac_addr)) != 0)
goto fail;
goto fail4;
sfxge_mac_filter_set_locked(sc);
/* Update MAC stats by DMA every second */
if ((rc = efx_mac_stats_periodic(enp, &port->mac_stats.dma_buf,
1000, B_FALSE)) != 0)
goto fail2;
1000, B_FALSE)) != 0)
goto fail6;
if ((rc = efx_mac_drain(enp, B_FALSE)) != 0)
goto fail3;
goto fail8;
if ((rc = sfxge_phy_cap_mask(sc, sc->media.ifm_cur->ifm_media,
&phy_cap_mask)) != 0)
goto fail4;
goto fail9;
if ((rc = efx_phy_adv_cap_set(sc->enp, phy_cap_mask)) != 0)
goto fail5;
goto fail10;
port->init_state = SFXGE_PORT_STARTED;
@ -501,15 +534,20 @@ sfxge_port_start(struct sfxge_softc *sc)
return (0);
fail5:
fail4:
fail10:
fail9:
(void)efx_mac_drain(enp, B_TRUE);
fail8:
(void)efx_mac_stats_periodic(enp, &port->mac_stats.dma_buf, 0, B_FALSE);
fail6:
fail4:
fail3:
(void)efx_mac_stats_periodic(enp, &port->mac_stats.dma_buf,
0, B_FALSE);
fail2:
efx_port_fini(sc->enp);
efx_port_fini(enp);
fail:
efx_filter_fini(enp);
fail_filter_init:
SFXGE_PORT_UNLOCK(port);
return (rc);
@ -652,12 +690,14 @@ sfxge_port_init(struct sfxge_softc *sc)
SFXGE_PORT_LOCK_INIT(port, device_get_nameunit(sc->dev));
DBGPRINT(sc->dev, "alloc PHY stats");
port->phy_stats.decode_buf = malloc(EFX_PHY_NSTATS * sizeof(uint32_t),
M_SFXGE, M_WAITOK | M_ZERO);
if ((rc = sfxge_dma_alloc(sc, EFX_PHY_STATS_SIZE, phy_stats_buf)) != 0)
goto fail;
sfxge_phy_stat_init(sc);
DBGPRINT(sc->dev, "init sysctl");
sysctl_ctx = device_get_sysctl_ctx(sc->dev);
sysctl_tree = device_get_sysctl_tree(sc->dev);
@ -673,6 +713,7 @@ sfxge_port_init(struct sfxge_softc *sc)
sfxge_port_link_fc_handler, "IU", "link flow control mode");
#endif
DBGPRINT(sc->dev, "alloc MAC stats");
port->mac_stats.decode_buf = malloc(EFX_MAC_NSTATS * sizeof(uint64_t),
M_SFXGE, M_WAITOK | M_ZERO);
if ((rc = sfxge_dma_alloc(sc, EFX_MAC_STATS_SIZE, mac_stats_buf)) != 0)
@ -681,6 +722,7 @@ sfxge_port_init(struct sfxge_softc *sc)
port->init_state = SFXGE_PORT_INITIALIZED;
DBGPRINT(sc->dev, "success");
return (0);
fail2:
@ -690,6 +732,7 @@ sfxge_port_init(struct sfxge_softc *sc)
free(port->phy_stats.decode_buf, M_SFXGE);
SFXGE_PORT_LOCK_DESTROY(port);
port->sc = NULL;
DBGPRINT(sc->dev, "failed %d", rc);
return (rc);
}
@ -704,6 +747,11 @@ static const int sfxge_link_mode[EFX_PHY_MEDIA_NTYPES][EFX_LINK_NMODES] = {
/* Don't know the module type, but assume SR for now. */
[EFX_LINK_10000FDX] = IFM_ETHER | IFM_FDX | IFM_10G_SR,
},
[EFX_PHY_MEDIA_QSFP_PLUS] = {
/* Don't know the module type, but assume SR for now. */
[EFX_LINK_10000FDX] = IFM_ETHER | IFM_FDX | IFM_10G_SR,
[EFX_LINK_40000FDX] = IFM_ETHER | IFM_FDX | IFM_40G_CR4,
},
[EFX_PHY_MEDIA_SFP_PLUS] = {
/* Don't know the module type, but assume SX/SR for now. */
[EFX_LINK_1000FDX] = IFM_ETHER | IFM_FDX | IFM_1000_SX,
@ -763,6 +811,8 @@ sfxge_link_mode_to_phy_cap(efx_link_mode_t mode)
return (EFX_PHY_CAP_1000FDX);
case EFX_LINK_10000FDX:
return (EFX_PHY_CAP_10000FDX);
case EFX_LINK_40000FDX:
return (EFX_PHY_CAP_40000FDX);
default:
EFSYS_ASSERT(B_FALSE);
return (EFX_PHY_CAP_INVALID);
@ -868,9 +918,13 @@ int sfxge_port_ifmedia_init(struct sfxge_softc *sc)
int mode_ifm, best_mode_ifm = 0;
int rc;
/* We need port state to initialise the ifmedia list. */
if ((rc = efx_nic_init(sc->enp)) != 0)
goto out;
/*
* We need port state to initialise the ifmedia list.
* It requires initialized NIC what is already done in
* sfxge_create() when resources are estimated.
*/
if ((rc = efx_filter_init(sc->enp)) != 0)
goto out1;
if ((rc = efx_port_init(sc->enp)) != 0)
goto out2;
@ -940,7 +994,7 @@ int sfxge_port_ifmedia_init(struct sfxge_softc *sc)
/* Now discard port state until interface is started. */
efx_port_fini(sc->enp);
out2:
efx_nic_fini(sc->enp);
out:
efx_filter_fini(sc->enp);
out1:
return (rc);
}

View File

@ -1,30 +1,34 @@
/*-
* Copyright (c) 2010-2011 Solarflare Communications, Inc.
* Copyright (c) 2010-2015 Solarflare Communications Inc.
* All rights reserved.
*
* This software was developed in part by Philip Paeps under contract for
* Solarflare Communications, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* modification, are permitted provided that the following conditions are met:
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the FreeBSD Project.
*/
#include <sys/cdefs.h>
@ -35,6 +39,7 @@ __FBSDID("$FreeBSD$");
#include <sys/smp.h>
#include <sys/socket.h>
#include <sys/sysctl.h>
#include <sys/syslog.h>
#include <sys/limits.h>
#include <sys/syslog.h>
@ -256,7 +261,7 @@ sfxge_rx_qfill(struct sfxge_rxq *rxq, unsigned int target, boolean_t retrying)
return;
batch = 0;
mblksize = sc->rx_buffer_size;
mblksize = sc->rx_buffer_size - sc->rx_buffer_align;
while (ntodo-- > 0) {
unsigned int id;
struct sfxge_rx_sw_desc *rx_desc;
@ -271,6 +276,12 @@ sfxge_rx_qfill(struct sfxge_rxq *rxq, unsigned int target, boolean_t retrying)
m = rx_desc->mbuf = sfxge_rx_alloc_mbuf(sc);
if (m == NULL)
break;
/* m_len specifies length of area to be mapped for DMA */
m->m_len = mblksize;
m->m_data = (caddr_t)P2ROUNDUP((uintptr_t)m->m_data, CACHE_LINE_SIZE);
m->m_data += sc->rx_buffer_align;
sfxge_map_mbuf_fast(rxq->mem.esm_tag, rxq->mem.esm_map, m, &seg);
addr[batch++] = seg.ds_addr;
@ -295,7 +306,15 @@ sfxge_rx_qfill(struct sfxge_rxq *rxq, unsigned int target, boolean_t retrying)
bus_dmamap_sync(rxq->mem.esm_tag, rxq->mem.esm_map,
BUS_DMASYNC_PREWRITE);
efx_rx_qpush(rxq->common, rxq->added);
efx_rx_qpush(rxq->common, rxq->added, &rxq->pushed);
/* The queue could still be empty if no descriptors were actually
* pushed, in which case there will be no event to cause the next
* refill, so we must schedule a refill ourselves.
*/
if(rxq->pushed == rxq->completed) {
sfxge_rx_schedule_refill(rxq, retrying);
}
}
void
@ -332,8 +351,10 @@ sfxge_rx_deliver(struct sfxge_softc *sc, struct sfxge_rx_sw_desc *rx_desc)
csum_flags |= CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
if (flags & (EFX_PKT_IPV4 | EFX_PKT_IPV6)) {
m->m_pkthdr.flowid = EFX_RX_HASH_VALUE(EFX_RX_HASHALG_TOEPLITZ,
mtod(m, uint8_t *));
m->m_pkthdr.flowid =
efx_psuedo_hdr_hash_get(sc->enp,
EFX_RX_HASHALG_TOEPLITZ,
mtod(m, uint8_t *));
/* The hash covers a 4-tuple for TCP only */
M_HASHTYPE_SET(m,
(flags & EFX_PKT_IPV4) ?
@ -666,8 +687,9 @@ sfxge_lro(struct sfxge_rxq *rxq, struct sfxge_rx_sw_desc *rx_buf)
unsigned bucket;
/* Get the hardware hash */
conn_hash = EFX_RX_HASH_VALUE(EFX_RX_HASHALG_TOEPLITZ,
mtod(m, uint8_t *));
conn_hash = efx_psuedo_hdr_hash_get(sc->enp,
EFX_RX_HASHALG_TOEPLITZ,
mtod(m, uint8_t *));
eh = (struct ether_header *)(m->m_data + sc->rx_prefix_size);
if (eh->ether_type == htons(ETHERTYPE_VLAN)) {
@ -824,6 +846,17 @@ sfxge_rx_qcomplete(struct sfxge_rxq *rxq, boolean_t eop)
if (rx_desc->flags & (EFX_ADDR_MISMATCH | EFX_DISCARD))
goto discard;
/* Read the length from the psuedo header if required */
if (rx_desc->flags & EFX_PKT_PREFIX_LEN) {
uint16_t tmp_size;
int rc;
rc = efx_psuedo_hdr_pkt_length_get(sc->enp,
mtod(m, uint8_t *),
&tmp_size);
KASSERT(rc == 0, ("cannot get packet length: %d", rc));
rx_desc->size = (int)tmp_size + sc->rx_prefix_size;
}
prefetch_read_many(mtod(m, caddr_t));
switch (rx_desc->flags & (EFX_PKT_IPV4 | EFX_PKT_IPV6)) {
@ -908,6 +941,9 @@ sfxge_rx_qstop(struct sfxge_softc *sc, unsigned int index)
struct sfxge_rxq *rxq;
struct sfxge_evq *evq;
unsigned int count;
unsigned int retry = 3;
SFXGE_ADAPTER_LOCK_ASSERT_OWNED(sc);
rxq = sc->rxq[index];
evq = sc->evq[index];
@ -921,30 +957,43 @@ sfxge_rx_qstop(struct sfxge_softc *sc, unsigned int index)
callout_stop(&rxq->refill_callout);
again:
rxq->flush_state = SFXGE_FLUSH_PENDING;
while (rxq->flush_state != SFXGE_FLUSH_DONE && retry != 0) {
rxq->flush_state = SFXGE_FLUSH_PENDING;
/* Flush the receive queue */
efx_rx_qflush(rxq->common);
SFXGE_EVQ_UNLOCK(evq);
SFXGE_EVQ_UNLOCK(evq);
count = 0;
do {
/* Spin for 100 ms */
DELAY(100000);
if (rxq->flush_state != SFXGE_FLUSH_PENDING)
/* Flush the receive queue */
if (efx_rx_qflush(rxq->common) != 0) {
SFXGE_EVQ_LOCK(evq);
rxq->flush_state = SFXGE_FLUSH_FAILED;
break;
}
} while (++count < 20);
count = 0;
do {
/* Spin for 100 ms */
DELAY(100000);
SFXGE_EVQ_LOCK(evq);
if (rxq->flush_state != SFXGE_FLUSH_PENDING)
break;
if (rxq->flush_state == SFXGE_FLUSH_FAILED)
goto again;
} while (++count < 20);
rxq->flush_state = SFXGE_FLUSH_DONE;
SFXGE_EVQ_LOCK(evq);
if (rxq->flush_state == SFXGE_FLUSH_PENDING) {
/* Flush timeout - neither done nor failed */
log(LOG_ERR, "%s: Cannot flush Rx queue %u\n",
device_get_nameunit(sc->dev), index);
rxq->flush_state = SFXGE_FLUSH_DONE;
}
retry--;
}
if (rxq->flush_state == SFXGE_FLUSH_FAILED) {
log(LOG_ERR, "%s: Flushing Rx queue %u failed\n",
device_get_nameunit(sc->dev), index);
rxq->flush_state = SFXGE_FLUSH_DONE;
}
rxq->pending = rxq->added;
sfxge_rx_qcomplete(rxq, B_TRUE);
@ -953,6 +1002,7 @@ sfxge_rx_qstop(struct sfxge_softc *sc, unsigned int index)
("rxq->completed != rxq->pending"));
rxq->added = 0;
rxq->pushed = 0;
rxq->pending = 0;
rxq->completed = 0;
rxq->loopback = 0;
@ -974,6 +1024,8 @@ sfxge_rx_qstart(struct sfxge_softc *sc, unsigned int index)
struct sfxge_evq *evq;
int rc;
SFXGE_ADAPTER_LOCK_ASSERT_OWNED(sc);
rxq = sc->rxq[index];
esmp = &rxq->mem;
evq = sc->evq[index];
@ -1000,6 +1052,7 @@ sfxge_rx_qstart(struct sfxge_softc *sc, unsigned int index)
efx_rx_qenable(rxq->common);
rxq->init_state = SFXGE_RXQ_STARTED;
rxq->flush_state = SFXGE_FLUSH_REQUIRED;
/* Try to fill the queue from the pool. */
sfxge_rx_qfill(rxq, EFX_RXQ_LIMIT(sc->rxq_entries), B_FALSE);
@ -1019,6 +1072,8 @@ sfxge_rx_stop(struct sfxge_softc *sc)
{
int index;
efx_mac_filter_default_rxq_clear(sc->enp);
/* Stop the receive queue(s) */
index = sc->rxq_count;
while (--index >= 0)
@ -1034,6 +1089,8 @@ int
sfxge_rx_start(struct sfxge_softc *sc)
{
struct sfxge_intr *intr;
const efx_nic_cfg_t *encp;
size_t hdrlen, align, reserved;
int index;
int rc;
@ -1043,17 +1100,35 @@ sfxge_rx_start(struct sfxge_softc *sc)
if ((rc = efx_rx_init(sc->enp)) != 0)
return (rc);
/* Calculate the receive packet buffer size. */
sc->rx_prefix_size = EFX_RX_PREFIX_SIZE;
sc->rx_buffer_size = (EFX_MAC_PDU(sc->ifnet->if_mtu) +
sc->rx_prefix_size);
encp = efx_nic_cfg_get(sc->enp);
sc->rx_buffer_size = EFX_MAC_PDU(sc->ifnet->if_mtu);
/* Calculate the receive packet buffer size. */
sc->rx_prefix_size = encp->enc_rx_prefix_size;
/* Ensure IP headers are 32bit aligned */
hdrlen = sc->rx_prefix_size + sizeof (struct ether_header);
sc->rx_buffer_align = P2ROUNDUP(hdrlen, 4) - hdrlen;
sc->rx_buffer_size += sc->rx_buffer_align;
/* Align end of packet buffer for RX DMA end padding */
align = MAX(1, encp->enc_rx_buf_align_end);
EFSYS_ASSERT(ISP2(align));
sc->rx_buffer_size = P2ROUNDUP(sc->rx_buffer_size, align);
/*
* Standard mbuf zones only guarantee pointer-size alignment;
* we need extra space to align to the cache line
*/
reserved = sc->rx_buffer_size + CACHE_LINE_SIZE;
/* Select zone for packet buffers */
if (sc->rx_buffer_size <= MCLBYTES)
if (reserved <= MCLBYTES)
sc->rx_buffer_zone = zone_clust;
else if (sc->rx_buffer_size <= MJUMPAGESIZE)
else if (reserved <= MJUMPAGESIZE)
sc->rx_buffer_zone = zone_jumbop;
else if (sc->rx_buffer_size <= MJUM9BYTES)
else if (reserved <= MJUM9BYTES)
sc->rx_buffer_zone = zone_jumbo9;
else
sc->rx_buffer_zone = zone_jumbo16;
@ -1070,8 +1145,8 @@ sfxge_rx_start(struct sfxge_softc *sc)
(1 << EFX_RX_HASH_IPV4) | (1 << EFX_RX_HASH_TCPIPV4) |
(1 << EFX_RX_HASH_IPV6) | (1 << EFX_RX_HASH_TCPIPV6), B_TRUE);
if ((rc = efx_rx_scale_toeplitz_ipv4_key_set(sc->enp, toep_key,
sizeof(toep_key))) != 0)
if ((rc = efx_rx_scale_key_set(sc->enp, toep_key,
sizeof(toep_key))) != 0)
goto fail;
/* Start the receive queue(s). */
@ -1080,8 +1155,14 @@ sfxge_rx_start(struct sfxge_softc *sc)
goto fail2;
}
rc = efx_mac_filter_default_rxq_set(sc->enp, sc->rxq[0]->common,
sc->intr.n_alloc > 1);
if (rc != 0)
goto fail3;
return (0);
fail3:
fail2:
while (--index >= 0)
sfxge_rx_qstop(sc, index);

View File

@ -1,30 +1,34 @@
/*-
* Copyright (c) 2010-2011 Solarflare Communications, Inc.
* Copyright (c) 2010-2015 Solarflare Communications Inc.
* All rights reserved.
*
* This software was developed in part by Philip Paeps under contract for
* Solarflare Communications, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* modification, are permitted provided that the following conditions are met:
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the FreeBSD Project.
*
* $FreeBSD$
*/
@ -39,22 +43,22 @@
#define SFXGE_LRO 1
#endif
#define SFXGE_MAGIC_RESERVED 0x8000
#define SFXGE_MAGIC_RESERVED 0x8000
#define SFXGE_MAGIC_DMAQ_LABEL_WIDTH 6
#define SFXGE_MAGIC_DMAQ_LABEL_MASK \
#define SFXGE_MAGIC_DMAQ_LABEL_MASK \
((1 << SFXGE_MAGIC_DMAQ_LABEL_WIDTH) - 1)
#define SFXGE_MAGIC_RX_QFLUSH_DONE \
#define SFXGE_MAGIC_RX_QFLUSH_DONE \
(SFXGE_MAGIC_RESERVED | (1 << SFXGE_MAGIC_DMAQ_LABEL_WIDTH))
#define SFXGE_MAGIC_RX_QFLUSH_FAILED \
#define SFXGE_MAGIC_RX_QFLUSH_FAILED \
(SFXGE_MAGIC_RESERVED | (2 << SFXGE_MAGIC_DMAQ_LABEL_WIDTH))
#define SFXGE_MAGIC_RX_QREFILL \
#define SFXGE_MAGIC_RX_QREFILL \
(SFXGE_MAGIC_RESERVED | (3 << SFXGE_MAGIC_DMAQ_LABEL_WIDTH))
#define SFXGE_MAGIC_TX_QFLUSH_DONE \
#define SFXGE_MAGIC_TX_QFLUSH_DONE \
(SFXGE_MAGIC_RESERVED | (4 << SFXGE_MAGIC_DMAQ_LABEL_WIDTH))
#define SFXGE_RX_SCALE_MAX EFX_MAXRSS
@ -152,6 +156,7 @@ struct sfxge_lro_state {
enum sfxge_flush_state {
SFXGE_FLUSH_DONE = 0,
SFXGE_FLUSH_REQUIRED,
SFXGE_FLUSH_PENDING,
SFXGE_FLUSH_FAILED
};
@ -175,6 +180,7 @@ struct sfxge_rxq {
struct sfxge_rx_sw_desc *queue __aligned(CACHE_LINE_SIZE);
unsigned int added;
unsigned int pushed;
unsigned int pending;
unsigned int completed;
unsigned int loopback;

View File

@ -1,30 +1,34 @@
/*-
* Copyright (c) 2010-2011 Solarflare Communications, Inc.
* Copyright (c) 2010-2015 Solarflare Communications Inc.
* All rights reserved.
*
* This software was developed in part by Philip Paeps under contract for
* Solarflare Communications, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* modification, are permitted provided that the following conditions are met:
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the FreeBSD Project.
*/
/* Theory of operation:
@ -67,23 +71,6 @@ __FBSDID("$FreeBSD$");
#include "sfxge.h"
#include "sfxge_tx.h"
/*
* Estimate maximum number of Tx descriptors required for TSO packet.
* With minimum MSS and maximum mbuf length we might need more (even
* than a ring-ful of descriptors), but this should not happen in
* practice except due to deliberate attack. In that case we will
* truncate the output at a packet boundary.
*/
#define SFXGE_TSO_MAX_DESC \
(SFXGE_TSO_MAX_SEGS * 2 + SFXGE_TX_MAPPING_MAX_SEG - 1)
/*
* Set the block level to ensure there is space to generate a
* large number of descriptors for TSO.
*/
#define SFXGE_TXQ_BLOCK_LEVEL(_entries) \
(EFX_TXQ_LIMIT(_entries) - SFXGE_TSO_MAX_DESC)
#define SFXGE_PARAM_TX_DPL_GET_MAX SFXGE_PARAM(tx_dpl_get_max)
static int sfxge_tx_dpl_get_max = SFXGE_TX_DPL_GET_PKT_LIMIT_DEFAULT;
@ -108,6 +95,13 @@ SYSCTL_INT(_hw_sfxge, OID_AUTO, tx_dpl_put_max, CTLFLAG_RDTUN,
&sfxge_tx_dpl_put_max, 0,
"Maximum number of any packets in deferred packet put-list");
#define SFXGE_PARAM_TSO_FW_ASSISTED SFXGE_PARAM(tso_fw_assisted)
static int sfxge_tso_fw_assisted = 1;
TUNABLE_INT(SFXGE_PARAM_TSO_FW_ASSISTED, &sfxge_tso_fw_assisted);
SYSCTL_INT(_hw_sfxge, OID_AUTO, tso_fw_assisted, CTLFLAG_RDTUN,
&sfxge_tso_fw_assisted, 0,
"Use FW-assisted TSO if supported by NIC firmware");
static const struct {
const char *name;
@ -134,7 +128,38 @@ static void sfxge_tx_qdpl_service(struct sfxge_txq *txq);
static void sfxge_tx_qlist_post(struct sfxge_txq *txq);
static void sfxge_tx_qunblock(struct sfxge_txq *txq);
static int sfxge_tx_queue_tso(struct sfxge_txq *txq, struct mbuf *mbuf,
const bus_dma_segment_t *dma_seg, int n_dma_seg);
const bus_dma_segment_t *dma_seg, int n_dma_seg,
int vlan_tagged);
static int
sfxge_tx_maybe_insert_tag(struct sfxge_txq *txq, struct mbuf *mbuf)
{
uint16_t this_tag = ((mbuf->m_flags & M_VLANTAG) ?
mbuf->m_pkthdr.ether_vtag :
0);
if (this_tag == txq->hw_vlan_tci)
return (0);
efx_tx_qdesc_vlantci_create(txq->common,
bswap16(this_tag),
&txq->pend_desc[0]);
txq->n_pend_desc = 1;
txq->hw_vlan_tci = this_tag;
return (1);
}
static inline void
sfxge_next_stmp(struct sfxge_txq *txq, struct sfxge_tx_mapping **pstmp)
{
KASSERT((*pstmp)->flags == 0, ("stmp flags are not 0"));
if (__predict_false(*pstmp ==
&txq->stmp[txq->ptr_mask]))
*pstmp = &txq->stmp[0];
else
(*pstmp)++;
}
void
sfxge_tx_qcomplete(struct sfxge_txq *txq, struct sfxge_evq *evq)
@ -252,29 +277,30 @@ static void
sfxge_tx_qlist_post(struct sfxge_txq *txq)
{
unsigned int old_added;
unsigned int block_level;
unsigned int level;
int rc;
SFXGE_TXQ_LOCK_ASSERT_OWNED(txq);
KASSERT(txq->n_pend_desc != 0, ("txq->n_pend_desc == 0"));
KASSERT(txq->n_pend_desc <= SFXGE_TSO_MAX_DESC,
KASSERT(txq->n_pend_desc <= txq->max_pkt_desc,
("txq->n_pend_desc too large"));
KASSERT(!txq->blocked, ("txq->blocked"));
old_added = txq->added;
/* Post the fragment list. */
rc = efx_tx_qpost(txq->common, txq->pend_desc, txq->n_pend_desc,
rc = efx_tx_qdesc_post(txq->common, txq->pend_desc, txq->n_pend_desc,
txq->reaped, &txq->added);
KASSERT(rc == 0, ("efx_tx_qpost() failed"));
KASSERT(rc == 0, ("efx_tx_qdesc_post() failed"));
/* If efx_tx_qpost() had to refragment, our information about
/* If efx_tx_qdesc_post() had to refragment, our information about
* buffers to free may be associated with the wrong
* descriptors.
*/
KASSERT(txq->added - old_added == txq->n_pend_desc,
("efx_tx_qpost() refragmented descriptors"));
("efx_tx_qdesc_post() refragmented descriptors"));
level = txq->added - txq->reaped;
KASSERT(level <= txq->entries, ("overfilled TX queue"));
@ -282,14 +308,20 @@ sfxge_tx_qlist_post(struct sfxge_txq *txq)
/* Clear the fragment list. */
txq->n_pend_desc = 0;
/*
* Set the block level to ensure there is space to generate a
* large number of descriptors for TSO.
*/
block_level = EFX_TXQ_LIMIT(txq->entries) - txq->max_pkt_desc;
/* Have we reached the block level? */
if (level < SFXGE_TXQ_BLOCK_LEVEL(txq->entries))
if (level < block_level)
return;
/* Reap, and check again */
sfxge_tx_qreap(txq);
level = txq->added - txq->reaped;
if (level < SFXGE_TXQ_BLOCK_LEVEL(txq->entries))
if (level < block_level)
return;
txq->blocked = 1;
@ -301,7 +333,7 @@ sfxge_tx_qlist_post(struct sfxge_txq *txq)
mb();
sfxge_tx_qreap(txq);
level = txq->added - txq->reaped;
if (level < SFXGE_TXQ_BLOCK_LEVEL(txq->entries)) {
if (level < block_level) {
mb();
txq->blocked = 0;
}
@ -314,10 +346,12 @@ static int sfxge_tx_queue_mbuf(struct sfxge_txq *txq, struct mbuf *mbuf)
bus_dma_segment_t dma_seg[SFXGE_TX_MAPPING_MAX_SEG];
unsigned int id;
struct sfxge_tx_mapping *stmp;
efx_buffer_t *desc;
efx_desc_t *desc;
int n_dma_seg;
int rc;
int i;
int eop;
int vlan_tagged;
KASSERT(!txq->blocked, ("txq->blocked"));
@ -354,35 +388,35 @@ static int sfxge_tx_queue_mbuf(struct sfxge_txq *txq, struct mbuf *mbuf)
used_map = &stmp->map;
vlan_tagged = sfxge_tx_maybe_insert_tag(txq, mbuf);
if (vlan_tagged) {
sfxge_next_stmp(txq, &stmp);
}
if (mbuf->m_pkthdr.csum_flags & CSUM_TSO) {
rc = sfxge_tx_queue_tso(txq, mbuf, dma_seg, n_dma_seg);
rc = sfxge_tx_queue_tso(txq, mbuf, dma_seg, n_dma_seg, vlan_tagged);
if (rc < 0)
goto reject_mapped;
stmp = &txq->stmp[rc];
stmp = &txq->stmp[(rc - 1) & txq->ptr_mask];
} else {
/* Add the mapping to the fragment list, and set flags
* for the buffer.
*/
i = 0;
for (;;) {
desc = &txq->pend_desc[i];
desc->eb_addr = dma_seg[i].ds_addr;
desc->eb_size = dma_seg[i].ds_len;
if (i == n_dma_seg - 1) {
desc->eb_eop = 1;
desc = &txq->pend_desc[i + vlan_tagged];
eop = (i == n_dma_seg - 1);
efx_tx_qdesc_dma_create(txq->common,
dma_seg[i].ds_addr,
dma_seg[i].ds_len,
eop,
desc);
if (eop)
break;
}
desc->eb_eop = 0;
i++;
stmp->flags = 0;
if (__predict_false(stmp ==
&txq->stmp[txq->ptr_mask]))
stmp = &txq->stmp[0];
else
stmp++;
sfxge_next_stmp(txq, &stmp);
}
txq->n_pend_desc = n_dma_seg;
txq->n_pend_desc = n_dma_seg + vlan_tagged;
}
/*
@ -469,7 +503,7 @@ sfxge_tx_qdpl_drain(struct sfxge_txq *txq)
/* Push the fragments to the hardware in batches. */
if (txq->added - pushed >= SFXGE_TX_BATCH) {
efx_tx_qpush(txq->common, txq->added);
efx_tx_qpush(txq->common, txq->added, pushed);
pushed = txq->added;
}
}
@ -489,14 +523,13 @@ sfxge_tx_qdpl_drain(struct sfxge_txq *txq)
}
if (txq->added != pushed)
efx_tx_qpush(txq->common, txq->added);
efx_tx_qpush(txq->common, txq->added, pushed);
KASSERT(txq->blocked || stdp->std_get_count == 0,
("queue unblocked but count is non-zero"));
}
#define SFXGE_TX_QDPL_PENDING(_txq) \
((_txq)->dpl.std_put != 0)
#define SFXGE_TX_QDPL_PENDING(_txq) ((_txq)->dpl.std_put != 0)
/*
* Service the deferred packet list.
@ -599,7 +632,7 @@ sfxge_tx_qdpl_put_unlocked(struct sfxge_txq *txq, struct mbuf *mbuf)
* Called from if_transmit - will try to grab the txq lock and enqueue to the
* put list if it succeeds, otherwise try to push onto the defer list if space.
*/
int
static int
sfxge_tx_packet_add(struct sfxge_txq *txq, struct mbuf *m)
{
int rc;
@ -746,6 +779,10 @@ struct sfxge_tso_state {
ssize_t tcph_off; /* Offset of TCP header */
unsigned header_len; /* Number of bytes of header */
unsigned seg_size; /* TCP segment size */
int fw_assisted; /* Use FW-assisted TSO */
u_short packet_id; /* IPv4 packet ID from the original packet */
efx_desc_t header_desc; /* Precomputed header descriptor for
* FW-assisted TSO */
};
static const struct ip *tso_iph(const struct sfxge_tso_state *tso)
@ -816,12 +853,16 @@ static void tso_fini(struct sfxge_txq *txq)
}
}
static void tso_start(struct sfxge_tso_state *tso, struct mbuf *mbuf)
static void tso_start(struct sfxge_txq *txq, struct sfxge_tso_state *tso,
const bus_dma_segment_t *hdr_dma_seg,
struct mbuf *mbuf)
{
struct ether_header *eh = mtod(mbuf, struct ether_header *);
const efx_nic_cfg_t *encp = efx_nic_cfg_get(txq->sc->enp);
const struct tcphdr *th;
struct tcphdr th_copy;
tso->fw_assisted = txq->sc->tso_fw_assisted;
tso->mbuf = mbuf;
/* Find network protocol and header */
@ -840,12 +881,19 @@ static void tso_start(struct sfxge_tso_state *tso, struct mbuf *mbuf)
KASSERT(tso_iph(tso)->ip_p == IPPROTO_TCP,
("TSO required on non-TCP packet"));
tso->tcph_off = tso->nh_off + 4 * tso_iph(tso)->ip_hl;
tso->packet_id = tso_iph(tso)->ip_id;
} else {
KASSERT(tso->protocol == htons(ETHERTYPE_IPV6),
("TSO required on non-IP packet"));
KASSERT(tso_ip6h(tso)->ip6_nxt == IPPROTO_TCP,
("TSO required on non-TCP packet"));
tso->tcph_off = tso->nh_off + sizeof(struct ip6_hdr);
tso->packet_id = 0;
}
if (tso->fw_assisted &&
__predict_false(tso->tcph_off >
encp->enc_tx_tso_tcp_header_offset_limit)) {
tso->fw_assisted = 0;
}
KASSERT(mbuf->m_len >= tso->tcph_off,
@ -875,6 +923,17 @@ static void tso_start(struct sfxge_tso_state *tso, struct mbuf *mbuf)
th->th_flags & (TH_URG | TH_SYN)));
tso->out_len = mbuf->m_pkthdr.len - tso->header_len;
if (tso->fw_assisted) {
if (hdr_dma_seg->ds_len >= tso->header_len)
efx_tx_qdesc_dma_create(txq->common,
hdr_dma_seg->ds_addr,
tso->header_len,
B_FALSE,
&tso->header_desc);
else
tso->fw_assisted = 0;
}
}
/*
@ -887,7 +946,7 @@ static void tso_start(struct sfxge_tso_state *tso, struct mbuf *mbuf)
static void tso_fill_packet_with_fragment(struct sfxge_txq *txq,
struct sfxge_tso_state *tso)
{
efx_buffer_t *desc;
efx_desc_t *desc;
int n;
if (tso->in_len == 0 || tso->packet_space == 0)
@ -903,9 +962,11 @@ static void tso_fill_packet_with_fragment(struct sfxge_txq *txq,
tso->in_len -= n;
desc = &txq->pend_desc[txq->n_pend_desc++];
desc->eb_addr = tso->dma_addr;
desc->eb_size = n;
desc->eb_eop = tso->out_len == 0 || tso->packet_space == 0;
efx_tx_qdesc_dma_create(txq->common,
tso->dma_addr,
n,
tso->out_len == 0 || tso->packet_space == 0,
desc);
tso->dma_addr += n;
}
@ -928,107 +989,139 @@ static void tso_map_long_header(void *dma_addr_ret,
*/
static int tso_start_new_packet(struct sfxge_txq *txq,
struct sfxge_tso_state *tso,
unsigned int id)
unsigned int *idp)
{
struct sfxge_tx_mapping *stmp = &txq->stmp[id];
unsigned int id = *idp;
struct tcphdr *tsoh_th;
unsigned ip_length;
caddr_t header;
uint64_t dma_addr;
bus_dmamap_t map;
efx_buffer_t *desc;
efx_desc_t *desc;
int rc;
/* Allocate a DMA-mapped header buffer. */
if (__predict_true(tso->header_len <= TSOH_STD_SIZE)) {
unsigned int page_index = (id / 2) / TSOH_PER_PAGE;
unsigned int buf_index = (id / 2) % TSOH_PER_PAGE;
if (tso->fw_assisted) {
uint8_t tcp_flags = tso_tcph(tso)->th_flags;
header = (txq->tsoh_buffer[page_index].esm_base +
buf_index * TSOH_STD_SIZE);
dma_addr = (txq->tsoh_buffer[page_index].esm_addr +
buf_index * TSOH_STD_SIZE);
map = txq->tsoh_buffer[page_index].esm_map;
if (tso->out_len > tso->seg_size)
tcp_flags &= ~(TH_FIN | TH_PUSH);
stmp->flags = 0;
/* TSO option descriptor */
desc = &txq->pend_desc[txq->n_pend_desc++];
efx_tx_qdesc_tso_create(txq->common,
tso->packet_id,
tso->seqnum,
tcp_flags,
desc++);
KASSERT(txq->stmp[id].flags == 0, ("stmp flags are not 0"));
id = (id + 1) & txq->ptr_mask;
/* Header DMA descriptor */
*desc = tso->header_desc;
txq->n_pend_desc++;
KASSERT(txq->stmp[id].flags == 0, ("stmp flags are not 0"));
id = (id + 1) & txq->ptr_mask;
tso->seqnum += tso->seg_size;
} else {
/* We cannot use bus_dmamem_alloc() as that may sleep */
header = malloc(tso->header_len, M_SFXGE, M_NOWAIT);
if (__predict_false(!header))
return (ENOMEM);
rc = bus_dmamap_load(txq->packet_dma_tag, stmp->map,
header, tso->header_len,
tso_map_long_header, &dma_addr,
BUS_DMA_NOWAIT);
if (__predict_false(dma_addr == 0)) {
if (rc == 0) {
/* Succeeded but got >1 segment */
bus_dmamap_unload(txq->packet_dma_tag,
stmp->map);
rc = EINVAL;
/* Allocate a DMA-mapped header buffer. */
if (__predict_true(tso->header_len <= TSOH_STD_SIZE)) {
unsigned int page_index = (id / 2) / TSOH_PER_PAGE;
unsigned int buf_index = (id / 2) % TSOH_PER_PAGE;
header = (txq->tsoh_buffer[page_index].esm_base +
buf_index * TSOH_STD_SIZE);
dma_addr = (txq->tsoh_buffer[page_index].esm_addr +
buf_index * TSOH_STD_SIZE);
map = txq->tsoh_buffer[page_index].esm_map;
KASSERT(txq->stmp[id].flags == 0,
("stmp flags are not 0"));
} else {
struct sfxge_tx_mapping *stmp = &txq->stmp[id];
/* We cannot use bus_dmamem_alloc() as that may sleep */
header = malloc(tso->header_len, M_SFXGE, M_NOWAIT);
if (__predict_false(!header))
return (ENOMEM);
rc = bus_dmamap_load(txq->packet_dma_tag, stmp->map,
header, tso->header_len,
tso_map_long_header, &dma_addr,
BUS_DMA_NOWAIT);
if (__predict_false(dma_addr == 0)) {
if (rc == 0) {
/* Succeeded but got >1 segment */
bus_dmamap_unload(txq->packet_dma_tag,
stmp->map);
rc = EINVAL;
}
free(header, M_SFXGE);
return (rc);
}
free(header, M_SFXGE);
return (rc);
map = stmp->map;
txq->tso_long_headers++;
stmp->u.heap_buf = header;
stmp->flags = TX_BUF_UNMAP;
}
map = stmp->map;
txq->tso_long_headers++;
stmp->u.heap_buf = header;
stmp->flags = TX_BUF_UNMAP;
tsoh_th = (struct tcphdr *)(header + tso->tcph_off);
/* Copy and update the headers. */
m_copydata(tso->mbuf, 0, tso->header_len, header);
tsoh_th->th_seq = htonl(tso->seqnum);
tso->seqnum += tso->seg_size;
if (tso->out_len > tso->seg_size) {
/* This packet will not finish the TSO burst. */
ip_length = tso->header_len - tso->nh_off + tso->seg_size;
tsoh_th->th_flags &= ~(TH_FIN | TH_PUSH);
} else {
/* This packet will be the last in the TSO burst. */
ip_length = tso->header_len - tso->nh_off + tso->out_len;
}
if (tso->protocol == htons(ETHERTYPE_IP)) {
struct ip *tsoh_iph = (struct ip *)(header + tso->nh_off);
tsoh_iph->ip_len = htons(ip_length);
/* XXX We should increment ip_id, but FreeBSD doesn't
* currently allocate extra IDs for multiple segments.
*/
} else {
struct ip6_hdr *tsoh_iph =
(struct ip6_hdr *)(header + tso->nh_off);
tsoh_iph->ip6_plen = htons(ip_length - sizeof(*tsoh_iph));
}
/* Make the header visible to the hardware. */
bus_dmamap_sync(txq->packet_dma_tag, map, BUS_DMASYNC_PREWRITE);
/* Form a descriptor for this header. */
desc = &txq->pend_desc[txq->n_pend_desc++];
efx_tx_qdesc_dma_create(txq->common,
dma_addr,
tso->header_len,
0,
desc);
id = (id + 1) & txq->ptr_mask;
}
tsoh_th = (struct tcphdr *)(header + tso->tcph_off);
/* Copy and update the headers. */
m_copydata(tso->mbuf, 0, tso->header_len, header);
tsoh_th->th_seq = htonl(tso->seqnum);
tso->seqnum += tso->seg_size;
if (tso->out_len > tso->seg_size) {
/* This packet will not finish the TSO burst. */
ip_length = tso->header_len - tso->nh_off + tso->seg_size;
tsoh_th->th_flags &= ~(TH_FIN | TH_PUSH);
} else {
/* This packet will be the last in the TSO burst. */
ip_length = tso->header_len - tso->nh_off + tso->out_len;
}
if (tso->protocol == htons(ETHERTYPE_IP)) {
struct ip *tsoh_iph = (struct ip *)(header + tso->nh_off);
tsoh_iph->ip_len = htons(ip_length);
/* XXX We should increment ip_id, but FreeBSD doesn't
* currently allocate extra IDs for multiple segments.
*/
} else {
struct ip6_hdr *tsoh_iph =
(struct ip6_hdr *)(header + tso->nh_off);
tsoh_iph->ip6_plen = htons(ip_length - sizeof(*tsoh_iph));
}
/* Make the header visible to the hardware. */
bus_dmamap_sync(txq->packet_dma_tag, map, BUS_DMASYNC_PREWRITE);
tso->packet_space = tso->seg_size;
txq->tso_packets++;
/* Form a descriptor for this header. */
desc = &txq->pend_desc[txq->n_pend_desc++];
desc->eb_addr = dma_addr;
desc->eb_size = tso->header_len;
desc->eb_eop = 0;
*idp = id;
return (0);
}
static int
sfxge_tx_queue_tso(struct sfxge_txq *txq, struct mbuf *mbuf,
const bus_dma_segment_t *dma_seg, int n_dma_seg)
const bus_dma_segment_t *dma_seg, int n_dma_seg,
int vlan_tagged)
{
struct sfxge_tso_state tso;
unsigned int id, next_id;
unsigned int id;
unsigned skipped = 0;
tso_start(&tso, mbuf);
tso_start(txq, &tso, dma_seg, mbuf);
while (dma_seg->ds_len + skipped <= tso.header_len) {
skipped += dma_seg->ds_len;
@ -1039,13 +1132,15 @@ sfxge_tx_queue_tso(struct sfxge_txq *txq, struct mbuf *mbuf,
tso.in_len = dma_seg->ds_len - (tso.header_len - skipped);
tso.dma_addr = dma_seg->ds_addr + (tso.header_len - skipped);
id = txq->added & txq->ptr_mask;
if (__predict_false(tso_start_new_packet(txq, &tso, id)))
id = (txq->added + vlan_tagged) & txq->ptr_mask;
if (__predict_false(tso_start_new_packet(txq, &tso, &id)))
return (-1);
while (1) {
id = (id + 1) & txq->ptr_mask;
tso_fill_packet_with_fragment(txq, &tso);
/* Exactly one DMA descriptor is added */
KASSERT(txq->stmp[id].flags == 0, ("stmp flags are not 0"));
id = (id + 1) & txq->ptr_mask;
/* Move onto the next fragment? */
if (tso.in_len == 0) {
@ -1064,18 +1159,17 @@ sfxge_tx_queue_tso(struct sfxge_txq *txq, struct mbuf *mbuf,
* the remainder of the input mbuf but do not
* roll back the work we have done.
*/
if (txq->n_pend_desc + 1 /* header */ + n_dma_seg >
SFXGE_TSO_MAX_DESC) {
if (txq->n_pend_desc + tso.fw_assisted +
1 /* header */ + n_dma_seg >
txq->max_pkt_desc) {
txq->tso_pdrop_too_many++;
break;
}
next_id = (id + 1) & txq->ptr_mask;
if (__predict_false(tso_start_new_packet(txq, &tso,
next_id))) {
&id))) {
txq->tso_pdrop_no_rsrc++;
break;
}
id = next_id;
}
}
@ -1128,38 +1222,52 @@ sfxge_tx_qstop(struct sfxge_softc *sc, unsigned int index)
struct sfxge_evq *evq;
unsigned int count;
SFXGE_ADAPTER_LOCK_ASSERT_OWNED(sc);
txq = sc->txq[index];
evq = sc->evq[txq->evq_index];
SFXGE_EVQ_LOCK(evq);
SFXGE_TXQ_LOCK(txq);
KASSERT(txq->init_state == SFXGE_TXQ_STARTED,
("txq->init_state != SFXGE_TXQ_STARTED"));
txq->init_state = SFXGE_TXQ_INITIALIZED;
txq->flush_state = SFXGE_FLUSH_PENDING;
/* Flush the transmit queue. */
efx_tx_qflush(txq->common);
if (txq->flush_state != SFXGE_FLUSH_DONE) {
txq->flush_state = SFXGE_FLUSH_PENDING;
SFXGE_TXQ_UNLOCK(txq);
SFXGE_EVQ_UNLOCK(evq);
SFXGE_TXQ_UNLOCK(txq);
count = 0;
do {
/* Spin for 100ms. */
DELAY(100000);
/* Flush the transmit queue. */
if (efx_tx_qflush(txq->common) != 0) {
log(LOG_ERR, "%s: Flushing Tx queue %u failed\n",
device_get_nameunit(sc->dev), index);
txq->flush_state = SFXGE_FLUSH_DONE;
} else {
count = 0;
do {
/* Spin for 100ms. */
DELAY(100000);
if (txq->flush_state != SFXGE_FLUSH_PENDING)
break;
} while (++count < 20);
}
SFXGE_EVQ_LOCK(evq);
SFXGE_TXQ_LOCK(txq);
if (txq->flush_state != SFXGE_FLUSH_PENDING)
break;
} while (++count < 20);
KASSERT(txq->flush_state != SFXGE_FLUSH_FAILED,
("txq->flush_state == SFXGE_FLUSH_FAILED"));
SFXGE_EVQ_LOCK(evq);
SFXGE_TXQ_LOCK(txq);
KASSERT(txq->flush_state != SFXGE_FLUSH_FAILED,
("txq->flush_state == SFXGE_FLUSH_FAILED"));
txq->flush_state = SFXGE_FLUSH_DONE;
if (txq->flush_state != SFXGE_FLUSH_DONE) {
/* Flush timeout */
log(LOG_ERR, "%s: Cannot flush Tx queue %u\n",
device_get_nameunit(sc->dev), index);
txq->flush_state = SFXGE_FLUSH_DONE;
}
}
txq->blocked = 0;
txq->pending = txq->added;
@ -1195,8 +1303,11 @@ sfxge_tx_qstart(struct sfxge_softc *sc, unsigned int index)
efsys_mem_t *esmp;
uint16_t flags;
struct sfxge_evq *evq;
unsigned int desc_index;
int rc;
SFXGE_ADAPTER_LOCK_ASSERT_OWNED(sc);
txq = sc->txq[index];
esmp = &txq->mem;
evq = sc->evq[txq->evq_index];
@ -1231,15 +1342,19 @@ sfxge_tx_qstart(struct sfxge_softc *sc, unsigned int index)
/* Create the common code transmit queue. */
if ((rc = efx_tx_qcreate(sc->enp, index, txq->type, esmp,
sc->txq_entries, txq->buf_base_id, flags, evq->common,
&txq->common)) != 0)
&txq->common, &desc_index)) != 0)
goto fail;
/* Initialise queue descriptor indexes */
txq->added = txq->pending = txq->completed = txq->reaped = desc_index;
SFXGE_TXQ_LOCK(txq);
/* Enable the transmit queue. */
efx_tx_qenable(txq->common);
txq->init_state = SFXGE_TXQ_STARTED;
txq->flush_state = SFXGE_FLUSH_REQUIRED;
SFXGE_TXQ_UNLOCK(txq);
@ -1348,9 +1463,41 @@ sfxge_tx_qfini(struct sfxge_softc *sc, unsigned int index)
free(txq, M_SFXGE);
}
/*
* Estimate maximum number of Tx descriptors required for TSO packet.
* With minimum MSS and maximum mbuf length we might need more (even
* than a ring-ful of descriptors), but this should not happen in
* practice except due to deliberate attack. In that case we will
* truncate the output at a packet boundary.
*/
static unsigned int
sfxge_tx_max_pkt_desc(const struct sfxge_softc *sc, enum sfxge_txq_type type)
{
/* One descriptor for every input fragment */
unsigned int max_descs = SFXGE_TX_MAPPING_MAX_SEG;
/* VLAN tagging Tx option descriptor may be required */
if (efx_nic_cfg_get(sc->enp)->enc_hw_tx_insert_vlan_enabled)
max_descs++;
if (type == SFXGE_TXQ_IP_TCP_UDP_CKSUM) {
/*
* Plus header and payload descriptor for each output segment.
* Minus one since header fragment is already counted.
*/
max_descs += SFXGE_TSO_MAX_SEGS * 2 - 1;
/* FW assisted TSO requires one more descriptor per segment */
if (sc->tso_fw_assisted)
max_descs += SFXGE_TSO_MAX_SEGS;
}
return (max_descs);
}
static int
sfxge_tx_qinit(struct sfxge_softc *sc, unsigned int txq_index,
enum sfxge_txq_type type, unsigned int evq_index)
enum sfxge_txq_type type, unsigned int evq_index)
{
char name[16];
struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->dev);
@ -1392,7 +1539,7 @@ sfxge_tx_qinit(struct sfxge_softc *sc, unsigned int txq_index,
}
/* Allocate pending descriptor array for batching writes. */
txq->pend_desc = malloc(sizeof(efx_buffer_t) * sc->txq_entries,
txq->pend_desc = malloc(sizeof(efx_desc_t) * sc->txq_entries,
M_SFXGE, M_ZERO | M_WAITOK);
/* Allocate and initialise mbuf DMA mapping array. */
@ -1475,6 +1622,9 @@ sfxge_tx_qinit(struct sfxge_softc *sc, unsigned int txq_index,
txq->evq_index = evq_index;
txq->txq_index = txq_index;
txq->init_state = SFXGE_TXQ_INITIALIZED;
txq->hw_vlan_tci = 0;
txq->max_pkt_desc = sfxge_tx_max_pkt_desc(sc, type);
return (0);
@ -1572,6 +1722,7 @@ sfxge_tx_fini(struct sfxge_softc *sc)
int
sfxge_tx_init(struct sfxge_softc *sc)
{
const efx_nic_cfg_t *encp = efx_nic_cfg_get(sc->enp);
struct sfxge_intr *intr;
int index;
int rc;
@ -1583,6 +1734,12 @@ sfxge_tx_init(struct sfxge_softc *sc)
sc->txq_count = SFXGE_TXQ_NTYPES - 1 + sc->intr.n_alloc;
sc->tso_fw_assisted = sfxge_tso_fw_assisted;
if (sc->tso_fw_assisted)
sc->tso_fw_assisted =
(encp->enc_features & EFX_FEATURE_FW_ASSISTED_TSO) &&
(encp->enc_fw_assisted_tso_enabled);
sc->txqs_node = SYSCTL_ADD_NODE(
device_get_sysctl_ctx(sc->dev),
SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)),

View File

@ -1,30 +1,34 @@
/*-
* Copyright (c) 2010-2011 Solarflare Communications, Inc.
* Copyright (c) 2010-2015 Solarflare Communications Inc.
* All rights reserved.
*
* This software was developed in part by Philip Paeps under contract for
* Solarflare Communications, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* modification, are permitted provided that the following conditions are met:
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the FreeBSD Project.
*
* $FreeBSD$
*/
@ -164,10 +168,11 @@ struct sfxge_txq {
unsigned int buf_base_id;
unsigned int entries;
unsigned int ptr_mask;
unsigned int max_pkt_desc;
struct sfxge_tx_mapping *stmp; /* Packets in flight. */
bus_dma_tag_t packet_dma_tag;
efx_buffer_t *pend_desc;
efx_desc_t *pend_desc;
efx_txq_t *common;
efsys_mem_t *tsoh_buffer;
@ -187,6 +192,11 @@ struct sfxge_txq {
unsigned int n_pend_desc;
unsigned int added;
unsigned int reaped;
/* The last VLAN TCI seen on the queue if FW-assisted tagging is
used */
uint16_t hw_vlan_tci;
/* Statistics */
unsigned long tso_bursts;
unsigned long tso_packets;
@ -210,7 +220,6 @@ struct sfxge_txq {
struct sfxge_evq;
extern int sfxge_tx_packet_add(struct sfxge_txq *, struct mbuf *);
extern uint64_t sfxge_tx_get_drops(struct sfxge_softc *sc);
extern int sfxge_tx_init(struct sfxge_softc *sc);

View File

@ -1,30 +1,34 @@
/*-
* Copyright (c) 2015 Solarflare Communications, Inc.
* Copyright (c) 2015 Solarflare Communications Inc.
* All rights reserved.
*
* This software was developed in part by OKTET Labs under contract for
* Solarflare Communications, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* modification, are permitted provided that the following conditions are met:
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the FreeBSD Project.
*
* $FreeBSD$
*/
@ -32,6 +36,6 @@
#ifndef _SFXGE_VERSION_H
#define _SFXGE_VERSION_H
#define SFXGE_VERSION_STRING "v3.3.4.6365"
#define SFXGE_VERSION_STRING "v4.5.1.1018"
#endif /* _SFXGE_DRIVER_VERSION_H */

View File

@ -9,22 +9,31 @@ SRCS+= opt_inet.h opt_inet6.h opt_sched.h
.PATH: ${.CURDIR}/../../dev/sfxge
SRCS+= sfxge.c sfxge_dma.c sfxge_ev.c
SRCS+= sfxge_intr.c sfxge_mcdi.c
SRCS+= sfxge_intr.c sfxge_mcdi.c sfxge_nvram.c
SRCS+= sfxge_port.c sfxge_rx.c sfxge_tx.c
SRCS+= sfxge.h sfxge_rx.h sfxge_tx.h sfxge_version.h
.PATH: ${.CURDIR}/../../dev/sfxge/common
SRCS+= efx_ev.c efx_intr.c efx_mac.c efx_mcdi.c efx_nic.c
SRCS+= efx_bootcfg.c efx_crc32.c efx_ev.c efx_intr.c efx_mac.c
SRCS+= efx_mcdi.c efx_mon.c efx_nic.c
SRCS+= efx_nvram.c efx_phy.c efx_port.c efx_rx.c efx_sram.c efx_tx.c
SRCS+= efx_vpd.c efx_wol.c
SRCS+= efx_vpd.c efx_wol.c efx_filter.c efx_hash.c
SRCS+= efsys.h
SRCS+= efx.h efx_impl.h efx_mcdi.h efx_regs.h efx_regs_ef10.h
SRCS+= efx_regs_mcdi.h efx_regs_pci.h efx_types.h
SRCS+= efx.h efx_check.h efx_impl.h efx_mcdi.h efx_regs.h efx_regs_ef10.h
SRCS+= efx_regs_mcdi.h efx_regs_pci.h efx_types.h efx_phy_ids.h
SRCS+= ef10_tlv_layout.h
SRCS+= siena_mac.c siena_nic.c siena_nvram.c siena_phy.c
SRCS+= mcdi_mon.c mcdi_mon.h
SRCS+= siena_mac.c siena_mcdi.c siena_nic.c siena_nvram.c siena_phy.c
SRCS+= siena_sram.c siena_vpd.c
SRCS+= siena_flash.h siena_impl.h
SRCS+= hunt_ev.c hunt_intr.c hunt_mac.c hunt_mcdi.c hunt_nic.c
SRCS+= hunt_nvram.c hunt_rx.c hunt_phy.c hunt_sram.c hunt_tx.c hunt_vpd.c
SRCS+= hunt_filter.c
SRCS+= hunt_impl.h
DEBUG_FLAGS= -DDEBUG=1
.include <bsd.kmod.mk>