1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * Copyright 2014 Cisco Systems, Inc. All rights reserved.
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * This program is free software; you may redistribute it and/or modify
5*4882a593Smuzhiyun * it under the terms of the GNU General Public License as published by
6*4882a593Smuzhiyun * the Free Software Foundation; version 2 of the License.
7*4882a593Smuzhiyun *
8*4882a593Smuzhiyun * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
9*4882a593Smuzhiyun * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
10*4882a593Smuzhiyun * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
11*4882a593Smuzhiyun * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
12*4882a593Smuzhiyun * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
13*4882a593Smuzhiyun * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14*4882a593Smuzhiyun * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
15*4882a593Smuzhiyun * SOFTWARE.
16*4882a593Smuzhiyun */
17*4882a593Smuzhiyun
18*4882a593Smuzhiyun #include <linux/errno.h>
19*4882a593Smuzhiyun #include <linux/types.h>
20*4882a593Smuzhiyun #include <linux/pci.h>
21*4882a593Smuzhiyun
22*4882a593Smuzhiyun #include "wq_enet_desc.h"
23*4882a593Smuzhiyun #include "cq_enet_desc.h"
24*4882a593Smuzhiyun #include "vnic_resource.h"
25*4882a593Smuzhiyun #include "vnic_dev.h"
26*4882a593Smuzhiyun #include "vnic_wq.h"
27*4882a593Smuzhiyun #include "vnic_cq.h"
28*4882a593Smuzhiyun #include "vnic_intr.h"
29*4882a593Smuzhiyun #include "vnic_stats.h"
30*4882a593Smuzhiyun #include "snic.h"
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun int
snic_get_vnic_config(struct snic * snic)33*4882a593Smuzhiyun snic_get_vnic_config(struct snic *snic)
34*4882a593Smuzhiyun {
35*4882a593Smuzhiyun struct vnic_snic_config *c = &snic->config;
36*4882a593Smuzhiyun int ret;
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun #define GET_CONFIG(m) \
39*4882a593Smuzhiyun do { \
40*4882a593Smuzhiyun ret = svnic_dev_spec(snic->vdev, \
41*4882a593Smuzhiyun offsetof(struct vnic_snic_config, m), \
42*4882a593Smuzhiyun sizeof(c->m), \
43*4882a593Smuzhiyun &c->m); \
44*4882a593Smuzhiyun if (ret) { \
45*4882a593Smuzhiyun SNIC_HOST_ERR(snic->shost, \
46*4882a593Smuzhiyun "Error getting %s, %d\n", #m, ret); \
47*4882a593Smuzhiyun return ret; \
48*4882a593Smuzhiyun } \
49*4882a593Smuzhiyun } while (0)
50*4882a593Smuzhiyun
51*4882a593Smuzhiyun GET_CONFIG(wq_enet_desc_count);
52*4882a593Smuzhiyun GET_CONFIG(maxdatafieldsize);
53*4882a593Smuzhiyun GET_CONFIG(intr_timer);
54*4882a593Smuzhiyun GET_CONFIG(intr_timer_type);
55*4882a593Smuzhiyun GET_CONFIG(flags);
56*4882a593Smuzhiyun GET_CONFIG(io_throttle_count);
57*4882a593Smuzhiyun GET_CONFIG(port_down_timeout);
58*4882a593Smuzhiyun GET_CONFIG(port_down_io_retries);
59*4882a593Smuzhiyun GET_CONFIG(luns_per_tgt);
60*4882a593Smuzhiyun GET_CONFIG(xpt_type);
61*4882a593Smuzhiyun GET_CONFIG(hid);
62*4882a593Smuzhiyun
63*4882a593Smuzhiyun c->wq_enet_desc_count = min_t(u32,
64*4882a593Smuzhiyun VNIC_SNIC_WQ_DESCS_MAX,
65*4882a593Smuzhiyun max_t(u32,
66*4882a593Smuzhiyun VNIC_SNIC_WQ_DESCS_MIN,
67*4882a593Smuzhiyun c->wq_enet_desc_count));
68*4882a593Smuzhiyun
69*4882a593Smuzhiyun c->wq_enet_desc_count = ALIGN(c->wq_enet_desc_count, 16);
70*4882a593Smuzhiyun
71*4882a593Smuzhiyun c->maxdatafieldsize = min_t(u32,
72*4882a593Smuzhiyun VNIC_SNIC_MAXDATAFIELDSIZE_MAX,
73*4882a593Smuzhiyun max_t(u32,
74*4882a593Smuzhiyun VNIC_SNIC_MAXDATAFIELDSIZE_MIN,
75*4882a593Smuzhiyun c->maxdatafieldsize));
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun c->io_throttle_count = min_t(u32,
78*4882a593Smuzhiyun VNIC_SNIC_IO_THROTTLE_COUNT_MAX,
79*4882a593Smuzhiyun max_t(u32,
80*4882a593Smuzhiyun VNIC_SNIC_IO_THROTTLE_COUNT_MIN,
81*4882a593Smuzhiyun c->io_throttle_count));
82*4882a593Smuzhiyun
83*4882a593Smuzhiyun c->port_down_timeout = min_t(u32,
84*4882a593Smuzhiyun VNIC_SNIC_PORT_DOWN_TIMEOUT_MAX,
85*4882a593Smuzhiyun c->port_down_timeout);
86*4882a593Smuzhiyun
87*4882a593Smuzhiyun c->port_down_io_retries = min_t(u32,
88*4882a593Smuzhiyun VNIC_SNIC_PORT_DOWN_IO_RETRIES_MAX,
89*4882a593Smuzhiyun c->port_down_io_retries);
90*4882a593Smuzhiyun
91*4882a593Smuzhiyun c->luns_per_tgt = min_t(u32,
92*4882a593Smuzhiyun VNIC_SNIC_LUNS_PER_TARGET_MAX,
93*4882a593Smuzhiyun max_t(u32,
94*4882a593Smuzhiyun VNIC_SNIC_LUNS_PER_TARGET_MIN,
95*4882a593Smuzhiyun c->luns_per_tgt));
96*4882a593Smuzhiyun
97*4882a593Smuzhiyun c->intr_timer = min_t(u32, VNIC_INTR_TIMER_MAX, c->intr_timer);
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun SNIC_INFO("vNIC resources wq %d\n", c->wq_enet_desc_count);
100*4882a593Smuzhiyun SNIC_INFO("vNIC mtu %d intr timer %d\n",
101*4882a593Smuzhiyun c->maxdatafieldsize,
102*4882a593Smuzhiyun c->intr_timer);
103*4882a593Smuzhiyun
104*4882a593Smuzhiyun SNIC_INFO("vNIC flags 0x%x luns per tgt %d\n",
105*4882a593Smuzhiyun c->flags,
106*4882a593Smuzhiyun c->luns_per_tgt);
107*4882a593Smuzhiyun
108*4882a593Smuzhiyun SNIC_INFO("vNIC io throttle count %d\n", c->io_throttle_count);
109*4882a593Smuzhiyun SNIC_INFO("vNIC port down timeout %d port down io retries %d\n",
110*4882a593Smuzhiyun c->port_down_timeout,
111*4882a593Smuzhiyun c->port_down_io_retries);
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun SNIC_INFO("vNIC back end type = %d\n", c->xpt_type);
114*4882a593Smuzhiyun SNIC_INFO("vNIC hid = %d\n", c->hid);
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun return 0;
117*4882a593Smuzhiyun }
118*4882a593Smuzhiyun
119*4882a593Smuzhiyun void
snic_get_res_counts(struct snic * snic)120*4882a593Smuzhiyun snic_get_res_counts(struct snic *snic)
121*4882a593Smuzhiyun {
122*4882a593Smuzhiyun snic->wq_count = svnic_dev_get_res_count(snic->vdev, RES_TYPE_WQ);
123*4882a593Smuzhiyun SNIC_BUG_ON(snic->wq_count == 0);
124*4882a593Smuzhiyun snic->cq_count = svnic_dev_get_res_count(snic->vdev, RES_TYPE_CQ);
125*4882a593Smuzhiyun SNIC_BUG_ON(snic->cq_count == 0);
126*4882a593Smuzhiyun snic->intr_count = svnic_dev_get_res_count(snic->vdev,
127*4882a593Smuzhiyun RES_TYPE_INTR_CTRL);
128*4882a593Smuzhiyun SNIC_BUG_ON(snic->intr_count == 0);
129*4882a593Smuzhiyun }
130*4882a593Smuzhiyun
131*4882a593Smuzhiyun void
snic_free_vnic_res(struct snic * snic)132*4882a593Smuzhiyun snic_free_vnic_res(struct snic *snic)
133*4882a593Smuzhiyun {
134*4882a593Smuzhiyun unsigned int i;
135*4882a593Smuzhiyun
136*4882a593Smuzhiyun for (i = 0; i < snic->wq_count; i++)
137*4882a593Smuzhiyun svnic_wq_free(&snic->wq[i]);
138*4882a593Smuzhiyun
139*4882a593Smuzhiyun for (i = 0; i < snic->cq_count; i++)
140*4882a593Smuzhiyun svnic_cq_free(&snic->cq[i]);
141*4882a593Smuzhiyun
142*4882a593Smuzhiyun for (i = 0; i < snic->intr_count; i++)
143*4882a593Smuzhiyun svnic_intr_free(&snic->intr[i]);
144*4882a593Smuzhiyun }
145*4882a593Smuzhiyun
146*4882a593Smuzhiyun int
snic_alloc_vnic_res(struct snic * snic)147*4882a593Smuzhiyun snic_alloc_vnic_res(struct snic *snic)
148*4882a593Smuzhiyun {
149*4882a593Smuzhiyun enum vnic_dev_intr_mode intr_mode;
150*4882a593Smuzhiyun unsigned int mask_on_assertion;
151*4882a593Smuzhiyun unsigned int intr_offset;
152*4882a593Smuzhiyun unsigned int err_intr_enable;
153*4882a593Smuzhiyun unsigned int err_intr_offset;
154*4882a593Smuzhiyun unsigned int i;
155*4882a593Smuzhiyun int ret;
156*4882a593Smuzhiyun
157*4882a593Smuzhiyun intr_mode = svnic_dev_get_intr_mode(snic->vdev);
158*4882a593Smuzhiyun
159*4882a593Smuzhiyun SNIC_INFO("vNIC interrupt mode: %s\n",
160*4882a593Smuzhiyun ((intr_mode == VNIC_DEV_INTR_MODE_INTX) ?
161*4882a593Smuzhiyun "Legacy PCI INTx" :
162*4882a593Smuzhiyun ((intr_mode == VNIC_DEV_INTR_MODE_MSI) ?
163*4882a593Smuzhiyun "MSI" :
164*4882a593Smuzhiyun ((intr_mode == VNIC_DEV_INTR_MODE_MSIX) ?
165*4882a593Smuzhiyun "MSI-X" : "Unknown"))));
166*4882a593Smuzhiyun
167*4882a593Smuzhiyun /* only MSI-X is supported */
168*4882a593Smuzhiyun SNIC_BUG_ON(intr_mode != VNIC_DEV_INTR_MODE_MSIX);
169*4882a593Smuzhiyun
170*4882a593Smuzhiyun SNIC_INFO("wq %d cq %d intr %d\n", snic->wq_count,
171*4882a593Smuzhiyun snic->cq_count,
172*4882a593Smuzhiyun snic->intr_count);
173*4882a593Smuzhiyun
174*4882a593Smuzhiyun
175*4882a593Smuzhiyun /* Allocate WQs used for SCSI IOs */
176*4882a593Smuzhiyun for (i = 0; i < snic->wq_count; i++) {
177*4882a593Smuzhiyun ret = svnic_wq_alloc(snic->vdev,
178*4882a593Smuzhiyun &snic->wq[i],
179*4882a593Smuzhiyun i,
180*4882a593Smuzhiyun snic->config.wq_enet_desc_count,
181*4882a593Smuzhiyun sizeof(struct wq_enet_desc));
182*4882a593Smuzhiyun if (ret)
183*4882a593Smuzhiyun goto error_cleanup;
184*4882a593Smuzhiyun }
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun /* CQ for each WQ */
187*4882a593Smuzhiyun for (i = 0; i < snic->wq_count; i++) {
188*4882a593Smuzhiyun ret = svnic_cq_alloc(snic->vdev,
189*4882a593Smuzhiyun &snic->cq[i],
190*4882a593Smuzhiyun i,
191*4882a593Smuzhiyun snic->config.wq_enet_desc_count,
192*4882a593Smuzhiyun sizeof(struct cq_enet_wq_desc));
193*4882a593Smuzhiyun if (ret)
194*4882a593Smuzhiyun goto error_cleanup;
195*4882a593Smuzhiyun }
196*4882a593Smuzhiyun
197*4882a593Smuzhiyun SNIC_BUG_ON(snic->cq_count != 2 * snic->wq_count);
198*4882a593Smuzhiyun /* CQ for FW TO host */
199*4882a593Smuzhiyun for (i = snic->wq_count; i < snic->cq_count; i++) {
200*4882a593Smuzhiyun ret = svnic_cq_alloc(snic->vdev,
201*4882a593Smuzhiyun &snic->cq[i],
202*4882a593Smuzhiyun i,
203*4882a593Smuzhiyun (snic->config.wq_enet_desc_count * 3),
204*4882a593Smuzhiyun sizeof(struct snic_fw_req));
205*4882a593Smuzhiyun if (ret)
206*4882a593Smuzhiyun goto error_cleanup;
207*4882a593Smuzhiyun }
208*4882a593Smuzhiyun
209*4882a593Smuzhiyun for (i = 0; i < snic->intr_count; i++) {
210*4882a593Smuzhiyun ret = svnic_intr_alloc(snic->vdev, &snic->intr[i], i);
211*4882a593Smuzhiyun if (ret)
212*4882a593Smuzhiyun goto error_cleanup;
213*4882a593Smuzhiyun }
214*4882a593Smuzhiyun
215*4882a593Smuzhiyun /*
216*4882a593Smuzhiyun * Init WQ Resources.
217*4882a593Smuzhiyun * WQ[0 to n] points to CQ[0 to n-1]
218*4882a593Smuzhiyun * firmware to host comm points to CQ[n to m+1]
219*4882a593Smuzhiyun */
220*4882a593Smuzhiyun err_intr_enable = 1;
221*4882a593Smuzhiyun err_intr_offset = snic->err_intr_offset;
222*4882a593Smuzhiyun
223*4882a593Smuzhiyun for (i = 0; i < snic->wq_count; i++) {
224*4882a593Smuzhiyun svnic_wq_init(&snic->wq[i],
225*4882a593Smuzhiyun i,
226*4882a593Smuzhiyun err_intr_enable,
227*4882a593Smuzhiyun err_intr_offset);
228*4882a593Smuzhiyun }
229*4882a593Smuzhiyun
230*4882a593Smuzhiyun for (i = 0; i < snic->cq_count; i++) {
231*4882a593Smuzhiyun intr_offset = i;
232*4882a593Smuzhiyun
233*4882a593Smuzhiyun svnic_cq_init(&snic->cq[i],
234*4882a593Smuzhiyun 0 /* flow_control_enable */,
235*4882a593Smuzhiyun 1 /* color_enable */,
236*4882a593Smuzhiyun 0 /* cq_head */,
237*4882a593Smuzhiyun 0 /* cq_tail */,
238*4882a593Smuzhiyun 1 /* cq_tail_color */,
239*4882a593Smuzhiyun 1 /* interrupt_enable */,
240*4882a593Smuzhiyun 1 /* cq_entry_enable */,
241*4882a593Smuzhiyun 0 /* cq_message_enable */,
242*4882a593Smuzhiyun intr_offset,
243*4882a593Smuzhiyun 0 /* cq_message_addr */);
244*4882a593Smuzhiyun }
245*4882a593Smuzhiyun
246*4882a593Smuzhiyun /*
247*4882a593Smuzhiyun * Init INTR resources
248*4882a593Smuzhiyun * Assumption : snic is always in MSI-X mode
249*4882a593Smuzhiyun */
250*4882a593Smuzhiyun SNIC_BUG_ON(intr_mode != VNIC_DEV_INTR_MODE_MSIX);
251*4882a593Smuzhiyun mask_on_assertion = 1;
252*4882a593Smuzhiyun
253*4882a593Smuzhiyun for (i = 0; i < snic->intr_count; i++) {
254*4882a593Smuzhiyun svnic_intr_init(&snic->intr[i],
255*4882a593Smuzhiyun snic->config.intr_timer,
256*4882a593Smuzhiyun snic->config.intr_timer_type,
257*4882a593Smuzhiyun mask_on_assertion);
258*4882a593Smuzhiyun }
259*4882a593Smuzhiyun
260*4882a593Smuzhiyun /* init the stats memory by making the first call here */
261*4882a593Smuzhiyun ret = svnic_dev_stats_dump(snic->vdev, &snic->stats);
262*4882a593Smuzhiyun if (ret) {
263*4882a593Smuzhiyun SNIC_HOST_ERR(snic->shost,
264*4882a593Smuzhiyun "svnic_dev_stats_dump failed - x%x\n",
265*4882a593Smuzhiyun ret);
266*4882a593Smuzhiyun goto error_cleanup;
267*4882a593Smuzhiyun }
268*4882a593Smuzhiyun
269*4882a593Smuzhiyun /* Clear LIF stats */
270*4882a593Smuzhiyun svnic_dev_stats_clear(snic->vdev);
271*4882a593Smuzhiyun ret = 0;
272*4882a593Smuzhiyun
273*4882a593Smuzhiyun return ret;
274*4882a593Smuzhiyun
275*4882a593Smuzhiyun error_cleanup:
276*4882a593Smuzhiyun snic_free_vnic_res(snic);
277*4882a593Smuzhiyun
278*4882a593Smuzhiyun return ret;
279*4882a593Smuzhiyun }
280*4882a593Smuzhiyun
281*4882a593Smuzhiyun void
snic_log_q_error(struct snic * snic)282*4882a593Smuzhiyun snic_log_q_error(struct snic *snic)
283*4882a593Smuzhiyun {
284*4882a593Smuzhiyun unsigned int i;
285*4882a593Smuzhiyun u32 err_status;
286*4882a593Smuzhiyun
287*4882a593Smuzhiyun for (i = 0; i < snic->wq_count; i++) {
288*4882a593Smuzhiyun err_status = ioread32(&snic->wq[i].ctrl->error_status);
289*4882a593Smuzhiyun if (err_status)
290*4882a593Smuzhiyun SNIC_HOST_ERR(snic->shost,
291*4882a593Smuzhiyun "WQ[%d] error status %d\n",
292*4882a593Smuzhiyun i,
293*4882a593Smuzhiyun err_status);
294*4882a593Smuzhiyun }
295*4882a593Smuzhiyun } /* end of snic_log_q_error */
296