diff options
-rw-r--r-- | drivers/net/cxgb3/sge.c | 82 |
1 files changed, 40 insertions, 42 deletions
diff --git a/drivers/net/cxgb3/sge.c b/drivers/net/cxgb3/sge.c index c15e43a8543b..7b13d8a31e38 100644 --- a/drivers/net/cxgb3/sge.c +++ b/drivers/net/cxgb3/sge.c | |||
@@ -91,6 +91,10 @@ struct rx_desc { | |||
91 | 91 | ||
92 | struct tx_sw_desc { /* SW state per Tx descriptor */ | 92 | struct tx_sw_desc { /* SW state per Tx descriptor */ |
93 | struct sk_buff *skb; | 93 | struct sk_buff *skb; |
94 | u8 eop; /* set if last descriptor for packet */ | ||
95 | u8 addr_idx; /* buffer index of first SGL entry in descriptor */ | ||
96 | u8 fragidx; /* first page fragment associated with descriptor */ | ||
97 | s8 sflit; /* start flit of first SGL entry in descriptor */ | ||
94 | }; | 98 | }; |
95 | 99 | ||
96 | struct rx_sw_desc { /* SW state per Rx descriptor */ | 100 | struct rx_sw_desc { /* SW state per Rx descriptor */ |
@@ -109,13 +113,6 @@ struct rsp_desc { /* response queue descriptor */ | |||
109 | u8 intr_gen; | 113 | u8 intr_gen; |
110 | }; | 114 | }; |
111 | 115 | ||
112 | struct unmap_info { /* packet unmapping info, overlays skb->cb */ | ||
113 | int sflit; /* start flit of first SGL entry in Tx descriptor */ | ||
114 | u16 fragidx; /* first page fragment in current Tx descriptor */ | ||
115 | u16 addr_idx; /* buffer index of first SGL entry in descriptor */ | ||
116 | u32 len; /* mapped length of skb main body */ | ||
117 | }; | ||
118 | |||
119 | /* | 116 | /* |
120 | * Holds unmapping information for Tx packets that need deferred unmapping. | 117 | * Holds unmapping information for Tx packets that need deferred unmapping. |
121 | * This structure lives at skb->head and must be allocated by callers. | 118 | * This structure lives at skb->head and must be allocated by callers. |
@@ -209,32 +206,36 @@ static inline int need_skb_unmap(void) | |||
209 | * | 206 | * |
210 | * Unmap the main body of an sk_buff and its page fragments, if any. | 207 | * Unmap the main body of an sk_buff and its page fragments, if any. |
211 | * Because of the fairly complicated structure of our SGLs and the desire | 208 | * Because of the fairly complicated structure of our SGLs and the desire |
212 | * to conserve space for metadata, we keep the information necessary to | 209 | * to conserve space for metadata, the information necessary to unmap an |
213 | * unmap an sk_buff partly in the sk_buff itself (in its cb), and partly | 210 | * sk_buff is spread across the sk_buff itself (buffer lengths), the HW Tx |
214 | * in the Tx descriptors (the physical addresses of the various data | 211 | * descriptors (the physical addresses of the various data buffers), and |
215 | * buffers). The send functions initialize the state in skb->cb so we | 212 | * the SW descriptor state (assorted indices). The send functions |
216 | * can unmap the buffers held in the first Tx descriptor here, and we | 213 | * initialize the indices for the first packet descriptor so we can unmap |
217 | * have enough information at this point to update the state for the next | 214 | * the buffers held in the first Tx descriptor here, and we have enough |
218 | * Tx descriptor. | 215 | * information at this point to set the state for the next Tx descriptor. |
216 | * | ||
217 | * Note that it is possible to clean up the first descriptor of a packet | ||
218 | * before the send routines have written the next descriptors, but this | ||
219 | * race does not cause any problem. We just end up writing the unmapping | ||
220 | * info for the descriptor first. | ||
219 | */ | 221 | */ |
220 | static inline void unmap_skb(struct sk_buff *skb, struct sge_txq *q, | 222 | static inline void unmap_skb(struct sk_buff *skb, struct sge_txq *q, |
221 | unsigned int cidx, struct pci_dev *pdev) | 223 | unsigned int cidx, struct pci_dev *pdev) |
222 | { | 224 | { |
223 | const struct sg_ent *sgp; | 225 | const struct sg_ent *sgp; |
224 | struct unmap_info *ui = (struct unmap_info *)skb->cb; | 226 | struct tx_sw_desc *d = &q->sdesc[cidx]; |
225 | int nfrags, frag_idx, curflit, j = ui->addr_idx; | 227 | int nfrags, frag_idx, curflit, j = d->addr_idx; |
226 | 228 | ||
227 | sgp = (struct sg_ent *)&q->desc[cidx].flit[ui->sflit]; | 229 | sgp = (struct sg_ent *)&q->desc[cidx].flit[d->sflit]; |
230 | frag_idx = d->fragidx; | ||
228 | 231 | ||
229 | if (ui->len) { | 232 | if (frag_idx == 0 && skb_headlen(skb)) { |
230 | pci_unmap_single(pdev, be64_to_cpu(sgp->addr[0]), ui->len, | 233 | pci_unmap_single(pdev, be64_to_cpu(sgp->addr[0]), |
231 | PCI_DMA_TODEVICE); | 234 | skb_headlen(skb), PCI_DMA_TODEVICE); |
232 | ui->len = 0; /* so we know for next descriptor for this skb */ | ||
233 | j = 1; | 235 | j = 1; |
234 | } | 236 | } |
235 | 237 | ||
236 | frag_idx = ui->fragidx; | 238 | curflit = d->sflit + 1 + j; |
237 | curflit = ui->sflit + 1 + j; | ||
238 | nfrags = skb_shinfo(skb)->nr_frags; | 239 | nfrags = skb_shinfo(skb)->nr_frags; |
239 | 240 | ||
240 | while (frag_idx < nfrags && curflit < WR_FLITS) { | 241 | while (frag_idx < nfrags && curflit < WR_FLITS) { |
@@ -250,10 +251,11 @@ static inline void unmap_skb(struct sk_buff *skb, struct sge_txq *q, | |||
250 | frag_idx++; | 251 | frag_idx++; |
251 | } | 252 | } |
252 | 253 | ||
253 | if (frag_idx < nfrags) { /* SGL continues into next Tx descriptor */ | 254 | if (frag_idx < nfrags) { /* SGL continues into next Tx descriptor */ |
254 | ui->fragidx = frag_idx; | 255 | d = cidx + 1 == q->size ? q->sdesc : d + 1; |
255 | ui->addr_idx = j; | 256 | d->fragidx = frag_idx; |
256 | ui->sflit = curflit - WR_FLITS - j; /* sflit can be -1 */ | 257 | d->addr_idx = j; |
258 | d->sflit = curflit - WR_FLITS - j; /* sflit can be -1 */ | ||
257 | } | 259 | } |
258 | } | 260 | } |
259 | 261 | ||
@@ -281,7 +283,7 @@ static void free_tx_desc(struct adapter *adapter, struct sge_txq *q, | |||
281 | if (d->skb) { /* an SGL is present */ | 283 | if (d->skb) { /* an SGL is present */ |
282 | if (need_unmap) | 284 | if (need_unmap) |
283 | unmap_skb(d->skb, q, cidx, pdev); | 285 | unmap_skb(d->skb, q, cidx, pdev); |
284 | if (d->skb->priority == cidx) | 286 | if (d->eop) |
285 | kfree_skb(d->skb); | 287 | kfree_skb(d->skb); |
286 | } | 288 | } |
287 | ++d; | 289 | ++d; |
@@ -912,15 +914,13 @@ static void write_wr_hdr_sgl(unsigned int ndesc, struct sk_buff *skb, | |||
912 | 914 | ||
913 | sd->skb = skb; | 915 | sd->skb = skb; |
914 | if (need_skb_unmap()) { | 916 | if (need_skb_unmap()) { |
915 | struct unmap_info *ui = (struct unmap_info *)skb->cb; | 917 | sd->fragidx = 0; |
916 | 918 | sd->addr_idx = 0; | |
917 | ui->fragidx = 0; | 919 | sd->sflit = flits; |
918 | ui->addr_idx = 0; | ||
919 | ui->sflit = flits; | ||
920 | } | 920 | } |
921 | 921 | ||
922 | if (likely(ndesc == 1)) { | 922 | if (likely(ndesc == 1)) { |
923 | skb->priority = pidx; | 923 | sd->eop = 1; |
924 | wrp->wr_hi = htonl(F_WR_SOP | F_WR_EOP | V_WR_DATATYPE(1) | | 924 | wrp->wr_hi = htonl(F_WR_SOP | F_WR_EOP | V_WR_DATATYPE(1) | |
925 | V_WR_SGLSFLT(flits)) | wr_hi; | 925 | V_WR_SGLSFLT(flits)) | wr_hi; |
926 | wmb(); | 926 | wmb(); |
@@ -948,6 +948,7 @@ static void write_wr_hdr_sgl(unsigned int ndesc, struct sk_buff *skb, | |||
948 | 948 | ||
949 | fp += avail; | 949 | fp += avail; |
950 | d++; | 950 | d++; |
951 | sd->eop = 0; | ||
951 | sd++; | 952 | sd++; |
952 | if (++pidx == q->size) { | 953 | if (++pidx == q->size) { |
953 | pidx = 0; | 954 | pidx = 0; |
@@ -966,7 +967,7 @@ static void write_wr_hdr_sgl(unsigned int ndesc, struct sk_buff *skb, | |||
966 | wr_gen2(d, gen); | 967 | wr_gen2(d, gen); |
967 | flits = 1; | 968 | flits = 1; |
968 | } | 969 | } |
969 | skb->priority = pidx; | 970 | sd->eop = 1; |
970 | wrp->wr_hi |= htonl(F_WR_EOP); | 971 | wrp->wr_hi |= htonl(F_WR_EOP); |
971 | wmb(); | 972 | wmb(); |
972 | wp->wr_lo = htonl(V_WR_LEN(WR_FLITS) | V_WR_GEN(ogen)) | wr_lo; | 973 | wp->wr_lo = htonl(V_WR_LEN(WR_FLITS) | V_WR_GEN(ogen)) | wr_lo; |
@@ -1051,8 +1052,6 @@ static void write_tx_pkt_wr(struct adapter *adap, struct sk_buff *skb, | |||
1051 | 1052 | ||
1052 | sgp = ndesc == 1 ? (struct sg_ent *)&d->flit[flits] : sgl; | 1053 | sgp = ndesc == 1 ? (struct sg_ent *)&d->flit[flits] : sgl; |
1053 | sgl_flits = make_sgl(skb, sgp, skb->data, skb_headlen(skb), adap->pdev); | 1054 | sgl_flits = make_sgl(skb, sgp, skb->data, skb_headlen(skb), adap->pdev); |
1054 | if (need_skb_unmap()) | ||
1055 | ((struct unmap_info *)skb->cb)->len = skb_headlen(skb); | ||
1056 | 1055 | ||
1057 | write_wr_hdr_sgl(ndesc, skb, d, pidx, q, sgl, flits, sgl_flits, gen, | 1056 | write_wr_hdr_sgl(ndesc, skb, d, pidx, q, sgl, flits, sgl_flits, gen, |
1058 | htonl(V_WR_OP(FW_WROPCODE_TUNNEL_TX_PKT) | compl), | 1057 | htonl(V_WR_OP(FW_WROPCODE_TUNNEL_TX_PKT) | compl), |
@@ -1380,13 +1379,14 @@ static void deferred_unmap_destructor(struct sk_buff *skb) | |||
1380 | const dma_addr_t *p; | 1379 | const dma_addr_t *p; |
1381 | const struct skb_shared_info *si; | 1380 | const struct skb_shared_info *si; |
1382 | const struct deferred_unmap_info *dui; | 1381 | const struct deferred_unmap_info *dui; |
1383 | const struct unmap_info *ui = (struct unmap_info *)skb->cb; | ||
1384 | 1382 | ||
1385 | dui = (struct deferred_unmap_info *)skb->head; | 1383 | dui = (struct deferred_unmap_info *)skb->head; |
1386 | p = dui->addr; | 1384 | p = dui->addr; |
1387 | 1385 | ||
1388 | if (ui->len) | 1386 | if (skb->tail - skb->transport_header) |
1389 | pci_unmap_single(dui->pdev, *p++, ui->len, PCI_DMA_TODEVICE); | 1387 | pci_unmap_single(dui->pdev, *p++, |
1388 | skb->tail - skb->transport_header, | ||
1389 | PCI_DMA_TODEVICE); | ||
1390 | 1390 | ||
1391 | si = skb_shinfo(skb); | 1391 | si = skb_shinfo(skb); |
1392 | for (i = 0; i < si->nr_frags; i++) | 1392 | for (i = 0; i < si->nr_frags; i++) |
@@ -1451,8 +1451,6 @@ static void write_ofld_wr(struct adapter *adap, struct sk_buff *skb, | |||
1451 | if (need_skb_unmap()) { | 1451 | if (need_skb_unmap()) { |
1452 | setup_deferred_unmapping(skb, adap->pdev, sgp, sgl_flits); | 1452 | setup_deferred_unmapping(skb, adap->pdev, sgp, sgl_flits); |
1453 | skb->destructor = deferred_unmap_destructor; | 1453 | skb->destructor = deferred_unmap_destructor; |
1454 | ((struct unmap_info *)skb->cb)->len = (skb->tail - | ||
1455 | skb->transport_header); | ||
1456 | } | 1454 | } |
1457 | 1455 | ||
1458 | write_wr_hdr_sgl(ndesc, skb, d, pidx, q, sgl, flits, sgl_flits, | 1456 | write_wr_hdr_sgl(ndesc, skb, d, pidx, q, sgl, flits, sgl_flits, |