1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2021 Adrian Chadd <adrian@FreeBSD.org> 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice unmodified, this list of conditions, and the following 11 * disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __FBSDID("$FreeBSD$"); 31 32 #include <sys/param.h> 33 #include <sys/systm.h> 34 #include <sys/bus.h> 35 36 #include <sys/kernel.h> 37 #include <sys/kthread.h> 38 #include <sys/module.h> 39 #include <sys/rman.h> 40 #include <sys/lock.h> 41 #include <sys/malloc.h> 42 #include <sys/mutex.h> 43 #include <sys/gpio.h> 44 #include <sys/mbuf.h> 45 #include <sys/socket.h> 46 #include <sys/sockio.h> 47 #include <sys/smp.h> 48 #include <sys/proc.h> 49 #include <sys/sched.h> 50 #include <sys/queue.h> 51 #include <sys/taskqueue.h> 52 53 #include <net/if.h> 54 #include <net/if_var.h> 55 #include <net/if_vlan_var.h> 56 #include <net/if_media.h> 57 #include <net/ethernet.h> 58 #include <net/if_types.h> 59 60 #include <machine/bus.h> 61 #include <machine/resource.h> 62 #include <machine/atomic.h> 63 64 #include <dev/gpio/gpiobusvar.h> 65 66 #include <dev/fdt/fdt_common.h> 67 #include <dev/ofw/ofw_bus.h> 68 #include <dev/ofw/ofw_bus_subr.h> 69 70 #include <dev/qcom_ess_edma/qcom_ess_edma_var.h> 71 #include <dev/qcom_ess_edma/qcom_ess_edma_reg.h> 72 #include <dev/qcom_ess_edma/qcom_ess_edma_hw.h> 73 #include <dev/qcom_ess_edma/qcom_ess_edma_desc.h> 74 #include <dev/qcom_ess_edma/qcom_ess_edma_rx.h> 75 #include <dev/qcom_ess_edma/qcom_ess_edma_tx.h> 76 #include <dev/qcom_ess_edma/qcom_ess_edma_debug.h> 77 #include <dev/qcom_ess_edma/qcom_ess_edma_gmac.h> 78 79 static int 80 qcom_ess_edma_gmac_mediachange(if_t ifp) 81 { 82 struct qcom_ess_edma_gmac *gmac = if_getsoftc(ifp); 83 struct qcom_ess_edma_softc *sc = gmac->sc; 84 struct ifmedia *ifm = &gmac->ifm; 85 struct ifmedia_entry *ife = ifm->ifm_cur; 86 87 if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) 88 return (EINVAL); 89 90 if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO) { 91 device_printf(sc->sc_dev, 92 "AUTO is not supported this MAC"); 93 return (EINVAL); 94 } 95 96 /* 97 * Ignore everything 98 */ 99 return (0); 100 } 101 102 static void 103 qcom_ess_edma_gmac_mediastatus(if_t ifp, struct ifmediareq *ifmr) 104 { 105 106 ifmr->ifm_status = IFM_AVALID | IFM_ACTIVE; 107 ifmr->ifm_active = IFM_ETHER | IFM_1000_T | IFM_FDX; 108 } 109 110 static int 111 qcom_ess_edma_gmac_ioctl(if_t ifp, u_long command, caddr_t data) 112 { 113 struct qcom_ess_edma_gmac *gmac = if_getsoftc(ifp); 114 struct qcom_ess_edma_softc *sc = gmac->sc; 115 struct ifreq *ifr = (struct ifreq *) data; 116 int error, mask; 117 118 switch (command) { 119 case SIOCSIFFLAGS: 120 if ((if_getflags(ifp) & IFF_UP) != 0) { 121 /* up */ 122 QCOM_ESS_EDMA_DPRINTF(sc, QCOM_ESS_EDMA_DBG_STATE, 123 "%s: gmac%d: IFF_UP\n", 124 __func__, 125 gmac->id); 126 if_setdrvflagbits(ifp, IFF_DRV_RUNNING, 127 IFF_DRV_OACTIVE); 128 if_link_state_change(ifp, LINK_STATE_UP); 129 130 } else if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) != 0) { 131 /* down */ 132 if_setdrvflagbits(ifp, 0, IFF_DRV_RUNNING); 133 QCOM_ESS_EDMA_DPRINTF(sc, QCOM_ESS_EDMA_DBG_STATE, 134 "%s: gmac%d: IF down\n", 135 __func__, 136 gmac->id); 137 if_link_state_change(ifp, LINK_STATE_DOWN); 138 } 139 error = 0; 140 break; 141 case SIOCGIFMEDIA: 142 case SIOCSIFMEDIA: 143 error = ifmedia_ioctl(ifp, ifr, &gmac->ifm, command); 144 break; 145 case SIOCSIFCAP: 146 mask = ifr->ifr_reqcap ^ if_getcapenable(ifp); 147 error = 0; 148 149 if ((mask & IFCAP_RXCSUM) != 0 && 150 (if_getcapabilities(ifp) & IFCAP_RXCSUM) != 0) 151 if_togglecapenable(ifp, IFCAP_RXCSUM); 152 153 if ((mask & IFCAP_VLAN_HWTAGGING) != 0 && 154 (if_getcapabilities(ifp) & IFCAP_VLAN_HWTAGGING) != 0) 155 if_togglecapenable(ifp, IFCAP_VLAN_HWTAGGING); 156 157 VLAN_CAPABILITIES(ifp); 158 break; 159 default: 160 error = ether_ioctl(ifp, command, data); 161 break; 162 } 163 164 return (error); 165 } 166 167 static void 168 qcom_ess_edma_gmac_init(void *arg) 169 { 170 struct qcom_ess_edma_gmac *gmac = arg; 171 struct qcom_ess_edma_softc *sc = gmac->sc; 172 173 QCOM_ESS_EDMA_DPRINTF(sc, QCOM_ESS_EDMA_DBG_STATE, 174 "%s: gmac%d: called\n", 175 __func__, 176 gmac->id); 177 178 if_setdrvflagbits(gmac->ifp, IFF_DRV_RUNNING, IFF_DRV_OACTIVE); 179 if_link_state_change(gmac->ifp, LINK_STATE_UP); 180 } 181 182 static int 183 qcom_ess_edma_gmac_transmit(if_t ifp, struct mbuf *m) 184 { 185 struct qcom_ess_edma_gmac *gmac = if_getsoftc(ifp); 186 struct qcom_ess_edma_softc *sc = gmac->sc; 187 struct qcom_ess_edma_tx_state *txs; 188 int ret; 189 int q; 190 191 /* Make sure our CPU doesn't change whilst we're running */ 192 sched_pin(); 193 194 /* 195 * Map flowid / curcpu to a given transmit queue. 196 * 197 * Since we're running on a platform with either two 198 * or four CPUs, we want to distribute the load to a set 199 * of TX queues that won't clash with any other CPU TX queue 200 * use. 201 */ 202 if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE) { 203 /* Map flowid to a queue */ 204 q = m->m_pkthdr.flowid % sc->sc_config.num_tx_queue_per_cpu; 205 206 /* Now, map the queue to a set of unique queues per CPU */ 207 q = q << (mp_ncpus * curcpu); 208 209 /* And ensure we're not overflowing */ 210 q = q % QCOM_ESS_EDMA_NUM_TX_RINGS; 211 } else { 212 /* 213 * Use the first TXQ in each CPU group, so we don't 214 * hit lock contention with traffic that has flowids. 215 */ 216 q = (mp_ncpus * curcpu) % QCOM_ESS_EDMA_NUM_TX_RINGS; 217 } 218 219 /* Attempt to enqueue in the buf_ring. */ 220 /* 221 * XXX TODO: maybe move this into *tx.c so gmac.c doesn't 222 * need to reach into the tx_state stuff? 223 */ 224 txs = &sc->sc_tx_state[q]; 225 226 /* XXX TODO: add an mbuf tag instead? for the transmit gmac/ifp ? */ 227 m->m_pkthdr.rcvif = ifp; 228 229 ret = buf_ring_enqueue(txs->br, m); 230 231 if (ret == 0) { 232 if (atomic_cmpset_int(&txs->enqueue_is_running, 0, 1) == 1) { 233 taskqueue_enqueue(txs->completion_tq, &txs->xmit_task); 234 } 235 } 236 237 sched_unpin(); 238 239 /* Don't consume mbuf; if_transmit caller will if needed */ 240 return (ret); 241 } 242 243 static void 244 qcom_ess_edma_gmac_qflush(if_t ifp) 245 { 246 struct qcom_ess_edma_gmac *gmac = if_getsoftc(ifp); 247 struct qcom_ess_edma_softc *sc = gmac->sc; 248 249 /* XXX TODO */ 250 device_printf(sc->sc_dev, "%s: gmac%d: called\n", 251 __func__, 252 gmac->id); 253 254 /* 255 * Flushing the ifnet would, sigh, require walking each buf_ring 256 * and then removing /only/ the entries matching that ifnet. 257 * Which is a complete pain to do right now. 258 */ 259 } 260 261 int 262 qcom_ess_edma_gmac_parse(struct qcom_ess_edma_softc *sc, int gmac_id) 263 { 264 struct qcom_ess_edma_gmac *gmac; 265 char gmac_name[10]; 266 uint32_t vlan_tag[2]; 267 phandle_t p; 268 int len; 269 270 sprintf(gmac_name, "gmac%d", gmac_id); 271 272 gmac = &sc->sc_gmac[gmac_id]; 273 274 /* Find our sub-device */ 275 p = ofw_bus_find_child(ofw_bus_get_node(sc->sc_dev), gmac_name); 276 if (p <= 0) { 277 device_printf(sc->sc_dev, 278 "%s: couldn't find %s\n", __func__, 279 gmac_name); 280 return (ENOENT); 281 } 282 283 /* local-mac-address */ 284 len = OF_getprop(p, "local-mac-address", (void *) &gmac->eaddr, 285 sizeof(struct ether_addr)); 286 if (len != sizeof(struct ether_addr)) { 287 device_printf(sc->sc_dev, 288 "gmac%d: Couldn't parse local-mac-address\n", 289 gmac_id); 290 memset(&gmac->eaddr, 0, sizeof(gmac->eaddr)); 291 } 292 293 /* vlan-tag - <id portmask> tuple */ 294 len = OF_getproplen(p, "vlan_tag"); 295 if (len != sizeof(vlan_tag)) { 296 device_printf(sc->sc_dev, 297 "gmac%d: no vlan_tag field or invalid size/values\n", 298 gmac_id); 299 return (EINVAL); 300 } 301 len = OF_getencprop(p, "vlan_tag", (void *) &vlan_tag, 302 sizeof(vlan_tag)); 303 if (len != sizeof(vlan_tag)) { 304 device_printf(sc->sc_dev, 305 "gmac%d: couldn't parse vlan_tag field\n", gmac_id); 306 return (EINVAL); 307 } 308 309 /* 310 * Setup the given gmac entry. 311 */ 312 gmac->sc = sc; 313 gmac->id = gmac_id; 314 gmac->enabled = true; 315 gmac->vlan_id = vlan_tag[0]; 316 gmac->port_mask = vlan_tag[1]; 317 318 device_printf(sc->sc_dev, 319 "gmac%d: MAC=%6D, vlan id=%d, port_mask=0x%04x\n", 320 gmac_id, 321 &gmac->eaddr, ":", 322 gmac->vlan_id, 323 gmac->port_mask); 324 325 return (0); 326 } 327 328 int 329 qcom_ess_edma_gmac_create_ifnet(struct qcom_ess_edma_softc *sc, int gmac_id) 330 { 331 struct qcom_ess_edma_gmac *gmac; 332 char gmac_name[10]; 333 334 sprintf(gmac_name, "gmac%d", gmac_id); 335 336 gmac = &sc->sc_gmac[gmac_id]; 337 338 /* Skip non-setup gmacs */ 339 if (gmac->enabled == false) 340 return (0); 341 342 gmac->ifp = if_alloc(IFT_ETHER); 343 if (gmac->ifp == NULL) { 344 device_printf(sc->sc_dev, "gmac%d: couldn't allocate ifnet\n", 345 gmac_id); 346 return (ENOSPC); 347 } 348 349 if_setsoftc(gmac->ifp, gmac); 350 351 if_initname(gmac->ifp, "gmac", gmac_id); 352 353 if (ETHER_IS_ZERO(gmac->eaddr.octet)) { 354 device_printf(sc->sc_dev, "gmac%d: generating random MAC\n", 355 gmac_id); 356 ether_gen_addr(gmac->ifp, (void *) &gmac->eaddr.octet); 357 } 358 359 if_setflags(gmac->ifp, IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST); 360 361 if_setioctlfn(gmac->ifp, qcom_ess_edma_gmac_ioctl); 362 if_setinitfn(gmac->ifp, qcom_ess_edma_gmac_init); 363 if_settransmitfn(gmac->ifp, qcom_ess_edma_gmac_transmit); 364 if_setqflushfn(gmac->ifp, qcom_ess_edma_gmac_qflush); 365 366 if_setcapabilitiesbit(gmac->ifp, IFCAP_VLAN_MTU | 367 IFCAP_VLAN_HWTAGGING, 0); 368 369 if_setcapabilitiesbit(gmac->ifp, IFCAP_RXCSUM, 0); 370 371 /* CSUM_TCP | CSUM_UDP for TX checksum offload */ 372 if_clearhwassist(gmac->ifp); 373 374 /* Configure a hard-coded media */ 375 ifmedia_init(&gmac->ifm, 0, qcom_ess_edma_gmac_mediachange, 376 qcom_ess_edma_gmac_mediastatus); 377 ifmedia_add(&gmac->ifm, IFM_ETHER | IFM_1000_T | IFM_FDX, 0, NULL); 378 ifmedia_set(&gmac->ifm, IFM_ETHER | IFM_1000_T | IFM_FDX); 379 380 ether_ifattach(gmac->ifp, (char *) &gmac->eaddr); 381 382 if_setcapenable(gmac->ifp, if_getcapabilities(gmac->ifp)); 383 384 return (0); 385 } 386 387 /* 388 * Setup the port mapping for the given GMAC. 389 * 390 * This populates sc->sc_gmac_port_map[] to point the given port 391 * entry to this gmac index. The receive path code can then use 392 * this to figure out which gmac ifp to push a receive frame into. 393 */ 394 int 395 qcom_ess_edma_gmac_setup_port_mapping(struct qcom_ess_edma_softc *sc, 396 int gmac_id) 397 { 398 struct qcom_ess_edma_gmac *gmac; 399 int i; 400 401 gmac = &sc->sc_gmac[gmac_id]; 402 403 /* Skip non-setup gmacs */ 404 if (gmac->enabled == false) 405 return (0); 406 407 for (i = 0; i < QCOM_ESS_EDMA_MAX_NUM_PORTS; i++) { 408 if ((gmac->port_mask & (1U << i)) == 0) 409 continue; 410 if (sc->sc_gmac_port_map[i] != -1) { 411 device_printf(sc->sc_dev, 412 "DUPLICATE GMAC port map (port %d)\n", 413 i); 414 return (ENXIO); 415 } 416 417 sc->sc_gmac_port_map[i] = gmac_id; 418 419 if (bootverbose) 420 device_printf(sc->sc_dev, 421 "ESS port %d maps to gmac%d\n", 422 i, gmac_id); 423 } 424 425 return (0); 426 } 427 428 /* 429 * Receive frames to into the network stack. 430 * 431 * This takes a list of mbufs in the mbufq and receives them 432 * up into the appopriate ifnet context. It takes care of 433 * the network epoch as well. 434 * 435 * This must be called with no locks held. 436 */ 437 int 438 qcom_ess_edma_gmac_receive_frames(struct qcom_ess_edma_softc *sc, 439 int rx_queue, struct mbufq *mq) 440 { 441 struct qcom_ess_edma_desc_ring *ring; 442 struct epoch_tracker et; 443 struct mbuf *m; 444 if_t ifp; 445 446 ring = &sc->sc_rx_ring[rx_queue]; 447 448 NET_EPOCH_ENTER(et); 449 while ((m = mbufq_dequeue(mq)) != NULL) { 450 if (m->m_pkthdr.rcvif == NULL) { 451 ring->stats.num_rx_no_gmac++; 452 m_freem(m); 453 } else { 454 ring->stats.num_rx_ok++; 455 ifp = m->m_pkthdr.rcvif; 456 if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); 457 if_input(ifp, m); 458 } 459 } 460 NET_EPOCH_EXIT(et); 461 return (0); 462 } 463