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