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#ifndef _VNIC_WQ_H_
2101f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman#define _VNIC_WQ_H_
2201f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman
2301f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman#include <linux/pci.h>
2401f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman
2501f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman#include "vnic_dev.h"
2601f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman#include "vnic_cq.h"
2701f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman
2801f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman/* Work queue control */
2901f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldmanstruct vnic_wq_ctrl {
3001f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman	u64 ring_base;			/* 0x00 */
3101f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman	u32 ring_size;			/* 0x08 */
3201f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman	u32 pad0;
3301f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman	u32 posted_index;		/* 0x10 */
3401f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman	u32 pad1;
3501f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman	u32 cq_index;			/* 0x18 */
3601f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman	u32 pad2;
3701f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman	u32 enable;			/* 0x20 */
3801f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman	u32 pad3;
3901f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman	u32 running;			/* 0x28 */
4001f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman	u32 pad4;
4101f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman	u32 fetch_index;		/* 0x30 */
4201f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman	u32 pad5;
4301f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman	u32 dca_value;			/* 0x38 */
4401f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman	u32 pad6;
4501f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman	u32 error_interrupt_enable;	/* 0x40 */
4601f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman	u32 pad7;
4701f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman	u32 error_interrupt_offset;	/* 0x48 */
4801f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman	u32 pad8;
4901f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman	u32 error_status;		/* 0x50 */
5001f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman	u32 pad9;
5101f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman};
5201f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman
5301f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldmanstruct vnic_wq_buf {
5401f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman	struct vnic_wq_buf *next;
5501f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman	dma_addr_t dma_addr;
5601f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman	void *os_buf;
5701f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman	unsigned int len;
5801f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman	unsigned int index;
5901f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman	int sop;
6001f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman	void *desc;
6101f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman};
6201f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman
63b5bab85c15ed3d1ae7f917a7c077086ac6c04572Vasanthy Kolluri/* Break the vnic_wq_buf allocations into blocks of 32/64 entries */
64b5bab85c15ed3d1ae7f917a7c077086ac6c04572Vasanthy Kolluri#define VNIC_WQ_BUF_MIN_BLK_ENTRIES 32
65b5bab85c15ed3d1ae7f917a7c077086ac6c04572Vasanthy Kolluri#define VNIC_WQ_BUF_DFLT_BLK_ENTRIES 64
66b5bab85c15ed3d1ae7f917a7c077086ac6c04572Vasanthy Kolluri#define VNIC_WQ_BUF_BLK_ENTRIES(entries) \
67b5bab85c15ed3d1ae7f917a7c077086ac6c04572Vasanthy Kolluri	((unsigned int)((entries < VNIC_WQ_BUF_DFLT_BLK_ENTRIES) ? \
68b5bab85c15ed3d1ae7f917a7c077086ac6c04572Vasanthy Kolluri	VNIC_WQ_BUF_MIN_BLK_ENTRIES : VNIC_WQ_BUF_DFLT_BLK_ENTRIES))
69b5bab85c15ed3d1ae7f917a7c077086ac6c04572Vasanthy Kolluri#define VNIC_WQ_BUF_BLK_SZ(entries) \
70b5bab85c15ed3d1ae7f917a7c077086ac6c04572Vasanthy Kolluri	(VNIC_WQ_BUF_BLK_ENTRIES(entries) * sizeof(struct vnic_wq_buf))
7101f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman#define VNIC_WQ_BUF_BLKS_NEEDED(entries) \
72b5bab85c15ed3d1ae7f917a7c077086ac6c04572Vasanthy Kolluri	DIV_ROUND_UP(entries, VNIC_WQ_BUF_BLK_ENTRIES(entries))
7301f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman#define VNIC_WQ_BUF_BLKS_MAX VNIC_WQ_BUF_BLKS_NEEDED(4096)
7401f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman
7501f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldmanstruct vnic_wq {
7601f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman	unsigned int index;
7701f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman	struct vnic_dev *vdev;
7801f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman	struct vnic_wq_ctrl __iomem *ctrl;              /* memory-mapped */
7901f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman	struct vnic_dev_ring ring;
8001f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman	struct vnic_wq_buf *bufs[VNIC_WQ_BUF_BLKS_MAX];
8101f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman	struct vnic_wq_buf *to_use;
8201f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman	struct vnic_wq_buf *to_clean;
8301f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman	unsigned int pkts_outstanding;
8401f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman};
8501f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman
8601f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldmanstatic inline unsigned int vnic_wq_desc_avail(struct vnic_wq *wq)
8701f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman{
8801f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman	/* how many does SW own? */
8901f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman	return wq->ring.desc_avail;
9001f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman}
9101f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman
9201f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldmanstatic inline unsigned int vnic_wq_desc_used(struct vnic_wq *wq)
9301f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman{
9401f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman	/* how many does HW own? */
9501f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman	return wq->ring.desc_count - wq->ring.desc_avail - 1;
9601f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman}
9701f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman
9801f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldmanstatic inline void *vnic_wq_next_desc(struct vnic_wq *wq)
9901f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman{
10001f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman	return wq->to_use->desc;
10101f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman}
10201f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman
10301f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldmanstatic inline void vnic_wq_post(struct vnic_wq *wq,
10401f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman	void *os_buf, dma_addr_t dma_addr,
10501f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman	unsigned int len, int sop, int eop)
10601f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman{
10701f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman	struct vnic_wq_buf *buf = wq->to_use;
10801f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman
10901f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman	buf->sop = sop;
11001f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman	buf->os_buf = eop ? os_buf : NULL;
11101f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman	buf->dma_addr = dma_addr;
11201f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman	buf->len = len;
11301f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman
11401f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman	buf = buf->next;
115845964515a76381e204d3399af82c149f8abcc1cScott Feldman	if (eop) {
116845964515a76381e204d3399af82c149f8abcc1cScott Feldman		/* Adding write memory barrier prevents compiler and/or CPU
117845964515a76381e204d3399af82c149f8abcc1cScott Feldman		 * reordering, thus avoiding descriptor posting before
118845964515a76381e204d3399af82c149f8abcc1cScott Feldman		 * descriptor is initialized. Otherwise, hardware can read
119845964515a76381e204d3399af82c149f8abcc1cScott Feldman		 * stale descriptor fields.
120845964515a76381e204d3399af82c149f8abcc1cScott Feldman		 */
121845964515a76381e204d3399af82c149f8abcc1cScott Feldman		wmb();
12201f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman		iowrite32(buf->index, &wq->ctrl->posted_index);
123845964515a76381e204d3399af82c149f8abcc1cScott Feldman	}
12401f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman	wq->to_use = buf;
12501f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman
12601f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman	wq->ring.desc_avail--;
12701f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman}
12801f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman
12901f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldmanstatic inline void vnic_wq_service(struct vnic_wq *wq,
13001f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman	struct cq_desc *cq_desc, u16 completed_index,
13101f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman	void (*buf_service)(struct vnic_wq *wq,
13201f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman	struct cq_desc *cq_desc, struct vnic_wq_buf *buf, void *opaque),
13301f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman	void *opaque)
13401f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman{
13501f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman	struct vnic_wq_buf *buf;
13601f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman
13701f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman	buf = wq->to_clean;
13801f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman	while (1) {
13901f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman
14001f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman		(*buf_service)(wq, cq_desc, buf, opaque);
14101f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman
14201f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman		wq->ring.desc_avail++;
14301f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman
14401f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman		wq->to_clean = buf->next;
14501f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman
14601f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman		if (buf->index == completed_index)
14701f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman			break;
14801f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman
14901f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman		buf = wq->to_clean;
15001f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman	}
15101f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman}
15201f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman
15301f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldmanvoid vnic_wq_free(struct vnic_wq *wq);
15401f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldmanint vnic_wq_alloc(struct vnic_dev *vdev, struct vnic_wq *wq, unsigned int index,
15501f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman	unsigned int desc_count, unsigned int desc_size);
15601f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldmanvoid vnic_wq_init(struct vnic_wq *wq, unsigned int cq_index,
15701f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman	unsigned int error_interrupt_enable,
15801f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman	unsigned int error_interrupt_offset);
15901f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldmanunsigned int vnic_wq_error_status(struct vnic_wq *wq);
16001f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldmanvoid vnic_wq_enable(struct vnic_wq *wq);
16101f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldmanint vnic_wq_disable(struct vnic_wq *wq);
16201f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldmanvoid vnic_wq_clean(struct vnic_wq *wq,
16301f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman	void (*buf_clean)(struct vnic_wq *wq, struct vnic_wq_buf *buf));
16401f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman
16501f2e4ead2c51226ed1283ef6a8388ca6f4cff8fScott Feldman#endif /* _VNIC_WQ_H_ */
166