ethernet-tx.c revision 4898c560103fb8075c10a8e9d70e0ca26873075e
180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney/*********************************************************************
280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * Author: Cavium Networks
380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney *
480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * Contact: support@caviumnetworks.com
580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * This file is part of the OCTEON SDK
680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney *
7166bdaa9aad9903bf4330ef68feb37f220c9eac8David Daney * Copyright (c) 2003-2010 Cavium Networks
880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney *
980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * This file is free software; you can redistribute it and/or modify
1080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * it under the terms of the GNU General Public License, Version 2, as
1180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * published by the Free Software Foundation.
1280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney *
1380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * This file is distributed in the hope that it will be useful, but
1480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
1580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
1680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * NONINFRINGEMENT.  See the GNU General Public License for more
1780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * details.
1880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney *
1980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * You should have received a copy of the GNU General Public License
2080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * along with this file; if not, write to the Free Software
2180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
2280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * or visit http://www.gnu.org/licenses/.
2380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney *
2480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * This file may also be available under a different license from Cavium.
2580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * Contact Cavium Networks for more information
2680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney*********************************************************************/
2780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#include <linux/module.h>
2880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#include <linux/kernel.h>
2980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#include <linux/netdevice.h>
3080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#include <linux/init.h>
3180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#include <linux/etherdevice.h>
3280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#include <linux/ip.h>
3380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#include <linux/string.h>
3480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#include <net/dst.h>
3580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#ifdef CONFIG_XFRM
3680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#include <linux/xfrm.h>
3780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#include <net/xfrm.h>
3880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#endif /* CONFIG_XFRM */
3980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney
4080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#include <asm/atomic.h>
4180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney
4280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#include <asm/octeon/octeon.h>
4380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney
4480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#include "ethernet-defines.h"
4580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#include "octeon-ethernet.h"
46a620c1632629b42369e78448acc7b384fe1faf48David Daney#include "ethernet-tx.h"
4780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#include "ethernet-util.h"
4880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney
4980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#include "cvmx-wqe.h"
5080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#include "cvmx-fau.h"
514898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney#include "cvmx-pip.h"
5280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#include "cvmx-pko.h"
5380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#include "cvmx-helper.h"
5480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney
5580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#include "cvmx-gmxx-defs.h"
5680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney
57924cc2680fbe181066ec138d369691d28d913ea2David Daney#define CVM_OCT_SKB_CB(skb)	((u64 *)((skb)->cb))
58924cc2680fbe181066ec138d369691d28d913ea2David Daney
5980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney/*
6080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * You can define GET_SKBUFF_QOS() to override how the skbuff output
6180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * function determines which output queue is used. The default
6280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * implementation always uses the base queue for the port. If, for
6380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * example, you wanted to use the skb->priority fieid, define
6480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * GET_SKBUFF_QOS as: #define GET_SKBUFF_QOS(skb) ((skb)->priority)
6580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney */
6680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#ifndef GET_SKBUFF_QOS
6780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#define GET_SKBUFF_QOS(skb) 0
6880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#endif
6980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney
704898c560103fb8075c10a8e9d70e0ca26873075eDavid Daneystatic void cvm_oct_tx_do_cleanup(unsigned long arg);
714898c560103fb8075c10a8e9d70e0ca26873075eDavid Daneystatic DECLARE_TASKLET(cvm_oct_tx_cleanup_tasklet, cvm_oct_tx_do_cleanup, 0);
724898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney
734898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney/* Maximum number of SKBs to try to free per xmit packet. */
744898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney#define MAX_SKB_TO_FREE (MAX_OUT_QUEUE_DEPTH * 2)
756888fc87768eaa218b6244f2e78c55416706981aDavid Daney
766888fc87768eaa218b6244f2e78c55416706981aDavid Daneystatic inline int32_t cvm_oct_adjust_skb_to_free(int32_t skb_to_free, int fau)
776888fc87768eaa218b6244f2e78c55416706981aDavid Daney{
786888fc87768eaa218b6244f2e78c55416706981aDavid Daney	int32_t undo;
796888fc87768eaa218b6244f2e78c55416706981aDavid Daney	undo = skb_to_free > 0 ? MAX_SKB_TO_FREE : skb_to_free + MAX_SKB_TO_FREE;
806888fc87768eaa218b6244f2e78c55416706981aDavid Daney	if (undo > 0)
816888fc87768eaa218b6244f2e78c55416706981aDavid Daney		cvmx_fau_atomic_add32(fau, -undo);
826888fc87768eaa218b6244f2e78c55416706981aDavid Daney	skb_to_free = -skb_to_free > MAX_SKB_TO_FREE ? MAX_SKB_TO_FREE : -skb_to_free;
836888fc87768eaa218b6244f2e78c55416706981aDavid Daney	return skb_to_free;
846888fc87768eaa218b6244f2e78c55416706981aDavid Daney}
856888fc87768eaa218b6244f2e78c55416706981aDavid Daney
864898c560103fb8075c10a8e9d70e0ca26873075eDavid Daneystatic void cvm_oct_kick_tx_poll_watchdog(void)
874898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney{
884898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney	union cvmx_ciu_timx ciu_timx;
894898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney	ciu_timx.u64 = 0;
904898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney	ciu_timx.s.one_shot = 1;
914898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney	ciu_timx.s.len = cvm_oct_tx_poll_interval;
924898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney	cvmx_write_csr(CVMX_CIU_TIMX(1), ciu_timx.u64);
934898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney}
944898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney
954898c560103fb8075c10a8e9d70e0ca26873075eDavid Daneyvoid cvm_oct_free_tx_skbs(struct net_device *dev)
966888fc87768eaa218b6244f2e78c55416706981aDavid Daney{
976888fc87768eaa218b6244f2e78c55416706981aDavid Daney	int32_t skb_to_free;
986888fc87768eaa218b6244f2e78c55416706981aDavid Daney	int qos, queues_per_port;
994898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney	int total_freed = 0;
1004898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney	int total_remaining = 0;
1014898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney	unsigned long flags;
1024898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney	struct octeon_ethernet *priv = netdev_priv(dev);
1034898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney
1046888fc87768eaa218b6244f2e78c55416706981aDavid Daney	queues_per_port = cvmx_pko_get_num_queues(priv->port);
1056888fc87768eaa218b6244f2e78c55416706981aDavid Daney	/* Drain any pending packets in the free list */
1066888fc87768eaa218b6244f2e78c55416706981aDavid Daney	for (qos = 0; qos < queues_per_port; qos++) {
1076888fc87768eaa218b6244f2e78c55416706981aDavid Daney		if (skb_queue_len(&priv->tx_free_list[qos]) == 0)
1086888fc87768eaa218b6244f2e78c55416706981aDavid Daney			continue;
1096888fc87768eaa218b6244f2e78c55416706981aDavid Daney		skb_to_free = cvmx_fau_fetch_and_add32(priv->fau+qos*4, MAX_SKB_TO_FREE);
1106888fc87768eaa218b6244f2e78c55416706981aDavid Daney		skb_to_free = cvm_oct_adjust_skb_to_free(skb_to_free, priv->fau+qos*4);
1116888fc87768eaa218b6244f2e78c55416706981aDavid Daney
1124898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney
1134898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney		total_freed += skb_to_free;
1144898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney		if (skb_to_free > 0) {
1154898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney			struct sk_buff *to_free_list = NULL;
1164898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney			spin_lock_irqsave(&priv->tx_free_list[qos].lock, flags);
1174898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney			while (skb_to_free > 0) {
1184898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney				struct sk_buff *t = __skb_dequeue(&priv->tx_free_list[qos]);
1194898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney				t->next = to_free_list;
1204898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney				to_free_list = t;
1214898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney				skb_to_free--;
1224898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney			}
1234898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney			spin_unlock_irqrestore(&priv->tx_free_list[qos].lock, flags);
1244898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney			/* Do the actual freeing outside of the lock. */
1254898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney			while (to_free_list) {
1264898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney				struct sk_buff *t = to_free_list;
1274898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney				to_free_list = to_free_list->next;
1284898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney				dev_kfree_skb_any(t);
1294898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney			}
1306888fc87768eaa218b6244f2e78c55416706981aDavid Daney		}
1314898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney		total_remaining += skb_queue_len(&priv->tx_free_list[qos]);
1326888fc87768eaa218b6244f2e78c55416706981aDavid Daney	}
1334898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney	if (total_freed >= 0 && netif_queue_stopped(dev))
1346888fc87768eaa218b6244f2e78c55416706981aDavid Daney		netif_wake_queue(dev);
1354898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney	if (total_remaining)
1364898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney		cvm_oct_kick_tx_poll_watchdog();
1376888fc87768eaa218b6244f2e78c55416706981aDavid Daney}
1386888fc87768eaa218b6244f2e78c55416706981aDavid Daney
13980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney/**
14080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * Packet transmit
14180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney *
14280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * @skb:    Packet to send
14380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * @dev:    Device info structure
14480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * Returns Always returns zero
14580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney */
14680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daneyint cvm_oct_xmit(struct sk_buff *skb, struct net_device *dev)
14780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney{
14880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	cvmx_pko_command_word0_t pko_command;
14980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	union cvmx_buf_ptr hw_buffer;
15080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	uint64_t old_scratch;
15180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	uint64_t old_scratch2;
15280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	int qos;
153924cc2680fbe181066ec138d369691d28d913ea2David Daney	int i;
1546888fc87768eaa218b6244f2e78c55416706981aDavid Daney	enum {QUEUE_CORE, QUEUE_HW, QUEUE_DROP} queue_type;
15580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	struct octeon_ethernet *priv = netdev_priv(dev);
1566888fc87768eaa218b6244f2e78c55416706981aDavid Daney	struct sk_buff *to_free_list;
157a620c1632629b42369e78448acc7b384fe1faf48David Daney	int32_t skb_to_free;
15880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	int32_t buffers_to_free;
1594898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney	u32 total_to_clean;
1606888fc87768eaa218b6244f2e78c55416706981aDavid Daney	unsigned long flags;
16180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#if REUSE_SKBUFFS_WITHOUT_FREE
16280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	unsigned char *fpa_head;
16380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#endif
16480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney
16580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	/*
16680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	 * Prefetch the private data structure.  It is larger that one
16780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	 * cache line.
16880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	 */
16980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	prefetch(priv);
17080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney
17180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	/*
17280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	 * The check on CVMX_PKO_QUEUES_PER_PORT_* is designed to
17380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	 * completely remove "qos" in the event neither interface
17480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	 * supports multiple queues per port.
17580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	 */
17680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	if ((CVMX_PKO_QUEUES_PER_PORT_INTERFACE0 > 1) ||
17780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	    (CVMX_PKO_QUEUES_PER_PORT_INTERFACE1 > 1)) {
17880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		qos = GET_SKBUFF_QOS(skb);
17980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		if (qos <= 0)
18080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney			qos = 0;
18180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		else if (qos >= cvmx_pko_get_num_queues(priv->port))
18280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney			qos = 0;
18380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	} else
18480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		qos = 0;
18580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney
18680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	if (USE_ASYNC_IOBDMA) {
18780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		/* Save scratch in case userspace is using it */
18880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		CVMX_SYNCIOBDMA;
18980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		old_scratch = cvmx_scratch_read64(CVMX_SCR_SCRATCH);
19080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		old_scratch2 = cvmx_scratch_read64(CVMX_SCR_SCRATCH + 8);
19180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney
19280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		/*
193a620c1632629b42369e78448acc7b384fe1faf48David Daney		 * Fetch and increment the number of packets to be
194a620c1632629b42369e78448acc7b384fe1faf48David Daney		 * freed.
19580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		 */
19680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		cvmx_fau_async_fetch_and_add32(CVMX_SCR_SCRATCH + 8,
19780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney					       FAU_NUM_PACKET_BUFFERS_TO_FREE,
19880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney					       0);
19980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		cvmx_fau_async_fetch_and_add32(CVMX_SCR_SCRATCH,
200a620c1632629b42369e78448acc7b384fe1faf48David Daney					       priv->fau + qos * 4,
201a620c1632629b42369e78448acc7b384fe1faf48David Daney					       MAX_SKB_TO_FREE);
20280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	}
20380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney
20480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	/*
205924cc2680fbe181066ec138d369691d28d913ea2David Daney	 * We have space for 6 segment pointers, If there will be more
206924cc2680fbe181066ec138d369691d28d913ea2David Daney	 * than that, we must linearize.
207924cc2680fbe181066ec138d369691d28d913ea2David Daney	 */
208924cc2680fbe181066ec138d369691d28d913ea2David Daney	if (unlikely(skb_shinfo(skb)->nr_frags > 5)) {
209924cc2680fbe181066ec138d369691d28d913ea2David Daney		if (unlikely(__skb_linearize(skb))) {
210924cc2680fbe181066ec138d369691d28d913ea2David Daney			queue_type = QUEUE_DROP;
211924cc2680fbe181066ec138d369691d28d913ea2David Daney			if (USE_ASYNC_IOBDMA) {
212924cc2680fbe181066ec138d369691d28d913ea2David Daney				/* Get the number of skbuffs in use by the hardware */
213924cc2680fbe181066ec138d369691d28d913ea2David Daney				CVMX_SYNCIOBDMA;
214924cc2680fbe181066ec138d369691d28d913ea2David Daney				skb_to_free = cvmx_scratch_read64(CVMX_SCR_SCRATCH);
215924cc2680fbe181066ec138d369691d28d913ea2David Daney			} else {
216924cc2680fbe181066ec138d369691d28d913ea2David Daney				/* Get the number of skbuffs in use by the hardware */
217924cc2680fbe181066ec138d369691d28d913ea2David Daney				skb_to_free = cvmx_fau_fetch_and_add32(priv->fau + qos * 4,
218924cc2680fbe181066ec138d369691d28d913ea2David Daney								       MAX_SKB_TO_FREE);
219924cc2680fbe181066ec138d369691d28d913ea2David Daney			}
220924cc2680fbe181066ec138d369691d28d913ea2David Daney			skb_to_free = cvm_oct_adjust_skb_to_free(skb_to_free, priv->fau + qos * 4);
221924cc2680fbe181066ec138d369691d28d913ea2David Daney			spin_lock_irqsave(&priv->tx_free_list[qos].lock, flags);
222924cc2680fbe181066ec138d369691d28d913ea2David Daney			goto skip_xmit;
223924cc2680fbe181066ec138d369691d28d913ea2David Daney		}
224924cc2680fbe181066ec138d369691d28d913ea2David Daney	}
225924cc2680fbe181066ec138d369691d28d913ea2David Daney
226924cc2680fbe181066ec138d369691d28d913ea2David Daney	/*
22780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	 * The CN3XXX series of parts has an errata (GMX-401) which
22880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	 * causes the GMX block to hang if a collision occurs towards
22980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	 * the end of a <68 byte packet. As a workaround for this, we
23080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	 * pad packets to be 68 bytes whenever we are in half duplex
23180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	 * mode. We don't handle the case of having a small packet but
23280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	 * no room to add the padding.  The kernel should always give
23380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	 * us at least a cache line
23480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	 */
23580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	if ((skb->len < 64) && OCTEON_IS_MODEL(OCTEON_CN3XXX)) {
23680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		union cvmx_gmxx_prtx_cfg gmx_prt_cfg;
23780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		int interface = INTERFACE(priv->port);
23880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		int index = INDEX(priv->port);
23980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney
24080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		if (interface < 2) {
24180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney			/* We only need to pad packet in half duplex mode */
24280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney			gmx_prt_cfg.u64 =
24380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney			    cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
24480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney			if (gmx_prt_cfg.s.duplex == 0) {
24580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney				int add_bytes = 64 - skb->len;
24680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney				if ((skb_tail_pointer(skb) + add_bytes) <=
24780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney				    skb_end_pointer(skb))
24880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney					memset(__skb_put(skb, add_bytes), 0,
24980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney					       add_bytes);
25080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney			}
25180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		}
25280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	}
25380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney
25480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	/* Build the PKO command */
25580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	pko_command.u64 = 0;
25680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	pko_command.s.n2 = 1;	/* Don't pollute L2 with the outgoing packet */
25780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	pko_command.s.segs = 1;
25880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	pko_command.s.total_bytes = skb->len;
25980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	pko_command.s.size0 = CVMX_FAU_OP_SIZE_32;
26080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	pko_command.s.subone0 = 1;
26180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney
26280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	pko_command.s.dontfree = 1;
263924cc2680fbe181066ec138d369691d28d913ea2David Daney
264924cc2680fbe181066ec138d369691d28d913ea2David Daney	/* Build the PKO buffer pointer */
265924cc2680fbe181066ec138d369691d28d913ea2David Daney	hw_buffer.u64 = 0;
266924cc2680fbe181066ec138d369691d28d913ea2David Daney	if (skb_shinfo(skb)->nr_frags == 0) {
267924cc2680fbe181066ec138d369691d28d913ea2David Daney		hw_buffer.s.addr = XKPHYS_TO_PHYS((u64)skb->data);
268924cc2680fbe181066ec138d369691d28d913ea2David Daney		hw_buffer.s.pool = 0;
269924cc2680fbe181066ec138d369691d28d913ea2David Daney		hw_buffer.s.size = skb->len;
270924cc2680fbe181066ec138d369691d28d913ea2David Daney	} else {
271924cc2680fbe181066ec138d369691d28d913ea2David Daney		hw_buffer.s.addr = XKPHYS_TO_PHYS((u64)skb->data);
272924cc2680fbe181066ec138d369691d28d913ea2David Daney		hw_buffer.s.pool = 0;
273924cc2680fbe181066ec138d369691d28d913ea2David Daney		hw_buffer.s.size = skb_headlen(skb);
274924cc2680fbe181066ec138d369691d28d913ea2David Daney		CVM_OCT_SKB_CB(skb)[0] = hw_buffer.u64;
275924cc2680fbe181066ec138d369691d28d913ea2David Daney		for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
276924cc2680fbe181066ec138d369691d28d913ea2David Daney			struct skb_frag_struct *fs = skb_shinfo(skb)->frags + i;
277924cc2680fbe181066ec138d369691d28d913ea2David Daney			hw_buffer.s.addr = XKPHYS_TO_PHYS((u64)(page_address(fs->page) + fs->page_offset));
278924cc2680fbe181066ec138d369691d28d913ea2David Daney			hw_buffer.s.size = fs->size;
279924cc2680fbe181066ec138d369691d28d913ea2David Daney			CVM_OCT_SKB_CB(skb)[i + 1] = hw_buffer.u64;
280924cc2680fbe181066ec138d369691d28d913ea2David Daney		}
281924cc2680fbe181066ec138d369691d28d913ea2David Daney		hw_buffer.s.addr = XKPHYS_TO_PHYS((u64)CVM_OCT_SKB_CB(skb));
282924cc2680fbe181066ec138d369691d28d913ea2David Daney		hw_buffer.s.size = skb_shinfo(skb)->nr_frags + 1;
283924cc2680fbe181066ec138d369691d28d913ea2David Daney		pko_command.s.segs = skb_shinfo(skb)->nr_frags + 1;
284924cc2680fbe181066ec138d369691d28d913ea2David Daney		pko_command.s.gather = 1;
285924cc2680fbe181066ec138d369691d28d913ea2David Daney		goto dont_put_skbuff_in_hw;
286924cc2680fbe181066ec138d369691d28d913ea2David Daney	}
287924cc2680fbe181066ec138d369691d28d913ea2David Daney
28880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	/*
28980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	 * See if we can put this skb in the FPA pool. Any strange
29080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	 * behavior from the Linux networking stack will most likely
29180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	 * be caused by a bug in the following code. If some field is
29280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	 * in use by the network stack and get carried over when a
29380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	 * buffer is reused, bad thing may happen.  If in doubt and
29480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	 * you dont need the absolute best performance, disable the
29580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	 * define REUSE_SKBUFFS_WITHOUT_FREE. The reuse of buffers has
29680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	 * shown a 25% increase in performance under some loads.
29780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	 */
29880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#if REUSE_SKBUFFS_WITHOUT_FREE
299166bdaa9aad9903bf4330ef68feb37f220c9eac8David Daney	fpa_head = skb->head + 256 - ((unsigned long)skb->head & 0x7f);
30080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	if (unlikely(skb->data < fpa_head)) {
30180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		/*
30280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		 * printk("TX buffer beginning can't meet FPA
30380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		 * alignment constraints\n");
30480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		 */
30580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		goto dont_put_skbuff_in_hw;
30680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	}
30780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	if (unlikely
30880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	    ((skb_end_pointer(skb) - fpa_head) < CVMX_FPA_PACKET_POOL_SIZE)) {
30980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		/*
31080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		   printk("TX buffer isn't large enough for the FPA\n");
31180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		 */
31280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		goto dont_put_skbuff_in_hw;
31380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	}
31480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	if (unlikely(skb_shared(skb))) {
31580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		/*
31680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		   printk("TX buffer sharing data with someone else\n");
31780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		 */
31880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		goto dont_put_skbuff_in_hw;
31980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	}
32080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	if (unlikely(skb_cloned(skb))) {
32180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		/*
32280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		   printk("TX buffer has been cloned\n");
32380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		 */
32480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		goto dont_put_skbuff_in_hw;
32580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	}
32680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	if (unlikely(skb_header_cloned(skb))) {
32780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		/*
32880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		   printk("TX buffer header has been cloned\n");
32980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		 */
33080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		goto dont_put_skbuff_in_hw;
33180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	}
33280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	if (unlikely(skb->destructor)) {
33380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		/*
33480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		   printk("TX buffer has a destructor\n");
33580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		 */
33680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		goto dont_put_skbuff_in_hw;
33780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	}
33880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	if (unlikely(skb_shinfo(skb)->nr_frags)) {
33980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		/*
34080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		   printk("TX buffer has fragments\n");
34180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		 */
34280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		goto dont_put_skbuff_in_hw;
34380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	}
34480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	if (unlikely
34580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	    (skb->truesize !=
34680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	     sizeof(*skb) + skb_end_pointer(skb) - skb->head)) {
34780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		/*
34880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		   printk("TX buffer truesize has been changed\n");
34980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		 */
35080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		goto dont_put_skbuff_in_hw;
35180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	}
35280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney
35380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	/*
35480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	 * We can use this buffer in the FPA.  We don't need the FAU
35580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	 * update anymore
35680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	 */
35780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	pko_command.s.dontfree = 0;
35880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney
359166bdaa9aad9903bf4330ef68feb37f220c9eac8David Daney	hw_buffer.s.back = ((unsigned long)skb->data >> 7) - ((unsigned long)fpa_head >> 7);
36080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	*(struct sk_buff **)(fpa_head - sizeof(void *)) = skb;
36180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney
36280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	/*
36380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	 * The skbuff will be reused without ever being freed. We must
364f696a10838ffab85e5bc07e7cff0d0e1870a30d7David Daney	 * cleanup a bunch of core things.
36580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	 */
366f696a10838ffab85e5bc07e7cff0d0e1870a30d7David Daney	dst_release(skb_dst(skb));
367f696a10838ffab85e5bc07e7cff0d0e1870a30d7David Daney	skb_dst_set(skb, NULL);
36880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#ifdef CONFIG_XFRM
36980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	secpath_put(skb->sp);
37080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	skb->sp = NULL;
37180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#endif
37280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	nf_reset(skb);
37380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney
37480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#ifdef CONFIG_NET_SCHED
37580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	skb->tc_index = 0;
37680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#ifdef CONFIG_NET_CLS_ACT
37780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	skb->tc_verd = 0;
37880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#endif /* CONFIG_NET_CLS_ACT */
37980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#endif /* CONFIG_NET_SCHED */
3806888fc87768eaa218b6244f2e78c55416706981aDavid Daney#endif /* REUSE_SKBUFFS_WITHOUT_FREE */
38180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney
38280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daneydont_put_skbuff_in_hw:
38380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney
38480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	/* Check if we can use the hardware checksumming */
38580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	if (USE_HW_TCPUDP_CHECKSUM && (skb->protocol == htons(ETH_P_IP)) &&
38680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	    (ip_hdr(skb)->version == 4) && (ip_hdr(skb)->ihl == 5) &&
38780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	    ((ip_hdr(skb)->frag_off == 0) || (ip_hdr(skb)->frag_off == 1 << 14))
388081f6749ae33f72b4fafea4c02976e163ef6ef37David Daney	    && ((ip_hdr(skb)->protocol == IPPROTO_TCP)
389081f6749ae33f72b4fafea4c02976e163ef6ef37David Daney		|| (ip_hdr(skb)->protocol == IPPROTO_UDP))) {
39080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		/* Use hardware checksum calc */
39180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		pko_command.s.ipoffp1 = sizeof(struct ethhdr) + 1;
39280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	}
39380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney
39480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	if (USE_ASYNC_IOBDMA) {
39580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		/* Get the number of skbuffs in use by the hardware */
39680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		CVMX_SYNCIOBDMA;
397a620c1632629b42369e78448acc7b384fe1faf48David Daney		skb_to_free = cvmx_scratch_read64(CVMX_SCR_SCRATCH);
39880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		buffers_to_free = cvmx_scratch_read64(CVMX_SCR_SCRATCH + 8);
39980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	} else {
40080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		/* Get the number of skbuffs in use by the hardware */
401a620c1632629b42369e78448acc7b384fe1faf48David Daney		skb_to_free = cvmx_fau_fetch_and_add32(priv->fau + qos * 4,
402a620c1632629b42369e78448acc7b384fe1faf48David Daney						       MAX_SKB_TO_FREE);
40380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		buffers_to_free =
40480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		    cvmx_fau_fetch_and_add32(FAU_NUM_PACKET_BUFFERS_TO_FREE, 0);
40580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	}
40680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney
4076888fc87768eaa218b6244f2e78c55416706981aDavid Daney	skb_to_free = cvm_oct_adjust_skb_to_free(skb_to_free, priv->fau+qos*4);
408a620c1632629b42369e78448acc7b384fe1faf48David Daney
409a620c1632629b42369e78448acc7b384fe1faf48David Daney	/*
41080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	 * If we're sending faster than the receive can free them then
41180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	 * don't do the HW free.
41280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	 */
4134898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney	if ((buffers_to_free < -100) && !pko_command.s.dontfree)
41480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		pko_command.s.dontfree = 1;
41580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney
4164898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney	if (pko_command.s.dontfree) {
4176888fc87768eaa218b6244f2e78c55416706981aDavid Daney		queue_type = QUEUE_CORE;
4184898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney		pko_command.s.reg0 = priv->fau+qos*4;
4194898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney	} else {
4206888fc87768eaa218b6244f2e78c55416706981aDavid Daney		queue_type = QUEUE_HW;
4214898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney	}
4224898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney	if (USE_ASYNC_IOBDMA)
4234898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney		cvmx_fau_async_fetch_and_add32(CVMX_SCR_SCRATCH, FAU_TOTAL_TX_TO_CLEAN, 1);
4246888fc87768eaa218b6244f2e78c55416706981aDavid Daney
4256888fc87768eaa218b6244f2e78c55416706981aDavid Daney	spin_lock_irqsave(&priv->tx_free_list[qos].lock, flags);
42680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney
42780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	/* Drop this packet if we have too many already queued to the HW */
4286888fc87768eaa218b6244f2e78c55416706981aDavid Daney	if (unlikely(skb_queue_len(&priv->tx_free_list[qos]) >= MAX_OUT_QUEUE_DEPTH)) {
4296888fc87768eaa218b6244f2e78c55416706981aDavid Daney		if (dev->tx_queue_len != 0) {
4306888fc87768eaa218b6244f2e78c55416706981aDavid Daney			/* Drop the lock when notifying the core.  */
4316888fc87768eaa218b6244f2e78c55416706981aDavid Daney			spin_unlock_irqrestore(&priv->tx_free_list[qos].lock, flags);
4326888fc87768eaa218b6244f2e78c55416706981aDavid Daney			netif_stop_queue(dev);
4336888fc87768eaa218b6244f2e78c55416706981aDavid Daney			spin_lock_irqsave(&priv->tx_free_list[qos].lock, flags);
4346888fc87768eaa218b6244f2e78c55416706981aDavid Daney		} else {
4356888fc87768eaa218b6244f2e78c55416706981aDavid Daney			/* If not using normal queueing.  */
4366888fc87768eaa218b6244f2e78c55416706981aDavid Daney			queue_type = QUEUE_DROP;
4376888fc87768eaa218b6244f2e78c55416706981aDavid Daney			goto skip_xmit;
4386888fc87768eaa218b6244f2e78c55416706981aDavid Daney		}
43980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	}
4406888fc87768eaa218b6244f2e78c55416706981aDavid Daney
4416888fc87768eaa218b6244f2e78c55416706981aDavid Daney	cvmx_pko_send_packet_prepare(priv->port, priv->queue + qos,
4426888fc87768eaa218b6244f2e78c55416706981aDavid Daney				     CVMX_PKO_LOCK_NONE);
4436888fc87768eaa218b6244f2e78c55416706981aDavid Daney
44480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	/* Send the packet to the output queue */
4456888fc87768eaa218b6244f2e78c55416706981aDavid Daney	if (unlikely(cvmx_pko_send_packet_finish(priv->port,
4466888fc87768eaa218b6244f2e78c55416706981aDavid Daney						 priv->queue + qos,
4476888fc87768eaa218b6244f2e78c55416706981aDavid Daney						 pko_command, hw_buffer,
4486888fc87768eaa218b6244f2e78c55416706981aDavid Daney						 CVMX_PKO_LOCK_NONE))) {
44980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		DEBUGPRINT("%s: Failed to send the packet\n", dev->name);
4506888fc87768eaa218b6244f2e78c55416706981aDavid Daney		queue_type = QUEUE_DROP;
45180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	}
4526888fc87768eaa218b6244f2e78c55416706981aDavid Daneyskip_xmit:
4536888fc87768eaa218b6244f2e78c55416706981aDavid Daney	to_free_list = NULL;
45480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney
4556888fc87768eaa218b6244f2e78c55416706981aDavid Daney	switch (queue_type) {
4566888fc87768eaa218b6244f2e78c55416706981aDavid Daney	case QUEUE_DROP:
4576888fc87768eaa218b6244f2e78c55416706981aDavid Daney		skb->next = to_free_list;
4586888fc87768eaa218b6244f2e78c55416706981aDavid Daney		to_free_list = skb;
4596888fc87768eaa218b6244f2e78c55416706981aDavid Daney		priv->stats.tx_dropped++;
4606888fc87768eaa218b6244f2e78c55416706981aDavid Daney		break;
4616888fc87768eaa218b6244f2e78c55416706981aDavid Daney	case QUEUE_HW:
4626888fc87768eaa218b6244f2e78c55416706981aDavid Daney		cvmx_fau_atomic_add32(FAU_NUM_PACKET_BUFFERS_TO_FREE, -1);
4636888fc87768eaa218b6244f2e78c55416706981aDavid Daney		break;
4646888fc87768eaa218b6244f2e78c55416706981aDavid Daney	case QUEUE_CORE:
4656888fc87768eaa218b6244f2e78c55416706981aDavid Daney		__skb_queue_tail(&priv->tx_free_list[qos], skb);
4666888fc87768eaa218b6244f2e78c55416706981aDavid Daney		break;
4676888fc87768eaa218b6244f2e78c55416706981aDavid Daney	default:
4686888fc87768eaa218b6244f2e78c55416706981aDavid Daney		BUG();
46980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	}
47080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney
4716888fc87768eaa218b6244f2e78c55416706981aDavid Daney	while (skb_to_free > 0) {
4726888fc87768eaa218b6244f2e78c55416706981aDavid Daney		struct sk_buff *t = __skb_dequeue(&priv->tx_free_list[qos]);
4736888fc87768eaa218b6244f2e78c55416706981aDavid Daney		t->next = to_free_list;
4746888fc87768eaa218b6244f2e78c55416706981aDavid Daney		to_free_list = t;
4756888fc87768eaa218b6244f2e78c55416706981aDavid Daney		skb_to_free--;
47680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	}
47780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney
4786888fc87768eaa218b6244f2e78c55416706981aDavid Daney	spin_unlock_irqrestore(&priv->tx_free_list[qos].lock, flags);
4796888fc87768eaa218b6244f2e78c55416706981aDavid Daney
4806888fc87768eaa218b6244f2e78c55416706981aDavid Daney	/* Do the actual freeing outside of the lock. */
4816888fc87768eaa218b6244f2e78c55416706981aDavid Daney	while (to_free_list) {
4826888fc87768eaa218b6244f2e78c55416706981aDavid Daney		struct sk_buff *t = to_free_list;
4836888fc87768eaa218b6244f2e78c55416706981aDavid Daney		to_free_list = to_free_list->next;
4846888fc87768eaa218b6244f2e78c55416706981aDavid Daney		dev_kfree_skb_any(t);
4856888fc87768eaa218b6244f2e78c55416706981aDavid Daney	}
4866888fc87768eaa218b6244f2e78c55416706981aDavid Daney
4876888fc87768eaa218b6244f2e78c55416706981aDavid Daney	if (USE_ASYNC_IOBDMA) {
4884898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney		CVMX_SYNCIOBDMA;
4894898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney		total_to_clean = cvmx_scratch_read64(CVMX_SCR_SCRATCH);
4906888fc87768eaa218b6244f2e78c55416706981aDavid Daney		/* Restore the scratch area */
4916888fc87768eaa218b6244f2e78c55416706981aDavid Daney		cvmx_scratch_write64(CVMX_SCR_SCRATCH, old_scratch);
4926888fc87768eaa218b6244f2e78c55416706981aDavid Daney		cvmx_scratch_write64(CVMX_SCR_SCRATCH + 8, old_scratch2);
4934898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney	} else {
4944898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney		total_to_clean = cvmx_fau_fetch_and_add32(FAU_TOTAL_TX_TO_CLEAN, 1);
49580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	}
49680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney
4974898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney	if (total_to_clean & 0x3ff) {
4984898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney		/*
4994898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney		 * Schedule the cleanup tasklet every 1024 packets for
5004898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney		 * the pathological case of high traffic on one port
5014898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney		 * delaying clean up of packets on a different port
5024898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney		 * that is blocked waiting for the cleanup.
5034898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney		 */
5044898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney		tasklet_schedule(&cvm_oct_tx_cleanup_tasklet);
5054898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney	}
5064898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney
5074898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney	cvm_oct_kick_tx_poll_watchdog();
5084898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney
5096888fc87768eaa218b6244f2e78c55416706981aDavid Daney	return NETDEV_TX_OK;
51080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney}
51180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney
51280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney/**
51380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * Packet transmit to the POW
51480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney *
51580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * @skb:    Packet to send
51680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * @dev:    Device info structure
51780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * Returns Always returns zero
51880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney */
51980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daneyint cvm_oct_xmit_pow(struct sk_buff *skb, struct net_device *dev)
52080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney{
52180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	struct octeon_ethernet *priv = netdev_priv(dev);
52280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	void *packet_buffer;
52380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	void *copy_location;
52480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney
52580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	/* Get a work queue entry */
52680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	cvmx_wqe_t *work = cvmx_fpa_alloc(CVMX_FPA_WQE_POOL);
52780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	if (unlikely(work == NULL)) {
52880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		DEBUGPRINT("%s: Failed to allocate a work queue entry\n",
52980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney			   dev->name);
53080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		priv->stats.tx_dropped++;
53180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		dev_kfree_skb(skb);
53280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		return 0;
53380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	}
53480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney
53580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	/* Get a packet buffer */
53680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	packet_buffer = cvmx_fpa_alloc(CVMX_FPA_PACKET_POOL);
53780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	if (unlikely(packet_buffer == NULL)) {
53880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		DEBUGPRINT("%s: Failed to allocate a packet buffer\n",
53980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney			   dev->name);
54080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		cvmx_fpa_free(work, CVMX_FPA_WQE_POOL, DONT_WRITEBACK(1));
54180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		priv->stats.tx_dropped++;
54280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		dev_kfree_skb(skb);
54380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		return 0;
54480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	}
54580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney
54680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	/*
54780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	 * Calculate where we need to copy the data to. We need to
54880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	 * leave 8 bytes for a next pointer (unused). We also need to
54980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	 * include any configure skip. Then we need to align the IP
55080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	 * packet src and dest into the same 64bit word. The below
55180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	 * calculation may add a little extra, but that doesn't
55280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	 * hurt.
55380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	 */
55480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	copy_location = packet_buffer + sizeof(uint64_t);
55580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	copy_location += ((CVMX_HELPER_FIRST_MBUFF_SKIP + 7) & 0xfff8) + 6;
55680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney
55780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	/*
55880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	 * We have to copy the packet since whoever processes this
55980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	 * packet will free it to a hardware pool. We can't use the
56080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	 * trick of counting outstanding packets like in
56180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	 * cvm_oct_xmit.
56280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	 */
56380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	memcpy(copy_location, skb->data, skb->len);
56480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney
56580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	/*
56680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	 * Fill in some of the work queue fields. We may need to add
56780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	 * more if the software at the other end needs them.
56880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	 */
56980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	work->hw_chksum = skb->csum;
57080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	work->len = skb->len;
57180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	work->ipprt = priv->port;
57280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	work->qos = priv->port & 0x7;
57380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	work->grp = pow_send_group;
57480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	work->tag_type = CVMX_HELPER_INPUT_TAG_TYPE;
57580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	work->tag = pow_send_group;	/* FIXME */
57680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	/* Default to zero. Sets of zero later are commented out */
57780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	work->word2.u64 = 0;
57880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	work->word2.s.bufs = 1;
57980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	work->packet_ptr.u64 = 0;
58080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	work->packet_ptr.s.addr = cvmx_ptr_to_phys(copy_location);
58180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	work->packet_ptr.s.pool = CVMX_FPA_PACKET_POOL;
58280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	work->packet_ptr.s.size = CVMX_FPA_PACKET_POOL_SIZE;
58380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	work->packet_ptr.s.back = (copy_location - packet_buffer) >> 7;
58480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney
58580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	if (skb->protocol == htons(ETH_P_IP)) {
58680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		work->word2.s.ip_offset = 14;
58780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#if 0
58880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		work->word2.s.vlan_valid = 0;	/* FIXME */
58980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		work->word2.s.vlan_cfi = 0;	/* FIXME */
59080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		work->word2.s.vlan_id = 0;	/* FIXME */
59180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		work->word2.s.dec_ipcomp = 0;	/* FIXME */
59280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#endif
59380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		work->word2.s.tcp_or_udp =
594081f6749ae33f72b4fafea4c02976e163ef6ef37David Daney		    (ip_hdr(skb)->protocol == IPPROTO_TCP)
595081f6749ae33f72b4fafea4c02976e163ef6ef37David Daney		    || (ip_hdr(skb)->protocol == IPPROTO_UDP);
59680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#if 0
59780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		/* FIXME */
59880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		work->word2.s.dec_ipsec = 0;
59980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		/* We only support IPv4 right now */
60080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		work->word2.s.is_v6 = 0;
60180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		/* Hardware would set to zero */
60280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		work->word2.s.software = 0;
60380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		/* No error, packet is internal */
60480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		work->word2.s.L4_error = 0;
60580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#endif
60680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		work->word2.s.is_frag = !((ip_hdr(skb)->frag_off == 0)
60780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney					  || (ip_hdr(skb)->frag_off ==
60880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney					      1 << 14));
60980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#if 0
61080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		/* Assume Linux is sending a good packet */
61180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		work->word2.s.IP_exc = 0;
61280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#endif
61380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		work->word2.s.is_bcast = (skb->pkt_type == PACKET_BROADCAST);
61480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		work->word2.s.is_mcast = (skb->pkt_type == PACKET_MULTICAST);
61580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#if 0
61680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		/* This is an IP packet */
61780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		work->word2.s.not_IP = 0;
61880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		/* No error, packet is internal */
61980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		work->word2.s.rcv_error = 0;
62080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		/* No error, packet is internal */
62180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		work->word2.s.err_code = 0;
62280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#endif
62380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney
62480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		/*
62580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		 * When copying the data, include 4 bytes of the
62680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		 * ethernet header to align the same way hardware
62780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		 * does.
62880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		 */
62980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		memcpy(work->packet_data, skb->data + 10,
63080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		       sizeof(work->packet_data));
63180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	} else {
63280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#if 0
63380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		work->word2.snoip.vlan_valid = 0;	/* FIXME */
63480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		work->word2.snoip.vlan_cfi = 0;	/* FIXME */
63580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		work->word2.snoip.vlan_id = 0;	/* FIXME */
63680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		work->word2.snoip.software = 0;	/* Hardware would set to zero */
63780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#endif
63880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		work->word2.snoip.is_rarp = skb->protocol == htons(ETH_P_RARP);
63980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		work->word2.snoip.is_arp = skb->protocol == htons(ETH_P_ARP);
64080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		work->word2.snoip.is_bcast =
64180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		    (skb->pkt_type == PACKET_BROADCAST);
64280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		work->word2.snoip.is_mcast =
64380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		    (skb->pkt_type == PACKET_MULTICAST);
64480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		work->word2.snoip.not_IP = 1;	/* IP was done up above */
64580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#if 0
64680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		/* No error, packet is internal */
64780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		work->word2.snoip.rcv_error = 0;
64880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		/* No error, packet is internal */
64980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		work->word2.snoip.err_code = 0;
65080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#endif
65180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		memcpy(work->packet_data, skb->data, sizeof(work->packet_data));
65280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	}
65380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney
65480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	/* Submit the packet to the POW */
65580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	cvmx_pow_work_submit(work, work->tag, work->tag_type, work->qos,
65680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney			     work->grp);
65780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	priv->stats.tx_packets++;
65880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	priv->stats.tx_bytes += skb->len;
65980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	dev_kfree_skb(skb);
66080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	return 0;
66180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney}
66280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney
66380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney/**
664bbc9a9916bc1cd997f3bf303e7930d5f3c804d37André Goddard Rosa * This function frees all skb that are currently queued for TX.
66580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney *
66680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * @dev:    Device being shutdown
66780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney */
6684898c560103fb8075c10a8e9d70e0ca26873075eDavid Daneyvoid cvm_oct_tx_shutdown_dev(struct net_device *dev)
66980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney{
67080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	struct octeon_ethernet *priv = netdev_priv(dev);
67180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	unsigned long flags;
67280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	int qos;
67380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney
67480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	for (qos = 0; qos < 16; qos++) {
67580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		spin_lock_irqsave(&priv->tx_free_list[qos].lock, flags);
67680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		while (skb_queue_len(&priv->tx_free_list[qos]))
67780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney			dev_kfree_skb_any(__skb_dequeue
67880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney					  (&priv->tx_free_list[qos]));
67980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney		spin_unlock_irqrestore(&priv->tx_free_list[qos].lock, flags);
68080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney	}
68180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney}
6824898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney
6834898c560103fb8075c10a8e9d70e0ca26873075eDavid Daneystatic void cvm_oct_tx_do_cleanup(unsigned long arg)
6844898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney{
6854898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney	int port;
6864898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney
6874898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney	for (port = 0; port < TOTAL_NUMBER_OF_PORTS; port++) {
6884898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney		if (cvm_oct_device[port]) {
6894898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney			struct net_device *dev = cvm_oct_device[port];
6904898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney			cvm_oct_free_tx_skbs(dev);
6914898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney		}
6924898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney	}
6934898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney}
6944898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney
6954898c560103fb8075c10a8e9d70e0ca26873075eDavid Daneystatic irqreturn_t cvm_oct_tx_cleanup_watchdog(int cpl, void *dev_id)
6964898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney{
6974898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney	/* Disable the interrupt.  */
6984898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney	cvmx_write_csr(CVMX_CIU_TIMX(1), 0);
6994898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney	/* Do the work in the tasklet.  */
7004898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney	tasklet_schedule(&cvm_oct_tx_cleanup_tasklet);
7014898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney	return IRQ_HANDLED;
7024898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney}
7034898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney
7044898c560103fb8075c10a8e9d70e0ca26873075eDavid Daneyvoid cvm_oct_tx_initialize(void)
7054898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney{
7064898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney	int i;
7074898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney
7084898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney	/* Disable the interrupt.  */
7094898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney	cvmx_write_csr(CVMX_CIU_TIMX(1), 0);
7104898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney	/* Register an IRQ hander for to receive CIU_TIMX(1) interrupts */
7114898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney	i = request_irq(OCTEON_IRQ_TIMER1,
7124898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney			cvm_oct_tx_cleanup_watchdog, 0,
7134898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney			"Ethernet", cvm_oct_device);
7144898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney
7154898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney	if (i)
7164898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney		panic("Could not acquire Ethernet IRQ %d\n", OCTEON_IRQ_TIMER1);
7174898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney}
7184898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney
7194898c560103fb8075c10a8e9d70e0ca26873075eDavid Daneyvoid cvm_oct_tx_shutdown(void)
7204898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney{
7214898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney	/* Free the interrupt handler */
7224898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney	free_irq(OCTEON_IRQ_TIMER1, cvm_oct_device);
7234898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney}
724