root/sys/dev/axgbe/xgbe-drv.c
/*
 * AMD 10Gb Ethernet driver
 *
 * Copyright (c) 2014-2016,2020 Advanced Micro Devices, Inc.
 *
 * This file is available to you under your choice of the following two
 * licenses:
 *
 * License 1: GPLv2
 *
 * This file is free software; you may copy, redistribute and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or (at
 * your option) any later version.
 *
 * This file is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * This file incorporates work covered by the following copyright and
 * permission notice:
 *     The Synopsys DWC ETHER XGMAC Software Driver and documentation
 *     (hereinafter "Software") is an unsupported proprietary work of Synopsys,
 *     Inc. unless otherwise expressly agreed to in writing between Synopsys
 *     and you.
 *
 *     The Software IS NOT an item of Licensed Software or Licensed Product
 *     under any End User Software License Agreement or Agreement for Licensed
 *     Product with Synopsys or any supplement thereto.  Permission is hereby
 *     granted, free of charge, to any person obtaining a copy of this software
 *     annotated with this license and the Software, to deal in the Software
 *     without restriction, including without limitation the rights to use,
 *     copy, modify, merge, publish, distribute, sublicense, and/or sell copies
 *     of the Software, and to permit persons to whom the Software is furnished
 *     to do so, subject to the following conditions:
 *
 *     The above copyright notice and this permission notice shall be included
 *     in all copies or substantial portions of the Software.
 *
 *     THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
 *     BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 *     TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 *     PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS
 *     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.
 *
 *
 * License 2: Modified BSD
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * 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.
 *     * Neither the name of Advanced Micro Devices, Inc. nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * 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 <COPYRIGHT HOLDER> 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.
 *
 * This file incorporates work covered by the following copyright and
 * permission notice:
 *     The Synopsys DWC ETHER XGMAC Software Driver and documentation
 *     (hereinafter "Software") is an unsupported proprietary work of Synopsys,
 *     Inc. unless otherwise expressly agreed to in writing between Synopsys
 *     and you.
 *
 *     The Software IS NOT an item of Licensed Software or Licensed Product
 *     under any End User Software License Agreement or Agreement for Licensed
 *     Product with Synopsys or any supplement thereto.  Permission is hereby
 *     granted, free of charge, to any person obtaining a copy of this software
 *     annotated with this license and the Software, to deal in the Software
 *     without restriction, including without limitation the rights to use,
 *     copy, modify, merge, publish, distribute, sublicense, and/or sell copies
 *     of the Software, and to permit persons to whom the Software is furnished
 *     to do so, subject to the following conditions:
 *
 *     The above copyright notice and this permission notice shall be included
 *     in all copies or substantial portions of the Software.
 *
 *     THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
 *     BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 *     TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 *     PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS
 *     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>
#include "xgbe.h"
#include "xgbe-common.h"

int
xgbe_calc_rx_buf_size(if_t netdev, unsigned int mtu)
{
        unsigned int rx_buf_size;

        if (mtu > XGMAC_JUMBO_PACKET_MTU)
                return (-EINVAL);

        rx_buf_size = mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN;
        rx_buf_size = min(max(rx_buf_size, XGBE_RX_MIN_BUF_SIZE), PAGE_SIZE);
        rx_buf_size = (rx_buf_size + XGBE_RX_BUF_ALIGN - 1) & 
            ~(XGBE_RX_BUF_ALIGN - 1);

        return (rx_buf_size);
}

void
xgbe_get_all_hw_features(struct xgbe_prv_data *pdata)
{
        unsigned int mac_hfr0, mac_hfr1, mac_hfr2;
        struct xgbe_hw_features *hw_feat = &pdata->hw_feat;

        DBGPR("-->xgbe_get_all_hw_features\n");

        mac_hfr0 = XGMAC_IOREAD(pdata, MAC_HWF0R);
        mac_hfr1 = XGMAC_IOREAD(pdata, MAC_HWF1R);
        mac_hfr2 = XGMAC_IOREAD(pdata, MAC_HWF2R);

        memset(hw_feat, 0, sizeof(*hw_feat));

        hw_feat->version = XGMAC_IOREAD(pdata, MAC_VR);

        /* Hardware feature register 0 */
        hw_feat->gmii   = XGMAC_GET_BITS(mac_hfr0, MAC_HWF0R, GMIISEL);
        hw_feat->vlhash = XGMAC_GET_BITS(mac_hfr0, MAC_HWF0R, VLHASH);
        hw_feat->sma    = XGMAC_GET_BITS(mac_hfr0, MAC_HWF0R, SMASEL);
        hw_feat->rwk    = XGMAC_GET_BITS(mac_hfr0, MAC_HWF0R, RWKSEL);
        hw_feat->mgk    = XGMAC_GET_BITS(mac_hfr0, MAC_HWF0R, MGKSEL);
        hw_feat->mmc    = XGMAC_GET_BITS(mac_hfr0, MAC_HWF0R, MMCSEL);
        hw_feat->aoe    = XGMAC_GET_BITS(mac_hfr0, MAC_HWF0R, ARPOFFSEL);
        hw_feat->ts     = XGMAC_GET_BITS(mac_hfr0, MAC_HWF0R, TSSEL);
        hw_feat->eee    = XGMAC_GET_BITS(mac_hfr0, MAC_HWF0R, EEESEL);
        hw_feat->tx_coe = XGMAC_GET_BITS(mac_hfr0, MAC_HWF0R, TXCOESEL);
        hw_feat->rx_coe = XGMAC_GET_BITS(mac_hfr0, MAC_HWF0R, RXCOESEL);
        hw_feat->addn_mac = XGMAC_GET_BITS(mac_hfr0, MAC_HWF0R,
                                              ADDMACADRSEL);
        hw_feat->ts_src = XGMAC_GET_BITS(mac_hfr0, MAC_HWF0R, TSSTSSEL);
        hw_feat->sa_vlan_ins = XGMAC_GET_BITS(mac_hfr0, MAC_HWF0R, SAVLANINS);
        hw_feat->vxn    = XGMAC_GET_BITS(mac_hfr0, MAC_HWF0R, VXN);

        /* Hardware feature register 1 */
        hw_feat->rx_fifo_size   = XGMAC_GET_BITS(mac_hfr1, MAC_HWF1R,
                                                RXFIFOSIZE);
        hw_feat->tx_fifo_size   = XGMAC_GET_BITS(mac_hfr1, MAC_HWF1R,
                                                TXFIFOSIZE);
        hw_feat->adv_ts_hi      = XGMAC_GET_BITS(mac_hfr1, MAC_HWF1R, ADVTHWORD);
        hw_feat->dma_width      = XGMAC_GET_BITS(mac_hfr1, MAC_HWF1R, ADDR64);
        hw_feat->dcb            = XGMAC_GET_BITS(mac_hfr1, MAC_HWF1R, DCBEN);
        hw_feat->sph            = XGMAC_GET_BITS(mac_hfr1, MAC_HWF1R, SPHEN);
        hw_feat->tso            = XGMAC_GET_BITS(mac_hfr1, MAC_HWF1R, TSOEN);
        hw_feat->dma_debug      = XGMAC_GET_BITS(mac_hfr1, MAC_HWF1R, DBGMEMA);
        hw_feat->rss            = XGMAC_GET_BITS(mac_hfr1, MAC_HWF1R, RSSEN);
        hw_feat->tc_cnt         = XGMAC_GET_BITS(mac_hfr1, MAC_HWF1R, NUMTC);
        hw_feat->hash_table_size = XGMAC_GET_BITS(mac_hfr1, MAC_HWF1R,
                                                  HASHTBLSZ);
        hw_feat->l3l4_filter_num = XGMAC_GET_BITS(mac_hfr1, MAC_HWF1R,
                                                  L3L4FNUM);

        /* Hardware feature register 2 */
        hw_feat->rx_q_cnt     = XGMAC_GET_BITS(mac_hfr2, MAC_HWF2R, RXQCNT);
        hw_feat->tx_q_cnt     = XGMAC_GET_BITS(mac_hfr2, MAC_HWF2R, TXQCNT);
        hw_feat->rx_ch_cnt    = XGMAC_GET_BITS(mac_hfr2, MAC_HWF2R, RXCHCNT);
        hw_feat->tx_ch_cnt    = XGMAC_GET_BITS(mac_hfr2, MAC_HWF2R, TXCHCNT);
        hw_feat->pps_out_num  = XGMAC_GET_BITS(mac_hfr2, MAC_HWF2R, PPSOUTNUM);
        hw_feat->aux_snap_num = XGMAC_GET_BITS(mac_hfr2, MAC_HWF2R, AUXSNAPNUM);

        /* Translate the Hash Table size into actual number */
        switch (hw_feat->hash_table_size) {
        case 0:
                break;
        case 1:
                hw_feat->hash_table_size = 64;
                break;
        case 2:
                hw_feat->hash_table_size = 128;
                break;
        case 3:
                hw_feat->hash_table_size = 256;
                break;
        }

        /* Translate the address width setting into actual number */
        switch (hw_feat->dma_width) {
        case 0:
                hw_feat->dma_width = 32;
                break;
        case 1:
                hw_feat->dma_width = 40;
                break;
        case 2:
                hw_feat->dma_width = 48;
                break;
        default:
                hw_feat->dma_width = 32;
        }

        /* The Queue, Channel and TC counts are zero based so increment them
         * to get the actual number
         */
        hw_feat->rx_q_cnt++;
        hw_feat->tx_q_cnt++;
        hw_feat->rx_ch_cnt++;
        hw_feat->tx_ch_cnt++;
        hw_feat->tc_cnt++;

        /* Translate the fifo sizes into actual numbers */
        hw_feat->rx_fifo_size = 1 << (hw_feat->rx_fifo_size + 7);
        hw_feat->tx_fifo_size = 1 << (hw_feat->tx_fifo_size + 7);
        DBGPR("%s: Tx fifo 0x%x Rx fifo 0x%x\n", __func__,
            hw_feat->tx_fifo_size, hw_feat->rx_fifo_size);

        DBGPR("Hardware features:\n");

        /* Hardware feature register 0 */
        DBGPR("  1GbE support              : %s\n",
            hw_feat->gmii ? "yes" : "no");
        DBGPR("  VLAN hash filter          : %s\n",
            hw_feat->vlhash ? "yes" : "no");
        DBGPR("  MDIO interface            : %s\n",
            hw_feat->sma ? "yes" : "no");
        DBGPR("  Wake-up packet support    : %s\n",
            hw_feat->rwk ? "yes" : "no");
        DBGPR("  Magic packet support      : %s\n",
            hw_feat->mgk ? "yes" : "no");
        DBGPR("  Management counters       : %s\n",
            hw_feat->mmc ? "yes" : "no");
        DBGPR("  ARP offload               : %s\n",
            hw_feat->aoe ? "yes" : "no");
        DBGPR("  IEEE 1588-2008 Timestamp  : %s\n",
            hw_feat->ts ? "yes" : "no");
        DBGPR("  Energy Efficient Ethernet : %s\n",
            hw_feat->eee ? "yes" : "no");
        DBGPR("  TX checksum offload       : %s\n",
            hw_feat->tx_coe ? "yes" : "no");
        DBGPR("  RX checksum offload       : %s\n",
            hw_feat->rx_coe ? "yes" : "no");
        DBGPR("  Additional MAC addresses  : %u\n",
            hw_feat->addn_mac);
        DBGPR("  Timestamp source          : %s\n",
            (hw_feat->ts_src == 1) ? "internal" :
            (hw_feat->ts_src == 2) ? "external" :
            (hw_feat->ts_src == 3) ? "internal/external" : "n/a");
        DBGPR("  SA/VLAN insertion         : %s\n",
            hw_feat->sa_vlan_ins ? "yes" : "no");

        /* Hardware feature register 1 */
        DBGPR("  RX fifo size              : %u\n",
            hw_feat->rx_fifo_size);
        DBGPR("  TX fifo size              : %u\n",
            hw_feat->tx_fifo_size);
        DBGPR("  IEEE 1588 high word       : %s\n",
            hw_feat->adv_ts_hi ? "yes" : "no");
        DBGPR("  DMA width                 : %u\n",
            hw_feat->dma_width);
        DBGPR("  Data Center Bridging      : %s\n",
            hw_feat->dcb ? "yes" : "no");
        DBGPR("  Split header              : %s\n",
            hw_feat->sph ? "yes" : "no");
        DBGPR("  TCP Segmentation Offload  : %s\n",
            hw_feat->tso ? "yes" : "no");
        DBGPR("  Debug memory interface    : %s\n",
            hw_feat->dma_debug ? "yes" : "no");
        DBGPR("  Receive Side Scaling      : %s\n",
            hw_feat->rss ? "yes" : "no");
        DBGPR("  Traffic Class count       : %u\n",
            hw_feat->tc_cnt);
        DBGPR("  Hash table size           : %u\n",
            hw_feat->hash_table_size);
        DBGPR("  L3/L4 Filters             : %u\n",
            hw_feat->l3l4_filter_num);

        /* Hardware feature register 2 */
        DBGPR("  RX queue count            : %u\n",
            hw_feat->rx_q_cnt);
        DBGPR("  TX queue count            : %u\n",
            hw_feat->tx_q_cnt);
        DBGPR("  RX DMA channel count      : %u\n",
            hw_feat->rx_ch_cnt);
        DBGPR("  TX DMA channel count      : %u\n",
            hw_feat->rx_ch_cnt);
        DBGPR("  PPS outputs               : %u\n",
            hw_feat->pps_out_num);
        DBGPR("  Auxiliary snapshot inputs : %u\n",
            hw_feat->aux_snap_num);
        
        DBGPR("<--xgbe_get_all_hw_features\n");
}

void
xgbe_init_tx_coalesce(struct xgbe_prv_data *pdata)
{
        struct xgbe_hw_if *hw_if = &pdata->hw_if;

        DBGPR("-->xgbe_init_tx_coalesce\n");

        pdata->tx_usecs = XGMAC_INIT_DMA_TX_USECS;
        pdata->tx_frames = XGMAC_INIT_DMA_TX_FRAMES;

        hw_if->config_tx_coalesce(pdata);

        DBGPR("<--xgbe_init_tx_coalesce\n");
}

void
xgbe_init_rx_coalesce(struct xgbe_prv_data *pdata)
{
        struct xgbe_hw_if *hw_if = &pdata->hw_if;

        DBGPR("-->xgbe_init_rx_coalesce\n");

        pdata->rx_riwt = hw_if->usec_to_riwt(pdata, XGMAC_INIT_DMA_RX_USECS);
        pdata->rx_usecs = XGMAC_INIT_DMA_RX_USECS;
        pdata->rx_frames = XGMAC_INIT_DMA_RX_FRAMES;

        hw_if->config_rx_coalesce(pdata);

        DBGPR("<--xgbe_init_rx_coalesce\n");
}