162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/***************************************************************************** 362306a36Sopenharmony_ci * * 462306a36Sopenharmony_ci * File: sge.c * 562306a36Sopenharmony_ci * $Revision: 1.26 $ * 662306a36Sopenharmony_ci * $Date: 2005/06/21 18:29:48 $ * 762306a36Sopenharmony_ci * Description: * 862306a36Sopenharmony_ci * DMA engine. * 962306a36Sopenharmony_ci * part of the Chelsio 10Gb Ethernet Driver. * 1062306a36Sopenharmony_ci * * 1162306a36Sopenharmony_ci * * 1262306a36Sopenharmony_ci * http://www.chelsio.com * 1362306a36Sopenharmony_ci * * 1462306a36Sopenharmony_ci * Copyright (c) 2003 - 2005 Chelsio Communications, Inc. * 1562306a36Sopenharmony_ci * All rights reserved. * 1662306a36Sopenharmony_ci * * 1762306a36Sopenharmony_ci * Maintainers: maintainers@chelsio.com * 1862306a36Sopenharmony_ci * * 1962306a36Sopenharmony_ci * Authors: Dimitrios Michailidis <dm@chelsio.com> * 2062306a36Sopenharmony_ci * Tina Yang <tainay@chelsio.com> * 2162306a36Sopenharmony_ci * Felix Marti <felix@chelsio.com> * 2262306a36Sopenharmony_ci * Scott Bardone <sbardone@chelsio.com> * 2362306a36Sopenharmony_ci * Kurt Ottaway <kottaway@chelsio.com> * 2462306a36Sopenharmony_ci * Frank DiMambro <frank@chelsio.com> * 2562306a36Sopenharmony_ci * * 2662306a36Sopenharmony_ci * History: * 2762306a36Sopenharmony_ci * * 2862306a36Sopenharmony_ci ****************************************************************************/ 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci#include "common.h" 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci#include <linux/types.h> 3362306a36Sopenharmony_ci#include <linux/errno.h> 3462306a36Sopenharmony_ci#include <linux/pci.h> 3562306a36Sopenharmony_ci#include <linux/ktime.h> 3662306a36Sopenharmony_ci#include <linux/netdevice.h> 3762306a36Sopenharmony_ci#include <linux/etherdevice.h> 3862306a36Sopenharmony_ci#include <linux/if_vlan.h> 3962306a36Sopenharmony_ci#include <linux/skbuff.h> 4062306a36Sopenharmony_ci#include <linux/mm.h> 4162306a36Sopenharmony_ci#include <linux/tcp.h> 4262306a36Sopenharmony_ci#include <linux/ip.h> 4362306a36Sopenharmony_ci#include <linux/in.h> 4462306a36Sopenharmony_ci#include <linux/if_arp.h> 4562306a36Sopenharmony_ci#include <linux/slab.h> 4662306a36Sopenharmony_ci#include <linux/prefetch.h> 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci#include "cpl5_cmd.h" 4962306a36Sopenharmony_ci#include "sge.h" 5062306a36Sopenharmony_ci#include "regs.h" 5162306a36Sopenharmony_ci#include "espi.h" 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci/* This belongs in if_ether.h */ 5462306a36Sopenharmony_ci#define ETH_P_CPL5 0xf 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci#define SGE_CMDQ_N 2 5762306a36Sopenharmony_ci#define SGE_FREELQ_N 2 5862306a36Sopenharmony_ci#define SGE_CMDQ0_E_N 1024 5962306a36Sopenharmony_ci#define SGE_CMDQ1_E_N 128 6062306a36Sopenharmony_ci#define SGE_FREEL_SIZE 4096 6162306a36Sopenharmony_ci#define SGE_JUMBO_FREEL_SIZE 512 6262306a36Sopenharmony_ci#define SGE_FREEL_REFILL_THRESH 16 6362306a36Sopenharmony_ci#define SGE_RESPQ_E_N 1024 6462306a36Sopenharmony_ci#define SGE_INTRTIMER_NRES 1000 6562306a36Sopenharmony_ci#define SGE_RX_SM_BUF_SIZE 1536 6662306a36Sopenharmony_ci#define SGE_TX_DESC_MAX_PLEN 16384 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci#define SGE_RESPQ_REPLENISH_THRES (SGE_RESPQ_E_N / 4) 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci/* 7162306a36Sopenharmony_ci * Period of the TX buffer reclaim timer. This timer does not need to run 7262306a36Sopenharmony_ci * frequently as TX buffers are usually reclaimed by new TX packets. 7362306a36Sopenharmony_ci */ 7462306a36Sopenharmony_ci#define TX_RECLAIM_PERIOD (HZ / 4) 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci#define M_CMD_LEN 0x7fffffff 7762306a36Sopenharmony_ci#define V_CMD_LEN(v) (v) 7862306a36Sopenharmony_ci#define G_CMD_LEN(v) ((v) & M_CMD_LEN) 7962306a36Sopenharmony_ci#define V_CMD_GEN1(v) ((v) << 31) 8062306a36Sopenharmony_ci#define V_CMD_GEN2(v) (v) 8162306a36Sopenharmony_ci#define F_CMD_DATAVALID (1 << 1) 8262306a36Sopenharmony_ci#define F_CMD_SOP (1 << 2) 8362306a36Sopenharmony_ci#define V_CMD_EOP(v) ((v) << 3) 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci/* 8662306a36Sopenharmony_ci * Command queue, receive buffer list, and response queue descriptors. 8762306a36Sopenharmony_ci */ 8862306a36Sopenharmony_ci#if defined(__BIG_ENDIAN_BITFIELD) 8962306a36Sopenharmony_cistruct cmdQ_e { 9062306a36Sopenharmony_ci u32 addr_lo; 9162306a36Sopenharmony_ci u32 len_gen; 9262306a36Sopenharmony_ci u32 flags; 9362306a36Sopenharmony_ci u32 addr_hi; 9462306a36Sopenharmony_ci}; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_cistruct freelQ_e { 9762306a36Sopenharmony_ci u32 addr_lo; 9862306a36Sopenharmony_ci u32 len_gen; 9962306a36Sopenharmony_ci u32 gen2; 10062306a36Sopenharmony_ci u32 addr_hi; 10162306a36Sopenharmony_ci}; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_cistruct respQ_e { 10462306a36Sopenharmony_ci u32 Qsleeping : 4; 10562306a36Sopenharmony_ci u32 Cmdq1CreditReturn : 5; 10662306a36Sopenharmony_ci u32 Cmdq1DmaComplete : 5; 10762306a36Sopenharmony_ci u32 Cmdq0CreditReturn : 5; 10862306a36Sopenharmony_ci u32 Cmdq0DmaComplete : 5; 10962306a36Sopenharmony_ci u32 FreelistQid : 2; 11062306a36Sopenharmony_ci u32 CreditValid : 1; 11162306a36Sopenharmony_ci u32 DataValid : 1; 11262306a36Sopenharmony_ci u32 Offload : 1; 11362306a36Sopenharmony_ci u32 Eop : 1; 11462306a36Sopenharmony_ci u32 Sop : 1; 11562306a36Sopenharmony_ci u32 GenerationBit : 1; 11662306a36Sopenharmony_ci u32 BufferLength; 11762306a36Sopenharmony_ci}; 11862306a36Sopenharmony_ci#elif defined(__LITTLE_ENDIAN_BITFIELD) 11962306a36Sopenharmony_cistruct cmdQ_e { 12062306a36Sopenharmony_ci u32 len_gen; 12162306a36Sopenharmony_ci u32 addr_lo; 12262306a36Sopenharmony_ci u32 addr_hi; 12362306a36Sopenharmony_ci u32 flags; 12462306a36Sopenharmony_ci}; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_cistruct freelQ_e { 12762306a36Sopenharmony_ci u32 len_gen; 12862306a36Sopenharmony_ci u32 addr_lo; 12962306a36Sopenharmony_ci u32 addr_hi; 13062306a36Sopenharmony_ci u32 gen2; 13162306a36Sopenharmony_ci}; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_cistruct respQ_e { 13462306a36Sopenharmony_ci u32 BufferLength; 13562306a36Sopenharmony_ci u32 GenerationBit : 1; 13662306a36Sopenharmony_ci u32 Sop : 1; 13762306a36Sopenharmony_ci u32 Eop : 1; 13862306a36Sopenharmony_ci u32 Offload : 1; 13962306a36Sopenharmony_ci u32 DataValid : 1; 14062306a36Sopenharmony_ci u32 CreditValid : 1; 14162306a36Sopenharmony_ci u32 FreelistQid : 2; 14262306a36Sopenharmony_ci u32 Cmdq0DmaComplete : 5; 14362306a36Sopenharmony_ci u32 Cmdq0CreditReturn : 5; 14462306a36Sopenharmony_ci u32 Cmdq1DmaComplete : 5; 14562306a36Sopenharmony_ci u32 Cmdq1CreditReturn : 5; 14662306a36Sopenharmony_ci u32 Qsleeping : 4; 14762306a36Sopenharmony_ci} ; 14862306a36Sopenharmony_ci#endif 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci/* 15162306a36Sopenharmony_ci * SW Context Command and Freelist Queue Descriptors 15262306a36Sopenharmony_ci */ 15362306a36Sopenharmony_cistruct cmdQ_ce { 15462306a36Sopenharmony_ci struct sk_buff *skb; 15562306a36Sopenharmony_ci DEFINE_DMA_UNMAP_ADDR(dma_addr); 15662306a36Sopenharmony_ci DEFINE_DMA_UNMAP_LEN(dma_len); 15762306a36Sopenharmony_ci}; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_cistruct freelQ_ce { 16062306a36Sopenharmony_ci struct sk_buff *skb; 16162306a36Sopenharmony_ci DEFINE_DMA_UNMAP_ADDR(dma_addr); 16262306a36Sopenharmony_ci DEFINE_DMA_UNMAP_LEN(dma_len); 16362306a36Sopenharmony_ci}; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci/* 16662306a36Sopenharmony_ci * SW command, freelist and response rings 16762306a36Sopenharmony_ci */ 16862306a36Sopenharmony_cistruct cmdQ { 16962306a36Sopenharmony_ci unsigned long status; /* HW DMA fetch status */ 17062306a36Sopenharmony_ci unsigned int in_use; /* # of in-use command descriptors */ 17162306a36Sopenharmony_ci unsigned int size; /* # of descriptors */ 17262306a36Sopenharmony_ci unsigned int processed; /* total # of descs HW has processed */ 17362306a36Sopenharmony_ci unsigned int cleaned; /* total # of descs SW has reclaimed */ 17462306a36Sopenharmony_ci unsigned int stop_thres; /* SW TX queue suspend threshold */ 17562306a36Sopenharmony_ci u16 pidx; /* producer index (SW) */ 17662306a36Sopenharmony_ci u16 cidx; /* consumer index (HW) */ 17762306a36Sopenharmony_ci u8 genbit; /* current generation (=valid) bit */ 17862306a36Sopenharmony_ci u8 sop; /* is next entry start of packet? */ 17962306a36Sopenharmony_ci struct cmdQ_e *entries; /* HW command descriptor Q */ 18062306a36Sopenharmony_ci struct cmdQ_ce *centries; /* SW command context descriptor Q */ 18162306a36Sopenharmony_ci dma_addr_t dma_addr; /* DMA addr HW command descriptor Q */ 18262306a36Sopenharmony_ci spinlock_t lock; /* Lock to protect cmdQ enqueuing */ 18362306a36Sopenharmony_ci}; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_cistruct freelQ { 18662306a36Sopenharmony_ci unsigned int credits; /* # of available RX buffers */ 18762306a36Sopenharmony_ci unsigned int size; /* free list capacity */ 18862306a36Sopenharmony_ci u16 pidx; /* producer index (SW) */ 18962306a36Sopenharmony_ci u16 cidx; /* consumer index (HW) */ 19062306a36Sopenharmony_ci u16 rx_buffer_size; /* Buffer size on this free list */ 19162306a36Sopenharmony_ci u16 dma_offset; /* DMA offset to align IP headers */ 19262306a36Sopenharmony_ci u16 recycleq_idx; /* skb recycle q to use */ 19362306a36Sopenharmony_ci u8 genbit; /* current generation (=valid) bit */ 19462306a36Sopenharmony_ci struct freelQ_e *entries; /* HW freelist descriptor Q */ 19562306a36Sopenharmony_ci struct freelQ_ce *centries; /* SW freelist context descriptor Q */ 19662306a36Sopenharmony_ci dma_addr_t dma_addr; /* DMA addr HW freelist descriptor Q */ 19762306a36Sopenharmony_ci}; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_cistruct respQ { 20062306a36Sopenharmony_ci unsigned int credits; /* credits to be returned to SGE */ 20162306a36Sopenharmony_ci unsigned int size; /* # of response Q descriptors */ 20262306a36Sopenharmony_ci u16 cidx; /* consumer index (SW) */ 20362306a36Sopenharmony_ci u8 genbit; /* current generation(=valid) bit */ 20462306a36Sopenharmony_ci struct respQ_e *entries; /* HW response descriptor Q */ 20562306a36Sopenharmony_ci dma_addr_t dma_addr; /* DMA addr HW response descriptor Q */ 20662306a36Sopenharmony_ci}; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci/* Bit flags for cmdQ.status */ 20962306a36Sopenharmony_cienum { 21062306a36Sopenharmony_ci CMDQ_STAT_RUNNING = 1, /* fetch engine is running */ 21162306a36Sopenharmony_ci CMDQ_STAT_LAST_PKT_DB = 2 /* last packet rung the doorbell */ 21262306a36Sopenharmony_ci}; 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci/* T204 TX SW scheduler */ 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci/* Per T204 TX port */ 21762306a36Sopenharmony_cistruct sched_port { 21862306a36Sopenharmony_ci unsigned int avail; /* available bits - quota */ 21962306a36Sopenharmony_ci unsigned int drain_bits_per_1024ns; /* drain rate */ 22062306a36Sopenharmony_ci unsigned int speed; /* drain rate, mbps */ 22162306a36Sopenharmony_ci unsigned int mtu; /* mtu size */ 22262306a36Sopenharmony_ci struct sk_buff_head skbq; /* pending skbs */ 22362306a36Sopenharmony_ci}; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci/* Per T204 device */ 22662306a36Sopenharmony_cistruct sched { 22762306a36Sopenharmony_ci ktime_t last_updated; /* last time quotas were computed */ 22862306a36Sopenharmony_ci unsigned int max_avail; /* max bits to be sent to any port */ 22962306a36Sopenharmony_ci unsigned int port; /* port index (round robin ports) */ 23062306a36Sopenharmony_ci unsigned int num; /* num skbs in per port queues */ 23162306a36Sopenharmony_ci struct sched_port p[MAX_NPORTS]; 23262306a36Sopenharmony_ci struct tasklet_struct sched_tsk;/* tasklet used to run scheduler */ 23362306a36Sopenharmony_ci struct sge *sge; 23462306a36Sopenharmony_ci}; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_cistatic void restart_sched(struct tasklet_struct *t); 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci/* 24062306a36Sopenharmony_ci * Main SGE data structure 24162306a36Sopenharmony_ci * 24262306a36Sopenharmony_ci * Interrupts are handled by a single CPU and it is likely that on a MP system 24362306a36Sopenharmony_ci * the application is migrated to another CPU. In that scenario, we try to 24462306a36Sopenharmony_ci * separate the RX(in irq context) and TX state in order to decrease memory 24562306a36Sopenharmony_ci * contention. 24662306a36Sopenharmony_ci */ 24762306a36Sopenharmony_cistruct sge { 24862306a36Sopenharmony_ci struct adapter *adapter; /* adapter backpointer */ 24962306a36Sopenharmony_ci struct net_device *netdev; /* netdevice backpointer */ 25062306a36Sopenharmony_ci struct freelQ freelQ[SGE_FREELQ_N]; /* buffer free lists */ 25162306a36Sopenharmony_ci struct respQ respQ; /* response Q */ 25262306a36Sopenharmony_ci unsigned long stopped_tx_queues; /* bitmap of suspended Tx queues */ 25362306a36Sopenharmony_ci unsigned int rx_pkt_pad; /* RX padding for L2 packets */ 25462306a36Sopenharmony_ci unsigned int jumbo_fl; /* jumbo freelist Q index */ 25562306a36Sopenharmony_ci unsigned int intrtimer_nres; /* no-resource interrupt timer */ 25662306a36Sopenharmony_ci unsigned int fixed_intrtimer;/* non-adaptive interrupt timer */ 25762306a36Sopenharmony_ci struct timer_list tx_reclaim_timer; /* reclaims TX buffers */ 25862306a36Sopenharmony_ci struct timer_list espibug_timer; 25962306a36Sopenharmony_ci unsigned long espibug_timeout; 26062306a36Sopenharmony_ci struct sk_buff *espibug_skb[MAX_NPORTS]; 26162306a36Sopenharmony_ci u32 sge_control; /* shadow value of sge control reg */ 26262306a36Sopenharmony_ci struct sge_intr_counts stats; 26362306a36Sopenharmony_ci struct sge_port_stats __percpu *port_stats[MAX_NPORTS]; 26462306a36Sopenharmony_ci struct sched *tx_sched; 26562306a36Sopenharmony_ci struct cmdQ cmdQ[SGE_CMDQ_N] ____cacheline_aligned_in_smp; 26662306a36Sopenharmony_ci}; 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_cistatic const u8 ch_mac_addr[ETH_ALEN] = { 26962306a36Sopenharmony_ci 0x0, 0x7, 0x43, 0x0, 0x0, 0x0 27062306a36Sopenharmony_ci}; 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci/* 27362306a36Sopenharmony_ci * stop tasklet and free all pending skb's 27462306a36Sopenharmony_ci */ 27562306a36Sopenharmony_cistatic void tx_sched_stop(struct sge *sge) 27662306a36Sopenharmony_ci{ 27762306a36Sopenharmony_ci struct sched *s = sge->tx_sched; 27862306a36Sopenharmony_ci int i; 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci tasklet_kill(&s->sched_tsk); 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci for (i = 0; i < MAX_NPORTS; i++) 28362306a36Sopenharmony_ci __skb_queue_purge(&s->p[s->port].skbq); 28462306a36Sopenharmony_ci} 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci/* 28762306a36Sopenharmony_ci * t1_sched_update_parms() is called when the MTU or link speed changes. It 28862306a36Sopenharmony_ci * re-computes scheduler parameters to scope with the change. 28962306a36Sopenharmony_ci */ 29062306a36Sopenharmony_ciunsigned int t1_sched_update_parms(struct sge *sge, unsigned int port, 29162306a36Sopenharmony_ci unsigned int mtu, unsigned int speed) 29262306a36Sopenharmony_ci{ 29362306a36Sopenharmony_ci struct sched *s = sge->tx_sched; 29462306a36Sopenharmony_ci struct sched_port *p = &s->p[port]; 29562306a36Sopenharmony_ci unsigned int max_avail_segs; 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci pr_debug("%s mtu=%d speed=%d\n", __func__, mtu, speed); 29862306a36Sopenharmony_ci if (speed) 29962306a36Sopenharmony_ci p->speed = speed; 30062306a36Sopenharmony_ci if (mtu) 30162306a36Sopenharmony_ci p->mtu = mtu; 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci if (speed || mtu) { 30462306a36Sopenharmony_ci unsigned long long drain = 1024ULL * p->speed * (p->mtu - 40); 30562306a36Sopenharmony_ci do_div(drain, (p->mtu + 50) * 1000); 30662306a36Sopenharmony_ci p->drain_bits_per_1024ns = (unsigned int) drain; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci if (p->speed < 1000) 30962306a36Sopenharmony_ci p->drain_bits_per_1024ns = 31062306a36Sopenharmony_ci 90 * p->drain_bits_per_1024ns / 100; 31162306a36Sopenharmony_ci } 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci if (board_info(sge->adapter)->board == CHBT_BOARD_CHT204) { 31462306a36Sopenharmony_ci p->drain_bits_per_1024ns -= 16; 31562306a36Sopenharmony_ci s->max_avail = max(4096U, p->mtu + 16 + 14 + 4); 31662306a36Sopenharmony_ci max_avail_segs = max(1U, 4096 / (p->mtu - 40)); 31762306a36Sopenharmony_ci } else { 31862306a36Sopenharmony_ci s->max_avail = 16384; 31962306a36Sopenharmony_ci max_avail_segs = max(1U, 9000 / (p->mtu - 40)); 32062306a36Sopenharmony_ci } 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci pr_debug("t1_sched_update_parms: mtu %u speed %u max_avail %u " 32362306a36Sopenharmony_ci "max_avail_segs %u drain_bits_per_1024ns %u\n", p->mtu, 32462306a36Sopenharmony_ci p->speed, s->max_avail, max_avail_segs, 32562306a36Sopenharmony_ci p->drain_bits_per_1024ns); 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci return max_avail_segs * (p->mtu - 40); 32862306a36Sopenharmony_ci} 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci#if 0 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci/* 33362306a36Sopenharmony_ci * t1_sched_max_avail_bytes() tells the scheduler the maximum amount of 33462306a36Sopenharmony_ci * data that can be pushed per port. 33562306a36Sopenharmony_ci */ 33662306a36Sopenharmony_civoid t1_sched_set_max_avail_bytes(struct sge *sge, unsigned int val) 33762306a36Sopenharmony_ci{ 33862306a36Sopenharmony_ci struct sched *s = sge->tx_sched; 33962306a36Sopenharmony_ci unsigned int i; 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci s->max_avail = val; 34262306a36Sopenharmony_ci for (i = 0; i < MAX_NPORTS; i++) 34362306a36Sopenharmony_ci t1_sched_update_parms(sge, i, 0, 0); 34462306a36Sopenharmony_ci} 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci/* 34762306a36Sopenharmony_ci * t1_sched_set_drain_bits_per_us() tells the scheduler at which rate a port 34862306a36Sopenharmony_ci * is draining. 34962306a36Sopenharmony_ci */ 35062306a36Sopenharmony_civoid t1_sched_set_drain_bits_per_us(struct sge *sge, unsigned int port, 35162306a36Sopenharmony_ci unsigned int val) 35262306a36Sopenharmony_ci{ 35362306a36Sopenharmony_ci struct sched *s = sge->tx_sched; 35462306a36Sopenharmony_ci struct sched_port *p = &s->p[port]; 35562306a36Sopenharmony_ci p->drain_bits_per_1024ns = val * 1024 / 1000; 35662306a36Sopenharmony_ci t1_sched_update_parms(sge, port, 0, 0); 35762306a36Sopenharmony_ci} 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci#endif /* 0 */ 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci/* 36262306a36Sopenharmony_ci * tx_sched_init() allocates resources and does basic initialization. 36362306a36Sopenharmony_ci */ 36462306a36Sopenharmony_cistatic int tx_sched_init(struct sge *sge) 36562306a36Sopenharmony_ci{ 36662306a36Sopenharmony_ci struct sched *s; 36762306a36Sopenharmony_ci int i; 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci s = kzalloc(sizeof (struct sched), GFP_KERNEL); 37062306a36Sopenharmony_ci if (!s) 37162306a36Sopenharmony_ci return -ENOMEM; 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci pr_debug("tx_sched_init\n"); 37462306a36Sopenharmony_ci tasklet_setup(&s->sched_tsk, restart_sched); 37562306a36Sopenharmony_ci s->sge = sge; 37662306a36Sopenharmony_ci sge->tx_sched = s; 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci for (i = 0; i < MAX_NPORTS; i++) { 37962306a36Sopenharmony_ci skb_queue_head_init(&s->p[i].skbq); 38062306a36Sopenharmony_ci t1_sched_update_parms(sge, i, 1500, 1000); 38162306a36Sopenharmony_ci } 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci return 0; 38462306a36Sopenharmony_ci} 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci/* 38762306a36Sopenharmony_ci * sched_update_avail() computes the delta since the last time it was called 38862306a36Sopenharmony_ci * and updates the per port quota (number of bits that can be sent to the any 38962306a36Sopenharmony_ci * port). 39062306a36Sopenharmony_ci */ 39162306a36Sopenharmony_cistatic inline int sched_update_avail(struct sge *sge) 39262306a36Sopenharmony_ci{ 39362306a36Sopenharmony_ci struct sched *s = sge->tx_sched; 39462306a36Sopenharmony_ci ktime_t now = ktime_get(); 39562306a36Sopenharmony_ci unsigned int i; 39662306a36Sopenharmony_ci long long delta_time_ns; 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci delta_time_ns = ktime_to_ns(ktime_sub(now, s->last_updated)); 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci pr_debug("sched_update_avail delta=%lld\n", delta_time_ns); 40162306a36Sopenharmony_ci if (delta_time_ns < 15000) 40262306a36Sopenharmony_ci return 0; 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci for (i = 0; i < MAX_NPORTS; i++) { 40562306a36Sopenharmony_ci struct sched_port *p = &s->p[i]; 40662306a36Sopenharmony_ci unsigned int delta_avail; 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci delta_avail = (p->drain_bits_per_1024ns * delta_time_ns) >> 13; 40962306a36Sopenharmony_ci p->avail = min(p->avail + delta_avail, s->max_avail); 41062306a36Sopenharmony_ci } 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci s->last_updated = now; 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci return 1; 41562306a36Sopenharmony_ci} 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci/* 41862306a36Sopenharmony_ci * sched_skb() is called from two different places. In the tx path, any 41962306a36Sopenharmony_ci * packet generating load on an output port will call sched_skb() 42062306a36Sopenharmony_ci * (skb != NULL). In addition, sched_skb() is called from the irq/soft irq 42162306a36Sopenharmony_ci * context (skb == NULL). 42262306a36Sopenharmony_ci * The scheduler only returns a skb (which will then be sent) if the 42362306a36Sopenharmony_ci * length of the skb is <= the current quota of the output port. 42462306a36Sopenharmony_ci */ 42562306a36Sopenharmony_cistatic struct sk_buff *sched_skb(struct sge *sge, struct sk_buff *skb, 42662306a36Sopenharmony_ci unsigned int credits) 42762306a36Sopenharmony_ci{ 42862306a36Sopenharmony_ci struct sched *s = sge->tx_sched; 42962306a36Sopenharmony_ci struct sk_buff_head *skbq; 43062306a36Sopenharmony_ci unsigned int i, len, update = 1; 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci pr_debug("sched_skb %p\n", skb); 43362306a36Sopenharmony_ci if (!skb) { 43462306a36Sopenharmony_ci if (!s->num) 43562306a36Sopenharmony_ci return NULL; 43662306a36Sopenharmony_ci } else { 43762306a36Sopenharmony_ci skbq = &s->p[skb->dev->if_port].skbq; 43862306a36Sopenharmony_ci __skb_queue_tail(skbq, skb); 43962306a36Sopenharmony_ci s->num++; 44062306a36Sopenharmony_ci skb = NULL; 44162306a36Sopenharmony_ci } 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci if (credits < MAX_SKB_FRAGS + 1) 44462306a36Sopenharmony_ci goto out; 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ciagain: 44762306a36Sopenharmony_ci for (i = 0; i < MAX_NPORTS; i++) { 44862306a36Sopenharmony_ci s->port = (s->port + 1) & (MAX_NPORTS - 1); 44962306a36Sopenharmony_ci skbq = &s->p[s->port].skbq; 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci skb = skb_peek(skbq); 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci if (!skb) 45462306a36Sopenharmony_ci continue; 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci len = skb->len; 45762306a36Sopenharmony_ci if (len <= s->p[s->port].avail) { 45862306a36Sopenharmony_ci s->p[s->port].avail -= len; 45962306a36Sopenharmony_ci s->num--; 46062306a36Sopenharmony_ci __skb_unlink(skb, skbq); 46162306a36Sopenharmony_ci goto out; 46262306a36Sopenharmony_ci } 46362306a36Sopenharmony_ci skb = NULL; 46462306a36Sopenharmony_ci } 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci if (update-- && sched_update_avail(sge)) 46762306a36Sopenharmony_ci goto again; 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ciout: 47062306a36Sopenharmony_ci /* If there are more pending skbs, we use the hardware to schedule us 47162306a36Sopenharmony_ci * again. 47262306a36Sopenharmony_ci */ 47362306a36Sopenharmony_ci if (s->num && !skb) { 47462306a36Sopenharmony_ci struct cmdQ *q = &sge->cmdQ[0]; 47562306a36Sopenharmony_ci clear_bit(CMDQ_STAT_LAST_PKT_DB, &q->status); 47662306a36Sopenharmony_ci if (test_and_set_bit(CMDQ_STAT_RUNNING, &q->status) == 0) { 47762306a36Sopenharmony_ci set_bit(CMDQ_STAT_LAST_PKT_DB, &q->status); 47862306a36Sopenharmony_ci writel(F_CMDQ0_ENABLE, sge->adapter->regs + A_SG_DOORBELL); 47962306a36Sopenharmony_ci } 48062306a36Sopenharmony_ci } 48162306a36Sopenharmony_ci pr_debug("sched_skb ret %p\n", skb); 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci return skb; 48462306a36Sopenharmony_ci} 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci/* 48762306a36Sopenharmony_ci * PIO to indicate that memory mapped Q contains valid descriptor(s). 48862306a36Sopenharmony_ci */ 48962306a36Sopenharmony_cistatic inline void doorbell_pio(struct adapter *adapter, u32 val) 49062306a36Sopenharmony_ci{ 49162306a36Sopenharmony_ci wmb(); 49262306a36Sopenharmony_ci writel(val, adapter->regs + A_SG_DOORBELL); 49362306a36Sopenharmony_ci} 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci/* 49662306a36Sopenharmony_ci * Frees all RX buffers on the freelist Q. The caller must make sure that 49762306a36Sopenharmony_ci * the SGE is turned off before calling this function. 49862306a36Sopenharmony_ci */ 49962306a36Sopenharmony_cistatic void free_freelQ_buffers(struct pci_dev *pdev, struct freelQ *q) 50062306a36Sopenharmony_ci{ 50162306a36Sopenharmony_ci unsigned int cidx = q->cidx; 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci while (q->credits--) { 50462306a36Sopenharmony_ci struct freelQ_ce *ce = &q->centries[cidx]; 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci dma_unmap_single(&pdev->dev, dma_unmap_addr(ce, dma_addr), 50762306a36Sopenharmony_ci dma_unmap_len(ce, dma_len), DMA_FROM_DEVICE); 50862306a36Sopenharmony_ci dev_kfree_skb(ce->skb); 50962306a36Sopenharmony_ci ce->skb = NULL; 51062306a36Sopenharmony_ci if (++cidx == q->size) 51162306a36Sopenharmony_ci cidx = 0; 51262306a36Sopenharmony_ci } 51362306a36Sopenharmony_ci} 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci/* 51662306a36Sopenharmony_ci * Free RX free list and response queue resources. 51762306a36Sopenharmony_ci */ 51862306a36Sopenharmony_cistatic void free_rx_resources(struct sge *sge) 51962306a36Sopenharmony_ci{ 52062306a36Sopenharmony_ci struct pci_dev *pdev = sge->adapter->pdev; 52162306a36Sopenharmony_ci unsigned int size, i; 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci if (sge->respQ.entries) { 52462306a36Sopenharmony_ci size = sizeof(struct respQ_e) * sge->respQ.size; 52562306a36Sopenharmony_ci dma_free_coherent(&pdev->dev, size, sge->respQ.entries, 52662306a36Sopenharmony_ci sge->respQ.dma_addr); 52762306a36Sopenharmony_ci } 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci for (i = 0; i < SGE_FREELQ_N; i++) { 53062306a36Sopenharmony_ci struct freelQ *q = &sge->freelQ[i]; 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci if (q->centries) { 53362306a36Sopenharmony_ci free_freelQ_buffers(pdev, q); 53462306a36Sopenharmony_ci kfree(q->centries); 53562306a36Sopenharmony_ci } 53662306a36Sopenharmony_ci if (q->entries) { 53762306a36Sopenharmony_ci size = sizeof(struct freelQ_e) * q->size; 53862306a36Sopenharmony_ci dma_free_coherent(&pdev->dev, size, q->entries, 53962306a36Sopenharmony_ci q->dma_addr); 54062306a36Sopenharmony_ci } 54162306a36Sopenharmony_ci } 54262306a36Sopenharmony_ci} 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci/* 54562306a36Sopenharmony_ci * Allocates basic RX resources, consisting of memory mapped freelist Qs and a 54662306a36Sopenharmony_ci * response queue. 54762306a36Sopenharmony_ci */ 54862306a36Sopenharmony_cistatic int alloc_rx_resources(struct sge *sge, struct sge_params *p) 54962306a36Sopenharmony_ci{ 55062306a36Sopenharmony_ci struct pci_dev *pdev = sge->adapter->pdev; 55162306a36Sopenharmony_ci unsigned int size, i; 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci for (i = 0; i < SGE_FREELQ_N; i++) { 55462306a36Sopenharmony_ci struct freelQ *q = &sge->freelQ[i]; 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci q->genbit = 1; 55762306a36Sopenharmony_ci q->size = p->freelQ_size[i]; 55862306a36Sopenharmony_ci q->dma_offset = sge->rx_pkt_pad ? 0 : NET_IP_ALIGN; 55962306a36Sopenharmony_ci size = sizeof(struct freelQ_e) * q->size; 56062306a36Sopenharmony_ci q->entries = dma_alloc_coherent(&pdev->dev, size, 56162306a36Sopenharmony_ci &q->dma_addr, GFP_KERNEL); 56262306a36Sopenharmony_ci if (!q->entries) 56362306a36Sopenharmony_ci goto err_no_mem; 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci size = sizeof(struct freelQ_ce) * q->size; 56662306a36Sopenharmony_ci q->centries = kzalloc(size, GFP_KERNEL); 56762306a36Sopenharmony_ci if (!q->centries) 56862306a36Sopenharmony_ci goto err_no_mem; 56962306a36Sopenharmony_ci } 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci /* 57262306a36Sopenharmony_ci * Calculate the buffer sizes for the two free lists. FL0 accommodates 57362306a36Sopenharmony_ci * regular sized Ethernet frames, FL1 is sized not to exceed 16K, 57462306a36Sopenharmony_ci * including all the sk_buff overhead. 57562306a36Sopenharmony_ci * 57662306a36Sopenharmony_ci * Note: For T2 FL0 and FL1 are reversed. 57762306a36Sopenharmony_ci */ 57862306a36Sopenharmony_ci sge->freelQ[!sge->jumbo_fl].rx_buffer_size = SGE_RX_SM_BUF_SIZE + 57962306a36Sopenharmony_ci sizeof(struct cpl_rx_data) + 58062306a36Sopenharmony_ci sge->freelQ[!sge->jumbo_fl].dma_offset; 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci size = (16 * 1024) - SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci sge->freelQ[sge->jumbo_fl].rx_buffer_size = size; 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci /* 58762306a36Sopenharmony_ci * Setup which skb recycle Q should be used when recycling buffers from 58862306a36Sopenharmony_ci * each free list. 58962306a36Sopenharmony_ci */ 59062306a36Sopenharmony_ci sge->freelQ[!sge->jumbo_fl].recycleq_idx = 0; 59162306a36Sopenharmony_ci sge->freelQ[sge->jumbo_fl].recycleq_idx = 1; 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci sge->respQ.genbit = 1; 59462306a36Sopenharmony_ci sge->respQ.size = SGE_RESPQ_E_N; 59562306a36Sopenharmony_ci sge->respQ.credits = 0; 59662306a36Sopenharmony_ci size = sizeof(struct respQ_e) * sge->respQ.size; 59762306a36Sopenharmony_ci sge->respQ.entries = 59862306a36Sopenharmony_ci dma_alloc_coherent(&pdev->dev, size, &sge->respQ.dma_addr, 59962306a36Sopenharmony_ci GFP_KERNEL); 60062306a36Sopenharmony_ci if (!sge->respQ.entries) 60162306a36Sopenharmony_ci goto err_no_mem; 60262306a36Sopenharmony_ci return 0; 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_cierr_no_mem: 60562306a36Sopenharmony_ci free_rx_resources(sge); 60662306a36Sopenharmony_ci return -ENOMEM; 60762306a36Sopenharmony_ci} 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci/* 61062306a36Sopenharmony_ci * Reclaims n TX descriptors and frees the buffers associated with them. 61162306a36Sopenharmony_ci */ 61262306a36Sopenharmony_cistatic void free_cmdQ_buffers(struct sge *sge, struct cmdQ *q, unsigned int n) 61362306a36Sopenharmony_ci{ 61462306a36Sopenharmony_ci struct cmdQ_ce *ce; 61562306a36Sopenharmony_ci struct pci_dev *pdev = sge->adapter->pdev; 61662306a36Sopenharmony_ci unsigned int cidx = q->cidx; 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci q->in_use -= n; 61962306a36Sopenharmony_ci ce = &q->centries[cidx]; 62062306a36Sopenharmony_ci while (n--) { 62162306a36Sopenharmony_ci if (likely(dma_unmap_len(ce, dma_len))) { 62262306a36Sopenharmony_ci dma_unmap_single(&pdev->dev, 62362306a36Sopenharmony_ci dma_unmap_addr(ce, dma_addr), 62462306a36Sopenharmony_ci dma_unmap_len(ce, dma_len), 62562306a36Sopenharmony_ci DMA_TO_DEVICE); 62662306a36Sopenharmony_ci if (q->sop) 62762306a36Sopenharmony_ci q->sop = 0; 62862306a36Sopenharmony_ci } 62962306a36Sopenharmony_ci if (ce->skb) { 63062306a36Sopenharmony_ci dev_kfree_skb_any(ce->skb); 63162306a36Sopenharmony_ci q->sop = 1; 63262306a36Sopenharmony_ci } 63362306a36Sopenharmony_ci ce++; 63462306a36Sopenharmony_ci if (++cidx == q->size) { 63562306a36Sopenharmony_ci cidx = 0; 63662306a36Sopenharmony_ci ce = q->centries; 63762306a36Sopenharmony_ci } 63862306a36Sopenharmony_ci } 63962306a36Sopenharmony_ci q->cidx = cidx; 64062306a36Sopenharmony_ci} 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci/* 64362306a36Sopenharmony_ci * Free TX resources. 64462306a36Sopenharmony_ci * 64562306a36Sopenharmony_ci * Assumes that SGE is stopped and all interrupts are disabled. 64662306a36Sopenharmony_ci */ 64762306a36Sopenharmony_cistatic void free_tx_resources(struct sge *sge) 64862306a36Sopenharmony_ci{ 64962306a36Sopenharmony_ci struct pci_dev *pdev = sge->adapter->pdev; 65062306a36Sopenharmony_ci unsigned int size, i; 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci for (i = 0; i < SGE_CMDQ_N; i++) { 65362306a36Sopenharmony_ci struct cmdQ *q = &sge->cmdQ[i]; 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci if (q->centries) { 65662306a36Sopenharmony_ci if (q->in_use) 65762306a36Sopenharmony_ci free_cmdQ_buffers(sge, q, q->in_use); 65862306a36Sopenharmony_ci kfree(q->centries); 65962306a36Sopenharmony_ci } 66062306a36Sopenharmony_ci if (q->entries) { 66162306a36Sopenharmony_ci size = sizeof(struct cmdQ_e) * q->size; 66262306a36Sopenharmony_ci dma_free_coherent(&pdev->dev, size, q->entries, 66362306a36Sopenharmony_ci q->dma_addr); 66462306a36Sopenharmony_ci } 66562306a36Sopenharmony_ci } 66662306a36Sopenharmony_ci} 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci/* 66962306a36Sopenharmony_ci * Allocates basic TX resources, consisting of memory mapped command Qs. 67062306a36Sopenharmony_ci */ 67162306a36Sopenharmony_cistatic int alloc_tx_resources(struct sge *sge, struct sge_params *p) 67262306a36Sopenharmony_ci{ 67362306a36Sopenharmony_ci struct pci_dev *pdev = sge->adapter->pdev; 67462306a36Sopenharmony_ci unsigned int size, i; 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci for (i = 0; i < SGE_CMDQ_N; i++) { 67762306a36Sopenharmony_ci struct cmdQ *q = &sge->cmdQ[i]; 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci q->genbit = 1; 68062306a36Sopenharmony_ci q->sop = 1; 68162306a36Sopenharmony_ci q->size = p->cmdQ_size[i]; 68262306a36Sopenharmony_ci q->in_use = 0; 68362306a36Sopenharmony_ci q->status = 0; 68462306a36Sopenharmony_ci q->processed = q->cleaned = 0; 68562306a36Sopenharmony_ci q->stop_thres = 0; 68662306a36Sopenharmony_ci spin_lock_init(&q->lock); 68762306a36Sopenharmony_ci size = sizeof(struct cmdQ_e) * q->size; 68862306a36Sopenharmony_ci q->entries = dma_alloc_coherent(&pdev->dev, size, 68962306a36Sopenharmony_ci &q->dma_addr, GFP_KERNEL); 69062306a36Sopenharmony_ci if (!q->entries) 69162306a36Sopenharmony_ci goto err_no_mem; 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci size = sizeof(struct cmdQ_ce) * q->size; 69462306a36Sopenharmony_ci q->centries = kzalloc(size, GFP_KERNEL); 69562306a36Sopenharmony_ci if (!q->centries) 69662306a36Sopenharmony_ci goto err_no_mem; 69762306a36Sopenharmony_ci } 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci /* 70062306a36Sopenharmony_ci * CommandQ 0 handles Ethernet and TOE packets, while queue 1 is TOE 70162306a36Sopenharmony_ci * only. For queue 0 set the stop threshold so we can handle one more 70262306a36Sopenharmony_ci * packet from each port, plus reserve an additional 24 entries for 70362306a36Sopenharmony_ci * Ethernet packets only. Queue 1 never suspends nor do we reserve 70462306a36Sopenharmony_ci * space for Ethernet packets. 70562306a36Sopenharmony_ci */ 70662306a36Sopenharmony_ci sge->cmdQ[0].stop_thres = sge->adapter->params.nports * 70762306a36Sopenharmony_ci (MAX_SKB_FRAGS + 1); 70862306a36Sopenharmony_ci return 0; 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_cierr_no_mem: 71162306a36Sopenharmony_ci free_tx_resources(sge); 71262306a36Sopenharmony_ci return -ENOMEM; 71362306a36Sopenharmony_ci} 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_cistatic inline void setup_ring_params(struct adapter *adapter, u64 addr, 71662306a36Sopenharmony_ci u32 size, int base_reg_lo, 71762306a36Sopenharmony_ci int base_reg_hi, int size_reg) 71862306a36Sopenharmony_ci{ 71962306a36Sopenharmony_ci writel((u32)addr, adapter->regs + base_reg_lo); 72062306a36Sopenharmony_ci writel(addr >> 32, adapter->regs + base_reg_hi); 72162306a36Sopenharmony_ci writel(size, adapter->regs + size_reg); 72262306a36Sopenharmony_ci} 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci/* 72562306a36Sopenharmony_ci * Enable/disable VLAN acceleration. 72662306a36Sopenharmony_ci */ 72762306a36Sopenharmony_civoid t1_vlan_mode(struct adapter *adapter, netdev_features_t features) 72862306a36Sopenharmony_ci{ 72962306a36Sopenharmony_ci struct sge *sge = adapter->sge; 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci if (features & NETIF_F_HW_VLAN_CTAG_RX) 73262306a36Sopenharmony_ci sge->sge_control |= F_VLAN_XTRACT; 73362306a36Sopenharmony_ci else 73462306a36Sopenharmony_ci sge->sge_control &= ~F_VLAN_XTRACT; 73562306a36Sopenharmony_ci if (adapter->open_device_map) { 73662306a36Sopenharmony_ci writel(sge->sge_control, adapter->regs + A_SG_CONTROL); 73762306a36Sopenharmony_ci readl(adapter->regs + A_SG_CONTROL); /* flush */ 73862306a36Sopenharmony_ci } 73962306a36Sopenharmony_ci} 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci/* 74262306a36Sopenharmony_ci * Programs the various SGE registers. However, the engine is not yet enabled, 74362306a36Sopenharmony_ci * but sge->sge_control is setup and ready to go. 74462306a36Sopenharmony_ci */ 74562306a36Sopenharmony_cistatic void configure_sge(struct sge *sge, struct sge_params *p) 74662306a36Sopenharmony_ci{ 74762306a36Sopenharmony_ci struct adapter *ap = sge->adapter; 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci writel(0, ap->regs + A_SG_CONTROL); 75062306a36Sopenharmony_ci setup_ring_params(ap, sge->cmdQ[0].dma_addr, sge->cmdQ[0].size, 75162306a36Sopenharmony_ci A_SG_CMD0BASELWR, A_SG_CMD0BASEUPR, A_SG_CMD0SIZE); 75262306a36Sopenharmony_ci setup_ring_params(ap, sge->cmdQ[1].dma_addr, sge->cmdQ[1].size, 75362306a36Sopenharmony_ci A_SG_CMD1BASELWR, A_SG_CMD1BASEUPR, A_SG_CMD1SIZE); 75462306a36Sopenharmony_ci setup_ring_params(ap, sge->freelQ[0].dma_addr, 75562306a36Sopenharmony_ci sge->freelQ[0].size, A_SG_FL0BASELWR, 75662306a36Sopenharmony_ci A_SG_FL0BASEUPR, A_SG_FL0SIZE); 75762306a36Sopenharmony_ci setup_ring_params(ap, sge->freelQ[1].dma_addr, 75862306a36Sopenharmony_ci sge->freelQ[1].size, A_SG_FL1BASELWR, 75962306a36Sopenharmony_ci A_SG_FL1BASEUPR, A_SG_FL1SIZE); 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci /* The threshold comparison uses <. */ 76262306a36Sopenharmony_ci writel(SGE_RX_SM_BUF_SIZE + 1, ap->regs + A_SG_FLTHRESHOLD); 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci setup_ring_params(ap, sge->respQ.dma_addr, sge->respQ.size, 76562306a36Sopenharmony_ci A_SG_RSPBASELWR, A_SG_RSPBASEUPR, A_SG_RSPSIZE); 76662306a36Sopenharmony_ci writel((u32)sge->respQ.size - 1, ap->regs + A_SG_RSPQUEUECREDIT); 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci sge->sge_control = F_CMDQ0_ENABLE | F_CMDQ1_ENABLE | F_FL0_ENABLE | 76962306a36Sopenharmony_ci F_FL1_ENABLE | F_CPL_ENABLE | F_RESPONSE_QUEUE_ENABLE | 77062306a36Sopenharmony_ci V_CMDQ_PRIORITY(2) | F_DISABLE_CMDQ1_GTS | F_ISCSI_COALESCE | 77162306a36Sopenharmony_ci V_RX_PKT_OFFSET(sge->rx_pkt_pad); 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci#if defined(__BIG_ENDIAN_BITFIELD) 77462306a36Sopenharmony_ci sge->sge_control |= F_ENABLE_BIG_ENDIAN; 77562306a36Sopenharmony_ci#endif 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci /* Initialize no-resource timer */ 77862306a36Sopenharmony_ci sge->intrtimer_nres = SGE_INTRTIMER_NRES * core_ticks_per_usec(ap); 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci t1_sge_set_coalesce_params(sge, p); 78162306a36Sopenharmony_ci} 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci/* 78462306a36Sopenharmony_ci * Return the payload capacity of the jumbo free-list buffers. 78562306a36Sopenharmony_ci */ 78662306a36Sopenharmony_cistatic inline unsigned int jumbo_payload_capacity(const struct sge *sge) 78762306a36Sopenharmony_ci{ 78862306a36Sopenharmony_ci return sge->freelQ[sge->jumbo_fl].rx_buffer_size - 78962306a36Sopenharmony_ci sge->freelQ[sge->jumbo_fl].dma_offset - 79062306a36Sopenharmony_ci sizeof(struct cpl_rx_data); 79162306a36Sopenharmony_ci} 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci/* 79462306a36Sopenharmony_ci * Frees all SGE related resources and the sge structure itself 79562306a36Sopenharmony_ci */ 79662306a36Sopenharmony_civoid t1_sge_destroy(struct sge *sge) 79762306a36Sopenharmony_ci{ 79862306a36Sopenharmony_ci int i; 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci for_each_port(sge->adapter, i) 80162306a36Sopenharmony_ci free_percpu(sge->port_stats[i]); 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci kfree(sge->tx_sched); 80462306a36Sopenharmony_ci free_tx_resources(sge); 80562306a36Sopenharmony_ci free_rx_resources(sge); 80662306a36Sopenharmony_ci kfree(sge); 80762306a36Sopenharmony_ci} 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci/* 81062306a36Sopenharmony_ci * Allocates new RX buffers on the freelist Q (and tracks them on the freelist 81162306a36Sopenharmony_ci * context Q) until the Q is full or alloc_skb fails. 81262306a36Sopenharmony_ci * 81362306a36Sopenharmony_ci * It is possible that the generation bits already match, indicating that the 81462306a36Sopenharmony_ci * buffer is already valid and nothing needs to be done. This happens when we 81562306a36Sopenharmony_ci * copied a received buffer into a new sk_buff during the interrupt processing. 81662306a36Sopenharmony_ci * 81762306a36Sopenharmony_ci * If the SGE doesn't automatically align packets properly (!sge->rx_pkt_pad), 81862306a36Sopenharmony_ci * we specify a RX_OFFSET in order to make sure that the IP header is 4B 81962306a36Sopenharmony_ci * aligned. 82062306a36Sopenharmony_ci */ 82162306a36Sopenharmony_cistatic void refill_free_list(struct sge *sge, struct freelQ *q) 82262306a36Sopenharmony_ci{ 82362306a36Sopenharmony_ci struct pci_dev *pdev = sge->adapter->pdev; 82462306a36Sopenharmony_ci struct freelQ_ce *ce = &q->centries[q->pidx]; 82562306a36Sopenharmony_ci struct freelQ_e *e = &q->entries[q->pidx]; 82662306a36Sopenharmony_ci unsigned int dma_len = q->rx_buffer_size - q->dma_offset; 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ci while (q->credits < q->size) { 82962306a36Sopenharmony_ci struct sk_buff *skb; 83062306a36Sopenharmony_ci dma_addr_t mapping; 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci skb = dev_alloc_skb(q->rx_buffer_size); 83362306a36Sopenharmony_ci if (!skb) 83462306a36Sopenharmony_ci break; 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci skb_reserve(skb, q->dma_offset); 83762306a36Sopenharmony_ci mapping = dma_map_single(&pdev->dev, skb->data, dma_len, 83862306a36Sopenharmony_ci DMA_FROM_DEVICE); 83962306a36Sopenharmony_ci skb_reserve(skb, sge->rx_pkt_pad); 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_ci ce->skb = skb; 84262306a36Sopenharmony_ci dma_unmap_addr_set(ce, dma_addr, mapping); 84362306a36Sopenharmony_ci dma_unmap_len_set(ce, dma_len, dma_len); 84462306a36Sopenharmony_ci e->addr_lo = (u32)mapping; 84562306a36Sopenharmony_ci e->addr_hi = (u64)mapping >> 32; 84662306a36Sopenharmony_ci e->len_gen = V_CMD_LEN(dma_len) | V_CMD_GEN1(q->genbit); 84762306a36Sopenharmony_ci wmb(); 84862306a36Sopenharmony_ci e->gen2 = V_CMD_GEN2(q->genbit); 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci e++; 85162306a36Sopenharmony_ci ce++; 85262306a36Sopenharmony_ci if (++q->pidx == q->size) { 85362306a36Sopenharmony_ci q->pidx = 0; 85462306a36Sopenharmony_ci q->genbit ^= 1; 85562306a36Sopenharmony_ci ce = q->centries; 85662306a36Sopenharmony_ci e = q->entries; 85762306a36Sopenharmony_ci } 85862306a36Sopenharmony_ci q->credits++; 85962306a36Sopenharmony_ci } 86062306a36Sopenharmony_ci} 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci/* 86362306a36Sopenharmony_ci * Calls refill_free_list for both free lists. If we cannot fill at least 1/4 86462306a36Sopenharmony_ci * of both rings, we go into 'few interrupt mode' in order to give the system 86562306a36Sopenharmony_ci * time to free up resources. 86662306a36Sopenharmony_ci */ 86762306a36Sopenharmony_cistatic void freelQs_empty(struct sge *sge) 86862306a36Sopenharmony_ci{ 86962306a36Sopenharmony_ci struct adapter *adapter = sge->adapter; 87062306a36Sopenharmony_ci u32 irq_reg = readl(adapter->regs + A_SG_INT_ENABLE); 87162306a36Sopenharmony_ci u32 irqholdoff_reg; 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci refill_free_list(sge, &sge->freelQ[0]); 87462306a36Sopenharmony_ci refill_free_list(sge, &sge->freelQ[1]); 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci if (sge->freelQ[0].credits > (sge->freelQ[0].size >> 2) && 87762306a36Sopenharmony_ci sge->freelQ[1].credits > (sge->freelQ[1].size >> 2)) { 87862306a36Sopenharmony_ci irq_reg |= F_FL_EXHAUSTED; 87962306a36Sopenharmony_ci irqholdoff_reg = sge->fixed_intrtimer; 88062306a36Sopenharmony_ci } else { 88162306a36Sopenharmony_ci /* Clear the F_FL_EXHAUSTED interrupts for now */ 88262306a36Sopenharmony_ci irq_reg &= ~F_FL_EXHAUSTED; 88362306a36Sopenharmony_ci irqholdoff_reg = sge->intrtimer_nres; 88462306a36Sopenharmony_ci } 88562306a36Sopenharmony_ci writel(irqholdoff_reg, adapter->regs + A_SG_INTRTIMER); 88662306a36Sopenharmony_ci writel(irq_reg, adapter->regs + A_SG_INT_ENABLE); 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_ci /* We reenable the Qs to force a freelist GTS interrupt later */ 88962306a36Sopenharmony_ci doorbell_pio(adapter, F_FL0_ENABLE | F_FL1_ENABLE); 89062306a36Sopenharmony_ci} 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ci#define SGE_PL_INTR_MASK (F_PL_INTR_SGE_ERR | F_PL_INTR_SGE_DATA) 89362306a36Sopenharmony_ci#define SGE_INT_FATAL (F_RESPQ_OVERFLOW | F_PACKET_TOO_BIG | F_PACKET_MISMATCH) 89462306a36Sopenharmony_ci#define SGE_INT_ENABLE (F_RESPQ_EXHAUSTED | F_RESPQ_OVERFLOW | \ 89562306a36Sopenharmony_ci F_FL_EXHAUSTED | F_PACKET_TOO_BIG | F_PACKET_MISMATCH) 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci/* 89862306a36Sopenharmony_ci * Disable SGE Interrupts 89962306a36Sopenharmony_ci */ 90062306a36Sopenharmony_civoid t1_sge_intr_disable(struct sge *sge) 90162306a36Sopenharmony_ci{ 90262306a36Sopenharmony_ci u32 val = readl(sge->adapter->regs + A_PL_ENABLE); 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci writel(val & ~SGE_PL_INTR_MASK, sge->adapter->regs + A_PL_ENABLE); 90562306a36Sopenharmony_ci writel(0, sge->adapter->regs + A_SG_INT_ENABLE); 90662306a36Sopenharmony_ci} 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_ci/* 90962306a36Sopenharmony_ci * Enable SGE interrupts. 91062306a36Sopenharmony_ci */ 91162306a36Sopenharmony_civoid t1_sge_intr_enable(struct sge *sge) 91262306a36Sopenharmony_ci{ 91362306a36Sopenharmony_ci u32 en = SGE_INT_ENABLE; 91462306a36Sopenharmony_ci u32 val = readl(sge->adapter->regs + A_PL_ENABLE); 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci if (sge->adapter->port[0].dev->hw_features & NETIF_F_TSO) 91762306a36Sopenharmony_ci en &= ~F_PACKET_TOO_BIG; 91862306a36Sopenharmony_ci writel(en, sge->adapter->regs + A_SG_INT_ENABLE); 91962306a36Sopenharmony_ci writel(val | SGE_PL_INTR_MASK, sge->adapter->regs + A_PL_ENABLE); 92062306a36Sopenharmony_ci} 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci/* 92362306a36Sopenharmony_ci * Clear SGE interrupts. 92462306a36Sopenharmony_ci */ 92562306a36Sopenharmony_civoid t1_sge_intr_clear(struct sge *sge) 92662306a36Sopenharmony_ci{ 92762306a36Sopenharmony_ci writel(SGE_PL_INTR_MASK, sge->adapter->regs + A_PL_CAUSE); 92862306a36Sopenharmony_ci writel(0xffffffff, sge->adapter->regs + A_SG_INT_CAUSE); 92962306a36Sopenharmony_ci} 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_ci/* 93262306a36Sopenharmony_ci * SGE 'Error' interrupt handler 93362306a36Sopenharmony_ci */ 93462306a36Sopenharmony_cibool t1_sge_intr_error_handler(struct sge *sge) 93562306a36Sopenharmony_ci{ 93662306a36Sopenharmony_ci struct adapter *adapter = sge->adapter; 93762306a36Sopenharmony_ci u32 cause = readl(adapter->regs + A_SG_INT_CAUSE); 93862306a36Sopenharmony_ci bool wake = false; 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_ci if (adapter->port[0].dev->hw_features & NETIF_F_TSO) 94162306a36Sopenharmony_ci cause &= ~F_PACKET_TOO_BIG; 94262306a36Sopenharmony_ci if (cause & F_RESPQ_EXHAUSTED) 94362306a36Sopenharmony_ci sge->stats.respQ_empty++; 94462306a36Sopenharmony_ci if (cause & F_RESPQ_OVERFLOW) { 94562306a36Sopenharmony_ci sge->stats.respQ_overflow++; 94662306a36Sopenharmony_ci pr_alert("%s: SGE response queue overflow\n", 94762306a36Sopenharmony_ci adapter->name); 94862306a36Sopenharmony_ci } 94962306a36Sopenharmony_ci if (cause & F_FL_EXHAUSTED) { 95062306a36Sopenharmony_ci sge->stats.freelistQ_empty++; 95162306a36Sopenharmony_ci freelQs_empty(sge); 95262306a36Sopenharmony_ci } 95362306a36Sopenharmony_ci if (cause & F_PACKET_TOO_BIG) { 95462306a36Sopenharmony_ci sge->stats.pkt_too_big++; 95562306a36Sopenharmony_ci pr_alert("%s: SGE max packet size exceeded\n", 95662306a36Sopenharmony_ci adapter->name); 95762306a36Sopenharmony_ci } 95862306a36Sopenharmony_ci if (cause & F_PACKET_MISMATCH) { 95962306a36Sopenharmony_ci sge->stats.pkt_mismatch++; 96062306a36Sopenharmony_ci pr_alert("%s: SGE packet mismatch\n", adapter->name); 96162306a36Sopenharmony_ci } 96262306a36Sopenharmony_ci if (cause & SGE_INT_FATAL) { 96362306a36Sopenharmony_ci t1_interrupts_disable(adapter); 96462306a36Sopenharmony_ci adapter->pending_thread_intr |= F_PL_INTR_SGE_ERR; 96562306a36Sopenharmony_ci wake = true; 96662306a36Sopenharmony_ci } 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci writel(cause, adapter->regs + A_SG_INT_CAUSE); 96962306a36Sopenharmony_ci return wake; 97062306a36Sopenharmony_ci} 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_ciconst struct sge_intr_counts *t1_sge_get_intr_counts(const struct sge *sge) 97362306a36Sopenharmony_ci{ 97462306a36Sopenharmony_ci return &sge->stats; 97562306a36Sopenharmony_ci} 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_civoid t1_sge_get_port_stats(const struct sge *sge, int port, 97862306a36Sopenharmony_ci struct sge_port_stats *ss) 97962306a36Sopenharmony_ci{ 98062306a36Sopenharmony_ci int cpu; 98162306a36Sopenharmony_ci 98262306a36Sopenharmony_ci memset(ss, 0, sizeof(*ss)); 98362306a36Sopenharmony_ci for_each_possible_cpu(cpu) { 98462306a36Sopenharmony_ci struct sge_port_stats *st = per_cpu_ptr(sge->port_stats[port], cpu); 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_ci ss->rx_cso_good += st->rx_cso_good; 98762306a36Sopenharmony_ci ss->tx_cso += st->tx_cso; 98862306a36Sopenharmony_ci ss->tx_tso += st->tx_tso; 98962306a36Sopenharmony_ci ss->tx_need_hdrroom += st->tx_need_hdrroom; 99062306a36Sopenharmony_ci ss->vlan_xtract += st->vlan_xtract; 99162306a36Sopenharmony_ci ss->vlan_insert += st->vlan_insert; 99262306a36Sopenharmony_ci } 99362306a36Sopenharmony_ci} 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_ci/** 99662306a36Sopenharmony_ci * recycle_fl_buf - recycle a free list buffer 99762306a36Sopenharmony_ci * @fl: the free list 99862306a36Sopenharmony_ci * @idx: index of buffer to recycle 99962306a36Sopenharmony_ci * 100062306a36Sopenharmony_ci * Recycles the specified buffer on the given free list by adding it at 100162306a36Sopenharmony_ci * the next available slot on the list. 100262306a36Sopenharmony_ci */ 100362306a36Sopenharmony_cistatic void recycle_fl_buf(struct freelQ *fl, int idx) 100462306a36Sopenharmony_ci{ 100562306a36Sopenharmony_ci struct freelQ_e *from = &fl->entries[idx]; 100662306a36Sopenharmony_ci struct freelQ_e *to = &fl->entries[fl->pidx]; 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_ci fl->centries[fl->pidx] = fl->centries[idx]; 100962306a36Sopenharmony_ci to->addr_lo = from->addr_lo; 101062306a36Sopenharmony_ci to->addr_hi = from->addr_hi; 101162306a36Sopenharmony_ci to->len_gen = G_CMD_LEN(from->len_gen) | V_CMD_GEN1(fl->genbit); 101262306a36Sopenharmony_ci wmb(); 101362306a36Sopenharmony_ci to->gen2 = V_CMD_GEN2(fl->genbit); 101462306a36Sopenharmony_ci fl->credits++; 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_ci if (++fl->pidx == fl->size) { 101762306a36Sopenharmony_ci fl->pidx = 0; 101862306a36Sopenharmony_ci fl->genbit ^= 1; 101962306a36Sopenharmony_ci } 102062306a36Sopenharmony_ci} 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_cistatic int copybreak __read_mostly = 256; 102362306a36Sopenharmony_cimodule_param(copybreak, int, 0); 102462306a36Sopenharmony_ciMODULE_PARM_DESC(copybreak, "Receive copy threshold"); 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_ci/** 102762306a36Sopenharmony_ci * get_packet - return the next ingress packet buffer 102862306a36Sopenharmony_ci * @adapter: the adapter that received the packet 102962306a36Sopenharmony_ci * @fl: the SGE free list holding the packet 103062306a36Sopenharmony_ci * @len: the actual packet length, excluding any SGE padding 103162306a36Sopenharmony_ci * 103262306a36Sopenharmony_ci * Get the next packet from a free list and complete setup of the 103362306a36Sopenharmony_ci * sk_buff. If the packet is small we make a copy and recycle the 103462306a36Sopenharmony_ci * original buffer, otherwise we use the original buffer itself. If a 103562306a36Sopenharmony_ci * positive drop threshold is supplied packets are dropped and their 103662306a36Sopenharmony_ci * buffers recycled if (a) the number of remaining buffers is under the 103762306a36Sopenharmony_ci * threshold and the packet is too big to copy, or (b) the packet should 103862306a36Sopenharmony_ci * be copied but there is no memory for the copy. 103962306a36Sopenharmony_ci */ 104062306a36Sopenharmony_cistatic inline struct sk_buff *get_packet(struct adapter *adapter, 104162306a36Sopenharmony_ci struct freelQ *fl, unsigned int len) 104262306a36Sopenharmony_ci{ 104362306a36Sopenharmony_ci const struct freelQ_ce *ce = &fl->centries[fl->cidx]; 104462306a36Sopenharmony_ci struct pci_dev *pdev = adapter->pdev; 104562306a36Sopenharmony_ci struct sk_buff *skb; 104662306a36Sopenharmony_ci 104762306a36Sopenharmony_ci if (len < copybreak) { 104862306a36Sopenharmony_ci skb = napi_alloc_skb(&adapter->napi, len); 104962306a36Sopenharmony_ci if (!skb) 105062306a36Sopenharmony_ci goto use_orig_buf; 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_ci skb_put(skb, len); 105362306a36Sopenharmony_ci dma_sync_single_for_cpu(&pdev->dev, 105462306a36Sopenharmony_ci dma_unmap_addr(ce, dma_addr), 105562306a36Sopenharmony_ci dma_unmap_len(ce, dma_len), 105662306a36Sopenharmony_ci DMA_FROM_DEVICE); 105762306a36Sopenharmony_ci skb_copy_from_linear_data(ce->skb, skb->data, len); 105862306a36Sopenharmony_ci dma_sync_single_for_device(&pdev->dev, 105962306a36Sopenharmony_ci dma_unmap_addr(ce, dma_addr), 106062306a36Sopenharmony_ci dma_unmap_len(ce, dma_len), 106162306a36Sopenharmony_ci DMA_FROM_DEVICE); 106262306a36Sopenharmony_ci recycle_fl_buf(fl, fl->cidx); 106362306a36Sopenharmony_ci return skb; 106462306a36Sopenharmony_ci } 106562306a36Sopenharmony_ci 106662306a36Sopenharmony_ciuse_orig_buf: 106762306a36Sopenharmony_ci if (fl->credits < 2) { 106862306a36Sopenharmony_ci recycle_fl_buf(fl, fl->cidx); 106962306a36Sopenharmony_ci return NULL; 107062306a36Sopenharmony_ci } 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_ci dma_unmap_single(&pdev->dev, dma_unmap_addr(ce, dma_addr), 107362306a36Sopenharmony_ci dma_unmap_len(ce, dma_len), DMA_FROM_DEVICE); 107462306a36Sopenharmony_ci skb = ce->skb; 107562306a36Sopenharmony_ci prefetch(skb->data); 107662306a36Sopenharmony_ci 107762306a36Sopenharmony_ci skb_put(skb, len); 107862306a36Sopenharmony_ci return skb; 107962306a36Sopenharmony_ci} 108062306a36Sopenharmony_ci 108162306a36Sopenharmony_ci/** 108262306a36Sopenharmony_ci * unexpected_offload - handle an unexpected offload packet 108362306a36Sopenharmony_ci * @adapter: the adapter 108462306a36Sopenharmony_ci * @fl: the free list that received the packet 108562306a36Sopenharmony_ci * 108662306a36Sopenharmony_ci * Called when we receive an unexpected offload packet (e.g., the TOE 108762306a36Sopenharmony_ci * function is disabled or the card is a NIC). Prints a message and 108862306a36Sopenharmony_ci * recycles the buffer. 108962306a36Sopenharmony_ci */ 109062306a36Sopenharmony_cistatic void unexpected_offload(struct adapter *adapter, struct freelQ *fl) 109162306a36Sopenharmony_ci{ 109262306a36Sopenharmony_ci struct freelQ_ce *ce = &fl->centries[fl->cidx]; 109362306a36Sopenharmony_ci struct sk_buff *skb = ce->skb; 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_ci dma_sync_single_for_cpu(&adapter->pdev->dev, 109662306a36Sopenharmony_ci dma_unmap_addr(ce, dma_addr), 109762306a36Sopenharmony_ci dma_unmap_len(ce, dma_len), DMA_FROM_DEVICE); 109862306a36Sopenharmony_ci pr_err("%s: unexpected offload packet, cmd %u\n", 109962306a36Sopenharmony_ci adapter->name, *skb->data); 110062306a36Sopenharmony_ci recycle_fl_buf(fl, fl->cidx); 110162306a36Sopenharmony_ci} 110262306a36Sopenharmony_ci 110362306a36Sopenharmony_ci/* 110462306a36Sopenharmony_ci * T1/T2 SGE limits the maximum DMA size per TX descriptor to 110562306a36Sopenharmony_ci * SGE_TX_DESC_MAX_PLEN (16KB). If the PAGE_SIZE is larger than 16KB, the 110662306a36Sopenharmony_ci * stack might send more than SGE_TX_DESC_MAX_PLEN in a contiguous manner. 110762306a36Sopenharmony_ci * Note that the *_large_page_tx_descs stuff will be optimized out when 110862306a36Sopenharmony_ci * PAGE_SIZE <= SGE_TX_DESC_MAX_PLEN. 110962306a36Sopenharmony_ci * 111062306a36Sopenharmony_ci * compute_large_page_descs() computes how many additional descriptors are 111162306a36Sopenharmony_ci * required to break down the stack's request. 111262306a36Sopenharmony_ci */ 111362306a36Sopenharmony_cistatic inline unsigned int compute_large_page_tx_descs(struct sk_buff *skb) 111462306a36Sopenharmony_ci{ 111562306a36Sopenharmony_ci unsigned int count = 0; 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_ci if (PAGE_SIZE > SGE_TX_DESC_MAX_PLEN) { 111862306a36Sopenharmony_ci unsigned int nfrags = skb_shinfo(skb)->nr_frags; 111962306a36Sopenharmony_ci unsigned int i, len = skb_headlen(skb); 112062306a36Sopenharmony_ci while (len > SGE_TX_DESC_MAX_PLEN) { 112162306a36Sopenharmony_ci count++; 112262306a36Sopenharmony_ci len -= SGE_TX_DESC_MAX_PLEN; 112362306a36Sopenharmony_ci } 112462306a36Sopenharmony_ci for (i = 0; nfrags--; i++) { 112562306a36Sopenharmony_ci const skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; 112662306a36Sopenharmony_ci len = skb_frag_size(frag); 112762306a36Sopenharmony_ci while (len > SGE_TX_DESC_MAX_PLEN) { 112862306a36Sopenharmony_ci count++; 112962306a36Sopenharmony_ci len -= SGE_TX_DESC_MAX_PLEN; 113062306a36Sopenharmony_ci } 113162306a36Sopenharmony_ci } 113262306a36Sopenharmony_ci } 113362306a36Sopenharmony_ci return count; 113462306a36Sopenharmony_ci} 113562306a36Sopenharmony_ci 113662306a36Sopenharmony_ci/* 113762306a36Sopenharmony_ci * Write a cmdQ entry. 113862306a36Sopenharmony_ci * 113962306a36Sopenharmony_ci * Since this function writes the 'flags' field, it must not be used to 114062306a36Sopenharmony_ci * write the first cmdQ entry. 114162306a36Sopenharmony_ci */ 114262306a36Sopenharmony_cistatic inline void write_tx_desc(struct cmdQ_e *e, dma_addr_t mapping, 114362306a36Sopenharmony_ci unsigned int len, unsigned int gen, 114462306a36Sopenharmony_ci unsigned int eop) 114562306a36Sopenharmony_ci{ 114662306a36Sopenharmony_ci BUG_ON(len > SGE_TX_DESC_MAX_PLEN); 114762306a36Sopenharmony_ci 114862306a36Sopenharmony_ci e->addr_lo = (u32)mapping; 114962306a36Sopenharmony_ci e->addr_hi = (u64)mapping >> 32; 115062306a36Sopenharmony_ci e->len_gen = V_CMD_LEN(len) | V_CMD_GEN1(gen); 115162306a36Sopenharmony_ci e->flags = F_CMD_DATAVALID | V_CMD_EOP(eop) | V_CMD_GEN2(gen); 115262306a36Sopenharmony_ci} 115362306a36Sopenharmony_ci 115462306a36Sopenharmony_ci/* 115562306a36Sopenharmony_ci * See comment for previous function. 115662306a36Sopenharmony_ci * 115762306a36Sopenharmony_ci * write_tx_descs_large_page() writes additional SGE tx descriptors if 115862306a36Sopenharmony_ci * *desc_len exceeds HW's capability. 115962306a36Sopenharmony_ci */ 116062306a36Sopenharmony_cistatic inline unsigned int write_large_page_tx_descs(unsigned int pidx, 116162306a36Sopenharmony_ci struct cmdQ_e **e, 116262306a36Sopenharmony_ci struct cmdQ_ce **ce, 116362306a36Sopenharmony_ci unsigned int *gen, 116462306a36Sopenharmony_ci dma_addr_t *desc_mapping, 116562306a36Sopenharmony_ci unsigned int *desc_len, 116662306a36Sopenharmony_ci unsigned int nfrags, 116762306a36Sopenharmony_ci struct cmdQ *q) 116862306a36Sopenharmony_ci{ 116962306a36Sopenharmony_ci if (PAGE_SIZE > SGE_TX_DESC_MAX_PLEN) { 117062306a36Sopenharmony_ci struct cmdQ_e *e1 = *e; 117162306a36Sopenharmony_ci struct cmdQ_ce *ce1 = *ce; 117262306a36Sopenharmony_ci 117362306a36Sopenharmony_ci while (*desc_len > SGE_TX_DESC_MAX_PLEN) { 117462306a36Sopenharmony_ci *desc_len -= SGE_TX_DESC_MAX_PLEN; 117562306a36Sopenharmony_ci write_tx_desc(e1, *desc_mapping, SGE_TX_DESC_MAX_PLEN, 117662306a36Sopenharmony_ci *gen, nfrags == 0 && *desc_len == 0); 117762306a36Sopenharmony_ci ce1->skb = NULL; 117862306a36Sopenharmony_ci dma_unmap_len_set(ce1, dma_len, 0); 117962306a36Sopenharmony_ci *desc_mapping += SGE_TX_DESC_MAX_PLEN; 118062306a36Sopenharmony_ci if (*desc_len) { 118162306a36Sopenharmony_ci ce1++; 118262306a36Sopenharmony_ci e1++; 118362306a36Sopenharmony_ci if (++pidx == q->size) { 118462306a36Sopenharmony_ci pidx = 0; 118562306a36Sopenharmony_ci *gen ^= 1; 118662306a36Sopenharmony_ci ce1 = q->centries; 118762306a36Sopenharmony_ci e1 = q->entries; 118862306a36Sopenharmony_ci } 118962306a36Sopenharmony_ci } 119062306a36Sopenharmony_ci } 119162306a36Sopenharmony_ci *e = e1; 119262306a36Sopenharmony_ci *ce = ce1; 119362306a36Sopenharmony_ci } 119462306a36Sopenharmony_ci return pidx; 119562306a36Sopenharmony_ci} 119662306a36Sopenharmony_ci 119762306a36Sopenharmony_ci/* 119862306a36Sopenharmony_ci * Write the command descriptors to transmit the given skb starting at 119962306a36Sopenharmony_ci * descriptor pidx with the given generation. 120062306a36Sopenharmony_ci */ 120162306a36Sopenharmony_cistatic inline void write_tx_descs(struct adapter *adapter, struct sk_buff *skb, 120262306a36Sopenharmony_ci unsigned int pidx, unsigned int gen, 120362306a36Sopenharmony_ci struct cmdQ *q) 120462306a36Sopenharmony_ci{ 120562306a36Sopenharmony_ci dma_addr_t mapping, desc_mapping; 120662306a36Sopenharmony_ci struct cmdQ_e *e, *e1; 120762306a36Sopenharmony_ci struct cmdQ_ce *ce; 120862306a36Sopenharmony_ci unsigned int i, flags, first_desc_len, desc_len, 120962306a36Sopenharmony_ci nfrags = skb_shinfo(skb)->nr_frags; 121062306a36Sopenharmony_ci 121162306a36Sopenharmony_ci e = e1 = &q->entries[pidx]; 121262306a36Sopenharmony_ci ce = &q->centries[pidx]; 121362306a36Sopenharmony_ci 121462306a36Sopenharmony_ci mapping = dma_map_single(&adapter->pdev->dev, skb->data, 121562306a36Sopenharmony_ci skb_headlen(skb), DMA_TO_DEVICE); 121662306a36Sopenharmony_ci 121762306a36Sopenharmony_ci desc_mapping = mapping; 121862306a36Sopenharmony_ci desc_len = skb_headlen(skb); 121962306a36Sopenharmony_ci 122062306a36Sopenharmony_ci flags = F_CMD_DATAVALID | F_CMD_SOP | 122162306a36Sopenharmony_ci V_CMD_EOP(nfrags == 0 && desc_len <= SGE_TX_DESC_MAX_PLEN) | 122262306a36Sopenharmony_ci V_CMD_GEN2(gen); 122362306a36Sopenharmony_ci first_desc_len = (desc_len <= SGE_TX_DESC_MAX_PLEN) ? 122462306a36Sopenharmony_ci desc_len : SGE_TX_DESC_MAX_PLEN; 122562306a36Sopenharmony_ci e->addr_lo = (u32)desc_mapping; 122662306a36Sopenharmony_ci e->addr_hi = (u64)desc_mapping >> 32; 122762306a36Sopenharmony_ci e->len_gen = V_CMD_LEN(first_desc_len) | V_CMD_GEN1(gen); 122862306a36Sopenharmony_ci ce->skb = NULL; 122962306a36Sopenharmony_ci dma_unmap_len_set(ce, dma_len, 0); 123062306a36Sopenharmony_ci 123162306a36Sopenharmony_ci if (PAGE_SIZE > SGE_TX_DESC_MAX_PLEN && 123262306a36Sopenharmony_ci desc_len > SGE_TX_DESC_MAX_PLEN) { 123362306a36Sopenharmony_ci desc_mapping += first_desc_len; 123462306a36Sopenharmony_ci desc_len -= first_desc_len; 123562306a36Sopenharmony_ci e1++; 123662306a36Sopenharmony_ci ce++; 123762306a36Sopenharmony_ci if (++pidx == q->size) { 123862306a36Sopenharmony_ci pidx = 0; 123962306a36Sopenharmony_ci gen ^= 1; 124062306a36Sopenharmony_ci e1 = q->entries; 124162306a36Sopenharmony_ci ce = q->centries; 124262306a36Sopenharmony_ci } 124362306a36Sopenharmony_ci pidx = write_large_page_tx_descs(pidx, &e1, &ce, &gen, 124462306a36Sopenharmony_ci &desc_mapping, &desc_len, 124562306a36Sopenharmony_ci nfrags, q); 124662306a36Sopenharmony_ci 124762306a36Sopenharmony_ci if (likely(desc_len)) 124862306a36Sopenharmony_ci write_tx_desc(e1, desc_mapping, desc_len, gen, 124962306a36Sopenharmony_ci nfrags == 0); 125062306a36Sopenharmony_ci } 125162306a36Sopenharmony_ci 125262306a36Sopenharmony_ci ce->skb = NULL; 125362306a36Sopenharmony_ci dma_unmap_addr_set(ce, dma_addr, mapping); 125462306a36Sopenharmony_ci dma_unmap_len_set(ce, dma_len, skb_headlen(skb)); 125562306a36Sopenharmony_ci 125662306a36Sopenharmony_ci for (i = 0; nfrags--; i++) { 125762306a36Sopenharmony_ci skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; 125862306a36Sopenharmony_ci e1++; 125962306a36Sopenharmony_ci ce++; 126062306a36Sopenharmony_ci if (++pidx == q->size) { 126162306a36Sopenharmony_ci pidx = 0; 126262306a36Sopenharmony_ci gen ^= 1; 126362306a36Sopenharmony_ci e1 = q->entries; 126462306a36Sopenharmony_ci ce = q->centries; 126562306a36Sopenharmony_ci } 126662306a36Sopenharmony_ci 126762306a36Sopenharmony_ci mapping = skb_frag_dma_map(&adapter->pdev->dev, frag, 0, 126862306a36Sopenharmony_ci skb_frag_size(frag), DMA_TO_DEVICE); 126962306a36Sopenharmony_ci desc_mapping = mapping; 127062306a36Sopenharmony_ci desc_len = skb_frag_size(frag); 127162306a36Sopenharmony_ci 127262306a36Sopenharmony_ci pidx = write_large_page_tx_descs(pidx, &e1, &ce, &gen, 127362306a36Sopenharmony_ci &desc_mapping, &desc_len, 127462306a36Sopenharmony_ci nfrags, q); 127562306a36Sopenharmony_ci if (likely(desc_len)) 127662306a36Sopenharmony_ci write_tx_desc(e1, desc_mapping, desc_len, gen, 127762306a36Sopenharmony_ci nfrags == 0); 127862306a36Sopenharmony_ci ce->skb = NULL; 127962306a36Sopenharmony_ci dma_unmap_addr_set(ce, dma_addr, mapping); 128062306a36Sopenharmony_ci dma_unmap_len_set(ce, dma_len, skb_frag_size(frag)); 128162306a36Sopenharmony_ci } 128262306a36Sopenharmony_ci ce->skb = skb; 128362306a36Sopenharmony_ci wmb(); 128462306a36Sopenharmony_ci e->flags = flags; 128562306a36Sopenharmony_ci} 128662306a36Sopenharmony_ci 128762306a36Sopenharmony_ci/* 128862306a36Sopenharmony_ci * Clean up completed Tx buffers. 128962306a36Sopenharmony_ci */ 129062306a36Sopenharmony_cistatic inline void reclaim_completed_tx(struct sge *sge, struct cmdQ *q) 129162306a36Sopenharmony_ci{ 129262306a36Sopenharmony_ci unsigned int reclaim = q->processed - q->cleaned; 129362306a36Sopenharmony_ci 129462306a36Sopenharmony_ci if (reclaim) { 129562306a36Sopenharmony_ci pr_debug("reclaim_completed_tx processed:%d cleaned:%d\n", 129662306a36Sopenharmony_ci q->processed, q->cleaned); 129762306a36Sopenharmony_ci free_cmdQ_buffers(sge, q, reclaim); 129862306a36Sopenharmony_ci q->cleaned += reclaim; 129962306a36Sopenharmony_ci } 130062306a36Sopenharmony_ci} 130162306a36Sopenharmony_ci 130262306a36Sopenharmony_ci/* 130362306a36Sopenharmony_ci * Called from tasklet. Checks the scheduler for any 130462306a36Sopenharmony_ci * pending skbs that can be sent. 130562306a36Sopenharmony_ci */ 130662306a36Sopenharmony_cistatic void restart_sched(struct tasklet_struct *t) 130762306a36Sopenharmony_ci{ 130862306a36Sopenharmony_ci struct sched *s = from_tasklet(s, t, sched_tsk); 130962306a36Sopenharmony_ci struct sge *sge = s->sge; 131062306a36Sopenharmony_ci struct adapter *adapter = sge->adapter; 131162306a36Sopenharmony_ci struct cmdQ *q = &sge->cmdQ[0]; 131262306a36Sopenharmony_ci struct sk_buff *skb; 131362306a36Sopenharmony_ci unsigned int credits, queued_skb = 0; 131462306a36Sopenharmony_ci 131562306a36Sopenharmony_ci spin_lock(&q->lock); 131662306a36Sopenharmony_ci reclaim_completed_tx(sge, q); 131762306a36Sopenharmony_ci 131862306a36Sopenharmony_ci credits = q->size - q->in_use; 131962306a36Sopenharmony_ci pr_debug("restart_sched credits=%d\n", credits); 132062306a36Sopenharmony_ci while ((skb = sched_skb(sge, NULL, credits)) != NULL) { 132162306a36Sopenharmony_ci unsigned int genbit, pidx, count; 132262306a36Sopenharmony_ci count = 1 + skb_shinfo(skb)->nr_frags; 132362306a36Sopenharmony_ci count += compute_large_page_tx_descs(skb); 132462306a36Sopenharmony_ci q->in_use += count; 132562306a36Sopenharmony_ci genbit = q->genbit; 132662306a36Sopenharmony_ci pidx = q->pidx; 132762306a36Sopenharmony_ci q->pidx += count; 132862306a36Sopenharmony_ci if (q->pidx >= q->size) { 132962306a36Sopenharmony_ci q->pidx -= q->size; 133062306a36Sopenharmony_ci q->genbit ^= 1; 133162306a36Sopenharmony_ci } 133262306a36Sopenharmony_ci write_tx_descs(adapter, skb, pidx, genbit, q); 133362306a36Sopenharmony_ci credits = q->size - q->in_use; 133462306a36Sopenharmony_ci queued_skb = 1; 133562306a36Sopenharmony_ci } 133662306a36Sopenharmony_ci 133762306a36Sopenharmony_ci if (queued_skb) { 133862306a36Sopenharmony_ci clear_bit(CMDQ_STAT_LAST_PKT_DB, &q->status); 133962306a36Sopenharmony_ci if (test_and_set_bit(CMDQ_STAT_RUNNING, &q->status) == 0) { 134062306a36Sopenharmony_ci set_bit(CMDQ_STAT_LAST_PKT_DB, &q->status); 134162306a36Sopenharmony_ci writel(F_CMDQ0_ENABLE, adapter->regs + A_SG_DOORBELL); 134262306a36Sopenharmony_ci } 134362306a36Sopenharmony_ci } 134462306a36Sopenharmony_ci spin_unlock(&q->lock); 134562306a36Sopenharmony_ci} 134662306a36Sopenharmony_ci 134762306a36Sopenharmony_ci/** 134862306a36Sopenharmony_ci * sge_rx - process an ingress ethernet packet 134962306a36Sopenharmony_ci * @sge: the sge structure 135062306a36Sopenharmony_ci * @fl: the free list that contains the packet buffer 135162306a36Sopenharmony_ci * @len: the packet length 135262306a36Sopenharmony_ci * 135362306a36Sopenharmony_ci * Process an ingress ethernet packet and deliver it to the stack. 135462306a36Sopenharmony_ci */ 135562306a36Sopenharmony_cistatic void sge_rx(struct sge *sge, struct freelQ *fl, unsigned int len) 135662306a36Sopenharmony_ci{ 135762306a36Sopenharmony_ci struct sk_buff *skb; 135862306a36Sopenharmony_ci const struct cpl_rx_pkt *p; 135962306a36Sopenharmony_ci struct adapter *adapter = sge->adapter; 136062306a36Sopenharmony_ci struct sge_port_stats *st; 136162306a36Sopenharmony_ci struct net_device *dev; 136262306a36Sopenharmony_ci 136362306a36Sopenharmony_ci skb = get_packet(adapter, fl, len - sge->rx_pkt_pad); 136462306a36Sopenharmony_ci if (unlikely(!skb)) { 136562306a36Sopenharmony_ci sge->stats.rx_drops++; 136662306a36Sopenharmony_ci return; 136762306a36Sopenharmony_ci } 136862306a36Sopenharmony_ci 136962306a36Sopenharmony_ci p = (const struct cpl_rx_pkt *) skb->data; 137062306a36Sopenharmony_ci if (p->iff >= adapter->params.nports) { 137162306a36Sopenharmony_ci kfree_skb(skb); 137262306a36Sopenharmony_ci return; 137362306a36Sopenharmony_ci } 137462306a36Sopenharmony_ci __skb_pull(skb, sizeof(*p)); 137562306a36Sopenharmony_ci 137662306a36Sopenharmony_ci st = this_cpu_ptr(sge->port_stats[p->iff]); 137762306a36Sopenharmony_ci dev = adapter->port[p->iff].dev; 137862306a36Sopenharmony_ci 137962306a36Sopenharmony_ci skb->protocol = eth_type_trans(skb, dev); 138062306a36Sopenharmony_ci if ((dev->features & NETIF_F_RXCSUM) && p->csum == 0xffff && 138162306a36Sopenharmony_ci skb->protocol == htons(ETH_P_IP) && 138262306a36Sopenharmony_ci (skb->data[9] == IPPROTO_TCP || skb->data[9] == IPPROTO_UDP)) { 138362306a36Sopenharmony_ci ++st->rx_cso_good; 138462306a36Sopenharmony_ci skb->ip_summed = CHECKSUM_UNNECESSARY; 138562306a36Sopenharmony_ci } else 138662306a36Sopenharmony_ci skb_checksum_none_assert(skb); 138762306a36Sopenharmony_ci 138862306a36Sopenharmony_ci if (p->vlan_valid) { 138962306a36Sopenharmony_ci st->vlan_xtract++; 139062306a36Sopenharmony_ci __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), ntohs(p->vlan)); 139162306a36Sopenharmony_ci } 139262306a36Sopenharmony_ci netif_receive_skb(skb); 139362306a36Sopenharmony_ci} 139462306a36Sopenharmony_ci 139562306a36Sopenharmony_ci/* 139662306a36Sopenharmony_ci * Returns true if a command queue has enough available descriptors that 139762306a36Sopenharmony_ci * we can resume Tx operation after temporarily disabling its packet queue. 139862306a36Sopenharmony_ci */ 139962306a36Sopenharmony_cistatic inline int enough_free_Tx_descs(const struct cmdQ *q) 140062306a36Sopenharmony_ci{ 140162306a36Sopenharmony_ci unsigned int r = q->processed - q->cleaned; 140262306a36Sopenharmony_ci 140362306a36Sopenharmony_ci return q->in_use - r < (q->size >> 1); 140462306a36Sopenharmony_ci} 140562306a36Sopenharmony_ci 140662306a36Sopenharmony_ci/* 140762306a36Sopenharmony_ci * Called when sufficient space has become available in the SGE command queues 140862306a36Sopenharmony_ci * after the Tx packet schedulers have been suspended to restart the Tx path. 140962306a36Sopenharmony_ci */ 141062306a36Sopenharmony_cistatic void restart_tx_queues(struct sge *sge) 141162306a36Sopenharmony_ci{ 141262306a36Sopenharmony_ci struct adapter *adap = sge->adapter; 141362306a36Sopenharmony_ci int i; 141462306a36Sopenharmony_ci 141562306a36Sopenharmony_ci if (!enough_free_Tx_descs(&sge->cmdQ[0])) 141662306a36Sopenharmony_ci return; 141762306a36Sopenharmony_ci 141862306a36Sopenharmony_ci for_each_port(adap, i) { 141962306a36Sopenharmony_ci struct net_device *nd = adap->port[i].dev; 142062306a36Sopenharmony_ci 142162306a36Sopenharmony_ci if (test_and_clear_bit(nd->if_port, &sge->stopped_tx_queues) && 142262306a36Sopenharmony_ci netif_running(nd)) { 142362306a36Sopenharmony_ci sge->stats.cmdQ_restarted[2]++; 142462306a36Sopenharmony_ci netif_wake_queue(nd); 142562306a36Sopenharmony_ci } 142662306a36Sopenharmony_ci } 142762306a36Sopenharmony_ci} 142862306a36Sopenharmony_ci 142962306a36Sopenharmony_ci/* 143062306a36Sopenharmony_ci * update_tx_info is called from the interrupt handler/NAPI to return cmdQ0 143162306a36Sopenharmony_ci * information. 143262306a36Sopenharmony_ci */ 143362306a36Sopenharmony_cistatic unsigned int update_tx_info(struct adapter *adapter, 143462306a36Sopenharmony_ci unsigned int flags, 143562306a36Sopenharmony_ci unsigned int pr0) 143662306a36Sopenharmony_ci{ 143762306a36Sopenharmony_ci struct sge *sge = adapter->sge; 143862306a36Sopenharmony_ci struct cmdQ *cmdq = &sge->cmdQ[0]; 143962306a36Sopenharmony_ci 144062306a36Sopenharmony_ci cmdq->processed += pr0; 144162306a36Sopenharmony_ci if (flags & (F_FL0_ENABLE | F_FL1_ENABLE)) { 144262306a36Sopenharmony_ci freelQs_empty(sge); 144362306a36Sopenharmony_ci flags &= ~(F_FL0_ENABLE | F_FL1_ENABLE); 144462306a36Sopenharmony_ci } 144562306a36Sopenharmony_ci if (flags & F_CMDQ0_ENABLE) { 144662306a36Sopenharmony_ci clear_bit(CMDQ_STAT_RUNNING, &cmdq->status); 144762306a36Sopenharmony_ci 144862306a36Sopenharmony_ci if (cmdq->cleaned + cmdq->in_use != cmdq->processed && 144962306a36Sopenharmony_ci !test_and_set_bit(CMDQ_STAT_LAST_PKT_DB, &cmdq->status)) { 145062306a36Sopenharmony_ci set_bit(CMDQ_STAT_RUNNING, &cmdq->status); 145162306a36Sopenharmony_ci writel(F_CMDQ0_ENABLE, adapter->regs + A_SG_DOORBELL); 145262306a36Sopenharmony_ci } 145362306a36Sopenharmony_ci if (sge->tx_sched) 145462306a36Sopenharmony_ci tasklet_hi_schedule(&sge->tx_sched->sched_tsk); 145562306a36Sopenharmony_ci 145662306a36Sopenharmony_ci flags &= ~F_CMDQ0_ENABLE; 145762306a36Sopenharmony_ci } 145862306a36Sopenharmony_ci 145962306a36Sopenharmony_ci if (unlikely(sge->stopped_tx_queues != 0)) 146062306a36Sopenharmony_ci restart_tx_queues(sge); 146162306a36Sopenharmony_ci 146262306a36Sopenharmony_ci return flags; 146362306a36Sopenharmony_ci} 146462306a36Sopenharmony_ci 146562306a36Sopenharmony_ci/* 146662306a36Sopenharmony_ci * Process SGE responses, up to the supplied budget. Returns the number of 146762306a36Sopenharmony_ci * responses processed. A negative budget is effectively unlimited. 146862306a36Sopenharmony_ci */ 146962306a36Sopenharmony_cistatic int process_responses(struct adapter *adapter, int budget) 147062306a36Sopenharmony_ci{ 147162306a36Sopenharmony_ci struct sge *sge = adapter->sge; 147262306a36Sopenharmony_ci struct respQ *q = &sge->respQ; 147362306a36Sopenharmony_ci struct respQ_e *e = &q->entries[q->cidx]; 147462306a36Sopenharmony_ci int done = 0; 147562306a36Sopenharmony_ci unsigned int flags = 0; 147662306a36Sopenharmony_ci unsigned int cmdq_processed[SGE_CMDQ_N] = {0, 0}; 147762306a36Sopenharmony_ci 147862306a36Sopenharmony_ci while (done < budget && e->GenerationBit == q->genbit) { 147962306a36Sopenharmony_ci flags |= e->Qsleeping; 148062306a36Sopenharmony_ci 148162306a36Sopenharmony_ci cmdq_processed[0] += e->Cmdq0CreditReturn; 148262306a36Sopenharmony_ci cmdq_processed[1] += e->Cmdq1CreditReturn; 148362306a36Sopenharmony_ci 148462306a36Sopenharmony_ci /* We batch updates to the TX side to avoid cacheline 148562306a36Sopenharmony_ci * ping-pong of TX state information on MP where the sender 148662306a36Sopenharmony_ci * might run on a different CPU than this function... 148762306a36Sopenharmony_ci */ 148862306a36Sopenharmony_ci if (unlikely((flags & F_CMDQ0_ENABLE) || cmdq_processed[0] > 64)) { 148962306a36Sopenharmony_ci flags = update_tx_info(adapter, flags, cmdq_processed[0]); 149062306a36Sopenharmony_ci cmdq_processed[0] = 0; 149162306a36Sopenharmony_ci } 149262306a36Sopenharmony_ci 149362306a36Sopenharmony_ci if (unlikely(cmdq_processed[1] > 16)) { 149462306a36Sopenharmony_ci sge->cmdQ[1].processed += cmdq_processed[1]; 149562306a36Sopenharmony_ci cmdq_processed[1] = 0; 149662306a36Sopenharmony_ci } 149762306a36Sopenharmony_ci 149862306a36Sopenharmony_ci if (likely(e->DataValid)) { 149962306a36Sopenharmony_ci struct freelQ *fl = &sge->freelQ[e->FreelistQid]; 150062306a36Sopenharmony_ci 150162306a36Sopenharmony_ci BUG_ON(!e->Sop || !e->Eop); 150262306a36Sopenharmony_ci if (unlikely(e->Offload)) 150362306a36Sopenharmony_ci unexpected_offload(adapter, fl); 150462306a36Sopenharmony_ci else 150562306a36Sopenharmony_ci sge_rx(sge, fl, e->BufferLength); 150662306a36Sopenharmony_ci 150762306a36Sopenharmony_ci ++done; 150862306a36Sopenharmony_ci 150962306a36Sopenharmony_ci /* 151062306a36Sopenharmony_ci * Note: this depends on each packet consuming a 151162306a36Sopenharmony_ci * single free-list buffer; cf. the BUG above. 151262306a36Sopenharmony_ci */ 151362306a36Sopenharmony_ci if (++fl->cidx == fl->size) 151462306a36Sopenharmony_ci fl->cidx = 0; 151562306a36Sopenharmony_ci prefetch(fl->centries[fl->cidx].skb); 151662306a36Sopenharmony_ci 151762306a36Sopenharmony_ci if (unlikely(--fl->credits < 151862306a36Sopenharmony_ci fl->size - SGE_FREEL_REFILL_THRESH)) 151962306a36Sopenharmony_ci refill_free_list(sge, fl); 152062306a36Sopenharmony_ci } else 152162306a36Sopenharmony_ci sge->stats.pure_rsps++; 152262306a36Sopenharmony_ci 152362306a36Sopenharmony_ci e++; 152462306a36Sopenharmony_ci if (unlikely(++q->cidx == q->size)) { 152562306a36Sopenharmony_ci q->cidx = 0; 152662306a36Sopenharmony_ci q->genbit ^= 1; 152762306a36Sopenharmony_ci e = q->entries; 152862306a36Sopenharmony_ci } 152962306a36Sopenharmony_ci prefetch(e); 153062306a36Sopenharmony_ci 153162306a36Sopenharmony_ci if (++q->credits > SGE_RESPQ_REPLENISH_THRES) { 153262306a36Sopenharmony_ci writel(q->credits, adapter->regs + A_SG_RSPQUEUECREDIT); 153362306a36Sopenharmony_ci q->credits = 0; 153462306a36Sopenharmony_ci } 153562306a36Sopenharmony_ci } 153662306a36Sopenharmony_ci 153762306a36Sopenharmony_ci flags = update_tx_info(adapter, flags, cmdq_processed[0]); 153862306a36Sopenharmony_ci sge->cmdQ[1].processed += cmdq_processed[1]; 153962306a36Sopenharmony_ci 154062306a36Sopenharmony_ci return done; 154162306a36Sopenharmony_ci} 154262306a36Sopenharmony_ci 154362306a36Sopenharmony_cistatic inline int responses_pending(const struct adapter *adapter) 154462306a36Sopenharmony_ci{ 154562306a36Sopenharmony_ci const struct respQ *Q = &adapter->sge->respQ; 154662306a36Sopenharmony_ci const struct respQ_e *e = &Q->entries[Q->cidx]; 154762306a36Sopenharmony_ci 154862306a36Sopenharmony_ci return e->GenerationBit == Q->genbit; 154962306a36Sopenharmony_ci} 155062306a36Sopenharmony_ci 155162306a36Sopenharmony_ci/* 155262306a36Sopenharmony_ci * A simpler version of process_responses() that handles only pure (i.e., 155362306a36Sopenharmony_ci * non data-carrying) responses. Such respones are too light-weight to justify 155462306a36Sopenharmony_ci * calling a softirq when using NAPI, so we handle them specially in hard 155562306a36Sopenharmony_ci * interrupt context. The function is called with a pointer to a response, 155662306a36Sopenharmony_ci * which the caller must ensure is a valid pure response. Returns 1 if it 155762306a36Sopenharmony_ci * encounters a valid data-carrying response, 0 otherwise. 155862306a36Sopenharmony_ci */ 155962306a36Sopenharmony_cistatic int process_pure_responses(struct adapter *adapter) 156062306a36Sopenharmony_ci{ 156162306a36Sopenharmony_ci struct sge *sge = adapter->sge; 156262306a36Sopenharmony_ci struct respQ *q = &sge->respQ; 156362306a36Sopenharmony_ci struct respQ_e *e = &q->entries[q->cidx]; 156462306a36Sopenharmony_ci const struct freelQ *fl = &sge->freelQ[e->FreelistQid]; 156562306a36Sopenharmony_ci unsigned int flags = 0; 156662306a36Sopenharmony_ci unsigned int cmdq_processed[SGE_CMDQ_N] = {0, 0}; 156762306a36Sopenharmony_ci 156862306a36Sopenharmony_ci prefetch(fl->centries[fl->cidx].skb); 156962306a36Sopenharmony_ci if (e->DataValid) 157062306a36Sopenharmony_ci return 1; 157162306a36Sopenharmony_ci 157262306a36Sopenharmony_ci do { 157362306a36Sopenharmony_ci flags |= e->Qsleeping; 157462306a36Sopenharmony_ci 157562306a36Sopenharmony_ci cmdq_processed[0] += e->Cmdq0CreditReturn; 157662306a36Sopenharmony_ci cmdq_processed[1] += e->Cmdq1CreditReturn; 157762306a36Sopenharmony_ci 157862306a36Sopenharmony_ci e++; 157962306a36Sopenharmony_ci if (unlikely(++q->cidx == q->size)) { 158062306a36Sopenharmony_ci q->cidx = 0; 158162306a36Sopenharmony_ci q->genbit ^= 1; 158262306a36Sopenharmony_ci e = q->entries; 158362306a36Sopenharmony_ci } 158462306a36Sopenharmony_ci prefetch(e); 158562306a36Sopenharmony_ci 158662306a36Sopenharmony_ci if (++q->credits > SGE_RESPQ_REPLENISH_THRES) { 158762306a36Sopenharmony_ci writel(q->credits, adapter->regs + A_SG_RSPQUEUECREDIT); 158862306a36Sopenharmony_ci q->credits = 0; 158962306a36Sopenharmony_ci } 159062306a36Sopenharmony_ci sge->stats.pure_rsps++; 159162306a36Sopenharmony_ci } while (e->GenerationBit == q->genbit && !e->DataValid); 159262306a36Sopenharmony_ci 159362306a36Sopenharmony_ci flags = update_tx_info(adapter, flags, cmdq_processed[0]); 159462306a36Sopenharmony_ci sge->cmdQ[1].processed += cmdq_processed[1]; 159562306a36Sopenharmony_ci 159662306a36Sopenharmony_ci return e->GenerationBit == q->genbit; 159762306a36Sopenharmony_ci} 159862306a36Sopenharmony_ci 159962306a36Sopenharmony_ci/* 160062306a36Sopenharmony_ci * Handler for new data events when using NAPI. This does not need any locking 160162306a36Sopenharmony_ci * or protection from interrupts as data interrupts are off at this point and 160262306a36Sopenharmony_ci * other adapter interrupts do not interfere. 160362306a36Sopenharmony_ci */ 160462306a36Sopenharmony_ciint t1_poll(struct napi_struct *napi, int budget) 160562306a36Sopenharmony_ci{ 160662306a36Sopenharmony_ci struct adapter *adapter = container_of(napi, struct adapter, napi); 160762306a36Sopenharmony_ci int work_done = process_responses(adapter, budget); 160862306a36Sopenharmony_ci 160962306a36Sopenharmony_ci if (likely(work_done < budget)) { 161062306a36Sopenharmony_ci napi_complete_done(napi, work_done); 161162306a36Sopenharmony_ci writel(adapter->sge->respQ.cidx, 161262306a36Sopenharmony_ci adapter->regs + A_SG_SLEEPING); 161362306a36Sopenharmony_ci } 161462306a36Sopenharmony_ci return work_done; 161562306a36Sopenharmony_ci} 161662306a36Sopenharmony_ci 161762306a36Sopenharmony_ciirqreturn_t t1_interrupt_thread(int irq, void *data) 161862306a36Sopenharmony_ci{ 161962306a36Sopenharmony_ci struct adapter *adapter = data; 162062306a36Sopenharmony_ci u32 pending_thread_intr; 162162306a36Sopenharmony_ci 162262306a36Sopenharmony_ci spin_lock_irq(&adapter->async_lock); 162362306a36Sopenharmony_ci pending_thread_intr = adapter->pending_thread_intr; 162462306a36Sopenharmony_ci adapter->pending_thread_intr = 0; 162562306a36Sopenharmony_ci spin_unlock_irq(&adapter->async_lock); 162662306a36Sopenharmony_ci 162762306a36Sopenharmony_ci if (!pending_thread_intr) 162862306a36Sopenharmony_ci return IRQ_NONE; 162962306a36Sopenharmony_ci 163062306a36Sopenharmony_ci if (pending_thread_intr & F_PL_INTR_EXT) 163162306a36Sopenharmony_ci t1_elmer0_ext_intr_handler(adapter); 163262306a36Sopenharmony_ci 163362306a36Sopenharmony_ci /* This error is fatal, interrupts remain off */ 163462306a36Sopenharmony_ci if (pending_thread_intr & F_PL_INTR_SGE_ERR) { 163562306a36Sopenharmony_ci pr_alert("%s: encountered fatal error, operation suspended\n", 163662306a36Sopenharmony_ci adapter->name); 163762306a36Sopenharmony_ci t1_sge_stop(adapter->sge); 163862306a36Sopenharmony_ci return IRQ_HANDLED; 163962306a36Sopenharmony_ci } 164062306a36Sopenharmony_ci 164162306a36Sopenharmony_ci spin_lock_irq(&adapter->async_lock); 164262306a36Sopenharmony_ci adapter->slow_intr_mask |= F_PL_INTR_EXT; 164362306a36Sopenharmony_ci 164462306a36Sopenharmony_ci writel(F_PL_INTR_EXT, adapter->regs + A_PL_CAUSE); 164562306a36Sopenharmony_ci writel(adapter->slow_intr_mask | F_PL_INTR_SGE_DATA, 164662306a36Sopenharmony_ci adapter->regs + A_PL_ENABLE); 164762306a36Sopenharmony_ci spin_unlock_irq(&adapter->async_lock); 164862306a36Sopenharmony_ci 164962306a36Sopenharmony_ci return IRQ_HANDLED; 165062306a36Sopenharmony_ci} 165162306a36Sopenharmony_ci 165262306a36Sopenharmony_ciirqreturn_t t1_interrupt(int irq, void *data) 165362306a36Sopenharmony_ci{ 165462306a36Sopenharmony_ci struct adapter *adapter = data; 165562306a36Sopenharmony_ci struct sge *sge = adapter->sge; 165662306a36Sopenharmony_ci irqreturn_t handled; 165762306a36Sopenharmony_ci 165862306a36Sopenharmony_ci if (likely(responses_pending(adapter))) { 165962306a36Sopenharmony_ci writel(F_PL_INTR_SGE_DATA, adapter->regs + A_PL_CAUSE); 166062306a36Sopenharmony_ci 166162306a36Sopenharmony_ci if (napi_schedule_prep(&adapter->napi)) { 166262306a36Sopenharmony_ci if (process_pure_responses(adapter)) 166362306a36Sopenharmony_ci __napi_schedule(&adapter->napi); 166462306a36Sopenharmony_ci else { 166562306a36Sopenharmony_ci /* no data, no NAPI needed */ 166662306a36Sopenharmony_ci writel(sge->respQ.cidx, adapter->regs + A_SG_SLEEPING); 166762306a36Sopenharmony_ci /* undo schedule_prep */ 166862306a36Sopenharmony_ci napi_enable(&adapter->napi); 166962306a36Sopenharmony_ci } 167062306a36Sopenharmony_ci } 167162306a36Sopenharmony_ci return IRQ_HANDLED; 167262306a36Sopenharmony_ci } 167362306a36Sopenharmony_ci 167462306a36Sopenharmony_ci spin_lock(&adapter->async_lock); 167562306a36Sopenharmony_ci handled = t1_slow_intr_handler(adapter); 167662306a36Sopenharmony_ci spin_unlock(&adapter->async_lock); 167762306a36Sopenharmony_ci 167862306a36Sopenharmony_ci if (handled == IRQ_NONE) 167962306a36Sopenharmony_ci sge->stats.unhandled_irqs++; 168062306a36Sopenharmony_ci 168162306a36Sopenharmony_ci return handled; 168262306a36Sopenharmony_ci} 168362306a36Sopenharmony_ci 168462306a36Sopenharmony_ci/* 168562306a36Sopenharmony_ci * Enqueues the sk_buff onto the cmdQ[qid] and has hardware fetch it. 168662306a36Sopenharmony_ci * 168762306a36Sopenharmony_ci * The code figures out how many entries the sk_buff will require in the 168862306a36Sopenharmony_ci * cmdQ and updates the cmdQ data structure with the state once the enqueue 168962306a36Sopenharmony_ci * has complete. Then, it doesn't access the global structure anymore, but 169062306a36Sopenharmony_ci * uses the corresponding fields on the stack. In conjunction with a spinlock 169162306a36Sopenharmony_ci * around that code, we can make the function reentrant without holding the 169262306a36Sopenharmony_ci * lock when we actually enqueue (which might be expensive, especially on 169362306a36Sopenharmony_ci * architectures with IO MMUs). 169462306a36Sopenharmony_ci * 169562306a36Sopenharmony_ci * This runs with softirqs disabled. 169662306a36Sopenharmony_ci */ 169762306a36Sopenharmony_cistatic int t1_sge_tx(struct sk_buff *skb, struct adapter *adapter, 169862306a36Sopenharmony_ci unsigned int qid, struct net_device *dev) 169962306a36Sopenharmony_ci{ 170062306a36Sopenharmony_ci struct sge *sge = adapter->sge; 170162306a36Sopenharmony_ci struct cmdQ *q = &sge->cmdQ[qid]; 170262306a36Sopenharmony_ci unsigned int credits, pidx, genbit, count, use_sched_skb = 0; 170362306a36Sopenharmony_ci 170462306a36Sopenharmony_ci spin_lock(&q->lock); 170562306a36Sopenharmony_ci 170662306a36Sopenharmony_ci reclaim_completed_tx(sge, q); 170762306a36Sopenharmony_ci 170862306a36Sopenharmony_ci pidx = q->pidx; 170962306a36Sopenharmony_ci credits = q->size - q->in_use; 171062306a36Sopenharmony_ci count = 1 + skb_shinfo(skb)->nr_frags; 171162306a36Sopenharmony_ci count += compute_large_page_tx_descs(skb); 171262306a36Sopenharmony_ci 171362306a36Sopenharmony_ci /* Ethernet packet */ 171462306a36Sopenharmony_ci if (unlikely(credits < count)) { 171562306a36Sopenharmony_ci if (!netif_queue_stopped(dev)) { 171662306a36Sopenharmony_ci netif_stop_queue(dev); 171762306a36Sopenharmony_ci set_bit(dev->if_port, &sge->stopped_tx_queues); 171862306a36Sopenharmony_ci sge->stats.cmdQ_full[2]++; 171962306a36Sopenharmony_ci pr_err("%s: Tx ring full while queue awake!\n", 172062306a36Sopenharmony_ci adapter->name); 172162306a36Sopenharmony_ci } 172262306a36Sopenharmony_ci spin_unlock(&q->lock); 172362306a36Sopenharmony_ci return NETDEV_TX_BUSY; 172462306a36Sopenharmony_ci } 172562306a36Sopenharmony_ci 172662306a36Sopenharmony_ci if (unlikely(credits - count < q->stop_thres)) { 172762306a36Sopenharmony_ci netif_stop_queue(dev); 172862306a36Sopenharmony_ci set_bit(dev->if_port, &sge->stopped_tx_queues); 172962306a36Sopenharmony_ci sge->stats.cmdQ_full[2]++; 173062306a36Sopenharmony_ci } 173162306a36Sopenharmony_ci 173262306a36Sopenharmony_ci /* T204 cmdQ0 skbs that are destined for a certain port have to go 173362306a36Sopenharmony_ci * through the scheduler. 173462306a36Sopenharmony_ci */ 173562306a36Sopenharmony_ci if (sge->tx_sched && !qid && skb->dev) { 173662306a36Sopenharmony_ciuse_sched: 173762306a36Sopenharmony_ci use_sched_skb = 1; 173862306a36Sopenharmony_ci /* Note that the scheduler might return a different skb than 173962306a36Sopenharmony_ci * the one passed in. 174062306a36Sopenharmony_ci */ 174162306a36Sopenharmony_ci skb = sched_skb(sge, skb, credits); 174262306a36Sopenharmony_ci if (!skb) { 174362306a36Sopenharmony_ci spin_unlock(&q->lock); 174462306a36Sopenharmony_ci return NETDEV_TX_OK; 174562306a36Sopenharmony_ci } 174662306a36Sopenharmony_ci pidx = q->pidx; 174762306a36Sopenharmony_ci count = 1 + skb_shinfo(skb)->nr_frags; 174862306a36Sopenharmony_ci count += compute_large_page_tx_descs(skb); 174962306a36Sopenharmony_ci } 175062306a36Sopenharmony_ci 175162306a36Sopenharmony_ci q->in_use += count; 175262306a36Sopenharmony_ci genbit = q->genbit; 175362306a36Sopenharmony_ci pidx = q->pidx; 175462306a36Sopenharmony_ci q->pidx += count; 175562306a36Sopenharmony_ci if (q->pidx >= q->size) { 175662306a36Sopenharmony_ci q->pidx -= q->size; 175762306a36Sopenharmony_ci q->genbit ^= 1; 175862306a36Sopenharmony_ci } 175962306a36Sopenharmony_ci spin_unlock(&q->lock); 176062306a36Sopenharmony_ci 176162306a36Sopenharmony_ci write_tx_descs(adapter, skb, pidx, genbit, q); 176262306a36Sopenharmony_ci 176362306a36Sopenharmony_ci /* 176462306a36Sopenharmony_ci * We always ring the doorbell for cmdQ1. For cmdQ0, we only ring 176562306a36Sopenharmony_ci * the doorbell if the Q is asleep. There is a natural race, where 176662306a36Sopenharmony_ci * the hardware is going to sleep just after we checked, however, 176762306a36Sopenharmony_ci * then the interrupt handler will detect the outstanding TX packet 176862306a36Sopenharmony_ci * and ring the doorbell for us. 176962306a36Sopenharmony_ci */ 177062306a36Sopenharmony_ci if (qid) 177162306a36Sopenharmony_ci doorbell_pio(adapter, F_CMDQ1_ENABLE); 177262306a36Sopenharmony_ci else { 177362306a36Sopenharmony_ci clear_bit(CMDQ_STAT_LAST_PKT_DB, &q->status); 177462306a36Sopenharmony_ci if (test_and_set_bit(CMDQ_STAT_RUNNING, &q->status) == 0) { 177562306a36Sopenharmony_ci set_bit(CMDQ_STAT_LAST_PKT_DB, &q->status); 177662306a36Sopenharmony_ci writel(F_CMDQ0_ENABLE, adapter->regs + A_SG_DOORBELL); 177762306a36Sopenharmony_ci } 177862306a36Sopenharmony_ci } 177962306a36Sopenharmony_ci 178062306a36Sopenharmony_ci if (use_sched_skb) { 178162306a36Sopenharmony_ci if (spin_trylock(&q->lock)) { 178262306a36Sopenharmony_ci credits = q->size - q->in_use; 178362306a36Sopenharmony_ci skb = NULL; 178462306a36Sopenharmony_ci goto use_sched; 178562306a36Sopenharmony_ci } 178662306a36Sopenharmony_ci } 178762306a36Sopenharmony_ci return NETDEV_TX_OK; 178862306a36Sopenharmony_ci} 178962306a36Sopenharmony_ci 179062306a36Sopenharmony_ci#define MK_ETH_TYPE_MSS(type, mss) (((mss) & 0x3FFF) | ((type) << 14)) 179162306a36Sopenharmony_ci 179262306a36Sopenharmony_ci/* 179362306a36Sopenharmony_ci * eth_hdr_len - return the length of an Ethernet header 179462306a36Sopenharmony_ci * @data: pointer to the start of the Ethernet header 179562306a36Sopenharmony_ci * 179662306a36Sopenharmony_ci * Returns the length of an Ethernet header, including optional VLAN tag. 179762306a36Sopenharmony_ci */ 179862306a36Sopenharmony_cistatic inline int eth_hdr_len(const void *data) 179962306a36Sopenharmony_ci{ 180062306a36Sopenharmony_ci const struct ethhdr *e = data; 180162306a36Sopenharmony_ci 180262306a36Sopenharmony_ci return e->h_proto == htons(ETH_P_8021Q) ? VLAN_ETH_HLEN : ETH_HLEN; 180362306a36Sopenharmony_ci} 180462306a36Sopenharmony_ci 180562306a36Sopenharmony_ci/* 180662306a36Sopenharmony_ci * Adds the CPL header to the sk_buff and passes it to t1_sge_tx. 180762306a36Sopenharmony_ci */ 180862306a36Sopenharmony_cinetdev_tx_t t1_start_xmit(struct sk_buff *skb, struct net_device *dev) 180962306a36Sopenharmony_ci{ 181062306a36Sopenharmony_ci struct adapter *adapter = dev->ml_priv; 181162306a36Sopenharmony_ci struct sge *sge = adapter->sge; 181262306a36Sopenharmony_ci struct sge_port_stats *st = this_cpu_ptr(sge->port_stats[dev->if_port]); 181362306a36Sopenharmony_ci struct cpl_tx_pkt *cpl; 181462306a36Sopenharmony_ci struct sk_buff *orig_skb = skb; 181562306a36Sopenharmony_ci int ret; 181662306a36Sopenharmony_ci 181762306a36Sopenharmony_ci if (skb->protocol == htons(ETH_P_CPL5)) 181862306a36Sopenharmony_ci goto send; 181962306a36Sopenharmony_ci 182062306a36Sopenharmony_ci /* 182162306a36Sopenharmony_ci * We are using a non-standard hard_header_len. 182262306a36Sopenharmony_ci * Allocate more header room in the rare cases it is not big enough. 182362306a36Sopenharmony_ci */ 182462306a36Sopenharmony_ci if (unlikely(skb_headroom(skb) < dev->hard_header_len - ETH_HLEN)) { 182562306a36Sopenharmony_ci skb = skb_realloc_headroom(skb, sizeof(struct cpl_tx_pkt_lso)); 182662306a36Sopenharmony_ci ++st->tx_need_hdrroom; 182762306a36Sopenharmony_ci dev_kfree_skb_any(orig_skb); 182862306a36Sopenharmony_ci if (!skb) 182962306a36Sopenharmony_ci return NETDEV_TX_OK; 183062306a36Sopenharmony_ci } 183162306a36Sopenharmony_ci 183262306a36Sopenharmony_ci if (skb_shinfo(skb)->gso_size) { 183362306a36Sopenharmony_ci int eth_type; 183462306a36Sopenharmony_ci struct cpl_tx_pkt_lso *hdr; 183562306a36Sopenharmony_ci 183662306a36Sopenharmony_ci ++st->tx_tso; 183762306a36Sopenharmony_ci 183862306a36Sopenharmony_ci eth_type = skb_network_offset(skb) == ETH_HLEN ? 183962306a36Sopenharmony_ci CPL_ETH_II : CPL_ETH_II_VLAN; 184062306a36Sopenharmony_ci 184162306a36Sopenharmony_ci hdr = skb_push(skb, sizeof(*hdr)); 184262306a36Sopenharmony_ci hdr->opcode = CPL_TX_PKT_LSO; 184362306a36Sopenharmony_ci hdr->ip_csum_dis = hdr->l4_csum_dis = 0; 184462306a36Sopenharmony_ci hdr->ip_hdr_words = ip_hdr(skb)->ihl; 184562306a36Sopenharmony_ci hdr->tcp_hdr_words = tcp_hdr(skb)->doff; 184662306a36Sopenharmony_ci hdr->eth_type_mss = htons(MK_ETH_TYPE_MSS(eth_type, 184762306a36Sopenharmony_ci skb_shinfo(skb)->gso_size)); 184862306a36Sopenharmony_ci hdr->len = htonl(skb->len - sizeof(*hdr)); 184962306a36Sopenharmony_ci cpl = (struct cpl_tx_pkt *)hdr; 185062306a36Sopenharmony_ci } else { 185162306a36Sopenharmony_ci /* 185262306a36Sopenharmony_ci * Packets shorter than ETH_HLEN can break the MAC, drop them 185362306a36Sopenharmony_ci * early. Also, we may get oversized packets because some 185462306a36Sopenharmony_ci * parts of the kernel don't handle our unusual hard_header_len 185562306a36Sopenharmony_ci * right, drop those too. 185662306a36Sopenharmony_ci */ 185762306a36Sopenharmony_ci if (unlikely(skb->len < ETH_HLEN || 185862306a36Sopenharmony_ci skb->len > dev->mtu + eth_hdr_len(skb->data))) { 185962306a36Sopenharmony_ci netdev_dbg(dev, "packet size %d hdr %d mtu%d\n", 186062306a36Sopenharmony_ci skb->len, eth_hdr_len(skb->data), dev->mtu); 186162306a36Sopenharmony_ci dev_kfree_skb_any(skb); 186262306a36Sopenharmony_ci return NETDEV_TX_OK; 186362306a36Sopenharmony_ci } 186462306a36Sopenharmony_ci 186562306a36Sopenharmony_ci if (skb->ip_summed == CHECKSUM_PARTIAL && 186662306a36Sopenharmony_ci ip_hdr(skb)->protocol == IPPROTO_UDP) { 186762306a36Sopenharmony_ci if (unlikely(skb_checksum_help(skb))) { 186862306a36Sopenharmony_ci netdev_dbg(dev, "unable to do udp checksum\n"); 186962306a36Sopenharmony_ci dev_kfree_skb_any(skb); 187062306a36Sopenharmony_ci return NETDEV_TX_OK; 187162306a36Sopenharmony_ci } 187262306a36Sopenharmony_ci } 187362306a36Sopenharmony_ci 187462306a36Sopenharmony_ci /* Hmmm, assuming to catch the gratious arp... and we'll use 187562306a36Sopenharmony_ci * it to flush out stuck espi packets... 187662306a36Sopenharmony_ci */ 187762306a36Sopenharmony_ci if ((unlikely(!adapter->sge->espibug_skb[dev->if_port]))) { 187862306a36Sopenharmony_ci if (skb->protocol == htons(ETH_P_ARP) && 187962306a36Sopenharmony_ci arp_hdr(skb)->ar_op == htons(ARPOP_REQUEST)) { 188062306a36Sopenharmony_ci adapter->sge->espibug_skb[dev->if_port] = skb; 188162306a36Sopenharmony_ci /* We want to re-use this skb later. We 188262306a36Sopenharmony_ci * simply bump the reference count and it 188362306a36Sopenharmony_ci * will not be freed... 188462306a36Sopenharmony_ci */ 188562306a36Sopenharmony_ci skb = skb_get(skb); 188662306a36Sopenharmony_ci } 188762306a36Sopenharmony_ci } 188862306a36Sopenharmony_ci 188962306a36Sopenharmony_ci cpl = __skb_push(skb, sizeof(*cpl)); 189062306a36Sopenharmony_ci cpl->opcode = CPL_TX_PKT; 189162306a36Sopenharmony_ci cpl->ip_csum_dis = 1; /* SW calculates IP csum */ 189262306a36Sopenharmony_ci cpl->l4_csum_dis = skb->ip_summed == CHECKSUM_PARTIAL ? 0 : 1; 189362306a36Sopenharmony_ci /* the length field isn't used so don't bother setting it */ 189462306a36Sopenharmony_ci 189562306a36Sopenharmony_ci st->tx_cso += (skb->ip_summed == CHECKSUM_PARTIAL); 189662306a36Sopenharmony_ci } 189762306a36Sopenharmony_ci cpl->iff = dev->if_port; 189862306a36Sopenharmony_ci 189962306a36Sopenharmony_ci if (skb_vlan_tag_present(skb)) { 190062306a36Sopenharmony_ci cpl->vlan_valid = 1; 190162306a36Sopenharmony_ci cpl->vlan = htons(skb_vlan_tag_get(skb)); 190262306a36Sopenharmony_ci st->vlan_insert++; 190362306a36Sopenharmony_ci } else 190462306a36Sopenharmony_ci cpl->vlan_valid = 0; 190562306a36Sopenharmony_ci 190662306a36Sopenharmony_cisend: 190762306a36Sopenharmony_ci ret = t1_sge_tx(skb, adapter, 0, dev); 190862306a36Sopenharmony_ci 190962306a36Sopenharmony_ci /* If transmit busy, and we reallocated skb's due to headroom limit, 191062306a36Sopenharmony_ci * then silently discard to avoid leak. 191162306a36Sopenharmony_ci */ 191262306a36Sopenharmony_ci if (unlikely(ret != NETDEV_TX_OK && skb != orig_skb)) { 191362306a36Sopenharmony_ci dev_kfree_skb_any(skb); 191462306a36Sopenharmony_ci ret = NETDEV_TX_OK; 191562306a36Sopenharmony_ci } 191662306a36Sopenharmony_ci return ret; 191762306a36Sopenharmony_ci} 191862306a36Sopenharmony_ci 191962306a36Sopenharmony_ci/* 192062306a36Sopenharmony_ci * Callback for the Tx buffer reclaim timer. Runs with softirqs disabled. 192162306a36Sopenharmony_ci */ 192262306a36Sopenharmony_cistatic void sge_tx_reclaim_cb(struct timer_list *t) 192362306a36Sopenharmony_ci{ 192462306a36Sopenharmony_ci int i; 192562306a36Sopenharmony_ci struct sge *sge = from_timer(sge, t, tx_reclaim_timer); 192662306a36Sopenharmony_ci 192762306a36Sopenharmony_ci for (i = 0; i < SGE_CMDQ_N; ++i) { 192862306a36Sopenharmony_ci struct cmdQ *q = &sge->cmdQ[i]; 192962306a36Sopenharmony_ci 193062306a36Sopenharmony_ci if (!spin_trylock(&q->lock)) 193162306a36Sopenharmony_ci continue; 193262306a36Sopenharmony_ci 193362306a36Sopenharmony_ci reclaim_completed_tx(sge, q); 193462306a36Sopenharmony_ci if (i == 0 && q->in_use) { /* flush pending credits */ 193562306a36Sopenharmony_ci writel(F_CMDQ0_ENABLE, sge->adapter->regs + A_SG_DOORBELL); 193662306a36Sopenharmony_ci } 193762306a36Sopenharmony_ci spin_unlock(&q->lock); 193862306a36Sopenharmony_ci } 193962306a36Sopenharmony_ci mod_timer(&sge->tx_reclaim_timer, jiffies + TX_RECLAIM_PERIOD); 194062306a36Sopenharmony_ci} 194162306a36Sopenharmony_ci 194262306a36Sopenharmony_ci/* 194362306a36Sopenharmony_ci * Propagate changes of the SGE coalescing parameters to the HW. 194462306a36Sopenharmony_ci */ 194562306a36Sopenharmony_ciint t1_sge_set_coalesce_params(struct sge *sge, struct sge_params *p) 194662306a36Sopenharmony_ci{ 194762306a36Sopenharmony_ci sge->fixed_intrtimer = p->rx_coalesce_usecs * 194862306a36Sopenharmony_ci core_ticks_per_usec(sge->adapter); 194962306a36Sopenharmony_ci writel(sge->fixed_intrtimer, sge->adapter->regs + A_SG_INTRTIMER); 195062306a36Sopenharmony_ci return 0; 195162306a36Sopenharmony_ci} 195262306a36Sopenharmony_ci 195362306a36Sopenharmony_ci/* 195462306a36Sopenharmony_ci * Allocates both RX and TX resources and configures the SGE. However, 195562306a36Sopenharmony_ci * the hardware is not enabled yet. 195662306a36Sopenharmony_ci */ 195762306a36Sopenharmony_ciint t1_sge_configure(struct sge *sge, struct sge_params *p) 195862306a36Sopenharmony_ci{ 195962306a36Sopenharmony_ci if (alloc_rx_resources(sge, p)) 196062306a36Sopenharmony_ci return -ENOMEM; 196162306a36Sopenharmony_ci if (alloc_tx_resources(sge, p)) { 196262306a36Sopenharmony_ci free_rx_resources(sge); 196362306a36Sopenharmony_ci return -ENOMEM; 196462306a36Sopenharmony_ci } 196562306a36Sopenharmony_ci configure_sge(sge, p); 196662306a36Sopenharmony_ci 196762306a36Sopenharmony_ci /* 196862306a36Sopenharmony_ci * Now that we have sized the free lists calculate the payload 196962306a36Sopenharmony_ci * capacity of the large buffers. Other parts of the driver use 197062306a36Sopenharmony_ci * this to set the max offload coalescing size so that RX packets 197162306a36Sopenharmony_ci * do not overflow our large buffers. 197262306a36Sopenharmony_ci */ 197362306a36Sopenharmony_ci p->large_buf_capacity = jumbo_payload_capacity(sge); 197462306a36Sopenharmony_ci return 0; 197562306a36Sopenharmony_ci} 197662306a36Sopenharmony_ci 197762306a36Sopenharmony_ci/* 197862306a36Sopenharmony_ci * Disables the DMA engine. 197962306a36Sopenharmony_ci */ 198062306a36Sopenharmony_civoid t1_sge_stop(struct sge *sge) 198162306a36Sopenharmony_ci{ 198262306a36Sopenharmony_ci int i; 198362306a36Sopenharmony_ci writel(0, sge->adapter->regs + A_SG_CONTROL); 198462306a36Sopenharmony_ci readl(sge->adapter->regs + A_SG_CONTROL); /* flush */ 198562306a36Sopenharmony_ci 198662306a36Sopenharmony_ci if (is_T2(sge->adapter)) 198762306a36Sopenharmony_ci del_timer_sync(&sge->espibug_timer); 198862306a36Sopenharmony_ci 198962306a36Sopenharmony_ci del_timer_sync(&sge->tx_reclaim_timer); 199062306a36Sopenharmony_ci if (sge->tx_sched) 199162306a36Sopenharmony_ci tx_sched_stop(sge); 199262306a36Sopenharmony_ci 199362306a36Sopenharmony_ci for (i = 0; i < MAX_NPORTS; i++) 199462306a36Sopenharmony_ci kfree_skb(sge->espibug_skb[i]); 199562306a36Sopenharmony_ci} 199662306a36Sopenharmony_ci 199762306a36Sopenharmony_ci/* 199862306a36Sopenharmony_ci * Enables the DMA engine. 199962306a36Sopenharmony_ci */ 200062306a36Sopenharmony_civoid t1_sge_start(struct sge *sge) 200162306a36Sopenharmony_ci{ 200262306a36Sopenharmony_ci refill_free_list(sge, &sge->freelQ[0]); 200362306a36Sopenharmony_ci refill_free_list(sge, &sge->freelQ[1]); 200462306a36Sopenharmony_ci 200562306a36Sopenharmony_ci writel(sge->sge_control, sge->adapter->regs + A_SG_CONTROL); 200662306a36Sopenharmony_ci doorbell_pio(sge->adapter, F_FL0_ENABLE | F_FL1_ENABLE); 200762306a36Sopenharmony_ci readl(sge->adapter->regs + A_SG_CONTROL); /* flush */ 200862306a36Sopenharmony_ci 200962306a36Sopenharmony_ci mod_timer(&sge->tx_reclaim_timer, jiffies + TX_RECLAIM_PERIOD); 201062306a36Sopenharmony_ci 201162306a36Sopenharmony_ci if (is_T2(sge->adapter)) 201262306a36Sopenharmony_ci mod_timer(&sge->espibug_timer, jiffies + sge->espibug_timeout); 201362306a36Sopenharmony_ci} 201462306a36Sopenharmony_ci 201562306a36Sopenharmony_ci/* 201662306a36Sopenharmony_ci * Callback for the T2 ESPI 'stuck packet feature' workaorund 201762306a36Sopenharmony_ci */ 201862306a36Sopenharmony_cistatic void espibug_workaround_t204(struct timer_list *t) 201962306a36Sopenharmony_ci{ 202062306a36Sopenharmony_ci struct sge *sge = from_timer(sge, t, espibug_timer); 202162306a36Sopenharmony_ci struct adapter *adapter = sge->adapter; 202262306a36Sopenharmony_ci unsigned int nports = adapter->params.nports; 202362306a36Sopenharmony_ci u32 seop[MAX_NPORTS]; 202462306a36Sopenharmony_ci 202562306a36Sopenharmony_ci if (adapter->open_device_map & PORT_MASK) { 202662306a36Sopenharmony_ci int i; 202762306a36Sopenharmony_ci 202862306a36Sopenharmony_ci if (t1_espi_get_mon_t204(adapter, &(seop[0]), 0) < 0) 202962306a36Sopenharmony_ci return; 203062306a36Sopenharmony_ci 203162306a36Sopenharmony_ci for (i = 0; i < nports; i++) { 203262306a36Sopenharmony_ci struct sk_buff *skb = sge->espibug_skb[i]; 203362306a36Sopenharmony_ci 203462306a36Sopenharmony_ci if (!netif_running(adapter->port[i].dev) || 203562306a36Sopenharmony_ci netif_queue_stopped(adapter->port[i].dev) || 203662306a36Sopenharmony_ci !seop[i] || ((seop[i] & 0xfff) != 0) || !skb) 203762306a36Sopenharmony_ci continue; 203862306a36Sopenharmony_ci 203962306a36Sopenharmony_ci if (!skb->cb[0]) { 204062306a36Sopenharmony_ci skb_copy_to_linear_data_offset(skb, 204162306a36Sopenharmony_ci sizeof(struct cpl_tx_pkt), 204262306a36Sopenharmony_ci ch_mac_addr, 204362306a36Sopenharmony_ci ETH_ALEN); 204462306a36Sopenharmony_ci skb_copy_to_linear_data_offset(skb, 204562306a36Sopenharmony_ci skb->len - 10, 204662306a36Sopenharmony_ci ch_mac_addr, 204762306a36Sopenharmony_ci ETH_ALEN); 204862306a36Sopenharmony_ci skb->cb[0] = 0xff; 204962306a36Sopenharmony_ci } 205062306a36Sopenharmony_ci 205162306a36Sopenharmony_ci /* bump the reference count to avoid freeing of 205262306a36Sopenharmony_ci * the skb once the DMA has completed. 205362306a36Sopenharmony_ci */ 205462306a36Sopenharmony_ci skb = skb_get(skb); 205562306a36Sopenharmony_ci t1_sge_tx(skb, adapter, 0, adapter->port[i].dev); 205662306a36Sopenharmony_ci } 205762306a36Sopenharmony_ci } 205862306a36Sopenharmony_ci mod_timer(&sge->espibug_timer, jiffies + sge->espibug_timeout); 205962306a36Sopenharmony_ci} 206062306a36Sopenharmony_ci 206162306a36Sopenharmony_cistatic void espibug_workaround(struct timer_list *t) 206262306a36Sopenharmony_ci{ 206362306a36Sopenharmony_ci struct sge *sge = from_timer(sge, t, espibug_timer); 206462306a36Sopenharmony_ci struct adapter *adapter = sge->adapter; 206562306a36Sopenharmony_ci 206662306a36Sopenharmony_ci if (netif_running(adapter->port[0].dev)) { 206762306a36Sopenharmony_ci struct sk_buff *skb = sge->espibug_skb[0]; 206862306a36Sopenharmony_ci u32 seop = t1_espi_get_mon(adapter, 0x930, 0); 206962306a36Sopenharmony_ci 207062306a36Sopenharmony_ci if ((seop & 0xfff0fff) == 0xfff && skb) { 207162306a36Sopenharmony_ci if (!skb->cb[0]) { 207262306a36Sopenharmony_ci skb_copy_to_linear_data_offset(skb, 207362306a36Sopenharmony_ci sizeof(struct cpl_tx_pkt), 207462306a36Sopenharmony_ci ch_mac_addr, 207562306a36Sopenharmony_ci ETH_ALEN); 207662306a36Sopenharmony_ci skb_copy_to_linear_data_offset(skb, 207762306a36Sopenharmony_ci skb->len - 10, 207862306a36Sopenharmony_ci ch_mac_addr, 207962306a36Sopenharmony_ci ETH_ALEN); 208062306a36Sopenharmony_ci skb->cb[0] = 0xff; 208162306a36Sopenharmony_ci } 208262306a36Sopenharmony_ci 208362306a36Sopenharmony_ci /* bump the reference count to avoid freeing of the 208462306a36Sopenharmony_ci * skb once the DMA has completed. 208562306a36Sopenharmony_ci */ 208662306a36Sopenharmony_ci skb = skb_get(skb); 208762306a36Sopenharmony_ci t1_sge_tx(skb, adapter, 0, adapter->port[0].dev); 208862306a36Sopenharmony_ci } 208962306a36Sopenharmony_ci } 209062306a36Sopenharmony_ci mod_timer(&sge->espibug_timer, jiffies + sge->espibug_timeout); 209162306a36Sopenharmony_ci} 209262306a36Sopenharmony_ci 209362306a36Sopenharmony_ci/* 209462306a36Sopenharmony_ci * Creates a t1_sge structure and returns suggested resource parameters. 209562306a36Sopenharmony_ci */ 209662306a36Sopenharmony_cistruct sge *t1_sge_create(struct adapter *adapter, struct sge_params *p) 209762306a36Sopenharmony_ci{ 209862306a36Sopenharmony_ci struct sge *sge = kzalloc(sizeof(*sge), GFP_KERNEL); 209962306a36Sopenharmony_ci int i; 210062306a36Sopenharmony_ci 210162306a36Sopenharmony_ci if (!sge) 210262306a36Sopenharmony_ci return NULL; 210362306a36Sopenharmony_ci 210462306a36Sopenharmony_ci sge->adapter = adapter; 210562306a36Sopenharmony_ci sge->netdev = adapter->port[0].dev; 210662306a36Sopenharmony_ci sge->rx_pkt_pad = t1_is_T1B(adapter) ? 0 : 2; 210762306a36Sopenharmony_ci sge->jumbo_fl = t1_is_T1B(adapter) ? 1 : 0; 210862306a36Sopenharmony_ci 210962306a36Sopenharmony_ci for_each_port(adapter, i) { 211062306a36Sopenharmony_ci sge->port_stats[i] = alloc_percpu(struct sge_port_stats); 211162306a36Sopenharmony_ci if (!sge->port_stats[i]) 211262306a36Sopenharmony_ci goto nomem_port; 211362306a36Sopenharmony_ci } 211462306a36Sopenharmony_ci 211562306a36Sopenharmony_ci timer_setup(&sge->tx_reclaim_timer, sge_tx_reclaim_cb, 0); 211662306a36Sopenharmony_ci 211762306a36Sopenharmony_ci if (is_T2(sge->adapter)) { 211862306a36Sopenharmony_ci timer_setup(&sge->espibug_timer, 211962306a36Sopenharmony_ci adapter->params.nports > 1 ? espibug_workaround_t204 : espibug_workaround, 212062306a36Sopenharmony_ci 0); 212162306a36Sopenharmony_ci 212262306a36Sopenharmony_ci if (adapter->params.nports > 1) 212362306a36Sopenharmony_ci tx_sched_init(sge); 212462306a36Sopenharmony_ci 212562306a36Sopenharmony_ci sge->espibug_timeout = 1; 212662306a36Sopenharmony_ci /* for T204, every 10ms */ 212762306a36Sopenharmony_ci if (adapter->params.nports > 1) 212862306a36Sopenharmony_ci sge->espibug_timeout = HZ/100; 212962306a36Sopenharmony_ci } 213062306a36Sopenharmony_ci 213162306a36Sopenharmony_ci 213262306a36Sopenharmony_ci p->cmdQ_size[0] = SGE_CMDQ0_E_N; 213362306a36Sopenharmony_ci p->cmdQ_size[1] = SGE_CMDQ1_E_N; 213462306a36Sopenharmony_ci p->freelQ_size[!sge->jumbo_fl] = SGE_FREEL_SIZE; 213562306a36Sopenharmony_ci p->freelQ_size[sge->jumbo_fl] = SGE_JUMBO_FREEL_SIZE; 213662306a36Sopenharmony_ci if (sge->tx_sched) { 213762306a36Sopenharmony_ci if (board_info(sge->adapter)->board == CHBT_BOARD_CHT204) 213862306a36Sopenharmony_ci p->rx_coalesce_usecs = 15; 213962306a36Sopenharmony_ci else 214062306a36Sopenharmony_ci p->rx_coalesce_usecs = 50; 214162306a36Sopenharmony_ci } else 214262306a36Sopenharmony_ci p->rx_coalesce_usecs = 50; 214362306a36Sopenharmony_ci 214462306a36Sopenharmony_ci p->coalesce_enable = 0; 214562306a36Sopenharmony_ci p->sample_interval_usecs = 0; 214662306a36Sopenharmony_ci 214762306a36Sopenharmony_ci return sge; 214862306a36Sopenharmony_cinomem_port: 214962306a36Sopenharmony_ci while (i >= 0) { 215062306a36Sopenharmony_ci free_percpu(sge->port_stats[i]); 215162306a36Sopenharmony_ci --i; 215262306a36Sopenharmony_ci } 215362306a36Sopenharmony_ci kfree(sge); 215462306a36Sopenharmony_ci return NULL; 215562306a36Sopenharmony_ci 215662306a36Sopenharmony_ci} 2157