nic_main.c revision 297448
1289550Szbb/* 2289550Szbb * Copyright (C) 2015 Cavium Inc. 3289550Szbb * All rights reserved. 4289550Szbb * 5289550Szbb * Redistribution and use in source and binary forms, with or without 6289550Szbb * modification, are permitted provided that the following conditions 7289550Szbb * are met: 8289550Szbb * 1. Redistributions of source code must retain the above copyright 9289550Szbb * notice, this list of conditions and the following disclaimer. 10289550Szbb * 2. Redistributions in binary form must reproduce the above copyright 11289550Szbb * notice, this list of conditions and the following disclaimer in the 12289550Szbb * documentation and/or other materials provided with the distribution. 13289550Szbb * 14289550Szbb * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15289550Szbb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16289550Szbb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17289550Szbb * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18289550Szbb * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19289550Szbb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20289550Szbb * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21289550Szbb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22289550Szbb * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23289550Szbb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24289550Szbb * SUCH DAMAGE. 25289550Szbb * 26289550Szbb * $FreeBSD: head/sys/dev/vnic/nic_main.c 297448 2016-03-31 12:10:17Z zbb $ 27289550Szbb * 28289550Szbb */ 29289550Szbb 30289551Szbb#include <sys/cdefs.h> 31289551Szbb__FBSDID("$FreeBSD: head/sys/dev/vnic/nic_main.c 297448 2016-03-31 12:10:17Z zbb $"); 32289550Szbb 33289551Szbb#include <sys/param.h> 34289551Szbb#include <sys/systm.h> 35289551Szbb#include <sys/bitset.h> 36289551Szbb#include <sys/bitstring.h> 37289551Szbb#include <sys/bus.h> 38289551Szbb#include <sys/endian.h> 39289551Szbb#include <sys/kernel.h> 40289551Szbb#include <sys/malloc.h> 41289551Szbb#include <sys/module.h> 42289551Szbb#include <sys/rman.h> 43289551Szbb#include <sys/pciio.h> 44289551Szbb#include <sys/pcpu.h> 45289551Szbb#include <sys/proc.h> 46289551Szbb#include <sys/socket.h> 47289551Szbb#include <sys/sockio.h> 48289551Szbb#include <sys/cpuset.h> 49289551Szbb#include <sys/lock.h> 50289551Szbb#include <sys/mutex.h> 51289551Szbb 52289551Szbb#include <net/ethernet.h> 53289551Szbb#include <net/if.h> 54289551Szbb#include <net/if_media.h> 55289551Szbb 56289551Szbb#include <machine/bus.h> 57289551Szbb#include <machine/_inttypes.h> 58289551Szbb 59289551Szbb#include <dev/pci/pcireg.h> 60289551Szbb#include <dev/pci/pcivar.h> 61289551Szbb 62289551Szbb#include <sys/dnv.h> 63289551Szbb#include <sys/nv.h> 64289551Szbb#ifdef PCI_IOV 65289551Szbb#include <sys/iov_schema.h> 66289551Szbb#include <dev/pci/pci_iov.h> 67289551Szbb#endif 68289551Szbb 69289551Szbb#include "thunder_bgx.h" 70289550Szbb#include "nic_reg.h" 71289550Szbb#include "nic.h" 72289550Szbb#include "q_struct.h" 73289550Szbb 74289551Szbb#define VNIC_PF_DEVSTR "Cavium Thunder NIC Physical Function Driver" 75289550Szbb 76289551Szbb#define VNIC_PF_REG_RID PCIR_BAR(PCI_CFG_REG_BAR_NUM) 77289551Szbb 78289551Szbb#define NIC_SET_VF_LMAC_MAP(bgx, lmac) ((((bgx) & 0xF) << 4) | ((lmac) & 0xF)) 79289551Szbb#define NIC_GET_BGX_FROM_VF_LMAC_MAP(map) (((map) >> 4) & 0xF) 80289551Szbb#define NIC_GET_LMAC_FROM_VF_LMAC_MAP(map) ((map) & 0xF) 81289551Szbb 82289551Szbb/* Structure to be used by the SR-IOV for VF configuration schemas */ 83289551Szbbstruct nicvf_info { 84289551Szbb boolean_t vf_enabled; 85289551Szbb int vf_flags; 86289551Szbb}; 87289551Szbb 88289550Szbbstruct nicpf { 89289551Szbb device_t dev; 90289551Szbb uint8_t node; 91289551Szbb u_int flags; 92289551Szbb uint8_t num_vf_en; /* No of VF enabled */ 93289551Szbb struct nicvf_info vf_info[MAX_NUM_VFS_SUPPORTED]; 94289551Szbb struct resource * reg_base; /* Register start address */ 95289550Szbb struct pkind_cfg pkind; 96289551Szbb uint8_t vf_lmac_map[MAX_LMAC]; 97289551Szbb boolean_t mbx_lock[MAX_NUM_VFS_SUPPORTED]; 98289550Szbb 99289551Szbb struct callout check_link; 100289551Szbb struct mtx check_link_mtx; 101289551Szbb 102289551Szbb uint8_t link[MAX_LMAC]; 103289551Szbb uint8_t duplex[MAX_LMAC]; 104289551Szbb uint32_t speed[MAX_LMAC]; 105289551Szbb uint16_t cpi_base[MAX_NUM_VFS_SUPPORTED]; 106289551Szbb uint16_t rss_ind_tbl_size; 107289551Szbb 108289550Szbb /* MSI-X */ 109289551Szbb boolean_t msix_enabled; 110289551Szbb uint8_t num_vec; 111289550Szbb struct msix_entry msix_entries[NIC_PF_MSIX_VECTORS]; 112289551Szbb struct resource * msix_table_res; 113289550Szbb}; 114289550Szbb 115289551Szbbstatic int nicpf_probe(device_t); 116289551Szbbstatic int nicpf_attach(device_t); 117289551Szbbstatic int nicpf_detach(device_t); 118289551Szbb 119289551Szbb#ifdef PCI_IOV 120289551Szbbstatic int nicpf_iov_init(device_t, uint16_t, const nvlist_t *); 121289551Szbbstatic void nicpf_iov_uninit(device_t); 122297448Szbbstatic int nicpf_iov_add_vf(device_t, uint16_t, const nvlist_t *); 123289551Szbb#endif 124289551Szbb 125289551Szbbstatic device_method_t nicpf_methods[] = { 126289551Szbb /* Device interface */ 127289551Szbb DEVMETHOD(device_probe, nicpf_probe), 128289551Szbb DEVMETHOD(device_attach, nicpf_attach), 129289551Szbb DEVMETHOD(device_detach, nicpf_detach), 130289551Szbb /* PCI SR-IOV interface */ 131289551Szbb#ifdef PCI_IOV 132289551Szbb DEVMETHOD(pci_iov_init, nicpf_iov_init), 133289551Szbb DEVMETHOD(pci_iov_uninit, nicpf_iov_uninit), 134297448Szbb DEVMETHOD(pci_iov_add_vf, nicpf_iov_add_vf), 135289551Szbb#endif 136289551Szbb DEVMETHOD_END, 137289550Szbb}; 138289550Szbb 139289551Szbbstatic driver_t nicpf_driver = { 140289551Szbb "vnicpf", 141289551Szbb nicpf_methods, 142289551Szbb sizeof(struct nicpf), 143289551Szbb}; 144289550Szbb 145289551Szbbstatic devclass_t nicpf_devclass; 146289551Szbb 147289551SzbbDRIVER_MODULE(nicpf, pci, nicpf_driver, nicpf_devclass, 0, 0); 148289551SzbbMODULE_DEPEND(nicpf, pci, 1, 1, 1); 149289551SzbbMODULE_DEPEND(nicpf, ether, 1, 1, 1); 150289551SzbbMODULE_DEPEND(nicpf, thunder_bgx, 1, 1, 1); 151289551Szbb 152289551Szbbstatic int nicpf_alloc_res(struct nicpf *); 153289551Szbbstatic void nicpf_free_res(struct nicpf *); 154289551Szbbstatic void nic_set_lmac_vf_mapping(struct nicpf *); 155289551Szbbstatic void nic_init_hw(struct nicpf *); 156289551Szbbstatic int nic_sriov_init(device_t, struct nicpf *); 157289551Szbbstatic void nic_poll_for_link(void *); 158289551Szbbstatic int nic_register_interrupts(struct nicpf *); 159289551Szbbstatic void nic_unregister_interrupts(struct nicpf *); 160289551Szbb 161289551Szbb/* 162289551Szbb * Device interface 163289550Szbb */ 164289551Szbbstatic int 165289551Szbbnicpf_probe(device_t dev) 166289551Szbb{ 167289551Szbb uint16_t vendor_id; 168289551Szbb uint16_t device_id; 169289550Szbb 170289551Szbb vendor_id = pci_get_vendor(dev); 171289551Szbb device_id = pci_get_device(dev); 172289551Szbb 173289551Szbb if (vendor_id == PCI_VENDOR_ID_CAVIUM && 174289551Szbb device_id == PCI_DEVICE_ID_THUNDER_NIC_PF) { 175289551Szbb device_set_desc(dev, VNIC_PF_DEVSTR); 176289551Szbb return (BUS_PROBE_DEFAULT); 177289551Szbb } 178289551Szbb 179289551Szbb return (ENXIO); 180289551Szbb} 181289551Szbb 182289551Szbbstatic int 183289551Szbbnicpf_attach(device_t dev) 184289551Szbb{ 185289551Szbb struct nicpf *nic; 186289551Szbb int err; 187289551Szbb 188289551Szbb nic = device_get_softc(dev); 189289551Szbb nic->dev = dev; 190289551Szbb 191289551Szbb /* Enable bus mastering */ 192289551Szbb pci_enable_busmaster(dev); 193289551Szbb 194289551Szbb /* Allocate PCI resources */ 195289551Szbb err = nicpf_alloc_res(nic); 196289551Szbb if (err != 0) { 197289551Szbb device_printf(dev, "Could not allocate PCI resources\n"); 198289551Szbb return (err); 199289551Szbb } 200289551Szbb 201289551Szbb nic->node = nic_get_node_id(nic->reg_base); 202289551Szbb 203289551Szbb /* Enable Traffic Network Switch (TNS) bypass mode by default */ 204289551Szbb nic->flags &= ~NIC_TNS_ENABLED; 205289551Szbb nic_set_lmac_vf_mapping(nic); 206289551Szbb 207289551Szbb /* Initialize hardware */ 208289551Szbb nic_init_hw(nic); 209289551Szbb 210289551Szbb /* Set RSS TBL size for each VF */ 211289551Szbb nic->rss_ind_tbl_size = NIC_MAX_RSS_IDR_TBL_SIZE; 212289551Szbb 213289551Szbb /* Setup interrupts */ 214289551Szbb err = nic_register_interrupts(nic); 215289551Szbb if (err != 0) 216289551Szbb goto err_free_res; 217289551Szbb 218289551Szbb /* Configure SRIOV */ 219289551Szbb err = nic_sriov_init(dev, nic); 220289551Szbb if (err != 0) 221289551Szbb goto err_free_intr; 222289551Szbb 223289551Szbb if (nic->flags & NIC_TNS_ENABLED) 224289551Szbb return (0); 225289551Szbb 226289551Szbb mtx_init(&nic->check_link_mtx, "VNIC PF link poll", NULL, MTX_DEF); 227289551Szbb /* Register physical link status poll callout */ 228289551Szbb callout_init_mtx(&nic->check_link, &nic->check_link_mtx, 0); 229289551Szbb mtx_lock(&nic->check_link_mtx); 230289551Szbb nic_poll_for_link(nic); 231289551Szbb mtx_unlock(&nic->check_link_mtx); 232289551Szbb 233289551Szbb return (0); 234289551Szbb 235289551Szbberr_free_intr: 236289551Szbb nic_unregister_interrupts(nic); 237289551Szbberr_free_res: 238289551Szbb nicpf_free_res(nic); 239289551Szbb pci_disable_busmaster(dev); 240289551Szbb 241289551Szbb return (err); 242289551Szbb} 243289551Szbb 244289551Szbbstatic int 245289551Szbbnicpf_detach(device_t dev) 246289551Szbb{ 247289551Szbb struct nicpf *nic; 248289551Szbb 249289551Szbb nic = device_get_softc(dev); 250289551Szbb 251289551Szbb callout_drain(&nic->check_link); 252289551Szbb mtx_destroy(&nic->check_link_mtx); 253289551Szbb 254289551Szbb nic_unregister_interrupts(nic); 255289551Szbb nicpf_free_res(nic); 256289551Szbb pci_disable_busmaster(dev); 257289551Szbb 258289551Szbb return (0); 259289551Szbb} 260289551Szbb 261289551Szbb/* 262289551Szbb * SR-IOV interface 263289551Szbb */ 264289551Szbb#ifdef PCI_IOV 265289551Szbbstatic int 266289551Szbbnicpf_iov_init(device_t dev, uint16_t num_vfs, const nvlist_t *params) 267289551Szbb{ 268289551Szbb struct nicpf *nic; 269289551Szbb 270289551Szbb nic = device_get_softc(dev); 271289551Szbb 272289551Szbb nic->num_vf_en = 0; 273289551Szbb if (num_vfs == 0) 274289551Szbb return (ENXIO); 275289551Szbb if (num_vfs > MAX_NUM_VFS_SUPPORTED) 276289551Szbb return (EINVAL); 277289551Szbb 278289551Szbb /* 279289551Szbb * Just set variables here. 280289551Szbb * The number of VFs will be written to configuration 281289551Szbb * space later in PCI_ADD_VF(). 282289551Szbb */ 283289551Szbb nic->num_vf_en = num_vfs; 284289551Szbb nic->flags |= NIC_SRIOV_ENABLED; 285289551Szbb 286289551Szbb return (0); 287289551Szbb} 288289551Szbb 289289551Szbbstatic void 290289551Szbbnicpf_iov_uninit(device_t dev) 291289551Szbb{ 292289551Szbb 293289551Szbb /* ARM64TODO: Implement this function */ 294289551Szbb} 295289551Szbb 296289551Szbbstatic int 297297448Szbbnicpf_iov_add_vf(device_t dev, uint16_t vfnum, const nvlist_t *params) 298289551Szbb{ 299289551Szbb const void *mac; 300289551Szbb struct nicpf *nic; 301289551Szbb size_t size; 302289551Szbb int bgx, lmac; 303289551Szbb 304289551Szbb nic = device_get_softc(dev); 305289551Szbb 306289551Szbb if ((nic->flags & NIC_SRIOV_ENABLED) == 0) 307289551Szbb return (ENXIO); 308289551Szbb 309289551Szbb if (nvlist_exists_binary(params, "mac-addr") != 0) { 310289551Szbb mac = nvlist_get_binary(params, "mac-addr", &size); 311289551Szbb bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vfnum]); 312289551Szbb lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vfnum]); 313289551Szbb bgx_set_lmac_mac(nic->node, bgx, lmac, mac); 314289551Szbb } 315289551Szbb 316289551Szbb return (0); 317289551Szbb} 318289551Szbb#endif 319289551Szbb 320289551Szbb/* 321289551Szbb * Helper routines 322289551Szbb */ 323289551Szbbstatic int 324289551Szbbnicpf_alloc_res(struct nicpf *nic) 325289551Szbb{ 326289551Szbb device_t dev; 327289551Szbb int rid; 328289551Szbb 329289551Szbb dev = nic->dev; 330289551Szbb 331289551Szbb rid = VNIC_PF_REG_RID; 332289551Szbb nic->reg_base = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 333289551Szbb RF_ACTIVE); 334289551Szbb if (nic->reg_base == NULL) { 335289551Szbb /* For verbose output print some more details */ 336289551Szbb if (bootverbose) { 337289551Szbb device_printf(dev, 338289551Szbb "Could not allocate registers memory\n"); 339289551Szbb } 340289551Szbb return (ENXIO); 341289551Szbb } 342289551Szbb 343289551Szbb return (0); 344289551Szbb} 345289551Szbb 346289551Szbbstatic void 347289551Szbbnicpf_free_res(struct nicpf *nic) 348289551Szbb{ 349289551Szbb device_t dev; 350289551Szbb 351289551Szbb dev = nic->dev; 352289551Szbb 353289551Szbb if (nic->reg_base != NULL) { 354289551Szbb bus_release_resource(dev, SYS_RES_MEMORY, 355289551Szbb rman_get_rid(nic->reg_base), nic->reg_base); 356289551Szbb } 357289551Szbb} 358289551Szbb 359289550Szbb/* Register read/write APIs */ 360289551Szbbstatic __inline void 361289551Szbbnic_reg_write(struct nicpf *nic, bus_space_handle_t offset, 362289551Szbb uint64_t val) 363289550Szbb{ 364289551Szbb 365289551Szbb bus_write_8(nic->reg_base, offset, val); 366289550Szbb} 367289550Szbb 368289551Szbbstatic __inline uint64_t 369289551Szbbnic_reg_read(struct nicpf *nic, uint64_t offset) 370289550Szbb{ 371289551Szbb uint64_t val; 372289551Szbb 373289551Szbb val = bus_read_8(nic->reg_base, offset); 374289551Szbb return (val); 375289550Szbb} 376289550Szbb 377289550Szbb/* PF -> VF mailbox communication APIs */ 378289551Szbbstatic void 379289551Szbbnic_enable_mbx_intr(struct nicpf *nic) 380289550Szbb{ 381289551Szbb 382289550Szbb /* Enable mailbox interrupt for all 128 VFs */ 383289551Szbb nic_reg_write(nic, NIC_PF_MAILBOX_ENA_W1S, ~0UL); 384289551Szbb nic_reg_write(nic, NIC_PF_MAILBOX_ENA_W1S + sizeof(uint64_t), ~0UL); 385289550Szbb} 386289550Szbb 387289551Szbbstatic void 388289551Szbbnic_clear_mbx_intr(struct nicpf *nic, int vf, int mbx_reg) 389289550Szbb{ 390289551Szbb 391289551Szbb nic_reg_write(nic, NIC_PF_MAILBOX_INT + (mbx_reg << 3), (1UL << vf)); 392289550Szbb} 393289550Szbb 394289551Szbbstatic uint64_t 395289551Szbbnic_get_mbx_addr(int vf) 396289550Szbb{ 397289551Szbb 398289551Szbb return (NIC_PF_VF_0_127_MAILBOX_0_1 + (vf << NIC_VF_NUM_SHIFT)); 399289550Szbb} 400289550Szbb 401289551Szbb/* 402289551Szbb * Send a mailbox message to VF 403289550Szbb * @vf: vf to which this message to be sent 404289550Szbb * @mbx: Message to be sent 405289550Szbb */ 406289551Szbbstatic void 407289551Szbbnic_send_msg_to_vf(struct nicpf *nic, int vf, union nic_mbx *mbx) 408289550Szbb{ 409289551Szbb bus_space_handle_t mbx_addr = nic_get_mbx_addr(vf); 410289551Szbb uint64_t *msg = (uint64_t *)mbx; 411289550Szbb 412289551Szbb /* 413289551Szbb * In first revision HW, mbox interrupt is triggerred 414289550Szbb * when PF writes to MBOX(1), in next revisions when 415289550Szbb * PF writes to MBOX(0) 416289550Szbb */ 417296037Szbb if (pass1_silicon(nic->dev)) { 418289551Szbb nic_reg_write(nic, mbx_addr + 0, msg[0]); 419289551Szbb nic_reg_write(nic, mbx_addr + 8, msg[1]); 420289550Szbb } else { 421289551Szbb nic_reg_write(nic, mbx_addr + 8, msg[1]); 422289551Szbb nic_reg_write(nic, mbx_addr + 0, msg[0]); 423289550Szbb } 424289550Szbb} 425289550Szbb 426289551Szbb/* 427289551Szbb * Responds to VF's READY message with VF's 428289550Szbb * ID, node, MAC address e.t.c 429289550Szbb * @vf: VF which sent READY message 430289550Szbb */ 431289551Szbbstatic void 432289551Szbbnic_mbx_send_ready(struct nicpf *nic, int vf) 433289550Szbb{ 434289550Szbb union nic_mbx mbx = {}; 435289550Szbb int bgx_idx, lmac; 436289550Szbb const char *mac; 437289550Szbb 438289550Szbb mbx.nic_cfg.msg = NIC_MBOX_MSG_READY; 439289550Szbb mbx.nic_cfg.vf_id = vf; 440289550Szbb 441289550Szbb if (nic->flags & NIC_TNS_ENABLED) 442289550Szbb mbx.nic_cfg.tns_mode = NIC_TNS_MODE; 443289550Szbb else 444289550Szbb mbx.nic_cfg.tns_mode = NIC_TNS_BYPASS_MODE; 445289550Szbb 446289550Szbb if (vf < MAX_LMAC) { 447289550Szbb bgx_idx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); 448289550Szbb lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); 449289550Szbb 450289550Szbb mac = bgx_get_lmac_mac(nic->node, bgx_idx, lmac); 451289551Szbb if (mac) { 452289551Szbb memcpy((uint8_t *)&mbx.nic_cfg.mac_addr, mac, 453289551Szbb ETHER_ADDR_LEN); 454289551Szbb } 455289550Szbb } 456289550Szbb mbx.nic_cfg.node_id = nic->node; 457289550Szbb 458289550Szbb mbx.nic_cfg.loopback_supported = vf < MAX_LMAC; 459289550Szbb 460289550Szbb nic_send_msg_to_vf(nic, vf, &mbx); 461289550Szbb} 462289550Szbb 463289551Szbb/* 464289551Szbb * ACKs VF's mailbox message 465289550Szbb * @vf: VF to which ACK to be sent 466289550Szbb */ 467289551Szbbstatic void 468289551Szbbnic_mbx_send_ack(struct nicpf *nic, int vf) 469289550Szbb{ 470289550Szbb union nic_mbx mbx = {}; 471289550Szbb 472289550Szbb mbx.msg.msg = NIC_MBOX_MSG_ACK; 473289550Szbb nic_send_msg_to_vf(nic, vf, &mbx); 474289550Szbb} 475289550Szbb 476289551Szbb/* 477289551Szbb * NACKs VF's mailbox message that PF is not able to 478289550Szbb * complete the action 479289550Szbb * @vf: VF to which ACK to be sent 480289550Szbb */ 481289551Szbbstatic void 482289551Szbbnic_mbx_send_nack(struct nicpf *nic, int vf) 483289550Szbb{ 484289550Szbb union nic_mbx mbx = {}; 485289550Szbb 486289550Szbb mbx.msg.msg = NIC_MBOX_MSG_NACK; 487289550Szbb nic_send_msg_to_vf(nic, vf, &mbx); 488289550Szbb} 489289550Szbb 490289551Szbb/* 491289551Szbb * Flush all in flight receive packets to memory and 492289550Szbb * bring down an active RQ 493289550Szbb */ 494289551Szbbstatic int 495289551Szbbnic_rcv_queue_sw_sync(struct nicpf *nic) 496289550Szbb{ 497289551Szbb uint16_t timeout = ~0x00; 498289550Szbb 499289550Szbb nic_reg_write(nic, NIC_PF_SW_SYNC_RX, 0x01); 500289550Szbb /* Wait till sync cycle is finished */ 501289550Szbb while (timeout) { 502289550Szbb if (nic_reg_read(nic, NIC_PF_SW_SYNC_RX_DONE) & 0x1) 503289550Szbb break; 504289550Szbb timeout--; 505289550Szbb } 506289550Szbb nic_reg_write(nic, NIC_PF_SW_SYNC_RX, 0x00); 507289550Szbb if (!timeout) { 508289551Szbb device_printf(nic->dev, "Receive queue software sync failed\n"); 509289551Szbb return (ETIMEDOUT); 510289550Szbb } 511289551Szbb return (0); 512289550Szbb} 513289550Szbb 514289550Szbb/* Get BGX Rx/Tx stats and respond to VF's request */ 515289551Szbbstatic void 516289551Szbbnic_get_bgx_stats(struct nicpf *nic, struct bgx_stats_msg *bgx) 517289550Szbb{ 518289550Szbb int bgx_idx, lmac; 519289550Szbb union nic_mbx mbx = {}; 520289550Szbb 521289550Szbb bgx_idx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[bgx->vf_id]); 522289550Szbb lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[bgx->vf_id]); 523289550Szbb 524289550Szbb mbx.bgx_stats.msg = NIC_MBOX_MSG_BGX_STATS; 525289550Szbb mbx.bgx_stats.vf_id = bgx->vf_id; 526289550Szbb mbx.bgx_stats.rx = bgx->rx; 527289550Szbb mbx.bgx_stats.idx = bgx->idx; 528289551Szbb if (bgx->rx != 0) { 529289551Szbb mbx.bgx_stats.stats = 530289551Szbb bgx_get_rx_stats(nic->node, bgx_idx, lmac, bgx->idx); 531289551Szbb } else { 532289551Szbb mbx.bgx_stats.stats = 533289551Szbb bgx_get_tx_stats(nic->node, bgx_idx, lmac, bgx->idx); 534289551Szbb } 535289550Szbb nic_send_msg_to_vf(nic, bgx->vf_id, &mbx); 536289550Szbb} 537289550Szbb 538289550Szbb/* Update hardware min/max frame size */ 539289551Szbbstatic int 540289551Szbbnic_update_hw_frs(struct nicpf *nic, int new_frs, int vf) 541289550Szbb{ 542289551Szbb 543289550Szbb if ((new_frs > NIC_HW_MAX_FRS) || (new_frs < NIC_HW_MIN_FRS)) { 544289551Szbb device_printf(nic->dev, 545289551Szbb "Invalid MTU setting from VF%d rejected, " 546289551Szbb "should be between %d and %d\n", 547289551Szbb vf, NIC_HW_MIN_FRS, NIC_HW_MAX_FRS); 548289551Szbb return (EINVAL); 549289550Szbb } 550289551Szbb new_frs += ETHER_HDR_LEN; 551289550Szbb if (new_frs <= nic->pkind.maxlen) 552289551Szbb return (0); 553289550Szbb 554289550Szbb nic->pkind.maxlen = new_frs; 555289551Szbb nic_reg_write(nic, NIC_PF_PKIND_0_15_CFG, *(uint64_t *)&nic->pkind); 556289551Szbb return (0); 557289550Szbb} 558289550Szbb 559289550Szbb/* Set minimum transmit packet size */ 560289551Szbbstatic void 561289551Szbbnic_set_tx_pkt_pad(struct nicpf *nic, int size) 562289550Szbb{ 563289550Szbb int lmac; 564289551Szbb uint64_t lmac_cfg; 565289550Szbb 566289550Szbb /* Max value that can be set is 60 */ 567289550Szbb if (size > 60) 568289550Szbb size = 60; 569289550Szbb 570289550Szbb for (lmac = 0; lmac < (MAX_BGX_PER_CN88XX * MAX_LMAC_PER_BGX); lmac++) { 571289550Szbb lmac_cfg = nic_reg_read(nic, NIC_PF_LMAC_0_7_CFG | (lmac << 3)); 572289550Szbb lmac_cfg &= ~(0xF << 2); 573289550Szbb lmac_cfg |= ((size / 4) << 2); 574289550Szbb nic_reg_write(nic, NIC_PF_LMAC_0_7_CFG | (lmac << 3), lmac_cfg); 575289550Szbb } 576289550Szbb} 577289550Szbb 578289551Szbb/* 579289551Szbb * Function to check number of LMACs present and set VF::LMAC mapping. 580289550Szbb * Mapping will be used while initializing channels. 581289550Szbb */ 582289551Szbbstatic void 583289551Szbbnic_set_lmac_vf_mapping(struct nicpf *nic) 584289550Szbb{ 585289550Szbb unsigned bgx_map = bgx_get_map(nic->node); 586289550Szbb int bgx, next_bgx_lmac = 0; 587289550Szbb int lmac, lmac_cnt = 0; 588289551Szbb uint64_t lmac_credit; 589289550Szbb 590289550Szbb nic->num_vf_en = 0; 591289550Szbb if (nic->flags & NIC_TNS_ENABLED) { 592289550Szbb nic->num_vf_en = DEFAULT_NUM_VF_ENABLED; 593289550Szbb return; 594289550Szbb } 595289550Szbb 596289550Szbb for (bgx = 0; bgx < NIC_MAX_BGX; bgx++) { 597289551Szbb if ((bgx_map & (1 << bgx)) == 0) 598289550Szbb continue; 599289550Szbb lmac_cnt = bgx_get_lmac_count(nic->node, bgx); 600289550Szbb for (lmac = 0; lmac < lmac_cnt; lmac++) 601289550Szbb nic->vf_lmac_map[next_bgx_lmac++] = 602289550Szbb NIC_SET_VF_LMAC_MAP(bgx, lmac); 603289550Szbb nic->num_vf_en += lmac_cnt; 604289550Szbb 605289550Szbb /* Program LMAC credits */ 606289551Szbb lmac_credit = (1UL << 1); /* channel credit enable */ 607289550Szbb lmac_credit |= (0x1ff << 2); /* Max outstanding pkt count */ 608289550Szbb /* 48KB BGX Tx buffer size, each unit is of size 16bytes */ 609289550Szbb lmac_credit |= (((((48 * 1024) / lmac_cnt) - 610289551Szbb NIC_HW_MAX_FRS) / 16) << 12); 611289550Szbb lmac = bgx * MAX_LMAC_PER_BGX; 612289551Szbb for (; lmac < lmac_cnt + (bgx * MAX_LMAC_PER_BGX); lmac++) { 613289551Szbb nic_reg_write(nic, NIC_PF_LMAC_0_7_CREDIT + (lmac * 8), 614289551Szbb lmac_credit); 615289551Szbb } 616289550Szbb } 617289550Szbb} 618289550Szbb 619289550Szbb#define TNS_PORT0_BLOCK 6 620289550Szbb#define TNS_PORT1_BLOCK 7 621289550Szbb#define BGX0_BLOCK 8 622289550Szbb#define BGX1_BLOCK 9 623289550Szbb 624289551Szbbstatic void 625289551Szbbnic_init_hw(struct nicpf *nic) 626289550Szbb{ 627289550Szbb int i; 628289550Szbb 629289550Szbb /* Enable NIC HW block */ 630289550Szbb nic_reg_write(nic, NIC_PF_CFG, 0x3); 631289550Szbb 632289550Szbb /* Enable backpressure */ 633289551Szbb nic_reg_write(nic, NIC_PF_BP_CFG, (1UL << 6) | 0x03); 634289550Szbb 635289550Szbb if (nic->flags & NIC_TNS_ENABLED) { 636289550Szbb nic_reg_write(nic, NIC_PF_INTF_0_1_SEND_CFG, 637289551Szbb (NIC_TNS_MODE << 7) | TNS_PORT0_BLOCK); 638289550Szbb nic_reg_write(nic, NIC_PF_INTF_0_1_SEND_CFG | (1 << 8), 639289551Szbb (NIC_TNS_MODE << 7) | TNS_PORT1_BLOCK); 640289550Szbb nic_reg_write(nic, NIC_PF_INTF_0_1_BP_CFG, 641289551Szbb (1UL << 63) | TNS_PORT0_BLOCK); 642289550Szbb nic_reg_write(nic, NIC_PF_INTF_0_1_BP_CFG + (1 << 8), 643289551Szbb (1UL << 63) | TNS_PORT1_BLOCK); 644289550Szbb 645289550Szbb } else { 646289550Szbb /* Disable TNS mode on both interfaces */ 647289550Szbb nic_reg_write(nic, NIC_PF_INTF_0_1_SEND_CFG, 648289551Szbb (NIC_TNS_BYPASS_MODE << 7) | BGX0_BLOCK); 649289550Szbb nic_reg_write(nic, NIC_PF_INTF_0_1_SEND_CFG | (1 << 8), 650289551Szbb (NIC_TNS_BYPASS_MODE << 7) | BGX1_BLOCK); 651289550Szbb nic_reg_write(nic, NIC_PF_INTF_0_1_BP_CFG, 652289551Szbb (1UL << 63) | BGX0_BLOCK); 653289550Szbb nic_reg_write(nic, NIC_PF_INTF_0_1_BP_CFG + (1 << 8), 654289551Szbb (1UL << 63) | BGX1_BLOCK); 655289550Szbb } 656289550Szbb 657289550Szbb /* PKIND configuration */ 658289550Szbb nic->pkind.minlen = 0; 659289551Szbb nic->pkind.maxlen = NIC_HW_MAX_FRS + ETHER_HDR_LEN; 660289550Szbb nic->pkind.lenerr_en = 1; 661289550Szbb nic->pkind.rx_hdr = 0; 662289550Szbb nic->pkind.hdr_sl = 0; 663289550Szbb 664289551Szbb for (i = 0; i < NIC_MAX_PKIND; i++) { 665289550Szbb nic_reg_write(nic, NIC_PF_PKIND_0_15_CFG | (i << 3), 666289551Szbb *(uint64_t *)&nic->pkind); 667289551Szbb } 668289550Szbb 669289550Szbb nic_set_tx_pkt_pad(nic, NIC_HW_MIN_FRS); 670289550Szbb 671289550Szbb /* Timer config */ 672289550Szbb nic_reg_write(nic, NIC_PF_INTR_TIMER_CFG, NICPF_CLK_PER_INT_TICK); 673289550Szbb 674289550Szbb /* Enable VLAN ethertype matching and stripping */ 675289550Szbb nic_reg_write(nic, NIC_PF_RX_ETYPE_0_7, 676289551Szbb (2 << 19) | (ETYPE_ALG_VLAN_STRIP << 16) | ETHERTYPE_VLAN); 677289550Szbb} 678289550Szbb 679289550Szbb/* Channel parse index configuration */ 680289551Szbbstatic void 681289551Szbbnic_config_cpi(struct nicpf *nic, struct cpi_cfg_msg *cfg) 682289550Szbb{ 683289551Szbb uint32_t vnic, bgx, lmac, chan; 684289551Szbb uint32_t padd, cpi_count = 0; 685289551Szbb uint64_t cpi_base, cpi, rssi_base, rssi; 686289551Szbb uint8_t qset, rq_idx = 0; 687289550Szbb 688289550Szbb vnic = cfg->vf_id; 689289550Szbb bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vnic]); 690289550Szbb lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vnic]); 691289550Szbb 692289550Szbb chan = (lmac * MAX_BGX_CHANS_PER_LMAC) + (bgx * NIC_CHANS_PER_INF); 693289550Szbb cpi_base = (lmac * NIC_MAX_CPI_PER_LMAC) + (bgx * NIC_CPI_PER_BGX); 694289550Szbb rssi_base = (lmac * nic->rss_ind_tbl_size) + (bgx * NIC_RSSI_PER_BGX); 695289550Szbb 696289550Szbb /* Rx channel configuration */ 697289550Szbb nic_reg_write(nic, NIC_PF_CHAN_0_255_RX_BP_CFG | (chan << 3), 698289551Szbb (1UL << 63) | (vnic << 0)); 699289550Szbb nic_reg_write(nic, NIC_PF_CHAN_0_255_RX_CFG | (chan << 3), 700289551Szbb ((uint64_t)cfg->cpi_alg << 62) | (cpi_base << 48)); 701289550Szbb 702289550Szbb if (cfg->cpi_alg == CPI_ALG_NONE) 703289550Szbb cpi_count = 1; 704289550Szbb else if (cfg->cpi_alg == CPI_ALG_VLAN) /* 3 bits of PCP */ 705289550Szbb cpi_count = 8; 706289550Szbb else if (cfg->cpi_alg == CPI_ALG_VLAN16) /* 3 bits PCP + DEI */ 707289550Szbb cpi_count = 16; 708289550Szbb else if (cfg->cpi_alg == CPI_ALG_DIFF) /* 6bits DSCP */ 709289550Szbb cpi_count = NIC_MAX_CPI_PER_LMAC; 710289550Szbb 711289550Szbb /* RSS Qset, Qidx mapping */ 712289550Szbb qset = cfg->vf_id; 713289550Szbb rssi = rssi_base; 714289550Szbb for (; rssi < (rssi_base + cfg->rq_cnt); rssi++) { 715289550Szbb nic_reg_write(nic, NIC_PF_RSSI_0_4097_RQ | (rssi << 3), 716289551Szbb (qset << 3) | rq_idx); 717289550Szbb rq_idx++; 718289550Szbb } 719289550Szbb 720289550Szbb rssi = 0; 721289550Szbb cpi = cpi_base; 722289550Szbb for (; cpi < (cpi_base + cpi_count); cpi++) { 723289550Szbb /* Determine port to channel adder */ 724289550Szbb if (cfg->cpi_alg != CPI_ALG_DIFF) 725289550Szbb padd = cpi % cpi_count; 726289550Szbb else 727289550Szbb padd = cpi % 8; /* 3 bits CS out of 6bits DSCP */ 728289550Szbb 729289550Szbb /* Leave RSS_SIZE as '0' to disable RSS */ 730296037Szbb if (pass1_silicon(nic->dev)) { 731296037Szbb nic_reg_write(nic, NIC_PF_CPI_0_2047_CFG | (cpi << 3), 732296037Szbb (vnic << 24) | (padd << 16) | (rssi_base + rssi)); 733296037Szbb } else { 734296037Szbb /* Set MPI_ALG to '0' to disable MCAM parsing */ 735296037Szbb nic_reg_write(nic, NIC_PF_CPI_0_2047_CFG | (cpi << 3), 736296037Szbb (padd << 16)); 737296037Szbb /* MPI index is same as CPI if MPI_ALG is not enabled */ 738296037Szbb nic_reg_write(nic, NIC_PF_MPI_0_2047_CFG | (cpi << 3), 739296037Szbb (vnic << 24) | (rssi_base + rssi)); 740296037Szbb } 741289550Szbb 742289550Szbb if ((rssi + 1) >= cfg->rq_cnt) 743289550Szbb continue; 744289550Szbb 745289550Szbb if (cfg->cpi_alg == CPI_ALG_VLAN) 746289550Szbb rssi++; 747289550Szbb else if (cfg->cpi_alg == CPI_ALG_VLAN16) 748289550Szbb rssi = ((cpi - cpi_base) & 0xe) >> 1; 749289550Szbb else if (cfg->cpi_alg == CPI_ALG_DIFF) 750289550Szbb rssi = ((cpi - cpi_base) & 0x38) >> 3; 751289550Szbb } 752289550Szbb nic->cpi_base[cfg->vf_id] = cpi_base; 753289550Szbb} 754289550Szbb 755289551Szbb/* 756289551Szbb * 4 level transmit side scheduler configutation 757289550Szbb * for TNS bypass mode 758289550Szbb * 759289550Szbb * Sample configuration for SQ0 760289550Szbb * VNIC0-SQ0 -> TL4(0) -> TL3[0] -> TL2[0] -> TL1[0] -> BGX0 761289550Szbb * VNIC1-SQ0 -> TL4(8) -> TL3[2] -> TL2[0] -> TL1[0] -> BGX0 762289550Szbb * VNIC2-SQ0 -> TL4(16) -> TL3[4] -> TL2[1] -> TL1[0] -> BGX0 763289550Szbb * VNIC3-SQ0 -> TL4(24) -> TL3[6] -> TL2[1] -> TL1[0] -> BGX0 764289550Szbb * VNIC4-SQ0 -> TL4(512) -> TL3[128] -> TL2[32] -> TL1[1] -> BGX1 765289550Szbb * VNIC5-SQ0 -> TL4(520) -> TL3[130] -> TL2[32] -> TL1[1] -> BGX1 766289550Szbb * VNIC6-SQ0 -> TL4(528) -> TL3[132] -> TL2[33] -> TL1[1] -> BGX1 767289550Szbb * VNIC7-SQ0 -> TL4(536) -> TL3[134] -> TL2[33] -> TL1[1] -> BGX1 768289550Szbb */ 769289551Szbbstatic void 770289551Szbbnic_tx_channel_cfg(struct nicpf *nic, uint8_t vnic, struct sq_cfg_msg *sq) 771289550Szbb{ 772289551Szbb uint32_t bgx, lmac, chan; 773289551Szbb uint32_t tl2, tl3, tl4; 774289551Szbb uint32_t rr_quantum; 775289551Szbb uint8_t sq_idx = sq->sq_num; 776289551Szbb uint8_t pqs_vnic; 777289550Szbb 778289551Szbb pqs_vnic = vnic; 779289550Szbb 780289550Szbb bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[pqs_vnic]); 781289550Szbb lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[pqs_vnic]); 782289550Szbb 783289550Szbb /* 24 bytes for FCS, IPG and preamble */ 784289550Szbb rr_quantum = ((NIC_HW_MAX_FRS + 24) / 4); 785289550Szbb 786289550Szbb tl4 = (lmac * NIC_TL4_PER_LMAC) + (bgx * NIC_TL4_PER_BGX); 787289550Szbb tl4 += sq_idx; 788289550Szbb 789289550Szbb tl3 = tl4 / (NIC_MAX_TL4 / NIC_MAX_TL3); 790289550Szbb nic_reg_write(nic, NIC_PF_QSET_0_127_SQ_0_7_CFG2 | 791289551Szbb ((uint64_t)vnic << NIC_QS_ID_SHIFT) | 792289551Szbb ((uint32_t)sq_idx << NIC_Q_NUM_SHIFT), tl4); 793289550Szbb nic_reg_write(nic, NIC_PF_TL4_0_1023_CFG | (tl4 << 3), 794289551Szbb ((uint64_t)vnic << 27) | ((uint32_t)sq_idx << 24) | rr_quantum); 795289550Szbb 796289550Szbb nic_reg_write(nic, NIC_PF_TL3_0_255_CFG | (tl3 << 3), rr_quantum); 797289550Szbb chan = (lmac * MAX_BGX_CHANS_PER_LMAC) + (bgx * NIC_CHANS_PER_INF); 798289550Szbb nic_reg_write(nic, NIC_PF_TL3_0_255_CHAN | (tl3 << 3), chan); 799289550Szbb /* Enable backpressure on the channel */ 800289550Szbb nic_reg_write(nic, NIC_PF_CHAN_0_255_TX_CFG | (chan << 3), 1); 801289550Szbb 802289550Szbb tl2 = tl3 >> 2; 803289550Szbb nic_reg_write(nic, NIC_PF_TL3A_0_63_CFG | (tl2 << 3), tl2); 804289550Szbb nic_reg_write(nic, NIC_PF_TL2_0_63_CFG | (tl2 << 3), rr_quantum); 805289550Szbb /* No priorities as of now */ 806289550Szbb nic_reg_write(nic, NIC_PF_TL2_0_63_PRI | (tl2 << 3), 0x00); 807289550Szbb} 808289550Szbb 809289551Szbbstatic int 810289551Szbbnic_config_loopback(struct nicpf *nic, struct set_loopback *lbk) 811289550Szbb{ 812289550Szbb int bgx_idx, lmac_idx; 813289550Szbb 814289550Szbb if (lbk->vf_id > MAX_LMAC) 815289551Szbb return (ENXIO); 816289550Szbb 817289550Szbb bgx_idx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[lbk->vf_id]); 818289550Szbb lmac_idx = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[lbk->vf_id]); 819289550Szbb 820289550Szbb bgx_lmac_internal_loopback(nic->node, bgx_idx, lmac_idx, lbk->enable); 821289550Szbb 822289551Szbb return (0); 823289550Szbb} 824289550Szbb 825289550Szbb/* Interrupt handler to handle mailbox messages from VFs */ 826289551Szbbstatic void 827289551Szbbnic_handle_mbx_intr(struct nicpf *nic, int vf) 828289550Szbb{ 829289550Szbb union nic_mbx mbx = {}; 830289551Szbb uint64_t *mbx_data; 831289551Szbb uint64_t mbx_addr; 832289551Szbb uint64_t reg_addr; 833289551Szbb uint64_t cfg; 834289550Szbb int bgx, lmac; 835289550Szbb int i; 836289550Szbb int ret = 0; 837289550Szbb 838289551Szbb nic->mbx_lock[vf] = TRUE; 839289550Szbb 840289550Szbb mbx_addr = nic_get_mbx_addr(vf); 841289551Szbb mbx_data = (uint64_t *)&mbx; 842289550Szbb 843289550Szbb for (i = 0; i < NIC_PF_VF_MAILBOX_SIZE; i++) { 844289550Szbb *mbx_data = nic_reg_read(nic, mbx_addr); 845289550Szbb mbx_data++; 846289551Szbb mbx_addr += sizeof(uint64_t); 847289550Szbb } 848289550Szbb 849289550Szbb switch (mbx.msg.msg) { 850289550Szbb case NIC_MBOX_MSG_READY: 851289550Szbb nic_mbx_send_ready(nic, vf); 852289550Szbb if (vf < MAX_LMAC) { 853289550Szbb nic->link[vf] = 0; 854289550Szbb nic->duplex[vf] = 0; 855289550Szbb nic->speed[vf] = 0; 856289550Szbb } 857289550Szbb ret = 1; 858289550Szbb break; 859289550Szbb case NIC_MBOX_MSG_QS_CFG: 860289550Szbb reg_addr = NIC_PF_QSET_0_127_CFG | 861289551Szbb (mbx.qs.num << NIC_QS_ID_SHIFT); 862289550Szbb cfg = mbx.qs.cfg; 863289550Szbb nic_reg_write(nic, reg_addr, cfg); 864289550Szbb break; 865289550Szbb case NIC_MBOX_MSG_RQ_CFG: 866289550Szbb reg_addr = NIC_PF_QSET_0_127_RQ_0_7_CFG | 867289551Szbb (mbx.rq.qs_num << NIC_QS_ID_SHIFT) | 868289551Szbb (mbx.rq.rq_num << NIC_Q_NUM_SHIFT); 869289550Szbb nic_reg_write(nic, reg_addr, mbx.rq.cfg); 870289550Szbb break; 871289550Szbb case NIC_MBOX_MSG_RQ_BP_CFG: 872289550Szbb reg_addr = NIC_PF_QSET_0_127_RQ_0_7_BP_CFG | 873289551Szbb (mbx.rq.qs_num << NIC_QS_ID_SHIFT) | 874289551Szbb (mbx.rq.rq_num << NIC_Q_NUM_SHIFT); 875289550Szbb nic_reg_write(nic, reg_addr, mbx.rq.cfg); 876289550Szbb break; 877289550Szbb case NIC_MBOX_MSG_RQ_SW_SYNC: 878289550Szbb ret = nic_rcv_queue_sw_sync(nic); 879289550Szbb break; 880289550Szbb case NIC_MBOX_MSG_RQ_DROP_CFG: 881289550Szbb reg_addr = NIC_PF_QSET_0_127_RQ_0_7_DROP_CFG | 882289551Szbb (mbx.rq.qs_num << NIC_QS_ID_SHIFT) | 883289551Szbb (mbx.rq.rq_num << NIC_Q_NUM_SHIFT); 884289550Szbb nic_reg_write(nic, reg_addr, mbx.rq.cfg); 885289550Szbb break; 886289550Szbb case NIC_MBOX_MSG_SQ_CFG: 887289550Szbb reg_addr = NIC_PF_QSET_0_127_SQ_0_7_CFG | 888289551Szbb (mbx.sq.qs_num << NIC_QS_ID_SHIFT) | 889289551Szbb (mbx.sq.sq_num << NIC_Q_NUM_SHIFT); 890289550Szbb nic_reg_write(nic, reg_addr, mbx.sq.cfg); 891289550Szbb nic_tx_channel_cfg(nic, mbx.qs.num, &mbx.sq); 892289550Szbb break; 893289550Szbb case NIC_MBOX_MSG_SET_MAC: 894289550Szbb lmac = mbx.mac.vf_id; 895289550Szbb bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[lmac]); 896289550Szbb lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[lmac]); 897289550Szbb bgx_set_lmac_mac(nic->node, bgx, lmac, mbx.mac.mac_addr); 898289550Szbb break; 899289550Szbb case NIC_MBOX_MSG_SET_MAX_FRS: 900289551Szbb ret = nic_update_hw_frs(nic, mbx.frs.max_frs, mbx.frs.vf_id); 901289550Szbb break; 902289550Szbb case NIC_MBOX_MSG_CPI_CFG: 903289550Szbb nic_config_cpi(nic, &mbx.cpi_cfg); 904289550Szbb break; 905289550Szbb case NIC_MBOX_MSG_CFG_DONE: 906289550Szbb /* Last message of VF config msg sequence */ 907289551Szbb nic->vf_info[vf].vf_enabled = TRUE; 908289550Szbb goto unlock; 909289550Szbb case NIC_MBOX_MSG_SHUTDOWN: 910289550Szbb /* First msg in VF teardown sequence */ 911289551Szbb nic->vf_info[vf].vf_enabled = FALSE; 912289550Szbb break; 913289550Szbb case NIC_MBOX_MSG_BGX_STATS: 914289550Szbb nic_get_bgx_stats(nic, &mbx.bgx_stats); 915289550Szbb goto unlock; 916289550Szbb case NIC_MBOX_MSG_LOOPBACK: 917289550Szbb ret = nic_config_loopback(nic, &mbx.lbk); 918289550Szbb break; 919289550Szbb default: 920289551Szbb device_printf(nic->dev, 921289551Szbb "Invalid msg from VF%d, msg 0x%x\n", vf, mbx.msg.msg); 922289550Szbb break; 923289550Szbb } 924289550Szbb 925289551Szbb if (ret == 0) 926289550Szbb nic_mbx_send_ack(nic, vf); 927289550Szbb else if (mbx.msg.msg != NIC_MBOX_MSG_READY) 928289550Szbb nic_mbx_send_nack(nic, vf); 929289550Szbbunlock: 930289551Szbb nic->mbx_lock[vf] = FALSE; 931289550Szbb} 932289550Szbb 933289551Szbbstatic void 934289551Szbbnic_mbx_intr_handler(struct nicpf *nic, int mbx) 935289550Szbb{ 936289551Szbb uint64_t intr; 937289551Szbb uint8_t vf, vf_per_mbx_reg = 64; 938289550Szbb 939289550Szbb intr = nic_reg_read(nic, NIC_PF_MAILBOX_INT + (mbx << 3)); 940289550Szbb for (vf = 0; vf < vf_per_mbx_reg; vf++) { 941289551Szbb if (intr & (1UL << vf)) { 942289550Szbb nic_handle_mbx_intr(nic, vf + (mbx * vf_per_mbx_reg)); 943289550Szbb nic_clear_mbx_intr(nic, vf, mbx); 944289550Szbb } 945289550Szbb } 946289550Szbb} 947289550Szbb 948289551Szbbstatic void 949289551Szbbnic_mbx0_intr_handler (void *arg) 950289550Szbb{ 951289551Szbb struct nicpf *nic = (struct nicpf *)arg; 952289550Szbb 953289550Szbb nic_mbx_intr_handler(nic, 0); 954289550Szbb} 955289550Szbb 956289551Szbbstatic void 957289551Szbbnic_mbx1_intr_handler (void *arg) 958289550Szbb{ 959289551Szbb struct nicpf *nic = (struct nicpf *)arg; 960289550Szbb 961289550Szbb nic_mbx_intr_handler(nic, 1); 962289550Szbb} 963289550Szbb 964289551Szbbstatic int 965289551Szbbnic_enable_msix(struct nicpf *nic) 966289550Szbb{ 967289551Szbb struct pci_devinfo *dinfo; 968289551Szbb int rid, count; 969289551Szbb int ret; 970289550Szbb 971289551Szbb dinfo = device_get_ivars(nic->dev); 972289551Szbb rid = dinfo->cfg.msix.msix_table_bar; 973289551Szbb nic->msix_table_res = 974289551Szbb bus_alloc_resource_any(nic->dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); 975289551Szbb if (nic->msix_table_res == NULL) { 976289551Szbb device_printf(nic->dev, 977289551Szbb "Could not allocate memory for MSI-X table\n"); 978289551Szbb return (ENXIO); 979289551Szbb } 980289550Szbb 981289551Szbb count = nic->num_vec = NIC_PF_MSIX_VECTORS; 982289550Szbb 983289551Szbb ret = pci_alloc_msix(nic->dev, &count); 984289551Szbb if ((ret != 0) || (count != nic->num_vec)) { 985289551Szbb device_printf(nic->dev, 986289551Szbb "Request for #%d msix vectors failed, error: %d\n", 987289551Szbb nic->num_vec, ret); 988289551Szbb return (ret); 989289550Szbb } 990289550Szbb 991289550Szbb nic->msix_enabled = 1; 992289551Szbb return (0); 993289550Szbb} 994289550Szbb 995289551Szbbstatic void 996289551Szbbnic_disable_msix(struct nicpf *nic) 997289550Szbb{ 998289550Szbb if (nic->msix_enabled) { 999289551Szbb pci_release_msi(nic->dev); 1000289550Szbb nic->msix_enabled = 0; 1001289550Szbb nic->num_vec = 0; 1002289550Szbb } 1003289550Szbb} 1004289550Szbb 1005289551Szbbstatic void 1006289551Szbbnic_free_all_interrupts(struct nicpf *nic) 1007289550Szbb{ 1008289550Szbb int irq; 1009289550Szbb 1010289550Szbb for (irq = 0; irq < nic->num_vec; irq++) { 1011289551Szbb if (nic->msix_entries[irq].irq_res == NULL) 1012289551Szbb continue; 1013289551Szbb if (nic->msix_entries[irq].handle != NULL) { 1014289551Szbb bus_teardown_intr(nic->dev, 1015289551Szbb nic->msix_entries[irq].irq_res, 1016289551Szbb nic->msix_entries[irq].handle); 1017289551Szbb } 1018289551Szbb 1019289551Szbb bus_release_resource(nic->dev, SYS_RES_IRQ, irq, 1020289551Szbb nic->msix_entries[irq].irq_res); 1021289550Szbb } 1022289550Szbb} 1023289550Szbb 1024289551Szbbstatic int 1025289551Szbbnic_register_interrupts(struct nicpf *nic) 1026289550Szbb{ 1027289551Szbb int irq, rid; 1028289550Szbb int ret; 1029289550Szbb 1030289550Szbb /* Enable MSI-X */ 1031289550Szbb ret = nic_enable_msix(nic); 1032289551Szbb if (ret != 0) 1033289551Szbb return (ret); 1034289550Szbb 1035289550Szbb /* Register mailbox interrupt handlers */ 1036289551Szbb irq = NIC_PF_INTR_ID_MBOX0; 1037289551Szbb rid = irq + 1; 1038289551Szbb nic->msix_entries[irq].irq_res = bus_alloc_resource_any(nic->dev, 1039289551Szbb SYS_RES_IRQ, &rid, (RF_SHAREABLE | RF_ACTIVE)); 1040289551Szbb if (nic->msix_entries[irq].irq_res == NULL) { 1041289551Szbb ret = ENXIO; 1042289550Szbb goto fail; 1043289551Szbb } 1044289551Szbb ret = bus_setup_intr(nic->dev, nic->msix_entries[irq].irq_res, 1045289551Szbb (INTR_MPSAFE | INTR_TYPE_MISC), NULL, nic_mbx0_intr_handler, nic, 1046289551Szbb &nic->msix_entries[irq].handle); 1047289551Szbb if (ret != 0) 1048289551Szbb goto fail; 1049289550Szbb 1050289551Szbb irq = NIC_PF_INTR_ID_MBOX1; 1051289551Szbb rid = irq + 1; 1052289551Szbb nic->msix_entries[irq].irq_res = bus_alloc_resource_any(nic->dev, 1053289551Szbb SYS_RES_IRQ, &rid, (RF_SHAREABLE | RF_ACTIVE)); 1054289551Szbb if (nic->msix_entries[irq].irq_res == NULL) { 1055289551Szbb ret = ENXIO; 1056289550Szbb goto fail; 1057289551Szbb } 1058289551Szbb ret = bus_setup_intr(nic->dev, nic->msix_entries[irq].irq_res, 1059289551Szbb (INTR_MPSAFE | INTR_TYPE_MISC), NULL, nic_mbx1_intr_handler, nic, 1060289551Szbb &nic->msix_entries[irq].handle); 1061289551Szbb if (ret != 0) 1062289551Szbb goto fail; 1063289550Szbb 1064289550Szbb /* Enable mailbox interrupt */ 1065289550Szbb nic_enable_mbx_intr(nic); 1066289551Szbb return (0); 1067289550Szbb 1068289550Szbbfail: 1069289550Szbb nic_free_all_interrupts(nic); 1070289551Szbb return (ret); 1071289550Szbb} 1072289550Szbb 1073289551Szbbstatic void 1074289551Szbbnic_unregister_interrupts(struct nicpf *nic) 1075289550Szbb{ 1076289551Szbb 1077289550Szbb nic_free_all_interrupts(nic); 1078289550Szbb nic_disable_msix(nic); 1079289550Szbb} 1080289550Szbb 1081289551Szbbstatic int nic_sriov_init(device_t dev, struct nicpf *nic) 1082289550Szbb{ 1083289551Szbb#ifdef PCI_IOV 1084289551Szbb nvlist_t *pf_schema, *vf_schema; 1085289551Szbb int iov_pos; 1086289550Szbb int err; 1087289551Szbb uint16_t total_vf_cnt; 1088289550Szbb 1089289551Szbb err = pci_find_extcap(dev, PCIZ_SRIOV, &iov_pos); 1090289551Szbb if (err != 0) { 1091289551Szbb device_printf(dev, 1092289551Szbb "SR-IOV capability is not found in PCIe config space\n"); 1093289551Szbb return (err); 1094289550Szbb } 1095289551Szbb /* Fix-up the number of enabled VFs */ 1096289551Szbb total_vf_cnt = pci_read_config(dev, iov_pos + PCIR_SRIOV_TOTAL_VFS, 2); 1097289550Szbb if (total_vf_cnt < nic->num_vf_en) 1098289550Szbb nic->num_vf_en = total_vf_cnt; 1099289550Szbb 1100289551Szbb if (total_vf_cnt == 0) 1101289551Szbb return (0); 1102289550Szbb 1103289551Szbb /* Attach SR-IOV */ 1104289551Szbb pf_schema = pci_iov_schema_alloc_node(); 1105289551Szbb vf_schema = pci_iov_schema_alloc_node(); 1106289551Szbb pci_iov_schema_add_unicast_mac(vf_schema, "mac-addr", 0, NULL); 1107289551Szbb /* 1108289551Szbb * All VFs can change their MACs. 1109289551Szbb * This flag will be ignored but we set it just for the record. 1110289551Szbb */ 1111289551Szbb pci_iov_schema_add_bool(vf_schema, "allow-set-mac", 1112289551Szbb IOV_SCHEMA_HASDEFAULT, TRUE); 1113289550Szbb 1114289551Szbb err = pci_iov_attach(dev, pf_schema, vf_schema); 1115289551Szbb if (err != 0) { 1116289551Szbb device_printf(dev, 1117289551Szbb "Failed to initialize SR-IOV (error=%d)\n", 1118289551Szbb err); 1119289550Szbb nic->num_vf_en = 0; 1120289551Szbb return (err); 1121289550Szbb } 1122289551Szbb#endif 1123289551Szbb return (0); 1124289550Szbb} 1125289550Szbb 1126289551Szbb/* 1127289551Szbb * Poll for BGX LMAC link status and update corresponding VF 1128289550Szbb * if there is a change, valid only if internal L2 switch 1129289550Szbb * is not present otherwise VF link is always treated as up 1130289550Szbb */ 1131289551Szbbstatic void 1132289551Szbbnic_poll_for_link(void *arg) 1133289550Szbb{ 1134289550Szbb union nic_mbx mbx = {}; 1135289550Szbb struct nicpf *nic; 1136289550Szbb struct bgx_link_status link; 1137289551Szbb uint8_t vf, bgx, lmac; 1138289550Szbb 1139289551Szbb nic = (struct nicpf *)arg; 1140289550Szbb 1141289550Szbb mbx.link_status.msg = NIC_MBOX_MSG_BGX_LINK_CHANGE; 1142289550Szbb 1143289550Szbb for (vf = 0; vf < nic->num_vf_en; vf++) { 1144289550Szbb /* Poll only if VF is UP */ 1145289551Szbb if (!nic->vf_info[vf].vf_enabled) 1146289550Szbb continue; 1147289550Szbb 1148289550Szbb /* Get BGX, LMAC indices for the VF */ 1149289550Szbb bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); 1150289550Szbb lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); 1151289550Szbb /* Get interface link status */ 1152289550Szbb bgx_get_lmac_link_state(nic->node, bgx, lmac, &link); 1153289550Szbb 1154289550Szbb /* Inform VF only if link status changed */ 1155289550Szbb if (nic->link[vf] == link.link_up) 1156289550Szbb continue; 1157289550Szbb 1158289550Szbb if (!nic->mbx_lock[vf]) { 1159289550Szbb nic->link[vf] = link.link_up; 1160289550Szbb nic->duplex[vf] = link.duplex; 1161289550Szbb nic->speed[vf] = link.speed; 1162289550Szbb 1163289550Szbb /* Send a mbox message to VF with current link status */ 1164289550Szbb mbx.link_status.link_up = link.link_up; 1165289550Szbb mbx.link_status.duplex = link.duplex; 1166289550Szbb mbx.link_status.speed = link.speed; 1167289550Szbb nic_send_msg_to_vf(nic, vf, &mbx); 1168289550Szbb } 1169289550Szbb } 1170289551Szbb callout_reset(&nic->check_link, hz * 2, nic_poll_for_link, nic); 1171289550Szbb} 1172