linux/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c
<<
>>
Prefs
   1/*
   2 * aQuantia Corporation Network Driver
   3 * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved
   4 *
   5 * This program is free software; you can redistribute it and/or modify it
   6 * under the terms and conditions of the GNU General Public License,
   7 * version 2, as published by the Free Software Foundation.
   8 */
   9
  10/* File hw_atl_utils.c: Definition of common functions for Atlantic hardware
  11 * abstraction layer.
  12 */
  13
  14#include "../aq_hw.h"
  15#include "../aq_hw_utils.h"
  16#include "../aq_pci_func.h"
  17#include "../aq_ring.h"
  18#include "../aq_vec.h"
  19#include "hw_atl_utils.h"
  20#include "hw_atl_llh.h"
  21
  22#include <linux/random.h>
  23
  24#define HW_ATL_UCP_0X370_REG    0x0370U
  25
  26#define HW_ATL_FW_SM_RAM        0x2U
  27#define HW_ATL_MPI_CONTROL_ADR  0x0368U
  28#define HW_ATL_MPI_STATE_ADR    0x036CU
  29
  30#define HW_ATL_MPI_STATE_MSK    0x00FFU
  31#define HW_ATL_MPI_STATE_SHIFT  0U
  32#define HW_ATL_MPI_SPEED_MSK    0xFFFFU
  33#define HW_ATL_MPI_SPEED_SHIFT  16U
  34
  35static int hw_atl_utils_fw_downld_dwords(struct aq_hw_s *self, u32 a,
  36                                         u32 *p, u32 cnt)
  37{
  38        int err = 0;
  39
  40        AQ_HW_WAIT_FOR(reg_glb_cpu_sem_get(self,
  41                                           HW_ATL_FW_SM_RAM) == 1U,
  42                                           1U, 10000U);
  43
  44        if (err < 0) {
  45                bool is_locked;
  46
  47                reg_glb_cpu_sem_set(self, 1U, HW_ATL_FW_SM_RAM);
  48                is_locked = reg_glb_cpu_sem_get(self, HW_ATL_FW_SM_RAM);
  49                if (!is_locked) {
  50                        err = -ETIME;
  51                        goto err_exit;
  52                }
  53        }
  54
  55        aq_hw_write_reg(self, 0x00000208U, a);
  56
  57        for (++cnt; --cnt;) {
  58                u32 i = 0U;
  59
  60                aq_hw_write_reg(self, 0x00000200U, 0x00008000U);
  61
  62                for (i = 1024U;
  63                        (0x100U & aq_hw_read_reg(self, 0x00000200U)) && --i;) {
  64                }
  65
  66                *(p++) = aq_hw_read_reg(self, 0x0000020CU);
  67        }
  68
  69        reg_glb_cpu_sem_set(self, 1U, HW_ATL_FW_SM_RAM);
  70
  71err_exit:
  72        return err;
  73}
  74
  75static int hw_atl_utils_fw_upload_dwords(struct aq_hw_s *self, u32 a, u32 *p,
  76                                         u32 cnt)
  77{
  78        int err = 0;
  79        bool is_locked;
  80
  81        is_locked = reg_glb_cpu_sem_get(self, HW_ATL_FW_SM_RAM);
  82        if (!is_locked) {
  83                err = -ETIME;
  84                goto err_exit;
  85        }
  86
  87        aq_hw_write_reg(self, 0x00000208U, a);
  88
  89        for (++cnt; --cnt;) {
  90                u32 i = 0U;
  91
  92                aq_hw_write_reg(self, 0x0000020CU, *(p++));
  93                aq_hw_write_reg(self, 0x00000200U, 0xC000U);
  94
  95                for (i = 1024U;
  96                        (0x100U & aq_hw_read_reg(self, 0x00000200U)) && --i;) {
  97                }
  98        }
  99
 100        reg_glb_cpu_sem_set(self, 1U, HW_ATL_FW_SM_RAM);
 101
 102err_exit:
 103        return err;
 104}
 105
 106static int hw_atl_utils_ver_match(u32 ver_expected, u32 ver_actual)
 107{
 108        int err = 0;
 109        const u32 dw_major_mask = 0xff000000U;
 110        const u32 dw_minor_mask = 0x00ffffffU;
 111
 112        err = (dw_major_mask & (ver_expected ^ ver_actual)) ? -EOPNOTSUPP : 0;
 113        if (err < 0)
 114                goto err_exit;
 115        err = ((dw_minor_mask & ver_expected) > (dw_minor_mask & ver_actual)) ?
 116                -EOPNOTSUPP : 0;
 117err_exit:
 118        return err;
 119}
 120
 121static int hw_atl_utils_init_ucp(struct aq_hw_s *self,
 122                                 struct aq_hw_caps_s *aq_hw_caps)
 123{
 124        int err = 0;
 125
 126        if (!aq_hw_read_reg(self, 0x370U)) {
 127                unsigned int rnd = 0U;
 128                unsigned int ucp_0x370 = 0U;
 129
 130                get_random_bytes(&rnd, sizeof(unsigned int));
 131
 132                ucp_0x370 = 0x02020202U | (0xFEFEFEFEU & rnd);
 133                aq_hw_write_reg(self, HW_ATL_UCP_0X370_REG, ucp_0x370);
 134        }
 135
 136        reg_glb_cpu_scratch_scp_set(self, 0x00000000U, 25U);
 137
 138        /* check 10 times by 1ms */
 139        AQ_HW_WAIT_FOR(0U != (PHAL_ATLANTIC_A0->mbox_addr =
 140                        aq_hw_read_reg(self, 0x360U)), 1000U, 10U);
 141
 142        err = hw_atl_utils_ver_match(aq_hw_caps->fw_ver_expected,
 143                                     aq_hw_read_reg(self, 0x18U));
 144
 145        if (err < 0)
 146                pr_err("%s: Bad FW version detected: expected=%x, actual=%x\n",
 147                       AQ_CFG_DRV_NAME,
 148                       aq_hw_caps->fw_ver_expected,
 149                       aq_hw_read_reg(self, 0x18U));
 150        return err;
 151}
 152
 153#define HW_ATL_RPC_CONTROL_ADR 0x0338U
 154#define HW_ATL_RPC_STATE_ADR   0x033CU
 155
 156struct aq_hw_atl_utils_fw_rpc_tid_s {
 157        union {
 158                u32 val;
 159                struct {
 160                        u16 tid;
 161                        u16 len;
 162                };
 163        };
 164};
 165
 166#define hw_atl_utils_fw_rpc_init(_H_) hw_atl_utils_fw_rpc_wait(_H_, NULL)
 167
 168static int hw_atl_utils_fw_rpc_call(struct aq_hw_s *self, unsigned int rpc_size)
 169{
 170        int err = 0;
 171        struct aq_hw_atl_utils_fw_rpc_tid_s sw;
 172
 173        if (!IS_CHIP_FEATURE(MIPS)) {
 174                err = -1;
 175                goto err_exit;
 176        }
 177        err = hw_atl_utils_fw_upload_dwords(self, PHAL_ATLANTIC->rpc_addr,
 178                                            (u32 *)(void *)&PHAL_ATLANTIC->rpc,
 179                                            (rpc_size + sizeof(u32) -
 180                                            sizeof(u8)) / sizeof(u32));
 181        if (err < 0)
 182                goto err_exit;
 183
 184        sw.tid = 0xFFFFU & (++PHAL_ATLANTIC->rpc_tid);
 185        sw.len = (u16)rpc_size;
 186        aq_hw_write_reg(self, HW_ATL_RPC_CONTROL_ADR, sw.val);
 187
 188err_exit:
 189        return err;
 190}
 191
 192static int hw_atl_utils_fw_rpc_wait(struct aq_hw_s *self,
 193                                    struct hw_aq_atl_utils_fw_rpc **rpc)
 194{
 195        int err = 0;
 196        struct aq_hw_atl_utils_fw_rpc_tid_s sw;
 197        struct aq_hw_atl_utils_fw_rpc_tid_s fw;
 198
 199        do {
 200                sw.val = aq_hw_read_reg(self, HW_ATL_RPC_CONTROL_ADR);
 201
 202                PHAL_ATLANTIC->rpc_tid = sw.tid;
 203
 204                AQ_HW_WAIT_FOR(sw.tid ==
 205                                (fw.val =
 206                                aq_hw_read_reg(self, HW_ATL_RPC_STATE_ADR),
 207                                fw.tid), 1000U, 100U);
 208                if (err < 0)
 209                        goto err_exit;
 210
 211                if (fw.len == 0xFFFFU) {
 212                        err = hw_atl_utils_fw_rpc_call(self, sw.len);
 213                        if (err < 0)
 214                                goto err_exit;
 215                }
 216        } while (sw.tid != fw.tid || 0xFFFFU == fw.len);
 217        if (err < 0)
 218                goto err_exit;
 219
 220        if (rpc) {
 221                if (fw.len) {
 222                        err =
 223                        hw_atl_utils_fw_downld_dwords(self,
 224                                                      PHAL_ATLANTIC->rpc_addr,
 225                                                      (u32 *)(void *)
 226                                                      &PHAL_ATLANTIC->rpc,
 227                                                      (fw.len + sizeof(u32) -
 228                                                      sizeof(u8)) /
 229                                                      sizeof(u32));
 230                        if (err < 0)
 231                                goto err_exit;
 232                }
 233
 234                *rpc = &PHAL_ATLANTIC->rpc;
 235        }
 236
 237err_exit:
 238        return err;
 239}
 240
 241static int hw_atl_utils_mpi_create(struct aq_hw_s *self,
 242                                   struct aq_hw_caps_s *aq_hw_caps)
 243{
 244        int err = 0;
 245
 246        err = hw_atl_utils_init_ucp(self, aq_hw_caps);
 247        if (err < 0)
 248                goto err_exit;
 249
 250        err = hw_atl_utils_fw_rpc_init(self);
 251        if (err < 0)
 252                goto err_exit;
 253
 254err_exit:
 255        return err;
 256}
 257
 258void hw_atl_utils_mpi_read_stats(struct aq_hw_s *self,
 259                                 struct hw_aq_atl_utils_mbox *pmbox)
 260{
 261        int err = 0;
 262
 263        err = hw_atl_utils_fw_downld_dwords(self,
 264                                            PHAL_ATLANTIC->mbox_addr,
 265                                            (u32 *)(void *)pmbox,
 266                                            sizeof(*pmbox) / sizeof(u32));
 267        if (err < 0)
 268                goto err_exit;
 269
 270        if (pmbox != &PHAL_ATLANTIC->mbox)
 271                memcpy(pmbox, &PHAL_ATLANTIC->mbox, sizeof(*pmbox));
 272
 273        if (IS_CHIP_FEATURE(REVISION_A0)) {
 274                unsigned int mtu = self->aq_nic_cfg ?
 275                                        self->aq_nic_cfg->mtu : 1514U;
 276                pmbox->stats.ubrc = pmbox->stats.uprc * mtu;
 277                pmbox->stats.ubtc = pmbox->stats.uptc * mtu;
 278                pmbox->stats.dpc = atomic_read(&PHAL_ATLANTIC_A0->dpc);
 279        } else {
 280                pmbox->stats.dpc = reg_rx_dma_stat_counter7get(self);
 281        }
 282
 283err_exit:;
 284}
 285
 286int hw_atl_utils_mpi_set_speed(struct aq_hw_s *self, u32 speed,
 287                               enum hal_atl_utils_fw_state_e state)
 288{
 289        u32 ucp_0x368 = 0;
 290
 291        ucp_0x368 = (speed << HW_ATL_MPI_SPEED_SHIFT) | state;
 292        aq_hw_write_reg(self, HW_ATL_MPI_CONTROL_ADR, ucp_0x368);
 293
 294        return 0;
 295}
 296
 297void hw_atl_utils_mpi_set(struct aq_hw_s *self,
 298                          enum hal_atl_utils_fw_state_e state, u32 speed)
 299{
 300        int err = 0;
 301        u32 transaction_id = 0;
 302
 303        if (state == MPI_RESET) {
 304                hw_atl_utils_mpi_read_stats(self, &PHAL_ATLANTIC->mbox);
 305
 306                transaction_id = PHAL_ATLANTIC->mbox.transaction_id;
 307
 308                AQ_HW_WAIT_FOR(transaction_id !=
 309                                (hw_atl_utils_mpi_read_stats
 310                                        (self, &PHAL_ATLANTIC->mbox),
 311                                        PHAL_ATLANTIC->mbox.transaction_id),
 312                                        1000U, 100U);
 313                if (err < 0)
 314                        goto err_exit;
 315        }
 316
 317        err = hw_atl_utils_mpi_set_speed(self, speed, state);
 318
 319err_exit:;
 320}
 321
 322int hw_atl_utils_mpi_get_link_status(struct aq_hw_s *self)
 323{
 324        u32 cp0x036C = aq_hw_read_reg(self, HW_ATL_MPI_STATE_ADR);
 325        u32 link_speed_mask = cp0x036C >> HW_ATL_MPI_SPEED_SHIFT;
 326        struct aq_hw_link_status_s *link_status = &self->aq_link_status;
 327
 328        if (!link_speed_mask) {
 329                link_status->mbps = 0U;
 330        } else {
 331                switch (link_speed_mask) {
 332                case HAL_ATLANTIC_RATE_10G:
 333                        link_status->mbps = 10000U;
 334                        break;
 335
 336                case HAL_ATLANTIC_RATE_5G:
 337                case HAL_ATLANTIC_RATE_5GSR:
 338                        link_status->mbps = 5000U;
 339                        break;
 340
 341                case HAL_ATLANTIC_RATE_2GS:
 342                        link_status->mbps = 2500U;
 343                        break;
 344
 345                case HAL_ATLANTIC_RATE_1G:
 346                        link_status->mbps = 1000U;
 347                        break;
 348
 349                case HAL_ATLANTIC_RATE_100M:
 350                        link_status->mbps = 100U;
 351                        break;
 352
 353                default:
 354                        link_status->mbps = 0U;
 355                        break;
 356                }
 357        }
 358
 359        return 0;
 360}
 361
 362int hw_atl_utils_get_mac_permanent(struct aq_hw_s *self,
 363                                   struct aq_hw_caps_s *aq_hw_caps,
 364                                   u8 *mac)
 365{
 366        int err = 0;
 367        u32 h = 0U;
 368        u32 l = 0U;
 369        u32 mac_addr[2];
 370
 371        self->mmio = aq_pci_func_get_mmio(self->aq_pci_func);
 372
 373        hw_atl_utils_hw_chip_features_init(self,
 374                                           &PHAL_ATLANTIC_A0->chip_features);
 375
 376        err = hw_atl_utils_mpi_create(self, aq_hw_caps);
 377        if (err < 0)
 378                goto err_exit;
 379
 380        if (!aq_hw_read_reg(self, HW_ATL_UCP_0X370_REG)) {
 381                unsigned int rnd = 0;
 382                unsigned int ucp_0x370 = 0;
 383
 384                get_random_bytes(&rnd, sizeof(unsigned int));
 385
 386                ucp_0x370 = 0x02020202 | (0xFEFEFEFE & rnd);
 387                aq_hw_write_reg(self, HW_ATL_UCP_0X370_REG, ucp_0x370);
 388        }
 389
 390        err = hw_atl_utils_fw_downld_dwords(self,
 391                                            aq_hw_read_reg(self, 0x00000374U) +
 392                                            (40U * 4U),
 393                                            mac_addr,
 394                                            AQ_DIMOF(mac_addr));
 395        if (err < 0) {
 396                mac_addr[0] = 0U;
 397                mac_addr[1] = 0U;
 398                err = 0;
 399        } else {
 400                mac_addr[0] = __swab32(mac_addr[0]);
 401                mac_addr[1] = __swab32(mac_addr[1]);
 402        }
 403
 404        ether_addr_copy(mac, (u8 *)mac_addr);
 405
 406        if ((mac[0] & 0x01U) || ((mac[0] | mac[1] | mac[2]) == 0x00U)) {
 407                /* chip revision */
 408                l = 0xE3000000U
 409                        | (0xFFFFU & aq_hw_read_reg(self, HW_ATL_UCP_0X370_REG))
 410                        | (0x00 << 16);
 411                h = 0x8001300EU;
 412
 413                mac[5] = (u8)(0xFFU & l);
 414                l >>= 8;
 415                mac[4] = (u8)(0xFFU & l);
 416                l >>= 8;
 417                mac[3] = (u8)(0xFFU & l);
 418                l >>= 8;
 419                mac[2] = (u8)(0xFFU & l);
 420                mac[1] = (u8)(0xFFU & h);
 421                h >>= 8;
 422                mac[0] = (u8)(0xFFU & h);
 423        }
 424
 425err_exit:
 426        return err;
 427}
 428
 429unsigned int hw_atl_utils_mbps_2_speed_index(unsigned int mbps)
 430{
 431        unsigned int ret = 0U;
 432
 433        switch (mbps) {
 434        case 100U:
 435                ret = 5U;
 436                break;
 437
 438        case 1000U:
 439                ret = 4U;
 440                break;
 441
 442        case 2500U:
 443                ret = 3U;
 444                break;
 445
 446        case 5000U:
 447                ret = 1U;
 448                break;
 449
 450        case 10000U:
 451                ret = 0U;
 452                break;
 453
 454        default:
 455                break;
 456        }
 457        return ret;
 458}
 459
 460void hw_atl_utils_hw_chip_features_init(struct aq_hw_s *self, u32 *p)
 461{
 462        u32 chip_features = 0U;
 463        u32 val = reg_glb_mif_id_get(self);
 464        u32 mif_rev = val & 0xFFU;
 465
 466        if ((3U & mif_rev) == 1U) {
 467                chip_features |=
 468                        HAL_ATLANTIC_UTILS_CHIP_REVISION_A0 |
 469                        HAL_ATLANTIC_UTILS_CHIP_MPI_AQ |
 470                        HAL_ATLANTIC_UTILS_CHIP_MIPS;
 471        } else if ((3U & mif_rev) == 2U) {
 472                chip_features |=
 473                        HAL_ATLANTIC_UTILS_CHIP_REVISION_B0 |
 474                        HAL_ATLANTIC_UTILS_CHIP_MPI_AQ |
 475                        HAL_ATLANTIC_UTILS_CHIP_MIPS |
 476                        HAL_ATLANTIC_UTILS_CHIP_TPO2 |
 477                        HAL_ATLANTIC_UTILS_CHIP_RPF2;
 478        }
 479
 480        *p = chip_features;
 481}
 482
 483int hw_atl_utils_hw_deinit(struct aq_hw_s *self)
 484{
 485        hw_atl_utils_mpi_set(self, MPI_DEINIT, 0x0U);
 486        return 0;
 487}
 488
 489int hw_atl_utils_hw_set_power(struct aq_hw_s *self,
 490                              unsigned int power_state)
 491{
 492        hw_atl_utils_mpi_set(self, MPI_POWER, 0x0U);
 493        return 0;
 494}
 495
 496int hw_atl_utils_get_hw_stats(struct aq_hw_s *self,
 497                              u64 *data, unsigned int *p_count)
 498{
 499        struct hw_atl_stats_s *stats = NULL;
 500        int i = 0;
 501
 502        hw_atl_utils_mpi_read_stats(self, &PHAL_ATLANTIC->mbox);
 503
 504        stats = &PHAL_ATLANTIC->mbox.stats;
 505
 506        data[i] = stats->uprc + stats->mprc + stats->bprc;
 507        data[++i] = stats->uprc;
 508        data[++i] = stats->mprc;
 509        data[++i] = stats->bprc;
 510        data[++i] = stats->erpt;
 511        data[++i] = stats->uptc + stats->mptc + stats->bptc;
 512        data[++i] = stats->uptc;
 513        data[++i] = stats->mptc;
 514        data[++i] = stats->bptc;
 515        data[++i] = stats->ubrc;
 516        data[++i] = stats->ubtc;
 517        data[++i] = stats->mbrc;
 518        data[++i] = stats->mbtc;
 519        data[++i] = stats->bbrc;
 520        data[++i] = stats->bbtc;
 521        data[++i] = stats->ubrc + stats->mbrc + stats->bbrc;
 522        data[++i] = stats->ubtc + stats->mbtc + stats->bbtc;
 523        data[++i] = stats_rx_dma_good_pkt_counterlsw_get(self);
 524        data[++i] = stats_tx_dma_good_pkt_counterlsw_get(self);
 525        data[++i] = stats_rx_dma_good_octet_counterlsw_get(self);
 526        data[++i] = stats_tx_dma_good_octet_counterlsw_get(self);
 527        data[++i] = stats->dpc;
 528
 529        if (p_count)
 530                *p_count = ++i;
 531
 532        return 0;
 533}
 534
 535static const u32 hw_atl_utils_hw_mac_regs[] = {
 536        0x00005580U, 0x00005590U, 0x000055B0U, 0x000055B4U,
 537        0x000055C0U, 0x00005B00U, 0x00005B04U, 0x00005B08U,
 538        0x00005B0CU, 0x00005B10U, 0x00005B14U, 0x00005B18U,
 539        0x00005B1CU, 0x00005B20U, 0x00005B24U, 0x00005B28U,
 540        0x00005B2CU, 0x00005B30U, 0x00005B34U, 0x00005B38U,
 541        0x00005B3CU, 0x00005B40U, 0x00005B44U, 0x00005B48U,
 542        0x00005B4CU, 0x00005B50U, 0x00005B54U, 0x00005B58U,
 543        0x00005B5CU, 0x00005B60U, 0x00005B64U, 0x00005B68U,
 544        0x00005B6CU, 0x00005B70U, 0x00005B74U, 0x00005B78U,
 545        0x00005B7CU, 0x00007C00U, 0x00007C04U, 0x00007C08U,
 546        0x00007C0CU, 0x00007C10U, 0x00007C14U, 0x00007C18U,
 547        0x00007C1CU, 0x00007C20U, 0x00007C40U, 0x00007C44U,
 548        0x00007C48U, 0x00007C4CU, 0x00007C50U, 0x00007C54U,
 549        0x00007C58U, 0x00007C5CU, 0x00007C60U, 0x00007C80U,
 550        0x00007C84U, 0x00007C88U, 0x00007C8CU, 0x00007C90U,
 551        0x00007C94U, 0x00007C98U, 0x00007C9CU, 0x00007CA0U,
 552        0x00007CC0U, 0x00007CC4U, 0x00007CC8U, 0x00007CCCU,
 553        0x00007CD0U, 0x00007CD4U, 0x00007CD8U, 0x00007CDCU,
 554        0x00007CE0U, 0x00000300U, 0x00000304U, 0x00000308U,
 555        0x0000030cU, 0x00000310U, 0x00000314U, 0x00000318U,
 556        0x0000031cU, 0x00000360U, 0x00000364U, 0x00000368U,
 557        0x0000036cU, 0x00000370U, 0x00000374U, 0x00006900U,
 558};
 559
 560int hw_atl_utils_hw_get_regs(struct aq_hw_s *self,
 561                             struct aq_hw_caps_s *aq_hw_caps,
 562                             u32 *regs_buff)
 563{
 564        unsigned int i = 0U;
 565
 566        for (i = 0; i < aq_hw_caps->mac_regs_count; i++)
 567                regs_buff[i] = aq_hw_read_reg(self,
 568                        hw_atl_utils_hw_mac_regs[i]);
 569        return 0;
 570}
 571
 572int hw_atl_utils_get_fw_version(struct aq_hw_s *self, u32 *fw_version)
 573{
 574        *fw_version = aq_hw_read_reg(self, 0x18U);
 575        return 0;
 576}
 577