101f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman/* 229046f9b1e36f6e3332ce2d8e366005fd177b37aVasanthy Kolluri * Copyright 2008-2010 Cisco Systems, Inc. All rights reserved. 301f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman * Copyright 2007 Nuova Systems, Inc. All rights reserved. 401f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman * 501f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman * This program is free software; you may redistribute it and/or modify 601f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman * it under the terms of the GNU General Public License as published by 701f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman * the Free Software Foundation; version 2 of the License. 801f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman * 901f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 1001f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 1101f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 1201f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 1301f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 1401f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 1501f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 1601f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman * SOFTWARE. 1701f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman * 1801f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman */ 1901f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman 2001f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman#include <linux/kernel.h> 2101f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman#include <linux/errno.h> 2201f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman#include <linux/types.h> 2301f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman#include <linux/pci.h> 2401f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman#include <linux/delay.h> 255a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 2601f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman 2701f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman#include "vnic_dev.h" 2801f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman#include "vnic_wq.h" 2901f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman 3001f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldmanstatic int vnic_wq_alloc_bufs(struct vnic_wq *wq) 3101f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman{ 3201f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman struct vnic_wq_buf *buf; 3301f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman struct vnic_dev *vdev; 3401f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman unsigned int i, j, count = wq->ring.desc_count; 3501f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman unsigned int blks = VNIC_WQ_BUF_BLKS_NEEDED(count); 3601f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman 3701f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman vdev = wq->vdev; 3801f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman 3901f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman for (i = 0; i < blks; i++) { 40b5bab85c15ed3d1ae7f917a7c077086ac6c04572Vasanthy Kolluri wq->bufs[i] = kzalloc(VNIC_WQ_BUF_BLK_SZ(count), GFP_ATOMIC); 41e404decb0fb017be80552adee894b35307b6c7b4Joe Perches if (!wq->bufs[i]) 4201f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman return -ENOMEM; 4301f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman } 4401f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman 4501f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman for (i = 0; i < blks; i++) { 4601f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman buf = wq->bufs[i]; 47b5bab85c15ed3d1ae7f917a7c077086ac6c04572Vasanthy Kolluri for (j = 0; j < VNIC_WQ_BUF_BLK_ENTRIES(count); j++) { 48b5bab85c15ed3d1ae7f917a7c077086ac6c04572Vasanthy Kolluri buf->index = i * VNIC_WQ_BUF_BLK_ENTRIES(count) + j; 4901f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman buf->desc = (u8 *)wq->ring.descs + 5001f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman wq->ring.desc_size * buf->index; 5101f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman if (buf->index + 1 == count) { 5201f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman buf->next = wq->bufs[0]; 5301f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman break; 54b5bab85c15ed3d1ae7f917a7c077086ac6c04572Vasanthy Kolluri } else if (j + 1 == VNIC_WQ_BUF_BLK_ENTRIES(count)) { 5501f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman buf->next = wq->bufs[i + 1]; 5601f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman } else { 5701f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman buf->next = buf + 1; 5801f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman buf++; 5901f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman } 6001f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman } 6101f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman } 6201f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman 6301f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman wq->to_use = wq->to_clean = wq->bufs[0]; 6401f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman 6501f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman return 0; 6601f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman} 6701f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman 6801f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldmanvoid vnic_wq_free(struct vnic_wq *wq) 6901f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman{ 7001f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman struct vnic_dev *vdev; 7101f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman unsigned int i; 7201f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman 7301f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman vdev = wq->vdev; 7401f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman 7501f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman vnic_dev_free_desc_ring(vdev, &wq->ring); 7601f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman 7701f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman for (i = 0; i < VNIC_WQ_BUF_BLKS_MAX; i++) { 78832177901a61aeda1f2122e323c39881ec84af65Roopa Prabhu if (wq->bufs[i]) { 79832177901a61aeda1f2122e323c39881ec84af65Roopa Prabhu kfree(wq->bufs[i]); 80832177901a61aeda1f2122e323c39881ec84af65Roopa Prabhu wq->bufs[i] = NULL; 81832177901a61aeda1f2122e323c39881ec84af65Roopa Prabhu } 8201f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman } 8301f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman 8401f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman wq->ctrl = NULL; 8501f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman} 8601f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman 8701f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldmanint vnic_wq_alloc(struct vnic_dev *vdev, struct vnic_wq *wq, unsigned int index, 8801f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman unsigned int desc_count, unsigned int desc_size) 8901f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman{ 9001f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman int err; 9101f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman 9201f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman wq->index = index; 9301f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman wq->vdev = vdev; 9401f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman 9501f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman wq->ctrl = vnic_dev_get_res(vdev, RES_TYPE_WQ, index); 9601f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman if (!wq->ctrl) { 97a7a79debcca02fbf908c0abed8d8fb25d0e51b48Vasanthy Kolluri pr_err("Failed to hook WQ[%d] resource\n", index); 9801f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman return -EINVAL; 9901f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman } 10001f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman 10101f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman vnic_wq_disable(wq); 10201f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman 10301f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman err = vnic_dev_alloc_desc_ring(vdev, &wq->ring, desc_count, desc_size); 10401f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman if (err) 10501f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman return err; 10601f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman 10701f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman err = vnic_wq_alloc_bufs(wq); 10801f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman if (err) { 10901f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman vnic_wq_free(wq); 11001f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman return err; 11101f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman } 11201f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman 11301f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman return 0; 11401f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman} 11501f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman 1162fdba3881154ee91927af7d7436d54eb05dcc3bfVasanthy Kolluristatic void vnic_wq_init_start(struct vnic_wq *wq, unsigned int cq_index, 1176fdfa97073a2bcbb60d900654c612b2ff09b9cb7Scott Feldman unsigned int fetch_index, unsigned int posted_index, 11801f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman unsigned int error_interrupt_enable, 11901f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman unsigned int error_interrupt_offset) 12001f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman{ 12101f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman u64 paddr; 122b5bab85c15ed3d1ae7f917a7c077086ac6c04572Vasanthy Kolluri unsigned int count = wq->ring.desc_count; 12301f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman 12401f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman paddr = (u64)wq->ring.base_addr | VNIC_PADDR_TARGET; 12501f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman writeq(paddr, &wq->ctrl->ring_base); 126b5bab85c15ed3d1ae7f917a7c077086ac6c04572Vasanthy Kolluri iowrite32(count, &wq->ctrl->ring_size); 1276fdfa97073a2bcbb60d900654c612b2ff09b9cb7Scott Feldman iowrite32(fetch_index, &wq->ctrl->fetch_index); 1286fdfa97073a2bcbb60d900654c612b2ff09b9cb7Scott Feldman iowrite32(posted_index, &wq->ctrl->posted_index); 12901f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman iowrite32(cq_index, &wq->ctrl->cq_index); 13001f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman iowrite32(error_interrupt_enable, &wq->ctrl->error_interrupt_enable); 13101f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman iowrite32(error_interrupt_offset, &wq->ctrl->error_interrupt_offset); 13201f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman iowrite32(0, &wq->ctrl->error_status); 1336fdfa97073a2bcbb60d900654c612b2ff09b9cb7Scott Feldman 1346fdfa97073a2bcbb60d900654c612b2ff09b9cb7Scott Feldman wq->to_use = wq->to_clean = 135b5bab85c15ed3d1ae7f917a7c077086ac6c04572Vasanthy Kolluri &wq->bufs[fetch_index / VNIC_WQ_BUF_BLK_ENTRIES(count)] 136b5bab85c15ed3d1ae7f917a7c077086ac6c04572Vasanthy Kolluri [fetch_index % VNIC_WQ_BUF_BLK_ENTRIES(count)]; 1376fdfa97073a2bcbb60d900654c612b2ff09b9cb7Scott Feldman} 1386fdfa97073a2bcbb60d900654c612b2ff09b9cb7Scott Feldman 1396fdfa97073a2bcbb60d900654c612b2ff09b9cb7Scott Feldmanvoid vnic_wq_init(struct vnic_wq *wq, unsigned int cq_index, 1406fdfa97073a2bcbb60d900654c612b2ff09b9cb7Scott Feldman unsigned int error_interrupt_enable, 1416fdfa97073a2bcbb60d900654c612b2ff09b9cb7Scott Feldman unsigned int error_interrupt_offset) 1426fdfa97073a2bcbb60d900654c612b2ff09b9cb7Scott Feldman{ 1436fdfa97073a2bcbb60d900654c612b2ff09b9cb7Scott Feldman vnic_wq_init_start(wq, cq_index, 0, 0, 1446fdfa97073a2bcbb60d900654c612b2ff09b9cb7Scott Feldman error_interrupt_enable, 1456fdfa97073a2bcbb60d900654c612b2ff09b9cb7Scott Feldman error_interrupt_offset); 14601f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman} 14701f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman 14801f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldmanunsigned int vnic_wq_error_status(struct vnic_wq *wq) 14901f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman{ 15001f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman return ioread32(&wq->ctrl->error_status); 15101f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman} 15201f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman 15301f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldmanvoid vnic_wq_enable(struct vnic_wq *wq) 15401f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman{ 15501f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman iowrite32(1, &wq->ctrl->enable); 15601f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman} 15701f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman 15801f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldmanint vnic_wq_disable(struct vnic_wq *wq) 15901f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman{ 16001f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman unsigned int wait; 16101f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman 16201f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman iowrite32(0, &wq->ctrl->enable); 16301f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman 16401f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman /* Wait for HW to ACK disable request */ 165b6d24eb663cdf4af9c08b37ad2e31056c5eb2561Vasanthy Kolluri for (wait = 0; wait < 1000; wait++) { 16601f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman if (!(ioread32(&wq->ctrl->running))) 16701f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman return 0; 168b6d24eb663cdf4af9c08b37ad2e31056c5eb2561Vasanthy Kolluri udelay(10); 16901f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman } 17001f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman 171a7a79debcca02fbf908c0abed8d8fb25d0e51b48Vasanthy Kolluri pr_err("Failed to disable WQ[%d]\n", wq->index); 17201f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman 17301f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman return -ETIMEDOUT; 17401f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman} 17501f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman 17601f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldmanvoid vnic_wq_clean(struct vnic_wq *wq, 17701f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman void (*buf_clean)(struct vnic_wq *wq, struct vnic_wq_buf *buf)) 17801f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman{ 17901f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman struct vnic_wq_buf *buf; 18001f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman 18101f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman buf = wq->to_clean; 18201f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman 18301f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman while (vnic_wq_desc_used(wq) > 0) { 18401f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman 18501f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman (*buf_clean)(wq, buf); 18601f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman 18701f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman buf = wq->to_clean = buf->next; 18801f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman wq->ring.desc_avail++; 18901f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman } 19001f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman 19101f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman wq->to_use = wq->to_clean = wq->bufs[0]; 19201f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman 19301f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman iowrite32(0, &wq->ctrl->fetch_index); 19401f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman iowrite32(0, &wq->ctrl->posted_index); 19501f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman iowrite32(0, &wq->ctrl->error_status); 19601f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman 19701f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman vnic_dev_clear_desc_ring(&wq->ring); 19801f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman} 199