linux/drivers/net/ethernet/huawei/hinic/hinic_hw_if.c
<<
>>
Prefs
   1/*
   2 * Huawei HiNIC PCI Express Linux driver
   3 * Copyright(c) 2017 Huawei Technologies Co., Ltd
   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 * This program is distributed in the hope it will be useful, but WITHOUT
  10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12 * for more details.
  13 *
  14 */
  15
  16#include <linux/pci.h>
  17#include <linux/device.h>
  18#include <linux/errno.h>
  19#include <linux/io.h>
  20#include <linux/types.h>
  21#include <linux/bitops.h>
  22
  23#include "hinic_hw_csr.h"
  24#include "hinic_hw_if.h"
  25
  26#define PCIE_ATTR_ENTRY         0
  27
  28#define VALID_MSIX_IDX(attr, msix_index) ((msix_index) < (attr)->num_irqs)
  29
  30/**
  31 * hinic_msix_attr_set - set message attribute for msix entry
  32 * @hwif: the HW interface of a pci function device
  33 * @msix_index: msix_index
  34 * @pending_limit: the maximum pending interrupt events (unit 8)
  35 * @coalesc_timer: coalesc period for interrupt (unit 8 us)
  36 * @lli_timer: replenishing period for low latency credit (unit 8 us)
  37 * @lli_credit_limit: maximum credits for low latency msix messages (unit 8)
  38 * @resend_timer: maximum wait for resending msix (unit coalesc period)
  39 *
  40 * Return 0 - Success, negative - Failure
  41 **/
  42int hinic_msix_attr_set(struct hinic_hwif *hwif, u16 msix_index,
  43                        u8 pending_limit, u8 coalesc_timer,
  44                        u8 lli_timer, u8 lli_credit_limit,
  45                        u8 resend_timer)
  46{
  47        u32 msix_ctrl, addr;
  48
  49        if (!VALID_MSIX_IDX(&hwif->attr, msix_index))
  50                return -EINVAL;
  51
  52        msix_ctrl = HINIC_MSIX_ATTR_SET(pending_limit, PENDING_LIMIT)   |
  53                    HINIC_MSIX_ATTR_SET(coalesc_timer, COALESC_TIMER)   |
  54                    HINIC_MSIX_ATTR_SET(lli_timer, LLI_TIMER)           |
  55                    HINIC_MSIX_ATTR_SET(lli_credit_limit, LLI_CREDIT)   |
  56                    HINIC_MSIX_ATTR_SET(resend_timer, RESEND_TIMER);
  57
  58        addr = HINIC_CSR_MSIX_CTRL_ADDR(msix_index);
  59
  60        hinic_hwif_write_reg(hwif, addr, msix_ctrl);
  61        return 0;
  62}
  63
  64/**
  65 * hinic_msix_attr_get - get message attribute of msix entry
  66 * @hwif: the HW interface of a pci function device
  67 * @msix_index: msix_index
  68 * @pending_limit: the maximum pending interrupt events (unit 8)
  69 * @coalesc_timer: coalesc period for interrupt (unit 8 us)
  70 * @lli_timer: replenishing period for low latency credit (unit 8 us)
  71 * @lli_credit_limit: maximum credits for low latency msix messages (unit 8)
  72 * @resend_timer: maximum wait for resending msix (unit coalesc period)
  73 *
  74 * Return 0 - Success, negative - Failure
  75 **/
  76int hinic_msix_attr_get(struct hinic_hwif *hwif, u16 msix_index,
  77                        u8 *pending_limit, u8 *coalesc_timer,
  78                        u8 *lli_timer, u8 *lli_credit_limit,
  79                        u8 *resend_timer)
  80{
  81        u32 addr, val;
  82
  83        if (!VALID_MSIX_IDX(&hwif->attr, msix_index))
  84                return -EINVAL;
  85
  86        addr = HINIC_CSR_MSIX_CTRL_ADDR(msix_index);
  87        val  = hinic_hwif_read_reg(hwif, addr);
  88
  89        *pending_limit    = HINIC_MSIX_ATTR_GET(val, PENDING_LIMIT);
  90        *coalesc_timer    = HINIC_MSIX_ATTR_GET(val, COALESC_TIMER);
  91        *lli_timer        = HINIC_MSIX_ATTR_GET(val, LLI_TIMER);
  92        *lli_credit_limit = HINIC_MSIX_ATTR_GET(val, LLI_CREDIT);
  93        *resend_timer     = HINIC_MSIX_ATTR_GET(val, RESEND_TIMER);
  94        return 0;
  95}
  96
  97/**
  98 * hinic_msix_attr_cnt_clear - clear message attribute counters for msix entry
  99 * @hwif: the HW interface of a pci function device
 100 * @msix_index: msix_index
 101 *
 102 * Return 0 - Success, negative - Failure
 103 **/
 104int hinic_msix_attr_cnt_clear(struct hinic_hwif *hwif, u16 msix_index)
 105{
 106        u32 msix_ctrl, addr;
 107
 108        if (!VALID_MSIX_IDX(&hwif->attr, msix_index))
 109                return -EINVAL;
 110
 111        msix_ctrl = HINIC_MSIX_CNT_SET(1, RESEND_TIMER);
 112        addr = HINIC_CSR_MSIX_CNT_ADDR(msix_index);
 113
 114        hinic_hwif_write_reg(hwif, addr, msix_ctrl);
 115        return 0;
 116}
 117
 118/**
 119 * hinic_set_pf_action - set action on pf channel
 120 * @hwif: the HW interface of a pci function device
 121 * @action: action on pf channel
 122 *
 123 * Return 0 - Success, negative - Failure
 124 **/
 125void hinic_set_pf_action(struct hinic_hwif *hwif, enum hinic_pf_action action)
 126{
 127        u32 attr5 = hinic_hwif_read_reg(hwif, HINIC_CSR_FUNC_ATTR5_ADDR);
 128
 129        attr5 = HINIC_FA5_CLEAR(attr5, PF_ACTION);
 130        attr5 |= HINIC_FA5_SET(action, PF_ACTION);
 131
 132        hinic_hwif_write_reg(hwif, HINIC_CSR_FUNC_ATTR5_ADDR, attr5);
 133}
 134
 135enum hinic_outbound_state hinic_outbound_state_get(struct hinic_hwif *hwif)
 136{
 137        u32 attr4 = hinic_hwif_read_reg(hwif, HINIC_CSR_FUNC_ATTR4_ADDR);
 138
 139        return HINIC_FA4_GET(attr4, OUTBOUND_STATE);
 140}
 141
 142void hinic_outbound_state_set(struct hinic_hwif *hwif,
 143                              enum hinic_outbound_state outbound_state)
 144{
 145        u32 attr4 = hinic_hwif_read_reg(hwif, HINIC_CSR_FUNC_ATTR4_ADDR);
 146
 147        attr4 = HINIC_FA4_CLEAR(attr4, OUTBOUND_STATE);
 148        attr4 |= HINIC_FA4_SET(outbound_state, OUTBOUND_STATE);
 149
 150        hinic_hwif_write_reg(hwif, HINIC_CSR_FUNC_ATTR4_ADDR, attr4);
 151}
 152
 153enum hinic_db_state hinic_db_state_get(struct hinic_hwif *hwif)
 154{
 155        u32 attr4 = hinic_hwif_read_reg(hwif, HINIC_CSR_FUNC_ATTR4_ADDR);
 156
 157        return HINIC_FA4_GET(attr4, DB_STATE);
 158}
 159
 160void hinic_db_state_set(struct hinic_hwif *hwif,
 161                        enum hinic_db_state db_state)
 162{
 163        u32 attr4 = hinic_hwif_read_reg(hwif, HINIC_CSR_FUNC_ATTR4_ADDR);
 164
 165        attr4 = HINIC_FA4_CLEAR(attr4, DB_STATE);
 166        attr4 |= HINIC_FA4_SET(db_state, DB_STATE);
 167
 168        hinic_hwif_write_reg(hwif, HINIC_CSR_FUNC_ATTR4_ADDR, attr4);
 169}
 170
 171/**
 172 * hwif_ready - test if the HW is ready for use
 173 * @hwif: the HW interface of a pci function device
 174 *
 175 * Return 0 - Success, negative - Failure
 176 **/
 177static int hwif_ready(struct hinic_hwif *hwif)
 178{
 179        struct pci_dev *pdev = hwif->pdev;
 180        u32 addr, attr1;
 181
 182        addr   = HINIC_CSR_FUNC_ATTR1_ADDR;
 183        attr1  = hinic_hwif_read_reg(hwif, addr);
 184
 185        if (!HINIC_FA1_GET(attr1, INIT_STATUS)) {
 186                dev_err(&pdev->dev, "hwif status is not ready\n");
 187                return -EFAULT;
 188        }
 189
 190        return 0;
 191}
 192
 193/**
 194 * set_hwif_attr - set the attributes in the relevant members in hwif
 195 * @hwif: the HW interface of a pci function device
 196 * @attr0: the first attribute that was read from the hw
 197 * @attr1: the second attribute that was read from the hw
 198 **/
 199static void set_hwif_attr(struct hinic_hwif *hwif, u32 attr0, u32 attr1)
 200{
 201        hwif->attr.func_idx     = HINIC_FA0_GET(attr0, FUNC_IDX);
 202        hwif->attr.pf_idx       = HINIC_FA0_GET(attr0, PF_IDX);
 203        hwif->attr.pci_intf_idx = HINIC_FA0_GET(attr0, PCI_INTF_IDX);
 204        hwif->attr.func_type    = HINIC_FA0_GET(attr0, FUNC_TYPE);
 205
 206        hwif->attr.num_aeqs = BIT(HINIC_FA1_GET(attr1, AEQS_PER_FUNC));
 207        hwif->attr.num_ceqs = BIT(HINIC_FA1_GET(attr1, CEQS_PER_FUNC));
 208        hwif->attr.num_irqs = BIT(HINIC_FA1_GET(attr1, IRQS_PER_FUNC));
 209        hwif->attr.num_dma_attr = BIT(HINIC_FA1_GET(attr1, DMA_ATTR_PER_FUNC));
 210}
 211
 212/**
 213 * read_hwif_attr - read the attributes and set members in hwif
 214 * @hwif: the HW interface of a pci function device
 215 **/
 216static void read_hwif_attr(struct hinic_hwif *hwif)
 217{
 218        u32 addr, attr0, attr1;
 219
 220        addr   = HINIC_CSR_FUNC_ATTR0_ADDR;
 221        attr0  = hinic_hwif_read_reg(hwif, addr);
 222
 223        addr   = HINIC_CSR_FUNC_ATTR1_ADDR;
 224        attr1  = hinic_hwif_read_reg(hwif, addr);
 225
 226        set_hwif_attr(hwif, attr0, attr1);
 227}
 228
 229/**
 230 * set_ppf - try to set hwif as ppf and set the type of hwif in this case
 231 * @hwif: the HW interface of a pci function device
 232 **/
 233static void set_ppf(struct hinic_hwif *hwif)
 234{
 235        struct hinic_func_attr *attr = &hwif->attr;
 236        u32 addr, val, ppf_election;
 237
 238        /* Read Modify Write */
 239        addr = HINIC_CSR_PPF_ELECTION_ADDR(HINIC_HWIF_PCI_INTF(hwif));
 240
 241        val = hinic_hwif_read_reg(hwif, addr);
 242        val = HINIC_PPF_ELECTION_CLEAR(val, IDX);
 243
 244        ppf_election = HINIC_PPF_ELECTION_SET(HINIC_HWIF_FUNC_IDX(hwif), IDX);
 245
 246        val |= ppf_election;
 247        hinic_hwif_write_reg(hwif, addr, val);
 248
 249        /* check PPF */
 250        val = hinic_hwif_read_reg(hwif, addr);
 251
 252        attr->ppf_idx = HINIC_PPF_ELECTION_GET(val, IDX);
 253        if (attr->ppf_idx == HINIC_HWIF_FUNC_IDX(hwif))
 254                attr->func_type = HINIC_PPF;
 255}
 256
 257/**
 258 * set_dma_attr - set the dma attributes in the HW
 259 * @hwif: the HW interface of a pci function device
 260 * @entry_idx: the entry index in the dma table
 261 * @st: PCIE TLP steering tag
 262 * @at: PCIE TLP AT field
 263 * @ph: PCIE TLP Processing Hint field
 264 * @no_snooping: PCIE TLP No snooping
 265 * @tph_en: PCIE TLP Processing Hint Enable
 266 **/
 267static void set_dma_attr(struct hinic_hwif *hwif, u32 entry_idx,
 268                         u8 st, u8 at, u8 ph,
 269                         enum hinic_pcie_nosnoop no_snooping,
 270                         enum hinic_pcie_tph tph_en)
 271{
 272        u32 addr, val, dma_attr_entry;
 273
 274        /* Read Modify Write */
 275        addr = HINIC_CSR_DMA_ATTR_ADDR(entry_idx);
 276
 277        val = hinic_hwif_read_reg(hwif, addr);
 278        val = HINIC_DMA_ATTR_CLEAR(val, ST)             &
 279              HINIC_DMA_ATTR_CLEAR(val, AT)             &
 280              HINIC_DMA_ATTR_CLEAR(val, PH)             &
 281              HINIC_DMA_ATTR_CLEAR(val, NO_SNOOPING)    &
 282              HINIC_DMA_ATTR_CLEAR(val, TPH_EN);
 283
 284        dma_attr_entry = HINIC_DMA_ATTR_SET(st, ST)                     |
 285                         HINIC_DMA_ATTR_SET(at, AT)                     |
 286                         HINIC_DMA_ATTR_SET(ph, PH)                     |
 287                         HINIC_DMA_ATTR_SET(no_snooping, NO_SNOOPING)   |
 288                         HINIC_DMA_ATTR_SET(tph_en, TPH_EN);
 289
 290        val |= dma_attr_entry;
 291        hinic_hwif_write_reg(hwif, addr, val);
 292}
 293
 294/**
 295 * dma_attr_table_init - initialize the the default dma attributes
 296 * @hwif: the HW interface of a pci function device
 297 **/
 298static void dma_attr_init(struct hinic_hwif *hwif)
 299{
 300        set_dma_attr(hwif, PCIE_ATTR_ENTRY, HINIC_PCIE_ST_DISABLE,
 301                     HINIC_PCIE_AT_DISABLE, HINIC_PCIE_PH_DISABLE,
 302                     HINIC_PCIE_SNOOP, HINIC_PCIE_TPH_DISABLE);
 303}
 304
 305/**
 306 * hinic_init_hwif - initialize the hw interface
 307 * @hwif: the HW interface of a pci function device
 308 * @pdev: the pci device for acessing PCI resources
 309 *
 310 * Return 0 - Success, negative - Failure
 311 **/
 312int hinic_init_hwif(struct hinic_hwif *hwif, struct pci_dev *pdev)
 313{
 314        int err;
 315
 316        hwif->pdev = pdev;
 317
 318        hwif->cfg_regs_bar = pci_ioremap_bar(pdev, HINIC_PCI_CFG_REGS_BAR);
 319        if (!hwif->cfg_regs_bar) {
 320                dev_err(&pdev->dev, "Failed to map configuration regs\n");
 321                return -ENOMEM;
 322        }
 323
 324        err = hwif_ready(hwif);
 325        if (err) {
 326                dev_err(&pdev->dev, "HW interface is not ready\n");
 327                goto err_hwif_ready;
 328        }
 329
 330        read_hwif_attr(hwif);
 331
 332        if (HINIC_IS_PF(hwif))
 333                set_ppf(hwif);
 334
 335        /* No transactionss before DMA is initialized */
 336        dma_attr_init(hwif);
 337        return 0;
 338
 339err_hwif_ready:
 340        iounmap(hwif->cfg_regs_bar);
 341        return err;
 342}
 343
 344/**
 345 * hinic_free_hwif - free the HW interface
 346 * @hwif: the HW interface of a pci function device
 347 **/
 348void hinic_free_hwif(struct hinic_hwif *hwif)
 349{
 350        iounmap(hwif->cfg_regs_bar);
 351}
 352