linux/drivers/scsi/snic/vnic_wq.c
<<
>>
Prefs
   1/*
   2 * Copyright 2014 Cisco Systems, Inc.  All rights reserved.
   3 *
   4 * This program is free software; you may redistribute it and/or modify
   5 * it under the terms of the GNU General Public License as published by
   6 * the Free Software Foundation; version 2 of the License.
   7 *
   8 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
   9 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  10 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  11 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
  12 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  13 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  14 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  15 * SOFTWARE.
  16 */
  17
  18#include <linux/errno.h>
  19#include <linux/types.h>
  20#include <linux/pci.h>
  21#include <linux/delay.h>
  22#include <linux/slab.h>
  23#include "vnic_dev.h"
  24#include "vnic_wq.h"
  25
  26static inline int vnic_wq_get_ctrl(struct vnic_dev *vdev, struct vnic_wq *wq,
  27        unsigned int index, enum vnic_res_type res_type)
  28{
  29        wq->ctrl = svnic_dev_get_res(vdev, res_type, index);
  30        if (!wq->ctrl)
  31                return -EINVAL;
  32
  33        return 0;
  34}
  35
  36static inline int vnic_wq_alloc_ring(struct vnic_dev *vdev, struct vnic_wq *wq,
  37        unsigned int index, unsigned int desc_count, unsigned int desc_size)
  38{
  39        return svnic_dev_alloc_desc_ring(vdev, &wq->ring, desc_count,
  40                                         desc_size);
  41}
  42
  43static int vnic_wq_alloc_bufs(struct vnic_wq *wq)
  44{
  45        struct vnic_wq_buf *buf;
  46        unsigned int i, j, count = wq->ring.desc_count;
  47        unsigned int blks = VNIC_WQ_BUF_BLKS_NEEDED(count);
  48
  49        for (i = 0; i < blks; i++) {
  50                wq->bufs[i] = kzalloc(VNIC_WQ_BUF_BLK_SZ, GFP_ATOMIC);
  51                if (!wq->bufs[i]) {
  52                        pr_err("Failed to alloc wq_bufs\n");
  53
  54                        return -ENOMEM;
  55                }
  56        }
  57
  58        for (i = 0; i < blks; i++) {
  59                buf = wq->bufs[i];
  60                for (j = 0; j < VNIC_WQ_BUF_DFLT_BLK_ENTRIES; j++) {
  61                        buf->index = i * VNIC_WQ_BUF_DFLT_BLK_ENTRIES + j;
  62                        buf->desc = (u8 *)wq->ring.descs +
  63                                wq->ring.desc_size * buf->index;
  64                        if (buf->index + 1 == count) {
  65                                buf->next = wq->bufs[0];
  66                                break;
  67                        } else if (j + 1 == VNIC_WQ_BUF_DFLT_BLK_ENTRIES) {
  68                                buf->next = wq->bufs[i + 1];
  69                        } else {
  70                                buf->next = buf + 1;
  71                                buf++;
  72                        }
  73                }
  74        }
  75
  76        wq->to_use = wq->to_clean = wq->bufs[0];
  77
  78        return 0;
  79}
  80
  81void svnic_wq_free(struct vnic_wq *wq)
  82{
  83        struct vnic_dev *vdev;
  84        unsigned int i;
  85
  86        vdev = wq->vdev;
  87
  88        svnic_dev_free_desc_ring(vdev, &wq->ring);
  89
  90        for (i = 0; i < VNIC_WQ_BUF_BLKS_MAX; i++) {
  91                kfree(wq->bufs[i]);
  92                wq->bufs[i] = NULL;
  93        }
  94
  95        wq->ctrl = NULL;
  96
  97}
  98
  99int vnic_wq_devcmd2_alloc(struct vnic_dev *vdev, struct vnic_wq *wq,
 100        unsigned int desc_count, unsigned int desc_size)
 101{
 102        int err;
 103
 104        wq->index = 0;
 105        wq->vdev = vdev;
 106
 107        err = vnic_wq_get_ctrl(vdev, wq, 0, RES_TYPE_DEVCMD2);
 108        if (err) {
 109                pr_err("Failed to get devcmd2 resource\n");
 110
 111                return err;
 112        }
 113
 114        svnic_wq_disable(wq);
 115
 116        err = vnic_wq_alloc_ring(vdev, wq, 0, desc_count, desc_size);
 117        if (err)
 118                return err;
 119
 120        return 0;
 121}
 122
 123int svnic_wq_alloc(struct vnic_dev *vdev, struct vnic_wq *wq,
 124        unsigned int index, unsigned int desc_count, unsigned int desc_size)
 125{
 126        int err;
 127
 128        wq->index = index;
 129        wq->vdev = vdev;
 130
 131        err = vnic_wq_get_ctrl(vdev, wq, index, RES_TYPE_WQ);
 132        if (err) {
 133                pr_err("Failed to hook WQ[%d] resource\n", index);
 134
 135                return err;
 136        }
 137
 138        svnic_wq_disable(wq);
 139
 140        err = vnic_wq_alloc_ring(vdev, wq, index, desc_count, desc_size);
 141        if (err)
 142                return err;
 143
 144        err = vnic_wq_alloc_bufs(wq);
 145        if (err) {
 146                svnic_wq_free(wq);
 147
 148                return err;
 149        }
 150
 151        return 0;
 152}
 153
 154void vnic_wq_init_start(struct vnic_wq *wq, unsigned int cq_index,
 155        unsigned int fetch_index, unsigned int posted_index,
 156        unsigned int error_interrupt_enable,
 157        unsigned int error_interrupt_offset)
 158{
 159        u64 paddr;
 160        unsigned int count = wq->ring.desc_count;
 161
 162        paddr = (u64)wq->ring.base_addr | VNIC_PADDR_TARGET;
 163        writeq(paddr, &wq->ctrl->ring_base);
 164        iowrite32(count, &wq->ctrl->ring_size);
 165        iowrite32(fetch_index, &wq->ctrl->fetch_index);
 166        iowrite32(posted_index, &wq->ctrl->posted_index);
 167        iowrite32(cq_index, &wq->ctrl->cq_index);
 168        iowrite32(error_interrupt_enable, &wq->ctrl->error_interrupt_enable);
 169        iowrite32(error_interrupt_offset, &wq->ctrl->error_interrupt_offset);
 170        iowrite32(0, &wq->ctrl->error_status);
 171
 172        wq->to_use = wq->to_clean =
 173                &wq->bufs[fetch_index / VNIC_WQ_BUF_BLK_ENTRIES(count)]
 174                        [fetch_index % VNIC_WQ_BUF_BLK_ENTRIES(count)];
 175}
 176
 177void svnic_wq_init(struct vnic_wq *wq, unsigned int cq_index,
 178        unsigned int error_interrupt_enable,
 179        unsigned int error_interrupt_offset)
 180{
 181        vnic_wq_init_start(wq, cq_index, 0, 0, error_interrupt_enable,
 182                           error_interrupt_offset);
 183}
 184
 185unsigned int svnic_wq_error_status(struct vnic_wq *wq)
 186{
 187        return ioread32(&wq->ctrl->error_status);
 188}
 189
 190void svnic_wq_enable(struct vnic_wq *wq)
 191{
 192        iowrite32(1, &wq->ctrl->enable);
 193}
 194
 195int svnic_wq_disable(struct vnic_wq *wq)
 196{
 197        unsigned int wait;
 198
 199        iowrite32(0, &wq->ctrl->enable);
 200
 201        /* Wait for HW to ACK disable request */
 202        for (wait = 0; wait < 100; wait++) {
 203                if (!(ioread32(&wq->ctrl->running)))
 204                        return 0;
 205                udelay(1);
 206        }
 207
 208        pr_err("Failed to disable WQ[%d]\n", wq->index);
 209
 210        return -ETIMEDOUT;
 211}
 212
 213void svnic_wq_clean(struct vnic_wq *wq,
 214        void (*buf_clean)(struct vnic_wq *wq, struct vnic_wq_buf *buf))
 215{
 216        struct vnic_wq_buf *buf;
 217
 218        BUG_ON(ioread32(&wq->ctrl->enable));
 219
 220        buf = wq->to_clean;
 221
 222        while (svnic_wq_desc_used(wq) > 0) {
 223
 224                (*buf_clean)(wq, buf);
 225
 226                buf = wq->to_clean = buf->next;
 227                wq->ring.desc_avail++;
 228        }
 229
 230        wq->to_use = wq->to_clean = wq->bufs[0];
 231
 232        iowrite32(0, &wq->ctrl->fetch_index);
 233        iowrite32(0, &wq->ctrl->posted_index);
 234        iowrite32(0, &wq->ctrl->error_status);
 235
 236        svnic_dev_clear_desc_ring(&wq->ring);
 237}
 238