xref: /openbmc/linux/drivers/scsi/fnic/vnic_wq.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
1*e6550b3eSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
25df6d737SAbhijeet Joglekar /*
35df6d737SAbhijeet Joglekar  * Copyright 2008 Cisco Systems, Inc.  All rights reserved.
45df6d737SAbhijeet Joglekar  * Copyright 2007 Nuova Systems, Inc.  All rights reserved.
55df6d737SAbhijeet Joglekar  */
65df6d737SAbhijeet Joglekar 
75df6d737SAbhijeet Joglekar #include <linux/errno.h>
85df6d737SAbhijeet Joglekar #include <linux/types.h>
95df6d737SAbhijeet Joglekar #include <linux/pci.h>
105df6d737SAbhijeet Joglekar #include <linux/delay.h>
115a0e3ad6STejun Heo #include <linux/slab.h>
125df6d737SAbhijeet Joglekar #include "vnic_dev.h"
135df6d737SAbhijeet Joglekar #include "vnic_wq.h"
145df6d737SAbhijeet Joglekar 
159d699c62SSatish Kharat 
vnic_wq_get_ctrl(struct vnic_dev * vdev,struct vnic_wq * wq,unsigned int index,enum vnic_res_type res_type)169ae58380SJason Yan static int vnic_wq_get_ctrl(struct vnic_dev *vdev, struct vnic_wq *wq,
179d699c62SSatish Kharat 		unsigned int index, enum vnic_res_type res_type)
189d699c62SSatish Kharat {
199d699c62SSatish Kharat 	wq->ctrl = vnic_dev_get_res(vdev, res_type, index);
209d699c62SSatish Kharat 
219d699c62SSatish Kharat 	if (!wq->ctrl)
229d699c62SSatish Kharat 		return -EINVAL;
239d699c62SSatish Kharat 
249d699c62SSatish Kharat 	return 0;
259d699c62SSatish Kharat }
269d699c62SSatish Kharat 
279d699c62SSatish Kharat 
vnic_wq_alloc_ring(struct vnic_dev * vdev,struct vnic_wq * wq,unsigned int desc_count,unsigned int desc_size)289ae58380SJason Yan static int vnic_wq_alloc_ring(struct vnic_dev *vdev, struct vnic_wq *wq,
299d699c62SSatish Kharat 		unsigned int desc_count, unsigned int desc_size)
309d699c62SSatish Kharat {
319d699c62SSatish Kharat 	return vnic_dev_alloc_desc_ring(vdev, &wq->ring, desc_count, desc_size);
329d699c62SSatish Kharat }
339d699c62SSatish Kharat 
349d699c62SSatish Kharat 
vnic_wq_alloc_bufs(struct vnic_wq * wq)355df6d737SAbhijeet Joglekar static int vnic_wq_alloc_bufs(struct vnic_wq *wq)
365df6d737SAbhijeet Joglekar {
375df6d737SAbhijeet Joglekar 	struct vnic_wq_buf *buf;
385df6d737SAbhijeet Joglekar 	unsigned int i, j, count = wq->ring.desc_count;
395df6d737SAbhijeet Joglekar 	unsigned int blks = VNIC_WQ_BUF_BLKS_NEEDED(count);
405df6d737SAbhijeet Joglekar 
415df6d737SAbhijeet Joglekar 	for (i = 0; i < blks; i++) {
425df6d737SAbhijeet Joglekar 		wq->bufs[i] = kzalloc(VNIC_WQ_BUF_BLK_SZ, GFP_ATOMIC);
435df6d737SAbhijeet Joglekar 		if (!wq->bufs[i]) {
445df6d737SAbhijeet Joglekar 			printk(KERN_ERR "Failed to alloc wq_bufs\n");
455df6d737SAbhijeet Joglekar 			return -ENOMEM;
465df6d737SAbhijeet Joglekar 		}
475df6d737SAbhijeet Joglekar 	}
485df6d737SAbhijeet Joglekar 
495df6d737SAbhijeet Joglekar 	for (i = 0; i < blks; i++) {
505df6d737SAbhijeet Joglekar 		buf = wq->bufs[i];
515df6d737SAbhijeet Joglekar 		for (j = 0; j < VNIC_WQ_BUF_BLK_ENTRIES; j++) {
525df6d737SAbhijeet Joglekar 			buf->index = i * VNIC_WQ_BUF_BLK_ENTRIES + j;
535df6d737SAbhijeet Joglekar 			buf->desc = (u8 *)wq->ring.descs +
545df6d737SAbhijeet Joglekar 				wq->ring.desc_size * buf->index;
555df6d737SAbhijeet Joglekar 			if (buf->index + 1 == count) {
565df6d737SAbhijeet Joglekar 				buf->next = wq->bufs[0];
575df6d737SAbhijeet Joglekar 				break;
585df6d737SAbhijeet Joglekar 			} else if (j + 1 == VNIC_WQ_BUF_BLK_ENTRIES) {
595df6d737SAbhijeet Joglekar 				buf->next = wq->bufs[i + 1];
605df6d737SAbhijeet Joglekar 			} else {
615df6d737SAbhijeet Joglekar 				buf->next = buf + 1;
625df6d737SAbhijeet Joglekar 				buf++;
635df6d737SAbhijeet Joglekar 			}
645df6d737SAbhijeet Joglekar 		}
655df6d737SAbhijeet Joglekar 	}
665df6d737SAbhijeet Joglekar 
675df6d737SAbhijeet Joglekar 	wq->to_use = wq->to_clean = wq->bufs[0];
685df6d737SAbhijeet Joglekar 
695df6d737SAbhijeet Joglekar 	return 0;
705df6d737SAbhijeet Joglekar }
715df6d737SAbhijeet Joglekar 
vnic_wq_free(struct vnic_wq * wq)725df6d737SAbhijeet Joglekar void vnic_wq_free(struct vnic_wq *wq)
735df6d737SAbhijeet Joglekar {
745df6d737SAbhijeet Joglekar 	struct vnic_dev *vdev;
755df6d737SAbhijeet Joglekar 	unsigned int i;
765df6d737SAbhijeet Joglekar 
775df6d737SAbhijeet Joglekar 	vdev = wq->vdev;
785df6d737SAbhijeet Joglekar 
795df6d737SAbhijeet Joglekar 	vnic_dev_free_desc_ring(vdev, &wq->ring);
805df6d737SAbhijeet Joglekar 
815df6d737SAbhijeet Joglekar 	for (i = 0; i < VNIC_WQ_BUF_BLKS_MAX; i++) {
825df6d737SAbhijeet Joglekar 		kfree(wq->bufs[i]);
835df6d737SAbhijeet Joglekar 		wq->bufs[i] = NULL;
845df6d737SAbhijeet Joglekar 	}
855df6d737SAbhijeet Joglekar 
865df6d737SAbhijeet Joglekar 	wq->ctrl = NULL;
875df6d737SAbhijeet Joglekar 
885df6d737SAbhijeet Joglekar }
895df6d737SAbhijeet Joglekar 
vnic_wq_alloc(struct vnic_dev * vdev,struct vnic_wq * wq,unsigned int index,unsigned int desc_count,unsigned int desc_size)905df6d737SAbhijeet Joglekar int vnic_wq_alloc(struct vnic_dev *vdev, struct vnic_wq *wq, unsigned int index,
915df6d737SAbhijeet Joglekar 	unsigned int desc_count, unsigned int desc_size)
925df6d737SAbhijeet Joglekar {
935df6d737SAbhijeet Joglekar 	int err;
945df6d737SAbhijeet Joglekar 
955df6d737SAbhijeet Joglekar 	wq->index = index;
965df6d737SAbhijeet Joglekar 	wq->vdev = vdev;
975df6d737SAbhijeet Joglekar 
985df6d737SAbhijeet Joglekar 	wq->ctrl = vnic_dev_get_res(vdev, RES_TYPE_WQ, index);
995df6d737SAbhijeet Joglekar 	if (!wq->ctrl) {
1005df6d737SAbhijeet Joglekar 		printk(KERN_ERR "Failed to hook WQ[%d] resource\n", index);
1015df6d737SAbhijeet Joglekar 		return -EINVAL;
1025df6d737SAbhijeet Joglekar 	}
1035df6d737SAbhijeet Joglekar 
1045df6d737SAbhijeet Joglekar 	vnic_wq_disable(wq);
1055df6d737SAbhijeet Joglekar 
1065df6d737SAbhijeet Joglekar 	err = vnic_dev_alloc_desc_ring(vdev, &wq->ring, desc_count, desc_size);
1075df6d737SAbhijeet Joglekar 	if (err)
1085df6d737SAbhijeet Joglekar 		return err;
1095df6d737SAbhijeet Joglekar 
1105df6d737SAbhijeet Joglekar 	err = vnic_wq_alloc_bufs(wq);
1115df6d737SAbhijeet Joglekar 	if (err) {
1125df6d737SAbhijeet Joglekar 		vnic_wq_free(wq);
1135df6d737SAbhijeet Joglekar 		return err;
1145df6d737SAbhijeet Joglekar 	}
1155df6d737SAbhijeet Joglekar 
1165df6d737SAbhijeet Joglekar 	return 0;
1175df6d737SAbhijeet Joglekar }
1185df6d737SAbhijeet Joglekar 
1199d699c62SSatish Kharat 
vnic_wq_devcmd2_alloc(struct vnic_dev * vdev,struct vnic_wq * wq,unsigned int desc_count,unsigned int desc_size)1209d699c62SSatish Kharat int vnic_wq_devcmd2_alloc(struct vnic_dev *vdev, struct vnic_wq *wq,
1219d699c62SSatish Kharat 		unsigned int desc_count, unsigned int desc_size)
1229d699c62SSatish Kharat {
1239d699c62SSatish Kharat 	int err;
1249d699c62SSatish Kharat 
1259d699c62SSatish Kharat 	wq->index = 0;
1269d699c62SSatish Kharat 	wq->vdev = vdev;
1279d699c62SSatish Kharat 
1289d699c62SSatish Kharat 	err = vnic_wq_get_ctrl(vdev, wq, 0, RES_TYPE_DEVCMD2);
1299d699c62SSatish Kharat 	if (err) {
1309d699c62SSatish Kharat 		pr_err("Failed to get devcmd2 resource\n");
1319d699c62SSatish Kharat 		return err;
1329d699c62SSatish Kharat 	}
1339d699c62SSatish Kharat 	vnic_wq_disable(wq);
1349d699c62SSatish Kharat 
1359d699c62SSatish Kharat 	err = vnic_wq_alloc_ring(vdev, wq, desc_count, desc_size);
1369d699c62SSatish Kharat 	if (err)
1379d699c62SSatish Kharat 		return err;
1389d699c62SSatish Kharat 	return 0;
1399d699c62SSatish Kharat }
1409d699c62SSatish Kharat 
vnic_wq_init_start(struct vnic_wq * wq,unsigned int cq_index,unsigned int fetch_index,unsigned int posted_index,unsigned int error_interrupt_enable,unsigned int error_interrupt_offset)1419d699c62SSatish Kharat void vnic_wq_init_start(struct vnic_wq *wq, unsigned int cq_index,
1429d699c62SSatish Kharat 		unsigned int fetch_index, unsigned int posted_index,
1439d699c62SSatish Kharat 		unsigned int error_interrupt_enable,
1449d699c62SSatish Kharat 		unsigned int error_interrupt_offset)
1459d699c62SSatish Kharat {
1469d699c62SSatish Kharat 	u64 paddr;
1479d699c62SSatish Kharat 	unsigned int count = wq->ring.desc_count;
1489d699c62SSatish Kharat 
1499d699c62SSatish Kharat 	paddr = (u64)wq->ring.base_addr | VNIC_PADDR_TARGET;
1509d699c62SSatish Kharat 	writeq(paddr, &wq->ctrl->ring_base);
1519d699c62SSatish Kharat 	iowrite32(count, &wq->ctrl->ring_size);
1529d699c62SSatish Kharat 	iowrite32(fetch_index, &wq->ctrl->fetch_index);
1539d699c62SSatish Kharat 	iowrite32(posted_index, &wq->ctrl->posted_index);
1549d699c62SSatish Kharat 	iowrite32(cq_index, &wq->ctrl->cq_index);
1559d699c62SSatish Kharat 	iowrite32(error_interrupt_enable, &wq->ctrl->error_interrupt_enable);
1569d699c62SSatish Kharat 	iowrite32(error_interrupt_offset, &wq->ctrl->error_interrupt_offset);
1579d699c62SSatish Kharat 	iowrite32(0, &wq->ctrl->error_status);
1589d699c62SSatish Kharat 
1599d699c62SSatish Kharat 	wq->to_use = wq->to_clean =
1609d699c62SSatish Kharat 		&wq->bufs[fetch_index / VNIC_WQ_BUF_BLK_ENTRIES]
1619d699c62SSatish Kharat 		[fetch_index % VNIC_WQ_BUF_BLK_ENTRIES];
1629d699c62SSatish Kharat }
1639d699c62SSatish Kharat 
1649d699c62SSatish Kharat 
vnic_wq_init(struct vnic_wq * wq,unsigned int cq_index,unsigned int error_interrupt_enable,unsigned int error_interrupt_offset)1655df6d737SAbhijeet Joglekar void vnic_wq_init(struct vnic_wq *wq, unsigned int cq_index,
1665df6d737SAbhijeet Joglekar 	unsigned int error_interrupt_enable,
1675df6d737SAbhijeet Joglekar 	unsigned int error_interrupt_offset)
1685df6d737SAbhijeet Joglekar {
1695df6d737SAbhijeet Joglekar 	u64 paddr;
1705df6d737SAbhijeet Joglekar 
1715df6d737SAbhijeet Joglekar 	paddr = (u64)wq->ring.base_addr | VNIC_PADDR_TARGET;
1725df6d737SAbhijeet Joglekar 	writeq(paddr, &wq->ctrl->ring_base);
1735df6d737SAbhijeet Joglekar 	iowrite32(wq->ring.desc_count, &wq->ctrl->ring_size);
1745df6d737SAbhijeet Joglekar 	iowrite32(0, &wq->ctrl->fetch_index);
1755df6d737SAbhijeet Joglekar 	iowrite32(0, &wq->ctrl->posted_index);
1765df6d737SAbhijeet Joglekar 	iowrite32(cq_index, &wq->ctrl->cq_index);
1775df6d737SAbhijeet Joglekar 	iowrite32(error_interrupt_enable, &wq->ctrl->error_interrupt_enable);
1785df6d737SAbhijeet Joglekar 	iowrite32(error_interrupt_offset, &wq->ctrl->error_interrupt_offset);
1795df6d737SAbhijeet Joglekar 	iowrite32(0, &wq->ctrl->error_status);
1805df6d737SAbhijeet Joglekar }
1815df6d737SAbhijeet Joglekar 
vnic_wq_error_status(struct vnic_wq * wq)1825df6d737SAbhijeet Joglekar unsigned int vnic_wq_error_status(struct vnic_wq *wq)
1835df6d737SAbhijeet Joglekar {
1845df6d737SAbhijeet Joglekar 	return ioread32(&wq->ctrl->error_status);
1855df6d737SAbhijeet Joglekar }
1865df6d737SAbhijeet Joglekar 
vnic_wq_enable(struct vnic_wq * wq)1875df6d737SAbhijeet Joglekar void vnic_wq_enable(struct vnic_wq *wq)
1885df6d737SAbhijeet Joglekar {
1895df6d737SAbhijeet Joglekar 	iowrite32(1, &wq->ctrl->enable);
1905df6d737SAbhijeet Joglekar }
1915df6d737SAbhijeet Joglekar 
vnic_wq_disable(struct vnic_wq * wq)1925df6d737SAbhijeet Joglekar int vnic_wq_disable(struct vnic_wq *wq)
1935df6d737SAbhijeet Joglekar {
1945df6d737SAbhijeet Joglekar 	unsigned int wait;
1955df6d737SAbhijeet Joglekar 
1965df6d737SAbhijeet Joglekar 	iowrite32(0, &wq->ctrl->enable);
1975df6d737SAbhijeet Joglekar 
1985df6d737SAbhijeet Joglekar 	/* Wait for HW to ACK disable request */
1995df6d737SAbhijeet Joglekar 	for (wait = 0; wait < 100; wait++) {
2005df6d737SAbhijeet Joglekar 		if (!(ioread32(&wq->ctrl->running)))
2015df6d737SAbhijeet Joglekar 			return 0;
2025df6d737SAbhijeet Joglekar 		udelay(1);
2035df6d737SAbhijeet Joglekar 	}
2045df6d737SAbhijeet Joglekar 
2055df6d737SAbhijeet Joglekar 	printk(KERN_ERR "Failed to disable WQ[%d]\n", wq->index);
2065df6d737SAbhijeet Joglekar 
2075df6d737SAbhijeet Joglekar 	return -ETIMEDOUT;
2085df6d737SAbhijeet Joglekar }
2095df6d737SAbhijeet Joglekar 
vnic_wq_clean(struct vnic_wq * wq,void (* buf_clean)(struct vnic_wq * wq,struct vnic_wq_buf * buf))2105df6d737SAbhijeet Joglekar void vnic_wq_clean(struct vnic_wq *wq,
2115df6d737SAbhijeet Joglekar 	void (*buf_clean)(struct vnic_wq *wq, struct vnic_wq_buf *buf))
2125df6d737SAbhijeet Joglekar {
2135df6d737SAbhijeet Joglekar 	struct vnic_wq_buf *buf;
2145df6d737SAbhijeet Joglekar 
2155df6d737SAbhijeet Joglekar 	BUG_ON(ioread32(&wq->ctrl->enable));
2165df6d737SAbhijeet Joglekar 
2175df6d737SAbhijeet Joglekar 	buf = wq->to_clean;
2185df6d737SAbhijeet Joglekar 
2195df6d737SAbhijeet Joglekar 	while (vnic_wq_desc_used(wq) > 0) {
2205df6d737SAbhijeet Joglekar 
2215df6d737SAbhijeet Joglekar 		(*buf_clean)(wq, buf);
2225df6d737SAbhijeet Joglekar 
2235df6d737SAbhijeet Joglekar 		buf = wq->to_clean = buf->next;
2245df6d737SAbhijeet Joglekar 		wq->ring.desc_avail++;
2255df6d737SAbhijeet Joglekar 	}
2265df6d737SAbhijeet Joglekar 
2275df6d737SAbhijeet Joglekar 	wq->to_use = wq->to_clean = wq->bufs[0];
2285df6d737SAbhijeet Joglekar 
2295df6d737SAbhijeet Joglekar 	iowrite32(0, &wq->ctrl->fetch_index);
2305df6d737SAbhijeet Joglekar 	iowrite32(0, &wq->ctrl->posted_index);
2315df6d737SAbhijeet Joglekar 	iowrite32(0, &wq->ctrl->error_status);
2325df6d737SAbhijeet Joglekar 
2335df6d737SAbhijeet Joglekar 	vnic_dev_clear_desc_ring(&wq->ring);
2345df6d737SAbhijeet Joglekar }
235