18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright 2014 Cisco Systems, Inc. All rights reserved. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * This program is free software; you may redistribute it and/or modify 58c2ecf20Sopenharmony_ci * it under the terms of the GNU General Public License as published by 68c2ecf20Sopenharmony_ci * the Free Software Foundation; version 2 of the License. 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 98c2ecf20Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 108c2ecf20Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 118c2ecf20Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 128c2ecf20Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 138c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 148c2ecf20Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 158c2ecf20Sopenharmony_ci * SOFTWARE. 168c2ecf20Sopenharmony_ci */ 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#ifndef _VNIC_WQ_H_ 198c2ecf20Sopenharmony_ci#define _VNIC_WQ_H_ 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include <linux/pci.h> 228c2ecf20Sopenharmony_ci#include "vnic_dev.h" 238c2ecf20Sopenharmony_ci#include "vnic_cq.h" 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci/* Work queue control */ 268c2ecf20Sopenharmony_cistruct vnic_wq_ctrl { 278c2ecf20Sopenharmony_ci u64 ring_base; /* 0x00 */ 288c2ecf20Sopenharmony_ci u32 ring_size; /* 0x08 */ 298c2ecf20Sopenharmony_ci u32 pad0; 308c2ecf20Sopenharmony_ci u32 posted_index; /* 0x10 */ 318c2ecf20Sopenharmony_ci u32 pad1; 328c2ecf20Sopenharmony_ci u32 cq_index; /* 0x18 */ 338c2ecf20Sopenharmony_ci u32 pad2; 348c2ecf20Sopenharmony_ci u32 enable; /* 0x20 */ 358c2ecf20Sopenharmony_ci u32 pad3; 368c2ecf20Sopenharmony_ci u32 running; /* 0x28 */ 378c2ecf20Sopenharmony_ci u32 pad4; 388c2ecf20Sopenharmony_ci u32 fetch_index; /* 0x30 */ 398c2ecf20Sopenharmony_ci u32 pad5; 408c2ecf20Sopenharmony_ci u32 dca_value; /* 0x38 */ 418c2ecf20Sopenharmony_ci u32 pad6; 428c2ecf20Sopenharmony_ci u32 error_interrupt_enable; /* 0x40 */ 438c2ecf20Sopenharmony_ci u32 pad7; 448c2ecf20Sopenharmony_ci u32 error_interrupt_offset; /* 0x48 */ 458c2ecf20Sopenharmony_ci u32 pad8; 468c2ecf20Sopenharmony_ci u32 error_status; /* 0x50 */ 478c2ecf20Sopenharmony_ci u32 pad9; 488c2ecf20Sopenharmony_ci}; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistruct vnic_wq_buf { 518c2ecf20Sopenharmony_ci struct vnic_wq_buf *next; 528c2ecf20Sopenharmony_ci dma_addr_t dma_addr; 538c2ecf20Sopenharmony_ci void *os_buf; 548c2ecf20Sopenharmony_ci unsigned int len; 558c2ecf20Sopenharmony_ci unsigned int index; 568c2ecf20Sopenharmony_ci int sop; 578c2ecf20Sopenharmony_ci void *desc; 588c2ecf20Sopenharmony_ci}; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci/* Break the vnic_wq_buf allocations into blocks of 64 entries */ 618c2ecf20Sopenharmony_ci#define VNIC_WQ_BUF_MIN_BLK_ENTRIES 32 628c2ecf20Sopenharmony_ci#define VNIC_WQ_BUF_DFLT_BLK_ENTRIES 64 638c2ecf20Sopenharmony_ci#define VNIC_WQ_BUF_BLK_ENTRIES(entries) \ 648c2ecf20Sopenharmony_ci ((unsigned int)(entries < VNIC_WQ_BUF_DFLT_BLK_ENTRIES) ? \ 658c2ecf20Sopenharmony_ci VNIC_WQ_BUF_MIN_BLK_ENTRIES : VNIC_WQ_BUF_DFLT_BLK_ENTRIES) 668c2ecf20Sopenharmony_ci#define VNIC_WQ_BUF_BLK_SZ \ 678c2ecf20Sopenharmony_ci (VNIC_WQ_BUF_DFLT_BLK_ENTRIES * sizeof(struct vnic_wq_buf)) 688c2ecf20Sopenharmony_ci#define VNIC_WQ_BUF_BLKS_NEEDED(entries) \ 698c2ecf20Sopenharmony_ci DIV_ROUND_UP(entries, VNIC_WQ_BUF_DFLT_BLK_ENTRIES) 708c2ecf20Sopenharmony_ci#define VNIC_WQ_BUF_BLKS_NEEDED(entries) \ 718c2ecf20Sopenharmony_ci DIV_ROUND_UP(entries, VNIC_WQ_BUF_DFLT_BLK_ENTRIES) 728c2ecf20Sopenharmony_ci#define VNIC_WQ_BUF_BLKS_MAX VNIC_WQ_BUF_BLKS_NEEDED(4096) 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_cistruct vnic_wq { 758c2ecf20Sopenharmony_ci unsigned int index; 768c2ecf20Sopenharmony_ci struct vnic_dev *vdev; 778c2ecf20Sopenharmony_ci struct vnic_wq_ctrl __iomem *ctrl; /* memory-mapped */ 788c2ecf20Sopenharmony_ci struct vnic_dev_ring ring; 798c2ecf20Sopenharmony_ci struct vnic_wq_buf *bufs[VNIC_WQ_BUF_BLKS_MAX]; 808c2ecf20Sopenharmony_ci struct vnic_wq_buf *to_use; 818c2ecf20Sopenharmony_ci struct vnic_wq_buf *to_clean; 828c2ecf20Sopenharmony_ci unsigned int pkts_outstanding; 838c2ecf20Sopenharmony_ci}; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_cistatic inline unsigned int svnic_wq_desc_avail(struct vnic_wq *wq) 868c2ecf20Sopenharmony_ci{ 878c2ecf20Sopenharmony_ci /* how many does SW own? */ 888c2ecf20Sopenharmony_ci return wq->ring.desc_avail; 898c2ecf20Sopenharmony_ci} 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_cistatic inline unsigned int svnic_wq_desc_used(struct vnic_wq *wq) 928c2ecf20Sopenharmony_ci{ 938c2ecf20Sopenharmony_ci /* how many does HW own? */ 948c2ecf20Sopenharmony_ci return wq->ring.desc_count - wq->ring.desc_avail - 1; 958c2ecf20Sopenharmony_ci} 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_cistatic inline void *svnic_wq_next_desc(struct vnic_wq *wq) 988c2ecf20Sopenharmony_ci{ 998c2ecf20Sopenharmony_ci return wq->to_use->desc; 1008c2ecf20Sopenharmony_ci} 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_cistatic inline void svnic_wq_post(struct vnic_wq *wq, 1038c2ecf20Sopenharmony_ci void *os_buf, dma_addr_t dma_addr, 1048c2ecf20Sopenharmony_ci unsigned int len, int sop, int eop) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci struct vnic_wq_buf *buf = wq->to_use; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci buf->sop = sop; 1098c2ecf20Sopenharmony_ci buf->os_buf = eop ? os_buf : NULL; 1108c2ecf20Sopenharmony_ci buf->dma_addr = dma_addr; 1118c2ecf20Sopenharmony_ci buf->len = len; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci buf = buf->next; 1148c2ecf20Sopenharmony_ci if (eop) { 1158c2ecf20Sopenharmony_ci /* Adding write memory barrier prevents compiler and/or CPU 1168c2ecf20Sopenharmony_ci * reordering, thus avoiding descriptor posting before 1178c2ecf20Sopenharmony_ci * descriptor is initialized. Otherwise, hardware can read 1188c2ecf20Sopenharmony_ci * stale descriptor fields. 1198c2ecf20Sopenharmony_ci */ 1208c2ecf20Sopenharmony_ci wmb(); 1218c2ecf20Sopenharmony_ci iowrite32(buf->index, &wq->ctrl->posted_index); 1228c2ecf20Sopenharmony_ci } 1238c2ecf20Sopenharmony_ci wq->to_use = buf; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci wq->ring.desc_avail--; 1268c2ecf20Sopenharmony_ci} 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_cistatic inline void svnic_wq_service(struct vnic_wq *wq, 1298c2ecf20Sopenharmony_ci struct cq_desc *cq_desc, u16 completed_index, 1308c2ecf20Sopenharmony_ci void (*buf_service)(struct vnic_wq *wq, 1318c2ecf20Sopenharmony_ci struct cq_desc *cq_desc, struct vnic_wq_buf *buf, void *opaque), 1328c2ecf20Sopenharmony_ci void *opaque) 1338c2ecf20Sopenharmony_ci{ 1348c2ecf20Sopenharmony_ci struct vnic_wq_buf *buf; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci buf = wq->to_clean; 1378c2ecf20Sopenharmony_ci while (1) { 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci (*buf_service)(wq, cq_desc, buf, opaque); 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci wq->ring.desc_avail++; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci wq->to_clean = buf->next; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci if (buf->index == completed_index) 1468c2ecf20Sopenharmony_ci break; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci buf = wq->to_clean; 1498c2ecf20Sopenharmony_ci } 1508c2ecf20Sopenharmony_ci} 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_civoid svnic_wq_free(struct vnic_wq *wq); 1538c2ecf20Sopenharmony_ciint svnic_wq_alloc(struct vnic_dev *vdev, struct vnic_wq *wq, 1548c2ecf20Sopenharmony_ci unsigned int index, unsigned int desc_count, unsigned int desc_size); 1558c2ecf20Sopenharmony_ciint vnic_wq_devcmd2_alloc(struct vnic_dev *vdev, struct vnic_wq *wq, 1568c2ecf20Sopenharmony_ci unsigned int desc_count, unsigned int desc_size); 1578c2ecf20Sopenharmony_civoid vnic_wq_init_start(struct vnic_wq *wq, unsigned int cq_index, 1588c2ecf20Sopenharmony_ci unsigned int fetch_index, unsigned int post_index, 1598c2ecf20Sopenharmony_ci unsigned int error_interrupt_enable, 1608c2ecf20Sopenharmony_ci unsigned int error_interrupt_offset); 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_civoid svnic_wq_init(struct vnic_wq *wq, unsigned int cq_index, 1638c2ecf20Sopenharmony_ci unsigned int error_interrupt_enable, 1648c2ecf20Sopenharmony_ci unsigned int error_interrupt_offset); 1658c2ecf20Sopenharmony_ciunsigned int svnic_wq_error_status(struct vnic_wq *wq); 1668c2ecf20Sopenharmony_civoid svnic_wq_enable(struct vnic_wq *wq); 1678c2ecf20Sopenharmony_ciint svnic_wq_disable(struct vnic_wq *wq); 1688c2ecf20Sopenharmony_civoid svnic_wq_clean(struct vnic_wq *wq, 1698c2ecf20Sopenharmony_ci void (*buf_clean)(struct vnic_wq *wq, struct vnic_wq_buf *buf)); 1708c2ecf20Sopenharmony_ci#endif /* _VNIC_WQ_H_ */ 171