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> 337a2eaf9358250706672783eb8511835706b0922bChristian Dietrich#include <linux/ratelimit.h> 3480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#include <linux/string.h> 35dc890df0a77cafe5f4a3d81c0dade637c27f1934Imre Kaloz#include <linux/interrupt.h> 3680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#include <net/dst.h> 3780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#ifdef CONFIG_XFRM 3880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#include <linux/xfrm.h> 3980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#include <net/xfrm.h> 4080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#endif /* CONFIG_XFRM */ 4180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney 4260063497a95e716c9a689af3be2687d261f115b4Arun Sharma#include <linux/atomic.h> 4380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney 4480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#include <asm/octeon/octeon.h> 4580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney 4680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#include "ethernet-defines.h" 4780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#include "octeon-ethernet.h" 48a620c1632629b42369e78448acc7b384fe1faf48David Daney#include "ethernet-tx.h" 4980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#include "ethernet-util.h" 5080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney 51af866496c7752d2c0bd97fcbb4627cac72aa9a64David Daney#include <asm/octeon/cvmx-wqe.h> 52af866496c7752d2c0bd97fcbb4627cac72aa9a64David Daney#include <asm/octeon/cvmx-fau.h> 53af866496c7752d2c0bd97fcbb4627cac72aa9a64David Daney#include <asm/octeon/cvmx-pip.h> 54af866496c7752d2c0bd97fcbb4627cac72aa9a64David Daney#include <asm/octeon/cvmx-pko.h> 55af866496c7752d2c0bd97fcbb4627cac72aa9a64David Daney#include <asm/octeon/cvmx-helper.h> 5680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney 57af866496c7752d2c0bd97fcbb4627cac72aa9a64David Daney#include <asm/octeon/cvmx-gmxx-defs.h> 5880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney 59924cc2680fbe181066ec138d369691d28d913ea2David Daney#define CVM_OCT_SKB_CB(skb) ((u64 *)((skb)->cb)) 60924cc2680fbe181066ec138d369691d28d913ea2David Daney 6180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney/* 6280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * You can define GET_SKBUFF_QOS() to override how the skbuff output 6380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * function determines which output queue is used. The default 6480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * implementation always uses the base queue for the port. If, for 6580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * example, you wanted to use the skb->priority fieid, define 6680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * GET_SKBUFF_QOS as: #define GET_SKBUFF_QOS(skb) ((skb)->priority) 6780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney */ 6880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#ifndef GET_SKBUFF_QOS 6980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#define GET_SKBUFF_QOS(skb) 0 7080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#endif 7180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney 724898c560103fb8075c10a8e9d70e0ca26873075eDavid Daneystatic void cvm_oct_tx_do_cleanup(unsigned long arg); 734898c560103fb8075c10a8e9d70e0ca26873075eDavid Daneystatic DECLARE_TASKLET(cvm_oct_tx_cleanup_tasklet, cvm_oct_tx_do_cleanup, 0); 744898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney 754898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney/* Maximum number of SKBs to try to free per xmit packet. */ 764898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney#define MAX_SKB_TO_FREE (MAX_OUT_QUEUE_DEPTH * 2) 776888fc87768eaa218b6244f2e78c55416706981aDavid Daney 786888fc87768eaa218b6244f2e78c55416706981aDavid Daneystatic inline int32_t cvm_oct_adjust_skb_to_free(int32_t skb_to_free, int fau) 796888fc87768eaa218b6244f2e78c55416706981aDavid Daney{ 806888fc87768eaa218b6244f2e78c55416706981aDavid Daney int32_t undo; 816888fc87768eaa218b6244f2e78c55416706981aDavid Daney undo = skb_to_free > 0 ? MAX_SKB_TO_FREE : skb_to_free + MAX_SKB_TO_FREE; 826888fc87768eaa218b6244f2e78c55416706981aDavid Daney if (undo > 0) 836888fc87768eaa218b6244f2e78c55416706981aDavid Daney cvmx_fau_atomic_add32(fau, -undo); 846888fc87768eaa218b6244f2e78c55416706981aDavid Daney skb_to_free = -skb_to_free > MAX_SKB_TO_FREE ? MAX_SKB_TO_FREE : -skb_to_free; 856888fc87768eaa218b6244f2e78c55416706981aDavid Daney return skb_to_free; 866888fc87768eaa218b6244f2e78c55416706981aDavid Daney} 876888fc87768eaa218b6244f2e78c55416706981aDavid Daney 884898c560103fb8075c10a8e9d70e0ca26873075eDavid Daneystatic void cvm_oct_kick_tx_poll_watchdog(void) 894898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney{ 904898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney union cvmx_ciu_timx ciu_timx; 914898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney ciu_timx.u64 = 0; 924898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney ciu_timx.s.one_shot = 1; 934898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney ciu_timx.s.len = cvm_oct_tx_poll_interval; 944898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney cvmx_write_csr(CVMX_CIU_TIMX(1), ciu_timx.u64); 954898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney} 964898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney 974898c560103fb8075c10a8e9d70e0ca26873075eDavid Daneyvoid cvm_oct_free_tx_skbs(struct net_device *dev) 986888fc87768eaa218b6244f2e78c55416706981aDavid Daney{ 996888fc87768eaa218b6244f2e78c55416706981aDavid Daney int32_t skb_to_free; 1006888fc87768eaa218b6244f2e78c55416706981aDavid Daney int qos, queues_per_port; 1014898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney int total_freed = 0; 1024898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney int total_remaining = 0; 1034898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney unsigned long flags; 1044898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney struct octeon_ethernet *priv = netdev_priv(dev); 1054898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney 1066888fc87768eaa218b6244f2e78c55416706981aDavid Daney queues_per_port = cvmx_pko_get_num_queues(priv->port); 1076888fc87768eaa218b6244f2e78c55416706981aDavid Daney /* Drain any pending packets in the free list */ 1086888fc87768eaa218b6244f2e78c55416706981aDavid Daney for (qos = 0; qos < queues_per_port; qos++) { 1096888fc87768eaa218b6244f2e78c55416706981aDavid Daney if (skb_queue_len(&priv->tx_free_list[qos]) == 0) 1106888fc87768eaa218b6244f2e78c55416706981aDavid Daney continue; 1116888fc87768eaa218b6244f2e78c55416706981aDavid Daney skb_to_free = cvmx_fau_fetch_and_add32(priv->fau+qos*4, MAX_SKB_TO_FREE); 1126888fc87768eaa218b6244f2e78c55416706981aDavid Daney skb_to_free = cvm_oct_adjust_skb_to_free(skb_to_free, priv->fau+qos*4); 1136888fc87768eaa218b6244f2e78c55416706981aDavid Daney 1144898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney 1154898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney total_freed += skb_to_free; 1164898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney if (skb_to_free > 0) { 1174898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney struct sk_buff *to_free_list = NULL; 1184898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney spin_lock_irqsave(&priv->tx_free_list[qos].lock, flags); 1194898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney while (skb_to_free > 0) { 1204898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney struct sk_buff *t = __skb_dequeue(&priv->tx_free_list[qos]); 1214898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney t->next = to_free_list; 1224898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney to_free_list = t; 1234898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney skb_to_free--; 1244898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney } 1254898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney spin_unlock_irqrestore(&priv->tx_free_list[qos].lock, flags); 1264898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney /* Do the actual freeing outside of the lock. */ 1274898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney while (to_free_list) { 1284898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney struct sk_buff *t = to_free_list; 1294898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney to_free_list = to_free_list->next; 1304898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney dev_kfree_skb_any(t); 1314898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney } 1326888fc87768eaa218b6244f2e78c55416706981aDavid Daney } 1334898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney total_remaining += skb_queue_len(&priv->tx_free_list[qos]); 1346888fc87768eaa218b6244f2e78c55416706981aDavid Daney } 1354898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney if (total_freed >= 0 && netif_queue_stopped(dev)) 1366888fc87768eaa218b6244f2e78c55416706981aDavid Daney netif_wake_queue(dev); 1374898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney if (total_remaining) 1384898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney cvm_oct_kick_tx_poll_watchdog(); 1396888fc87768eaa218b6244f2e78c55416706981aDavid Daney} 1406888fc87768eaa218b6244f2e78c55416706981aDavid Daney 14180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney/** 142ec977c5b473e29dbfdac8f2c7477eccc2142e3bcDavid Daney * cvm_oct_xmit - transmit a packet 14380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * @skb: Packet to send 14480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * @dev: Device info structure 145ec977c5b473e29dbfdac8f2c7477eccc2142e3bcDavid Daney * 146ec977c5b473e29dbfdac8f2c7477eccc2142e3bcDavid Daney * Returns Always returns NETDEV_TX_OK 14780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney */ 14880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daneyint cvm_oct_xmit(struct sk_buff *skb, struct net_device *dev) 14980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney{ 15080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney cvmx_pko_command_word0_t pko_command; 15180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney union cvmx_buf_ptr hw_buffer; 15280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney uint64_t old_scratch; 15380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney uint64_t old_scratch2; 15480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney int qos; 155924cc2680fbe181066ec138d369691d28d913ea2David Daney int i; 1566888fc87768eaa218b6244f2e78c55416706981aDavid Daney enum {QUEUE_CORE, QUEUE_HW, QUEUE_DROP} queue_type; 15780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney struct octeon_ethernet *priv = netdev_priv(dev); 1586888fc87768eaa218b6244f2e78c55416706981aDavid Daney struct sk_buff *to_free_list; 159a620c1632629b42369e78448acc7b384fe1faf48David Daney int32_t skb_to_free; 16080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney int32_t buffers_to_free; 1614898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney u32 total_to_clean; 1626888fc87768eaa218b6244f2e78c55416706981aDavid Daney unsigned long flags; 16380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#if REUSE_SKBUFFS_WITHOUT_FREE 16480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney unsigned char *fpa_head; 16580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#endif 16680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney 16780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney /* 16880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * Prefetch the private data structure. It is larger that one 16980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * cache line. 17080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney */ 17180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney prefetch(priv); 17280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney 17380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney /* 17480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * The check on CVMX_PKO_QUEUES_PER_PORT_* is designed to 17580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * completely remove "qos" in the event neither interface 17680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * supports multiple queues per port. 17780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney */ 17880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney if ((CVMX_PKO_QUEUES_PER_PORT_INTERFACE0 > 1) || 17980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney (CVMX_PKO_QUEUES_PER_PORT_INTERFACE1 > 1)) { 18080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney qos = GET_SKBUFF_QOS(skb); 18180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney if (qos <= 0) 18280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney qos = 0; 18380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney else if (qos >= cvmx_pko_get_num_queues(priv->port)) 18480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney qos = 0; 18580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney } else 18680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney qos = 0; 18780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney 18880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney if (USE_ASYNC_IOBDMA) { 18980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney /* Save scratch in case userspace is using it */ 19080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney CVMX_SYNCIOBDMA; 19180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney old_scratch = cvmx_scratch_read64(CVMX_SCR_SCRATCH); 19280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney old_scratch2 = cvmx_scratch_read64(CVMX_SCR_SCRATCH + 8); 19380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney 19480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney /* 195a620c1632629b42369e78448acc7b384fe1faf48David Daney * Fetch and increment the number of packets to be 196a620c1632629b42369e78448acc7b384fe1faf48David Daney * freed. 19780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney */ 19880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney cvmx_fau_async_fetch_and_add32(CVMX_SCR_SCRATCH + 8, 19980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney FAU_NUM_PACKET_BUFFERS_TO_FREE, 20080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney 0); 20180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney cvmx_fau_async_fetch_and_add32(CVMX_SCR_SCRATCH, 202a620c1632629b42369e78448acc7b384fe1faf48David Daney priv->fau + qos * 4, 203a620c1632629b42369e78448acc7b384fe1faf48David Daney MAX_SKB_TO_FREE); 20480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney } 20580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney 20680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney /* 207924cc2680fbe181066ec138d369691d28d913ea2David Daney * We have space for 6 segment pointers, If there will be more 208924cc2680fbe181066ec138d369691d28d913ea2David Daney * than that, we must linearize. 209924cc2680fbe181066ec138d369691d28d913ea2David Daney */ 210924cc2680fbe181066ec138d369691d28d913ea2David Daney if (unlikely(skb_shinfo(skb)->nr_frags > 5)) { 211924cc2680fbe181066ec138d369691d28d913ea2David Daney if (unlikely(__skb_linearize(skb))) { 212924cc2680fbe181066ec138d369691d28d913ea2David Daney queue_type = QUEUE_DROP; 213924cc2680fbe181066ec138d369691d28d913ea2David Daney if (USE_ASYNC_IOBDMA) { 214924cc2680fbe181066ec138d369691d28d913ea2David Daney /* Get the number of skbuffs in use by the hardware */ 215924cc2680fbe181066ec138d369691d28d913ea2David Daney CVMX_SYNCIOBDMA; 216924cc2680fbe181066ec138d369691d28d913ea2David Daney skb_to_free = cvmx_scratch_read64(CVMX_SCR_SCRATCH); 217924cc2680fbe181066ec138d369691d28d913ea2David Daney } else { 218924cc2680fbe181066ec138d369691d28d913ea2David Daney /* Get the number of skbuffs in use by the hardware */ 219924cc2680fbe181066ec138d369691d28d913ea2David Daney skb_to_free = cvmx_fau_fetch_and_add32(priv->fau + qos * 4, 220924cc2680fbe181066ec138d369691d28d913ea2David Daney MAX_SKB_TO_FREE); 221924cc2680fbe181066ec138d369691d28d913ea2David Daney } 222924cc2680fbe181066ec138d369691d28d913ea2David Daney skb_to_free = cvm_oct_adjust_skb_to_free(skb_to_free, priv->fau + qos * 4); 223924cc2680fbe181066ec138d369691d28d913ea2David Daney spin_lock_irqsave(&priv->tx_free_list[qos].lock, flags); 224924cc2680fbe181066ec138d369691d28d913ea2David Daney goto skip_xmit; 225924cc2680fbe181066ec138d369691d28d913ea2David Daney } 226924cc2680fbe181066ec138d369691d28d913ea2David Daney } 227924cc2680fbe181066ec138d369691d28d913ea2David Daney 228924cc2680fbe181066ec138d369691d28d913ea2David Daney /* 22980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * The CN3XXX series of parts has an errata (GMX-401) which 23080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * causes the GMX block to hang if a collision occurs towards 23180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * the end of a <68 byte packet. As a workaround for this, we 23280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * pad packets to be 68 bytes whenever we are in half duplex 23380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * mode. We don't handle the case of having a small packet but 23480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * no room to add the padding. The kernel should always give 23580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * us at least a cache line 23680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney */ 23780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney if ((skb->len < 64) && OCTEON_IS_MODEL(OCTEON_CN3XXX)) { 23880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney union cvmx_gmxx_prtx_cfg gmx_prt_cfg; 23980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney int interface = INTERFACE(priv->port); 24080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney int index = INDEX(priv->port); 24180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney 24280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney if (interface < 2) { 24380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney /* We only need to pad packet in half duplex mode */ 24480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney gmx_prt_cfg.u64 = 24580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface)); 24680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney if (gmx_prt_cfg.s.duplex == 0) { 24780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney int add_bytes = 64 - skb->len; 24880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney if ((skb_tail_pointer(skb) + add_bytes) <= 24980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney skb_end_pointer(skb)) 25080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney memset(__skb_put(skb, add_bytes), 0, 25180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney add_bytes); 25280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney } 25380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney } 25480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney } 25580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney 25680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney /* Build the PKO command */ 25780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney pko_command.u64 = 0; 25880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney pko_command.s.n2 = 1; /* Don't pollute L2 with the outgoing packet */ 25980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney pko_command.s.segs = 1; 26080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney pko_command.s.total_bytes = skb->len; 26180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney pko_command.s.size0 = CVMX_FAU_OP_SIZE_32; 26280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney pko_command.s.subone0 = 1; 26380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney 26480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney pko_command.s.dontfree = 1; 265924cc2680fbe181066ec138d369691d28d913ea2David Daney 266924cc2680fbe181066ec138d369691d28d913ea2David Daney /* Build the PKO buffer pointer */ 267924cc2680fbe181066ec138d369691d28d913ea2David Daney hw_buffer.u64 = 0; 268924cc2680fbe181066ec138d369691d28d913ea2David Daney if (skb_shinfo(skb)->nr_frags == 0) { 269924cc2680fbe181066ec138d369691d28d913ea2David Daney hw_buffer.s.addr = XKPHYS_TO_PHYS((u64)skb->data); 270924cc2680fbe181066ec138d369691d28d913ea2David Daney hw_buffer.s.pool = 0; 271924cc2680fbe181066ec138d369691d28d913ea2David Daney hw_buffer.s.size = skb->len; 272924cc2680fbe181066ec138d369691d28d913ea2David Daney } else { 273924cc2680fbe181066ec138d369691d28d913ea2David Daney hw_buffer.s.addr = XKPHYS_TO_PHYS((u64)skb->data); 274924cc2680fbe181066ec138d369691d28d913ea2David Daney hw_buffer.s.pool = 0; 275924cc2680fbe181066ec138d369691d28d913ea2David Daney hw_buffer.s.size = skb_headlen(skb); 276924cc2680fbe181066ec138d369691d28d913ea2David Daney CVM_OCT_SKB_CB(skb)[0] = hw_buffer.u64; 277924cc2680fbe181066ec138d369691d28d913ea2David Daney for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { 278924cc2680fbe181066ec138d369691d28d913ea2David Daney struct skb_frag_struct *fs = skb_shinfo(skb)->frags + i; 2798d804d4fdf90b3af62a41a20bf8b21b75529a003David Daney hw_buffer.s.addr = XKPHYS_TO_PHYS((u64)(page_address(fs->page.p) + fs->page_offset)); 280924cc2680fbe181066ec138d369691d28d913ea2David Daney hw_buffer.s.size = fs->size; 281924cc2680fbe181066ec138d369691d28d913ea2David Daney CVM_OCT_SKB_CB(skb)[i + 1] = hw_buffer.u64; 282924cc2680fbe181066ec138d369691d28d913ea2David Daney } 283924cc2680fbe181066ec138d369691d28d913ea2David Daney hw_buffer.s.addr = XKPHYS_TO_PHYS((u64)CVM_OCT_SKB_CB(skb)); 284924cc2680fbe181066ec138d369691d28d913ea2David Daney hw_buffer.s.size = skb_shinfo(skb)->nr_frags + 1; 285924cc2680fbe181066ec138d369691d28d913ea2David Daney pko_command.s.segs = skb_shinfo(skb)->nr_frags + 1; 286924cc2680fbe181066ec138d369691d28d913ea2David Daney pko_command.s.gather = 1; 287924cc2680fbe181066ec138d369691d28d913ea2David Daney goto dont_put_skbuff_in_hw; 288924cc2680fbe181066ec138d369691d28d913ea2David Daney } 289924cc2680fbe181066ec138d369691d28d913ea2David Daney 29080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney /* 29180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * See if we can put this skb in the FPA pool. Any strange 29280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * behavior from the Linux networking stack will most likely 29380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * be caused by a bug in the following code. If some field is 29480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * in use by the network stack and get carried over when a 29580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * buffer is reused, bad thing may happen. If in doubt and 29680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * you dont need the absolute best performance, disable the 29780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * define REUSE_SKBUFFS_WITHOUT_FREE. The reuse of buffers has 29880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * shown a 25% increase in performance under some loads. 29980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney */ 30080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#if REUSE_SKBUFFS_WITHOUT_FREE 301166bdaa9aad9903bf4330ef68feb37f220c9eac8David Daney fpa_head = skb->head + 256 - ((unsigned long)skb->head & 0x7f); 30280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney if (unlikely(skb->data < fpa_head)) { 30380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney /* 30480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * printk("TX buffer beginning can't meet FPA 30580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * alignment constraints\n"); 30680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney */ 30780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney goto dont_put_skbuff_in_hw; 30880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney } 30980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney if (unlikely 31080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney ((skb_end_pointer(skb) - fpa_head) < CVMX_FPA_PACKET_POOL_SIZE)) { 31180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney /* 31280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney printk("TX buffer isn't large enough for the FPA\n"); 31380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney */ 31480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney goto dont_put_skbuff_in_hw; 31580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney } 31680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney if (unlikely(skb_shared(skb))) { 31780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney /* 31880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney printk("TX buffer sharing data with someone else\n"); 31980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney */ 32080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney goto dont_put_skbuff_in_hw; 32180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney } 32280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney if (unlikely(skb_cloned(skb))) { 32380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney /* 32480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney printk("TX buffer has been cloned\n"); 32580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney */ 32680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney goto dont_put_skbuff_in_hw; 32780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney } 32880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney if (unlikely(skb_header_cloned(skb))) { 32980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney /* 33080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney printk("TX buffer header has been cloned\n"); 33180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney */ 33280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney goto dont_put_skbuff_in_hw; 33380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney } 33480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney if (unlikely(skb->destructor)) { 33580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney /* 33680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney printk("TX buffer has a destructor\n"); 33780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney */ 33880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney goto dont_put_skbuff_in_hw; 33980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney } 34080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney if (unlikely(skb_shinfo(skb)->nr_frags)) { 34180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney /* 34280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney printk("TX buffer has fragments\n"); 34380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney */ 34480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney goto dont_put_skbuff_in_hw; 34580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney } 34680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney if (unlikely 34780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney (skb->truesize != 34880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney sizeof(*skb) + skb_end_pointer(skb) - skb->head)) { 34980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney /* 35080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney printk("TX buffer truesize has been changed\n"); 35180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney */ 35280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney goto dont_put_skbuff_in_hw; 35380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney } 35480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney 35580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney /* 35680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * We can use this buffer in the FPA. We don't need the FAU 35780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * update anymore 35880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney */ 35980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney pko_command.s.dontfree = 0; 36080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney 361166bdaa9aad9903bf4330ef68feb37f220c9eac8David Daney hw_buffer.s.back = ((unsigned long)skb->data >> 7) - ((unsigned long)fpa_head >> 7); 36280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney *(struct sk_buff **)(fpa_head - sizeof(void *)) = skb; 36380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney 36480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney /* 36580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * The skbuff will be reused without ever being freed. We must 366f696a10838ffab85e5bc07e7cff0d0e1870a30d7David Daney * cleanup a bunch of core things. 36780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney */ 368f696a10838ffab85e5bc07e7cff0d0e1870a30d7David Daney dst_release(skb_dst(skb)); 369f696a10838ffab85e5bc07e7cff0d0e1870a30d7David Daney skb_dst_set(skb, NULL); 37080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#ifdef CONFIG_XFRM 37180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney secpath_put(skb->sp); 37280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney skb->sp = NULL; 37380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#endif 37480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney nf_reset(skb); 37580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney 37680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#ifdef CONFIG_NET_SCHED 37780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney skb->tc_index = 0; 37880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#ifdef CONFIG_NET_CLS_ACT 37980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney skb->tc_verd = 0; 38080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#endif /* CONFIG_NET_CLS_ACT */ 38180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#endif /* CONFIG_NET_SCHED */ 3826888fc87768eaa218b6244f2e78c55416706981aDavid Daney#endif /* REUSE_SKBUFFS_WITHOUT_FREE */ 38380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney 38480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daneydont_put_skbuff_in_hw: 38580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney 38680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney /* Check if we can use the hardware checksumming */ 38780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney if (USE_HW_TCPUDP_CHECKSUM && (skb->protocol == htons(ETH_P_IP)) && 38880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney (ip_hdr(skb)->version == 4) && (ip_hdr(skb)->ihl == 5) && 38980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney ((ip_hdr(skb)->frag_off == 0) || (ip_hdr(skb)->frag_off == 1 << 14)) 390081f6749ae33f72b4fafea4c02976e163ef6ef37David Daney && ((ip_hdr(skb)->protocol == IPPROTO_TCP) 391081f6749ae33f72b4fafea4c02976e163ef6ef37David Daney || (ip_hdr(skb)->protocol == IPPROTO_UDP))) { 39280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney /* Use hardware checksum calc */ 39380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney pko_command.s.ipoffp1 = sizeof(struct ethhdr) + 1; 39480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney } 39580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney 39680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney if (USE_ASYNC_IOBDMA) { 39780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney /* Get the number of skbuffs in use by the hardware */ 39880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney CVMX_SYNCIOBDMA; 399a620c1632629b42369e78448acc7b384fe1faf48David Daney skb_to_free = cvmx_scratch_read64(CVMX_SCR_SCRATCH); 40080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney buffers_to_free = cvmx_scratch_read64(CVMX_SCR_SCRATCH + 8); 40180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney } else { 40280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney /* Get the number of skbuffs in use by the hardware */ 403a620c1632629b42369e78448acc7b384fe1faf48David Daney skb_to_free = cvmx_fau_fetch_and_add32(priv->fau + qos * 4, 404a620c1632629b42369e78448acc7b384fe1faf48David Daney MAX_SKB_TO_FREE); 40580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney buffers_to_free = 40680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney cvmx_fau_fetch_and_add32(FAU_NUM_PACKET_BUFFERS_TO_FREE, 0); 40780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney } 40880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney 4096888fc87768eaa218b6244f2e78c55416706981aDavid Daney skb_to_free = cvm_oct_adjust_skb_to_free(skb_to_free, priv->fau+qos*4); 410a620c1632629b42369e78448acc7b384fe1faf48David Daney 411a620c1632629b42369e78448acc7b384fe1faf48David Daney /* 41280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * If we're sending faster than the receive can free them then 41380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * don't do the HW free. 41480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney */ 4154898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney if ((buffers_to_free < -100) && !pko_command.s.dontfree) 41680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney pko_command.s.dontfree = 1; 41780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney 4184898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney if (pko_command.s.dontfree) { 4196888fc87768eaa218b6244f2e78c55416706981aDavid Daney queue_type = QUEUE_CORE; 4204898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney pko_command.s.reg0 = priv->fau+qos*4; 4214898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney } else { 4226888fc87768eaa218b6244f2e78c55416706981aDavid Daney queue_type = QUEUE_HW; 4234898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney } 4244898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney if (USE_ASYNC_IOBDMA) 4254898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney cvmx_fau_async_fetch_and_add32(CVMX_SCR_SCRATCH, FAU_TOTAL_TX_TO_CLEAN, 1); 4266888fc87768eaa218b6244f2e78c55416706981aDavid Daney 4276888fc87768eaa218b6244f2e78c55416706981aDavid Daney spin_lock_irqsave(&priv->tx_free_list[qos].lock, flags); 42880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney 42980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney /* Drop this packet if we have too many already queued to the HW */ 4306888fc87768eaa218b6244f2e78c55416706981aDavid Daney if (unlikely(skb_queue_len(&priv->tx_free_list[qos]) >= MAX_OUT_QUEUE_DEPTH)) { 4316888fc87768eaa218b6244f2e78c55416706981aDavid Daney if (dev->tx_queue_len != 0) { 4326888fc87768eaa218b6244f2e78c55416706981aDavid Daney /* Drop the lock when notifying the core. */ 4336888fc87768eaa218b6244f2e78c55416706981aDavid Daney spin_unlock_irqrestore(&priv->tx_free_list[qos].lock, flags); 4346888fc87768eaa218b6244f2e78c55416706981aDavid Daney netif_stop_queue(dev); 4356888fc87768eaa218b6244f2e78c55416706981aDavid Daney spin_lock_irqsave(&priv->tx_free_list[qos].lock, flags); 4366888fc87768eaa218b6244f2e78c55416706981aDavid Daney } else { 4376888fc87768eaa218b6244f2e78c55416706981aDavid Daney /* If not using normal queueing. */ 4386888fc87768eaa218b6244f2e78c55416706981aDavid Daney queue_type = QUEUE_DROP; 4396888fc87768eaa218b6244f2e78c55416706981aDavid Daney goto skip_xmit; 4406888fc87768eaa218b6244f2e78c55416706981aDavid Daney } 44180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney } 4426888fc87768eaa218b6244f2e78c55416706981aDavid Daney 4436888fc87768eaa218b6244f2e78c55416706981aDavid Daney cvmx_pko_send_packet_prepare(priv->port, priv->queue + qos, 4446888fc87768eaa218b6244f2e78c55416706981aDavid Daney CVMX_PKO_LOCK_NONE); 4456888fc87768eaa218b6244f2e78c55416706981aDavid Daney 44680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney /* Send the packet to the output queue */ 4476888fc87768eaa218b6244f2e78c55416706981aDavid Daney if (unlikely(cvmx_pko_send_packet_finish(priv->port, 4486888fc87768eaa218b6244f2e78c55416706981aDavid Daney priv->queue + qos, 4496888fc87768eaa218b6244f2e78c55416706981aDavid Daney pko_command, hw_buffer, 4506888fc87768eaa218b6244f2e78c55416706981aDavid Daney CVMX_PKO_LOCK_NONE))) { 4517a2eaf9358250706672783eb8511835706b0922bChristian Dietrich printk_ratelimited("%s: Failed to send the packet\n", dev->name); 4526888fc87768eaa218b6244f2e78c55416706981aDavid Daney queue_type = QUEUE_DROP; 45380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney } 4546888fc87768eaa218b6244f2e78c55416706981aDavid Daneyskip_xmit: 4556888fc87768eaa218b6244f2e78c55416706981aDavid Daney to_free_list = NULL; 45680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney 4576888fc87768eaa218b6244f2e78c55416706981aDavid Daney switch (queue_type) { 4586888fc87768eaa218b6244f2e78c55416706981aDavid Daney case QUEUE_DROP: 4596888fc87768eaa218b6244f2e78c55416706981aDavid Daney skb->next = to_free_list; 4606888fc87768eaa218b6244f2e78c55416706981aDavid Daney to_free_list = skb; 4616888fc87768eaa218b6244f2e78c55416706981aDavid Daney priv->stats.tx_dropped++; 4626888fc87768eaa218b6244f2e78c55416706981aDavid Daney break; 4636888fc87768eaa218b6244f2e78c55416706981aDavid Daney case QUEUE_HW: 4646888fc87768eaa218b6244f2e78c55416706981aDavid Daney cvmx_fau_atomic_add32(FAU_NUM_PACKET_BUFFERS_TO_FREE, -1); 4656888fc87768eaa218b6244f2e78c55416706981aDavid Daney break; 4666888fc87768eaa218b6244f2e78c55416706981aDavid Daney case QUEUE_CORE: 4676888fc87768eaa218b6244f2e78c55416706981aDavid Daney __skb_queue_tail(&priv->tx_free_list[qos], skb); 4686888fc87768eaa218b6244f2e78c55416706981aDavid Daney break; 4696888fc87768eaa218b6244f2e78c55416706981aDavid Daney default: 4706888fc87768eaa218b6244f2e78c55416706981aDavid Daney BUG(); 47180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney } 47280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney 4736888fc87768eaa218b6244f2e78c55416706981aDavid Daney while (skb_to_free > 0) { 4746888fc87768eaa218b6244f2e78c55416706981aDavid Daney struct sk_buff *t = __skb_dequeue(&priv->tx_free_list[qos]); 4756888fc87768eaa218b6244f2e78c55416706981aDavid Daney t->next = to_free_list; 4766888fc87768eaa218b6244f2e78c55416706981aDavid Daney to_free_list = t; 4776888fc87768eaa218b6244f2e78c55416706981aDavid Daney skb_to_free--; 47880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney } 47980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney 4806888fc87768eaa218b6244f2e78c55416706981aDavid Daney spin_unlock_irqrestore(&priv->tx_free_list[qos].lock, flags); 4816888fc87768eaa218b6244f2e78c55416706981aDavid Daney 4826888fc87768eaa218b6244f2e78c55416706981aDavid Daney /* Do the actual freeing outside of the lock. */ 4836888fc87768eaa218b6244f2e78c55416706981aDavid Daney while (to_free_list) { 4846888fc87768eaa218b6244f2e78c55416706981aDavid Daney struct sk_buff *t = to_free_list; 4856888fc87768eaa218b6244f2e78c55416706981aDavid Daney to_free_list = to_free_list->next; 4866888fc87768eaa218b6244f2e78c55416706981aDavid Daney dev_kfree_skb_any(t); 4876888fc87768eaa218b6244f2e78c55416706981aDavid Daney } 4886888fc87768eaa218b6244f2e78c55416706981aDavid Daney 4896888fc87768eaa218b6244f2e78c55416706981aDavid Daney if (USE_ASYNC_IOBDMA) { 4904898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney CVMX_SYNCIOBDMA; 4914898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney total_to_clean = cvmx_scratch_read64(CVMX_SCR_SCRATCH); 4926888fc87768eaa218b6244f2e78c55416706981aDavid Daney /* Restore the scratch area */ 4936888fc87768eaa218b6244f2e78c55416706981aDavid Daney cvmx_scratch_write64(CVMX_SCR_SCRATCH, old_scratch); 4946888fc87768eaa218b6244f2e78c55416706981aDavid Daney cvmx_scratch_write64(CVMX_SCR_SCRATCH + 8, old_scratch2); 4954898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney } else { 4964898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney total_to_clean = cvmx_fau_fetch_and_add32(FAU_TOTAL_TX_TO_CLEAN, 1); 49780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney } 49880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney 4994898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney if (total_to_clean & 0x3ff) { 5004898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney /* 5014898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney * Schedule the cleanup tasklet every 1024 packets for 5024898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney * the pathological case of high traffic on one port 5034898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney * delaying clean up of packets on a different port 5044898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney * that is blocked waiting for the cleanup. 5054898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney */ 5064898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney tasklet_schedule(&cvm_oct_tx_cleanup_tasklet); 5074898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney } 5084898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney 5094898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney cvm_oct_kick_tx_poll_watchdog(); 5104898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney 5116888fc87768eaa218b6244f2e78c55416706981aDavid Daney return NETDEV_TX_OK; 51280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney} 51380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney 51480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney/** 515ec977c5b473e29dbfdac8f2c7477eccc2142e3bcDavid Daney * cvm_oct_xmit_pow - transmit a packet to the POW 51680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * @skb: Packet to send 51780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * @dev: Device info structure 518ec977c5b473e29dbfdac8f2c7477eccc2142e3bcDavid Daney 51980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * Returns Always returns zero 52080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney */ 52180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daneyint cvm_oct_xmit_pow(struct sk_buff *skb, struct net_device *dev) 52280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney{ 52380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney struct octeon_ethernet *priv = netdev_priv(dev); 52480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney void *packet_buffer; 52580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney void *copy_location; 52680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney 52780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney /* Get a work queue entry */ 52880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney cvmx_wqe_t *work = cvmx_fpa_alloc(CVMX_FPA_WQE_POOL); 52980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney if (unlikely(work == NULL)) { 5307a2eaf9358250706672783eb8511835706b0922bChristian Dietrich printk_ratelimited("%s: Failed to allocate a work " 5317a2eaf9358250706672783eb8511835706b0922bChristian Dietrich "queue entry\n", dev->name); 53280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney priv->stats.tx_dropped++; 53380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney dev_kfree_skb(skb); 53480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney return 0; 53580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney } 53680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney 53780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney /* Get a packet buffer */ 53880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney packet_buffer = cvmx_fpa_alloc(CVMX_FPA_PACKET_POOL); 53980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney if (unlikely(packet_buffer == NULL)) { 5407a2eaf9358250706672783eb8511835706b0922bChristian Dietrich printk_ratelimited("%s: Failed to allocate a packet buffer\n", 5417a2eaf9358250706672783eb8511835706b0922bChristian Dietrich dev->name); 54280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney cvmx_fpa_free(work, CVMX_FPA_WQE_POOL, DONT_WRITEBACK(1)); 54380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney priv->stats.tx_dropped++; 54480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney dev_kfree_skb(skb); 54580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney return 0; 54680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney } 54780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney 54880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney /* 54980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * Calculate where we need to copy the data to. We need to 55080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * leave 8 bytes for a next pointer (unused). We also need to 55180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * include any configure skip. Then we need to align the IP 55280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * packet src and dest into the same 64bit word. The below 55380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * calculation may add a little extra, but that doesn't 55480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * hurt. 55580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney */ 55680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney copy_location = packet_buffer + sizeof(uint64_t); 55780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney copy_location += ((CVMX_HELPER_FIRST_MBUFF_SKIP + 7) & 0xfff8) + 6; 55880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney 55980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney /* 56080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * We have to copy the packet since whoever processes this 56180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * packet will free it to a hardware pool. We can't use the 56280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * trick of counting outstanding packets like in 56380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * cvm_oct_xmit. 56480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney */ 56580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney memcpy(copy_location, skb->data, skb->len); 56680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney 56780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney /* 56880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * Fill in some of the work queue fields. We may need to add 56980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * more if the software at the other end needs them. 57080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney */ 57180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney work->hw_chksum = skb->csum; 57280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney work->len = skb->len; 57380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney work->ipprt = priv->port; 57480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney work->qos = priv->port & 0x7; 57580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney work->grp = pow_send_group; 57680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney work->tag_type = CVMX_HELPER_INPUT_TAG_TYPE; 57780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney work->tag = pow_send_group; /* FIXME */ 57880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney /* Default to zero. Sets of zero later are commented out */ 57980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney work->word2.u64 = 0; 58080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney work->word2.s.bufs = 1; 58180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney work->packet_ptr.u64 = 0; 58280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney work->packet_ptr.s.addr = cvmx_ptr_to_phys(copy_location); 58380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney work->packet_ptr.s.pool = CVMX_FPA_PACKET_POOL; 58480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney work->packet_ptr.s.size = CVMX_FPA_PACKET_POOL_SIZE; 58580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney work->packet_ptr.s.back = (copy_location - packet_buffer) >> 7; 58680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney 58780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney if (skb->protocol == htons(ETH_P_IP)) { 58880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney work->word2.s.ip_offset = 14; 58980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#if 0 59080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney work->word2.s.vlan_valid = 0; /* FIXME */ 59180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney work->word2.s.vlan_cfi = 0; /* FIXME */ 59280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney work->word2.s.vlan_id = 0; /* FIXME */ 59380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney work->word2.s.dec_ipcomp = 0; /* FIXME */ 59480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#endif 59580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney work->word2.s.tcp_or_udp = 596081f6749ae33f72b4fafea4c02976e163ef6ef37David Daney (ip_hdr(skb)->protocol == IPPROTO_TCP) 597081f6749ae33f72b4fafea4c02976e163ef6ef37David Daney || (ip_hdr(skb)->protocol == IPPROTO_UDP); 59880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#if 0 59980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney /* FIXME */ 60080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney work->word2.s.dec_ipsec = 0; 60180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney /* We only support IPv4 right now */ 60280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney work->word2.s.is_v6 = 0; 60380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney /* Hardware would set to zero */ 60480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney work->word2.s.software = 0; 60580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney /* No error, packet is internal */ 60680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney work->word2.s.L4_error = 0; 60780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#endif 60880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney work->word2.s.is_frag = !((ip_hdr(skb)->frag_off == 0) 60980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney || (ip_hdr(skb)->frag_off == 61080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney 1 << 14)); 61180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#if 0 61280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney /* Assume Linux is sending a good packet */ 61380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney work->word2.s.IP_exc = 0; 61480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#endif 61580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney work->word2.s.is_bcast = (skb->pkt_type == PACKET_BROADCAST); 61680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney work->word2.s.is_mcast = (skb->pkt_type == PACKET_MULTICAST); 61780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#if 0 61880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney /* This is an IP packet */ 61980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney work->word2.s.not_IP = 0; 62080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney /* No error, packet is internal */ 62180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney work->word2.s.rcv_error = 0; 62280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney /* No error, packet is internal */ 62380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney work->word2.s.err_code = 0; 62480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#endif 62580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney 62680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney /* 62780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * When copying the data, include 4 bytes of the 62880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * ethernet header to align the same way hardware 62980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * does. 63080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney */ 63180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney memcpy(work->packet_data, skb->data + 10, 63280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney sizeof(work->packet_data)); 63380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney } else { 63480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#if 0 63580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney work->word2.snoip.vlan_valid = 0; /* FIXME */ 63680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney work->word2.snoip.vlan_cfi = 0; /* FIXME */ 63780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney work->word2.snoip.vlan_id = 0; /* FIXME */ 63880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney work->word2.snoip.software = 0; /* Hardware would set to zero */ 63980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#endif 64080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney work->word2.snoip.is_rarp = skb->protocol == htons(ETH_P_RARP); 64180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney work->word2.snoip.is_arp = skb->protocol == htons(ETH_P_ARP); 64280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney work->word2.snoip.is_bcast = 64380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney (skb->pkt_type == PACKET_BROADCAST); 64480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney work->word2.snoip.is_mcast = 64580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney (skb->pkt_type == PACKET_MULTICAST); 64680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney work->word2.snoip.not_IP = 1; /* IP was done up above */ 64780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#if 0 64880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney /* No error, packet is internal */ 64980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney work->word2.snoip.rcv_error = 0; 65080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney /* No error, packet is internal */ 65180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney work->word2.snoip.err_code = 0; 65280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney#endif 65380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney memcpy(work->packet_data, skb->data, sizeof(work->packet_data)); 65480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney } 65580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney 65680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney /* Submit the packet to the POW */ 65780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney cvmx_pow_work_submit(work, work->tag, work->tag_type, work->qos, 65880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney work->grp); 65980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney priv->stats.tx_packets++; 66080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney priv->stats.tx_bytes += skb->len; 66180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney dev_kfree_skb(skb); 66280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney return 0; 66380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney} 66480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney 66580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney/** 666ec977c5b473e29dbfdac8f2c7477eccc2142e3bcDavid Daney * cvm_oct_tx_shutdown_dev - free all skb that are currently queued for TX. 66780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney * @dev: Device being shutdown 668ec977c5b473e29dbfdac8f2c7477eccc2142e3bcDavid Daney * 66980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney */ 6704898c560103fb8075c10a8e9d70e0ca26873075eDavid Daneyvoid cvm_oct_tx_shutdown_dev(struct net_device *dev) 67180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney{ 67280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney struct octeon_ethernet *priv = netdev_priv(dev); 67380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney unsigned long flags; 67480ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney int qos; 67580ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney 67680ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney for (qos = 0; qos < 16; qos++) { 67780ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney spin_lock_irqsave(&priv->tx_free_list[qos].lock, flags); 67880ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney while (skb_queue_len(&priv->tx_free_list[qos])) 67980ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney dev_kfree_skb_any(__skb_dequeue 68080ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney (&priv->tx_free_list[qos])); 68180ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney spin_unlock_irqrestore(&priv->tx_free_list[qos].lock, flags); 68280ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney } 68380ff0fd3ab6451407a20c19b80c1643c4a6d6434David Daney} 6844898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney 6854898c560103fb8075c10a8e9d70e0ca26873075eDavid Daneystatic void cvm_oct_tx_do_cleanup(unsigned long arg) 6864898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney{ 6874898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney int port; 6884898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney 6894898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney for (port = 0; port < TOTAL_NUMBER_OF_PORTS; port++) { 6904898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney if (cvm_oct_device[port]) { 6914898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney struct net_device *dev = cvm_oct_device[port]; 6924898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney cvm_oct_free_tx_skbs(dev); 6934898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney } 6944898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney } 6954898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney} 6964898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney 6974898c560103fb8075c10a8e9d70e0ca26873075eDavid Daneystatic irqreturn_t cvm_oct_tx_cleanup_watchdog(int cpl, void *dev_id) 6984898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney{ 6994898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney /* Disable the interrupt. */ 7004898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney cvmx_write_csr(CVMX_CIU_TIMX(1), 0); 7014898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney /* Do the work in the tasklet. */ 7024898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney tasklet_schedule(&cvm_oct_tx_cleanup_tasklet); 7034898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney return IRQ_HANDLED; 7044898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney} 7054898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney 7064898c560103fb8075c10a8e9d70e0ca26873075eDavid Daneyvoid cvm_oct_tx_initialize(void) 7074898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney{ 7084898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney int i; 7094898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney 7104898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney /* Disable the interrupt. */ 7114898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney cvmx_write_csr(CVMX_CIU_TIMX(1), 0); 7124898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney /* Register an IRQ hander for to receive CIU_TIMX(1) interrupts */ 7134898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney i = request_irq(OCTEON_IRQ_TIMER1, 7144898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney cvm_oct_tx_cleanup_watchdog, 0, 7154898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney "Ethernet", cvm_oct_device); 7164898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney 7174898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney if (i) 7184898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney panic("Could not acquire Ethernet IRQ %d\n", OCTEON_IRQ_TIMER1); 7194898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney} 7204898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney 7214898c560103fb8075c10a8e9d70e0ca26873075eDavid Daneyvoid cvm_oct_tx_shutdown(void) 7224898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney{ 7234898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney /* Free the interrupt handler */ 7244898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney free_irq(OCTEON_IRQ_TIMER1, cvm_oct_device); 7254898c560103fb8075c10a8e9d70e0ca26873075eDavid Daney} 726