linux/drivers/vdpa/ifcvf/ifcvf_base.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Intel IFC VF NIC driver for virtio dataplane offloading
   4 *
   5 * Copyright (C) 2020 Intel Corporation.
   6 *
   7 * Author: Zhu Lingshan <lingshan.zhu@intel.com>
   8 *
   9 */
  10
  11#include "ifcvf_base.h"
  12
  13static inline u8 ifc_ioread8(u8 __iomem *addr)
  14{
  15        return ioread8(addr);
  16}
  17static inline u16 ifc_ioread16 (__le16 __iomem *addr)
  18{
  19        return ioread16(addr);
  20}
  21
  22static inline u32 ifc_ioread32(__le32 __iomem *addr)
  23{
  24        return ioread32(addr);
  25}
  26
  27static inline void ifc_iowrite8(u8 value, u8 __iomem *addr)
  28{
  29        iowrite8(value, addr);
  30}
  31
  32static inline void ifc_iowrite16(u16 value, __le16 __iomem *addr)
  33{
  34        iowrite16(value, addr);
  35}
  36
  37static inline void ifc_iowrite32(u32 value, __le32 __iomem *addr)
  38{
  39        iowrite32(value, addr);
  40}
  41
  42static void ifc_iowrite64_twopart(u64 val,
  43                                  __le32 __iomem *lo, __le32 __iomem *hi)
  44{
  45        ifc_iowrite32((u32)val, lo);
  46        ifc_iowrite32(val >> 32, hi);
  47}
  48
  49struct ifcvf_adapter *vf_to_adapter(struct ifcvf_hw *hw)
  50{
  51        return container_of(hw, struct ifcvf_adapter, vf);
  52}
  53
  54static void __iomem *get_cap_addr(struct ifcvf_hw *hw,
  55                                  struct virtio_pci_cap *cap)
  56{
  57        struct ifcvf_adapter *ifcvf;
  58        struct pci_dev *pdev;
  59        u32 length, offset;
  60        u8 bar;
  61
  62        length = le32_to_cpu(cap->length);
  63        offset = le32_to_cpu(cap->offset);
  64        bar = cap->bar;
  65
  66        ifcvf= vf_to_adapter(hw);
  67        pdev = ifcvf->pdev;
  68
  69        if (bar >= IFCVF_PCI_MAX_RESOURCE) {
  70                IFCVF_DBG(pdev,
  71                          "Invalid bar number %u to get capabilities\n", bar);
  72                return NULL;
  73        }
  74
  75        if (offset + length > pci_resource_len(pdev, bar)) {
  76                IFCVF_DBG(pdev,
  77                          "offset(%u) + len(%u) overflows bar%u's capability\n",
  78                          offset, length, bar);
  79                return NULL;
  80        }
  81
  82        return hw->base[bar] + offset;
  83}
  84
  85static int ifcvf_read_config_range(struct pci_dev *dev,
  86                                   uint32_t *val, int size, int where)
  87{
  88        int ret, i;
  89
  90        for (i = 0; i < size; i += 4) {
  91                ret = pci_read_config_dword(dev, where + i, val + i / 4);
  92                if (ret < 0)
  93                        return ret;
  94        }
  95
  96        return 0;
  97}
  98
  99int ifcvf_init_hw(struct ifcvf_hw *hw, struct pci_dev *pdev)
 100{
 101        struct virtio_pci_cap cap;
 102        u16 notify_off;
 103        int ret;
 104        u8 pos;
 105        u32 i;
 106
 107        ret = pci_read_config_byte(pdev, PCI_CAPABILITY_LIST, &pos);
 108        if (ret < 0) {
 109                IFCVF_ERR(pdev, "Failed to read PCI capability list\n");
 110                return -EIO;
 111        }
 112
 113        while (pos) {
 114                ret = ifcvf_read_config_range(pdev, (u32 *)&cap,
 115                                              sizeof(cap), pos);
 116                if (ret < 0) {
 117                        IFCVF_ERR(pdev,
 118                                  "Failed to get PCI capability at %x\n", pos);
 119                        break;
 120                }
 121
 122                if (cap.cap_vndr != PCI_CAP_ID_VNDR)
 123                        goto next;
 124
 125                switch (cap.cfg_type) {
 126                case VIRTIO_PCI_CAP_COMMON_CFG:
 127                        hw->common_cfg = get_cap_addr(hw, &cap);
 128                        IFCVF_DBG(pdev, "hw->common_cfg = %p\n",
 129                                  hw->common_cfg);
 130                        break;
 131                case VIRTIO_PCI_CAP_NOTIFY_CFG:
 132                        pci_read_config_dword(pdev, pos + sizeof(cap),
 133                                              &hw->notify_off_multiplier);
 134                        hw->notify_bar = cap.bar;
 135                        hw->notify_base = get_cap_addr(hw, &cap);
 136                        hw->notify_base_pa = pci_resource_start(pdev, cap.bar) +
 137                                        le32_to_cpu(cap.offset);
 138                        IFCVF_DBG(pdev, "hw->notify_base = %p\n",
 139                                  hw->notify_base);
 140                        break;
 141                case VIRTIO_PCI_CAP_ISR_CFG:
 142                        hw->isr = get_cap_addr(hw, &cap);
 143                        IFCVF_DBG(pdev, "hw->isr = %p\n", hw->isr);
 144                        break;
 145                case VIRTIO_PCI_CAP_DEVICE_CFG:
 146                        hw->net_cfg = get_cap_addr(hw, &cap);
 147                        IFCVF_DBG(pdev, "hw->net_cfg = %p\n", hw->net_cfg);
 148                        break;
 149                }
 150
 151next:
 152                pos = cap.cap_next;
 153        }
 154
 155        if (hw->common_cfg == NULL || hw->notify_base == NULL ||
 156            hw->isr == NULL || hw->net_cfg == NULL) {
 157                IFCVF_ERR(pdev, "Incomplete PCI capabilities\n");
 158                return -EIO;
 159        }
 160
 161        for (i = 0; i < IFCVF_MAX_QUEUE_PAIRS * 2; i++) {
 162                ifc_iowrite16(i, &hw->common_cfg->queue_select);
 163                notify_off = ifc_ioread16(&hw->common_cfg->queue_notify_off);
 164                hw->vring[i].notify_addr = hw->notify_base +
 165                        notify_off * hw->notify_off_multiplier;
 166                hw->vring[i].notify_pa = hw->notify_base_pa +
 167                        notify_off * hw->notify_off_multiplier;
 168        }
 169
 170        hw->lm_cfg = hw->base[IFCVF_LM_BAR];
 171
 172        IFCVF_DBG(pdev,
 173                  "PCI capability mapping: common cfg: %p, notify base: %p\n, isr cfg: %p, device cfg: %p, multiplier: %u\n",
 174                  hw->common_cfg, hw->notify_base, hw->isr,
 175                  hw->net_cfg, hw->notify_off_multiplier);
 176
 177        return 0;
 178}
 179
 180u8 ifcvf_get_status(struct ifcvf_hw *hw)
 181{
 182        return ifc_ioread8(&hw->common_cfg->device_status);
 183}
 184
 185void ifcvf_set_status(struct ifcvf_hw *hw, u8 status)
 186{
 187        ifc_iowrite8(status, &hw->common_cfg->device_status);
 188}
 189
 190void ifcvf_reset(struct ifcvf_hw *hw)
 191{
 192        hw->config_cb.callback = NULL;
 193        hw->config_cb.private = NULL;
 194
 195        ifcvf_set_status(hw, 0);
 196        /* flush set_status, make sure VF is stopped, reset */
 197        ifcvf_get_status(hw);
 198}
 199
 200static void ifcvf_add_status(struct ifcvf_hw *hw, u8 status)
 201{
 202        if (status != 0)
 203                status |= ifcvf_get_status(hw);
 204
 205        ifcvf_set_status(hw, status);
 206        ifcvf_get_status(hw);
 207}
 208
 209u64 ifcvf_get_hw_features(struct ifcvf_hw *hw)
 210{
 211        struct virtio_pci_common_cfg __iomem *cfg = hw->common_cfg;
 212        u32 features_lo, features_hi;
 213        u64 features;
 214
 215        ifc_iowrite32(0, &cfg->device_feature_select);
 216        features_lo = ifc_ioread32(&cfg->device_feature);
 217
 218        ifc_iowrite32(1, &cfg->device_feature_select);
 219        features_hi = ifc_ioread32(&cfg->device_feature);
 220
 221        features = ((u64)features_hi << 32) | features_lo;
 222
 223        return features;
 224}
 225
 226u64 ifcvf_get_features(struct ifcvf_hw *hw)
 227{
 228        return hw->hw_features;
 229}
 230
 231int ifcvf_verify_min_features(struct ifcvf_hw *hw, u64 features)
 232{
 233        struct ifcvf_adapter *ifcvf = vf_to_adapter(hw);
 234
 235        if (!(features & BIT_ULL(VIRTIO_F_ACCESS_PLATFORM)) && features) {
 236                IFCVF_ERR(ifcvf->pdev, "VIRTIO_F_ACCESS_PLATFORM is not negotiated\n");
 237                return -EINVAL;
 238        }
 239
 240        return 0;
 241}
 242
 243void ifcvf_read_net_config(struct ifcvf_hw *hw, u64 offset,
 244                           void *dst, int length)
 245{
 246        u8 old_gen, new_gen, *p;
 247        int i;
 248
 249        WARN_ON(offset + length > sizeof(struct virtio_net_config));
 250        do {
 251                old_gen = ifc_ioread8(&hw->common_cfg->config_generation);
 252                p = dst;
 253                for (i = 0; i < length; i++)
 254                        *p++ = ifc_ioread8(hw->net_cfg + offset + i);
 255
 256                new_gen = ifc_ioread8(&hw->common_cfg->config_generation);
 257        } while (old_gen != new_gen);
 258}
 259
 260void ifcvf_write_net_config(struct ifcvf_hw *hw, u64 offset,
 261                            const void *src, int length)
 262{
 263        const u8 *p;
 264        int i;
 265
 266        p = src;
 267        WARN_ON(offset + length > sizeof(struct virtio_net_config));
 268        for (i = 0; i < length; i++)
 269                ifc_iowrite8(*p++, hw->net_cfg + offset + i);
 270}
 271
 272static void ifcvf_set_features(struct ifcvf_hw *hw, u64 features)
 273{
 274        struct virtio_pci_common_cfg __iomem *cfg = hw->common_cfg;
 275
 276        ifc_iowrite32(0, &cfg->guest_feature_select);
 277        ifc_iowrite32((u32)features, &cfg->guest_feature);
 278
 279        ifc_iowrite32(1, &cfg->guest_feature_select);
 280        ifc_iowrite32(features >> 32, &cfg->guest_feature);
 281}
 282
 283static int ifcvf_config_features(struct ifcvf_hw *hw)
 284{
 285        struct ifcvf_adapter *ifcvf;
 286
 287        ifcvf = vf_to_adapter(hw);
 288        ifcvf_set_features(hw, hw->req_features);
 289        ifcvf_add_status(hw, VIRTIO_CONFIG_S_FEATURES_OK);
 290
 291        if (!(ifcvf_get_status(hw) & VIRTIO_CONFIG_S_FEATURES_OK)) {
 292                IFCVF_ERR(ifcvf->pdev, "Failed to set FEATURES_OK status\n");
 293                return -EIO;
 294        }
 295
 296        return 0;
 297}
 298
 299u16 ifcvf_get_vq_state(struct ifcvf_hw *hw, u16 qid)
 300{
 301        struct ifcvf_lm_cfg __iomem *ifcvf_lm;
 302        void __iomem *avail_idx_addr;
 303        u16 last_avail_idx;
 304        u32 q_pair_id;
 305
 306        ifcvf_lm = (struct ifcvf_lm_cfg __iomem *)hw->lm_cfg;
 307        q_pair_id = qid / (IFCVF_MAX_QUEUE_PAIRS * 2);
 308        avail_idx_addr = &ifcvf_lm->vring_lm_cfg[q_pair_id].idx_addr[qid % 2];
 309        last_avail_idx = ifc_ioread16(avail_idx_addr);
 310
 311        return last_avail_idx;
 312}
 313
 314int ifcvf_set_vq_state(struct ifcvf_hw *hw, u16 qid, u16 num)
 315{
 316        struct ifcvf_lm_cfg __iomem *ifcvf_lm;
 317        void __iomem *avail_idx_addr;
 318        u32 q_pair_id;
 319
 320        ifcvf_lm = (struct ifcvf_lm_cfg __iomem *)hw->lm_cfg;
 321        q_pair_id = qid / (IFCVF_MAX_QUEUE_PAIRS * 2);
 322        avail_idx_addr = &ifcvf_lm->vring_lm_cfg[q_pair_id].idx_addr[qid % 2];
 323        hw->vring[qid].last_avail_idx = num;
 324        ifc_iowrite16(num, avail_idx_addr);
 325
 326        return 0;
 327}
 328
 329static int ifcvf_hw_enable(struct ifcvf_hw *hw)
 330{
 331        struct virtio_pci_common_cfg __iomem *cfg;
 332        struct ifcvf_adapter *ifcvf;
 333        u32 i;
 334
 335        ifcvf = vf_to_adapter(hw);
 336        cfg = hw->common_cfg;
 337        ifc_iowrite16(IFCVF_MSI_CONFIG_OFF, &cfg->msix_config);
 338
 339        if (ifc_ioread16(&cfg->msix_config) == VIRTIO_MSI_NO_VECTOR) {
 340                IFCVF_ERR(ifcvf->pdev, "No msix vector for device config\n");
 341                return -EINVAL;
 342        }
 343
 344        for (i = 0; i < hw->nr_vring; i++) {
 345                if (!hw->vring[i].ready)
 346                        break;
 347
 348                ifc_iowrite16(i, &cfg->queue_select);
 349                ifc_iowrite64_twopart(hw->vring[i].desc, &cfg->queue_desc_lo,
 350                                     &cfg->queue_desc_hi);
 351                ifc_iowrite64_twopart(hw->vring[i].avail, &cfg->queue_avail_lo,
 352                                      &cfg->queue_avail_hi);
 353                ifc_iowrite64_twopart(hw->vring[i].used, &cfg->queue_used_lo,
 354                                     &cfg->queue_used_hi);
 355                ifc_iowrite16(hw->vring[i].size, &cfg->queue_size);
 356                ifc_iowrite16(i + IFCVF_MSI_QUEUE_OFF, &cfg->queue_msix_vector);
 357
 358                if (ifc_ioread16(&cfg->queue_msix_vector) ==
 359                    VIRTIO_MSI_NO_VECTOR) {
 360                        IFCVF_ERR(ifcvf->pdev,
 361                                  "No msix vector for queue %u\n", i);
 362                        return -EINVAL;
 363                }
 364
 365                ifcvf_set_vq_state(hw, i, hw->vring[i].last_avail_idx);
 366                ifc_iowrite16(1, &cfg->queue_enable);
 367        }
 368
 369        return 0;
 370}
 371
 372static void ifcvf_hw_disable(struct ifcvf_hw *hw)
 373{
 374        struct virtio_pci_common_cfg __iomem *cfg;
 375        u32 i;
 376
 377        cfg = hw->common_cfg;
 378        ifc_iowrite16(VIRTIO_MSI_NO_VECTOR, &cfg->msix_config);
 379
 380        for (i = 0; i < hw->nr_vring; i++) {
 381                ifc_iowrite16(i, &cfg->queue_select);
 382                ifc_iowrite16(VIRTIO_MSI_NO_VECTOR, &cfg->queue_msix_vector);
 383        }
 384
 385        ifc_ioread16(&cfg->queue_msix_vector);
 386}
 387
 388int ifcvf_start_hw(struct ifcvf_hw *hw)
 389{
 390        ifcvf_reset(hw);
 391        ifcvf_add_status(hw, VIRTIO_CONFIG_S_ACKNOWLEDGE);
 392        ifcvf_add_status(hw, VIRTIO_CONFIG_S_DRIVER);
 393
 394        if (ifcvf_config_features(hw) < 0)
 395                return -EINVAL;
 396
 397        if (ifcvf_hw_enable(hw) < 0)
 398                return -EINVAL;
 399
 400        ifcvf_add_status(hw, VIRTIO_CONFIG_S_DRIVER_OK);
 401
 402        return 0;
 403}
 404
 405void ifcvf_stop_hw(struct ifcvf_hw *hw)
 406{
 407        ifcvf_hw_disable(hw);
 408        ifcvf_reset(hw);
 409}
 410
 411void ifcvf_notify_queue(struct ifcvf_hw *hw, u16 qid)
 412{
 413        ifc_iowrite16(qid, hw->vring[qid].notify_addr);
 414}
 415