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