1 /*
   2  * Copyright (c) 2008-2015 Solarflare Communications Inc.
   3  * All rights reserved.
   4  *
   5  * Redistribution and use in source and binary forms, with or without
   6  * modification, are permitted provided that the following conditions are met:
   7  *
   8  * 1. Redistributions of source code must retain the above copyright notice,
   9  *    this list of conditions and the following disclaimer.
  10  * 2. Redistributions in binary form must reproduce the above copyright notice,
  11  *    this list of conditions and the following disclaimer in the documentation
  12  *    and/or other materials provided with the distribution.
  13  *
  14  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  15  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  16  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  17  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
  21  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  22  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  23  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
  24  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25  *
  26  * The views and conclusions contained in the software and documentation are
  27  * those of the authors and should not be interpreted as representing official
  28  * policies, either expressed or implied, of the FreeBSD Project.
  29  */
  30 
  31 #include <sys/types.h>
  32 #include <sys/sysmacros.h>
  33 #include <sys/ddi.h>
  34 #include <sys/sunddi.h>
  35 #include <sys/cyclic.h>
  36 
  37 #include "sfxge.h"
  38 #include "efx.h"
  39 
  40 /*
  41  * All efx_phy_*() must be after efx_port_init()
  42  *
  43  * LOCKING STRATEGY: Aquire sm_lock and test sm_state==SFXGE_MAC_STARTED
  44  * to serialise against sfxge_restart()
  45  *
  46  * Note that there is no seperate PHY lock
  47  * Everything is driven from MAC code and the MAC lock is used
  48  */
  49 
  50 /* PHY DMA attributes */
  51 static ddi_device_acc_attr_t sfxge_phy_devacc = {
  52 
  53         DDI_DEVICE_ATTR_V0,     /* devacc_attr_version */
  54         DDI_NEVERSWAP_ACC,      /* devacc_attr_endian_flags */
  55         DDI_STRICTORDER_ACC     /* devacc_attr_dataorder */
  56 };
  57 
  58 static ddi_dma_attr_t sfxge_phy_dma_attr = {
  59         DMA_ATTR_V0,            /* dma_attr_version     */
  60         0,                      /* dma_attr_addr_lo     */
  61         0xffffffffffffffffull,  /* dma_attr_addr_hi     */
  62         0xffffffffffffffffull,  /* dma_attr_count_max   */
  63         0x1000,                 /* dma_attr_align       */
  64         0xffffffff,             /* dma_attr_burstsizes  */
  65         1,                      /* dma_attr_minxfer     */
  66         0xffffffffffffffffull,  /* dma_attr_maxxfer     */
  67         0xffffffffffffffffull,  /* dma_attr_seg         */
  68         1,                      /* dma_attr_sgllen      */
  69         1,                      /* dma_attr_granular    */
  70         0                       /* dma_attr_flags       */
  71 };
  72 
  73 
  74 static int
  75 sfxge_phy_kstat_update(kstat_t *ksp, int rw)
  76 {
  77         sfxge_t *sp = ksp->ks_private;
  78         sfxge_mac_t *smp = &(sp->s_mac);
  79         sfxge_phy_t *spp = &(smp->sm_phy);
  80         efx_nic_t *enp = sp->s_enp;
  81         kstat_named_t *knp;
  82         const efx_nic_cfg_t *encp;
  83         int rc, sn;
  84 
  85         if (rw != KSTAT_READ) {
  86                 rc = EACCES;
  87                 goto fail1;
  88         }
  89 
  90         ASSERT(mutex_owned(&(smp->sm_lock)));
  91 
  92         if (smp->sm_state != SFXGE_MAC_STARTED)
  93                 goto done;
  94 
  95         /* Synchronize the DMA memory for reading */
  96         (void) ddi_dma_sync(spp->sp_mem.esm_dma_handle,
  97             0, EFX_PHY_STATS_SIZE, DDI_DMA_SYNC_FORKERNEL);
  98 
  99         if ((rc = efx_phy_stats_update(enp, &spp->sp_mem, spp->sp_statbuf))
 100             != 0)
 101                 goto fail2;
 102 
 103         knp = spp->sp_stat;
 104         for (sn = 0; sn < EFX_PHY_NSTATS; sn++) {
 105                 knp->value.ui64 = spp->sp_statbuf[sn];
 106                 knp++;
 107         }
 108 
 109         encp = efx_nic_cfg_get(enp);
 110         knp->value.ui64 = encp->enc_port;
 111 
 112 done:
 113         return (0);
 114 
 115 fail2:
 116         DTRACE_PROBE(fail2);
 117 fail1:
 118         DTRACE_PROBE1(fail1, int, rc);
 119 
 120         return (rc);
 121 }
 122 
 123 int
 124 sfxge_phy_kstat_init(sfxge_t *sp)
 125 {
 126         dev_info_t *dip = sp->s_dip;
 127         sfxge_phy_t *spp = &(sp->s_mac.sm_phy);
 128         efx_nic_t *enp = sp->s_enp;
 129         kstat_t *ksp;
 130         kstat_named_t *knp;
 131         const efx_nic_cfg_t *encp;
 132         unsigned int id;
 133         char name[MAXNAMELEN];
 134         int rc;
 135 
 136         if ((spp->sp_statbuf = kmem_zalloc(sizeof (uint32_t) * EFX_PHY_NSTATS,
 137             KM_NOSLEEP)) == NULL) {
 138                 rc = ENOMEM;
 139                 goto fail1;
 140         }
 141 
 142         encp = efx_nic_cfg_get(enp);
 143 
 144         (void) snprintf(name, MAXNAMELEN - 1, "%s_%s", ddi_driver_name(dip),
 145             encp->enc_phy_name);
 146 
 147         /* Create the set */
 148         if ((ksp = kstat_create((char *)ddi_driver_name(dip),
 149             ddi_get_instance(dip), name, "phy", KSTAT_TYPE_NAMED,
 150             EFX_PHY_NSTATS + 1, 0)) == NULL) {
 151                 rc = ENOMEM;
 152                 goto fail2;
 153         }
 154 
 155         spp->sp_ksp = ksp;
 156 
 157         ksp->ks_update = sfxge_phy_kstat_update;
 158         ksp->ks_private = sp;
 159         ksp->ks_lock = &(sp->s_mac.sm_lock);
 160 
 161         /* Initialise the named stats */
 162         spp->sp_stat = knp = ksp->ks_data;
 163         for (id = 0; id < EFX_PHY_NSTATS; id++) {
 164                 kstat_named_init(knp, (char *)efx_phy_stat_name(enp, id),
 165                     KSTAT_DATA_UINT64);
 166                 knp++;
 167         }
 168 
 169         kstat_named_init(knp, "port", KSTAT_DATA_UINT64);
 170         kstat_install(ksp);
 171 
 172         return (0);
 173 
 174 fail2:
 175         DTRACE_PROBE(fail2)
 176         kmem_free(spp->sp_statbuf, sizeof (uint32_t) * EFX_PHY_NSTATS);
 177 
 178 fail1:
 179         DTRACE_PROBE1(fail1, int, rc);
 180 
 181         return (rc);
 182 }
 183 
 184 void
 185 sfxge_phy_kstat_fini(sfxge_t *sp)
 186 {
 187         sfxge_phy_t *spp = &(sp->s_mac.sm_phy);
 188 
 189         /* Destroy the set */
 190         kstat_delete(spp->sp_ksp);
 191         spp->sp_ksp = NULL;
 192         spp->sp_stat = NULL;
 193 
 194         kmem_free(spp->sp_statbuf, sizeof (uint32_t) * EFX_PHY_NSTATS);
 195 }
 196 
 197 
 198 int
 199 sfxge_phy_init(sfxge_t *sp)
 200 {
 201         sfxge_phy_t *spp = &(sp->s_mac.sm_phy);
 202         efsys_mem_t *esmp = &(spp->sp_mem);
 203         sfxge_dma_buffer_attr_t dma_attr;
 204         int rc;
 205 
 206         dma_attr.sdba_dip        = sp->s_dip;
 207         dma_attr.sdba_dattrp     = &sfxge_phy_dma_attr;
 208         dma_attr.sdba_callback   = DDI_DMA_SLEEP;
 209         dma_attr.sdba_length     = EFX_PHY_STATS_SIZE;
 210         dma_attr.sdba_memflags   = DDI_DMA_CONSISTENT;
 211         dma_attr.sdba_devaccp    = &sfxge_phy_devacc;
 212         dma_attr.sdba_bindflags  = DDI_DMA_READ | DDI_DMA_CONSISTENT;
 213         dma_attr.sdba_maxcookies = 1;
 214         dma_attr.sdba_zeroinit   = B_TRUE;
 215 
 216         if ((rc = sfxge_dma_buffer_create(esmp, &dma_attr)) != 0)
 217                 goto fail1;
 218 
 219         return (0);
 220 
 221 fail1:
 222         DTRACE_PROBE1(fail1, int, rc);
 223         SFXGE_OBJ_CHECK(spp, sfxge_phy_t);
 224 
 225         return (rc);
 226 }
 227 
 228 uint8_t
 229 sfxge_phy_lp_cap_test(sfxge_t *sp, uint32_t field)
 230 {
 231         sfxge_mac_t *smp = &(sp->s_mac);
 232         uint32_t cap = 0;
 233 
 234         mutex_enter(&(smp->sm_lock));
 235 
 236         if (smp->sm_state != SFXGE_MAC_STARTED)
 237                 goto done;
 238 
 239         efx_phy_lp_cap_get(sp->s_enp, &cap);
 240 
 241 done:
 242         mutex_exit(&(smp->sm_lock));
 243 
 244         return (cap & (1 << field));
 245 }
 246 
 247 /*
 248  * Set up the advertised capabilities that may have been asked for
 249  * when the mac was not in the state SFXGE_MAC_STARTED.
 250  * Must be called after efx_port_init().
 251  */
 252 int
 253 sfxge_phy_cap_apply(sfxge_t *sp, boolean_t use_default)
 254 {
 255         sfxge_mac_t *smp = &(sp->s_mac);
 256         efx_nic_t *enp;
 257         uint32_t adv_cap;
 258         int rc;
 259         int err;
 260 
 261         ASSERT(mutex_owned(&(smp->sm_lock)));
 262 
 263         enp = sp->s_enp;
 264 
 265         if (use_default)
 266                 efx_phy_adv_cap_get(enp, EFX_PHY_CAP_DEFAULT, &adv_cap);
 267         else
 268                 efx_phy_adv_cap_get(enp, EFX_PHY_CAP_CURRENT, &adv_cap);
 269 
 270         adv_cap |= smp->sm_phy_cap_to_set;
 271         smp->sm_phy_cap_to_set = 0;
 272         adv_cap &= ~(smp->sm_phy_cap_to_unset);
 273         smp->sm_phy_cap_to_unset = 0;
 274         if ((err = efx_phy_adv_cap_set(enp, adv_cap)) != 0) {
 275                 if (err == EINVAL) {
 276                         /*
 277                          * The configuation wasn't accepted, so set to
 278                          * defaults.
 279                          */
 280                         uint32_t requested = adv_cap;
 281                         uint32_t supported;
 282                         efx_phy_adv_cap_get(enp, EFX_PHY_CAP_PERM, &supported);
 283                         efx_phy_adv_cap_get(enp, EFX_PHY_CAP_DEFAULT, &adv_cap);
 284                         if ((rc = efx_phy_adv_cap_set(enp, adv_cap)) != 0)
 285                                 goto fail1;
 286                         dev_err(sp->s_dip, CE_WARN, SFXGE_CMN_ERR
 287                             "Setting of advertised link capabilities failed. "
 288                             "Using default settings. "
 289                             "(Requested 0x%x Given 0x%x Supported 0x%x)",
 290                             requested,
 291                             adv_cap,
 292                             supported);
 293                 } else {
 294                         rc = err;
 295                         goto fail2;
 296                 }
 297         }
 298 
 299         return (0);
 300 
 301 fail2:
 302         DTRACE_PROBE(fail2);
 303 
 304 fail1:
 305         DTRACE_PROBE1(fail1, int, rc);
 306 
 307         return (rc);
 308 }
 309 
 310 uint8_t
 311 sfxge_phy_cap_test(sfxge_t *sp, uint32_t flag, uint32_t field,
 312         boolean_t *mutablep)
 313 {
 314         sfxge_mac_t *smp = &(sp->s_mac);
 315         efx_nic_t *enp;
 316         uint32_t cap = 0;
 317         uint32_t perm = 0;
 318 
 319         mutex_enter(&(smp->sm_lock));
 320         enp = sp->s_enp;
 321 
 322         if (smp->sm_state != SFXGE_MAC_STARTED)
 323                 goto done;
 324 
 325         efx_phy_adv_cap_get(enp, flag, &cap);
 326         efx_phy_adv_cap_get(enp, EFX_PHY_CAP_PERM, &perm);
 327 
 328 done:
 329         mutex_exit(&(smp->sm_lock));
 330 
 331         if (mutablep)
 332                 *mutablep = (perm & (1 << field)) ? B_TRUE : B_FALSE;
 333 
 334         return ((cap & (1 << field)) ? 1 : 0);
 335 }
 336 
 337 
 338 int
 339 sfxge_phy_cap_set(sfxge_t *sp, uint32_t field, int set)
 340 {
 341         sfxge_mac_t *smp = &(sp->s_mac);
 342         efx_nic_t *enp = sp->s_enp;
 343         uint32_t cap;
 344         int rc = 0;
 345 
 346         mutex_enter(&(smp->sm_lock));
 347 
 348         if (smp->sm_state != SFXGE_MAC_STARTED) {
 349                 /* Store the request for when the mac is started */
 350                 if (set)
 351                         smp->sm_phy_cap_to_set |= (1 << field);
 352                 else
 353                         smp->sm_phy_cap_to_unset |= (1 << field);
 354                 goto done;
 355         }
 356 
 357         efx_phy_adv_cap_get(enp, EFX_PHY_CAP_CURRENT, &cap);
 358 
 359         if (set)
 360                 cap |= (1 << field);
 361         else
 362                 cap &= ~(1 << field);
 363 
 364         rc = efx_phy_adv_cap_set(enp, cap);
 365 done:
 366         mutex_exit(&(smp->sm_lock));
 367 
 368         return (rc);
 369 }
 370 
 371 
 372 void
 373 sfxge_phy_fini(sfxge_t *sp)
 374 {
 375         sfxge_phy_t *spp = &(sp->s_mac.sm_phy);
 376         efsys_mem_t *esmp = &(spp->sp_mem);
 377 
 378         sfxge_dma_buffer_destroy(esmp);
 379 }