Print this page
MFV: illumos-gate@bbb9d5d65bf8372aae4b8821c80e218b8b832846
9994 cxgbe t4nex: Handle get_fl_payload() alloc failures
9995 cxgbe t4_devo_attach() should initialize ->sfl
Reviewed by: Toomas Soome <tsoome@me.com>
Reviewed by: Garrett D'Amore <garrett@damore.org>
Approved by: Dan McDonald <danmcd@joyent.com>
Author: John Levon <john.levon@joyent.com>
9484 cxgbe should clean TX descriptors in timely manner
Reviewed by: Patrick Mooney <patrick.mooney@joyent.com>
Reviewed by: Ryan Zezeski <rpz@joyent.com>
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
Reviewed by: Toomas Soome <tsoome@me.com>
Approved by: Dan McDonald <danmcd@joyent.com>

Split Close
Expand all
Collapse all
          --- old/usr/src/uts/common/io/cxgbe/t4nex/t4_sge.c
          +++ new/usr/src/uts/common/io/cxgbe/t4nex/t4_sge.c
↓ open down ↓ 685 lines elided ↑ open up ↑
 686  686          if (mp != NULL)
 687  687                  mac_rx_ring(rxq->port->mh, rxq->ring_handle, mp,
 688  688                              rxq->ring_gen_num);
 689  689  }
 690  690  
 691  691  /* Deals with interrupts on the given ingress queue */
 692  692  /* ARGSUSED */
 693  693  uint_t
 694  694  t4_intr(caddr_t arg1, caddr_t arg2)
 695  695  {
 696      -        /* LINTED: E_BAD_PTR_CAST_ALIGN */
 697  696          struct sge_iq *iq = (struct sge_iq *)arg2;
 698  697          int state;
 699  698  
 700  699          /* Right now receive polling is only enabled for MSI-X and
 701  700           * when we have enough msi-x vectors i.e no interrupt forwarding.
 702  701           */
 703  702          if (iq->adapter->props.multi_rings) {
 704  703                  t4_intr_rx_work(iq);
 705  704          } else {
 706  705                  state = atomic_cas_uint(&iq->state, IQS_IDLE, IQS_BUSY);
↓ open down ↓ 62 lines elided ↑ open up ↑
 769  768                          ASSERT(iq->flags & IQ_HAS_FL);
 770  769  
 771  770                          if (CPL_RX_PKT == rss->opcode) {
 772  771                                  cpl = (void *)(rss + 1);
 773  772                                  pkt_len = be16_to_cpu(cpl->len);
 774  773  
 775  774                                  if (iq->polling && ((received_bytes + pkt_len) > budget))
 776  775                                          goto done;
 777  776  
 778  777                                  m = get_fl_payload(sc, fl, lq, &fl_bufs_used);
 779      -                                if (m == NULL) {
 780      -                                        panic("%s: line %d.", __func__,
 781      -                                            __LINE__);
 782      -                                }
      778 +                                if (m == NULL)
      779 +                                        goto done;
 783  780  
 784  781                                  iq->intr_next = iq->intr_params;
 785  782                                  m->b_rptr += sc->sge.pktshift;
 786  783                                  if (sc->params.tp.rx_pkt_encap)
 787  784                                  /* It is enabled only in T6 config file */
 788  785                                          err_vec = G_T6_COMPR_RXERR_VEC(ntohs(cpl->err_vec));
 789  786                                  else
 790  787                                          err_vec = ntohs(cpl->err_vec);
 791  788  
 792  789                                  csum_ok = cpl->csum_calc && !err_vec;
↓ open down ↓ 9 lines elided ↑ open up ↑
 802  799                                  rxq->rxbytes += pkt_len;
 803  800                                  received_bytes += pkt_len;
 804  801  
 805  802                                  *mblk_tail = m;
 806  803                                  mblk_tail = &m->b_next;
 807  804  
 808  805                                  break;
 809  806                          }
 810  807  
 811  808                          m = get_fl_payload(sc, fl, lq, &fl_bufs_used);
 812      -                        if (m == NULL) {
 813      -                                panic("%s: line %d.", __func__,
 814      -                                    __LINE__);
 815      -                        }
      809 +                        if (m == NULL)
      810 +                                goto done;
      811 +                        /* FALLTHROUGH */
 816  812  
 817  813                  case X_RSPD_TYPE_CPL:
 818  814                          ASSERT(rss->opcode < NUM_CPL_CMDS);
 819  815                          sc->cpl_handler[rss->opcode](iq, rss, m);
 820  816                          break;
 821  817  
 822  818                  default:
 823  819                          break;
 824  820                  }
 825  821                  iq_next(iq);
↓ open down ↓ 28 lines elided ↑ open up ↑
 854  850  {
 855  851          struct sge_iq *q;
 856  852          struct sge_rxq *rxq = iq_to_rxq(iq);    /* Use iff iq is part of rxq */
 857  853          struct sge_fl *fl = &rxq->fl;           /* Use iff IQ_HAS_FL */
 858  854          struct adapter *sc = iq->adapter;
 859  855          struct rsp_ctrl *ctrl;
 860  856          const struct rss_header *rss;
 861  857          int ndescs = 0, limit, fl_bufs_used = 0;
 862  858          int rsp_type;
 863  859          uint32_t lq;
      860 +        int starved;
 864  861          mblk_t *m;
 865  862          STAILQ_HEAD(, sge_iq) iql = STAILQ_HEAD_INITIALIZER(iql);
 866  863  
 867  864          limit = budget ? budget : iq->qsize / 8;
 868  865  
 869  866          /*
 870  867           * We always come back and check the descriptor ring for new indirect
 871  868           * interrupts and other responses after running a single handler.
 872  869           */
 873  870          for (;;) {
↓ open down ↓ 6 lines elided ↑ open up ↑
 880  877                          lq = be32_to_cpu(ctrl->pldbuflen_qid);
 881  878                          rss = (const void *)iq->cdesc;
 882  879  
 883  880                          switch (rsp_type) {
 884  881                          case X_RSPD_TYPE_FLBUF:
 885  882  
 886  883                                  ASSERT(iq->flags & IQ_HAS_FL);
 887  884  
 888  885                                  m = get_fl_payload(sc, fl, lq, &fl_bufs_used);
 889  886                                  if (m == NULL) {
 890      -                                        panic("%s: line %d.", __func__,
 891      -                                            __LINE__);
      887 +                                        /*
      888 +                                         * Rearm the iq with a
      889 +                                         * longer-than-default timer
      890 +                                         */
      891 +                                        t4_write_reg(sc, MYPF_REG(A_SGE_PF_GTS), V_CIDXINC(ndescs) |
      892 +                                                        V_INGRESSQID((u32)iq->cntxt_id) |
      893 +                                                        V_SEINTARM(V_QINTR_TIMER_IDX(SGE_NTIMERS-1)));
      894 +                                        if (fl_bufs_used > 0) {
      895 +                                                ASSERT(iq->flags & IQ_HAS_FL);
      896 +                                                FL_LOCK(fl);
      897 +                                                fl->needed += fl_bufs_used;
      898 +                                                starved = refill_fl(sc, fl, fl->cap / 8);
      899 +                                                FL_UNLOCK(fl);
      900 +                                                if (starved)
      901 +                                                        add_fl_to_sfl(sc, fl);
      902 +                                        }
      903 +                                        return (0);
 892  904                                  }
 893  905  
 894  906                          /* FALLTHRU */
 895  907                          case X_RSPD_TYPE_CPL:
 896  908  
 897  909                                  ASSERT(rss->opcode < NUM_CPL_CMDS);
 898  910                                  sc->cpl_handler[rss->opcode](iq, rss, m);
 899  911                                  break;
 900  912  
 901  913                          case X_RSPD_TYPE_INTR:
↓ open down ↓ 59 lines elided ↑ open up ↑
 961  973                  if (service_iq(q, q->qsize / 8) == 0)
 962  974                          (void) atomic_cas_uint(&q->state, IQS_BUSY, IQS_IDLE);
 963  975                  else
 964  976                          STAILQ_INSERT_TAIL(&iql, q, link);
 965  977          }
 966  978  
 967  979          t4_write_reg(sc, MYPF_REG(A_SGE_PF_GTS), V_CIDXINC(ndescs) |
 968  980              V_INGRESSQID((u32)iq->cntxt_id) | V_SEINTARM(iq->intr_next));
 969  981  
 970  982          if (iq->flags & IQ_HAS_FL) {
 971      -                int starved;
 972  983  
 973  984                  FL_LOCK(fl);
 974  985                  fl->needed += fl_bufs_used;
 975  986                  starved = refill_fl(sc, fl, fl->cap / 4);
 976  987                  FL_UNLOCK(fl);
 977  988                  if (starved != 0)
 978  989                          add_fl_to_sfl(sc, fl);
 979  990          }
 980  991  
 981  992          return (0);
↓ open down ↓ 264 lines elided ↑ open up ↑
1246 1257          }
1247 1258          iq->qsize = roundup(qsize, 16);         /* See FW_IQ_CMD/iqsize */
1248 1259          iq->esize = max(esize, 16);             /* See FW_IQ_CMD/iqesize */
1249 1260  }
1250 1261  
1251 1262  static inline void
1252 1263  init_fl(struct sge_fl *fl, uint16_t qsize)
1253 1264  {
1254 1265  
1255 1266          fl->qsize = qsize;
     1267 +        fl->allocb_fail = 0;
1256 1268  }
1257 1269  
1258 1270  static inline void
1259 1271  init_eq(struct adapter *sc, struct sge_eq *eq, uint16_t eqtype, uint16_t qsize,
1260 1272      uint8_t tx_chan, uint16_t iqid)
1261 1273  {
1262 1274          struct sge *s = &sc->sge;
1263 1275          uint32_t r;
1264 1276  
1265 1277          ASSERT(tx_chan < NCHAN);
↓ open down ↓ 414 lines elided ↑ open up ↑
1680 1692          int rc, cntxt_id;
1681 1693          struct fw_eq_eth_cmd c;
1682 1694  
1683 1695          bzero(&c, sizeof (c));
1684 1696  
1685 1697          c.op_to_vfn = BE_32(V_FW_CMD_OP(FW_EQ_ETH_CMD) | F_FW_CMD_REQUEST |
1686 1698              F_FW_CMD_WRITE | F_FW_CMD_EXEC | V_FW_EQ_ETH_CMD_PFN(sc->pf) |
1687 1699              V_FW_EQ_ETH_CMD_VFN(0));
1688 1700          c.alloc_to_len16 = BE_32(F_FW_EQ_ETH_CMD_ALLOC |
1689 1701              F_FW_EQ_ETH_CMD_EQSTART | FW_LEN16(c));
1690      -        c.autoequiqe_to_viid = BE_32(V_FW_EQ_ETH_CMD_VIID(pi->viid));
     1702 +        c.autoequiqe_to_viid = BE_32(F_FW_EQ_ETH_CMD_AUTOEQUIQE |
     1703 +            F_FW_EQ_ETH_CMD_AUTOEQUEQE | V_FW_EQ_ETH_CMD_VIID(pi->viid));
1691 1704          c.fetchszm_to_iqid =
1692 1705              BE_32(V_FW_EQ_ETH_CMD_HOSTFCMODE(X_HOSTFCMODE_STATUS_PAGE) |
1693 1706              V_FW_EQ_ETH_CMD_PCIECHN(eq->tx_chan) | F_FW_EQ_ETH_CMD_FETCHRO |
1694 1707              V_FW_EQ_ETH_CMD_IQID(eq->iqid));
1695 1708          c.dcaen_to_eqsize = BE_32(V_FW_EQ_ETH_CMD_FBMIN(X_FETCHBURSTMIN_64B) |
1696 1709              V_FW_EQ_ETH_CMD_FBMAX(X_FETCHBURSTMAX_512B) |
1697 1710              V_FW_EQ_ETH_CMD_CIDXFTHRESH(X_CIDXFLUSHTHRESH_32) |
1698 1711              V_FW_EQ_ETH_CMD_EQSIZE(eq->qsize));
1699 1712          c.eqaddr = BE_64(eq->ba);
1700 1713  
↓ open down ↓ 622 lines elided ↑ open up ↑
2323 2336   * Note that fl->cidx and fl->offset are left unchanged in case of failure.
2324 2337   */
2325 2338  static mblk_t *
2326 2339  get_fl_payload(struct adapter *sc, struct sge_fl *fl,
2327 2340                 uint32_t len_newbuf, int *fl_bufs_used)
2328 2341  {
2329 2342          struct mblk_pair frame = {0};
2330 2343          struct rxbuf *rxb;
2331 2344          mblk_t *m = NULL;
2332 2345          uint_t nbuf = 0, len, copy, n;
2333      -        uint32_t cidx, offset;
     2346 +        uint32_t cidx, offset, rcidx, roffset;
2334 2347  
2335 2348          /*
2336 2349           * The SGE won't pack a new frame into the current buffer if the entire
2337 2350           * payload doesn't fit in the remaining space.  Move on to the next buf
2338 2351           * in that case.
2339 2352           */
     2353 +        rcidx = fl->cidx;
     2354 +        roffset = fl->offset;
2340 2355          if (fl->offset > 0 && len_newbuf & F_RSPD_NEWBUF) {
2341 2356                  fl->offset = 0;
2342 2357                  if (++fl->cidx == fl->cap)
2343 2358                          fl->cidx = 0;
2344 2359                  nbuf++;
2345 2360          }
2346 2361          cidx = fl->cidx;
2347 2362          offset = fl->offset;
2348 2363  
2349 2364          len = G_RSPD_LEN(len_newbuf);   /* pktshift + payload length */
2350 2365          copy = (len <= fl->copy_threshold);
2351 2366          if (copy != 0) {
2352 2367                  frame.head = m = allocb(len, BPRI_HI);
2353      -                if (m == NULL)
     2368 +                if (m == NULL) {
     2369 +                        fl->allocb_fail++;
     2370 +                        cmn_err(CE_WARN,"%s: mbuf allocation failure "
     2371 +                                        "count = %llu", __func__,
     2372 +                                        (unsigned long long)fl->allocb_fail);
     2373 +                        fl->cidx = rcidx;
     2374 +                        fl->offset = roffset;
2354 2375                          return (NULL);
     2376 +                }
2355 2377          }
2356 2378  
2357 2379          while (len) {
2358 2380                  rxb = fl->sdesc[cidx].rxb;
2359 2381                  n = min(len, rxb->buf_size - offset);
2360 2382  
2361 2383                  (void) ddi_dma_sync(rxb->dhdl, offset, n,
2362 2384                      DDI_DMA_SYNC_FORKERNEL);
2363 2385  
2364 2386                  if (copy != 0)
2365 2387                          bcopy(rxb->va + offset, m->b_wptr, n);
2366 2388                  else {
2367 2389                          m = desballoc((unsigned char *)rxb->va + offset, n,
2368 2390                              BPRI_HI, &rxb->freefunc);
2369 2391                          if (m == NULL) {
2370      -                                freemsg(frame.head);
     2392 +                                fl->allocb_fail++;
     2393 +                                cmn_err(CE_WARN,
     2394 +                                        "%s: mbuf allocation failure "
     2395 +                                        "count = %llu", __func__,
     2396 +                                        (unsigned long long)fl->allocb_fail);
     2397 +                                if (frame.head)
     2398 +                                        freemsgchain(frame.head);
     2399 +                                fl->cidx = rcidx;
     2400 +                                fl->offset = roffset;
2371 2401                                  return (NULL);
2372 2402                          }
2373 2403                          atomic_inc_uint(&rxb->ref_cnt);
2374 2404                          if (frame.head != NULL)
2375 2405                                  frame.tail->b_cont = m;
2376 2406                          else
2377 2407                                  frame.head = m;
2378 2408                          frame.tail = m;
2379 2409                  }
2380 2410                  m->b_wptr += n;
↓ open down ↓ 958 lines elided ↑ open up ↑
3339 3369  
3340 3370          t4_write_reg(sc, MYPF_REG(A_SGE_PF_KDOORBELL), v);
3341 3371  
3342 3372          /*
3343 3373           * Update pending count:
3344 3374           * Deduct the number of descriptors posted
3345 3375           */
3346 3376          fl->pending -= ndesc * 8;
3347 3377  }
3348 3378  
     3379 +static void
     3380 +tx_reclaim_task(void *arg)
     3381 +{
     3382 +        struct sge_txq *txq = arg;
     3383 +
     3384 +        TXQ_LOCK(txq);
     3385 +        reclaim_tx_descs(txq, txq->eq.qsize);
     3386 +        TXQ_UNLOCK(txq);
     3387 +}
     3388 +
3349 3389  /* ARGSUSED */
3350 3390  static int
3351 3391  handle_sge_egr_update(struct sge_iq *iq, const struct rss_header *rss,
3352 3392                  mblk_t *m)
3353 3393  {
3354 3394          const struct cpl_sge_egr_update *cpl = (const void *)(rss + 1);
3355 3395          unsigned int qid = G_EGR_QID(ntohl(cpl->opcode_qid));
3356 3396          struct adapter *sc = iq->adapter;
3357 3397          struct sge *s = &sc->sge;
     3398 +        struct sge_eq *eq;
3358 3399          struct sge_txq *txq;
3359 3400  
3360 3401          txq = (void *)s->eqmap[qid - s->eq_start];
     3402 +        eq = &txq->eq;
3361 3403          txq->qflush++;
3362 3404          t4_mac_tx_update(txq->port, txq);
3363 3405  
     3406 +        ddi_taskq_dispatch(sc->tq[eq->tx_chan], tx_reclaim_task,
     3407 +                (void *)txq, DDI_NOSLEEP);
     3408 +
3364 3409          return (0);
3365 3410  }
3366 3411  
3367 3412  static int
3368 3413  handle_fw_rpl(struct sge_iq *iq, const struct rss_header *rss, mblk_t *m)
3369 3414  {
3370 3415          struct adapter *sc = iq->adapter;
3371 3416          const struct cpl_fw6_msg *cpl = (const void *)(rss + 1);
3372 3417  
3373 3418          ASSERT(m == NULL);
↓ open down ↓ 381 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX