18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright 2008 Cisco Systems, Inc. All rights reserved. 38c2ecf20Sopenharmony_ci * Copyright 2007 Nuova Systems, Inc. All rights reserved. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * This program is free software; you may redistribute it and/or modify 68c2ecf20Sopenharmony_ci * it under the terms of the GNU General Public License as published by 78c2ecf20Sopenharmony_ci * the Free Software Foundation; version 2 of the License. 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 108c2ecf20Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 118c2ecf20Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 128c2ecf20Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 138c2ecf20Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 148c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 158c2ecf20Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 168c2ecf20Sopenharmony_ci * SOFTWARE. 178c2ecf20Sopenharmony_ci */ 188c2ecf20Sopenharmony_ci#ifndef _VNIC_RQ_H_ 198c2ecf20Sopenharmony_ci#define _VNIC_RQ_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/* 268c2ecf20Sopenharmony_ci * These defines avoid symbol clash between fnic and enic (Cisco 10G Eth 278c2ecf20Sopenharmony_ci * Driver) when both are built with CONFIG options =y 288c2ecf20Sopenharmony_ci */ 298c2ecf20Sopenharmony_ci#define vnic_rq_desc_avail fnic_rq_desc_avail 308c2ecf20Sopenharmony_ci#define vnic_rq_desc_used fnic_rq_desc_used 318c2ecf20Sopenharmony_ci#define vnic_rq_next_desc fnic_rq_next_desc 328c2ecf20Sopenharmony_ci#define vnic_rq_next_index fnic_rq_next_index 338c2ecf20Sopenharmony_ci#define vnic_rq_next_buf_index fnic_rq_next_buf_index 348c2ecf20Sopenharmony_ci#define vnic_rq_post fnic_rq_post 358c2ecf20Sopenharmony_ci#define vnic_rq_posting_soon fnic_rq_posting_soon 368c2ecf20Sopenharmony_ci#define vnic_rq_return_descs fnic_rq_return_descs 378c2ecf20Sopenharmony_ci#define vnic_rq_service fnic_rq_service 388c2ecf20Sopenharmony_ci#define vnic_rq_fill fnic_rq_fill 398c2ecf20Sopenharmony_ci#define vnic_rq_free fnic_rq_free 408c2ecf20Sopenharmony_ci#define vnic_rq_alloc fnic_rq_alloc 418c2ecf20Sopenharmony_ci#define vnic_rq_init fnic_rq_init 428c2ecf20Sopenharmony_ci#define vnic_rq_error_status fnic_rq_error_status 438c2ecf20Sopenharmony_ci#define vnic_rq_enable fnic_rq_enable 448c2ecf20Sopenharmony_ci#define vnic_rq_disable fnic_rq_disable 458c2ecf20Sopenharmony_ci#define vnic_rq_clean fnic_rq_clean 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci/* Receive queue control */ 488c2ecf20Sopenharmony_cistruct vnic_rq_ctrl { 498c2ecf20Sopenharmony_ci u64 ring_base; /* 0x00 */ 508c2ecf20Sopenharmony_ci u32 ring_size; /* 0x08 */ 518c2ecf20Sopenharmony_ci u32 pad0; 528c2ecf20Sopenharmony_ci u32 posted_index; /* 0x10 */ 538c2ecf20Sopenharmony_ci u32 pad1; 548c2ecf20Sopenharmony_ci u32 cq_index; /* 0x18 */ 558c2ecf20Sopenharmony_ci u32 pad2; 568c2ecf20Sopenharmony_ci u32 enable; /* 0x20 */ 578c2ecf20Sopenharmony_ci u32 pad3; 588c2ecf20Sopenharmony_ci u32 running; /* 0x28 */ 598c2ecf20Sopenharmony_ci u32 pad4; 608c2ecf20Sopenharmony_ci u32 fetch_index; /* 0x30 */ 618c2ecf20Sopenharmony_ci u32 pad5; 628c2ecf20Sopenharmony_ci u32 error_interrupt_enable; /* 0x38 */ 638c2ecf20Sopenharmony_ci u32 pad6; 648c2ecf20Sopenharmony_ci u32 error_interrupt_offset; /* 0x40 */ 658c2ecf20Sopenharmony_ci u32 pad7; 668c2ecf20Sopenharmony_ci u32 error_status; /* 0x48 */ 678c2ecf20Sopenharmony_ci u32 pad8; 688c2ecf20Sopenharmony_ci u32 dropped_packet_count; /* 0x50 */ 698c2ecf20Sopenharmony_ci u32 pad9; 708c2ecf20Sopenharmony_ci u32 dropped_packet_count_rc; /* 0x58 */ 718c2ecf20Sopenharmony_ci u32 pad10; 728c2ecf20Sopenharmony_ci}; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci/* Break the vnic_rq_buf allocations into blocks of 64 entries */ 758c2ecf20Sopenharmony_ci#define VNIC_RQ_BUF_BLK_ENTRIES 64 768c2ecf20Sopenharmony_ci#define VNIC_RQ_BUF_BLK_SZ \ 778c2ecf20Sopenharmony_ci (VNIC_RQ_BUF_BLK_ENTRIES * sizeof(struct vnic_rq_buf)) 788c2ecf20Sopenharmony_ci#define VNIC_RQ_BUF_BLKS_NEEDED(entries) \ 798c2ecf20Sopenharmony_ci DIV_ROUND_UP(entries, VNIC_RQ_BUF_BLK_ENTRIES) 808c2ecf20Sopenharmony_ci#define VNIC_RQ_BUF_BLKS_MAX VNIC_RQ_BUF_BLKS_NEEDED(4096) 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_cistruct vnic_rq_buf { 838c2ecf20Sopenharmony_ci struct vnic_rq_buf *next; 848c2ecf20Sopenharmony_ci dma_addr_t dma_addr; 858c2ecf20Sopenharmony_ci void *os_buf; 868c2ecf20Sopenharmony_ci unsigned int os_buf_index; 878c2ecf20Sopenharmony_ci unsigned int len; 888c2ecf20Sopenharmony_ci unsigned int index; 898c2ecf20Sopenharmony_ci void *desc; 908c2ecf20Sopenharmony_ci}; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_cistruct vnic_rq { 938c2ecf20Sopenharmony_ci unsigned int index; 948c2ecf20Sopenharmony_ci struct vnic_dev *vdev; 958c2ecf20Sopenharmony_ci struct vnic_rq_ctrl __iomem *ctrl; /* memory-mapped */ 968c2ecf20Sopenharmony_ci struct vnic_dev_ring ring; 978c2ecf20Sopenharmony_ci struct vnic_rq_buf *bufs[VNIC_RQ_BUF_BLKS_MAX]; 988c2ecf20Sopenharmony_ci struct vnic_rq_buf *to_use; 998c2ecf20Sopenharmony_ci struct vnic_rq_buf *to_clean; 1008c2ecf20Sopenharmony_ci void *os_buf_head; 1018c2ecf20Sopenharmony_ci unsigned int buf_index; 1028c2ecf20Sopenharmony_ci unsigned int pkts_outstanding; 1038c2ecf20Sopenharmony_ci}; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_cistatic inline unsigned int vnic_rq_desc_avail(struct vnic_rq *rq) 1068c2ecf20Sopenharmony_ci{ 1078c2ecf20Sopenharmony_ci /* how many does SW own? */ 1088c2ecf20Sopenharmony_ci return rq->ring.desc_avail; 1098c2ecf20Sopenharmony_ci} 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_cistatic inline unsigned int vnic_rq_desc_used(struct vnic_rq *rq) 1128c2ecf20Sopenharmony_ci{ 1138c2ecf20Sopenharmony_ci /* how many does HW own? */ 1148c2ecf20Sopenharmony_ci return rq->ring.desc_count - rq->ring.desc_avail - 1; 1158c2ecf20Sopenharmony_ci} 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_cistatic inline void *vnic_rq_next_desc(struct vnic_rq *rq) 1188c2ecf20Sopenharmony_ci{ 1198c2ecf20Sopenharmony_ci return rq->to_use->desc; 1208c2ecf20Sopenharmony_ci} 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_cistatic inline unsigned int vnic_rq_next_index(struct vnic_rq *rq) 1238c2ecf20Sopenharmony_ci{ 1248c2ecf20Sopenharmony_ci return rq->to_use->index; 1258c2ecf20Sopenharmony_ci} 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_cistatic inline unsigned int vnic_rq_next_buf_index(struct vnic_rq *rq) 1288c2ecf20Sopenharmony_ci{ 1298c2ecf20Sopenharmony_ci return rq->buf_index++; 1308c2ecf20Sopenharmony_ci} 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_cistatic inline void vnic_rq_post(struct vnic_rq *rq, 1338c2ecf20Sopenharmony_ci void *os_buf, unsigned int os_buf_index, 1348c2ecf20Sopenharmony_ci dma_addr_t dma_addr, unsigned int len) 1358c2ecf20Sopenharmony_ci{ 1368c2ecf20Sopenharmony_ci struct vnic_rq_buf *buf = rq->to_use; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci buf->os_buf = os_buf; 1398c2ecf20Sopenharmony_ci buf->os_buf_index = os_buf_index; 1408c2ecf20Sopenharmony_ci buf->dma_addr = dma_addr; 1418c2ecf20Sopenharmony_ci buf->len = len; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci buf = buf->next; 1448c2ecf20Sopenharmony_ci rq->to_use = buf; 1458c2ecf20Sopenharmony_ci rq->ring.desc_avail--; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci /* Move the posted_index every nth descriptor 1488c2ecf20Sopenharmony_ci */ 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci#ifndef VNIC_RQ_RETURN_RATE 1518c2ecf20Sopenharmony_ci#define VNIC_RQ_RETURN_RATE 0xf /* keep 2^n - 1 */ 1528c2ecf20Sopenharmony_ci#endif 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci if ((buf->index & VNIC_RQ_RETURN_RATE) == 0) { 1558c2ecf20Sopenharmony_ci /* Adding write memory barrier prevents compiler and/or CPU 1568c2ecf20Sopenharmony_ci * reordering, thus avoiding descriptor posting before 1578c2ecf20Sopenharmony_ci * descriptor is initialized. Otherwise, hardware can read 1588c2ecf20Sopenharmony_ci * stale descriptor fields. 1598c2ecf20Sopenharmony_ci */ 1608c2ecf20Sopenharmony_ci wmb(); 1618c2ecf20Sopenharmony_ci iowrite32(buf->index, &rq->ctrl->posted_index); 1628c2ecf20Sopenharmony_ci } 1638c2ecf20Sopenharmony_ci} 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_cistatic inline int vnic_rq_posting_soon(struct vnic_rq *rq) 1668c2ecf20Sopenharmony_ci{ 1678c2ecf20Sopenharmony_ci return (rq->to_use->index & VNIC_RQ_RETURN_RATE) == 0; 1688c2ecf20Sopenharmony_ci} 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_cistatic inline void vnic_rq_return_descs(struct vnic_rq *rq, unsigned int count) 1718c2ecf20Sopenharmony_ci{ 1728c2ecf20Sopenharmony_ci rq->ring.desc_avail += count; 1738c2ecf20Sopenharmony_ci} 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_cienum desc_return_options { 1768c2ecf20Sopenharmony_ci VNIC_RQ_RETURN_DESC, 1778c2ecf20Sopenharmony_ci VNIC_RQ_DEFER_RETURN_DESC, 1788c2ecf20Sopenharmony_ci}; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_cistatic inline void vnic_rq_service(struct vnic_rq *rq, 1818c2ecf20Sopenharmony_ci struct cq_desc *cq_desc, u16 completed_index, 1828c2ecf20Sopenharmony_ci int desc_return, void (*buf_service)(struct vnic_rq *rq, 1838c2ecf20Sopenharmony_ci struct cq_desc *cq_desc, struct vnic_rq_buf *buf, 1848c2ecf20Sopenharmony_ci int skipped, void *opaque), void *opaque) 1858c2ecf20Sopenharmony_ci{ 1868c2ecf20Sopenharmony_ci struct vnic_rq_buf *buf; 1878c2ecf20Sopenharmony_ci int skipped; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci buf = rq->to_clean; 1908c2ecf20Sopenharmony_ci while (1) { 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci skipped = (buf->index != completed_index); 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci (*buf_service)(rq, cq_desc, buf, skipped, opaque); 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci if (desc_return == VNIC_RQ_RETURN_DESC) 1978c2ecf20Sopenharmony_ci rq->ring.desc_avail++; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci rq->to_clean = buf->next; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci if (!skipped) 2028c2ecf20Sopenharmony_ci break; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci buf = rq->to_clean; 2058c2ecf20Sopenharmony_ci } 2068c2ecf20Sopenharmony_ci} 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_cistatic inline int vnic_rq_fill(struct vnic_rq *rq, 2098c2ecf20Sopenharmony_ci int (*buf_fill)(struct vnic_rq *rq)) 2108c2ecf20Sopenharmony_ci{ 2118c2ecf20Sopenharmony_ci int err; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci while (vnic_rq_desc_avail(rq) > 1) { 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci err = (*buf_fill)(rq); 2168c2ecf20Sopenharmony_ci if (err) 2178c2ecf20Sopenharmony_ci return err; 2188c2ecf20Sopenharmony_ci } 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci return 0; 2218c2ecf20Sopenharmony_ci} 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_civoid vnic_rq_free(struct vnic_rq *rq); 2248c2ecf20Sopenharmony_ciint vnic_rq_alloc(struct vnic_dev *vdev, struct vnic_rq *rq, unsigned int index, 2258c2ecf20Sopenharmony_ci unsigned int desc_count, unsigned int desc_size); 2268c2ecf20Sopenharmony_civoid vnic_rq_init(struct vnic_rq *rq, unsigned int cq_index, 2278c2ecf20Sopenharmony_ci unsigned int error_interrupt_enable, 2288c2ecf20Sopenharmony_ci unsigned int error_interrupt_offset); 2298c2ecf20Sopenharmony_ciunsigned int vnic_rq_error_status(struct vnic_rq *rq); 2308c2ecf20Sopenharmony_civoid vnic_rq_enable(struct vnic_rq *rq); 2318c2ecf20Sopenharmony_ciint vnic_rq_disable(struct vnic_rq *rq); 2328c2ecf20Sopenharmony_civoid vnic_rq_clean(struct vnic_rq *rq, 2338c2ecf20Sopenharmony_ci void (*buf_clean)(struct vnic_rq *rq, struct vnic_rq_buf *buf)); 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci#endif /* _VNIC_RQ_H_ */ 236