1233545Sjchandra/*- 2233545Sjchandra * Copyright (c) 2003-2012 Broadcom Corporation 3233545Sjchandra * All Rights Reserved 4233545Sjchandra * 5233545Sjchandra * Redistribution and use in source and binary forms, with or without 6233545Sjchandra * modification, are permitted provided that the following conditions 7233545Sjchandra * are met: 8233545Sjchandra * 9233545Sjchandra * 1. Redistributions of source code must retain the above copyright 10233545Sjchandra * notice, this list of conditions and the following disclaimer. 11233545Sjchandra * 2. Redistributions in binary form must reproduce the above copyright 12233545Sjchandra * notice, this list of conditions and the following disclaimer in 13233545Sjchandra * the documentation and/or other materials provided with the 14233545Sjchandra * distribution. 15233545Sjchandra * 16233545Sjchandra * THIS SOFTWARE IS PROVIDED BY BROADCOM ``AS IS'' AND ANY EXPRESS OR 17233545Sjchandra * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18233545Sjchandra * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19233545Sjchandra * ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM OR CONTRIBUTORS BE LIABLE 20233545Sjchandra * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21233545Sjchandra * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22233545Sjchandra * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 23233545Sjchandra * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 24233545Sjchandra * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 25233545Sjchandra * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 26233545Sjchandra * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27233545Sjchandra */ 28233545Sjchandra 29233545Sjchandra#include <sys/cdefs.h> 30233545Sjchandra__FBSDID("$FreeBSD: stable/10/sys/mips/nlm/dev/net/xlpge.c 314667 2017-03-04 13:03:31Z avg $"); 31233545Sjchandra#include <sys/endian.h> 32233545Sjchandra#include <sys/systm.h> 33233545Sjchandra#include <sys/sockio.h> 34233545Sjchandra#include <sys/param.h> 35233545Sjchandra#include <sys/lock.h> 36233545Sjchandra#include <sys/mutex.h> 37233545Sjchandra#include <sys/proc.h> 38233545Sjchandra#include <sys/limits.h> 39233545Sjchandra#include <sys/bus.h> 40233545Sjchandra#include <sys/mbuf.h> 41233545Sjchandra#include <sys/malloc.h> 42233545Sjchandra#include <sys/kernel.h> 43233545Sjchandra#include <sys/module.h> 44233545Sjchandra#include <sys/socket.h> 45233545Sjchandra#define __RMAN_RESOURCE_VISIBLE 46233545Sjchandra#include <sys/rman.h> 47233545Sjchandra#include <sys/taskqueue.h> 48233545Sjchandra 49233545Sjchandra#include <net/if.h> 50233545Sjchandra#include <net/if_arp.h> 51233545Sjchandra#include <net/ethernet.h> 52233545Sjchandra#include <net/if_dl.h> 53233545Sjchandra#include <net/if_media.h> 54233545Sjchandra#include <net/bpf.h> 55233545Sjchandra#include <net/if_types.h> 56233545Sjchandra#include <net/if_vlan_var.h> 57233545Sjchandra 58233545Sjchandra#include <dev/pci/pcivar.h> 59233545Sjchandra 60233545Sjchandra#include <netinet/in_systm.h> 61233545Sjchandra#include <netinet/in.h> 62233545Sjchandra#include <netinet/ip.h> 63233545Sjchandra 64233545Sjchandra#include <vm/vm.h> 65233545Sjchandra#include <vm/pmap.h> 66233545Sjchandra#include <vm/uma.h> 67233545Sjchandra 68233545Sjchandra#include <machine/reg.h> 69233545Sjchandra#include <machine/cpu.h> 70233545Sjchandra#include <machine/mips_opcode.h> 71233545Sjchandra#include <machine/asm.h> 72233545Sjchandra#include <machine/cpuregs.h> 73233545Sjchandra 74233545Sjchandra#include <machine/param.h> 75233545Sjchandra#include <machine/intr_machdep.h> 76233545Sjchandra#include <machine/clock.h> /* for DELAY */ 77233545Sjchandra#include <machine/bus.h> 78233545Sjchandra#include <machine/resource.h> 79233545Sjchandra#include <mips/nlm/hal/haldefs.h> 80233545Sjchandra#include <mips/nlm/hal/iomap.h> 81233545Sjchandra#include <mips/nlm/hal/mips-extns.h> 82233545Sjchandra#include <mips/nlm/hal/cop2.h> 83233545Sjchandra#include <mips/nlm/hal/fmn.h> 84233545Sjchandra#include <mips/nlm/hal/sys.h> 85233545Sjchandra#include <mips/nlm/hal/nae.h> 86233545Sjchandra#include <mips/nlm/hal/mdio.h> 87233545Sjchandra#include <mips/nlm/hal/sgmii.h> 88233545Sjchandra#include <mips/nlm/hal/xaui.h> 89233545Sjchandra#include <mips/nlm/hal/poe.h> 90233545Sjchandra#include <ucore_app_bin.h> 91233545Sjchandra#include <mips/nlm/hal/ucore_loader.h> 92233545Sjchandra#include <mips/nlm/xlp.h> 93233545Sjchandra#include <mips/nlm/board.h> 94233545Sjchandra#include <mips/nlm/msgring.h> 95233545Sjchandra 96233545Sjchandra#include <dev/mii/mii.h> 97233545Sjchandra#include <dev/mii/miivar.h> 98233545Sjchandra#include "miidevs.h" 99233545Sjchandra#include <dev/mii/brgphyreg.h> 100233545Sjchandra#include "miibus_if.h" 101233545Sjchandra#include <sys/sysctl.h> 102233545Sjchandra 103233545Sjchandra#include <mips/nlm/dev/net/xlpge.h> 104233545Sjchandra 105233545Sjchandra/*#define XLP_DRIVER_LOOPBACK*/ 106233545Sjchandra 107233545Sjchandrastatic struct nae_port_config nae_port_config[64]; 108233545Sjchandra 109233545Sjchandraint poe_cl_tbl[MAX_POE_CLASSES] = { 110233545Sjchandra 0x0, 0x249249, 111233545Sjchandra 0x492492, 0x6db6db, 112233545Sjchandra 0x924924, 0xb6db6d, 113233545Sjchandra 0xdb6db6, 0xffffff 114233545Sjchandra}; 115233545Sjchandra 116233545Sjchandra/* #define DUMP_PACKET */ 117233545Sjchandra 118233545Sjchandrastatic uint64_t 119233545Sjchandranlm_paddr_ld(uint64_t paddr) 120233545Sjchandra{ 121233545Sjchandra uint64_t xkaddr = 0x9800000000000000 | paddr; 122233545Sjchandra 123233545Sjchandra return (nlm_load_dword_daddr(xkaddr)); 124233545Sjchandra} 125233545Sjchandra 126233545Sjchandrastruct nlm_xlp_portdata ifp_ports[64]; 127233545Sjchandrastatic uma_zone_t nl_tx_desc_zone; 128233545Sjchandra 129233545Sjchandra/* This implementation will register the following tree of device 130233545Sjchandra * registration: 131233545Sjchandra * pcibus 132233545Sjchandra * | 133233545Sjchandra * xlpnae (1 instance - virtual entity) 134233545Sjchandra * | 135233545Sjchandra * xlpge 136233545Sjchandra * (18 sgmii / 4 xaui / 2 interlaken instances) 137233545Sjchandra * | 138233545Sjchandra * miibus 139233545Sjchandra */ 140233545Sjchandra 141233545Sjchandrastatic int nlm_xlpnae_probe(device_t); 142233545Sjchandrastatic int nlm_xlpnae_attach(device_t); 143233545Sjchandrastatic int nlm_xlpnae_detach(device_t); 144233545Sjchandrastatic int nlm_xlpnae_suspend(device_t); 145233545Sjchandrastatic int nlm_xlpnae_resume(device_t); 146233545Sjchandrastatic int nlm_xlpnae_shutdown(device_t); 147233545Sjchandra 148233545Sjchandrastatic device_method_t nlm_xlpnae_methods[] = { 149233545Sjchandra /* Methods from the device interface */ 150233545Sjchandra DEVMETHOD(device_probe, nlm_xlpnae_probe), 151233545Sjchandra DEVMETHOD(device_attach, nlm_xlpnae_attach), 152233545Sjchandra DEVMETHOD(device_detach, nlm_xlpnae_detach), 153233545Sjchandra DEVMETHOD(device_suspend, nlm_xlpnae_suspend), 154233545Sjchandra DEVMETHOD(device_resume, nlm_xlpnae_resume), 155233545Sjchandra DEVMETHOD(device_shutdown, nlm_xlpnae_shutdown), 156233545Sjchandra 157233545Sjchandra DEVMETHOD(bus_driver_added, bus_generic_driver_added), 158233545Sjchandra 159233545Sjchandra DEVMETHOD_END 160233545Sjchandra}; 161233545Sjchandra 162233545Sjchandrastatic driver_t nlm_xlpnae_driver = { 163233545Sjchandra "xlpnae", 164233545Sjchandra nlm_xlpnae_methods, 165233545Sjchandra sizeof(struct nlm_xlpnae_softc) 166233545Sjchandra}; 167233545Sjchandra 168233545Sjchandrastatic devclass_t nlm_xlpnae_devclass; 169233545Sjchandra 170233545Sjchandrastatic int nlm_xlpge_probe(device_t); 171233545Sjchandrastatic int nlm_xlpge_attach(device_t); 172233545Sjchandrastatic int nlm_xlpge_detach(device_t); 173233545Sjchandrastatic int nlm_xlpge_suspend(device_t); 174233545Sjchandrastatic int nlm_xlpge_resume(device_t); 175233545Sjchandrastatic int nlm_xlpge_shutdown(device_t); 176233545Sjchandra 177233545Sjchandra/* mii override functions */ 178233545Sjchandrastatic int nlm_xlpge_mii_read(struct device *, int, int); 179233545Sjchandrastatic int nlm_xlpge_mii_write(struct device *, int, int, int); 180233545Sjchandrastatic void nlm_xlpge_mii_statchg(device_t); 181233545Sjchandra 182233545Sjchandrastatic device_method_t nlm_xlpge_methods[] = { 183233545Sjchandra /* Methods from the device interface */ 184233545Sjchandra DEVMETHOD(device_probe, nlm_xlpge_probe), 185233545Sjchandra DEVMETHOD(device_attach, nlm_xlpge_attach), 186233545Sjchandra DEVMETHOD(device_detach, nlm_xlpge_detach), 187233545Sjchandra DEVMETHOD(device_suspend, nlm_xlpge_suspend), 188233545Sjchandra DEVMETHOD(device_resume, nlm_xlpge_resume), 189233545Sjchandra DEVMETHOD(device_shutdown, nlm_xlpge_shutdown), 190233545Sjchandra 191233545Sjchandra /* Methods from the nexus bus needed for explicitly 192233545Sjchandra * probing children when driver is loaded as a kernel module 193233545Sjchandra */ 194233545Sjchandra DEVMETHOD(miibus_readreg, nlm_xlpge_mii_read), 195233545Sjchandra DEVMETHOD(miibus_writereg, nlm_xlpge_mii_write), 196233545Sjchandra DEVMETHOD(miibus_statchg, nlm_xlpge_mii_statchg), 197233545Sjchandra 198233545Sjchandra /* Terminate method list */ 199233545Sjchandra DEVMETHOD_END 200233545Sjchandra}; 201233545Sjchandra 202233545Sjchandrastatic driver_t nlm_xlpge_driver = { 203233545Sjchandra "xlpge", 204233545Sjchandra nlm_xlpge_methods, 205233545Sjchandra sizeof(struct nlm_xlpge_softc) 206233545Sjchandra}; 207233545Sjchandra 208233545Sjchandrastatic devclass_t nlm_xlpge_devclass; 209233545Sjchandra 210233545SjchandraDRIVER_MODULE(xlpnae, pci, nlm_xlpnae_driver, nlm_xlpnae_devclass, 0, 0); 211233545SjchandraDRIVER_MODULE(xlpge, xlpnae, nlm_xlpge_driver, nlm_xlpge_devclass, 0, 0); 212233545SjchandraDRIVER_MODULE(miibus, xlpge, miibus_driver, miibus_devclass, 0, 0); 213233545Sjchandra 214233545SjchandraMODULE_DEPEND(pci, xlpnae, 1, 1, 1); 215233545SjchandraMODULE_DEPEND(xlpnae, xlpge, 1, 1, 1); 216233545SjchandraMODULE_DEPEND(xlpge, ether, 1, 1, 1); 217233545SjchandraMODULE_DEPEND(xlpge, miibus, 1, 1, 1); 218233545Sjchandra 219233545Sjchandra#define SGMII_RCV_CONTEXT_WIDTH 8 220233545Sjchandra 221233545Sjchandra/* prototypes */ 222233545Sjchandrastatic void nlm_xlpge_msgring_handler(int vc, int size, 223233545Sjchandra int code, int srcid, struct nlm_fmn_msg *msg, void *data); 224233545Sjchandrastatic void nlm_xlpge_submit_rx_free_desc(struct nlm_xlpge_softc *sc, int num); 225233545Sjchandrastatic void nlm_xlpge_init(void *addr); 226233545Sjchandrastatic void nlm_xlpge_port_disable(struct nlm_xlpge_softc *sc); 227233545Sjchandrastatic void nlm_xlpge_port_enable(struct nlm_xlpge_softc *sc); 228233545Sjchandra 229233545Sjchandra/* globals */ 230233545Sjchandraint dbg_on = 1; 231233545Sjchandraint cntx2port[524]; 232233545Sjchandra 233233545Sjchandrastatic __inline void 234233545Sjchandraatomic_incr_long(unsigned long *addr) 235233545Sjchandra{ 236233545Sjchandra atomic_add_long(addr, 1); 237233545Sjchandra} 238233545Sjchandra 239233545Sjchandra/* 240233545Sjchandra * xlpnae driver implementation 241233545Sjchandra */ 242233545Sjchandrastatic int 243233545Sjchandranlm_xlpnae_probe(device_t dev) 244233545Sjchandra{ 245233545Sjchandra if (pci_get_vendor(dev) != PCI_VENDOR_NETLOGIC || 246233545Sjchandra pci_get_device(dev) != PCI_DEVICE_ID_NLM_NAE) 247233545Sjchandra return (ENXIO); 248233545Sjchandra 249233545Sjchandra return (BUS_PROBE_DEFAULT); 250233545Sjchandra} 251233545Sjchandra 252233545Sjchandrastatic void 253233545Sjchandranlm_xlpnae_print_frin_desc_carving(struct nlm_xlpnae_softc *sc) 254233545Sjchandra{ 255233545Sjchandra int intf; 256233545Sjchandra uint32_t value; 257233545Sjchandra int start, size; 258233545Sjchandra 259233545Sjchandra /* XXXJC: use max_ports instead of 20 ? */ 260233545Sjchandra for (intf = 0; intf < 20; intf++) { 261233545Sjchandra nlm_write_nae_reg(sc->base, NAE_FREE_IN_FIFO_CFG, 262233545Sjchandra (0x80000000 | intf)); 263233545Sjchandra value = nlm_read_nae_reg(sc->base, NAE_FREE_IN_FIFO_CFG); 264233545Sjchandra size = 2 * ((value >> 20) & 0x3ff); 265233545Sjchandra start = 2 * ((value >> 8) & 0x1ff); 266233545Sjchandra } 267233545Sjchandra} 268233545Sjchandra 269233545Sjchandrastatic void 270233545Sjchandranlm_config_egress(struct nlm_xlpnae_softc *sc, int nblock, 271233545Sjchandra int context_base, int hwport, int max_channels) 272233545Sjchandra{ 273233545Sjchandra int offset, num_channels; 274233545Sjchandra uint32_t data; 275233545Sjchandra 276233545Sjchandra num_channels = sc->portcfg[hwport].num_channels; 277233545Sjchandra 278233545Sjchandra data = (2048 << 12) | (hwport << 4) | 1; 279233545Sjchandra nlm_write_nae_reg(sc->base, NAE_TX_IF_BURSTMAX_CMD, data); 280233545Sjchandra 281233545Sjchandra data = ((context_base + num_channels - 1) << 22) | 282233545Sjchandra (context_base << 12) | (hwport << 4) | 1; 283233545Sjchandra nlm_write_nae_reg(sc->base, NAE_TX_DDR_ACTVLIST_CMD, data); 284233545Sjchandra 285233545Sjchandra config_egress_fifo_carvings(sc->base, hwport, 286233545Sjchandra context_base, num_channels, max_channels, sc->portcfg); 287233545Sjchandra config_egress_fifo_credits(sc->base, hwport, 288233545Sjchandra context_base, num_channels, max_channels, sc->portcfg); 289233545Sjchandra 290233545Sjchandra data = nlm_read_nae_reg(sc->base, NAE_DMA_TX_CREDIT_TH); 291233545Sjchandra data |= (1 << 25) | (1 << 24); 292233545Sjchandra nlm_write_nae_reg(sc->base, NAE_DMA_TX_CREDIT_TH, data); 293233545Sjchandra 294233545Sjchandra for (offset = 0; offset < num_channels; offset++) { 295233545Sjchandra nlm_write_nae_reg(sc->base, NAE_TX_SCHED_MAP_CMD1, 296233545Sjchandra NAE_DRR_QUANTA); 297233545Sjchandra data = (hwport << 15) | ((context_base + offset) << 5); 298233545Sjchandra if (sc->cmplx_type[nblock] == ILC) 299233545Sjchandra data |= (offset << 20); 300233545Sjchandra nlm_write_nae_reg(sc->base, NAE_TX_SCHED_MAP_CMD0, data | 1); 301233545Sjchandra nlm_write_nae_reg(sc->base, NAE_TX_SCHED_MAP_CMD0, data); 302233545Sjchandra } 303233545Sjchandra} 304233545Sjchandra 305233545Sjchandrastatic int 306233545Sjchandraxlpnae_get_maxchannels(struct nlm_xlpnae_softc *sc) 307233545Sjchandra{ 308233545Sjchandra int maxchans = 0; 309255368Sjchandra int i; 310233545Sjchandra 311255368Sjchandra for (i = 0; i < sc->max_ports; i++) { 312255368Sjchandra if (sc->portcfg[i].type == UNKNOWN) 313255368Sjchandra continue; 314255368Sjchandra maxchans += sc->portcfg[i].num_channels; 315233545Sjchandra } 316233545Sjchandra 317233545Sjchandra return (maxchans); 318233545Sjchandra} 319233545Sjchandra 320233545Sjchandrastatic void 321233545Sjchandranlm_setup_interface(struct nlm_xlpnae_softc *sc, int nblock, 322233545Sjchandra int port, uint32_t cur_flow_base, uint32_t flow_mask, 323233545Sjchandra int max_channels, int context) 324233545Sjchandra{ 325233545Sjchandra uint64_t nae_base = sc->base; 326233545Sjchandra int mtu = 1536; /* XXXJC: don't hard code */ 327233545Sjchandra uint32_t ucore_mask; 328233545Sjchandra 329233545Sjchandra if (sc->cmplx_type[nblock] == XAUIC) 330233545Sjchandra nlm_config_xaui(nae_base, nblock, mtu, 331233545Sjchandra mtu, sc->portcfg[port].vlan_pri_en); 332233545Sjchandra nlm_config_freein_fifo_uniq_cfg(nae_base, 333233545Sjchandra port, sc->portcfg[port].free_desc_sizes); 334233545Sjchandra nlm_config_ucore_iface_mask_cfg(nae_base, 335233545Sjchandra port, sc->portcfg[port].ucore_mask); 336233545Sjchandra 337233545Sjchandra nlm_program_flow_cfg(nae_base, port, cur_flow_base, flow_mask); 338233545Sjchandra 339233545Sjchandra if (sc->cmplx_type[nblock] == SGMIIC) 340233545Sjchandra nlm_configure_sgmii_interface(nae_base, nblock, port, mtu, 0); 341233545Sjchandra 342233545Sjchandra nlm_config_egress(sc, nblock, context, port, max_channels); 343233545Sjchandra 344233545Sjchandra nlm_nae_init_netior(nae_base, sc->nblocks); 345233545Sjchandra nlm_nae_open_if(nae_base, nblock, sc->cmplx_type[nblock], port, 346233545Sjchandra sc->portcfg[port].free_desc_sizes); 347233545Sjchandra 348233545Sjchandra /* XXXJC: check mask calculation */ 349233545Sjchandra ucore_mask = (1 << sc->nucores) - 1; 350233545Sjchandra nlm_nae_init_ucore(nae_base, port, ucore_mask); 351233545Sjchandra} 352233545Sjchandra 353233545Sjchandrastatic void 354233545Sjchandranlm_setup_interfaces(struct nlm_xlpnae_softc *sc) 355233545Sjchandra{ 356233545Sjchandra uint64_t nae_base; 357233545Sjchandra uint32_t cur_slot, cur_slot_base; 358233545Sjchandra uint32_t cur_flow_base, port, flow_mask; 359233545Sjchandra int max_channels; 360255368Sjchandra int i, context; 361233545Sjchandra 362233545Sjchandra cur_slot = 0; 363233545Sjchandra cur_slot_base = 0; 364233545Sjchandra cur_flow_base = 0; 365233545Sjchandra nae_base = sc->base; 366233545Sjchandra flow_mask = nlm_get_flow_mask(sc->total_num_ports); 367233545Sjchandra /* calculate max_channels */ 368233545Sjchandra max_channels = xlpnae_get_maxchannels(sc); 369233545Sjchandra 370233545Sjchandra port = 0; 371233545Sjchandra context = 0; 372255368Sjchandra for (i = 0; i < sc->max_ports; i++) { 373255368Sjchandra if (sc->portcfg[i].type == UNKNOWN) 374255368Sjchandra continue; 375255368Sjchandra nlm_setup_interface(sc, sc->portcfg[i].block, i, cur_flow_base, 376255368Sjchandra flow_mask, max_channels, context); 377255368Sjchandra cur_flow_base += sc->per_port_num_flows; 378255368Sjchandra context += sc->portcfg[i].num_channels; 379233545Sjchandra } 380233545Sjchandra} 381233545Sjchandra 382233545Sjchandrastatic void 383233545Sjchandranlm_xlpnae_init(int node, struct nlm_xlpnae_softc *sc) 384233545Sjchandra{ 385233545Sjchandra uint64_t nae_base; 386233545Sjchandra uint32_t ucoremask = 0; 387233545Sjchandra uint32_t val; 388233545Sjchandra int i; 389233545Sjchandra 390233545Sjchandra nae_base = sc->base; 391233545Sjchandra 392233545Sjchandra nlm_nae_flush_free_fifo(nae_base, sc->nblocks); 393233545Sjchandra nlm_deflate_frin_fifo_carving(nae_base, sc->max_ports); 394233545Sjchandra nlm_reset_nae(node); 395233545Sjchandra 396233545Sjchandra for (i = 0; i < sc->nucores; i++) /* XXXJC: code repeated below */ 397233545Sjchandra ucoremask |= (0x1 << i); 398233545Sjchandra printf("Loading 0x%x ucores with microcode\n", ucoremask); 399233545Sjchandra nlm_ucore_load_all(nae_base, ucoremask, 1); 400233545Sjchandra 401233545Sjchandra val = nlm_set_device_frequency(node, DFS_DEVICE_NAE, sc->freq); 402233545Sjchandra printf("Setup NAE frequency to %dMHz\n", val); 403233545Sjchandra 404245881Sjchandra nlm_mdio_reset_all(nae_base); 405245881Sjchandra 406233545Sjchandra printf("Initialze SGMII PCS for blocks 0x%x\n", sc->sgmiimask); 407233545Sjchandra nlm_sgmii_pcs_init(nae_base, sc->sgmiimask); 408233545Sjchandra 409233545Sjchandra printf("Initialze XAUI PCS for blocks 0x%x\n", sc->xauimask); 410233545Sjchandra nlm_xaui_pcs_init(nae_base, sc->xauimask); 411233545Sjchandra 412233545Sjchandra /* clear NETIOR soft reset */ 413233545Sjchandra nlm_write_nae_reg(nae_base, NAE_LANE_CFG_SOFTRESET, 0x0); 414233545Sjchandra 415233545Sjchandra /* Disable RX enable bit in RX_CONFIG */ 416233545Sjchandra val = nlm_read_nae_reg(nae_base, NAE_RX_CONFIG); 417233545Sjchandra val &= 0xfffffffe; 418233545Sjchandra nlm_write_nae_reg(nae_base, NAE_RX_CONFIG, val); 419233545Sjchandra 420233545Sjchandra if (nlm_is_xlp8xx_ax() == 0) { 421233545Sjchandra val = nlm_read_nae_reg(nae_base, NAE_TX_CONFIG); 422233545Sjchandra val &= ~(1 << 3); 423233545Sjchandra nlm_write_nae_reg(nae_base, NAE_TX_CONFIG, val); 424233545Sjchandra } 425233545Sjchandra 426233545Sjchandra nlm_setup_poe_class_config(nae_base, MAX_POE_CLASSES, 427233545Sjchandra sc->ncontexts, poe_cl_tbl); 428233545Sjchandra 429233545Sjchandra nlm_setup_vfbid_mapping(nae_base); 430233545Sjchandra 431233545Sjchandra nlm_setup_flow_crc_poly(nae_base, sc->flow_crc_poly); 432233545Sjchandra 433233545Sjchandra nlm_setup_rx_cal_cfg(nae_base, sc->max_ports, sc->portcfg); 434233545Sjchandra /* note: xlp8xx Ax does not have Tx Calendering */ 435233545Sjchandra if (!nlm_is_xlp8xx_ax()) 436233545Sjchandra nlm_setup_tx_cal_cfg(nae_base, sc->max_ports, sc->portcfg); 437233545Sjchandra 438233545Sjchandra nlm_setup_interfaces(sc); 439233545Sjchandra nlm_config_poe(sc->poe_base, sc->poedv_base); 440233545Sjchandra 441233545Sjchandra if (sc->hw_parser_en) 442233545Sjchandra nlm_enable_hardware_parser(nae_base); 443233545Sjchandra 444233545Sjchandra if (sc->prepad_en) 445233545Sjchandra nlm_prepad_enable(nae_base, sc->prepad_size); 446233545Sjchandra 447233545Sjchandra if (sc->ieee_1588_en) 448233545Sjchandra nlm_setup_1588_timer(sc->base, sc->portcfg); 449233545Sjchandra} 450233545Sjchandra 451233545Sjchandrastatic void 452233545Sjchandranlm_xlpnae_update_pde(void *dummy __unused) 453233545Sjchandra{ 454233545Sjchandra struct nlm_xlpnae_softc *sc; 455233545Sjchandra uint32_t dv[NUM_WORDS_PER_DV]; 456233545Sjchandra device_t dev; 457233545Sjchandra int vec; 458233545Sjchandra 459233545Sjchandra dev = devclass_get_device(devclass_find("xlpnae"), 0); 460233545Sjchandra sc = device_get_softc(dev); 461233545Sjchandra 462233545Sjchandra nlm_write_poe_reg(sc->poe_base, POE_DISTR_EN, 0); 463233545Sjchandra for (vec = 0; vec < NUM_DIST_VEC; vec++) { 464233545Sjchandra if (nlm_get_poe_distvec(vec, dv) != 0) 465233545Sjchandra continue; 466233545Sjchandra 467233545Sjchandra nlm_write_poe_distvec(sc->poedv_base, vec, dv); 468233545Sjchandra } 469233545Sjchandra nlm_write_poe_reg(sc->poe_base, POE_DISTR_EN, 1); 470233545Sjchandra} 471233545Sjchandra 472233545SjchandraSYSINIT(nlm_xlpnae_update_pde, SI_SUB_SMP, SI_ORDER_ANY, 473233545Sjchandra nlm_xlpnae_update_pde, NULL); 474233545Sjchandra 475233545Sjchandra/* configuration common for sgmii, xaui, ilaken goes here */ 476233545Sjchandrastatic void 477233545Sjchandranlm_setup_portcfg(struct nlm_xlpnae_softc *sc, struct xlp_nae_ivars *naep, 478233545Sjchandra int block, int port) 479233545Sjchandra{ 480233545Sjchandra int i; 481233545Sjchandra uint32_t ucore_mask = 0; 482233545Sjchandra struct xlp_block_ivars *bp; 483233545Sjchandra struct xlp_port_ivars *p; 484233545Sjchandra 485233545Sjchandra bp = &(naep->block_ivars[block]); 486233545Sjchandra p = &(bp->port_ivars[port & 0x3]); 487233545Sjchandra 488255368Sjchandra sc->portcfg[port].node = p->node; 489255368Sjchandra sc->portcfg[port].block = p->block; 490255368Sjchandra sc->portcfg[port].port = p->port; 491255368Sjchandra sc->portcfg[port].type = p->type; 492255368Sjchandra sc->portcfg[port].mdio_bus = p->mdio_bus; 493255368Sjchandra sc->portcfg[port].phy_addr = p->phy_addr; 494233545Sjchandra sc->portcfg[port].loopback_mode = p->loopback_mode; 495233545Sjchandra sc->portcfg[port].num_channels = p->num_channels; 496233545Sjchandra if (p->free_desc_sizes != MCLBYTES) { 497233545Sjchandra printf("[%d, %d] Error: free_desc_sizes %d != %d\n", 498233545Sjchandra block, port, p->free_desc_sizes, MCLBYTES); 499233545Sjchandra return; 500233545Sjchandra } 501233545Sjchandra sc->portcfg[port].free_desc_sizes = p->free_desc_sizes; 502233545Sjchandra for (i = 0; i < sc->nucores; i++) /* XXXJC: configure this */ 503233545Sjchandra ucore_mask |= (0x1 << i); 504233545Sjchandra sc->portcfg[port].ucore_mask = ucore_mask; 505233545Sjchandra sc->portcfg[port].vlan_pri_en = p->vlan_pri_en; 506233545Sjchandra sc->portcfg[port].num_free_descs = p->num_free_descs; 507233545Sjchandra sc->portcfg[port].iface_fifo_size = p->iface_fifo_size; 508233545Sjchandra sc->portcfg[port].rxbuf_size = p->rxbuf_size; 509233545Sjchandra sc->portcfg[port].rx_slots_reqd = p->rx_slots_reqd; 510233545Sjchandra sc->portcfg[port].tx_slots_reqd = p->tx_slots_reqd; 511233545Sjchandra sc->portcfg[port].pseq_fifo_size = p->pseq_fifo_size; 512233545Sjchandra 513233545Sjchandra sc->portcfg[port].stg2_fifo_size = p->stg2_fifo_size; 514233545Sjchandra sc->portcfg[port].eh_fifo_size = p->eh_fifo_size; 515233545Sjchandra sc->portcfg[port].frout_fifo_size = p->frout_fifo_size; 516233545Sjchandra sc->portcfg[port].ms_fifo_size = p->ms_fifo_size; 517233545Sjchandra sc->portcfg[port].pkt_fifo_size = p->pkt_fifo_size; 518233545Sjchandra sc->portcfg[port].pktlen_fifo_size = p->pktlen_fifo_size; 519233545Sjchandra sc->portcfg[port].max_stg2_offset = p->max_stg2_offset; 520233545Sjchandra sc->portcfg[port].max_eh_offset = p->max_eh_offset; 521233545Sjchandra sc->portcfg[port].max_frout_offset = p->max_frout_offset; 522233545Sjchandra sc->portcfg[port].max_ms_offset = p->max_ms_offset; 523233545Sjchandra sc->portcfg[port].max_pmem_offset = p->max_pmem_offset; 524233545Sjchandra sc->portcfg[port].stg1_2_credit = p->stg1_2_credit; 525233545Sjchandra sc->portcfg[port].stg2_eh_credit = p->stg2_eh_credit; 526233545Sjchandra sc->portcfg[port].stg2_frout_credit = p->stg2_frout_credit; 527233545Sjchandra sc->portcfg[port].stg2_ms_credit = p->stg2_ms_credit; 528233545Sjchandra sc->portcfg[port].ieee1588_inc_intg = p->ieee1588_inc_intg; 529233545Sjchandra sc->portcfg[port].ieee1588_inc_den = p->ieee1588_inc_den; 530233545Sjchandra sc->portcfg[port].ieee1588_inc_num = p->ieee1588_inc_num; 531233545Sjchandra sc->portcfg[port].ieee1588_userval = p->ieee1588_userval; 532233545Sjchandra sc->portcfg[port].ieee1588_ptpoff = p->ieee1588_ptpoff; 533233545Sjchandra sc->portcfg[port].ieee1588_tmr1 = p->ieee1588_tmr1; 534233545Sjchandra sc->portcfg[port].ieee1588_tmr2 = p->ieee1588_tmr2; 535233545Sjchandra sc->portcfg[port].ieee1588_tmr3 = p->ieee1588_tmr3; 536233545Sjchandra 537233545Sjchandra sc->total_free_desc += sc->portcfg[port].free_desc_sizes; 538233545Sjchandra sc->total_num_ports++; 539233545Sjchandra} 540233545Sjchandra 541233545Sjchandrastatic int 542233545Sjchandranlm_xlpnae_attach(device_t dev) 543233545Sjchandra{ 544233545Sjchandra struct xlp_nae_ivars *nae_ivars; 545233545Sjchandra struct nlm_xlpnae_softc *sc; 546233545Sjchandra device_t tmpd; 547233545Sjchandra uint32_t dv[NUM_WORDS_PER_DV]; 548255368Sjchandra int port, i, j, nchan, nblock, node, qstart, qnum; 549233545Sjchandra int offset, context, txq_base, rxvcbase; 550233545Sjchandra uint64_t poe_pcibase, nae_pcibase; 551233545Sjchandra 552233545Sjchandra node = pci_get_slot(dev) / 8; 553233545Sjchandra nae_ivars = &xlp_board_info.nodes[node].nae_ivars; 554233545Sjchandra 555233545Sjchandra sc = device_get_softc(dev); 556233545Sjchandra sc->xlpnae_dev = dev; 557233545Sjchandra sc->node = nae_ivars->node; 558233545Sjchandra sc->base = nlm_get_nae_regbase(sc->node); 559233545Sjchandra sc->poe_base = nlm_get_poe_regbase(sc->node); 560233545Sjchandra sc->poedv_base = nlm_get_poedv_regbase(sc->node); 561233545Sjchandra sc->portcfg = nae_port_config; 562255368Sjchandra sc->blockmask = nae_ivars->blockmask; 563255368Sjchandra sc->ilmask = nae_ivars->ilmask; 564233545Sjchandra sc->xauimask = nae_ivars->xauimask; 565233545Sjchandra sc->sgmiimask = nae_ivars->sgmiimask; 566233545Sjchandra sc->nblocks = nae_ivars->nblocks; 567233545Sjchandra sc->freq = nae_ivars->freq; 568233545Sjchandra 569233545Sjchandra /* flow table generation is done by CRC16 polynomial */ 570233545Sjchandra sc->flow_crc_poly = nae_ivars->flow_crc_poly; 571233545Sjchandra 572233545Sjchandra sc->hw_parser_en = nae_ivars->hw_parser_en; 573233545Sjchandra sc->prepad_en = nae_ivars->prepad_en; 574233545Sjchandra sc->prepad_size = nae_ivars->prepad_size; 575233545Sjchandra sc->ieee_1588_en = nae_ivars->ieee_1588_en; 576233545Sjchandra 577233545Sjchandra nae_pcibase = nlm_get_nae_pcibase(sc->node); 578233545Sjchandra sc->ncontexts = nlm_read_reg(nae_pcibase, XLP_PCI_DEVINFO_REG5); 579233545Sjchandra sc->nucores = nlm_num_uengines(nae_pcibase); 580233545Sjchandra 581255368Sjchandra for (nblock = 0; nblock < sc->nblocks; nblock++) { 582233545Sjchandra sc->cmplx_type[nblock] = nae_ivars->block_ivars[nblock].type; 583255368Sjchandra sc->portmask[nblock] = nae_ivars->block_ivars[nblock].portmask; 584255368Sjchandra } 585233545Sjchandra 586233545Sjchandra for (i = 0; i < sc->ncontexts; i++) 587233545Sjchandra cntx2port[i] = 18; /* 18 is an invalid port */ 588233545Sjchandra 589233545Sjchandra if (sc->nblocks == 5) 590233545Sjchandra sc->max_ports = 18; /* 8xx has a block 4 with 2 ports */ 591233545Sjchandra else 592233545Sjchandra sc->max_ports = sc->nblocks * PORTS_PER_CMPLX; 593233545Sjchandra 594255368Sjchandra for (i = 0; i < sc->max_ports; i++) 595255368Sjchandra sc->portcfg[i].type = UNKNOWN; /* Port Not Present */ 596233545Sjchandra /* 597233545Sjchandra * Now setup all internal fifo carvings based on 598233545Sjchandra * total number of ports in the system 599233545Sjchandra */ 600233545Sjchandra sc->total_free_desc = 0; 601233545Sjchandra sc->total_num_ports = 0; 602233545Sjchandra port = 0; 603233545Sjchandra context = 0; 604233545Sjchandra txq_base = nlm_qidstart(nae_pcibase); 605233545Sjchandra rxvcbase = txq_base + sc->ncontexts; 606233545Sjchandra for (i = 0; i < sc->nblocks; i++) { 607255368Sjchandra uint32_t portmask; 608255368Sjchandra 609255368Sjchandra if ((nae_ivars->blockmask & (1 << i)) == 0) { 610255368Sjchandra port += 4; 611255368Sjchandra continue; 612255368Sjchandra } 613255368Sjchandra portmask = nae_ivars->block_ivars[i].portmask; 614255368Sjchandra for (j = 0; j < PORTS_PER_CMPLX; j++, port++) { 615255368Sjchandra if ((portmask & (1 << j)) == 0) 616233545Sjchandra continue; 617233545Sjchandra nlm_setup_portcfg(sc, nae_ivars, i, port); 618233545Sjchandra nchan = sc->portcfg[port].num_channels; 619233545Sjchandra for (offset = 0; offset < nchan; offset++) 620233545Sjchandra cntx2port[context + offset] = port; 621233545Sjchandra sc->portcfg[port].txq = txq_base + context; 622233545Sjchandra sc->portcfg[port].rxfreeq = rxvcbase + port; 623233545Sjchandra context += nchan; 624233545Sjchandra } 625233545Sjchandra } 626233545Sjchandra 627233545Sjchandra poe_pcibase = nlm_get_poe_pcibase(sc->node); 628233545Sjchandra sc->per_port_num_flows = 629233545Sjchandra nlm_poe_max_flows(poe_pcibase) / sc->total_num_ports; 630233545Sjchandra 631233545Sjchandra /* zone for P2P descriptors */ 632233545Sjchandra nl_tx_desc_zone = uma_zcreate("NL Tx Desc", 633233545Sjchandra sizeof(struct xlpge_tx_desc), NULL, NULL, NULL, NULL, 634233545Sjchandra NAE_CACHELINE_SIZE, 0); 635233545Sjchandra 636233545Sjchandra /* NAE FMN messages have CMS src station id's in the 637233545Sjchandra * range of qstart to qnum. 638233545Sjchandra */ 639233545Sjchandra qstart = nlm_qidstart(nae_pcibase); 640233545Sjchandra qnum = nlm_qnum(nae_pcibase); 641233545Sjchandra if (register_msgring_handler(qstart, qstart + qnum - 1, 642233545Sjchandra nlm_xlpge_msgring_handler, sc)) { 643233545Sjchandra panic("Couldn't register NAE msgring handler\n"); 644233545Sjchandra } 645233545Sjchandra 646233545Sjchandra /* POE FMN messages have CMS src station id's in the 647233545Sjchandra * range of qstart to qnum. 648233545Sjchandra */ 649233545Sjchandra qstart = nlm_qidstart(poe_pcibase); 650233545Sjchandra qnum = nlm_qnum(poe_pcibase); 651233545Sjchandra if (register_msgring_handler(qstart, qstart + qnum - 1, 652233545Sjchandra nlm_xlpge_msgring_handler, sc)) { 653233545Sjchandra panic("Couldn't register POE msgring handler\n"); 654233545Sjchandra } 655233545Sjchandra 656233545Sjchandra nlm_xlpnae_init(node, sc); 657233545Sjchandra 658255368Sjchandra for (i = 0; i < sc->max_ports; i++) { 659233545Sjchandra char desc[32]; 660255368Sjchandra int block, port; 661233545Sjchandra 662255368Sjchandra if (sc->portcfg[i].type == UNKNOWN) 663233545Sjchandra continue; 664255368Sjchandra block = sc->portcfg[i].block; 665255368Sjchandra port = sc->portcfg[i].port; 666255368Sjchandra tmpd = device_add_child(dev, "xlpge", i); 667255368Sjchandra device_set_ivars(tmpd, 668255368Sjchandra &(nae_ivars->block_ivars[block].port_ivars[port])); 669255368Sjchandra sprintf(desc, "XLP NAE Port %d,%d", block, port); 670255368Sjchandra device_set_desc_copy(tmpd, desc); 671233545Sjchandra } 672255368Sjchandra nlm_setup_iface_fifo_cfg(sc->base, sc->max_ports, sc->portcfg); 673255368Sjchandra nlm_setup_rx_base_config(sc->base, sc->max_ports, sc->portcfg); 674255368Sjchandra nlm_setup_rx_buf_config(sc->base, sc->max_ports, sc->portcfg); 675255368Sjchandra nlm_setup_freein_fifo_cfg(sc->base, sc->portcfg); 676255368Sjchandra nlm_program_nae_parser_seq_fifo(sc->base, sc->max_ports, sc->portcfg); 677233545Sjchandra 678255368Sjchandra nlm_xlpnae_print_frin_desc_carving(sc); 679233545Sjchandra bus_generic_probe(dev); 680233545Sjchandra bus_generic_attach(dev); 681233545Sjchandra 682233545Sjchandra /* 683233545Sjchandra * Enable only boot cpu at this point, full distribution comes 684233545Sjchandra * only after SMP is started 685233545Sjchandra */ 686233545Sjchandra nlm_write_poe_reg(sc->poe_base, POE_DISTR_EN, 0); 687233545Sjchandra nlm_calc_poe_distvec(0x1, 0, 0, 0, 0x1 << XLPGE_RX_VC, dv); 688233545Sjchandra nlm_write_poe_distvec(sc->poedv_base, 0, dv); 689233545Sjchandra nlm_write_poe_reg(sc->poe_base, POE_DISTR_EN, 1); 690233545Sjchandra 691233545Sjchandra return (0); 692233545Sjchandra} 693233545Sjchandra 694233545Sjchandrastatic int 695233545Sjchandranlm_xlpnae_detach(device_t dev) 696233545Sjchandra{ 697233545Sjchandra /* TODO - free zone here */ 698233545Sjchandra return (0); 699233545Sjchandra} 700233545Sjchandra 701233545Sjchandrastatic int 702233545Sjchandranlm_xlpnae_suspend(device_t dev) 703233545Sjchandra{ 704233545Sjchandra return (0); 705233545Sjchandra} 706233545Sjchandra 707233545Sjchandrastatic int 708233545Sjchandranlm_xlpnae_resume(device_t dev) 709233545Sjchandra{ 710233545Sjchandra return (0); 711233545Sjchandra} 712233545Sjchandra 713233545Sjchandrastatic int 714233545Sjchandranlm_xlpnae_shutdown(device_t dev) 715233545Sjchandra{ 716233545Sjchandra return (0); 717233545Sjchandra} 718233545Sjchandra 719233545Sjchandra/* 720233545Sjchandra * xlpge driver implementation 721233545Sjchandra */ 722233545Sjchandra 723233545Sjchandrastatic void 724233545Sjchandranlm_xlpge_mac_set_rx_mode(struct nlm_xlpge_softc *sc) 725233545Sjchandra{ 726233545Sjchandra if (sc->if_flags & IFF_PROMISC) { 727233545Sjchandra if (sc->type == SGMIIC) 728233545Sjchandra nlm_nae_setup_rx_mode_sgmii(sc->base_addr, 729233545Sjchandra sc->block, sc->port, sc->type, 1 /* broadcast */, 730233545Sjchandra 1/* multicast */, 0 /* pause */, 1 /* promisc */); 731233545Sjchandra else 732233545Sjchandra nlm_nae_setup_rx_mode_xaui(sc->base_addr, 733233545Sjchandra sc->block, sc->port, sc->type, 1 /* broadcast */, 734233545Sjchandra 1/* multicast */, 0 /* pause */, 1 /* promisc */); 735233545Sjchandra } else { 736233545Sjchandra if (sc->type == SGMIIC) 737233545Sjchandra nlm_nae_setup_rx_mode_sgmii(sc->base_addr, 738233545Sjchandra sc->block, sc->port, sc->type, 1 /* broadcast */, 739233545Sjchandra 1/* multicast */, 0 /* pause */, 0 /* promisc */); 740233545Sjchandra else 741233545Sjchandra nlm_nae_setup_rx_mode_xaui(sc->base_addr, 742233545Sjchandra sc->block, sc->port, sc->type, 1 /* broadcast */, 743233545Sjchandra 1/* multicast */, 0 /* pause */, 0 /* promisc */); 744233545Sjchandra } 745233545Sjchandra} 746233545Sjchandra 747233545Sjchandrastatic int 748233545Sjchandranlm_xlpge_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 749233545Sjchandra{ 750233545Sjchandra struct mii_data *mii; 751233545Sjchandra struct nlm_xlpge_softc *sc; 752233545Sjchandra struct ifreq *ifr; 753233545Sjchandra int error; 754233545Sjchandra 755233545Sjchandra sc = ifp->if_softc; 756233545Sjchandra error = 0; 757233545Sjchandra ifr = (struct ifreq *)data; 758233545Sjchandra 759233545Sjchandra switch (command) { 760233545Sjchandra case SIOCSIFFLAGS: 761233545Sjchandra XLPGE_LOCK(sc); 762233545Sjchandra sc->if_flags = ifp->if_flags; 763233545Sjchandra if (ifp->if_flags & IFF_UP) { 764233545Sjchandra if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 765233545Sjchandra nlm_xlpge_init(sc); 766245881Sjchandra else 767245881Sjchandra nlm_xlpge_port_enable(sc); 768245881Sjchandra nlm_xlpge_mac_set_rx_mode(sc); 769233545Sjchandra sc->link = NLM_LINK_UP; 770233545Sjchandra } else { 771233545Sjchandra if (ifp->if_drv_flags & IFF_DRV_RUNNING) 772233545Sjchandra nlm_xlpge_port_disable(sc); 773233545Sjchandra sc->link = NLM_LINK_DOWN; 774233545Sjchandra } 775233545Sjchandra XLPGE_UNLOCK(sc); 776233545Sjchandra error = 0; 777233545Sjchandra break; 778233545Sjchandra case SIOCGIFMEDIA: 779233545Sjchandra case SIOCSIFMEDIA: 780233545Sjchandra if (sc->mii_bus != NULL) { 781233545Sjchandra mii = device_get_softc(sc->mii_bus); 782233545Sjchandra error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, 783233545Sjchandra command); 784233545Sjchandra } 785233545Sjchandra break; 786233545Sjchandra default: 787233545Sjchandra error = ether_ioctl(ifp, command, data); 788233545Sjchandra break; 789233545Sjchandra } 790233545Sjchandra 791233545Sjchandra return (error); 792233545Sjchandra} 793233545Sjchandra 794233545Sjchandrastatic int 795233545Sjchandraxlpge_tx(struct ifnet *ifp, struct mbuf *mbuf_chain) 796233545Sjchandra{ 797233545Sjchandra struct nlm_fmn_msg msg; 798233545Sjchandra struct xlpge_tx_desc *p2p; 799233545Sjchandra struct nlm_xlpge_softc *sc; 800233545Sjchandra struct mbuf *m; 801233545Sjchandra vm_paddr_t paddr; 802233545Sjchandra int fbid, dst, pos, err; 803233545Sjchandra int ret = 0, tx_msgstatus, retries; 804233545Sjchandra 805233545Sjchandra err = 0; 806233545Sjchandra if (mbuf_chain == NULL) 807233545Sjchandra return (0); 808233545Sjchandra 809233545Sjchandra sc = ifp->if_softc; 810233545Sjchandra p2p = NULL; 811233545Sjchandra if (!(ifp->if_drv_flags & IFF_DRV_RUNNING) || 812233545Sjchandra ifp->if_drv_flags & IFF_DRV_OACTIVE) { 813233545Sjchandra err = ENXIO; 814233545Sjchandra goto fail; 815233545Sjchandra } 816233545Sjchandra 817233545Sjchandra /* free a few in coming messages on the fb vc */ 818233545Sjchandra xlp_handle_msg_vc(1 << XLPGE_FB_VC, 2); 819233545Sjchandra 820233545Sjchandra /* vfb id table is setup to map cpu to vc 3 of the cpu */ 821233545Sjchandra fbid = nlm_cpuid(); 822233545Sjchandra dst = sc->txq; 823233545Sjchandra 824233545Sjchandra pos = 0; 825233545Sjchandra p2p = uma_zalloc(nl_tx_desc_zone, M_NOWAIT); 826233545Sjchandra if (p2p == NULL) { 827233545Sjchandra printf("alloc fail\n"); 828233545Sjchandra err = ENOBUFS; 829233545Sjchandra goto fail; 830233545Sjchandra } 831233545Sjchandra 832233545Sjchandra for (m = mbuf_chain; m != NULL; m = m->m_next) { 833233545Sjchandra vm_offset_t buf = (vm_offset_t) m->m_data; 834233545Sjchandra int len = m->m_len; 835233545Sjchandra int frag_sz; 836245884Sjchandra uint64_t desc; 837233545Sjchandra 838233545Sjchandra /*printf("m_data = %p len %d\n", m->m_data, len); */ 839233545Sjchandra while (len) { 840233545Sjchandra if (pos == XLP_NTXFRAGS - 3) { 841233545Sjchandra device_printf(sc->xlpge_dev, 842233545Sjchandra "packet defrag %d\n", 843233545Sjchandra m_length(mbuf_chain, NULL)); 844233545Sjchandra err = ENOBUFS; /* TODO fix error */ 845233545Sjchandra goto fail; 846233545Sjchandra } 847233545Sjchandra paddr = vtophys(buf); 848233545Sjchandra frag_sz = PAGE_SIZE - (buf & PAGE_MASK); 849233545Sjchandra if (len < frag_sz) 850233545Sjchandra frag_sz = len; 851245884Sjchandra desc = nae_tx_desc(P2D_NEOP, 0, 127, 852233545Sjchandra frag_sz, paddr); 853245884Sjchandra p2p->frag[pos] = htobe64(desc); 854233545Sjchandra pos++; 855233545Sjchandra len -= frag_sz; 856233545Sjchandra buf += frag_sz; 857233545Sjchandra } 858233545Sjchandra } 859233545Sjchandra 860233545Sjchandra KASSERT(pos != 0, ("Zero-length mbuf chain?\n")); 861233545Sjchandra 862233545Sjchandra /* Make the last one P2D EOP */ 863245884Sjchandra p2p->frag[pos-1] |= htobe64((uint64_t)P2D_EOP << 62); 864233545Sjchandra 865233545Sjchandra /* stash useful pointers in the desc */ 866233545Sjchandra p2p->frag[XLP_NTXFRAGS-3] = 0xf00bad; 867233545Sjchandra p2p->frag[XLP_NTXFRAGS-2] = (uintptr_t)p2p; 868233545Sjchandra p2p->frag[XLP_NTXFRAGS-1] = (uintptr_t)mbuf_chain; 869233545Sjchandra 870233545Sjchandra paddr = vtophys(p2p); 871233545Sjchandra msg.msg[0] = nae_tx_desc(P2P, 0, fbid, pos, paddr); 872233545Sjchandra 873233545Sjchandra for (retries = 16; retries > 0; retries--) { 874233545Sjchandra ret = nlm_fmn_msgsend(dst, 1, FMN_SWCODE_NAE, &msg); 875233545Sjchandra if (ret == 0) 876233545Sjchandra return (0); 877233545Sjchandra } 878233545Sjchandra 879233545Sjchandrafail: 880233545Sjchandra if (ret != 0) { 881233545Sjchandra tx_msgstatus = nlm_read_c2_txmsgstatus(); 882233545Sjchandra if ((tx_msgstatus >> 24) & 0x1) 883233545Sjchandra device_printf(sc->xlpge_dev, "Transmit queue full - "); 884233545Sjchandra if ((tx_msgstatus >> 3) & 0x1) 885233545Sjchandra device_printf(sc->xlpge_dev, "ECC error - "); 886233545Sjchandra if ((tx_msgstatus >> 2) & 0x1) 887233545Sjchandra device_printf(sc->xlpge_dev, "Pending Sync - "); 888233545Sjchandra if ((tx_msgstatus >> 1) & 0x1) 889233545Sjchandra device_printf(sc->xlpge_dev, 890233545Sjchandra "Insufficient input queue credits - "); 891233545Sjchandra if (tx_msgstatus & 0x1) 892233545Sjchandra device_printf(sc->xlpge_dev, 893233545Sjchandra "Insufficient output queue credits - "); 894233545Sjchandra } 895233545Sjchandra device_printf(sc->xlpge_dev, "Send failed! err = %d\n", err); 896233545Sjchandra if (p2p) 897233545Sjchandra uma_zfree(nl_tx_desc_zone, p2p); 898233545Sjchandra m_freem(mbuf_chain); 899233545Sjchandra /*atomic_incr_long(&ifp->if_iqdrops); */ 900233545Sjchandra ifp->if_iqdrops++; 901233545Sjchandra return (err); 902233545Sjchandra} 903233545Sjchandra 904233545Sjchandra 905233545Sjchandrastatic int 906233545Sjchandranlm_xlpge_gmac_config_speed(struct nlm_xlpge_softc *sc) 907233545Sjchandra{ 908233545Sjchandra struct mii_data *mii; 909233545Sjchandra 910233545Sjchandra if (sc->type == XAUIC || sc->type == ILC) 911233545Sjchandra return (0); 912233545Sjchandra 913233545Sjchandra if (sc->mii_bus) { 914233545Sjchandra mii = device_get_softc(sc->mii_bus); 915233545Sjchandra mii_pollstat(mii); 916233545Sjchandra } 917233545Sjchandra 918233545Sjchandra return (0); 919233545Sjchandra} 920233545Sjchandra 921233545Sjchandrastatic void 922233545Sjchandranlm_xlpge_port_disable(struct nlm_xlpge_softc *sc) 923233545Sjchandra{ 924233545Sjchandra struct ifnet *ifp; 925233545Sjchandra 926233545Sjchandra ifp = sc->xlpge_if; 927233545Sjchandra ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 928233545Sjchandra 929233545Sjchandra callout_stop(&sc->xlpge_callout); 930233545Sjchandra nlm_mac_disable(sc->base_addr, sc->block, sc->type, sc->port); 931233545Sjchandra} 932233545Sjchandra 933233545Sjchandrastatic void 934233545Sjchandranlm_mii_pollstat(void *arg) 935233545Sjchandra{ 936233545Sjchandra struct nlm_xlpge_softc *sc = (struct nlm_xlpge_softc *)arg; 937233545Sjchandra struct mii_data *mii = NULL; 938233545Sjchandra 939233545Sjchandra if (sc->mii_bus) { 940233545Sjchandra mii = device_get_softc(sc->mii_bus); 941233545Sjchandra 942249409Sjchandra KASSERT(mii != NULL, ("mii ptr is NULL")); 943233545Sjchandra 944233545Sjchandra mii_pollstat(mii); 945233545Sjchandra 946233545Sjchandra callout_reset(&sc->xlpge_callout, hz, 947233545Sjchandra nlm_mii_pollstat, sc); 948233545Sjchandra } 949233545Sjchandra} 950233545Sjchandra 951233545Sjchandrastatic void 952233545Sjchandranlm_xlpge_port_enable(struct nlm_xlpge_softc *sc) 953233545Sjchandra{ 954233545Sjchandra if ((sc->type != SGMIIC) && (sc->type != XAUIC)) 955233545Sjchandra return; 956233545Sjchandra nlm_mac_enable(sc->base_addr, sc->block, sc->type, sc->port); 957233545Sjchandra nlm_mii_pollstat((void *)sc); 958233545Sjchandra} 959233545Sjchandra 960233545Sjchandrastatic void 961233545Sjchandranlm_xlpge_init(void *addr) 962233545Sjchandra{ 963233545Sjchandra struct nlm_xlpge_softc *sc; 964233545Sjchandra struct ifnet *ifp; 965233545Sjchandra struct mii_data *mii = NULL; 966233545Sjchandra 967233545Sjchandra sc = (struct nlm_xlpge_softc *)addr; 968233545Sjchandra ifp = sc->xlpge_if; 969233545Sjchandra 970233545Sjchandra if (ifp->if_drv_flags & IFF_DRV_RUNNING) 971233545Sjchandra return; 972233545Sjchandra 973233545Sjchandra if (sc->mii_bus) { 974233545Sjchandra mii = device_get_softc(sc->mii_bus); 975233545Sjchandra mii_mediachg(mii); 976233545Sjchandra } 977233545Sjchandra 978233545Sjchandra nlm_xlpge_gmac_config_speed(sc); 979233545Sjchandra ifp->if_drv_flags |= IFF_DRV_RUNNING; 980233545Sjchandra ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 981233545Sjchandra nlm_xlpge_port_enable(sc); 982233545Sjchandra 983233545Sjchandra /* start the callout */ 984233545Sjchandra callout_reset(&sc->xlpge_callout, hz, nlm_mii_pollstat, sc); 985233545Sjchandra} 986233545Sjchandra 987233545Sjchandra/* 988233545Sjchandra * Read the MAC address from FDT or board eeprom. 989233545Sjchandra */ 990233545Sjchandrastatic void 991233545Sjchandraxlpge_read_mac_addr(struct nlm_xlpge_softc *sc) 992233545Sjchandra{ 993233545Sjchandra 994233545Sjchandra xlpge_get_macaddr(sc->dev_addr); 995233545Sjchandra /* last octet is port specific */ 996233545Sjchandra sc->dev_addr[5] += (sc->block * 4) + sc->port; 997233545Sjchandra 998233545Sjchandra if (sc->type == SGMIIC) 999233545Sjchandra nlm_nae_setup_mac_addr_sgmii(sc->base_addr, sc->block, 1000233545Sjchandra sc->port, sc->type, sc->dev_addr); 1001233545Sjchandra else if (sc->type == XAUIC) 1002233545Sjchandra nlm_nae_setup_mac_addr_xaui(sc->base_addr, sc->block, 1003233545Sjchandra sc->port, sc->type, sc->dev_addr); 1004233545Sjchandra} 1005233545Sjchandra 1006233545Sjchandra 1007233545Sjchandrastatic int 1008233545Sjchandraxlpge_mediachange(struct ifnet *ifp) 1009233545Sjchandra{ 1010233545Sjchandra return (0); 1011233545Sjchandra} 1012233545Sjchandra 1013233545Sjchandrastatic void 1014233545Sjchandraxlpge_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr) 1015233545Sjchandra{ 1016233545Sjchandra struct nlm_xlpge_softc *sc; 1017233545Sjchandra struct mii_data *md; 1018233545Sjchandra 1019233545Sjchandra md = NULL; 1020233545Sjchandra sc = ifp->if_softc; 1021233545Sjchandra 1022233545Sjchandra if (sc->mii_bus) 1023233545Sjchandra md = device_get_softc(sc->mii_bus); 1024233545Sjchandra 1025233545Sjchandra ifmr->ifm_status = IFM_AVALID; 1026233545Sjchandra ifmr->ifm_active = IFM_ETHER; 1027233545Sjchandra 1028233545Sjchandra if (sc->link == NLM_LINK_DOWN) 1029233545Sjchandra return; 1030233545Sjchandra 1031233545Sjchandra if (md != NULL) 1032233545Sjchandra ifmr->ifm_active = md->mii_media.ifm_cur->ifm_media; 1033233545Sjchandra ifmr->ifm_status |= IFM_ACTIVE; 1034233545Sjchandra} 1035233545Sjchandra 1036233545Sjchandrastatic int 1037233545Sjchandranlm_xlpge_ifinit(struct nlm_xlpge_softc *sc) 1038233545Sjchandra{ 1039233545Sjchandra struct ifnet *ifp; 1040233545Sjchandra device_t dev; 1041233545Sjchandra int port = sc->block * 4 + sc->port; 1042233545Sjchandra 1043233545Sjchandra dev = sc->xlpge_dev; 1044233545Sjchandra ifp = sc->xlpge_if = if_alloc(IFT_ETHER); 1045233545Sjchandra /*(sc->network_sc)->ifp_ports[port].xlpge_if = ifp;*/ 1046233545Sjchandra ifp_ports[port].xlpge_if = ifp; 1047233545Sjchandra 1048233545Sjchandra if (ifp == NULL) { 1049233545Sjchandra device_printf(dev, "cannot if_alloc()\n"); 1050233545Sjchandra return (ENOSPC); 1051233545Sjchandra } 1052233545Sjchandra ifp->if_softc = sc; 1053233545Sjchandra if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 1054233545Sjchandra ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 1055233545Sjchandra sc->if_flags = ifp->if_flags; 1056233545Sjchandra /*ifp->if_capabilities = IFCAP_TXCSUM | IFCAP_VLAN_HWTAGGING;*/ 1057233545Sjchandra ifp->if_capabilities = 0; 1058233545Sjchandra ifp->if_capenable = ifp->if_capabilities; 1059233545Sjchandra ifp->if_ioctl = nlm_xlpge_ioctl; 1060233545Sjchandra ifp->if_init = nlm_xlpge_init ; 1061233545Sjchandra ifp->if_hwassist = 0; 1062233545Sjchandra ifp->if_snd.ifq_drv_maxlen = NLM_XLPGE_TXQ_SIZE; /* TODO: make this a sysint */ 1063233545Sjchandra IFQ_SET_MAXLEN(&ifp->if_snd, ifp->if_snd.ifq_drv_maxlen); 1064233545Sjchandra IFQ_SET_READY(&ifp->if_snd); 1065233545Sjchandra 1066233545Sjchandra ifmedia_init(&sc->xlpge_mii.mii_media, 0, xlpge_mediachange, 1067233545Sjchandra xlpge_mediastatus); 1068233545Sjchandra ifmedia_add(&sc->xlpge_mii.mii_media, IFM_ETHER | IFM_AUTO, 0, NULL); 1069233545Sjchandra ifmedia_set(&sc->xlpge_mii.mii_media, IFM_ETHER | IFM_AUTO); 1070233545Sjchandra sc->xlpge_mii.mii_media.ifm_media = 1071233545Sjchandra sc->xlpge_mii.mii_media.ifm_cur->ifm_media; 1072233545Sjchandra xlpge_read_mac_addr(sc); 1073233545Sjchandra 1074233545Sjchandra ether_ifattach(ifp, sc->dev_addr); 1075233545Sjchandra 1076233545Sjchandra /* override if_transmit : per ifnet(9), do it after if_attach */ 1077233545Sjchandra ifp->if_transmit = xlpge_tx; 1078233545Sjchandra 1079233545Sjchandra return (0); 1080233545Sjchandra} 1081233545Sjchandra 1082233545Sjchandrastatic int 1083233545Sjchandranlm_xlpge_probe(device_t dev) 1084233545Sjchandra{ 1085233545Sjchandra return (BUS_PROBE_DEFAULT); 1086233545Sjchandra} 1087233545Sjchandra 1088233545Sjchandrastatic void * 1089233545Sjchandraget_buf(void) 1090233545Sjchandra{ 1091233545Sjchandra struct mbuf *m_new; 1092233545Sjchandra uint64_t *md; 1093233545Sjchandra#ifdef INVARIANTS 1094233545Sjchandra vm_paddr_t temp1, temp2; 1095233545Sjchandra#endif 1096233545Sjchandra 1097243882Sglebius if ((m_new = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR)) == NULL) 1098233545Sjchandra return (NULL); 1099233545Sjchandra m_new->m_len = m_new->m_pkthdr.len = MCLBYTES; 1100245884Sjchandra KASSERT(((uintptr_t)m_new->m_data & (NAE_CACHELINE_SIZE - 1)) == 0, 1101245884Sjchandra ("m_new->m_data is not cacheline aligned")); 1102233545Sjchandra md = (uint64_t *)m_new->m_data; 1103233545Sjchandra md[0] = (intptr_t)m_new; /* Back Ptr */ 1104233545Sjchandra md[1] = 0xf00bad; 1105233545Sjchandra m_adj(m_new, NAE_CACHELINE_SIZE); 1106233545Sjchandra 1107233545Sjchandra#ifdef INVARIANTS 1108233545Sjchandra temp1 = vtophys((vm_offset_t) m_new->m_data); 1109233545Sjchandra temp2 = vtophys((vm_offset_t) m_new->m_data + 1536); 1110249409Sjchandra KASSERT((temp1 + 1536) == temp2, 1111233545Sjchandra ("Alloced buffer is not contiguous")); 1112233545Sjchandra#endif 1113233545Sjchandra return ((void *)m_new->m_data); 1114233545Sjchandra} 1115233545Sjchandra 1116233545Sjchandrastatic void 1117233545Sjchandranlm_xlpge_mii_init(device_t dev, struct nlm_xlpge_softc *sc) 1118233545Sjchandra{ 1119233545Sjchandra int error; 1120233545Sjchandra 1121233545Sjchandra error = mii_attach(dev, &sc->mii_bus, sc->xlpge_if, 1122233545Sjchandra xlpge_mediachange, xlpge_mediastatus, 1123233545Sjchandra BMSR_DEFCAPMASK, sc->phy_addr, MII_OFFSET_ANY, 0); 1124233545Sjchandra 1125233545Sjchandra if (error) { 1126233545Sjchandra device_printf(dev, "attaching PHYs failed\n"); 1127233545Sjchandra sc->mii_bus = NULL; 1128233545Sjchandra } 1129233545Sjchandra 1130233545Sjchandra if (sc->mii_bus != NULL) { 1131233545Sjchandra /* enable MDIO interrupts in the PHY */ 1132233545Sjchandra /* XXXJC: TODO */ 1133233545Sjchandra } 1134233545Sjchandra} 1135233545Sjchandra 1136233545Sjchandrastatic int 1137233545Sjchandraxlpge_stats_sysctl(SYSCTL_HANDLER_ARGS) 1138233545Sjchandra{ 1139233545Sjchandra struct nlm_xlpge_softc *sc; 1140233545Sjchandra uint32_t val; 1141233545Sjchandra int reg, field; 1142233545Sjchandra 1143233545Sjchandra sc = arg1; 1144233545Sjchandra field = arg2; 1145233545Sjchandra reg = SGMII_STATS_MLR(sc->block, sc->port) + field; 1146233545Sjchandra val = nlm_read_nae_reg(sc->base_addr, reg); 1147233545Sjchandra return (sysctl_handle_int(oidp, &val, 0, req)); 1148233545Sjchandra} 1149233545Sjchandra 1150233545Sjchandrastatic void 1151233545Sjchandranlm_xlpge_setup_stats_sysctl(device_t dev, struct nlm_xlpge_softc *sc) 1152233545Sjchandra{ 1153233545Sjchandra struct sysctl_ctx_list *ctx; 1154233545Sjchandra struct sysctl_oid_list *child; 1155233545Sjchandra struct sysctl_oid *tree; 1156233545Sjchandra 1157233545Sjchandra ctx = device_get_sysctl_ctx(dev); 1158233545Sjchandra tree = device_get_sysctl_tree(dev); 1159233545Sjchandra child = SYSCTL_CHILDREN(tree); 1160233545Sjchandra 1161233545Sjchandra#define XLPGE_STAT(name, offset, desc) \ 1162233545Sjchandra SYSCTL_ADD_PROC(ctx, child, OID_AUTO, name, \ 1163233545Sjchandra CTLTYPE_UINT | CTLFLAG_RD, sc, offset, \ 1164233545Sjchandra xlpge_stats_sysctl, "IU", desc) 1165233545Sjchandra 1166233545Sjchandra XLPGE_STAT("tr127", nlm_sgmii_stats_tr127, "TxRx 64 - 127 Bytes"); 1167233545Sjchandra XLPGE_STAT("tr255", nlm_sgmii_stats_tr255, "TxRx 128 - 255 Bytes"); 1168233545Sjchandra XLPGE_STAT("tr511", nlm_sgmii_stats_tr511, "TxRx 256 - 511 Bytes"); 1169233545Sjchandra XLPGE_STAT("tr1k", nlm_sgmii_stats_tr1k, "TxRx 512 - 1023 Bytes"); 1170233545Sjchandra XLPGE_STAT("trmax", nlm_sgmii_stats_trmax, "TxRx 1024 - 1518 Bytes"); 1171233545Sjchandra XLPGE_STAT("trmgv", nlm_sgmii_stats_trmgv, "TxRx 1519 - 1522 Bytes"); 1172233545Sjchandra 1173233545Sjchandra XLPGE_STAT("rbyt", nlm_sgmii_stats_rbyt, "Rx Bytes"); 1174233545Sjchandra XLPGE_STAT("rpkt", nlm_sgmii_stats_rpkt, "Rx Packets"); 1175233545Sjchandra XLPGE_STAT("rfcs", nlm_sgmii_stats_rfcs, "Rx FCS Error"); 1176233545Sjchandra XLPGE_STAT("rmca", nlm_sgmii_stats_rmca, "Rx Multicast Packets"); 1177233545Sjchandra XLPGE_STAT("rbca", nlm_sgmii_stats_rbca, "Rx Broadcast Packets"); 1178233545Sjchandra XLPGE_STAT("rxcf", nlm_sgmii_stats_rxcf, "Rx Control Frames"); 1179233545Sjchandra XLPGE_STAT("rxpf", nlm_sgmii_stats_rxpf, "Rx Pause Frames"); 1180233545Sjchandra XLPGE_STAT("rxuo", nlm_sgmii_stats_rxuo, "Rx Unknown Opcode"); 1181233545Sjchandra XLPGE_STAT("raln", nlm_sgmii_stats_raln, "Rx Alignment Errors"); 1182233545Sjchandra XLPGE_STAT("rflr", nlm_sgmii_stats_rflr, "Rx Framelength Errors"); 1183233545Sjchandra XLPGE_STAT("rcde", nlm_sgmii_stats_rcde, "Rx Code Errors"); 1184233545Sjchandra XLPGE_STAT("rcse", nlm_sgmii_stats_rcse, "Rx Carrier Sense Errors"); 1185233545Sjchandra XLPGE_STAT("rund", nlm_sgmii_stats_rund, "Rx Undersize Packet Errors"); 1186233545Sjchandra XLPGE_STAT("rovr", nlm_sgmii_stats_rovr, "Rx Oversize Packet Errors"); 1187233545Sjchandra XLPGE_STAT("rfrg", nlm_sgmii_stats_rfrg, "Rx Fragments"); 1188233545Sjchandra XLPGE_STAT("rjbr", nlm_sgmii_stats_rjbr, "Rx Jabber"); 1189233545Sjchandra 1190233545Sjchandra XLPGE_STAT("tbyt", nlm_sgmii_stats_tbyt, "Tx Bytes"); 1191233545Sjchandra XLPGE_STAT("tpkt", nlm_sgmii_stats_tpkt, "Tx Packets"); 1192233545Sjchandra XLPGE_STAT("tmca", nlm_sgmii_stats_tmca, "Tx Multicast Packets"); 1193233545Sjchandra XLPGE_STAT("tbca", nlm_sgmii_stats_tbca, "Tx Broadcast Packets"); 1194233545Sjchandra XLPGE_STAT("txpf", nlm_sgmii_stats_txpf, "Tx Pause Frame"); 1195233545Sjchandra XLPGE_STAT("tdfr", nlm_sgmii_stats_tdfr, "Tx Deferral Packets"); 1196233545Sjchandra XLPGE_STAT("tedf", nlm_sgmii_stats_tedf, "Tx Excessive Deferral Pkts"); 1197233545Sjchandra XLPGE_STAT("tscl", nlm_sgmii_stats_tscl, "Tx Single Collisions"); 1198233545Sjchandra XLPGE_STAT("tmcl", nlm_sgmii_stats_tmcl, "Tx Multiple Collisions"); 1199233545Sjchandra XLPGE_STAT("tlcl", nlm_sgmii_stats_tlcl, "Tx Late Collision Pkts"); 1200233545Sjchandra XLPGE_STAT("txcl", nlm_sgmii_stats_txcl, "Tx Excessive Collisions"); 1201233545Sjchandra XLPGE_STAT("tncl", nlm_sgmii_stats_tncl, "Tx Total Collisions"); 1202233545Sjchandra XLPGE_STAT("tjbr", nlm_sgmii_stats_tjbr, "Tx Jabber Frames"); 1203233545Sjchandra XLPGE_STAT("tfcs", nlm_sgmii_stats_tfcs, "Tx FCS Errors"); 1204233545Sjchandra XLPGE_STAT("txcf", nlm_sgmii_stats_txcf, "Tx Control Frames"); 1205233545Sjchandra XLPGE_STAT("tovr", nlm_sgmii_stats_tovr, "Tx Oversize Frames"); 1206233545Sjchandra XLPGE_STAT("tund", nlm_sgmii_stats_tund, "Tx Undersize Frames"); 1207233545Sjchandra XLPGE_STAT("tfrg", nlm_sgmii_stats_tfrg, "Tx Fragments"); 1208233545Sjchandra#undef XLPGE_STAT 1209233545Sjchandra} 1210233545Sjchandra 1211233545Sjchandrastatic int 1212233545Sjchandranlm_xlpge_attach(device_t dev) 1213233545Sjchandra{ 1214233545Sjchandra struct xlp_port_ivars *pv; 1215233545Sjchandra struct nlm_xlpge_softc *sc; 1216233545Sjchandra int port; 1217233545Sjchandra 1218233545Sjchandra pv = device_get_ivars(dev); 1219233545Sjchandra sc = device_get_softc(dev); 1220233545Sjchandra sc->xlpge_dev = dev; 1221233545Sjchandra sc->mii_bus = NULL; 1222233545Sjchandra sc->block = pv->block; 1223233545Sjchandra sc->node = pv->node; 1224233545Sjchandra sc->port = pv->port; 1225233545Sjchandra sc->type = pv->type; 1226233545Sjchandra sc->xlpge_if = NULL; 1227233545Sjchandra sc->phy_addr = pv->phy_addr; 1228233545Sjchandra sc->mdio_bus = pv->mdio_bus; 1229233545Sjchandra sc->portcfg = nae_port_config; 1230233545Sjchandra sc->hw_parser_en = pv->hw_parser_en; 1231233545Sjchandra 1232233545Sjchandra /* default settings */ 1233233545Sjchandra sc->speed = NLM_SGMII_SPEED_10; 1234233545Sjchandra sc->duplexity = NLM_SGMII_DUPLEX_FULL; 1235233545Sjchandra sc->link = NLM_LINK_DOWN; 1236233545Sjchandra sc->flowctrl = NLM_FLOWCTRL_DISABLED; 1237233545Sjchandra 1238233545Sjchandra sc->network_sc = device_get_softc(device_get_parent(dev)); 1239233545Sjchandra sc->base_addr = sc->network_sc->base; 1240233545Sjchandra sc->prepad_en = sc->network_sc->prepad_en; 1241233545Sjchandra sc->prepad_size = sc->network_sc->prepad_size; 1242233545Sjchandra 1243314667Savg callout_init(&sc->xlpge_callout, 1); 1244233545Sjchandra 1245233545Sjchandra XLPGE_LOCK_INIT(sc, device_get_nameunit(dev)); 1246233545Sjchandra 1247233545Sjchandra port = (sc->block*4)+sc->port; 1248233545Sjchandra sc->nfree_desc = nae_port_config[port].num_free_descs; 1249233545Sjchandra sc->txq = nae_port_config[port].txq; 1250233545Sjchandra sc->rxfreeq = nae_port_config[port].rxfreeq; 1251233545Sjchandra 1252233545Sjchandra nlm_xlpge_submit_rx_free_desc(sc, sc->nfree_desc); 1253233545Sjchandra if (sc->hw_parser_en) 1254233545Sjchandra nlm_enable_hardware_parser_per_port(sc->base_addr, 1255233545Sjchandra sc->block, sc->port); 1256233545Sjchandra 1257233545Sjchandra nlm_xlpge_ifinit(sc); 1258233545Sjchandra ifp_ports[port].xlpge_sc = sc; 1259233545Sjchandra nlm_xlpge_mii_init(dev, sc); 1260245881Sjchandra 1261233545Sjchandra nlm_xlpge_setup_stats_sysctl(dev, sc); 1262233545Sjchandra 1263233545Sjchandra return (0); 1264233545Sjchandra} 1265233545Sjchandra 1266233545Sjchandrastatic int 1267233545Sjchandranlm_xlpge_detach(device_t dev) 1268233545Sjchandra{ 1269233545Sjchandra return (0); 1270233545Sjchandra} 1271233545Sjchandra 1272233545Sjchandrastatic int 1273233545Sjchandranlm_xlpge_suspend(device_t dev) 1274233545Sjchandra{ 1275233545Sjchandra return (0); 1276233545Sjchandra} 1277233545Sjchandra 1278233545Sjchandrastatic int 1279233545Sjchandranlm_xlpge_resume(device_t dev) 1280233545Sjchandra{ 1281233545Sjchandra return (0); 1282233545Sjchandra} 1283233545Sjchandra 1284233545Sjchandrastatic int 1285233545Sjchandranlm_xlpge_shutdown(device_t dev) 1286233545Sjchandra{ 1287233545Sjchandra return (0); 1288233545Sjchandra} 1289233545Sjchandra 1290233545Sjchandra/* 1291233545Sjchandra * miibus function with custom implementation 1292233545Sjchandra */ 1293233545Sjchandrastatic int 1294233545Sjchandranlm_xlpge_mii_read(struct device *dev, int phyaddr, int regidx) 1295233545Sjchandra{ 1296233545Sjchandra struct nlm_xlpge_softc *sc; 1297233545Sjchandra int val; 1298233545Sjchandra 1299233545Sjchandra sc = device_get_softc(dev); 1300233545Sjchandra if (sc->type == SGMIIC) 1301233545Sjchandra val = nlm_gmac_mdio_read(sc->base_addr, sc->mdio_bus, 1302233545Sjchandra BLOCK_7, LANE_CFG, phyaddr, regidx); 1303233545Sjchandra else 1304233545Sjchandra val = 0xffff; 1305233545Sjchandra 1306233545Sjchandra return (val); 1307233545Sjchandra} 1308233545Sjchandra 1309233545Sjchandrastatic int 1310233545Sjchandranlm_xlpge_mii_write(struct device *dev, int phyaddr, int regidx, int val) 1311233545Sjchandra{ 1312233545Sjchandra struct nlm_xlpge_softc *sc; 1313233545Sjchandra 1314233545Sjchandra sc = device_get_softc(dev); 1315233545Sjchandra if (sc->type == SGMIIC) 1316233545Sjchandra nlm_gmac_mdio_write(sc->base_addr, sc->mdio_bus, BLOCK_7, 1317233545Sjchandra LANE_CFG, phyaddr, regidx, val); 1318233545Sjchandra 1319233545Sjchandra return (0); 1320233545Sjchandra} 1321233545Sjchandra 1322233545Sjchandrastatic void 1323233545Sjchandranlm_xlpge_mii_statchg(device_t dev) 1324233545Sjchandra{ 1325233545Sjchandra struct nlm_xlpge_softc *sc; 1326233545Sjchandra struct mii_data *mii; 1327233545Sjchandra char *speed, *duplexity; 1328233545Sjchandra 1329233545Sjchandra sc = device_get_softc(dev); 1330233545Sjchandra if (sc->mii_bus == NULL) 1331233545Sjchandra return; 1332233545Sjchandra 1333233545Sjchandra mii = device_get_softc(sc->mii_bus); 1334233545Sjchandra if (mii->mii_media_status & IFM_ACTIVE) { 1335233545Sjchandra if (IFM_SUBTYPE(mii->mii_media_active) == IFM_10_T) { 1336233545Sjchandra sc->speed = NLM_SGMII_SPEED_10; 1337245880Sjchandra speed = "10Mbps"; 1338233545Sjchandra } else if (IFM_SUBTYPE(mii->mii_media_active) == IFM_100_TX) { 1339233545Sjchandra sc->speed = NLM_SGMII_SPEED_100; 1340245880Sjchandra speed = "100Mbps"; 1341233545Sjchandra } else { /* default to 1G */ 1342233545Sjchandra sc->speed = NLM_SGMII_SPEED_1000; 1343245880Sjchandra speed = "1Gbps"; 1344233545Sjchandra } 1345233545Sjchandra 1346233545Sjchandra if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) { 1347233545Sjchandra sc->duplexity = NLM_SGMII_DUPLEX_FULL; 1348233545Sjchandra duplexity = "full"; 1349233545Sjchandra } else { 1350233545Sjchandra sc->duplexity = NLM_SGMII_DUPLEX_HALF; 1351233545Sjchandra duplexity = "half"; 1352233545Sjchandra } 1353233545Sjchandra 1354245880Sjchandra printf("Port [%d, %d] setup with speed=%s duplex=%s\n", 1355233545Sjchandra sc->block, sc->port, speed, duplexity); 1356233545Sjchandra 1357233545Sjchandra nlm_nae_setup_mac(sc->base_addr, sc->block, sc->port, 0, 1, 1, 1358245881Sjchandra sc->speed, sc->duplexity); 1359233545Sjchandra } 1360233545Sjchandra} 1361233545Sjchandra 1362233545Sjchandra/* 1363233545Sjchandra * xlpge support function implementations 1364233545Sjchandra */ 1365233545Sjchandrastatic void 1366233545Sjchandranlm_xlpge_release_mbuf(uint64_t paddr) 1367233545Sjchandra{ 1368233545Sjchandra uint64_t mag, desc, mbuf; 1369233545Sjchandra 1370233545Sjchandra paddr += (XLP_NTXFRAGS - 3) * sizeof(uint64_t); 1371233545Sjchandra mag = nlm_paddr_ld(paddr); 1372233545Sjchandra desc = nlm_paddr_ld(paddr + sizeof(uint64_t)); 1373233545Sjchandra mbuf = nlm_paddr_ld(paddr + 2 * sizeof(uint64_t)); 1374233545Sjchandra 1375233545Sjchandra if (mag != 0xf00bad) { 1376233545Sjchandra /* somebody else packet Error - FIXME in intialization */ 1377233545Sjchandra printf("cpu %d: ERR Tx packet paddr %jx, mag %jx, desc %jx mbuf %jx\n", 1378233545Sjchandra nlm_cpuid(), (uintmax_t)paddr, (uintmax_t)mag, 1379233545Sjchandra (intmax_t)desc, (uintmax_t)mbuf); 1380233545Sjchandra return; 1381233545Sjchandra } 1382233545Sjchandra m_freem((struct mbuf *)(uintptr_t)mbuf); 1383233545Sjchandra uma_zfree(nl_tx_desc_zone, (void *)(uintptr_t)desc); 1384233545Sjchandra} 1385233545Sjchandra 1386233545Sjchandrastatic void 1387233545Sjchandranlm_xlpge_rx(struct nlm_xlpge_softc *sc, int port, vm_paddr_t paddr, int len) 1388233545Sjchandra{ 1389233545Sjchandra struct ifnet *ifp; 1390233545Sjchandra struct mbuf *m; 1391233545Sjchandra vm_offset_t temp; 1392233545Sjchandra unsigned long mag; 1393233545Sjchandra int prepad_size; 1394233545Sjchandra 1395233545Sjchandra ifp = sc->xlpge_if; 1396233545Sjchandra temp = nlm_paddr_ld(paddr - NAE_CACHELINE_SIZE); 1397233545Sjchandra mag = nlm_paddr_ld(paddr - NAE_CACHELINE_SIZE + sizeof(uint64_t)); 1398233545Sjchandra 1399233545Sjchandra m = (struct mbuf *)(intptr_t)temp; 1400233545Sjchandra if (mag != 0xf00bad) { 1401233545Sjchandra /* somebody else packet Error - FIXME in intialization */ 1402233545Sjchandra printf("cpu %d: ERR Rx packet paddr %jx, temp %p, mag %lx\n", 1403233545Sjchandra nlm_cpuid(), (uintmax_t)paddr, (void *)temp, mag); 1404233545Sjchandra return; 1405233545Sjchandra } 1406233545Sjchandra 1407233545Sjchandra m->m_pkthdr.rcvif = ifp; 1408233545Sjchandra 1409233545Sjchandra#ifdef DUMP_PACKET 1410233545Sjchandra { 1411233545Sjchandra int i = 0, j = 64; 1412233545Sjchandra unsigned char *buf = (char *)m->m_data; 1413233545Sjchandra printf("(cpu_%d: nlge_rx, !RX_COPY) Rx Packet: length=%d\n", 1414233545Sjchandra nlm_cpuid(), len); 1415233545Sjchandra if (len < j) 1416233545Sjchandra j = len; 1417233545Sjchandra if (sc->prepad_en) 1418233545Sjchandra j += ((sc->prepad_size + 1) * 16); 1419233545Sjchandra for (i = 0; i < j; i++) { 1420233545Sjchandra if (i && (i % 16) == 0) 1421233545Sjchandra printf("\n"); 1422233545Sjchandra printf("%02x ", buf[i]); 1423233545Sjchandra } 1424233545Sjchandra printf("\n"); 1425233545Sjchandra } 1426233545Sjchandra#endif 1427233545Sjchandra 1428233545Sjchandra if (sc->prepad_en) { 1429233545Sjchandra prepad_size = ((sc->prepad_size + 1) * 16); 1430233545Sjchandra m->m_data += prepad_size; 1431233545Sjchandra m->m_pkthdr.len = m->m_len = (len - prepad_size); 1432233545Sjchandra } else 1433233545Sjchandra m->m_pkthdr.len = m->m_len = len; 1434233545Sjchandra 1435233545Sjchandra /*atomic_incr_long(&ifp->if_ipackets);*/ 1436233545Sjchandra ifp->if_ipackets++; 1437233545Sjchandra#ifdef XLP_DRIVER_LOOPBACK 1438233545Sjchandra if (port == 16 || port == 17) 1439233545Sjchandra (*ifp->if_input)(ifp, m); 1440233545Sjchandra else 1441233545Sjchandra xlpge_tx(ifp, m); 1442233545Sjchandra#else 1443233545Sjchandra (*ifp->if_input)(ifp, m); 1444233545Sjchandra#endif 1445233545Sjchandra} 1446233545Sjchandra 1447233545Sjchandravoid 1448233545Sjchandranlm_xlpge_submit_rx_free_desc(struct nlm_xlpge_softc *sc, int num) 1449233545Sjchandra{ 1450233545Sjchandra int i, size, ret, n; 1451233545Sjchandra struct nlm_fmn_msg msg; 1452233545Sjchandra void *ptr; 1453233545Sjchandra 1454233545Sjchandra for(i = 0; i < num; i++) { 1455233545Sjchandra memset(&msg, 0, sizeof(msg)); 1456233545Sjchandra ptr = get_buf(); 1457233545Sjchandra if (!ptr) { 1458233545Sjchandra device_printf(sc->xlpge_dev, "Cannot allocate mbuf\n"); 1459233545Sjchandra break; 1460233545Sjchandra } 1461233545Sjchandra 1462233545Sjchandra msg.msg[0] = vtophys(ptr); 1463233545Sjchandra if (msg.msg[0] == 0) { 1464233545Sjchandra printf("Bad ptr for %p\n", ptr); 1465233545Sjchandra break; 1466233545Sjchandra } 1467233545Sjchandra size = 1; 1468233545Sjchandra 1469233545Sjchandra n = 0; 1470233545Sjchandra while (1) { 1471233545Sjchandra /* on success returns 1, else 0 */ 1472233545Sjchandra ret = nlm_fmn_msgsend(sc->rxfreeq, size, 0, &msg); 1473233545Sjchandra if (ret == 0) 1474233545Sjchandra break; 1475233545Sjchandra if (n++ > 10000) { 1476233545Sjchandra printf("Too many credit fails for send free desc\n"); 1477233545Sjchandra break; 1478233545Sjchandra } 1479233545Sjchandra } 1480233545Sjchandra } 1481233545Sjchandra} 1482233545Sjchandra 1483233545Sjchandravoid 1484233545Sjchandranlm_xlpge_msgring_handler(int vc, int size, int code, int src_id, 1485233545Sjchandra struct nlm_fmn_msg *msg, void *data) 1486233545Sjchandra{ 1487233545Sjchandra uint64_t phys_addr; 1488233545Sjchandra struct nlm_xlpnae_softc *sc; 1489233545Sjchandra struct nlm_xlpge_softc *xlpge_sc; 1490233545Sjchandra struct ifnet *ifp; 1491233545Sjchandra uint32_t context; 1492233545Sjchandra uint32_t port = 0; 1493233545Sjchandra uint32_t length; 1494233545Sjchandra 1495233545Sjchandra sc = (struct nlm_xlpnae_softc *)data; 1496233545Sjchandra KASSERT(sc != NULL, ("Null sc in msgring handler")); 1497233545Sjchandra 1498233545Sjchandra if (size == 1) { /* process transmit complete */ 1499233545Sjchandra phys_addr = msg->msg[0] & 0xffffffffffULL; 1500233545Sjchandra 1501233545Sjchandra /* context is SGMII_RCV_CONTEXT_NUM + three bit vlan type 1502233545Sjchandra * or vlan priority 1503233545Sjchandra */ 1504233545Sjchandra context = (msg->msg[0] >> 40) & 0x3fff; 1505233545Sjchandra port = cntx2port[context]; 1506233545Sjchandra 1507233545Sjchandra if (port >= XLP_MAX_PORTS) { 1508233545Sjchandra printf("%s:%d Bad port %d (context=%d)\n", 1509233545Sjchandra __func__, __LINE__, port, context); 1510233545Sjchandra return; 1511233545Sjchandra } 1512233545Sjchandra ifp = ifp_ports[port].xlpge_if; 1513233545Sjchandra xlpge_sc = ifp_ports[port].xlpge_sc; 1514233545Sjchandra 1515233545Sjchandra nlm_xlpge_release_mbuf(phys_addr); 1516233545Sjchandra 1517233545Sjchandra /*atomic_incr_long(&ifp->if_opackets);*/ 1518233545Sjchandra ifp->if_opackets++; 1519233545Sjchandra 1520233545Sjchandra } else if (size > 1) { /* Recieve packet */ 1521245884Sjchandra phys_addr = msg->msg[1] & 0xffffffffc0ULL; 1522233545Sjchandra length = (msg->msg[1] >> 40) & 0x3fff; 1523233545Sjchandra length -= MAC_CRC_LEN; 1524233545Sjchandra 1525233545Sjchandra /* context is SGMII_RCV_CONTEXT_NUM + three bit vlan type 1526233545Sjchandra * or vlan priority 1527233545Sjchandra */ 1528233545Sjchandra context = (msg->msg[1] >> 54) & 0x3ff; 1529233545Sjchandra port = cntx2port[context]; 1530233545Sjchandra 1531233545Sjchandra if (port >= XLP_MAX_PORTS) { 1532233545Sjchandra printf("%s:%d Bad port %d (context=%d)\n", 1533233545Sjchandra __func__, __LINE__, port, context); 1534233545Sjchandra return; 1535233545Sjchandra } 1536233545Sjchandra 1537233545Sjchandra ifp = ifp_ports[port].xlpge_if; 1538233545Sjchandra xlpge_sc = ifp_ports[port].xlpge_sc; 1539233545Sjchandra 1540233545Sjchandra nlm_xlpge_rx(xlpge_sc, port, phys_addr, length); 1541233545Sjchandra /* return back a free descriptor to NA */ 1542233545Sjchandra nlm_xlpge_submit_rx_free_desc(xlpge_sc, 1); 1543233545Sjchandra } 1544233545Sjchandra} 1545