|
@@ -4558,7 +4558,7 @@ static int tg3_rx(struct tg3_napi *tnapi, int budget)
|
|
|
u32 sw_idx = tnapi->rx_rcb_ptr;
|
|
|
u16 hw_idx;
|
|
|
int received;
|
|
|
- struct tg3_rx_prodring_set *tpr = &tp->prodring[0];
|
|
|
+ struct tg3_rx_prodring_set *tpr = tnapi->prodring;
|
|
|
|
|
|
hw_idx = *(tnapi->rx_rcb_prod_idx);
|
|
|
/*
|
|
@@ -4581,13 +4581,13 @@ static int tg3_rx(struct tg3_napi *tnapi, int budget)
|
|
|
desc_idx = desc->opaque & RXD_OPAQUE_INDEX_MASK;
|
|
|
opaque_key = desc->opaque & RXD_OPAQUE_RING_MASK;
|
|
|
if (opaque_key == RXD_OPAQUE_RING_STD) {
|
|
|
- ri = &tpr->rx_std_buffers[desc_idx];
|
|
|
+ ri = &tp->prodring[0].rx_std_buffers[desc_idx];
|
|
|
dma_addr = pci_unmap_addr(ri, mapping);
|
|
|
skb = ri->skb;
|
|
|
post_ptr = &std_prod_idx;
|
|
|
rx_std_posted++;
|
|
|
} else if (opaque_key == RXD_OPAQUE_RING_JUMBO) {
|
|
|
- ri = &tpr->rx_jmb_buffers[desc_idx];
|
|
|
+ ri = &tp->prodring[0].rx_jmb_buffers[desc_idx];
|
|
|
dma_addr = pci_unmap_addr(ri, mapping);
|
|
|
skb = ri->skb;
|
|
|
post_ptr = &jmb_prod_idx;
|
|
@@ -4704,15 +4704,30 @@ next_pkt_nopost:
|
|
|
tw32_rx_mbox(tnapi->consmbox, sw_idx);
|
|
|
|
|
|
/* Refill RX ring(s). */
|
|
|
- if (work_mask & RXD_OPAQUE_RING_STD) {
|
|
|
+ if (!(tp->tg3_flags3 & TG3_FLG3_ENABLE_RSS) || tnapi == &tp->napi[1]) {
|
|
|
+ if (work_mask & RXD_OPAQUE_RING_STD) {
|
|
|
+ tpr->rx_std_prod_idx = std_prod_idx % TG3_RX_RING_SIZE;
|
|
|
+ tw32_rx_mbox(TG3_RX_STD_PROD_IDX_REG,
|
|
|
+ tpr->rx_std_prod_idx);
|
|
|
+ }
|
|
|
+ if (work_mask & RXD_OPAQUE_RING_JUMBO) {
|
|
|
+ tpr->rx_jmb_prod_idx = jmb_prod_idx %
|
|
|
+ TG3_RX_JUMBO_RING_SIZE;
|
|
|
+ tw32_rx_mbox(TG3_RX_JMB_PROD_IDX_REG,
|
|
|
+ tpr->rx_jmb_prod_idx);
|
|
|
+ }
|
|
|
+ mmiowb();
|
|
|
+ } else if (work_mask) {
|
|
|
+ /* rx_std_buffers[] and rx_jmb_buffers[] entries must be
|
|
|
+ * updated before the producer indices can be updated.
|
|
|
+ */
|
|
|
+ smp_wmb();
|
|
|
+
|
|
|
tpr->rx_std_prod_idx = std_prod_idx % TG3_RX_RING_SIZE;
|
|
|
- tw32_rx_mbox(TG3_RX_STD_PROD_IDX_REG, tpr->rx_std_prod_idx);
|
|
|
- }
|
|
|
- if (work_mask & RXD_OPAQUE_RING_JUMBO) {
|
|
|
tpr->rx_jmb_prod_idx = jmb_prod_idx % TG3_RX_JUMBO_RING_SIZE;
|
|
|
- tw32_rx_mbox(TG3_RX_JMB_PROD_IDX_REG, tpr->rx_jmb_prod_idx);
|
|
|
+
|
|
|
+ napi_schedule(&tp->napi[1].napi);
|
|
|
}
|
|
|
- mmiowb();
|
|
|
|
|
|
return received;
|
|
|
}
|
|
@@ -4743,6 +4758,93 @@ static void tg3_poll_link(struct tg3 *tp)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+static void tg3_rx_prodring_xfer(struct tg3 *tp,
|
|
|
+ struct tg3_rx_prodring_set *dpr,
|
|
|
+ struct tg3_rx_prodring_set *spr)
|
|
|
+{
|
|
|
+ u32 si, di, cpycnt, src_prod_idx;
|
|
|
+ int i;
|
|
|
+
|
|
|
+ while (1) {
|
|
|
+ src_prod_idx = spr->rx_std_prod_idx;
|
|
|
+
|
|
|
+ /* Make sure updates to the rx_std_buffers[] entries and the
|
|
|
+ * standard producer index are seen in the correct order.
|
|
|
+ */
|
|
|
+ smp_rmb();
|
|
|
+
|
|
|
+ if (spr->rx_std_cons_idx == src_prod_idx)
|
|
|
+ break;
|
|
|
+
|
|
|
+ if (spr->rx_std_cons_idx < src_prod_idx)
|
|
|
+ cpycnt = src_prod_idx - spr->rx_std_cons_idx;
|
|
|
+ else
|
|
|
+ cpycnt = TG3_RX_RING_SIZE - spr->rx_std_cons_idx;
|
|
|
+
|
|
|
+ cpycnt = min(cpycnt, TG3_RX_RING_SIZE - dpr->rx_std_prod_idx);
|
|
|
+
|
|
|
+ si = spr->rx_std_cons_idx;
|
|
|
+ di = dpr->rx_std_prod_idx;
|
|
|
+
|
|
|
+ memcpy(&dpr->rx_std_buffers[di],
|
|
|
+ &spr->rx_std_buffers[si],
|
|
|
+ cpycnt * sizeof(struct ring_info));
|
|
|
+
|
|
|
+ for (i = 0; i < cpycnt; i++, di++, si++) {
|
|
|
+ struct tg3_rx_buffer_desc *sbd, *dbd;
|
|
|
+ sbd = &spr->rx_std[si];
|
|
|
+ dbd = &dpr->rx_std[di];
|
|
|
+ dbd->addr_hi = sbd->addr_hi;
|
|
|
+ dbd->addr_lo = sbd->addr_lo;
|
|
|
+ }
|
|
|
+
|
|
|
+ spr->rx_std_cons_idx = (spr->rx_std_cons_idx + cpycnt) %
|
|
|
+ TG3_RX_RING_SIZE;
|
|
|
+ dpr->rx_std_prod_idx = (dpr->rx_std_prod_idx + cpycnt) %
|
|
|
+ TG3_RX_RING_SIZE;
|
|
|
+ }
|
|
|
+
|
|
|
+ while (1) {
|
|
|
+ src_prod_idx = spr->rx_jmb_prod_idx;
|
|
|
+
|
|
|
+ /* Make sure updates to the rx_jmb_buffers[] entries and
|
|
|
+ * the jumbo producer index are seen in the correct order.
|
|
|
+ */
|
|
|
+ smp_rmb();
|
|
|
+
|
|
|
+ if (spr->rx_jmb_cons_idx == src_prod_idx)
|
|
|
+ break;
|
|
|
+
|
|
|
+ if (spr->rx_jmb_cons_idx < src_prod_idx)
|
|
|
+ cpycnt = src_prod_idx - spr->rx_jmb_cons_idx;
|
|
|
+ else
|
|
|
+ cpycnt = TG3_RX_JUMBO_RING_SIZE - spr->rx_jmb_cons_idx;
|
|
|
+
|
|
|
+ cpycnt = min(cpycnt,
|
|
|
+ TG3_RX_JUMBO_RING_SIZE - dpr->rx_jmb_prod_idx);
|
|
|
+
|
|
|
+ si = spr->rx_jmb_cons_idx;
|
|
|
+ di = dpr->rx_jmb_prod_idx;
|
|
|
+
|
|
|
+ memcpy(&dpr->rx_jmb_buffers[di],
|
|
|
+ &spr->rx_jmb_buffers[si],
|
|
|
+ cpycnt * sizeof(struct ring_info));
|
|
|
+
|
|
|
+ for (i = 0; i < cpycnt; i++, di++, si++) {
|
|
|
+ struct tg3_rx_buffer_desc *sbd, *dbd;
|
|
|
+ sbd = &spr->rx_jmb[si].std;
|
|
|
+ dbd = &dpr->rx_jmb[di].std;
|
|
|
+ dbd->addr_hi = sbd->addr_hi;
|
|
|
+ dbd->addr_lo = sbd->addr_lo;
|
|
|
+ }
|
|
|
+
|
|
|
+ spr->rx_jmb_cons_idx = (spr->rx_jmb_cons_idx + cpycnt) %
|
|
|
+ TG3_RX_JUMBO_RING_SIZE;
|
|
|
+ dpr->rx_jmb_prod_idx = (dpr->rx_jmb_prod_idx + cpycnt) %
|
|
|
+ TG3_RX_JUMBO_RING_SIZE;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
static int tg3_poll_work(struct tg3_napi *tnapi, int work_done, int budget)
|
|
|
{
|
|
|
struct tg3 *tp = tnapi->tp;
|
|
@@ -4761,6 +4863,30 @@ static int tg3_poll_work(struct tg3_napi *tnapi, int work_done, int budget)
|
|
|
if (*(tnapi->rx_rcb_prod_idx) != tnapi->rx_rcb_ptr)
|
|
|
work_done += tg3_rx(tnapi, budget - work_done);
|
|
|
|
|
|
+ if ((tp->tg3_flags3 & TG3_FLG3_ENABLE_RSS) && tnapi == &tp->napi[1]) {
|
|
|
+ int i;
|
|
|
+ u32 std_prod_idx = tp->prodring[0].rx_std_prod_idx;
|
|
|
+ u32 jmb_prod_idx = tp->prodring[0].rx_jmb_prod_idx;
|
|
|
+
|
|
|
+ for (i = 2; i < tp->irq_cnt; i++)
|
|
|
+ tg3_rx_prodring_xfer(tp, tnapi->prodring,
|
|
|
+ tp->napi[i].prodring);
|
|
|
+
|
|
|
+ wmb();
|
|
|
+
|
|
|
+ if (std_prod_idx != tp->prodring[0].rx_std_prod_idx) {
|
|
|
+ u32 mbox = TG3_RX_STD_PROD_IDX_REG;
|
|
|
+ tw32_rx_mbox(mbox, tp->prodring[0].rx_std_prod_idx);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (jmb_prod_idx != tp->prodring[0].rx_jmb_prod_idx) {
|
|
|
+ u32 mbox = TG3_RX_JMB_PROD_IDX_REG;
|
|
|
+ tw32_rx_mbox(mbox, tp->prodring[0].rx_jmb_prod_idx);
|
|
|
+ }
|
|
|
+
|
|
|
+ mmiowb();
|
|
|
+ }
|
|
|
+
|
|
|
return work_done;
|
|
|
}
|
|
|
|
|
@@ -5715,8 +5841,23 @@ static void tg3_rx_prodring_free(struct tg3 *tp,
|
|
|
{
|
|
|
int i;
|
|
|
|
|
|
- if (tpr != &tp->prodring[0])
|
|
|
+ if (tpr != &tp->prodring[0]) {
|
|
|
+ for (i = tpr->rx_std_cons_idx; i != tpr->rx_std_prod_idx;
|
|
|
+ i = (i + 1) % TG3_RX_RING_SIZE)
|
|
|
+ tg3_rx_skb_free(tp, &tpr->rx_std_buffers[i],
|
|
|
+ tp->rx_pkt_map_sz);
|
|
|
+
|
|
|
+ if (tp->tg3_flags & TG3_FLAG_JUMBO_CAPABLE) {
|
|
|
+ for (i = tpr->rx_jmb_cons_idx;
|
|
|
+ i != tpr->rx_jmb_prod_idx;
|
|
|
+ i = (i + 1) % TG3_RX_JUMBO_RING_SIZE) {
|
|
|
+ tg3_rx_skb_free(tp, &tpr->rx_jmb_buffers[i],
|
|
|
+ TG3_RX_JMB_MAP_SZ);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
return;
|
|
|
+ }
|
|
|
|
|
|
for (i = 0; i < TG3_RX_RING_SIZE; i++)
|
|
|
tg3_rx_skb_free(tp, &tpr->rx_std_buffers[i],
|
|
@@ -5741,6 +5882,11 @@ static int tg3_rx_prodring_alloc(struct tg3 *tp,
|
|
|
{
|
|
|
u32 i, rx_pkt_dma_sz;
|
|
|
|
|
|
+ tpr->rx_std_cons_idx = 0;
|
|
|
+ tpr->rx_std_prod_idx = 0;
|
|
|
+ tpr->rx_jmb_cons_idx = 0;
|
|
|
+ tpr->rx_jmb_prod_idx = 0;
|
|
|
+
|
|
|
if (tpr != &tp->prodring[0]) {
|
|
|
memset(&tpr->rx_std_buffers[0], 0, TG3_RX_STD_BUFF_RING_SIZE);
|
|
|
if (tp->tg3_flags & TG3_FLAG_JUMBO_CAPABLE)
|
|
@@ -6062,6 +6208,11 @@ static int tg3_alloc_consistent(struct tg3 *tp)
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
+ if (tp->irq_cnt == 1)
|
|
|
+ tnapi->prodring = &tp->prodring[0];
|
|
|
+ else if (i)
|
|
|
+ tnapi->prodring = &tp->prodring[i - 1];
|
|
|
+
|
|
|
/*
|
|
|
* If multivector RSS is enabled, vector 0 does not handle
|
|
|
* rx or tx interrupts. Don't allocate any resources for it.
|