1 1.29 skrll /* $NetBSD: if_cnmac.c,v 1.29 2022/09/29 07:00:46 skrll Exp $ */ 2 1.24 simonb 3 1.24 simonb /* 4 1.24 simonb * Copyright (c) 2007 Internet Initiative Japan, Inc. 5 1.24 simonb * All rights reserved. 6 1.24 simonb * 7 1.24 simonb * Redistribution and use in source and binary forms, with or without 8 1.24 simonb * modification, are permitted provided that the following conditions 9 1.24 simonb * are met: 10 1.24 simonb * 1. Redistributions of source code must retain the above copyright 11 1.24 simonb * notice, this list of conditions and the following disclaimer. 12 1.24 simonb * 2. Redistributions in binary form must reproduce the above copyright 13 1.24 simonb * notice, this list of conditions and the following disclaimer in the 14 1.24 simonb * documentation and/or other materials provided with the distribution. 15 1.24 simonb * 16 1.24 simonb * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 17 1.24 simonb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 1.24 simonb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 1.24 simonb * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 20 1.24 simonb * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 1.24 simonb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 1.24 simonb * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 1.24 simonb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 1.24 simonb * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 1.24 simonb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 1.24 simonb * SUCH DAMAGE. 27 1.24 simonb */ 28 1.1 hikaru 29 1.1 hikaru #include <sys/cdefs.h> 30 1.29 skrll __KERNEL_RCSID(0, "$NetBSD: if_cnmac.c,v 1.29 2022/09/29 07:00:46 skrll Exp $"); 31 1.1 hikaru 32 1.1 hikaru /* 33 1.15 gutterid * If no free send buffer is available, free all the sent buffers and bail out. 34 1.1 hikaru */ 35 1.19 simonb #define CNMAC_SEND_QUEUE_CHECK 36 1.1 hikaru 37 1.1 hikaru /* XXX XXX XXX XXX XXX XXX */ 38 1.1 hikaru 39 1.1 hikaru #include <sys/param.h> 40 1.1 hikaru #include <sys/systm.h> 41 1.1 hikaru #include <sys/pool.h> 42 1.1 hikaru #include <sys/mbuf.h> 43 1.1 hikaru #include <sys/kernel.h> 44 1.1 hikaru #include <sys/socket.h> 45 1.1 hikaru #include <sys/ioctl.h> 46 1.1 hikaru #include <sys/errno.h> 47 1.1 hikaru #include <sys/device.h> 48 1.1 hikaru #include <sys/queue.h> 49 1.1 hikaru #include <sys/conf.h> 50 1.1 hikaru #include <sys/sysctl.h> 51 1.1 hikaru #include <sys/syslog.h> 52 1.1 hikaru 53 1.1 hikaru #include <net/if.h> 54 1.1 hikaru #include <net/if_media.h> 55 1.1 hikaru #include <net/if_ether.h> 56 1.1 hikaru #include <net/route.h> 57 1.1 hikaru #include <net/bpf.h> 58 1.1 hikaru 59 1.1 hikaru #include <netinet/in.h> 60 1.1 hikaru #include <netinet/in_systm.h> 61 1.1 hikaru #include <netinet/in_var.h> 62 1.1 hikaru #include <netinet/ip.h> 63 1.1 hikaru 64 1.1 hikaru #include <sys/bus.h> 65 1.1 hikaru #include <machine/intr.h> 66 1.1 hikaru #include <machine/endian.h> 67 1.1 hikaru #include <machine/locore.h> 68 1.1 hikaru 69 1.1 hikaru #include <dev/mii/mii.h> 70 1.1 hikaru #include <dev/mii/miivar.h> 71 1.1 hikaru 72 1.1 hikaru #include <mips/cpuregs.h> 73 1.1 hikaru 74 1.22 simonb #include <mips/cavium/octeonreg.h> 75 1.24 simonb #include <mips/cavium/octeonvar.h> 76 1.22 simonb #include <mips/cavium/include/iobusvar.h> 77 1.22 simonb 78 1.1 hikaru #include <mips/cavium/dev/octeon_ciureg.h> 79 1.24 simonb #include <mips/cavium/dev/octeon_faureg.h> 80 1.24 simonb #include <mips/cavium/dev/octeon_fpareg.h> 81 1.1 hikaru #include <mips/cavium/dev/octeon_gmxreg.h> 82 1.1 hikaru #include <mips/cavium/dev/octeon_pipreg.h> 83 1.1 hikaru #include <mips/cavium/dev/octeon_powreg.h> 84 1.24 simonb #include <mips/cavium/dev/octeon_fauvar.h> 85 1.1 hikaru #include <mips/cavium/dev/octeon_fpavar.h> 86 1.1 hikaru #include <mips/cavium/dev/octeon_gmxvar.h> 87 1.1 hikaru #include <mips/cavium/dev/octeon_ipdvar.h> 88 1.1 hikaru #include <mips/cavium/dev/octeon_pipvar.h> 89 1.1 hikaru #include <mips/cavium/dev/octeon_pkovar.h> 90 1.24 simonb #include <mips/cavium/dev/octeon_powvar.h> 91 1.1 hikaru #include <mips/cavium/dev/octeon_smivar.h> 92 1.24 simonb 93 1.1 hikaru #include <mips/cavium/dev/if_cnmacvar.h> 94 1.1 hikaru 95 1.1 hikaru /* 96 1.1 hikaru * Set the PKO to think command buffers are an odd length. This makes it so we 97 1.1 hikaru * never have to divide a comamnd across two buffers. 98 1.1 hikaru */ 99 1.1 hikaru #define OCTEON_POOL_NWORDS_CMD \ 100 1.1 hikaru (((uint32_t)OCTEON_POOL_SIZE_CMD / sizeof(uint64_t)) - 1) 101 1.1 hikaru #define FPA_COMMAND_BUFFER_POOL_NWORDS OCTEON_POOL_NWORDS_CMD /* XXX */ 102 1.1 hikaru 103 1.19 simonb static void cnmac_buf_init(struct cnmac_softc *); 104 1.1 hikaru 105 1.19 simonb static int cnmac_match(device_t, struct cfdata *, void *); 106 1.19 simonb static void cnmac_attach(device_t, device_t, void *); 107 1.19 simonb static void cnmac_pip_init(struct cnmac_softc *); 108 1.19 simonb static void cnmac_ipd_init(struct cnmac_softc *); 109 1.19 simonb static void cnmac_pko_init(struct cnmac_softc *); 110 1.19 simonb 111 1.19 simonb static void cnmac_board_mac_addr(uint8_t *, size_t, struct cnmac_softc *); 112 1.19 simonb 113 1.19 simonb static int cnmac_mii_readreg(device_t, int, int, uint16_t *); 114 1.19 simonb static int cnmac_mii_writereg(device_t, int, int, uint16_t); 115 1.19 simonb static void cnmac_mii_statchg(struct ifnet *); 116 1.19 simonb 117 1.19 simonb static int cnmac_mediainit(struct cnmac_softc *); 118 1.19 simonb static void cnmac_mediastatus(struct ifnet *, struct ifmediareq *); 119 1.19 simonb 120 1.19 simonb static inline void cnmac_send_queue_flush_prefetch(struct cnmac_softc *); 121 1.19 simonb static inline void cnmac_send_queue_flush_fetch(struct cnmac_softc *); 122 1.19 simonb static inline void cnmac_send_queue_flush(struct cnmac_softc *); 123 1.19 simonb static inline void cnmac_send_queue_flush_sync(struct cnmac_softc *); 124 1.26 simonb static void cnmac_send_queue_check_and_flush(struct cnmac_softc *); 125 1.19 simonb static inline int cnmac_send_queue_is_full(struct cnmac_softc *); 126 1.19 simonb static inline void cnmac_send_queue_add(struct cnmac_softc *, struct mbuf *, 127 1.19 simonb uint64_t *); 128 1.19 simonb static inline void cnmac_send_queue_del(struct cnmac_softc *, struct mbuf **, 129 1.19 simonb uint64_t **); 130 1.24 simonb static inline int cnmac_buf_free_work(struct cnmac_softc *, uint64_t *); 131 1.24 simonb static inline void cnmac_buf_ext_free(struct mbuf *, void *, size_t, void *); 132 1.1 hikaru 133 1.19 simonb static int cnmac_ioctl(struct ifnet *, u_long, void *); 134 1.19 simonb static void cnmac_watchdog(struct ifnet *); 135 1.19 simonb static int cnmac_init(struct ifnet *); 136 1.19 simonb static void cnmac_stop(struct ifnet *, int); 137 1.19 simonb static void cnmac_start(struct ifnet *); 138 1.19 simonb 139 1.19 simonb static inline int cnmac_send_cmd(struct cnmac_softc *, uint64_t, uint64_t, 140 1.19 simonb int *); 141 1.19 simonb static inline uint64_t cnmac_send_makecmd_w1(int, paddr_t); 142 1.24 simonb static inline uint64_t cnmac_send_makecmd_w0(uint64_t, uint64_t, size_t, int, 143 1.24 simonb int); 144 1.19 simonb static inline int cnmac_send_makecmd_gbuf(struct cnmac_softc *, struct mbuf *, 145 1.19 simonb uint64_t *, int *); 146 1.19 simonb static inline int cnmac_send_makecmd(struct cnmac_softc *, struct mbuf *, 147 1.19 simonb uint64_t *, uint64_t *, uint64_t *); 148 1.19 simonb static inline int cnmac_send_buf(struct cnmac_softc *, struct mbuf *, 149 1.19 simonb uint64_t *, int *); 150 1.19 simonb static inline int cnmac_send(struct cnmac_softc *, struct mbuf *, int *); 151 1.19 simonb 152 1.19 simonb static int cnmac_reset(struct cnmac_softc *); 153 1.19 simonb static int cnmac_configure(struct cnmac_softc *); 154 1.19 simonb static int cnmac_configure_common(struct cnmac_softc *); 155 1.19 simonb 156 1.19 simonb static void cnmac_tick_free(void *); 157 1.19 simonb static void cnmac_tick_misc(void *); 158 1.19 simonb 159 1.19 simonb static inline int cnmac_recv_mbuf(struct cnmac_softc *, uint64_t *, 160 1.19 simonb struct mbuf **); 161 1.19 simonb static inline int cnmac_recv_check(struct cnmac_softc *, uint64_t); 162 1.19 simonb static inline int cnmac_recv(struct cnmac_softc *, uint64_t *); 163 1.24 simonb static int cnmac_intr(void *); 164 1.1 hikaru 165 1.24 simonb /* device parameters */ 166 1.19 simonb int cnmac_param_pko_cmd_w0_n2 = 1; 167 1.1 hikaru 168 1.19 simonb CFATTACH_DECL_NEW(cnmac, sizeof(struct cnmac_softc), 169 1.19 simonb cnmac_match, cnmac_attach, NULL, NULL); 170 1.1 hikaru 171 1.1 hikaru /* ---- buffer management */ 172 1.1 hikaru 173 1.19 simonb static const struct cnmac_pool_param { 174 1.1 hikaru int poolno; 175 1.1 hikaru size_t size; 176 1.1 hikaru size_t nelems; 177 1.19 simonb } cnmac_pool_params[] = { 178 1.1 hikaru #define _ENTRY(x) { OCTEON_POOL_NO_##x, OCTEON_POOL_SIZE_##x, OCTEON_POOL_NELEMS_##x } 179 1.1 hikaru _ENTRY(PKT), 180 1.1 hikaru _ENTRY(WQE), 181 1.1 hikaru _ENTRY(CMD), 182 1.1 hikaru _ENTRY(SG) 183 1.1 hikaru #undef _ENTRY 184 1.1 hikaru }; 185 1.24 simonb struct octfpa_buf *cnmac_pools[FPA_NPOOLS]; 186 1.19 simonb #define cnmac_fb_pkt cnmac_pools[OCTEON_POOL_NO_PKT] 187 1.19 simonb #define cnmac_fb_wqe cnmac_pools[OCTEON_POOL_NO_WQE] 188 1.19 simonb #define cnmac_fb_cmd cnmac_pools[OCTEON_POOL_NO_CMD] 189 1.19 simonb #define cnmac_fb_sg cnmac_pools[OCTEON_POOL_NO_SG] 190 1.1 hikaru 191 1.24 simonb static int cnmac_npowgroups = 0; 192 1.24 simonb 193 1.1 hikaru static void 194 1.19 simonb cnmac_buf_init(struct cnmac_softc *sc) 195 1.1 hikaru { 196 1.1 hikaru static int once; 197 1.1 hikaru int i; 198 1.19 simonb const struct cnmac_pool_param *pp; 199 1.19 simonb struct octfpa_buf *fb; 200 1.1 hikaru 201 1.1 hikaru if (once == 1) 202 1.1 hikaru return; 203 1.1 hikaru once = 1; 204 1.1 hikaru 205 1.19 simonb for (i = 0; i < (int)__arraycount(cnmac_pool_params); i++) { 206 1.19 simonb pp = &cnmac_pool_params[i]; 207 1.19 simonb octfpa_buf_init(pp->poolno, pp->size, pp->nelems, &fb); 208 1.19 simonb cnmac_pools[i] = fb; 209 1.1 hikaru } 210 1.1 hikaru } 211 1.1 hikaru 212 1.1 hikaru /* ---- autoconf */ 213 1.1 hikaru 214 1.1 hikaru static int 215 1.19 simonb cnmac_match(device_t parent, struct cfdata *match, void *aux) 216 1.1 hikaru { 217 1.19 simonb struct octgmx_attach_args *ga = aux; 218 1.1 hikaru 219 1.1 hikaru if (strcmp(match->cf_name, ga->ga_name) != 0) { 220 1.1 hikaru return 0; 221 1.1 hikaru } 222 1.1 hikaru return 1; 223 1.1 hikaru } 224 1.1 hikaru 225 1.1 hikaru static void 226 1.19 simonb cnmac_attach(device_t parent, device_t self, void *aux) 227 1.1 hikaru { 228 1.19 simonb struct cnmac_softc *sc = device_private(self); 229 1.19 simonb struct octgmx_attach_args *ga = aux; 230 1.1 hikaru struct ifnet *ifp = &sc->sc_ethercom.ec_if; 231 1.18 mrg prop_dictionary_t dict; 232 1.18 mrg prop_object_t clk; 233 1.1 hikaru uint8_t enaddr[ETHER_ADDR_LEN]; 234 1.1 hikaru 235 1.24 simonb if (cnmac_npowgroups >= OCTEON_POW_GROUP_MAX) { 236 1.24 simonb printf(": out of POW groups\n"); 237 1.24 simonb } 238 1.24 simonb 239 1.1 hikaru sc->sc_dev = self; 240 1.1 hikaru sc->sc_regt = ga->ga_regt; 241 1.1 hikaru sc->sc_port = ga->ga_portno; 242 1.1 hikaru sc->sc_port_type = ga->ga_port_type; 243 1.1 hikaru sc->sc_gmx = ga->ga_gmx; 244 1.1 hikaru sc->sc_gmx_port = ga->ga_gmx_port; 245 1.24 simonb sc->sc_smi = ga->ga_smi; 246 1.24 simonb sc->sc_powgroup = cnmac_npowgroups++; 247 1.1 hikaru 248 1.20 simonb if (sc->sc_port >= CVMSEG_LM_ETHER_COUNT) { 249 1.20 simonb /* 250 1.20 simonb * If we got here, increase CVMSEG_LM_ETHER_COUNT 251 1.20 simonb * in octeonvar.h . 252 1.20 simonb */ 253 1.20 simonb printf("%s: ERROR out of CVMSEG LM buffers\n", 254 1.20 simonb device_xname(self)); 255 1.20 simonb return; 256 1.20 simonb } 257 1.20 simonb 258 1.1 hikaru sc->sc_init_flag = 0; 259 1.1 hikaru /* 260 1.1 hikaru * XXXUEBAYASI 261 1.1 hikaru * Setting PIP_IP_OFFSET[OFFSET] to 8 causes panic ... why??? 262 1.1 hikaru */ 263 1.1 hikaru sc->sc_ip_offset = 0/* XXX */; 264 1.1 hikaru 265 1.1 hikaru if (MIPS_PRID_IMPL(mips_options.mips_cpu_id) <= MIPS_CN30XX) { 266 1.19 simonb SET(sc->sc_quirks, CNMAC_QUIRKS_NO_PRE_ALIGN); 267 1.19 simonb SET(sc->sc_quirks, CNMAC_QUIRKS_NO_RX_INBND); 268 1.1 hikaru } 269 1.1 hikaru 270 1.19 simonb cnmac_board_mac_addr(enaddr, sizeof(enaddr), sc); 271 1.24 simonb printf("%s: Ethernet address %s\n", device_xname(self), 272 1.1 hikaru ether_sprintf(enaddr)); 273 1.1 hikaru 274 1.1 hikaru SIMPLEQ_INIT(&sc->sc_sendq); 275 1.1 hikaru sc->sc_soft_req_thresh = 15/* XXX */; 276 1.1 hikaru sc->sc_ext_callback_cnt = 0; 277 1.1 hikaru 278 1.19 simonb octgmx_stats_init(sc->sc_gmx_port); 279 1.1 hikaru 280 1.1 hikaru callout_init(&sc->sc_tick_misc_ch, 0); 281 1.25 simonb callout_setfunc(&sc->sc_tick_misc_ch, cnmac_tick_misc, sc); 282 1.25 simonb 283 1.1 hikaru callout_init(&sc->sc_tick_free_ch, 0); 284 1.25 simonb callout_setfunc(&sc->sc_tick_free_ch, cnmac_tick_free, sc); 285 1.1 hikaru 286 1.24 simonb const int dv_unit = device_unit(self); 287 1.19 simonb octfau_op_init(&sc->sc_fau_done, 288 1.24 simonb OCTEON_CVMSEG_ETHER_OFFSET(dv_unit, csm_ether_fau_done), 289 1.24 simonb OCT_FAU_REG_ADDR_END - (8 * (dv_unit + 1))/* XXX */); 290 1.19 simonb octfau_op_set_8(&sc->sc_fau_done, 0); 291 1.1 hikaru 292 1.19 simonb cnmac_pip_init(sc); 293 1.19 simonb cnmac_ipd_init(sc); 294 1.19 simonb cnmac_pko_init(sc); 295 1.24 simonb 296 1.24 simonb cnmac_configure_common(sc); 297 1.1 hikaru 298 1.1 hikaru sc->sc_gmx_port->sc_ipd = sc->sc_ipd; 299 1.1 hikaru sc->sc_gmx_port->sc_port_mii = &sc->sc_mii; 300 1.1 hikaru sc->sc_gmx_port->sc_port_ec = &sc->sc_ethercom; 301 1.1 hikaru /* XXX */ 302 1.1 hikaru sc->sc_gmx_port->sc_quirks = sc->sc_quirks; 303 1.1 hikaru 304 1.1 hikaru /* XXX */ 305 1.19 simonb sc->sc_pow = &octpow_softc; 306 1.1 hikaru 307 1.19 simonb cnmac_mediainit(sc); 308 1.1 hikaru 309 1.24 simonb strncpy(ifp->if_xname, device_xname(self), sizeof(ifp->if_xname)); 310 1.1 hikaru ifp->if_softc = sc; 311 1.1 hikaru ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 312 1.19 simonb ifp->if_ioctl = cnmac_ioctl; 313 1.19 simonb ifp->if_start = cnmac_start; 314 1.19 simonb ifp->if_watchdog = cnmac_watchdog; 315 1.19 simonb ifp->if_init = cnmac_init; 316 1.19 simonb ifp->if_stop = cnmac_stop; 317 1.10 riastrad IFQ_SET_MAXLEN(&ifp->if_snd, uimax(GATHER_QUEUE_SIZE, IFQ_MAXLEN)); 318 1.1 hikaru IFQ_SET_READY(&ifp->if_snd); 319 1.1 hikaru 320 1.28 skrll 321 1.1 hikaru ifp->if_capabilities = 322 1.24 simonb #if 0 /* XXX: no tx checksum yet */ 323 1.24 simonb IFCAP_CSUM_IPv4_Tx | IFCAP_CSUM_IPv4_Rx | 324 1.24 simonb IFCAP_CSUM_TCPv4_Tx | IFCAP_CSUM_TCPv4_Rx | 325 1.24 simonb IFCAP_CSUM_UDPv4_Tx | IFCAP_CSUM_UDPv4_Rx | 326 1.24 simonb IFCAP_CSUM_TCPv6_Tx | IFCAP_CSUM_TCPv6_Rx | 327 1.24 simonb IFCAP_CSUM_UDPv6_Tx | IFCAP_CSUM_UDPv6_Rx; 328 1.24 simonb #else 329 1.12 msaitoh IFCAP_CSUM_IPv4_Rx | IFCAP_CSUM_TCPv4_Rx | IFCAP_CSUM_UDPv4_Rx | 330 1.12 msaitoh IFCAP_CSUM_TCPv6_Rx | IFCAP_CSUM_UDPv6_Rx; 331 1.24 simonb #endif 332 1.1 hikaru 333 1.7 jmcneill /* 802.1Q VLAN-sized frames are supported */ 334 1.7 jmcneill sc->sc_ethercom.ec_capabilities |= ETHERCAP_VLAN_MTU; 335 1.7 jmcneill 336 1.19 simonb octgmx_set_mac_addr(sc->sc_gmx_port, enaddr); 337 1.1 hikaru 338 1.1 hikaru if_attach(ifp); 339 1.1 hikaru ether_ifattach(ifp, enaddr); 340 1.19 simonb octgmx_set_filter(sc->sc_gmx_port); 341 1.1 hikaru 342 1.1 hikaru #if 1 343 1.19 simonb cnmac_buf_init(sc); 344 1.1 hikaru #endif 345 1.1 hikaru 346 1.24 simonb sc->sc_ih = octeon_intr_establish(POW_WORKQ_IRQ(sc->sc_powgroup), 347 1.24 simonb IPL_NET, cnmac_intr, sc); 348 1.24 simonb if (sc->sc_ih == NULL) 349 1.24 simonb panic("%s: could not set up interrupt", device_xname(self)); 350 1.1 hikaru 351 1.18 mrg dict = device_properties(sc->sc_gmx->sc_dev); 352 1.18 mrg 353 1.18 mrg clk = prop_dictionary_get(dict, "rgmii-tx"); 354 1.24 simonb if (clk) 355 1.24 simonb sc->sc_gmx_port->sc_clk_tx_setting = 356 1.24 simonb prop_number_signed_value(clk); 357 1.18 mrg clk = prop_dictionary_get(dict, "rgmii-rx"); 358 1.24 simonb if (clk) 359 1.24 simonb sc->sc_gmx_port->sc_clk_rx_setting = 360 1.24 simonb prop_number_signed_value(clk); 361 1.1 hikaru } 362 1.1 hikaru 363 1.1 hikaru /* ---- submodules */ 364 1.1 hikaru 365 1.1 hikaru /* XXX */ 366 1.1 hikaru static void 367 1.19 simonb cnmac_pip_init(struct cnmac_softc *sc) 368 1.1 hikaru { 369 1.19 simonb struct octpip_attach_args pip_aa; 370 1.1 hikaru 371 1.1 hikaru pip_aa.aa_port = sc->sc_port; 372 1.1 hikaru pip_aa.aa_regt = sc->sc_regt; 373 1.1 hikaru pip_aa.aa_tag_type = POW_TAG_TYPE_ORDERED/* XXX */; 374 1.24 simonb pip_aa.aa_receive_group = sc->sc_powgroup; 375 1.1 hikaru pip_aa.aa_ip_offset = sc->sc_ip_offset; 376 1.19 simonb octpip_init(&pip_aa, &sc->sc_pip); 377 1.24 simonb octpip_port_config(sc->sc_pip); 378 1.1 hikaru } 379 1.1 hikaru 380 1.1 hikaru /* XXX */ 381 1.1 hikaru static void 382 1.19 simonb cnmac_ipd_init(struct cnmac_softc *sc) 383 1.1 hikaru { 384 1.19 simonb struct octipd_attach_args ipd_aa; 385 1.1 hikaru 386 1.1 hikaru ipd_aa.aa_port = sc->sc_port; 387 1.1 hikaru ipd_aa.aa_regt = sc->sc_regt; 388 1.1 hikaru ipd_aa.aa_first_mbuff_skip = 184/* XXX */; 389 1.1 hikaru ipd_aa.aa_not_first_mbuff_skip = 0/* XXX */; 390 1.19 simonb octipd_init(&ipd_aa, &sc->sc_ipd); 391 1.1 hikaru } 392 1.1 hikaru 393 1.1 hikaru /* XXX */ 394 1.1 hikaru static void 395 1.19 simonb cnmac_pko_init(struct cnmac_softc *sc) 396 1.1 hikaru { 397 1.19 simonb struct octpko_attach_args pko_aa; 398 1.1 hikaru 399 1.1 hikaru pko_aa.aa_port = sc->sc_port; 400 1.1 hikaru pko_aa.aa_regt = sc->sc_regt; 401 1.1 hikaru pko_aa.aa_cmdptr = &sc->sc_cmdptr; 402 1.1 hikaru pko_aa.aa_cmd_buf_pool = OCTEON_POOL_NO_CMD; 403 1.1 hikaru pko_aa.aa_cmd_buf_size = OCTEON_POOL_NWORDS_CMD; 404 1.19 simonb octpko_init(&pko_aa, &sc->sc_pko); 405 1.1 hikaru } 406 1.1 hikaru 407 1.1 hikaru /* ---- XXX */ 408 1.1 hikaru 409 1.1 hikaru #define ADDR2UINT64(u, a) \ 410 1.1 hikaru do { \ 411 1.1 hikaru u = \ 412 1.1 hikaru (((uint64_t)a[0] << 40) | ((uint64_t)a[1] << 32) | \ 413 1.1 hikaru ((uint64_t)a[2] << 24) | ((uint64_t)a[3] << 16) | \ 414 1.12 msaitoh ((uint64_t)a[4] << 8) | ((uint64_t)a[5] << 0)); \ 415 1.1 hikaru } while (0) 416 1.1 hikaru #define UINT642ADDR(a, u) \ 417 1.1 hikaru do { \ 418 1.1 hikaru a[0] = (uint8_t)((u) >> 40); a[1] = (uint8_t)((u) >> 32); \ 419 1.1 hikaru a[2] = (uint8_t)((u) >> 24); a[3] = (uint8_t)((u) >> 16); \ 420 1.12 msaitoh a[4] = (uint8_t)((u) >> 8); a[5] = (uint8_t)((u) >> 0); \ 421 1.1 hikaru } while (0) 422 1.1 hikaru 423 1.1 hikaru static void 424 1.19 simonb cnmac_board_mac_addr(uint8_t *enaddr, size_t size, struct cnmac_softc *sc) 425 1.1 hikaru { 426 1.1 hikaru prop_dictionary_t dict; 427 1.1 hikaru prop_data_t ea; 428 1.1 hikaru 429 1.1 hikaru dict = device_properties(sc->sc_dev); 430 1.1 hikaru KASSERT(dict != NULL); 431 1.1 hikaru ea = prop_dictionary_get(dict, "mac-address"); 432 1.1 hikaru KASSERT(ea != NULL); 433 1.21 simonb memcpy(enaddr, prop_data_value(ea), size); 434 1.1 hikaru } 435 1.1 hikaru 436 1.1 hikaru /* ---- media */ 437 1.1 hikaru 438 1.1 hikaru static int 439 1.19 simonb cnmac_mii_readreg(device_t self, int phy_addr, int reg, uint16_t *val) 440 1.1 hikaru { 441 1.19 simonb struct cnmac_softc *sc = device_private(self); 442 1.1 hikaru 443 1.19 simonb return octsmi_read(sc->sc_smi, phy_addr, reg, val); 444 1.1 hikaru } 445 1.1 hikaru 446 1.11 msaitoh static int 447 1.19 simonb cnmac_mii_writereg(device_t self, int phy_addr, int reg, uint16_t val) 448 1.1 hikaru { 449 1.19 simonb struct cnmac_softc *sc = device_private(self); 450 1.1 hikaru 451 1.19 simonb return octsmi_write(sc->sc_smi, phy_addr, reg, val); 452 1.1 hikaru } 453 1.1 hikaru 454 1.1 hikaru static void 455 1.19 simonb cnmac_mii_statchg(struct ifnet *ifp) 456 1.1 hikaru { 457 1.19 simonb struct cnmac_softc *sc = ifp->if_softc; 458 1.1 hikaru 459 1.19 simonb octpko_port_enable(sc->sc_pko, 0); 460 1.19 simonb octgmx_port_enable(sc->sc_gmx_port, 0); 461 1.1 hikaru 462 1.19 simonb cnmac_reset(sc); 463 1.1 hikaru 464 1.1 hikaru if (ISSET(ifp->if_flags, IFF_RUNNING)) 465 1.19 simonb octgmx_set_filter(sc->sc_gmx_port); 466 1.1 hikaru 467 1.19 simonb octpko_port_enable(sc->sc_pko, 1); 468 1.19 simonb octgmx_port_enable(sc->sc_gmx_port, 1); 469 1.1 hikaru } 470 1.1 hikaru 471 1.1 hikaru static int 472 1.19 simonb cnmac_mediainit(struct cnmac_softc *sc) 473 1.1 hikaru { 474 1.1 hikaru struct ifnet *ifp = &sc->sc_ethercom.ec_if; 475 1.13 msaitoh struct mii_data *mii = &sc->sc_mii; 476 1.1 hikaru prop_object_t phy; 477 1.1 hikaru 478 1.13 msaitoh mii->mii_ifp = ifp; 479 1.19 simonb mii->mii_readreg = cnmac_mii_readreg; 480 1.19 simonb mii->mii_writereg = cnmac_mii_writereg; 481 1.19 simonb mii->mii_statchg = cnmac_mii_statchg; 482 1.13 msaitoh sc->sc_ethercom.ec_mii = mii; 483 1.13 msaitoh 484 1.13 msaitoh /* Initialize ifmedia structures. */ 485 1.19 simonb ifmedia_init(&mii->mii_media, 0, ether_mediachange, cnmac_mediastatus); 486 1.1 hikaru 487 1.1 hikaru phy = prop_dictionary_get(device_properties(sc->sc_dev), "phy-addr"); 488 1.1 hikaru KASSERT(phy != NULL); 489 1.1 hikaru 490 1.21 simonb mii_attach(sc->sc_dev, mii, 0xffffffff, prop_number_signed_value(phy), 491 1.1 hikaru MII_OFFSET_ANY, MIIF_DOPAUSE); 492 1.1 hikaru 493 1.1 hikaru /* XXX XXX XXX */ 494 1.13 msaitoh if (LIST_FIRST(&mii->mii_phys) != NULL) { 495 1.1 hikaru /* XXX XXX XXX */ 496 1.13 msaitoh ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_AUTO); 497 1.1 hikaru /* XXX XXX XXX */ 498 1.1 hikaru } else { 499 1.1 hikaru /* XXX XXX XXX */ 500 1.13 msaitoh ifmedia_add(&mii->mii_media, IFM_ETHER | IFM_NONE, 501 1.1 hikaru MII_MEDIA_NONE, NULL); 502 1.1 hikaru /* XXX XXX XXX */ 503 1.13 msaitoh ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_NONE); 504 1.1 hikaru /* XXX XXX XXX */ 505 1.1 hikaru } 506 1.1 hikaru /* XXX XXX XXX */ 507 1.1 hikaru 508 1.1 hikaru return 0; 509 1.1 hikaru } 510 1.1 hikaru 511 1.1 hikaru static void 512 1.19 simonb cnmac_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr) 513 1.1 hikaru { 514 1.19 simonb struct cnmac_softc *sc = ifp->if_softc; 515 1.1 hikaru 516 1.1 hikaru mii_pollstat(&sc->sc_mii); 517 1.1 hikaru 518 1.1 hikaru ifmr->ifm_status = sc->sc_mii.mii_media_status; 519 1.1 hikaru ifmr->ifm_active = sc->sc_mii.mii_media_active; 520 1.1 hikaru ifmr->ifm_active = (sc->sc_mii.mii_media_active & ~IFM_ETH_FMASK) | 521 1.1 hikaru sc->sc_gmx_port->sc_port_flowflags; 522 1.1 hikaru } 523 1.1 hikaru 524 1.1 hikaru /* ---- send buffer garbage collection */ 525 1.1 hikaru 526 1.1 hikaru static inline void 527 1.19 simonb cnmac_send_queue_flush_prefetch(struct cnmac_softc *sc) 528 1.1 hikaru { 529 1.23 simonb 530 1.23 simonb KASSERT(sc->sc_prefetch == 0); 531 1.19 simonb octfau_op_inc_fetch_8(&sc->sc_fau_done, 0); 532 1.1 hikaru sc->sc_prefetch = 1; 533 1.1 hikaru } 534 1.1 hikaru 535 1.1 hikaru static inline void 536 1.19 simonb cnmac_send_queue_flush_fetch(struct cnmac_softc *sc) 537 1.1 hikaru { 538 1.23 simonb 539 1.23 simonb KASSERT(sc->sc_prefetch == 1); 540 1.19 simonb sc->sc_hard_done_cnt = octfau_op_inc_read_8(&sc->sc_fau_done); 541 1.23 simonb KASSERT(sc->sc_hard_done_cnt <= 0); 542 1.1 hikaru sc->sc_prefetch = 0; 543 1.1 hikaru } 544 1.1 hikaru 545 1.1 hikaru static inline void 546 1.19 simonb cnmac_send_queue_flush(struct cnmac_softc *sc) 547 1.1 hikaru { 548 1.1 hikaru const int64_t sent_count = sc->sc_hard_done_cnt; 549 1.1 hikaru int i; 550 1.1 hikaru 551 1.23 simonb KASSERT(sc->sc_flush == 0); 552 1.23 simonb KASSERT(sent_count <= 0); 553 1.1 hikaru 554 1.1 hikaru for (i = 0; i < 0 - sent_count; i++) { 555 1.1 hikaru struct mbuf *m; 556 1.1 hikaru uint64_t *gbuf; 557 1.1 hikaru 558 1.19 simonb cnmac_send_queue_del(sc, &m, &gbuf); 559 1.1 hikaru 560 1.19 simonb octfpa_buf_put(cnmac_fb_sg, gbuf); 561 1.1 hikaru 562 1.1 hikaru m_freem(m); 563 1.8 jmcneill 564 1.27 thorpej sc->sc_txbusy = false; 565 1.1 hikaru } 566 1.1 hikaru 567 1.19 simonb octfau_op_inc_fetch_8(&sc->sc_fau_done, i); 568 1.1 hikaru sc->sc_flush = i; 569 1.1 hikaru } 570 1.1 hikaru 571 1.1 hikaru static inline void 572 1.19 simonb cnmac_send_queue_flush_sync(struct cnmac_softc *sc) 573 1.1 hikaru { 574 1.1 hikaru if (sc->sc_flush == 0) 575 1.1 hikaru return; 576 1.1 hikaru 577 1.23 simonb KASSERT(sc->sc_flush > 0); 578 1.1 hikaru 579 1.1 hikaru /* XXX XXX XXX */ 580 1.19 simonb octfau_op_inc_read_8(&sc->sc_fau_done); 581 1.1 hikaru sc->sc_soft_req_cnt -= sc->sc_flush; 582 1.23 simonb KASSERT(sc->sc_soft_req_cnt >= 0); 583 1.1 hikaru /* XXX XXX XXX */ 584 1.1 hikaru 585 1.1 hikaru sc->sc_flush = 0; 586 1.1 hikaru } 587 1.1 hikaru 588 1.1 hikaru static inline int 589 1.19 simonb cnmac_send_queue_is_full(struct cnmac_softc *sc) 590 1.1 hikaru { 591 1.19 simonb #ifdef CNMAC_SEND_QUEUE_CHECK 592 1.1 hikaru int64_t nofree_cnt; 593 1.1 hikaru 594 1.12 msaitoh nofree_cnt = sc->sc_soft_req_cnt + sc->sc_hard_done_cnt; 595 1.1 hikaru 596 1.1 hikaru if (__predict_false(nofree_cnt == GATHER_QUEUE_SIZE - 1)) { 597 1.19 simonb cnmac_send_queue_flush(sc); 598 1.19 simonb cnmac_send_queue_flush_sync(sc); 599 1.1 hikaru return 1; 600 1.1 hikaru } 601 1.1 hikaru 602 1.1 hikaru #endif 603 1.1 hikaru return 0; 604 1.1 hikaru } 605 1.1 hikaru 606 1.26 simonb static void 607 1.26 simonb cnmac_send_queue_check_and_flush(struct cnmac_softc *sc) 608 1.26 simonb { 609 1.26 simonb int s; 610 1.26 simonb 611 1.26 simonb /* XXX XXX XXX */ 612 1.26 simonb s = splnet(); 613 1.26 simonb if (sc->sc_soft_req_cnt > 0) { 614 1.26 simonb cnmac_send_queue_flush_prefetch(sc); 615 1.26 simonb cnmac_send_queue_flush_fetch(sc); 616 1.26 simonb cnmac_send_queue_flush(sc); 617 1.26 simonb cnmac_send_queue_flush_sync(sc); 618 1.26 simonb } 619 1.26 simonb splx(s); 620 1.26 simonb /* XXX XXX XXX */ 621 1.26 simonb } 622 1.26 simonb 623 1.1 hikaru /* 624 1.1 hikaru * (Ab)use m_nextpkt and m_paddr to maintain mbuf chain and pointer to gather 625 1.1 hikaru * buffer. Other mbuf members may be used by m_freem(), so don't touch them! 626 1.1 hikaru */ 627 1.1 hikaru 628 1.1 hikaru struct _send_queue_entry { 629 1.1 hikaru union { 630 1.1 hikaru struct mbuf _sqe_s_mbuf; 631 1.1 hikaru struct { 632 1.1 hikaru char _sqe_s_entry_pad[offsetof(struct mbuf, m_nextpkt)]; 633 1.1 hikaru SIMPLEQ_ENTRY(_send_queue_entry) _sqe_s_entry_entry; 634 1.1 hikaru } _sqe_s_entry; 635 1.1 hikaru struct { 636 1.1 hikaru char _sqe_s_gbuf_pad[offsetof(struct mbuf, m_paddr)]; 637 1.1 hikaru uint64_t *_sqe_s_gbuf_gbuf; 638 1.1 hikaru } _sqe_s_gbuf; 639 1.1 hikaru } _sqe_u; 640 1.1 hikaru #define _sqe_entry _sqe_u._sqe_s_entry._sqe_s_entry_entry 641 1.1 hikaru #define _sqe_gbuf _sqe_u._sqe_s_gbuf._sqe_s_gbuf_gbuf 642 1.1 hikaru }; 643 1.1 hikaru 644 1.1 hikaru static inline void 645 1.19 simonb cnmac_send_queue_add(struct cnmac_softc *sc, struct mbuf *m, 646 1.1 hikaru uint64_t *gbuf) 647 1.1 hikaru { 648 1.1 hikaru struct _send_queue_entry *sqe = (struct _send_queue_entry *)m; 649 1.1 hikaru 650 1.1 hikaru sqe->_sqe_gbuf = gbuf; 651 1.1 hikaru SIMPLEQ_INSERT_TAIL(&sc->sc_sendq, sqe, _sqe_entry); 652 1.1 hikaru 653 1.1 hikaru if ((m->m_flags & M_EXT) && m->m_ext.ext_free != NULL) 654 1.1 hikaru sc->sc_ext_callback_cnt++; 655 1.1 hikaru } 656 1.1 hikaru 657 1.1 hikaru static inline void 658 1.19 simonb cnmac_send_queue_del(struct cnmac_softc *sc, struct mbuf **rm, uint64_t **rgbuf) 659 1.1 hikaru { 660 1.1 hikaru struct _send_queue_entry *sqe; 661 1.1 hikaru 662 1.1 hikaru sqe = SIMPLEQ_FIRST(&sc->sc_sendq); 663 1.23 simonb KASSERT(sqe != NULL); 664 1.1 hikaru SIMPLEQ_REMOVE_HEAD(&sc->sc_sendq, _sqe_entry); 665 1.1 hikaru 666 1.1 hikaru *rm = (void *)sqe; 667 1.1 hikaru *rgbuf = sqe->_sqe_gbuf; 668 1.1 hikaru 669 1.1 hikaru if (((*rm)->m_flags & M_EXT) && (*rm)->m_ext.ext_free != NULL) { 670 1.1 hikaru sc->sc_ext_callback_cnt--; 671 1.23 simonb KASSERT(sc->sc_ext_callback_cnt >= 0); 672 1.1 hikaru } 673 1.1 hikaru } 674 1.1 hikaru 675 1.1 hikaru static inline int 676 1.24 simonb cnmac_buf_free_work(struct cnmac_softc *sc, uint64_t *work) 677 1.1 hikaru { 678 1.24 simonb 679 1.1 hikaru /* XXX when jumbo frame */ 680 1.24 simonb if (ISSET(work[2], PIP_WQE_WORD2_IP_BUFS)) { 681 1.1 hikaru paddr_t addr; 682 1.1 hikaru paddr_t start_buffer; 683 1.1 hikaru 684 1.1 hikaru addr = work[3] & PIP_WQE_WORD3_ADDR; 685 1.1 hikaru start_buffer = addr & ~(2048 - 1); 686 1.1 hikaru 687 1.19 simonb octfpa_buf_put_paddr(cnmac_fb_pkt, start_buffer); 688 1.1 hikaru } 689 1.1 hikaru 690 1.19 simonb octfpa_buf_put(cnmac_fb_wqe, work); 691 1.1 hikaru 692 1.1 hikaru return 0; 693 1.1 hikaru } 694 1.1 hikaru 695 1.1 hikaru static inline void 696 1.24 simonb cnmac_buf_ext_free(struct mbuf *m, void *buf, size_t size, void *arg) 697 1.1 hikaru { 698 1.19 simonb octfpa_buf_put(cnmac_fb_pkt, buf); 699 1.1 hikaru 700 1.23 simonb KASSERT(m != NULL); 701 1.1 hikaru 702 1.1 hikaru pool_cache_put(mb_cache, m); 703 1.1 hikaru } 704 1.1 hikaru 705 1.1 hikaru /* ---- ifnet interfaces */ 706 1.1 hikaru 707 1.1 hikaru static int 708 1.19 simonb cnmac_ioctl(struct ifnet *ifp, u_long cmd, void *data) 709 1.1 hikaru { 710 1.19 simonb struct cnmac_softc *sc = ifp->if_softc; 711 1.1 hikaru struct ifreq *ifr = (struct ifreq *)data; 712 1.1 hikaru int s, error; 713 1.1 hikaru 714 1.1 hikaru s = splnet(); 715 1.1 hikaru switch (cmd) { 716 1.1 hikaru case SIOCSIFMEDIA: 717 1.1 hikaru /* Flow control requires full-duplex mode. */ 718 1.1 hikaru if (IFM_SUBTYPE(ifr->ifr_media) == IFM_AUTO || 719 1.1 hikaru (ifr->ifr_media & IFM_FDX) == 0) { 720 1.1 hikaru ifr->ifr_media &= ~IFM_ETH_FMASK; 721 1.1 hikaru } 722 1.1 hikaru if (IFM_SUBTYPE(ifr->ifr_media) != IFM_AUTO) { 723 1.1 hikaru if ((ifr->ifr_media & IFM_ETH_FMASK) == IFM_FLOW) { 724 1.1 hikaru ifr->ifr_media |= 725 1.1 hikaru IFM_ETH_TXPAUSE | IFM_ETH_RXPAUSE; 726 1.1 hikaru } 727 1.12 msaitoh sc->sc_gmx_port->sc_port_flowflags = 728 1.1 hikaru ifr->ifr_media & IFM_ETH_FMASK; 729 1.1 hikaru } 730 1.1 hikaru error = ifmedia_ioctl(ifp, ifr, &sc->sc_mii.mii_media, cmd); 731 1.1 hikaru break; 732 1.1 hikaru default: 733 1.1 hikaru error = ether_ioctl(ifp, cmd, data); 734 1.1 hikaru break; 735 1.1 hikaru } 736 1.24 simonb 737 1.24 simonb if (error == ENETRESET) { 738 1.24 simonb if (ISSET(ifp->if_flags, IFF_RUNNING)) 739 1.24 simonb octgmx_set_filter(sc->sc_gmx_port); 740 1.24 simonb error = 0; 741 1.24 simonb } 742 1.24 simonb 743 1.19 simonb cnmac_start(ifp); 744 1.24 simonb 745 1.1 hikaru splx(s); 746 1.1 hikaru 747 1.12 msaitoh return error; 748 1.1 hikaru } 749 1.1 hikaru 750 1.1 hikaru /* ---- send (output) */ 751 1.1 hikaru 752 1.1 hikaru static inline uint64_t 753 1.24 simonb cnmac_send_makecmd_w0(uint64_t fau0, uint64_t fau1, size_t len, int segs, 754 1.24 simonb int ipoffp1) 755 1.1 hikaru { 756 1.24 simonb 757 1.19 simonb return octpko_cmd_word0( 758 1.1 hikaru OCT_FAU_OP_SIZE_64, /* sz1 */ 759 1.1 hikaru OCT_FAU_OP_SIZE_64, /* sz0 */ 760 1.1 hikaru 1, fau1, 1, fau0, /* s1, reg1, s0, reg0 */ 761 1.1 hikaru 0, /* le */ 762 1.19 simonb cnmac_param_pko_cmd_w0_n2, /* n2 */ 763 1.1 hikaru 1, 0, /* q, r */ 764 1.1 hikaru (segs == 1) ? 0 : 1, /* g */ 765 1.1 hikaru 0, 0, 1, /* ipoffp1, ii, df */ 766 1.1 hikaru segs, (int)len); /* segs, totalbytes */ 767 1.1 hikaru } 768 1.1 hikaru 769 1.12 msaitoh static inline uint64_t 770 1.19 simonb cnmac_send_makecmd_w1(int size, paddr_t addr) 771 1.1 hikaru { 772 1.24 simonb 773 1.19 simonb return octpko_cmd_word1( 774 1.1 hikaru 0, 0, /* i, back */ 775 1.24 simonb OCTEON_POOL_NO_SG, /* pool */ 776 1.1 hikaru size, addr); /* size, addr */ 777 1.1 hikaru } 778 1.1 hikaru 779 1.1 hikaru static inline int 780 1.19 simonb cnmac_send_makecmd_gbuf(struct cnmac_softc *sc, struct mbuf *m0, uint64_t *gbuf, 781 1.19 simonb int *rsegs) 782 1.1 hikaru { 783 1.1 hikaru struct mbuf *m; 784 1.1 hikaru int segs = 0; 785 1.1 hikaru uintptr_t laddr, rlen, nlen; 786 1.1 hikaru 787 1.1 hikaru for (m = m0; m != NULL; m = m->m_next) { 788 1.1 hikaru 789 1.1 hikaru if (__predict_false(m->m_len == 0)) 790 1.1 hikaru continue; 791 1.1 hikaru 792 1.12 msaitoh /* Aligned 4k */ 793 1.1 hikaru laddr = (uintptr_t)m->m_data & (PAGE_SIZE - 1); 794 1.1 hikaru 795 1.1 hikaru if (laddr + m->m_len > PAGE_SIZE) { 796 1.1 hikaru /* XXX XXX XXX */ 797 1.1 hikaru rlen = PAGE_SIZE - laddr; 798 1.1 hikaru nlen = m->m_len - rlen; 799 1.19 simonb *(gbuf + segs) = cnmac_send_makecmd_w1(rlen, 800 1.1 hikaru kvtophys((vaddr_t)m->m_data)); 801 1.1 hikaru segs++; 802 1.1 hikaru if (segs > 63) { 803 1.1 hikaru return 1; 804 1.1 hikaru } 805 1.1 hikaru /* XXX XXX XXX */ 806 1.1 hikaru } else { 807 1.1 hikaru rlen = 0; 808 1.1 hikaru nlen = m->m_len; 809 1.1 hikaru } 810 1.1 hikaru 811 1.19 simonb *(gbuf + segs) = cnmac_send_makecmd_w1(nlen, 812 1.1 hikaru kvtophys((vaddr_t)(m->m_data + rlen))); 813 1.1 hikaru segs++; 814 1.1 hikaru if (segs > 63) { 815 1.1 hikaru return 1; 816 1.1 hikaru } 817 1.1 hikaru } 818 1.1 hikaru 819 1.23 simonb KASSERT(m == NULL); 820 1.1 hikaru 821 1.1 hikaru *rsegs = segs; 822 1.1 hikaru 823 1.1 hikaru return 0; 824 1.1 hikaru } 825 1.1 hikaru 826 1.1 hikaru static inline int 827 1.19 simonb cnmac_send_makecmd(struct cnmac_softc *sc, struct mbuf *m, 828 1.1 hikaru uint64_t *gbuf, uint64_t *rpko_cmd_w0, uint64_t *rpko_cmd_w1) 829 1.1 hikaru { 830 1.1 hikaru uint64_t pko_cmd_w0, pko_cmd_w1; 831 1.24 simonb int ipoffp1; 832 1.1 hikaru int segs; 833 1.1 hikaru int result = 0; 834 1.1 hikaru 835 1.19 simonb if (cnmac_send_makecmd_gbuf(sc, m, gbuf, &segs)) { 836 1.1 hikaru log(LOG_WARNING, "%s: there are a lot of number of segments" 837 1.1 hikaru " of transmission data", device_xname(sc->sc_dev)); 838 1.1 hikaru result = 1; 839 1.1 hikaru goto done; 840 1.1 hikaru } 841 1.1 hikaru 842 1.24 simonb /* Get the IP packet offset for TCP/UDP checksum offloading. */ 843 1.24 simonb ipoffp1 = (m->m_pkthdr.csum_flags & (M_CSUM_TCPv4 | M_CSUM_UDPv4)) 844 1.24 simonb ? (ETHER_HDR_LEN + 1) : 0; 845 1.24 simonb 846 1.1 hikaru /* 847 1.1 hikaru * segs == 1 -> link mode (single continuous buffer) 848 1.1 hikaru * WORD1[size] is number of bytes pointed by segment 849 1.1 hikaru * 850 1.1 hikaru * segs > 1 -> gather mode (scatter-gather buffer) 851 1.1 hikaru * WORD1[size] is number of segments 852 1.1 hikaru */ 853 1.19 simonb pko_cmd_w0 = cnmac_send_makecmd_w0(sc->sc_fau_done.fd_regno, 854 1.24 simonb 0, m->m_pkthdr.len, segs, ipoffp1); 855 1.4 matt if (segs == 1) { 856 1.19 simonb pko_cmd_w1 = cnmac_send_makecmd_w1( 857 1.4 matt m->m_pkthdr.len, kvtophys((vaddr_t)m->m_data)); 858 1.4 matt } else { 859 1.4 matt #ifdef __mips_n32 860 1.4 matt KASSERT(MIPS_KSEG0_P(gbuf)); 861 1.19 simonb pko_cmd_w1 = cnmac_send_makecmd_w1(segs, 862 1.4 matt MIPS_KSEG0_TO_PHYS(gbuf)); 863 1.4 matt #else 864 1.19 simonb pko_cmd_w1 = cnmac_send_makecmd_w1(segs, 865 1.4 matt MIPS_XKPHYS_TO_PHYS(gbuf)); 866 1.4 matt #endif 867 1.4 matt } 868 1.1 hikaru 869 1.1 hikaru *rpko_cmd_w0 = pko_cmd_w0; 870 1.1 hikaru *rpko_cmd_w1 = pko_cmd_w1; 871 1.1 hikaru 872 1.1 hikaru done: 873 1.1 hikaru return result; 874 1.1 hikaru } 875 1.1 hikaru 876 1.1 hikaru static inline int 877 1.19 simonb cnmac_send_cmd(struct cnmac_softc *sc, uint64_t pko_cmd_w0, 878 1.8 jmcneill uint64_t pko_cmd_w1, int *pwdc) 879 1.1 hikaru { 880 1.1 hikaru uint64_t *cmdptr; 881 1.1 hikaru int result = 0; 882 1.1 hikaru 883 1.4 matt #ifdef __mips_n32 884 1.4 matt KASSERT((sc->sc_cmdptr.cmdptr & ~MIPS_PHYS_MASK) == 0); 885 1.4 matt cmdptr = (uint64_t *)MIPS_PHYS_TO_KSEG0(sc->sc_cmdptr.cmdptr); 886 1.4 matt #else 887 1.1 hikaru cmdptr = (uint64_t *)MIPS_PHYS_TO_XKPHYS_CACHED(sc->sc_cmdptr.cmdptr); 888 1.4 matt #endif 889 1.1 hikaru cmdptr += sc->sc_cmdptr.cmdptr_idx; 890 1.1 hikaru 891 1.23 simonb KASSERT(cmdptr != NULL); 892 1.1 hikaru 893 1.1 hikaru *cmdptr++ = pko_cmd_w0; 894 1.1 hikaru *cmdptr++ = pko_cmd_w1; 895 1.1 hikaru 896 1.23 simonb KASSERT(sc->sc_cmdptr.cmdptr_idx + 2 <= FPA_COMMAND_BUFFER_POOL_NWORDS - 1); 897 1.1 hikaru 898 1.1 hikaru if (sc->sc_cmdptr.cmdptr_idx + 2 == FPA_COMMAND_BUFFER_POOL_NWORDS - 1) { 899 1.1 hikaru paddr_t buf; 900 1.1 hikaru 901 1.19 simonb buf = octfpa_buf_get_paddr(cnmac_fb_cmd); 902 1.1 hikaru if (buf == 0) { 903 1.1 hikaru log(LOG_WARNING, 904 1.1 hikaru "%s: can not allocate command buffer from free pool allocator\n", 905 1.1 hikaru device_xname(sc->sc_dev)); 906 1.1 hikaru result = 1; 907 1.1 hikaru goto done; 908 1.1 hikaru } 909 1.1 hikaru *cmdptr++ = buf; 910 1.1 hikaru sc->sc_cmdptr.cmdptr = (uint64_t)buf; 911 1.1 hikaru sc->sc_cmdptr.cmdptr_idx = 0; 912 1.1 hikaru } else { 913 1.1 hikaru sc->sc_cmdptr.cmdptr_idx += 2; 914 1.1 hikaru } 915 1.1 hikaru 916 1.8 jmcneill *pwdc += 2; 917 1.1 hikaru 918 1.1 hikaru done: 919 1.1 hikaru return result; 920 1.1 hikaru } 921 1.1 hikaru 922 1.1 hikaru static inline int 923 1.19 simonb cnmac_send_buf(struct cnmac_softc *sc, struct mbuf *m, uint64_t *gbuf, 924 1.19 simonb int *pwdc) 925 1.1 hikaru { 926 1.1 hikaru int result = 0, error; 927 1.1 hikaru uint64_t pko_cmd_w0, pko_cmd_w1; 928 1.1 hikaru 929 1.19 simonb error = cnmac_send_makecmd(sc, m, gbuf, &pko_cmd_w0, &pko_cmd_w1); 930 1.1 hikaru if (error != 0) { 931 1.12 msaitoh /* Already logging */ 932 1.1 hikaru result = error; 933 1.1 hikaru goto done; 934 1.1 hikaru } 935 1.1 hikaru 936 1.19 simonb error = cnmac_send_cmd(sc, pko_cmd_w0, pko_cmd_w1, pwdc); 937 1.1 hikaru if (error != 0) { 938 1.12 msaitoh /* Already logging */ 939 1.1 hikaru result = error; 940 1.1 hikaru } 941 1.1 hikaru 942 1.1 hikaru done: 943 1.1 hikaru return result; 944 1.1 hikaru } 945 1.1 hikaru 946 1.1 hikaru static inline int 947 1.19 simonb cnmac_send(struct cnmac_softc *sc, struct mbuf *m, int *pwdc) 948 1.1 hikaru { 949 1.1 hikaru paddr_t gaddr = 0; 950 1.1 hikaru uint64_t *gbuf = NULL; 951 1.1 hikaru int result = 0, error; 952 1.1 hikaru 953 1.19 simonb gaddr = octfpa_buf_get_paddr(cnmac_fb_sg); 954 1.1 hikaru if (gaddr == 0) { 955 1.12 msaitoh log(LOG_WARNING, "%s: can not allocate gather buffer from " 956 1.12 msaitoh "free pool allocator\n", device_xname(sc->sc_dev)); 957 1.1 hikaru result = 1; 958 1.1 hikaru goto done; 959 1.1 hikaru } 960 1.1 hikaru 961 1.4 matt #ifdef __mips_n32 962 1.4 matt KASSERT((gaddr & ~MIPS_PHYS_MASK) == 0); 963 1.4 matt gbuf = (uint64_t *)(uintptr_t)MIPS_PHYS_TO_KSEG0(gaddr); 964 1.4 matt #else 965 1.1 hikaru gbuf = (uint64_t *)(uintptr_t)MIPS_PHYS_TO_XKPHYS_CACHED(gaddr); 966 1.4 matt #endif 967 1.1 hikaru 968 1.23 simonb KASSERT(gbuf != NULL); 969 1.1 hikaru 970 1.19 simonb error = cnmac_send_buf(sc, m, gbuf, pwdc); 971 1.1 hikaru if (error != 0) { 972 1.12 msaitoh /* Already logging */ 973 1.19 simonb octfpa_buf_put_paddr(cnmac_fb_sg, gaddr); 974 1.1 hikaru result = error; 975 1.1 hikaru goto done; 976 1.1 hikaru } 977 1.1 hikaru 978 1.19 simonb cnmac_send_queue_add(sc, m, gbuf); 979 1.1 hikaru 980 1.1 hikaru done: 981 1.1 hikaru return result; 982 1.1 hikaru } 983 1.1 hikaru 984 1.1 hikaru static void 985 1.19 simonb cnmac_start(struct ifnet *ifp) 986 1.1 hikaru { 987 1.19 simonb struct cnmac_softc *sc = ifp->if_softc; 988 1.1 hikaru struct mbuf *m; 989 1.8 jmcneill int wdc = 0; 990 1.1 hikaru 991 1.1 hikaru /* 992 1.12 msaitoh * Performance tuning 993 1.15 gutterid * pre-send iobdma request 994 1.1 hikaru */ 995 1.19 simonb cnmac_send_queue_flush_prefetch(sc); 996 1.1 hikaru 997 1.27 thorpej if ((ifp->if_flags & IFF_RUNNING) == 0) 998 1.27 thorpej goto last; 999 1.27 thorpej 1000 1.27 thorpej if (sc->sc_txbusy) 1001 1.1 hikaru goto last; 1002 1.1 hikaru 1003 1.24 simonb if (__predict_false(!octgmx_link_status(sc->sc_gmx_port))) 1004 1.1 hikaru goto last; 1005 1.1 hikaru 1006 1.1 hikaru for (;;) { 1007 1.1 hikaru IFQ_POLL(&ifp->if_snd, m); 1008 1.1 hikaru if (__predict_false(m == NULL)) 1009 1.1 hikaru break; 1010 1.1 hikaru 1011 1.1 hikaru /* XXX XXX XXX */ 1012 1.19 simonb cnmac_send_queue_flush_fetch(sc); 1013 1.1 hikaru 1014 1.1 hikaru /* 1015 1.12 msaitoh * If no free send buffer is available, free all the sent 1016 1.15 gutterid * buffers and bail out. 1017 1.1 hikaru */ 1018 1.19 simonb if (cnmac_send_queue_is_full(sc)) { 1019 1.27 thorpej sc->sc_txbusy = true; 1020 1.8 jmcneill if (wdc > 0) 1021 1.19 simonb octpko_op_doorbell_write(sc->sc_port, 1022 1.8 jmcneill sc->sc_port, wdc); 1023 1.25 simonb callout_schedule(&sc->sc_tick_free_ch, 1); 1024 1.1 hikaru return; 1025 1.1 hikaru } 1026 1.1 hikaru /* XXX XXX XXX */ 1027 1.1 hikaru 1028 1.1 hikaru IFQ_DEQUEUE(&ifp->if_snd, m); 1029 1.1 hikaru 1030 1.9 msaitoh bpf_mtap(ifp, m, BPF_D_OUT); 1031 1.1 hikaru 1032 1.1 hikaru /* XXX XXX XXX */ 1033 1.1 hikaru if (sc->sc_soft_req_cnt > sc->sc_soft_req_thresh) 1034 1.19 simonb cnmac_send_queue_flush(sc); 1035 1.19 simonb if (cnmac_send(sc, m, &wdc)) { 1036 1.1 hikaru IF_DROP(&ifp->if_snd); 1037 1.1 hikaru m_freem(m); 1038 1.1 hikaru log(LOG_WARNING, 1039 1.12 msaitoh "%s: failed in the transmission of the packet\n", 1040 1.12 msaitoh device_xname(sc->sc_dev)); 1041 1.12 msaitoh } else 1042 1.1 hikaru sc->sc_soft_req_cnt++; 1043 1.12 msaitoh 1044 1.1 hikaru if (sc->sc_flush) 1045 1.19 simonb cnmac_send_queue_flush_sync(sc); 1046 1.1 hikaru /* XXX XXX XXX */ 1047 1.1 hikaru 1048 1.12 msaitoh /* Send next iobdma request */ 1049 1.19 simonb cnmac_send_queue_flush_prefetch(sc); 1050 1.1 hikaru } 1051 1.1 hikaru 1052 1.8 jmcneill if (wdc > 0) 1053 1.19 simonb octpko_op_doorbell_write(sc->sc_port, sc->sc_port, wdc); 1054 1.8 jmcneill 1055 1.1 hikaru last: 1056 1.19 simonb cnmac_send_queue_flush_fetch(sc); 1057 1.25 simonb callout_schedule(&sc->sc_tick_free_ch, 1); 1058 1.1 hikaru } 1059 1.1 hikaru 1060 1.1 hikaru static void 1061 1.19 simonb cnmac_watchdog(struct ifnet *ifp) 1062 1.1 hikaru { 1063 1.19 simonb struct cnmac_softc *sc = ifp->if_softc; 1064 1.1 hikaru 1065 1.1 hikaru printf("%s: device timeout\n", device_xname(sc->sc_dev)); 1066 1.1 hikaru 1067 1.19 simonb cnmac_configure(sc); 1068 1.1 hikaru 1069 1.1 hikaru SET(ifp->if_flags, IFF_RUNNING); 1070 1.27 thorpej sc->sc_txbusy = false; 1071 1.1 hikaru ifp->if_timer = 0; 1072 1.1 hikaru 1073 1.19 simonb cnmac_start(ifp); 1074 1.1 hikaru } 1075 1.1 hikaru 1076 1.1 hikaru static int 1077 1.19 simonb cnmac_init(struct ifnet *ifp) 1078 1.1 hikaru { 1079 1.19 simonb struct cnmac_softc *sc = ifp->if_softc; 1080 1.1 hikaru 1081 1.1 hikaru /* XXX don't disable commonly used parts!!! XXX */ 1082 1.1 hikaru if (sc->sc_init_flag == 0) { 1083 1.1 hikaru /* Cancel any pending I/O. */ 1084 1.19 simonb cnmac_stop(ifp, 0); 1085 1.1 hikaru 1086 1.1 hikaru /* Initialize the device */ 1087 1.19 simonb cnmac_configure(sc); 1088 1.1 hikaru 1089 1.19 simonb octpko_enable(sc->sc_pko); 1090 1.19 simonb octipd_enable(sc->sc_ipd); 1091 1.1 hikaru 1092 1.1 hikaru sc->sc_init_flag = 1; 1093 1.1 hikaru } else { 1094 1.19 simonb octgmx_port_enable(sc->sc_gmx_port, 1); 1095 1.1 hikaru } 1096 1.17 thorpej mii_ifmedia_change(&sc->sc_mii); 1097 1.1 hikaru 1098 1.19 simonb octgmx_set_filter(sc->sc_gmx_port); 1099 1.1 hikaru 1100 1.25 simonb callout_schedule(&sc->sc_tick_misc_ch, hz); 1101 1.25 simonb callout_schedule(&sc->sc_tick_free_ch, hz); 1102 1.1 hikaru 1103 1.1 hikaru SET(ifp->if_flags, IFF_RUNNING); 1104 1.27 thorpej sc->sc_txbusy = false; 1105 1.1 hikaru 1106 1.1 hikaru return 0; 1107 1.1 hikaru } 1108 1.1 hikaru 1109 1.1 hikaru static void 1110 1.19 simonb cnmac_stop(struct ifnet *ifp, int disable) 1111 1.1 hikaru { 1112 1.19 simonb struct cnmac_softc *sc = ifp->if_softc; 1113 1.1 hikaru 1114 1.1 hikaru callout_stop(&sc->sc_tick_misc_ch); 1115 1.1 hikaru callout_stop(&sc->sc_tick_free_ch); 1116 1.1 hikaru 1117 1.1 hikaru mii_down(&sc->sc_mii); 1118 1.1 hikaru 1119 1.19 simonb octgmx_port_enable(sc->sc_gmx_port, 0); 1120 1.1 hikaru 1121 1.1 hikaru /* Mark the interface as down and cancel the watchdog timer. */ 1122 1.27 thorpej CLR(ifp->if_flags, IFF_RUNNING); 1123 1.27 thorpej sc->sc_txbusy = false; 1124 1.1 hikaru ifp->if_timer = 0; 1125 1.1 hikaru } 1126 1.1 hikaru 1127 1.1 hikaru /* ---- misc */ 1128 1.1 hikaru 1129 1.1 hikaru static int 1130 1.19 simonb cnmac_reset(struct cnmac_softc *sc) 1131 1.1 hikaru { 1132 1.19 simonb octgmx_reset_speed(sc->sc_gmx_port); 1133 1.19 simonb octgmx_reset_flowctl(sc->sc_gmx_port); 1134 1.19 simonb octgmx_reset_timing(sc->sc_gmx_port); 1135 1.1 hikaru 1136 1.1 hikaru return 0; 1137 1.1 hikaru } 1138 1.1 hikaru 1139 1.1 hikaru static int 1140 1.19 simonb cnmac_configure(struct cnmac_softc *sc) 1141 1.1 hikaru { 1142 1.19 simonb octgmx_port_enable(sc->sc_gmx_port, 0); 1143 1.1 hikaru 1144 1.19 simonb cnmac_reset(sc); 1145 1.1 hikaru 1146 1.19 simonb cnmac_configure_common(sc); 1147 1.1 hikaru 1148 1.19 simonb octpko_port_config(sc->sc_pko); 1149 1.19 simonb octpko_port_enable(sc->sc_pko, 1); 1150 1.24 simonb octpow_config(sc->sc_pow, sc->sc_powgroup); 1151 1.1 hikaru 1152 1.19 simonb octgmx_tx_stats_rd_clr(sc->sc_gmx_port, 1); 1153 1.19 simonb octgmx_rx_stats_rd_clr(sc->sc_gmx_port, 1); 1154 1.1 hikaru 1155 1.19 simonb octgmx_port_enable(sc->sc_gmx_port, 1); 1156 1.1 hikaru 1157 1.1 hikaru return 0; 1158 1.1 hikaru } 1159 1.1 hikaru 1160 1.1 hikaru static int 1161 1.19 simonb cnmac_configure_common(struct cnmac_softc *sc) 1162 1.1 hikaru { 1163 1.1 hikaru static int once; 1164 1.1 hikaru 1165 1.1 hikaru if (once == 1) 1166 1.1 hikaru return 0; 1167 1.1 hikaru once = 1; 1168 1.1 hikaru 1169 1.19 simonb octipd_config(sc->sc_ipd); 1170 1.19 simonb octpko_config(sc->sc_pko); 1171 1.1 hikaru 1172 1.1 hikaru return 0; 1173 1.1 hikaru } 1174 1.1 hikaru 1175 1.1 hikaru /* ---- receive (input) */ 1176 1.1 hikaru 1177 1.1 hikaru static inline int 1178 1.19 simonb cnmac_recv_mbuf(struct cnmac_softc *sc, uint64_t *work, struct mbuf **rm) 1179 1.1 hikaru { 1180 1.1 hikaru struct mbuf *m; 1181 1.24 simonb vaddr_t addr; 1182 1.24 simonb vaddr_t ext_buf; 1183 1.1 hikaru size_t ext_size; 1184 1.1 hikaru uint64_t word1 = work[1]; 1185 1.1 hikaru uint64_t word2 = work[2]; 1186 1.1 hikaru uint64_t word3 = work[3]; 1187 1.1 hikaru 1188 1.1 hikaru MGETHDR(m, M_NOWAIT, MT_DATA); 1189 1.1 hikaru if (m == NULL) 1190 1.1 hikaru return 1; 1191 1.1 hikaru 1192 1.24 simonb octfpa_buf_put(cnmac_fb_wqe, work); 1193 1.24 simonb 1194 1.24 simonb if (__SHIFTOUT(word2, PIP_WQE_WORD2_IP_BUFS) != 1) 1195 1.24 simonb panic("%s: expected one buffer, got %" PRId64, __func__, 1196 1.24 simonb __SHIFTOUT(word2, PIP_WQE_WORD2_IP_BUFS)); 1197 1.1 hikaru 1198 1.1 hikaru 1199 1.4 matt #ifdef __mips_n32 1200 1.24 simonb KASSERT((word3 & ~MIPS_PHYS_MASK) == 0); 1201 1.24 simonb addr = MIPS_PHYS_TO_KSEG0(word3 & PIP_WQE_WORD3_ADDR); 1202 1.4 matt #else 1203 1.24 simonb addr = MIPS_PHYS_TO_XKPHYS_CACHED(word3 & PIP_WQE_WORD3_ADDR); 1204 1.4 matt #endif 1205 1.1 hikaru 1206 1.24 simonb ext_size = OCTEON_POOL_SIZE_PKT; 1207 1.24 simonb ext_buf = addr & ~(ext_size - 1); 1208 1.24 simonb MEXTADD(m, ext_buf, ext_size, 0, cnmac_buf_ext_free, NULL); 1209 1.1 hikaru 1210 1.24 simonb m->m_data = (void *)addr; 1211 1.1 hikaru m->m_len = m->m_pkthdr.len = (word1 & PIP_WQE_WORD1_LEN) >> 48; 1212 1.3 ozaki m_set_rcvif(m, &sc->sc_ethercom.ec_if); 1213 1.12 msaitoh 1214 1.12 msaitoh /* Not readonly buffer */ 1215 1.1 hikaru m->m_flags |= M_EXT_RW; 1216 1.1 hikaru 1217 1.1 hikaru *rm = m; 1218 1.1 hikaru 1219 1.23 simonb KASSERT(*rm != NULL); 1220 1.1 hikaru 1221 1.1 hikaru return 0; 1222 1.1 hikaru } 1223 1.1 hikaru 1224 1.1 hikaru static inline int 1225 1.24 simonb cnmac_recv_check(struct cnmac_softc *sc, uint64_t word2) 1226 1.1 hikaru { 1227 1.24 simonb static struct timeval rxerr_log_interval = { 0, 2500000 }; 1228 1.24 simonb uint64_t opecode; 1229 1.1 hikaru 1230 1.1 hikaru if (__predict_true(!ISSET(word2, PIP_WQE_WORD2_NOIP_RE))) 1231 1.1 hikaru return 0; 1232 1.1 hikaru 1233 1.24 simonb opecode = word2 & PIP_WQE_WORD2_NOIP_OPECODE; 1234 1.24 simonb if ((sc->sc_ethercom.ec_if.if_flags & IFF_DEBUG) && 1235 1.24 simonb ratecheck(&sc->sc_rxerr_log_last, &rxerr_log_interval)) 1236 1.24 simonb log(LOG_DEBUG, "%s: rx error (%"PRId64")\n", 1237 1.24 simonb device_xname(sc->sc_dev), opecode); 1238 1.24 simonb 1239 1.12 msaitoh /* This error is harmless */ 1240 1.24 simonb if (opecode == PIP_WQE_WORD2_RE_OPCODE_OVRRUN) 1241 1.1 hikaru return 0; 1242 1.1 hikaru 1243 1.1 hikaru return 1; 1244 1.1 hikaru } 1245 1.1 hikaru 1246 1.1 hikaru static inline int 1247 1.19 simonb cnmac_recv(struct cnmac_softc *sc, uint64_t *work) 1248 1.1 hikaru { 1249 1.1 hikaru struct ifnet *ifp; 1250 1.1 hikaru struct mbuf *m; 1251 1.1 hikaru uint64_t word2; 1252 1.1 hikaru 1253 1.23 simonb KASSERT(sc != NULL); 1254 1.23 simonb KASSERT(work != NULL); 1255 1.1 hikaru 1256 1.1 hikaru word2 = work[2]; 1257 1.1 hikaru ifp = &sc->sc_ethercom.ec_if; 1258 1.1 hikaru 1259 1.23 simonb KASSERT(ifp != NULL); 1260 1.1 hikaru 1261 1.24 simonb if (!ISSET(ifp->if_flags, IFF_RUNNING)) 1262 1.24 simonb goto drop; 1263 1.24 simonb 1264 1.19 simonb if (__predict_false(cnmac_recv_check(sc, word2) != 0)) { 1265 1.16 thorpej if_statinc(ifp, if_ierrors); 1266 1.1 hikaru goto drop; 1267 1.1 hikaru } 1268 1.1 hikaru 1269 1.19 simonb if (__predict_false(cnmac_recv_mbuf(sc, work, &m) != 0)) { 1270 1.16 thorpej if_statinc(ifp, if_ierrors); 1271 1.1 hikaru goto drop; 1272 1.1 hikaru } 1273 1.1 hikaru 1274 1.1 hikaru /* work[0] .. work[3] may not be valid any more */ 1275 1.1 hikaru 1276 1.23 simonb KASSERT(m != NULL); 1277 1.1 hikaru 1278 1.19 simonb octipd_offload(word2, m->m_data, &m->m_pkthdr.csum_flags); 1279 1.1 hikaru 1280 1.2 ozaki if_percpuq_enqueue(ifp->if_percpuq, m); 1281 1.1 hikaru 1282 1.1 hikaru return 0; 1283 1.1 hikaru 1284 1.1 hikaru drop: 1285 1.24 simonb cnmac_buf_free_work(sc, work); 1286 1.24 simonb return 1; 1287 1.1 hikaru } 1288 1.1 hikaru 1289 1.24 simonb static int 1290 1.24 simonb cnmac_intr(void *arg) 1291 1.1 hikaru { 1292 1.24 simonb struct cnmac_softc *sc = arg; 1293 1.24 simonb uint64_t *work; 1294 1.24 simonb uint64_t wqmask = __BIT(sc->sc_powgroup); 1295 1.24 simonb uint32_t coreid = 0; /* XXX octeon_get_coreid() */ 1296 1.24 simonb uint32_t port; 1297 1.24 simonb 1298 1.24 simonb _POW_WR8(sc->sc_pow, POW_PP_GRP_MSK_OFFSET(coreid), wqmask); 1299 1.24 simonb 1300 1.24 simonb octpow_tag_sw_wait(); 1301 1.24 simonb octpow_work_request_async(OCTEON_CVMSEG_OFFSET(csm_pow_intr), 1302 1.24 simonb POW_NO_WAIT); 1303 1.1 hikaru 1304 1.24 simonb for (;;) { 1305 1.24 simonb work = (uint64_t *)octpow_work_response_async( 1306 1.24 simonb OCTEON_CVMSEG_OFFSET(csm_pow_intr)); 1307 1.24 simonb if (work == NULL) 1308 1.24 simonb break; 1309 1.1 hikaru 1310 1.24 simonb octpow_tag_sw_wait(); 1311 1.24 simonb octpow_work_request_async(OCTEON_CVMSEG_OFFSET(csm_pow_intr), 1312 1.24 simonb POW_NO_WAIT); 1313 1.24 simonb 1314 1.24 simonb port = __SHIFTOUT(work[1], PIP_WQE_WORD1_IPRT); 1315 1.24 simonb if (port != sc->sc_port) { 1316 1.24 simonb printf("%s: unexpected wqe port %u, should be %u\n", 1317 1.24 simonb device_xname(sc->sc_dev), port, sc->sc_port); 1318 1.24 simonb goto wqe_error; 1319 1.24 simonb } 1320 1.1 hikaru 1321 1.24 simonb (void)cnmac_recv(sc, work); 1322 1.26 simonb 1323 1.26 simonb cnmac_send_queue_check_and_flush(sc); 1324 1.1 hikaru } 1325 1.1 hikaru 1326 1.24 simonb _POW_WR8(sc->sc_pow, POW_WQ_INT_OFFSET, wqmask); 1327 1.1 hikaru 1328 1.24 simonb return 1; 1329 1.1 hikaru 1330 1.24 simonb wqe_error: 1331 1.24 simonb printf("word0: 0x%016" PRIx64 "\n", work[0]); 1332 1.24 simonb printf("word1: 0x%016" PRIx64 "\n", work[1]); 1333 1.24 simonb printf("word2: 0x%016" PRIx64 "\n", work[2]); 1334 1.24 simonb printf("word3: 0x%016" PRIx64 "\n", work[3]); 1335 1.24 simonb panic("wqe_error"); 1336 1.1 hikaru } 1337 1.1 hikaru 1338 1.1 hikaru /* ---- tick */ 1339 1.1 hikaru 1340 1.1 hikaru /* 1341 1.19 simonb * cnmac_tick_free 1342 1.1 hikaru * 1343 1.1 hikaru * => garbage collect send gather buffer / mbuf 1344 1.1 hikaru * => called at softclock 1345 1.1 hikaru */ 1346 1.1 hikaru static void 1347 1.19 simonb cnmac_tick_free(void *arg) 1348 1.1 hikaru { 1349 1.19 simonb struct cnmac_softc *sc = arg; 1350 1.1 hikaru int timo; 1351 1.1 hikaru 1352 1.26 simonb cnmac_send_queue_check_and_flush(sc); 1353 1.1 hikaru 1354 1.25 simonb timo = (sc->sc_ext_callback_cnt > 0) ? 1 : hz; 1355 1.1 hikaru callout_schedule(&sc->sc_tick_free_ch, timo); 1356 1.1 hikaru } 1357 1.1 hikaru 1358 1.1 hikaru /* 1359 1.19 simonb * cnmac_tick_misc 1360 1.1 hikaru * 1361 1.1 hikaru * => collect statistics 1362 1.1 hikaru * => check link status 1363 1.1 hikaru * => called at softclock 1364 1.1 hikaru */ 1365 1.1 hikaru static void 1366 1.19 simonb cnmac_tick_misc(void *arg) 1367 1.1 hikaru { 1368 1.19 simonb struct cnmac_softc *sc = arg; 1369 1.1 hikaru struct ifnet *ifp; 1370 1.1 hikaru int s; 1371 1.1 hikaru 1372 1.1 hikaru s = splnet(); 1373 1.1 hikaru 1374 1.1 hikaru ifp = &sc->sc_ethercom.ec_if; 1375 1.1 hikaru 1376 1.19 simonb octgmx_stats(sc->sc_gmx_port); 1377 1.19 simonb octpip_stats(sc->sc_pip, ifp, sc->sc_port); 1378 1.1 hikaru mii_tick(&sc->sc_mii); 1379 1.1 hikaru 1380 1.1 hikaru splx(s); 1381 1.1 hikaru 1382 1.1 hikaru callout_schedule(&sc->sc_tick_misc_ch, hz); 1383 1.1 hikaru } 1384