summaryrefslogtreecommitdiffstats
path: root/sys/dev/oce/oce_if.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/oce/oce_if.c')
-rw-r--r--sys/dev/oce/oce_if.c150
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;
+ }
+}
OpenPOWER on IntegriCloud