diff options
author | David Daney <ddaney@caviumnetworks.com> | 2010-01-07 14:05:05 -0500 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2010-02-27 06:53:08 -0500 |
commit | 924cc2680fbe181066ec138d369691d28d913ea2 (patch) | |
tree | 009d3b28ddf2ebc9466b882fd8170ea97e6d8a73 /drivers | |
parent | 3368c784bcf77124aaf39372e627016c36bd4472 (diff) |
Staging: Octeon Ethernet: Enable scatter-gather.
Octeon ethernet hardware can handle NETIF_F_SG, so we enable it.
A gather list of up to six fragments will fit in the SKB's CB
structure, so no extra memory is required. If a SKB has more than six
fragments, we must linearize it.
Signed-off-by: David Daney <ddaney@caviumnetworks.com>
To: linux-mips@linux-mips.org
To: gregkh@suse.de
Patchwork: http://patchwork.linux-mips.org/patch/838/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/staging/octeon/ethernet-tx.c | 57 | ||||
-rw-r--r-- | drivers/staging/octeon/ethernet.c | 7 |
2 files changed, 55 insertions, 9 deletions
diff --git a/drivers/staging/octeon/ethernet-tx.c b/drivers/staging/octeon/ethernet-tx.c index 05b58f8b58fd..bc67e416e421 100644 --- a/drivers/staging/octeon/ethernet-tx.c +++ b/drivers/staging/octeon/ethernet-tx.c | |||
@@ -53,6 +53,8 @@ | |||
53 | 53 | ||
54 | #include "cvmx-gmxx-defs.h" | 54 | #include "cvmx-gmxx-defs.h" |
55 | 55 | ||
56 | #define CVM_OCT_SKB_CB(skb) ((u64 *)((skb)->cb)) | ||
57 | |||
56 | /* | 58 | /* |
57 | * You can define GET_SKBUFF_QOS() to override how the skbuff output | 59 | * You can define GET_SKBUFF_QOS() to override how the skbuff output |
58 | * function determines which output queue is used. The default | 60 | * function determines which output queue is used. The default |
@@ -121,6 +123,7 @@ int cvm_oct_xmit(struct sk_buff *skb, struct net_device *dev) | |||
121 | uint64_t old_scratch; | 123 | uint64_t old_scratch; |
122 | uint64_t old_scratch2; | 124 | uint64_t old_scratch2; |
123 | int qos; | 125 | int qos; |
126 | int i; | ||
124 | enum {QUEUE_CORE, QUEUE_HW, QUEUE_DROP} queue_type; | 127 | enum {QUEUE_CORE, QUEUE_HW, QUEUE_DROP} queue_type; |
125 | struct octeon_ethernet *priv = netdev_priv(dev); | 128 | struct octeon_ethernet *priv = netdev_priv(dev); |
126 | struct sk_buff *to_free_list; | 129 | struct sk_buff *to_free_list; |
@@ -171,6 +174,28 @@ int cvm_oct_xmit(struct sk_buff *skb, struct net_device *dev) | |||
171 | } | 174 | } |
172 | 175 | ||
173 | /* | 176 | /* |
177 | * We have space for 6 segment pointers, If there will be more | ||
178 | * than that, we must linearize. | ||
179 | */ | ||
180 | if (unlikely(skb_shinfo(skb)->nr_frags > 5)) { | ||
181 | if (unlikely(__skb_linearize(skb))) { | ||
182 | queue_type = QUEUE_DROP; | ||
183 | if (USE_ASYNC_IOBDMA) { | ||
184 | /* Get the number of skbuffs in use by the hardware */ | ||
185 | CVMX_SYNCIOBDMA; | ||
186 | skb_to_free = cvmx_scratch_read64(CVMX_SCR_SCRATCH); | ||
187 | } else { | ||
188 | /* Get the number of skbuffs in use by the hardware */ | ||
189 | skb_to_free = cvmx_fau_fetch_and_add32(priv->fau + qos * 4, | ||
190 | MAX_SKB_TO_FREE); | ||
191 | } | ||
192 | skb_to_free = cvm_oct_adjust_skb_to_free(skb_to_free, priv->fau + qos * 4); | ||
193 | spin_lock_irqsave(&priv->tx_free_list[qos].lock, flags); | ||
194 | goto skip_xmit; | ||
195 | } | ||
196 | } | ||
197 | |||
198 | /* | ||
174 | * The CN3XXX series of parts has an errata (GMX-401) which | 199 | * The CN3XXX series of parts has an errata (GMX-401) which |
175 | * causes the GMX block to hang if a collision occurs towards | 200 | * causes the GMX block to hang if a collision occurs towards |
176 | * the end of a <68 byte packet. As a workaround for this, we | 201 | * the end of a <68 byte packet. As a workaround for this, we |
@@ -198,13 +223,6 @@ int cvm_oct_xmit(struct sk_buff *skb, struct net_device *dev) | |||
198 | } | 223 | } |
199 | } | 224 | } |
200 | 225 | ||
201 | /* Build the PKO buffer pointer */ | ||
202 | hw_buffer.u64 = 0; | ||
203 | hw_buffer.s.addr = cvmx_ptr_to_phys(skb->data); | ||
204 | hw_buffer.s.pool = 0; | ||
205 | hw_buffer.s.size = | ||
206 | (unsigned long)skb_end_pointer(skb) - (unsigned long)skb->head; | ||
207 | |||
208 | /* Build the PKO command */ | 226 | /* Build the PKO command */ |
209 | pko_command.u64 = 0; | 227 | pko_command.u64 = 0; |
210 | pko_command.s.n2 = 1; /* Don't pollute L2 with the outgoing packet */ | 228 | pko_command.s.n2 = 1; /* Don't pollute L2 with the outgoing packet */ |
@@ -215,6 +233,31 @@ int cvm_oct_xmit(struct sk_buff *skb, struct net_device *dev) | |||
215 | 233 | ||
216 | pko_command.s.dontfree = 1; | 234 | pko_command.s.dontfree = 1; |
217 | pko_command.s.reg0 = priv->fau + qos * 4; | 235 | pko_command.s.reg0 = priv->fau + qos * 4; |
236 | |||
237 | /* Build the PKO buffer pointer */ | ||
238 | hw_buffer.u64 = 0; | ||
239 | if (skb_shinfo(skb)->nr_frags == 0) { | ||
240 | hw_buffer.s.addr = XKPHYS_TO_PHYS((u64)skb->data); | ||
241 | hw_buffer.s.pool = 0; | ||
242 | hw_buffer.s.size = skb->len; | ||
243 | } else { | ||
244 | hw_buffer.s.addr = XKPHYS_TO_PHYS((u64)skb->data); | ||
245 | hw_buffer.s.pool = 0; | ||
246 | hw_buffer.s.size = skb_headlen(skb); | ||
247 | CVM_OCT_SKB_CB(skb)[0] = hw_buffer.u64; | ||
248 | for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { | ||
249 | struct skb_frag_struct *fs = skb_shinfo(skb)->frags + i; | ||
250 | hw_buffer.s.addr = XKPHYS_TO_PHYS((u64)(page_address(fs->page) + fs->page_offset)); | ||
251 | hw_buffer.s.size = fs->size; | ||
252 | CVM_OCT_SKB_CB(skb)[i + 1] = hw_buffer.u64; | ||
253 | } | ||
254 | hw_buffer.s.addr = XKPHYS_TO_PHYS((u64)CVM_OCT_SKB_CB(skb)); | ||
255 | hw_buffer.s.size = skb_shinfo(skb)->nr_frags + 1; | ||
256 | pko_command.s.segs = skb_shinfo(skb)->nr_frags + 1; | ||
257 | pko_command.s.gather = 1; | ||
258 | goto dont_put_skbuff_in_hw; | ||
259 | } | ||
260 | |||
218 | /* | 261 | /* |
219 | * See if we can put this skb in the FPA pool. Any strange | 262 | * See if we can put this skb in the FPA pool. Any strange |
220 | * behavior from the Linux networking stack will most likely | 263 | * behavior from the Linux networking stack will most likely |
diff --git a/drivers/staging/octeon/ethernet.c b/drivers/staging/octeon/ethernet.c index 9f5b7419e777..9d632020b9ee 100644 --- a/drivers/staging/octeon/ethernet.c +++ b/drivers/staging/octeon/ethernet.c | |||
@@ -484,8 +484,11 @@ int cvm_oct_common_init(struct net_device *dev) | |||
484 | && (always_use_pow || strstr(pow_send_list, dev->name))) | 484 | && (always_use_pow || strstr(pow_send_list, dev->name))) |
485 | priv->queue = -1; | 485 | priv->queue = -1; |
486 | 486 | ||
487 | if (priv->queue != -1 && USE_HW_TCPUDP_CHECKSUM) | 487 | if (priv->queue != -1) { |
488 | dev->features |= NETIF_F_IP_CSUM; | 488 | dev->features |= NETIF_F_SG; |
489 | if (USE_HW_TCPUDP_CHECKSUM) | ||
490 | dev->features |= NETIF_F_IP_CSUM; | ||
491 | } | ||
489 | 492 | ||
490 | /* We do our own locking, Linux doesn't need to */ | 493 | /* We do our own locking, Linux doesn't need to */ |
491 | dev->features |= NETIF_F_LLTX; | 494 | dev->features |= NETIF_F_LLTX; |