13c0086b8SZbigniew Bodek /*
23c0086b8SZbigniew Bodek * Copyright (C) 2015 Cavium Inc.
33c0086b8SZbigniew Bodek * All rights reserved.
43c0086b8SZbigniew Bodek *
53c0086b8SZbigniew Bodek * Redistribution and use in source and binary forms, with or without
63c0086b8SZbigniew Bodek * modification, are permitted provided that the following conditions
73c0086b8SZbigniew Bodek * are met:
83c0086b8SZbigniew Bodek * 1. Redistributions of source code must retain the above copyright
93c0086b8SZbigniew Bodek * notice, this list of conditions and the following disclaimer.
103c0086b8SZbigniew Bodek * 2. Redistributions in binary form must reproduce the above copyright
113c0086b8SZbigniew Bodek * notice, this list of conditions and the following disclaimer in the
123c0086b8SZbigniew Bodek * documentation and/or other materials provided with the distribution.
133c0086b8SZbigniew Bodek *
143c0086b8SZbigniew Bodek * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
153c0086b8SZbigniew Bodek * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
163c0086b8SZbigniew Bodek * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
173c0086b8SZbigniew Bodek * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
183c0086b8SZbigniew Bodek * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
193c0086b8SZbigniew Bodek * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
203c0086b8SZbigniew Bodek * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
213c0086b8SZbigniew Bodek * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
223c0086b8SZbigniew Bodek * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
233c0086b8SZbigniew Bodek * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
243c0086b8SZbigniew Bodek * SUCH DAMAGE.
253c0086b8SZbigniew Bodek *
263c0086b8SZbigniew Bodek */
273c0086b8SZbigniew Bodek
28941650aaSEd Maste /*
29941650aaSEd Maste * Marvell/Cavium ThunderX vnic/bgx network controller
30941650aaSEd Maste *
31941650aaSEd Maste * UNIMPLEMENTED FEATURES
32941650aaSEd Maste * ----------------------
33941650aaSEd Maste * A number of features supported by the hardware are not yet implemented in
34941650aaSEd Maste * this driver:
35941650aaSEd Maste *
3629e9b487SEd Maste * - PR223573 multicast rx filter
37941650aaSEd Maste * - PR223575 non-promiscuous mode (driver currently forces promisc)
38941650aaSEd Maste */
39941650aaSEd Maste
402306b72aSZbigniew Bodek #include <sys/param.h>
412306b72aSZbigniew Bodek #include <sys/systm.h>
422306b72aSZbigniew Bodek #include <sys/bitset.h>
432306b72aSZbigniew Bodek #include <sys/bitstring.h>
442306b72aSZbigniew Bodek #include <sys/bus.h>
452306b72aSZbigniew Bodek #include <sys/endian.h>
462306b72aSZbigniew Bodek #include <sys/kernel.h>
472306b72aSZbigniew Bodek #include <sys/malloc.h>
482306b72aSZbigniew Bodek #include <sys/module.h>
492306b72aSZbigniew Bodek #include <sys/rman.h>
502306b72aSZbigniew Bodek #include <sys/pciio.h>
512306b72aSZbigniew Bodek #include <sys/pcpu.h>
522306b72aSZbigniew Bodek #include <sys/proc.h>
532306b72aSZbigniew Bodek #include <sys/socket.h>
542306b72aSZbigniew Bodek #include <sys/sockio.h>
552306b72aSZbigniew Bodek #include <sys/cpuset.h>
562306b72aSZbigniew Bodek #include <sys/lock.h>
572306b72aSZbigniew Bodek #include <sys/mutex.h>
582306b72aSZbigniew Bodek
592306b72aSZbigniew Bodek #include <net/ethernet.h>
602306b72aSZbigniew Bodek #include <net/if.h>
612306b72aSZbigniew Bodek #include <net/if_media.h>
622306b72aSZbigniew Bodek
632306b72aSZbigniew Bodek #include <machine/bus.h>
642306b72aSZbigniew Bodek #include <machine/_inttypes.h>
652306b72aSZbigniew Bodek
662306b72aSZbigniew Bodek #include <dev/pci/pcireg.h>
672306b72aSZbigniew Bodek #include <dev/pci/pcivar.h>
682306b72aSZbigniew Bodek
692306b72aSZbigniew Bodek #include <sys/dnv.h>
702306b72aSZbigniew Bodek #include <sys/nv.h>
712306b72aSZbigniew Bodek #ifdef PCI_IOV
722306b72aSZbigniew Bodek #include <sys/iov_schema.h>
732306b72aSZbigniew Bodek #include <dev/pci/pci_iov.h>
742306b72aSZbigniew Bodek #endif
752306b72aSZbigniew Bodek
762306b72aSZbigniew Bodek #include "thunder_bgx.h"
773c0086b8SZbigniew Bodek #include "nic_reg.h"
783c0086b8SZbigniew Bodek #include "nic.h"
793c0086b8SZbigniew Bodek #include "q_struct.h"
803c0086b8SZbigniew Bodek
812306b72aSZbigniew Bodek #define VNIC_PF_DEVSTR "Cavium Thunder NIC Physical Function Driver"
822306b72aSZbigniew Bodek
832306b72aSZbigniew Bodek #define VNIC_PF_REG_RID PCIR_BAR(PCI_CFG_REG_BAR_NUM)
842306b72aSZbigniew Bodek
852306b72aSZbigniew Bodek #define NIC_SET_VF_LMAC_MAP(bgx, lmac) ((((bgx) & 0xF) << 4) | ((lmac) & 0xF))
862306b72aSZbigniew Bodek #define NIC_GET_BGX_FROM_VF_LMAC_MAP(map) (((map) >> 4) & 0xF)
872306b72aSZbigniew Bodek #define NIC_GET_LMAC_FROM_VF_LMAC_MAP(map) ((map) & 0xF)
882306b72aSZbigniew Bodek
892306b72aSZbigniew Bodek /* Structure to be used by the SR-IOV for VF configuration schemas */
902306b72aSZbigniew Bodek struct nicvf_info {
912306b72aSZbigniew Bodek boolean_t vf_enabled;
922306b72aSZbigniew Bodek int vf_flags;
932306b72aSZbigniew Bodek };
943c0086b8SZbigniew Bodek
953c0086b8SZbigniew Bodek struct nicpf {
962306b72aSZbigniew Bodek device_t dev;
972306b72aSZbigniew Bodek uint8_t node;
982306b72aSZbigniew Bodek u_int flags;
992306b72aSZbigniew Bodek uint8_t num_vf_en; /* No of VF enabled */
1002306b72aSZbigniew Bodek struct nicvf_info vf_info[MAX_NUM_VFS_SUPPORTED];
1012306b72aSZbigniew Bodek struct resource * reg_base; /* Register start address */
1023c0086b8SZbigniew Bodek struct pkind_cfg pkind;
1032306b72aSZbigniew Bodek uint8_t vf_lmac_map[MAX_LMAC];
1042306b72aSZbigniew Bodek boolean_t mbx_lock[MAX_NUM_VFS_SUPPORTED];
1052306b72aSZbigniew Bodek
1062306b72aSZbigniew Bodek struct callout check_link;
1072306b72aSZbigniew Bodek struct mtx check_link_mtx;
1082306b72aSZbigniew Bodek
1092306b72aSZbigniew Bodek uint8_t link[MAX_LMAC];
1102306b72aSZbigniew Bodek uint8_t duplex[MAX_LMAC];
1112306b72aSZbigniew Bodek uint32_t speed[MAX_LMAC];
1122306b72aSZbigniew Bodek uint16_t cpi_base[MAX_NUM_VFS_SUPPORTED];
1138191a879SZbigniew Bodek uint16_t rssi_base[MAX_NUM_VFS_SUPPORTED];
1142306b72aSZbigniew Bodek uint16_t rss_ind_tbl_size;
1153c0086b8SZbigniew Bodek
1163c0086b8SZbigniew Bodek /* MSI-X */
1172306b72aSZbigniew Bodek boolean_t msix_enabled;
1182306b72aSZbigniew Bodek uint8_t num_vec;
1193c0086b8SZbigniew Bodek struct msix_entry msix_entries[NIC_PF_MSIX_VECTORS];
1202306b72aSZbigniew Bodek struct resource * msix_table_res;
1213c0086b8SZbigniew Bodek };
1223c0086b8SZbigniew Bodek
1232306b72aSZbigniew Bodek static int nicpf_probe(device_t);
1242306b72aSZbigniew Bodek static int nicpf_attach(device_t);
1252306b72aSZbigniew Bodek static int nicpf_detach(device_t);
1262306b72aSZbigniew Bodek
1272306b72aSZbigniew Bodek #ifdef PCI_IOV
1282306b72aSZbigniew Bodek static int nicpf_iov_init(device_t, uint16_t, const nvlist_t *);
1292306b72aSZbigniew Bodek static void nicpf_iov_uninit(device_t);
130055dba6dSZbigniew Bodek static int nicpf_iov_add_vf(device_t, uint16_t, const nvlist_t *);
1312306b72aSZbigniew Bodek #endif
1322306b72aSZbigniew Bodek
1332306b72aSZbigniew Bodek static device_method_t nicpf_methods[] = {
1342306b72aSZbigniew Bodek /* Device interface */
1352306b72aSZbigniew Bodek DEVMETHOD(device_probe, nicpf_probe),
1362306b72aSZbigniew Bodek DEVMETHOD(device_attach, nicpf_attach),
1372306b72aSZbigniew Bodek DEVMETHOD(device_detach, nicpf_detach),
1382306b72aSZbigniew Bodek /* PCI SR-IOV interface */
1392306b72aSZbigniew Bodek #ifdef PCI_IOV
1402306b72aSZbigniew Bodek DEVMETHOD(pci_iov_init, nicpf_iov_init),
1412306b72aSZbigniew Bodek DEVMETHOD(pci_iov_uninit, nicpf_iov_uninit),
142055dba6dSZbigniew Bodek DEVMETHOD(pci_iov_add_vf, nicpf_iov_add_vf),
1432306b72aSZbigniew Bodek #endif
1442306b72aSZbigniew Bodek DEVMETHOD_END,
1453c0086b8SZbigniew Bodek };
1463c0086b8SZbigniew Bodek
147f4aafb9eSWojciech Macek static driver_t vnicpf_driver = {
1482306b72aSZbigniew Bodek "vnicpf",
1492306b72aSZbigniew Bodek nicpf_methods,
1502306b72aSZbigniew Bodek sizeof(struct nicpf),
1512306b72aSZbigniew Bodek };
1523c0086b8SZbigniew Bodek
153*94412ad7SJohn Baldwin DRIVER_MODULE(vnicpf, pci, vnicpf_driver, 0, 0);
154f4aafb9eSWojciech Macek MODULE_VERSION(vnicpf, 1);
155f4aafb9eSWojciech Macek MODULE_DEPEND(vnicpf, pci, 1, 1, 1);
156f4aafb9eSWojciech Macek MODULE_DEPEND(vnicpf, ether, 1, 1, 1);
157f4aafb9eSWojciech Macek MODULE_DEPEND(vnicpf, thunder_bgx, 1, 1, 1);
1582306b72aSZbigniew Bodek
1592306b72aSZbigniew Bodek static int nicpf_alloc_res(struct nicpf *);
1602306b72aSZbigniew Bodek static void nicpf_free_res(struct nicpf *);
1612306b72aSZbigniew Bodek static void nic_set_lmac_vf_mapping(struct nicpf *);
1622306b72aSZbigniew Bodek static void nic_init_hw(struct nicpf *);
1632306b72aSZbigniew Bodek static int nic_sriov_init(device_t, struct nicpf *);
1642306b72aSZbigniew Bodek static void nic_poll_for_link(void *);
1652306b72aSZbigniew Bodek static int nic_register_interrupts(struct nicpf *);
1662306b72aSZbigniew Bodek static void nic_unregister_interrupts(struct nicpf *);
1672306b72aSZbigniew Bodek
1682306b72aSZbigniew Bodek /*
1692306b72aSZbigniew Bodek * Device interface
1703c0086b8SZbigniew Bodek */
1712306b72aSZbigniew Bodek static int
nicpf_probe(device_t dev)1722306b72aSZbigniew Bodek nicpf_probe(device_t dev)
1733c0086b8SZbigniew Bodek {
1742306b72aSZbigniew Bodek uint16_t vendor_id;
1752306b72aSZbigniew Bodek uint16_t device_id;
1762306b72aSZbigniew Bodek
1772306b72aSZbigniew Bodek vendor_id = pci_get_vendor(dev);
1782306b72aSZbigniew Bodek device_id = pci_get_device(dev);
1792306b72aSZbigniew Bodek
1802306b72aSZbigniew Bodek if (vendor_id == PCI_VENDOR_ID_CAVIUM &&
1812306b72aSZbigniew Bodek device_id == PCI_DEVICE_ID_THUNDER_NIC_PF) {
1822306b72aSZbigniew Bodek device_set_desc(dev, VNIC_PF_DEVSTR);
1832306b72aSZbigniew Bodek return (BUS_PROBE_DEFAULT);
1843c0086b8SZbigniew Bodek }
1853c0086b8SZbigniew Bodek
1862306b72aSZbigniew Bodek return (ENXIO);
1872306b72aSZbigniew Bodek }
1882306b72aSZbigniew Bodek
1892306b72aSZbigniew Bodek static int
nicpf_attach(device_t dev)1902306b72aSZbigniew Bodek nicpf_attach(device_t dev)
1913c0086b8SZbigniew Bodek {
1922306b72aSZbigniew Bodek struct nicpf *nic;
1932306b72aSZbigniew Bodek int err;
1942306b72aSZbigniew Bodek
1952306b72aSZbigniew Bodek nic = device_get_softc(dev);
1962306b72aSZbigniew Bodek nic->dev = dev;
1972306b72aSZbigniew Bodek
1982306b72aSZbigniew Bodek /* Enable bus mastering */
1992306b72aSZbigniew Bodek pci_enable_busmaster(dev);
2002306b72aSZbigniew Bodek
2012306b72aSZbigniew Bodek /* Allocate PCI resources */
2022306b72aSZbigniew Bodek err = nicpf_alloc_res(nic);
2032306b72aSZbigniew Bodek if (err != 0) {
2042306b72aSZbigniew Bodek device_printf(dev, "Could not allocate PCI resources\n");
2052306b72aSZbigniew Bodek return (err);
2062306b72aSZbigniew Bodek }
2072306b72aSZbigniew Bodek
2082306b72aSZbigniew Bodek nic->node = nic_get_node_id(nic->reg_base);
2092306b72aSZbigniew Bodek
2102306b72aSZbigniew Bodek /* Enable Traffic Network Switch (TNS) bypass mode by default */
2112306b72aSZbigniew Bodek nic->flags &= ~NIC_TNS_ENABLED;
2122306b72aSZbigniew Bodek nic_set_lmac_vf_mapping(nic);
2132306b72aSZbigniew Bodek
2142306b72aSZbigniew Bodek /* Initialize hardware */
2152306b72aSZbigniew Bodek nic_init_hw(nic);
2162306b72aSZbigniew Bodek
2172306b72aSZbigniew Bodek /* Set RSS TBL size for each VF */
2182306b72aSZbigniew Bodek nic->rss_ind_tbl_size = NIC_MAX_RSS_IDR_TBL_SIZE;
2192306b72aSZbigniew Bodek
2202306b72aSZbigniew Bodek /* Setup interrupts */
2212306b72aSZbigniew Bodek err = nic_register_interrupts(nic);
2222306b72aSZbigniew Bodek if (err != 0)
2232306b72aSZbigniew Bodek goto err_free_res;
2242306b72aSZbigniew Bodek
2252306b72aSZbigniew Bodek /* Configure SRIOV */
2262306b72aSZbigniew Bodek err = nic_sriov_init(dev, nic);
2272306b72aSZbigniew Bodek if (err != 0)
2282306b72aSZbigniew Bodek goto err_free_intr;
2292306b72aSZbigniew Bodek
2302306b72aSZbigniew Bodek if (nic->flags & NIC_TNS_ENABLED)
2312306b72aSZbigniew Bodek return (0);
2322306b72aSZbigniew Bodek
2332306b72aSZbigniew Bodek mtx_init(&nic->check_link_mtx, "VNIC PF link poll", NULL, MTX_DEF);
2342306b72aSZbigniew Bodek /* Register physical link status poll callout */
2352306b72aSZbigniew Bodek callout_init_mtx(&nic->check_link, &nic->check_link_mtx, 0);
2362306b72aSZbigniew Bodek mtx_lock(&nic->check_link_mtx);
2372306b72aSZbigniew Bodek nic_poll_for_link(nic);
2382306b72aSZbigniew Bodek mtx_unlock(&nic->check_link_mtx);
2392306b72aSZbigniew Bodek
2402306b72aSZbigniew Bodek return (0);
2412306b72aSZbigniew Bodek
2422306b72aSZbigniew Bodek err_free_intr:
2432306b72aSZbigniew Bodek nic_unregister_interrupts(nic);
2442306b72aSZbigniew Bodek err_free_res:
2452306b72aSZbigniew Bodek nicpf_free_res(nic);
2462306b72aSZbigniew Bodek pci_disable_busmaster(dev);
2472306b72aSZbigniew Bodek
2482306b72aSZbigniew Bodek return (err);
2492306b72aSZbigniew Bodek }
2502306b72aSZbigniew Bodek
2512306b72aSZbigniew Bodek static int
nicpf_detach(device_t dev)2522306b72aSZbigniew Bodek nicpf_detach(device_t dev)
2532306b72aSZbigniew Bodek {
2542306b72aSZbigniew Bodek struct nicpf *nic;
2557056927eSWojciech Macek int err;
2562306b72aSZbigniew Bodek
2577056927eSWojciech Macek err = 0;
2582306b72aSZbigniew Bodek nic = device_get_softc(dev);
2592306b72aSZbigniew Bodek
2602306b72aSZbigniew Bodek callout_drain(&nic->check_link);
2612306b72aSZbigniew Bodek mtx_destroy(&nic->check_link_mtx);
2622306b72aSZbigniew Bodek
2632306b72aSZbigniew Bodek nic_unregister_interrupts(nic);
2642306b72aSZbigniew Bodek nicpf_free_res(nic);
2652306b72aSZbigniew Bodek pci_disable_busmaster(dev);
2662306b72aSZbigniew Bodek
2677056927eSWojciech Macek #ifdef PCI_IOV
2687056927eSWojciech Macek err = pci_iov_detach(dev);
2697056927eSWojciech Macek if (err != 0)
2707056927eSWojciech Macek device_printf(dev, "SR-IOV in use. Detach first.\n");
2717056927eSWojciech Macek #endif
2727056927eSWojciech Macek return (err);
2732306b72aSZbigniew Bodek }
2742306b72aSZbigniew Bodek
2752306b72aSZbigniew Bodek /*
2762306b72aSZbigniew Bodek * SR-IOV interface
2772306b72aSZbigniew Bodek */
2782306b72aSZbigniew Bodek #ifdef PCI_IOV
2792306b72aSZbigniew Bodek static int
nicpf_iov_init(device_t dev,uint16_t num_vfs,const nvlist_t * params)2802306b72aSZbigniew Bodek nicpf_iov_init(device_t dev, uint16_t num_vfs, const nvlist_t *params)
2812306b72aSZbigniew Bodek {
2822306b72aSZbigniew Bodek struct nicpf *nic;
2832306b72aSZbigniew Bodek
2842306b72aSZbigniew Bodek nic = device_get_softc(dev);
2852306b72aSZbigniew Bodek
2862306b72aSZbigniew Bodek if (num_vfs == 0)
2872306b72aSZbigniew Bodek return (ENXIO);
2882306b72aSZbigniew Bodek
2892306b72aSZbigniew Bodek nic->flags |= NIC_SRIOV_ENABLED;
2902306b72aSZbigniew Bodek
2912306b72aSZbigniew Bodek return (0);
2922306b72aSZbigniew Bodek }
2932306b72aSZbigniew Bodek
2942306b72aSZbigniew Bodek static void
nicpf_iov_uninit(device_t dev)2952306b72aSZbigniew Bodek nicpf_iov_uninit(device_t dev)
2962306b72aSZbigniew Bodek {
2972306b72aSZbigniew Bodek
2982306b72aSZbigniew Bodek /* ARM64TODO: Implement this function */
2992306b72aSZbigniew Bodek }
3002306b72aSZbigniew Bodek
3012306b72aSZbigniew Bodek static int
nicpf_iov_add_vf(device_t dev,uint16_t vfnum,const nvlist_t * params)302055dba6dSZbigniew Bodek nicpf_iov_add_vf(device_t dev, uint16_t vfnum, const nvlist_t *params)
3032306b72aSZbigniew Bodek {
3042306b72aSZbigniew Bodek const void *mac;
3052306b72aSZbigniew Bodek struct nicpf *nic;
3062306b72aSZbigniew Bodek size_t size;
3072306b72aSZbigniew Bodek int bgx, lmac;
3082306b72aSZbigniew Bodek
3092306b72aSZbigniew Bodek nic = device_get_softc(dev);
3102306b72aSZbigniew Bodek
3112306b72aSZbigniew Bodek if ((nic->flags & NIC_SRIOV_ENABLED) == 0)
3122306b72aSZbigniew Bodek return (ENXIO);
3132306b72aSZbigniew Bodek
31447646691SZbigniew Bodek if (vfnum > (nic->num_vf_en - 1))
31547646691SZbigniew Bodek return (EINVAL);
31647646691SZbigniew Bodek
3172306b72aSZbigniew Bodek if (nvlist_exists_binary(params, "mac-addr") != 0) {
3182306b72aSZbigniew Bodek mac = nvlist_get_binary(params, "mac-addr", &size);
3192306b72aSZbigniew Bodek bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vfnum]);
3202306b72aSZbigniew Bodek lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vfnum]);
3212306b72aSZbigniew Bodek bgx_set_lmac_mac(nic->node, bgx, lmac, mac);
3222306b72aSZbigniew Bodek }
3232306b72aSZbigniew Bodek
3242306b72aSZbigniew Bodek return (0);
3252306b72aSZbigniew Bodek }
3262306b72aSZbigniew Bodek #endif
3272306b72aSZbigniew Bodek
3282306b72aSZbigniew Bodek /*
3292306b72aSZbigniew Bodek * Helper routines
3302306b72aSZbigniew Bodek */
3312306b72aSZbigniew Bodek static int
nicpf_alloc_res(struct nicpf * nic)3322306b72aSZbigniew Bodek nicpf_alloc_res(struct nicpf *nic)
3332306b72aSZbigniew Bodek {
3342306b72aSZbigniew Bodek device_t dev;
3352306b72aSZbigniew Bodek int rid;
3362306b72aSZbigniew Bodek
3372306b72aSZbigniew Bodek dev = nic->dev;
3382306b72aSZbigniew Bodek
3392306b72aSZbigniew Bodek rid = VNIC_PF_REG_RID;
3402306b72aSZbigniew Bodek nic->reg_base = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
3412306b72aSZbigniew Bodek RF_ACTIVE);
3422306b72aSZbigniew Bodek if (nic->reg_base == NULL) {
3432306b72aSZbigniew Bodek /* For verbose output print some more details */
3442306b72aSZbigniew Bodek if (bootverbose) {
3452306b72aSZbigniew Bodek device_printf(dev,
3462306b72aSZbigniew Bodek "Could not allocate registers memory\n");
3472306b72aSZbigniew Bodek }
3482306b72aSZbigniew Bodek return (ENXIO);
3492306b72aSZbigniew Bodek }
3502306b72aSZbigniew Bodek
3512306b72aSZbigniew Bodek return (0);
3522306b72aSZbigniew Bodek }
3532306b72aSZbigniew Bodek
3542306b72aSZbigniew Bodek static void
nicpf_free_res(struct nicpf * nic)3552306b72aSZbigniew Bodek nicpf_free_res(struct nicpf *nic)
3562306b72aSZbigniew Bodek {
3572306b72aSZbigniew Bodek device_t dev;
3582306b72aSZbigniew Bodek
3592306b72aSZbigniew Bodek dev = nic->dev;
3602306b72aSZbigniew Bodek
3612306b72aSZbigniew Bodek if (nic->reg_base != NULL) {
3622306b72aSZbigniew Bodek bus_release_resource(dev, SYS_RES_MEMORY,
3632306b72aSZbigniew Bodek rman_get_rid(nic->reg_base), nic->reg_base);
3642306b72aSZbigniew Bodek }
3652306b72aSZbigniew Bodek }
3662306b72aSZbigniew Bodek
3672306b72aSZbigniew Bodek /* Register read/write APIs */
3682306b72aSZbigniew Bodek static __inline void
nic_reg_write(struct nicpf * nic,bus_space_handle_t offset,uint64_t val)3692306b72aSZbigniew Bodek nic_reg_write(struct nicpf *nic, bus_space_handle_t offset,
3702306b72aSZbigniew Bodek uint64_t val)
3712306b72aSZbigniew Bodek {
3722306b72aSZbigniew Bodek
3732306b72aSZbigniew Bodek bus_write_8(nic->reg_base, offset, val);
3742306b72aSZbigniew Bodek }
3752306b72aSZbigniew Bodek
3762306b72aSZbigniew Bodek static __inline uint64_t
nic_reg_read(struct nicpf * nic,uint64_t offset)3772306b72aSZbigniew Bodek nic_reg_read(struct nicpf *nic, uint64_t offset)
3782306b72aSZbigniew Bodek {
3792306b72aSZbigniew Bodek uint64_t val;
3802306b72aSZbigniew Bodek
3812306b72aSZbigniew Bodek val = bus_read_8(nic->reg_base, offset);
3822306b72aSZbigniew Bodek return (val);
3833c0086b8SZbigniew Bodek }
3843c0086b8SZbigniew Bodek
3853c0086b8SZbigniew Bodek /* PF -> VF mailbox communication APIs */
3862306b72aSZbigniew Bodek static void
nic_enable_mbx_intr(struct nicpf * nic)3872306b72aSZbigniew Bodek nic_enable_mbx_intr(struct nicpf *nic)
3883c0086b8SZbigniew Bodek {
3892306b72aSZbigniew Bodek
3903c0086b8SZbigniew Bodek /* Enable mailbox interrupt for all 128 VFs */
3912306b72aSZbigniew Bodek nic_reg_write(nic, NIC_PF_MAILBOX_ENA_W1S, ~0UL);
3922306b72aSZbigniew Bodek nic_reg_write(nic, NIC_PF_MAILBOX_ENA_W1S + sizeof(uint64_t), ~0UL);
3933c0086b8SZbigniew Bodek }
3943c0086b8SZbigniew Bodek
3952306b72aSZbigniew Bodek static void
nic_clear_mbx_intr(struct nicpf * nic,int vf,int mbx_reg)3962306b72aSZbigniew Bodek nic_clear_mbx_intr(struct nicpf *nic, int vf, int mbx_reg)
3973c0086b8SZbigniew Bodek {
3982306b72aSZbigniew Bodek
3992306b72aSZbigniew Bodek nic_reg_write(nic, NIC_PF_MAILBOX_INT + (mbx_reg << 3), (1UL << vf));
4003c0086b8SZbigniew Bodek }
4013c0086b8SZbigniew Bodek
4022306b72aSZbigniew Bodek static uint64_t
nic_get_mbx_addr(int vf)4032306b72aSZbigniew Bodek nic_get_mbx_addr(int vf)
4043c0086b8SZbigniew Bodek {
4052306b72aSZbigniew Bodek
4062306b72aSZbigniew Bodek return (NIC_PF_VF_0_127_MAILBOX_0_1 + (vf << NIC_VF_NUM_SHIFT));
4073c0086b8SZbigniew Bodek }
4083c0086b8SZbigniew Bodek
4092306b72aSZbigniew Bodek /*
4102306b72aSZbigniew Bodek * Send a mailbox message to VF
4113c0086b8SZbigniew Bodek * @vf: vf to which this message to be sent
4123c0086b8SZbigniew Bodek * @mbx: Message to be sent
4133c0086b8SZbigniew Bodek */
4142306b72aSZbigniew Bodek static void
nic_send_msg_to_vf(struct nicpf * nic,int vf,union nic_mbx * mbx)4152306b72aSZbigniew Bodek nic_send_msg_to_vf(struct nicpf *nic, int vf, union nic_mbx *mbx)
4163c0086b8SZbigniew Bodek {
4172306b72aSZbigniew Bodek bus_space_handle_t mbx_addr = nic_get_mbx_addr(vf);
4182306b72aSZbigniew Bodek uint64_t *msg = (uint64_t *)mbx;
4193c0086b8SZbigniew Bodek
4202306b72aSZbigniew Bodek /*
4212306b72aSZbigniew Bodek * In first revision HW, mbox interrupt is triggerred
4223c0086b8SZbigniew Bodek * when PF writes to MBOX(1), in next revisions when
4233c0086b8SZbigniew Bodek * PF writes to MBOX(0)
4243c0086b8SZbigniew Bodek */
4253ad422a9SZbigniew Bodek if (pass1_silicon(nic->dev)) {
4262306b72aSZbigniew Bodek nic_reg_write(nic, mbx_addr + 0, msg[0]);
4272306b72aSZbigniew Bodek nic_reg_write(nic, mbx_addr + 8, msg[1]);
4283c0086b8SZbigniew Bodek } else {
4292306b72aSZbigniew Bodek nic_reg_write(nic, mbx_addr + 8, msg[1]);
4302306b72aSZbigniew Bodek nic_reg_write(nic, mbx_addr + 0, msg[0]);
4313c0086b8SZbigniew Bodek }
4323c0086b8SZbigniew Bodek }
4333c0086b8SZbigniew Bodek
4342306b72aSZbigniew Bodek /*
4352306b72aSZbigniew Bodek * Responds to VF's READY message with VF's
4363c0086b8SZbigniew Bodek * ID, node, MAC address e.t.c
4373c0086b8SZbigniew Bodek * @vf: VF which sent READY message
4383c0086b8SZbigniew Bodek */
4392306b72aSZbigniew Bodek static void
nic_mbx_send_ready(struct nicpf * nic,int vf)4402306b72aSZbigniew Bodek nic_mbx_send_ready(struct nicpf *nic, int vf)
4413c0086b8SZbigniew Bodek {
4423c0086b8SZbigniew Bodek union nic_mbx mbx = {};
4433c0086b8SZbigniew Bodek int bgx_idx, lmac;
4443c0086b8SZbigniew Bodek const char *mac;
4453c0086b8SZbigniew Bodek
4463c0086b8SZbigniew Bodek mbx.nic_cfg.msg = NIC_MBOX_MSG_READY;
4473c0086b8SZbigniew Bodek mbx.nic_cfg.vf_id = vf;
4483c0086b8SZbigniew Bodek
4493c0086b8SZbigniew Bodek if (nic->flags & NIC_TNS_ENABLED)
4503c0086b8SZbigniew Bodek mbx.nic_cfg.tns_mode = NIC_TNS_MODE;
4513c0086b8SZbigniew Bodek else
4523c0086b8SZbigniew Bodek mbx.nic_cfg.tns_mode = NIC_TNS_BYPASS_MODE;
4533c0086b8SZbigniew Bodek
4543c0086b8SZbigniew Bodek if (vf < MAX_LMAC) {
4553c0086b8SZbigniew Bodek bgx_idx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]);
4563c0086b8SZbigniew Bodek lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]);
4573c0086b8SZbigniew Bodek
4583c0086b8SZbigniew Bodek mac = bgx_get_lmac_mac(nic->node, bgx_idx, lmac);
4592306b72aSZbigniew Bodek if (mac) {
4602306b72aSZbigniew Bodek memcpy((uint8_t *)&mbx.nic_cfg.mac_addr, mac,
4612306b72aSZbigniew Bodek ETHER_ADDR_LEN);
4623c0086b8SZbigniew Bodek }
4632306b72aSZbigniew Bodek }
4643c0086b8SZbigniew Bodek mbx.nic_cfg.node_id = nic->node;
4653c0086b8SZbigniew Bodek
4663c0086b8SZbigniew Bodek mbx.nic_cfg.loopback_supported = vf < MAX_LMAC;
4673c0086b8SZbigniew Bodek
4683c0086b8SZbigniew Bodek nic_send_msg_to_vf(nic, vf, &mbx);
4693c0086b8SZbigniew Bodek }
4703c0086b8SZbigniew Bodek
4712306b72aSZbigniew Bodek /*
4722306b72aSZbigniew Bodek * ACKs VF's mailbox message
4733c0086b8SZbigniew Bodek * @vf: VF to which ACK to be sent
4743c0086b8SZbigniew Bodek */
4752306b72aSZbigniew Bodek static void
nic_mbx_send_ack(struct nicpf * nic,int vf)4762306b72aSZbigniew Bodek nic_mbx_send_ack(struct nicpf *nic, int vf)
4773c0086b8SZbigniew Bodek {
4783c0086b8SZbigniew Bodek union nic_mbx mbx = {};
4793c0086b8SZbigniew Bodek
4803c0086b8SZbigniew Bodek mbx.msg.msg = NIC_MBOX_MSG_ACK;
4813c0086b8SZbigniew Bodek nic_send_msg_to_vf(nic, vf, &mbx);
4823c0086b8SZbigniew Bodek }
4833c0086b8SZbigniew Bodek
4842306b72aSZbigniew Bodek /*
4852306b72aSZbigniew Bodek * NACKs VF's mailbox message that PF is not able to
4863c0086b8SZbigniew Bodek * complete the action
4873c0086b8SZbigniew Bodek * @vf: VF to which ACK to be sent
4883c0086b8SZbigniew Bodek */
4892306b72aSZbigniew Bodek static void
nic_mbx_send_nack(struct nicpf * nic,int vf)4902306b72aSZbigniew Bodek nic_mbx_send_nack(struct nicpf *nic, int vf)
4913c0086b8SZbigniew Bodek {
4923c0086b8SZbigniew Bodek union nic_mbx mbx = {};
4933c0086b8SZbigniew Bodek
4943c0086b8SZbigniew Bodek mbx.msg.msg = NIC_MBOX_MSG_NACK;
4953c0086b8SZbigniew Bodek nic_send_msg_to_vf(nic, vf, &mbx);
4963c0086b8SZbigniew Bodek }
4973c0086b8SZbigniew Bodek
4982306b72aSZbigniew Bodek /*
4992306b72aSZbigniew Bodek * Flush all in flight receive packets to memory and
5003c0086b8SZbigniew Bodek * bring down an active RQ
5013c0086b8SZbigniew Bodek */
5022306b72aSZbigniew Bodek static int
nic_rcv_queue_sw_sync(struct nicpf * nic)5032306b72aSZbigniew Bodek nic_rcv_queue_sw_sync(struct nicpf *nic)
5043c0086b8SZbigniew Bodek {
5052306b72aSZbigniew Bodek uint16_t timeout = ~0x00;
5063c0086b8SZbigniew Bodek
5073c0086b8SZbigniew Bodek nic_reg_write(nic, NIC_PF_SW_SYNC_RX, 0x01);
5083c0086b8SZbigniew Bodek /* Wait till sync cycle is finished */
5093c0086b8SZbigniew Bodek while (timeout) {
5103c0086b8SZbigniew Bodek if (nic_reg_read(nic, NIC_PF_SW_SYNC_RX_DONE) & 0x1)
5113c0086b8SZbigniew Bodek break;
5123c0086b8SZbigniew Bodek timeout--;
5133c0086b8SZbigniew Bodek }
5143c0086b8SZbigniew Bodek nic_reg_write(nic, NIC_PF_SW_SYNC_RX, 0x00);
5153c0086b8SZbigniew Bodek if (!timeout) {
5162306b72aSZbigniew Bodek device_printf(nic->dev, "Receive queue software sync failed\n");
5172306b72aSZbigniew Bodek return (ETIMEDOUT);
5183c0086b8SZbigniew Bodek }
5192306b72aSZbigniew Bodek return (0);
5203c0086b8SZbigniew Bodek }
5213c0086b8SZbigniew Bodek
5223c0086b8SZbigniew Bodek /* Get BGX Rx/Tx stats and respond to VF's request */
5232306b72aSZbigniew Bodek static void
nic_get_bgx_stats(struct nicpf * nic,struct bgx_stats_msg * bgx)5242306b72aSZbigniew Bodek nic_get_bgx_stats(struct nicpf *nic, struct bgx_stats_msg *bgx)
5253c0086b8SZbigniew Bodek {
5263c0086b8SZbigniew Bodek int bgx_idx, lmac;
5273c0086b8SZbigniew Bodek union nic_mbx mbx = {};
5283c0086b8SZbigniew Bodek
5293c0086b8SZbigniew Bodek bgx_idx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[bgx->vf_id]);
5303c0086b8SZbigniew Bodek lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[bgx->vf_id]);
5313c0086b8SZbigniew Bodek
5323c0086b8SZbigniew Bodek mbx.bgx_stats.msg = NIC_MBOX_MSG_BGX_STATS;
5333c0086b8SZbigniew Bodek mbx.bgx_stats.vf_id = bgx->vf_id;
5343c0086b8SZbigniew Bodek mbx.bgx_stats.rx = bgx->rx;
5353c0086b8SZbigniew Bodek mbx.bgx_stats.idx = bgx->idx;
5362306b72aSZbigniew Bodek if (bgx->rx != 0) {
5372306b72aSZbigniew Bodek mbx.bgx_stats.stats =
5382306b72aSZbigniew Bodek bgx_get_rx_stats(nic->node, bgx_idx, lmac, bgx->idx);
5392306b72aSZbigniew Bodek } else {
5402306b72aSZbigniew Bodek mbx.bgx_stats.stats =
5412306b72aSZbigniew Bodek bgx_get_tx_stats(nic->node, bgx_idx, lmac, bgx->idx);
5422306b72aSZbigniew Bodek }
5433c0086b8SZbigniew Bodek nic_send_msg_to_vf(nic, bgx->vf_id, &mbx);
5443c0086b8SZbigniew Bodek }
5453c0086b8SZbigniew Bodek
5463c0086b8SZbigniew Bodek /* Update hardware min/max frame size */
5472306b72aSZbigniew Bodek static int
nic_update_hw_frs(struct nicpf * nic,int new_frs,int vf)5482306b72aSZbigniew Bodek nic_update_hw_frs(struct nicpf *nic, int new_frs, int vf)
5493c0086b8SZbigniew Bodek {
5502306b72aSZbigniew Bodek
5513c0086b8SZbigniew Bodek if ((new_frs > NIC_HW_MAX_FRS) || (new_frs < NIC_HW_MIN_FRS)) {
5522306b72aSZbigniew Bodek device_printf(nic->dev,
5532306b72aSZbigniew Bodek "Invalid MTU setting from VF%d rejected, "
5542306b72aSZbigniew Bodek "should be between %d and %d\n",
5553c0086b8SZbigniew Bodek vf, NIC_HW_MIN_FRS, NIC_HW_MAX_FRS);
5562306b72aSZbigniew Bodek return (EINVAL);
5573c0086b8SZbigniew Bodek }
5582306b72aSZbigniew Bodek new_frs += ETHER_HDR_LEN;
5593c0086b8SZbigniew Bodek if (new_frs <= nic->pkind.maxlen)
5602306b72aSZbigniew Bodek return (0);
5613c0086b8SZbigniew Bodek
5623c0086b8SZbigniew Bodek nic->pkind.maxlen = new_frs;
5632306b72aSZbigniew Bodek nic_reg_write(nic, NIC_PF_PKIND_0_15_CFG, *(uint64_t *)&nic->pkind);
5642306b72aSZbigniew Bodek return (0);
5653c0086b8SZbigniew Bodek }
5663c0086b8SZbigniew Bodek
5673c0086b8SZbigniew Bodek /* Set minimum transmit packet size */
5682306b72aSZbigniew Bodek static void
nic_set_tx_pkt_pad(struct nicpf * nic,int size)5692306b72aSZbigniew Bodek nic_set_tx_pkt_pad(struct nicpf *nic, int size)
5703c0086b8SZbigniew Bodek {
5713c0086b8SZbigniew Bodek int lmac;
5722306b72aSZbigniew Bodek uint64_t lmac_cfg;
5733c0086b8SZbigniew Bodek
5743c0086b8SZbigniew Bodek /* Max value that can be set is 60 */
5753c0086b8SZbigniew Bodek if (size > 60)
5763c0086b8SZbigniew Bodek size = 60;
5773c0086b8SZbigniew Bodek
5783c0086b8SZbigniew Bodek for (lmac = 0; lmac < (MAX_BGX_PER_CN88XX * MAX_LMAC_PER_BGX); lmac++) {
5793c0086b8SZbigniew Bodek lmac_cfg = nic_reg_read(nic, NIC_PF_LMAC_0_7_CFG | (lmac << 3));
5803c0086b8SZbigniew Bodek lmac_cfg &= ~(0xF << 2);
5813c0086b8SZbigniew Bodek lmac_cfg |= ((size / 4) << 2);
5823c0086b8SZbigniew Bodek nic_reg_write(nic, NIC_PF_LMAC_0_7_CFG | (lmac << 3), lmac_cfg);
5833c0086b8SZbigniew Bodek }
5843c0086b8SZbigniew Bodek }
5853c0086b8SZbigniew Bodek
5862306b72aSZbigniew Bodek /*
5872306b72aSZbigniew Bodek * Function to check number of LMACs present and set VF::LMAC mapping.
5883c0086b8SZbigniew Bodek * Mapping will be used while initializing channels.
5893c0086b8SZbigniew Bodek */
5902306b72aSZbigniew Bodek static void
nic_set_lmac_vf_mapping(struct nicpf * nic)5912306b72aSZbigniew Bodek nic_set_lmac_vf_mapping(struct nicpf *nic)
5923c0086b8SZbigniew Bodek {
5933c0086b8SZbigniew Bodek unsigned bgx_map = bgx_get_map(nic->node);
5943c0086b8SZbigniew Bodek int bgx, next_bgx_lmac = 0;
5953c0086b8SZbigniew Bodek int lmac, lmac_cnt = 0;
5962306b72aSZbigniew Bodek uint64_t lmac_credit;
5973c0086b8SZbigniew Bodek
5983c0086b8SZbigniew Bodek nic->num_vf_en = 0;
5993c0086b8SZbigniew Bodek if (nic->flags & NIC_TNS_ENABLED) {
6003c0086b8SZbigniew Bodek nic->num_vf_en = DEFAULT_NUM_VF_ENABLED;
6013c0086b8SZbigniew Bodek return;
6023c0086b8SZbigniew Bodek }
6033c0086b8SZbigniew Bodek
6043c0086b8SZbigniew Bodek for (bgx = 0; bgx < NIC_MAX_BGX; bgx++) {
6052306b72aSZbigniew Bodek if ((bgx_map & (1 << bgx)) == 0)
6063c0086b8SZbigniew Bodek continue;
6073c0086b8SZbigniew Bodek lmac_cnt = bgx_get_lmac_count(nic->node, bgx);
6083c0086b8SZbigniew Bodek for (lmac = 0; lmac < lmac_cnt; lmac++)
6093c0086b8SZbigniew Bodek nic->vf_lmac_map[next_bgx_lmac++] =
6103c0086b8SZbigniew Bodek NIC_SET_VF_LMAC_MAP(bgx, lmac);
6113c0086b8SZbigniew Bodek nic->num_vf_en += lmac_cnt;
6123c0086b8SZbigniew Bodek
6133c0086b8SZbigniew Bodek /* Program LMAC credits */
6142306b72aSZbigniew Bodek lmac_credit = (1UL << 1); /* channel credit enable */
6153c0086b8SZbigniew Bodek lmac_credit |= (0x1ff << 2); /* Max outstanding pkt count */
6163c0086b8SZbigniew Bodek /* 48KB BGX Tx buffer size, each unit is of size 16bytes */
6173c0086b8SZbigniew Bodek lmac_credit |= (((((48 * 1024) / lmac_cnt) -
6183c0086b8SZbigniew Bodek NIC_HW_MAX_FRS) / 16) << 12);
6193c0086b8SZbigniew Bodek lmac = bgx * MAX_LMAC_PER_BGX;
6202306b72aSZbigniew Bodek for (; lmac < lmac_cnt + (bgx * MAX_LMAC_PER_BGX); lmac++) {
6212306b72aSZbigniew Bodek nic_reg_write(nic, NIC_PF_LMAC_0_7_CREDIT + (lmac * 8),
6223c0086b8SZbigniew Bodek lmac_credit);
6233c0086b8SZbigniew Bodek }
6243c0086b8SZbigniew Bodek }
6252306b72aSZbigniew Bodek }
6263c0086b8SZbigniew Bodek
6273c0086b8SZbigniew Bodek #define TNS_PORT0_BLOCK 6
6283c0086b8SZbigniew Bodek #define TNS_PORT1_BLOCK 7
6293c0086b8SZbigniew Bodek #define BGX0_BLOCK 8
6303c0086b8SZbigniew Bodek #define BGX1_BLOCK 9
6313c0086b8SZbigniew Bodek
6322306b72aSZbigniew Bodek static void
nic_init_hw(struct nicpf * nic)6332306b72aSZbigniew Bodek nic_init_hw(struct nicpf *nic)
6343c0086b8SZbigniew Bodek {
6353c0086b8SZbigniew Bodek int i;
6363c0086b8SZbigniew Bodek
6373c0086b8SZbigniew Bodek /* Enable NIC HW block */
6383c0086b8SZbigniew Bodek nic_reg_write(nic, NIC_PF_CFG, 0x3);
6393c0086b8SZbigniew Bodek
6403c0086b8SZbigniew Bodek /* Enable backpressure */
6412306b72aSZbigniew Bodek nic_reg_write(nic, NIC_PF_BP_CFG, (1UL << 6) | 0x03);
6423c0086b8SZbigniew Bodek
6433c0086b8SZbigniew Bodek if (nic->flags & NIC_TNS_ENABLED) {
6443c0086b8SZbigniew Bodek nic_reg_write(nic, NIC_PF_INTF_0_1_SEND_CFG,
6453c0086b8SZbigniew Bodek (NIC_TNS_MODE << 7) | TNS_PORT0_BLOCK);
6463c0086b8SZbigniew Bodek nic_reg_write(nic, NIC_PF_INTF_0_1_SEND_CFG | (1 << 8),
6473c0086b8SZbigniew Bodek (NIC_TNS_MODE << 7) | TNS_PORT1_BLOCK);
6483c0086b8SZbigniew Bodek nic_reg_write(nic, NIC_PF_INTF_0_1_BP_CFG,
6492306b72aSZbigniew Bodek (1UL << 63) | TNS_PORT0_BLOCK);
6503c0086b8SZbigniew Bodek nic_reg_write(nic, NIC_PF_INTF_0_1_BP_CFG + (1 << 8),
6512306b72aSZbigniew Bodek (1UL << 63) | TNS_PORT1_BLOCK);
6523c0086b8SZbigniew Bodek
6533c0086b8SZbigniew Bodek } else {
6543c0086b8SZbigniew Bodek /* Disable TNS mode on both interfaces */
6553c0086b8SZbigniew Bodek nic_reg_write(nic, NIC_PF_INTF_0_1_SEND_CFG,
6563c0086b8SZbigniew Bodek (NIC_TNS_BYPASS_MODE << 7) | BGX0_BLOCK);
6573c0086b8SZbigniew Bodek nic_reg_write(nic, NIC_PF_INTF_0_1_SEND_CFG | (1 << 8),
6583c0086b8SZbigniew Bodek (NIC_TNS_BYPASS_MODE << 7) | BGX1_BLOCK);
6593c0086b8SZbigniew Bodek nic_reg_write(nic, NIC_PF_INTF_0_1_BP_CFG,
6602306b72aSZbigniew Bodek (1UL << 63) | BGX0_BLOCK);
6613c0086b8SZbigniew Bodek nic_reg_write(nic, NIC_PF_INTF_0_1_BP_CFG + (1 << 8),
6622306b72aSZbigniew Bodek (1UL << 63) | BGX1_BLOCK);
6633c0086b8SZbigniew Bodek }
6643c0086b8SZbigniew Bodek
6653c0086b8SZbigniew Bodek /* PKIND configuration */
6663c0086b8SZbigniew Bodek nic->pkind.minlen = 0;
6672306b72aSZbigniew Bodek nic->pkind.maxlen = NIC_HW_MAX_FRS + ETHER_HDR_LEN;
6683c0086b8SZbigniew Bodek nic->pkind.lenerr_en = 1;
6693c0086b8SZbigniew Bodek nic->pkind.rx_hdr = 0;
6703c0086b8SZbigniew Bodek nic->pkind.hdr_sl = 0;
6713c0086b8SZbigniew Bodek
6722306b72aSZbigniew Bodek for (i = 0; i < NIC_MAX_PKIND; i++) {
6733c0086b8SZbigniew Bodek nic_reg_write(nic, NIC_PF_PKIND_0_15_CFG | (i << 3),
6742306b72aSZbigniew Bodek *(uint64_t *)&nic->pkind);
6752306b72aSZbigniew Bodek }
6763c0086b8SZbigniew Bodek
6773c0086b8SZbigniew Bodek nic_set_tx_pkt_pad(nic, NIC_HW_MIN_FRS);
6783c0086b8SZbigniew Bodek
6793c0086b8SZbigniew Bodek /* Timer config */
6803c0086b8SZbigniew Bodek nic_reg_write(nic, NIC_PF_INTR_TIMER_CFG, NICPF_CLK_PER_INT_TICK);
6813c0086b8SZbigniew Bodek
6823c0086b8SZbigniew Bodek /* Enable VLAN ethertype matching and stripping */
6833c0086b8SZbigniew Bodek nic_reg_write(nic, NIC_PF_RX_ETYPE_0_7,
6842306b72aSZbigniew Bodek (2 << 19) | (ETYPE_ALG_VLAN_STRIP << 16) | ETHERTYPE_VLAN);
6853c0086b8SZbigniew Bodek }
6863c0086b8SZbigniew Bodek
6873c0086b8SZbigniew Bodek /* Channel parse index configuration */
6882306b72aSZbigniew Bodek static void
nic_config_cpi(struct nicpf * nic,struct cpi_cfg_msg * cfg)6892306b72aSZbigniew Bodek nic_config_cpi(struct nicpf *nic, struct cpi_cfg_msg *cfg)
6903c0086b8SZbigniew Bodek {
6912306b72aSZbigniew Bodek uint32_t vnic, bgx, lmac, chan;
6922306b72aSZbigniew Bodek uint32_t padd, cpi_count = 0;
6932306b72aSZbigniew Bodek uint64_t cpi_base, cpi, rssi_base, rssi;
6942306b72aSZbigniew Bodek uint8_t qset, rq_idx = 0;
6953c0086b8SZbigniew Bodek
6963c0086b8SZbigniew Bodek vnic = cfg->vf_id;
6973c0086b8SZbigniew Bodek bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vnic]);
6983c0086b8SZbigniew Bodek lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vnic]);
6993c0086b8SZbigniew Bodek
7003c0086b8SZbigniew Bodek chan = (lmac * MAX_BGX_CHANS_PER_LMAC) + (bgx * NIC_CHANS_PER_INF);
7013c0086b8SZbigniew Bodek cpi_base = (lmac * NIC_MAX_CPI_PER_LMAC) + (bgx * NIC_CPI_PER_BGX);
7023c0086b8SZbigniew Bodek rssi_base = (lmac * nic->rss_ind_tbl_size) + (bgx * NIC_RSSI_PER_BGX);
7033c0086b8SZbigniew Bodek
7043c0086b8SZbigniew Bodek /* Rx channel configuration */
7053c0086b8SZbigniew Bodek nic_reg_write(nic, NIC_PF_CHAN_0_255_RX_BP_CFG | (chan << 3),
7062306b72aSZbigniew Bodek (1UL << 63) | (vnic << 0));
7073c0086b8SZbigniew Bodek nic_reg_write(nic, NIC_PF_CHAN_0_255_RX_CFG | (chan << 3),
7082306b72aSZbigniew Bodek ((uint64_t)cfg->cpi_alg << 62) | (cpi_base << 48));
7093c0086b8SZbigniew Bodek
7103c0086b8SZbigniew Bodek if (cfg->cpi_alg == CPI_ALG_NONE)
7113c0086b8SZbigniew Bodek cpi_count = 1;
7123c0086b8SZbigniew Bodek else if (cfg->cpi_alg == CPI_ALG_VLAN) /* 3 bits of PCP */
7133c0086b8SZbigniew Bodek cpi_count = 8;
7143c0086b8SZbigniew Bodek else if (cfg->cpi_alg == CPI_ALG_VLAN16) /* 3 bits PCP + DEI */
7153c0086b8SZbigniew Bodek cpi_count = 16;
7163c0086b8SZbigniew Bodek else if (cfg->cpi_alg == CPI_ALG_DIFF) /* 6bits DSCP */
7173c0086b8SZbigniew Bodek cpi_count = NIC_MAX_CPI_PER_LMAC;
7183c0086b8SZbigniew Bodek
7193c0086b8SZbigniew Bodek /* RSS Qset, Qidx mapping */
7203c0086b8SZbigniew Bodek qset = cfg->vf_id;
7213c0086b8SZbigniew Bodek rssi = rssi_base;
7223c0086b8SZbigniew Bodek for (; rssi < (rssi_base + cfg->rq_cnt); rssi++) {
7233c0086b8SZbigniew Bodek nic_reg_write(nic, NIC_PF_RSSI_0_4097_RQ | (rssi << 3),
7243c0086b8SZbigniew Bodek (qset << 3) | rq_idx);
7253c0086b8SZbigniew Bodek rq_idx++;
7263c0086b8SZbigniew Bodek }
7273c0086b8SZbigniew Bodek
7283c0086b8SZbigniew Bodek rssi = 0;
7293c0086b8SZbigniew Bodek cpi = cpi_base;
7303c0086b8SZbigniew Bodek for (; cpi < (cpi_base + cpi_count); cpi++) {
7313c0086b8SZbigniew Bodek /* Determine port to channel adder */
7323c0086b8SZbigniew Bodek if (cfg->cpi_alg != CPI_ALG_DIFF)
7333c0086b8SZbigniew Bodek padd = cpi % cpi_count;
7343c0086b8SZbigniew Bodek else
7353c0086b8SZbigniew Bodek padd = cpi % 8; /* 3 bits CS out of 6bits DSCP */
7363c0086b8SZbigniew Bodek
7373c0086b8SZbigniew Bodek /* Leave RSS_SIZE as '0' to disable RSS */
7383ad422a9SZbigniew Bodek if (pass1_silicon(nic->dev)) {
7393c0086b8SZbigniew Bodek nic_reg_write(nic, NIC_PF_CPI_0_2047_CFG | (cpi << 3),
7403c0086b8SZbigniew Bodek (vnic << 24) | (padd << 16) | (rssi_base + rssi));
7413ad422a9SZbigniew Bodek } else {
7423ad422a9SZbigniew Bodek /* Set MPI_ALG to '0' to disable MCAM parsing */
7433ad422a9SZbigniew Bodek nic_reg_write(nic, NIC_PF_CPI_0_2047_CFG | (cpi << 3),
7443ad422a9SZbigniew Bodek (padd << 16));
7453ad422a9SZbigniew Bodek /* MPI index is same as CPI if MPI_ALG is not enabled */
7463ad422a9SZbigniew Bodek nic_reg_write(nic, NIC_PF_MPI_0_2047_CFG | (cpi << 3),
7473ad422a9SZbigniew Bodek (vnic << 24) | (rssi_base + rssi));
7483ad422a9SZbigniew Bodek }
7493c0086b8SZbigniew Bodek
7503c0086b8SZbigniew Bodek if ((rssi + 1) >= cfg->rq_cnt)
7513c0086b8SZbigniew Bodek continue;
7523c0086b8SZbigniew Bodek
7533c0086b8SZbigniew Bodek if (cfg->cpi_alg == CPI_ALG_VLAN)
7543c0086b8SZbigniew Bodek rssi++;
7553c0086b8SZbigniew Bodek else if (cfg->cpi_alg == CPI_ALG_VLAN16)
7563c0086b8SZbigniew Bodek rssi = ((cpi - cpi_base) & 0xe) >> 1;
7573c0086b8SZbigniew Bodek else if (cfg->cpi_alg == CPI_ALG_DIFF)
7583c0086b8SZbigniew Bodek rssi = ((cpi - cpi_base) & 0x38) >> 3;
7593c0086b8SZbigniew Bodek }
7603c0086b8SZbigniew Bodek nic->cpi_base[cfg->vf_id] = cpi_base;
7618191a879SZbigniew Bodek nic->rssi_base[cfg->vf_id] = rssi_base;
7628191a879SZbigniew Bodek }
7638191a879SZbigniew Bodek
7648191a879SZbigniew Bodek /* Responsds to VF with its RSS indirection table size */
7658191a879SZbigniew Bodek static void
nic_send_rss_size(struct nicpf * nic,int vf)7668191a879SZbigniew Bodek nic_send_rss_size(struct nicpf *nic, int vf)
7678191a879SZbigniew Bodek {
7688191a879SZbigniew Bodek union nic_mbx mbx = {};
7698191a879SZbigniew Bodek
7708191a879SZbigniew Bodek mbx.rss_size.msg = NIC_MBOX_MSG_RSS_SIZE;
7718191a879SZbigniew Bodek mbx.rss_size.ind_tbl_size = nic->rss_ind_tbl_size;
7728191a879SZbigniew Bodek nic_send_msg_to_vf(nic, vf, &mbx);
7738191a879SZbigniew Bodek }
7748191a879SZbigniew Bodek
7758191a879SZbigniew Bodek /*
7768191a879SZbigniew Bodek * Receive side scaling configuration
7778191a879SZbigniew Bodek * configure:
7788191a879SZbigniew Bodek * - RSS index
7798191a879SZbigniew Bodek * - indir table i.e hash::RQ mapping
7808191a879SZbigniew Bodek * - no of hash bits to consider
7818191a879SZbigniew Bodek */
7828191a879SZbigniew Bodek static void
nic_config_rss(struct nicpf * nic,struct rss_cfg_msg * cfg)7838191a879SZbigniew Bodek nic_config_rss(struct nicpf *nic, struct rss_cfg_msg *cfg)
7848191a879SZbigniew Bodek {
7858191a879SZbigniew Bodek uint8_t qset, idx;
7868191a879SZbigniew Bodek uint64_t cpi_cfg, cpi_base, rssi_base, rssi;
7878191a879SZbigniew Bodek uint64_t idx_addr;
7888191a879SZbigniew Bodek
7898191a879SZbigniew Bodek idx = 0;
7908191a879SZbigniew Bodek rssi_base = nic->rssi_base[cfg->vf_id] + cfg->tbl_offset;
7918191a879SZbigniew Bodek
7928191a879SZbigniew Bodek rssi = rssi_base;
7938191a879SZbigniew Bodek qset = cfg->vf_id;
7948191a879SZbigniew Bodek
7958191a879SZbigniew Bodek for (; rssi < (rssi_base + cfg->tbl_len); rssi++) {
7968191a879SZbigniew Bodek nic_reg_write(nic, NIC_PF_RSSI_0_4097_RQ | (rssi << 3),
7978191a879SZbigniew Bodek (qset << 3) | (cfg->ind_tbl[idx] & 0x7));
7988191a879SZbigniew Bodek idx++;
7998191a879SZbigniew Bodek }
8008191a879SZbigniew Bodek
8018191a879SZbigniew Bodek cpi_base = nic->cpi_base[cfg->vf_id];
8028191a879SZbigniew Bodek if (pass1_silicon(nic->dev))
8038191a879SZbigniew Bodek idx_addr = NIC_PF_CPI_0_2047_CFG;
8048191a879SZbigniew Bodek else
8058191a879SZbigniew Bodek idx_addr = NIC_PF_MPI_0_2047_CFG;
8068191a879SZbigniew Bodek cpi_cfg = nic_reg_read(nic, idx_addr | (cpi_base << 3));
8078191a879SZbigniew Bodek cpi_cfg &= ~(0xFUL << 20);
8088191a879SZbigniew Bodek cpi_cfg |= (cfg->hash_bits << 20);
8098191a879SZbigniew Bodek nic_reg_write(nic, idx_addr | (cpi_base << 3), cpi_cfg);
8103c0086b8SZbigniew Bodek }
8113c0086b8SZbigniew Bodek
8122306b72aSZbigniew Bodek /*
8132306b72aSZbigniew Bodek * 4 level transmit side scheduler configutation
8143c0086b8SZbigniew Bodek * for TNS bypass mode
8153c0086b8SZbigniew Bodek *
8163c0086b8SZbigniew Bodek * Sample configuration for SQ0
8173c0086b8SZbigniew Bodek * VNIC0-SQ0 -> TL4(0) -> TL3[0] -> TL2[0] -> TL1[0] -> BGX0
8183c0086b8SZbigniew Bodek * VNIC1-SQ0 -> TL4(8) -> TL3[2] -> TL2[0] -> TL1[0] -> BGX0
8193c0086b8SZbigniew Bodek * VNIC2-SQ0 -> TL4(16) -> TL3[4] -> TL2[1] -> TL1[0] -> BGX0
8203c0086b8SZbigniew Bodek * VNIC3-SQ0 -> TL4(24) -> TL3[6] -> TL2[1] -> TL1[0] -> BGX0
8213c0086b8SZbigniew Bodek * VNIC4-SQ0 -> TL4(512) -> TL3[128] -> TL2[32] -> TL1[1] -> BGX1
8223c0086b8SZbigniew Bodek * VNIC5-SQ0 -> TL4(520) -> TL3[130] -> TL2[32] -> TL1[1] -> BGX1
8233c0086b8SZbigniew Bodek * VNIC6-SQ0 -> TL4(528) -> TL3[132] -> TL2[33] -> TL1[1] -> BGX1
8243c0086b8SZbigniew Bodek * VNIC7-SQ0 -> TL4(536) -> TL3[134] -> TL2[33] -> TL1[1] -> BGX1
8253c0086b8SZbigniew Bodek */
8262306b72aSZbigniew Bodek static void
nic_tx_channel_cfg(struct nicpf * nic,uint8_t vnic,struct sq_cfg_msg * sq)8272306b72aSZbigniew Bodek nic_tx_channel_cfg(struct nicpf *nic, uint8_t vnic, struct sq_cfg_msg *sq)
8283c0086b8SZbigniew Bodek {
8292306b72aSZbigniew Bodek uint32_t bgx, lmac, chan;
8302306b72aSZbigniew Bodek uint32_t tl2, tl3, tl4;
8312306b72aSZbigniew Bodek uint32_t rr_quantum;
8322306b72aSZbigniew Bodek uint8_t sq_idx = sq->sq_num;
8332306b72aSZbigniew Bodek uint8_t pqs_vnic;
8343c0086b8SZbigniew Bodek
8353c0086b8SZbigniew Bodek pqs_vnic = vnic;
8363c0086b8SZbigniew Bodek
8373c0086b8SZbigniew Bodek bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[pqs_vnic]);
8383c0086b8SZbigniew Bodek lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[pqs_vnic]);
8393c0086b8SZbigniew Bodek
8403c0086b8SZbigniew Bodek /* 24 bytes for FCS, IPG and preamble */
8413c0086b8SZbigniew Bodek rr_quantum = ((NIC_HW_MAX_FRS + 24) / 4);
8423c0086b8SZbigniew Bodek
8433c0086b8SZbigniew Bodek tl4 = (lmac * NIC_TL4_PER_LMAC) + (bgx * NIC_TL4_PER_BGX);
8443c0086b8SZbigniew Bodek tl4 += sq_idx;
8453c0086b8SZbigniew Bodek
8463c0086b8SZbigniew Bodek tl3 = tl4 / (NIC_MAX_TL4 / NIC_MAX_TL3);
8473c0086b8SZbigniew Bodek nic_reg_write(nic, NIC_PF_QSET_0_127_SQ_0_7_CFG2 |
8482306b72aSZbigniew Bodek ((uint64_t)vnic << NIC_QS_ID_SHIFT) |
8492306b72aSZbigniew Bodek ((uint32_t)sq_idx << NIC_Q_NUM_SHIFT), tl4);
8503c0086b8SZbigniew Bodek nic_reg_write(nic, NIC_PF_TL4_0_1023_CFG | (tl4 << 3),
8512306b72aSZbigniew Bodek ((uint64_t)vnic << 27) | ((uint32_t)sq_idx << 24) | rr_quantum);
8523c0086b8SZbigniew Bodek
8533c0086b8SZbigniew Bodek nic_reg_write(nic, NIC_PF_TL3_0_255_CFG | (tl3 << 3), rr_quantum);
8543c0086b8SZbigniew Bodek chan = (lmac * MAX_BGX_CHANS_PER_LMAC) + (bgx * NIC_CHANS_PER_INF);
8553c0086b8SZbigniew Bodek nic_reg_write(nic, NIC_PF_TL3_0_255_CHAN | (tl3 << 3), chan);
8563c0086b8SZbigniew Bodek /* Enable backpressure on the channel */
8573c0086b8SZbigniew Bodek nic_reg_write(nic, NIC_PF_CHAN_0_255_TX_CFG | (chan << 3), 1);
8583c0086b8SZbigniew Bodek
8593c0086b8SZbigniew Bodek tl2 = tl3 >> 2;
8603c0086b8SZbigniew Bodek nic_reg_write(nic, NIC_PF_TL3A_0_63_CFG | (tl2 << 3), tl2);
8613c0086b8SZbigniew Bodek nic_reg_write(nic, NIC_PF_TL2_0_63_CFG | (tl2 << 3), rr_quantum);
8623c0086b8SZbigniew Bodek /* No priorities as of now */
8633c0086b8SZbigniew Bodek nic_reg_write(nic, NIC_PF_TL2_0_63_PRI | (tl2 << 3), 0x00);
8643c0086b8SZbigniew Bodek }
8653c0086b8SZbigniew Bodek
8662306b72aSZbigniew Bodek static int
nic_config_loopback(struct nicpf * nic,struct set_loopback * lbk)8672306b72aSZbigniew Bodek nic_config_loopback(struct nicpf *nic, struct set_loopback *lbk)
8683c0086b8SZbigniew Bodek {
8693c0086b8SZbigniew Bodek int bgx_idx, lmac_idx;
8703c0086b8SZbigniew Bodek
8713c0086b8SZbigniew Bodek if (lbk->vf_id > MAX_LMAC)
8722306b72aSZbigniew Bodek return (ENXIO);
8733c0086b8SZbigniew Bodek
8743c0086b8SZbigniew Bodek bgx_idx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[lbk->vf_id]);
8753c0086b8SZbigniew Bodek lmac_idx = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[lbk->vf_id]);
8763c0086b8SZbigniew Bodek
8773c0086b8SZbigniew Bodek bgx_lmac_internal_loopback(nic->node, bgx_idx, lmac_idx, lbk->enable);
8783c0086b8SZbigniew Bodek
8792306b72aSZbigniew Bodek return (0);
8803c0086b8SZbigniew Bodek }
8813c0086b8SZbigniew Bodek
8823c0086b8SZbigniew Bodek /* Interrupt handler to handle mailbox messages from VFs */
8832306b72aSZbigniew Bodek static void
nic_handle_mbx_intr(struct nicpf * nic,int vf)8842306b72aSZbigniew Bodek nic_handle_mbx_intr(struct nicpf *nic, int vf)
8853c0086b8SZbigniew Bodek {
8863c0086b8SZbigniew Bodek union nic_mbx mbx = {};
8872306b72aSZbigniew Bodek uint64_t *mbx_data;
8882306b72aSZbigniew Bodek uint64_t mbx_addr;
8892306b72aSZbigniew Bodek uint64_t reg_addr;
8902306b72aSZbigniew Bodek uint64_t cfg;
8913c0086b8SZbigniew Bodek int bgx, lmac;
8923c0086b8SZbigniew Bodek int i;
8933c0086b8SZbigniew Bodek int ret = 0;
8943c0086b8SZbigniew Bodek
8952306b72aSZbigniew Bodek nic->mbx_lock[vf] = TRUE;
8963c0086b8SZbigniew Bodek
8973c0086b8SZbigniew Bodek mbx_addr = nic_get_mbx_addr(vf);
8982306b72aSZbigniew Bodek mbx_data = (uint64_t *)&mbx;
8993c0086b8SZbigniew Bodek
9003c0086b8SZbigniew Bodek for (i = 0; i < NIC_PF_VF_MAILBOX_SIZE; i++) {
9013c0086b8SZbigniew Bodek *mbx_data = nic_reg_read(nic, mbx_addr);
9023c0086b8SZbigniew Bodek mbx_data++;
9032306b72aSZbigniew Bodek mbx_addr += sizeof(uint64_t);
9043c0086b8SZbigniew Bodek }
9053c0086b8SZbigniew Bodek
9063c0086b8SZbigniew Bodek switch (mbx.msg.msg) {
9073c0086b8SZbigniew Bodek case NIC_MBOX_MSG_READY:
9083c0086b8SZbigniew Bodek nic_mbx_send_ready(nic, vf);
9093c0086b8SZbigniew Bodek if (vf < MAX_LMAC) {
9103c0086b8SZbigniew Bodek nic->link[vf] = 0;
9113c0086b8SZbigniew Bodek nic->duplex[vf] = 0;
9123c0086b8SZbigniew Bodek nic->speed[vf] = 0;
9133c0086b8SZbigniew Bodek }
9143c0086b8SZbigniew Bodek ret = 1;
9153c0086b8SZbigniew Bodek break;
9163c0086b8SZbigniew Bodek case NIC_MBOX_MSG_QS_CFG:
9173c0086b8SZbigniew Bodek reg_addr = NIC_PF_QSET_0_127_CFG |
9183c0086b8SZbigniew Bodek (mbx.qs.num << NIC_QS_ID_SHIFT);
9193c0086b8SZbigniew Bodek cfg = mbx.qs.cfg;
9203c0086b8SZbigniew Bodek nic_reg_write(nic, reg_addr, cfg);
9213c0086b8SZbigniew Bodek break;
9223c0086b8SZbigniew Bodek case NIC_MBOX_MSG_RQ_CFG:
9233c0086b8SZbigniew Bodek reg_addr = NIC_PF_QSET_0_127_RQ_0_7_CFG |
9243c0086b8SZbigniew Bodek (mbx.rq.qs_num << NIC_QS_ID_SHIFT) |
9253c0086b8SZbigniew Bodek (mbx.rq.rq_num << NIC_Q_NUM_SHIFT);
9263c0086b8SZbigniew Bodek nic_reg_write(nic, reg_addr, mbx.rq.cfg);
9273c0086b8SZbigniew Bodek break;
9283c0086b8SZbigniew Bodek case NIC_MBOX_MSG_RQ_BP_CFG:
9293c0086b8SZbigniew Bodek reg_addr = NIC_PF_QSET_0_127_RQ_0_7_BP_CFG |
9303c0086b8SZbigniew Bodek (mbx.rq.qs_num << NIC_QS_ID_SHIFT) |
9313c0086b8SZbigniew Bodek (mbx.rq.rq_num << NIC_Q_NUM_SHIFT);
9323c0086b8SZbigniew Bodek nic_reg_write(nic, reg_addr, mbx.rq.cfg);
9333c0086b8SZbigniew Bodek break;
9343c0086b8SZbigniew Bodek case NIC_MBOX_MSG_RQ_SW_SYNC:
9353c0086b8SZbigniew Bodek ret = nic_rcv_queue_sw_sync(nic);
9363c0086b8SZbigniew Bodek break;
9373c0086b8SZbigniew Bodek case NIC_MBOX_MSG_RQ_DROP_CFG:
9383c0086b8SZbigniew Bodek reg_addr = NIC_PF_QSET_0_127_RQ_0_7_DROP_CFG |
9393c0086b8SZbigniew Bodek (mbx.rq.qs_num << NIC_QS_ID_SHIFT) |
9403c0086b8SZbigniew Bodek (mbx.rq.rq_num << NIC_Q_NUM_SHIFT);
9413c0086b8SZbigniew Bodek nic_reg_write(nic, reg_addr, mbx.rq.cfg);
9423c0086b8SZbigniew Bodek break;
9433c0086b8SZbigniew Bodek case NIC_MBOX_MSG_SQ_CFG:
9443c0086b8SZbigniew Bodek reg_addr = NIC_PF_QSET_0_127_SQ_0_7_CFG |
9453c0086b8SZbigniew Bodek (mbx.sq.qs_num << NIC_QS_ID_SHIFT) |
9463c0086b8SZbigniew Bodek (mbx.sq.sq_num << NIC_Q_NUM_SHIFT);
9473c0086b8SZbigniew Bodek nic_reg_write(nic, reg_addr, mbx.sq.cfg);
9483c0086b8SZbigniew Bodek nic_tx_channel_cfg(nic, mbx.qs.num, &mbx.sq);
9493c0086b8SZbigniew Bodek break;
9503c0086b8SZbigniew Bodek case NIC_MBOX_MSG_SET_MAC:
9513c0086b8SZbigniew Bodek lmac = mbx.mac.vf_id;
9523c0086b8SZbigniew Bodek bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[lmac]);
9533c0086b8SZbigniew Bodek lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[lmac]);
9543c0086b8SZbigniew Bodek bgx_set_lmac_mac(nic->node, bgx, lmac, mbx.mac.mac_addr);
9553c0086b8SZbigniew Bodek break;
9563c0086b8SZbigniew Bodek case NIC_MBOX_MSG_SET_MAX_FRS:
9572306b72aSZbigniew Bodek ret = nic_update_hw_frs(nic, mbx.frs.max_frs, mbx.frs.vf_id);
9583c0086b8SZbigniew Bodek break;
9593c0086b8SZbigniew Bodek case NIC_MBOX_MSG_CPI_CFG:
9603c0086b8SZbigniew Bodek nic_config_cpi(nic, &mbx.cpi_cfg);
9613c0086b8SZbigniew Bodek break;
9628191a879SZbigniew Bodek case NIC_MBOX_MSG_RSS_SIZE:
9638191a879SZbigniew Bodek nic_send_rss_size(nic, vf);
9648191a879SZbigniew Bodek goto unlock;
9658191a879SZbigniew Bodek case NIC_MBOX_MSG_RSS_CFG:
9668191a879SZbigniew Bodek case NIC_MBOX_MSG_RSS_CFG_CONT: /* fall through */
9678191a879SZbigniew Bodek nic_config_rss(nic, &mbx.rss_cfg);
9688191a879SZbigniew Bodek break;
9693c0086b8SZbigniew Bodek case NIC_MBOX_MSG_CFG_DONE:
9703c0086b8SZbigniew Bodek /* Last message of VF config msg sequence */
9712306b72aSZbigniew Bodek nic->vf_info[vf].vf_enabled = TRUE;
9723c0086b8SZbigniew Bodek goto unlock;
9733c0086b8SZbigniew Bodek case NIC_MBOX_MSG_SHUTDOWN:
9743c0086b8SZbigniew Bodek /* First msg in VF teardown sequence */
9752306b72aSZbigniew Bodek nic->vf_info[vf].vf_enabled = FALSE;
9763c0086b8SZbigniew Bodek break;
9773c0086b8SZbigniew Bodek case NIC_MBOX_MSG_BGX_STATS:
9783c0086b8SZbigniew Bodek nic_get_bgx_stats(nic, &mbx.bgx_stats);
9793c0086b8SZbigniew Bodek goto unlock;
9803c0086b8SZbigniew Bodek case NIC_MBOX_MSG_LOOPBACK:
9813c0086b8SZbigniew Bodek ret = nic_config_loopback(nic, &mbx.lbk);
9823c0086b8SZbigniew Bodek break;
9833c0086b8SZbigniew Bodek default:
9842306b72aSZbigniew Bodek device_printf(nic->dev,
9853c0086b8SZbigniew Bodek "Invalid msg from VF%d, msg 0x%x\n", vf, mbx.msg.msg);
9863c0086b8SZbigniew Bodek break;
9873c0086b8SZbigniew Bodek }
9883c0086b8SZbigniew Bodek
9892306b72aSZbigniew Bodek if (ret == 0)
9903c0086b8SZbigniew Bodek nic_mbx_send_ack(nic, vf);
9913c0086b8SZbigniew Bodek else if (mbx.msg.msg != NIC_MBOX_MSG_READY)
9923c0086b8SZbigniew Bodek nic_mbx_send_nack(nic, vf);
9933c0086b8SZbigniew Bodek unlock:
9942306b72aSZbigniew Bodek nic->mbx_lock[vf] = FALSE;
9953c0086b8SZbigniew Bodek }
9963c0086b8SZbigniew Bodek
9972306b72aSZbigniew Bodek static void
nic_mbx_intr_handler(struct nicpf * nic,int mbx)9982306b72aSZbigniew Bodek nic_mbx_intr_handler(struct nicpf *nic, int mbx)
9993c0086b8SZbigniew Bodek {
10002306b72aSZbigniew Bodek uint64_t intr;
10012306b72aSZbigniew Bodek uint8_t vf, vf_per_mbx_reg = 64;
10023c0086b8SZbigniew Bodek
10033c0086b8SZbigniew Bodek intr = nic_reg_read(nic, NIC_PF_MAILBOX_INT + (mbx << 3));
10043c0086b8SZbigniew Bodek for (vf = 0; vf < vf_per_mbx_reg; vf++) {
10052306b72aSZbigniew Bodek if (intr & (1UL << vf)) {
10063c0086b8SZbigniew Bodek nic_handle_mbx_intr(nic, vf + (mbx * vf_per_mbx_reg));
10073c0086b8SZbigniew Bodek nic_clear_mbx_intr(nic, vf, mbx);
10083c0086b8SZbigniew Bodek }
10093c0086b8SZbigniew Bodek }
10103c0086b8SZbigniew Bodek }
10113c0086b8SZbigniew Bodek
10122306b72aSZbigniew Bodek static void
nic_mbx0_intr_handler(void * arg)10132306b72aSZbigniew Bodek nic_mbx0_intr_handler (void *arg)
10143c0086b8SZbigniew Bodek {
10152306b72aSZbigniew Bodek struct nicpf *nic = (struct nicpf *)arg;
10163c0086b8SZbigniew Bodek
10173c0086b8SZbigniew Bodek nic_mbx_intr_handler(nic, 0);
10183c0086b8SZbigniew Bodek }
10193c0086b8SZbigniew Bodek
10202306b72aSZbigniew Bodek static void
nic_mbx1_intr_handler(void * arg)10212306b72aSZbigniew Bodek nic_mbx1_intr_handler (void *arg)
10223c0086b8SZbigniew Bodek {
10232306b72aSZbigniew Bodek struct nicpf *nic = (struct nicpf *)arg;
10243c0086b8SZbigniew Bodek
10253c0086b8SZbigniew Bodek nic_mbx_intr_handler(nic, 1);
10263c0086b8SZbigniew Bodek }
10273c0086b8SZbigniew Bodek
10282306b72aSZbigniew Bodek static int
nic_enable_msix(struct nicpf * nic)10292306b72aSZbigniew Bodek nic_enable_msix(struct nicpf *nic)
10303c0086b8SZbigniew Bodek {
10312306b72aSZbigniew Bodek struct pci_devinfo *dinfo;
10322306b72aSZbigniew Bodek int rid, count;
10332306b72aSZbigniew Bodek int ret;
10343c0086b8SZbigniew Bodek
10352306b72aSZbigniew Bodek dinfo = device_get_ivars(nic->dev);
10362306b72aSZbigniew Bodek rid = dinfo->cfg.msix.msix_table_bar;
10372306b72aSZbigniew Bodek nic->msix_table_res =
10382306b72aSZbigniew Bodek bus_alloc_resource_any(nic->dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
10392306b72aSZbigniew Bodek if (nic->msix_table_res == NULL) {
10402306b72aSZbigniew Bodek device_printf(nic->dev,
10412306b72aSZbigniew Bodek "Could not allocate memory for MSI-X table\n");
10422306b72aSZbigniew Bodek return (ENXIO);
10432306b72aSZbigniew Bodek }
10443c0086b8SZbigniew Bodek
10452306b72aSZbigniew Bodek count = nic->num_vec = NIC_PF_MSIX_VECTORS;
10463c0086b8SZbigniew Bodek
10472306b72aSZbigniew Bodek ret = pci_alloc_msix(nic->dev, &count);
10482306b72aSZbigniew Bodek if ((ret != 0) || (count != nic->num_vec)) {
10492306b72aSZbigniew Bodek device_printf(nic->dev,
10502306b72aSZbigniew Bodek "Request for #%d msix vectors failed, error: %d\n",
10512306b72aSZbigniew Bodek nic->num_vec, ret);
10522306b72aSZbigniew Bodek return (ret);
10533c0086b8SZbigniew Bodek }
10543c0086b8SZbigniew Bodek
10553c0086b8SZbigniew Bodek nic->msix_enabled = 1;
10562306b72aSZbigniew Bodek return (0);
10573c0086b8SZbigniew Bodek }
10583c0086b8SZbigniew Bodek
10592306b72aSZbigniew Bodek static void
nic_disable_msix(struct nicpf * nic)10602306b72aSZbigniew Bodek nic_disable_msix(struct nicpf *nic)
10613c0086b8SZbigniew Bodek {
10623c0086b8SZbigniew Bodek if (nic->msix_enabled) {
10632306b72aSZbigniew Bodek pci_release_msi(nic->dev);
10643c0086b8SZbigniew Bodek nic->msix_enabled = 0;
10653c0086b8SZbigniew Bodek nic->num_vec = 0;
10663c0086b8SZbigniew Bodek }
10677056927eSWojciech Macek
10687056927eSWojciech Macek bus_release_resource(nic->dev, SYS_RES_MEMORY,
10697056927eSWojciech Macek rman_get_rid(nic->msix_table_res), nic->msix_table_res);
10703c0086b8SZbigniew Bodek }
10713c0086b8SZbigniew Bodek
10722306b72aSZbigniew Bodek static void
nic_free_all_interrupts(struct nicpf * nic)10732306b72aSZbigniew Bodek nic_free_all_interrupts(struct nicpf *nic)
10743c0086b8SZbigniew Bodek {
10753c0086b8SZbigniew Bodek int irq;
10763c0086b8SZbigniew Bodek
10773c0086b8SZbigniew Bodek for (irq = 0; irq < nic->num_vec; irq++) {
10782306b72aSZbigniew Bodek if (nic->msix_entries[irq].irq_res == NULL)
10792306b72aSZbigniew Bodek continue;
10802306b72aSZbigniew Bodek if (nic->msix_entries[irq].handle != NULL) {
10812306b72aSZbigniew Bodek bus_teardown_intr(nic->dev,
10822306b72aSZbigniew Bodek nic->msix_entries[irq].irq_res,
10832306b72aSZbigniew Bodek nic->msix_entries[irq].handle);
10842306b72aSZbigniew Bodek }
10852306b72aSZbigniew Bodek
10867056927eSWojciech Macek bus_release_resource(nic->dev, SYS_RES_IRQ, irq + 1,
10872306b72aSZbigniew Bodek nic->msix_entries[irq].irq_res);
10883c0086b8SZbigniew Bodek }
10893c0086b8SZbigniew Bodek }
10903c0086b8SZbigniew Bodek
10912306b72aSZbigniew Bodek static int
nic_register_interrupts(struct nicpf * nic)10922306b72aSZbigniew Bodek nic_register_interrupts(struct nicpf *nic)
10933c0086b8SZbigniew Bodek {
10942306b72aSZbigniew Bodek int irq, rid;
10953c0086b8SZbigniew Bodek int ret;
10963c0086b8SZbigniew Bodek
10973c0086b8SZbigniew Bodek /* Enable MSI-X */
10983c0086b8SZbigniew Bodek ret = nic_enable_msix(nic);
10992306b72aSZbigniew Bodek if (ret != 0)
11002306b72aSZbigniew Bodek return (ret);
11013c0086b8SZbigniew Bodek
11023c0086b8SZbigniew Bodek /* Register mailbox interrupt handlers */
11032306b72aSZbigniew Bodek irq = NIC_PF_INTR_ID_MBOX0;
11042306b72aSZbigniew Bodek rid = irq + 1;
11052306b72aSZbigniew Bodek nic->msix_entries[irq].irq_res = bus_alloc_resource_any(nic->dev,
11062306b72aSZbigniew Bodek SYS_RES_IRQ, &rid, (RF_SHAREABLE | RF_ACTIVE));
11072306b72aSZbigniew Bodek if (nic->msix_entries[irq].irq_res == NULL) {
11082306b72aSZbigniew Bodek ret = ENXIO;
11092306b72aSZbigniew Bodek goto fail;
11102306b72aSZbigniew Bodek }
11112306b72aSZbigniew Bodek ret = bus_setup_intr(nic->dev, nic->msix_entries[irq].irq_res,
11122306b72aSZbigniew Bodek (INTR_MPSAFE | INTR_TYPE_MISC), NULL, nic_mbx0_intr_handler, nic,
11132306b72aSZbigniew Bodek &nic->msix_entries[irq].handle);
11142306b72aSZbigniew Bodek if (ret != 0)
11153c0086b8SZbigniew Bodek goto fail;
11163c0086b8SZbigniew Bodek
11172306b72aSZbigniew Bodek irq = NIC_PF_INTR_ID_MBOX1;
11182306b72aSZbigniew Bodek rid = irq + 1;
11192306b72aSZbigniew Bodek nic->msix_entries[irq].irq_res = bus_alloc_resource_any(nic->dev,
11202306b72aSZbigniew Bodek SYS_RES_IRQ, &rid, (RF_SHAREABLE | RF_ACTIVE));
11212306b72aSZbigniew Bodek if (nic->msix_entries[irq].irq_res == NULL) {
11222306b72aSZbigniew Bodek ret = ENXIO;
11233c0086b8SZbigniew Bodek goto fail;
11242306b72aSZbigniew Bodek }
11252306b72aSZbigniew Bodek ret = bus_setup_intr(nic->dev, nic->msix_entries[irq].irq_res,
11262306b72aSZbigniew Bodek (INTR_MPSAFE | INTR_TYPE_MISC), NULL, nic_mbx1_intr_handler, nic,
11272306b72aSZbigniew Bodek &nic->msix_entries[irq].handle);
11282306b72aSZbigniew Bodek if (ret != 0)
11292306b72aSZbigniew Bodek goto fail;
11303c0086b8SZbigniew Bodek
11313c0086b8SZbigniew Bodek /* Enable mailbox interrupt */
11323c0086b8SZbigniew Bodek nic_enable_mbx_intr(nic);
11332306b72aSZbigniew Bodek return (0);
11343c0086b8SZbigniew Bodek
11353c0086b8SZbigniew Bodek fail:
11363c0086b8SZbigniew Bodek nic_free_all_interrupts(nic);
11372306b72aSZbigniew Bodek return (ret);
11383c0086b8SZbigniew Bodek }
11393c0086b8SZbigniew Bodek
11402306b72aSZbigniew Bodek static void
nic_unregister_interrupts(struct nicpf * nic)11412306b72aSZbigniew Bodek nic_unregister_interrupts(struct nicpf *nic)
11423c0086b8SZbigniew Bodek {
11432306b72aSZbigniew Bodek
11443c0086b8SZbigniew Bodek nic_free_all_interrupts(nic);
11453c0086b8SZbigniew Bodek nic_disable_msix(nic);
11463c0086b8SZbigniew Bodek }
11473c0086b8SZbigniew Bodek
nic_sriov_init(device_t dev,struct nicpf * nic)11482306b72aSZbigniew Bodek static int nic_sriov_init(device_t dev, struct nicpf *nic)
11493c0086b8SZbigniew Bodek {
11502306b72aSZbigniew Bodek #ifdef PCI_IOV
11512306b72aSZbigniew Bodek nvlist_t *pf_schema, *vf_schema;
11522306b72aSZbigniew Bodek int iov_pos;
11533c0086b8SZbigniew Bodek int err;
11542306b72aSZbigniew Bodek uint16_t total_vf_cnt;
11553c0086b8SZbigniew Bodek
11562306b72aSZbigniew Bodek err = pci_find_extcap(dev, PCIZ_SRIOV, &iov_pos);
11572306b72aSZbigniew Bodek if (err != 0) {
11582306b72aSZbigniew Bodek device_printf(dev,
11592306b72aSZbigniew Bodek "SR-IOV capability is not found in PCIe config space\n");
11602306b72aSZbigniew Bodek return (err);
11613c0086b8SZbigniew Bodek }
11622306b72aSZbigniew Bodek /* Fix-up the number of enabled VFs */
11632306b72aSZbigniew Bodek total_vf_cnt = pci_read_config(dev, iov_pos + PCIR_SRIOV_TOTAL_VFS, 2);
11642306b72aSZbigniew Bodek if (total_vf_cnt == 0)
116547646691SZbigniew Bodek return (ENXIO);
11663c0086b8SZbigniew Bodek
11672306b72aSZbigniew Bodek /* Attach SR-IOV */
11682306b72aSZbigniew Bodek pf_schema = pci_iov_schema_alloc_node();
11692306b72aSZbigniew Bodek vf_schema = pci_iov_schema_alloc_node();
11702306b72aSZbigniew Bodek pci_iov_schema_add_unicast_mac(vf_schema, "mac-addr", 0, NULL);
11712306b72aSZbigniew Bodek /*
11722306b72aSZbigniew Bodek * All VFs can change their MACs.
11732306b72aSZbigniew Bodek * This flag will be ignored but we set it just for the record.
11742306b72aSZbigniew Bodek */
11752306b72aSZbigniew Bodek pci_iov_schema_add_bool(vf_schema, "allow-set-mac",
11762306b72aSZbigniew Bodek IOV_SCHEMA_HASDEFAULT, TRUE);
11773c0086b8SZbigniew Bodek
11782306b72aSZbigniew Bodek err = pci_iov_attach(dev, pf_schema, vf_schema);
11792306b72aSZbigniew Bodek if (err != 0) {
11802306b72aSZbigniew Bodek device_printf(dev,
11812306b72aSZbigniew Bodek "Failed to initialize SR-IOV (error=%d)\n",
11822306b72aSZbigniew Bodek err);
11832306b72aSZbigniew Bodek return (err);
11842306b72aSZbigniew Bodek }
11852306b72aSZbigniew Bodek #endif
11862306b72aSZbigniew Bodek return (0);
11873c0086b8SZbigniew Bodek }
11883c0086b8SZbigniew Bodek
11892306b72aSZbigniew Bodek /*
11902306b72aSZbigniew Bodek * Poll for BGX LMAC link status and update corresponding VF
11913c0086b8SZbigniew Bodek * if there is a change, valid only if internal L2 switch
11923c0086b8SZbigniew Bodek * is not present otherwise VF link is always treated as up
11933c0086b8SZbigniew Bodek */
11942306b72aSZbigniew Bodek static void
nic_poll_for_link(void * arg)11952306b72aSZbigniew Bodek nic_poll_for_link(void *arg)
11963c0086b8SZbigniew Bodek {
11973c0086b8SZbigniew Bodek union nic_mbx mbx = {};
11983c0086b8SZbigniew Bodek struct nicpf *nic;
11993c0086b8SZbigniew Bodek struct bgx_link_status link;
12002306b72aSZbigniew Bodek uint8_t vf, bgx, lmac;
12013c0086b8SZbigniew Bodek
12022306b72aSZbigniew Bodek nic = (struct nicpf *)arg;
12033c0086b8SZbigniew Bodek
12043c0086b8SZbigniew Bodek mbx.link_status.msg = NIC_MBOX_MSG_BGX_LINK_CHANGE;
12053c0086b8SZbigniew Bodek
12063c0086b8SZbigniew Bodek for (vf = 0; vf < nic->num_vf_en; vf++) {
12073c0086b8SZbigniew Bodek /* Poll only if VF is UP */
12082306b72aSZbigniew Bodek if (!nic->vf_info[vf].vf_enabled)
12093c0086b8SZbigniew Bodek continue;
12103c0086b8SZbigniew Bodek
12113c0086b8SZbigniew Bodek /* Get BGX, LMAC indices for the VF */
12123c0086b8SZbigniew Bodek bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]);
12133c0086b8SZbigniew Bodek lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]);
12143c0086b8SZbigniew Bodek /* Get interface link status */
12153c0086b8SZbigniew Bodek bgx_get_lmac_link_state(nic->node, bgx, lmac, &link);
12163c0086b8SZbigniew Bodek
12173c0086b8SZbigniew Bodek /* Inform VF only if link status changed */
12183c0086b8SZbigniew Bodek if (nic->link[vf] == link.link_up)
12193c0086b8SZbigniew Bodek continue;
12203c0086b8SZbigniew Bodek
12213c0086b8SZbigniew Bodek if (!nic->mbx_lock[vf]) {
12223c0086b8SZbigniew Bodek nic->link[vf] = link.link_up;
12233c0086b8SZbigniew Bodek nic->duplex[vf] = link.duplex;
12243c0086b8SZbigniew Bodek nic->speed[vf] = link.speed;
12253c0086b8SZbigniew Bodek
12263c0086b8SZbigniew Bodek /* Send a mbox message to VF with current link status */
12273c0086b8SZbigniew Bodek mbx.link_status.link_up = link.link_up;
12283c0086b8SZbigniew Bodek mbx.link_status.duplex = link.duplex;
12293c0086b8SZbigniew Bodek mbx.link_status.speed = link.speed;
12303c0086b8SZbigniew Bodek nic_send_msg_to_vf(nic, vf, &mbx);
12313c0086b8SZbigniew Bodek }
12323c0086b8SZbigniew Bodek }
12332306b72aSZbigniew Bodek callout_reset(&nic->check_link, hz * 2, nic_poll_for_link, nic);
12343c0086b8SZbigniew Bodek }
1235