nic_main.c revision 289551
1230557Sjimharris/* 2230557Sjimharris * Copyright (C) 2015 Cavium Inc. 3230557Sjimharris * All rights reserved. 4230557Sjimharris * 5230557Sjimharris * Redistribution and use in source and binary forms, with or without 6230557Sjimharris * modification, are permitted provided that the following conditions 7230557Sjimharris * are met: 8230557Sjimharris * 1. Redistributions of source code must retain the above copyright 9230557Sjimharris * notice, this list of conditions and the following disclaimer. 10230557Sjimharris * 2. Redistributions in binary form must reproduce the above copyright 11230557Sjimharris * notice, this list of conditions and the following disclaimer in the 12230557Sjimharris * documentation and/or other materials provided with the distribution. 13230557Sjimharris * 14230557Sjimharris * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15230557Sjimharris * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16230557Sjimharris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17230557Sjimharris * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18230557Sjimharris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19230557Sjimharris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20230557Sjimharris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21230557Sjimharris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22230557Sjimharris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23230557Sjimharris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24230557Sjimharris * SUCH DAMAGE. 25230557Sjimharris * 26230557Sjimharris * $FreeBSD: head/sys/dev/vnic/nic_main.c 289551 2015-10-18 22:02:58Z zbb $ 27230557Sjimharris * 28230557Sjimharris */ 29230557Sjimharris 30230557Sjimharris#include <sys/cdefs.h> 31230557Sjimharris__FBSDID("$FreeBSD: head/sys/dev/vnic/nic_main.c 289551 2015-10-18 22:02:58Z zbb $"); 32230557Sjimharris 33230557Sjimharris#include <sys/param.h> 34230557Sjimharris#include <sys/systm.h> 35230557Sjimharris#include <sys/bitset.h> 36230557Sjimharris#include <sys/bitstring.h> 37230557Sjimharris#include <sys/bus.h> 38230557Sjimharris#include <sys/endian.h> 39230557Sjimharris#include <sys/kernel.h> 40230557Sjimharris#include <sys/malloc.h> 41230557Sjimharris#include <sys/module.h> 42230557Sjimharris#include <sys/rman.h> 43230557Sjimharris#include <sys/pciio.h> 44230557Sjimharris#include <sys/pcpu.h> 45230557Sjimharris#include <sys/proc.h> 46230557Sjimharris#include <sys/socket.h> 47230557Sjimharris#include <sys/sockio.h> 48230557Sjimharris#include <sys/cpuset.h> 49230557Sjimharris#include <sys/lock.h> 50230557Sjimharris#include <sys/mutex.h> 51230557Sjimharris 52230557Sjimharris#include <net/ethernet.h> 53230557Sjimharris#include <net/if.h> 54230557Sjimharris#include <net/if_media.h> 55230557Sjimharris 56230557Sjimharris#include <machine/bus.h> 57230557Sjimharris#include <machine/_inttypes.h> 58230557Sjimharris 59230557Sjimharris#include <dev/pci/pcireg.h> 60230557Sjimharris#include <dev/pci/pcivar.h> 61230557Sjimharris 62230557Sjimharris#include <sys/dnv.h> 63230557Sjimharris#include <sys/nv.h> 64230557Sjimharris#ifdef PCI_IOV 65230557Sjimharris#include <sys/iov_schema.h> 66230557Sjimharris#include <dev/pci/pci_iov.h> 67230557Sjimharris#endif 68230557Sjimharris 69230557Sjimharris#include "thunder_bgx.h" 70230557Sjimharris#include "nic_reg.h" 71230557Sjimharris#include "nic.h" 72230557Sjimharris#include "q_struct.h" 73230557Sjimharris 74230557Sjimharris#define VNIC_PF_DEVSTR "Cavium Thunder NIC Physical Function Driver" 75230557Sjimharris 76230557Sjimharris#define VNIC_PF_REG_RID PCIR_BAR(PCI_CFG_REG_BAR_NUM) 77230557Sjimharris 78230557Sjimharris#define NIC_SET_VF_LMAC_MAP(bgx, lmac) ((((bgx) & 0xF) << 4) | ((lmac) & 0xF)) 79230557Sjimharris#define NIC_GET_BGX_FROM_VF_LMAC_MAP(map) (((map) >> 4) & 0xF) 80230557Sjimharris#define NIC_GET_LMAC_FROM_VF_LMAC_MAP(map) ((map) & 0xF) 81230557Sjimharris 82230557Sjimharris/* Structure to be used by the SR-IOV for VF configuration schemas */ 83230557Sjimharrisstruct nicvf_info { 84230557Sjimharris boolean_t vf_enabled; 85230557Sjimharris int vf_flags; 86230557Sjimharris}; 87230557Sjimharris 88230557Sjimharrisstruct nicpf { 89230557Sjimharris device_t dev; 90230557Sjimharris uint8_t rev_id; 91230557Sjimharris uint8_t node; 92230557Sjimharris u_int flags; 93230557Sjimharris uint8_t num_vf_en; /* No of VF enabled */ 94230557Sjimharris struct nicvf_info vf_info[MAX_NUM_VFS_SUPPORTED]; 95230557Sjimharris struct resource * reg_base; /* Register start address */ 96230557Sjimharris struct pkind_cfg pkind; 97230557Sjimharris uint8_t vf_lmac_map[MAX_LMAC]; 98230557Sjimharris boolean_t mbx_lock[MAX_NUM_VFS_SUPPORTED]; 99230557Sjimharris 100230557Sjimharris struct callout check_link; 101230557Sjimharris struct mtx check_link_mtx; 102230557Sjimharris 103230557Sjimharris uint8_t link[MAX_LMAC]; 104230557Sjimharris uint8_t duplex[MAX_LMAC]; 105230557Sjimharris uint32_t speed[MAX_LMAC]; 106230557Sjimharris uint16_t cpi_base[MAX_NUM_VFS_SUPPORTED]; 107230557Sjimharris uint16_t rss_ind_tbl_size; 108230557Sjimharris 109230557Sjimharris /* MSI-X */ 110230557Sjimharris boolean_t msix_enabled; 111230557Sjimharris uint8_t num_vec; 112230557Sjimharris struct msix_entry msix_entries[NIC_PF_MSIX_VECTORS]; 113230557Sjimharris struct resource * msix_table_res; 114230557Sjimharris}; 115230557Sjimharris 116230557Sjimharrisstatic int nicpf_probe(device_t); 117230557Sjimharrisstatic int nicpf_attach(device_t); 118230557Sjimharrisstatic int nicpf_detach(device_t); 119230557Sjimharris 120230557Sjimharris#ifdef PCI_IOV 121230557Sjimharrisstatic int nicpf_iov_init(device_t, uint16_t, const nvlist_t *); 122230557Sjimharrisstatic void nicpf_iov_uninit(device_t); 123230557Sjimharrisstatic int nicpf_iov_addr_vf(device_t, uint16_t, const nvlist_t *); 124230557Sjimharris#endif 125230557Sjimharris 126230557Sjimharrisstatic device_method_t nicpf_methods[] = { 127230557Sjimharris /* Device interface */ 128230557Sjimharris DEVMETHOD(device_probe, nicpf_probe), 129230557Sjimharris DEVMETHOD(device_attach, nicpf_attach), 130230557Sjimharris DEVMETHOD(device_detach, nicpf_detach), 131230557Sjimharris /* PCI SR-IOV interface */ 132230557Sjimharris#ifdef PCI_IOV 133230557Sjimharris DEVMETHOD(pci_iov_init, nicpf_iov_init), 134230557Sjimharris DEVMETHOD(pci_iov_uninit, nicpf_iov_uninit), 135230557Sjimharris DEVMETHOD(pci_iov_add_vf, nicpf_iov_addr_vf), 136230557Sjimharris#endif 137230557Sjimharris DEVMETHOD_END, 138230557Sjimharris}; 139230557Sjimharris 140230557Sjimharrisstatic driver_t nicpf_driver = { 141230557Sjimharris "vnicpf", 142230557Sjimharris nicpf_methods, 143230557Sjimharris sizeof(struct nicpf), 144230557Sjimharris}; 145230557Sjimharris 146230557Sjimharrisstatic devclass_t nicpf_devclass; 147230557Sjimharris 148230557SjimharrisDRIVER_MODULE(nicpf, pci, nicpf_driver, nicpf_devclass, 0, 0); 149230557SjimharrisMODULE_DEPEND(nicpf, pci, 1, 1, 1); 150230557SjimharrisMODULE_DEPEND(nicpf, ether, 1, 1, 1); 151230557SjimharrisMODULE_DEPEND(nicpf, thunder_bgx, 1, 1, 1); 152230557Sjimharris 153230557Sjimharrisstatic int nicpf_alloc_res(struct nicpf *); 154230557Sjimharrisstatic void nicpf_free_res(struct nicpf *); 155230557Sjimharrisstatic void nic_set_lmac_vf_mapping(struct nicpf *); 156230557Sjimharrisstatic void nic_init_hw(struct nicpf *); 157230557Sjimharrisstatic int nic_sriov_init(device_t, struct nicpf *); 158230557Sjimharrisstatic void nic_poll_for_link(void *); 159230557Sjimharrisstatic int nic_register_interrupts(struct nicpf *); 160230557Sjimharrisstatic void nic_unregister_interrupts(struct nicpf *); 161230557Sjimharris 162230557Sjimharris/* 163230557Sjimharris * Device interface 164230557Sjimharris */ 165230557Sjimharrisstatic int 166230557Sjimharrisnicpf_probe(device_t dev) 167230557Sjimharris{ 168230557Sjimharris uint16_t vendor_id; 169230557Sjimharris uint16_t device_id; 170230557Sjimharris 171230557Sjimharris vendor_id = pci_get_vendor(dev); 172230557Sjimharris device_id = pci_get_device(dev); 173230557Sjimharris 174230557Sjimharris if (vendor_id == PCI_VENDOR_ID_CAVIUM && 175230557Sjimharris device_id == PCI_DEVICE_ID_THUNDER_NIC_PF) { 176230557Sjimharris device_set_desc(dev, VNIC_PF_DEVSTR); 177230557Sjimharris return (BUS_PROBE_DEFAULT); 178230557Sjimharris } 179230557Sjimharris 180230557Sjimharris return (ENXIO); 181230557Sjimharris} 182230557Sjimharris 183230557Sjimharrisstatic int 184230557Sjimharrisnicpf_attach(device_t dev) 185230557Sjimharris{ 186230557Sjimharris struct nicpf *nic; 187230557Sjimharris int err; 188230557Sjimharris 189230557Sjimharris nic = device_get_softc(dev); 190230557Sjimharris nic->dev = dev; 191230557Sjimharris 192230557Sjimharris /* Enable bus mastering */ 193230557Sjimharris pci_enable_busmaster(dev); 194230557Sjimharris 195230557Sjimharris /* Allocate PCI resources */ 196230557Sjimharris err = nicpf_alloc_res(nic); 197230557Sjimharris if (err != 0) { 198230557Sjimharris device_printf(dev, "Could not allocate PCI resources\n"); 199230557Sjimharris return (err); 200230557Sjimharris } 201230557Sjimharris 202230557Sjimharris nic->node = nic_get_node_id(nic->reg_base); 203230557Sjimharris nic->rev_id = pci_read_config(dev, PCIR_REVID, 1); 204230557Sjimharris 205230557Sjimharris /* Enable Traffic Network Switch (TNS) bypass mode by default */ 206230557Sjimharris nic->flags &= ~NIC_TNS_ENABLED; 207230557Sjimharris nic_set_lmac_vf_mapping(nic); 208230557Sjimharris 209230557Sjimharris /* Initialize hardware */ 210230557Sjimharris nic_init_hw(nic); 211230557Sjimharris 212230557Sjimharris /* Set RSS TBL size for each VF */ 213230557Sjimharris nic->rss_ind_tbl_size = NIC_MAX_RSS_IDR_TBL_SIZE; 214230557Sjimharris 215230557Sjimharris /* Setup interrupts */ 216230557Sjimharris err = nic_register_interrupts(nic); 217230557Sjimharris if (err != 0) 218230557Sjimharris goto err_free_res; 219230557Sjimharris 220230557Sjimharris /* Configure SRIOV */ 221230557Sjimharris err = nic_sriov_init(dev, nic); 222230557Sjimharris if (err != 0) 223230557Sjimharris goto err_free_intr; 224230557Sjimharris 225230557Sjimharris if (nic->flags & NIC_TNS_ENABLED) 226230557Sjimharris return (0); 227230557Sjimharris 228230557Sjimharris mtx_init(&nic->check_link_mtx, "VNIC PF link poll", NULL, MTX_DEF); 229230557Sjimharris /* Register physical link status poll callout */ 230230557Sjimharris callout_init_mtx(&nic->check_link, &nic->check_link_mtx, 0); 231230557Sjimharris mtx_lock(&nic->check_link_mtx); 232230557Sjimharris nic_poll_for_link(nic); 233230557Sjimharris mtx_unlock(&nic->check_link_mtx); 234230557Sjimharris 235230557Sjimharris return (0); 236230557Sjimharris 237230557Sjimharriserr_free_intr: 238230557Sjimharris nic_unregister_interrupts(nic); 239230557Sjimharriserr_free_res: 240230557Sjimharris nicpf_free_res(nic); 241230557Sjimharris pci_disable_busmaster(dev); 242230557Sjimharris 243230557Sjimharris return (err); 244230557Sjimharris} 245230557Sjimharris 246230557Sjimharrisstatic int 247230557Sjimharrisnicpf_detach(device_t dev) 248230557Sjimharris{ 249230557Sjimharris struct nicpf *nic; 250230557Sjimharris 251230557Sjimharris nic = device_get_softc(dev); 252230557Sjimharris 253230557Sjimharris callout_drain(&nic->check_link); 254230557Sjimharris mtx_destroy(&nic->check_link_mtx); 255230557Sjimharris 256230557Sjimharris nic_unregister_interrupts(nic); 257230557Sjimharris nicpf_free_res(nic); 258230557Sjimharris pci_disable_busmaster(dev); 259230557Sjimharris 260230557Sjimharris return (0); 261230557Sjimharris} 262230557Sjimharris 263230557Sjimharris/* 264230557Sjimharris * SR-IOV interface 265230557Sjimharris */ 266230557Sjimharris#ifdef PCI_IOV 267230557Sjimharrisstatic int 268230557Sjimharrisnicpf_iov_init(device_t dev, uint16_t num_vfs, const nvlist_t *params) 269230557Sjimharris{ 270230557Sjimharris struct nicpf *nic; 271230557Sjimharris 272230557Sjimharris nic = device_get_softc(dev); 273230557Sjimharris 274230557Sjimharris nic->num_vf_en = 0; 275230557Sjimharris if (num_vfs == 0) 276230557Sjimharris return (ENXIO); 277230557Sjimharris if (num_vfs > MAX_NUM_VFS_SUPPORTED) 278230557Sjimharris return (EINVAL); 279230557Sjimharris 280230557Sjimharris /* 281230557Sjimharris * Just set variables here. 282230557Sjimharris * The number of VFs will be written to configuration 283230557Sjimharris * space later in PCI_ADD_VF(). 284230557Sjimharris */ 285230557Sjimharris nic->num_vf_en = num_vfs; 286230557Sjimharris nic->flags |= NIC_SRIOV_ENABLED; 287230557Sjimharris 288230557Sjimharris return (0); 289230557Sjimharris} 290230557Sjimharris 291230557Sjimharrisstatic void 292230557Sjimharrisnicpf_iov_uninit(device_t dev) 293230557Sjimharris{ 294230557Sjimharris 295230557Sjimharris /* ARM64TODO: Implement this function */ 296230557Sjimharris} 297230557Sjimharris 298230557Sjimharrisstatic int 299230557Sjimharrisnicpf_iov_addr_vf(device_t dev, uint16_t vfnum, const nvlist_t *params) 300230557Sjimharris{ 301230557Sjimharris const void *mac; 302230557Sjimharris struct nicpf *nic; 303230557Sjimharris size_t size; 304230557Sjimharris int bgx, lmac; 305230557Sjimharris 306230557Sjimharris nic = device_get_softc(dev); 307230557Sjimharris 308230557Sjimharris if ((nic->flags & NIC_SRIOV_ENABLED) == 0) 309230557Sjimharris return (ENXIO); 310230557Sjimharris 311230557Sjimharris if (nvlist_exists_binary(params, "mac-addr") != 0) { 312230557Sjimharris mac = nvlist_get_binary(params, "mac-addr", &size); 313230557Sjimharris bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vfnum]); 314230557Sjimharris lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vfnum]); 315230557Sjimharris bgx_set_lmac_mac(nic->node, bgx, lmac, mac); 316230557Sjimharris } 317230557Sjimharris 318230557Sjimharris return (0); 319230557Sjimharris} 320230557Sjimharris#endif 321230557Sjimharris 322230557Sjimharris/* 323230557Sjimharris * Helper routines 324230557Sjimharris */ 325230557Sjimharrisstatic int 326230557Sjimharrisnicpf_alloc_res(struct nicpf *nic) 327230557Sjimharris{ 328230557Sjimharris device_t dev; 329230557Sjimharris int rid; 330230557Sjimharris 331230557Sjimharris dev = nic->dev; 332230557Sjimharris 333230557Sjimharris rid = VNIC_PF_REG_RID; 334230557Sjimharris nic->reg_base = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 335230557Sjimharris RF_ACTIVE); 336230557Sjimharris if (nic->reg_base == NULL) { 337230557Sjimharris /* For verbose output print some more details */ 338230557Sjimharris if (bootverbose) { 339230557Sjimharris device_printf(dev, 340230557Sjimharris "Could not allocate registers memory\n"); 341230557Sjimharris } 342230557Sjimharris return (ENXIO); 343230557Sjimharris } 344230557Sjimharris 345230557Sjimharris return (0); 346230557Sjimharris} 347230557Sjimharris 348230557Sjimharrisstatic void 349230557Sjimharrisnicpf_free_res(struct nicpf *nic) 350230557Sjimharris{ 351230557Sjimharris device_t dev; 352230557Sjimharris 353230557Sjimharris dev = nic->dev; 354230557Sjimharris 355230557Sjimharris if (nic->reg_base != NULL) { 356230557Sjimharris bus_release_resource(dev, SYS_RES_MEMORY, 357230557Sjimharris rman_get_rid(nic->reg_base), nic->reg_base); 358230557Sjimharris } 359230557Sjimharris} 360230557Sjimharris 361230557Sjimharris/* Register read/write APIs */ 362235043Sjimharrisstatic __inline void 363230557Sjimharrisnic_reg_write(struct nicpf *nic, bus_space_handle_t offset, 364230557Sjimharris uint64_t val) 365230557Sjimharris{ 366230557Sjimharris 367230557Sjimharris bus_write_8(nic->reg_base, offset, val); 368230557Sjimharris} 369230557Sjimharris 370230557Sjimharrisstatic __inline uint64_t 371230557Sjimharrisnic_reg_read(struct nicpf *nic, uint64_t offset) 372230557Sjimharris{ 373230557Sjimharris uint64_t val; 374230557Sjimharris 375230557Sjimharris val = bus_read_8(nic->reg_base, offset); 376230557Sjimharris return (val); 377230557Sjimharris} 378230557Sjimharris 379230557Sjimharris/* PF -> VF mailbox communication APIs */ 380230557Sjimharrisstatic void 381230557Sjimharrisnic_enable_mbx_intr(struct nicpf *nic) 382230557Sjimharris{ 383230557Sjimharris 384230557Sjimharris /* Enable mailbox interrupt for all 128 VFs */ 385230557Sjimharris nic_reg_write(nic, NIC_PF_MAILBOX_ENA_W1S, ~0UL); 386230557Sjimharris nic_reg_write(nic, NIC_PF_MAILBOX_ENA_W1S + sizeof(uint64_t), ~0UL); 387230557Sjimharris} 388230557Sjimharris 389230557Sjimharrisstatic void 390230557Sjimharrisnic_clear_mbx_intr(struct nicpf *nic, int vf, int mbx_reg) 391230557Sjimharris{ 392230557Sjimharris 393230557Sjimharris nic_reg_write(nic, NIC_PF_MAILBOX_INT + (mbx_reg << 3), (1UL << vf)); 394230557Sjimharris} 395230557Sjimharris 396230557Sjimharrisstatic uint64_t 397230557Sjimharrisnic_get_mbx_addr(int vf) 398230557Sjimharris{ 399230557Sjimharris 400230557Sjimharris return (NIC_PF_VF_0_127_MAILBOX_0_1 + (vf << NIC_VF_NUM_SHIFT)); 401230557Sjimharris} 402230557Sjimharris 403230557Sjimharris/* 404230557Sjimharris * Send a mailbox message to VF 405230557Sjimharris * @vf: vf to which this message to be sent 406230557Sjimharris * @mbx: Message to be sent 407230557Sjimharris */ 408230557Sjimharrisstatic void 409230557Sjimharrisnic_send_msg_to_vf(struct nicpf *nic, int vf, union nic_mbx *mbx) 410230557Sjimharris{ 411230557Sjimharris bus_space_handle_t mbx_addr = nic_get_mbx_addr(vf); 412230557Sjimharris uint64_t *msg = (uint64_t *)mbx; 413230557Sjimharris 414230557Sjimharris /* 415230557Sjimharris * In first revision HW, mbox interrupt is triggerred 416230557Sjimharris * when PF writes to MBOX(1), in next revisions when 417230557Sjimharris * PF writes to MBOX(0) 418230557Sjimharris */ 419230557Sjimharris if (nic->rev_id == 0) { 420230557Sjimharris nic_reg_write(nic, mbx_addr + 0, msg[0]); 421230557Sjimharris nic_reg_write(nic, mbx_addr + 8, msg[1]); 422230557Sjimharris } else { 423230557Sjimharris nic_reg_write(nic, mbx_addr + 8, msg[1]); 424230557Sjimharris nic_reg_write(nic, mbx_addr + 0, msg[0]); 425230557Sjimharris } 426230557Sjimharris} 427230557Sjimharris 428230557Sjimharris/* 429230557Sjimharris * Responds to VF's READY message with VF's 430230557Sjimharris * ID, node, MAC address e.t.c 431230557Sjimharris * @vf: VF which sent READY message 432230557Sjimharris */ 433230557Sjimharrisstatic void 434230557Sjimharrisnic_mbx_send_ready(struct nicpf *nic, int vf) 435230557Sjimharris{ 436230557Sjimharris union nic_mbx mbx = {}; 437230557Sjimharris int bgx_idx, lmac; 438230557Sjimharris const char *mac; 439230557Sjimharris 440230557Sjimharris mbx.nic_cfg.msg = NIC_MBOX_MSG_READY; 441230557Sjimharris mbx.nic_cfg.vf_id = vf; 442230557Sjimharris 443230557Sjimharris if (nic->flags & NIC_TNS_ENABLED) 444230557Sjimharris mbx.nic_cfg.tns_mode = NIC_TNS_MODE; 445230557Sjimharris else 446230557Sjimharris mbx.nic_cfg.tns_mode = NIC_TNS_BYPASS_MODE; 447230557Sjimharris 448230557Sjimharris if (vf < MAX_LMAC) { 449230557Sjimharris bgx_idx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); 450230557Sjimharris lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); 451230557Sjimharris 452230557Sjimharris mac = bgx_get_lmac_mac(nic->node, bgx_idx, lmac); 453230557Sjimharris if (mac) { 454230557Sjimharris memcpy((uint8_t *)&mbx.nic_cfg.mac_addr, mac, 455230557Sjimharris ETHER_ADDR_LEN); 456230557Sjimharris } 457230557Sjimharris } 458230557Sjimharris mbx.nic_cfg.node_id = nic->node; 459230557Sjimharris 460230557Sjimharris mbx.nic_cfg.loopback_supported = vf < MAX_LMAC; 461230557Sjimharris 462230557Sjimharris nic_send_msg_to_vf(nic, vf, &mbx); 463230557Sjimharris} 464230557Sjimharris 465230557Sjimharris/* 466230557Sjimharris * ACKs VF's mailbox message 467230557Sjimharris * @vf: VF to which ACK to be sent 468230557Sjimharris */ 469230557Sjimharrisstatic void 470230557Sjimharrisnic_mbx_send_ack(struct nicpf *nic, int vf) 471230557Sjimharris{ 472230557Sjimharris union nic_mbx mbx = {}; 473230557Sjimharris 474230557Sjimharris mbx.msg.msg = NIC_MBOX_MSG_ACK; 475230557Sjimharris nic_send_msg_to_vf(nic, vf, &mbx); 476230557Sjimharris} 477230557Sjimharris 478230557Sjimharris/* 479230557Sjimharris * NACKs VF's mailbox message that PF is not able to 480230557Sjimharris * complete the action 481230557Sjimharris * @vf: VF to which ACK to be sent 482230557Sjimharris */ 483230557Sjimharrisstatic void 484230557Sjimharrisnic_mbx_send_nack(struct nicpf *nic, int vf) 485230557Sjimharris{ 486230557Sjimharris union nic_mbx mbx = {}; 487230557Sjimharris 488230557Sjimharris mbx.msg.msg = NIC_MBOX_MSG_NACK; 489230557Sjimharris nic_send_msg_to_vf(nic, vf, &mbx); 490230557Sjimharris} 491230557Sjimharris 492230557Sjimharris/* 493230557Sjimharris * Flush all in flight receive packets to memory and 494230557Sjimharris * bring down an active RQ 495230557Sjimharris */ 496230557Sjimharrisstatic int 497230557Sjimharrisnic_rcv_queue_sw_sync(struct nicpf *nic) 498230557Sjimharris{ 499230557Sjimharris uint16_t timeout = ~0x00; 500230557Sjimharris 501230557Sjimharris nic_reg_write(nic, NIC_PF_SW_SYNC_RX, 0x01); 502230557Sjimharris /* Wait till sync cycle is finished */ 503230557Sjimharris while (timeout) { 504230557Sjimharris if (nic_reg_read(nic, NIC_PF_SW_SYNC_RX_DONE) & 0x1) 505230557Sjimharris break; 506230557Sjimharris timeout--; 507230557Sjimharris } 508230557Sjimharris nic_reg_write(nic, NIC_PF_SW_SYNC_RX, 0x00); 509230557Sjimharris if (!timeout) { 510230557Sjimharris device_printf(nic->dev, "Receive queue software sync failed\n"); 511230557Sjimharris return (ETIMEDOUT); 512230557Sjimharris } 513230557Sjimharris return (0); 514230557Sjimharris} 515230557Sjimharris 516230557Sjimharris/* Get BGX Rx/Tx stats and respond to VF's request */ 517230557Sjimharrisstatic void 518230557Sjimharrisnic_get_bgx_stats(struct nicpf *nic, struct bgx_stats_msg *bgx) 519230557Sjimharris{ 520230557Sjimharris int bgx_idx, lmac; 521230557Sjimharris union nic_mbx mbx = {}; 522230557Sjimharris 523230557Sjimharris bgx_idx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[bgx->vf_id]); 524230557Sjimharris lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[bgx->vf_id]); 525230557Sjimharris 526230557Sjimharris mbx.bgx_stats.msg = NIC_MBOX_MSG_BGX_STATS; 527230557Sjimharris mbx.bgx_stats.vf_id = bgx->vf_id; 528230557Sjimharris mbx.bgx_stats.rx = bgx->rx; 529230557Sjimharris mbx.bgx_stats.idx = bgx->idx; 530230557Sjimharris if (bgx->rx != 0) { 531230557Sjimharris mbx.bgx_stats.stats = 532230557Sjimharris bgx_get_rx_stats(nic->node, bgx_idx, lmac, bgx->idx); 533230557Sjimharris } else { 534230557Sjimharris mbx.bgx_stats.stats = 535230557Sjimharris bgx_get_tx_stats(nic->node, bgx_idx, lmac, bgx->idx); 536230557Sjimharris } 537230557Sjimharris nic_send_msg_to_vf(nic, bgx->vf_id, &mbx); 538230557Sjimharris} 539230557Sjimharris 540230557Sjimharris/* Update hardware min/max frame size */ 541230557Sjimharrisstatic int 542230557Sjimharrisnic_update_hw_frs(struct nicpf *nic, int new_frs, int vf) 543230557Sjimharris{ 544230557Sjimharris 545230557Sjimharris if ((new_frs > NIC_HW_MAX_FRS) || (new_frs < NIC_HW_MIN_FRS)) { 546230557Sjimharris device_printf(nic->dev, 547230557Sjimharris "Invalid MTU setting from VF%d rejected, " 548230557Sjimharris "should be between %d and %d\n", 549230557Sjimharris vf, NIC_HW_MIN_FRS, NIC_HW_MAX_FRS); 550230557Sjimharris return (EINVAL); 551230557Sjimharris } 552230557Sjimharris new_frs += ETHER_HDR_LEN; 553230557Sjimharris if (new_frs <= nic->pkind.maxlen) 554230557Sjimharris return (0); 555230557Sjimharris 556230557Sjimharris nic->pkind.maxlen = new_frs; 557230557Sjimharris nic_reg_write(nic, NIC_PF_PKIND_0_15_CFG, *(uint64_t *)&nic->pkind); 558230557Sjimharris return (0); 559230557Sjimharris} 560230557Sjimharris 561230557Sjimharris/* Set minimum transmit packet size */ 562230557Sjimharrisstatic void 563230557Sjimharrisnic_set_tx_pkt_pad(struct nicpf *nic, int size) 564230557Sjimharris{ 565230557Sjimharris int lmac; 566230557Sjimharris uint64_t lmac_cfg; 567230557Sjimharris 568230557Sjimharris /* Max value that can be set is 60 */ 569230557Sjimharris if (size > 60) 570230557Sjimharris size = 60; 571230557Sjimharris 572230557Sjimharris for (lmac = 0; lmac < (MAX_BGX_PER_CN88XX * MAX_LMAC_PER_BGX); lmac++) { 573230557Sjimharris lmac_cfg = nic_reg_read(nic, NIC_PF_LMAC_0_7_CFG | (lmac << 3)); 574230557Sjimharris lmac_cfg &= ~(0xF << 2); 575230557Sjimharris lmac_cfg |= ((size / 4) << 2); 576230557Sjimharris nic_reg_write(nic, NIC_PF_LMAC_0_7_CFG | (lmac << 3), lmac_cfg); 577230557Sjimharris } 578230557Sjimharris} 579230557Sjimharris 580230557Sjimharris/* 581230557Sjimharris * Function to check number of LMACs present and set VF::LMAC mapping. 582230557Sjimharris * Mapping will be used while initializing channels. 583230557Sjimharris */ 584230557Sjimharrisstatic void 585230557Sjimharrisnic_set_lmac_vf_mapping(struct nicpf *nic) 586230557Sjimharris{ 587230557Sjimharris unsigned bgx_map = bgx_get_map(nic->node); 588230557Sjimharris int bgx, next_bgx_lmac = 0; 589230557Sjimharris int lmac, lmac_cnt = 0; 590230557Sjimharris uint64_t lmac_credit; 591230557Sjimharris 592230557Sjimharris nic->num_vf_en = 0; 593230557Sjimharris if (nic->flags & NIC_TNS_ENABLED) { 594230557Sjimharris nic->num_vf_en = DEFAULT_NUM_VF_ENABLED; 595230557Sjimharris return; 596230557Sjimharris } 597230557Sjimharris 598230557Sjimharris for (bgx = 0; bgx < NIC_MAX_BGX; bgx++) { 599230557Sjimharris if ((bgx_map & (1 << bgx)) == 0) 600230557Sjimharris continue; 601230557Sjimharris lmac_cnt = bgx_get_lmac_count(nic->node, bgx); 602230557Sjimharris for (lmac = 0; lmac < lmac_cnt; lmac++) 603230557Sjimharris nic->vf_lmac_map[next_bgx_lmac++] = 604230557Sjimharris NIC_SET_VF_LMAC_MAP(bgx, lmac); 605230557Sjimharris nic->num_vf_en += lmac_cnt; 606230557Sjimharris 607230557Sjimharris /* Program LMAC credits */ 608230557Sjimharris lmac_credit = (1UL << 1); /* channel credit enable */ 609230557Sjimharris lmac_credit |= (0x1ff << 2); /* Max outstanding pkt count */ 610230557Sjimharris /* 48KB BGX Tx buffer size, each unit is of size 16bytes */ 611230557Sjimharris lmac_credit |= (((((48 * 1024) / lmac_cnt) - 612230557Sjimharris NIC_HW_MAX_FRS) / 16) << 12); 613230557Sjimharris lmac = bgx * MAX_LMAC_PER_BGX; 614230557Sjimharris for (; lmac < lmac_cnt + (bgx * MAX_LMAC_PER_BGX); lmac++) { 615230557Sjimharris nic_reg_write(nic, NIC_PF_LMAC_0_7_CREDIT + (lmac * 8), 616230557Sjimharris lmac_credit); 617230557Sjimharris } 618230557Sjimharris } 619230557Sjimharris} 620230557Sjimharris 621230557Sjimharris#define TNS_PORT0_BLOCK 6 622230557Sjimharris#define TNS_PORT1_BLOCK 7 623230557Sjimharris#define BGX0_BLOCK 8 624230557Sjimharris#define BGX1_BLOCK 9 625230557Sjimharris 626230557Sjimharrisstatic void 627230557Sjimharrisnic_init_hw(struct nicpf *nic) 628230557Sjimharris{ 629230557Sjimharris int i; 630230557Sjimharris 631230557Sjimharris /* Reset NIC, in case the driver is repeatedly inserted and removed */ 632230557Sjimharris nic_reg_write(nic, NIC_PF_SOFT_RESET, 1); 633230557Sjimharris 634230557Sjimharris /* Enable NIC HW block */ 635230557Sjimharris nic_reg_write(nic, NIC_PF_CFG, 0x3); 636230557Sjimharris 637230557Sjimharris /* Enable backpressure */ 638230557Sjimharris nic_reg_write(nic, NIC_PF_BP_CFG, (1UL << 6) | 0x03); 639230557Sjimharris 640230557Sjimharris if (nic->flags & NIC_TNS_ENABLED) { 641230557Sjimharris nic_reg_write(nic, NIC_PF_INTF_0_1_SEND_CFG, 642230557Sjimharris (NIC_TNS_MODE << 7) | TNS_PORT0_BLOCK); 643230557Sjimharris nic_reg_write(nic, NIC_PF_INTF_0_1_SEND_CFG | (1 << 8), 644230557Sjimharris (NIC_TNS_MODE << 7) | TNS_PORT1_BLOCK); 645230557Sjimharris nic_reg_write(nic, NIC_PF_INTF_0_1_BP_CFG, 646230557Sjimharris (1UL << 63) | TNS_PORT0_BLOCK); 647230557Sjimharris nic_reg_write(nic, NIC_PF_INTF_0_1_BP_CFG + (1 << 8), 648230557Sjimharris (1UL << 63) | TNS_PORT1_BLOCK); 649230557Sjimharris 650230557Sjimharris } else { 651230557Sjimharris /* Disable TNS mode on both interfaces */ 652230557Sjimharris nic_reg_write(nic, NIC_PF_INTF_0_1_SEND_CFG, 653230557Sjimharris (NIC_TNS_BYPASS_MODE << 7) | BGX0_BLOCK); 654230557Sjimharris nic_reg_write(nic, NIC_PF_INTF_0_1_SEND_CFG | (1 << 8), 655230557Sjimharris (NIC_TNS_BYPASS_MODE << 7) | BGX1_BLOCK); 656230557Sjimharris nic_reg_write(nic, NIC_PF_INTF_0_1_BP_CFG, 657230557Sjimharris (1UL << 63) | BGX0_BLOCK); 658230557Sjimharris nic_reg_write(nic, NIC_PF_INTF_0_1_BP_CFG + (1 << 8), 659230557Sjimharris (1UL << 63) | BGX1_BLOCK); 660230557Sjimharris } 661230557Sjimharris 662230557Sjimharris /* PKIND configuration */ 663230557Sjimharris nic->pkind.minlen = 0; 664230557Sjimharris nic->pkind.maxlen = NIC_HW_MAX_FRS + ETHER_HDR_LEN; 665230557Sjimharris nic->pkind.lenerr_en = 1; 666230557Sjimharris nic->pkind.rx_hdr = 0; 667230557Sjimharris nic->pkind.hdr_sl = 0; 668230557Sjimharris 669230557Sjimharris for (i = 0; i < NIC_MAX_PKIND; i++) { 670230557Sjimharris nic_reg_write(nic, NIC_PF_PKIND_0_15_CFG | (i << 3), 671230557Sjimharris *(uint64_t *)&nic->pkind); 672230557Sjimharris } 673230557Sjimharris 674230557Sjimharris nic_set_tx_pkt_pad(nic, NIC_HW_MIN_FRS); 675230557Sjimharris 676230557Sjimharris /* Timer config */ 677230557Sjimharris nic_reg_write(nic, NIC_PF_INTR_TIMER_CFG, NICPF_CLK_PER_INT_TICK); 678230557Sjimharris 679230557Sjimharris /* Enable VLAN ethertype matching and stripping */ 680230557Sjimharris nic_reg_write(nic, NIC_PF_RX_ETYPE_0_7, 681230557Sjimharris (2 << 19) | (ETYPE_ALG_VLAN_STRIP << 16) | ETHERTYPE_VLAN); 682230557Sjimharris} 683230557Sjimharris 684230557Sjimharris/* Channel parse index configuration */ 685230557Sjimharrisstatic void 686230557Sjimharrisnic_config_cpi(struct nicpf *nic, struct cpi_cfg_msg *cfg) 687230557Sjimharris{ 688230557Sjimharris uint32_t vnic, bgx, lmac, chan; 689230557Sjimharris uint32_t padd, cpi_count = 0; 690230557Sjimharris uint64_t cpi_base, cpi, rssi_base, rssi; 691230557Sjimharris uint8_t qset, rq_idx = 0; 692230557Sjimharris 693230557Sjimharris vnic = cfg->vf_id; 694230557Sjimharris bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vnic]); 695230557Sjimharris lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vnic]); 696230557Sjimharris 697230557Sjimharris chan = (lmac * MAX_BGX_CHANS_PER_LMAC) + (bgx * NIC_CHANS_PER_INF); 698230557Sjimharris cpi_base = (lmac * NIC_MAX_CPI_PER_LMAC) + (bgx * NIC_CPI_PER_BGX); 699230557Sjimharris rssi_base = (lmac * nic->rss_ind_tbl_size) + (bgx * NIC_RSSI_PER_BGX); 700230557Sjimharris 701230557Sjimharris /* Rx channel configuration */ 702230557Sjimharris nic_reg_write(nic, NIC_PF_CHAN_0_255_RX_BP_CFG | (chan << 3), 703230557Sjimharris (1UL << 63) | (vnic << 0)); 704230557Sjimharris nic_reg_write(nic, NIC_PF_CHAN_0_255_RX_CFG | (chan << 3), 705230557Sjimharris ((uint64_t)cfg->cpi_alg << 62) | (cpi_base << 48)); 706230557Sjimharris 707230557Sjimharris if (cfg->cpi_alg == CPI_ALG_NONE) 708230557Sjimharris cpi_count = 1; 709230557Sjimharris else if (cfg->cpi_alg == CPI_ALG_VLAN) /* 3 bits of PCP */ 710230557Sjimharris cpi_count = 8; 711230557Sjimharris else if (cfg->cpi_alg == CPI_ALG_VLAN16) /* 3 bits PCP + DEI */ 712230557Sjimharris cpi_count = 16; 713230557Sjimharris else if (cfg->cpi_alg == CPI_ALG_DIFF) /* 6bits DSCP */ 714230557Sjimharris cpi_count = NIC_MAX_CPI_PER_LMAC; 715230557Sjimharris 716230557Sjimharris /* RSS Qset, Qidx mapping */ 717230557Sjimharris qset = cfg->vf_id; 718230557Sjimharris rssi = rssi_base; 719230557Sjimharris for (; rssi < (rssi_base + cfg->rq_cnt); rssi++) { 720230557Sjimharris nic_reg_write(nic, NIC_PF_RSSI_0_4097_RQ | (rssi << 3), 721230557Sjimharris (qset << 3) | rq_idx); 722230557Sjimharris rq_idx++; 723230557Sjimharris } 724230557Sjimharris 725230557Sjimharris rssi = 0; 726230557Sjimharris cpi = cpi_base; 727230557Sjimharris for (; cpi < (cpi_base + cpi_count); cpi++) { 728230557Sjimharris /* Determine port to channel adder */ 729230557Sjimharris if (cfg->cpi_alg != CPI_ALG_DIFF) 730230557Sjimharris padd = cpi % cpi_count; 731230557Sjimharris else 732230557Sjimharris padd = cpi % 8; /* 3 bits CS out of 6bits DSCP */ 733230557Sjimharris 734230557Sjimharris /* Leave RSS_SIZE as '0' to disable RSS */ 735230557Sjimharris nic_reg_write(nic, NIC_PF_CPI_0_2047_CFG | (cpi << 3), 736230557Sjimharris (vnic << 24) | (padd << 16) | (rssi_base + rssi)); 737230557Sjimharris 738230557Sjimharris if ((rssi + 1) >= cfg->rq_cnt) 739230557Sjimharris continue; 740230557Sjimharris 741230557Sjimharris if (cfg->cpi_alg == CPI_ALG_VLAN) 742230557Sjimharris rssi++; 743230557Sjimharris else if (cfg->cpi_alg == CPI_ALG_VLAN16) 744230557Sjimharris rssi = ((cpi - cpi_base) & 0xe) >> 1; 745230557Sjimharris else if (cfg->cpi_alg == CPI_ALG_DIFF) 746230557Sjimharris rssi = ((cpi - cpi_base) & 0x38) >> 3; 747230557Sjimharris } 748230557Sjimharris nic->cpi_base[cfg->vf_id] = cpi_base; 749230557Sjimharris} 750230557Sjimharris 751230557Sjimharris/* 752230557Sjimharris * 4 level transmit side scheduler configutation 753230557Sjimharris * for TNS bypass mode 754230557Sjimharris * 755230557Sjimharris * Sample configuration for SQ0 756230557Sjimharris * VNIC0-SQ0 -> TL4(0) -> TL3[0] -> TL2[0] -> TL1[0] -> BGX0 757230557Sjimharris * VNIC1-SQ0 -> TL4(8) -> TL3[2] -> TL2[0] -> TL1[0] -> BGX0 758230557Sjimharris * VNIC2-SQ0 -> TL4(16) -> TL3[4] -> TL2[1] -> TL1[0] -> BGX0 759230557Sjimharris * VNIC3-SQ0 -> TL4(24) -> TL3[6] -> TL2[1] -> TL1[0] -> BGX0 760230557Sjimharris * VNIC4-SQ0 -> TL4(512) -> TL3[128] -> TL2[32] -> TL1[1] -> BGX1 761230557Sjimharris * VNIC5-SQ0 -> TL4(520) -> TL3[130] -> TL2[32] -> TL1[1] -> BGX1 762230557Sjimharris * VNIC6-SQ0 -> TL4(528) -> TL3[132] -> TL2[33] -> TL1[1] -> BGX1 763230557Sjimharris * VNIC7-SQ0 -> TL4(536) -> TL3[134] -> TL2[33] -> TL1[1] -> BGX1 764230557Sjimharris */ 765230557Sjimharrisstatic void 766230557Sjimharrisnic_tx_channel_cfg(struct nicpf *nic, uint8_t vnic, struct sq_cfg_msg *sq) 767230557Sjimharris{ 768230557Sjimharris uint32_t bgx, lmac, chan; 769230557Sjimharris uint32_t tl2, tl3, tl4; 770230557Sjimharris uint32_t rr_quantum; 771230557Sjimharris uint8_t sq_idx = sq->sq_num; 772230557Sjimharris uint8_t pqs_vnic; 773230557Sjimharris 774230557Sjimharris pqs_vnic = vnic; 775230557Sjimharris 776230557Sjimharris bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[pqs_vnic]); 777230557Sjimharris lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[pqs_vnic]); 778230557Sjimharris 779230557Sjimharris /* 24 bytes for FCS, IPG and preamble */ 780230557Sjimharris rr_quantum = ((NIC_HW_MAX_FRS + 24) / 4); 781230557Sjimharris 782230557Sjimharris tl4 = (lmac * NIC_TL4_PER_LMAC) + (bgx * NIC_TL4_PER_BGX); 783230557Sjimharris tl4 += sq_idx; 784230557Sjimharris 785230557Sjimharris tl3 = tl4 / (NIC_MAX_TL4 / NIC_MAX_TL3); 786230557Sjimharris nic_reg_write(nic, NIC_PF_QSET_0_127_SQ_0_7_CFG2 | 787230557Sjimharris ((uint64_t)vnic << NIC_QS_ID_SHIFT) | 788230557Sjimharris ((uint32_t)sq_idx << NIC_Q_NUM_SHIFT), tl4); 789230557Sjimharris nic_reg_write(nic, NIC_PF_TL4_0_1023_CFG | (tl4 << 3), 790230557Sjimharris ((uint64_t)vnic << 27) | ((uint32_t)sq_idx << 24) | rr_quantum); 791230557Sjimharris 792230557Sjimharris nic_reg_write(nic, NIC_PF_TL3_0_255_CFG | (tl3 << 3), rr_quantum); 793230557Sjimharris chan = (lmac * MAX_BGX_CHANS_PER_LMAC) + (bgx * NIC_CHANS_PER_INF); 794230557Sjimharris nic_reg_write(nic, NIC_PF_TL3_0_255_CHAN | (tl3 << 3), chan); 795230557Sjimharris /* Enable backpressure on the channel */ 796230557Sjimharris nic_reg_write(nic, NIC_PF_CHAN_0_255_TX_CFG | (chan << 3), 1); 797230557Sjimharris 798230557Sjimharris tl2 = tl3 >> 2; 799230557Sjimharris nic_reg_write(nic, NIC_PF_TL3A_0_63_CFG | (tl2 << 3), tl2); 800 nic_reg_write(nic, NIC_PF_TL2_0_63_CFG | (tl2 << 3), rr_quantum); 801 /* No priorities as of now */ 802 nic_reg_write(nic, NIC_PF_TL2_0_63_PRI | (tl2 << 3), 0x00); 803} 804 805static int 806nic_config_loopback(struct nicpf *nic, struct set_loopback *lbk) 807{ 808 int bgx_idx, lmac_idx; 809 810 if (lbk->vf_id > MAX_LMAC) 811 return (ENXIO); 812 813 bgx_idx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[lbk->vf_id]); 814 lmac_idx = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[lbk->vf_id]); 815 816 bgx_lmac_internal_loopback(nic->node, bgx_idx, lmac_idx, lbk->enable); 817 818 return (0); 819} 820 821/* Interrupt handler to handle mailbox messages from VFs */ 822static void 823nic_handle_mbx_intr(struct nicpf *nic, int vf) 824{ 825 union nic_mbx mbx = {}; 826 uint64_t *mbx_data; 827 uint64_t mbx_addr; 828 uint64_t reg_addr; 829 uint64_t cfg; 830 int bgx, lmac; 831 int i; 832 int ret = 0; 833 834 nic->mbx_lock[vf] = TRUE; 835 836 mbx_addr = nic_get_mbx_addr(vf); 837 mbx_data = (uint64_t *)&mbx; 838 839 for (i = 0; i < NIC_PF_VF_MAILBOX_SIZE; i++) { 840 *mbx_data = nic_reg_read(nic, mbx_addr); 841 mbx_data++; 842 mbx_addr += sizeof(uint64_t); 843 } 844 845 switch (mbx.msg.msg) { 846 case NIC_MBOX_MSG_READY: 847 nic_mbx_send_ready(nic, vf); 848 if (vf < MAX_LMAC) { 849 nic->link[vf] = 0; 850 nic->duplex[vf] = 0; 851 nic->speed[vf] = 0; 852 } 853 ret = 1; 854 break; 855 case NIC_MBOX_MSG_QS_CFG: 856 reg_addr = NIC_PF_QSET_0_127_CFG | 857 (mbx.qs.num << NIC_QS_ID_SHIFT); 858 cfg = mbx.qs.cfg; 859 nic_reg_write(nic, reg_addr, cfg); 860 break; 861 case NIC_MBOX_MSG_RQ_CFG: 862 reg_addr = NIC_PF_QSET_0_127_RQ_0_7_CFG | 863 (mbx.rq.qs_num << NIC_QS_ID_SHIFT) | 864 (mbx.rq.rq_num << NIC_Q_NUM_SHIFT); 865 nic_reg_write(nic, reg_addr, mbx.rq.cfg); 866 break; 867 case NIC_MBOX_MSG_RQ_BP_CFG: 868 reg_addr = NIC_PF_QSET_0_127_RQ_0_7_BP_CFG | 869 (mbx.rq.qs_num << NIC_QS_ID_SHIFT) | 870 (mbx.rq.rq_num << NIC_Q_NUM_SHIFT); 871 nic_reg_write(nic, reg_addr, mbx.rq.cfg); 872 break; 873 case NIC_MBOX_MSG_RQ_SW_SYNC: 874 ret = nic_rcv_queue_sw_sync(nic); 875 break; 876 case NIC_MBOX_MSG_RQ_DROP_CFG: 877 reg_addr = NIC_PF_QSET_0_127_RQ_0_7_DROP_CFG | 878 (mbx.rq.qs_num << NIC_QS_ID_SHIFT) | 879 (mbx.rq.rq_num << NIC_Q_NUM_SHIFT); 880 nic_reg_write(nic, reg_addr, mbx.rq.cfg); 881 break; 882 case NIC_MBOX_MSG_SQ_CFG: 883 reg_addr = NIC_PF_QSET_0_127_SQ_0_7_CFG | 884 (mbx.sq.qs_num << NIC_QS_ID_SHIFT) | 885 (mbx.sq.sq_num << NIC_Q_NUM_SHIFT); 886 nic_reg_write(nic, reg_addr, mbx.sq.cfg); 887 nic_tx_channel_cfg(nic, mbx.qs.num, &mbx.sq); 888 break; 889 case NIC_MBOX_MSG_SET_MAC: 890 lmac = mbx.mac.vf_id; 891 bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[lmac]); 892 lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[lmac]); 893 bgx_set_lmac_mac(nic->node, bgx, lmac, mbx.mac.mac_addr); 894 break; 895 case NIC_MBOX_MSG_SET_MAX_FRS: 896 ret = nic_update_hw_frs(nic, mbx.frs.max_frs, mbx.frs.vf_id); 897 break; 898 case NIC_MBOX_MSG_CPI_CFG: 899 nic_config_cpi(nic, &mbx.cpi_cfg); 900 break; 901 case NIC_MBOX_MSG_CFG_DONE: 902 /* Last message of VF config msg sequence */ 903 nic->vf_info[vf].vf_enabled = TRUE; 904 goto unlock; 905 case NIC_MBOX_MSG_SHUTDOWN: 906 /* First msg in VF teardown sequence */ 907 nic->vf_info[vf].vf_enabled = FALSE; 908 break; 909 case NIC_MBOX_MSG_BGX_STATS: 910 nic_get_bgx_stats(nic, &mbx.bgx_stats); 911 goto unlock; 912 case NIC_MBOX_MSG_LOOPBACK: 913 ret = nic_config_loopback(nic, &mbx.lbk); 914 break; 915 default: 916 device_printf(nic->dev, 917 "Invalid msg from VF%d, msg 0x%x\n", vf, mbx.msg.msg); 918 break; 919 } 920 921 if (ret == 0) 922 nic_mbx_send_ack(nic, vf); 923 else if (mbx.msg.msg != NIC_MBOX_MSG_READY) 924 nic_mbx_send_nack(nic, vf); 925unlock: 926 nic->mbx_lock[vf] = FALSE; 927} 928 929static void 930nic_mbx_intr_handler(struct nicpf *nic, int mbx) 931{ 932 uint64_t intr; 933 uint8_t vf, vf_per_mbx_reg = 64; 934 935 intr = nic_reg_read(nic, NIC_PF_MAILBOX_INT + (mbx << 3)); 936 for (vf = 0; vf < vf_per_mbx_reg; vf++) { 937 if (intr & (1UL << vf)) { 938 nic_handle_mbx_intr(nic, vf + (mbx * vf_per_mbx_reg)); 939 nic_clear_mbx_intr(nic, vf, mbx); 940 } 941 } 942} 943 944static void 945nic_mbx0_intr_handler (void *arg) 946{ 947 struct nicpf *nic = (struct nicpf *)arg; 948 949 nic_mbx_intr_handler(nic, 0); 950} 951 952static void 953nic_mbx1_intr_handler (void *arg) 954{ 955 struct nicpf *nic = (struct nicpf *)arg; 956 957 nic_mbx_intr_handler(nic, 1); 958} 959 960static int 961nic_enable_msix(struct nicpf *nic) 962{ 963 struct pci_devinfo *dinfo; 964 int rid, count; 965 int ret; 966 967 dinfo = device_get_ivars(nic->dev); 968 rid = dinfo->cfg.msix.msix_table_bar; 969 nic->msix_table_res = 970 bus_alloc_resource_any(nic->dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); 971 if (nic->msix_table_res == NULL) { 972 device_printf(nic->dev, 973 "Could not allocate memory for MSI-X table\n"); 974 return (ENXIO); 975 } 976 977 count = nic->num_vec = NIC_PF_MSIX_VECTORS; 978 979 ret = pci_alloc_msix(nic->dev, &count); 980 if ((ret != 0) || (count != nic->num_vec)) { 981 device_printf(nic->dev, 982 "Request for #%d msix vectors failed, error: %d\n", 983 nic->num_vec, ret); 984 return (ret); 985 } 986 987 nic->msix_enabled = 1; 988 return (0); 989} 990 991static void 992nic_disable_msix(struct nicpf *nic) 993{ 994 if (nic->msix_enabled) { 995 pci_release_msi(nic->dev); 996 nic->msix_enabled = 0; 997 nic->num_vec = 0; 998 } 999} 1000 1001static void 1002nic_free_all_interrupts(struct nicpf *nic) 1003{ 1004 int irq; 1005 1006 for (irq = 0; irq < nic->num_vec; irq++) { 1007 if (nic->msix_entries[irq].irq_res == NULL) 1008 continue; 1009 if (nic->msix_entries[irq].handle != NULL) { 1010 bus_teardown_intr(nic->dev, 1011 nic->msix_entries[irq].irq_res, 1012 nic->msix_entries[irq].handle); 1013 } 1014 1015 bus_release_resource(nic->dev, SYS_RES_IRQ, irq, 1016 nic->msix_entries[irq].irq_res); 1017 } 1018} 1019 1020static int 1021nic_register_interrupts(struct nicpf *nic) 1022{ 1023 int irq, rid; 1024 int ret; 1025 1026 /* Enable MSI-X */ 1027 ret = nic_enable_msix(nic); 1028 if (ret != 0) 1029 return (ret); 1030 1031 /* Register mailbox interrupt handlers */ 1032 irq = NIC_PF_INTR_ID_MBOX0; 1033 rid = irq + 1; 1034 nic->msix_entries[irq].irq_res = bus_alloc_resource_any(nic->dev, 1035 SYS_RES_IRQ, &rid, (RF_SHAREABLE | RF_ACTIVE)); 1036 if (nic->msix_entries[irq].irq_res == NULL) { 1037 ret = ENXIO; 1038 goto fail; 1039 } 1040 ret = bus_setup_intr(nic->dev, nic->msix_entries[irq].irq_res, 1041 (INTR_MPSAFE | INTR_TYPE_MISC), NULL, nic_mbx0_intr_handler, nic, 1042 &nic->msix_entries[irq].handle); 1043 if (ret != 0) 1044 goto fail; 1045 1046 irq = NIC_PF_INTR_ID_MBOX1; 1047 rid = irq + 1; 1048 nic->msix_entries[irq].irq_res = bus_alloc_resource_any(nic->dev, 1049 SYS_RES_IRQ, &rid, (RF_SHAREABLE | RF_ACTIVE)); 1050 if (nic->msix_entries[irq].irq_res == NULL) { 1051 ret = ENXIO; 1052 goto fail; 1053 } 1054 ret = bus_setup_intr(nic->dev, nic->msix_entries[irq].irq_res, 1055 (INTR_MPSAFE | INTR_TYPE_MISC), NULL, nic_mbx1_intr_handler, nic, 1056 &nic->msix_entries[irq].handle); 1057 if (ret != 0) 1058 goto fail; 1059 1060 /* Enable mailbox interrupt */ 1061 nic_enable_mbx_intr(nic); 1062 return (0); 1063 1064fail: 1065 nic_free_all_interrupts(nic); 1066 return (ret); 1067} 1068 1069static void 1070nic_unregister_interrupts(struct nicpf *nic) 1071{ 1072 1073 nic_free_all_interrupts(nic); 1074 nic_disable_msix(nic); 1075} 1076 1077static int nic_sriov_init(device_t dev, struct nicpf *nic) 1078{ 1079#ifdef PCI_IOV 1080 nvlist_t *pf_schema, *vf_schema; 1081 int iov_pos; 1082 int err; 1083 uint16_t total_vf_cnt; 1084 1085 err = pci_find_extcap(dev, PCIZ_SRIOV, &iov_pos); 1086 if (err != 0) { 1087 device_printf(dev, 1088 "SR-IOV capability is not found in PCIe config space\n"); 1089 return (err); 1090 } 1091 /* Fix-up the number of enabled VFs */ 1092 total_vf_cnt = pci_read_config(dev, iov_pos + PCIR_SRIOV_TOTAL_VFS, 2); 1093 if (total_vf_cnt < nic->num_vf_en) 1094 nic->num_vf_en = total_vf_cnt; 1095 1096 if (total_vf_cnt == 0) 1097 return (0); 1098 1099 /* Attach SR-IOV */ 1100 pf_schema = pci_iov_schema_alloc_node(); 1101 vf_schema = pci_iov_schema_alloc_node(); 1102 pci_iov_schema_add_unicast_mac(vf_schema, "mac-addr", 0, NULL); 1103 /* 1104 * All VFs can change their MACs. 1105 * This flag will be ignored but we set it just for the record. 1106 */ 1107 pci_iov_schema_add_bool(vf_schema, "allow-set-mac", 1108 IOV_SCHEMA_HASDEFAULT, TRUE); 1109 1110 err = pci_iov_attach(dev, pf_schema, vf_schema); 1111 if (err != 0) { 1112 device_printf(dev, 1113 "Failed to initialize SR-IOV (error=%d)\n", 1114 err); 1115 nic->num_vf_en = 0; 1116 return (err); 1117 } 1118#endif 1119 return (0); 1120} 1121 1122/* 1123 * Poll for BGX LMAC link status and update corresponding VF 1124 * if there is a change, valid only if internal L2 switch 1125 * is not present otherwise VF link is always treated as up 1126 */ 1127static void 1128nic_poll_for_link(void *arg) 1129{ 1130 union nic_mbx mbx = {}; 1131 struct nicpf *nic; 1132 struct bgx_link_status link; 1133 uint8_t vf, bgx, lmac; 1134 1135 nic = (struct nicpf *)arg; 1136 1137 mbx.link_status.msg = NIC_MBOX_MSG_BGX_LINK_CHANGE; 1138 1139 for (vf = 0; vf < nic->num_vf_en; vf++) { 1140 /* Poll only if VF is UP */ 1141 if (!nic->vf_info[vf].vf_enabled) 1142 continue; 1143 1144 /* Get BGX, LMAC indices for the VF */ 1145 bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); 1146 lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); 1147 /* Get interface link status */ 1148 bgx_get_lmac_link_state(nic->node, bgx, lmac, &link); 1149 1150 /* Inform VF only if link status changed */ 1151 if (nic->link[vf] == link.link_up) 1152 continue; 1153 1154 if (!nic->mbx_lock[vf]) { 1155 nic->link[vf] = link.link_up; 1156 nic->duplex[vf] = link.duplex; 1157 nic->speed[vf] = link.speed; 1158 1159 /* Send a mbox message to VF with current link status */ 1160 mbx.link_status.link_up = link.link_up; 1161 mbx.link_status.duplex = link.duplex; 1162 mbx.link_status.speed = link.speed; 1163 nic_send_msg_to_vf(nic, vf, &mbx); 1164 } 1165 } 1166 callout_reset(&nic->check_link, hz * 2, nic_poll_for_link, nic); 1167} 1168