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