101f2e4eaSScott Feldman /* 229046f9bSVasanthy Kolluri * Copyright 2008-2010 Cisco Systems, Inc. All rights reserved. 301f2e4eaSScott Feldman * Copyright 2007 Nuova Systems, Inc. All rights reserved. 401f2e4eaSScott Feldman * 501f2e4eaSScott Feldman * This program is free software; you may redistribute it and/or modify 601f2e4eaSScott Feldman * it under the terms of the GNU General Public License as published by 701f2e4eaSScott Feldman * the Free Software Foundation; version 2 of the License. 801f2e4eaSScott Feldman * 901f2e4eaSScott Feldman * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 1001f2e4eaSScott Feldman * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 1101f2e4eaSScott Feldman * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 1201f2e4eaSScott Feldman * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 1301f2e4eaSScott Feldman * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 1401f2e4eaSScott Feldman * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 1501f2e4eaSScott Feldman * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 1601f2e4eaSScott Feldman * SOFTWARE. 1701f2e4eaSScott Feldman * 1801f2e4eaSScott Feldman */ 1901f2e4eaSScott Feldman 2001f2e4eaSScott Feldman #include <linux/kernel.h> 2101f2e4eaSScott Feldman #include <linux/errno.h> 2201f2e4eaSScott Feldman #include <linux/types.h> 2301f2e4eaSScott Feldman #include <linux/pci.h> 2401f2e4eaSScott Feldman #include <linux/delay.h> 255a0e3ad6STejun Heo #include <linux/slab.h> 2601f2e4eaSScott Feldman 2701f2e4eaSScott Feldman #include "vnic_dev.h" 2801f2e4eaSScott Feldman #include "vnic_wq.h" 296a3c2f83SGovindarajulu Varadarajan #include "enic.h" 3001f2e4eaSScott Feldman 3101f2e4eaSScott Feldman static int vnic_wq_alloc_bufs(struct vnic_wq *wq) 3201f2e4eaSScott Feldman { 3301f2e4eaSScott Feldman struct vnic_wq_buf *buf; 3401f2e4eaSScott Feldman unsigned int i, j, count = wq->ring.desc_count; 3501f2e4eaSScott Feldman unsigned int blks = VNIC_WQ_BUF_BLKS_NEEDED(count); 3601f2e4eaSScott Feldman 3701f2e4eaSScott Feldman for (i = 0; i < blks; i++) { 38*039b1d5eSJia-Ju Bai wq->bufs[i] = kzalloc(VNIC_WQ_BUF_BLK_SZ(count), GFP_KERNEL); 39e404decbSJoe Perches if (!wq->bufs[i]) 4001f2e4eaSScott Feldman return -ENOMEM; 4101f2e4eaSScott Feldman } 4201f2e4eaSScott Feldman 4301f2e4eaSScott Feldman for (i = 0; i < blks; i++) { 4401f2e4eaSScott Feldman buf = wq->bufs[i]; 45b5bab85cSVasanthy Kolluri for (j = 0; j < VNIC_WQ_BUF_BLK_ENTRIES(count); j++) { 46b5bab85cSVasanthy Kolluri buf->index = i * VNIC_WQ_BUF_BLK_ENTRIES(count) + j; 4701f2e4eaSScott Feldman buf->desc = (u8 *)wq->ring.descs + 4801f2e4eaSScott Feldman wq->ring.desc_size * buf->index; 4901f2e4eaSScott Feldman if (buf->index + 1 == count) { 5001f2e4eaSScott Feldman buf->next = wq->bufs[0]; 515e32066dSGovindarajulu Varadarajan buf->next->prev = buf; 5201f2e4eaSScott Feldman break; 53b5bab85cSVasanthy Kolluri } else if (j + 1 == VNIC_WQ_BUF_BLK_ENTRIES(count)) { 5401f2e4eaSScott Feldman buf->next = wq->bufs[i + 1]; 555e32066dSGovindarajulu Varadarajan buf->next->prev = buf; 5601f2e4eaSScott Feldman } else { 5701f2e4eaSScott Feldman buf->next = buf + 1; 585e32066dSGovindarajulu Varadarajan buf->next->prev = buf; 5901f2e4eaSScott Feldman buf++; 6001f2e4eaSScott Feldman } 6101f2e4eaSScott Feldman } 6201f2e4eaSScott Feldman } 6301f2e4eaSScott Feldman 6401f2e4eaSScott Feldman wq->to_use = wq->to_clean = wq->bufs[0]; 6501f2e4eaSScott Feldman 6601f2e4eaSScott Feldman return 0; 6701f2e4eaSScott Feldman } 6801f2e4eaSScott Feldman 6901f2e4eaSScott Feldman void vnic_wq_free(struct vnic_wq *wq) 7001f2e4eaSScott Feldman { 7101f2e4eaSScott Feldman struct vnic_dev *vdev; 7201f2e4eaSScott Feldman unsigned int i; 7301f2e4eaSScott Feldman 7401f2e4eaSScott Feldman vdev = wq->vdev; 7501f2e4eaSScott Feldman 7601f2e4eaSScott Feldman vnic_dev_free_desc_ring(vdev, &wq->ring); 7701f2e4eaSScott Feldman 7801f2e4eaSScott Feldman for (i = 0; i < VNIC_WQ_BUF_BLKS_MAX; i++) { 7983217790SRoopa Prabhu if (wq->bufs[i]) { 8001f2e4eaSScott Feldman kfree(wq->bufs[i]); 8101f2e4eaSScott Feldman wq->bufs[i] = NULL; 8201f2e4eaSScott Feldman } 8383217790SRoopa Prabhu } 8401f2e4eaSScott Feldman 8501f2e4eaSScott Feldman wq->ctrl = NULL; 8601f2e4eaSScott Feldman } 8701f2e4eaSScott Feldman 8801f2e4eaSScott Feldman int vnic_wq_alloc(struct vnic_dev *vdev, struct vnic_wq *wq, unsigned int index, 8901f2e4eaSScott Feldman unsigned int desc_count, unsigned int desc_size) 9001f2e4eaSScott Feldman { 9101f2e4eaSScott Feldman int err; 9201f2e4eaSScott Feldman 9301f2e4eaSScott Feldman wq->index = index; 9401f2e4eaSScott Feldman wq->vdev = vdev; 9501f2e4eaSScott Feldman 9601f2e4eaSScott Feldman wq->ctrl = vnic_dev_get_res(vdev, RES_TYPE_WQ, index); 9701f2e4eaSScott Feldman if (!wq->ctrl) { 98e327f4e1SJoe Perches vdev_err(vdev, "Failed to hook WQ[%d] resource\n", index); 9901f2e4eaSScott Feldman return -EINVAL; 10001f2e4eaSScott Feldman } 10101f2e4eaSScott Feldman 10201f2e4eaSScott Feldman vnic_wq_disable(wq); 10301f2e4eaSScott Feldman 10401f2e4eaSScott Feldman err = vnic_dev_alloc_desc_ring(vdev, &wq->ring, desc_count, desc_size); 10501f2e4eaSScott Feldman if (err) 10601f2e4eaSScott Feldman return err; 10701f2e4eaSScott Feldman 10801f2e4eaSScott Feldman err = vnic_wq_alloc_bufs(wq); 10901f2e4eaSScott Feldman if (err) { 11001f2e4eaSScott Feldman vnic_wq_free(wq); 11101f2e4eaSScott Feldman return err; 11201f2e4eaSScott Feldman } 11301f2e4eaSScott Feldman 11401f2e4eaSScott Feldman return 0; 11501f2e4eaSScott Feldman } 11601f2e4eaSScott Feldman 1173dc33e23SDavid S. Miller int enic_wq_devcmd2_alloc(struct vnic_dev *vdev, struct vnic_wq *wq, 118373fb087SGovindarajulu Varadarajan unsigned int desc_count, unsigned int desc_size) 119373fb087SGovindarajulu Varadarajan { 120373fb087SGovindarajulu Varadarajan int err; 121373fb087SGovindarajulu Varadarajan 122373fb087SGovindarajulu Varadarajan wq->index = 0; 123373fb087SGovindarajulu Varadarajan wq->vdev = vdev; 124373fb087SGovindarajulu Varadarajan 125373fb087SGovindarajulu Varadarajan wq->ctrl = vnic_dev_get_res(vdev, RES_TYPE_DEVCMD2, 0); 126373fb087SGovindarajulu Varadarajan if (!wq->ctrl) 127373fb087SGovindarajulu Varadarajan return -EINVAL; 128373fb087SGovindarajulu Varadarajan vnic_wq_disable(wq); 129373fb087SGovindarajulu Varadarajan err = vnic_dev_alloc_desc_ring(vdev, &wq->ring, desc_count, desc_size); 130373fb087SGovindarajulu Varadarajan 131373fb087SGovindarajulu Varadarajan return err; 132373fb087SGovindarajulu Varadarajan } 133373fb087SGovindarajulu Varadarajan 1343dc33e23SDavid S. Miller void enic_wq_init_start(struct vnic_wq *wq, unsigned int cq_index, 1356fdfa970SScott Feldman unsigned int fetch_index, unsigned int posted_index, 13601f2e4eaSScott Feldman unsigned int error_interrupt_enable, 13701f2e4eaSScott Feldman unsigned int error_interrupt_offset) 13801f2e4eaSScott Feldman { 13901f2e4eaSScott Feldman u64 paddr; 140b5bab85cSVasanthy Kolluri unsigned int count = wq->ring.desc_count; 14101f2e4eaSScott Feldman 14201f2e4eaSScott Feldman paddr = (u64)wq->ring.base_addr | VNIC_PADDR_TARGET; 14301f2e4eaSScott Feldman writeq(paddr, &wq->ctrl->ring_base); 144b5bab85cSVasanthy Kolluri iowrite32(count, &wq->ctrl->ring_size); 1456fdfa970SScott Feldman iowrite32(fetch_index, &wq->ctrl->fetch_index); 1466fdfa970SScott Feldman iowrite32(posted_index, &wq->ctrl->posted_index); 14701f2e4eaSScott Feldman iowrite32(cq_index, &wq->ctrl->cq_index); 14801f2e4eaSScott Feldman iowrite32(error_interrupt_enable, &wq->ctrl->error_interrupt_enable); 14901f2e4eaSScott Feldman iowrite32(error_interrupt_offset, &wq->ctrl->error_interrupt_offset); 15001f2e4eaSScott Feldman iowrite32(0, &wq->ctrl->error_status); 1516fdfa970SScott Feldman 1526fdfa970SScott Feldman wq->to_use = wq->to_clean = 153b5bab85cSVasanthy Kolluri &wq->bufs[fetch_index / VNIC_WQ_BUF_BLK_ENTRIES(count)] 154b5bab85cSVasanthy Kolluri [fetch_index % VNIC_WQ_BUF_BLK_ENTRIES(count)]; 1556fdfa970SScott Feldman } 1566fdfa970SScott Feldman 1576fdfa970SScott Feldman void vnic_wq_init(struct vnic_wq *wq, unsigned int cq_index, 1586fdfa970SScott Feldman unsigned int error_interrupt_enable, 1596fdfa970SScott Feldman unsigned int error_interrupt_offset) 1606fdfa970SScott Feldman { 1613dc33e23SDavid S. Miller enic_wq_init_start(wq, cq_index, 0, 0, 1626fdfa970SScott Feldman error_interrupt_enable, 1636fdfa970SScott Feldman error_interrupt_offset); 16401f2e4eaSScott Feldman } 16501f2e4eaSScott Feldman 16601f2e4eaSScott Feldman unsigned int vnic_wq_error_status(struct vnic_wq *wq) 16701f2e4eaSScott Feldman { 16801f2e4eaSScott Feldman return ioread32(&wq->ctrl->error_status); 16901f2e4eaSScott Feldman } 17001f2e4eaSScott Feldman 17101f2e4eaSScott Feldman void vnic_wq_enable(struct vnic_wq *wq) 17201f2e4eaSScott Feldman { 17301f2e4eaSScott Feldman iowrite32(1, &wq->ctrl->enable); 17401f2e4eaSScott Feldman } 17501f2e4eaSScott Feldman 17601f2e4eaSScott Feldman int vnic_wq_disable(struct vnic_wq *wq) 17701f2e4eaSScott Feldman { 17801f2e4eaSScott Feldman unsigned int wait; 1796a3c2f83SGovindarajulu Varadarajan struct vnic_dev *vdev = wq->vdev; 18001f2e4eaSScott Feldman 18101f2e4eaSScott Feldman iowrite32(0, &wq->ctrl->enable); 18201f2e4eaSScott Feldman 18301f2e4eaSScott Feldman /* Wait for HW to ACK disable request */ 184b6d24eb6SVasanthy Kolluri for (wait = 0; wait < 1000; wait++) { 18501f2e4eaSScott Feldman if (!(ioread32(&wq->ctrl->running))) 18601f2e4eaSScott Feldman return 0; 187b6d24eb6SVasanthy Kolluri udelay(10); 18801f2e4eaSScott Feldman } 18901f2e4eaSScott Feldman 190e327f4e1SJoe Perches vdev_neterr(vdev, "Failed to disable WQ[%d]\n", wq->index); 19101f2e4eaSScott Feldman 19201f2e4eaSScott Feldman return -ETIMEDOUT; 19301f2e4eaSScott Feldman } 19401f2e4eaSScott Feldman 19501f2e4eaSScott Feldman void vnic_wq_clean(struct vnic_wq *wq, 19601f2e4eaSScott Feldman void (*buf_clean)(struct vnic_wq *wq, struct vnic_wq_buf *buf)) 19701f2e4eaSScott Feldman { 19801f2e4eaSScott Feldman struct vnic_wq_buf *buf; 19901f2e4eaSScott Feldman 20001f2e4eaSScott Feldman buf = wq->to_clean; 20101f2e4eaSScott Feldman 20201f2e4eaSScott Feldman while (vnic_wq_desc_used(wq) > 0) { 20301f2e4eaSScott Feldman 20401f2e4eaSScott Feldman (*buf_clean)(wq, buf); 20501f2e4eaSScott Feldman 20601f2e4eaSScott Feldman buf = wq->to_clean = buf->next; 20701f2e4eaSScott Feldman wq->ring.desc_avail++; 20801f2e4eaSScott Feldman } 20901f2e4eaSScott Feldman 21001f2e4eaSScott Feldman wq->to_use = wq->to_clean = wq->bufs[0]; 21101f2e4eaSScott Feldman 21201f2e4eaSScott Feldman iowrite32(0, &wq->ctrl->fetch_index); 21301f2e4eaSScott Feldman iowrite32(0, &wq->ctrl->posted_index); 21401f2e4eaSScott Feldman iowrite32(0, &wq->ctrl->error_status); 21501f2e4eaSScott Feldman 21601f2e4eaSScott Feldman vnic_dev_clear_desc_ring(&wq->ring); 21701f2e4eaSScott Feldman } 218