linux/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/* Atlantic Network Driver
   3 *
   4 * Copyright (C) 2014-2019 aQuantia Corporation
   5 * Copyright (C) 2019-2020 Marvell International Ltd.
   6 */
   7
   8/* File hw_atl_utils_fw2x.c: Definition of firmware 2.x functions for
   9 * Atlantic hardware abstraction layer.
  10 */
  11
  12#include "../aq_hw.h"
  13#include "../aq_hw_utils.h"
  14#include "../aq_pci_func.h"
  15#include "../aq_ring.h"
  16#include "../aq_vec.h"
  17#include "../aq_nic.h"
  18#include "hw_atl_utils.h"
  19#include "hw_atl_llh.h"
  20
  21#define HW_ATL_FW2X_MPI_LED_ADDR         0x31c
  22#define HW_ATL_FW2X_MPI_RPC_ADDR         0x334
  23
  24#define HW_ATL_FW2X_MPI_MBOX_ADDR        0x360
  25#define HW_ATL_FW2X_MPI_EFUSE_ADDR       0x364
  26#define HW_ATL_FW2X_MPI_CONTROL_ADDR     0x368
  27#define HW_ATL_FW2X_MPI_CONTROL2_ADDR    0x36C
  28#define HW_ATL_FW2X_MPI_STATE_ADDR       0x370
  29#define HW_ATL_FW2X_MPI_STATE2_ADDR      0x374
  30
  31#define HW_ATL_FW3X_EXT_CONTROL_ADDR     0x378
  32#define HW_ATL_FW3X_EXT_STATE_ADDR       0x37c
  33
  34#define HW_ATL_FW3X_PTP_ADJ_LSW_ADDR     0x50a0
  35#define HW_ATL_FW3X_PTP_ADJ_MSW_ADDR     0x50a4
  36
  37#define HW_ATL_FW2X_CAP_PAUSE            BIT(CAPS_HI_PAUSE)
  38#define HW_ATL_FW2X_CAP_ASYM_PAUSE       BIT(CAPS_HI_ASYMMETRIC_PAUSE)
  39#define HW_ATL_FW2X_CAP_SLEEP_PROXY      BIT(CAPS_HI_SLEEP_PROXY)
  40#define HW_ATL_FW2X_CAP_WOL              BIT(CAPS_HI_WOL)
  41
  42#define HW_ATL_FW2X_CTRL_WAKE_ON_LINK     BIT(CTRL_WAKE_ON_LINK)
  43#define HW_ATL_FW2X_CTRL_SLEEP_PROXY      BIT(CTRL_SLEEP_PROXY)
  44#define HW_ATL_FW2X_CTRL_WOL              BIT(CTRL_WOL)
  45#define HW_ATL_FW2X_CTRL_LINK_DROP        BIT(CTRL_LINK_DROP)
  46#define HW_ATL_FW2X_CTRL_PAUSE            BIT(CTRL_PAUSE)
  47#define HW_ATL_FW2X_CTRL_TEMPERATURE      BIT(CTRL_TEMPERATURE)
  48#define HW_ATL_FW2X_CTRL_ASYMMETRIC_PAUSE BIT(CTRL_ASYMMETRIC_PAUSE)
  49#define HW_ATL_FW2X_CTRL_INT_LOOPBACK     BIT(CTRL_INT_LOOPBACK)
  50#define HW_ATL_FW2X_CTRL_EXT_LOOPBACK     BIT(CTRL_EXT_LOOPBACK)
  51#define HW_ATL_FW2X_CTRL_DOWNSHIFT        BIT(CTRL_DOWNSHIFT)
  52#define HW_ATL_FW2X_CTRL_FORCE_RECONNECT  BIT(CTRL_FORCE_RECONNECT)
  53
  54#define HW_ATL_FW2X_CAP_EEE_1G_MASK      BIT(CAPS_HI_1000BASET_FD_EEE)
  55#define HW_ATL_FW2X_CAP_EEE_2G5_MASK     BIT(CAPS_HI_2P5GBASET_FD_EEE)
  56#define HW_ATL_FW2X_CAP_EEE_5G_MASK      BIT(CAPS_HI_5GBASET_FD_EEE)
  57#define HW_ATL_FW2X_CAP_EEE_10G_MASK     BIT(CAPS_HI_10GBASET_FD_EEE)
  58
  59#define HW_ATL_FW2X_CAP_MACSEC           BIT(CAPS_LO_MACSEC)
  60
  61#define HAL_ATLANTIC_WOL_FILTERS_COUNT   8
  62#define HAL_ATLANTIC_UTILS_FW2X_MSG_WOL  0x0E
  63
  64#define HW_ATL_FW_VER_LED                0x03010026U
  65#define HW_ATL_FW_VER_MEDIA_CONTROL      0x0301005aU
  66
  67struct __packed fw2x_msg_wol_pattern {
  68        u8 mask[16];
  69        u32 crc;
  70};
  71
  72struct __packed fw2x_msg_wol {
  73        u32 msg_id;
  74        u8 hw_addr[ETH_ALEN];
  75        u8 magic_packet_enabled;
  76        u8 filter_count;
  77        struct fw2x_msg_wol_pattern filter[HAL_ATLANTIC_WOL_FILTERS_COUNT];
  78        u8 link_up_enabled;
  79        u8 link_down_enabled;
  80        u16 reserved;
  81        u32 link_up_timeout;
  82        u32 link_down_timeout;
  83};
  84
  85static int aq_fw2x_set_link_speed(struct aq_hw_s *self, u32 speed);
  86static int aq_fw2x_set_state(struct aq_hw_s *self,
  87                             enum hal_atl_utils_fw_state_e state);
  88
  89static u32 aq_fw2x_mbox_get(struct aq_hw_s *self);
  90static u32 aq_fw2x_rpc_get(struct aq_hw_s *self);
  91static int aq_fw2x_settings_get(struct aq_hw_s *self, u32 *addr);
  92static u32 aq_fw2x_state_get(struct aq_hw_s *self);
  93static u32 aq_fw2x_state2_get(struct aq_hw_s *self);
  94
  95static int aq_fw2x_init(struct aq_hw_s *self)
  96{
  97        int err = 0;
  98
  99        /* check 10 times by 1ms */
 100        err = readx_poll_timeout_atomic(aq_fw2x_mbox_get,
 101                                        self, self->mbox_addr,
 102                                        self->mbox_addr != 0U,
 103                                        1000U, 10000U);
 104
 105        err = readx_poll_timeout_atomic(aq_fw2x_rpc_get,
 106                                        self, self->rpc_addr,
 107                                        self->rpc_addr != 0U,
 108                                        1000U, 100000U);
 109
 110        err = aq_fw2x_settings_get(self, &self->settings_addr);
 111
 112        return err;
 113}
 114
 115static int aq_fw2x_deinit(struct aq_hw_s *self)
 116{
 117        int err = aq_fw2x_set_link_speed(self, 0);
 118
 119        if (!err)
 120                err = aq_fw2x_set_state(self, MPI_DEINIT);
 121
 122        return err;
 123}
 124
 125static enum hw_atl_fw2x_rate link_speed_mask_2fw2x_ratemask(u32 speed)
 126{
 127        enum hw_atl_fw2x_rate rate = 0;
 128
 129        if (speed & AQ_NIC_RATE_10G)
 130                rate |= FW2X_RATE_10G;
 131
 132        if (speed & AQ_NIC_RATE_5G)
 133                rate |= FW2X_RATE_5G;
 134
 135        if (speed & AQ_NIC_RATE_5GSR)
 136                rate |= FW2X_RATE_5G;
 137
 138        if (speed & AQ_NIC_RATE_2G5)
 139                rate |= FW2X_RATE_2G5;
 140
 141        if (speed & AQ_NIC_RATE_1G)
 142                rate |= FW2X_RATE_1G;
 143
 144        if (speed & AQ_NIC_RATE_100M)
 145                rate |= FW2X_RATE_100M;
 146
 147        return rate;
 148}
 149
 150static u32 fw2x_to_eee_mask(u32 speed)
 151{
 152        u32 rate = 0;
 153
 154        if (speed & HW_ATL_FW2X_CAP_EEE_10G_MASK)
 155                rate |= AQ_NIC_RATE_EEE_10G;
 156        if (speed & HW_ATL_FW2X_CAP_EEE_5G_MASK)
 157                rate |= AQ_NIC_RATE_EEE_5G;
 158        if (speed & HW_ATL_FW2X_CAP_EEE_2G5_MASK)
 159                rate |= AQ_NIC_RATE_EEE_2G5;
 160        if (speed & HW_ATL_FW2X_CAP_EEE_1G_MASK)
 161                rate |= AQ_NIC_RATE_EEE_1G;
 162
 163        return rate;
 164}
 165
 166static u32 eee_mask_to_fw2x(u32 speed)
 167{
 168        u32 rate = 0;
 169
 170        if (speed & AQ_NIC_RATE_EEE_10G)
 171                rate |= HW_ATL_FW2X_CAP_EEE_10G_MASK;
 172        if (speed & AQ_NIC_RATE_EEE_5G)
 173                rate |= HW_ATL_FW2X_CAP_EEE_5G_MASK;
 174        if (speed & AQ_NIC_RATE_EEE_2G5)
 175                rate |= HW_ATL_FW2X_CAP_EEE_2G5_MASK;
 176        if (speed & AQ_NIC_RATE_EEE_1G)
 177                rate |= HW_ATL_FW2X_CAP_EEE_1G_MASK;
 178
 179        return rate;
 180}
 181
 182static int aq_fw2x_set_link_speed(struct aq_hw_s *self, u32 speed)
 183{
 184        u32 val = link_speed_mask_2fw2x_ratemask(speed);
 185
 186        aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL_ADDR, val);
 187
 188        return 0;
 189}
 190
 191static void aq_fw2x_upd_flow_control_bits(struct aq_hw_s *self,
 192                                          u32 *mpi_state, u32 fc)
 193{
 194        *mpi_state &= ~(HW_ATL_FW2X_CTRL_PAUSE |
 195                        HW_ATL_FW2X_CTRL_ASYMMETRIC_PAUSE);
 196
 197        switch (fc) {
 198        /* There is not explicit mode of RX only pause frames,
 199         * thus, we join this mode with FC full.
 200         * FC full is either Rx, either Tx, or both.
 201         */
 202        case AQ_NIC_FC_FULL:
 203        case AQ_NIC_FC_RX:
 204                *mpi_state |= HW_ATL_FW2X_CTRL_PAUSE |
 205                              HW_ATL_FW2X_CTRL_ASYMMETRIC_PAUSE;
 206                break;
 207        case AQ_NIC_FC_TX:
 208                *mpi_state |= HW_ATL_FW2X_CTRL_ASYMMETRIC_PAUSE;
 209                break;
 210        }
 211}
 212
 213static void aq_fw2x_upd_eee_rate_bits(struct aq_hw_s *self, u32 *mpi_opts,
 214                                      u32 eee_speeds)
 215{
 216        *mpi_opts &= ~(HW_ATL_FW2X_CAP_EEE_1G_MASK |
 217                       HW_ATL_FW2X_CAP_EEE_2G5_MASK |
 218                       HW_ATL_FW2X_CAP_EEE_5G_MASK |
 219                       HW_ATL_FW2X_CAP_EEE_10G_MASK);
 220
 221        *mpi_opts |= eee_mask_to_fw2x(eee_speeds);
 222}
 223
 224static int aq_fw2x_set_state(struct aq_hw_s *self,
 225                             enum hal_atl_utils_fw_state_e state)
 226{
 227        u32 mpi_state = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
 228        struct aq_nic_cfg_s *cfg = self->aq_nic_cfg;
 229
 230        switch (state) {
 231        case MPI_INIT:
 232                mpi_state &= ~BIT(CAPS_HI_LINK_DROP);
 233                aq_fw2x_upd_eee_rate_bits(self, &mpi_state, cfg->eee_speeds);
 234                aq_fw2x_upd_flow_control_bits(self, &mpi_state,
 235                                              self->aq_nic_cfg->fc.req);
 236                break;
 237        case MPI_DEINIT:
 238                mpi_state |= BIT(CAPS_HI_LINK_DROP);
 239                break;
 240        case MPI_RESET:
 241        case MPI_POWER:
 242                /* No actions */
 243                break;
 244        }
 245        aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_state);
 246
 247        return 0;
 248}
 249
 250static int aq_fw2x_update_link_status(struct aq_hw_s *self)
 251{
 252        struct aq_hw_link_status_s *link_status = &self->aq_link_status;
 253        u32 mpi_state;
 254        u32 speed;
 255
 256        mpi_state = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_STATE_ADDR);
 257        speed = mpi_state & (FW2X_RATE_100M | FW2X_RATE_1G |
 258                             FW2X_RATE_2G5 | FW2X_RATE_5G |
 259                             FW2X_RATE_10G);
 260
 261        if (speed) {
 262                if (speed & FW2X_RATE_10G)
 263                        link_status->mbps = 10000;
 264                else if (speed & FW2X_RATE_5G)
 265                        link_status->mbps = 5000;
 266                else if (speed & FW2X_RATE_2G5)
 267                        link_status->mbps = 2500;
 268                else if (speed & FW2X_RATE_1G)
 269                        link_status->mbps = 1000;
 270                else if (speed & FW2X_RATE_100M)
 271                        link_status->mbps = 100;
 272                else
 273                        link_status->mbps = 10000;
 274        } else {
 275                link_status->mbps = 0;
 276        }
 277        link_status->full_duplex = true;
 278
 279        return 0;
 280}
 281
 282static int aq_fw2x_get_mac_permanent(struct aq_hw_s *self, u8 *mac)
 283{
 284        u32 efuse_addr = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_EFUSE_ADDR);
 285        u32 mac_addr[2] = { 0 };
 286        int err = 0;
 287
 288        if (efuse_addr != 0) {
 289                err = hw_atl_utils_fw_downld_dwords(self,
 290                                                    efuse_addr + (40U * 4U),
 291                                                    mac_addr,
 292                                                    ARRAY_SIZE(mac_addr));
 293                if (err)
 294                        return err;
 295                mac_addr[0] = __swab32(mac_addr[0]);
 296                mac_addr[1] = __swab32(mac_addr[1]);
 297        }
 298
 299        ether_addr_copy(mac, (u8 *)mac_addr);
 300
 301        return err;
 302}
 303
 304static int aq_fw2x_update_stats(struct aq_hw_s *self)
 305{
 306        u32 mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
 307        u32 orig_stats_val = mpi_opts & BIT(CAPS_HI_STATISTICS);
 308        u32 stats_val;
 309        int err = 0;
 310
 311        /* Toggle statistics bit for FW to update */
 312        mpi_opts = mpi_opts ^ BIT(CAPS_HI_STATISTICS);
 313        aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
 314
 315        /* Wait FW to report back */
 316        err = readx_poll_timeout_atomic(aq_fw2x_state2_get,
 317                                        self, stats_val,
 318                                        orig_stats_val != (stats_val &
 319                                        BIT(CAPS_HI_STATISTICS)),
 320                                        1U, 10000U);
 321        if (err)
 322                return err;
 323
 324        return hw_atl_utils_update_stats(self);
 325}
 326
 327static int aq_fw2x_get_phy_temp(struct aq_hw_s *self, int *temp)
 328{
 329        u32 mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
 330        u32 temp_val = mpi_opts & HW_ATL_FW2X_CTRL_TEMPERATURE;
 331        u32 phy_temp_offset;
 332        u32 temp_res;
 333        int err = 0;
 334        u32 val;
 335
 336        phy_temp_offset = self->mbox_addr + offsetof(struct hw_atl_utils_mbox,
 337                                                     info.phy_temperature);
 338
 339        /* Toggle statistics bit for FW to 0x36C.18 (CTRL_TEMPERATURE) */
 340        mpi_opts = mpi_opts ^ HW_ATL_FW2X_CTRL_TEMPERATURE;
 341        aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
 342        /* Wait FW to report back */
 343        err = readx_poll_timeout_atomic(aq_fw2x_state2_get, self, val,
 344                                        temp_val !=
 345                                        (val & HW_ATL_FW2X_CTRL_TEMPERATURE),
 346                                        1U, 10000U);
 347        err = hw_atl_utils_fw_downld_dwords(self, phy_temp_offset,
 348                                            &temp_res, 1);
 349
 350        if (err)
 351                return err;
 352
 353        /* Convert PHY temperature from 1/256 degree Celsius
 354         * to 1/1000 degree Celsius.
 355         */
 356        *temp = (int16_t)(temp_res & 0xFFFF) * 1000 / 256;
 357
 358        return 0;
 359}
 360
 361static int aq_fw2x_set_wol(struct aq_hw_s *self, u8 *mac)
 362{
 363        struct hw_atl_utils_fw_rpc *rpc = NULL;
 364        struct offload_info *info = NULL;
 365        u32 wol_bits = 0;
 366        u32 rpc_size;
 367        int err = 0;
 368        u32 val;
 369
 370        if (self->aq_nic_cfg->wol & WAKE_PHY) {
 371                aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR,
 372                                HW_ATL_FW2X_CTRL_LINK_DROP);
 373                readx_poll_timeout_atomic(aq_fw2x_state2_get, self, val,
 374                                          (val &
 375                                           HW_ATL_FW2X_CTRL_LINK_DROP) != 0,
 376                                          1000, 100000);
 377                wol_bits |= HW_ATL_FW2X_CTRL_WAKE_ON_LINK;
 378        }
 379
 380        if (self->aq_nic_cfg->wol & WAKE_MAGIC) {
 381                wol_bits |= HW_ATL_FW2X_CTRL_SLEEP_PROXY |
 382                            HW_ATL_FW2X_CTRL_WOL;
 383
 384                err = hw_atl_utils_fw_rpc_wait(self, &rpc);
 385                if (err < 0)
 386                        goto err_exit;
 387
 388                rpc_size = sizeof(*info) +
 389                           offsetof(struct hw_atl_utils_fw_rpc, fw2x_offloads);
 390                memset(rpc, 0, rpc_size);
 391                info = &rpc->fw2x_offloads;
 392                memcpy(info->mac_addr, mac, ETH_ALEN);
 393                info->len = sizeof(*info);
 394
 395                err = hw_atl_utils_fw_rpc_call(self, rpc_size);
 396                if (err < 0)
 397                        goto err_exit;
 398        }
 399
 400        aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, wol_bits);
 401
 402err_exit:
 403        return err;
 404}
 405
 406static int aq_fw2x_set_power(struct aq_hw_s *self, unsigned int power_state,
 407                             u8 *mac)
 408{
 409        int err = 0;
 410
 411        if (self->aq_nic_cfg->wol)
 412                err = aq_fw2x_set_wol(self, mac);
 413
 414        return err;
 415}
 416
 417static int aq_fw2x_send_fw_request(struct aq_hw_s *self,
 418                                   const struct hw_fw_request_iface *fw_req,
 419                                   size_t size)
 420{
 421        u32 ctrl2, orig_ctrl2;
 422        u32 dword_cnt;
 423        int err = 0;
 424        u32 val;
 425
 426        /* Write data to drvIface Mailbox */
 427        dword_cnt = size / sizeof(u32);
 428        if (size % sizeof(u32))
 429                dword_cnt++;
 430        err = hw_atl_write_fwcfg_dwords(self, (void *)fw_req, dword_cnt);
 431        if (err < 0)
 432                goto err_exit;
 433
 434        /* Toggle statistics bit for FW to update */
 435        ctrl2 = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
 436        orig_ctrl2 = ctrl2 & BIT(CAPS_HI_FW_REQUEST);
 437        ctrl2 = ctrl2 ^ BIT(CAPS_HI_FW_REQUEST);
 438        aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, ctrl2);
 439
 440        /* Wait FW to report back */
 441        err = readx_poll_timeout_atomic(aq_fw2x_state2_get, self, val,
 442                                        orig_ctrl2 != (val &
 443                                                       BIT(CAPS_HI_FW_REQUEST)),
 444                                        1U, 10000U);
 445
 446err_exit:
 447        return err;
 448}
 449
 450static void aq_fw3x_enable_ptp(struct aq_hw_s *self, int enable)
 451{
 452        u32 ptp_opts = aq_hw_read_reg(self, HW_ATL_FW3X_EXT_STATE_ADDR);
 453        u32 all_ptp_features = BIT(CAPS_EX_PHY_PTP_EN) |
 454                                                   BIT(CAPS_EX_PTP_GPIO_EN);
 455
 456        if (enable)
 457                ptp_opts |= all_ptp_features;
 458        else
 459                ptp_opts &= ~all_ptp_features;
 460
 461        aq_hw_write_reg(self, HW_ATL_FW3X_EXT_CONTROL_ADDR, ptp_opts);
 462}
 463
 464static void aq_fw3x_adjust_ptp(struct aq_hw_s *self, uint64_t adj)
 465{
 466        aq_hw_write_reg(self, HW_ATL_FW3X_PTP_ADJ_LSW_ADDR,
 467                        (adj >>  0) & 0xffffffff);
 468        aq_hw_write_reg(self, HW_ATL_FW3X_PTP_ADJ_MSW_ADDR,
 469                        (adj >> 32) & 0xffffffff);
 470}
 471
 472static int aq_fw2x_led_control(struct aq_hw_s *self, u32 mode)
 473{
 474        if (self->fw_ver_actual < HW_ATL_FW_VER_LED)
 475                return -EOPNOTSUPP;
 476
 477        aq_hw_write_reg(self, HW_ATL_FW2X_MPI_LED_ADDR, mode);
 478
 479        return 0;
 480}
 481
 482static int aq_fw2x_set_eee_rate(struct aq_hw_s *self, u32 speed)
 483{
 484        u32 mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
 485
 486        aq_fw2x_upd_eee_rate_bits(self, &mpi_opts, speed);
 487
 488        aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
 489
 490        return 0;
 491}
 492
 493static int aq_fw2x_get_eee_rate(struct aq_hw_s *self, u32 *rate,
 494                                u32 *supported_rates)
 495{
 496        u32 mpi_state;
 497        u32 caps_hi;
 498        int err = 0;
 499        u32 offset;
 500
 501        offset = self->mbox_addr + offsetof(struct hw_atl_utils_mbox,
 502                                            info.caps_hi);
 503
 504        err = hw_atl_utils_fw_downld_dwords(self, offset, &caps_hi, 1);
 505
 506        if (err)
 507                return err;
 508
 509        *supported_rates = fw2x_to_eee_mask(caps_hi);
 510
 511        mpi_state = aq_fw2x_state2_get(self);
 512        *rate = fw2x_to_eee_mask(mpi_state);
 513
 514        return err;
 515}
 516
 517static int aq_fw2x_renegotiate(struct aq_hw_s *self)
 518{
 519        u32 mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
 520
 521        mpi_opts |= BIT(CTRL_FORCE_RECONNECT);
 522
 523        aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
 524
 525        return 0;
 526}
 527
 528static int aq_fw2x_set_flow_control(struct aq_hw_s *self)
 529{
 530        u32 mpi_state = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
 531
 532        aq_fw2x_upd_flow_control_bits(self, &mpi_state,
 533                                      self->aq_nic_cfg->fc.req);
 534
 535        aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_state);
 536
 537        return 0;
 538}
 539
 540static u32 aq_fw2x_get_flow_control(struct aq_hw_s *self, u32 *fcmode)
 541{
 542        u32 mpi_state = aq_fw2x_state2_get(self);
 543        *fcmode = 0;
 544
 545        if (mpi_state & HW_ATL_FW2X_CAP_PAUSE)
 546                *fcmode |= AQ_NIC_FC_RX;
 547
 548        if (mpi_state & HW_ATL_FW2X_CAP_ASYM_PAUSE)
 549                *fcmode |= AQ_NIC_FC_TX;
 550
 551        return 0;
 552}
 553
 554static int aq_fw2x_set_phyloopback(struct aq_hw_s *self, u32 mode, bool enable)
 555{
 556        u32 mpi_opts;
 557
 558        switch (mode) {
 559        case AQ_HW_LOOPBACK_PHYINT_SYS:
 560                mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
 561                if (enable)
 562                        mpi_opts |= HW_ATL_FW2X_CTRL_INT_LOOPBACK;
 563                else
 564                        mpi_opts &= ~HW_ATL_FW2X_CTRL_INT_LOOPBACK;
 565                aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
 566                break;
 567        case AQ_HW_LOOPBACK_PHYEXT_SYS:
 568                mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
 569                if (enable)
 570                        mpi_opts |= HW_ATL_FW2X_CTRL_EXT_LOOPBACK;
 571                else
 572                        mpi_opts &= ~HW_ATL_FW2X_CTRL_EXT_LOOPBACK;
 573                aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
 574                break;
 575        default:
 576                return -EINVAL;
 577        }
 578
 579        return 0;
 580}
 581
 582static u32 aq_fw2x_mbox_get(struct aq_hw_s *self)
 583{
 584        return aq_hw_read_reg(self, HW_ATL_FW2X_MPI_MBOX_ADDR);
 585}
 586
 587static u32 aq_fw2x_rpc_get(struct aq_hw_s *self)
 588{
 589        return aq_hw_read_reg(self, HW_ATL_FW2X_MPI_RPC_ADDR);
 590}
 591
 592static int aq_fw2x_settings_get(struct aq_hw_s *self, u32 *addr)
 593{
 594        int err = 0;
 595        u32 offset;
 596
 597        offset = self->mbox_addr + offsetof(struct hw_atl_utils_mbox,
 598                                            info.setting_address);
 599
 600        err = hw_atl_utils_fw_downld_dwords(self, offset, addr, 1);
 601
 602        return err;
 603}
 604
 605static u32 aq_fw2x_state_get(struct aq_hw_s *self)
 606{
 607        return aq_hw_read_reg(self, HW_ATL_FW2X_MPI_STATE_ADDR);
 608}
 609
 610static u32 aq_fw2x_state2_get(struct aq_hw_s *self)
 611{
 612        return aq_hw_read_reg(self, HW_ATL_FW2X_MPI_STATE2_ADDR);
 613}
 614
 615static u32 aq_fw2x_get_link_capabilities(struct aq_hw_s *self)
 616{
 617        int err = 0;
 618        u32 offset;
 619        u32 val;
 620
 621        offset = self->mbox_addr +
 622                 offsetof(struct hw_atl_utils_mbox, info.caps_lo);
 623
 624        err = hw_atl_utils_fw_downld_dwords(self, offset, &val, 1);
 625
 626        if (err)
 627                return 0;
 628
 629        return val;
 630}
 631
 632static int aq_fw2x_send_macsec_req(struct aq_hw_s *hw,
 633                                   struct macsec_msg_fw_request *req,
 634                                   struct macsec_msg_fw_response *response)
 635{
 636        u32 low_status, low_req = 0;
 637        u32 dword_cnt;
 638        u32 caps_lo;
 639        u32 offset;
 640        int err;
 641
 642        if (!req || !response)
 643                return -EINVAL;
 644
 645        caps_lo = aq_fw2x_get_link_capabilities(hw);
 646        if (!(caps_lo & BIT(CAPS_LO_MACSEC)))
 647                return -EOPNOTSUPP;
 648
 649        /* Write macsec request to cfg memory */
 650        dword_cnt = (sizeof(*req) + sizeof(u32) - 1) / sizeof(u32);
 651        err = hw_atl_write_fwcfg_dwords(hw, (void *)req, dword_cnt);
 652        if (err < 0)
 653                return err;
 654
 655        /* Toggle 0x368.CAPS_LO_MACSEC bit */
 656        low_req = aq_hw_read_reg(hw, HW_ATL_FW2X_MPI_CONTROL_ADDR);
 657        low_req ^= HW_ATL_FW2X_CAP_MACSEC;
 658        aq_hw_write_reg(hw, HW_ATL_FW2X_MPI_CONTROL_ADDR, low_req);
 659
 660        /* Wait FW to report back */
 661        err = readx_poll_timeout_atomic(aq_fw2x_state_get, hw, low_status,
 662                low_req != (low_status & BIT(CAPS_LO_MACSEC)), 1U, 10000U);
 663        if (err)
 664                return -EIO;
 665
 666        /* Read status of write operation */
 667        offset = hw->rpc_addr + sizeof(u32);
 668        err = hw_atl_utils_fw_downld_dwords(hw, offset, (u32 *)(void *)response,
 669                                            sizeof(*response) / sizeof(u32));
 670
 671        return err;
 672}
 673
 674const struct aq_fw_ops aq_fw_2x_ops = {
 675        .init               = aq_fw2x_init,
 676        .deinit             = aq_fw2x_deinit,
 677        .reset              = NULL,
 678        .renegotiate        = aq_fw2x_renegotiate,
 679        .get_mac_permanent  = aq_fw2x_get_mac_permanent,
 680        .set_link_speed     = aq_fw2x_set_link_speed,
 681        .set_state          = aq_fw2x_set_state,
 682        .update_link_status = aq_fw2x_update_link_status,
 683        .update_stats       = aq_fw2x_update_stats,
 684        .get_mac_temp       = NULL,
 685        .get_phy_temp       = aq_fw2x_get_phy_temp,
 686        .set_power          = aq_fw2x_set_power,
 687        .set_eee_rate       = aq_fw2x_set_eee_rate,
 688        .get_eee_rate       = aq_fw2x_get_eee_rate,
 689        .set_flow_control   = aq_fw2x_set_flow_control,
 690        .get_flow_control   = aq_fw2x_get_flow_control,
 691        .send_fw_request    = aq_fw2x_send_fw_request,
 692        .enable_ptp         = aq_fw3x_enable_ptp,
 693        .led_control        = aq_fw2x_led_control,
 694        .set_phyloopback    = aq_fw2x_set_phyloopback,
 695        .adjust_ptp         = aq_fw3x_adjust_ptp,
 696        .get_link_capabilities = aq_fw2x_get_link_capabilities,
 697        .send_macsec_req    = aq_fw2x_send_macsec_req,
 698};
 699