1 /*
   2  * Copyright (c) 2008-2016 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 
  36 #include "sfxge.h"
  37 #include "efx.h"
  38 
  39 /*
  40  * All efx_phy_*() must be after efx_port_init()
  41  *
  42  * LOCKING STRATEGY: Aquire sm_lock and test sm_state==SFXGE_MAC_STARTED
  43  * to serialise against sfxge_restart()
  44  *
  45  * Note that there is no seperate PHY lock
  46  * Everything is driven from MAC code and the MAC lock is used
  47  */
  48 
  49 /* PHY DMA attributes */
  50 static ddi_device_acc_attr_t sfxge_phy_devacc = {
  51 
  52         DDI_DEVICE_ATTR_V0,     /* devacc_attr_version */
  53         DDI_NEVERSWAP_ACC,      /* devacc_attr_endian_flags */
  54         DDI_STRICTORDER_ACC     /* devacc_attr_dataorder */
  55 };
  56 
  57 static ddi_dma_attr_t sfxge_phy_dma_attr = {
  58         DMA_ATTR_V0,            /* dma_attr_version     */
  59         0,                      /* dma_attr_addr_lo     */
  60         0xffffffffffffffffull,  /* dma_attr_addr_hi     */
  61         0xffffffffffffffffull,  /* dma_attr_count_max   */
  62         0x1000,                 /* dma_attr_align       */
  63         0xffffffff,             /* dma_attr_burstsizes  */
  64         1,                      /* dma_attr_minxfer     */
  65         0xffffffffffffffffull,  /* dma_attr_maxxfer     */
  66         0xffffffffffffffffull,  /* dma_attr_seg         */
  67         1,                      /* dma_attr_sgllen      */
  68         1,                      /* dma_attr_granular    */
  69         0                       /* dma_attr_flags       */
  70 };
  71 
  72 
  73 static int
  74 sfxge_phy_kstat_update(kstat_t *ksp, int rw)
  75 {
  76         sfxge_t *sp = ksp->ks_private;
  77         sfxge_mac_t *smp = &(sp->s_mac);
  78         sfxge_phy_t *spp = &(smp->sm_phy);
  79         efx_nic_t *enp = sp->s_enp;
  80         kstat_named_t *knp;
  81         const efx_nic_cfg_t *encp;
  82         int rc, sn;
  83 
  84         if (rw != KSTAT_READ) {
  85                 rc = EACCES;
  86                 goto fail1;
  87         }
  88 
  89         ASSERT(mutex_owned(&(smp->sm_lock)));
  90 
  91         if (smp->sm_state != SFXGE_MAC_STARTED)
  92                 goto done;
  93 
  94         /* Synchronize the DMA memory for reading */
  95         (void) ddi_dma_sync(spp->sp_mem.esm_dma_handle,
  96             0, EFX_PHY_STATS_SIZE, DDI_DMA_SYNC_FORKERNEL);
  97 
  98         if ((rc = efx_phy_stats_update(enp, &spp->sp_mem, spp->sp_statbuf))
  99             != 0)
 100                 goto fail2;
 101 
 102         knp = spp->sp_stat;
 103         for (sn = 0; sn < EFX_PHY_NSTATS; sn++) {
 104                 knp->value.ui64 = spp->sp_statbuf[sn];
 105                 knp++;
 106         }
 107 
 108         encp = efx_nic_cfg_get(enp);
 109         knp->value.ui64 = encp->enc_port;
 110 
 111 done:
 112         return (0);
 113 
 114 fail2:
 115         DTRACE_PROBE(fail2);
 116 fail1:
 117         DTRACE_PROBE1(fail1, int, rc);
 118 
 119         return (rc);
 120 }
 121 
 122 int
 123 sfxge_phy_kstat_init(sfxge_t *sp)
 124 {
 125         dev_info_t *dip = sp->s_dip;
 126         sfxge_phy_t *spp = &(sp->s_mac.sm_phy);
 127         efx_nic_t *enp = sp->s_enp;
 128         kstat_t *ksp;
 129         kstat_named_t *knp;
 130         const efx_nic_cfg_t *encp;
 131         unsigned int id;
 132         char name[MAXNAMELEN];
 133         int rc;
 134 
 135         if ((spp->sp_statbuf = kmem_zalloc(sizeof (uint32_t) * EFX_PHY_NSTATS,
 136             KM_NOSLEEP)) == NULL) {
 137                 rc = ENOMEM;
 138                 goto fail1;
 139         }
 140 
 141         encp = efx_nic_cfg_get(enp);
 142 
 143         (void) snprintf(name, MAXNAMELEN - 1, "%s_%s", ddi_driver_name(dip),
 144             encp->enc_phy_name);
 145 
 146         /* Create the set */
 147         if ((ksp = kstat_create((char *)ddi_driver_name(dip),
 148             ddi_get_instance(dip), name, "phy", KSTAT_TYPE_NAMED,
 149             EFX_PHY_NSTATS + 1, 0)) == NULL) {
 150                 rc = ENOMEM;
 151                 goto fail2;
 152         }
 153 
 154         spp->sp_ksp = ksp;
 155 
 156         ksp->ks_update = sfxge_phy_kstat_update;
 157         ksp->ks_private = sp;
 158         ksp->ks_lock = &(sp->s_mac.sm_lock);
 159 
 160         /* Initialise the named stats */
 161         spp->sp_stat = knp = ksp->ks_data;
 162         for (id = 0; id < EFX_PHY_NSTATS; id++) {
 163                 kstat_named_init(knp, (char *)efx_phy_stat_name(enp, id),
 164                     KSTAT_DATA_UINT64);
 165                 knp++;
 166         }
 167 
 168         kstat_named_init(knp, "port", KSTAT_DATA_UINT64);
 169         kstat_install(ksp);
 170 
 171         return (0);
 172 
 173 fail2:
 174         DTRACE_PROBE(fail2)
 175         kmem_free(spp->sp_statbuf, sizeof (uint32_t) * EFX_PHY_NSTATS);
 176 
 177 fail1:
 178         DTRACE_PROBE1(fail1, int, rc);
 179 
 180         return (rc);
 181 }
 182 
 183 void
 184 sfxge_phy_kstat_fini(sfxge_t *sp)
 185 {
 186         sfxge_phy_t *spp = &(sp->s_mac.sm_phy);
 187 
 188         /* Destroy the set */
 189         kstat_delete(spp->sp_ksp);
 190         spp->sp_ksp = NULL;
 191         spp->sp_stat = NULL;
 192 
 193         kmem_free(spp->sp_statbuf, sizeof (uint32_t) * EFX_PHY_NSTATS);
 194 }
 195 
 196 
 197 int
 198 sfxge_phy_init(sfxge_t *sp)
 199 {
 200         sfxge_phy_t *spp = &(sp->s_mac.sm_phy);
 201         efsys_mem_t *esmp = &(spp->sp_mem);
 202         sfxge_dma_buffer_attr_t dma_attr;
 203         int rc;
 204 
 205         dma_attr.sdba_dip        = sp->s_dip;
 206         dma_attr.sdba_dattrp     = &sfxge_phy_dma_attr;
 207         dma_attr.sdba_callback   = DDI_DMA_SLEEP;
 208         dma_attr.sdba_length     = EFX_PHY_STATS_SIZE;
 209         dma_attr.sdba_memflags   = DDI_DMA_CONSISTENT;
 210         dma_attr.sdba_devaccp    = &sfxge_phy_devacc;
 211         dma_attr.sdba_bindflags  = DDI_DMA_READ | DDI_DMA_CONSISTENT;
 212         dma_attr.sdba_maxcookies = 1;
 213         dma_attr.sdba_zeroinit   = B_TRUE;
 214 
 215         if ((rc = sfxge_dma_buffer_create(esmp, &dma_attr)) != 0)
 216                 goto fail1;
 217 
 218         return (0);
 219 
 220 fail1:
 221         DTRACE_PROBE1(fail1, int, rc);
 222         SFXGE_OBJ_CHECK(spp, sfxge_phy_t);
 223 
 224         return (rc);
 225 }
 226 
 227 uint8_t
 228 sfxge_phy_lp_cap_test(sfxge_t *sp, uint32_t field)
 229 {
 230         sfxge_mac_t *smp = &(sp->s_mac);
 231         uint32_t cap = 0;
 232 
 233         mutex_enter(&(smp->sm_lock));
 234 
 235         if (smp->sm_state != SFXGE_MAC_STARTED)
 236                 goto done;
 237 
 238         efx_phy_lp_cap_get(sp->s_enp, &cap);
 239 
 240 done:
 241         mutex_exit(&(smp->sm_lock));
 242 
 243         return (cap & (1 << field));
 244 }
 245 
 246 /*
 247  * Set up the advertised capabilities that may have been asked for
 248  * when the mac was not in the state SFXGE_MAC_STARTED.
 249  * Must be called after efx_port_init().
 250  */
 251 int
 252 sfxge_phy_cap_apply(sfxge_t *sp, boolean_t use_default)
 253 {
 254         sfxge_mac_t *smp = &(sp->s_mac);
 255         efx_nic_t *enp;
 256         uint32_t adv_cap;
 257         int rc;
 258         int err;
 259 
 260         ASSERT(mutex_owned(&(smp->sm_lock)));
 261 
 262         enp = sp->s_enp;
 263 
 264         if (use_default)
 265                 efx_phy_adv_cap_get(enp, EFX_PHY_CAP_DEFAULT, &adv_cap);
 266         else
 267                 efx_phy_adv_cap_get(enp, EFX_PHY_CAP_CURRENT, &adv_cap);
 268 
 269         adv_cap |= smp->sm_phy_cap_to_set;
 270         smp->sm_phy_cap_to_set = 0;
 271         adv_cap &= ~(smp->sm_phy_cap_to_unset);
 272         smp->sm_phy_cap_to_unset = 0;
 273         if ((err = efx_phy_adv_cap_set(enp, adv_cap)) != 0) {
 274                 if (err == EINVAL) {
 275                         /*
 276                          * The configuation wasn't accepted, so set to
 277                          * defaults.
 278                          */
 279                         uint32_t requested = adv_cap;
 280                         uint32_t supported;
 281                         efx_phy_adv_cap_get(enp, EFX_PHY_CAP_PERM, &supported);
 282                         efx_phy_adv_cap_get(enp, EFX_PHY_CAP_DEFAULT, &adv_cap);
 283                         if ((rc = efx_phy_adv_cap_set(enp, adv_cap)) != 0)
 284                                 goto fail1;
 285                         dev_err(sp->s_dip, CE_WARN, SFXGE_CMN_ERR
 286                             "Setting of advertised link capabilities failed. "
 287                             "Using default settings. "
 288                             "(Requested 0x%x Given 0x%x Supported 0x%x)",
 289                             requested,
 290                             adv_cap,
 291                             supported);
 292                 } else {
 293                         rc = err;
 294                         goto fail2;
 295                 }
 296         }
 297 
 298         return (0);
 299 
 300 fail2:
 301         DTRACE_PROBE(fail2);
 302 
 303 fail1:
 304         DTRACE_PROBE1(fail1, int, rc);
 305 
 306         return (rc);
 307 }
 308 
 309 uint8_t
 310 sfxge_phy_cap_test(sfxge_t *sp, uint32_t flag, uint32_t field,
 311     boolean_t *mutablep)
 312 {
 313         sfxge_mac_t *smp = &(sp->s_mac);
 314         efx_nic_t *enp;
 315         uint32_t cap = 0;
 316         uint32_t perm = 0;
 317 
 318         mutex_enter(&(smp->sm_lock));
 319         enp = sp->s_enp;
 320 
 321         if (smp->sm_state != SFXGE_MAC_STARTED)
 322                 goto done;
 323 
 324         efx_phy_adv_cap_get(enp, flag, &cap);
 325         efx_phy_adv_cap_get(enp, EFX_PHY_CAP_PERM, &perm);
 326 
 327 done:
 328         mutex_exit(&(smp->sm_lock));
 329 
 330         if (mutablep)
 331                 *mutablep = (perm & (1 << field)) ? B_TRUE : B_FALSE;
 332 
 333         return ((cap & (1 << field)) ? 1 : 0);
 334 }
 335 
 336 
 337 int
 338 sfxge_phy_cap_set(sfxge_t *sp, uint32_t field, int set)
 339 {
 340         sfxge_mac_t *smp = &(sp->s_mac);
 341         efx_nic_t *enp = sp->s_enp;
 342         uint32_t cap;
 343         int rc = 0;
 344 
 345         mutex_enter(&(smp->sm_lock));
 346 
 347         if (smp->sm_state != SFXGE_MAC_STARTED) {
 348                 /* Store the request for when the mac is started */
 349                 if (set)
 350                         smp->sm_phy_cap_to_set |= (1 << field);
 351                 else
 352                         smp->sm_phy_cap_to_unset |= (1 << field);
 353                 goto done;
 354         }
 355 
 356         efx_phy_adv_cap_get(enp, EFX_PHY_CAP_CURRENT, &cap);
 357 
 358         if (set)
 359                 cap |= (1 << field);
 360         else
 361                 cap &= ~(1 << field);
 362 
 363         rc = efx_phy_adv_cap_set(enp, cap);
 364 done:
 365         mutex_exit(&(smp->sm_lock));
 366 
 367         return (rc);
 368 }
 369 
 370 
 371 void
 372 sfxge_phy_fini(sfxge_t *sp)
 373 {
 374         sfxge_phy_t *spp = &(sp->s_mac.sm_phy);
 375         efsys_mem_t *esmp = &(spp->sp_mem);
 376 
 377         sfxge_dma_buffer_destroy(esmp);
 378 }