- upgrade to reflect state of 1.0.0.86
        - move from firmware rev 3.2 to 4.0.0
        - import driver bits for offload functionality
	- remove binary distribution clause from top level files as it
	  runs counter to the intent of purely supporting the hardware

MFC after: 3 days
This commit is contained in:
Kip Macy 2007-05-25 09:48:20 +00:00
parent 55e1a40108
commit d722cab49a
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=169978
23 changed files with 4921 additions and 1125 deletions

View file

@ -514,6 +514,8 @@ dev/cs/if_cs.c optional cs
dev/cs/if_cs_isa.c optional cs isa
dev/cs/if_cs_pccard.c optional cs pccard
dev/cxgb/cxgb_main.c optional cxgb pci
dev/cxgb/cxgb_offload.c optional cxgb pci
dev/cxgb/cxgb_l2t.c optional cxgb pci
dev/cxgb/cxgb_lro.c optional cxgb pci
dev/cxgb/cxgb_sge.c optional cxgb pci
dev/cxgb/common/cxgb_mc5.c optional cxgb pci

View file

@ -46,6 +46,7 @@ enum {
NMTUS = 16, /* size of MTU table */
NCCTRL_WIN = 32, /* # of congestion control windows */
NTX_SCHED = 8, /* # of HW Tx scheduling queues */
TP_TMR_RES = 200, /* TP timer resolution in usec */
};
#define MAX_RX_COALESCING_LEN 16224U
@ -57,7 +58,6 @@ enum {
};
enum {
SUPPORTED_OFFLOAD = 1 << 24,
SUPPORTED_IRQ = 1 << 25
};
@ -70,8 +70,8 @@ enum { /* adapter interrupt-maintained statistics */
};
enum {
FW_VERSION_MAJOR = 3,
FW_VERSION_MINOR = 2,
FW_VERSION_MAJOR = 4,
FW_VERSION_MINOR = 0,
FW_VERSION_MICRO = 0
};
@ -309,6 +309,9 @@ enum {
MC5_MODE_72_BIT = 2
};
/* MC5 min active region size */
enum { MC5_MIN_TIDS = 16 };
struct vpd_params {
unsigned int cclk;
unsigned int mclk;
@ -354,6 +357,7 @@ struct adapter_params {
unsigned int stats_update_period; /* MAC stats accumulation period */
unsigned int linkpoll_period; /* link poll period in 0.1s */
unsigned int rev; /* chip revision */
unsigned int offload;
};
enum { /* chip revisions */
@ -427,8 +431,11 @@ struct cmac {
adapter_t *adapter;
unsigned int offset;
unsigned int nucast; /* # of address filters for unicast MACs */
unsigned int tcnt;
unsigned int xcnt;
unsigned int tx_tcnt;
unsigned int tx_xcnt;
u64 tx_mcnt;
unsigned int rx_xcnt;
u64 rx_mcnt;
unsigned int toggle_cnt;
unsigned int txen;
struct mac_stats stats;
@ -555,7 +562,7 @@ static inline int is_10G(const adapter_t *adap)
static inline int is_offload(const adapter_t *adap)
{
#ifdef CONFIG_CHELSIO_T3_CORE
return adapter_info(adap)->caps & SUPPORTED_OFFLOAD;
return adap->params.offload;
#else
return 0;
#endif

View file

@ -329,6 +329,9 @@ int t3_mc5_init(struct mc5 *mc5, unsigned int nservers, unsigned int nfilters,
unsigned int tcam_size = mc5->tcam_size;
adapter_t *adap = mc5->adapter;
if (tcam_size == 0)
return 0;
if (nroutes > MAX_ROUTES || nroutes + nservers + nfilters > tcam_size)
return -EINVAL;

View file

@ -260,6 +260,20 @@ struct work_request_hdr {
#define V_WR_BCNTLFLT(x) ((x) << S_WR_BCNTLFLT)
#define G_WR_BCNTLFLT(x) (((x) >> S_WR_BCNTLFLT) & M_WR_BCNTLFLT)
/* Applicable to BYPASS WRs only: the uP will added a CPL_BARRIER before
* and after the BYPASS WR if the ATOMIC bit is set.
*/
#define S_WR_ATOMIC 16
#define V_WR_ATOMIC(x) ((x) << S_WR_ATOMIC)
#define F_WR_ATOMIC V_WR_ATOMIC(1U)
/* Applicable to BYPASS WRs only: the uP will flush buffered non abort
* related WRs.
*/
#define S_WR_FLUSH 17
#define V_WR_FLUSH(x) ((x) << S_WR_FLUSH)
#define F_WR_FLUSH V_WR_FLUSH(1U)
#define S_WR_DATATYPE 20
#define V_WR_DATATYPE(x) ((x) << S_WR_DATATYPE)
#define F_WR_DATATYPE V_WR_DATATYPE(1U)
@ -1487,4 +1501,46 @@ struct cpl_rdma_terminate {
#define M_TERM_TID 0xFFFFF
#define V_TERM_TID(x) ((x) << S_TERM_TID)
#define G_TERM_TID(x) (((x) >> S_TERM_TID) & M_TERM_TID)
/* ULP_TX opcodes */
enum { ULP_MEM_READ = 2, ULP_MEM_WRITE = 3, ULP_TXPKT = 4 };
#define S_ULPTX_CMD 28
#define M_ULPTX_CMD 0xF
#define V_ULPTX_CMD(x) ((x) << S_ULPTX_CMD)
#define S_ULPTX_NFLITS 0
#define M_ULPTX_NFLITS 0xFF
#define V_ULPTX_NFLITS(x) ((x) << S_ULPTX_NFLITS)
struct ulp_mem_io {
WR_HDR;
__be32 cmd_lock_addr;
__be32 len;
};
/* ulp_mem_io.cmd_lock_addr fields */
#define S_ULP_MEMIO_ADDR 0
#define M_ULP_MEMIO_ADDR 0x7FFFFFF
#define V_ULP_MEMIO_ADDR(x) ((x) << S_ULP_MEMIO_ADDR)
#define S_ULP_MEMIO_LOCK 27
#define V_ULP_MEMIO_LOCK(x) ((x) << S_ULP_MEMIO_LOCK)
#define F_ULP_MEMIO_LOCK V_ULP_MEMIO_LOCK(1U)
/* ulp_mem_io.len fields */
#define S_ULP_MEMIO_DATA_LEN 28
#define M_ULP_MEMIO_DATA_LEN 0xF
#define V_ULP_MEMIO_DATA_LEN(x) ((x) << S_ULP_MEMIO_DATA_LEN)
struct ulp_txpkt {
__be32 cmd_dest;
__be32 len;
};
/* ulp_txpkt.cmd_dest fields */
#define S_ULP_TXPKT_DEST 24
#define M_ULP_TXPKT_DEST 0xF
#define V_ULP_TXPKT_DEST(x) ((x) << S_ULP_TXPKT_DEST)
#endif /* T3_CPL_H */

View file

@ -441,23 +441,23 @@ static struct adapter_info t3_adap_info[] = {
{ 2, 0, 0, 0,
F_GPIO2_OEN | F_GPIO4_OEN |
F_GPIO2_OUT_VAL | F_GPIO4_OUT_VAL, F_GPIO3 | F_GPIO5,
SUPPORTED_OFFLOAD,
0,
&mi1_mdio_ops, "Chelsio PE9000" },
{ 2, 0, 0, 0,
F_GPIO2_OEN | F_GPIO4_OEN |
F_GPIO2_OUT_VAL | F_GPIO4_OUT_VAL, F_GPIO3 | F_GPIO5,
SUPPORTED_OFFLOAD,
0,
&mi1_mdio_ops, "Chelsio T302" },
{ 1, 0, 0, 0,
F_GPIO1_OEN | F_GPIO6_OEN | F_GPIO7_OEN | F_GPIO10_OEN |
F_GPIO1_OUT_VAL | F_GPIO6_OUT_VAL | F_GPIO10_OUT_VAL, 0,
SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_OFFLOAD,
SUPPORTED_10000baseT_Full | SUPPORTED_AUI,
&mi1_mdio_ext_ops, "Chelsio T310" },
{ 2, 0, 0, 0,
F_GPIO1_OEN | F_GPIO2_OEN | F_GPIO4_OEN | F_GPIO5_OEN | F_GPIO6_OEN |
F_GPIO7_OEN | F_GPIO10_OEN | F_GPIO11_OEN | F_GPIO1_OUT_VAL |
F_GPIO5_OUT_VAL | F_GPIO6_OUT_VAL | F_GPIO10_OUT_VAL, 0,
SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_OFFLOAD,
SUPPORTED_10000baseT_Full | SUPPORTED_AUI,
&mi1_mdio_ext_ops, "Chelsio T320" },
};
@ -2387,9 +2387,6 @@ static void tp_config(adapter_t *adap, const struct tp_params *p)
t3_write_reg(adap, A_TP_MOD_RATE_LIMIT, 0);
}
/* Desired TP timer resolution in usec */
#define TP_TMR_RES 200
/* TCP timer values in ms */
#define TP_DACK_TIMER 50
#define TP_RTO_MIN 250
@ -3005,6 +3002,9 @@ static int mc7_init(struct mc7 *mc7, unsigned int mc7_clock, int mem_type)
adapter_t *adapter = mc7->adapter;
const struct mc7_timing_params *p = &mc7_timings[mem_type];
if (mc7->size == 0)
return 0;
val = t3_read_reg(adapter, mc7->offset + A_MC7_CFG);
slow = val & F_SLOW;
width = G_WIDTH(val);
@ -3209,9 +3209,10 @@ int t3_init_hw(adapter_t *adapter, u32 fw_params)
do { /* wait for uP to initialize */
t3_os_sleep(20);
} while (t3_read_reg(adapter, A_CIM_HOST_ACC_DATA) && --attempts);
if (!attempts)
if (!attempts) {
CH_ERR(adapter, "uP initialization timed out\n");
goto out_err;
}
err = 0;
out_err:
return err;
@ -3309,7 +3310,7 @@ static void __devinit mc7_prep(adapter_t *adapter, struct mc7 *mc7,
mc7->name = name;
mc7->offset = base_addr - MC7_PMRX_BASE_ADDR;
cfg = t3_read_reg(adapter, mc7->offset + A_MC7_CFG);
mc7->size = mc7_calc_size(cfg);
mc7->size = G_DEN(cfg) == M_DEN ? 0 : mc7_calc_size(cfg);
mc7->width = G_WIDTH(cfg);
}
@ -3336,7 +3337,8 @@ void early_hw_init(adapter_t *adapter, const struct adapter_info *ai)
V_I2C_CLKDIV(adapter->params.vpd.cclk / 80 - 1));
t3_write_reg(adapter, A_T3DBG_GPIO_EN,
ai->gpio_out | F_GPIO0_OEN | F_GPIO0_OUT_VAL);
t3_write_reg(adapter, A_MC5_DB_SERVER_INDEX, 0);
if (adapter->params.rev == 0 || !uses_xaui(adapter))
val |= F_ENRGMII;
@ -3435,7 +3437,12 @@ int __devinit t3_prep_adapter(adapter_t *adapter,
p->ntimer_qs = p->cm_size >= (128 << 20) ||
adapter->params.rev > 0 ? 12 : 6;
p->dack_re = fls(adapter->params.vpd.cclk / 10) - 1; /* 100us */
}
adapter->params.offload = t3_mc7_size(&adapter->pmrx) &&
t3_mc7_size(&adapter->pmtx) &&
t3_mc7_size(&adapter->cm);
if (is_offload(adapter)) {
adapter->params.mc5.nservers = DEFAULT_NSERVERS;
adapter->params.mc5.nfilters = adapter->params.rev > 0 ?
DEFAULT_NFILTERS : 0;

View file

@ -41,5 +41,5 @@ POSSIBILITY OF SUCH DAMAGE.
#define __CHELSIO_VERSION_H
#define DRV_DESC "Chelsio T3 Network Driver"
#define DRV_NAME "cxgb"
#define DRV_VERSION "1.0.071"
#endif
#define DRV_VERSION "1.0.086"
#endif

View file

@ -329,8 +329,8 @@ int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu)
thres = mtu > thres ? (mtu - thres + 7) / 8 : 0;
thres = max(thres, 8U); /* need at least 8 */
t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + mac->offset,
V_TXFIFOTHRESH(M_TXFIFOTHRESH) | V_TXIPG(M_TXIPG),
V_TXFIFOTHRESH(thres) | V_TXIPG(1));
V_TXFIFOTHRESH(M_TXFIFOTHRESH) | V_TXIPG(M_TXIPG),
V_TXFIFOTHRESH(thres) | V_TXIPG(1));
/* Assuming a minimum drain rate of 2.5Gbps...
*/
@ -365,7 +365,7 @@ int t3_mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex, int fc)
t3_set_reg_field(adap, A_XGM_PORT_CFG + oft,
V_PORTSPEED(M_PORTSPEED), val);
}
#if 0
#if 0
val = t3_read_reg(adap, A_XGM_RXFIFO_CFG + oft);
val &= ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM);
if (fc & PAUSE_TX)
@ -382,6 +382,7 @@ int t3_mac_enable(struct cmac *mac, int which)
int idx = macidx(mac);
adapter_t *adap = mac->adapter;
unsigned int oft = mac->offset;
struct mac_stats *s = &mac->stats;
if (which & MAC_DIRECTION_TX) {
t3_write_reg(adap, A_XGM_TX_CTRL + oft, F_TXEN);
@ -391,12 +392,20 @@ int t3_mac_enable(struct cmac *mac, int which)
t3_set_reg_field(adap, A_TP_PIO_DATA, 1 << idx, 1 << idx);
t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CNT_CH0 + idx);
mac->tcnt = (G_TXDROPCNTCH0RCVD(t3_read_reg(adap, A_TP_PIO_DATA)));
mac->xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap, A_XGM_TX_SPI4_SOP_EOP_CNT)));
mac->tx_mcnt = s->tx_frames;
mac->tx_tcnt = (G_TXDROPCNTCH0RCVD(t3_read_reg(adap,
A_TP_PIO_DATA)));
mac->tx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap,
A_XGM_TX_SPI4_SOP_EOP_CNT +
oft)));
mac->rx_mcnt = s->rx_frames;
mac->rx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap,
A_XGM_RX_SPI4_SOP_EOP_CNT +
oft)));
mac->txen = F_TXEN;
mac->toggle_cnt = 0;
}
if (which & MAC_DIRECTION_RX)
if (which & MAC_DIRECTION_RX)
t3_write_reg(adap, A_XGM_RX_CTRL + oft, F_RXEN);
return 0;
}
@ -405,6 +414,7 @@ int t3_mac_disable(struct cmac *mac, int which)
{
int idx = macidx(mac);
adapter_t *adap = mac->adapter;
int val;
if (which & MAC_DIRECTION_TX) {
t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, 0);
@ -414,39 +424,99 @@ int t3_mac_disable(struct cmac *mac, int which)
t3_set_reg_field(adap, A_TP_PIO_DATA, 1 << idx, 1 << idx);
mac->txen = 0;
}
if (which & MAC_DIRECTION_RX)
if (which & MAC_DIRECTION_RX) {
t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset,
F_PCS_RESET_, 0);
t3_os_sleep(100);
t3_write_reg(adap, A_XGM_RX_CTRL + mac->offset, 0);
val = F_MAC_RESET_;
if (is_10G(adap))
val |= F_PCS_RESET_;
else if (uses_xaui(adap))
val |= F_PCS_RESET_ | F_XG2G_RESET_;
else
val |= F_RGMII_RESET_ | F_XG2G_RESET_;
t3_write_reg(mac->adapter, A_XGM_RESET_CTRL + mac->offset, val);
}
return 0;
}
int t3b2_mac_watchdog_task(struct cmac *mac)
{
int status;
unsigned int tcnt, xcnt;
unsigned int tx_tcnt, tx_xcnt;
adapter_t *adap = mac->adapter;
t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CNT_CH0 + macidx(mac));
tcnt = (G_TXDROPCNTCH0RCVD(t3_read_reg(adap, A_TP_PIO_DATA)));
xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap, A_XGM_TX_SPI4_SOP_EOP_CNT + mac->offset)));
struct mac_stats *s = &mac->stats;
unsigned int tx_mcnt = (unsigned int)s->tx_frames;
unsigned int rx_mcnt = (unsigned int)s->rx_frames;
unsigned int rx_xcnt;
if ((tcnt != mac->tcnt) && (xcnt == 0) && (mac->xcnt == 0)) {
if (mac->toggle_cnt > 4) {
t3b2_mac_reset(mac);
mac->toggle_cnt = 0;
status = 2;
status = 0;
tx_xcnt = 1; /* By default tx_xcnt is making progress*/
tx_tcnt = mac->tx_tcnt; /* If tx_mcnt is progressing ignore tx_tcnt*/
rx_xcnt = 1; /* By default rx_xcnt is making progress*/
if (tx_mcnt == mac->tx_mcnt) {
tx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap,
A_XGM_TX_SPI4_SOP_EOP_CNT +
mac->offset)));
if (tx_xcnt == 0) {
t3_write_reg(adap, A_TP_PIO_ADDR,
A_TP_TX_DROP_CNT_CH0 + macidx(mac));
tx_tcnt = (G_TXDROPCNTCH0RCVD(t3_read_reg(adap,
A_TP_PIO_DATA)));
} else {
t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, 0);
t3_read_reg(adap, A_XGM_TX_CTRL + mac->offset); /* flush */
t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, mac->txen);
t3_read_reg(adap, A_XGM_TX_CTRL + mac->offset); /* flush */
mac->toggle_cnt++;
status = 1;
}
goto rxcheck;
}
} else {
mac->toggle_cnt = 0;
status = 0;
goto rxcheck;
}
if (((tx_tcnt != mac->tx_tcnt) &&
(tx_xcnt == 0) && (mac->tx_xcnt == 0)) ||
((mac->tx_mcnt == tx_mcnt) &&
(tx_xcnt != 0) && (mac->tx_xcnt != 0))) {
if (mac->toggle_cnt > 4) {
status = 2;
goto out;
} else {
status = 1;
goto out;
}
} else {
mac->toggle_cnt = 0;
goto rxcheck;
}
rxcheck:
if (rx_mcnt != mac->rx_mcnt)
rx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap,
A_XGM_RX_SPI4_SOP_EOP_CNT +
mac->offset)));
else
goto out;
if (mac->rx_mcnt != s->rx_frames && rx_xcnt == 0 && mac->rx_xcnt == 0) {
status = 2;
goto out;
}
out:
mac->tx_tcnt = tx_tcnt;
mac->tx_xcnt = tx_xcnt;
mac->tx_mcnt = s->tx_frames;
mac->rx_xcnt = rx_xcnt;
mac->rx_mcnt = s->rx_frames;
if (status == 1) {
t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, 0);
t3_read_reg(adap, A_XGM_TX_CTRL + mac->offset); /* flush */
t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, mac->txen);
t3_read_reg(adap, A_XGM_TX_CTRL + mac->offset); /* flush */
mac->toggle_cnt++;
} else if (status == 2) {
t3b2_mac_reset(mac);
mac->toggle_cnt = 0;
}
mac->tcnt = tcnt;
mac->xcnt = xcnt;
return status;
}

140
sys/dev/cxgb/common/jhash.h Normal file
View file

@ -0,0 +1,140 @@
#ifndef _JHASH_H
#define _JHASH_H
/* jhash.h: Jenkins hash support.
*
* Copyright (C) 1996 Bob Jenkins (bob_jenkins@burtleburtle.net)
*
* http://burtleburtle.net/bob/hash/
*
* These are the credits from Bob's sources:
*
* lookup2.c, by Bob Jenkins, December 1996, Public Domain.
* hash(), hash2(), hash3, and mix() are externally useful functions.
* Routines to test the hash are included if SELF_TEST is defined.
* You can use this free for any purpose. It has no warranty.
*
* $FreeBSD$
*/
/* NOTE: Arguments are modified. */
#define __jhash_mix(a, b, c) \
{ \
a -= b; a -= c; a ^= (c>>13); \
b -= c; b -= a; b ^= (a<<8); \
c -= a; c -= b; c ^= (b>>13); \
a -= b; a -= c; a ^= (c>>12); \
b -= c; b -= a; b ^= (a<<16); \
c -= a; c -= b; c ^= (b>>5); \
a -= b; a -= c; a ^= (c>>3); \
b -= c; b -= a; b ^= (a<<10); \
c -= a; c -= b; c ^= (b>>15); \
}
/* The golden ration: an arbitrary value */
#define JHASH_GOLDEN_RATIO 0x9e3779b9
/* The most generic version, hashes an arbitrary sequence
* of bytes. No alignment or length assumptions are made about
* the input key.
*/
static inline u32 jhash(const void *key, u32 length, u32 initval)
{
u32 a, b, c, len;
const u8 *k = key;
len = length;
a = b = JHASH_GOLDEN_RATIO;
c = initval;
while (len >= 12) {
a += (k[0] +((u32)k[1]<<8) +((u32)k[2]<<16) +((u32)k[3]<<24));
b += (k[4] +((u32)k[5]<<8) +((u32)k[6]<<16) +((u32)k[7]<<24));
c += (k[8] +((u32)k[9]<<8) +((u32)k[10]<<16)+((u32)k[11]<<24));
__jhash_mix(a,b,c);
k += 12;
len -= 12;
}
c += length;
switch (len) {
case 11: c += ((u32)k[10]<<24);
case 10: c += ((u32)k[9]<<16);
case 9 : c += ((u32)k[8]<<8);
case 8 : b += ((u32)k[7]<<24);
case 7 : b += ((u32)k[6]<<16);
case 6 : b += ((u32)k[5]<<8);
case 5 : b += k[4];
case 4 : a += ((u32)k[3]<<24);
case 3 : a += ((u32)k[2]<<16);
case 2 : a += ((u32)k[1]<<8);
case 1 : a += k[0];
};
__jhash_mix(a,b,c);
return c;
}
/* A special optimized version that handles 1 or more of u32s.
* The length parameter here is the number of u32s in the key.
*/
static inline u32 jhash2(u32 *k, u32 length, u32 initval)
{
u32 a, b, c, len;
a = b = JHASH_GOLDEN_RATIO;
c = initval;
len = length;
while (len >= 3) {
a += k[0];
b += k[1];
c += k[2];
__jhash_mix(a, b, c);
k += 3; len -= 3;
}
c += length * 4;
switch (len) {
case 2 : b += k[1];
case 1 : a += k[0];
};
__jhash_mix(a,b,c);
return c;
}
/* A special ultra-optimized versions that knows they are hashing exactly
* 3, 2 or 1 word(s).
*
* NOTE: In partilar the "c += length; __jhash_mix(a,b,c);" normally
* done at the end is not done here.
*/
static inline u32 jhash_3words(u32 a, u32 b, u32 c, u32 initval)
{
a += JHASH_GOLDEN_RATIO;
b += JHASH_GOLDEN_RATIO;
c += initval;
__jhash_mix(a, b, c);
return c;
}
static inline u32 jhash_2words(u32 a, u32 b, u32 initval)
{
return jhash_3words(a, b, 0, initval);
}
static inline u32 jhash_1word(u32 a, u32 initval)
{
return jhash_3words(a, 0, 0, initval);
}
#endif /* _JHASH_H */

View file

@ -9,11 +9,7 @@ modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the Chelsio Corporation nor the names of its
2. Neither the name of the Chelsio Corporation nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
@ -59,6 +55,9 @@ __FBSDID("$FreeBSD$");
#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>
#include <dev/cxgb/ulp/toecore/toedev.h>
#include <dev/cxgb/sys/mbufq.h>
struct adapter;
struct sge_qset;
extern int cxgb_debug;
@ -91,9 +90,6 @@ enum { /* adapter flags */
FW_UPTODATE = (1 << 4),
};
/* Max active LRO sessions per queue set */
#define MAX_LRO_PER_QSET 8
#define FL_Q_SIZE 4096
#define JUMBO_Q_SIZE 512
@ -114,25 +110,23 @@ enum {
LRO_ACTIVE = (1 << 8),
};
struct sge_lro_session {
struct mbuf *m;
/* Max concurrent LRO sessions per queue set */
#define MAX_LRO_SES 8
struct t3_lro_session {
struct mbuf *head;
struct mbuf *tail;
uint32_t seq;
uint16_t ip_len;
uint16_t vtag;
uint8_t npkts;
};
struct sge_lro {
unsigned int enabled;
unsigned int num_active;
struct sge_lro_session *last_s;
struct sge_lro_session s[MAX_LRO_PER_QSET];
};
/* has its own header on linux XXX
* but I don't even know what it is :-/
*/
struct t3cdev {
int foo; /* XXX fill in */
struct lro_state {
unsigned short enabled;
unsigned short active_idx;
unsigned int nactive;
struct t3_lro_session sess[MAX_LRO_SES];
};
#define RX_BUNDLE_SIZE 8
@ -148,14 +142,21 @@ struct sge_rspq {
uint32_t holdoff_tmr;
uint32_t next_holdoff;
uint32_t imm_data;
uint32_t pure_rsps;
struct rsp_desc *desc;
bus_addr_t phys_addr;
uint32_t cntxt_id;
struct mtx lock;
struct mbuf *rx_head; /* offload packet receive queue head */
struct mbuf *rx_tail; /* offload packet receive queue tail */
uint32_t offload_pkts;
uint32_t offload_bundles;
uint32_t pure_rsps;
uint32_t unhandled_irqs;
bus_addr_t phys_addr;
bus_dma_tag_t desc_tag;
bus_dmamap_t desc_map;
struct mbuf *m;
struct mtx lock;
};
struct rx_desc;
@ -198,12 +199,14 @@ struct sge_txq {
struct tx_sw_desc *sdesc;
uint32_t token;
bus_addr_t phys_addr;
struct task qresume_tsk;
uint32_t cntxt_id;
uint64_t stops;
uint64_t restarts;
bus_dma_tag_t desc_tag;
bus_dmamap_t desc_map;
bus_dma_tag_t entry_tag;
struct mbuf_head sendq;
struct mtx lock;
};
@ -224,9 +227,9 @@ enum {
struct sge_qset {
struct sge_rspq rspq;
struct sge_fl fl[SGE_RXQ_PER_SET];
struct sge_lro lro;
struct lro_state lro;
struct sge_txq txq[SGE_TXQ_PER_SET];
unsigned long txq_stopped; /* which Tx queues are stopped */
uint32_t txq_stopped; /* which Tx queues are stopped */
uint64_t port_stats[SGE_PSTAT_MAX];
struct port_info *port;
int idx; /* qset # */
@ -240,6 +243,7 @@ struct sge {
struct adapter {
device_t dev;
int flags;
TAILQ_ENTRY(adapter) adapter_entry;
/* PCI register resources */
uint32_t regs_rid;
@ -248,6 +252,7 @@ struct adapter {
bus_space_tag_t bt;
bus_size_t mmio_len;
uint32_t link_width;
/* DMA resources */
bus_dma_tag_t parent_dmat;
@ -293,10 +298,13 @@ struct adapter {
struct port_info port[MAX_NPORTS];
device_t portdev[MAX_NPORTS];
struct t3cdev tdev;
struct toedev tdev;
char fw_version[64];
uint32_t open_device_map;
uint32_t registered_device_map;
struct mtx lock;
driver_intr_t *cxgb_intr;
int msi_count;
};
struct t3_rx_mode {
@ -384,6 +392,7 @@ int t3_os_pci_restore_state(struct adapter *adapter);
void t3_os_link_changed(adapter_t *adapter, int port_id, int link_status,
int speed, int duplex, int fc);
void t3_sge_err_intr_handler(adapter_t *adapter);
int t3_offload_tx(struct toedev *, struct mbuf *);
void t3_os_ext_intr_handler(adapter_t *adapter);
void t3_os_set_hw_addr(adapter_t *adapter, int port_idx, u8 hw_addr[]);
int t3_mgmt_tx(adapter_t *adap, struct mbuf *m);
@ -395,6 +404,7 @@ int t3_sge_alloc_qset(adapter_t *, uint32_t, int, int, const struct qset_params
int, struct port_info *);
void t3_free_sge_resources(adapter_t *);
void t3_sge_start(adapter_t *);
void t3_sge_stop(adapter_t *);
void t3b_intr(void *data);
void t3_intr_msi(void *data);
void t3_intr_msix(void *data);
@ -406,7 +416,7 @@ void t3_sge_deinit_sw(adapter_t *);
void t3_rx_eth_lro(adapter_t *adap, struct sge_rspq *rq, struct mbuf *m,
int ethpad, uint32_t rss_hash, uint32_t rss_csum, int lro);
void t3_rx_eth(struct port_info *p, struct sge_rspq *rq, struct mbuf *m, int ethpad);
void t3_sge_lro_flush_all(adapter_t *adap, struct sge_qset *qs);
void t3_lro_flush(adapter_t *adap, struct sge_qset *qs, struct lro_state *state);
void t3_add_sysctls(adapter_t *sc);
int t3_get_desc(const struct sge_qset *qs, unsigned int qnum, unsigned int idx,
@ -437,6 +447,19 @@ txq_to_qset(struct sge_txq *q, int qidx)
return container_of(q, struct sge_qset, txq[qidx]);
}
static __inline struct adapter *
tdev2adap(struct toedev *d)
{
return container_of(d, struct adapter, tdev);
}
#undef container_of
#define OFFLOAD_DEVMAP_BIT 15
static inline int offload_running(adapter_t *adapter)
{
return isset(&adapter->open_device_map, OFFLOAD_DEVMAP_BIT);
}
#endif

View file

@ -9,11 +9,7 @@ modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the Chelsio Corporation nor the names of its
2. Neither the name of the Chelsio Corporation nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.

View file

@ -9,11 +9,7 @@ modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the Chelsio Corporation nor the names of its
2. Neither the name of the Chelsio Corporation nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
@ -68,7 +64,8 @@ enum {
CH_IFCONF_GETREGS,
CH_GETMIIREGS,
CH_SETMIIREGS,
CH_SET_FILTER,
CH_SET_HW_SCHED,
};
struct ch_reg {
@ -217,6 +214,7 @@ struct mii_data {
#define CHELSIO_SETREG _IOW('f', CH_SETREG, struct ch_reg)
#define CHELSIO_GETREG _IOWR('f', CH_GETREG, struct ch_reg)
#define CHELSIO_READ_TCAM_WORD _IOR('f', CH_READ_TCAM_WORD, struct ch_tcam)
#define CHELSIO_GET_MEM _IOWR('f', CH_GET_MEM, struct ch_mem_range)
#define CHELSIO_GET_SGE_CONTEXT _IOWR('f', CH_GET_SGE_CONTEXT, struct ch_cntxt)
#define CHELSIO_GET_SGE_DESC _IOWR('f', CH_GET_SGE_DESC, struct ch_desc)
@ -224,6 +222,8 @@ struct mii_data {
#define CHELSIO_SET_QSET_PARAMS _IOW('f', CH_SET_QSET_PARAMS, struct ch_qset_params)
#define CHELSIO_GET_QSET_NUM _IOWR('f', CH_GET_QSET_NUM, struct ch_reg)
#define CHELSIO_SET_QSET_NUM _IOW('f', CH_SET_QSET_NUM, struct ch_reg)
#define CHELSIO_GETMTUTAB _IOR('f', CH_GET_QSET_NUM, struct ch_mtus)
#define CHELSIO_SETMTUTAB _IOW('f', CH_SET_QSET_NUM, struct ch_mtus)
#define CHELSIO_SET_TRACE_FILTER _IOW('f', CH_SET_TRACE_FILTER, struct ch_trace)
@ -231,4 +231,6 @@ struct mii_data {
#define CHELSIO_IFCONF_GETREGS _IOWR('f', CH_IFCONF_GETREGS, struct ifconf_regs)
#define SIOCGMIIREG _IOWR('f', CH_GETMIIREGS, struct mii_data)
#define SIOCSMIIREG _IOWR('f', CH_SETMIIREGS, struct mii_data)
#define CHELSIO_SET_HW_SCHED _IOWR('f', CH_SET_HW_SCHED, struct ch_hw_sched)
#define CHELSIO_DEVUP _IO('f', CH_DEVUP)
#endif

670
sys/dev/cxgb/cxgb_l2t.c Normal file
View file

@ -0,0 +1,670 @@
/**************************************************************************
Copyright (c) 2007, Chelsio Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Neither the name of the Chelsio Corporation nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
***************************************************************************/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/bus.h>
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/rwlock.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <net/if.h>
#include <net/ethernet.h>
#include <net/if_vlan_var.h>
#include <net/if_dl.h>
#include <net/route.h>
#include <netinet/in.h>
#include <netinet/if_ether.h>
#include <dev/cxgb/common/cxgb_common.h>
#include <dev/cxgb/common/cxgb_regs.h>
#include <dev/cxgb/common/cxgb_sge_defs.h>
#include <dev/cxgb/common/cxgb_t3_cpl.h>
#include <dev/cxgb/common/cxgb_firmware_exports.h>
#include <dev/cxgb/common/jhash.h>
#include <dev/cxgb/cxgb_offload.h>
#define VLAN_NONE 0xfff
#define SDL(s) ((struct sockaddr_dl *)s)
#define RT_ENADDR(rt) ((char *)LLADDR(SDL((rt))))
#define rt_expire rt_rmx.rmx_expire
struct llinfo_arp {
struct callout la_timer;
struct rtentry *la_rt;
struct mbuf *la_hold; /* last packet until resolved/timeout */
u_short la_preempt; /* countdown for pre-expiry arps */
u_short la_asked; /* # requests sent */
};
/*
* Module locking notes: There is a RW lock protecting the L2 table as a
* whole plus a spinlock per L2T entry. Entry lookups and allocations happen
* under the protection of the table lock, individual entry changes happen
* while holding that entry's spinlock. The table lock nests outside the
* entry locks. Allocations of new entries take the table lock as writers so
* no other lookups can happen while allocating new entries. Entry updates
* take the table lock as readers so multiple entries can be updated in
* parallel. An L2T entry can be dropped by decrementing its reference count
* and therefore can happen in parallel with entry allocation but no entry
* can change state or increment its ref count during allocation as both of
* these perform lookups.
*/
static inline unsigned int
vlan_prio(const struct l2t_entry *e)
{
return e->vlan >> 13;
}
static inline unsigned int
arp_hash(u32 key, int ifindex, const struct l2t_data *d)
{
return jhash_2words(key, ifindex, 0) & (d->nentries - 1);
}
static inline void
neigh_replace(struct l2t_entry *e, struct rtentry *rt)
{
RT_LOCK(rt);
RT_ADDREF(rt);
RT_UNLOCK(rt);
if (e->neigh) {
RT_LOCK(e->neigh);
RT_REMREF(e->neigh);
RT_UNLOCK(e->neigh);
}
e->neigh = rt;
}
/*
* Set up an L2T entry and send any packets waiting in the arp queue. The
* supplied mbuf is used for the CPL_L2T_WRITE_REQ. Must be called with the
* entry locked.
*/
static int
setup_l2e_send_pending(struct toedev *dev, struct mbuf *m,
struct l2t_entry *e)
{
struct cpl_l2t_write_req *req;
if (!m) {
if ((m = m_gethdr(M_NOWAIT, MT_DATA)) == NULL)
return (ENOMEM);
}
/*
* XXX MH_ALIGN
*/
req = mtod(m, struct cpl_l2t_write_req *);
req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_L2T_WRITE_REQ, e->idx));
req->params = htonl(V_L2T_W_IDX(e->idx) | V_L2T_W_IFF(e->smt_idx) |
V_L2T_W_VLAN(e->vlan & EVL_VLID_MASK) |
V_L2T_W_PRIO(vlan_prio(e)));
memcpy(e->dmac, RT_ENADDR(e->neigh), sizeof(e->dmac));
memcpy(req->dst_mac, e->dmac, sizeof(req->dst_mac));
m_set_priority(m, CPL_PRIORITY_CONTROL);
cxgb_ofld_send(dev, m);
while (e->arpq_head) {
m = e->arpq_head;
e->arpq_head = m->m_next;
m->m_next = NULL;
cxgb_ofld_send(dev, m);
}
e->arpq_tail = NULL;
e->state = L2T_STATE_VALID;
return 0;
}
/*
* Add a packet to the an L2T entry's queue of packets awaiting resolution.
* Must be called with the entry's lock held.
*/
static inline void
arpq_enqueue(struct l2t_entry *e, struct mbuf *m)
{
m->m_next = NULL;
if (e->arpq_head)
e->arpq_tail->m_next = m;
else
e->arpq_head = m;
e->arpq_tail = m;
}
int
t3_l2t_send_slow(struct toedev *dev, struct mbuf *m,
struct l2t_entry *e)
{
struct rtentry *rt;
struct mbuf *m0;
if ((m0 = m_gethdr(M_NOWAIT, MT_DATA)) == NULL)
return (ENOMEM);
rt = e->neigh;
again:
switch (e->state) {
case L2T_STATE_STALE: /* entry is stale, kick off revalidation */
arpresolve(rt->rt_ifp, rt, m0, rt->rt_gateway, RT_ENADDR(rt));
mtx_lock(&e->lock);
if (e->state == L2T_STATE_STALE)
e->state = L2T_STATE_VALID;
mtx_unlock(&e->lock);
case L2T_STATE_VALID: /* fast-path, send the packet on */
return cxgb_ofld_send(dev, m);
case L2T_STATE_RESOLVING:
mtx_lock(&e->lock);
if (e->state != L2T_STATE_RESOLVING) { // ARP already completed
mtx_unlock(&e->lock);
goto again;
}
arpq_enqueue(e, m);
mtx_unlock(&e->lock);
if ((m0 = m_gethdr(M_NOWAIT, MT_DATA)) == NULL)
return (ENOMEM);
/*
* Only the first packet added to the arpq should kick off
* resolution. However, because the m_gethdr below can fail,
* we allow each packet added to the arpq to retry resolution
* as a way of recovering from transient memory exhaustion.
* A better way would be to use a work request to retry L2T
* entries when there's no memory.
*/
if (arpresolve(rt->rt_ifp, rt, m0, rt->rt_gateway, RT_ENADDR(rt)) == 0) {
mtx_lock(&e->lock);
if (e->arpq_head)
setup_l2e_send_pending(dev, m, e);
else
m_freem(m);
mtx_unlock(&e->lock);
}
}
return 0;
}
void
t3_l2t_send_event(struct toedev *dev, struct l2t_entry *e)
{
struct rtentry *rt;
struct mbuf *m0;
if ((m0 = m_gethdr(M_NOWAIT, MT_DATA)) == NULL)
return;
rt = e->neigh;
again:
switch (e->state) {
case L2T_STATE_STALE: /* entry is stale, kick off revalidation */
arpresolve(rt->rt_ifp, rt, m0, rt->rt_gateway, RT_ENADDR(rt));
mtx_lock(&e->lock);
if (e->state == L2T_STATE_STALE) {
e->state = L2T_STATE_VALID;
}
mtx_unlock(&e->lock);
return;
case L2T_STATE_VALID: /* fast-path, send the packet on */
return;
case L2T_STATE_RESOLVING:
mtx_lock(&e->lock);
if (e->state != L2T_STATE_RESOLVING) { // ARP already completed
mtx_unlock(&e->lock);
goto again;
}
mtx_unlock(&e->lock);
if ((m0 = m_gethdr(M_NOWAIT, MT_DATA)) == NULL)
return;
/*
* Only the first packet added to the arpq should kick off
* resolution. However, because the alloc_skb below can fail,
* we allow each packet added to the arpq to retry resolution
* as a way of recovering from transient memory exhaustion.
* A better way would be to use a work request to retry L2T
* entries when there's no memory.
*/
arpresolve(rt->rt_ifp, rt, m0, rt->rt_gateway, RT_ENADDR(rt));
}
return;
}
/*
* Allocate a free L2T entry. Must be called with l2t_data.lock held.
*/
static struct l2t_entry *
alloc_l2e(struct l2t_data *d)
{
struct l2t_entry *end, *e, **p;
if (!atomic_load_acq_int(&d->nfree))
return NULL;
/* there's definitely a free entry */
for (e = d->rover, end = &d->l2tab[d->nentries]; e != end; ++e)
if (atomic_load_acq_int(&e->refcnt) == 0)
goto found;
for (e = &d->l2tab[1]; atomic_load_acq_int(&e->refcnt); ++e) ;
found:
d->rover = e + 1;
atomic_add_int(&d->nfree, -1);
/*
* The entry we found may be an inactive entry that is
* presently in the hash table. We need to remove it.
*/
if (e->state != L2T_STATE_UNUSED) {
int hash = arp_hash(e->addr, e->ifindex, d);
for (p = &d->l2tab[hash].first; *p; p = &(*p)->next)
if (*p == e) {
*p = e->next;
break;
}
e->state = L2T_STATE_UNUSED;
}
return e;
}
/*
* Called when an L2T entry has no more users. The entry is left in the hash
* table since it is likely to be reused but we also bump nfree to indicate
* that the entry can be reallocated for a different neighbor. We also drop
* the existing neighbor reference in case the neighbor is going away and is
* waiting on our reference.
*
* Because entries can be reallocated to other neighbors once their ref count
* drops to 0 we need to take the entry's lock to avoid races with a new
* incarnation.
*/
void
t3_l2e_free(struct l2t_data *d, struct l2t_entry *e)
{
mtx_lock(&e->lock);
if (atomic_load_acq_int(&e->refcnt) == 0) { /* hasn't been recycled */
if (e->neigh) {
RT_LOCK(e->neigh);
RT_REMREF(e->neigh);
RT_UNLOCK(e->neigh);
e->neigh = NULL;
}
}
mtx_unlock(&e->lock);
atomic_add_int(&d->nfree, 1);
}
/*
* Update an L2T entry that was previously used for the same next hop as neigh.
* Must be called with softirqs disabled.
*/
static inline void
reuse_entry(struct l2t_entry *e, struct rtentry *neigh)
{
struct llinfo_arp *la;
la = (struct llinfo_arp *)neigh->rt_llinfo;
mtx_lock(&e->lock); /* avoid race with t3_l2t_free */
if (neigh != e->neigh)
neigh_replace(e, neigh);
if (memcmp(e->dmac, RT_ENADDR(neigh), sizeof(e->dmac)) ||
(neigh->rt_expire > time_uptime))
e->state = L2T_STATE_RESOLVING;
else if (la->la_hold == NULL)
e->state = L2T_STATE_VALID;
else
e->state = L2T_STATE_STALE;
mtx_unlock(&e->lock);
}
struct l2t_entry *
t3_l2t_get(struct toedev *dev, struct rtentry *neigh,
unsigned int smt_idx)
{
struct l2t_entry *e;
struct l2t_data *d = L2DATA(dev);
u32 addr = *(u32 *) rt_key(neigh);
int ifidx = neigh->rt_ifp->if_index;
int hash = arp_hash(addr, ifidx, d);
rw_wlock(&d->lock);
for (e = d->l2tab[hash].first; e; e = e->next)
if (e->addr == addr && e->ifindex == ifidx &&
e->smt_idx == smt_idx) {
l2t_hold(d, e);
if (atomic_load_acq_int(&e->refcnt) == 1)
reuse_entry(e, neigh);
goto done;
}
/* Need to allocate a new entry */
e = alloc_l2e(d);
if (e) {
mtx_lock(&e->lock); /* avoid race with t3_l2t_free */
e->next = d->l2tab[hash].first;
d->l2tab[hash].first = e;
e->state = L2T_STATE_RESOLVING;
e->addr = addr;
e->ifindex = ifidx;
e->smt_idx = smt_idx;
atomic_store_rel_int(&e->refcnt, 1);
neigh_replace(e, neigh);
#ifdef notyet
/*
* XXX need to add accessor function for vlan tag
*/
if (neigh->rt_ifp->if_vlantrunk)
e->vlan = VLAN_DEV_INFO(neigh->dev)->vlan_id;
else
#endif
e->vlan = VLAN_NONE;
mtx_unlock(&e->lock);
}
done:
rw_wunlock(&d->lock);
return e;
}
/*
* Called when address resolution fails for an L2T entry to handle packets
* on the arpq head. If a packet specifies a failure handler it is invoked,
* otherwise the packets is sent to the TOE.
*
* XXX: maybe we should abandon the latter behavior and just require a failure
* handler.
*/
static void
handle_failed_resolution(struct toedev *dev, struct mbuf *arpq)
{
while (arpq) {
struct mbuf *m = arpq;
#ifdef notyet
struct l2t_mbuf_cb *cb = L2T_MBUF_CB(m);
#endif
arpq = m->m_next;
m->m_next = NULL;
#ifdef notyet
if (cb->arp_failure_handler)
cb->arp_failure_handler(dev, m);
else
#endif
cxgb_ofld_send(dev, m);
}
}
#if defined(NETEVENT) || !defined(CONFIG_CHELSIO_T3_MODULE)
/*
* Called when the host's ARP layer makes a change to some entry that is
* loaded into the HW L2 table.
*/
void
t3_l2t_update(struct toedev *dev, struct rtentry *neigh)
{
struct l2t_entry *e;
struct mbuf *arpq = NULL;
struct l2t_data *d = L2DATA(dev);
u32 addr = *(u32 *) rt_key(neigh);
int ifidx = neigh->rt_ifp->if_index;
int hash = arp_hash(addr, ifidx, d);
struct llinfo_arp *la;
rw_rlock(&d->lock);
for (e = d->l2tab[hash].first; e; e = e->next)
if (e->addr == addr && e->ifindex == ifidx) {
mtx_lock(&e->lock);
goto found;
}
rw_runlock(&d->lock);
return;
found:
rw_runlock(&d->lock);
if (atomic_load_acq_int(&e->refcnt)) {
if (neigh != e->neigh)
neigh_replace(e, neigh);
la = (struct llinfo_arp *)neigh->rt_llinfo;
if (e->state == L2T_STATE_RESOLVING) {
if (la->la_asked >= 5 /* arp_maxtries */) {
arpq = e->arpq_head;
e->arpq_head = e->arpq_tail = NULL;
} else if (la->la_hold == NULL)
setup_l2e_send_pending(dev, NULL, e);
} else {
e->state = (la->la_hold == NULL) ?
L2T_STATE_VALID : L2T_STATE_STALE;
if (memcmp(e->dmac, RT_ENADDR(neigh), 6))
setup_l2e_send_pending(dev, NULL, e);
}
}
mtx_unlock(&e->lock);
if (arpq)
handle_failed_resolution(dev, arpq);
}
#else
/*
* Called from a kprobe, interrupts are off.
*/
void
t3_l2t_update(struct toedev *dev, struct rtentry *neigh)
{
struct l2t_entry *e;
struct l2t_data *d = L2DATA(dev);
u32 addr = *(u32 *) rt_key(neigh);
int ifidx = neigh->dev->ifindex;
int hash = arp_hash(addr, ifidx, d);
rw_rlock(&d->lock);
for (e = d->l2tab[hash].first; e; e = e->next)
if (e->addr == addr && e->ifindex == ifidx) {
mtx_lock(&e->lock);
if (atomic_load_acq_int(&e->refcnt)) {
if (neigh != e->neigh)
neigh_replace(e, neigh);
e->tdev = dev;
mod_timer(&e->update_timer, jiffies + 1);
}
mtx_unlock(&e->lock);
break;
}
rw_runlock(&d->lock);
}
static void
update_timer_cb(unsigned long data)
{
struct mbuf *arpq = NULL;
struct l2t_entry *e = (struct l2t_entry *)data;
struct rtentry *neigh = e->neigh;
struct toedev *dev = e->tdev;
barrier();
if (!atomic_load_acq_int(&e->refcnt))
return;
rw_rlock(&neigh->lock);
mtx_lock(&e->lock);
if (atomic_load_acq_int(&e->refcnt)) {
if (e->state == L2T_STATE_RESOLVING) {
if (neigh->nud_state & NUD_FAILED) {
arpq = e->arpq_head;
e->arpq_head = e->arpq_tail = NULL;
} else if (neigh_is_connected(neigh) && e->arpq_head)
setup_l2e_send_pending(dev, NULL, e);
} else {
e->state = neigh_is_connected(neigh) ?
L2T_STATE_VALID : L2T_STATE_STALE;
if (memcmp(e->dmac, RT_ENADDR(neigh), sizeof(e->dmac)))
setup_l2e_send_pending(dev, NULL, e);
}
}
mtx_unlock(&e->lock);
rw_runlock(&neigh->lock);
if (arpq)
handle_failed_resolution(dev, arpq);
}
#endif
struct l2t_data *
t3_init_l2t(unsigned int l2t_capacity)
{
struct l2t_data *d;
int i, size = sizeof(*d) + l2t_capacity * sizeof(struct l2t_entry);
d = cxgb_alloc_mem(size);
if (!d)
return NULL;
d->nentries = l2t_capacity;
d->rover = &d->l2tab[1]; /* entry 0 is not used */
atomic_store_rel_int(&d->nfree, l2t_capacity - 1);
rw_init(&d->lock, "L2T");
for (i = 0; i < l2t_capacity; ++i) {
d->l2tab[i].idx = i;
d->l2tab[i].state = L2T_STATE_UNUSED;
mtx_init(&d->l2tab[i].lock, "L2TAB", NULL, MTX_DEF);
atomic_store_rel_int(&d->l2tab[i].refcnt, 0);
#ifndef NETEVENT
#ifdef CONFIG_CHELSIO_T3_MODULE
setup_timer(&d->l2tab[i].update_timer, update_timer_cb,
(unsigned long)&d->l2tab[i]);
#endif
#endif
}
return d;
}
void
t3_free_l2t(struct l2t_data *d)
{
#ifndef NETEVENT
#ifdef CONFIG_CHELSIO_T3_MODULE
int i;
/* Stop all L2T timers */
for (i = 0; i < d->nentries; ++i)
del_timer_sync(&d->l2tab[i].update_timer);
#endif
#endif
cxgb_free_mem(d);
}
#ifdef CONFIG_PROC_FS
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
static inline void *
l2t_get_idx(struct seq_file *seq, loff_t pos)
{
struct l2t_data *d = seq->private;
return pos >= d->nentries ? NULL : &d->l2tab[pos];
}
static void *
l2t_seq_start(struct seq_file *seq, loff_t *pos)
{
return *pos ? l2t_get_idx(seq, *pos) : SEQ_START_TOKEN;
}
static void *
l2t_seq_next(struct seq_file *seq, void *v, loff_t *pos)
{
v = l2t_get_idx(seq, *pos + 1);
if (v)
++*pos;
return v;
}
static void
l2t_seq_stop(struct seq_file *seq, void *v)
{
}
static char
l2e_state(const struct l2t_entry *e)
{
switch (e->state) {
case L2T_STATE_VALID: return 'V'; /* valid, fast-path entry */
case L2T_STATE_STALE: return 'S'; /* needs revalidation, but usable */
case L2T_STATE_RESOLVING:
return e->arpq_head ? 'A' : 'R';
default:
return 'U';
}
}
static int
l2t_seq_show(struct seq_file *seq, void *v)
{
if (v == SEQ_START_TOKEN)
seq_puts(seq, "Index IP address Ethernet address VLAN "
"Prio State Users SMTIDX Port\n");
else {
char ip[20];
struct l2t_entry *e = v;
mtx_lock(&e->lock);
sprintf(ip, "%u.%u.%u.%u", NIPQUAD(e->addr));
seq_printf(seq, "%-5u %-15s %02x:%02x:%02x:%02x:%02x:%02x %4d"
" %3u %c %7u %4u %s\n",
e->idx, ip, e->dmac[0], e->dmac[1], e->dmac[2],
e->dmac[3], e->dmac[4], e->dmac[5],
e->vlan & EVL_VLID_MASK, vlan_prio(e),
l2e_state(e), atomic_load_acq_int(&e->refcnt), e->smt_idx,
e->neigh ? e->neigh->dev->name : "");
mtx_unlock(&e->lock);
}
return 0;
}
#endif

154
sys/dev/cxgb/cxgb_l2t.h Normal file
View file

@ -0,0 +1,154 @@
/**************************************************************************
Copyright (c) 2007, Chelsio Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Neither the name of the Chelsio Corporation nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
$FreeBSD$
***************************************************************************/
#ifndef _CHELSIO_L2T_H
#define _CHELSIO_L2T_H
#include <dev/cxgb/ulp/toecore/toedev.h>
#include <sys/lock.h>
#include <sys/rwlock.h>
enum {
L2T_STATE_VALID, /* entry is up to date */
L2T_STATE_STALE, /* entry may be used but needs revalidation */
L2T_STATE_RESOLVING, /* entry needs address resolution */
L2T_STATE_UNUSED /* entry not in use */
};
/*
* Each L2T entry plays multiple roles. First of all, it keeps state for the
* corresponding entry of the HW L2 table and maintains a queue of offload
* packets awaiting address resolution. Second, it is a node of a hash table
* chain, where the nodes of the chain are linked together through their next
* pointer. Finally, each node is a bucket of a hash table, pointing to the
* first element in its chain through its first pointer.
*/
struct l2t_entry {
uint16_t state; /* entry state */
uint16_t idx; /* entry index */
uint32_t addr; /* dest IP address */
int ifindex; /* neighbor's net_device's ifindex */
uint16_t smt_idx; /* SMT index */
uint16_t vlan; /* VLAN TCI (id: bits 0-11, prio: 13-15 */
struct rtentry *neigh; /* associated neighbour */
struct l2t_entry *first; /* start of hash chain */
struct l2t_entry *next; /* next l2t_entry on chain */
struct mbuf *arpq_head; /* queue of packets awaiting resolution */
struct mbuf *arpq_tail;
struct mtx lock;
volatile uint32_t refcnt; /* entry reference count */
uint8_t dmac[6]; /* neighbour's MAC address */
#ifndef NETEVENT
#ifdef CONFIG_CHELSIO_T3_MODULE
struct timer_list update_timer;
struct toedev *tdev;
#endif
#endif
};
struct l2t_data {
unsigned int nentries; /* number of entries */
struct l2t_entry *rover; /* starting point for next allocation */
volatile uint32_t nfree; /* number of free entries */
struct rwlock lock;
struct l2t_entry l2tab[0];
};
typedef void (*arp_failure_handler_func)(struct toedev *dev,
struct mbuf *m);
/*
* Callback stored in an skb to handle address resolution failure.
*/
struct l2t_mbuf_cb {
arp_failure_handler_func arp_failure_handler;
};
/*
* XXX
*/
#define L2T_MBUF_CB(skb) ((struct l2t_mbuf_cb *)(skb)->cb)
static __inline void set_arp_failure_handler(struct mbuf *m,
arp_failure_handler_func hnd)
{
#if 0
L2T_SKB_CB(skb)->arp_failure_handler = hnd;
#endif
panic("implement me");
}
/*
* Getting to the L2 data from an offload device.
*/
#define L2DATA(dev) ((dev)->l2opt)
void t3_l2e_free(struct l2t_data *d, struct l2t_entry *e);
void t3_l2t_update(struct toedev *dev, struct rtentry *ifp);
struct l2t_entry *t3_l2t_get(struct toedev *dev, struct rtentry *neigh,
unsigned int smt_idx);
int t3_l2t_send_slow(struct toedev *dev, struct mbuf *m,
struct l2t_entry *e);
void t3_l2t_send_event(struct toedev *dev, struct l2t_entry *e);
struct l2t_data *t3_init_l2t(unsigned int l2t_capacity);
void t3_free_l2t(struct l2t_data *d);
#ifdef CONFIG_PROC_FS
int t3_l2t_proc_setup(struct proc_dir_entry *dir, struct l2t_data *d);
void t3_l2t_proc_free(struct proc_dir_entry *dir);
#else
#define l2t_proc_setup(dir, d) 0
#define l2t_proc_free(dir)
#endif
int cxgb_ofld_send(struct toedev *dev, struct mbuf *m);
static inline int l2t_send(struct toedev *dev, struct mbuf *m,
struct l2t_entry *e)
{
if (__predict_true(e->state == L2T_STATE_VALID))
return cxgb_ofld_send(dev, m);
return t3_l2t_send_slow(dev, m, e);
}
static inline void l2t_release(struct l2t_data *d, struct l2t_entry *e)
{
if (atomic_fetchadd_int(&e->refcnt, -1) == 1)
t3_l2e_free(d, e);
}
static inline void l2t_hold(struct l2t_data *d, struct l2t_entry *e)
{
if (atomic_fetchadd_int(&e->refcnt, 1) == 1) /* 0 -> 1 transition */
atomic_add_int(&d->nfree, 1);
}
#endif

View file

@ -9,11 +9,7 @@ modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the Chelsio Corporation nor the names of its
2. Neither the name of the Chelsio Corporation nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
@ -82,51 +78,40 @@ __FBSDID("$FreeBSD$");
#endif
#define IPH_OFFSET (2 + sizeof (struct cpl_rx_pkt) + ETHER_HDR_LEN)
#define LRO_SESSION_IDX_HINT_HASH(hash) (hash & (MAX_LRO_PER_QSET - 1))
#define LRO_IDX_INC(idx) idx = (idx + 1) & (MAX_LRO_PER_QSET - 1)
static __inline struct sge_lro_session *
lro_session(struct sge_lro *l, int idx)
{
return l->s + idx;
}
#define LRO_SESSION_IDX_HINT_HASH(hash) (hash & (MAX_LRO_SES - 1))
#define LRO_IDX_INC(idx) idx = (idx + 1) & (MAX_LRO_SES - 1)
static __inline int
lro_match_session(struct sge_lro_session *s,
struct ip *ih, struct tcphdr *th)
lro_match(struct mbuf *m, struct ip *ih, struct tcphdr *th)
{
struct ip *sih = (struct ip *)(s->m->m_data + IPH_OFFSET);
struct ip *sih = (struct ip *)(m->m_data + IPH_OFFSET);
struct tcphdr *sth = (struct tcphdr *) (sih + 1);
/*
* Linux driver doesn't include destination port check --
* need to find out why XXX
* Why don't we check dest ports?
*/
return (*(uint32_t *)&th->th_sport == *(uint32_t *)&sth->th_sport &&
*(uint32_t *)&th->th_dport == *(uint32_t *)&sth->th_dport &&
ih->ip_src.s_addr == ih->ip_src.s_addr &&
ih->ip_dst.s_addr == sih->ip_dst.s_addr);
}
static __inline struct sge_lro_session *
lro_find_session(struct sge_lro *l, int idx, struct ip *ih, struct tcphdr *th)
static __inline struct t3_lro_session *
lro_lookup(struct lro_state *l, int idx, struct ip *ih, struct tcphdr *th)
{
struct sge_lro_session *s;
int active = 0;
struct t3_lro_session *s = NULL;
int active = l->nactive;
while (active < l->num_active) {
s = lro_session(l, idx);
if (s->m) {
if (lro_match_session(s, ih, th)) {
l->last_s = s;
return s;
}
active++;
while (active) {
s = &l->sess[idx];
if (s->head) {
if (lro_match(s->head, ih, th))
break;
active--;
}
LRO_IDX_INC(idx);
}
return NULL;
return (s);
}
static __inline int
@ -174,7 +159,7 @@ can_lro_tcpsegment(struct tcphdr *th)
}
static __inline void
lro_new_session_init(struct sge_lro_session *s, struct mbuf *m)
lro_new_session_init(struct t3_lro_session *s, struct mbuf *m)
{
struct ip *ih = (struct ip *)(m->m_data + IPH_OFFSET);
struct tcphdr *th = (struct tcphdr *) (ih + 1);
@ -182,7 +167,7 @@ lro_new_session_init(struct sge_lro_session *s, struct mbuf *m)
DPRINTF("%s(s=%p, m=%p)\n", __FUNCTION__, s, m);
s->m = m;
s->head = m;
MBUF_HEADER_CHECK(m);
s->ip_len = ip_len;
@ -191,10 +176,10 @@ lro_new_session_init(struct sge_lro_session *s, struct mbuf *m)
}
static void
lro_flush_session(struct sge_qset *qs, struct sge_lro_session *s, struct mbuf *m)
lro_flush_session(struct sge_qset *qs, struct t3_lro_session *s, struct mbuf *m)
{
struct sge_lro *l = &qs->lro;
struct mbuf *sm = s->m;
struct lro_state *l = &qs->lro;
struct mbuf *sm = s->head;
struct ip *ih = (struct ip *)(sm->m_data + IPH_OFFSET);
@ -216,33 +201,33 @@ lro_flush_session(struct sge_qset *qs, struct sge_lro_session *s, struct mbuf *m
t3_rx_eth(qs->port, &qs->rspq, sm, 2);
if (m) {
s->m = m;
s->head = m;
lro_new_session_init(s, m);
} else {
s->m = NULL;
l->num_active--;
s->head = NULL;
l->nactive--;
}
qs->port_stats[SGE_PSTATS_LRO_FLUSHED]++;
}
static __inline struct sge_lro_session *
static __inline struct t3_lro_session *
lro_new_session(struct sge_qset *qs, struct mbuf *m, uint32_t rss_hash)
{
struct sge_lro *l = &qs->lro;
struct lro_state *l = &qs->lro;
int idx = LRO_SESSION_IDX_HINT_HASH(rss_hash);
struct sge_lro_session *s = lro_session(l, idx);
struct t3_lro_session *s = &l->sess[idx];
DPRINTF("%s(qs=%p, m=%p, rss_hash=0x%x)\n", __FUNCTION__,
qs, m, rss_hash);
if (__predict_true(!s->m))
if (__predict_true(!s->head))
goto done;
if (l->num_active > MAX_LRO_PER_QSET)
if (l->nactive > MAX_LRO_SES)
panic("MAX_LRO_PER_QSET exceeded");
if (l->num_active == MAX_LRO_PER_QSET) {
if (l->nactive == MAX_LRO_SES) {
lro_flush_session(qs, s, m);
qs->port_stats[SGE_PSTATS_LRO_X_STREAMS]++;
return s;
@ -250,21 +235,21 @@ lro_new_session(struct sge_qset *qs, struct mbuf *m, uint32_t rss_hash)
while (1) {
LRO_IDX_INC(idx);
s = lro_session(l, idx);
if (!s->m)
s = &l->sess[idx];
if (!s->head)
break;
}
done:
lro_new_session_init(s, m);
l->num_active++;
l->nactive++;
return s;
}
static __inline int
lro_update_session(struct sge_lro_session *s, struct mbuf *m)
lro_update_session(struct t3_lro_session *s, struct mbuf *m)
{
struct mbuf *sm = s->m;
struct mbuf *sm = s->head;
struct cpl_rx_pkt *cpl = (struct cpl_rx_pkt *)(sm->m_data + 2);
struct cpl_rx_pkt *ncpl = (struct cpl_rx_pkt *)(m->m_data + 2);
struct ip *nih = (struct ip *)(m->m_data + IPH_OFFSET);
@ -354,7 +339,7 @@ t3_rx_eth_lro(adapter_t *adap, struct sge_rspq *rq, struct mbuf *m,
struct ether_header *eh = (struct ether_header *)(cpl + 1);
struct ip *ih;
struct tcphdr *th;
struct sge_lro_session *s = NULL;
struct t3_lro_session *s = NULL;
struct port_info *pi = qs->port;
if (lro == 0)
@ -369,7 +354,7 @@ t3_rx_eth_lro(adapter_t *adap, struct sge_rspq *rq, struct mbuf *m,
ih = (struct ip *)(eh + 1);
th = (struct tcphdr *)(ih + 1);
s = lro_find_session(&qs->lro,
s = lro_lookup(&qs->lro,
LRO_SESSION_IDX_HINT_HASH(rss_hash), ih, th);
if (__predict_false(!can_lro_tcpsegment(th))) {
@ -380,7 +365,7 @@ t3_rx_eth_lro(adapter_t *adap, struct sge_rspq *rq, struct mbuf *m,
if (lro_update_session(s, m)) {
lro_flush_session(qs, s, m);
}
if (__predict_false(s->m->m_pkthdr.len + pi->ifp->if_mtu > 65535)) {
if (__predict_false(s->head->m_pkthdr.len + pi->ifp->if_mtu > 65535)) {
lro_flush_session(qs, s, NULL);
}
}
@ -398,21 +383,15 @@ t3_rx_eth_lro(adapter_t *adap, struct sge_rspq *rq, struct mbuf *m,
}
void
t3_sge_lro_flush_all(adapter_t *adap, struct sge_qset *qs)
t3_lro_flush(adapter_t *adap, struct sge_qset *qs, struct lro_state *state)
{
struct sge_lro *l = &qs->lro;
struct sge_lro_session *s = l->last_s;
int active = 0, idx = 0, num_active = l->num_active;
unsigned int idx = state->active_idx;
if (__predict_false(!s))
s = lro_session(l, idx);
while (active < num_active) {
if (s->m) {
while (state->nactive) {
struct t3_lro_session *s = &state->sess[idx];
if (s->head)
lro_flush_session(qs, s, NULL);
active++;
}
LRO_IDX_INC(idx);
s = lro_session(l, idx);
}
}

View file

@ -9,11 +9,7 @@ modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the Chelsio Corporation nor the names of its
2. Neither the name of the Chelsio Corporation nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
@ -79,6 +75,7 @@ __FBSDID("$FreeBSD$");
#include <dev/cxgb/cxgb_osdep.h>
#include <dev/cxgb/common/cxgb_common.h>
#include <dev/cxgb/cxgb_ioctl.h>
#include <dev/cxgb/cxgb_offload.h>
#include <dev/cxgb/common/cxgb_regs.h>
#include <dev/cxgb/common/cxgb_t3_cpl.h>
#include <dev/cxgb/common/cxgb_firmware_exports.h>
@ -103,6 +100,7 @@ static void cxgb_media_status(struct ifnet *, struct ifmediareq *);
static int setup_sge_qsets(adapter_t *);
static void cxgb_async_intr(void *);
static void cxgb_ext_intr_handler(void *, int);
static void cxgb_down(struct adapter *sc);
static void cxgb_tick(void *);
static void setup_rss(adapter_t *sc);
@ -117,6 +115,10 @@ static __inline void reg_block_dump(struct adapter *ap, uint8_t *buf, unsigned i
unsigned int end);
static void cxgb_get_regs(adapter_t *sc, struct ifconf_regs *regs, uint8_t *buf);
static int cxgb_get_regs_len(void);
static int offload_open(struct port_info *pi);
static int offload_close(struct toedev *tdev);
static device_method_t cxgb_controller_methods[] = {
DEVMETHOD(device_probe, cxgb_controller_probe),
@ -179,14 +181,27 @@ extern int collapse_mbufs;
*/
static int msi_allowed = 2;
TUNABLE_INT("hw.cxgb.msi_allowed", &msi_allowed);
SYSCTL_NODE(_hw, OID_AUTO, cxgb, CTLFLAG_RD, 0, "CXGB driver parameters");
SYSCTL_UINT(_hw_cxgb, OID_AUTO, msi_allowed, CTLFLAG_RDTUN, &msi_allowed, 0,
"MSI-X, MSI, INTx selector");
/*
* Multiple queues need further tuning
* The driver enables offload as a default.
* To disable it, use ofld_disable = 1.
*/
static int ofld_disable = 0;
TUNABLE_INT("hw.cxgb.ofld_disable", &ofld_disable);
SYSCTL_UINT(_hw_cxgb, OID_AUTO, ofld_disable, CTLFLAG_RDTUN, &ofld_disable, 0,
"disable ULP offload");
/*
* The driver uses an auto-queue algorithm by default.
* To disable it and force a single queue-set per port, use singleq = 1.
*/
static int singleq = 1;
TUNABLE_INT("hw.cxgb.singleq", &singleq);
SYSCTL_UINT(_hw_cxgb, OID_AUTO, singleq, CTLFLAG_RDTUN, &singleq, 0,
"use a single queue-set per port");
enum {
MAX_TXQ_ENTRIES = 16384,
@ -272,7 +287,7 @@ cxgb_controller_probe(device_t dev)
}
static int
cxgb_fw_download(adapter_t *sc, device_t dev)
upgrade_fw(adapter_t *sc)
{
char buf[32];
#ifdef FIRMWARE_LATEST
@ -282,15 +297,14 @@ cxgb_fw_download(adapter_t *sc, device_t dev)
#endif
int status;
snprintf(&buf[0], sizeof(buf), "t3fw%d%d", FW_VERSION_MAJOR,
FW_VERSION_MINOR);
snprintf(&buf[0], sizeof(buf), "t3fw%d%d%d", FW_VERSION_MAJOR,
FW_VERSION_MINOR, FW_VERSION_MICRO);
fw = firmware_get(buf);
if (fw == NULL) {
device_printf(dev, "Could not find firmware image %s\n", buf);
return ENOENT;
device_printf(sc->dev, "Could not find firmware image %s\n", buf);
return (ENOENT);
}
status = t3_load_fw(sc, (const uint8_t *)fw->data, fw->datasize);
@ -300,7 +314,6 @@ cxgb_fw_download(adapter_t *sc, device_t dev)
return (status);
}
static int
cxgb_controller_attach(device_t dev)
{
@ -308,13 +321,14 @@ cxgb_controller_attach(device_t dev)
device_t child;
const struct adapter_info *ai;
struct adapter *sc;
int i, reg, msi_needed, msi_count = 0, error = 0;
int i, reg, msi_needed, error = 0;
uint32_t vers;
int port_qsets = 1;
sc = device_get_softc(dev);
sc->dev = dev;
sc->msi_count = 0;
/* find the PCIe link width and set max read request to 4KB*/
if (pci_find_extcap(dev, PCIY_EXPRESS, &reg) == 0) {
uint16_t lnk, pectl;
@ -370,13 +384,14 @@ cxgb_controller_attach(device_t dev)
(sc->msix_regs_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
&sc->msix_regs_rid, RF_ACTIVE)) != NULL) {
msi_needed = msi_count = SGE_MSIX_COUNT;
msi_needed = sc->msi_count = SGE_MSIX_COUNT;
if ((pci_alloc_msix(dev, &msi_count) != 0) ||
(msi_count != msi_needed)) {
device_printf(dev, "msix allocation failed"
" will try msi\n");
msi_count = 0;
if (((error = pci_alloc_msix(dev, &sc->msi_count)) != 0) ||
(sc->msi_count != msi_needed)) {
device_printf(dev, "msix allocation failed - msi_count = %d"
" msi_needed=%d will try msi err=%d\n", sc->msi_count,
msi_needed, error);
sc->msi_count = 0;
pci_release_msi(dev);
bus_release_resource(dev, SYS_RES_MEMORY,
sc->msix_regs_rid, sc->msix_regs_res);
@ -387,11 +402,11 @@ cxgb_controller_attach(device_t dev)
}
}
if ((msi_allowed >= 1) && (msi_count == 0)) {
msi_count = 1;
if (pci_alloc_msi(dev, &msi_count)) {
if ((msi_allowed >= 1) && (sc->msi_count == 0)) {
sc->msi_count = 1;
if (pci_alloc_msi(dev, &sc->msi_count)) {
device_printf(dev, "alloc msi failed - will try INTx\n");
msi_count = 0;
sc->msi_count = 0;
pci_release_msi(dev);
} else {
sc->flags |= USING_MSI;
@ -400,7 +415,7 @@ cxgb_controller_attach(device_t dev)
}
}
#endif
if (msi_count == 0) {
if (sc->msi_count == 0) {
device_printf(dev, "using line interrupts\n");
sc->irq_rid = 0;
cxgb_intr = t3b_intr;
@ -432,22 +447,14 @@ cxgb_controller_attach(device_t dev)
/*
* Warn user that a firmware update will be attempted in init.
*/
device_printf(dev, "firmware needs to be updated to version %d.%d\n",
FW_VERSION_MAJOR, FW_VERSION_MINOR);
device_printf(dev, "firmware needs to be updated to version %d.%d.%d\n",
FW_VERSION_MAJOR, FW_VERSION_MINOR, FW_VERSION_MICRO);
sc->flags &= ~FW_UPTODATE;
} else {
sc->flags |= FW_UPTODATE;
}
if (t3_init_hw(sc, 0) != 0) {
device_printf(dev, "hw initialization failed\n");
error = ENXIO;
goto out;
}
t3_write_reg(sc, A_ULPRX_TDDP_PSZ, V_HPZ0(PAGE_SHIFT - 12));
if ((singleq == 0) && (sc->flags & USING_MSIX))
if ((sc->flags & USING_MSIX) && !singleq)
port_qsets = min((SGE_QSETS/(sc)->params.nports), mp_ncpus);
/*
@ -468,52 +475,32 @@ cxgb_controller_attach(device_t dev)
device_set_softc(child, &sc->port[i]);
}
if ((error = bus_generic_attach(dev)) != 0)
goto out;;
if ((error = setup_sge_qsets(sc)) != 0)
goto out;
setup_rss(sc);
/* If it's MSI or INTx, allocate a single interrupt for everything */
if ((sc->flags & USING_MSIX) == 0) {
if ((sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ,
&sc->irq_rid, RF_SHAREABLE | RF_ACTIVE)) == NULL) {
device_printf(dev, "Cannot allocate interrupt rid=%d\n", sc->irq_rid);
error = EINVAL;
goto out;
}
device_printf(dev, "allocated irq_res=%p\n", sc->irq_res);
if (bus_setup_intr(dev, sc->irq_res, INTR_MPSAFE|INTR_TYPE_NET,
#ifdef INTR_FILTERS
NULL,
#endif
cxgb_intr, sc, &sc->intr_tag)) {
device_printf(dev, "Cannot set up interrupt\n");
error = EINVAL;
goto out;
}
} else {
cxgb_setup_msix(sc, msi_count);
}
/*
* XXX need to poll for link status
*/
sc->params.stats_update_period = 1;
/* initialize sge private state */
t3_sge_init_sw(sc);
t3_led_ready(sc);
cxgb_offload_init();
if (is_offload(sc)) {
setbit(&sc->registered_device_map, OFFLOAD_DEVMAP_BIT);
cxgb_adapter_ofld(sc);
}
error = t3_get_fw_version(sc, &vers);
if (error)
goto out;
snprintf(&sc->fw_version[0], sizeof(sc->fw_version), "%d.%d", G_FW_VERSION_MAJOR(vers),
G_FW_VERSION_MINOR(vers));
snprintf(&sc->fw_version[0], sizeof(sc->fw_version), "%d.%d.%d",
G_FW_VERSION_MAJOR(vers), G_FW_VERSION_MINOR(vers),
G_FW_VERSION_MICRO(vers));
t3_add_sysctls(sc);
out:
if (error)
cxgb_free(sc);
@ -538,11 +525,25 @@ cxgb_free(struct adapter *sc)
{
int i;
cxgb_down(sc);
#ifdef MSI_SUPPORTED
if (sc->flags & (USING_MSI | USING_MSIX)) {
device_printf(sc->dev, "releasing msi message(s)\n");
pci_release_msi(sc->dev);
} else {
device_printf(sc->dev, "no msi message to release\n");
}
#endif
if (sc->msix_regs_res != NULL) {
bus_release_resource(sc->dev, SYS_RES_MEMORY, sc->msix_regs_rid,
sc->msix_regs_res);
}
/*
* XXX need to drain the ifq by hand until
* it is taught about mbuf iovecs
*/
callout_drain(&sc->cxgb_tick_ch);
t3_sge_deinit_sw(sc);
@ -559,41 +560,14 @@ cxgb_free(struct adapter *sc)
bus_generic_detach(sc->dev);
if (is_offload(sc)) {
cxgb_adapter_unofld(sc);
if (isset(&sc->open_device_map, OFFLOAD_DEVMAP_BIT))
offload_close(&sc->tdev);
}
t3_free_sge_resources(sc);
t3_sge_free(sc);
for (i = 0; i < SGE_QSETS; i++) {
if (sc->msix_intr_tag[i] != NULL) {
bus_teardown_intr(sc->dev, sc->msix_irq_res[i],
sc->msix_intr_tag[i]);
}
if (sc->msix_irq_res[i] != NULL) {
bus_release_resource(sc->dev, SYS_RES_IRQ,
sc->msix_irq_rid[i], sc->msix_irq_res[i]);
}
}
if (sc->intr_tag != NULL) {
bus_teardown_intr(sc->dev, sc->irq_res, sc->intr_tag);
}
if (sc->irq_res != NULL) {
device_printf(sc->dev, "de-allocating interrupt irq_rid=%d irq_res=%p\n",
sc->irq_rid, sc->irq_res);
bus_release_resource(sc->dev, SYS_RES_IRQ, sc->irq_rid,
sc->irq_res);
}
#ifdef MSI_SUPPORTED
if (sc->flags & (USING_MSI | USING_MSIX)) {
device_printf(sc->dev, "releasing msi message(s)\n");
pci_release_msi(sc->dev);
}
#endif
if (sc->msix_regs_res != NULL) {
bus_release_resource(sc->dev, SYS_RES_MEMORY, sc->msix_regs_rid,
sc->msix_regs_res);
}
if (sc->regs_res != NULL)
bus_release_resource(sc->dev, SYS_RES_MEMORY, sc->regs_rid,
sc->regs_res);
@ -617,7 +591,7 @@ static int
setup_sge_qsets(adapter_t *sc)
{
int i, j, err, irq_idx, qset_idx;
u_int ntxq = 3;
u_int ntxq = SGE_TXQ_PER_SET;
if ((err = t3_sge_alloc(sc)) != 0) {
device_printf(sc->dev, "t3_sge_alloc returned %d\n", err);
@ -821,7 +795,7 @@ cxgb_port_attach(device_t dev)
ifmedia_add(&p->media, IFM_ETHER | IFM_AUTO, 0, NULL);
ifmedia_set(&p->media, media_flags);
snprintf(buf, sizeof(buf), "cxgb_port_taskq%d", p->port);
snprintf(buf, sizeof(buf), "cxgb_port_taskq%d", p->port);
#ifdef TASKQUEUE_CURRENT
/* Create a port for handling TX without starvation */
p->tq = taskqueue_create(buf, M_NOWAIT,
@ -851,6 +825,11 @@ cxgb_port_detach(device_t dev)
struct port_info *p;
p = device_get_softc(dev);
PORT_LOCK(p);
cxgb_stop_locked(p);
PORT_UNLOCK(p);
mtx_destroy(&p->lock);
if (p->tq != NULL) {
taskqueue_drain(p->tq, &p->start_task);
@ -962,15 +941,20 @@ t3_os_link_changed(adapter_t *adapter, int port_id, int link_status, int speed,
int duplex, int fc)
{
struct port_info *pi = &adapter->port[port_id];
struct cmac *mac = &adapter->port[port_id].mac;
if ((pi->ifp->if_flags & IFF_UP) == 0)
return;
if (link_status)
if (link_status) {
t3_mac_enable(mac, MAC_DIRECTION_RX);
if_link_state_change(pi->ifp, LINK_STATE_UP);
else
} else {
if_link_state_change(pi->ifp, LINK_STATE_DOWN);
pi->phy.ops->power_down(&pi->phy, 1);
t3_mac_disable(mac, MAC_DIRECTION_RX);
t3_link_start(&pi->phy, mac, &pi->link_config);
}
}
@ -988,11 +972,13 @@ t3_os_ext_intr_handler(adapter_t *sc)
* interrupts in the meantime and let the task reenable them when
* it's done.
*/
ADAPTER_LOCK(sc);
if (sc->slow_intr_mask) {
sc->slow_intr_mask &= ~F_T3DBG;
t3_write_reg(sc, A_PL_INT_ENABLE0, sc->slow_intr_mask);
taskqueue_enqueue(sc->tq, &sc->ext_intr_task);
}
ADAPTER_UNLOCK(sc);
}
void
@ -1067,6 +1053,66 @@ setup_rss(adapter_t *adap)
V_RRCPLCPUSIZE(6), cpus, rspq_map);
}
/*
* Sends an mbuf to an offload queue driver
* after dealing with any active network taps.
*/
static inline int
offload_tx(struct toedev *tdev, struct mbuf *m)
{
int ret;
critical_enter();
ret = t3_offload_tx(tdev, m);
critical_exit();
return ret;
}
static int
write_smt_entry(struct adapter *adapter, int idx)
{
struct port_info *pi = &adapter->port[idx];
struct cpl_smt_write_req *req;
struct mbuf *m;
if ((m = m_gethdr(M_NOWAIT, MT_DATA)) == NULL)
return (ENOMEM);
req = mtod(m, struct cpl_smt_write_req *);
req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SMT_WRITE_REQ, idx));
req->mtu_idx = NMTUS - 1; /* should be 0 but there's a T3 bug */
req->iff = idx;
memset(req->src_mac1, 0, sizeof(req->src_mac1));
memcpy(req->src_mac0, pi->hw_addr, ETHER_ADDR_LEN);
m_set_priority(m, 1);
offload_tx(&adapter->tdev, m);
return (0);
}
static int
init_smt(struct adapter *adapter)
{
int i;
for_each_port(adapter, i)
write_smt_entry(adapter, i);
return 0;
}
static void
init_port_mtus(adapter_t *adapter)
{
unsigned int mtus = adapter->port[0].ifp->if_mtu;
if (adapter->port[1].ifp)
mtus |= adapter->port[1].ifp->if_mtu << 16;
t3_write_reg(adapter, A_TP_MTU_PORT_TABLE, mtus);
}
static void
send_pktsched_cmd(struct adapter *adap, int sched, int qidx, int lo,
int hi, int port)
@ -1076,7 +1122,7 @@ send_pktsched_cmd(struct adapter *adap, int sched, int qidx, int lo,
m = m_gethdr(M_NOWAIT, MT_DATA);
if (m) {
req = (struct mngt_pktsched_wr *)m->m_data;
req = mtod(m, struct mngt_pktsched_wr *);
req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_MNGT));
req->mngt_opcode = FW_MNGTOPCODE_PKTSCHED_SET;
req->sched = sched;
@ -1103,6 +1149,192 @@ bind_qsets(adapter_t *sc)
}
}
/**
* cxgb_up - enable the adapter
* @adap: adapter being enabled
*
* Called when the first port is enabled, this function performs the
* actions necessary to make an adapter operational, such as completing
* the initialization of HW modules, and enabling interrupts.
*
*/
static int
cxgb_up(struct adapter *sc)
{
int err = 0;
if ((sc->flags & FULL_INIT_DONE) == 0) {
if ((sc->flags & FW_UPTODATE) == 0)
err = upgrade_fw(sc);
if (err)
goto out;
err = t3_init_hw(sc, 0);
if (err)
goto out;
t3_write_reg(sc, A_ULPRX_TDDP_PSZ, V_HPZ0(PAGE_SHIFT - 12));
err = setup_sge_qsets(sc);
if (err)
goto out;
setup_rss(sc);
sc->flags |= FULL_INIT_DONE;
}
t3_intr_clear(sc);
/* If it's MSI or INTx, allocate a single interrupt for everything */
if ((sc->flags & USING_MSIX) == 0) {
if ((sc->irq_res = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ,
&sc->irq_rid, RF_SHAREABLE | RF_ACTIVE)) == NULL) {
device_printf(sc->dev, "Cannot allocate interrupt rid=%d\n", sc->irq_rid);
err = EINVAL;
goto out;
}
device_printf(sc->dev, "allocated irq_res=%p\n", sc->irq_res);
if (bus_setup_intr(sc->dev, sc->irq_res, INTR_MPSAFE|INTR_TYPE_NET,
#ifdef INTR_FILTERS
NULL,
#endif
sc->cxgb_intr, sc, &sc->intr_tag)) {
device_printf(sc->dev, "Cannot set up interrupt\n");
err = EINVAL;
goto irq_err;
}
} else {
cxgb_setup_msix(sc, sc->msi_count);
}
t3_sge_start(sc);
t3_intr_enable(sc);
if ((sc->flags & (USING_MSIX | QUEUES_BOUND)) == USING_MSIX)
bind_qsets(sc);
sc->flags |= QUEUES_BOUND;
out:
return (err);
irq_err:
CH_ERR(sc, "request_irq failed, err %d\n", err);
goto out;
}
/*
* Release resources when all the ports and offloading have been stopped.
*/
static void
cxgb_down(struct adapter *sc)
{
int i;
t3_sge_stop(sc);
t3_intr_disable(sc);
for (i = 0; i < SGE_QSETS; i++) {
if (sc->msix_intr_tag[i] != NULL) {
bus_teardown_intr(sc->dev, sc->msix_irq_res[i],
sc->msix_intr_tag[i]);
sc->msix_intr_tag[i] = NULL;
}
if (sc->msix_irq_res[i] != NULL) {
bus_release_resource(sc->dev, SYS_RES_IRQ,
sc->msix_irq_rid[i], sc->msix_irq_res[i]);
sc->msix_irq_res[i] = NULL;
}
}
if (sc->intr_tag != NULL) {
bus_teardown_intr(sc->dev, sc->irq_res, sc->intr_tag);
sc->intr_tag = NULL;
}
if (sc->irq_res != NULL) {
device_printf(sc->dev, "de-allocating interrupt irq_rid=%d irq_res=%p\n",
sc->irq_rid, sc->irq_res);
bus_release_resource(sc->dev, SYS_RES_IRQ, sc->irq_rid,
sc->irq_res);
sc->irq_res = NULL;
}
callout_drain(&sc->sge_timer_ch);
taskqueue_drain(sc->tq, &sc->slow_intr_task);
taskqueue_drain(sc->tq, &sc->timer_reclaim_task);
}
static int
offload_open(struct port_info *pi)
{
struct adapter *adapter = pi->adapter;
struct toedev *tdev = TOEDEV(pi->ifp);
int adap_up = adapter->open_device_map & PORT_MASK;
int err = 0;
if (atomic_cmpset_int(&adapter->open_device_map,
(adapter->open_device_map & ~OFFLOAD_DEVMAP_BIT),
(adapter->open_device_map | OFFLOAD_DEVMAP_BIT)) == 0)
return (0);
ADAPTER_LOCK(pi->adapter);
if (!adap_up)
err = cxgb_up(adapter);
ADAPTER_UNLOCK(pi->adapter);
if (err < 0)
return (err);
t3_tp_set_offload_mode(adapter, 1);
tdev->lldev = adapter->port[0].ifp;
err = cxgb_offload_activate(adapter);
if (err)
goto out;
init_port_mtus(adapter);
t3_load_mtus(adapter, adapter->params.mtus, adapter->params.a_wnd,
adapter->params.b_wnd,
adapter->params.rev == 0 ?
adapter->port[0].ifp->if_mtu : 0xffff);
init_smt(adapter);
/* Call back all registered clients */
cxgb_add_clients(tdev);
out:
/* restore them in case the offload module has changed them */
if (err) {
t3_tp_set_offload_mode(adapter, 0);
clrbit(&adapter->open_device_map, OFFLOAD_DEVMAP_BIT);
cxgb_set_dummy_ops(tdev);
}
return (err);
}
static int
offload_close(struct toedev *tdev)
{
struct adapter *adapter = tdev2adap(tdev);
if (!isset(&adapter->open_device_map, OFFLOAD_DEVMAP_BIT))
return 0;
/* Call back all registered clients */
cxgb_remove_clients(tdev);
tdev->lldev = NULL;
cxgb_set_dummy_ops(tdev);
t3_tp_set_offload_mode(adapter, 0);
clrbit(&adapter->open_device_map, OFFLOAD_DEVMAP_BIT);
ADAPTER_LOCK(adapter);
if (!adapter->open_device_map)
cxgb_down(adapter);
ADAPTER_UNLOCK(adapter);
cxgb_offload_deactivate(adapter);
return 0;
}
static void
cxgb_init(void *arg)
{
@ -1118,43 +1350,39 @@ cxgb_init_locked(struct port_info *p)
{
struct ifnet *ifp;
adapter_t *sc = p->adapter;
int error;
int err;
mtx_assert(&p->lock, MA_OWNED);
ifp = p->ifp;
if ((sc->flags & FW_UPTODATE) == 0) {
device_printf(sc->dev, "updating firmware to version %d.%d\n",
FW_VERSION_MAJOR, FW_VERSION_MINOR);
if ((error = cxgb_fw_download(sc, sc->dev)) != 0) {
device_printf(sc->dev, "firmware download failed err: %d"
"interface will be unavailable\n", error);
return;
}
sc->flags |= FW_UPTODATE;
}
cxgb_link_start(p);
ADAPTER_LOCK(p->adapter);
if ((sc->open_device_map == 0) && ((err = cxgb_up(sc)) < 0)) {
ADAPTER_UNLOCK(p->adapter);
cxgb_stop_locked(p);
return;
}
if (p->adapter->open_device_map == 0)
t3_intr_clear(sc);
t3_sge_start(sc);
p->adapter->open_device_map |= (1 << p->port);
setbit(&p->adapter->open_device_map, p->port);
ADAPTER_UNLOCK(p->adapter);
t3_intr_enable(sc);
if (is_offload(sc) && !ofld_disable) {
err = offload_open(p);
if (err)
log(LOG_WARNING,
"Could not initialize offload capabilities\n");
}
cxgb_link_start(p);
t3_port_intr_enable(sc, p->port);
if ((p->adapter->flags & (USING_MSIX | QUEUES_BOUND)) == USING_MSIX)
bind_qsets(sc);
p->adapter->flags |= QUEUES_BOUND;
callout_reset(&sc->cxgb_tick_ch, sc->params.stats_update_period * hz,
cxgb_tick, sc);
PORT_LOCK(p);
ifp->if_drv_flags |= IFF_DRV_RUNNING;
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
PORT_UNLOCK(p);
}
static void
@ -1179,15 +1407,21 @@ cxgb_stop_locked(struct port_info *p)
ifp = p->ifp;
ADAPTER_LOCK(p->adapter);
ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
p->adapter->open_device_map &= ~(1 << p->port);
if (p->adapter->open_device_map == 0)
t3_intr_disable(p->adapter);
ADAPTER_UNLOCK(p->adapter);
t3_port_intr_disable(p->adapter, p->port);
PORT_LOCK(p);
ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
PORT_UNLOCK(p);
p->phy.ops->power_down(&p->phy, 1);
t3_mac_disable(&p->mac, MAC_DIRECTION_TX | MAC_DIRECTION_RX);
ADAPTER_LOCK(p->adapter);
clrbit(&p->adapter->open_device_map, p->port);
/*
* XXX cancel check_task
*/
if (p->adapter->open_device_map == 0)
cxgb_down(p->adapter);
ADAPTER_UNLOCK(p->adapter);
}
static int
@ -1357,7 +1591,7 @@ cxgb_start_tx(struct ifnet *ifp, uint32_t txmax)
m = m0;
if ((err = t3_encap(p, &m)) != 0)
break;
BPF_MTAP(ifp, m);
BPF_MTAP(ifp, m);
}
mtx_unlock(&txq->lock);
@ -1468,11 +1702,13 @@ cxgb_ext_intr_handler(void *arg, int count)
t3_phy_intr_handler(sc);
/* Now reenable external interrupts */
ADAPTER_LOCK(sc);
if (sc->slow_intr_mask) {
sc->slow_intr_mask |= F_T3DBG;
t3_write_reg(sc, A_PL_INT_CAUSE0, F_T3DBG);
t3_write_reg(sc, A_PL_INT_ENABLE0, sc->slow_intr_mask);
}
ADAPTER_UNLOCK(sc);
}
static void
@ -1750,9 +1986,9 @@ cxgb_extension_ioctl(struct cdev *dev, unsigned long cmd, caddr_t data,
if (edata->val + sc->port[!port_idx].nqsets > SGE_QSETS)
return (EINVAL);
sc->port[port_idx].nqsets = edata->val;
sc->port[0].first_qset = 0;
/*
* XXX we're hardcoding ourselves to 2 ports
* just like the LEENUX
* XXX hardcode ourselves to 2 ports just like LEEENUX
*/
sc->port[1].first_qset = sc->port[0].nqsets;
break;
@ -1762,20 +1998,52 @@ cxgb_extension_ioctl(struct cdev *dev, unsigned long cmd, caddr_t data,
edata->val = pi->nqsets;
break;
}
#ifdef notyet
/*
* XXX FreeBSD driver does not currently support any
* offload functionality
*/
#ifdef notyet
case CHELSIO_LOAD_FW:
case CHELSIO_DEVUP:
case CHELSIO_SETMTUTAB:
case CHELSIO_GET_PM:
case CHELSIO_SET_PM:
case CHELSIO_READ_TCAM_WORD:
return (EOPNOTSUPP);
break;
#endif
case CHELSIO_SETMTUTAB: {
struct ch_mtus *m = (struct ch_mtus *)data;
int i;
if (!is_offload(sc))
return (EOPNOTSUPP);
if (offload_running(sc))
return (EBUSY);
if (m->nmtus != NMTUS)
return (EINVAL);
if (m->mtus[0] < 81) /* accommodate SACK */
return (EINVAL);
/*
* MTUs must be in ascending order
*/
for (i = 1; i < NMTUS; ++i)
if (m->mtus[i] < m->mtus[i - 1])
return (EINVAL);
memcpy(sc->params.mtus, m->mtus,
sizeof(sc->params.mtus));
break;
}
case CHELSIO_GETMTUTAB: {
struct ch_mtus *m = (struct ch_mtus *)data;
if (!is_offload(sc))
return (EOPNOTSUPP);
memcpy(m->mtus, sc->params.mtus, sizeof(m->mtus));
m->nmtus = NMTUS;
break;
}
case CHELSIO_DEVUP:
if (!is_offload(sc))
return (EOPNOTSUPP);
return offload_open(pi);
break;
case CHELSIO_GET_MEM: {
struct ch_mem_range *t = (struct ch_mem_range *)data;
struct mc7 *mem;
@ -1823,6 +2091,14 @@ cxgb_extension_ioctl(struct cdev *dev, unsigned long cmd, caddr_t data,
}
break;
}
case CHELSIO_READ_TCAM_WORD: {
struct ch_tcam_word *t = (struct ch_tcam_word *)data;
if (!is_offload(sc))
return (EOPNOTSUPP);
return -t3_read_mc5_range(&sc->mc5, t->addr, 1, t->buf);
break;
}
case CHELSIO_SET_TRACE_FILTER: {
struct ch_trace *t = (struct ch_trace *)data;
const struct trace_params *tp;
@ -1864,6 +2140,42 @@ cxgb_extension_ioctl(struct cdev *dev, unsigned long cmd, caddr_t data,
break;
}
case CHELSIO_SET_HW_SCHED: {
struct ch_hw_sched *t = (struct ch_hw_sched *)data;
unsigned int ticks_per_usec = core_ticks_per_usec(sc);
if ((sc->flags & FULL_INIT_DONE) == 0)
return (EAGAIN); /* need TP to be initialized */
if (t->sched >= NTX_SCHED || !in_range(t->mode, 0, 1) ||
!in_range(t->channel, 0, 1) ||
!in_range(t->kbps, 0, 10000000) ||
!in_range(t->class_ipg, 0, 10000 * 65535 / ticks_per_usec) ||
!in_range(t->flow_ipg, 0,
dack_ticks_to_usec(sc, 0x7ff)))
return (EINVAL);
if (t->kbps >= 0) {
error = t3_config_sched(sc, t->kbps, t->sched);
if (error < 0)
return (-error);
}
if (t->class_ipg >= 0)
t3_set_sched_ipg(sc, t->sched, t->class_ipg);
if (t->flow_ipg >= 0) {
t->flow_ipg *= 1000; /* us -> ns */
t3_set_pace_tbl(sc, &t->flow_ipg, t->sched, 1);
}
if (t->mode >= 0) {
int bit = 1 << (S_TX_MOD_TIMER_MODE + t->sched);
t3_set_reg_field(sc, A_TP_TX_MOD_QUEUE_REQ_MAP,
bit, t->mode ? bit : 0);
}
if (t->channel >= 0)
t3_set_reg_field(sc, A_TP_TX_MOD_QUEUE_REQ_MAP,
1 << t->sched, t->channel << t->sched);
break;
}
default:
return (EOPNOTSUPP);
break;

1634
sys/dev/cxgb/cxgb_offload.c Normal file

File diff suppressed because it is too large Load diff

260
sys/dev/cxgb/cxgb_offload.h Normal file
View file

@ -0,0 +1,260 @@
/**************************************************************************
Copyright (c) 2007, Chelsio Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the Chelsio Corporation nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
$FreeBSD$
***************************************************************************/
#ifndef _CXGB_OFFLOAD_H
#define _CXGB_OFFLOAD_H
#include <dev/cxgb/common/cxgb_tcb.h>
#include <dev/cxgb/cxgb_l2t.h>
#include <dev/cxgb/ulp/toecore/toedev.h>
#include <dev/cxgb/common/cxgb_t3_cpl.h>
struct adapter;
struct cxgb_client;
void cxgb_offload_init(void);
void cxgb_offload_exit(void);
void cxgb_adapter_ofld(struct adapter *adapter);
void cxgb_adapter_unofld(struct adapter *adapter);
int cxgb_offload_activate(struct adapter *adapter);
void cxgb_offload_deactivate(struct adapter *adapter);
int cxgb_ofld_recv(struct toedev *dev, struct mbuf **m, int n);
void cxgb_set_dummy_ops(struct toedev *dev);
/*
* Client registration. Users of T3 driver must register themselves.
* The T3 driver will call the add function of every client for each T3
* adapter activated, passing up the toedev ptr. Each client fills out an
* array of callback functions to process CPL messages.
*/
void cxgb_register_client(struct cxgb_client *client);
void cxgb_unregister_client(struct cxgb_client *client);
void cxgb_add_clients(struct toedev *tdev);
void cxgb_remove_clients(struct toedev *tdev);
typedef int (*cxgb_cpl_handler_func)(struct toedev *dev,
struct mbuf *m, void *ctx);
struct cxgb_client {
char *name;
void (*add) (struct toedev *);
void (*remove) (struct toedev *);
cxgb_cpl_handler_func *handlers;
int (*redirect)(void *ctx, struct rtentry *old,
struct rtentry *new,
struct l2t_entry *l2t);
TAILQ_ENTRY(cxgb_client) client_entry;
};
/*
* TID allocation services.
*/
int cxgb_alloc_atid(struct toedev *dev, struct cxgb_client *client,
void *ctx);
int cxgb_alloc_stid(struct toedev *dev, struct cxgb_client *client,
void *ctx);
void *cxgb_free_atid(struct toedev *dev, int atid);
void cxgb_free_stid(struct toedev *dev, int stid);
void cxgb_insert_tid(struct toedev *dev, struct cxgb_client *client,
void *ctx,
unsigned int tid);
void cxgb_queue_tid_release(struct toedev *dev, unsigned int tid);
void cxgb_remove_tid(struct toedev *dev, void *ctx, unsigned int tid);
struct toe_tid_entry {
struct cxgb_client *client;
void *ctx;
};
/* CPL message priority levels */
enum {
CPL_PRIORITY_DATA = 0, /* data messages */
CPL_PRIORITY_SETUP = 1, /* connection setup messages */
CPL_PRIORITY_TEARDOWN = 0, /* connection teardown messages */
CPL_PRIORITY_LISTEN = 1, /* listen start/stop messages */
CPL_PRIORITY_ACK = 1, /* RX ACK messages */
CPL_PRIORITY_CONTROL = 1 /* offload control messages */
};
/* Flags for return value of CPL message handlers */
enum {
CPL_RET_BUF_DONE = 1, // buffer processing done, buffer may be freed
CPL_RET_BAD_MSG = 2, // bad CPL message (e.g., unknown opcode)
CPL_RET_UNKNOWN_TID = 4 // unexpected unknown TID
};
typedef int (*cpl_handler_func)(struct toedev *dev, struct mbuf *m);
/*
* Returns a pointer to the first byte of the CPL header in an sk_buff that
* contains a CPL message.
*/
static inline void *cplhdr(struct mbuf *m)
{
return m->m_data;
}
void t3_register_cpl_handler(unsigned int opcode, cpl_handler_func h);
union listen_entry {
struct toe_tid_entry toe_tid;
union listen_entry *next;
};
union active_open_entry {
struct toe_tid_entry toe_tid;
union active_open_entry *next;
};
/*
* Holds the size, base address, free list start, etc of the TID, server TID,
* and active-open TID tables for a offload device.
* The tables themselves are allocated dynamically.
*/
struct tid_info {
struct toe_tid_entry *tid_tab;
unsigned int ntids;
volatile int tids_in_use;
union listen_entry *stid_tab;
unsigned int nstids;
unsigned int stid_base;
union active_open_entry *atid_tab;
unsigned int natids;
unsigned int atid_base;
/*
* The following members are accessed R/W so we put them in their own
* cache lines.
*
* XXX We could combine the atid fields above with the lock here since
* atids are use once (unlike other tids). OTOH the above fields are
* usually in cache due to tid_tab.
*/
struct mtx atid_lock /* ____cacheline_aligned_in_smp */;
union active_open_entry *afree;
unsigned int atids_in_use;
struct mtx stid_lock /*____cacheline_aligned */;
union listen_entry *sfree;
unsigned int stids_in_use;
};
struct toe_data {
#ifdef notyet
struct list_head list_node;
#endif
struct toedev *dev;
unsigned int tx_max_chunk; /* max payload for TX_DATA */
unsigned int max_wrs; /* max in-flight WRs per connection */
unsigned int nmtus;
const unsigned short *mtus;
struct tid_info tid_maps;
struct toe_tid_entry *tid_release_list;
struct mtx tid_release_lock;
struct task tid_release_task;
};
/*
* toedev -> toe_data accessor
*/
#define TOE_DATA(dev) (*(struct toe_data **)&(dev)->l4opt)
/*
* Map an ATID or STID to their entries in the corresponding TID tables.
*/
static inline union active_open_entry *atid2entry(const struct tid_info *t,
unsigned int atid)
{
return &t->atid_tab[atid - t->atid_base];
}
static inline union listen_entry *stid2entry(const struct tid_info *t,
unsigned int stid)
{
return &t->stid_tab[stid - t->stid_base];
}
/*
* Find the connection corresponding to a TID.
*/
static inline struct toe_tid_entry *lookup_tid(const struct tid_info *t,
unsigned int tid)
{
return tid < t->ntids ? &(t->tid_tab[tid]) : NULL;
}
/*
* Find the connection corresponding to a server TID.
*/
static inline struct toe_tid_entry *lookup_stid(const struct tid_info *t,
unsigned int tid)
{
if (tid < t->stid_base || tid >= t->stid_base + t->nstids)
return NULL;
return &(stid2entry(t, tid)->toe_tid);
}
/*
* Find the connection corresponding to an active-open TID.
*/
static inline struct toe_tid_entry *lookup_atid(const struct tid_info *t,
unsigned int tid)
{
if (tid < t->atid_base || tid >= t->atid_base + t->natids)
return NULL;
return &(atid2entry(t, tid)->toe_tid);
}
void *cxgb_alloc_mem(unsigned long size);
void cxgb_free_mem(void *addr);
void cxgb_neigh_update(struct rtentry *rt);
void cxgb_redirect(struct rtentry *old, struct rtentry *new);
int process_rx(struct toedev *dev, struct mbuf **m, int n);
int attach_toedev(struct toedev *dev);
void detach_toedev(struct toedev *dev);
#endif

View file

@ -9,11 +9,7 @@ modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the Chelsio Corporation nor the names of its
2. Neither the name of the Chelsio Corporation nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
@ -49,9 +45,17 @@ POSSIBILITY OF SUCH DAMAGE.
#define _CXGB_OSDEP_H_
typedef struct adapter adapter_t;
struct sge_rspq;
#define PANIC_IF(exp) do { \
if (exp) \
panic("BUG: %s", exp); \
} while (0)
#define m_get_priority(m) ((uintptr_t)(m)->m_pkthdr.rcvif)
#define m_set_priority(m, pri) ((m)->m_pkthdr.rcvif = (struct ifnet *)(pri))
#if __FreeBSD_version > 700030
#define INTR_FILTERS
#define FIRMWARE_LATEST
@ -68,6 +72,8 @@ struct sge_rspq;
#define TASKQUEUE_CURRENT
#endif
#define __read_mostly __attribute__((__section__(".data.read_mostly")))
/*
* Workaround for weird Chelsio issue
*/
@ -75,9 +81,10 @@ struct sge_rspq;
#define PRIV_SUPPORTED
#endif
#define CXGB_TX_CLEANUP_THRESHOLD 32
#define CXGB_TX_CLEANUP_THRESHOLD 32
#define LOG_WARNING 1
#define LOG_WARNING 1
#define LOG_ERR 2
#ifdef DEBUG_PRINT
#define DPRINTF printf
@ -107,6 +114,16 @@ void prefetch(void *x)
__asm volatile("prefetcht0 %0" :: "m" (*(unsigned long *)x));
}
extern void kdb_backtrace(void);
#define WARN_ON(condition) do { \
if (unlikely((condition)!=0)) { \
log(LOG_WARNING, "BUG: warning at %s:%d/%s()\n", __FILE__, __LINE__, __FUNCTION__); \
kdb_backtrace(); \
} \
} while (0)
#else /* !i386 && !amd64 */
#define mb()
#define rmb()
@ -137,7 +154,13 @@ static const int debug_flags = DBG_RX;
#define t3_os_sleep(x) DELAY((x) * 1000)
#define test_and_clear_bit(bit, p) atomic_cmpset_int((p), ((*(p)) | bit), ((*(p)) & ~bit))
#define max_t(type, a, b) (type)max((a), (b))
#define net_device ifnet
/* Standard PHY definitions */
#define BMCR_LOOPBACK BMCR_LOOP

File diff suppressed because it is too large Load diff

86
sys/dev/cxgb/sys/mbufq.h Normal file
View file

@ -0,0 +1,86 @@
/**************************************************************************
Copyright (c) 2007, Chelsio Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Neither the name of the Chelsio Corporation nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
$FreeBSD$
***************************************************************************/
struct mbuf_head {
struct mbuf *head;
struct mbuf *tail;
uint32_t qlen;
struct mtx lock;
};
static __inline void
mbufq_init(struct mbuf_head *l)
{
l->head = l->tail = NULL;
}
static __inline int
mbufq_empty(struct mbuf_head *l)
{
return (l->head == NULL);
}
static __inline int
mbufq_len(struct mbuf_head *l)
{
return (l->qlen);
}
static __inline void
mbufq_tail(struct mbuf_head *l, struct mbuf *m)
{
l->qlen++;
l->tail->m_nextpkt = m;
l->tail = m;
}
static __inline struct mbuf *
mbufq_dequeue(struct mbuf_head *l)
{
struct mbuf *m;
m = l->head;
if (m) {
if (m == l->tail)
l->tail = NULL;
l->head = m->m_nextpkt;
l->qlen--;
}
return (m);
}
static __inline struct mbuf *
mbufq_peek(struct mbuf_head *l)
{
return (l->head);
}

View file

@ -1,478 +0,0 @@
/*******************************************************************************
Copyright (c) 2007, Chelsio Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the Chelsio Inc, nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
$FreeBSD$
***************************************************************************/
begin 644 t3fw
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
F(Q36JAPY(A"B5!-O-2%"%:5/%$*)6JBV`T>?Z/H;`"WDR?AO````
`
end

View file

@ -0,0 +1,483 @@
/**************************************************************************
Copyright (c) 2007, Chelsio Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Neither the name of the Chelsio Corporation nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
$FreeBSD$
***************************************************************************/
begin 644 t3fw-4.0.0.bin.gz
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
!````
`
end

View file

@ -6,19 +6,21 @@ CXGB = ${.CURDIR}/../../dev/cxgb
KMOD= if_cxgb
SRCS= cxgb_mc5.c cxgb_vsc8211.c cxgb_ael1002.c cxgb_mv88e1xxx.c
SRCS+= cxgb_xgmac.c cxgb_t3_hw.c cxgb_main.c cxgb_sge.c cxgb_lro.c
SRCS+= device_if.h bus_if.h pci_if.h
SRCS+= cxgb_offload.c cxgb_l2t.c
SRCS+= device_if.h bus_if.h pci_if.h opt_zero.h
SRCS+= uipc_mvec.c
CFLAGS+= -DCONFIG_CHELSIO_T3_CORE -g -DDEFAULT_JUMBO -DCONFIG_DEFINED
CFLAGS+= -DCONFIG_CHELSIO_T3_CORE -g -DDEFAULT_JUMBO -DCONFIG_DEFINED
#CFLAGS+= -DINVARIANT_SUPPORT -DINVARIANTS -DDEBUG
.if ${MACHINE_ARCH} != "ia64"
# ld is broken on ia64
t3fw-3.2.bin: ${CXGB}/t3fw-3.2.bin.gz.uu
uudecode -p < ${CXGB}/t3fw-3.2.bin.gz.uu \
t3fw-4.0.0.bin: ${CXGB}/t3fw-4.0.0.bin.gz.uu
uudecode -p < ${CXGB}/t3fw-4.0.0.bin.gz.uu \
| gzip -dc > ${.TARGET}
FIRMWS= t3fw-3.2.bin:t3fw32
CLEANFILES+= t3fw-3.2.bin
FIRMWS= t3fw-4.0.0.bin:t3fw400
CLEANFILES+= t3fw-4.0.0.bin
.endif