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