diff options
Diffstat (limited to 'sys/dev/oce/oce_if.c')
-rw-r--r-- | sys/dev/oce/oce_if.c | 150 |
1 files changed, 77 insertions, 73 deletions
diff --git a/sys/dev/oce/oce_if.c b/sys/dev/oce/oce_if.c index 48cdb16..166828b 100644 --- a/sys/dev/oce/oce_if.c +++ b/sys/dev/oce/oce_if.c @@ -1,5 +1,5 @@ /*- - * Copyright (C) 2012 Emulex + * Copyright (C) 2013 Emulex * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -96,6 +96,7 @@ static void update_queues_got(POCE_SOFTC sc); static void process_link_state(POCE_SOFTC sc, struct oce_async_cqe_link_state *acqe); static int oce_tx_asic_stall_verify(POCE_SOFTC sc, struct mbuf *m); +static void oce_get_config(POCE_SOFTC sc); static struct mbuf *oce_insert_vlan_tag(POCE_SOFTC sc, struct mbuf *m, boolean_t *complete); /* IP specific */ @@ -147,6 +148,7 @@ static uint32_t supportedDevices[] = { (PCI_VENDOR_EMULEX << 16) | PCI_PRODUCT_BE3, (PCI_VENDOR_EMULEX << 16) | PCI_PRODUCT_XE201, (PCI_VENDOR_EMULEX << 16) | PCI_PRODUCT_XE201_VF, + (PCI_VENDOR_EMULEX << 16) | PCI_PRODUCT_SH }; @@ -190,6 +192,9 @@ oce_probe(device_t dev) case PCI_PRODUCT_XE201_VF: sc->flags |= OCE_FLAGS_XE201; break; + case PCI_PRODUCT_SH: + sc->flags |= OCE_FLAGS_SH; + break; default: return ENXIO; } @@ -214,7 +219,6 @@ oce_attach(device_t dev) if (rc) return rc; - sc->rss_enable = oce_enable_rss; sc->tx_ring_size = OCE_TX_RING_SIZE; sc->rx_ring_size = OCE_RX_RING_SIZE; sc->rq_frag_size = OCE_RQ_BUF_SIZE; @@ -229,6 +233,8 @@ oce_attach(device_t dev) if (rc) goto pci_res_free; + oce_get_config(sc); + setup_max_queues_want(sc); rc = oce_setup_intr(sc); @@ -486,17 +492,18 @@ oce_multiq_start(struct ifnet *ifp, struct mbuf *m) int queue_index = 0; int status = 0; + if (!sc->link_status) + return ENXIO; + if ((m->m_flags & M_FLOWID) != 0) queue_index = m->m_pkthdr.flowid % sc->nwqs; - + wq = sc->wq[queue_index]; - if (TRY_LOCK(&wq->tx_lock)) { - status = oce_multiq_transmit(ifp, m, wq); - UNLOCK(&wq->tx_lock); - } else { - status = drbr_enqueue(ifp, wq->br, m); - } + LOCK(&wq->tx_lock); + status = oce_multiq_transmit(ifp, m, wq); + UNLOCK(&wq->tx_lock); + return status; } @@ -579,7 +586,7 @@ oce_setup_intr(POCE_SOFTC sc) int rc = 0, use_intx = 0; int vector = 0, req_vectors = 0; - if (sc->rss_enable) + if (is_rss_enabled(sc)) req_vectors = MAX((sc->nrqs - 1), sc->nwqs); else req_vectors = 1; @@ -778,7 +785,6 @@ oce_tx(POCE_SOFTC sc, struct mbuf **mpp, int wq_index) struct mbuf *m, *m_temp; struct oce_wq *wq = sc->wq[wq_index]; struct oce_packet_desc *pd; - uint32_t out; struct oce_nic_hdr_wqe *nichdr; struct oce_nic_frag_wqe *nicfrag; int num_wqes; @@ -816,20 +822,14 @@ oce_tx(POCE_SOFTC sc, struct mbuf **mpp, int wq_index) } } - out = wq->packets_out + 1; - if (out == OCE_WQ_PACKET_ARRAY_SIZE) - out = 0; - if (out == wq->packets_in) - return EBUSY; - - pd = &wq->pckts[wq->packets_out]; + pd = &wq->pckts[wq->pkt_desc_head]; retry: rc = bus_dmamap_load_mbuf_sg(wq->tag, pd->map, m, segs, &pd->nsegs, BUS_DMA_NOWAIT); if (rc == 0) { num_wqes = pd->nsegs + 1; - if (IS_BE(sc)) { + if (IS_BE(sc) || IS_SH(sc)) { /*Dummy required only for BE3.*/ if (num_wqes & 1) num_wqes++; @@ -838,10 +838,11 @@ retry: bus_dmamap_unload(wq->tag, pd->map); return EBUSY; } - + atomic_store_rel_int(&wq->pkt_desc_head, + (wq->pkt_desc_head + 1) % \ + OCE_WQ_PACKET_ARRAY_SIZE); bus_dmamap_sync(wq->tag, pd->map, BUS_DMASYNC_PREWRITE); pd->mbuf = m; - wq->packets_out = out; nichdr = RING_GET_PRODUCER_ITEM_VA(wq->ring, struct oce_nic_hdr_wqe); @@ -870,12 +871,12 @@ retry: nichdr->u0.s.lso = 1; nichdr->u0.s.lso_mss = m->m_pkthdr.tso_segsz; } - if (!IS_BE(sc)) + if (!IS_BE(sc) || !IS_SH(sc)) nichdr->u0.s.ipcs = 1; } RING_PUT(wq->ring, 1); - wq->ring->num_used++; + atomic_add_int(&wq->ring->num_used, 1); for (i = 0; i < pd->nsegs; i++) { nicfrag = @@ -887,7 +888,7 @@ retry: nicfrag->u0.s.frag_len = segs[i].ds_len; pd->wqe_idx = wq->ring->pidx; RING_PUT(wq->ring, 1); - wq->ring->num_used++; + atomic_add_int(&wq->ring->num_used, 1); } if (num_wqes > (pd->nsegs + 1)) { nicfrag = @@ -899,7 +900,7 @@ retry: nicfrag->u0.dw[3] = 0; pd->wqe_idx = wq->ring->pidx; RING_PUT(wq->ring, 1); - wq->ring->num_used++; + atomic_add_int(&wq->ring->num_used, 1); pd->nsegs++; } @@ -912,7 +913,7 @@ retry: bus_dmamap_sync(wq->ring->dma.tag, wq->ring->dma.map, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); reg_value = (num_wqes << 16) | wq->wq_id; - OCE_WRITE_REG32(sc, db, PD_TXULP_DB, reg_value); + OCE_WRITE_REG32(sc, db, wq->db_offset, reg_value); } else if (rc == EFBIG) { if (retry_cnt == 0) { @@ -929,7 +930,7 @@ retry: return rc; else goto free_ret; - + return 0; free_ret: @@ -942,21 +943,14 @@ free_ret: static void oce_tx_complete(struct oce_wq *wq, uint32_t wqe_idx, uint32_t status) { - uint32_t in; struct oce_packet_desc *pd; POCE_SOFTC sc = (POCE_SOFTC) wq->parent; struct mbuf *m; - if (wq->packets_out == wq->packets_in) - device_printf(sc->dev, "WQ transmit descriptor missing\n"); - - in = wq->packets_in + 1; - if (in == OCE_WQ_PACKET_ARRAY_SIZE) - in = 0; - - pd = &wq->pckts[wq->packets_in]; - wq->packets_in = in; - wq->ring->num_used -= (pd->nsegs + 1); + pd = &wq->pckts[wq->pkt_desc_tail]; + atomic_store_rel_int(&wq->pkt_desc_tail, + (wq->pkt_desc_tail + 1) % OCE_WQ_PACKET_ARRAY_SIZE); + atomic_subtract_int(&wq->ring->num_used, pd->nsegs + 1); bus_dmamap_sync(wq->tag, pd->map, BUS_DMASYNC_POSTWRITE); bus_dmamap_unload(wq->tag, pd->map); @@ -964,6 +958,7 @@ oce_tx_complete(struct oce_wq *wq, uint32_t wqe_idx, uint32_t status) m_freem(m); pd->mbuf = NULL; + if (sc->ifp->if_drv_flags & IFF_DRV_OACTIVE) { if (wq->ring->num_used < (wq->ring->num_items / 2)) { sc->ifp->if_drv_flags &= ~(IFF_DRV_OACTIVE); @@ -1066,16 +1061,15 @@ oce_tx_task(void *arg, int npending) POCE_SOFTC sc = wq->parent; struct ifnet *ifp = sc->ifp; int rc = 0; - + #if __FreeBSD_version >= 800000 - if (TRY_LOCK(&wq->tx_lock)) { - rc = oce_multiq_transmit(ifp, NULL, wq); - if (rc) { - device_printf(sc->dev, - "TX[%d] restart failed\n", wq->queue_index); - } - UNLOCK(&wq->tx_lock); + LOCK(&wq->tx_lock); + rc = oce_multiq_transmit(ifp, NULL, wq); + if (rc) { + device_printf(sc->dev, + "TX[%d] restart failed\n", wq->queue_index); } + UNLOCK(&wq->tx_lock); #else oce_start(ifp); #endif @@ -1134,7 +1128,6 @@ oce_wq_handler(void *arg) struct oce_nic_tx_cqe *cqe; int num_cqes = 0; - LOCK(&wq->tx_lock); bus_dmamap_sync(cq->ring->dma.tag, cq->ring->dma.map, BUS_DMASYNC_POSTWRITE); cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_tx_cqe); @@ -1158,7 +1151,6 @@ oce_wq_handler(void *arg) if (num_cqes) oce_arm_cq(sc, cq->cq_id, num_cqes, FALSE); - UNLOCK(&wq->tx_lock); return 0; } @@ -1233,7 +1225,7 @@ oce_rx(struct oce_rq *rq, uint32_t rqe_idx, struct oce_nic_rx_cqe *cqe) } /* Get vlan_tag value */ - if(IS_BE(sc)) + if(IS_BE(sc) || IS_SH(sc)) vtag = BSWAP_16(cqe->u0.s.vlan_tag); else vtag = cqe->u0.s.vlan_tag; @@ -1294,7 +1286,10 @@ oce_rx(struct oce_rq *rq, uint32_t rqe_idx, struct oce_nic_rx_cqe *cqe) m->m_pkthdr.rcvif = sc->ifp; #if __FreeBSD_version >= 800000 - m->m_pkthdr.flowid = rq->queue_index; + if (rq->queue_index) + m->m_pkthdr.flowid = (rq->queue_index - 1); + else + m->m_pkthdr.flowid = rq->queue_index; m->m_flags |= M_FLOWID; #endif /* This deternies if vlan tag is Valid */ @@ -1401,7 +1396,7 @@ oce_cqe_portid_valid(POCE_SOFTC sc, struct oce_nic_rx_cqe *cqe) struct oce_nic_rx_cqe_v1 *cqe_v1; int port_id = 0; - if (sc->be3_native && IS_BE(sc)) { + if (sc->be3_native && (IS_BE(sc) || IS_SH(sc))) { cqe_v1 = (struct oce_nic_rx_cqe_v1 *)cqe; port_id = cqe_v1->u0.s.port; if (sc->port_id != port_id) @@ -1547,7 +1542,6 @@ oce_rq_handler(void *arg) int num_cqes = 0, rq_buffers_used = 0; - LOCK(&rq->rx_lock); bus_dmamap_sync(cq->ring->dma.tag, cq->ring->dma.map, BUS_DMASYNC_POSTWRITE); cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_rx_cqe); @@ -1594,8 +1588,6 @@ oce_rq_handler(void *arg) oce_alloc_rx_bufs(rq, (rq_buffers_used - 1)); } - UNLOCK(&rq->rx_lock); - return 0; } @@ -1889,7 +1881,7 @@ oce_local_timer(void *arg) oce_tx_restart(sc, sc->wq[i]); /* calculate and set the eq delay for optimal interrupt rate */ - if (IS_BE(sc)) + if (IS_BE(sc) || IS_SH(sc)) oce_eqd_set_periodic(sc); callout_reset(&sc->timer, hz, oce_local_timer, sc); @@ -2080,38 +2072,22 @@ oce_mq_handler(void *arg) static void setup_max_queues_want(POCE_SOFTC sc) { - int max_rss = 0; - /* Check if it is FLEX machine. Is so dont use RSS */ if ((sc->function_mode & FNM_FLEX10_MODE) || (sc->function_mode & FNM_UMC_MODE) || (sc->function_mode & FNM_VNIC_MODE) || - (!sc->rss_enable) || + (!is_rss_enabled(sc)) || (sc->flags & OCE_FLAGS_BE2)) { sc->nrqs = 1; sc->nwqs = 1; - sc->rss_enable = 0; - } else { - /* For multiq, our deisgn is to have TX rings equal to - RSS rings. So that we can pair up one RSS ring and TX - to a single intr, which improves CPU cache efficiency. - */ - if (IS_BE(sc) && (!sc->be3_native)) - max_rss = OCE_LEGACY_MODE_RSS; - else - max_rss = OCE_MAX_RSS; - - sc->nrqs = MIN(OCE_NCPUS, max_rss) + 1; /* 1 for def RX */ - sc->nwqs = MIN(OCE_NCPUS, max_rss); } - } static void update_queues_got(POCE_SOFTC sc) { - if (sc->rss_enable) { + if (is_rss_enabled(sc)) { sc->nrqs = sc->intr_count + 1; sc->nwqs = sc->intr_count; } else { @@ -2196,3 +2172,31 @@ oce_tx_asic_stall_verify(POCE_SOFTC sc, struct mbuf *m) } return FALSE; } + +static void +oce_get_config(POCE_SOFTC sc) +{ + int rc = 0; + uint32_t max_rss = 0; + + if ((IS_BE(sc) || IS_SH(sc)) && (!sc->be3_native)) + max_rss = OCE_LEGACY_MODE_RSS; + else + max_rss = OCE_MAX_RSS; + + if (!IS_BE(sc)) { + rc = oce_get_func_config(sc); + if (rc) { + sc->nwqs = OCE_MAX_WQ; + sc->nrssqs = max_rss; + sc->nrqs = sc->nrssqs + 1; + } + } + else { + rc = oce_get_profile_config(sc); + sc->nrssqs = max_rss; + sc->nrqs = sc->nrssqs + 1; + if (rc) + sc->nwqs = OCE_MAX_WQ; + } +} |