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_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/* 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_wq_desc_avail fnic_wq_desc_avail 308c2ecf20Sopenharmony_ci#define vnic_wq_desc_used fnic_wq_desc_used 318c2ecf20Sopenharmony_ci#define vnic_wq_next_desc fni_cwq_next_desc 328c2ecf20Sopenharmony_ci#define vnic_wq_post fnic_wq_post 338c2ecf20Sopenharmony_ci#define vnic_wq_service fnic_wq_service 348c2ecf20Sopenharmony_ci#define vnic_wq_free fnic_wq_free 358c2ecf20Sopenharmony_ci#define vnic_wq_alloc fnic_wq_alloc 368c2ecf20Sopenharmony_ci#define vnic_wq_devcmd2_alloc fnic_wq_devcmd2_alloc 378c2ecf20Sopenharmony_ci#define vnic_wq_init_start fnic_wq_init_start 388c2ecf20Sopenharmony_ci#define vnic_wq_init fnic_wq_init 398c2ecf20Sopenharmony_ci#define vnic_wq_error_status fnic_wq_error_status 408c2ecf20Sopenharmony_ci#define vnic_wq_enable fnic_wq_enable 418c2ecf20Sopenharmony_ci#define vnic_wq_disable fnic_wq_disable 428c2ecf20Sopenharmony_ci#define vnic_wq_clean fnic_wq_clean 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci/* Work queue control */ 458c2ecf20Sopenharmony_cistruct vnic_wq_ctrl { 468c2ecf20Sopenharmony_ci u64 ring_base; /* 0x00 */ 478c2ecf20Sopenharmony_ci u32 ring_size; /* 0x08 */ 488c2ecf20Sopenharmony_ci u32 pad0; 498c2ecf20Sopenharmony_ci u32 posted_index; /* 0x10 */ 508c2ecf20Sopenharmony_ci u32 pad1; 518c2ecf20Sopenharmony_ci u32 cq_index; /* 0x18 */ 528c2ecf20Sopenharmony_ci u32 pad2; 538c2ecf20Sopenharmony_ci u32 enable; /* 0x20 */ 548c2ecf20Sopenharmony_ci u32 pad3; 558c2ecf20Sopenharmony_ci u32 running; /* 0x28 */ 568c2ecf20Sopenharmony_ci u32 pad4; 578c2ecf20Sopenharmony_ci u32 fetch_index; /* 0x30 */ 588c2ecf20Sopenharmony_ci u32 pad5; 598c2ecf20Sopenharmony_ci u32 dca_value; /* 0x38 */ 608c2ecf20Sopenharmony_ci u32 pad6; 618c2ecf20Sopenharmony_ci u32 error_interrupt_enable; /* 0x40 */ 628c2ecf20Sopenharmony_ci u32 pad7; 638c2ecf20Sopenharmony_ci u32 error_interrupt_offset; /* 0x48 */ 648c2ecf20Sopenharmony_ci u32 pad8; 658c2ecf20Sopenharmony_ci u32 error_status; /* 0x50 */ 668c2ecf20Sopenharmony_ci u32 pad9; 678c2ecf20Sopenharmony_ci}; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_cistruct vnic_wq_buf { 708c2ecf20Sopenharmony_ci struct vnic_wq_buf *next; 718c2ecf20Sopenharmony_ci dma_addr_t dma_addr; 728c2ecf20Sopenharmony_ci void *os_buf; 738c2ecf20Sopenharmony_ci unsigned int len; 748c2ecf20Sopenharmony_ci unsigned int index; 758c2ecf20Sopenharmony_ci int sop; 768c2ecf20Sopenharmony_ci void *desc; 778c2ecf20Sopenharmony_ci}; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci/* Break the vnic_wq_buf allocations into blocks of 64 entries */ 808c2ecf20Sopenharmony_ci#define VNIC_WQ_BUF_BLK_ENTRIES 64 818c2ecf20Sopenharmony_ci#define VNIC_WQ_BUF_BLK_SZ \ 828c2ecf20Sopenharmony_ci (VNIC_WQ_BUF_BLK_ENTRIES * sizeof(struct vnic_wq_buf)) 838c2ecf20Sopenharmony_ci#define VNIC_WQ_BUF_BLKS_NEEDED(entries) \ 848c2ecf20Sopenharmony_ci DIV_ROUND_UP(entries, VNIC_WQ_BUF_BLK_ENTRIES) 858c2ecf20Sopenharmony_ci#define VNIC_WQ_BUF_BLKS_MAX VNIC_WQ_BUF_BLKS_NEEDED(4096) 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_cistruct vnic_wq { 888c2ecf20Sopenharmony_ci unsigned int index; 898c2ecf20Sopenharmony_ci struct vnic_dev *vdev; 908c2ecf20Sopenharmony_ci struct vnic_wq_ctrl __iomem *ctrl; /* memory-mapped */ 918c2ecf20Sopenharmony_ci struct vnic_dev_ring ring; 928c2ecf20Sopenharmony_ci struct vnic_wq_buf *bufs[VNIC_WQ_BUF_BLKS_MAX]; 938c2ecf20Sopenharmony_ci struct vnic_wq_buf *to_use; 948c2ecf20Sopenharmony_ci struct vnic_wq_buf *to_clean; 958c2ecf20Sopenharmony_ci unsigned int pkts_outstanding; 968c2ecf20Sopenharmony_ci}; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_cistatic inline unsigned int vnic_wq_desc_avail(struct vnic_wq *wq) 998c2ecf20Sopenharmony_ci{ 1008c2ecf20Sopenharmony_ci /* how many does SW own? */ 1018c2ecf20Sopenharmony_ci return wq->ring.desc_avail; 1028c2ecf20Sopenharmony_ci} 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_cistatic inline unsigned int vnic_wq_desc_used(struct vnic_wq *wq) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci /* how many does HW own? */ 1078c2ecf20Sopenharmony_ci return wq->ring.desc_count - wq->ring.desc_avail - 1; 1088c2ecf20Sopenharmony_ci} 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_cistatic inline void *vnic_wq_next_desc(struct vnic_wq *wq) 1118c2ecf20Sopenharmony_ci{ 1128c2ecf20Sopenharmony_ci return wq->to_use->desc; 1138c2ecf20Sopenharmony_ci} 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_cistatic inline void vnic_wq_post(struct vnic_wq *wq, 1168c2ecf20Sopenharmony_ci void *os_buf, dma_addr_t dma_addr, 1178c2ecf20Sopenharmony_ci unsigned int len, int sop, int eop) 1188c2ecf20Sopenharmony_ci{ 1198c2ecf20Sopenharmony_ci struct vnic_wq_buf *buf = wq->to_use; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci buf->sop = sop; 1228c2ecf20Sopenharmony_ci buf->os_buf = eop ? os_buf : NULL; 1238c2ecf20Sopenharmony_ci buf->dma_addr = dma_addr; 1248c2ecf20Sopenharmony_ci buf->len = len; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci buf = buf->next; 1278c2ecf20Sopenharmony_ci if (eop) { 1288c2ecf20Sopenharmony_ci /* Adding write memory barrier prevents compiler and/or CPU 1298c2ecf20Sopenharmony_ci * reordering, thus avoiding descriptor posting before 1308c2ecf20Sopenharmony_ci * descriptor is initialized. Otherwise, hardware can read 1318c2ecf20Sopenharmony_ci * stale descriptor fields. 1328c2ecf20Sopenharmony_ci */ 1338c2ecf20Sopenharmony_ci wmb(); 1348c2ecf20Sopenharmony_ci iowrite32(buf->index, &wq->ctrl->posted_index); 1358c2ecf20Sopenharmony_ci } 1368c2ecf20Sopenharmony_ci wq->to_use = buf; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci wq->ring.desc_avail--; 1398c2ecf20Sopenharmony_ci} 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_cistatic inline void vnic_wq_service(struct vnic_wq *wq, 1428c2ecf20Sopenharmony_ci struct cq_desc *cq_desc, u16 completed_index, 1438c2ecf20Sopenharmony_ci void (*buf_service)(struct vnic_wq *wq, 1448c2ecf20Sopenharmony_ci struct cq_desc *cq_desc, struct vnic_wq_buf *buf, void *opaque), 1458c2ecf20Sopenharmony_ci void *opaque) 1468c2ecf20Sopenharmony_ci{ 1478c2ecf20Sopenharmony_ci struct vnic_wq_buf *buf; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci buf = wq->to_clean; 1508c2ecf20Sopenharmony_ci while (1) { 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci (*buf_service)(wq, cq_desc, buf, opaque); 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci wq->ring.desc_avail++; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci wq->to_clean = buf->next; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci if (buf->index == completed_index) 1598c2ecf20Sopenharmony_ci break; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci buf = wq->to_clean; 1628c2ecf20Sopenharmony_ci } 1638c2ecf20Sopenharmony_ci} 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_civoid vnic_wq_free(struct vnic_wq *wq); 1668c2ecf20Sopenharmony_ciint vnic_wq_alloc(struct vnic_dev *vdev, struct vnic_wq *wq, unsigned int index, 1678c2ecf20Sopenharmony_ci unsigned int desc_count, unsigned int desc_size); 1688c2ecf20Sopenharmony_ciint vnic_wq_devcmd2_alloc(struct vnic_dev *vdev, struct vnic_wq *wq, 1698c2ecf20Sopenharmony_ci unsigned int desc_count, unsigned int desc_size); 1708c2ecf20Sopenharmony_civoid vnic_wq_init_start(struct vnic_wq *wq, unsigned int cq_index, 1718c2ecf20Sopenharmony_ci unsigned int fetch_index, unsigned int posted_index, 1728c2ecf20Sopenharmony_ci unsigned int error_interrupt_enable, 1738c2ecf20Sopenharmony_ci unsigned int error_interrupt_offset); 1748c2ecf20Sopenharmony_civoid vnic_wq_init(struct vnic_wq *wq, unsigned int cq_index, 1758c2ecf20Sopenharmony_ci unsigned int error_interrupt_enable, 1768c2ecf20Sopenharmony_ci unsigned int error_interrupt_offset); 1778c2ecf20Sopenharmony_ciunsigned int vnic_wq_error_status(struct vnic_wq *wq); 1788c2ecf20Sopenharmony_civoid vnic_wq_enable(struct vnic_wq *wq); 1798c2ecf20Sopenharmony_ciint vnic_wq_disable(struct vnic_wq *wq); 1808c2ecf20Sopenharmony_civoid vnic_wq_clean(struct vnic_wq *wq, 1818c2ecf20Sopenharmony_ci void (*buf_clean)(struct vnic_wq *wq, struct vnic_wq_buf *buf)); 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci#endif /* _VNIC_WQ_H_ */ 184