0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035 #include <linux/delay.h>
0036 #include <linux/jiffies.h>
0037 #include <linux/string.h>
0038 #include <scsi/scsi_device.h>
0039 #include <scsi/scsi_transport_fc.h>
0040
0041 #include "csio_hw.h"
0042 #include "csio_lnode.h"
0043 #include "csio_rnode.h"
0044 #include "csio_mb.h"
0045 #include "csio_wr.h"
0046
0047 #define csio_mb_is_host_owner(__owner) ((__owner) == CSIO_MBOWNER_PL)
0048
0049
0050
0051
0052
0053
0054
0055 enum fw_retval
0056 csio_mb_fw_retval(struct csio_mb *mbp)
0057 {
0058 struct fw_cmd_hdr *hdr;
0059
0060 hdr = (struct fw_cmd_hdr *)(mbp->mb);
0061
0062 return FW_CMD_RETVAL_G(ntohl(hdr->lo));
0063 }
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075 void
0076 csio_mb_hello(struct csio_hw *hw, struct csio_mb *mbp, uint32_t tmo,
0077 uint32_t m_mbox, uint32_t a_mbox, enum csio_dev_master master,
0078 void (*cbfn) (struct csio_hw *, struct csio_mb *))
0079 {
0080 struct fw_hello_cmd *cmdp = (struct fw_hello_cmd *)(mbp->mb);
0081
0082 CSIO_INIT_MBP(mbp, cmdp, tmo, hw, cbfn, 1);
0083
0084 cmdp->op_to_write = htonl(FW_CMD_OP_V(FW_HELLO_CMD) |
0085 FW_CMD_REQUEST_F | FW_CMD_WRITE_F);
0086 cmdp->retval_len16 = htonl(FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
0087 cmdp->err_to_clearinit = htonl(
0088 FW_HELLO_CMD_MASTERDIS_V(master == CSIO_MASTER_CANT) |
0089 FW_HELLO_CMD_MASTERFORCE_V(master == CSIO_MASTER_MUST) |
0090 FW_HELLO_CMD_MBMASTER_V(master == CSIO_MASTER_MUST ?
0091 m_mbox : FW_HELLO_CMD_MBMASTER_M) |
0092 FW_HELLO_CMD_MBASYNCNOT_V(a_mbox) |
0093 FW_HELLO_CMD_STAGE_V(fw_hello_cmd_stage_os) |
0094 FW_HELLO_CMD_CLEARINIT_F);
0095
0096 }
0097
0098
0099
0100
0101
0102
0103
0104
0105
0106
0107 void
0108 csio_mb_process_hello_rsp(struct csio_hw *hw, struct csio_mb *mbp,
0109 enum fw_retval *retval, enum csio_dev_state *state,
0110 uint8_t *mpfn)
0111 {
0112 struct fw_hello_cmd *rsp = (struct fw_hello_cmd *)(mbp->mb);
0113 uint32_t value;
0114
0115 *retval = FW_CMD_RETVAL_G(ntohl(rsp->retval_len16));
0116
0117 if (*retval == FW_SUCCESS) {
0118 hw->fwrev = ntohl(rsp->fwrev);
0119
0120 value = ntohl(rsp->err_to_clearinit);
0121 *mpfn = FW_HELLO_CMD_MBMASTER_G(value);
0122
0123 if (value & FW_HELLO_CMD_INIT_F)
0124 *state = CSIO_DEV_STATE_INIT;
0125 else if (value & FW_HELLO_CMD_ERR_F)
0126 *state = CSIO_DEV_STATE_ERR;
0127 else
0128 *state = CSIO_DEV_STATE_UNINIT;
0129 }
0130 }
0131
0132
0133
0134
0135
0136
0137
0138
0139 void
0140 csio_mb_bye(struct csio_hw *hw, struct csio_mb *mbp, uint32_t tmo,
0141 void (*cbfn) (struct csio_hw *, struct csio_mb *))
0142 {
0143 struct fw_bye_cmd *cmdp = (struct fw_bye_cmd *)(mbp->mb);
0144
0145 CSIO_INIT_MBP(mbp, cmdp, tmo, hw, cbfn, 1);
0146
0147 cmdp->op_to_write = htonl(FW_CMD_OP_V(FW_BYE_CMD) |
0148 FW_CMD_REQUEST_F | FW_CMD_WRITE_F);
0149 cmdp->retval_len16 = htonl(FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
0150
0151 }
0152
0153
0154
0155
0156
0157
0158
0159
0160
0161 void
0162 csio_mb_reset(struct csio_hw *hw, struct csio_mb *mbp, uint32_t tmo,
0163 int reset, int halt,
0164 void (*cbfn) (struct csio_hw *, struct csio_mb *))
0165 {
0166 struct fw_reset_cmd *cmdp = (struct fw_reset_cmd *)(mbp->mb);
0167
0168 CSIO_INIT_MBP(mbp, cmdp, tmo, hw, cbfn, 1);
0169
0170 cmdp->op_to_write = htonl(FW_CMD_OP_V(FW_RESET_CMD) |
0171 FW_CMD_REQUEST_F | FW_CMD_WRITE_F);
0172 cmdp->retval_len16 = htonl(FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
0173 cmdp->val = htonl(reset);
0174 cmdp->halt_pkd = htonl(halt);
0175
0176 }
0177
0178
0179
0180
0181
0182
0183
0184
0185
0186
0187
0188
0189
0190
0191
0192 void
0193 csio_mb_params(struct csio_hw *hw, struct csio_mb *mbp, uint32_t tmo,
0194 unsigned int pf, unsigned int vf, unsigned int nparams,
0195 const u32 *params, u32 *val, bool wr,
0196 void (*cbfn)(struct csio_hw *, struct csio_mb *))
0197 {
0198 uint32_t i;
0199 uint32_t temp_params = 0, temp_val = 0;
0200 struct fw_params_cmd *cmdp = (struct fw_params_cmd *)(mbp->mb);
0201 __be32 *p = &cmdp->param[0].mnem;
0202
0203 CSIO_INIT_MBP(mbp, cmdp, tmo, hw, cbfn, 1);
0204
0205 cmdp->op_to_vfn = htonl(FW_CMD_OP_V(FW_PARAMS_CMD) |
0206 FW_CMD_REQUEST_F |
0207 (wr ? FW_CMD_WRITE_F : FW_CMD_READ_F) |
0208 FW_PARAMS_CMD_PFN_V(pf) |
0209 FW_PARAMS_CMD_VFN_V(vf));
0210 cmdp->retval_len16 = htonl(FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
0211
0212
0213 if (wr) {
0214 while (nparams--) {
0215 temp_params = *params++;
0216 temp_val = *val++;
0217
0218 *p++ = htonl(temp_params);
0219 *p++ = htonl(temp_val);
0220 }
0221 } else {
0222 for (i = 0; i < nparams; i++, p += 2) {
0223 temp_params = *params++;
0224 *p = htonl(temp_params);
0225 }
0226 }
0227
0228 }
0229
0230
0231
0232
0233
0234
0235
0236
0237
0238
0239 void
0240 csio_mb_process_read_params_rsp(struct csio_hw *hw, struct csio_mb *mbp,
0241 enum fw_retval *retval, unsigned int nparams,
0242 u32 *val)
0243 {
0244 struct fw_params_cmd *rsp = (struct fw_params_cmd *)(mbp->mb);
0245 uint32_t i;
0246 __be32 *p = &rsp->param[0].val;
0247
0248 *retval = FW_CMD_RETVAL_G(ntohl(rsp->retval_len16));
0249
0250 if (*retval == FW_SUCCESS)
0251 for (i = 0; i < nparams; i++, p += 2)
0252 *val++ = ntohl(*p);
0253 }
0254
0255
0256
0257
0258
0259
0260
0261
0262
0263 void
0264 csio_mb_ldst(struct csio_hw *hw, struct csio_mb *mbp, uint32_t tmo, int reg)
0265 {
0266 struct fw_ldst_cmd *ldst_cmd = (struct fw_ldst_cmd *)(mbp->mb);
0267 CSIO_INIT_MBP(mbp, ldst_cmd, tmo, hw, NULL, 1);
0268
0269
0270
0271
0272
0273 ldst_cmd->op_to_addrspace =
0274 htonl(FW_CMD_OP_V(FW_LDST_CMD) |
0275 FW_CMD_REQUEST_F |
0276 FW_CMD_READ_F |
0277 FW_LDST_CMD_ADDRSPACE_V(FW_LDST_ADDRSPC_FUNC_PCIE));
0278 ldst_cmd->cycles_to_len16 = htonl(FW_LEN16(struct fw_ldst_cmd));
0279 ldst_cmd->u.pcie.select_naccess = FW_LDST_CMD_NACCESS_V(1);
0280 ldst_cmd->u.pcie.ctrl_to_fn =
0281 (FW_LDST_CMD_LC_F | FW_LDST_CMD_FN_V(hw->pfn));
0282 ldst_cmd->u.pcie.r = (uint8_t)reg;
0283 }
0284
0285
0286
0287
0288
0289
0290
0291
0292
0293
0294
0295
0296
0297
0298
0299 void
0300 csio_mb_caps_config(struct csio_hw *hw, struct csio_mb *mbp, uint32_t tmo,
0301 bool wr, bool init, bool tgt, bool cofld,
0302 void (*cbfn) (struct csio_hw *, struct csio_mb *))
0303 {
0304 struct fw_caps_config_cmd *cmdp =
0305 (struct fw_caps_config_cmd *)(mbp->mb);
0306
0307 CSIO_INIT_MBP(mbp, cmdp, tmo, hw, cbfn, wr ? 0 : 1);
0308
0309 cmdp->op_to_write = htonl(FW_CMD_OP_V(FW_CAPS_CONFIG_CMD) |
0310 FW_CMD_REQUEST_F |
0311 (wr ? FW_CMD_WRITE_F : FW_CMD_READ_F));
0312 cmdp->cfvalid_to_len16 = htonl(FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
0313
0314
0315 if (!wr)
0316 return;
0317
0318
0319 cmdp->fcoecaps = 0;
0320
0321 if (cofld)
0322 cmdp->fcoecaps |= htons(FW_CAPS_CONFIG_FCOE_CTRL_OFLD);
0323 if (init)
0324 cmdp->fcoecaps |= htons(FW_CAPS_CONFIG_FCOE_INITIATOR);
0325 if (tgt)
0326 cmdp->fcoecaps |= htons(FW_CAPS_CONFIG_FCOE_TARGET);
0327 }
0328
0329
0330
0331
0332
0333
0334
0335
0336
0337
0338
0339
0340
0341 void
0342 csio_mb_port(struct csio_hw *hw, struct csio_mb *mbp, uint32_t tmo,
0343 u8 portid, bool wr, uint32_t fc, uint16_t fw_caps,
0344 void (*cbfn) (struct csio_hw *, struct csio_mb *))
0345 {
0346 struct fw_port_cmd *cmdp = (struct fw_port_cmd *)(mbp->mb);
0347
0348 CSIO_INIT_MBP(mbp, cmdp, tmo, hw, cbfn, 1);
0349
0350 cmdp->op_to_portid = htonl(FW_CMD_OP_V(FW_PORT_CMD) |
0351 FW_CMD_REQUEST_F |
0352 (wr ? FW_CMD_EXEC_F : FW_CMD_READ_F) |
0353 FW_PORT_CMD_PORTID_V(portid));
0354 if (!wr) {
0355 cmdp->action_to_len16 = htonl(
0356 FW_PORT_CMD_ACTION_V(fw_caps == FW_CAPS16
0357 ? FW_PORT_ACTION_GET_PORT_INFO
0358 : FW_PORT_ACTION_GET_PORT_INFO32) |
0359 FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
0360 return;
0361 }
0362
0363
0364 cmdp->action_to_len16 = htonl(
0365 FW_PORT_CMD_ACTION_V(fw_caps == FW_CAPS16
0366 ? FW_PORT_ACTION_L1_CFG
0367 : FW_PORT_ACTION_L1_CFG32) |
0368 FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
0369
0370 if (fw_caps == FW_CAPS16)
0371 cmdp->u.l1cfg.rcap = cpu_to_be32(fwcaps32_to_caps16(fc));
0372 else
0373 cmdp->u.l1cfg32.rcap32 = cpu_to_be32(fc);
0374 }
0375
0376
0377
0378
0379
0380
0381
0382
0383
0384 void
0385 csio_mb_process_read_port_rsp(struct csio_hw *hw, struct csio_mb *mbp,
0386 enum fw_retval *retval, uint16_t fw_caps,
0387 u32 *pcaps, u32 *acaps)
0388 {
0389 struct fw_port_cmd *rsp = (struct fw_port_cmd *)(mbp->mb);
0390
0391 *retval = FW_CMD_RETVAL_G(ntohl(rsp->action_to_len16));
0392
0393 if (*retval == FW_SUCCESS) {
0394 if (fw_caps == FW_CAPS16) {
0395 *pcaps = fwcaps16_to_caps32(ntohs(rsp->u.info.pcap));
0396 *acaps = fwcaps16_to_caps32(ntohs(rsp->u.info.acap));
0397 } else {
0398 *pcaps = be32_to_cpu(rsp->u.info32.pcaps32);
0399 *acaps = be32_to_cpu(rsp->u.info32.acaps32);
0400 }
0401 }
0402 }
0403
0404
0405
0406
0407
0408
0409
0410
0411
0412 void
0413 csio_mb_initialize(struct csio_hw *hw, struct csio_mb *mbp, uint32_t tmo,
0414 void (*cbfn) (struct csio_hw *, struct csio_mb *))
0415 {
0416 struct fw_initialize_cmd *cmdp = (struct fw_initialize_cmd *)(mbp->mb);
0417
0418 CSIO_INIT_MBP(mbp, cmdp, tmo, hw, cbfn, 1);
0419
0420 cmdp->op_to_write = htonl(FW_CMD_OP_V(FW_INITIALIZE_CMD) |
0421 FW_CMD_REQUEST_F | FW_CMD_WRITE_F);
0422 cmdp->retval_len16 = htonl(FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
0423
0424 }
0425
0426
0427
0428
0429
0430
0431
0432
0433
0434
0435
0436
0437
0438
0439 static void
0440 csio_mb_iq_alloc(struct csio_hw *hw, struct csio_mb *mbp, void *priv,
0441 uint32_t mb_tmo, struct csio_iq_params *iq_params,
0442 void (*cbfn) (struct csio_hw *, struct csio_mb *))
0443 {
0444 struct fw_iq_cmd *cmdp = (struct fw_iq_cmd *)(mbp->mb);
0445
0446 CSIO_INIT_MBP(mbp, cmdp, mb_tmo, priv, cbfn, 1);
0447
0448 cmdp->op_to_vfn = htonl(FW_CMD_OP_V(FW_IQ_CMD) |
0449 FW_CMD_REQUEST_F | FW_CMD_EXEC_F |
0450 FW_IQ_CMD_PFN_V(iq_params->pfn) |
0451 FW_IQ_CMD_VFN_V(iq_params->vfn));
0452
0453 cmdp->alloc_to_len16 = htonl(FW_IQ_CMD_ALLOC_F |
0454 FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
0455
0456 cmdp->type_to_iqandstindex = htonl(
0457 FW_IQ_CMD_VIID_V(iq_params->viid) |
0458 FW_IQ_CMD_TYPE_V(iq_params->type) |
0459 FW_IQ_CMD_IQASYNCH_V(iq_params->iqasynch));
0460
0461 cmdp->fl0size = htons(iq_params->fl0size);
0462 cmdp->fl0size = htons(iq_params->fl1size);
0463
0464 }
0465
0466
0467
0468
0469
0470
0471
0472
0473
0474
0475
0476
0477
0478
0479
0480
0481
0482
0483
0484 static void
0485 csio_mb_iq_write(struct csio_hw *hw, struct csio_mb *mbp, void *priv,
0486 uint32_t mb_tmo, bool cascaded_req,
0487 struct csio_iq_params *iq_params,
0488 void (*cbfn) (struct csio_hw *, struct csio_mb *))
0489 {
0490 struct fw_iq_cmd *cmdp = (struct fw_iq_cmd *)(mbp->mb);
0491
0492 uint32_t iq_start_stop = (iq_params->iq_start) ?
0493 FW_IQ_CMD_IQSTART_F :
0494 FW_IQ_CMD_IQSTOP_F;
0495 int relaxed = !(hw->flags & CSIO_HWF_ROOT_NO_RELAXED_ORDERING);
0496
0497
0498
0499
0500
0501
0502 if (!cascaded_req)
0503 CSIO_INIT_MBP(mbp, cmdp, mb_tmo, priv, cbfn, 1);
0504
0505 cmdp->op_to_vfn |= htonl(FW_CMD_OP_V(FW_IQ_CMD) |
0506 FW_CMD_REQUEST_F | FW_CMD_WRITE_F |
0507 FW_IQ_CMD_PFN_V(iq_params->pfn) |
0508 FW_IQ_CMD_VFN_V(iq_params->vfn));
0509 cmdp->alloc_to_len16 |= htonl(iq_start_stop |
0510 FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
0511 cmdp->iqid |= htons(iq_params->iqid);
0512 cmdp->fl0id |= htons(iq_params->fl0id);
0513 cmdp->fl1id |= htons(iq_params->fl1id);
0514 cmdp->type_to_iqandstindex |= htonl(
0515 FW_IQ_CMD_IQANDST_V(iq_params->iqandst) |
0516 FW_IQ_CMD_IQANUS_V(iq_params->iqanus) |
0517 FW_IQ_CMD_IQANUD_V(iq_params->iqanud) |
0518 FW_IQ_CMD_IQANDSTINDEX_V(iq_params->iqandstindex));
0519 cmdp->iqdroprss_to_iqesize |= htons(
0520 FW_IQ_CMD_IQPCIECH_V(iq_params->iqpciech) |
0521 FW_IQ_CMD_IQDCAEN_V(iq_params->iqdcaen) |
0522 FW_IQ_CMD_IQDCACPU_V(iq_params->iqdcacpu) |
0523 FW_IQ_CMD_IQINTCNTTHRESH_V(iq_params->iqintcntthresh) |
0524 FW_IQ_CMD_IQCPRIO_V(iq_params->iqcprio) |
0525 FW_IQ_CMD_IQESIZE_V(iq_params->iqesize));
0526
0527 cmdp->iqsize |= htons(iq_params->iqsize);
0528 cmdp->iqaddr |= cpu_to_be64(iq_params->iqaddr);
0529
0530 if (iq_params->type == 0) {
0531 cmdp->iqns_to_fl0congen |= htonl(
0532 FW_IQ_CMD_IQFLINTIQHSEN_V(iq_params->iqflintiqhsen)|
0533 FW_IQ_CMD_IQFLINTCONGEN_V(iq_params->iqflintcongen));
0534 }
0535
0536 if (iq_params->fl0size && iq_params->fl0addr &&
0537 (iq_params->fl0id != 0xFFFF)) {
0538
0539 cmdp->iqns_to_fl0congen |= htonl(
0540 FW_IQ_CMD_FL0HOSTFCMODE_V(iq_params->fl0hostfcmode)|
0541 FW_IQ_CMD_FL0CPRIO_V(iq_params->fl0cprio) |
0542 FW_IQ_CMD_FL0FETCHRO_V(relaxed) |
0543 FW_IQ_CMD_FL0DATARO_V(relaxed) |
0544 FW_IQ_CMD_FL0PADEN_V(iq_params->fl0paden) |
0545 FW_IQ_CMD_FL0PACKEN_V(iq_params->fl0packen));
0546 cmdp->fl0dcaen_to_fl0cidxfthresh |= htons(
0547 FW_IQ_CMD_FL0DCAEN_V(iq_params->fl0dcaen) |
0548 FW_IQ_CMD_FL0DCACPU_V(iq_params->fl0dcacpu) |
0549 FW_IQ_CMD_FL0FBMIN_V(iq_params->fl0fbmin) |
0550 FW_IQ_CMD_FL0FBMAX_V(iq_params->fl0fbmax) |
0551 FW_IQ_CMD_FL0CIDXFTHRESH_V(iq_params->fl0cidxfthresh));
0552 cmdp->fl0size |= htons(iq_params->fl0size);
0553 cmdp->fl0addr |= cpu_to_be64(iq_params->fl0addr);
0554 }
0555 }
0556
0557
0558
0559
0560
0561
0562
0563
0564
0565
0566
0567
0568
0569
0570 void
0571 csio_mb_iq_alloc_write(struct csio_hw *hw, struct csio_mb *mbp, void *priv,
0572 uint32_t mb_tmo, struct csio_iq_params *iq_params,
0573 void (*cbfn) (struct csio_hw *, struct csio_mb *))
0574 {
0575 csio_mb_iq_alloc(hw, mbp, priv, mb_tmo, iq_params, cbfn);
0576 csio_mb_iq_write(hw, mbp, priv, mb_tmo, true, iq_params, cbfn);
0577 }
0578
0579
0580
0581
0582
0583
0584
0585
0586
0587
0588
0589 void
0590 csio_mb_iq_alloc_write_rsp(struct csio_hw *hw, struct csio_mb *mbp,
0591 enum fw_retval *ret_val,
0592 struct csio_iq_params *iq_params)
0593 {
0594 struct fw_iq_cmd *rsp = (struct fw_iq_cmd *)(mbp->mb);
0595
0596 *ret_val = FW_CMD_RETVAL_G(ntohl(rsp->alloc_to_len16));
0597 if (*ret_val == FW_SUCCESS) {
0598 iq_params->physiqid = ntohs(rsp->physiqid);
0599 iq_params->iqid = ntohs(rsp->iqid);
0600 iq_params->fl0id = ntohs(rsp->fl0id);
0601 iq_params->fl1id = ntohs(rsp->fl1id);
0602 } else {
0603 iq_params->physiqid = iq_params->iqid =
0604 iq_params->fl0id = iq_params->fl1id = 0;
0605 }
0606 }
0607
0608
0609
0610
0611
0612
0613
0614
0615
0616
0617
0618
0619
0620
0621 void
0622 csio_mb_iq_free(struct csio_hw *hw, struct csio_mb *mbp, void *priv,
0623 uint32_t mb_tmo, struct csio_iq_params *iq_params,
0624 void (*cbfn) (struct csio_hw *, struct csio_mb *))
0625 {
0626 struct fw_iq_cmd *cmdp = (struct fw_iq_cmd *)(mbp->mb);
0627
0628 CSIO_INIT_MBP(mbp, cmdp, mb_tmo, priv, cbfn, 1);
0629
0630 cmdp->op_to_vfn = htonl(FW_CMD_OP_V(FW_IQ_CMD) |
0631 FW_CMD_REQUEST_F | FW_CMD_EXEC_F |
0632 FW_IQ_CMD_PFN_V(iq_params->pfn) |
0633 FW_IQ_CMD_VFN_V(iq_params->vfn));
0634 cmdp->alloc_to_len16 = htonl(FW_IQ_CMD_FREE_F |
0635 FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
0636 cmdp->type_to_iqandstindex = htonl(FW_IQ_CMD_TYPE_V(iq_params->type));
0637
0638 cmdp->iqid = htons(iq_params->iqid);
0639 cmdp->fl0id = htons(iq_params->fl0id);
0640 cmdp->fl1id = htons(iq_params->fl1id);
0641
0642 }
0643
0644
0645
0646
0647
0648
0649
0650
0651
0652
0653
0654
0655
0656
0657 static void
0658 csio_mb_eq_ofld_alloc(struct csio_hw *hw, struct csio_mb *mbp, void *priv,
0659 uint32_t mb_tmo, struct csio_eq_params *eq_ofld_params,
0660 void (*cbfn) (struct csio_hw *, struct csio_mb *))
0661 {
0662 struct fw_eq_ofld_cmd *cmdp = (struct fw_eq_ofld_cmd *)(mbp->mb);
0663
0664 CSIO_INIT_MBP(mbp, cmdp, mb_tmo, priv, cbfn, 1);
0665 cmdp->op_to_vfn = htonl(FW_CMD_OP_V(FW_EQ_OFLD_CMD) |
0666 FW_CMD_REQUEST_F | FW_CMD_EXEC_F |
0667 FW_EQ_OFLD_CMD_PFN_V(eq_ofld_params->pfn) |
0668 FW_EQ_OFLD_CMD_VFN_V(eq_ofld_params->vfn));
0669 cmdp->alloc_to_len16 = htonl(FW_EQ_OFLD_CMD_ALLOC_F |
0670 FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
0671
0672 }
0673
0674
0675
0676
0677
0678
0679
0680
0681
0682
0683
0684
0685
0686
0687
0688
0689
0690
0691
0692
0693 static void
0694 csio_mb_eq_ofld_write(struct csio_hw *hw, struct csio_mb *mbp, void *priv,
0695 uint32_t mb_tmo, bool cascaded_req,
0696 struct csio_eq_params *eq_ofld_params,
0697 void (*cbfn) (struct csio_hw *, struct csio_mb *))
0698 {
0699 struct fw_eq_ofld_cmd *cmdp = (struct fw_eq_ofld_cmd *)(mbp->mb);
0700
0701 uint32_t eq_start_stop = (eq_ofld_params->eqstart) ?
0702 FW_EQ_OFLD_CMD_EQSTART_F :
0703 FW_EQ_OFLD_CMD_EQSTOP_F;
0704
0705
0706
0707
0708
0709
0710 if (!cascaded_req)
0711 CSIO_INIT_MBP(mbp, cmdp, mb_tmo, priv, cbfn, 1);
0712
0713 cmdp->op_to_vfn |= htonl(FW_CMD_OP_V(FW_EQ_OFLD_CMD) |
0714 FW_CMD_REQUEST_F | FW_CMD_WRITE_F |
0715 FW_EQ_OFLD_CMD_PFN_V(eq_ofld_params->pfn) |
0716 FW_EQ_OFLD_CMD_VFN_V(eq_ofld_params->vfn));
0717 cmdp->alloc_to_len16 |= htonl(eq_start_stop |
0718 FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
0719
0720 cmdp->eqid_pkd |= htonl(FW_EQ_OFLD_CMD_EQID_V(eq_ofld_params->eqid));
0721
0722 cmdp->fetchszm_to_iqid |= htonl(
0723 FW_EQ_OFLD_CMD_HOSTFCMODE_V(eq_ofld_params->hostfcmode) |
0724 FW_EQ_OFLD_CMD_CPRIO_V(eq_ofld_params->cprio) |
0725 FW_EQ_OFLD_CMD_PCIECHN_V(eq_ofld_params->pciechn) |
0726 FW_EQ_OFLD_CMD_IQID_V(eq_ofld_params->iqid));
0727
0728 cmdp->dcaen_to_eqsize |= htonl(
0729 FW_EQ_OFLD_CMD_DCAEN_V(eq_ofld_params->dcaen) |
0730 FW_EQ_OFLD_CMD_DCACPU_V(eq_ofld_params->dcacpu) |
0731 FW_EQ_OFLD_CMD_FBMIN_V(eq_ofld_params->fbmin) |
0732 FW_EQ_OFLD_CMD_FBMAX_V(eq_ofld_params->fbmax) |
0733 FW_EQ_OFLD_CMD_CIDXFTHRESHO_V(eq_ofld_params->cidxfthresho) |
0734 FW_EQ_OFLD_CMD_CIDXFTHRESH_V(eq_ofld_params->cidxfthresh) |
0735 FW_EQ_OFLD_CMD_EQSIZE_V(eq_ofld_params->eqsize));
0736
0737 cmdp->eqaddr |= cpu_to_be64(eq_ofld_params->eqaddr);
0738
0739 }
0740
0741
0742
0743
0744
0745
0746
0747
0748
0749
0750
0751
0752
0753
0754 void
0755 csio_mb_eq_ofld_alloc_write(struct csio_hw *hw, struct csio_mb *mbp,
0756 void *priv, uint32_t mb_tmo,
0757 struct csio_eq_params *eq_ofld_params,
0758 void (*cbfn) (struct csio_hw *, struct csio_mb *))
0759 {
0760 csio_mb_eq_ofld_alloc(hw, mbp, priv, mb_tmo, eq_ofld_params, cbfn);
0761 csio_mb_eq_ofld_write(hw, mbp, priv, mb_tmo, true,
0762 eq_ofld_params, cbfn);
0763 }
0764
0765
0766
0767
0768
0769
0770
0771
0772
0773
0774
0775 void
0776 csio_mb_eq_ofld_alloc_write_rsp(struct csio_hw *hw,
0777 struct csio_mb *mbp, enum fw_retval *ret_val,
0778 struct csio_eq_params *eq_ofld_params)
0779 {
0780 struct fw_eq_ofld_cmd *rsp = (struct fw_eq_ofld_cmd *)(mbp->mb);
0781
0782 *ret_val = FW_CMD_RETVAL_G(ntohl(rsp->alloc_to_len16));
0783
0784 if (*ret_val == FW_SUCCESS) {
0785 eq_ofld_params->eqid = FW_EQ_OFLD_CMD_EQID_G(
0786 ntohl(rsp->eqid_pkd));
0787 eq_ofld_params->physeqid = FW_EQ_OFLD_CMD_PHYSEQID_G(
0788 ntohl(rsp->physeqid_pkd));
0789 } else
0790 eq_ofld_params->eqid = 0;
0791
0792 }
0793
0794
0795
0796
0797
0798
0799
0800
0801
0802
0803
0804
0805
0806
0807 void
0808 csio_mb_eq_ofld_free(struct csio_hw *hw, struct csio_mb *mbp, void *priv,
0809 uint32_t mb_tmo, struct csio_eq_params *eq_ofld_params,
0810 void (*cbfn) (struct csio_hw *, struct csio_mb *))
0811 {
0812 struct fw_eq_ofld_cmd *cmdp = (struct fw_eq_ofld_cmd *)(mbp->mb);
0813
0814 CSIO_INIT_MBP(mbp, cmdp, mb_tmo, priv, cbfn, 1);
0815
0816 cmdp->op_to_vfn = htonl(FW_CMD_OP_V(FW_EQ_OFLD_CMD) |
0817 FW_CMD_REQUEST_F | FW_CMD_EXEC_F |
0818 FW_EQ_OFLD_CMD_PFN_V(eq_ofld_params->pfn) |
0819 FW_EQ_OFLD_CMD_VFN_V(eq_ofld_params->vfn));
0820 cmdp->alloc_to_len16 = htonl(FW_EQ_OFLD_CMD_FREE_F |
0821 FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
0822 cmdp->eqid_pkd = htonl(FW_EQ_OFLD_CMD_EQID_V(eq_ofld_params->eqid));
0823
0824 }
0825
0826
0827
0828
0829
0830
0831
0832
0833
0834
0835
0836
0837 void
0838 csio_write_fcoe_link_cond_init_mb(struct csio_lnode *ln, struct csio_mb *mbp,
0839 uint32_t mb_tmo, uint8_t port_id, uint32_t sub_opcode,
0840 uint8_t cos, bool link_status, uint32_t fcfi,
0841 void (*cbfn) (struct csio_hw *, struct csio_mb *))
0842 {
0843 struct fw_fcoe_link_cmd *cmdp =
0844 (struct fw_fcoe_link_cmd *)(mbp->mb);
0845
0846 CSIO_INIT_MBP(mbp, cmdp, mb_tmo, ln, cbfn, 1);
0847
0848 cmdp->op_to_portid = htonl((
0849 FW_CMD_OP_V(FW_FCOE_LINK_CMD) |
0850 FW_CMD_REQUEST_F |
0851 FW_CMD_WRITE_F |
0852 FW_FCOE_LINK_CMD_PORTID(port_id)));
0853 cmdp->sub_opcode_fcfi = htonl(
0854 FW_FCOE_LINK_CMD_SUB_OPCODE(sub_opcode) |
0855 FW_FCOE_LINK_CMD_FCFI(fcfi));
0856 cmdp->lstatus = link_status;
0857 cmdp->retval_len16 = htonl(FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
0858
0859 }
0860
0861
0862
0863
0864
0865
0866
0867
0868
0869
0870
0871
0872 void
0873 csio_fcoe_read_res_info_init_mb(struct csio_hw *hw, struct csio_mb *mbp,
0874 uint32_t mb_tmo,
0875 void (*cbfn) (struct csio_hw *, struct csio_mb *))
0876 {
0877 struct fw_fcoe_res_info_cmd *cmdp =
0878 (struct fw_fcoe_res_info_cmd *)(mbp->mb);
0879
0880 CSIO_INIT_MBP(mbp, cmdp, mb_tmo, hw, cbfn, 1);
0881
0882 cmdp->op_to_read = htonl((FW_CMD_OP_V(FW_FCOE_RES_INFO_CMD) |
0883 FW_CMD_REQUEST_F |
0884 FW_CMD_READ_F));
0885
0886 cmdp->retval_len16 = htonl(FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
0887
0888 }
0889
0890
0891
0892
0893
0894
0895
0896
0897
0898
0899
0900
0901
0902
0903
0904
0905
0906 void
0907 csio_fcoe_vnp_alloc_init_mb(struct csio_lnode *ln, struct csio_mb *mbp,
0908 uint32_t mb_tmo, uint32_t fcfi, uint32_t vnpi, uint16_t iqid,
0909 uint8_t vnport_wwnn[8], uint8_t vnport_wwpn[8],
0910 void (*cbfn) (struct csio_hw *, struct csio_mb *))
0911 {
0912 struct fw_fcoe_vnp_cmd *cmdp =
0913 (struct fw_fcoe_vnp_cmd *)(mbp->mb);
0914
0915 CSIO_INIT_MBP(mbp, cmdp, mb_tmo, ln, cbfn, 1);
0916
0917 cmdp->op_to_fcfi = htonl((FW_CMD_OP_V(FW_FCOE_VNP_CMD) |
0918 FW_CMD_REQUEST_F |
0919 FW_CMD_EXEC_F |
0920 FW_FCOE_VNP_CMD_FCFI(fcfi)));
0921
0922 cmdp->alloc_to_len16 = htonl(FW_FCOE_VNP_CMD_ALLOC |
0923 FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
0924
0925 cmdp->gen_wwn_to_vnpi = htonl(FW_FCOE_VNP_CMD_VNPI(vnpi));
0926
0927 cmdp->iqid = htons(iqid);
0928
0929 if (!wwn_to_u64(vnport_wwnn) && !wwn_to_u64(vnport_wwpn))
0930 cmdp->gen_wwn_to_vnpi |= htonl(FW_FCOE_VNP_CMD_GEN_WWN);
0931
0932 if (vnport_wwnn)
0933 memcpy(cmdp->vnport_wwnn, vnport_wwnn, 8);
0934 if (vnport_wwpn)
0935 memcpy(cmdp->vnport_wwpn, vnport_wwpn, 8);
0936
0937 }
0938
0939
0940
0941
0942
0943
0944
0945
0946
0947
0948 void
0949 csio_fcoe_vnp_read_init_mb(struct csio_lnode *ln, struct csio_mb *mbp,
0950 uint32_t mb_tmo, uint32_t fcfi, uint32_t vnpi,
0951 void (*cbfn) (struct csio_hw *, struct csio_mb *))
0952 {
0953 struct fw_fcoe_vnp_cmd *cmdp =
0954 (struct fw_fcoe_vnp_cmd *)(mbp->mb);
0955
0956 CSIO_INIT_MBP(mbp, cmdp, mb_tmo, ln, cbfn, 1);
0957 cmdp->op_to_fcfi = htonl(FW_CMD_OP_V(FW_FCOE_VNP_CMD) |
0958 FW_CMD_REQUEST_F |
0959 FW_CMD_READ_F |
0960 FW_FCOE_VNP_CMD_FCFI(fcfi));
0961 cmdp->alloc_to_len16 = htonl(FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
0962 cmdp->gen_wwn_to_vnpi = htonl(FW_FCOE_VNP_CMD_VNPI(vnpi));
0963 }
0964
0965
0966
0967
0968
0969
0970
0971
0972
0973
0974
0975
0976
0977 void
0978 csio_fcoe_vnp_free_init_mb(struct csio_lnode *ln, struct csio_mb *mbp,
0979 uint32_t mb_tmo, uint32_t fcfi, uint32_t vnpi,
0980 void (*cbfn) (struct csio_hw *, struct csio_mb *))
0981 {
0982 struct fw_fcoe_vnp_cmd *cmdp =
0983 (struct fw_fcoe_vnp_cmd *)(mbp->mb);
0984
0985 CSIO_INIT_MBP(mbp, cmdp, mb_tmo, ln, cbfn, 1);
0986
0987 cmdp->op_to_fcfi = htonl(FW_CMD_OP_V(FW_FCOE_VNP_CMD) |
0988 FW_CMD_REQUEST_F |
0989 FW_CMD_EXEC_F |
0990 FW_FCOE_VNP_CMD_FCFI(fcfi));
0991 cmdp->alloc_to_len16 = htonl(FW_FCOE_VNP_CMD_FREE |
0992 FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
0993 cmdp->gen_wwn_to_vnpi = htonl(FW_FCOE_VNP_CMD_VNPI(vnpi));
0994 }
0995
0996
0997
0998
0999
1000
1001
1002
1003
1004
1005
1006
1007
1008 void
1009 csio_fcoe_read_fcf_init_mb(struct csio_lnode *ln, struct csio_mb *mbp,
1010 uint32_t mb_tmo, uint32_t portid, uint32_t fcfi,
1011 void (*cbfn) (struct csio_hw *, struct csio_mb *))
1012 {
1013 struct fw_fcoe_fcf_cmd *cmdp =
1014 (struct fw_fcoe_fcf_cmd *)(mbp->mb);
1015
1016 CSIO_INIT_MBP(mbp, cmdp, mb_tmo, ln, cbfn, 1);
1017
1018 cmdp->op_to_fcfi = htonl(FW_CMD_OP_V(FW_FCOE_FCF_CMD) |
1019 FW_CMD_REQUEST_F |
1020 FW_CMD_READ_F |
1021 FW_FCOE_FCF_CMD_FCFI(fcfi));
1022 cmdp->retval_len16 = htonl(FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
1023
1024 }
1025
1026 void
1027 csio_fcoe_read_portparams_init_mb(struct csio_hw *hw, struct csio_mb *mbp,
1028 uint32_t mb_tmo,
1029 struct fw_fcoe_port_cmd_params *portparams,
1030 void (*cbfn)(struct csio_hw *,
1031 struct csio_mb *))
1032 {
1033 struct fw_fcoe_stats_cmd *cmdp = (struct fw_fcoe_stats_cmd *)(mbp->mb);
1034
1035 CSIO_INIT_MBP(mbp, cmdp, mb_tmo, hw, cbfn, 1);
1036 mbp->mb_size = 64;
1037
1038 cmdp->op_to_flowid = htonl(FW_CMD_OP_V(FW_FCOE_STATS_CMD) |
1039 FW_CMD_REQUEST_F | FW_CMD_READ_F);
1040 cmdp->free_to_len16 = htonl(FW_CMD_LEN16_V(CSIO_MAX_MB_SIZE/16));
1041
1042 cmdp->u.ctl.nstats_port = FW_FCOE_STATS_CMD_NSTATS(portparams->nstats) |
1043 FW_FCOE_STATS_CMD_PORT(portparams->portid);
1044
1045 cmdp->u.ctl.port_valid_ix = FW_FCOE_STATS_CMD_IX(portparams->idx) |
1046 FW_FCOE_STATS_CMD_PORT_VALID;
1047
1048 }
1049
1050 void
1051 csio_mb_process_portparams_rsp(struct csio_hw *hw,
1052 struct csio_mb *mbp,
1053 enum fw_retval *retval,
1054 struct fw_fcoe_port_cmd_params *portparams,
1055 struct fw_fcoe_port_stats *portstats)
1056 {
1057 struct fw_fcoe_stats_cmd *rsp = (struct fw_fcoe_stats_cmd *)(mbp->mb);
1058 struct fw_fcoe_port_stats stats;
1059 uint8_t *src;
1060 uint8_t *dst;
1061
1062 *retval = FW_CMD_RETVAL_G(ntohl(rsp->free_to_len16));
1063
1064 memset(&stats, 0, sizeof(struct fw_fcoe_port_stats));
1065
1066 if (*retval == FW_SUCCESS) {
1067 dst = (uint8_t *)(&stats) + ((portparams->idx - 1) * 8);
1068 src = (uint8_t *)rsp + (CSIO_STATS_OFFSET * 8);
1069 memcpy(dst, src, (portparams->nstats * 8));
1070 if (portparams->idx == 1) {
1071
1072 portstats->tx_bcast_bytes = stats.tx_bcast_bytes;
1073 portstats->tx_bcast_frames = stats.tx_bcast_frames;
1074 portstats->tx_mcast_bytes = stats.tx_mcast_bytes;
1075 portstats->tx_mcast_frames = stats.tx_mcast_frames;
1076 portstats->tx_ucast_bytes = stats.tx_ucast_bytes;
1077 portstats->tx_ucast_frames = stats.tx_ucast_frames;
1078 }
1079 if (portparams->idx == 7) {
1080
1081 portstats->tx_drop_frames = stats.tx_drop_frames;
1082 portstats->tx_offload_bytes = stats.tx_offload_bytes;
1083 portstats->tx_offload_frames = stats.tx_offload_frames;
1084 #if 0
1085 portstats->rx_pf_bytes = stats.rx_pf_bytes;
1086 portstats->rx_pf_frames = stats.rx_pf_frames;
1087 #endif
1088 portstats->rx_bcast_bytes = stats.rx_bcast_bytes;
1089 portstats->rx_bcast_frames = stats.rx_bcast_frames;
1090 portstats->rx_mcast_bytes = stats.rx_mcast_bytes;
1091 }
1092 if (portparams->idx == 13) {
1093
1094 portstats->rx_mcast_frames = stats.rx_mcast_frames;
1095 portstats->rx_ucast_bytes = stats.rx_ucast_bytes;
1096 portstats->rx_ucast_frames = stats.rx_ucast_frames;
1097 portstats->rx_err_frames = stats.rx_err_frames;
1098 }
1099 }
1100 }
1101
1102
1103
1104
1105
1106
1107
1108
1109 void
1110 csio_mb_intr_enable(struct csio_hw *hw)
1111 {
1112 csio_wr_reg32(hw, MBMSGRDYINTEN_F, MYPF_REG(CIM_PF_HOST_INT_ENABLE_A));
1113 csio_rd_reg32(hw, MYPF_REG(CIM_PF_HOST_INT_ENABLE_A));
1114 }
1115
1116
1117
1118
1119
1120
1121
1122 void
1123 csio_mb_intr_disable(struct csio_hw *hw)
1124 {
1125 csio_wr_reg32(hw, MBMSGRDYINTEN_V(0),
1126 MYPF_REG(CIM_PF_HOST_INT_ENABLE_A));
1127 csio_rd_reg32(hw, MYPF_REG(CIM_PF_HOST_INT_ENABLE_A));
1128 }
1129
1130 static void
1131 csio_mb_dump_fw_dbg(struct csio_hw *hw, __be64 *cmd)
1132 {
1133 struct fw_debug_cmd *dbg = (struct fw_debug_cmd *)cmd;
1134
1135 if ((FW_DEBUG_CMD_TYPE_G(ntohl(dbg->op_type))) == 1) {
1136 csio_info(hw, "FW print message:\n");
1137 csio_info(hw, "\tdebug->dprtstridx = %d\n",
1138 ntohs(dbg->u.prt.dprtstridx));
1139 csio_info(hw, "\tdebug->dprtstrparam0 = 0x%x\n",
1140 ntohl(dbg->u.prt.dprtstrparam0));
1141 csio_info(hw, "\tdebug->dprtstrparam1 = 0x%x\n",
1142 ntohl(dbg->u.prt.dprtstrparam1));
1143 csio_info(hw, "\tdebug->dprtstrparam2 = 0x%x\n",
1144 ntohl(dbg->u.prt.dprtstrparam2));
1145 csio_info(hw, "\tdebug->dprtstrparam3 = 0x%x\n",
1146 ntohl(dbg->u.prt.dprtstrparam3));
1147 } else {
1148
1149 csio_fatal(hw, "FW assertion at %.16s:%u, val0 %#x, val1 %#x\n",
1150 dbg->u.assert.filename_0_7,
1151 ntohl(dbg->u.assert.line),
1152 ntohl(dbg->u.assert.x),
1153 ntohl(dbg->u.assert.y));
1154 }
1155 }
1156
1157 static void
1158 csio_mb_debug_cmd_handler(struct csio_hw *hw)
1159 {
1160 int i;
1161 __be64 cmd[CSIO_MB_MAX_REGS];
1162 uint32_t ctl_reg = PF_REG(hw->pfn, CIM_PF_MAILBOX_CTRL_A);
1163 uint32_t data_reg = PF_REG(hw->pfn, CIM_PF_MAILBOX_DATA_A);
1164 int size = sizeof(struct fw_debug_cmd);
1165
1166
1167 for (i = 0; i < size; i += 8)
1168 cmd[i / 8] = cpu_to_be64(csio_rd_reg64(hw, data_reg + i));
1169
1170 csio_mb_dump_fw_dbg(hw, cmd);
1171
1172
1173 csio_wr_reg32(hw, MBMSGVALID_F | MBINTREQ_F |
1174 MBOWNER_V(CSIO_MBOWNER_FW), ctl_reg);
1175
1176 csio_rd_reg32(hw, ctl_reg);
1177 wmb();
1178 }
1179
1180
1181
1182
1183
1184
1185
1186
1187 int
1188 csio_mb_issue(struct csio_hw *hw, struct csio_mb *mbp)
1189 {
1190 uint32_t owner, ctl;
1191 int i;
1192 uint32_t ii;
1193 __be64 *cmd = mbp->mb;
1194 __be64 hdr;
1195 struct csio_mbm *mbm = &hw->mbm;
1196 uint32_t ctl_reg = PF_REG(hw->pfn, CIM_PF_MAILBOX_CTRL_A);
1197 uint32_t data_reg = PF_REG(hw->pfn, CIM_PF_MAILBOX_DATA_A);
1198 int size = mbp->mb_size;
1199 int rv = -EINVAL;
1200 struct fw_cmd_hdr *fw_hdr;
1201
1202
1203 if (mbp->mb_cbfn == NULL) {
1204
1205 if (mbp->tmo < CSIO_MB_POLL_FREQ) {
1206 csio_err(hw, "Invalid tmo: 0x%x\n", mbp->tmo);
1207 goto error_out;
1208 }
1209 } else if (!csio_is_host_intr_enabled(hw) ||
1210 !csio_is_hw_intr_enabled(hw)) {
1211 csio_err(hw, "Cannot issue mailbox in interrupt mode 0x%x\n",
1212 *((uint8_t *)mbp->mb));
1213 goto error_out;
1214 }
1215
1216 if (mbm->mcurrent != NULL) {
1217
1218 if (mbp->mb_cbfn == NULL) {
1219 rv = -EBUSY;
1220 csio_dbg(hw, "Couldn't own Mailbox %x op:0x%x\n",
1221 hw->pfn, *((uint8_t *)mbp->mb));
1222
1223 goto error_out;
1224 } else {
1225 list_add_tail(&mbp->list, &mbm->req_q);
1226 CSIO_INC_STATS(mbm, n_activeq);
1227
1228 return 0;
1229 }
1230 }
1231
1232
1233 owner = MBOWNER_G(csio_rd_reg32(hw, ctl_reg));
1234
1235 if (!csio_mb_is_host_owner(owner)) {
1236
1237 for (i = 0; (owner == CSIO_MBOWNER_NONE) && (i < 3); i++)
1238 owner = MBOWNER_G(csio_rd_reg32(hw, ctl_reg));
1239
1240
1241
1242
1243 if (!csio_mb_is_host_owner(owner)) {
1244 if (mbp->mb_cbfn == NULL) {
1245 rv = owner ? -EBUSY : -ETIMEDOUT;
1246
1247 csio_dbg(hw,
1248 "Couldn't own Mailbox %x op:0x%x "
1249 "owner:%x\n",
1250 hw->pfn, *((uint8_t *)mbp->mb), owner);
1251 goto error_out;
1252 } else {
1253 if (mbm->mcurrent == NULL) {
1254 csio_err(hw,
1255 "Couldn't own Mailbox %x "
1256 "op:0x%x owner:%x\n",
1257 hw->pfn, *((uint8_t *)mbp->mb),
1258 owner);
1259 csio_err(hw,
1260 "No outstanding driver"
1261 " mailbox as well\n");
1262 goto error_out;
1263 }
1264 }
1265 }
1266 }
1267
1268
1269 for (i = 0; i < size; i += 8) {
1270 csio_wr_reg64(hw, be64_to_cpu(*cmd), data_reg + i);
1271 cmd++;
1272 }
1273
1274 CSIO_DUMP_MB(hw, hw->pfn, data_reg);
1275
1276
1277 if (mbp->mb_cbfn != NULL) {
1278 mbm->mcurrent = mbp;
1279 mod_timer(&mbm->timer, jiffies + msecs_to_jiffies(mbp->tmo));
1280 csio_wr_reg32(hw, MBMSGVALID_F | MBINTREQ_F |
1281 MBOWNER_V(CSIO_MBOWNER_FW), ctl_reg);
1282 } else
1283 csio_wr_reg32(hw, MBMSGVALID_F | MBOWNER_V(CSIO_MBOWNER_FW),
1284 ctl_reg);
1285
1286
1287 csio_rd_reg32(hw, ctl_reg);
1288 wmb();
1289
1290 CSIO_INC_STATS(mbm, n_req);
1291
1292 if (mbp->mb_cbfn)
1293 return 0;
1294
1295
1296 cmd = mbp->mb;
1297
1298 for (ii = 0; ii < mbp->tmo; ii += CSIO_MB_POLL_FREQ) {
1299 mdelay(CSIO_MB_POLL_FREQ);
1300
1301
1302 ctl = csio_rd_reg32(hw, ctl_reg);
1303 if (csio_mb_is_host_owner(MBOWNER_G(ctl))) {
1304
1305 if (!(ctl & MBMSGVALID_F)) {
1306 csio_wr_reg32(hw, 0, ctl_reg);
1307 continue;
1308 }
1309
1310 CSIO_DUMP_MB(hw, hw->pfn, data_reg);
1311
1312 hdr = cpu_to_be64(csio_rd_reg64(hw, data_reg));
1313 fw_hdr = (struct fw_cmd_hdr *)&hdr;
1314
1315 switch (FW_CMD_OP_G(ntohl(fw_hdr->hi))) {
1316 case FW_DEBUG_CMD:
1317 csio_mb_debug_cmd_handler(hw);
1318 continue;
1319 }
1320
1321
1322 for (i = 0; i < size; i += 8)
1323 *cmd++ = cpu_to_be64(csio_rd_reg64
1324 (hw, data_reg + i));
1325 csio_wr_reg32(hw, 0, ctl_reg);
1326
1327 if (csio_mb_fw_retval(mbp) != FW_SUCCESS)
1328 CSIO_INC_STATS(mbm, n_err);
1329
1330 CSIO_INC_STATS(mbm, n_rsp);
1331 return 0;
1332 }
1333 }
1334
1335 CSIO_INC_STATS(mbm, n_tmo);
1336
1337 csio_err(hw, "Mailbox %x op:0x%x timed out!\n",
1338 hw->pfn, *((uint8_t *)cmd));
1339
1340 return -ETIMEDOUT;
1341
1342 error_out:
1343 CSIO_INC_STATS(mbm, n_err);
1344 return rv;
1345 }
1346
1347
1348
1349
1350
1351
1352
1353 void
1354 csio_mb_completions(struct csio_hw *hw, struct list_head *cbfn_q)
1355 {
1356 struct csio_mb *mbp;
1357 struct csio_mbm *mbm = &hw->mbm;
1358 enum fw_retval rv;
1359
1360 while (!list_empty(cbfn_q)) {
1361 mbp = list_first_entry(cbfn_q, struct csio_mb, list);
1362 list_del_init(&mbp->list);
1363
1364 rv = csio_mb_fw_retval(mbp);
1365 if ((rv != FW_SUCCESS) && (rv != FW_HOSTERROR))
1366 CSIO_INC_STATS(mbm, n_err);
1367 else if (rv != FW_HOSTERROR)
1368 CSIO_INC_STATS(mbm, n_rsp);
1369
1370 if (mbp->mb_cbfn)
1371 mbp->mb_cbfn(hw, mbp);
1372 }
1373 }
1374
1375 static void
1376 csio_mb_portmod_changed(struct csio_hw *hw, uint8_t port_id)
1377 {
1378 static char *mod_str[] = {
1379 NULL, "LR", "SR", "ER", "TWINAX", "active TWINAX", "LRM"
1380 };
1381
1382 struct csio_pport *port = &hw->pport[port_id];
1383
1384 if (port->mod_type == FW_PORT_MOD_TYPE_NONE)
1385 csio_info(hw, "Port:%d - port module unplugged\n", port_id);
1386 else if (port->mod_type < ARRAY_SIZE(mod_str))
1387 csio_info(hw, "Port:%d - %s port module inserted\n", port_id,
1388 mod_str[port->mod_type]);
1389 else if (port->mod_type == FW_PORT_MOD_TYPE_NOTSUPPORTED)
1390 csio_info(hw,
1391 "Port:%d - unsupported optical port module "
1392 "inserted\n", port_id);
1393 else if (port->mod_type == FW_PORT_MOD_TYPE_UNKNOWN)
1394 csio_info(hw,
1395 "Port:%d - unknown port module inserted, forcing "
1396 "TWINAX\n", port_id);
1397 else if (port->mod_type == FW_PORT_MOD_TYPE_ERROR)
1398 csio_info(hw, "Port:%d - transceiver module error\n", port_id);
1399 else
1400 csio_info(hw, "Port:%d - unknown module type %d inserted\n",
1401 port_id, port->mod_type);
1402 }
1403
1404 int
1405 csio_mb_fwevt_handler(struct csio_hw *hw, __be64 *cmd)
1406 {
1407 uint8_t opcode = *(uint8_t *)cmd;
1408 struct fw_port_cmd *pcmd;
1409 uint8_t port_id;
1410 uint32_t link_status;
1411 uint16_t action;
1412 uint8_t mod_type;
1413 fw_port_cap32_t linkattr;
1414
1415 if (opcode == FW_PORT_CMD) {
1416 pcmd = (struct fw_port_cmd *)cmd;
1417 port_id = FW_PORT_CMD_PORTID_G(
1418 ntohl(pcmd->op_to_portid));
1419 action = FW_PORT_CMD_ACTION_G(
1420 ntohl(pcmd->action_to_len16));
1421 if (action != FW_PORT_ACTION_GET_PORT_INFO &&
1422 action != FW_PORT_ACTION_GET_PORT_INFO32) {
1423 csio_err(hw, "Unhandled FW_PORT_CMD action: %u\n",
1424 action);
1425 return -EINVAL;
1426 }
1427
1428 if (action == FW_PORT_ACTION_GET_PORT_INFO) {
1429 link_status = ntohl(pcmd->u.info.lstatus_to_modtype);
1430 mod_type = FW_PORT_CMD_MODTYPE_G(link_status);
1431 linkattr = lstatus_to_fwcap(link_status);
1432
1433 hw->pport[port_id].link_status =
1434 FW_PORT_CMD_LSTATUS_G(link_status);
1435 } else {
1436 link_status =
1437 ntohl(pcmd->u.info32.lstatus32_to_cbllen32);
1438 mod_type = FW_PORT_CMD_MODTYPE32_G(link_status);
1439 linkattr = ntohl(pcmd->u.info32.linkattr32);
1440
1441 hw->pport[port_id].link_status =
1442 FW_PORT_CMD_LSTATUS32_G(link_status);
1443 }
1444
1445 hw->pport[port_id].link_speed = fwcap_to_fwspeed(linkattr);
1446
1447 csio_info(hw, "Port:%x - LINK %s\n", port_id,
1448 hw->pport[port_id].link_status ? "UP" : "DOWN");
1449
1450 if (mod_type != hw->pport[port_id].mod_type) {
1451 hw->pport[port_id].mod_type = mod_type;
1452 csio_mb_portmod_changed(hw, port_id);
1453 }
1454 } else if (opcode == FW_DEBUG_CMD) {
1455 csio_mb_dump_fw_dbg(hw, cmd);
1456 } else {
1457 csio_dbg(hw, "Gen MB can't handle op:0x%x on evtq.\n", opcode);
1458 return -EINVAL;
1459 }
1460
1461 return 0;
1462 }
1463
1464
1465
1466
1467
1468
1469
1470
1471 int
1472 csio_mb_isr_handler(struct csio_hw *hw)
1473 {
1474 struct csio_mbm *mbm = &hw->mbm;
1475 struct csio_mb *mbp = mbm->mcurrent;
1476 __be64 *cmd;
1477 uint32_t ctl, cim_cause, pl_cause;
1478 int i;
1479 uint32_t ctl_reg = PF_REG(hw->pfn, CIM_PF_MAILBOX_CTRL_A);
1480 uint32_t data_reg = PF_REG(hw->pfn, CIM_PF_MAILBOX_DATA_A);
1481 int size;
1482 __be64 hdr;
1483 struct fw_cmd_hdr *fw_hdr;
1484
1485 pl_cause = csio_rd_reg32(hw, MYPF_REG(PL_PF_INT_CAUSE_A));
1486 cim_cause = csio_rd_reg32(hw, MYPF_REG(CIM_PF_HOST_INT_CAUSE_A));
1487
1488 if (!(pl_cause & PFCIM_F) || !(cim_cause & MBMSGRDYINT_F)) {
1489 CSIO_INC_STATS(hw, n_mbint_unexp);
1490 return -EINVAL;
1491 }
1492
1493
1494
1495
1496
1497
1498
1499 csio_wr_reg32(hw, MBMSGRDYINT_F, MYPF_REG(CIM_PF_HOST_INT_CAUSE_A));
1500 csio_wr_reg32(hw, PFCIM_F, MYPF_REG(PL_PF_INT_CAUSE_A));
1501
1502 ctl = csio_rd_reg32(hw, ctl_reg);
1503
1504 if (csio_mb_is_host_owner(MBOWNER_G(ctl))) {
1505
1506 CSIO_DUMP_MB(hw, hw->pfn, data_reg);
1507
1508 if (!(ctl & MBMSGVALID_F)) {
1509 csio_warn(hw,
1510 "Stray mailbox interrupt recvd,"
1511 " mailbox data not valid\n");
1512 csio_wr_reg32(hw, 0, ctl_reg);
1513
1514 csio_rd_reg32(hw, ctl_reg);
1515 return -EINVAL;
1516 }
1517
1518 hdr = cpu_to_be64(csio_rd_reg64(hw, data_reg));
1519 fw_hdr = (struct fw_cmd_hdr *)&hdr;
1520
1521 switch (FW_CMD_OP_G(ntohl(fw_hdr->hi))) {
1522 case FW_DEBUG_CMD:
1523 csio_mb_debug_cmd_handler(hw);
1524 return -EINVAL;
1525 #if 0
1526 case FW_ERROR_CMD:
1527 case FW_INITIALIZE_CMD:
1528 #endif
1529 }
1530
1531 CSIO_ASSERT(mbp != NULL);
1532
1533 cmd = mbp->mb;
1534 size = mbp->mb_size;
1535
1536 for (i = 0; i < size; i += 8)
1537 *cmd++ = cpu_to_be64(csio_rd_reg64
1538 (hw, data_reg + i));
1539
1540 csio_wr_reg32(hw, 0, ctl_reg);
1541
1542 csio_rd_reg32(hw, ctl_reg);
1543
1544 mbm->mcurrent = NULL;
1545
1546
1547 list_add_tail(&mbp->list, &mbm->cbfn_q);
1548 CSIO_INC_STATS(mbm, n_cbfnq);
1549
1550
1551
1552
1553
1554 if (csio_enqueue_evt(hw, CSIO_EVT_MBX, mbp, sizeof(mbp)))
1555 CSIO_INC_STATS(hw, n_evt_drop);
1556
1557 return 0;
1558
1559 } else {
1560
1561
1562
1563
1564 csio_dbg(hw, "Host not owner, no mailbox interrupt\n");
1565 CSIO_INC_STATS(hw, n_int_stray);
1566 return -EINVAL;
1567 }
1568 }
1569
1570
1571
1572
1573
1574
1575 struct csio_mb *
1576 csio_mb_tmo_handler(struct csio_hw *hw)
1577 {
1578 struct csio_mbm *mbm = &hw->mbm;
1579 struct csio_mb *mbp = mbm->mcurrent;
1580 struct fw_cmd_hdr *fw_hdr;
1581
1582
1583
1584
1585
1586 if (mbp == NULL) {
1587 CSIO_DB_ASSERT(0);
1588 return NULL;
1589 }
1590
1591 fw_hdr = (struct fw_cmd_hdr *)(mbp->mb);
1592
1593 csio_dbg(hw, "Mailbox num:%x op:0x%x timed out\n", hw->pfn,
1594 FW_CMD_OP_G(ntohl(fw_hdr->hi)));
1595
1596 mbm->mcurrent = NULL;
1597 CSIO_INC_STATS(mbm, n_tmo);
1598 fw_hdr->lo = htonl(FW_CMD_RETVAL_V(FW_ETIMEDOUT));
1599
1600 return mbp;
1601 }
1602
1603
1604
1605
1606
1607
1608
1609
1610 void
1611 csio_mb_cancel_all(struct csio_hw *hw, struct list_head *cbfn_q)
1612 {
1613 struct csio_mb *mbp;
1614 struct csio_mbm *mbm = &hw->mbm;
1615 struct fw_cmd_hdr *hdr;
1616 struct list_head *tmp;
1617
1618 if (mbm->mcurrent) {
1619 mbp = mbm->mcurrent;
1620
1621
1622 del_timer_sync(&mbm->timer);
1623
1624
1625 list_add_tail(&mbp->list, cbfn_q);
1626 mbm->mcurrent = NULL;
1627 }
1628
1629 if (!list_empty(&mbm->req_q)) {
1630 list_splice_tail_init(&mbm->req_q, cbfn_q);
1631 mbm->stats.n_activeq = 0;
1632 }
1633
1634 if (!list_empty(&mbm->cbfn_q)) {
1635 list_splice_tail_init(&mbm->cbfn_q, cbfn_q);
1636 mbm->stats.n_cbfnq = 0;
1637 }
1638
1639 if (list_empty(cbfn_q))
1640 return;
1641
1642 list_for_each(tmp, cbfn_q) {
1643 mbp = (struct csio_mb *)tmp;
1644 hdr = (struct fw_cmd_hdr *)(mbp->mb);
1645
1646 csio_dbg(hw, "Cancelling pending mailbox num %x op:%x\n",
1647 hw->pfn, FW_CMD_OP_G(ntohl(hdr->hi)));
1648
1649 CSIO_INC_STATS(mbm, n_cancel);
1650 hdr->lo = htonl(FW_CMD_RETVAL_V(FW_HOSTERROR));
1651 }
1652 }
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662 int
1663 csio_mbm_init(struct csio_mbm *mbm, struct csio_hw *hw,
1664 void (*timer_fn)(struct timer_list *))
1665 {
1666 mbm->hw = hw;
1667 timer_setup(&mbm->timer, timer_fn, 0);
1668
1669 INIT_LIST_HEAD(&mbm->req_q);
1670 INIT_LIST_HEAD(&mbm->cbfn_q);
1671 csio_set_mb_intr_idx(mbm, -1);
1672
1673 return 0;
1674 }
1675
1676
1677
1678
1679
1680
1681
1682 void
1683 csio_mbm_exit(struct csio_mbm *mbm)
1684 {
1685 del_timer_sync(&mbm->timer);
1686
1687 CSIO_DB_ASSERT(mbm->mcurrent == NULL);
1688 CSIO_DB_ASSERT(list_empty(&mbm->req_q));
1689 CSIO_DB_ASSERT(list_empty(&mbm->cbfn_q));
1690 }