/* The SGE keeps track of its Producer and Consumer Indices in terms *ofEgressQueueUnitssowecanonlytellitaboutintegralnumbers *ofmultiplesofFreeListEntriesperEgressQueueUnits...
*/ if (fl->pend_cred >= FL_PER_EQ_UNIT) { if (is_t4(adapter->params.chip))
val |= PIDX_V(fl->pend_cred / FL_PER_EQ_UNIT); else
val |= PIDX_T5_V(fl->pend_cred / FL_PER_EQ_UNIT);
/* Make sure all memory writes to the Free List queue are *committedbeforewetellthehardwareaboutthem.
*/
wmb();
/* If we don't have access to the new User Doorbell (T5+), use *theolddoorbellmechanism;otherwiseusethenewBAR2 *mechanism.
*/ if (unlikely(fl->bar2_addr == NULL)) {
t4_write_reg(adapter,
T4VF_SGE_BASE_ADDR + SGE_VF_KDOORBELL,
QID_V(fl->cntxt_id) | val);
} else {
writel(val | QID_V(fl->bar2_qid),
fl->bar2_addr + SGE_UDB_KDOORBELL);
/* This Write memory Barrier will force the write to *theUserDoorbellareatobeflushed.
*/
wmb();
}
fl->pend_cred %= FL_PER_EQ_UNIT;
}
}
if (likely(part0))
memcpy(sgl->sge, buf, part0);
part1 = (u8 *)end - (u8 *)tq->stat;
memcpy(tq->desc, (u8 *)buf + part0, part1);
end = (void *)tq->desc + part1;
} if ((uintptr_t)end & 8) /* 0-pad to multiple of 16 */
*end = 0;
}
/** *ring_tx_db-checkandpotentiallyringaTXqueue'sdoorbell *@adapter:theadapter *@tq:theTXqueue *@n:numberofnewdescriptorstogivetoHW * *RingthedoorbelforaTXqueue.
*/ staticinlinevoid ring_tx_db(struct adapter *adapter, struct sge_txq *tq, int n)
{ /* Make sure that all writes to the TX Descriptors are committed *beforewetellthehardwareaboutthem.
*/
wmb();
/* If we don't have access to the new User Doorbell (T5+), use the old *doorbellmechanism;otherwiseusethenewBAR2mechanism.
*/ if (unlikely(tq->bar2_addr == NULL)) {
u32 val = PIDX_V(n);
/* T4 and later chips share the same PIDX field offset within *thedoorbell,butT5andlatershrankthefieldinorderto *gainabitforDoorbellPriority.Thefieldwasabsurdly *largeinthefirstplace(14bits)sowejustusetheT5 *andlaterlimitsandwarnifaQueueIDistoolarge.
*/
WARN_ON(val & DBPRIO_F);
/* If we're only writing a single Egress Unit and the BAR2 *QueueIDis0,wecanusetheWriteCombiningDoorbell *GatherBuffer;otherwiseweusethesimpledoorbell.
*/ if (n == 1 && tq->bar2_qid == 0) { unsignedint index = (tq->pidx
? (tq->pidx - 1)
: (tq->size - 1));
__be64 *src = (__be64 *)&tq->desc[index];
__be64 __iomem *dst = (__be64 __iomem *)(tq->bar2_addr +
SGE_UDB_WCDOORBELL); unsignedint count = EQ_UNIT / sizeof(__be64);
/* Copy the TX Descriptor in a tight loop in order to *trytogetittotheadapterinasingleWrite *CombinedtransferonthePCI-EBus.IftheWrite *Combinefails(saybecauseofaninterrupt,etc.) *thehardwarewillsimplytakethelastwriteasa *simpledoorbellwritewithaPIDXIncrementof1 *andwillfetchtheTXDescriptorfrommemoryvia *DMA.
*/ while (count) { /* the (__force u64) is because the compiler *doesn'tunderstandtheendianswizzling *goingon
*/
writeq((__force u64)*src, dst);
src++;
dst++;
count--;
}
} else
writel(val | QID_V(tq->bar2_qid),
tq->bar2_addr + SGE_UDB_KDOORBELL);
/* This Write Memory Barrier will force the write to the User *Doorbellareatobeflushed.Thisisneededtoprevent *writesondifferentCPUsforthesamequeuefromhitting *theadapteroutoforder.ThisisrequiredwhensomeWork *RequeststaketheWriteCombineGatherBufferpath(user *doorbellareaoffset[SGE_UDB_WCDOORBELL..+63])andsome *takethetraditionalpathwherewesimplyincrementthe *PIDX(UserDoorbellareaSGE_UDB_KDOORBELL)andhavethe *hardwareDMAreadtheactualWorkRequest.
*/
wmb();
}
}
/* Discard the packet if the length is greater than mtu */
max_pkt_len = ETH_HLEN + dev->mtu; if (skb_vlan_tagged(skb))
max_pkt_len += VLAN_HLEN; if (!skb_shinfo(skb)->gso_size && (unlikely(skb->len > max_pkt_len))) goto out_free;
/*
* If this is a Large Send Offload packet we'll put in an LSO CPL
* message with an encapsulated TX Packet CPL message. Otherwise we
* just use a TX Packet CPL message.
*/
ssi = skb_shinfo(skb);
if (ssi->gso_size) {
struct cpl_tx_pkt_lso_core *lso = (void *)(wr + 1);
bool v6 = (ssi->gso_type & SKB_GSO_TCPV6) != 0;
int l3hdr_len = skb_network_header_len(skb);
int eth_xtra_len = skb_network_offset(skb) - ETH_HLEN;
/*
* Set up TX Packet CPL pointer, control word and perform
* accounting.
*/
cpl = (void *)(wr + 1);
if (skb->ip_summed == CHECKSUM_PARTIAL) {
cntrl = hwcsum(adapter->params.chip, skb) |
TXPKT_IPCSUM_DIS_F;
txq->tx_cso++;
} else
cntrl = TXPKT_L4CSUM_DIS_F | TXPKT_IPCSUM_DIS_F;
}
/*
* If there's a VLAN tag present, add that to the list of things to
* do in this Work Request.
*/
if (skb_vlan_tag_present(skb)) {
txq->vlan_ins++;
cntrl |= TXPKT_VLAN_VLD_F | TXPKT_VLAN_V(skb_vlan_tag_get(skb));
}
/*
* Fill in the TX Packet CPL message header.
*/
cpl->ctrl0 = cpu_to_be32(TXPKT_OPCODE_V(CPL_TX_PKT_XT) |
TXPKT_INTF_V(pi->port_id) |
TXPKT_PF_V(0));
cpl->pack = cpu_to_be16(0);
cpl->len = cpu_to_be16(skb->len);
cpl->ctrl1 = cpu_to_be64(cntrl);
/*
* Fill in the body of the TX Packet CPL message with either in-lined
* data or a Scatter/Gather List.
*/
if (is_eth_imm(skb)) {
/*
* In-line the packet's data and free the skb since we don't
* need it any longer.
*/
inline_tx_skb(skb, &txq->q, cpl + 1);
dev_consume_skb_any(skb);
} else {
/*
* Write the skb's Scatter/Gather list into the TX Packet CPL
* message and retain a pointer to the skb so we can free it
* later when its DMA completes. (We store the skb pointer
* in the Software Descriptor corresponding to the last TX
* Descriptor used by the Work Request.)
*
* The retained skb will be freed when the corresponding TX
* Descriptors are reclaimed after their DMAs complete.
* However, this could take quite a while since, in general,
* the hardware is set up to be lazy about sending DMA
* completion notifications to us and we mostly perform TX
* reclaims in the transmit routine.
*
* This is good for performamce but means that we rely on new
* TX packets arriving to run the destructors of completed
* packets, which open up space in their sockets' send queues.
* Sometimes we do not get such new packets causing TX to
* stall. A single UDP transmitter is a good example of this
* situation. We have a clean up timer that periodically
* reclaims completed packets but it doesn't run often enough
* (nor do we want it to) to prevent lengthy stalls. A
* solution to this problem is to run the destructor early,
* after the packet is queued but before it's DMAd. A con is
* that we lie to socket memory accounting, but the amount of
* extra memory is reasonable (limited by the number of TX
* descriptors), the packets do actually get freed quickly by
* new packets almost always, and for protocols like TCP that
* wait for acks to really free up the data the extra memory
* is even less. On the positive side we run the destructors
* on the sending CPU rather than on a potentially different
* completing CPU, usually a good thing.
*
* Run the destructor before telling the DMA engine about the
* packet to make sure it doesn't complete and get freed
* prematurely.
*/
struct ulptx_sgl *sgl = (struct ulptx_sgl *)(cpl + 1);
struct sge_txq *tq = &txq->q;
int last_desc;
/*
* If the Work Request header was an exact multiple of our TX
* Descriptor length, then it's possible that the starting SGL
* pointer lines up exactly with the end of our TX Descriptor
* ring. If that's the case, wrap around to the beginning
* here ...
*/
if (unlikely((void *)sgl == (void *)tq->stat)) {
sgl = (void *)tq->desc;
end = ((void *)tq->desc + ((void *)end - (void *)tq->stat));
}
/*
* Advance our internal TX Queue state, tell the hardware about
* the new TX descriptors and return success.
*/
txq_advance(&txq->q, ndesc);
netif_trans_update(dev);
ring_tx_db(adapter, &txq->q, ndesc);
return NETDEV_TX_OK;
out_free:
/*
* An error of some sort happened. Free the TX skb and tell the
* OS that we've "dealt" with the packet ...
*/
dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
/**
* copy_frags - copy fragments from gather list into skb_shared_info
* @skb: destination skb
* @gl: source internal packet gather list
* @offset: packet start offset in first page
*
* Copy an internal packet gather list into a Linux skb_shared_info
* structure.
*/
static inline void copy_frags(struct sk_buff *skb,
const struct pkt_gl *gl,
unsigned int offset)
{
int i;
/* usually there's just one frag */
__skb_fill_page_desc(skb, 0, gl->frags[0].page,
gl->frags[0].offset + offset,
gl->frags[0].size - offset);
skb_shinfo(skb)->nr_frags = gl->nfrags;
for (i = 1; i < gl->nfrags; i++)
__skb_fill_page_desc(skb, i, gl->frags[i].page,
gl->frags[i].offset,
gl->frags[i].size);
/* get a reference to the last page, we don't own it */
get_page(gl->frags[gl->nfrags - 1].page);
}
/**
* t4vf_pktgl_to_skb - build an sk_buff from a packet gather list
* @gl: the gather list
* @skb_len: size of sk_buff main body if it carries fragments
* @pull_len: amount of data to move to the sk_buff's main body
*
* Builds an sk_buff from the given packet gather list. Returns the
* sk_buff or %NULL if sk_buff allocation failed.
*/
static struct sk_buff *t4vf_pktgl_to_skb(const struct pkt_gl *gl,
unsigned int skb_len,
unsigned int pull_len)
{
struct sk_buff *skb;
/*
* If the ingress packet is small enough, allocate an skb large enough
* for all of the data and copy it inline. Otherwise, allocate an skb
* with enough room to pull in the header and reference the rest of
* the data via the skb fragment list.
*
* Below we rely on RX_COPY_THRES being less than the smallest Rx
* buff! size, which is expected since buffers are at least
* PAGE_SIZEd. In this case packets up to RX_COPY_THRES have only one
* fragment.
*/
if (gl->tot_len <= RX_COPY_THRES) {
/* small packets have only one fragment */
skb = alloc_skb(gl->tot_len, GFP_ATOMIC);
if (unlikely(!skb))
goto out;
__skb_put(skb, gl->tot_len);
skb_copy_to_linear_data(skb, gl->va, gl->tot_len);
} else {
skb = alloc_skb(skb_len, GFP_ATOMIC);
if (unlikely(!skb))
goto out;
__skb_put(skb, pull_len);
skb_copy_to_linear_data(skb, gl->va, pull_len);
/**
* t4vf_pktgl_free - free a packet gather list
* @gl: the gather list
*
* Releases the pages of a packet gather list. We do not own the last
* page on the list and do not free it.
*/
static void t4vf_pktgl_free(const struct pkt_gl *gl)
{
int frag;
frag = gl->nfrags - 1;
while (frag--)
put_page(gl->frags[frag].page);
}
/**
* do_gro - perform Generic Receive Offload ingress packet processing
* @rxq: ingress RX Ethernet Queue
* @gl: gather list for ingress packet
* @pkt: CPL header for last packet fragment
*
* Perform Generic Receive Offload (GRO) ingress packet processing.
* We use the standard Linux GRO interfaces for this.
*/
static void do_gro(struct sge_eth_rxq *rxq, const struct pkt_gl *gl,
const struct cpl_rx_pkt *pkt)
{
struct adapter *adapter = rxq->rspq.adapter;
struct sge *s = &adapter->sge;
struct port_info *pi;
int ret;
struct sk_buff *skb;
skb = napi_get_frags(&rxq->rspq.napi);
if (unlikely(!skb)) {
t4vf_pktgl_free(gl);
rxq->stats.rx_drops++;
return;
}
if (pkt->vlan_ex && !pi->vlan_id) {
__vlan_hwaccel_put_tag(skb, cpu_to_be16(ETH_P_8021Q),
be16_to_cpu(pkt->vlan));
rxq->stats.vlan_ex++;
}
ret = napi_gro_frags(&rxq->rspq.napi);
if (ret == GRO_HELD)
rxq->stats.lro_pkts++;
else if (ret == GRO_MERGED || ret == GRO_MERGED_FREE)
rxq->stats.lro_merged++;
rxq->stats.pkts++;
rxq->stats.rx_cso++;
}
/**
* t4vf_ethrx_handler - process an ingress ethernet packet
* @rspq: the response queue that received the packet
* @rsp: the response queue descriptor holding the RX_PKT message
* @gl: the gather list of packet fragments
*
* Process an ingress ethernet packet and deliver it to the stack.
*/
int t4vf_ethrx_handler(struct sge_rspq *rspq, const __be64 *rsp,
const struct pkt_gl *gl)
{
struct sk_buff *skb;
const struct cpl_rx_pkt *pkt = (void *)rsp;
bool csum_ok = pkt->csum_calc && !pkt->err_vec &&
(rspq->netdev->features & NETIF_F_RXCSUM);
struct sge_eth_rxq *rxq = container_of(rspq, struct sge_eth_rxq, rspq);
struct adapter *adapter = rspq->adapter;
struct sge *s = &adapter->sge;
struct port_info *pi;
/*
* If this is a good TCP packet and we have Generic Receive Offload
* enabled, handle the packet in the GRO path.
*/
if ((pkt->l2info & cpu_to_be32(RXF_TCP_F)) &&
(rspq->netdev->features & NETIF_F_GRO) && csum_ok &&
!pkt->ip_frag) {
do_gro(rxq, gl, pkt);
return 0;
}
/*
* Convert the Packet Gather List into an skb.
*/
skb = t4vf_pktgl_to_skb(gl, RX_SKB_LEN, RX_PULL_LEN);
if (unlikely(!skb)) {
t4vf_pktgl_free(gl);
rxq->stats.rx_drops++;
return 0;
}
__skb_pull(skb, s->pktshift);
skb->protocol = eth_type_trans(skb, rspq->netdev);
skb_record_rx_queue(skb, rspq->idx);
pi = netdev_priv(skb->dev);
rxq->stats.pkts++;
if (pkt->vlan_ex && !pi->vlan_id) {
rxq->stats.vlan_ex++;
__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q),
be16_to_cpu(pkt->vlan));
}
netif_receive_skb(skb);
return 0;
}
/**
* is_new_response - check if a response is newly written
* @rc: the response control descriptor
* @rspq: the response queue
*
* Returns true if a response descriptor contains a yet unprocessed
* response.
*/
static inline bool is_new_response(const struct rsp_ctrl *rc,
const struct sge_rspq *rspq)
{
return ((rc->type_gen >> RSPD_GEN_S) & 0x1) == rspq->gen;
}
/**
* restore_rx_bufs - put back a packet's RX buffers
* @gl: the packet gather list
* @fl: the SGE Free List
* @frags: how many fragments in @si
*
* Called when we find out that the current packet, @si, can't be
* processed right away for some reason. This is a very rare event and
* there's no effort to make this suspension/resumption process
* particularly efficient.
*
* We implement the suspension by putting all of the RX buffers associated
* with the current packet back on the original Free List. The buffers
* have already been unmapped and are left unmapped, we mark them as
* unmapped in order to prevent further unmapping attempts. (Effectively
* this function undoes the series of @unmap_rx_buf calls which were done
* to create the current packet's gather list.) This leaves us ready to
* restart processing of the packet the next time we start processing the
* RX Queue ...
*/
static void restore_rx_bufs(const struct pkt_gl *gl, struct sge_fl *fl,
int frags)
{
struct rx_sw_desc *sdesc;
/**
* rspq_next - advance to the next entry in a response queue
* @rspq: the queue
*
* Updates the state of a response queue to advance it to the next entry.
*/
static inline void rspq_next(struct sge_rspq *rspq)
{
rspq->cur_desc = (void *)rspq->cur_desc + rspq->iqe_len;
if (unlikely(++rspq->cidx == rspq->size)) {
rspq->cidx = 0;
rspq->gen ^= 1;
rspq->cur_desc = rspq->desc;
}
}
/**
* process_responses - process responses from an SGE response queue
* @rspq: the ingress response queue to process
* @budget: how many responses can be processed in this round
*
* Process responses from a Scatter Gather Engine response queue up to
* the supplied budget. Responses include received packets as well as
* control messages from firmware or hardware.
*
* Additionally choose the interrupt holdoff time for the next interrupt
* on this queue. If the system is under memory shortage use a fairly
* long delay to help recovery.
*/
static int process_responses(struct sge_rspq *rspq, int budget)
{
struct sge_eth_rxq *rxq = container_of(rspq, struct sge_eth_rxq, rspq);
struct adapter *adapter = rspq->adapter;
struct sge *s = &adapter->sge;
int budget_left = budget;
while (likely(budget_left)) {
int ret, rsp_type;
const struct rsp_ctrl *rc;
/*
* Figure out what kind of response we've received from the
* SGE.
*/
dma_rmb();
rsp_type = RSPD_TYPE_G(rc->type_gen);
if (likely(rsp_type == RSPD_TYPE_FLBUF_X)) {
struct page_frag *fp;
struct pkt_gl gl;
const struct rx_sw_desc *sdesc;
u32 bufsz, frag;
u32 len = be32_to_cpu(rc->pldbuflen_qid);
/*
* If we get a "new buffer" message from the SGE we
* need to move on to the next Free List buffer.
*/
if (len & RSPD_NEWBUF_F) {
/*
* We get one "new buffer" message when we
* first start up a queue so we need to ignore
* it when our offset into the buffer is 0.
*/
if (likely(rspq->offset > 0)) {
free_rx_bufs(rspq->adapter, &rxq->fl, 1);
rspq->offset = 0;
}
len = RSPD_LEN_G(len);
}
gl.tot_len = len;
/*
* Last buffer remains mapped so explicitly make it
* coherent for CPU access and start preloading first
* cache line ...
*/
dma_sync_single_for_cpu(rspq->adapter->pdev_dev,
get_buf_addr(sdesc),
fp->size, DMA_FROM_DEVICE);
gl.va = (page_address(gl.frags[0].page) +
gl.frags[0].offset);
prefetch(gl.va);
/*
* Hand the new ingress packet to the handler for
* this Response Queue.
*/
ret = rspq->handler(rspq, rspq->cur_desc, &gl);
if (likely(ret == 0))
rspq->offset += ALIGN(fp->size, s->fl_align);
else
restore_rx_bufs(&gl, &rxq->fl, frag);
} else if (likely(rsp_type == RSPD_TYPE_CPL_X)) {
ret = rspq->handler(rspq, rspq->cur_desc, NULL);
} else {
WARN_ON(rsp_type > RSPD_TYPE_CPL_X);
ret = 0;
}
if (unlikely(ret)) {
/*
* Couldn't process descriptor, back off for recovery.
* We use the SGE's last timer which has the longest
* interrupt coalescing value ...
*/
const int NOMEM_TIMER_IDX = SGE_NTIMERS-1;
rspq->next_intr_params =
QINTR_TIMER_IDX_V(NOMEM_TIMER_IDX);
break;
}
rspq_next(rspq);
budget_left--;
}
/*
* If this is a Response Queue with an associated Free List and
* at least two Egress Queue units available in the Free List
* for new buffer pointers, refill the Free List.
*/
if (rspq->offset >= 0 &&
fl_cap(&rxq->fl) - rxq->fl.avail >= 2*FL_PER_EQ_UNIT)
__refill_fl(rspq->adapter, &rxq->fl);
return budget - budget_left;
}
/**
* napi_rx_handler - the NAPI handler for RX processing
* @napi: the napi instance
* @budget: how many packets we can process in this round
*
* Handler for new data events when using NAPI. This does not need any
* locking or protection from interrupts as data interrupts are off at
* this point and other adapter interrupts do not interfere (the latter
* in not a concern at all with MSI-X as non-data interrupts then have
* a separate handler).
*/
static int napi_rx_handler(struct napi_struct *napi, int budget)
{
unsigned int intr_params;
struct sge_rspq *rspq = container_of(napi, struct sge_rspq, napi);
int work_done = process_responses(rspq, budget);
u32 val;
if (unlikely(work_done == 0))
rspq->unhandled_irqs++;
val = CIDXINC_V(work_done) | SEINTARM_V(intr_params);
/* If we don't have access to the new User GTS (T5+), use the old
* doorbell mechanism; otherwise use the new BAR2 mechanism.
*/
if (unlikely(!rspq->bar2_addr)) {
t4_write_reg(rspq->adapter,
T4VF_SGE_BASE_ADDR + SGE_VF_GTS,
val | INGRESSQID_V((u32)rspq->cntxt_id));
} else {
writel(val | INGRESSQID_V(rspq->bar2_qid),
rspq->bar2_addr + SGE_UDB_GTS);
wmb();
}
return work_done;
}
/*
* The MSI-X interrupt handler for an SGE response queue for the NAPI case
* (i.e., response queue serviced by NAPI polling).
*/
irqreturn_t t4vf_sge_intr_msix(int irq, void *cookie)
{
struct sge_rspq *rspq = cookie;
napi_schedule(&rspq->napi);
return IRQ_HANDLED;
}
/*
* Process the indirect interrupt entries in the interrupt queue and kick off
* NAPI for each queue that has generated an entry.
*/
static unsigned int process_intrq(struct adapter *adapter)
{
struct sge *s = &adapter->sge;
struct sge_rspq *intrq = &s->intrq;
unsigned int work_done;
u32 val;
spin_lock(&adapter->sge.intrq_lock);
for (work_done = 0; ; work_done++) {
const struct rsp_ctrl *rc;
unsigned int qid, iq_idx;
struct sge_rspq *rspq;
/*
* Grab the next response from the interrupt queue and bail
* out if it's not a new response.
*/
rc = (void *)intrq->cur_desc + (intrq->iqe_len - sizeof(*rc));
if (!is_new_response(rc, intrq))
break;
/*
* If the response isn't a forwarded interrupt message issue a
* error and go on to the next response message. This should
* never happen ...
*/
dma_rmb();
if (unlikely(RSPD_TYPE_G(rc->type_gen) != RSPD_TYPE_INTR_X)) {
dev_err(adapter->pdev_dev,
"Unexpected INTRQ response type %d\n",
RSPD_TYPE_G(rc->type_gen));
continue;
}
/*
* Extract the Queue ID from the interrupt message and perform
* sanity checking to make sure it really refers to one of our
* Ingress Queues which is active and matches the queue's ID.
* None of these error conditions should ever happen so we may
* want to either make them fatal and/or conditionalized under
* DEBUG.
*/
qid = RSPD_QID_G(be32_to_cpu(rc->pldbuflen_qid));
iq_idx = IQ_IDX(s, qid);
if (unlikely(iq_idx >= MAX_INGQ)) {
dev_err(adapter->pdev_dev,
"Ingress QID %d out of range\n", qid);
continue;
}
rspq = s->ingr_map[iq_idx];
if (unlikely(rspq == NULL)) {
dev_err(adapter->pdev_dev,
"Ingress QID %d RSPQ=NULL\n", qid);
continue;
}
if (unlikely(rspq->abs_id != qid)) {
dev_err(adapter->pdev_dev,
"Ingress QID %d refers to RSPQ %d\n",
qid, rspq->abs_id);
continue;
}
/*
* Schedule NAPI processing on the indicated Response Queue
* and move on to the next entry in the Forwarded Interrupt
* Queue.
*/
napi_schedule(&rspq->napi);
rspq_next(intrq);
}
val = CIDXINC_V(work_done) | SEINTARM_V(intrq->intr_params);
/* If we don't have access to the new User GTS (T5+), use the old
* doorbell mechanism; otherwise use the new BAR2 mechanism.
*/
if (unlikely(!intrq->bar2_addr)) {
t4_write_reg(adapter, T4VF_SGE_BASE_ADDR + SGE_VF_GTS,
val | INGRESSQID_V(intrq->cntxt_id));
} else {
writel(val | INGRESSQID_V(intrq->bar2_qid),
intrq->bar2_addr + SGE_UDB_GTS);
wmb();
}
spin_unlock(&adapter->sge.intrq_lock);
return work_done;
}
/*
* The MSI interrupt handler handles data events from SGE response queues as
* well as error and other async events as they all use the same MSI vector.
*/
static irqreturn_t t4vf_intr_msi(int irq, void *cookie)
{
struct adapter *adapter = cookie;
process_intrq(adapter);
return IRQ_HANDLED;
}
/**
* t4vf_intr_handler - select the top-level interrupt handler
* @adapter: the adapter
*
* Selects the top-level interrupt handler based on the type of interrupts
* (MSI-X or MSI).
*/
irq_handler_t t4vf_intr_handler(struct adapter *adapter)
{
BUG_ON((adapter->flags &
(CXGB4VF_USING_MSIX | CXGB4VF_USING_MSI)) == 0);
if (adapter->flags & CXGB4VF_USING_MSIX)
return t4vf_sge_intr_msix;
else
return t4vf_intr_msi;
}
/**
* sge_rx_timer_cb - perform periodic maintenance of SGE RX queues
* @t: Rx timer
*
* Runs periodically from a timer to perform maintenance of SGE RX queues.
*
* a) Replenishes RX queues that have run out due to memory shortage.
* Normally new RX buffers are added when existing ones are consumed but
* when out of memory a queue can become empty. We schedule NAPI to do
* the actual refill.
*/
static void sge_rx_timer_cb(struct timer_list *t)
{
struct adapter *adapter = timer_container_of(adapter, t, sge.rx_timer);
struct sge *s = &adapter->sge;
unsigned int i;
/*
* Scan the "Starving Free Lists" flag array looking for any Free
* Lists in need of more free buffers. If we find one and it's not
* being actively polled, then bump its "starving" counter and attempt
* to refill it. If we're successful in adding enough buffers to push
* the Free List over the starving threshold, then we can clear its
* "starving" status.
*/
for (i = 0; i < ARRAY_SIZE(s->starving_fl); i++) {
unsigned long m;
for (m = s->starving_fl[i]; m; m &= m - 1) {
unsigned int id = __ffs(m) + i * BITS_PER_LONG;
struct sge_fl *fl = s->egr_map[id];
/*
* Since we are accessing fl without a lock there's a
* small probability of a false positive where we
* schedule napi but the FL is no longer starving.
* No biggie.
*/
if (fl_starving(adapter, fl)) {
struct sge_eth_rxq *rxq;
/*
* Reschedule the next scan for starving Free Lists ...
*/
mod_timer(&s->rx_timer, jiffies + RX_QCHECK_PERIOD);
}
/**
* sge_tx_timer_cb - perform periodic maintenance of SGE Tx queues
* @t: Tx timer
*
* Runs periodically from a timer to perform maintenance of SGE TX queues.
*
* b) Reclaims completed Tx packets for the Ethernet queues. Normally
* packets are cleaned up by new Tx packets, this timer cleans up packets
* when no new packets are being submitted. This is essential for pktgen,
* at least.
*/
static void sge_tx_timer_cb(struct timer_list *t)
{
struct adapter *adapter = timer_container_of(adapter, t, sge.tx_timer);
struct sge *s = &adapter->sge;
unsigned int i, budget;
budget = MAX_TIMER_TX_RECLAIM;
i = s->ethtxq_rover;
do {
struct sge_eth_txq *txq = &s->ethtxq[i];
if (reclaimable(&txq->q) && __netif_tx_trylock(txq->txq)) {
int avail = reclaimable(&txq->q);
i++;
if (i >= s->ethqsets)
i = 0;
} while (i != s->ethtxq_rover);
s->ethtxq_rover = i;
/*
* If we found too many reclaimable packets schedule a timer in the
* near future to continue where we left off. Otherwise the next timer
* will be at its normal interval.
*/
mod_timer(&s->tx_timer, jiffies + (budget ? TX_QCHECK_PERIOD : 2));
}
/**
* bar2_address - return the BAR2 address for an SGE Queue's Registers
* @adapter: the adapter
* @qid: the SGE Queue ID
* @qtype: the SGE Queue Type (Egress or Ingress)
* @pbar2_qid: BAR2 Queue ID or 0 for Queue ID inferred SGE Queues
*
* Returns the BAR2 address for the SGE Queue Registers associated with
* @qid. If BAR2 SGE Registers aren't available, returns NULL. Also
* returns the BAR2 Queue ID to be used with writes to the BAR2 SGE
* Queue Registers. If the BAR2 Queue ID is 0, then "Inferred Queue ID"
* Registers are supported (e.g. the Write Combining Doorbell Buffer).
*/
static void __iomem *bar2_address(struct adapter *adapter,
unsigned int qid,
enum t4_bar2_qtype qtype,
unsigned int *pbar2_qid)
{
u64 bar2_qoffset;
int ret;
ret = t4vf_bar2_sge_qregs(adapter, qid, qtype,
&bar2_qoffset, pbar2_qid);
if (ret)
return NULL;
return adapter->bar2 + bar2_qoffset;
}
/**
* t4vf_sge_alloc_rxq - allocate an SGE RX Queue
* @adapter: the adapter
* @rspq: pointer to the new rxq's Response Queue to be filled in
* @iqasynch: if 0, a normal rspq; if 1, an asynchronous event queue
* @dev: the network device associated with the new rspq
* @intr_dest: MSI-X vector index (overriden in MSI mode)
* @fl: pointer to the new rxq's Free List to be filled in
* @hnd: the interrupt handler to invoke for the rspq
*/
int t4vf_sge_alloc_rxq(struct adapter *adapter, struct sge_rspq *rspq,
bool iqasynch, struct net_device *dev,
int intr_dest,
struct sge_fl *fl, rspq_handler_t hnd)
{
struct sge *s = &adapter->sge;
struct port_info *pi = netdev_priv(dev);
struct fw_iq_cmd cmd, rpl;
int ret, iqandst, flsz = 0;
int relaxed = !(adapter->flags & CXGB4VF_ROOT_NO_RELAXED_ORDERING);
/*
* If we're using MSI interrupts and we're not initializing the
* Forwarded Interrupt Queue itself, then set up this queue for
* indirect interrupts to the Forwarded Interrupt Queue. Obviously
* the Forwarded Interrupt Queue must be set up before any other
* ingress queue ...
*/
if ((adapter->flags & CXGB4VF_USING_MSI) &&
rspq != &adapter->sge.intrq) {
iqandst = SGE_INTRDST_IQ;
intr_dest = adapter->sge.intrq.abs_id;
} else
iqandst = SGE_INTRDST_PCI;
/*
* Allocate the hardware ring for the Response Queue. The size needs
* to be a multiple of 16 which includes the mandatory status entry
* (regardless of whether the Status Page capabilities are enabled or
* not).
*/
rspq->size = roundup(rspq->size, 16);
rspq->desc = alloc_ring(adapter->pdev_dev, rspq->size, rspq->iqe_len, 0, &rspq->phys_addr, NULL, 0);
if (!rspq->desc)
return -ENOMEM;
/*
* Fill in the Ingress Queue Command. Note: Ideally this code would
* be in t4vf_hw.c but there are so many parameters and dependencies
* on our Linux SGE state that we would end up having to pass tons of
* parameters. We'll have to think about how this might be migrated
* into OS-independent common code ...
*/
memset(&cmd, 0, sizeof(cmd));
cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP_V(FW_IQ_CMD) |
FW_CMD_REQUEST_F |
FW_CMD_WRITE_F |
FW_CMD_EXEC_F);
cmd.alloc_to_len16 = cpu_to_be32(FW_IQ_CMD_ALLOC_F |
FW_IQ_CMD_IQSTART_F |
FW_LEN16(cmd));
cmd.type_to_iqandstindex =
cpu_to_be32(FW_IQ_CMD_TYPE_V(FW_IQ_TYPE_FL_INT_CAP) |
FW_IQ_CMD_IQASYNCH_V(iqasynch) |
FW_IQ_CMD_VIID_V(pi->viid) |
FW_IQ_CMD_IQANDST_V(iqandst) |
FW_IQ_CMD_IQANUS_V(1) |
FW_IQ_CMD_IQANUD_V(SGE_UPDATEDEL_INTR) |
FW_IQ_CMD_IQANDSTINDEX_V(intr_dest));
cmd.iqdroprss_to_iqesize =
cpu_to_be16(FW_IQ_CMD_IQPCIECH_V(pi->port_id) |
FW_IQ_CMD_IQGTSMODE_F |
FW_IQ_CMD_IQINTCNTTHRESH_V(rspq->pktcnt_idx) |
FW_IQ_CMD_IQESIZE_V(ilog2(rspq->iqe_len) - 4));
cmd.iqsize = cpu_to_be16(rspq->size);
cmd.iqaddr = cpu_to_be64(rspq->phys_addr);
if (fl) {
unsigned int chip_ver =
CHELSIO_CHIP_VERSION(adapter->params.chip);
/*
* Allocate the ring for the hardware free list (with space
* for its status page) along with the associated software
* descriptor ring. The free list size needs to be a multiple
* of the Egress Queue Unit and at least 2 Egress Units larger
* than the SGE's Egress Congrestion Threshold
* (fl_starve_thres - 1).
*/
if (fl->size < s->fl_starve_thres - 1 + 2 * FL_PER_EQ_UNIT)
fl->size = s->fl_starve_thres - 1 + 2 * FL_PER_EQ_UNIT;
fl->size = roundup(fl->size, FL_PER_EQ_UNIT);
fl->desc = alloc_ring(adapter->pdev_dev, fl->size,
sizeof(__be64), sizeof(struct rx_sw_desc),
&fl->addr, &fl->sdesc, s->stat_len);
if (!fl->desc) {
ret = -ENOMEM;
goto err;
}
/*
* Calculate the size of the hardware free list ring plus
* Status Page (which the SGE will place after the end of the
* free list ring) in Egress Queue Units.
*/
flsz = (fl->size / FL_PER_EQ_UNIT +
s->stat_len / EQ_UNIT);
/*
* Fill in all the relevant firmware Ingress Queue Command
* fields for the free list.
*/
cmd.iqns_to_fl0congen =
cpu_to_be32(
FW_IQ_CMD_FL0HOSTFCMODE_V(SGE_HOSTFCMODE_NONE) |
FW_IQ_CMD_FL0PACKEN_F |
FW_IQ_CMD_FL0FETCHRO_V(relaxed) |
FW_IQ_CMD_FL0DATARO_V(relaxed) |
FW_IQ_CMD_FL0PADEN_F);
/* In T6, for egress queue type FL there is internal overhead
* of 16B for header going into FLM module. Hence the maximum
* allowed burst size is 448 bytes. For T4/T5, the hardware
* doesn't coalesce fetch requests if more than 64 bytes of
* Free List pointers are provided, so we use a 128-byte Fetch
* Burst Minimum there (T6 implements coalescing so we can use
* the smaller 64-byte value there).
*/
cmd.fl0dcaen_to_fl0cidxfthresh =
cpu_to_be16(
FW_IQ_CMD_FL0FBMIN_V(chip_ver <= CHELSIO_T5
? FETCHBURSTMIN_128B_X
: FETCHBURSTMIN_64B_T6_X) |
FW_IQ_CMD_FL0FBMAX_V((chip_ver <= CHELSIO_T5) ?
FETCHBURSTMAX_512B_X :
FETCHBURSTMAX_256B_X));
cmd.fl0size = cpu_to_be16(flsz);
cmd.fl0addr = cpu_to_be64(fl->addr);
}
/*
* Issue the firmware Ingress Queue Command and extract the results if
* it completes successfully.
*/
ret = t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), &rpl);
if (ret)
goto err;
/* Note, we must initialize the BAR2 Free List User Doorbell
* information before refilling the Free List!
*/
fl->bar2_addr = bar2_address(adapter,
fl->cntxt_id,
T4_BAR2_QTYPE_EGRESS,
&fl->bar2_qid);
refill_fl(adapter, fl, fl_cap(fl), GFP_KERNEL);
}
return 0;
err:
/*
* An error occurred. Clean up our partial allocation state and
* return the error.
*/
if (rspq->desc) {
dma_free_coherent(adapter->pdev_dev, rspq->size * rspq->iqe_len,
rspq->desc, rspq->phys_addr);
rspq->desc = NULL;
}
if (fl && fl->desc) {
kfree(fl->sdesc);
fl->sdesc = NULL;
dma_free_coherent(adapter->pdev_dev, flsz * EQ_UNIT,
fl->desc, fl->addr);
fl->desc = NULL;
}
return ret;
}
/**
* t4vf_sge_alloc_eth_txq - allocate an SGE Ethernet TX Queue
* @adapter: the adapter
* @txq: pointer to the new txq to be filled in
* @dev: the network device
* @devq: the network TX queue associated with the new txq
* @iqid: the relative ingress queue ID to which events relating to
* the new txq should be directed
*/
int t4vf_sge_alloc_eth_txq(struct adapter *adapter, struct sge_eth_txq *txq,
struct net_device *dev, struct netdev_queue *devq,
unsigned int iqid)
{
unsigned int chip_ver = CHELSIO_CHIP_VERSION(adapter->params.chip);
struct port_info *pi = netdev_priv(dev);
struct fw_eq_eth_cmd cmd, rpl;
struct sge *s = &adapter->sge;
int ret, nentries;
/*
* Calculate the size of the hardware TX Queue (including the Status
* Page on the end of the TX Queue) in units of TX Descriptors.
*/
nentries = txq->q.size + s->stat_len / sizeof(struct tx_desc);
/*
* Allocate the hardware ring for the TX ring (with space for its
* status page) along with the associated software descriptor ring.
*/
txq->q.desc = alloc_ring(adapter->pdev_dev, txq->q.size,
sizeof(struct tx_desc),
sizeof(struct tx_sw_desc),
&txq->q.phys_addr, &txq->q.sdesc, s->stat_len);
if (!txq->q.desc)
return -ENOMEM;
/*
* Fill in the Egress Queue Command. Note: As with the direct use of
* the firmware Ingress Queue COmmand above in our RXQ allocation
* routine, ideally, this code would be in t4vf_hw.c. Again, we'll
* have to see if there's some reasonable way to parameterize it
* into the common code ...
*/
memset(&cmd, 0, sizeof(cmd));
cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP_V(FW_EQ_ETH_CMD) |
FW_CMD_REQUEST_F |
FW_CMD_WRITE_F |
FW_CMD_EXEC_F);
cmd.alloc_to_len16 = cpu_to_be32(FW_EQ_ETH_CMD_ALLOC_F |
FW_EQ_ETH_CMD_EQSTART_F |
FW_LEN16(cmd));
cmd.autoequiqe_to_viid = cpu_to_be32(FW_EQ_ETH_CMD_AUTOEQUEQE_F |
FW_EQ_ETH_CMD_VIID_V(pi->viid));
cmd.fetchszm_to_iqid =
cpu_to_be32(FW_EQ_ETH_CMD_HOSTFCMODE_V(SGE_HOSTFCMODE_STPG) |
FW_EQ_ETH_CMD_PCIECHN_V(pi->port_id) |
FW_EQ_ETH_CMD_IQID_V(iqid));
cmd.dcaen_to_eqsize =
cpu_to_be32(FW_EQ_ETH_CMD_FBMIN_V(chip_ver <= CHELSIO_T5
? FETCHBURSTMIN_64B_X
: FETCHBURSTMIN_64B_T6_X) |
FW_EQ_ETH_CMD_FBMAX_V(FETCHBURSTMAX_512B_X) |
FW_EQ_ETH_CMD_CIDXFTHRESH_V(
CIDXFLUSHTHRESH_32_X) |
FW_EQ_ETH_CMD_EQSIZE_V(nentries));
cmd.eqaddr = cpu_to_be64(txq->q.phys_addr);
/*
* Issue the firmware Egress Queue Command and extract the results if
* it completes successfully.
*/
ret = t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), &rpl);
if (ret) {
/*
* The girmware Ingress Queue Command failed for some reason.
* Free up our partial allocation state and return the error.
*/
kfree(txq->q.sdesc);
txq->q.sdesc = NULL;
dma_free_coherent(adapter->pdev_dev,
nentries * sizeof(struct tx_desc),
txq->q.desc, txq->q.phys_addr);
txq->q.desc = NULL; return ret;
}
/* We only bother using the Large Page logic if the Large Page Buffer *islargerthanourPageSizeBuffer.
*/ if (fl_large_pg <= fl_small_pg)
fl_large_pg = 0;
/* The Page Size Buffer must be exactly equal to our Page Size and the *LargePageSizeBuffershouldbe0(perabove)orapowerof2.
*/ if (fl_small_pg != PAGE_SIZE ||
(fl_large_pg & (fl_large_pg - 1)) != 0) {
dev_err(adapter->pdev_dev, "bad SGE FL buffer sizes [%d, %d]\n",
fl_small_pg, fl_large_pg); return -EINVAL;
} if ((sge_params->sge_control & RXPKTCPLMODE_F) !=
RXPKTCPLMODE_V(RXPKTCPLMODE_SPLIT_X)) {
dev_err(adapter->pdev_dev, "bad SGE CPL MODE\n"); return -EINVAL;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.