1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2008-2013 Solarflare Communications Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 #include <sys/types.h>
  28 #include <sys/ddi.h>
  29 #include <sys/sunddi.h>
  30 #include <sys/gld.h>
  31 #include <sys/stream.h>
  32 #include <sys/strsun.h>
  33 #include <sys/strsubr.h>
  34 #include <sys/dlpi.h>
  35 #include <sys/pattr.h>
  36 #include <sys/ksynch.h>
  37 #include <sys/spl.h>
  38 
  39 #include <inet/nd.h>
  40 #include <inet/mi.h>
  41 
  42 #include "sfxge.h"
  43 
  44 #ifdef _USE_GLD_V2
  45 
  46 void
  47 sfxge_gld_link_update(sfxge_t *sp)
  48 {
  49         sfxge_mac_t *smp = &(sp->s_mac);
  50         int32_t link;
  51 
  52         switch (smp->sm_link_mode) {
  53         case EFX_LINK_UNKNOWN:
  54                 link = GLD_LINKSTATE_UNKNOWN;
  55                 break;
  56         case EFX_LINK_DOWN:
  57                 link = GLD_LINKSTATE_DOWN;
  58                 break;
  59         default:
  60                 link = GLD_LINKSTATE_UP;
  61         }
  62 
  63         gld_linkstate(sp->s_gmip, link);
  64 }
  65 
  66 void
  67 sfxge_gld_mtu_update(sfxge_t *sp)
  68 {
  69 }
  70 
  71 void
  72 sfxge_gld_rx_post(sfxge_t *sp, unsigned int index, mblk_t *mp)
  73 {
  74         mblk_t **mpp;
  75 
  76         _NOTE(ARGUNUSED(index))
  77 
  78         mutex_enter(&(sp->s_rx_lock));
  79         *(sp->s_mpp) = mp;
  80 
  81         mpp = &mp;
  82         while ((mp = *mpp) != NULL)
  83                 mpp = &(mp->b_next);
  84 
  85         sp->s_mpp = mpp;
  86         mutex_exit(&(sp->s_rx_lock));
  87 }
  88 
  89 void
  90 sfxge_gld_rx_push(sfxge_t *sp)
  91 {
  92         mblk_t *mp;
  93 
  94         mutex_enter(&(sp->s_rx_lock));
  95         mp = sp->s_mp;
  96         sp->s_mp = NULL;
  97         sp->s_mpp = &(sp->s_mp);
  98         mutex_exit(&(sp->s_rx_lock));
  99 
 100         while (mp != NULL) {
 101                 mblk_t *next;
 102 
 103                 next = mp->b_next;
 104                 mp->b_next = NULL;
 105 
 106                 /* The stack behaves badly with multi-fragment messages */
 107                 if (mp->b_cont != NULL) {
 108                         uint16_t flags = DB_CKSUMFLAGS(mp);
 109 
 110                         (void) pullupmsg(mp, -1);
 111 
 112                         DB_CKSUMFLAGS(mp) = flags;
 113                 }
 114 
 115                 gld_recv(sp->s_gmip, mp);
 116 
 117                 mp = next;
 118         }
 119 }
 120 
 121 static int
 122 sfxge_gld_get_stats(gld_mac_info_t *gmip, struct gld_stats *gsp)
 123 {
 124         sfxge_t *sp = (sfxge_t *)(gmip->gldm_private);
 125         unsigned int speed;
 126         sfxge_link_duplex_t duplex;
 127         uint64_t val;
 128 
 129         sfxge_mac_stat_get(sp, EFX_MAC_TX_ERRORS, &val);
 130         gsp->glds_errxmt = (uint32_t)val;
 131 
 132         sfxge_mac_stat_get(sp, EFX_MAC_RX_ERRORS, &val);
 133         gsp->glds_errrcv = (uint32_t)val;
 134 
 135         sfxge_mac_stat_get(sp, EFX_MAC_RX_FCS_ERRORS, &val);
 136         gsp->glds_crc = (uint32_t)val;
 137 
 138         sfxge_mac_stat_get(sp, EFX_MAC_RX_DROP_EVENTS, &val);
 139         gsp->glds_norcvbuf = (uint32_t)val;
 140 
 141         sfxge_mac_link_speed_get(sp, &speed);
 142         gsp->glds_speed = (uint64_t)speed * 1000000ull;
 143 
 144         sfxge_mac_link_duplex_get(sp, &duplex);
 145 
 146         switch (duplex) {
 147         case SFXGE_LINK_DUPLEX_UNKNOWN:
 148                 gsp->glds_duplex = GLD_DUPLEX_UNKNOWN;
 149                 break;
 150 
 151         case SFXGE_LINK_DUPLEX_HALF:
 152                 gsp->glds_duplex = GLD_DUPLEX_HALF;
 153                 break;
 154 
 155         case SFXGE_LINK_DUPLEX_FULL:
 156                 gsp->glds_duplex = GLD_DUPLEX_FULL;
 157                 break;
 158 
 159         default:
 160                 ASSERT(B_FALSE);
 161                 break;
 162         }
 163 
 164         return (GLD_SUCCESS);
 165 }
 166 
 167 static int
 168 sfxge_gld_reset(gld_mac_info_t *gmip)
 169 {
 170         /*
 171          * The driver already has hardware resets at appropriate times
 172          * This is only ever called before gld_start()
 173          */
 174         return (GLD_SUCCESS);
 175 }
 176 
 177 static int
 178 sfxge_gld_start(gld_mac_info_t *gmip)
 179 {
 180         sfxge_t *sp = (sfxge_t *)(gmip->gldm_private);
 181         int rc;
 182 
 183         mutex_enter(&(sp->s_rx_lock));
 184         sp->s_mpp = &(sp->s_mp);
 185         mutex_exit(&(sp->s_rx_lock));
 186 
 187         if ((rc = sfxge_start(sp, B_FALSE)) != 0)
 188                 goto fail1;
 189 
 190         return (GLD_SUCCESS);
 191 
 192 fail1:
 193         DTRACE_PROBE1(fail1, int, rc);
 194 
 195         mutex_enter(&(sp->s_rx_lock));
 196         ASSERT3P(sp->s_mp, ==, NULL);
 197         sp->s_mpp = NULL;
 198         mutex_exit(&(sp->s_rx_lock));
 199 
 200         return (GLD_FAILURE);
 201 }
 202 
 203 static int
 204 sfxge_gld_stop(gld_mac_info_t *gmip)
 205 {
 206         sfxge_t *sp = (sfxge_t *)(gmip->gldm_private);
 207 
 208         sfxge_stop(sp);
 209 
 210         mutex_enter(&(sp->s_rx_lock));
 211         ASSERT3P(sp->s_mp, ==, NULL);
 212         sp->s_mpp = NULL;
 213         mutex_exit(&(sp->s_rx_lock));
 214 
 215         return (GLD_SUCCESS);
 216 }
 217 
 218 static int
 219 sfxge_gld_set_promiscuous(gld_mac_info_t *gmip, int flags)
 220 {
 221         sfxge_t *sp = (sfxge_t *)(gmip->gldm_private);
 222         int rc;
 223 
 224         switch (flags) {
 225         case GLD_MAC_PROMISC_NONE:
 226                 if ((rc = sfxge_mac_promisc_set(sp, SFXGE_PROMISC_OFF)) != 0)
 227                         goto fail1;
 228                 break;
 229         case GLD_MAC_PROMISC_MULTI:
 230                 if ((rc = sfxge_mac_promisc_set(sp, SFXGE_PROMISC_ALL_MULTI))
 231                     != 0)
 232                         goto fail2;
 233                 break;
 234         default:
 235                 if ((rc = sfxge_mac_promisc_set(sp, SFXGE_PROMISC_ALL_PHYS))
 236                     != 0)
 237                         goto fail3;
 238                 break;
 239         }
 240 
 241         return (GLD_SUCCESS);
 242 
 243 fail3:
 244         DTRACE_PROBE(fail3);
 245 fail2:
 246         DTRACE_PROBE(fail2);
 247 fail1:
 248         DTRACE_PROBE1(fail1, int, rc);
 249         return (GLD_FAILURE);
 250 }
 251 
 252 static int
 253 sfxge_gld_set_multicast(gld_mac_info_t *gmip, unsigned char *addr, int flag)
 254 {
 255         sfxge_t *sp = (sfxge_t *)(gmip->gldm_private);
 256         int rc;
 257 
 258         switch (flag) {
 259         case GLD_MULTI_ENABLE:
 260                 if ((rc = sfxge_mac_multicst_add(sp, addr)) != 0)
 261                         goto fail1;
 262                 break;
 263         case GLD_MULTI_DISABLE:
 264                 if ((rc = sfxge_mac_multicst_remove(sp, addr)) != 0)
 265                         goto fail2;
 266                 break;
 267         default:
 268                 ASSERT(B_FALSE);
 269                 break;
 270         }
 271 
 272         return (GLD_SUCCESS);
 273 
 274 fail2:
 275         DTRACE_PROBE(fail2);
 276 fail1:
 277         DTRACE_PROBE1(fail1, int, rc);
 278         return (GLD_FAILURE);
 279 }
 280 
 281 static int
 282 sfxge_gld_set_mac_addr(gld_mac_info_t *gmip, unsigned char *addr)
 283 {
 284         sfxge_t *sp = (sfxge_t *)(gmip->gldm_private);
 285         int rc;
 286 
 287         if ((rc = sfxge_mac_unicst_set(sp, addr)) != 0)
 288                 goto fail1;
 289 
 290         return (GLD_SUCCESS);
 291 
 292 fail1:
 293         DTRACE_PROBE1(fail1, int, rc);
 294 
 295         return (GLD_BADARG);
 296 }
 297 
 298 int
 299 sfxge_gld_send(gld_mac_info_t *gmip, mblk_t *mp)
 300 {
 301         sfxge_t *sp = (sfxge_t *)(gmip->gldm_private);
 302 
 303         (void) sfxge_tx_packet_add(sp, mp);
 304 
 305         /*
 306          * This gives no TX backpressure, which can cause unbounded TX DPL
 307          * size. See bug 18984. This feature is implemented for GLDv3
 308          */
 309         return (GLD_SUCCESS);
 310 }
 311 
 312 int
 313 sfxge_gld_ioctl(gld_mac_info_t *gmip, queue_t *wq, mblk_t *mp)
 314 {
 315         sfxge_t *sp = (sfxge_t *)(gmip->gldm_private);
 316         struct iocblk *iocp;
 317 
 318         iocp = (struct iocblk *)mp->b_rptr;
 319 
 320         switch (iocp->ioc_cmd) {
 321         case ND_GET:
 322         case ND_SET:
 323                 if (!nd_getset(wq, sp->s_ndh, mp))
 324                         miocnak(wq, mp, 0, EINVAL);
 325                 else
 326                         qreply(wq, mp);
 327                 break;
 328 
 329         default:
 330                 sfxge_ioctl(sp, wq, mp);
 331                 break;
 332         }
 333 
 334         return (GLD_SUCCESS);
 335 }
 336 
 337 
 338 int
 339 sfxge_gld_register(sfxge_t *sp)
 340 {
 341         gld_mac_info_t *gmip;
 342         unsigned int pri;
 343         int rc;
 344 
 345         mutex_init(&(sp->s_rx_lock), NULL, MUTEX_DRIVER,
 346             DDI_INTR_PRI(sp->s_intr.si_intr_pri));
 347 
 348         if ((rc = sfxge_gld_nd_register(sp)) != 0)
 349                 goto fail1;
 350 
 351         gmip = gld_mac_alloc(sp->s_dip);
 352 
 353         gmip->gldm_private = (caddr_t)sp;
 354 
 355         gmip->gldm_reset = sfxge_gld_reset;
 356         gmip->gldm_start = sfxge_gld_start;
 357         gmip->gldm_stop = sfxge_gld_stop;
 358         gmip->gldm_set_mac_addr = sfxge_gld_set_mac_addr;
 359         gmip->gldm_set_multicast = sfxge_gld_set_multicast;
 360         gmip->gldm_set_promiscuous = sfxge_gld_set_promiscuous;
 361         gmip->gldm_send = sfxge_gld_send;
 362         gmip->gldm_get_stats = sfxge_gld_get_stats;
 363         gmip->gldm_ioctl = sfxge_gld_ioctl;
 364 
 365         gmip->gldm_ident = (char *)sfxge_ident;
 366         gmip->gldm_type = DL_ETHER;
 367         gmip->gldm_minpkt = 0;
 368         gmip->gldm_maxpkt = sp->s_mtu;
 369         gmip->gldm_addrlen = ETHERADDRL;
 370         gmip->gldm_saplen = -2;
 371         gmip->gldm_broadcast_addr = sfxge_brdcst;
 372 
 373         gmip->gldm_vendor_addr = kmem_alloc(ETHERADDRL, KM_SLEEP);
 374 
 375         if ((rc = sfxge_mac_unicst_get(sp, SFXGE_UNICST_BIA,
 376             gmip->gldm_vendor_addr)) != 0)
 377                 goto fail2;
 378 
 379         gmip->gldm_devinfo = sp->s_dip;
 380         gmip->gldm_ppa = ddi_get_instance(sp->s_dip);
 381 
 382         gmip->gldm_cookie = spltoipl(0);
 383 
 384         gmip->gldm_capabilities =
 385             GLD_CAP_LINKSTATE |
 386             GLD_CAP_CKSUM_IPHDR |
 387             GLD_CAP_CKSUM_FULL_V4 |
 388             GLD_CAP_ZEROCOPY;
 389 
 390         if ((rc = gld_register(sp->s_dip, (char *)ddi_driver_name(sp->s_dip),
 391             gmip)) != 0)
 392                 goto fail3;
 393 
 394         sp->s_gmip = gmip;
 395         return (0);
 396 
 397 fail3:
 398         DTRACE_PROBE(fail3);
 399 fail2:
 400         DTRACE_PROBE(fail2);
 401 
 402         kmem_free(gmip->gldm_vendor_addr, ETHERADDRL);
 403         gld_mac_free(gmip);
 404 
 405         sfxge_gld_nd_unregister(sp);
 406 
 407 fail1:
 408         DTRACE_PROBE1(fail1, int, rc);
 409         mutex_destroy(&(sp->s_rx_lock));
 410 
 411         return (rc);
 412 }
 413 
 414 int
 415 sfxge_gld_unregister(sfxge_t *sp)
 416 {
 417         gld_mac_info_t *gmip = sp->s_gmip;
 418         int rc;
 419 
 420         if ((rc = gld_unregister(gmip)) != 0)
 421                 goto fail1;
 422 
 423         sp->s_gmip = NULL;
 424 
 425         kmem_free(gmip->gldm_vendor_addr, ETHERADDRL);
 426         gld_mac_free(gmip);
 427 
 428         sfxge_gld_nd_unregister(sp);
 429 
 430         mutex_destroy(&(sp->s_rx_lock));
 431 
 432         return (0);
 433 
 434 fail1:
 435         DTRACE_PROBE1(fail1, int, rc);
 436 
 437         return (rc);
 438 }
 439 #endif  /* _USE_GLD_V2 */