if_cnmac.c revision 1.20
1/* $NetBSD: if_cnmac.c,v 1.20 2020/06/05 09:18:35 simonb Exp $ */ 2 3#include <sys/cdefs.h> 4#if 0 5__KERNEL_RCSID(0, "$NetBSD: if_cnmac.c,v 1.20 2020/06/05 09:18:35 simonb Exp $"); 6#endif 7 8#include "opt_octeon.h" 9 10#ifdef CNMAC_DEBUG 11 12#ifndef DIAGNOSTIC 13#define DIAGNOSTIC 14#endif 15 16#ifndef DEBUG 17#define DEBUG 18#endif 19 20#endif 21 22/* 23 * If no free send buffer is available, free all the sent buffers and bail out. 24 */ 25#define CNMAC_SEND_QUEUE_CHECK 26 27/* XXX XXX XXX XXX XXX XXX */ 28 29#include <sys/param.h> 30#include <sys/systm.h> 31#include <sys/pool.h> 32#include <sys/mbuf.h> 33#include <sys/malloc.h> 34#include <sys/kernel.h> 35#include <sys/socket.h> 36#include <sys/ioctl.h> 37#include <sys/errno.h> 38#include <sys/device.h> 39#include <sys/queue.h> 40#include <sys/conf.h> 41#include <sys/sysctl.h> 42#include <sys/syslog.h> 43 44#include <net/if.h> 45#include <net/if_dl.h> 46#include <net/if_media.h> 47#include <net/if_ether.h> 48#include <net/route.h> 49#include <net/bpf.h> 50 51#include <netinet/in.h> 52#include <netinet/in_systm.h> 53#include <netinet/in_var.h> 54#include <netinet/ip.h> 55 56#include <sys/bus.h> 57#include <machine/intr.h> 58#include <machine/endian.h> 59#include <machine/locore.h> 60 61#include <dev/mii/mii.h> 62#include <dev/mii/miivar.h> 63 64#include <mips/cpuregs.h> 65 66#include <mips/cavium/dev/octeon_asxreg.h> 67#include <mips/cavium/dev/octeon_ciureg.h> 68#include <mips/cavium/dev/octeon_npireg.h> 69#include <mips/cavium/dev/octeon_gmxreg.h> 70#include <mips/cavium/dev/octeon_ipdreg.h> 71#include <mips/cavium/dev/octeon_pipreg.h> 72#include <mips/cavium/dev/octeon_powreg.h> 73#include <mips/cavium/dev/octeon_faureg.h> 74#include <mips/cavium/dev/octeon_fpareg.h> 75#include <mips/cavium/dev/octeon_bootbusreg.h> 76#include <mips/cavium/include/iobusvar.h> 77#include <mips/cavium/octeonvar.h> 78#include <mips/cavium/dev/octeon_fpavar.h> 79#include <mips/cavium/dev/octeon_gmxvar.h> 80#include <mips/cavium/dev/octeon_fauvar.h> 81#include <mips/cavium/dev/octeon_powvar.h> 82#include <mips/cavium/dev/octeon_ipdvar.h> 83#include <mips/cavium/dev/octeon_pipvar.h> 84#include <mips/cavium/dev/octeon_pkovar.h> 85#include <mips/cavium/dev/octeon_asxvar.h> 86#include <mips/cavium/dev/octeon_smivar.h> 87#include <mips/cavium/dev/if_cnmacvar.h> 88 89#ifdef CNMAC_DEBUG 90#define CNMAC_KASSERT(x) KASSERT(x) 91#define CNMAC_KDASSERT(x) KDASSERT(x) 92#else 93#define CNMAC_KASSERT(x) 94#define CNMAC_KDASSERT(x) 95#endif 96 97/* 98 * Set the PKO to think command buffers are an odd length. This makes it so we 99 * never have to divide a comamnd across two buffers. 100 */ 101#define OCTEON_POOL_NWORDS_CMD \ 102 (((uint32_t)OCTEON_POOL_SIZE_CMD / sizeof(uint64_t)) - 1) 103#define FPA_COMMAND_BUFFER_POOL_NWORDS OCTEON_POOL_NWORDS_CMD /* XXX */ 104 105static void cnmac_buf_init(struct cnmac_softc *); 106 107static int cnmac_match(device_t, struct cfdata *, void *); 108static void cnmac_attach(device_t, device_t, void *); 109static void cnmac_pip_init(struct cnmac_softc *); 110static void cnmac_ipd_init(struct cnmac_softc *); 111static void cnmac_pko_init(struct cnmac_softc *); 112static void cnmac_asx_init(struct cnmac_softc *); 113static void cnmac_smi_init(struct cnmac_softc *); 114 115static void cnmac_board_mac_addr(uint8_t *, size_t, struct cnmac_softc *); 116 117static int cnmac_mii_readreg(device_t, int, int, uint16_t *); 118static int cnmac_mii_writereg(device_t, int, int, uint16_t); 119static void cnmac_mii_statchg(struct ifnet *); 120 121static int cnmac_mediainit(struct cnmac_softc *); 122static void cnmac_mediastatus(struct ifnet *, struct ifmediareq *); 123 124static inline void cnmac_send_queue_flush_prefetch(struct cnmac_softc *); 125static inline void cnmac_send_queue_flush_fetch(struct cnmac_softc *); 126static inline void cnmac_send_queue_flush(struct cnmac_softc *); 127static inline void cnmac_send_queue_flush_sync(struct cnmac_softc *); 128static inline int cnmac_send_queue_is_full(struct cnmac_softc *); 129static inline void cnmac_send_queue_add(struct cnmac_softc *, struct mbuf *, 130 uint64_t *); 131static inline void cnmac_send_queue_del(struct cnmac_softc *, struct mbuf **, 132 uint64_t **); 133static inline int cnmac_buf_free_work(struct cnmac_softc *, uint64_t *, 134 uint64_t); 135static inline void cnmac_buf_ext_free_m(struct mbuf *, void *, size_t, void *); 136static inline void cnmac_buf_ext_free_ext(struct mbuf *, void *, size_t, 137 void *); 138 139static int cnmac_ioctl(struct ifnet *, u_long, void *); 140static void cnmac_watchdog(struct ifnet *); 141static int cnmac_init(struct ifnet *); 142static void cnmac_stop(struct ifnet *, int); 143static void cnmac_start(struct ifnet *); 144 145static inline int cnmac_send_cmd(struct cnmac_softc *, uint64_t, uint64_t, 146 int *); 147static inline uint64_t cnmac_send_makecmd_w1(int, paddr_t); 148static inline uint64_t cnmac_send_makecmd_w0(uint64_t, uint64_t, size_t, int); 149static inline int cnmac_send_makecmd_gbuf(struct cnmac_softc *, struct mbuf *, 150 uint64_t *, int *); 151static inline int cnmac_send_makecmd(struct cnmac_softc *, struct mbuf *, 152 uint64_t *, uint64_t *, uint64_t *); 153static inline int cnmac_send_buf(struct cnmac_softc *, struct mbuf *, 154 uint64_t *, int *); 155static inline int cnmac_send(struct cnmac_softc *, struct mbuf *, int *); 156 157static int cnmac_reset(struct cnmac_softc *); 158static int cnmac_configure(struct cnmac_softc *); 159static int cnmac_configure_common(struct cnmac_softc *); 160 161static void cnmac_tick_free(void *); 162static void cnmac_tick_misc(void *); 163 164static inline int cnmac_recv_mbuf(struct cnmac_softc *, uint64_t *, 165 struct mbuf **); 166static inline int cnmac_recv_check_code(struct cnmac_softc *, uint64_t); 167static inline int cnmac_recv_check_jumbo(struct cnmac_softc *, uint64_t); 168static inline int cnmac_recv_check_link(struct cnmac_softc *, uint64_t); 169static inline int cnmac_recv_check(struct cnmac_softc *, uint64_t); 170static inline int cnmac_recv(struct cnmac_softc *, uint64_t *); 171static void cnmac_recv_redir(struct ifnet *, struct mbuf *); 172static inline void cnmac_recv_intr(void *, uint64_t *); 173 174/* Device driver context */ 175static struct cnmac_softc *cnmac_gsc[GMX_PORT_NUNITS]; 176static void *cnmac_pow_recv_ih; 177 178/* sysctl'able parameters */ 179int cnmac_param_pko_cmd_w0_n2 = 1; 180int cnmac_param_pip_dyn_rs = 1; 181int cnmac_param_redir = 0; 182int cnmac_param_pktbuf = 0; 183int cnmac_param_rate = 0; 184int cnmac_param_intr = 0; 185 186CFATTACH_DECL_NEW(cnmac, sizeof(struct cnmac_softc), 187 cnmac_match, cnmac_attach, NULL, NULL); 188 189#ifdef CNMAC_DEBUG 190 191static const struct octeon_evcnt_entry octeon_evcnt_entries[] = { 192#define _ENTRY(name, type, parent, descr) \ 193 OCTEON_EVCNT_ENTRY(struct cnmac_softc, name, type, parent, descr) 194 _ENTRY(rx, MISC, NULL, "rx"), 195 _ENTRY(rxint, INTR, NULL, "rx intr"), 196 _ENTRY(rxrs, MISC, NULL, "rx dynamic short"), 197 _ENTRY(rxbufpkalloc, MISC, NULL, "rx buf pkt alloc"), 198 _ENTRY(rxbufpkput, MISC, NULL, "rx buf pkt put"), 199 _ENTRY(rxbufwqalloc, MISC, NULL, "rx buf wqe alloc"), 200 _ENTRY(rxbufwqput, MISC, NULL, "rx buf wqe put"), 201 _ENTRY(rxerrcode, MISC, NULL, "rx code error"), 202 _ENTRY(rxerrfix, MISC, NULL, "rx fixup error"), 203 _ENTRY(rxerrjmb, MISC, NULL, "rx jmb error"), 204 _ENTRY(rxerrlink, MISC, NULL, "rx link error"), 205 _ENTRY(rxerroff, MISC, NULL, "rx offload error"), 206 _ENTRY(rxonperrshort, MISC, NULL, "rx onp fixup short error"), 207 _ENTRY(rxonperrpreamble, MISC, NULL, "rx onp fixup preamble error"), 208 _ENTRY(rxonperrcrc, MISC, NULL, "rx onp fixup crc error"), 209 _ENTRY(rxonperraddress, MISC, NULL, "rx onp fixup address error"), 210 _ENTRY(rxonponp, MISC, NULL, "rx onp fixup onp packets"), 211 _ENTRY(rxonpok, MISC, NULL, "rx onp fixup success packets"), 212 _ENTRY(tx, MISC, NULL, "tx"), 213 _ENTRY(txadd, MISC, NULL, "tx add"), 214 _ENTRY(txbufcballoc, MISC, NULL, "tx buf cb alloc"), 215 _ENTRY(txbufcbget, MISC, NULL, "tx buf cb get"), 216 _ENTRY(txbufgballoc, MISC, NULL, "tx buf gb alloc"), 217 _ENTRY(txbufgbget, MISC, NULL, "tx buf gb get"), 218 _ENTRY(txbufgbput, MISC, NULL, "tx buf gb put"), 219 _ENTRY(txdel, MISC, NULL, "tx del"), 220 _ENTRY(txerr, MISC, NULL, "tx error"), 221 _ENTRY(txerrcmd, MISC, NULL, "tx cmd error"), 222 _ENTRY(txerrgbuf, MISC, NULL, "tx gbuf error"), 223 _ENTRY(txerrlink, MISC, NULL, "tx link error"), 224 _ENTRY(txerrmkcmd, MISC, NULL, "tx makecmd error"), 225#undef _ENTRY 226}; 227#endif 228 229/* ---- buffer management */ 230 231static const struct cnmac_pool_param { 232 int poolno; 233 size_t size; 234 size_t nelems; 235} cnmac_pool_params[] = { 236#define _ENTRY(x) { OCTEON_POOL_NO_##x, OCTEON_POOL_SIZE_##x, OCTEON_POOL_NELEMS_##x } 237 _ENTRY(PKT), 238 _ENTRY(WQE), 239 _ENTRY(CMD), 240 _ENTRY(SG) 241#undef _ENTRY 242}; 243struct octfpa_buf *cnmac_pools[8/* XXX */]; 244#define cnmac_fb_pkt cnmac_pools[OCTEON_POOL_NO_PKT] 245#define cnmac_fb_wqe cnmac_pools[OCTEON_POOL_NO_WQE] 246#define cnmac_fb_cmd cnmac_pools[OCTEON_POOL_NO_CMD] 247#define cnmac_fb_sg cnmac_pools[OCTEON_POOL_NO_SG] 248 249static void 250cnmac_buf_init(struct cnmac_softc *sc) 251{ 252 static int once; 253 int i; 254 const struct cnmac_pool_param *pp; 255 struct octfpa_buf *fb; 256 257 if (once == 1) 258 return; 259 once = 1; 260 261 for (i = 0; i < (int)__arraycount(cnmac_pool_params); i++) { 262 pp = &cnmac_pool_params[i]; 263 octfpa_buf_init(pp->poolno, pp->size, pp->nelems, &fb); 264 cnmac_pools[i] = fb; 265 } 266} 267 268/* ---- autoconf */ 269 270static int 271cnmac_match(device_t parent, struct cfdata *match, void *aux) 272{ 273 struct octgmx_attach_args *ga = aux; 274 275 if (strcmp(match->cf_name, ga->ga_name) != 0) { 276 return 0; 277 } 278 return 1; 279} 280 281static void 282cnmac_attach(device_t parent, device_t self, void *aux) 283{ 284 struct cnmac_softc *sc = device_private(self); 285 struct octgmx_attach_args *ga = aux; 286 struct ifnet *ifp = &sc->sc_ethercom.ec_if; 287 prop_dictionary_t dict; 288 prop_object_t clk; 289 uint8_t enaddr[ETHER_ADDR_LEN]; 290 291 sc->sc_dev = self; 292 sc->sc_regt = ga->ga_regt; 293 sc->sc_port = ga->ga_portno; 294 sc->sc_port_type = ga->ga_port_type; 295 sc->sc_gmx = ga->ga_gmx; 296 sc->sc_gmx_port = ga->ga_gmx_port; 297 298 if (sc->sc_port >= CVMSEG_LM_ETHER_COUNT) { 299 /* 300 * If we got here, increase CVMSEG_LM_ETHER_COUNT 301 * in octeonvar.h . 302 */ 303 printf("%s: ERROR out of CVMSEG LM buffers\n", 304 device_xname(self)); 305 return; 306 } 307 308 sc->sc_init_flag = 0; 309 /* 310 * XXXUEBAYASI 311 * Setting PIP_IP_OFFSET[OFFSET] to 8 causes panic ... why??? 312 */ 313 sc->sc_ip_offset = 0/* XXX */; 314 315 if (MIPS_PRID_IMPL(mips_options.mips_cpu_id) <= MIPS_CN30XX) { 316 SET(sc->sc_quirks, CNMAC_QUIRKS_NO_PRE_ALIGN); 317 SET(sc->sc_quirks, CNMAC_QUIRKS_NO_RX_INBND); 318 } 319 320 cnmac_board_mac_addr(enaddr, sizeof(enaddr), sc); 321 printf("%s: Ethernet address %s\n", device_xname(sc->sc_dev), 322 ether_sprintf(enaddr)); 323 324 cnmac_gsc[sc->sc_port] = sc; 325 326 SIMPLEQ_INIT(&sc->sc_sendq); 327 sc->sc_soft_req_thresh = 15/* XXX */; 328 sc->sc_ext_callback_cnt = 0; 329 330 octgmx_stats_init(sc->sc_gmx_port); 331 332 callout_init(&sc->sc_tick_misc_ch, 0); 333 callout_init(&sc->sc_tick_free_ch, 0); 334 335 octfau_op_init(&sc->sc_fau_done, 336 OCTEON_CVMSEG_ETHER_OFFSET(sc->sc_port, csm_ether_fau_done), 337 OCT_FAU_REG_ADDR_END - (8 * (sc->sc_port + 1))/* XXX */); 338 octfau_op_set_8(&sc->sc_fau_done, 0); 339 340 cnmac_pip_init(sc); 341 cnmac_ipd_init(sc); 342 cnmac_pko_init(sc); 343 cnmac_asx_init(sc); 344 cnmac_smi_init(sc); 345 346 sc->sc_gmx_port->sc_ipd = sc->sc_ipd; 347 sc->sc_gmx_port->sc_port_asx = sc->sc_asx; 348 sc->sc_gmx_port->sc_port_mii = &sc->sc_mii; 349 sc->sc_gmx_port->sc_port_ec = &sc->sc_ethercom; 350 /* XXX */ 351 sc->sc_gmx_port->sc_quirks = sc->sc_quirks; 352 353 /* XXX */ 354 sc->sc_pow = &octpow_softc; 355 356 cnmac_mediainit(sc); 357 358 strncpy(ifp->if_xname, device_xname(sc->sc_dev), sizeof(ifp->if_xname)); 359 ifp->if_softc = sc; 360 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 361 ifp->if_ioctl = cnmac_ioctl; 362 ifp->if_start = cnmac_start; 363 ifp->if_watchdog = cnmac_watchdog; 364 ifp->if_init = cnmac_init; 365 ifp->if_stop = cnmac_stop; 366 IFQ_SET_MAXLEN(&ifp->if_snd, uimax(GATHER_QUEUE_SIZE, IFQ_MAXLEN)); 367 IFQ_SET_READY(&ifp->if_snd); 368 369 /* XXX: not yet tx checksum */ 370 ifp->if_capabilities = 371 IFCAP_CSUM_IPv4_Rx | IFCAP_CSUM_TCPv4_Rx | IFCAP_CSUM_UDPv4_Rx | 372 IFCAP_CSUM_TCPv6_Rx | IFCAP_CSUM_UDPv6_Rx; 373 374 /* 802.1Q VLAN-sized frames are supported */ 375 sc->sc_ethercom.ec_capabilities |= ETHERCAP_VLAN_MTU; 376 377 octgmx_set_mac_addr(sc->sc_gmx_port, enaddr); 378 379 if_attach(ifp); 380 ether_ifattach(ifp, enaddr); 381 octgmx_set_filter(sc->sc_gmx_port); 382 383 /* XXX */ 384 sc->sc_rate_recv_check_link_cap.tv_sec = 1; 385 sc->sc_rate_recv_check_jumbo_cap.tv_sec = 1; 386 sc->sc_rate_recv_check_code_cap.tv_sec = 1; 387 sc->sc_rate_recv_fixup_odd_nibble_short_cap.tv_sec = 1; 388 sc->sc_rate_recv_fixup_odd_nibble_preamble_cap.tv_sec = 1; 389 sc->sc_rate_recv_fixup_odd_nibble_crc_cap.tv_sec = 1; 390#ifdef CNMAC_DEBUG 391 sc->sc_rate_recv_fixup_odd_nibble_addr_cap.tv_sec = 1; 392#endif 393 /* XXX */ 394 395#if 1 396 cnmac_buf_init(sc); 397#endif 398 399 if (cnmac_pow_recv_ih == NULL) 400 cnmac_pow_recv_ih 401 = octpow_intr_establish(OCTEON_POW_GROUP_PIP, 402 IPL_NET, cnmac_recv_intr, NULL, NULL); 403 404 OCTEON_EVCNT_ATTACH_EVCNTS(sc, octeon_evcnt_entries, 405 device_xname(sc->sc_dev)); 406 407 dict = device_properties(sc->sc_gmx->sc_dev); 408 409 clk = prop_dictionary_get(dict, "rgmii-tx"); 410 KASSERT(clk != NULL); 411 sc->sc_gmx_port->sc_clk_tx_setting = prop_number_integer_value(clk); 412 clk = prop_dictionary_get(dict, "rgmii-rx"); 413 KASSERT(clk != NULL); 414 sc->sc_gmx_port->sc_clk_rx_setting = prop_number_integer_value(clk); 415} 416 417/* ---- submodules */ 418 419/* XXX */ 420static void 421cnmac_pip_init(struct cnmac_softc *sc) 422{ 423 struct octpip_attach_args pip_aa; 424 425 pip_aa.aa_port = sc->sc_port; 426 pip_aa.aa_regt = sc->sc_regt; 427 pip_aa.aa_tag_type = POW_TAG_TYPE_ORDERED/* XXX */; 428 pip_aa.aa_receive_group = OCTEON_POW_GROUP_PIP; 429 pip_aa.aa_ip_offset = sc->sc_ip_offset; 430 octpip_init(&pip_aa, &sc->sc_pip); 431} 432 433/* XXX */ 434static void 435cnmac_ipd_init(struct cnmac_softc *sc) 436{ 437 struct octipd_attach_args ipd_aa; 438 439 ipd_aa.aa_port = sc->sc_port; 440 ipd_aa.aa_regt = sc->sc_regt; 441 ipd_aa.aa_first_mbuff_skip = 184/* XXX */; 442 ipd_aa.aa_not_first_mbuff_skip = 0/* XXX */; 443 octipd_init(&ipd_aa, &sc->sc_ipd); 444} 445 446/* XXX */ 447static void 448cnmac_pko_init(struct cnmac_softc *sc) 449{ 450 struct octpko_attach_args pko_aa; 451 452 pko_aa.aa_port = sc->sc_port; 453 pko_aa.aa_regt = sc->sc_regt; 454 pko_aa.aa_cmdptr = &sc->sc_cmdptr; 455 pko_aa.aa_cmd_buf_pool = OCTEON_POOL_NO_CMD; 456 pko_aa.aa_cmd_buf_size = OCTEON_POOL_NWORDS_CMD; 457 octpko_init(&pko_aa, &sc->sc_pko); 458} 459 460/* XXX */ 461static void 462cnmac_asx_init(struct cnmac_softc *sc) 463{ 464 struct octasx_attach_args asx_aa; 465 466 asx_aa.aa_port = sc->sc_port; 467 asx_aa.aa_regt = sc->sc_regt; 468 octasx_init(&asx_aa, &sc->sc_asx); 469} 470 471static void 472cnmac_smi_init(struct cnmac_softc *sc) 473{ 474 struct octsmi_attach_args smi_aa; 475 476 smi_aa.aa_port = sc->sc_port; 477 smi_aa.aa_regt = sc->sc_regt; 478 octsmi_init(&smi_aa, &sc->sc_smi); 479 octsmi_set_clock(sc->sc_smi, 0x1464ULL); /* XXX */ 480} 481 482/* ---- XXX */ 483 484#define ADDR2UINT64(u, a) \ 485 do { \ 486 u = \ 487 (((uint64_t)a[0] << 40) | ((uint64_t)a[1] << 32) | \ 488 ((uint64_t)a[2] << 24) | ((uint64_t)a[3] << 16) | \ 489 ((uint64_t)a[4] << 8) | ((uint64_t)a[5] << 0)); \ 490 } while (0) 491#define UINT642ADDR(a, u) \ 492 do { \ 493 a[0] = (uint8_t)((u) >> 40); a[1] = (uint8_t)((u) >> 32); \ 494 a[2] = (uint8_t)((u) >> 24); a[3] = (uint8_t)((u) >> 16); \ 495 a[4] = (uint8_t)((u) >> 8); a[5] = (uint8_t)((u) >> 0); \ 496 } while (0) 497 498static void 499cnmac_board_mac_addr(uint8_t *enaddr, size_t size, struct cnmac_softc *sc) 500{ 501 prop_dictionary_t dict; 502 prop_data_t ea; 503 504 dict = device_properties(sc->sc_dev); 505 KASSERT(dict != NULL); 506 ea = prop_dictionary_get(dict, "mac-address"); 507 KASSERT(ea != NULL); 508 memcpy(enaddr, prop_data_data_nocopy(ea), size); 509} 510 511/* ---- media */ 512 513static int 514cnmac_mii_readreg(device_t self, int phy_addr, int reg, uint16_t *val) 515{ 516 struct cnmac_softc *sc = device_private(self); 517 518 return octsmi_read(sc->sc_smi, phy_addr, reg, val); 519} 520 521static int 522cnmac_mii_writereg(device_t self, int phy_addr, int reg, uint16_t val) 523{ 524 struct cnmac_softc *sc = device_private(self); 525 526 return octsmi_write(sc->sc_smi, phy_addr, reg, val); 527} 528 529static void 530cnmac_mii_statchg(struct ifnet *ifp) 531{ 532 struct cnmac_softc *sc = ifp->if_softc; 533 534 octpko_port_enable(sc->sc_pko, 0); 535 octgmx_port_enable(sc->sc_gmx_port, 0); 536 537 cnmac_reset(sc); 538 539 if (ISSET(ifp->if_flags, IFF_RUNNING)) 540 octgmx_set_filter(sc->sc_gmx_port); 541 542 octpko_port_enable(sc->sc_pko, 1); 543 octgmx_port_enable(sc->sc_gmx_port, 1); 544} 545 546static int 547cnmac_mediainit(struct cnmac_softc *sc) 548{ 549 struct ifnet *ifp = &sc->sc_ethercom.ec_if; 550 struct mii_data *mii = &sc->sc_mii; 551 prop_object_t phy; 552 553 mii->mii_ifp = ifp; 554 mii->mii_readreg = cnmac_mii_readreg; 555 mii->mii_writereg = cnmac_mii_writereg; 556 mii->mii_statchg = cnmac_mii_statchg; 557 sc->sc_ethercom.ec_mii = mii; 558 559 /* Initialize ifmedia structures. */ 560 ifmedia_init(&mii->mii_media, 0, ether_mediachange, cnmac_mediastatus); 561 562 phy = prop_dictionary_get(device_properties(sc->sc_dev), "phy-addr"); 563 KASSERT(phy != NULL); 564 565 mii_attach(sc->sc_dev, mii, 0xffffffff, prop_number_integer_value(phy), 566 MII_OFFSET_ANY, MIIF_DOPAUSE); 567 568 /* XXX XXX XXX */ 569 if (LIST_FIRST(&mii->mii_phys) != NULL) { 570 /* XXX XXX XXX */ 571 ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_AUTO); 572 /* XXX XXX XXX */ 573 } else { 574 /* XXX XXX XXX */ 575 ifmedia_add(&mii->mii_media, IFM_ETHER | IFM_NONE, 576 MII_MEDIA_NONE, NULL); 577 /* XXX XXX XXX */ 578 ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_NONE); 579 /* XXX XXX XXX */ 580 } 581 /* XXX XXX XXX */ 582 583 return 0; 584} 585 586static void 587cnmac_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr) 588{ 589 struct cnmac_softc *sc = ifp->if_softc; 590 591 mii_pollstat(&sc->sc_mii); 592 593 ifmr->ifm_status = sc->sc_mii.mii_media_status; 594 ifmr->ifm_active = sc->sc_mii.mii_media_active; 595 ifmr->ifm_active = (sc->sc_mii.mii_media_active & ~IFM_ETH_FMASK) | 596 sc->sc_gmx_port->sc_port_flowflags; 597} 598 599/* ---- send buffer garbage collection */ 600 601static inline void 602cnmac_send_queue_flush_prefetch(struct cnmac_softc *sc) 603{ 604 CNMAC_KASSERT(sc->sc_prefetch == 0); 605 octfau_op_inc_fetch_8(&sc->sc_fau_done, 0); 606 sc->sc_prefetch = 1; 607} 608 609static inline void 610cnmac_send_queue_flush_fetch(struct cnmac_softc *sc) 611{ 612#ifndef CNMAC_DEBUG 613 if (!sc->sc_prefetch) 614 return; 615#endif 616 CNMAC_KASSERT(sc->sc_prefetch == 1); 617 sc->sc_hard_done_cnt = octfau_op_inc_read_8(&sc->sc_fau_done); 618 CNMAC_KASSERT(sc->sc_hard_done_cnt <= 0); 619 sc->sc_prefetch = 0; 620} 621 622static inline void 623cnmac_send_queue_flush(struct cnmac_softc *sc) 624{ 625 struct ifnet *ifp = &sc->sc_ethercom.ec_if; 626 const int64_t sent_count = sc->sc_hard_done_cnt; 627 int i; 628 629 CNMAC_KASSERT(sc->sc_flush == 0); 630 CNMAC_KASSERT(sent_count <= 0); 631 632 for (i = 0; i < 0 - sent_count; i++) { 633 struct mbuf *m; 634 uint64_t *gbuf; 635 636 cnmac_send_queue_del(sc, &m, &gbuf); 637 638 octfpa_buf_put(cnmac_fb_sg, gbuf); 639 OCTEON_EVCNT_INC(sc, txbufgbput); 640 641 m_freem(m); 642 643 CLR(ifp->if_flags, IFF_OACTIVE); 644 } 645 646 octfau_op_inc_fetch_8(&sc->sc_fau_done, i); 647 sc->sc_flush = i; 648} 649 650static inline void 651cnmac_send_queue_flush_sync(struct cnmac_softc *sc) 652{ 653 if (sc->sc_flush == 0) 654 return; 655 656 CNMAC_KASSERT(sc->sc_flush > 0); 657 658 /* XXX XXX XXX */ 659 octfau_op_inc_read_8(&sc->sc_fau_done); 660 sc->sc_soft_req_cnt -= sc->sc_flush; 661 CNMAC_KASSERT(sc->sc_soft_req_cnt >= 0); 662 /* XXX XXX XXX */ 663 664 sc->sc_flush = 0; 665} 666 667static inline int 668cnmac_send_queue_is_full(struct cnmac_softc *sc) 669{ 670#ifdef CNMAC_SEND_QUEUE_CHECK 671 int64_t nofree_cnt; 672 673 nofree_cnt = sc->sc_soft_req_cnt + sc->sc_hard_done_cnt; 674 675 if (__predict_false(nofree_cnt == GATHER_QUEUE_SIZE - 1)) { 676 cnmac_send_queue_flush(sc); 677 OCTEON_EVCNT_INC(sc, txerrgbuf); 678 cnmac_send_queue_flush_sync(sc); 679 return 1; 680 } 681 682#endif 683 return 0; 684} 685 686/* 687 * (Ab)use m_nextpkt and m_paddr to maintain mbuf chain and pointer to gather 688 * buffer. Other mbuf members may be used by m_freem(), so don't touch them! 689 */ 690 691struct _send_queue_entry { 692 union { 693 struct mbuf _sqe_s_mbuf; 694 struct { 695 char _sqe_s_entry_pad[offsetof(struct mbuf, m_nextpkt)]; 696 SIMPLEQ_ENTRY(_send_queue_entry) _sqe_s_entry_entry; 697 } _sqe_s_entry; 698 struct { 699 char _sqe_s_gbuf_pad[offsetof(struct mbuf, m_paddr)]; 700 uint64_t *_sqe_s_gbuf_gbuf; 701 } _sqe_s_gbuf; 702 } _sqe_u; 703#define _sqe_entry _sqe_u._sqe_s_entry._sqe_s_entry_entry 704#define _sqe_gbuf _sqe_u._sqe_s_gbuf._sqe_s_gbuf_gbuf 705}; 706 707static inline void 708cnmac_send_queue_add(struct cnmac_softc *sc, struct mbuf *m, 709 uint64_t *gbuf) 710{ 711 struct _send_queue_entry *sqe = (struct _send_queue_entry *)m; 712 713 sqe->_sqe_gbuf = gbuf; 714 SIMPLEQ_INSERT_TAIL(&sc->sc_sendq, sqe, _sqe_entry); 715 716 if ((m->m_flags & M_EXT) && m->m_ext.ext_free != NULL) 717 sc->sc_ext_callback_cnt++; 718 719 OCTEON_EVCNT_INC(sc, txadd); 720} 721 722static inline void 723cnmac_send_queue_del(struct cnmac_softc *sc, struct mbuf **rm, uint64_t **rgbuf) 724{ 725 struct _send_queue_entry *sqe; 726 727 sqe = SIMPLEQ_FIRST(&sc->sc_sendq); 728 CNMAC_KASSERT(sqe != NULL); 729 SIMPLEQ_REMOVE_HEAD(&sc->sc_sendq, _sqe_entry); 730 731 *rm = (void *)sqe; 732 *rgbuf = sqe->_sqe_gbuf; 733 734 if (((*rm)->m_flags & M_EXT) && (*rm)->m_ext.ext_free != NULL) { 735 sc->sc_ext_callback_cnt--; 736 CNMAC_KASSERT(sc->sc_ext_callback_cnt >= 0); 737 } 738 739 OCTEON_EVCNT_INC(sc, txdel); 740} 741 742static inline int 743cnmac_buf_free_work(struct cnmac_softc *sc, uint64_t *work, uint64_t word2) 744{ 745 /* XXX when jumbo frame */ 746 if (ISSET(word2, PIP_WQE_WORD2_IP_BUFS)) { 747 paddr_t addr; 748 paddr_t start_buffer; 749 750 addr = work[3] & PIP_WQE_WORD3_ADDR; 751 start_buffer = addr & ~(2048 - 1); 752 753 octfpa_buf_put_paddr(cnmac_fb_pkt, start_buffer); 754 OCTEON_EVCNT_INC(sc, rxbufpkput); 755 } 756 757 octfpa_buf_put(cnmac_fb_wqe, work); 758 OCTEON_EVCNT_INC(sc, rxbufwqput); 759 760 return 0; 761} 762 763static inline void 764cnmac_buf_ext_free_m(struct mbuf *m, void *buf, size_t size, void *arg) 765{ 766 uint64_t *work = (void *)arg; 767#ifdef CNMAC_DEBUG 768 struct cnmac_softc *sc = (void *)(uintptr_t)work[0]; 769#endif 770 int s = splnet(); 771 772 OCTEON_EVCNT_INC(sc, rxrs); 773 774 octfpa_buf_put(cnmac_fb_wqe, work); 775 OCTEON_EVCNT_INC(sc, rxbufwqput); 776 777 CNMAC_KASSERT(m != NULL); 778 779 pool_cache_put(mb_cache, m); 780 781 splx(s); 782} 783 784static inline void 785cnmac_buf_ext_free_ext(struct mbuf *m, void *buf, size_t size, void *arg) 786{ 787 uint64_t *work = (void *)arg; 788#ifdef CNMAC_DEBUG 789 struct cnmac_softc *sc = (void *)(uintptr_t)work[0]; 790#endif 791 int s = splnet(); 792 793 octfpa_buf_put(cnmac_fb_wqe, work); 794 OCTEON_EVCNT_INC(sc, rxbufwqput); 795 796 octfpa_buf_put(cnmac_fb_pkt, buf); 797 OCTEON_EVCNT_INC(sc, rxbufpkput); 798 799 CNMAC_KASSERT(m != NULL); 800 801 pool_cache_put(mb_cache, m); 802 803 splx(s); 804} 805 806/* ---- ifnet interfaces */ 807 808static int 809cnmac_ioctl(struct ifnet *ifp, u_long cmd, void *data) 810{ 811 struct cnmac_softc *sc = ifp->if_softc; 812 struct ifreq *ifr = (struct ifreq *)data; 813 int s, error; 814 815 s = splnet(); 816 switch (cmd) { 817 case SIOCSIFMEDIA: 818 /* Flow control requires full-duplex mode. */ 819 if (IFM_SUBTYPE(ifr->ifr_media) == IFM_AUTO || 820 (ifr->ifr_media & IFM_FDX) == 0) { 821 ifr->ifr_media &= ~IFM_ETH_FMASK; 822 } 823 if (IFM_SUBTYPE(ifr->ifr_media) != IFM_AUTO) { 824 if ((ifr->ifr_media & IFM_ETH_FMASK) == IFM_FLOW) { 825 ifr->ifr_media |= 826 IFM_ETH_TXPAUSE | IFM_ETH_RXPAUSE; 827 } 828 sc->sc_gmx_port->sc_port_flowflags = 829 ifr->ifr_media & IFM_ETH_FMASK; 830 } 831 error = ifmedia_ioctl(ifp, ifr, &sc->sc_mii.mii_media, cmd); 832 break; 833 default: 834 error = ether_ioctl(ifp, cmd, data); 835 if (error == ENETRESET) { 836 /* 837 * Multicast list has changed; set the hardware filter 838 * accordingly. 839 */ 840 if (ISSET(ifp->if_flags, IFF_RUNNING)) 841 octgmx_set_filter(sc->sc_gmx_port); 842 error = 0; 843 } 844 break; 845 } 846 cnmac_start(ifp); 847 splx(s); 848 849 return error; 850} 851 852/* ---- send (output) */ 853 854static inline uint64_t 855cnmac_send_makecmd_w0(uint64_t fau0, uint64_t fau1, size_t len, int segs) 856{ 857 return octpko_cmd_word0( 858 OCT_FAU_OP_SIZE_64, /* sz1 */ 859 OCT_FAU_OP_SIZE_64, /* sz0 */ 860 1, fau1, 1, fau0, /* s1, reg1, s0, reg0 */ 861 0, /* le */ 862 cnmac_param_pko_cmd_w0_n2, /* n2 */ 863 1, 0, /* q, r */ 864 (segs == 1) ? 0 : 1, /* g */ 865 0, 0, 1, /* ipoffp1, ii, df */ 866 segs, (int)len); /* segs, totalbytes */ 867} 868 869static inline uint64_t 870cnmac_send_makecmd_w1(int size, paddr_t addr) 871{ 872 return octpko_cmd_word1( 873 0, 0, /* i, back */ 874 FPA_GATHER_BUFFER_POOL, /* pool */ 875 size, addr); /* size, addr */ 876} 877 878static inline int 879cnmac_send_makecmd_gbuf(struct cnmac_softc *sc, struct mbuf *m0, uint64_t *gbuf, 880 int *rsegs) 881{ 882 struct mbuf *m; 883 int segs = 0; 884 uintptr_t laddr, rlen, nlen; 885 886 for (m = m0; m != NULL; m = m->m_next) { 887 888 if (__predict_false(m->m_len == 0)) 889 continue; 890 891#if 0 892 CNMAC_KASSERT(((uint32_t)m->m_data & (PAGE_SIZE - 1)) 893 == (kvtophys((vaddr_t)m->m_data) & (PAGE_SIZE - 1))); 894#endif 895 896 /* Aligned 4k */ 897 laddr = (uintptr_t)m->m_data & (PAGE_SIZE - 1); 898 899 if (laddr + m->m_len > PAGE_SIZE) { 900 /* XXX XXX XXX */ 901 rlen = PAGE_SIZE - laddr; 902 nlen = m->m_len - rlen; 903 *(gbuf + segs) = cnmac_send_makecmd_w1(rlen, 904 kvtophys((vaddr_t)m->m_data)); 905 segs++; 906 if (segs > 63) { 907 return 1; 908 } 909 /* XXX XXX XXX */ 910 } else { 911 rlen = 0; 912 nlen = m->m_len; 913 } 914 915 *(gbuf + segs) = cnmac_send_makecmd_w1(nlen, 916 kvtophys((vaddr_t)(m->m_data + rlen))); 917 segs++; 918 if (segs > 63) { 919 return 1; 920 } 921 } 922 923 CNMAC_KASSERT(m == NULL); 924 925 *rsegs = segs; 926 927 return 0; 928} 929 930static inline int 931cnmac_send_makecmd(struct cnmac_softc *sc, struct mbuf *m, 932 uint64_t *gbuf, uint64_t *rpko_cmd_w0, uint64_t *rpko_cmd_w1) 933{ 934 uint64_t pko_cmd_w0, pko_cmd_w1; 935 int segs; 936 int result = 0; 937 938 if (cnmac_send_makecmd_gbuf(sc, m, gbuf, &segs)) { 939 log(LOG_WARNING, "%s: there are a lot of number of segments" 940 " of transmission data", device_xname(sc->sc_dev)); 941 result = 1; 942 goto done; 943 } 944 945 /* 946 * segs == 1 -> link mode (single continuous buffer) 947 * WORD1[size] is number of bytes pointed by segment 948 * 949 * segs > 1 -> gather mode (scatter-gather buffer) 950 * WORD1[size] is number of segments 951 */ 952 pko_cmd_w0 = cnmac_send_makecmd_w0(sc->sc_fau_done.fd_regno, 953 0, m->m_pkthdr.len, segs); 954 if (segs == 1) { 955 pko_cmd_w1 = cnmac_send_makecmd_w1( 956 m->m_pkthdr.len, kvtophys((vaddr_t)m->m_data)); 957 } else { 958#ifdef __mips_n32 959 KASSERT(MIPS_KSEG0_P(gbuf)); 960 pko_cmd_w1 = cnmac_send_makecmd_w1(segs, 961 MIPS_KSEG0_TO_PHYS(gbuf)); 962#else 963 pko_cmd_w1 = cnmac_send_makecmd_w1(segs, 964 MIPS_XKPHYS_TO_PHYS(gbuf)); 965#endif 966 } 967 968 *rpko_cmd_w0 = pko_cmd_w0; 969 *rpko_cmd_w1 = pko_cmd_w1; 970 971done: 972 return result; 973} 974 975static inline int 976cnmac_send_cmd(struct cnmac_softc *sc, uint64_t pko_cmd_w0, 977 uint64_t pko_cmd_w1, int *pwdc) 978{ 979 uint64_t *cmdptr; 980 int result = 0; 981 982#ifdef __mips_n32 983 KASSERT((sc->sc_cmdptr.cmdptr & ~MIPS_PHYS_MASK) == 0); 984 cmdptr = (uint64_t *)MIPS_PHYS_TO_KSEG0(sc->sc_cmdptr.cmdptr); 985#else 986 cmdptr = (uint64_t *)MIPS_PHYS_TO_XKPHYS_CACHED(sc->sc_cmdptr.cmdptr); 987#endif 988 cmdptr += sc->sc_cmdptr.cmdptr_idx; 989 990 CNMAC_KASSERT(cmdptr != NULL); 991 992 *cmdptr++ = pko_cmd_w0; 993 *cmdptr++ = pko_cmd_w1; 994 995 CNMAC_KASSERT(sc->sc_cmdptr.cmdptr_idx + 2 <= FPA_COMMAND_BUFFER_POOL_NWORDS - 1); 996 997 if (sc->sc_cmdptr.cmdptr_idx + 2 == FPA_COMMAND_BUFFER_POOL_NWORDS - 1) { 998 paddr_t buf; 999 1000 buf = octfpa_buf_get_paddr(cnmac_fb_cmd); 1001 if (buf == 0) { 1002 log(LOG_WARNING, 1003 "%s: can not allocate command buffer from free pool allocator\n", 1004 device_xname(sc->sc_dev)); 1005 result = 1; 1006 goto done; 1007 } 1008 OCTEON_EVCNT_INC(sc, txbufcbget); 1009 *cmdptr++ = buf; 1010 sc->sc_cmdptr.cmdptr = (uint64_t)buf; 1011 sc->sc_cmdptr.cmdptr_idx = 0; 1012 } else { 1013 sc->sc_cmdptr.cmdptr_idx += 2; 1014 } 1015 1016 *pwdc += 2; 1017 1018done: 1019 return result; 1020} 1021 1022static inline int 1023cnmac_send_buf(struct cnmac_softc *sc, struct mbuf *m, uint64_t *gbuf, 1024 int *pwdc) 1025{ 1026 int result = 0, error; 1027 uint64_t pko_cmd_w0, pko_cmd_w1; 1028 1029 error = cnmac_send_makecmd(sc, m, gbuf, &pko_cmd_w0, &pko_cmd_w1); 1030 if (error != 0) { 1031 /* Already logging */ 1032 OCTEON_EVCNT_INC(sc, txerrmkcmd); 1033 result = error; 1034 goto done; 1035 } 1036 1037 error = cnmac_send_cmd(sc, pko_cmd_w0, pko_cmd_w1, pwdc); 1038 if (error != 0) { 1039 /* Already logging */ 1040 OCTEON_EVCNT_INC(sc, txerrcmd); 1041 result = error; 1042 } 1043 1044done: 1045 return result; 1046} 1047 1048static inline int 1049cnmac_send(struct cnmac_softc *sc, struct mbuf *m, int *pwdc) 1050{ 1051 paddr_t gaddr = 0; 1052 uint64_t *gbuf = NULL; 1053 int result = 0, error; 1054 1055 OCTEON_EVCNT_INC(sc, tx); 1056 1057 gaddr = octfpa_buf_get_paddr(cnmac_fb_sg); 1058 if (gaddr == 0) { 1059 log(LOG_WARNING, "%s: can not allocate gather buffer from " 1060 "free pool allocator\n", device_xname(sc->sc_dev)); 1061 OCTEON_EVCNT_INC(sc, txerrgbuf); 1062 result = 1; 1063 goto done; 1064 } 1065 OCTEON_EVCNT_INC(sc, txbufgbget); 1066 1067#ifdef __mips_n32 1068 KASSERT((gaddr & ~MIPS_PHYS_MASK) == 0); 1069 gbuf = (uint64_t *)(uintptr_t)MIPS_PHYS_TO_KSEG0(gaddr); 1070#else 1071 gbuf = (uint64_t *)(uintptr_t)MIPS_PHYS_TO_XKPHYS_CACHED(gaddr); 1072#endif 1073 1074 CNMAC_KASSERT(gbuf != NULL); 1075 1076 error = cnmac_send_buf(sc, m, gbuf, pwdc); 1077 if (error != 0) { 1078 /* Already logging */ 1079 octfpa_buf_put_paddr(cnmac_fb_sg, gaddr); 1080 OCTEON_EVCNT_INC(sc, txbufgbput); 1081 result = error; 1082 goto done; 1083 } 1084 1085 cnmac_send_queue_add(sc, m, gbuf); 1086 1087done: 1088 return result; 1089} 1090 1091static void 1092cnmac_start(struct ifnet *ifp) 1093{ 1094 struct cnmac_softc *sc = ifp->if_softc; 1095 struct mbuf *m; 1096 int wdc = 0; 1097 1098 /* 1099 * Performance tuning 1100 * pre-send iobdma request 1101 */ 1102 cnmac_send_queue_flush_prefetch(sc); 1103 1104 if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING) 1105 goto last; 1106 1107 /* XXX assume that OCTEON doesn't buffer packets */ 1108 if (__predict_false(!octgmx_link_status(sc->sc_gmx_port))) { 1109 /* Dequeue and drop them */ 1110 while (1) { 1111 IFQ_DEQUEUE(&ifp->if_snd, m); 1112 if (m == NULL) 1113 break; 1114 1115 m_freem(m); 1116 IF_DROP(&ifp->if_snd); 1117 OCTEON_EVCNT_INC(sc, txerrlink); 1118 } 1119 goto last; 1120 } 1121 1122 for (;;) { 1123 IFQ_POLL(&ifp->if_snd, m); 1124 if (__predict_false(m == NULL)) 1125 break; 1126 1127 /* XXX XXX XXX */ 1128 cnmac_send_queue_flush_fetch(sc); 1129 1130 /* 1131 * If no free send buffer is available, free all the sent 1132 * buffers and bail out. 1133 */ 1134 if (cnmac_send_queue_is_full(sc)) { 1135 SET(ifp->if_flags, IFF_OACTIVE); 1136 if (wdc > 0) 1137 octpko_op_doorbell_write(sc->sc_port, 1138 sc->sc_port, wdc); 1139 return; 1140 } 1141 /* XXX XXX XXX */ 1142 1143 IFQ_DEQUEUE(&ifp->if_snd, m); 1144 1145 bpf_mtap(ifp, m, BPF_D_OUT); 1146 1147 /* XXX XXX XXX */ 1148 if (sc->sc_soft_req_cnt > sc->sc_soft_req_thresh) 1149 cnmac_send_queue_flush(sc); 1150 if (cnmac_send(sc, m, &wdc)) { 1151 IF_DROP(&ifp->if_snd); 1152 m_freem(m); 1153 log(LOG_WARNING, 1154 "%s: failed in the transmission of the packet\n", 1155 device_xname(sc->sc_dev)); 1156 OCTEON_EVCNT_INC(sc, txerr); 1157 } else 1158 sc->sc_soft_req_cnt++; 1159 1160 if (sc->sc_flush) 1161 cnmac_send_queue_flush_sync(sc); 1162 /* XXX XXX XXX */ 1163 1164 /* Send next iobdma request */ 1165 cnmac_send_queue_flush_prefetch(sc); 1166 } 1167 1168 if (wdc > 0) 1169 octpko_op_doorbell_write(sc->sc_port, sc->sc_port, wdc); 1170 1171/* 1172 * Don't schedule send-buffer-free callout every time - those buffers are freed 1173 * by "free tick". This makes some packets like NFS slower. 1174 */ 1175#ifdef CNMAC_USENFS 1176 if (__predict_false(sc->sc_ext_callback_cnt > 0)) { 1177 int timo; 1178 1179 /* ??? */ 1180 timo = hz - (100 * sc->sc_ext_callback_cnt); 1181 if (timo < 10) 1182 timo = 10; 1183 callout_schedule(&sc->sc_tick_free_ch, timo); 1184 } 1185#endif 1186 1187last: 1188 cnmac_send_queue_flush_fetch(sc); 1189} 1190 1191static void 1192cnmac_watchdog(struct ifnet *ifp) 1193{ 1194 struct cnmac_softc *sc = ifp->if_softc; 1195 1196 printf("%s: device timeout\n", device_xname(sc->sc_dev)); 1197 1198 cnmac_configure(sc); 1199 1200 SET(ifp->if_flags, IFF_RUNNING); 1201 CLR(ifp->if_flags, IFF_OACTIVE); 1202 ifp->if_timer = 0; 1203 1204 cnmac_start(ifp); 1205} 1206 1207static int 1208cnmac_init(struct ifnet *ifp) 1209{ 1210 struct cnmac_softc *sc = ifp->if_softc; 1211 1212 /* XXX don't disable commonly used parts!!! XXX */ 1213 if (sc->sc_init_flag == 0) { 1214 /* Cancel any pending I/O. */ 1215 cnmac_stop(ifp, 0); 1216 1217 /* Initialize the device */ 1218 cnmac_configure(sc); 1219 1220 octpko_enable(sc->sc_pko); 1221 octipd_enable(sc->sc_ipd); 1222 1223 sc->sc_init_flag = 1; 1224 } else { 1225 octgmx_port_enable(sc->sc_gmx_port, 1); 1226 } 1227 mii_ifmedia_change(&sc->sc_mii); 1228 1229 octgmx_set_filter(sc->sc_gmx_port); 1230 1231 callout_reset(&sc->sc_tick_misc_ch, hz, cnmac_tick_misc, sc); 1232 callout_reset(&sc->sc_tick_free_ch, hz, cnmac_tick_free, sc); 1233 1234 SET(ifp->if_flags, IFF_RUNNING); 1235 CLR(ifp->if_flags, IFF_OACTIVE); 1236 1237 return 0; 1238} 1239 1240static void 1241cnmac_stop(struct ifnet *ifp, int disable) 1242{ 1243 struct cnmac_softc *sc = ifp->if_softc; 1244 1245 callout_stop(&sc->sc_tick_misc_ch); 1246 callout_stop(&sc->sc_tick_free_ch); 1247 1248 mii_down(&sc->sc_mii); 1249 1250 octgmx_port_enable(sc->sc_gmx_port, 0); 1251 1252 /* Mark the interface as down and cancel the watchdog timer. */ 1253 CLR(ifp->if_flags, IFF_RUNNING | IFF_OACTIVE); 1254 ifp->if_timer = 0; 1255} 1256 1257/* ---- misc */ 1258 1259#define PKO_INDEX_MASK ((1ULL << 12/* XXX */) - 1) 1260 1261static int 1262cnmac_reset(struct cnmac_softc *sc) 1263{ 1264 octgmx_reset_speed(sc->sc_gmx_port); 1265 octgmx_reset_flowctl(sc->sc_gmx_port); 1266 octgmx_reset_timing(sc->sc_gmx_port); 1267 1268 return 0; 1269} 1270 1271static int 1272cnmac_configure(struct cnmac_softc *sc) 1273{ 1274 octgmx_port_enable(sc->sc_gmx_port, 0); 1275 1276 cnmac_reset(sc); 1277 1278 cnmac_configure_common(sc); 1279 1280 octpko_port_config(sc->sc_pko); 1281 octpko_port_enable(sc->sc_pko, 1); 1282 octpip_port_config(sc->sc_pip); 1283 1284 octgmx_tx_stats_rd_clr(sc->sc_gmx_port, 1); 1285 octgmx_rx_stats_rd_clr(sc->sc_gmx_port, 1); 1286 1287 octgmx_port_enable(sc->sc_gmx_port, 1); 1288 1289 return 0; 1290} 1291 1292static int 1293cnmac_configure_common(struct cnmac_softc *sc) 1294{ 1295 static int once; 1296 1297 if (once == 1) 1298 return 0; 1299 once = 1; 1300 1301 octipd_config(sc->sc_ipd); 1302#ifdef CNMAC_IPD_RED 1303 octipd_red(sc->sc_ipd, RECV_QUEUE_SIZE >> 2, RECV_QUEUE_SIZE >> 3); 1304#endif 1305 octpko_config(sc->sc_pko); 1306 1307 octpow_config(sc->sc_pow, OCTEON_POW_GROUP_PIP); 1308 1309 return 0; 1310} 1311 1312/* ---- receive (input) */ 1313 1314static inline int 1315cnmac_recv_mbuf(struct cnmac_softc *sc, uint64_t *work, struct mbuf **rm) 1316{ 1317 struct mbuf *m; 1318 void (*ext_free)(struct mbuf *, void *, size_t, void *); 1319 void *ext_buf; 1320 size_t ext_size; 1321 void *data; 1322 uint64_t word1 = work[1]; 1323 uint64_t word2 = work[2]; 1324 uint64_t word3 = work[3]; 1325 1326 MGETHDR(m, M_NOWAIT, MT_DATA); 1327 if (m == NULL) 1328 return 1; 1329 CNMAC_KASSERT(m != NULL); 1330 1331 if ((word2 & PIP_WQE_WORD2_IP_BUFS) == 0) { 1332 /* Dynamic short */ 1333 ext_free = cnmac_buf_ext_free_m; 1334 ext_buf = &work[4]; 1335 ext_size = 96; 1336 1337 data = &work[4 + sc->sc_ip_offset / sizeof(uint64_t)]; 1338 } else { 1339 vaddr_t addr; 1340 vaddr_t start_buffer; 1341 1342#ifdef __mips_n32 1343 KASSERT((word3 & ~MIPS_PHYS_MASK) == 0); 1344 addr = MIPS_PHYS_TO_KSEG0(word3 & PIP_WQE_WORD3_ADDR); 1345#else 1346 addr = MIPS_PHYS_TO_XKPHYS_CACHED(word3 & PIP_WQE_WORD3_ADDR); 1347#endif 1348 start_buffer = addr & ~(2048 - 1); 1349 1350 ext_free = cnmac_buf_ext_free_ext; 1351 ext_buf = (void *)start_buffer; 1352 ext_size = 2048; 1353 1354 data = (void *)addr; 1355 } 1356 1357 /* Embed sc pointer into work[0] for _ext_free evcnt */ 1358 work[0] = (uintptr_t)sc; 1359 1360 MEXTADD(m, ext_buf, ext_size, 0, ext_free, work); 1361 CNMAC_KASSERT(ISSET(m->m_flags, M_EXT)); 1362 1363 m->m_data = data; 1364 m->m_len = m->m_pkthdr.len = (word1 & PIP_WQE_WORD1_LEN) >> 48; 1365 m_set_rcvif(m, &sc->sc_ethercom.ec_if); 1366 1367 /* Not readonly buffer */ 1368 m->m_flags |= M_EXT_RW; 1369 1370 *rm = m; 1371 1372 CNMAC_KASSERT(*rm != NULL); 1373 1374 return 0; 1375} 1376 1377static inline int 1378cnmac_recv_check_code(struct cnmac_softc *sc, uint64_t word2) 1379{ 1380 uint64_t opecode = word2 & PIP_WQE_WORD2_NOIP_OPECODE; 1381 1382 if (__predict_true(!ISSET(word2, PIP_WQE_WORD2_NOIP_RE))) 1383 return 0; 1384 1385 /* This error is harmless */ 1386 if (opecode == PIP_OVER_ERR) 1387 return 0; 1388 1389 return 1; 1390} 1391 1392static inline int 1393cnmac_recv_check_jumbo(struct cnmac_softc *sc, uint64_t word2) 1394{ 1395 if (__predict_false((word2 & PIP_WQE_WORD2_IP_BUFS) > (1ULL << 56))) 1396 return 1; 1397 return 0; 1398} 1399 1400static inline int 1401cnmac_recv_check_link(struct cnmac_softc *sc, uint64_t word2) 1402{ 1403 if (__predict_false(!octgmx_link_status(sc->sc_gmx_port))) 1404 return 1; 1405 return 0; 1406} 1407 1408static inline int 1409cnmac_recv_check(struct cnmac_softc *sc, uint64_t word2) 1410{ 1411 if (__predict_false(cnmac_recv_check_link(sc, word2)) != 0) { 1412 if (ratecheck(&sc->sc_rate_recv_check_link_last, 1413 &sc->sc_rate_recv_check_link_cap)) 1414 log(LOG_DEBUG, 1415 "%s: link is not up, the packet was dropped\n", 1416 device_xname(sc->sc_dev)); 1417 OCTEON_EVCNT_INC(sc, rxerrlink); 1418 return 1; 1419 } 1420 1421#if 0 /* XXX Performance tuning (Jumbo-frame is not supported yet!) */ 1422 if (__predict_false(cnmac_recv_check_jumbo(sc, word2)) != 0) { 1423 /* XXX jumbo frame */ 1424 if (ratecheck(&sc->sc_rate_recv_check_jumbo_last, 1425 &sc->sc_rate_recv_check_jumbo_cap)) 1426 log(LOG_DEBUG, 1427 "jumbo frame was received\n"); 1428 OCTEON_EVCNT_INC(sc, rxerrjmb); 1429 return 1; 1430 } 1431#endif 1432 1433 if (__predict_false(cnmac_recv_check_code(sc, word2)) != 0) { 1434 1435 if ((word2 & PIP_WQE_WORD2_NOIP_OPECODE) == 1436 PIP_WQE_WORD2_RE_OPCODE_LENGTH) { 1437 /* No logging */ 1438 /* XXX increment special error count */ 1439 } else if ((word2 & PIP_WQE_WORD2_NOIP_OPECODE) == 1440 PIP_WQE_WORD2_RE_OPCODE_PARTIAL) { 1441 /* Not an error, it's because of overload */ 1442 } else { 1443 1444 if (ratecheck(&sc->sc_rate_recv_check_code_last, 1445 &sc->sc_rate_recv_check_code_cap)) 1446 log(LOG_WARNING, 1447 "%s: reception error, packet dropped " 1448 "(error code = %" PRId64 ")\n", 1449 device_xname(sc->sc_dev), word2 & PIP_WQE_WORD2_NOIP_OPECODE); 1450 } 1451 OCTEON_EVCNT_INC(sc, rxerrcode); 1452 return 1; 1453 } 1454 1455 return 0; 1456} 1457 1458static inline int 1459cnmac_recv(struct cnmac_softc *sc, uint64_t *work) 1460{ 1461 int result = 0; 1462 struct ifnet *ifp; 1463 struct mbuf *m; 1464 uint64_t word2; 1465 1466 /* XXX XXX XXX */ 1467 /* 1468 * Performance tuning 1469 * pre-send iobdma request 1470 */ 1471 if (sc->sc_soft_req_cnt > sc->sc_soft_req_thresh) { 1472 cnmac_send_queue_flush_prefetch(sc); 1473 } 1474 /* XXX XXX XXX */ 1475 1476 CNMAC_KASSERT(sc != NULL); 1477 CNMAC_KASSERT(work != NULL); 1478 1479 OCTEON_EVCNT_INC(sc, rx); 1480 1481 word2 = work[2]; 1482 ifp = &sc->sc_ethercom.ec_if; 1483 1484 CNMAC_KASSERT(ifp != NULL); 1485 1486 if (__predict_false(cnmac_recv_check(sc, word2) != 0)) { 1487 if_statinc(ifp, if_ierrors); 1488 result = 1; 1489 cnmac_buf_free_work(sc, work, word2); 1490 goto drop; 1491 } 1492 1493 if (__predict_false(cnmac_recv_mbuf(sc, work, &m) != 0)) { 1494 if_statinc(ifp, if_ierrors); 1495 result = 1; 1496 cnmac_buf_free_work(sc, work, word2); 1497 goto drop; 1498 } 1499 1500 /* work[0] .. work[3] may not be valid any more */ 1501 1502 CNMAC_KASSERT(m != NULL); 1503 1504 octipd_offload(word2, m->m_data, &m->m_pkthdr.csum_flags); 1505 1506 /* XXX XXX XXX */ 1507 if (sc->sc_soft_req_cnt > sc->sc_soft_req_thresh) { 1508 cnmac_send_queue_flush_fetch(sc); 1509 cnmac_send_queue_flush(sc); 1510 } 1511 1512 /* XXX XXX XXX */ 1513 if (sc->sc_flush) 1514 cnmac_send_queue_flush_sync(sc); 1515 /* XXX XXX XXX */ 1516 1517 if_percpuq_enqueue(ifp->if_percpuq, m); 1518 1519 return 0; 1520 1521drop: 1522 /* XXX XXX XXX */ 1523 if (sc->sc_soft_req_cnt > sc->sc_soft_req_thresh) { 1524 cnmac_send_queue_flush_fetch(sc); 1525 } 1526 /* XXX XXX XXX */ 1527 1528 return result; 1529} 1530 1531static void 1532cnmac_recv_redir(struct ifnet *ifp, struct mbuf *m) 1533{ 1534 struct cnmac_softc *rsc = ifp->if_softc; 1535 struct cnmac_softc *sc = NULL; 1536 int i, wdc = 0; 1537 1538 for (i = 0; i < 3 /* XXX */; i++) { 1539 if (rsc->sc_redir & (1 << i)) 1540 sc = cnmac_gsc[i]; 1541 } 1542 1543 if (sc == NULL) { 1544 m_freem(m); 1545 return; 1546 } 1547 cnmac_send_queue_flush_prefetch(sc); 1548 1549 cnmac_send_queue_flush_fetch(sc); 1550 1551 if (cnmac_send_queue_is_full(sc)) { 1552 m_freem(m); 1553 return; 1554 } 1555 if (sc->sc_soft_req_cnt > sc->sc_soft_req_thresh) 1556 cnmac_send_queue_flush(sc); 1557 1558 if (cnmac_send(sc, m, &wdc)) { 1559 IF_DROP(&ifp->if_snd); 1560 m_freem(m); 1561 } else { 1562 octpko_op_doorbell_write(sc->sc_port, sc->sc_port, wdc); 1563 sc->sc_soft_req_cnt++; 1564 } 1565 1566 if (sc->sc_flush) 1567 cnmac_send_queue_flush_sync(sc); 1568} 1569 1570static inline void 1571cnmac_recv_intr(void *data, uint64_t *work) 1572{ 1573 struct cnmac_softc *sc; 1574 int port; 1575 1576 CNMAC_KASSERT(work != NULL); 1577 1578 port = (work[1] & PIP_WQE_WORD1_IPRT) >> 42; 1579 1580 CNMAC_KASSERT(port < GMX_PORT_NUNITS); 1581 1582 sc = cnmac_gsc[port]; 1583 1584 CNMAC_KASSERT(sc != NULL); 1585 CNMAC_KASSERT(port == sc->sc_port); 1586 1587 /* XXX process all work queue entries anyway */ 1588 1589 (void)cnmac_recv(sc, work); 1590} 1591 1592/* ---- tick */ 1593 1594/* 1595 * cnmac_tick_free 1596 * 1597 * => garbage collect send gather buffer / mbuf 1598 * => called at softclock 1599 */ 1600static void 1601cnmac_tick_free(void *arg) 1602{ 1603 struct cnmac_softc *sc = arg; 1604 int timo; 1605 int s; 1606 1607 s = splnet(); 1608 /* XXX XXX XXX */ 1609 if (sc->sc_soft_req_cnt > 0) { 1610 cnmac_send_queue_flush_prefetch(sc); 1611 cnmac_send_queue_flush_fetch(sc); 1612 cnmac_send_queue_flush(sc); 1613 cnmac_send_queue_flush_sync(sc); 1614 } 1615 /* XXX XXX XXX */ 1616 1617 /* XXX XXX XXX */ 1618 /* ??? */ 1619 timo = hz - (100 * sc->sc_ext_callback_cnt); 1620 if (timo < 10) 1621 timo = 10; 1622 callout_schedule(&sc->sc_tick_free_ch, timo); 1623 /* XXX XXX XXX */ 1624 splx(s); 1625} 1626 1627/* 1628 * cnmac_tick_misc 1629 * 1630 * => collect statistics 1631 * => check link status 1632 * => called at softclock 1633 */ 1634static void 1635cnmac_tick_misc(void *arg) 1636{ 1637 struct cnmac_softc *sc = arg; 1638 struct ifnet *ifp; 1639 int s; 1640 1641 s = splnet(); 1642 1643 ifp = &sc->sc_ethercom.ec_if; 1644 1645 octgmx_stats(sc->sc_gmx_port); 1646 octpip_stats(sc->sc_pip, ifp, sc->sc_port); 1647 mii_tick(&sc->sc_mii); 1648 1649 splx(s); 1650 1651 callout_schedule(&sc->sc_tick_misc_ch, hz); 1652} 1653 1654/* ---- Odd nibble preamble workaround (software CRC processing) */ 1655 1656/* ---- sysctl */ 1657 1658static int cnmac_sysctl_verify(SYSCTLFN_ARGS); 1659static int cnmac_sysctl_pool(SYSCTLFN_ARGS); 1660static int cnmac_sysctl_rd(SYSCTLFN_ARGS); 1661 1662static int cnmac_sysctl_pkocmdw0n2_num; 1663static int cnmac_sysctl_pipdynrs_num; 1664static int cnmac_sysctl_redir_num; 1665static int cnmac_sysctl_pkt_pool_num; 1666static int cnmac_sysctl_wqe_pool_num; 1667static int cnmac_sysctl_cmd_pool_num; 1668static int cnmac_sysctl_sg_pool_num; 1669static int cnmac_sysctl_pktbuf_num; 1670 1671/* 1672 * Set up sysctl(3) MIB, hw.cnmac.*. 1673 */ 1674SYSCTL_SETUP(sysctl_octeon_eth, "sysctl cnmac subtree setup") 1675{ 1676 int rc; 1677 int cnmac_sysctl_root_num; 1678 const struct sysctlnode *node; 1679 1680 if ((rc = sysctl_createv(clog, 0, NULL, NULL, 1681 0, CTLTYPE_NODE, "hw", NULL, 1682 NULL, 0, NULL, 0, CTL_HW, CTL_EOL)) != 0) { 1683 goto err; 1684 } 1685 1686 if ((rc = sysctl_createv(clog, 0, NULL, &node, 1687 0, CTLTYPE_NODE, "cnmac", 1688 SYSCTL_DESCR("cnmac interface controls"), 1689 NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL)) != 0) { 1690 goto err; 1691 } 1692 1693 cnmac_sysctl_root_num = node->sysctl_num; 1694 1695 if ((rc = sysctl_createv(clog, 0, NULL, &node, 1696 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 1697 CTLTYPE_INT, "pko_cmd_w0_n2", 1698 SYSCTL_DESCR("PKO command WORD0 N2 bit"), 1699 cnmac_sysctl_verify, 0, 1700 &cnmac_param_pko_cmd_w0_n2, 1701 0, CTL_HW, cnmac_sysctl_root_num, CTL_CREATE, 1702 CTL_EOL)) != 0) { 1703 goto err; 1704 } 1705 1706 cnmac_sysctl_pkocmdw0n2_num = node->sysctl_num; 1707 1708 if ((rc = sysctl_createv(clog, 0, NULL, &node, 1709 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 1710 CTLTYPE_INT, "pip_dyn_rs", 1711 SYSCTL_DESCR("PIP dynamic short in WQE"), 1712 cnmac_sysctl_verify, 0, 1713 &cnmac_param_pip_dyn_rs, 1714 0, CTL_HW, cnmac_sysctl_root_num, CTL_CREATE, 1715 CTL_EOL)) != 0) { 1716 goto err; 1717 } 1718 1719 cnmac_sysctl_pipdynrs_num = node->sysctl_num; 1720 1721 if ((rc = sysctl_createv(clog, 0, NULL, &node, 1722 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 1723 CTLTYPE_INT, "redir", 1724 SYSCTL_DESCR("input port redirection"), 1725 cnmac_sysctl_verify, 0, 1726 &cnmac_param_redir, 1727 0, CTL_HW, cnmac_sysctl_root_num, CTL_CREATE, 1728 CTL_EOL)) != 0) { 1729 goto err; 1730 } 1731 1732 cnmac_sysctl_redir_num = node->sysctl_num; 1733 1734 if ((rc = sysctl_createv(clog, 0, NULL, &node, 1735 CTLFLAG_PERMANENT, 1736 CTLTYPE_INT, "pkt_pool", 1737 SYSCTL_DESCR("packet pool available"), 1738 cnmac_sysctl_pool, 0, NULL, 1739 0, CTL_HW, cnmac_sysctl_root_num, CTL_CREATE, 1740 CTL_EOL)) != 0) { 1741 goto err; 1742 } 1743 1744 cnmac_sysctl_pkt_pool_num = node->sysctl_num; 1745 1746 if ((rc = sysctl_createv(clog, 0, NULL, &node, 1747 CTLFLAG_PERMANENT, 1748 CTLTYPE_INT, "wqe_pool", 1749 SYSCTL_DESCR("wqe pool available"), 1750 cnmac_sysctl_pool, 0, NULL, 1751 0, CTL_HW, cnmac_sysctl_root_num, CTL_CREATE, 1752 CTL_EOL)) != 0) { 1753 goto err; 1754 } 1755 1756 cnmac_sysctl_wqe_pool_num = node->sysctl_num; 1757 1758 if ((rc = sysctl_createv(clog, 0, NULL, &node, 1759 CTLFLAG_PERMANENT, 1760 CTLTYPE_INT, "cmd_pool", 1761 SYSCTL_DESCR("cmd pool available"), 1762 cnmac_sysctl_pool, 0, NULL, 1763 0, CTL_HW, cnmac_sysctl_root_num, CTL_CREATE, 1764 CTL_EOL)) != 0) { 1765 goto err; 1766 } 1767 1768 cnmac_sysctl_cmd_pool_num = node->sysctl_num; 1769 1770 if ((rc = sysctl_createv(clog, 0, NULL, &node, 1771 CTLFLAG_PERMANENT, 1772 CTLTYPE_INT, "sg_pool", 1773 SYSCTL_DESCR("sg pool available"), 1774 cnmac_sysctl_pool, 0, NULL, 1775 0, CTL_HW, cnmac_sysctl_root_num, CTL_CREATE, 1776 CTL_EOL)) != 0) { 1777 goto err; 1778 } 1779 1780 cnmac_sysctl_sg_pool_num = node->sysctl_num; 1781 1782 if ((rc = sysctl_createv(clog, 0, NULL, &node, 1783 CTLFLAG_PERMANENT | CTLFLAG_READONLY, 1784 CTLTYPE_INT, "pktbuf", 1785 SYSCTL_DESCR("input packet buffer size on POW"), 1786 cnmac_sysctl_rd, 0, 1787 &cnmac_param_pktbuf, 1788 0, CTL_HW, cnmac_sysctl_root_num, CTL_CREATE, 1789 CTL_EOL)) != 0) { 1790 goto err; 1791 } 1792 1793 cnmac_sysctl_pktbuf_num = node->sysctl_num; 1794 1795 return; 1796 1797err: 1798 aprint_error("%s: syctl_createv failed (rc = %d)\n", __func__, rc); 1799} 1800 1801static int 1802cnmac_sysctl_verify(SYSCTLFN_ARGS) 1803{ 1804 int error, v; 1805 struct sysctlnode node; 1806 struct cnmac_softc *sc; 1807 int i; 1808 int s; 1809 1810 node = *rnode; 1811 v = *(int *)rnode->sysctl_data; 1812 node.sysctl_data = &v; 1813 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 1814 if (error || newp == NULL) 1815 return error; 1816 1817 if (node.sysctl_num == cnmac_sysctl_pkocmdw0n2_num) { 1818 if (v < 0 || v > 1) 1819 return EINVAL; 1820 *(int *)rnode->sysctl_data = v; 1821 return 0; 1822 } 1823 1824 if (node.sysctl_num == cnmac_sysctl_pipdynrs_num) { 1825 if (v < 0 || v > 1) 1826 return EINVAL; 1827 *(int *)rnode->sysctl_data = v; 1828 s = splnet(); 1829 for (i = 0; i < 3/* XXX */; i++) { 1830 sc = cnmac_gsc[i]; /* XXX */ 1831 octpip_prt_cfg_enable(sc->sc_pip, 1832 PIP_PRT_CFGN_DYN_RS, v); 1833 } 1834 splx(s); 1835 return 0; 1836 } 1837 1838 if (node.sysctl_num == cnmac_sysctl_redir_num) { 1839 if (v & ~((0x7 << (4 * 0)) | (0x7 << (4 * 1)) | (0x7 << (4 * 2)))) 1840 return EINVAL; 1841 *(int *)rnode->sysctl_data = v; 1842 s = splnet(); 1843 for (i = 0; i < 3/* XXX */; i++) { 1844 struct ifnet *ifp; 1845 1846 sc = cnmac_gsc[i]; /* XXX */ 1847 ifp = &sc->sc_ethercom.ec_if; 1848 1849 sc->sc_redir 1850 = (cnmac_param_redir >> (4 * i)) & 0x7; 1851 if (sc->sc_redir == 0) { 1852 if (ISSET(ifp->if_flags, IFF_PROMISC)) { 1853 CLR(ifp->if_flags, IFF_PROMISC); 1854 cnmac_mii_statchg(ifp); 1855 /* octgmx_set_filter(sc->sc_gmx_port); */ 1856 } 1857 ifp->_if_input = ether_input; 1858 } 1859 else { 1860 if (!ISSET(ifp->if_flags, IFF_PROMISC)) { 1861 SET(ifp->if_flags, IFF_PROMISC); 1862 cnmac_mii_statchg(ifp); 1863 /* octgmx_set_filter(sc->sc_gmx_port); */ 1864 } 1865 ifp->_if_input = cnmac_recv_redir; 1866 } 1867 } 1868 splx(s); 1869 return 0; 1870 } 1871 1872 return EINVAL; 1873} 1874 1875static int 1876cnmac_sysctl_pool(SYSCTLFN_ARGS) 1877{ 1878 int error, newval = 0; 1879 struct sysctlnode node; 1880 int s; 1881 1882 node = *rnode; 1883 node.sysctl_data = &newval; 1884 s = splnet(); 1885 if (node.sysctl_num == cnmac_sysctl_pkt_pool_num) { 1886 error = octfpa_available_fpa_pool(&newval, 1887 OCTEON_POOL_NO_PKT); 1888 } else if (node.sysctl_num == cnmac_sysctl_wqe_pool_num) { 1889 error = octfpa_available_fpa_pool(&newval, 1890 OCTEON_POOL_NO_WQE); 1891 } else if (node.sysctl_num == cnmac_sysctl_cmd_pool_num) { 1892 error = octfpa_available_fpa_pool(&newval, 1893 OCTEON_POOL_NO_CMD); 1894 } else if (node.sysctl_num == cnmac_sysctl_sg_pool_num) { 1895 error = octfpa_available_fpa_pool(&newval, 1896 OCTEON_POOL_NO_SG); 1897 } else { 1898 splx(s); 1899 return EINVAL; 1900 } 1901 splx(s); 1902 if (error) 1903 return error; 1904 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 1905 if (error || newp == NULL) 1906 return error; 1907 1908 return 0; 1909} 1910 1911static int 1912cnmac_sysctl_rd(SYSCTLFN_ARGS) 1913{ 1914 int error, v; 1915 struct sysctlnode node; 1916 int s; 1917 1918 node = *rnode; 1919 v = *(int *)rnode->sysctl_data; 1920 node.sysctl_data = &v; 1921 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 1922 if (error || newp != NULL) 1923 return error; 1924 1925 if (node.sysctl_num == cnmac_sysctl_pktbuf_num) { 1926 uint64_t tmp; 1927 int n; 1928 1929 s = splnet(); 1930 tmp = octfpa_query(0); 1931 n = (int)tmp; 1932 splx(s); 1933 *(int *)rnode->sysctl_data = n; 1934 cnmac_param_pktbuf = n; 1935 *(int *)oldp = n; 1936 return 0; 1937 } 1938 1939 return EINVAL; 1940} 1941