diff options
| author | Kip Macy <kmacy@FreeBSD.org> | 2007-08-18 09:10:26 +0000 |
|---|---|---|
| committer | Kip Macy <kmacy@FreeBSD.org> | 2007-08-18 09:10:26 +0000 |
| commit | f048630ee48e858dc47c8e2104dfd52332a2c93a (patch) | |
| tree | 686ed9d5a9610acbd5321137b5494f477f45cd92 /sys/dev/cxgb | |
| parent | 85fc7ca020774f84b1cd8cfed6a294e04d1b3802 (diff) | |
Notes
Diffstat (limited to 'sys/dev/cxgb')
| -rw-r--r-- | sys/dev/cxgb/common/cxgb_common.h | 27 | ||||
| -rw-r--r-- | sys/dev/cxgb/common/cxgb_ctl_defs.h | 24 | ||||
| -rw-r--r-- | sys/dev/cxgb/common/cxgb_mc5.c | 45 | ||||
| -rw-r--r-- | sys/dev/cxgb/common/cxgb_t3_cpl.h | 36 | ||||
| -rw-r--r-- | sys/dev/cxgb/common/cxgb_t3_hw.c | 161 | ||||
| -rw-r--r-- | sys/dev/cxgb/common/cxgb_vsc7323.c | 37 | ||||
| -rw-r--r-- | sys/dev/cxgb/common/cxgb_xgmac.c | 55 | ||||
| -rw-r--r-- | sys/dev/cxgb/cxgb_adapter.h | 21 | ||||
| -rw-r--r-- | sys/dev/cxgb/cxgb_include.h | 8 | ||||
| -rw-r--r-- | sys/dev/cxgb/cxgb_ioctl.h | 29 | ||||
| -rw-r--r-- | sys/dev/cxgb/cxgb_l2t.c | 4 | ||||
| -rw-r--r-- | sys/dev/cxgb/cxgb_main.c | 667 | ||||
| -rw-r--r-- | sys/dev/cxgb/cxgb_offload.c | 39 | ||||
| -rw-r--r-- | sys/dev/cxgb/cxgb_offload.h | 19 | ||||
| -rw-r--r-- | sys/dev/cxgb/cxgb_osdep.h | 4 | ||||
| -rw-r--r-- | sys/dev/cxgb/cxgb_sge.c | 228 | ||||
| -rw-r--r-- | sys/dev/cxgb/sys/mvec.h | 3 | ||||
| -rw-r--r-- | sys/dev/cxgb/t3fw-4.1.0.bin.gz.uu | 482 | ||||
| -rw-r--r-- | sys/dev/cxgb/ulp/toecore/toedev.h | 2 |
19 files changed, 1080 insertions, 811 deletions
diff --git a/sys/dev/cxgb/common/cxgb_common.h b/sys/dev/cxgb/common/cxgb_common.h index 0a60a560c42e..9d75102a7bd3 100644 --- a/sys/dev/cxgb/common/cxgb_common.h +++ b/sys/dev/cxgb/common/cxgb_common.h @@ -38,8 +38,6 @@ $FreeBSD$ #endif enum { - MAX_NPORTS = 4, - TP_TMR_RES = 200, /* TP timer resolution in usec */ MAX_FRAME_SIZE = 10240, /* max MAC frame size, includes header + FCS */ EEPROMSIZE = 8192, /* Serial EEPROM size */ RSS_TABLE_SIZE = 64, /* size of RSS lookup and mapping tables */ @@ -48,6 +46,10 @@ enum { NCCTRL_WIN = 32, /* # of congestion control windows */ NTX_SCHED = 8, /* # of HW Tx scheduling queues */ PROTO_SRAM_LINES = 128, /* size of protocol sram */ + MAX_NPORTS = 4, + TP_TMR_RES = 200, + TP_SRAM_OFFSET = 4096, /* TP SRAM content offset in eeprom */ + TP_SRAM_LEN = 2112, /* TP SRAM content offset in eeprom */ }; #define MAX_RX_COALESCING_LEN 12288U @@ -72,8 +74,8 @@ enum { /* adapter interrupt-maintained statistics */ enum { TP_VERSION_MAJOR = 1, - TP_VERSION_MINOR = 0, - TP_VERSION_MICRO = 44 + TP_VERSION_MINOR = 1, + TP_VERSION_MICRO = 0 }; #define S_TP_VERSION_MAJOR 16 @@ -96,7 +98,7 @@ enum { enum { FW_VERSION_MAJOR = 4, - FW_VERSION_MINOR = 1, + FW_VERSION_MINOR = 5, FW_VERSION_MICRO = 0 }; @@ -393,6 +395,7 @@ enum { /* chip revisions */ T3_REV_A = 0, T3_REV_B = 2, T3_REV_B2 = 3, + T3_REV_C = 4, }; struct trace_params { @@ -467,6 +470,7 @@ struct cmac { unsigned int tx_xcnt; u64 tx_mcnt; unsigned int rx_xcnt; + unsigned int rx_ocnt; u64 rx_mcnt; unsigned int toggle_cnt; unsigned int txen; @@ -562,6 +566,9 @@ static inline void cphy_init(struct cphy *phy, adapter_t *adapter, /* Accumulate MAC statistics every 180 seconds. For 1G we multiply by 10. */ #define MAC_STATS_ACCUM_SECS 180 +/* The external MAC needs accumulation every 30 seconds */ +#define VSC_STATS_ACCUM_SECS 30 + #define XGM_REG(reg_addr, idx) \ ((reg_addr) + (idx) * (XGMAC0_1_BASE_ADDR - XGMAC0_0_BASE_ADDR)) @@ -656,9 +663,10 @@ int t3_seeprom_write(adapter_t *adapter, u32 addr, u32 data); int t3_seeprom_wp(adapter_t *adapter, int enable); int t3_read_flash(adapter_t *adapter, unsigned int addr, unsigned int nwords, u32 *data, int byte_oriented); +int t3_get_tp_version(adapter_t *adapter, u32 *vers); int t3_check_tpsram_version(adapter_t *adapter); -int t3_check_tpsram(adapter_t *adapter, u8 *tp_ram, unsigned int size); -int t3_load_fw(adapter_t *adapter, const u8 *fw_data, unsigned int size); +int t3_check_tpsram(adapter_t *adapter, const u8 *tp_ram, unsigned int size); +int t3_load_fw(adapter_t *adapter, const const u8 *fw_data, unsigned int size); int t3_get_fw_version(adapter_t *adapter, u32 *vers); int t3_check_fw_version(adapter_t *adapter); int t3_init_hw(adapter_t *adapter, u32 fw_params); @@ -668,10 +676,11 @@ int t3_prep_adapter(adapter_t *adapter, const struct adapter_info *ai, int reset void t3_led_ready(adapter_t *adapter); void t3_fatal_err(adapter_t *adapter); void t3_set_vlan_accel(adapter_t *adapter, unsigned int ports, int on); +void t3_enable_filters(adapter_t *adap); void t3_config_rss(adapter_t *adapter, unsigned int rss_config, const u8 *cpus, const u16 *rspq); int t3_read_rss(adapter_t *adapter, u8 *lkup, u16 *map); -int t3_set_proto_sram(adapter_t *adap, u8 *data); +int t3_set_proto_sram(adapter_t *adap, const u8 *data); int t3_mps_set_active_ports(adapter_t *adap, unsigned int port_mask); void t3_port_failover(adapter_t *adapter, int port); void t3_failover_done(adapter_t *adapter, int port); @@ -753,8 +762,8 @@ int t3_elmr_blk_write(adapter_t *adap, int start, const u32 *vals, int n); int t3_elmr_blk_read(adapter_t *adap, int start, u32 *vals, int n); int t3_vsc7323_init(adapter_t *adap, int nports); int t3_vsc7323_set_speed_fc(adapter_t *adap, int speed, int fc, int port); -int t3_vsc7323_set_addr(adapter_t *adap, u8 addr[6], int port); int t3_vsc7323_set_mtu(adapter_t *adap, unsigned int mtu, int port); +int t3_vsc7323_set_addr(adapter_t *adap, u8 addr[6], int port); int t3_vsc7323_enable(adapter_t *adap, int port, int which); int t3_vsc7323_disable(adapter_t *adap, int port, int which); const struct mac_stats *t3_vsc7323_update_stats(struct cmac *mac); diff --git a/sys/dev/cxgb/common/cxgb_ctl_defs.h b/sys/dev/cxgb/common/cxgb_ctl_defs.h index 590995588854..e96f497bd4c3 100644 --- a/sys/dev/cxgb/common/cxgb_ctl_defs.h +++ b/sys/dev/cxgb/common/cxgb_ctl_defs.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2007 Chelsio Communications. All rights reserved. + * Copyright (C) 2003-2006 Chelsio Communications. All rights reserved. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or @@ -12,7 +12,6 @@ #ifndef _CXGB3_OFFLOAD_CTL_DEFS_H #define _CXGB3_OFFLOAD_CTL_DEFS_H - enum { GET_MAX_OUTSTANDING_WR, GET_TX_MAX_CHUNK, @@ -25,9 +24,6 @@ enum { GET_IFF_FROM_MAC, GET_DDP_PARAMS, GET_PORTS, - FAILOVER, - FAILOVER_DONE, - FAILOVER_CLEAR, ULP_ISCSI_GET_PARAMS, ULP_ISCSI_SET_PARAMS, @@ -38,6 +34,14 @@ enum { RDMA_CQ_DISABLE, RDMA_CTRL_QP_SETUP, RDMA_GET_MEM, + + FAILOVER, + FAILOVER_DONE, + FAILOVER_CLEAR, + + GET_CPUIDX_OF_QSET, + + GET_RX_PAGE_INFO, }; /* @@ -81,7 +85,7 @@ struct ddp_params { struct adap_ports { unsigned int nports; /* number of ports on this adapter */ - struct ifnet *lldevs[4]; + struct net_device *lldevs[2]; }; /* @@ -102,6 +106,14 @@ struct ulp_iscsi_info { }; /* + * Offload TX/RX page information. + */ +struct ofld_page_info { + unsigned int page_size; /* Page size, should be a power of 2 */ + unsigned int num; /* Number of pages */ +}; + +/* * Structure used to return information to the RDMA layer. */ struct rdma_info { diff --git a/sys/dev/cxgb/common/cxgb_mc5.c b/sys/dev/cxgb/common/cxgb_mc5.c index 07a4d39b33ab..d3eed4a2c32e 100644 --- a/sys/dev/cxgb/common/cxgb_mc5.c +++ b/sys/dev/cxgb/common/cxgb_mc5.c @@ -165,16 +165,26 @@ static int init_mask_data_array(struct mc5 *mc5, u32 mask_array_base, return -1; /* Initialize the mask array. */ - dbgi_wr_data3(adap, 0xffffffff, 0xffffffff, 0xff); - for (i = 0; i < size72; i++) { - if (i == server_base) /* entering server or routing region */ - t3_write_reg(adap, A_MC5_DB_DBGI_REQ_DATA0, - mc5->mode == MC5_MODE_144_BIT ? - 0xfffffff9 : 0xfffffffd); + for (i = 0; i < server_base; i++) { + dbgi_wr_data3(adap, 0x3fffffff, 0xfff80000, 0xff); + if (mc5_write(adap, mask_array_base + (i << addr_shift), + write_cmd)) + return -1; + i++; + dbgi_wr_data3(adap, 0xffffffff, 0xffffffff, 0xff); if (mc5_write(adap, mask_array_base + (i << addr_shift), write_cmd)) return -1; } + + dbgi_wr_data3(adap, + mc5->mode == MC5_MODE_144_BIT ? 0xfffffff9 : 0xfffffffd, + 0xffffffff, 0xff); + for (; i < size72; i++) + if (mc5_write(adap, mask_array_base + (i << addr_shift), + write_cmd)) + return -1; + return 0; } @@ -305,17 +315,15 @@ static int init_idt43102(struct mc5 *mc5) /* Put MC5 in DBGI mode. */ static inline void mc5_dbgi_mode_enable(const struct mc5 *mc5) { - t3_write_reg(mc5->adapter, A_MC5_DB_CONFIG, - V_TMMODE(mc5->mode == MC5_MODE_72_BIT) | F_DBGIEN); + t3_set_reg_field(mc5->adapter, A_MC5_DB_CONFIG, F_PRTYEN | F_MBUSEN, + F_DBGIEN); } /* Put MC5 in M-Bus mode. */ static void mc5_dbgi_mode_disable(const struct mc5 *mc5) { - t3_write_reg(mc5->adapter, A_MC5_DB_CONFIG, - V_TMMODE(mc5->mode == MC5_MODE_72_BIT) | - V_COMPEN(mc5->mode == MC5_MODE_72_BIT) | - V_PRTYEN(mc5->parity_enabled) | F_MBUSEN); + t3_set_reg_field(mc5->adapter, A_MC5_DB_CONFIG, F_DBGIEN, + V_PRTYEN(mc5->parity_enabled) | F_MBUSEN); } /* @@ -325,9 +333,9 @@ static void mc5_dbgi_mode_disable(const struct mc5 *mc5) int t3_mc5_init(struct mc5 *mc5, unsigned int nservers, unsigned int nfilters, unsigned int nroutes) { - u32 cfg; int err; unsigned int tcam_size = mc5->tcam_size; + unsigned int mode72 = mc5->mode == MC5_MODE_72_BIT; adapter_t *adap = mc5->adapter; if (!tcam_size) @@ -336,10 +344,12 @@ int t3_mc5_init(struct mc5 *mc5, unsigned int nservers, unsigned int nfilters, if (nroutes > MAX_ROUTES || nroutes + nservers + nfilters > tcam_size) return -EINVAL; + if (nfilters && adap->params.rev < T3_REV_C) + mc5->parity_enabled = 0; + /* Reset the TCAM */ - cfg = t3_read_reg(adap, A_MC5_DB_CONFIG) & ~F_TMMODE; - cfg |= V_TMMODE(mc5->mode == MC5_MODE_72_BIT) | F_TMRST; - t3_write_reg(adap, A_MC5_DB_CONFIG, cfg); + t3_set_reg_field(adap, A_MC5_DB_CONFIG, F_TMMODE | F_COMPEN, + V_COMPEN(mode72) | V_TMMODE(mode72) | F_TMRST); if (t3_wait_op_done(adap, A_MC5_DB_CONFIG, F_TMRDY, 1, 500, 0)) { CH_ERR(adap, "TCAM reset timed out\n"); return -1; @@ -351,8 +361,6 @@ int t3_mc5_init(struct mc5 *mc5, unsigned int nservers, unsigned int nfilters, t3_write_reg(adap, A_MC5_DB_SERVER_INDEX, tcam_size - nroutes - nfilters - nservers); - mc5->parity_enabled = 1; - /* All the TCAM addresses we access have only the low 32 bits non 0 */ t3_write_reg(adap, A_MC5_DB_DBGI_REQ_ADDR1, 0); t3_write_reg(adap, A_MC5_DB_DBGI_REQ_ADDR2, 0); @@ -467,6 +475,7 @@ void __devinit t3_mc5_prep(adapter_t *adapter, struct mc5 *mc5, int mode) u32 cfg = t3_read_reg(adapter, A_MC5_DB_CONFIG); mc5->adapter = adapter; + mc5->parity_enabled = 1; mc5->mode = (unsigned char) mode; mc5->part_type = (unsigned char) G_TMTYPE(cfg); if (cfg & F_TMTYPEHI) diff --git a/sys/dev/cxgb/common/cxgb_t3_cpl.h b/sys/dev/cxgb/common/cxgb_t3_cpl.h index 06e99f264d74..e1b40303a6f7 100644 --- a/sys/dev/cxgb/common/cxgb_t3_cpl.h +++ b/sys/dev/cxgb/common/cxgb_t3_cpl.h @@ -31,10 +31,6 @@ $FreeBSD$ #ifndef T3_CPL_H #define T3_CPL_H -#if !defined(__LITTLE_ENDIAN_BITFIELD) && !defined(__BIG_ENDIAN_BITFIELD) -# include <asm/byteorder.h> -#endif - enum CPL_opcode { CPL_PASS_OPEN_REQ = 0x1, CPL_PASS_ACCEPT_RPL = 0x2, @@ -133,6 +129,7 @@ enum CPL_error { enum { CPL_CONN_POLICY_AUTO = 0, CPL_CONN_POLICY_ASK = 1, + CPL_CONN_POLICY_FILTER = 2, CPL_CONN_POLICY_DENY = 3 }; @@ -259,16 +256,16 @@ struct work_request_hdr { /* 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) +#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_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) @@ -415,6 +412,11 @@ struct work_request_hdr { #define V_CPU_IDX(x) ((x) << S_CPU_IDX) #define G_CPU_IDX(x) (((x) >> S_CPU_IDX) & M_CPU_IDX) +#define S_OPT1_VLAN 6 +#define M_OPT1_VLAN 0xFFF +#define V_OPT1_VLAN(x) ((x) << S_OPT1_VLAN) +#define G_OPT1_VLAN(x) (((x) >> S_OPT1_VLAN) & M_OPT1_VLAN) + #define S_MAC_MATCH_VALID 18 #define V_MAC_MATCH_VALID(x) ((x) << S_MAC_MATCH_VALID) #define F_MAC_MATCH_VALID V_MAC_MATCH_VALID(1U) @@ -808,6 +810,12 @@ struct tx_data_wr { __be32 param; }; +/* tx_data_wr.flags fields */ +#define S_TX_ACK_PAGES 21 +#define M_TX_ACK_PAGES 0x7 +#define V_TX_ACK_PAGES(x) ((x) << S_TX_ACK_PAGES) +#define G_TX_ACK_PAGES(x) (((x) >> S_TX_ACK_PAGES) & M_TX_ACK_PAGES) + /* tx_data_wr.param fields */ #define S_TX_PORT 0 #define M_TX_PORT 0x7 @@ -1009,7 +1017,7 @@ struct cpl_rx_data_ddp { union { __be32 nxt_seq; __be32 ddp_report; - } __U; + } u; __be32 ulp_crc; __be32 ddpvld_status; }; @@ -1515,7 +1523,7 @@ struct ulp_mem_io { __be32 len; }; - /* ulp_mem_io.cmd_lock_addr fields */ +/* 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) @@ -1524,7 +1532,7 @@ struct ulp_mem_io { #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 */ +/* 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) @@ -1534,7 +1542,7 @@ struct ulp_txpkt { __be32 len; }; - /* ulp_txpkt.cmd_dest fields */ +/* 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) diff --git a/sys/dev/cxgb/common/cxgb_t3_hw.c b/sys/dev/cxgb/common/cxgb_t3_hw.c index 2b3b045a90f6..69e0e83353fd 100644 --- a/sys/dev/cxgb/common/cxgb_t3_hw.c +++ b/sys/dev/cxgb/common/cxgb_t3_hw.c @@ -37,8 +37,8 @@ __FBSDID("$FreeBSD$"); #include <dev/cxgb/cxgb_include.h> #endif -#define DENTER() printf("entered %s\n", __FUNCTION__); -#define DEXIT() printf("exiting %s\n", __FUNCTION__); +#undef msleep +#define msleep t3_os_sleep /** @@ -355,7 +355,7 @@ int t3_phy_reset(struct cphy *phy, int mmd, int wait) return err; ctl &= BMCR_RESET; if (ctl) - t3_os_sleep(1); + msleep(1); } while (ctl && --wait); return ctl ? -1 : 0; @@ -482,7 +482,7 @@ const struct adapter_info *t3_get_adapter_info(unsigned int id) #define CAPS_10G (SUPPORTED_10000baseT_Full | SUPPORTED_AUI) static struct port_type_info port_types[] = { - { NULL, 0, NULL }, + { NULL }, { t3_ael1002_phy_prep, CAPS_10G | SUPPORTED_FIBRE, "10GBASE-XR" }, { t3_vsc8211_phy_prep, CAPS_1G | SUPPORTED_TP | SUPPORTED_IRQ, @@ -501,7 +501,7 @@ static struct port_type_info port_types[] = { #undef CAPS_10G #define VPD_ENTRY(name, len) \ - u8 name##_kword[2]; u8 name##_len; u8 name##_data[len] + u8 name##_kword[2]; u8 name##_len; char name##_data[len] /* * Partial EEPROM Vital Product Data structure. Includes only the ID and @@ -594,7 +594,7 @@ int t3_seeprom_write(adapter_t *adapter, u32 addr, u32 data) t3_os_pci_write_config_2(adapter, base + PCI_VPD_ADDR, (u16)addr | PCI_VPD_ADDR_F); do { - t3_os_sleep(1); + msleep(1); t3_os_pci_read_config_2(adapter, base + PCI_VPD_ADDR, &val); } while ((val & PCI_VPD_ADDR_F) && --attempts); @@ -653,11 +653,11 @@ static int get_vpd_params(adapter_t *adapter, struct vpd_params *p) return ret; } - p->cclk = simple_strtoul((char *)vpd.cclk_data, NULL, 10); - p->mclk = simple_strtoul((char *)vpd.mclk_data, NULL, 10); - p->uclk = simple_strtoul((char *)vpd.uclk_data, NULL, 10); - p->mdc = simple_strtoul((char *)vpd.mdc_data, NULL, 10); - p->mem_timing = simple_strtoul((char *)vpd.mt_data, NULL, 10); + p->cclk = simple_strtoul(vpd.cclk_data, NULL, 10); + p->mclk = simple_strtoul(vpd.mclk_data, NULL, 10); + p->uclk = simple_strtoul(vpd.uclk_data, NULL, 10); + p->mdc = simple_strtoul(vpd.mdc_data, NULL, 10); + p->mem_timing = simple_strtoul(vpd.mt_data, NULL, 10); /* Old eeproms didn't have port information */ if (adapter->params.rev == 0 && !vpd.port0_data[0]) { @@ -668,8 +668,8 @@ static int get_vpd_params(adapter_t *adapter, struct vpd_params *p) p->port_type[1] = (u8)hex2int(vpd.port1_data[0]); p->port_type[2] = (u8)hex2int(vpd.port2_data[0]); p->port_type[3] = (u8)hex2int(vpd.port3_data[0]); - p->xauicfg[0] = simple_strtoul((char *)vpd.xaui0cfg_data, NULL, 16); - p->xauicfg[1] = simple_strtoul((char *)vpd.xaui1cfg_data, NULL, 16); + p->xauicfg[0] = simple_strtoul(vpd.xaui0cfg_data, NULL, 16); + p->xauicfg[1] = simple_strtoul(vpd.xaui1cfg_data, NULL, 16); } for (i = 0; i < 6; i++) @@ -770,7 +770,7 @@ static int flash_wait_op(adapter_t *adapter, int attempts, int delay) if (--attempts == 0) return -EAGAIN; if (delay) - t3_os_sleep(delay); + msleep(delay); } } @@ -860,10 +860,32 @@ static int t3_write_flash(adapter_t *adapter, unsigned int addr, } /** + * t3_get_tp_version - read the tp sram version + * @adapter: the adapter + * @vers: where to place the version + * + * Reads the protocol sram version from sram. + */ +int t3_get_tp_version(adapter_t *adapter, u32 *vers) +{ + int ret; + + /* Get version loaded in SRAM */ + t3_write_reg(adapter, A_TP_EMBED_OP_FIELD0, 0); + ret = t3_wait_op_done(adapter, A_TP_EMBED_OP_FIELD0, + 1, 1, 5, 1); + if (ret) + return ret; + + *vers = t3_read_reg(adapter, A_TP_EMBED_OP_FIELD1); + + return 0; +} + +/** * t3_check_tpsram_version - read the tp sram version * @adapter: the adapter * - * Reads the protocol sram version from serial eeprom. */ int t3_check_tpsram_version(adapter_t *adapter) { @@ -886,6 +908,9 @@ int t3_check_tpsram_version(adapter_t *adapter) if (major == TP_VERSION_MAJOR && minor == TP_VERSION_MINOR) return 0; + CH_ERR(adapter, "found wrong TP version (%u.%u), " + "driver needs version %d.%d\n", major, minor, + TP_VERSION_MAJOR, TP_VERSION_MINOR); return -EINVAL; } @@ -899,7 +924,7 @@ int t3_check_tpsram_version(adapter_t *adapter) * Checks if an adapter's tp sram is compatible with the driver. * Returns 0 if the versions are compatible, a negative error otherwise. */ -int t3_check_tpsram(adapter_t *adapter, u8 *tp_sram, unsigned int size) +int t3_check_tpsram(adapter_t *adapter, const u8 *tp_sram, unsigned int size) { u32 csum; unsigned int i; @@ -960,8 +985,8 @@ int t3_check_fw_version(adapter_t *adapter) return 0; CH_ERR(adapter, "found wrong FW version (%u.%u), " - "driver needs version %d.%d\n", major, minor, - FW_VERSION_MAJOR, FW_VERSION_MINOR); + "driver needs version %d.%d\n", major, minor, + FW_VERSION_MAJOR, FW_VERSION_MINOR); return -EINVAL; } @@ -2329,6 +2354,28 @@ void t3_tp_set_offload_mode(adapter_t *adap, int enable) V_NICMODE(!enable)); } +static void tp_wr_bits_indirect(adapter_t *adap, unsigned int addr, + unsigned int mask, unsigned int val) +{ + t3_write_reg(adap, A_TP_PIO_ADDR, addr); + val |= t3_read_reg(adap, A_TP_PIO_DATA) & ~mask; + t3_write_reg(adap, A_TP_PIO_DATA, val); +} + +/** + * t3_enable_filters - enable the HW filters + * @adap: the adapter + * + * Enables the HW filters for NIC traffic. + */ +void t3_enable_filters(adapter_t *adap) +{ + t3_set_reg_field(adap, A_TP_IN_CONFIG, F_NICMODE, 0); + t3_set_reg_field(adap, A_MC5_DB_CONFIG, 0, F_FILTEREN); + t3_set_reg_field(adap, A_TP_GLOBAL_CONFIG, 0, V_FIVETUPLELOOKUP(3)); + tp_wr_bits_indirect(adap, A_TP_INGRESS_CONFIG, 0, F_LOOKUPEVERYPKT); +} + /** * pm_num_pages - calculate the number of pages of the payload memory * @mem_size: the size of the payload memory @@ -2422,14 +2469,6 @@ static inline void tp_wr_indirect(adapter_t *adap, unsigned int addr, u32 val) t3_write_reg(adap, A_TP_PIO_DATA, val); } -static void tp_wr_bits_indirect(adapter_t *adap, unsigned int addr, - unsigned int mask, unsigned int val) -{ - t3_write_reg(adap, A_TP_PIO_ADDR, addr); - val |= t3_read_reg(adap, A_TP_PIO_DATA) & ~mask; - t3_write_reg(adap, A_TP_PIO_DATA, val); -} - static void tp_config(adapter_t *adap, const struct tp_params *p) { t3_write_reg(adap, A_TP_GLOBAL_CONFIG, F_TXPACINGENABLE | F_PATHMTU | @@ -2459,10 +2498,12 @@ static void tp_config(adapter_t *adap, const struct tp_params *p) if (adap->params.rev > 0) { tp_wr_indirect(adap, A_TP_EGRESS_CONFIG, F_REWRITEFORCETOSIZE); - t3_set_reg_field(adap, A_TP_PARA_REG3, F_TXPACEAUTO, - F_TXPACEAUTO); + t3_set_reg_field(adap, A_TP_PARA_REG3, 0, + F_TXPACEAUTO | F_TXPACEAUTOSTRICT); t3_set_reg_field(adap, A_TP_PC_CONFIG, F_LOCKTID, F_LOCKTID); - t3_set_reg_field(adap, A_TP_PARA_REG3, 0, F_TXPACEAUTOSTRICT); + tp_wr_indirect(adap, A_TP_VLAN_PRI_MAP, 0xfa50); + tp_wr_indirect(adap, A_TP_MAC_MATCH_MAP0, 0xfac688); + tp_wr_indirect(adap, A_TP_MAC_MATCH_MAP1, 0xfac688); } else t3_set_reg_field(adap, A_TP_PARA_REG3, 0, F_TXPACEFIXED); @@ -2816,17 +2857,17 @@ static void ulp_config(adapter_t *adap, const struct tp_params *p) * * Write the contents of the protocol SRAM. */ -int t3_set_proto_sram(adapter_t *adap, u8 *data) +int t3_set_proto_sram(adapter_t *adap, const u8 *data) { int i; - u32 *buf = (u32 *)data; + u32 *buf = (u32 *)(uintptr_t)data; for (i = 0; i < PROTO_SRAM_LINES; i++) { - t3_write_reg(adap, A_TP_EMBED_OP_FIELD5, htobe32(*buf++)); - t3_write_reg(adap, A_TP_EMBED_OP_FIELD4, htobe32(*buf++)); - t3_write_reg(adap, A_TP_EMBED_OP_FIELD3, htobe32(*buf++)); - t3_write_reg(adap, A_TP_EMBED_OP_FIELD2, htobe32(*buf++)); - t3_write_reg(adap, A_TP_EMBED_OP_FIELD1, htobe32(*buf++)); + t3_write_reg(adap, A_TP_EMBED_OP_FIELD5, cpu_to_be32(*buf++)); + t3_write_reg(adap, A_TP_EMBED_OP_FIELD4, cpu_to_be32(*buf++)); + t3_write_reg(adap, A_TP_EMBED_OP_FIELD3, cpu_to_be32(*buf++)); + t3_write_reg(adap, A_TP_EMBED_OP_FIELD2, cpu_to_be32(*buf++)); + t3_write_reg(adap, A_TP_EMBED_OP_FIELD1, cpu_to_be32(*buf++)); t3_write_reg(adap, A_TP_EMBED_OP_FIELD0, i << 1 | 1 << 31); if (t3_wait_op_done(adap, A_TP_EMBED_OP_FIELD0, 1, 1, 5, 1)) @@ -3053,7 +3094,7 @@ static int calibrate_xgm(adapter_t *adapter) for (i = 0; i < 5; ++i) { t3_write_reg(adapter, A_XGM_XAUI_IMP, 0); (void) t3_read_reg(adapter, A_XGM_XAUI_IMP); - t3_os_sleep(1); + msleep(1); v = t3_read_reg(adapter, A_XGM_XAUI_IMP); if (!(v & (F_XGM_CALFAULT | F_CALBUSY))) { t3_write_reg(adapter, A_XGM_XAUI_IMP, @@ -3140,12 +3181,12 @@ static int mc7_init(struct mc7 *mc7, unsigned int mc7_clock, int mem_type) t3_write_reg(adapter, mc7->offset + A_MC7_CFG, val | F_IFEN); val = t3_read_reg(adapter, mc7->offset + A_MC7_CFG); /* flush */ - t3_os_sleep(1); + msleep(1); if (!slow) { t3_write_reg(adapter, mc7->offset + A_MC7_CAL, F_SGL_CAL_EN); (void) t3_read_reg(adapter, mc7->offset + A_MC7_CAL); - t3_os_sleep(1); + msleep(1); if (t3_read_reg(adapter, mc7->offset + A_MC7_CAL) & (F_BUSY | F_SGL_CAL_EN | F_CAL_FAULT)) { CH_ERR(adapter, "%s MC7 calibration timed out\n", @@ -3211,7 +3252,7 @@ static int mc7_init(struct mc7 *mc7, unsigned int mc7_clock, int mem_type) attempts = 50; do { - t3_os_sleep(250); + msleep(250); val = t3_read_reg(adapter, mc7->offset + A_MC7_BIST_OP); } while ((val & F_BUSY) && --attempts); if (val & F_BUSY) { @@ -3297,11 +3338,8 @@ int t3_init_hw(adapter_t *adapter, u32 fw_params) else if (calibrate_xgm(adapter)) goto out_err; - if (adapter->params.nports > 2) { + if (adapter->params.nports > 2) t3_mac_reset(&adap2pinfo(adapter, 0)->mac); - if ((err = t3_vsc7323_init(adapter, adapter->params.nports))) - goto out_err; - } if (vpd->mclk) { partition_mem(adapter, &adapter->params.tp); @@ -3341,7 +3379,7 @@ int t3_init_hw(adapter_t *adapter, u32 fw_params) (void) t3_read_reg(adapter, A_CIM_BOOT_CFG); /* flush */ do { /* wait for uP to initialize */ - t3_os_sleep(20); + msleep(20); } while (t3_read_reg(adapter, A_CIM_HOST_ACC_DATA) && --attempts); if (!attempts) { CH_ERR(adapter, "uP initialization timed out\n"); @@ -3453,7 +3491,6 @@ void mac_prep(struct cmac *mac, adapter_t *adapter, int index) { mac->adapter = adapter; mac->multiport = adapter->params.nports > 2; - if (mac->multiport) { mac->ext_port = (unsigned char)index; mac->nucast = 8; @@ -3516,7 +3553,7 @@ static int t3_reset_adapter(adapter_t *adapter) * XXX The delay time should be modified. */ for (i = 0; i < 10; i++) { - t3_os_sleep(50); + msleep(50); t3_os_pci_read_config_2(adapter, 0x00, &devid); if (devid == 0x1425) break; @@ -3548,16 +3585,18 @@ int __devinit t3_prep_adapter(adapter_t *adapter, adapter->params.chan_map = !!ai->nports0 | (!!ai->nports1 << 1); adapter->params.rev = t3_read_reg(adapter, A_PL_REV); adapter->params.linkpoll_period = 0; - adapter->params.stats_update_period = is_10G(adapter) ? - MAC_STATS_ACCUM_SECS : (MAC_STATS_ACCUM_SECS * 10); + if (adapter->params.nports > 2) + adapter->params.stats_update_period = VSC_STATS_ACCUM_SECS; + else + adapter->params.stats_update_period = is_10G(adapter) ? + MAC_STATS_ACCUM_SECS : (MAC_STATS_ACCUM_SECS * 10); adapter->params.pci.vpd_cap_addr = t3_os_find_pci_capability(adapter, PCI_CAP_ID_VPD); ret = get_vpd_params(adapter, &adapter->params.vpd); - if (ret < 0) { - printf("failed to get VPD params\n"); + if (ret < 0) return ret; - } + if (reset && t3_reset_adapter(adapter)) return -1; @@ -3606,24 +3645,18 @@ int __devinit t3_prep_adapter(adapter_t *adapter, early_hw_init(adapter, ai); + if (adapter->params.nports > 2 && + (ret = t3_vsc7323_init(adapter, adapter->params.nports))) + return ret; + for_each_port(adapter, i) { u8 hw_addr[6]; struct port_info *p = adap2pinfo(adapter, i); - while (adapter->params.vpd.port_type[j] == 0) { + while (!adapter->params.vpd.port_type[j]) ++j; - } - if (adapter->params.vpd.port_type[j] > sizeof(port_types)/sizeof(port_types[0])) { - printf("bad port type idx=%d\n", adapter->params.vpd.port_type[j]); - printf("port types: "); - for (i = 0; i < j; i++) - printf("port[%d]=%d ", i, adapter->params.vpd.port_type[i]); - printf("\n"); - return -1; - } - - p->port_type = &port_types[adapter->params.vpd.port_type[j]]; + p->port_type = &port_types[adapter->params.vpd.port_type[j]]; p->port_type->phy_prep(&p->phy, adapter, ai->phy_base_addr + j, ai->mdio_ops); mac_prep(&p->mac, adapter, j); diff --git a/sys/dev/cxgb/common/cxgb_vsc7323.c b/sys/dev/cxgb/common/cxgb_vsc7323.c index 51e254eb15c4..4efd24e42228 100644 --- a/sys/dev/cxgb/common/cxgb_vsc7323.c +++ b/sys/dev/cxgb/common/cxgb_vsc7323.c @@ -115,13 +115,16 @@ int t3_vsc7323_init(adapter_t *adap, int nports) { VSC_REG(2, 0, 0x2f), 0 }, { VSC_REG(2, 0, 0xf), 0xa0010291 }, { VSC_REG(2, 1, 0x2f), 1 }, - { VSC_REG(2, 1, 0xf), 0xa0026301 } + { VSC_REG(2, 1, 0xf), 0xa026301 } }; static struct addr_val_pair xg_avp[] = { { VSC_REG(1, 10, 0), 0x600b }, - { VSC_REG(1, 10, 2), 0x4000 }, + { VSC_REG(1, 10, 1), 0x70600 }, //QUANTA = 96*1024*8/512 + { VSC_REG(1, 10, 2), 0x2710 }, { VSC_REG(1, 10, 5), 0x65 }, - { VSC_REG(1, 10, 7), 3 }, + { VSC_REG(1, 10, 7), 0x23 }, + { VSC_REG(1, 10, 0x23), 0x800007bf }, + { VSC_REG(1, 10, 0x23), 0x000007bf }, { VSC_REG(1, 10, 0x23), 0x800007bf }, { VSC_REG(1, 10, 0x24), 4 } }; @@ -130,10 +133,9 @@ int t3_vsc7323_init(adapter_t *adap, int nports) for (i = 0; i < ARRAY_SIZE(sys_avp); i++) if ((ret = t3_elmr_blk_write(adap, sys_avp[i].reg_addr, - &sys_avp[i].val, 1))) + &sys_avp[i].val, 1))) return ret; - ing_step = 0xc0 / nports; egr_step = 0x40 / nports; ing_bot = egr_bot = 0; @@ -141,22 +143,27 @@ int t3_vsc7323_init(adapter_t *adap, int nports) // egr_wm = egr_step * 64; /* {ING,EGR}_CONTROL.CLR = 1 here */ - for (i = 0; i < nports; i++) - if ((ret = elmr_write(adap, VSC_REG(2, 0, 0x10 + i), + for (i = 0; i < nports; i++) { + if ( + (ret = elmr_write(adap, VSC_REG(2, 0, 0x10 + i), ((ing_bot + ing_step) << 16) | ing_bot)) || - (ret = elmr_write(adap, VSC_REG(2, 0, 0x50 + i), 0)) || + (ret = elmr_write(adap, VSC_REG(2, 0, 0x40 + i), + 0x6000a00)) || + (ret = elmr_write(adap, VSC_REG(2, 0, 0x50 + i), 1)) || (ret = elmr_write(adap, VSC_REG(2, 1, 0x10 + i), ((egr_bot + egr_step) << 16) | egr_bot)) || (ret = elmr_write(adap, VSC_REG(2, 1, 0x40 + i), 0x2000280)) || (ret = elmr_write(adap, VSC_REG(2, 1, 0x50 + i), 0))) return ret; - + ing_bot += ing_step; + egr_bot += egr_step; + } for (i = 0; i < ARRAY_SIZE(fifo_avp); i++) if ((ret = t3_elmr_blk_write(adap, fifo_avp[i].reg_addr, - &fifo_avp[i].val, 1))) - return ret; + &fifo_avp[i].val, 1))) + return ret; for (i = 0; i < ARRAY_SIZE(xg_avp); i++) if ((ret = t3_elmr_blk_write(adap, xg_avp[i].reg_addr, @@ -198,7 +205,7 @@ int t3_vsc7323_set_speed_fc(adapter_t *adap, int speed, int fc, int port) return r; } - r = (fc & PAUSE_RX) ? 0x6ffff : 0x2ffff; + r = (fc & PAUSE_RX) ? 0x60200 : 0x20200; //QUANTA = 32*1024*8/512 if (fc & PAUSE_TX) r |= (1 << 19); return elmr_write(adap, VSC_REG(1, port, 1), r); @@ -212,12 +219,12 @@ int t3_vsc7323_set_mtu(adapter_t *adap, unsigned int mtu, int port) int t3_vsc7323_set_addr(adapter_t *adap, u8 addr[6], int port) { int ret; - + ret = elmr_write(adap, VSC_REG(1, port, 3), - (addr[0] << 16) | (addr[1] << 8) | addr[2]); + (addr[0] << 16) | (addr[1] << 8) | addr[2]); if (!ret) ret = elmr_write(adap, VSC_REG(1, port, 4), - (addr[3] << 16) | (addr[4] << 8) | addr[5]); + (addr[3] << 16) | (addr[4] << 8) | addr[5]); return ret; } diff --git a/sys/dev/cxgb/common/cxgb_xgmac.c b/sys/dev/cxgb/common/cxgb_xgmac.c index 34b05cd09241..f11b34336337 100644 --- a/sys/dev/cxgb/common/cxgb_xgmac.c +++ b/sys/dev/cxgb/common/cxgb_xgmac.c @@ -37,6 +37,9 @@ __FBSDID("$FreeBSD$"); #include <dev/cxgb/cxgb_include.h> #endif +#undef msleep +#define msleep t3_os_sleep + /* * # of exact address filters. The first one is used for the station address, * the rest are available for multicast addresses. @@ -154,7 +157,7 @@ int t3_mac_reset(struct cmac *mac) t3_write_reg(adap, A_XGM_RESET_CTRL + oft, val); (void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */ if ((val & F_PCS_RESET_) && adap->params.rev) { - t3_os_sleep(1); + msleep(1); t3b_pcs_reset(mac); } @@ -179,7 +182,7 @@ static int t3b2_mac_reset(struct cmac *mac) t3_write_reg(adap, A_XGM_RESET_CTRL + oft, F_MAC_RESET_); (void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */ - t3_os_sleep(10); + msleep(10); /* Check for xgm Rx fifo empty */ if (t3_wait_op_done(adap, A_XGM_RX_MAX_PKT_SIZE_ERR_CNT + oft, @@ -202,7 +205,7 @@ static int t3b2_mac_reset(struct cmac *mac) t3_write_reg(adap, A_XGM_RESET_CTRL + oft, val); (void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */ if ((val & F_PCS_RESET_) && adap->params.rev) { - t3_os_sleep(1); + msleep(1); t3b_pcs_reset(mac); } t3_write_reg(adap, A_XGM_RX_CFG + oft, @@ -243,7 +246,6 @@ int t3_mac_set_address(struct cmac *mac, unsigned int idx, u8 addr[6]) set_addr_filter(mac, idx, addr); if (mac->multiport && idx < mac->adapter->params.nports) t3_vsc7323_set_addr(mac->adapter, addr, idx); - return 0; } @@ -425,8 +427,17 @@ int t3_mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex, int fc) if (duplex >= 0 && duplex != DUPLEX_FULL) return -EINVAL; - if (mac->multiport) + if (mac->multiport) { + val = t3_read_reg(adap, A_XGM_RXFIFO_CFG + oft); + val &= ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM); + val |= V_RXFIFOPAUSEHWM(rx_fifo_hwm(t3_read_reg(adap, + A_XGM_RX_MAX_PKT_SIZE + oft)) / 8); + t3_write_reg(adap, A_XGM_RXFIFO_CFG + oft, val); + + t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN, + F_TXPAUSEEN); return t3_vsc7323_set_speed_fc(adap, speed, fc, mac->ext_port); + } if (speed >= 0) { if (speed == SPEED_10) val = V_PORTSPEED(0); @@ -451,7 +462,7 @@ int t3_mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex, int fc) t3_write_reg(adap, A_XGM_RXFIFO_CFG + oft, val); t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN, - (fc & PAUSE_RX) ? F_TXPAUSEEN : 0); + (fc & PAUSE_RX) ? F_TXPAUSEEN : 0); return 0; } @@ -466,12 +477,13 @@ int t3_mac_enable(struct cmac *mac, int which) return t3_vsc7323_enable(adap, mac->ext_port, which); if (which & MAC_DIRECTION_TX) { - t3_write_reg(adap, A_XGM_TX_CTRL + oft, F_TXEN); t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx); t3_write_reg(adap, A_TP_PIO_DATA, 0xc0ede401); t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_MODE); t3_set_reg_field(adap, A_TP_PIO_DATA, 1 << idx, 1 << idx); + t3_write_reg(adap, A_XGM_TX_CTRL + oft, F_TXEN); + t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CNT_CH0 + idx); mac->tx_mcnt = s->tx_frames; mac->tx_tcnt = (G_TXDROPCNTCH0RCVD(t3_read_reg(adap, @@ -493,7 +505,6 @@ int t3_mac_enable(struct cmac *mac, int which) int t3_mac_disable(struct cmac *mac, int which) { - int idx = macidx(mac); adapter_t *adap = mac->adapter; int val; @@ -501,17 +512,14 @@ int t3_mac_disable(struct cmac *mac, int which) return t3_vsc7323_disable(adap, mac->ext_port, which); if (which & MAC_DIRECTION_TX) { + val = t3_read_reg(adap, A_MPS_CFG); t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, 0); - t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx); - t3_write_reg(adap, A_TP_PIO_DATA, 0xc000001f); - t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_MODE); - t3_set_reg_field(adap, A_TP_PIO_DATA, 1 << idx, 1 << idx); mac->txen = 0; } 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); + msleep(100); t3_write_reg(adap, A_XGM_RX_CTRL + mac->offset, 0); val = F_MAC_RESET_; if (is_10G(adap)) @@ -535,6 +543,13 @@ int t3b2_mac_watchdog_task(struct cmac *mac) unsigned int rx_mcnt = (unsigned int)s->rx_frames; unsigned int rx_xcnt; + if (mac->multiport) { + tx_mcnt = t3_read_reg(adap, A_XGM_STAT_TX_FRAME_LOW); + rx_mcnt = t3_read_reg(adap, A_XGM_STAT_RX_FRAMES_LOW); + } else { + tx_mcnt = (unsigned int)s->tx_frames; + rx_mcnt = (unsigned int)s->rx_frames; + } 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*/ @@ -573,15 +588,18 @@ int t3b2_mac_watchdog_task(struct cmac *mac) } rxcheck: - if (rx_mcnt != mac->rx_mcnt) + if (rx_mcnt != mac->rx_mcnt) { rx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap, A_XGM_RX_SPI4_SOP_EOP_CNT + - mac->offset))); - else + mac->offset))) + + (s->rx_fifo_ovfl - mac->rx_ocnt); + mac->rx_ocnt = s->rx_fifo_ovfl; + } else goto out; if (mac->rx_mcnt != s->rx_frames && rx_xcnt == 0 && mac->rx_xcnt == 0) { - status = 2; + if (!mac->multiport) + status = 2; goto out; } @@ -622,6 +640,9 @@ const struct mac_stats *t3_mac_update_stats(struct cmac *mac) u32 v, lo; + if (mac->multiport) + return t3_vsc7323_update_stats(mac); + RMON_UPDATE64(mac, rx_octets, RX_BYTES_LOW, RX_BYTES_HIGH); RMON_UPDATE64(mac, rx_frames, RX_FRAMES_LOW, RX_FRAMES_HIGH); RMON_UPDATE(mac, rx_mcast_frames, RX_MCAST_FRAMES); diff --git a/sys/dev/cxgb/cxgb_adapter.h b/sys/dev/cxgb/cxgb_adapter.h index bdca764a38ba..6605ea9693e4 100644 --- a/sys/dev/cxgb/cxgb_adapter.h +++ b/sys/dev/cxgb/cxgb_adapter.h @@ -117,7 +117,7 @@ struct port_info { #else struct mtx lock; #endif - int port; + int port_id; uint8_t hw_addr[ETHER_ADDR_LEN]; uint8_t nqsets; uint8_t first_qset; @@ -138,6 +138,7 @@ enum { /* adapter flags */ USING_MSIX = (1 << 2), QUEUES_BOUND = (1 << 3), FW_UPTODATE = (1 << 4), + TPS_UPTODATE = (1 << 5), }; @@ -239,6 +240,8 @@ struct sge_fl { struct tx_desc; struct tx_sw_desc; +#define TXQ_TRANSMITTING 0x1 + struct sge_txq { uint64_t flags; uint32_t in_use; @@ -254,7 +257,9 @@ struct sge_txq { struct tx_sw_desc *sdesc; uint32_t token; bus_addr_t phys_addr; - struct task qresume_tsk; + struct task qresume_task; + struct task qreclaim_task; + struct port_info *port; uint32_t cntxt_id; uint64_t stops; uint64_t restarts; @@ -297,13 +302,15 @@ struct sge { struct mtx reg_lock; }; +struct filter_info; + struct adapter { device_t dev; int flags; TAILQ_ENTRY(adapter) adapter_entry; /* PCI register resources */ - uint32_t regs_rid; + int regs_rid; struct resource *regs_res; bus_space_handle_t bh; bus_space_tag_t bt; @@ -327,7 +334,11 @@ struct adapter { struct resource *msix_irq_res[SGE_QSETS]; int msix_irq_rid[SGE_QSETS]; void *msix_intr_tag[SGE_QSETS]; + uint8_t rxpkt_map[8]; /* maps RX_PKT interface values to port ids */ + uint8_t rrss_map[SGE_QSETS]; /* revers RSS map table */ + struct filter_info *filters; + /* Tasks */ struct task ext_intr_task; struct task slow_intr_task; @@ -391,13 +402,13 @@ struct t3_rx_mode { #define PORT_UNLOCK(port) sx_xunlock(&(port)->lock); #define PORT_LOCK_INIT(port, name) SX_INIT(&(port)->lock, name) #define PORT_LOCK_DEINIT(port) SX_DESTROY(&(port)->lock) -#define PORT_LOCK_ASSERT_OWNED(port) sx_assert(&(port)->lock, SX_LOCKED) +#define PORT_LOCK_ASSERT_OWNED(port) sx_assert(&(port)->lock, SA_LOCKED) #define ADAPTER_LOCK(adap) sx_xlock(&(adap)->lock); #define ADAPTER_UNLOCK(adap) sx_xunlock(&(adap)->lock); #define ADAPTER_LOCK_INIT(adap, name) SX_INIT(&(adap)->lock, name) #define ADAPTER_LOCK_DEINIT(adap) SX_DESTROY(&(adap)->lock) -#define ADAPTER_LOCK_ASSERT_NOTOWNED(adap) sx_assert(&(adap)->lock, SX_UNLOCKED) +#define ADAPTER_LOCK_ASSERT_NOTOWNED(adap) sx_assert(&(adap)->lock, SA_UNLOCKED) #else #define PORT_LOCK(port) mtx_lock(&(port)->lock); #define PORT_UNLOCK(port) mtx_unlock(&(port)->lock); diff --git a/sys/dev/cxgb/cxgb_include.h b/sys/dev/cxgb/cxgb_include.h index 0caebec62120..c4eb5add9ffe 100644 --- a/sys/dev/cxgb/cxgb_include.h +++ b/sys/dev/cxgb/cxgb_include.h @@ -5,15 +5,13 @@ #ifdef CONFIG_DEFINED #include <cxgb_osdep.h> -#include <cxgb_l2t.h> #include <common/cxgb_common.h> #include <cxgb_ioctl.h> #include <cxgb_offload.h> #include <common/cxgb_regs.h> #include <common/cxgb_t3_cpl.h> -#include <common/cxgb_tcb.h> -#include <common/cxgb_ctl_defs.h> -#include <common/cxgb_sge_defs.h> +#include <dev/cxgb/common/cxgb_ctl_defs.h> +#include <dev/cxgb/common/cxgb_sge_defs.h> #include <common/cxgb_firmware_exports.h> #include <sys/mvec.h> #include <ulp/toecore/toedev.h> @@ -25,10 +23,8 @@ #include <dev/cxgb/cxgb_osdep.h> #include <dev/cxgb/common/cxgb_common.h> #include <dev/cxgb/cxgb_ioctl.h> -#include <dev/cxgb/cxgb_l2t.h> #include <dev/cxgb/cxgb_offload.h> #include <dev/cxgb/common/cxgb_regs.h> -#include <dev/cxgb/common/cxgb_tcb.h> #include <dev/cxgb/common/cxgb_t3_cpl.h> #include <dev/cxgb/common/cxgb_ctl_defs.h> #include <dev/cxgb/common/cxgb_sge_defs.h> diff --git a/sys/dev/cxgb/cxgb_ioctl.h b/sys/dev/cxgb/cxgb_ioctl.h index d725a9a06ae9..65deb447da3b 100644 --- a/sys/dev/cxgb/cxgb_ioctl.h +++ b/sys/dev/cxgb/cxgb_ioctl.h @@ -66,6 +66,7 @@ enum { CH_SETMIIREGS, CH_SET_FILTER, CH_SET_HW_SCHED, + CH_DEL_FILTER, }; struct ch_reg { @@ -127,7 +128,31 @@ struct ch_hw_sched { int8_t channel; int32_t kbps; /* rate in Kbps */ int32_t class_ipg; /* tenths of nanoseconds */ - int32_t flow_ipg; /* usec */ + uint32_t flow_ipg; /* usec */ +}; + +struct ch_filter_tuple { + uint32_t sip; + uint32_t dip; + uint16_t sport; + uint16_t dport; + uint16_t vlan:12; + uint16_t vlan_prio:3; +}; + +struct ch_filter { + uint32_t cmd; + uint32_t filter_id; + struct ch_filter_tuple val; + struct ch_filter_tuple mask; + uint16_t mac_addr_idx; + uint8_t mac_hit:1; + uint8_t proto:2; + + uint8_t want_filter_id:1; /* report filter TID instead of RSS hash */ + uint8_t pass:1; /* whether to pass or drop packets */ + uint8_t rss:1; /* use RSS or specified qset */ + uint8_t qset; }; #ifndef TCB_SIZE @@ -232,5 +257,7 @@ struct mii_data { #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_SET_FILTER _IOW('f', CH_SET_FILTER, struct ch_filter) +#define CHELSIO_DEL_FILTER _IOW('f', CH_DEL_FILTER, struct ch_filter) #define CHELSIO_DEVUP _IO('f', CH_DEVUP) #endif diff --git a/sys/dev/cxgb/cxgb_l2t.c b/sys/dev/cxgb/cxgb_l2t.c index 97c0ffafc381..d4a40bad430d 100644 --- a/sys/dev/cxgb/cxgb_l2t.c +++ b/sys/dev/cxgb/cxgb_l2t.c @@ -37,7 +37,9 @@ __FBSDID("$FreeBSD$"); #include <sys/bus.h> #include <sys/lock.h> #include <sys/mutex.h> - +#if __FreeBSD_version > 700000 +#include <sys/rwlock.h> +#endif #include <sys/socket.h> #include <sys/socketvar.h> diff --git a/sys/dev/cxgb/cxgb_main.c b/sys/dev/cxgb/cxgb_main.c index 07e4b175d0cd..04fd15fd5c44 100644 --- a/sys/dev/cxgb/cxgb_main.c +++ b/sys/dev/cxgb/cxgb_main.c @@ -189,6 +189,7 @@ extern int collapse_mbufs; * msi = 0: force pin interrupts */ 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, @@ -224,6 +225,28 @@ enum { MIN_FL_ENTRIES = 32 }; +struct filter_info { + u32 sip; + u32 sip_mask; + u32 dip; + u16 sport; + u16 dport; + u32 vlan:12; + u32 vlan_prio:3; + u32 mac_hit:1; + u32 mac_idx:4; + u32 mac_vld:1; + u32 pkt_type:2; + u32 report_filter_id:1; + u32 pass:1; + u32 rss:1; + u32 qset:3; + u32 locked:1; + u32 valid:1; +}; + +enum { FILTER_NO_VLAN_PRI = 7 }; + #define PORT_MASK ((1 << MAX_NPORTS) - 1) /* Table for probing the cards. The desc field isn't actually used */ @@ -247,6 +270,29 @@ struct cxgb_ident { {0, 0, 0, NULL} }; + +static int set_eeprom(struct port_info *pi, const uint8_t *data, int len, int offset); + +static inline char +t3rev2char(struct adapter *adapter) +{ + char rev = 'z'; + + switch(adapter->params.rev) { + case T3_REV_A: + rev = 'a'; + break; + case T3_REV_B: + case T3_REV_B2: + rev = 'b'; + break; + case T3_REV_C: + rev = 'c'; + break; + } + return rev; +} + static struct cxgb_ident * cxgb_get_ident(device_t dev) { @@ -298,6 +344,10 @@ cxgb_controller_probe(device_t dev) return (BUS_PROBE_DEFAULT); } +#define FW_FNAME "t3fw%d%d%d" +#define TPEEPROM_NAME "t3%ctpe%d%d%d" +#define TPSRAM_NAME "t3%cps%d%d%d" + static int upgrade_fw(adapter_t *sc) { @@ -309,7 +359,7 @@ upgrade_fw(adapter_t *sc) #endif int status; - snprintf(&buf[0], sizeof(buf), "t3fw%d%d%d", FW_VERSION_MAJOR, + snprintf(&buf[0], sizeof(buf), FW_FNAME, FW_VERSION_MAJOR, FW_VERSION_MINOR, FW_VERSION_MICRO); fw = firmware_get(buf); @@ -317,9 +367,12 @@ upgrade_fw(adapter_t *sc) if (fw == NULL) { device_printf(sc->dev, "Could not find firmware image %s\n", buf); return (ENOENT); - } + } else + device_printf(sc->dev, "updating firmware on card with %s\n", buf); status = t3_load_fw(sc, (const uint8_t *)fw->data, fw->datasize); + device_printf(sc->dev, "firmware update returned %s %d\n", (status == 0) ? "success" : "fail", status); + firmware_put(fw, FIRMWARE_UNLOAD); return (status); @@ -331,14 +384,17 @@ cxgb_controller_attach(device_t dev) device_t child; const struct adapter_info *ai; struct adapter *sc; - int i, reg, msi_needed, error = 0; + int i, reg, error = 0; uint32_t vers; int port_qsets = 1; +#ifdef MSI_SUPPORTED + int msi_needed; +#endif + sc = device_get_softc(dev); sc->dev = dev; sc->msi_count = 0; - msi_needed = 0; /* find the PCIe link width and set max read request to 4KB*/ if (pci_find_extcap(dev, PCIY_EXPRESS, ®) == 0) { @@ -350,7 +406,10 @@ cxgb_controller_attach(device_t dev) pectl = (pectl & ~0x7000) | (5 << 12); pci_write_config(dev, reg + 0x8, pectl, 2); } - if (sc->link_width != 0 && sc->link_width <= 4) { + + ai = cxgb_get_adapter_info(dev); + if (sc->link_width != 0 && sc->link_width <= 4 && + (ai->nports0 + ai->nports1) <= 2) { device_printf(sc->dev, "PCIe x%d Link, expect reduced performance\n", sc->link_width); @@ -363,7 +422,7 @@ cxgb_controller_attach(device_t dev) */ sc->regs_rid = PCIR_BAR(0); if ((sc->regs_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, - (int *)&sc->regs_rid, RF_ACTIVE)) == NULL) { + &sc->regs_rid, RF_ACTIVE)) == NULL) { device_printf(dev, "Cannot allocate BAR\n"); return (ENXIO); } @@ -387,7 +446,6 @@ cxgb_controller_attach(device_t dev) sc->bh = rman_get_bushandle(sc->regs_res); sc->mmio_len = rman_get_size(sc->regs_res); - ai = cxgb_get_adapter_info(dev); if (t3_prep_adapter(sc, ai, 1) < 0) { printf("prep adapter failed\n"); error = ENODEV; @@ -455,12 +513,12 @@ cxgb_controller_attach(device_t dev) device_printf(dev, "failed to allocate controller task queue\n"); goto out; } - + taskqueue_start_threads(&sc->tq, 1, PI_NET, "%s taskq", device_get_nameunit(dev)); TASK_INIT(&sc->ext_intr_task, 0, cxgb_ext_intr_handler, sc); - TASK_INIT(&sc->tick_task, 0, cxgb_tick_handler, sc); + /* Create a periodic callout for checking adapter status */ callout_init(&sc->cxgb_tick_ch, TRUE); @@ -475,6 +533,17 @@ cxgb_controller_attach(device_t dev) } else { sc->flags |= FW_UPTODATE; } + + if (t3_check_tpsram_version(sc) != 0) { + /* + * Warn user that a firmware update will be attempted in init. + */ + device_printf(dev, "SRAM needs to be updated to version %c-%d.%d.%d\n", + t3rev2char(sc), TP_VERSION_MAJOR, TP_VERSION_MINOR, TP_VERSION_MICRO); + sc->flags &= ~TPS_UPTODATE; + } else { + sc->flags |= TPS_UPTODATE; + } if ((sc->flags & USING_MSIX) && !singleq) port_qsets = min((SGE_QSETS/(sc)->params.nports), mp_ncpus); @@ -489,11 +558,11 @@ cxgb_controller_attach(device_t dev) error = EINVAL; goto out; } - sc->portdev[i] = child; sc->port[i].adapter = sc; sc->port[i].nqsets = port_qsets; sc->port[i].first_qset = i*port_qsets; - sc->port[i].port = i; + sc->port[i].port_id = i; + sc->portdev[i] = child; device_set_softc(child, &sc->port[i]); } if ((error = bus_generic_attach(dev)) != 0) @@ -569,12 +638,12 @@ cxgb_free(struct adapter *sc) t3_sge_deinit_sw(sc); if (sc->tq != NULL) { - taskqueue_drain(sc->tq, &sc->tick_task); taskqueue_drain(sc->tq, &sc->ext_intr_task); + taskqueue_drain(sc->tq, &sc->tick_task); taskqueue_free(sc->tq); + } tsleep(&sc, 0, "cxgb unload", hz); - } for (i = 0; i < (sc)->params.nports; ++i) { if (sc->portdev[i] != NULL) @@ -588,8 +657,10 @@ cxgb_free(struct adapter *sc) if (isset(&sc->open_device_map, OFFLOAD_DEVMAP_BIT)) offload_close(&sc->tdev); } -#endif +#endif + t3_free_sge_resources(sc); + free(sc->filters, M_DEVBUF); t3_sge_free(sc); cxgb_offload_exit(); @@ -606,6 +677,111 @@ cxgb_free(struct adapter *sc) return; } +static int +alloc_filters(struct adapter *adap) +{ + struct filter_info *p; + int nfilters; + + if ((nfilters = adap->params.mc5.nfilters) == 0) + return (0); + + adap->filters = malloc(nfilters*sizeof(struct filter_info), + M_DEVBUF, M_ZERO|M_WAITOK); + + if (adap->filters == NULL) + return (ENOMEM); + + /* Set the default filters, only need to set non-0 fields here. */ + p = &adap->filters[nfilters - 1]; + p->vlan = 0xfff; + p->vlan_prio = FILTER_NO_VLAN_PRI; + p->pass = p->rss = p->valid = p->locked = 1; + + return (0); +} + +static inline void +set_tcb_field_ulp(struct cpl_set_tcb_field *req, + unsigned int tid, unsigned int word, + uint64_t mask, uint64_t val) +{ + struct ulp_txpkt *txpkt = (struct ulp_txpkt *)req; + + txpkt->cmd_dest = htonl(V_ULPTX_CMD(ULP_TXPKT)); + txpkt->len = htonl(V_ULPTX_NFLITS(sizeof(*req) / 8)); + OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, tid)); + req->reply = V_NO_REPLY(1); + req->cpu_idx = 0; + req->word = htons(word); + req->mask = htobe64(mask); + req->val = htobe64(val); +} + +static int +set_filter(struct adapter *adap, int id, const struct filter_info *f) +{ + int len; + struct mbuf *m; + struct ulp_txpkt *txpkt; + struct work_request_hdr *wr; + struct cpl_pass_open_req *oreq; + struct cpl_set_tcb_field *sreq; + + len = sizeof(*wr) + sizeof(*oreq) + 2 * sizeof(*sreq); + id += t3_mc5_size(&adap->mc5) - adap->params.mc5.nroutes - + adap->params.mc5.nfilters; + + m = m_gethdr(M_TRYWAIT, MT_DATA); + wr = mtod(m, struct work_request_hdr *); + wr->wr_hi = htonl(V_WR_OP(FW_WROPCODE_BYPASS) | F_WR_ATOMIC); + m->m_len = m->m_pkthdr.len = len; + + oreq = (struct cpl_pass_open_req *)(wr + 1); + txpkt = (struct ulp_txpkt *)oreq; + txpkt->cmd_dest = htonl(V_ULPTX_CMD(ULP_TXPKT)); + txpkt->len = htonl(V_ULPTX_NFLITS(sizeof(*oreq) / 8)); + OPCODE_TID(oreq) = htonl(MK_OPCODE_TID(CPL_PASS_OPEN_REQ, id)); + oreq->local_port = htons(f->dport); + oreq->peer_port = htons(f->sport); + oreq->local_ip = htonl(f->dip); + oreq->peer_ip = htonl(f->sip); + oreq->peer_netmask = htonl(f->sip_mask); + oreq->opt0h = 0; + oreq->opt0l = htonl(F_NO_OFFLOAD); + oreq->opt1 = htonl(V_MAC_MATCH_VALID(f->mac_vld) | + V_CONN_POLICY(CPL_CONN_POLICY_FILTER) | + V_VLAN_PRI(f->vlan_prio >> 1) | + V_VLAN_PRI_VALID(f->vlan_prio != FILTER_NO_VLAN_PRI) | + V_PKT_TYPE(f->pkt_type) | V_OPT1_VLAN(f->vlan) | + V_MAC_MATCH(f->mac_idx | (f->mac_hit << 4))); + + sreq = (struct cpl_set_tcb_field *)(oreq + 1); + set_tcb_field_ulp(sreq, id, 1, 0x1800808000ULL, + (f->report_filter_id << 15) | (1 << 23) | + ((u64)f->pass << 35) | ((u64)!f->rss << 36)); + set_tcb_field_ulp(sreq + 1, id, 25, 0x3f80000, + (u64)adap->rrss_map[f->qset] << 19); + t3_mgmt_tx(adap, m); + return 0; +} + +static int +setup_hw_filters(struct adapter *adap) +{ + int i, err; + + if (adap->filters == NULL) + return 0; + + t3_enable_filters(adap); + + for (i = err = 0; i < adap->params.mc5.nfilters && !err; i++) + if (adap->filters[i].locked) + err = set_filter(adap, i, &adap->filters[i]); + return err; +} + /** * setup_sge_qsets - configure SGE Tx/Rx/response queues * @sc: the controller softc @@ -695,7 +871,7 @@ cxgb_setup_msix(adapter_t *sc, int msix_count) nqsets = sc->port[i].nqsets; for (j = 0; j < nqsets; j++, k++) { struct sge_qset *qs = &sc->sge.qs[k]; - + rid = k + 2; if (cxgb_debug) printf("rid=%d ", rid); @@ -732,7 +908,7 @@ cxgb_port_probe(device_t dev) p = device_get_softc(dev); - snprintf(buf, sizeof(buf), "Port %d %s", p->port, p->port_type->desc); + snprintf(buf, sizeof(buf), "Port %d %s", p->port_id, p->port_type->desc); device_set_desc_copy(dev, buf); return (0); } @@ -743,7 +919,7 @@ cxgb_makedev(struct port_info *pi) { pi->port_cdev = make_dev(&cxgb_cdevsw, pi->ifp->if_dunit, - UID_ROOT, GID_WHEEL, 0600, pi->ifp->if_xname); + UID_ROOT, GID_WHEEL, 0600, if_name(pi->ifp)); if (pi->port_cdev == NULL) return (ENOMEM); @@ -763,6 +939,7 @@ cxgb_makedev(struct port_info *pi) /* Don't enable TSO6 yet */ #define CXGB_CAP_ENABLE (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM | IFCAP_JUMBO_MTU) #define IFCAP_TSO4 0x0 +#define IFCAP_TSO6 0x0 #define CSUM_TSO 0x0 #endif @@ -777,7 +954,7 @@ cxgb_port_attach(device_t dev) p = device_get_softc(dev); snprintf(p->lockbuf, PORT_NAME_LEN, "cxgb port lock %d:%d", - device_get_unit(device_get_parent(dev)), p->port); + device_get_unit(device_get_parent(dev)), p->port_id); PORT_LOCK_INIT(p, p->lockbuf); /* Allocate an ifnet object and set it up */ @@ -807,11 +984,21 @@ cxgb_port_attach(device_t dev) ifp->if_capabilities |= CXGB_CAP; ifp->if_capenable |= CXGB_CAP_ENABLE; ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP | CSUM_IP | CSUM_TSO); - + /* + * disable TSO on 4-port - it isn't supported by the firmware yet + */ + if (p->adapter->params.nports > 2) { + ifp->if_capabilities &= ~(IFCAP_TSO4 | IFCAP_TSO6); + ifp->if_capenable &= ~(IFCAP_TSO4 | IFCAP_TSO6); + ifp->if_hwassist &= ~CSUM_TSO; + } + ether_ifattach(ifp, p->hw_addr); -#ifdef DEFAULT_JUMBO - ifp->if_mtu = 9000; -#endif + /* + * Only default to jumbo frames on 10GigE + */ + if (p->adapter->params.nports <= 2) + ifp->if_mtu = 9000; if ((err = cxgb_makedev(p)) != 0) { printf("makedev failed %d\n", err); return (err); @@ -849,7 +1036,7 @@ cxgb_port_attach(device_t dev) } - snprintf(p->taskqbuf, TASKQ_NAME_LEN, "cxgb_port_taskq%d", p->port); + snprintf(p->taskqbuf, TASKQ_NAME_LEN, "cxgb_port_taskq%d", p->port_id); #ifdef TASKQUEUE_CURRENT /* Create a port for handling TX without starvation */ p->tq = taskqueue_create(p->taskqbuf, M_NOWAIT, @@ -866,6 +1053,7 @@ cxgb_port_attach(device_t dev) } taskqueue_start_threads(&p->tq, 1, PI_NET, "%s taskq", device_get_nameunit(dev)); + TASK_INIT(&p->start_task, 0, cxgb_start_proc, ifp); t3_sge_init_port(p); @@ -1012,7 +1200,6 @@ t3_os_link_changed(adapter_t *adapter, int port_id, int link_status, int speed, } } - /* * Interrupt-context handler for external (PHY) interrupts. */ @@ -1089,23 +1276,30 @@ static void setup_rss(adapter_t *adap) { int i; - u_int nq0 = adap->port[0].nqsets; - u_int nq1 = max((u_int)adap->port[1].nqsets, 1U); + u_int nq[2]; uint8_t cpus[SGE_QSETS + 1]; uint16_t rspq_map[RSS_TABLE_SIZE]; - + + nq[0] = adap->port[0].nqsets; + nq[1] = max((u_int)adap->port[1].nqsets, 1U); + for (i = 0; i < SGE_QSETS; ++i) cpus[i] = i; cpus[SGE_QSETS] = 0xff; for (i = 0; i < RSS_TABLE_SIZE / 2; ++i) { - rspq_map[i] = i % nq0; - rspq_map[i + RSS_TABLE_SIZE / 2] = (i % nq1) + nq0; + rspq_map[i] = nq[0] ? i % nq[0] : 0; + rspq_map[i + RSS_TABLE_SIZE / 2] = nq[1] ? i % nq[1] + nq[0] : 0; } + /* Calculate the reverse RSS map table */ + for (i = 0; i < RSS_TABLE_SIZE; ++i) + if (adap->rrss_map[rspq_map[i]] == 0xff) + adap->rrss_map[rspq_map[i]] = i; t3_config_rss(adap, F_RQFEEDBACKENABLE | F_TNLLKPEN | F_TNLMAPEN | - F_TNLPRTEN | F_TNL2TUPEN | F_TNL4TUPEN | - V_RRCPLCPUSIZE(6), cpus, rspq_map); + F_TNLPRTEN | F_TNL2TUPEN | F_TNL4TUPEN | F_OFDMAPEN | + F_RRCPLMAPEN | V_RRCPLCPUSIZE(6), cpus, rspq_map); + } /* @@ -1175,7 +1369,7 @@ send_pktsched_cmd(struct adapter *adap, int sched, int qidx, int lo, struct mbuf *m; struct mngt_pktsched_wr *req; - m = m_gethdr(M_NOWAIT, MT_DATA); + m = m_gethdr(M_DONTWAIT, MT_DATA); if (m) { req = mtod(m, struct mngt_pktsched_wr *); req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_MNGT)); @@ -1204,6 +1398,101 @@ bind_qsets(adapter_t *sc) } } +static void +update_tpeeprom(struct adapter *adap) +{ + const struct firmware *tpeeprom; + char buf[64]; + uint32_t version; + unsigned int major, minor; + int ret, len; + char rev; + + t3_seeprom_read(adap, TP_SRAM_OFFSET, &version); + + major = G_TP_VERSION_MAJOR(version); + minor = G_TP_VERSION_MINOR(version); + if (major == TP_VERSION_MAJOR && minor == TP_VERSION_MINOR) + return; + + rev = t3rev2char(adap); + + snprintf(buf, sizeof(buf), TPEEPROM_NAME, rev, + TP_VERSION_MAJOR, TP_VERSION_MINOR, TP_VERSION_MICRO); + + tpeeprom = firmware_get(buf); + if (tpeeprom == NULL) { + device_printf(adap->dev, "could not load TP EEPROM: unable to load %s\n", + buf); + return; + } + + len = tpeeprom->datasize - 4; + + ret = t3_check_tpsram(adap, tpeeprom->data, tpeeprom->datasize); + if (ret) + goto release_tpeeprom; + + if (len != TP_SRAM_LEN) { + device_printf(adap->dev, "%s length is wrong len=%d expected=%d\n", buf, len, TP_SRAM_LEN); + return; + } + + ret = set_eeprom(&adap->port[0], tpeeprom->data, tpeeprom->datasize, + TP_SRAM_OFFSET); + + if (!ret) { + device_printf(adap->dev, + "Protocol SRAM image updated in EEPROM to %d.%d.%d\n", + TP_VERSION_MAJOR, TP_VERSION_MINOR, TP_VERSION_MICRO); + } else + device_printf(adap->dev, "Protocol SRAM image update in EEPROM failed\n"); + +release_tpeeprom: + firmware_put(tpeeprom, FIRMWARE_UNLOAD); + + return; +} + +static int +update_tpsram(struct adapter *adap) +{ + const struct firmware *tpsram; + char buf[64]; + int ret; + char rev; + + rev = t3rev2char(adap); + if (!rev) + return 0; + + update_tpeeprom(adap); + + snprintf(buf, sizeof(buf), TPSRAM_NAME, rev, + TP_VERSION_MAJOR, TP_VERSION_MINOR, TP_VERSION_MICRO); + + tpsram = firmware_get(buf); + if (tpsram == NULL){ + device_printf(adap->dev, "could not load TP SRAM: unable to load %s\n", + buf); + return (EINVAL); + } else + device_printf(adap->dev, "updating TP SRAM with %s\n", buf); + + ret = t3_check_tpsram(adap, tpsram->data, tpsram->datasize); + if (ret) + goto release_tpsram; + + ret = t3_set_proto_sram(adap, tpsram->data); + if (ret) + device_printf(adap->dev, "loading protocol SRAM failed\n"); + +release_tpsram: + firmware_put(tpsram, FIRMWARE_UNLOAD); + + return ret; +} + /** * cxgb_up - enable the adapter * @adap: adapter being enabled @@ -1221,11 +1510,11 @@ cxgb_up(struct adapter *sc) if ((sc->flags & FULL_INIT_DONE) == 0) { if ((sc->flags & FW_UPTODATE) == 0) - err = upgrade_fw(sc); - - if (err) - goto out; - + if ((err = upgrade_fw(sc))) + goto out; + if ((sc->flags & TPS_UPTODATE) == 0) + if ((err = update_tpsram(sc))) + goto out; err = t3_init_hw(sc, 0); if (err) goto out; @@ -1236,6 +1525,7 @@ cxgb_up(struct adapter *sc) if (err) goto out; + alloc_filters(sc); setup_rss(sc); sc->flags |= FULL_INIT_DONE; } @@ -1252,12 +1542,13 @@ cxgb_up(struct adapter *sc) } device_printf(sc->dev, "allocated irq_res=%p\n", sc->irq_res); - if ((err = bus_setup_intr(sc->dev, sc->irq_res, INTR_MPSAFE|INTR_TYPE_NET, + 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 %d\n", err); + sc->cxgb_intr, sc, &sc->intr_tag)) { + device_printf(sc->dev, "Cannot set up interrupt\n"); + err = EINVAL; goto irq_err; } } else { @@ -1267,9 +1558,11 @@ cxgb_up(struct adapter *sc) t3_sge_start(sc); t3_intr_enable(sc); - if ((sc->flags & (USING_MSIX | QUEUES_BOUND)) == USING_MSIX) + if ((sc->flags & (USING_MSIX | QUEUES_BOUND)) == USING_MSIX) { bind_qsets(sc); - sc->flags |= QUEUES_BOUND; + setup_hw_filters(sc); + sc->flags |= QUEUES_BOUND; + } out: return (err); irq_err: @@ -1333,7 +1626,7 @@ offload_open(struct port_info *pi) if (!adap_up) err = cxgb_up(adapter); ADAPTER_UNLOCK(pi->adapter); - if (err < 0) + if (err) return (err); t3_tp_set_offload_mode(adapter, 1); @@ -1361,7 +1654,6 @@ out: } return (err); } - #ifdef notyet static int offload_close(struct toedev *tdev) @@ -1407,7 +1699,7 @@ cxgb_init_locked(struct port_info *p) ifp = p->ifp; ADAPTER_LOCK(p->adapter); - if ((sc->open_device_map == 0) && ((err = cxgb_up(sc)) < 0)) { + if ((sc->open_device_map == 0) && (err = cxgb_up(sc))) { ADAPTER_UNLOCK(p->adapter); cxgb_stop_locked(p); return; @@ -1416,7 +1708,7 @@ cxgb_init_locked(struct port_info *p) t3_intr_clear(sc); t3_sge_init_adapter(sc); } - setbit(&p->adapter->open_device_map, p->port); + setbit(&p->adapter->open_device_map, p->port_id); ADAPTER_UNLOCK(p->adapter); if (is_offload(sc) && !ofld_disable) { @@ -1426,18 +1718,16 @@ cxgb_init_locked(struct port_info *p) "Could not initialize offload capabilities\n"); } cxgb_link_start(p); - t3_link_changed(sc, p->port); + t3_link_changed(sc, p->port_id); ifp->if_baudrate = p->link_config.speed * 1000000; - t3_port_intr_enable(sc, p->port); + t3_port_intr_enable(sc, p->port_id); 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 @@ -1462,13 +1752,13 @@ cxgb_stop_locked(struct port_info *p) ifp = p->ifp; - t3_port_intr_disable(p->adapter, p->port); + t3_port_intr_disable(p->adapter, p->port_id); ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 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); + clrbit(&p->adapter->open_device_map, p->port_id); if (p->adapter->open_device_map == 0) { @@ -1615,7 +1905,11 @@ cxgb_start_tx(struct ifnet *ifp, uint32_t txmax) txq = &qs->txq[TXQ_ETH]; err = 0; + if (txq->flags & TXQ_TRANSMITTING) + return (EINPROGRESS); + mtx_lock(&txq->lock); + txq->flags |= TXQ_TRANSMITTING; in_use_init = txq->in_use; while ((txq->in_use - in_use_init < txmax) && (txq->size > txq->in_use + TX_MAX_DESC)) { @@ -1637,7 +1931,7 @@ cxgb_start_tx(struct ifnet *ifp, uint32_t txmax) m0->m_flags &= ~M_PKTHDR; m0 = m0->m_next; } - M_SANITY(m0, 0); + m_sanity(m0, 0); m0 = m; #endif if (collapse_mbufs && m->m_pkthdr.len > MCLBYTES && @@ -1646,13 +1940,14 @@ cxgb_start_tx(struct ifnet *ifp, uint32_t txmax) m = m0; m_collapse(m, TX_MAX_SEGS, &m0); } else - break; + break; } m = m0; if ((err = t3_encap(p, &m)) != 0) break; BPF_MTAP(ifp, m); } + txq->flags &= ~TXQ_TRANSMITTING; mtx_unlock(&txq->lock); if (__predict_false(err)) { @@ -1686,9 +1981,8 @@ cxgb_start_proc(void *arg, int ncount) txq = &qs->txq[TXQ_ETH]; do { - if (desc_reclaimable(txq) > TX_CLEAN_MAX_DESC) - taskqueue_enqueue(pi->adapter->tq, - &pi->timer_reclaim_task); + if (desc_reclaimable(txq) > TX_CLEAN_MAX_DESC >> 2) + taskqueue_enqueue(pi->tq, &txq->qreclaim_task); error = cxgb_start_tx(ifp, TX_START_MAX_DESC); } while (error == 0); @@ -1705,9 +1999,9 @@ cxgb_start(struct ifnet *ifp) qs = &pi->adapter->sge.qs[pi->first_qset]; txq = &qs->txq[TXQ_ETH]; - if (desc_reclaimable(txq) > TX_CLEAN_MAX_DESC) - taskqueue_enqueue(pi->adapter->tq, - &pi->timer_reclaim_task); + if (desc_reclaimable(txq) > TX_CLEAN_MAX_DESC >> 2) + taskqueue_enqueue(pi->tq, + &txq->qreclaim_task); err = cxgb_start_tx(ifp, TX_START_MAX_DESC); @@ -1829,7 +2123,7 @@ check_t3b2_mac(struct adapter *adapter) cxgb_set_rxmode(p); t3_link_start(&p->phy, mac, &p->link_config); t3_mac_enable(mac, MAC_DIRECTION_RX | MAC_DIRECTION_TX); - t3_port_intr_enable(adapter, p->port); + t3_port_intr_enable(adapter, p->port_id); p->mac.stats.num_resets++; } PORT_UNLOCK(p); @@ -1854,8 +2148,8 @@ cxgb_tick_handler(void *arg, int count) adapter_t *sc = (adapter_t *)arg; const struct adapter_params *p = &sc->params; - if (p->linkpoll_period) ADAPTER_LOCK(sc); + if (p->linkpoll_period) check_link_status(sc); /* @@ -1864,10 +2158,170 @@ cxgb_tick_handler(void *arg, int count) */ ADAPTER_UNLOCK(sc); - if (p->rev == T3_REV_B2) + if (p->rev == T3_REV_B2 && p->nports < 4) check_t3b2_mac(sc); } +#if 0 +static void * +filter_get_idx(struct seq_file *seq, loff_t pos) +{ + int i; + struct adapter *adap = seq->private; + struct filter_info *p = adap->filters; + + if (!p) + return NULL; + + for (i = 0; i < adap->params.mc5.nfilters; i++, p++) + if (p->valid) { + if (!pos) + return p; + pos--; + } + return NULL; +} + +static void *filter_get_nxt_idx(struct seq_file *seq, struct filter_info *p) +{ + struct adapter *adap = seq->private; + struct filter_info *end = &adap->filters[adap->params.mc5.nfilters]; + + while (++p < end && !p->valid) + ; + return p < end ? p : NULL; +} + +static void *filter_seq_start(struct seq_file *seq, loff_t *pos) +{ + return *pos ? filter_get_idx(seq, *pos - 1) : SEQ_START_TOKEN; +} + +static void *filter_seq_next(struct seq_file *seq, void *v, loff_t *pos) +{ + v = *pos ? filter_get_nxt_idx(seq, v) : filter_get_idx(seq, 0); + if (v) + ++*pos; + return v; +} + +static void filter_seq_stop(struct seq_file *seq, void *v) +{ +} + +static int filter_seq_show(struct seq_file *seq, void *v) +{ + static const char *pkt_type[] = { "any", "tcp", "udp", "frag" }; + + if (v == SEQ_START_TOKEN) + seq_puts(seq, "index SIP DIP sport " + "dport VLAN PRI MAC type Q\n"); + else { + char sip[20], dip[20]; + struct filter_info *f = v; + struct adapter *adap = seq->private; + + sprintf(sip, NIPQUAD_FMT "/%-2u", HIPQUAD(f->sip), + f->sip_mask ? 33 - ffs(f->sip_mask) : 0); + sprintf(dip, NIPQUAD_FMT, HIPQUAD(f->dip)); + seq_printf(seq, "%5zu %18s %15s ", f - adap->filters, sip, dip); + seq_printf(seq, f->sport ? "%5u " : " * ", f->sport); + seq_printf(seq, f->dport ? "%5u " : " * ", f->dport); + seq_printf(seq, f->vlan != 0xfff ? "%4u " : " * ", f->vlan); + seq_printf(seq, f->vlan_prio == FILTER_NO_VLAN_PRI ? + " * " : "%1u/%1u ", f->vlan_prio, f->vlan_prio | 1); + if (!f->mac_vld) + seq_printf(seq, " * "); + else if (f->mac_hit) + seq_printf(seq, "%3u ", f->mac_idx); + else + seq_printf(seq, " -1 "); + seq_printf(seq, "%4s ", pkt_type[f->pkt_type]); + if (!f->pass) + seq_printf(seq, "-\n"); + else if (f->rss) + seq_printf(seq, "*\n"); + else + seq_printf(seq, "%1u\n", f->qset); + } + return 0; +} + +static struct seq_operations filter_seq_ops = { + .start = filter_seq_start, + .next = filter_seq_next, + .stop = filter_seq_stop, + .show = filter_seq_show +}; + +static int filter_seq_open(struct inode *inode, struct file *file) +{ + int rc = seq_open(file, &filter_seq_ops); + + if (!rc) { + struct proc_dir_entry *dp = PDE(inode); + struct seq_file *seq = file->private_data; + + seq->private = dp->data; + } + return rc; +} + +static struct file_operations filter_seq_fops = { + .owner = THIS_MODULE, + .open = filter_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release +}; + +#endif + +static int +set_eeprom(struct port_info *pi, const uint8_t *data, int len, int offset) +{ + uint8_t *buf; + int err = 0; + u32 aligned_offset, aligned_len, *p; + struct adapter *adapter = pi->adapter; + + + aligned_offset = offset & ~3; + aligned_len = (len + (offset & 3) + 3) & ~3; + + if (aligned_offset != offset || aligned_len != len) { + buf = malloc(aligned_len, M_DEVBUF, M_WAITOK|M_ZERO); + if (!buf) + return (ENOMEM); + err = t3_seeprom_read(adapter, aligned_offset, (u32 *)buf); + if (!err && aligned_len > 4) + err = t3_seeprom_read(adapter, + aligned_offset + aligned_len - 4, + (u32 *)&buf[aligned_len - 4]); + if (err) + goto out; + memcpy(buf + (offset & 3), data, len); + } else + buf = (uint8_t *)(uintptr_t)data; + + err = t3_seeprom_wp(adapter, 0); + if (err) + goto out; + + for (p = (u32 *)buf; !err && aligned_len; aligned_len -= 4, p++) { + err = t3_seeprom_write(adapter, aligned_offset, *p); + aligned_offset += 4; + } + + if (!err) + err = t3_seeprom_wp(adapter, 1); +out: + if (buf != data) + free(buf, M_DEVBUF); + return err; +} + + static int in_range(int val, int lo, int hi) { @@ -1921,7 +2375,7 @@ cxgb_extension_ioctl(struct cdev *dev, unsigned long cmd, caddr_t data, if (!mmd) mmd = MDIO_DEV_PCS; else if (mmd > MDIO_DEV_XGXS) - return -EINVAL; + return (EINVAL); error = phy->mdio_read(sc, mid->phy_id & 0x1f, mmd, mid->reg_num, &val); @@ -2011,7 +2465,7 @@ cxgb_extension_ioctl(struct cdev *dev, unsigned long cmd, caddr_t data, struct ch_qset_params *t = (struct ch_qset_params *)data; if (t->qset_idx >= SGE_QSETS) - return -EINVAL; + return (EINVAL); if (!in_range(t->intr_lat, 0, M_NEWTIMER) || !in_range(t->cong_thres, 0, 255) || !in_range(t->txq_size[0], MIN_TXQ_ENTRIES, @@ -2024,13 +2478,13 @@ cxgb_extension_ioctl(struct cdev *dev, unsigned long cmd, caddr_t data, !in_range(t->fl_size[1], MIN_FL_ENTRIES, MAX_RX_JUMBO_BUFFERS) || !in_range(t->rspq_size, MIN_RSPQ_ENTRIES, MAX_RSPQ_ENTRIES)) - return -EINVAL; + return (EINVAL); if ((sc->flags & FULL_INIT_DONE) && (t->rspq_size >= 0 || t->fl_size[0] >= 0 || t->fl_size[1] >= 0 || t->txq_size[0] >= 0 || t->txq_size[1] >= 0 || t->txq_size[2] >= 0 || t->polling >= 0 || t->cong_thres >= 0)) - return -EBUSY; + return (EBUSY); q = &sc->params.sge.qset[t->qset_idx]; @@ -2077,7 +2531,7 @@ cxgb_extension_ioctl(struct cdev *dev, unsigned long cmd, caddr_t data, } case CHELSIO_SET_QSET_NUM: { struct ch_reg *edata = (struct ch_reg *)data; - unsigned int port_idx = pi->port; + unsigned int port_idx = pi->port_id; if (sc->flags & FULL_INIT_DONE) return (EBUSY); @@ -2139,6 +2593,79 @@ cxgb_extension_ioctl(struct cdev *dev, unsigned long cmd, caddr_t data, memcpy(m->mtus, sc->params.mtus, sizeof(m->mtus)); m->nmtus = NMTUS; break; + } + case CHELSIO_SET_FILTER: { + struct ch_filter *f = (struct ch_filter *)data; + struct filter_info *p; + int ret; + + if (sc->params.mc5.nfilters == 0) + return (EOPNOTSUPP); + if (!(sc->flags & FULL_INIT_DONE)) + return (EAGAIN); /* can still change nfilters */ + if (sc->filters == NULL) + return (ENOMEM); + + if (f->filter_id >= sc->params.mc5.nfilters || + (f->val.dip && f->mask.dip != 0xffffffff) || + (f->val.sport && f->mask.sport != 0xffff) || + (f->val.dport && f->mask.dport != 0xffff) || + (f->mask.vlan && f->mask.vlan != 0xfff) || + (f->mask.vlan_prio && f->mask.vlan_prio != 7) || + (f->mac_addr_idx != 0xffff && f->mac_addr_idx > 15) || + f->qset >= SGE_QSETS || + sc->rrss_map[f->qset] >= RSS_TABLE_SIZE) + return (EINVAL); + + p = &sc->filters[f->filter_id]; + if (p->locked) + return (EPERM); + + p->sip = f->val.sip; + p->sip_mask = f->mask.sip; + p->dip = f->val.dip; + p->sport = f->val.sport; + p->dport = f->val.dport; + p->vlan = f->mask.vlan ? f->val.vlan : 0xfff; + p->vlan_prio = f->mask.vlan_prio ? (f->val.vlan_prio & 6) : + FILTER_NO_VLAN_PRI; + p->mac_hit = f->mac_hit; + p->mac_vld = f->mac_addr_idx != 0xffff; + p->mac_idx = f->mac_addr_idx; + p->pkt_type = f->proto; + p->report_filter_id = f->want_filter_id; + p->pass = f->pass; + p->rss = f->rss; + p->qset = f->qset; + + ret = set_filter(sc, f->filter_id, p); + if (ret) + return ret; + p->valid = 1; + break; + } + case CHELSIO_DEL_FILTER: { + struct ch_filter *f = (struct ch_filter *)data; + struct filter_info *p; + + if (sc->params.mc5.nfilters == 0) + return (EOPNOTSUPP); + if (!(sc->flags & FULL_INIT_DONE)) + return (EAGAIN); /* can still change nfilters */ + if (sc->filters == NULL) + return (ENOMEM); + if (f->filter_id >= sc->params.mc5.nfilters) + return (EINVAL); + + p = &sc->filters[f->filter_id]; + if (p->locked) + return (EPERM); + memset(p, 0, sizeof(*p)); + p->sip_mask = 0xffffffff; + p->vlan = 0xfff; + p->vlan_prio = FILTER_NO_VLAN_PRI; + p->pkt_type = 1; + return set_filter(sc, f->filter_id, p); } case CHELSIO_DEVUP: if (!is_offload(sc)) @@ -2197,6 +2724,8 @@ cxgb_extension_ioctl(struct cdev *dev, unsigned long cmd, caddr_t data, if (!is_offload(sc)) return (EOPNOTSUPP); + if (!(sc->flags & FULL_INIT_DONE)) + return (EIO); /* need MC5 */ return -t3_read_mc5_range(&sc->mc5, t->addr, 1, t->buf); break; } @@ -2264,7 +2793,7 @@ cxgb_extension_ioctl(struct cdev *dev, unsigned long cmd, caddr_t data, 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, (uint32_t *)&t->flow_ipg, t->sched, 1); + 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); diff --git a/sys/dev/cxgb/cxgb_offload.c b/sys/dev/cxgb/cxgb_offload.c index 0559c134089e..991fb7e96a65 100644 --- a/sys/dev/cxgb/cxgb_offload.c +++ b/sys/dev/cxgb/cxgb_offload.c @@ -1,3 +1,4 @@ + /************************************************************************** Copyright (c) 2007, Chelsio Inc. @@ -271,7 +272,7 @@ cxgb_ulp_iscsi_ctl(adapter_t *adapter, unsigned int req, void *data) t3_write_reg(adapter, A_ULPRX_ISCSI_TAGMASK, uiip->tagmask); break; default: - ret = -EOPNOTSUPP; + ret = (EOPNOTSUPP); } return ret; } @@ -314,7 +315,7 @@ cxgb_rdma_ctl(adapter_t *adapter, unsigned int req, void *data) struct mc7 *mem; if ((t->addr & 7) || (t->len & 7)) - return -EINVAL; + return (EINVAL); if (t->mem_id == MEM_CM) mem = &adapter->cm; else if (t->mem_id == MEM_PMRX) @@ -322,11 +323,11 @@ cxgb_rdma_ctl(adapter_t *adapter, unsigned int req, void *data) else if (t->mem_id == MEM_PMTX) mem = &adapter->pmtx; else - return -EINVAL; + return (EINVAL); ret = t3_mc7_bd_read(mem, t->addr/8, t->len/8, (u64 *)t->buf); if (ret) - return ret; + return (ret); break; } case RDMA_CQ_SETUP: { @@ -357,9 +358,9 @@ cxgb_rdma_ctl(adapter_t *adapter, unsigned int req, void *data) break; } default: - ret = -EOPNOTSUPP; + ret = EOPNOTSUPP; } - return ret; + return (ret); } static int @@ -438,7 +439,7 @@ cxgb_offload_ctl(struct toedev *tdev, unsigned int req, void *data) case ULP_ISCSI_GET_PARAMS: case ULP_ISCSI_SET_PARAMS: if (!offload_running(adapter)) - return -EAGAIN; + return (EAGAIN); return cxgb_ulp_iscsi_ctl(adapter, req, data); case RDMA_GET_PARAMS: case RDMA_CQ_OP: @@ -447,10 +448,10 @@ cxgb_offload_ctl(struct toedev *tdev, unsigned int req, void *data) case RDMA_CTRL_QP_SETUP: case RDMA_GET_MEM: if (!offload_running(adapter)) - return -EAGAIN; + return (EAGAIN); return cxgb_rdma_ctl(adapter, req, data); default: - return -EOPNOTSUPP; + return (EOPNOTSUPP); } return 0; } @@ -463,8 +464,8 @@ cxgb_offload_ctl(struct toedev *tdev, unsigned int req, void *data) static int rx_offload_blackhole(struct toedev *dev, struct mbuf **m, int n) { - CH_ERR(tdev2adap(dev), "%d unexpected offload packets, first data %u\n", - n, ntohl(*mtod(m[0], uint32_t *))); + CH_ERR(tdev2adap(dev), "%d unexpected offload packets, first data 0x%x\n", + n, *mtod(m[0], uint32_t *)); while (n--) m_freem(m[n]); return 0; @@ -525,7 +526,7 @@ cxgb_insert_tid(struct toedev *tdev, struct cxgb_client *client, t->tid_tab[tid].client = client; t->tid_tab[tid].ctx = ctx; - atomic_add_int((volatile unsigned int *)&t->tids_in_use, 1); + atomic_add_int(&t->tids_in_use, 1); } /* @@ -595,7 +596,7 @@ cxgb_remove_tid(struct toedev *tdev, void *ctx, unsigned int tid) BUG_ON(tid >= t->ntids); if (tdev->type == T3A) - atomic_cmpset_ptr((void *)&t->tid_tab[tid].ctx, (long)NULL, (long)ctx); + atomic_cmpset_ptr((uintptr_t *)&t->tid_tab[tid].ctx, (long)NULL, (long)ctx); else { struct mbuf *m; @@ -607,7 +608,7 @@ cxgb_remove_tid(struct toedev *tdev, void *ctx, unsigned int tid) } else cxgb_queue_tid_release(tdev, tid); } - atomic_add_int((volatile unsigned int *)&t->tids_in_use, -1); + atomic_add_int(&t->tids_in_use, -1); } int @@ -1249,7 +1250,7 @@ cxgb_redirect(struct rtentry *old, struct rtentry *new) } /* Add new L2T entry */ - e = t3_l2t_get(tdev, new, ((struct port_info *)new->rt_ifp->if_softc)->port); + e = t3_l2t_get(tdev, new, ((struct port_info *)new->rt_ifp->if_softc)->port_id); if (!e) { log(LOG_ERR, "%s: couldn't allocate new l2t entry!\n", __FUNCTION__); @@ -1307,7 +1308,7 @@ init_tid_tabs(struct tid_info *t, unsigned int ntids, t->tid_tab = cxgb_alloc_mem(size); if (!t->tid_tab) - return -ENOMEM; + return (ENOMEM); t->stid_tab = (union listen_entry *)&t->tid_tab[ntids]; t->atid_tab = (union active_open_entry *)&t->stid_tab[nstids]; @@ -1319,7 +1320,7 @@ init_tid_tabs(struct tid_info *t, unsigned int ntids, t->atid_base = atid_base; t->afree = NULL; t->stids_in_use = t->atids_in_use = 0; - atomic_set_int((volatile unsigned int *)&t->tids_in_use, 0); + atomic_set_int(&t->tids_in_use, 0); mtx_init(&t->stid_lock, "stid", NULL, MTX_DEF); mtx_init(&t->atid_lock, "atid", NULL, MTX_DEF); @@ -1597,11 +1598,11 @@ offload_info_proc_setup(struct proc_dir_entry *dir, struct proc_dir_entry *p; if (!dir) - return -EINVAL; + return (EINVAL); p = create_proc_read_entry("info", 0, dir, offload_info_read_proc, d); if (!p) - return -ENOMEM; + return (ENOMEM); p->owner = THIS_MODULE; return 0; diff --git a/sys/dev/cxgb/cxgb_offload.h b/sys/dev/cxgb/cxgb_offload.h index 10b4aab11b16..62ecfa8183ce 100644 --- a/sys/dev/cxgb/cxgb_offload.h +++ b/sys/dev/cxgb/cxgb_offload.h @@ -10,11 +10,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. @@ -37,11 +33,12 @@ $FreeBSD$ #ifndef _CXGB_OFFLOAD_H #define _CXGB_OFFLOAD_H -#ifdef CONFIG_DEFINED -#include <cxgb_include.h> -#else -#include <dev/cxgb/cxgb_include.h> -#endif + +#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; @@ -152,7 +149,7 @@ union active_open_entry { struct tid_info { struct toe_tid_entry *tid_tab; unsigned int ntids; - volatile int tids_in_use; + volatile unsigned int tids_in_use; union listen_entry *stid_tab; unsigned int nstids; diff --git a/sys/dev/cxgb/cxgb_osdep.h b/sys/dev/cxgb/cxgb_osdep.h index d5ebf960d830..ccef5c5c5456 100644 --- a/sys/dev/cxgb/cxgb_osdep.h +++ b/sys/dev/cxgb/cxgb_osdep.h @@ -165,8 +165,12 @@ static const int debug_flags = DBG_RX; #define max_t(type, a, b) (type)max((a), (b)) #define net_device ifnet +#define cpu_to_be32 htobe32 +#ifndef if_name +#define if_name(ifp) (ifp)->if_xname +#endif /* Standard PHY definitions */ #define BMCR_LOOPBACK BMCR_LOOP diff --git a/sys/dev/cxgb/cxgb_sge.c b/sys/dev/cxgb/cxgb_sge.c index b84147e58900..de4a3bedf823 100644 --- a/sys/dev/cxgb/cxgb_sge.c +++ b/sys/dev/cxgb/cxgb_sge.c @@ -66,9 +66,10 @@ __FBSDID("$FreeBSD$"); uint32_t collapse_free = 0; uint32_t mb_free_vec_free = 0; +int txq_fills = 0; int collapse_mbufs = 0; static int recycle_enable = 1; - +static int bogus_imm = 0; /* * XXX GC @@ -186,7 +187,8 @@ int cxgb_debug = 0; static void t3_free_qset(adapter_t *sc, struct sge_qset *q); static void sge_timer_cb(void *arg); static void sge_timer_reclaim(void *arg, int ncount); -static int free_tx_desc(adapter_t *sc, struct sge_txq *q, int n, struct mbuf **m_vec); +static void sge_txq_reclaim_handler(void *arg, int ncount); +static int free_tx_desc(struct sge_txq *q, int n, struct mbuf **m_vec); /** * reclaim_completed_tx - reclaims completed Tx descriptors @@ -198,14 +200,14 @@ static int free_tx_desc(adapter_t *sc, struct sge_txq *q, int n, struct mbuf **m * queue's lock held. */ static __inline int -reclaim_completed_tx(adapter_t *adapter, struct sge_txq *q, int nbufs, struct mbuf **mvec) +reclaim_completed_tx(struct sge_txq *q, int nbufs, struct mbuf **mvec) { int reclaimed, reclaim = desc_reclaimable(q); int n = 0; mtx_assert(&q->lock, MA_OWNED); if (reclaim > 0) { - n = free_tx_desc(adapter, q, min(reclaim, nbufs), mvec); + n = free_tx_desc(q, min(reclaim, nbufs), mvec); reclaimed = min(reclaim, nbufs); q->cleaned += reclaimed; q->in_use -= reclaimed; @@ -290,20 +292,23 @@ sgl_len(unsigned int n) * * Return a packet containing the immediate data of the given response. */ -static __inline void -get_imm_packet(adapter_t *sc, const struct rsp_desc *resp, struct mbuf *m, void *cl) +static int +get_imm_packet(adapter_t *sc, const struct rsp_desc *resp, struct mbuf *m, void *cl, uint32_t flags) { - int len; - uint32_t flags = ntohl(resp->flags); + int len, error; uint8_t sopeop = G_RSPD_SOP_EOP(flags); - + /* * would be a firmware bug */ - if (sopeop == RSPQ_NSOP_NEOP || sopeop == RSPQ_SOP) - return; - len = G_RSPD_LEN(ntohl(resp->len_cq)); + if (sopeop == RSPQ_NSOP_NEOP || sopeop == RSPQ_SOP) { + if (cxgb_debug) + device_printf(sc->dev, "unexpected value sopeop=%d flags=0x%x len=%din get_imm_packet\n", sopeop, flags, len); + bogus_imm++; + return (EINVAL); + } + error = 0; switch (sopeop) { case RSPQ_SOP_EOP: m->m_len = m->m_pkthdr.len = len; @@ -313,7 +318,12 @@ get_imm_packet(adapter_t *sc, const struct rsp_desc *resp, struct mbuf *m, void memcpy(cl, resp->imm_data, len); m_iovappend(m, cl, MSIZE, len, 0); break; + default: + bogus_imm++; + error = EINVAL; } + + return (error); } @@ -360,8 +370,11 @@ t3_sge_prep(adapter_t *adap, struct sge_params *p) q->polling = adap->params.rev > 0; - q->coalesce_nsecs = 5000; - + if (adap->params.nports > 2) + q->coalesce_nsecs = 50000; + else + q->coalesce_nsecs = 5000; + q->rspq_size = RSPQ_Q_SIZE; q->fl_size = FL_Q_SIZE; q->jumbo_size = JUMBO_Q_SIZE; @@ -662,6 +675,35 @@ sge_slow_intr_handler(void *arg, int ncount) t3_slow_intr_handler(sc); } +/** + * sge_timer_cb - perform periodic maintenance of an SGE qset + * @data: the SGE queue set to maintain + * + * Runs periodically from a timer to perform maintenance of an SGE queue + * set. It performs two tasks: + * + * a) Cleans up any completed Tx descriptors that may still be pending. + * Normal descriptor cleanup happens when new packets are added to a Tx + * queue so this timer is relatively infrequent and does any cleanup only + * if the Tx queue has not seen any new packets in a while. We make a + * best effort attempt to reclaim descriptors, in that we don't wait + * around if we cannot get a queue's lock (which most likely is because + * someone else is queueing new packets and so will also handle the clean + * up). Since control queues use immediate data exclusively we don't + * bother cleaning them up here. + * + * b) Replenishes Rx queues that have run out due to memory shortage. + * Normally new Rx buffers are added when existing ones are consumed but + * when out of memory a queue can become empty. We try to add only a few + * buffers here, the queue will be replenished fully as these new buffers + * are used up if memory shortage has subsided. + * + * c) Return coalesced response queue credits in case a response queue is + * starved. + * + * d) Ring doorbells for T304 tunnel queues since we have seen doorbell + * fifo overflows and the FW doesn't implement any recovery scheme yet. + */ static void sge_timer_cb(void *arg) { @@ -686,6 +728,17 @@ sge_timer_cb(void *arg) break; } } + if (sc->params.nports > 2) { + int i; + + for_each_port(sc, i) { + struct port_info *pi = &sc->port[i]; + + t3_write_reg(sc, A_SG_KDOORBELL, + F_SELEGRCNTX | + (FW_TUNNEL_SGEEC_START + pi->first_qset)); + } + } if (sc->open_device_map != 0) callout_reset(&sc->sge_timer_ch, TX_RECLAIM_PERIOD, sge_timer_cb, sc); } @@ -708,7 +761,6 @@ int t3_sge_init_port(struct port_info *p) { TASK_INIT(&p->timer_reclaim_task, 0, sge_timer_reclaim, p); - return (0); } @@ -743,6 +795,45 @@ refill_rspq(adapter_t *sc, const struct sge_rspq *q, u_int credits) V_RSPQ(q->cntxt_id) | V_CREDITS(credits)); } +static __inline void +sge_txq_reclaim_(struct sge_txq *txq) +{ + int reclaimable, i, n; + struct mbuf *m_vec[TX_CLEAN_MAX_DESC]; + struct port_info *p; + + p = txq->port; +reclaim_more: + n = 0; + reclaimable = desc_reclaimable(txq); + if (reclaimable > 0 && mtx_trylock(&txq->lock)) { + n = reclaim_completed_tx(txq, TX_CLEAN_MAX_DESC, m_vec); + mtx_unlock(&txq->lock); + } + if (n == 0) + return; + + for (i = 0; i < n; i++) { + m_freem_vec(m_vec[i]); + } + if (p && p->ifp->if_drv_flags & IFF_DRV_OACTIVE && + txq->size - txq->in_use >= TX_START_MAX_DESC) { + txq_fills++; + p->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + taskqueue_enqueue(p->tq, &p->start_task); + } + + if (n) + goto reclaim_more; +} + +static void +sge_txq_reclaim_handler(void *arg, int ncount) +{ + struct sge_txq *q = arg; + + sge_txq_reclaim_(q); +} static void sge_timer_reclaim(void *arg, int ncount) @@ -753,39 +844,15 @@ sge_timer_reclaim(void *arg, int ncount) struct sge_qset *qs; struct sge_txq *txq; struct mtx *lock; - struct mbuf *m_vec[TX_CLEAN_MAX_DESC]; - int n, reclaimable; for (i = 0; i < nqsets; i++) { qs = &sc->sge.qs[i]; txq = &qs->txq[TXQ_ETH]; - reclaimable = desc_reclaimable(txq); - if (reclaimable > 0) { - mtx_lock(&txq->lock); - n = reclaim_completed_tx(sc, txq, TX_CLEAN_MAX_DESC, m_vec); - mtx_unlock(&txq->lock); - - for (i = 0; i < n; i++) - m_freem_vec(m_vec[i]); - - if (p->ifp->if_drv_flags & IFF_DRV_OACTIVE && - txq->size - txq->in_use >= TX_START_MAX_DESC) { - p->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; - taskqueue_enqueue(p->tq, &p->start_task); - } - } + sge_txq_reclaim_(txq); txq = &qs->txq[TXQ_OFLD]; - reclaimable = desc_reclaimable(txq); - if (reclaimable > 0) { - mtx_lock(&txq->lock); - n = reclaim_completed_tx(sc, txq, TX_CLEAN_MAX_DESC, m_vec); - mtx_unlock(&txq->lock); - - for (i = 0; i < n; i++) - m_freem_vec(m_vec[i]); - } - + sge_txq_reclaim_(txq); + lock = (sc->flags & USING_MSIX) ? &qs->rspq.lock : &sc->sge.qs[0].rspq.lock; @@ -904,7 +971,7 @@ busdma_map_mbufs(struct mbuf **m, struct sge_txq *txq, #endif if (err == EFBIG) { /* Too many segments, try to defrag */ - m0 = m_defrag(m0, M_NOWAIT); + m0 = m_defrag(m0, M_DONTWAIT); if (m0 == NULL) { m_freem(*m); *m = NULL; @@ -1102,7 +1169,7 @@ t3_encap(struct port_info *p, struct mbuf **m) struct tx_sw_desc *stx; struct txq_state txqs; unsigned int ndesc, flits, cntrl, mlen; - int nsegs, err, tso_info = 0; + int err, nsegs, tso_info = 0; struct work_request_hdr *wrp; struct tx_sw_desc *txsd; @@ -1129,7 +1196,7 @@ t3_encap(struct port_info *p, struct mbuf **m) * XXX handle checksum, TSO, and VLAN here * */ - cntrl = V_TXPKT_INTF(p->port); + cntrl = V_TXPKT_INTF(p->port_id); /* * XXX need to add VLAN support for 6.x @@ -1145,7 +1212,7 @@ t3_encap(struct port_info *p, struct mbuf **m) struct cpl_tx_pkt_lso *hdr = (struct cpl_tx_pkt_lso *) cpl; struct ip *ip; struct tcphdr *tcp; - uint8_t *pkthdr, tmp[TCPPKTHDRSIZE]; /* is this too large for the stack? */ + char *pkthdr, tmp[TCPPKTHDRSIZE]; /* is this too large for the stack? */ txd->flit[2] = 0; cntrl |= V_TXPKT_OPCODE(CPL_TX_PKT_LSO); @@ -1153,9 +1220,9 @@ t3_encap(struct port_info *p, struct mbuf **m) if (__predict_false(m0->m_len < TCPPKTHDRSIZE)) { pkthdr = &tmp[0]; - m_copydata(m0, 0, TCPPKTHDRSIZE, (caddr_t)pkthdr); + m_copydata(m0, 0, TCPPKTHDRSIZE, pkthdr); } else { - pkthdr = mtod(m0, uint8_t *); + pkthdr = mtod(m0, char *); } if (__predict_false(m0->m_flags & M_VLANTAG)) { @@ -1562,8 +1629,8 @@ t3_sge_stop(adapter_t *sc) for (i = 0; i < nqsets; ++i) { struct sge_qset *qs = &sc->sge.qs[i]; - taskqueue_drain(sc->tq, &qs->txq[TXQ_OFLD].qresume_tsk); - taskqueue_drain(sc->tq, &qs->txq[TXQ_CTRL].qresume_tsk); + taskqueue_drain(sc->tq, &qs->txq[TXQ_OFLD].qresume_task); + taskqueue_drain(sc->tq, &qs->txq[TXQ_CTRL].qresume_task); } } @@ -1578,7 +1645,7 @@ t3_sge_stop(adapter_t *sc) * Tx buffers. Called with the Tx queue lock held. */ int -free_tx_desc(adapter_t *sc, struct sge_txq *q, int n, struct mbuf **m_vec) +free_tx_desc(struct sge_txq *q, int n, struct mbuf **m_vec) { struct tx_sw_desc *d; unsigned int cidx = q->cidx; @@ -1725,9 +1792,9 @@ calc_tx_descs_ofld(struct mbuf *m, unsigned int nsegs) static int ofld_xmit(adapter_t *adap, struct sge_txq *q, struct mbuf *m) { - int ret; - unsigned int pidx, gen, ndesc; - int nsegs; + int ret, nsegs; + unsigned int ndesc; + unsigned int pidx, gen; struct mbuf *m_vec[TX_CLEAN_MAX_DESC]; bus_dma_segment_t segs[TX_MAX_SEGS]; int i, cleaned; @@ -1739,7 +1806,7 @@ ofld_xmit(adapter_t *adap, struct sge_txq *q, struct mbuf *m) return (ret); } ndesc = calc_tx_descs_ofld(m, nsegs); -again: cleaned = reclaim_completed_tx(adap, q, TX_CLEAN_MAX_DESC, m_vec); +again: cleaned = reclaim_completed_tx(q, TX_CLEAN_MAX_DESC, m_vec); ret = check_desc_avail(adap, q, m, ndesc, TXQ_OFLD); if (__predict_false(ret)) { @@ -1796,7 +1863,7 @@ restart_offloadq(void *data, int npending) struct tx_sw_desc *stx = &q->sdesc[q->pidx]; mtx_lock(&q->lock); -again: cleaned = reclaim_completed_tx(adap, q, TX_CLEAN_MAX_DESC, m_vec); +again: cleaned = reclaim_completed_tx(q, TX_CLEAN_MAX_DESC, m_vec); while ((m = mbufq_peek(&q->sendq)) != NULL) { unsigned int gen, pidx; @@ -1935,13 +2002,13 @@ restart_tx(struct sge_qset *qs) should_restart_tx(&qs->txq[TXQ_OFLD]) && test_and_clear_bit(TXQ_OFLD, &qs->txq_stopped)) { qs->txq[TXQ_OFLD].restarts++; - taskqueue_enqueue(sc->tq, &qs->txq[TXQ_OFLD].qresume_tsk); + taskqueue_enqueue(sc->tq, &qs->txq[TXQ_OFLD].qresume_task); } if (isset(&qs->txq_stopped, TXQ_CTRL) && should_restart_tx(&qs->txq[TXQ_CTRL]) && test_and_clear_bit(TXQ_CTRL, &qs->txq_stopped)) { qs->txq[TXQ_CTRL].restarts++; - taskqueue_enqueue(sc->tq, &qs->txq[TXQ_CTRL].qresume_tsk); + taskqueue_enqueue(sc->tq, &qs->txq[TXQ_CTRL].qresume_task); } } @@ -2020,14 +2087,19 @@ t3_sge_alloc_qset(adapter_t *sc, u_int id, int nports, int irq_vec_idx, MTX_INIT(&q->txq[i].lock, q->txq[i].lockbuf, NULL, MTX_DEF); } - TASK_INIT(&q->txq[TXQ_OFLD].qresume_tsk, 0, restart_offloadq, q); - TASK_INIT(&q->txq[TXQ_CTRL].qresume_tsk, 0, restart_ctrlq, q); + q->txq[TXQ_ETH].port = pi; + TASK_INIT(&q->txq[TXQ_OFLD].qresume_task, 0, restart_offloadq, q); + TASK_INIT(&q->txq[TXQ_CTRL].qresume_task, 0, restart_ctrlq, q); + TASK_INIT(&q->txq[TXQ_ETH].qreclaim_task, 0, sge_txq_reclaim_handler, &q->txq[TXQ_ETH]); + TASK_INIT(&q->txq[TXQ_OFLD].qreclaim_task, 0, sge_txq_reclaim_handler, &q->txq[TXQ_OFLD]); + q->fl[0].gen = q->fl[1].gen = 1; q->fl[0].size = p->fl_size; q->fl[1].size = p->jumbo_size; q->rspq.gen = 1; + q->rspq.cidx = 0; q->rspq.size = p->rspq_size; q->txq[TXQ_ETH].stop_thres = nports * @@ -2188,7 +2260,7 @@ get_packet(adapter_t *adap, unsigned int drop_thres, struct sge_qset *qs, int ret = 0; prefetch(sd->cl); - + fl->credits--; bus_dmamap_sync(fl->entry_tag, sd->map, BUS_DMASYNC_POSTREAD); @@ -2305,7 +2377,7 @@ process_responses(adapter_t *adap, struct sge_qset *qs, int budget) int ngathered = 0; #ifdef DEBUG static int last_holdoff = 0; - if (rspq->holdoff_tmr != last_holdoff) { + if (cxgb_debug && rspq->holdoff_tmr != last_holdoff) { printf("next_holdoff=%d\n", rspq->holdoff_tmr); last_holdoff = rspq->holdoff_tmr; } @@ -2326,26 +2398,31 @@ process_responses(adapter_t *adap, struct sge_qset *qs, int budget) } else if (flags & F_RSPD_IMM_DATA_VALID) { struct mbuf *m = NULL; + if (cxgb_debug) - printf("IMM DATA VALID\n"); + printf("IMM DATA VALID opcode=0x%x rspq->cidx=%d\n", r->rss_hdr.opcode, rspq->cidx); if (rspq->m == NULL) - rspq->m = m_gethdr(M_NOWAIT, MT_DATA); + rspq->m = m_gethdr(M_DONTWAIT, MT_DATA); else - m = m_gethdr(M_NOWAIT, MT_DATA); + m = m_gethdr(M_DONTWAIT, MT_DATA); - if (rspq->m == NULL || m == NULL) { + /* + * XXX revisit me + */ + if (rspq->m == NULL && m == NULL) { rspq->next_holdoff = NOMEM_INTR_DELAY; budget_left--; break; } - get_imm_packet(adap, r, rspq->m, m); + if (get_imm_packet(adap, r, rspq->m, m, flags)) + goto skip; eop = 1; rspq->imm_data++; } else if (r->len_cq) { int drop_thresh = eth ? SGE_RX_DROP_THRES : 0; if (rspq->m == NULL) - rspq->m = m_gethdr(M_NOWAIT, MT_DATA); + rspq->m = m_gethdr(M_DONTWAIT, MT_DATA); if (rspq->m == NULL) { log(LOG_WARNING, "failed to get mbuf for packet\n"); break; @@ -2362,7 +2439,7 @@ process_responses(adapter_t *adap, struct sge_qset *qs, int budget) sleeping |= flags & RSPD_GTS_MASK; handle_rsp_cntrl_info(qs, flags); } - + skip: r++; if (__predict_false(++rspq->cidx == rspq->size)) { rspq->cidx = 0; @@ -2395,12 +2472,9 @@ process_responses(adapter_t *adap, struct sge_qset *qs, int budget) ngathered = rx_offload(&adap->tdev, rspq, rspq->m, offload_mbufs, ngathered); } -#ifdef notyet - taskqueue_enqueue(adap->tq, &adap->timer_reclaim_task); -#else __refill_fl(adap, &qs->fl[0]); __refill_fl(adap, &qs->fl[1]); -#endif + } --budget_left; } @@ -2637,6 +2711,14 @@ t3_add_sysctls(adapter_t *sc) "collapse_mbufs", CTLFLAG_RW, &collapse_mbufs, 0, "collapse mbuf chains into iovecs"); + SYSCTL_ADD_INT(ctx, children, OID_AUTO, + "txq_overrun", + CTLFLAG_RD, &txq_fills, + 0, "#times txq overrun"); + SYSCTL_ADD_INT(ctx, children, OID_AUTO, + "bogus_imm", + CTLFLAG_RD, &bogus_imm, + 0, "#times a bogus immediate response was seen"); } /** diff --git a/sys/dev/cxgb/sys/mvec.h b/sys/dev/cxgb/sys/mvec.h index 7e0c082cb44b..ec7817b2f08d 100644 --- a/sys/dev/cxgb/sys/mvec.h +++ b/sys/dev/cxgb/sys/mvec.h @@ -129,6 +129,9 @@ m_cljset(struct mbuf *m, void *cl, int type) m->m_ext.ext_size = size; m->m_ext.ext_type = type; m->m_ext.ref_cnt = uma_find_refcnt(zone, cl); + if (*m->m_ext.ref_cnt == 0) + *m->m_ext.ref_cnt = 1; + m->m_flags |= M_EXT; } diff --git a/sys/dev/cxgb/t3fw-4.1.0.bin.gz.uu b/sys/dev/cxgb/t3fw-4.1.0.bin.gz.uu deleted file mode 100644 index e434c1d696f5..000000000000 --- a/sys/dev/cxgb/t3fw-4.1.0.bin.gz.uu +++ /dev/null @@ -1,482 +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. 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.1.0.bin.gz -M'XL("$@Q:T8``W0S9G<M-"XQ+C`N8FEN`.R\"UP3U]HO/)D$DDPFY$+`@!"2 -M$&!RCUAOK;74NFM;[5ML:S>[=K=L$ZRV6FUKJU4KB$##/2!B`@206B]X`VJM -M5ML.:!&5MBBM52'<5-2J>*F]*_,]:P)J^^Z]?^_Y?N=WOO.=\T;7S)HUZ_*L -MM9[+_UEK#<D8#SN#85(YPQ!J#,.2L<>P7@S/P/@8NCLQ#H;U8&RHAB@V9<J4 -M!/1\!N.$W(WS$M2<GCOY<+BKL:1R&L/.CL*^'X5=&855C\+6C\)PC-;@_:,X -M.-:DCB:P!520>9S-/.X^\[CQYG$3HQ_D0(Y&-6V#%]9QF'6<U#I.;1UG\[_0 -M$E)_F;AQ6-PX:=PX=1S[BHMC<J8]F&DG<6R-6LX<OR=*CUJC3H=(6S!S#"6T -MA3#'0IECM.T[=<`<3C*FX(T-@*HY,AS^OS5*P9^J"!A-\GF/O#WJ++QZ:\(5 -M#-7>',(TTS8\#D_&`NYDX4V"]]?8UNDCZM7J#$VF=O'HP-:'6O^>C,FR$G?- -M++5%3^0M'OV#UD3:&9^<^3B:2%LP@0]-K5%K30ELU1_2\5Q+`%M+?3!3OT8M -M8^H)*?;?O__^_:_X@9R>_+<93HR2,C\3__)UU"U_.(,%;OB7<8;&4/CG\:9. -M?[RITQ\7IL&])XHYT@KQ##5+(R?M#"9;BNX0,LY@\E_4(#P0(B!^"]TAJ,]@ -MP4ITAS`1XBAM(H0$B(]'=PC3(8[2ID-(A/ACZ`[A!8BCM!<@)$,\"=TAS(<X -M2IL/81'$YZ([A#R(H[2\H;@3[BX(VX;BVX;B&^#>IL:X=?XXM\X?5V3\[QE/ -MMOKCR59__'7>_U?Q/_+HB[HHYFL:3)4:^*(-XDO]]#Y;`?EU/6!S4($HYN!9 -M-?;,94AO56,O[8*\W_AYJ>D:Q-']8-2M00R3,`RR40$0$B"D85A8%\-@7=L_ -MN_HP/(]!C=)@%"&+#;U/QK!%+!W`G"S3_X+*J"!P,`&&_F-B"$I_'K8@"15' -M0.`EL(\8"8'+ML7#`ME>V;!N#%$A()G/&8;IAM##9U!MOV!\!H2`095!W_A< -M>,6@Q&M\AAGD,JGP>`#"<+$HYL"U:G\_HI+9N@5IB=`<RL%VEKD&::$P;DW0 -M*^;G#_QCE0'!Y>^!2*VV,FG,(+0"N3',A$%Y'%$>Q;0H4:]02U#V*@>3H;+K -M(10QS%64]GL4\]DUAOD9Q6_#.)_$.+]#6T=`G@]U]F)(=\1)>Z'7:IL?2\`< -MV"`L@CK60)Z3$&!^6GB]0$HO:I;;YC(FVM.,B>]`<$'8F`;M2A`645L'43UI -M0"_4!+1RF%^,B?5I\$X*=\R8V`#A4PKN4.[3:DB7&1,_@;3]:;TP]KT`;'J@ -MC5YV]M.@+X>`1P[U1-W&!'"_"70(?/"#>P30[()P&;)J:';,6DQJ[+EO(%R& -M_H%.>>XF!-`KSR5',8=-D&8#WDR&9C20!GJ)NQ_*[&%^9ZZIL1>^4&-_CX'0 -M#OP<#'GWJS'>LRP[,4=:[N5WSI]TK%J*)=P)"N@[,-.=,)PV')08K8[@8'>" -MFI/`I@T'E/;G9Y3G;DC^0]!QJM78])X_AFDG[PG*H2!58T_`_?'[U-A4T,%_ -MZ;PKO]-!5J>O&+I#F/;/@L!_GPIZ]]%.*.^Z6YYW4(W90-_R=JFQA^$=#\9N -M`NA3'NC9AR!=W:+&QKK5V'V@FZT@_Y;%:LQ@4V,Z:#-^LQJ+A.=PT`W!"C4F -MWZ/&I-"6%.H5@ST1@0U`=N8O<_TA@%1C?-!%DR!]#.3CM2(:XAU^6M#=\:=_ -M_S-^(`L]_GMS*_`AZ+M#*_ZG5/S?O__^_6_X`WZ_X+>,_^SW3](?B4[[K]3K -MU\E_K1[2S3?_F/Y_16#MT=`=0A+HPQ<==Y__SP[#\XT@$[+30_&'X)9VS_/G -M<$NXYQF!"?6?GJ5_>A;\Z9GWIV?\3\\<A`6&XL-I=W\OE'#^7H*_6,)]J01[ -MY+_"V7_ZO>#B_-V%O^CBON3"GOE_4;ZB!(MT<;PE>&4)MZJ$)R@)$)8$$B5\ -MT7^1G`HH[,(K7?Q(%[?*Q5OJ"GC'%;C,Q5_^7R2GDVW?5X)WE7"[2WB\DH"` -MDL#`$CZ_1"`H$0I+"*)$].]HZ83"+KS+)8+VNUV\7:Z`CUR!NUW\CUV"/2[A -M7A?QB4NT[U_3`C+Q-TW$R0IY!--%T/_Y/<)SF@A7L6)-2#!S&[]@*PGE1A.K -M;6M'$#9_^9E2[#CXQH/$4'TSD[#V/SR[L6_^\'P3^_;N\__(+T"!V9E?_X>+ -M_?_F-U\:P)'A2:'EQR1H)8[&:`V&C\(?'X4]AI8*:4QVE0R^*N:R"X?*JZ*1 -M5TG:)?B$?'>30)^%47D\P[9;*S81GC1]%H?*$QBV_4(\H5BP1>1)\ZSRI.NS -MN%2>5'$5XR=@B@$F=("!B'R`"1Y@UJCI9'J1<F!0,3!(I?LSW(8K2Q.N&/@= -MQ7GLX,^7\FB;?.#G=/6;&CP9>X!."![X<;5MM6WQJ+C0@1]"!FYD)NZ:N399 -M,7`M(T'W)*.;_)`H`:,7A0Y<CIV-P?\E\[Y3#ER@7X_+PJ";J#YT8^M50^R> -MYS_?Z6H]P3-J590V4J\+-,3@R[-Q8BM^>%_PP(EVB:F.;ZG#Z&/<`<+2-^6T -M6M2#=52G[#S/UHK*"PP:/);`WMHD==ZGCP](?4^06A40^`H.%1&B:2V?MO[U -MM+K#UIF0)/X.E1DY<,#24$F?7-F.)W/*S`W>[C;',7><FJ3I=5)RB6SK2GU? -M%D40[ZR&]V9]7Z9J8(^C2$?%<P1.19"3LW"5CNZEVRD-K_('@5,F=N*1`_7N -MZ]YK)(Y1#5[S+265IZ1V>]^[CSZ;NN0^Y<#6PC&=/:J!VHJB2E>!NK1$,(!7 -M%M-]RH&-E6O=:R2"!(E31I7R4W\66)_`)#MQ:PR^<DD`-4I,Q6C?71)@&"4Q -MQ&A6+!EOF*BV$AR*P,2_C!<()CO25BD'UD4-K+-F3<*JG5A;WKU7(,;0X#5L -M4QIV>W-L2S9-L&IX^:,+XND,X2'1KE;WZ\J!'!XC<R]R&BO?]BZ)''BO]"WH -MBOL-PIT0Z)0)&)PB(N!J?9MWF#:H2;)6)JH5Z&LRA8=%^HV9*8EOT&IP\X$: -M@J4FI?!U.[,D8N!5Y<`K]/I\J46KVK8"B-`WI&/'>%AM.+4*%V[!];O3(5%P -M=E0A77DMG\YNVN7STN]Z`BQ-'$LS9M7@_O[;!Q]OEY@)S#[X#R,1B!OPI*`- -M]L$Q!M/BCH2DH#7'JX])YDN)$[9HT^(UP<$#3R5CKX0/3#N8IAIX`O@(6K#& -MIUMZ<43_6-1@T-E1^=O+V[*W.W?N\N@WBM_)YA;NJ-JNU^`&(H'PX/H8_*MG -MLY.%\V;,70.S/AD8)ADQS#2Z[D1=R\?TC(QZ^G4>;RI_!>YHE-&+*`UN(C"! -M8%I*8;-^-@;EYJWYU!!?N7`C;F<66^*]NQYS7)T/PV:</E@FA[%[?Z?^1I:O -MCN6IO^EO9#J*GJ$;Z=7A`UJ8EXHS93T"!HUY52\0:XKW&N9+3:U*TUAORHRW -M.UT6@F,E,.'5\1+)9,>U4M5`F'(@C.J?]$I]>.K'`6B^Z3Q1E&+!KR)_W'\U -M$%A><LB`;,FA:4Z[6<-[;[;P,Q$])6J`+.FMZLDPKNMWG^?Y9`%3\)(^^EK5 -M.;(J(9"127QXXVVX>,_JU>3Q:M(C>]]#%6?N^E1P4D259AZ30/)PXO'JX40D -M5T`BP9*8PKQ@9V9[I'.+_YJM,ZDE1G50?:M))ZF;OF%?W3ZC+FC/JY2+;W!Q -M-SCK:PTEW#HG5<+/"4X2\O*E<X^![O'2/;DZ@UJBO'+&L(NK5P<5UNEW\='P -MU%7J[(/SVR5#\T.>*=/I=$%TO5$GH>OL@T]'7CE*UU-:58%\^W8_%V"]/&Q? -MN.K*0<GG.'#$'7;(;G.["ML*CN]BJMI2+P98CG,L)UC^^YSEO]M7<X*]"H^L -M/(1NR)/Y@!5J<D/R%=DR^^`6:.GV!=`[@90Z$#AHGE,A%$X[7'1'S9"?LJ(! -M_\.O;#'65*JN?+!P-\P[9J[QTJ\[VGZQ@JYI)G^2U;ZJ;\BB"UBFB-8W9"JO -M5#F*PD&YV.-`N;2[VP2ILD#H];&LL<HK)8&%BL#`J9%7JIP9WJ+(*Y4[G5%7 -M*I'(NO(-PCG20!^.IJTXUB:WVDR4+9ADI#RG-'".5#`'EZ3BJ*(U^?=[2YSC -MW&NSQD=><966QM9X"R?$SE=6K7..J2QWNT'!H0K+\FVQ&[U+OANGO)*NNI*6 -M-SHGGKY9Y:VLR#*:2H/I(X92.5T-M996&DIE8I9M>"MED@'$.0.XI50*0\PJ -MPTQ!BXC:#<HB6TN@\8B\,OL@;64%U%B3KN_%R7VX<2.:$>'944Y?55JN+[M[ -MU[YRWW(/KZ#+<D(,$T(R?H50!88SXLJSV'6>&53+?&QY.&J"K46P!Z?NU$)[ -MT[)I9],NCX=^)SO`W,0Q-V,6#1[T&6Y!U23Y=8@XW:]#!`9UH%&#S]W,F[N) -M<TPB$DQK*403V9G084LBI_G)5ET9I^^K7%@*TY1H[?/2/L?UQ\!>L-9BQ]OZ -MV5F-F>P</F2:G<F=`!IB+/VZ\HJI1*[3\-S7UOU`OREX3,:'@;W^GMFJB51> -ML?)_%@J6X.OH$5>L5)]W76.<30I&@UPBY4_!1UPQ4OU>B)0TO3<F0^Y8]%B7 -MS2OST:E+0G9-*)A`Q8=6'G(WYX^S3)2:FP7F5I*O5"S(UI@[E7L\T<4*Y\4U -M;>YCSO.KK[B/4\4A:[YQMZ^^9+FL7O-MOHR^C^ZI9R22IUY=/(Z^C_^.D/00 -M_'$DG_OPX?A*]WY/W>B6^]G[^)9T=(<\E'Q!CJBRTE(JJW17ENLK;,HK`='- -MP2,N_Z371,0URZTQD7%:+-43`.)OB8FT-(^@FD/#+M\.8&369F74Y4OZYA#@ -M/FNS8NZFE]&,S<Y$2F,.,,4&5DR&]+O89!_,''FY,^SR:7H]L$B^=.MRO^$P -M]Z7KBW#Q=MS</SS'=55I^779#6`[ZI#M:.!8=M]K.Q[,IBAMX#NKGFILMS9' -M6)I5EF8-71Q^^3"=H6^.#KM\PM"L-32'AU_^5M\<:6B.HII'*B^WT^NIYACE -MY>/$)[A@*4XUZP`_V)EI?GXA?T+\0KL!G]B9<<`W>G4@&(&Y;M[<=<`W8`E: -M\N\H`-&G2!\:U63HY2WD)[*-M:::+#U!KD"FY;"I)M/1>,`XNY+5"5\89WL; -M\QSUG^HU:F%:LED]\1"#\2=QB$GU._C?3R!JA>(=,LOEB*"@AR4#W/H!N`?5 -MB@S;(KZK7OE=A%D38PV_M:PC6+R#E/0F8\))'/ZD^J7"]R802XCL6$K+%SK) -M);G03@5]TJ")MF@T];4$\90A)GK9)7G=-N!\4TRT&(00=752NX1NHZ_1Q25R -MNE=Y><7:8'I*#"BB#]UU]&K!3)D@"7?74^J).39>!H=W=;R`D0J=',&5\7R? -M%%0/49A`E"7P:Z6434J[='F#O(OC)5<GB!@IX9%*/+C8@Q<:S=!-!M=K8L1F -MA5"O4%Q>(IB)\T`UT1EJT%:"*3+!%)S.@4M)8Z&!YY%5'806H:A@?$*`4THX -M<2'(4;-./9%W7P(QA;5>API'TVE5!_+CW2V5A[U->JVB\87Z,D.L8NT7[J.> -M(QGC2UH+[Z_ZLN"!RJ_R)WB_SAD3,]MK:)9FCXUY0:EOECG'Q<SQ4LUR'1BV -M*;*-4ZR3,S.#K;<2K8]F9L@/+\J)S=9OJC7$!A(>4BA\3!\3DY*XD.5<Q+;D -M2OM@8+LDXK+Q8+7RLM'"ZC;]['1`.PA6S!E&.U\"VODR]VO@V"_?W<O-_LKS -M)8P]X1_XVU]4R$ZKRZ7\Y7A2X-_R9+E2N@U,/@'3?V5\2M<4^^T-0TPX$S'A -M'S`UR1V+PW@#-\Y[#Z:Y>)@AP2[1BX3$M,,;OTQ$QI(W'4\2C8C;P&4I9]DS -M'EO\L=2DB383O)9#8B]N1CS0%G;IEJ6X<F$_5/:"H=CK6/^<(92@;QS:">RL -MO/0CN5^VN57?!/A8RJJ\1TQ-P,X/&C76@CFB2V.!?QWUFZT:M:2.Y4;)I/I? -MA(43)(Q0Q(@D@H<))[?>*1`\O)F1_`8`$U_:AG@XM2.4"K\E_HT4K&=+`?-O -M%N9,D-02^;%Z+5_L(9>50UL9^7;O@>S9GB9GBKO%FBR=]S-@A:/K#E-:I54; -M7`Z3775DY3Z45A;67EVNH%=%73I*G\D/KP@Q@2)NKVH3M,J"6O&*8Q&7#NB3 -MI<8FKV$VW[A?:6SV'MVINM2.!BHOI%!A3N9ZI*1/)EX@,'>JDSB_6K3!<;'* -M^@%+;'#+0\[80OW[3G>L@"$EDL>LP`\S`M&`FN>K59>:/-+A6I(X&^S,P7;) -MPK6@DEX[V.-7#K[$),$Y5I?L1OPC&K`/OL!&+ML'GRG_@BX"$;Q1==@+C+OR -M0YB0T14AY8JR,$?B#KK'7S/T'`BLDA8JO$H@<OL"EL:V;$6!,C]LQPZ+@YL7 -MFZO?WDKN(T6BQRIB<^888V*$M639'!@H^H;0*:!BE?9!$]A3:K_2'0K30>1P -MD5YXV!#*!Y`/3D/J2:!Y%4S-LG:(+'6&%H[8S(#QA#)^>DZKC7)A4L".E.V5 -M.6&YBKR0@CGVP1?];"K:BOHWI`N)92>JZ1G`>';F0<2W"')KH@$P&;8Q?DTT -MM^3!>>XQ1HUF^58K8%;`[R9M)'("#W,ZJL$'O#3SW_F`P,TI.S^#@9XO59RP -M60A>'(&!-$1>>F*N.V#N.CP9+S5H=(ZGN91&NPPT(?X:4`#-MWA9=8U0)#&# -ME0=M2$[\\O608UG>>/J&HVDY<#SMSAE'9Q'N">ZHACPQN&FA0:#0Q;4"2TW6 -MR@.0=XH%U'G?)*/&DO.R:.M8T%5QFB@J5.QHF,*ONU<A'ZKB+R%$2PB^X&'A -ML!`L<4;&A?)3TZR4)L:M7)(;IPU5O*=TCM"&W^*_1^*O)T>'AF!<5(5V!8<; -M-T&PA-#*%='RD.Q89]R09L=5M,MSP>EP7\R>XTPI/Z?O%U']Q#(0`]P$7$\7 -MK38XDX'O!3F@G2>(:J6`\22@M=T30`FO&1FMB0(US(U6\)W2-1&KU>XP9Y1@ -MM$PP&E=>DH/ZA<B:\&BMR%'W55RH4A<:&A,Z(G,NO7CM97I&^17G*QGSW%=+ -M!D`=TVG\J1S)%`XO:3R=P']V_(A+W,R1_)GX>V%KSV9&\)%J!SB**[X?%&P& -M98Y#/"/<W5/2"T,6L'9(O0,F@B)Q<N7:?J@R1C["K^1Y!W$)Z/GS.GEHG@IF -M1:_1D?MDV_<9&C+K/-MJ#;LS*6V(/D97[Z1B0PXORH_-TV_RF6,#Q:TD23YF -M`@E].HGE%,,V#LMS.L#W]"KH#;TK%DA/$+W*D<SA!&:,IY-%6>-S1Y:?S8UP -MAHO*<7<O?PK@9VG@%#ST^V.\#3CO/ASB)3U0+",L<&Q"`/N.MP\O[X>.`('0 -M$0+<YQ9<`G;JO)UYLO%+4XS)0J3YY2'@[W@2'^0?B)E7`CKMR[FE?4A6DHC+ -M]MO@V#2>-,>8[,Q7=*\%W9L/%<;M5ZR3\_D/"Y9PG9'U2R"V3K9U2=P*1:H3 -M3,=-8!TJ5+!D-<0O..7`0.FRS5IM*!\8Q7Y[!\BK*51F"96#O(8&=RQ*XC4: -MY<&1WZ^VR.7T#9-<EK+MYYR7[;<_:9<80J6.&1_0:=ESW<'E5SR7L^<Y7_$, -MN*\ZYQGD4K<T^Q5WZ):]'L7R\H!L:;W'$TIG`"OH-5%^MC"$A@'8!7X%"QZG -MB0&>XL<I>$MDPB7XZM`<Q9IY]*BR5V)@K*L%21S)3$[`_>,!*=")@C'C@3UG -M2@-J<4%F0L"8":N-HIE28B8>,!H/^?XM@3L!(FMZ<M2948):&:2'?S\_^/OY -M$%G;FV,`MN+6XF5GH6*#/"Q@3$+`3"G@">"AM?V0!HP$:<1,A!*`F89Y:'5* -M0;!SSOL#F_=0H0$@3<MS<<MECF@KZ0RI3''/`>'2;_*`>`D$CU$Q,4Z5)[;\ -M9>`Z<J]LNU=_/!,4@,`CT)_(C/Q^E/WW&WZ=1[S&SJD_F]@C,!1G+=P$IBC= -M6ISIN+:"?C_X>ZM9@R12Y)/Q6F7B5MS\A!RNE==5W\?Y$BJO%1C7_;CNYW4_ -M5=SD#N"5-Y"+5)S9N<BX7VTLS>Q(,.@"H:4D`D.ZE9U0F%B84^X#.++M0C4[ -MK^+A>3U1[=Q$SZ!"I?9!(S(OQ+/^-3D!R*EH,O]^1?T64=D$_70;72_<XU]- -MNAKY/3?B>Z[IQ*17UH>G;@K`$IV8*X]0*19<%/GC_BO=EFNCB^E5=`^:SYN2 -MESB2@O&"`:EP)H>^%E`XGL]()0MQO5PJRDPP50R2^>,#,B<XC>`9HIGU20-\ -M>)`/!S\3S$O$Q=L`!$DGOGN;0:-V)V2J>6XI@IHS<4K#"_@"7_MPH4'@E%5- -M$54E6-03H>Z@20D!`U*H[:TY`H,FBC`HDC$<KCRPU]M1S=Y'K>J)`C<N>2B! -M\"^J3+6HR:B+S>2`;.>`N2]3_*7(W(\6+:X%?.Y?K^#9&6*^E*!I>J.1P%(6 -MG:`7T8ET":"9`B.]:K5->(HC?&^\8(E4+U=P"Q,DA0C5`@GT#8D/.BW.',^? -M":`-NLKS2<4+</%,W%PQ*"X<3S!2/H,',#ADYE8E`/F5"?EJ7J54X).A0=B. -M>Q^&82!;I#`,<5H".@$Z$+H>]R@/N@L]O[>[)DT4:8+N!I@T:HB(O_QWW<T9 -M[N[Q.O%VU&%@3U]"P8PC?0VU]:WF3FG0TK%N:(TL3'2?JCJ9_4SATQYYE=33 -M475ZY6JB?E_,"U+'RI_L3&N^W"G;GB^X2.J?XRSMX!9*ZQGO,U5/VP=/(7ON -ML#T98$O&B$D<X:1Z-Y$]P:B>*)Q.'=JY;327Q7M4'@=LG6"T8.7'409-C"G\ -MUIM;0XD'2+*>-8_XI'I*F#Z!JR6`ON,VF)4B._,)BW%)L.,`;X<AK4&#@VTG -M!-,.9]W%M(+9]V+:7)N>X"W^&,8G.J4I//SBX^::RH4G0`P'335>^@<'_5/D -MQ4>=XP%<.U9Q3*&!(*X1%Q-`H+?Y730I<M&P+G--IE?I:#O1>-"JL13,/:V6 -M#(PU:Z(Z>BK#9C$'D/$M&P'Z`<$)S@/YRFR[I]TY>]U)]_'"E*I3!2_GA%5V -MY,TI^[;B=.[<Y5LA3US413W=FQ\*TL]BT,IV^HP?AU[4(#E'.%0XA$,WJ2[> -MS^(\96$8G09`SRT=`GG4+.:O!2-:KB+\N>./^#/:CS\IU47C4,EJ0RCR3V8Q -M@+L.@U^W&TR,\!G[X$&P"$@?"!/M@WN@^^4*L*3$/H&^81C28Y?T#9D.U[E8 -M#<]+5QX0S)4A2];(+K9X\VQH;7NC=\FA!Y07?L\9G1]/WU1=^+FJJ-)5:%RW -MMFP=XK]BLC(A<$#F+>4M0$S>V(.XM(1=D,XT;%,;T(*0BYTSA"+Y2=R(E!W@ -M_7_4+G$D9J@N'/=WG[[F1[EAWI"[`S`B_^6"$*<?Y1;,V9[?V;.T@U-_V1F6 -M.Z)BCO=EY*MMK?4[:F6QA7/!68-1JIIK'U2`@6,5M9"'%*AP&SB^8#(_.JW. -M520)Q?;;6_VO!;?NP:[\HW>PZ\M(=S:^0:&=!@%X^T>ROGP1Y4(\R&^$LJ`W -M3(0\B=L>NP&+V\!'$^)?/`J_L%E?4QEQ80.[?I1O!$:\[JC/!!DEK\AJ3U%@ -M*#+AQ8>FXDS.09ZCL99NM\1+G9-B1PE+I!D/Q<;P!'-DXCEXY(6/O'6E]:`] -MLI2E'])S2S_"#O)X&4I!RS,80"2P&;L"NF1!3EQU86OHA4*(N!OH='>CZL*6 -M4AIF0%?C]3;IIBMU&[T'=AJ^"(3YT!5GZJ9+=:69!6,J#?ECO<:<<66F[/%F -M`R;\F\)CID8%6VR4;M0(BVYB4-!4'B\AUJ;7Q43JY!@5$Q&K>]`P*@1&@Q`^ -M+-Q"ZBLNZV.B5IX?(:Y.QLA)',$D8QZ'W#,A","0AX175DV4\L)[DE7)C306 -M-(DCFE3_:5#'!$O%+4N,FMPWEJ:I42,-H\),,=&F&!U@-D!-IEBE:"!"Q$10 -M,5IKC,428S6K%888C5C\B%FG@$'_*I$>U=@$0Y_$?8M>YQ]Y4!-Z72#``G`A -MT"QT)/@2:#I)$$^OHT?]^:7JPH,'VRC_CD%-NK$1%S.XE5U*%)T=E7W%[2J\ -MDGMU%U-U)74OUSG@O@*^@YC=+;#?'@1)4EZP8KT\O58U\H)Y:Q=V.]Q8@SQ_ -M4<?0JB9X_KD]GCIG3V[?+J>[9^G>`%,?Q]3/KD=VL>N1MS\&'7I:'7'AX<@+ -M,;F:J`L)HL=%.ZEW5D^E>T1[<2/!$7XV/BAH\I'SUB]OFW^:],K#X:E3`S`; -M,L0\)5J;\\?]U_3UP'`6`N.R95*N'K$S7W;91%J2+J((3*(5X`_)16Z_N;=3 -M4&'6I$.NU+(H_2UIZKH`K,>)U>4)H^3MD@6_B?Q/_NO[^OU;Z5XZ370!E3V: -M98&B_4!+`:+%A7+PHN2H#!OW7UE:H%6NV[\]5&AGBNEKPJ$=@OUV=$(!9(I2 -M!\Y]#[2.,Y;@@'I/>;H""2*2JUG,7KI.=?YVWH;@\U\6JBDBC=H@IM.#6CET -M3]P&TJR)X(*RJ8E6/TA?YW(3N(/CB0$I4JL;4%*/8#0'DJ+.#XC`?+9RHLY? -M@7>J\Y<K-L`3F^VUXZ$+!&#IL'H>-B_\W7*!G1F`206R@\^?59T_:]7PZC[5 -M5T=0U2,EDJ?`%@N=.-KP$S\B],GT.:G"PQQ@!G.UPK-!*)PJ\,C8IY#A2*@_ -M$N3A1)X_;JE6(<;9$"K,5N@WA+!7!7L-UE='1IX_ZJ\;I#;[`ZX3ZN7DFU7G -MF\61BB`?1^Q#%7D^R#9$GF\2"I\*\"!2J`TJ\.6H#9'L-:)@DYB1B0<X`!6L -MU>K*32"Q@@$9^Z09CFC]$>X`)[HFF"TVLM#$_>$QZ%X`@]X4;K%LT`85*"P; -M-.Q5[=S,WJ.RC6(G!YH6LTV'G:\QUVB$#"?L?'7`:!G`(_'V1]V;83ZB:[3- -MA=R@Q[GO*V`"`D?+`,Q:-FH/(AL@%C\:R/8D\GQ)=`Z7RP`548?RH?T@R`=S -MN47`<)RUT)!^HR9:/3'R?"XW.D'"OCLTJ6H+`"(H$Z1*`$(KM^C5$X//9W`\ -M4K0@6`M/,&S""0DXFQ!V_F5$+XH\FK_!75M(%<1R?3`V)'T]:'`"#HP"-FG# -M:DC.7LL=("$MZOP;7.`4'X=]$QL;'!NKB(T-B8O!G;'Y9K<>0+T^5AQ\_CY] -M/+L5@'49XKV.ZI,(\G\B>[_67).U9_J[!^!%F[X&#.@1C[2D"'B9KH\\;]Q3 -M82[%>$^"K9!:-)'$)MS1\R@%!9TRKE-@3<^4/"6R9F7&QD0>>>>KOQJU*KTV -M<KD'I!\[O#?X?,B_6OTXO@AXU4E9M8%+KS]&7U.>U]!-D7`YFRL-.Q\DFB;: -M/<535UF?HZ[:Y?ZHZF/5>:5G#VBPR@\#/7C%7N^^R/,C(LYS$0C]A`0WJ@'I -M->9ENL6$%KE?8C$#_U&D)E%DRMW]=I!90SQW83KT]2:='-Q_><3YF(C^`8LZ -MI#!V9/_W,6J13@-@7VB>H9LW&3(=*J.6_8K6Y0ZEYC7D?KBP$^Q=!-;(J[N` -M.<,W;T;;-[%\`'MSUQB@[P;H^Q8.77=XS[_?^Z?4#KH7HWG0??ZGT`L.\2LI -MODV*Q6'"BQ-@MMY)K]>KR9']+:1'MM5C*<YZ[7PUN%2.S\N4_;_2WZCZCWCK -M*^M,:J+T0P&H@X8"-=J8WV56\\L^KMIM_HB(U?'1;FQQIJE5;2K-M#/_^"99 -MAX;(BIJGZV-U(=98?M!)=B]@IFY>,73QQWGKX)HS=PUDB]=KHU*J3'KU\_.* -MX#&:S=`3WG_*$J\Q;&>*>\SQ&E-\]"Z?>:/FW<,!IGBM::/&J'O>/O@+=(LN -M(GXA!>X)_+U<X1:.\%?`-&%;G`+A5+TN1'"!W'P2FG2X5J)A]&*^\.W;Q9_B -MWKB4_]AM(?"@__!O=M6".O/OUVZKH)JRZ-^6_@"$K-`W93JJWA[9OR>\?Z^R -M?S5]-K)_=661UU6H+EU7MK:TI'R-'\;AF*4IDSYIN:RV-&<BF_B]S:P+C(W! -MR]$.7P[XED]5Q=F9G'9)+)ML'WP(+2JR?$WF":Q-60M_AO9(MKU`>E=D_X)R -M:(:"(5^#ML.*"]7@'565Y,=:8-#7>4LM:X<&W=B4B1S?YLQ8&([;%Y%OYNIP -MI2SZP3!=:9RHI!O!L(A:_(;LJ\C^F1'],\%O_2[QE6>C3"_<3CW$;HK7Y9$J -M9,N^%_F?_-?<!`.4+9@:))DJ(I\1/9;(:Y62*_"*41']LW8YT1X$D&3+?\2I -M]HX!Q]0=7QB[D;'&!N8G1/6_NNS$5.YR$?U-1/_]WOJ*.NB)YT,$CX%YD%+: -ME1]K4O.]NYV4Z2/"_;%53>IU?'E_',G(:ACMC<Q=*_$!D>6G3(0QX:6\7\.^ -ML=R`E*"5Z,W0D8H6O\W4V1D#"USS$LKER[^*IC\T353Z$K]+3`H8S)73KG(I -MW6N&WEP9[^A^,3>A0&IGXOR+S%W)93*$\S%>1^)WU3FRI,!':1==#W@`_*HX -M&,$Z^D!4__T%"3NM0053>5=$I]M2VW&#[Q>Z[:U+2ZI"DC&5IYK:)L72G&XY -MG89=RZL*=J]W)#^G!T3BX[YUZ9D]6PJK^2<)R<*Q._=)YI!5:2==*+.4?U*T -MQXFEY;EE5`TV#VWG9S:TZD-Y[M"E/[R4O;Y0D5*UX<,!ZS9E=LCI:^_\@!MN -M_Y*R<+,9Z0EN_N2.MO#^4)@:ZQ28D3*;83+7JL66'PM0]LL$M1SEN1_*QJ#Y -MB2^8+!H@*R?GQV[_U!N;/>4XO66O9\HQ2>;[DBSR@Q]+J[-JUKX?N`!/G<6I -M7^"MR9]L9S;6M\:M4'H4=F8QVKLWJ$/TZE#%N<_`6W"X)IO4(MY70F.O3OCI -M6/$^TGA.M[V6(*8:="%'JG,?*:2R)]=MQHIX2%\QDGVX,99?&"O90RY]8`3K -M=X(4#*`MEQK_61):<TPBKB6A.G\=V_=!A8[J1;F/Y%.%D^MV8-=YV$#X#I]X -M'UX>1Z\?>:[RXZ_"SE6:`8A>E:$3"[7A._<ACZLXW?HP+MB,4Z4(3DK.CBJH -M\_9DUSD;=GD\=>]DRYWUT*J[#AVLB<&U!`?8!RUO;QDF`HEG)>M+EX2M"6E/ -MR`AQ)M!%@I=G"`13`]SCJ=#`9"S^JQ?T:L4*I+=^`)<FH=/F6Y04,.6;ZL,U -M]`SZ'ZO7OU?-Y4[E"Z9";O[+,SJ3';2;3J:K47]IH7!:2M6G\][\)/N1=Y%_ -M(\BG5I0&&-7/.QK""V.%KTX5#Y*.GOFJ<\[&-,'X<68U&7;.X56`1^<=L<6G -M/YZUV\DZG>\:CV<ZZI:4R\ND^9,KE-[@H*ZQV7&^'HF'7(GV?F(+@E=VP!UL -M0*Z\,\$K<X9:U7R?K4"VF;'J^-V)LP9_9G=58#92/B\<>6ZJ7BT2>41Z+X=R -M%>M=:_SP+>Q<VA8G7%3GTM#6Y<`X.S.'5>;KP\Y-`C]`=>Z!_!'(&2A.W^$K -M4/BG0G5NC&0G>WBD]#\='K&>P%(O\@J/P1U\0S132`UN`S5H5`?.^Q`H'DGW -MT#]8=8'Y4RPZOC?.2WGUWEA+P@CAK*<!HUMTHET#%AU))4B,.H=`\!=*1U@F -M!RSJAS'IIZ^//!<:)'@QMX'CE"&4RH1C=;S-#$4,UC$229B`&4NG2R13!<PX -MJR[4/IC!'HSIL81R9C%3P8/NI=L*I?0JHG""!#1$5VCVY'R9)]@^V."5.1)= -M_I'D/HA;Y)Q9@[\IS]ZBZV%^(L[^CO;=]X63W;+(L[]NN[6=T=_(M&A5PBTB -M_4^9_J,=^N/(SQ'NQ?4G_G">*\=_GFN+++\1?!PO[3]UP?KZ=\Y@L.-]PXH4 -M>V<^91^\0:^F@/K;S4!0"'<BGL2]\DTUX`\6:P1&G?T]Y&R7>+HL].QO^>H< -MK;@#QT^1Q!,B0RRNK[C9<M_"2AAD\=8C&RW+SCQWJN[H6`/!`>`DW#I>))I\ -M=!=U^W9,%K@J$7?=IG!D%&K_X#CEJ&N/++L(8[Z_3'V\[9@$*N"R%:1\_JF= -MH4_;1!9RXT!0*^FPO1$T5LZZ4X%3R&%?:JX>6BF=="CM[9PH_7S6EV)MC5") -MFLKY@_UY_^)^`UU/IQ'LLNO17",4W3WLUX'G5)W'4\F1S6+C_FO-U_N9*I:P -M>QRJ'#N3#[Z><,C7VVUG]NZW^G.=MM%IPDF*QKJ@?:1HVEB]3T#W"EG?[<A[ -M0P-RY^B8*T_D7^)EX_YKKAIXUP=_4$=9N\.CDR+-OC#C[^H%5>AO78!/H -M=<32]?(##<NWP,@5GTYFE\!9*6Q,27P*`(&A30F@D")^MZI%1K4"`)-@'T?, -M"*GK.J-.(1@06'X$M7A\&/!R.I(/?SP,^?@LY`,;-H3Y^N_LGW+0)J)0,BV% -M*89*Z_:)1%.A-D?=%RL^7D4WDA5H:8>H07Y<Z]\L-L'RWC!KF[+E]IWRV$U$ -MHW]U!J#LO/1N_Y;@O*(3?ASC!Z$6M<BD#A$/"*V].J!\9ZOIG`Z`:4>RX_,= -M0*25)9(AK#<0+KWFQZ619PUVQH6D?S_C)^OH1RL^1@3YMS67'T;`]E_W$<D& -MT(#HBT4@O(65`?\ZZ,*U+QUY=FZ)UK]KB?H1AN@63&M)]ZLPHFQX68-N/*WF -M/H##2!VN'5K+XBKUU;(3U2O7"8S$;5$YQ[A!1L\PJ17T-^)6W*0#L[BQ74+? -MW:3F3+QSUD#`'8>GS.#3HY*QV*_0RNNB_$6=">(%,Y*X^[ZK;MF&K$3&^M75 -M/-Y4,!2GDQW5+70RA8Y6^D]('LE>-/),/WM&\G-C`WON!3LX\DQ?Q)E>8X/7 -M.AUWU'T$BH?LDFV[#"@5,&HR!T.8T?6;ZDPGO3K\S"EPQ==\6%8W=$BROM*E -M.G,<?*H^;TF1N5-I[O>FS'AQSSOT>I!;DI5;1]UCJC-?1YYI0^L4DU5U3Z`- -M#1<Z%DD,KV^P3_YKV)G/_:AUBU.;GDE7XY-%VJS,87MR1YND?%YK9^I6VZ"7 -M=F8DPM8:GO+,-?8@!#?RS-:#0%:M\LRVH2.HZ>@(JI#!K5E#9L-TG#0?#UIQ -MBA]YICJOVW2"/'B-:KT%BC'L3`7`1W>%,0MC<;L;<9!616EX$6=*H\Y\9VK$ -ME_X^"=2R\DP)?0S0/M0MZ1ZJF#P[*N+,5]LN%]"%32M_Y18<J*2M&IRZ?,M- -MEZ>A7*C&1]LE4#SJ3`9];.=`U)G54(?^1KKP%*[_::@.9T]Y6F%/=A_8M'XL -MU<-U]KI[$'^=8I>[!@/8-4X.\F&Y+X6=>?.>\;IGM':72<%7Y.X%W^!V.WM. -M)9;`CCY]9^]S%C-_F&=1_GO$]VC]NQ]?&I;>.VNPR58;UT+\;`;=$8-;=420 -MCV/6*0#8)7$6VIE-0Z+"^J0:'(_%@=\.I[4F&>8O1@W.&ESDEW+PT>5G'B7W -MRVJ.@)NNG\Y]MWP%..FJ,X\[7&]6NO:LJY]F+.6D)#:<LIU>9&)/V_*_]I^V -M_4O$F4G*,Y.HYF$;XE?1D0I@HE-_4-)TM=4FL"[&K,GD/:C^,X3J_7I["-1O -MMS,?1I[1*,^HZ?5@U"VS5=N/`LI`5E6;/G1*.G;8JM:!5;USTHU74(\.NOV# -M/>B6`IZ5`O@$^MJYR)<`KD!=$OYKKO3?$,&>OU`K0.?5>_0ZQ=Q56KK>H,&- -MND"">*1E@XG`8.SIMN%U;4[HL`2@<C9NTRY0^`:;C"*BEZX?O7R][>@,T$P+ -MUSH<B8_/+7ET6'7,8BK0')/36II8773,?[:(C:/@`I.@[.L!DX`\6=88>'2; -M!\`4V)D=H(-H5-$LYEN@U$`($*!&VJF:OG!7@8?</0=U="9@`Z,V2GF&;]"J -M-E.`#$C`[[%1AEC5TJV1+0THJYY(VZ+7QZKTL9&T2Q\;==SEI\6P_1?(9F=. -M^O4<]":.P%Y;ET!O1,,$&DP7*!`\$LB2T+(J#@R:5F741BZK%[?4^ND$^)2$ -MM3H2YY@T.$E..WP@&?L6)F7>6M!Q#68-+A9/2VG[/+QOD[6FTD((4B\]I:_Q -M.ER/1_0=6>=2]:T#Q4:O]JLU.K.RM*JH:AW,O+G&2^D"S9TVHP8W;_22[#DQ -M_WE[&S8W>\F03N>\;V>R(OOR#]8I^_*&CI[Y%Z"!XN$%Z$)?Y;4\=*RVU71" -MO,(CS>Z"*??X1'?6P.'Q[D/KBT9H86_L'1[(0:G'%PV-EVFQ?[]YUFV/G1'Y -M]U38M=K;:_U\$DB[3J@-R8%:0OW:!S`&WX[HFZOJFP/NIF;>!G@^1_T#"2E[ -MR#;9WXDW_#)J`H[]4K;IM+4FJ^'Q5'144HG6T8KD)47*OEE[*MRNE!E/[)E` -MKP>'E]P^7BR>[&A[*:KO.57?7RT__5G'#^.N>W0\76V&%GRR33[3\4QRNLAT -M(E.?'#BW*-22''*DGTX'L:(<@3B#)`OQ#`MFH"TAVU9*]QH[XVF7&!VLQK'. -M5EEF1Z9>Y-#7_-WP)3;V2"P39C'^<P"HJ4X9_X@`>K/P)^AWM17Z<JTLLB]% -MV6>B#Y@<@177W=>H9*+\!W3B^D9>,C+#/_&H9,4RM!R^QW@3^2&FFDST'<#& -M3/HZ(N7V^)2N3^V#33M\RCXIUL@SSE9A!E9SO#&L.=X>GO:V\FO9;<[CX"BV -MO9,=H#_.T9_`C/_`15MQ(ZB.P96@-^AZ'XS_92/ZSJ)W1ZNR%R%__7"=5K9. -MI&KNU$E[KCG!RNQRNNFEOP;HFSCZ9LST#YPN(K?A)J20_MHNT;*$FVLRD6'> -MF-GR/%+&"4EX+#NH=4-R&VA@/_=9ELVAJ\&9O-AXO/$@CY\0UA="-]`W)4]Q -M1-,XY5*A3N"H?G:!8!K*NFJ:L1I;49_Z[EZTPK9L1LQ*%,F>NS=L[B>A>D+T -M3KV4+EQ:+VHL?Z<^L/&SQ@)J`[:R?IZQFD^`C?D$7_PA;OCTEY8-=F8[.A:C -MP;_Z&FRL&4#9L8`W]_*3,<WA2?X5U]X]_W+%-1E4>;4T6SKW/?2A1TH5."JO -MI3!E<&V7.%*+Z7\T?F;<@-D9)_*Y'3.VQ\5C?/Y4RK28=;4SD;[6\,)ZSRP# -M!L<WJ7HK#U9']7K#>JO\F`$Y_-=QPGG7X3?UD9:^H!47^:K>-7E73?WDP31] -MZRTP\.&]A:`T/-N,I1A8^*^>R[8-?[WRCR'U@)73MI:)+#H;]9X-?;W"G^I+ -M=AQ3L.C,/(3.#A;:PGM3)0B=[374^+]@>3Z\=UG==$.-MXMV['RR0H'.?O:^ -M71Y,[I.5RS?O0YO%TP-8V#-7WY!YTN4.<13-H9M">U^G5X_L?<VLX:U[O[Q: -MX),)?+BR=ZYW/5K22_<VGD2;W%G>U)]$V2&EKHHB<XE`7R%-F9&^Y_X.5XS_ -M*Y>7_':W(*HW6=F;3"'1CBA4I/X\Y%))_)M>]SA4`#-S;58Y+W5W]*Y!(2,* -MZYUFOBFHN%YZ[5Z,TC>,4<)ZI_S3=*2_LFUQ!&=E)8C'=+J1;@-@#NIN%O.L -M?7`B?8UXR;]UE6)G7D4?M\S\%Q^W//!//FX)G77KR:&/6[ZF>U:S'[?TF@SW -ML1^WV/3WL1^WV-#'+4\.3Y[)_VF+C?VXQ3XXAG;9!TN`?RP`"GN?67ET:8$\ -MK%="7W<&1_1*L%4\9>^3P$.;!]`^>U,ZQH3KBW#B-]S0/'1H/J^'ZL-79'/S -MSE0@7&=HO5768]R("7_U;V=^6CG"(Z/K<T([70CC8?W9LH(1C2=-!/KTPJMD -M-P,XC^0K[;?7>)5HWYZ;Q'D(/6;0-OOM=:Q,JWJE43T_@#T>T:L#,VG01IVH -MP_?ZG?4H?47:D+-^7PR1MO'()O.R]A=/)1\=9V"_:0O<S+K#>88KMZT;_^BO -M#R_BWN.O@WL&#OLI&,Y3!K#IC:9=W.-U0_N-F_TPZR,[L^>T+=!,;O(Y;._J -M_8T,^>OI>FBE=))XG)SZ[=H2\-E7#/OLR7_PV9/S_-</#'0R]Y2`^BU-0)'1 -M!$<P=GQ@X&1'\C0*ZLF:Q/\/\I7>\-3S0^`PZ,Y>Z#`T%+>0FZD/G!20JM$. -MD4JG#3ORKX,F0>OFP/SC_2F;[$PM(*&B#PS0.STJ,.33CU$TM@7X2/&38_6? -M"N@9PB36IW?ZR7CE6'CJ=T,^O1A]$_('GSY6&VD?S(!6D^[UZ=%'#,/VF&6\ -M64S!T+F%GF7ZFDI5S]OL9M=^@"UTO<.UJWP-_8.RYRT0<:H4`PF7^'!S*8<U -M55ZC3<!:*^_A.E#[['D*;/.P;)EM4KU-9K0%8YYX;'^\H^TO!ILBLN=]K#9^ -MZ><!XG*A:1<VLF?]G.H`<870<)`3T5,5V5.UM5RT%W^M/D#?APGWDF1%Q*ZM -MXE:!X6"N\6!>$N<+.[/6;)./["G"3L<O[0X058H,9[$Y=("H2F2ZR0&L"K7; -MF6\C>Z8<K+NSS6_JQ47#V_S@^&3[W*Y"7U[W+J;*EWJ8Z^QR^T`^1/YM_L'^ -M>[Y?/:&>]PPY/$SL?MC<IV=`/_<\D*VSJB464`6,52?9,%`W8-$%F5W<NNGU -M/M`&YA+0!E0>`YI@UN_3YLT80Z>E.TS)DO`>HTG'-28'9:N-.CX@78_:[?![ -M/NS^M[',H7,$T6KZF-DA\8\BBWFY+Y+B)%EHSQCQ@[)";9Y&_'?)1B,Y483. -MNFC)([@IEN-H>S.X!Z31M.TD/0,T)._Y\00Q>>F'=O(P?G2SZ?;M:'!H[O!L -MPCT\FY#GO^9HB-."9<C$MI9IK%K\\'4TD^`C"%\83Y*34[[>:V?VTZ[]9J_& -MJ_9HA<5HP67Y@>^2L0V\QW'22`;N$XC&R@,'2$?U*Q0TF#4I\!7\E7^$I[X< -M@-'LT4*_*F?C_NM^_89/0/&F$4-;.Y/_3.@_$R[1:;+6L+^V3`/P`WU<G48. -M<7BVG<D#*4H3#CE>]79F5[MD/\@4Q\Z8#%_^@HK$P7B*)\IRM<KNOAP-^`_W -M(_^A7%NF6;HUV.\]T&W[]1Z-1^W5HK4U\!E0N3-(WW7OQ$;QZ/7*[IWD0^"$ -MJ"*[MZ&E>Y_?]4?0:=CUSVLKI^_"L:#L8R!WGC;_>C'XP1H6EZ$HS*^\T[9G -M7,J,]^FBDRXJ5)J,V;YZ_K2Z(JR#SK>QZRZSF+]W5A_>T%Z]9Y-_[<52@X%Y -M#PJ::@F5GDYVK'^:M?!T-6O@&_-M8M:Z*[M;5=WI1K6H4!VT3VBIUQGKM711 -MT#Z2[A%5CL]]?3-3'B5R)KI52]"72::.!&7WVV'=M.`7D>`"41#ECJ32YPL' -M."O1L;?1I^J4W:];U:0GO&HD>)I5$0)&0-W(TN_G+448A-+?R%1VSW,415'I -ME5'=+R_,@D2[]897'RIS7'_>()>><.G5(;4>(;NA^5H9O,[+4XD+IZ8TUN^9 -M+Q:^)'XLD>>1"A_'/?\8WI:SSL%2GA[[)Q_@567WS*CNYY#^^Z,/$(GT^.D_ -M^0!YD6:YE&J:KU?S@YSD=G_S_$(;U3Q_V4_H.ZG([HDF@`>MLNVM^B8`!L*] -M(GUS)GN^\(_^P'MV)K\=$`/48!^<6?>XLMLH*9<)PQ0>55CW8O^@4:%B&#-5 -M]R+`2O;!HQ5A]">&T&#V7-ZBO#"#/-@^&$W7AW5'H:V'[LC\B#M;#R.'OEOM -M#AWZ;O4_;SVPWZU:CW.&MA[VL%L/M]L/MBF[A2.[B2%_L`&!>'3FHIM[]]MK -M<`GO?FD)OD&0_H08G%7VE`;Z#.@V](Q^/Z+K=TK#J[A&TQ[TH3N@TO"N']W7 -M_2<!3;H0_U%`^^!4M'!(9^2KHKK'N6554D?;?_B2]\PWS%<6JO0K!`M^?:B[ -M[:1_)Y'=1^RF3:WJDXM0@@(2J->Y<2ND52'=+L""[F_,G>H=!2>K#=O4V#5G -M52C:21R1DOA"CM(^^##=I.SJC.I6Y8:;U43@9Z*&?>B3U[[(KJ_=/9XS%;TT -M;=+Q[YD^H@:_,W^64#FH:E^",51!U\\:W&&4*RQRN?WV982IV'?PIB-AUN"M -MX3?'[_W;!;FCZ6H3P4G&<,,V#K:>A[6$"QHX2^NN^75RX#!6_#&RJW9DU\^' -MJIQUPBU<80ZGK,YX#'\G;41$U\;(KAL`S<2U0Z!,='84T-78$_09'A3TE.5; -M'*:776LQO.)2=O5'=9V/Z+J@ZG*'=:TU]Z5K*R(D/HZQB/T,<A]')'K*N!:' -M*IQI99[PKFYW69E[R+<B0KLZ([K>&]'UGL0LXW<1E:&D2=3@X_L(K]P<7K+] -M2V^(Z4N.@789Z2(!^JP?-]+%)GJ-8)^,W(='[Q>(:B.,A",I\.]EP=;756ND -M5;)O%@5WM>2$Y`8;JK&8B=VB6BI7FA0X,U<FVDKEA1I#><;F".14V;`W#H?D -M*0R):N/]:K*62@J<3A\C?./,?Z%V36F8V3#Z[0FG&Y84R@M"G2&[!NJ=[I#* -MT-2+U4-V#>U8HK$,[TJ"=I(X.>PJ]BSFUY%=,^F#^GJ\91M9@9/D4Z:/<!*- -ME:IK1E17.0P.0B'#7X?ZYRNBZ[&178^SAT[3]8WXFSL#X16:3'E72617J;*K -M5+R=8]Z=+G!S!(*GJ"]PD(OBK[2M]PW-)WV63@SMFM">H%<'*KK&L,<Z?IB' -MC@=G1W0YR0>!P8Q-/QJ:;IH?QI>O?VA7K:7I9T/SS95;`@Q-/T%D^1;CH2JP -M#O!$$1QB*XXYPX5.KJ'Y1WB)Q'QVNH#A6-D/!,5G1\7HGE^V+]3:]).^Z6?1 -M#E+B(8,\I%"O:"E+QGXD]I`"2I&2=IDN%I["A<*G]'_!V8[F4$9MX+)Z\-A> -M,6FC4KYV^'D_L%5@;LI:^!T0>PRD(++K08>K1=D55%GD=EG5Q-HU8G2\PZE& -M*P\E5C6_O-10RK>N)6+8LQ?F)G#=U>;F3/_ZHK_*C:V&IBRZ#+FMF-O0E.FH -M+J9_4791D5W42-^-,-\/E>L]U=GJM9N\'ZS=X'Z?78#"P;>FFC+10G:>FFK. -MM.H"8V+PY:?P@%FXX[,](WQ=_VP?!(8J9><Y^Z`;2%%V<=AQPN^,$PC,2-_O -M^H=Q-+.ST]'"U9RA>4<?:OM^-+&OS+/3D2J;,P3QAN8TPO>%WSN*]#4NWBG4 -M'L-Q/T\H?8.D'AS"L*[@W#3G*N$6CKXY??DJ;G9=:S%Z']$5!$(\)'7?(JG+ -M<6D[32`\99W^NHF0+DSNJXWH"J"=H5U<780TV+?Y5()AXB*L.JM,BKER/$K] -M;&Q!SE.2*EE`I1"_35AZ,"XCE`S(>`.$X?A\XW6*:"%%SK&Y/?4>N-7F"/:1 -MU'5]>8_Q^`+#B?FB(Z2@=JRS5RB<#'?"2;I[M]8:3BRH+P-@5Y8\O*ZB\/5# -M5T)\YX)]W<[$+:./%,QB3M*T(?ZF,?['BD1@,BK^)TO\SZ*=I&"`E`R0019% -M,@:FDOC,'^47)/@STS,B?4L.+30?PZ-\2V#HEZ]_F(K_V52#&;;Q#&-O+LL. -M,,3_!)'E6YZ$"*;A(29/"@\$)A_[(Z0CZW,C7>#A^+<8H`90GH`?EV^)'-I$ -MOI$.I;#GPP-KN<0]V>HNE2>T[FXY2#8A2`EIVD\8RXUT?(!SG+8,9_I/?T/& -MKZ>A_T_0HWB4D%H5:?V->2UC1:3O/=(BV^'+/9;3IO+]9?GZ!YSM>=6[:LO: -MEF5S<XZ7M2W?\FS.<2"DHQJ;$"[Q<,N.&4ZP?[Z@+UWHY`"K4<.:99A^G9]^ -M8Q^B_SAM>!C''@R7^+CB?1PCFY=`]!VGAR$[HJ_#IO!IZ32PT<#T>L3T/`^A -M+T9K2R[_VI*??I4O@C3*=GRBK\FBB,GLV8A,4TTF/<I!OQOI>U;ADV__%'7E -M$+-\_8/^G@"YR[)Y.<?A_K^D+X'(0:';8FQ\RH:%=5X1/"87.@DJ?4IGHB@- -M&]EYF7Q"MK567Y,A_)M(OS'#WR]_F;#.7B@#)>\I$-'934Z3;=MG:,@@GA<9 -M=F>P-I!>11ID$9VG1G:>V`9U96TU&NL2N!X!.@;A#']G%5];DX''BX;W)P*- -M!.90)X?ZJ$QI<&>+#ES83P3&[8/&!HMA^Z`H[.&Y:QZ=6_S4O**D9.PIM+OV -M(/)9#34&<UT103QIJG,9MMT0L-]EO77X05-=L;ENC?]QV6&+T8#M&:V;SGGC -M\2W`D*F?3PWQ2>W,/J@FYOX+=J8AAG#8F6UF@A!^.][.O+_H)5%`@<+Z("?F -M9I'EIFO13A'A5.@?Y!A*UE`EQ;PG\%F#(^S,EN'B;[+\H>R\%=[Y._ZX0K]1 -M-O3G,]+EN/`1B4>&SAV-#J>CP9YHPX5:+I[.479>XVIQ;9;<O^:NINOHQ"SI -MB,[\0_]1(E-TYB5CHWS5KZWG1W9FY;>)MY.=R2,[SX5W'E%UKB).4T&O@;J] -M;VMM!UK7/&YSV+).)!IM2/<;WDC/DRUK>26R<XGX[X3YN"[@>5S4AK57.ZPG -M#%H.D:/@U7(<#]68XCEDGH+7RB&/XLL:UR1CC[=+4JLD,2]P``"G5/U`)YZJ -M3MUT-;)S#EWGK^AT(EO/(0:;P:-[L8%PR0"W4F9G/H`R6"*/$(8A=[+.SBQ] -MK9$_LO-ON76BHR10%-'I577N)O=3D9V[=[16'+,S,>QX174FJCIG!'?6RSL; -MZ#:Z,1D3MTL,-Q.LMSB6R](W>E\R]F6MC`\'U_>UAO/@"`B(^EH_;%N>^YV= -M&6B7Z/LRQ9_("*/"\?EAPO#PX0UUM5[7+D_+MKK-[#W#7(KI*W@B`]KJVT)Z -M7=XB<REN+N4"3+4SI2,[XTV[T]#"Q^Y5P_CE87FG01_>1!'F\,ZXD9VNX,XB -MR!`=;T82!IQ8C8E$"2+W!"I&-:\&)#MK%C,CI#,CO#/1>/\%XGY.$@\S:E3$ -M/JJ]NCPQB=O;69V;2%>3^P1)W)Z0SN46#1[9^3IO`!<_2%EB</-S6!+W))MG -M/9OG.T7GF_0--M=BR7`N;T(2]VO(E$#7;-N7Q/W*`([A+K";[(>P>!*W#U@Z -MK',V_:VR\^6HSKFJSKD1G7-'=CZ4J=:58+H2GJY$()I)Z4K(@(#`;2_L>''G -M2YMGZI[=:GYVF^[F)?/-R[JS1O-9D_G@?-W!5^V,&8V#@;`9">XLY@EYYU\. -MK*<_I.]7=DZ)Z)QRP*5O#D4#DC5B%O,(/3VRH]MBOG7@NK4?I9K;E+K^$8ZV -M+P[4`$!G'O#?)C3MI.LIR%6LST*Y=*CL?<AZ$.L/?4B?;.JC!TWF6TV%%%NU -MM7E$5,<5"QLW-X\X<*(Q/;IY2*`,37)1+8?MO*%9WO@^_:&?'*H9[5@8A[-9 -MFN3HK]@TR]DJ4`9#\P@#43.+"0WKC*8_;CK:^*W!?,M"U%@VLLUL9'=JV+B1 -MC>LW2H])#M2P8R"T,V/0F,@[O@_N5$1V*L([0U2=(1&=(70"_>S(CO[0CDJ* -M$,0B;#"Z6_W&43Q02X[HZ.''45N7[GAG^QNU2ZRQ:=:U&=$9.=$3.3$9>;J, -MW+C8RKA8KRZV2GN+$]7!!'=RH8H%.:..7TN%\@P9UM$F9*BM/^_X9?NOM8RV -M-"TZ,Z-^=,SB/-WB7.WB'%UIE;6TTEKJK;?2ORH[?@SK^%S5<3.BHRF\XR8Y -MGQK9\0,I#MQ\LO;TUH[*.OT'&=:,G*B.JZJ.JW21/B.7_L``1.R.(@=(R^Y( -MRV[5R([O=W:3^TAEQ\7PCHNJCN]K3^_P41M;=#]B,=]LTWVS5?=-K7%COW'C -M.=W&\\,V1-G1R^JXX+".SU(+@Q<(1&B@O8.&FN#4G3P[<Z5=(N\X%=[QG+)C -M-YOQ0;I>L&<"M4$)3^DQ#O4BNFY$1UU4!ZWJH!4=;;2-?C:O.K*CN$(:T?'9 -M`OVTTW4?[@Y\%7_CU1!E1][;1WFY4M&KI&`/I7]R<).3*N5T5(=U9"UCT[>2 -MPKU4_=;MI4%N@<0CH$J]%/K31FG1I571CMP81UY8Q]KPCOM,WMNF)C$Z8A*A -M:/D:Z93`^GTH?L#.W``?N,GBO5U>`P:*7@4FJL[I?A](+;P"EP*T*I_O"A(^ -MM?*[\)$=:F&DPMQYP?R!SOQ!C/D#K?F#:-,NM.9JK;A@61]C_4!G_4!K^2!Z -M>*SD'6\J.S)9(MX:V;$XHN/-R(XWZ,28$Q14&].L1]?=!G3=:!R"5L4!P1T" -MH9.DQF*SF`V*CFPD.I.CHSJR>,\J2I#\6&_$J#I65Z&3W`57%!TO!+VHL(P- -MF,7,G,5(D-[M>+>QS@QL_AMC.?$`FIM1N.G$_4.*8PR>A'\S:_#`K$$OJNK) -M6S$_F6<-_GWHK$!PQ\(,6\SDIUN?BPZ?_OY?8AY].F-&XT.+[^<>LAZ3!#Q" -M%,?7/[)FQEULI.RP.]-BTI\^DOC>C+HE<Q:%!"V5[7$&9`F<R7$K&(`(L?-O -MO9QZ/3,QY26?LB,I)XVJD;2L@O33:C"BLRY]*>UXM@@KYJS!2[BR#ENZE/.] -MK4;&N3:*3N"=#<5P3-;Q9+HT^@D,;&:Q5-:AHC7%4M[941G<U6!+5Z'O3CG1 -MZ&\B2CNFW*TG:KB>Z_?4\T"Z-/AT!UO/O16TVSBCV?)CBK!5G!3IXZOP%.F4 -M5=ROHX9K(X=KNW%/;7&HMDM_K(V6%G&+\")4ZS<VSB.02^,">_.SM$-]ES95 -MNA0Z<MJW6CK4I9'R#EFQ]&[-,E3SB?]$Y[<V#OI[H>F*U2$9H9DC-!&+.`IL -MZ*^`EH2N'8%?L"7#^V*EO(//K;?A_:'1H9@VE`,9Y1T\#HYQ=3A/)YPO#2*Y -M-G$@%GF:*516@*:T!6&VBC"28ZL,KQ@IOD7DT1S5_U/9\<<T<87?O7=7M+WV -M6J"-Y>?UKMM0?O0=12M$+5!TD&WJ$/`/3:C6JJ1*45C4N>D$=<,)(J`3E<TL -MF5F6F=B8+?MO11)UD2QE+L:[L"AJ2)R)`;=LR>+2O6NA_AC@UC^:][[W_7SW -MW?O>NUZ_#UX;X,*@P]J9=BQ=#R4#D#A*ZDQF+<"`I$QEW*A,Z(FRD;DQ/VA] -MNVTU')-::P[6J7)"4EOMH;4`S98W,I@CI2NC:<HHFV=BOV+G?YXQY,X]GV$_ -MGZGK9\.\OKN8W%/B<X#$^RPC9#^J\.NBC^)YP#3!?'>&$DE7KAL6F'2YVNM% -MK1??*[;T7&0=;/B.5;F>J0QQ=Q=?N-`7(3P3X"N9RI5)<)PS.T@.XX.$?SO_ -M4>ZEOCY^3[NN??Z1!==Z3_,7SYR9?]1^]?:UP7X[8:)F!`4_3-H"X5VLZ@'A -MO=@S()BJA)(LH*WT<!E<"$^4:FHIYKZ4%$L0JOY+.IZ_4_GR*0ZL1=.AJ7AH -M#%\MA="#*BA8`>DQ"4$/08C)28PQ'N85-H[!%)4\@S2I7XQG;"\/;_"I2CN1 -MW%IVJ+2G##TC<YA+ED=3%&T/'S913].;@G$)3$C@L21HSQ$#3<K>%&4O&I-2 -ME;UD7,U*JNS1JEE);V*3/$P_PG8+\D6?4#X"2E;\<4_L,7:;5#]4-C[KAUG* -M%NXN9N_CCE$V2A&O[$_9-+[G;'+W/.&O*!NEL^5;($QSG)43$'>/N)WWZR'] -MD*[C\K$[_:/Z*,7=5U7D-$`/,0=POU5/X<_2^M,[PK>-G0-<Y$7_S5+>X"R@ -MX\[1%%7L+Q1AX1]/:YUW=C0O&9)SJ5%9DJD4LTB:<FU]E,Y2/!=&#$.ZSD$8 -MI0Q1*DLI\4<W9LLA$*$YO?78H/Z>Q`E0+Q"C_;`2AP3`TZ@*(V@E&_\M^'N$ -MZLFM#)$&.BGDIH%$0VB%51+!%?*RD<BBV$3#*KR)?W>_8\X^A_5]1XD7'!'/ -MCO?B$]+)PD^<T))*S2&!=40<2<#$];^W87')G5.X3SI=>,8)%Z1"%><[@ID_ -M,MX5.3[<_5//#3&#H.6/&,4ED2G*4T5]"Q<LTN0N2N+FT'!9*E+)#A`RHA(Y -M2(9MY*A"%%2O/A_APK8(QPDF(8]"E;C)H1.71$FWZ;4_$/(08X!H0L(\"%<1 -M"H3P93YA45B(3/J?1?Z-&<,_`TTU%1+BSK@F^DVDE'G&+\WR!7(4PE\X:;=: -M;XH53#3MH07H=S\4M<BNG0,9#SEK(,:ZOUX'RU,O5OA7/8R]DV8;YLSRIV&U -M9-=TU&%GN')ZVKAM,=F=,\E6>7\X(^](_%XVR_LFZ5W3T>^:HO_7:(*^<29Z -M49OV4MOK9^0_4#*[[9.YA,WR2HO\<:+LF.VY_,?_I0:965Y&-)BI`EEL&4I\ -MS++3(N_X?S7.S/*KL_"?O(:9*L^9%3#+YEEY/,WW3'AI+7)50L7L:>;C!G># -M>U[;L82V+]A[ZT^+[$HP2WXYO6J/)D7.[3&V&@4!;.7-!XWV<J`K!8>-9#=U -MTGC(>&AUP^H'L5@8$Q;+%6[+R`%J+NXG@$1@3"-\J1"&I)`3P3+H9,5"$D[5 -M9Q%H<`V-),H,`XL]@2(^4&@(2`R@R+2TV-8W>4%CP,G8JFDO\-NJ&2^H#RS2 -M!Q82B,8+UAQ8ZP4K`RY&LX&@+T_:0;[=@9*L0+%^OYL>_L`+I+G'"2Q7[9WS -M`E$7(KW,?6[#?C?##I"V2:^^1J,C7<,H:4!N`E+(\^-287V37=O$I+`MS@*4 -MUT7G=Z&,7CJS%Q5TT8XNE-5+9_>VUK35'JR+[2L`#9")]46OJM>CEA6K>7NU -MK:>FMU:L%NS58D]=[UI?]-MX[/LU'IN'[&A<\@)#4�!&DP09%!CR4PM?X, -MV>$X)I&=C,.)6$.DX6,\M>>`@G:R)F".JS3'59'CJLQQO1FO[Q>/_?'??V!C -M8?%-G@G2M)MN66=G*EA0ILZZ0&BK],T^&FUF0P)90%%*:K,/DE55E=#LH\(V -M(O-:0IZ:<WS=`^TPIP6>K?YMS0U!?L5:OF)Y>>WK2S&?4_Y.P[86?L7.!OZM -M#7MXOHB77"6XN,2YB%]=4<,78NSB@XW\9O^VAMT%&YH;?)O\S0U;&OT[FPM\ -MP>TECJW