xref: /linux/drivers/net/ethernet/cisco/enic/vnic_wq.c (revision 3eb66e91a25497065c5322b1268cbc3953642227)
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