diff options
author | kmacy <kmacy@FreeBSD.org> | 2007-06-13 05:36:00 +0000 |
---|---|---|
committer | kmacy <kmacy@FreeBSD.org> | 2007-06-13 05:36:00 +0000 |
commit | ca1df96c1a9664f95b9ecb36fac419db0b745b4c (patch) | |
tree | 35a64009a2837c5c69bdb3309b0435cdd0fe3a46 /sys/dev/cxgb/common | |
parent | eb05a4b69fd72f248ee8d73dfb09a1e7dd6af8a3 (diff) | |
download | FreeBSD-src-ca1df96c1a9664f95b9ecb36fac419db0b745b4c.zip FreeBSD-src-ca1df96c1a9664f95b9ecb36fac419db0b745b4c.tar.gz |
- import new common code for the T304
- update to firmware version 4.1.0
- switch over to standard method for initializing cdevs (contributed by scottl@)
- break out timer_reclaim_task to be per-port
- move msix teardown into separate function
- fix bus_setup_intr for msi-x for the multi-port case so that msi-x resources
are not corrupted on unload
- handle 10/100/1000 base-T media and auto negotiation
- bind qset to cpu even for singleq case
- white space cleanups
- remove recursive PORT_LOCK
- move mtu setting to separate function
- stop and re-init port when changing mtu
- replace all direct references to m_data with calls to mtod
- handle attach failure better by not trying to de-initialize
taskqueues when they have not been allocated
- no longer default to jumbo frames
Sponsored by: Chelsio
MFC after: 3 days
Diffstat (limited to 'sys/dev/cxgb/common')
-rw-r--r-- | sys/dev/cxgb/common/cxgb_ael1002.c | 10 | ||||
-rw-r--r-- | sys/dev/cxgb/common/cxgb_common.h | 71 | ||||
-rw-r--r-- | sys/dev/cxgb/common/cxgb_mc5.c | 10 | ||||
-rw-r--r-- | sys/dev/cxgb/common/cxgb_t3_hw.c | 304 | ||||
-rw-r--r-- | sys/dev/cxgb/common/cxgb_vsc7323.c | 340 | ||||
-rw-r--r-- | sys/dev/cxgb/common/cxgb_xgmac.c | 117 |
6 files changed, 744 insertions, 108 deletions
diff --git a/sys/dev/cxgb/common/cxgb_ael1002.c b/sys/dev/cxgb/common/cxgb_ael1002.c index 3d67b06..c570ed3 100644 --- a/sys/dev/cxgb/common/cxgb_ael1002.c +++ b/sys/dev/cxgb/common/cxgb_ael1002.c @@ -277,7 +277,13 @@ static int xaui_direct_get_link_status(struct cphy *phy, int *link_ok, unsigned int status; status = t3_read_reg(phy->adapter, - XGM_REG(A_XGM_SERDES_STAT0, phy->addr)); + XGM_REG(A_XGM_SERDES_STAT0, phy->addr)) | + t3_read_reg(phy->adapter, + XGM_REG(A_XGM_SERDES_STAT1, phy->addr)) | + t3_read_reg(phy->adapter, + XGM_REG(A_XGM_SERDES_STAT2, phy->addr)) | + t3_read_reg(phy->adapter, + XGM_REG(A_XGM_SERDES_STAT3, phy->addr)); *link_ok = !(status & F_LOWSIG0); } if (speed) @@ -323,5 +329,5 @@ static struct cphy_ops xaui_direct_ops = { void t3_xaui_direct_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr, const struct mdio_ops *mdio_ops) { - cphy_init(phy, adapter, 1, &xaui_direct_ops, mdio_ops); + cphy_init(phy, adapter, phy_addr, &xaui_direct_ops, mdio_ops); } diff --git a/sys/dev/cxgb/common/cxgb_common.h b/sys/dev/cxgb/common/cxgb_common.h index 1a04772..0a60a56 100644 --- a/sys/dev/cxgb/common/cxgb_common.h +++ b/sys/dev/cxgb/common/cxgb_common.h @@ -38,18 +38,19 @@ $FreeBSD$ #endif enum { - MAX_NPORTS = 2, /* max # of ports */ - MAX_FRAME_SIZE = 10240, /* max MAC frame size, including header + FCS */ + 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 */ TCB_SIZE = 128, /* TCB size */ NMTUS = 16, /* size of MTU table */ NCCTRL_WIN = 32, /* # of congestion control windows */ NTX_SCHED = 8, /* # of HW Tx scheduling queues */ - TP_TMR_RES = 200, /* TP timer resolution in usec */ + PROTO_SRAM_LINES = 128, /* size of protocol sram */ }; -#define MAX_RX_COALESCING_LEN 16224U +#define MAX_RX_COALESCING_LEN 12288U enum { PAUSE_RX = 1 << 0, @@ -58,7 +59,7 @@ enum { }; enum { - SUPPORTED_IRQ = 1 << 25 + SUPPORTED_IRQ = 1 << 24 }; enum { /* adapter interrupt-maintained statistics */ @@ -70,8 +71,32 @@ enum { /* adapter interrupt-maintained statistics */ }; enum { + TP_VERSION_MAJOR = 1, + TP_VERSION_MINOR = 0, + TP_VERSION_MICRO = 44 +}; + +#define S_TP_VERSION_MAJOR 16 +#define M_TP_VERSION_MAJOR 0xFF +#define V_TP_VERSION_MAJOR(x) ((x) << S_TP_VERSION_MAJOR) +#define G_TP_VERSION_MAJOR(x) \ + (((x) >> S_TP_VERSION_MAJOR) & M_TP_VERSION_MAJOR) + +#define S_TP_VERSION_MINOR 8 +#define M_TP_VERSION_MINOR 0xFF +#define V_TP_VERSION_MINOR(x) ((x) << S_TP_VERSION_MINOR) +#define G_TP_VERSION_MINOR(x) \ + (((x) >> S_TP_VERSION_MINOR) & M_TP_VERSION_MINOR) + +#define S_TP_VERSION_MICRO 0 +#define M_TP_VERSION_MICRO 0xFF +#define V_TP_VERSION_MICRO(x) ((x) << S_TP_VERSION_MICRO) +#define G_TP_VERSION_MICRO(x) \ + (((x) >> S_TP_VERSION_MICRO) & M_TP_VERSION_MICRO) + +enum { FW_VERSION_MAJOR = 4, - FW_VERSION_MINOR = 0, + FW_VERSION_MINOR = 1, FW_VERSION_MICRO = 0 }; @@ -116,10 +141,11 @@ struct mdio_ops { }; struct adapter_info { - unsigned char nports; /* # of ports */ + unsigned char nports0; /* # of ports on channel 0 */ + unsigned char nports1; /* # of ports on channel 1 */ unsigned char phy_base_addr; /* MDIO PHY base address */ - unsigned char mdien; - unsigned char mdiinv; + unsigned char mdien:1; + unsigned char mdiinv:1; unsigned int gpio_out; /* GPIO output settings */ unsigned int gpio_intr; /* GPIO IRQ enable mask */ unsigned long caps; /* adapter capabilities */ @@ -271,11 +297,13 @@ struct tp_params { unsigned int rx_num_pgs; /* # of Rx pages */ unsigned int tx_num_pgs; /* # of Tx pages */ unsigned int ntimer_qs; /* # of timer queues */ + unsigned int tre; /* log2 of core clocks per TP tick */ unsigned int dack_re; /* DACK timer resolution */ }; struct qset_params { /* SGE queue set parameters */ unsigned int polling; /* polling/interrupt service for rspq */ + unsigned int lro; /* large receive offload */ unsigned int coalesce_nsecs; /* irq coalescing timer */ unsigned int rspq_size; /* # of entries in response queue */ unsigned int fl_size; /* # of entries in regular free list */ @@ -354,6 +382,7 @@ struct adapter_params { unsigned short b_wnd[NCCTRL_WIN]; #endif unsigned int nports; /* # of ethernet ports */ + unsigned int chan_map; /* bitmap of in-use Tx channels */ unsigned int stats_update_period; /* MAC stats accumulation period */ unsigned int linkpoll_period; /* link poll period in 0.1s */ unsigned int rev; /* chip revision */ @@ -430,7 +459,10 @@ static inline unsigned int t3_mc7_size(const struct mc7 *p) struct cmac { adapter_t *adapter; unsigned int offset; - unsigned int nucast; /* # of address filters for unicast MACs */ + unsigned char nucast; /* # of address filters for unicast MACs */ + unsigned char multiport; /* multiple ports connected to this MAC */ + unsigned char ext_port; /* external MAC port */ + unsigned char promisc_map; /* which external ports are promiscuous */ unsigned int tx_tcnt; unsigned int tx_xcnt; u64 tx_mcnt; @@ -589,9 +621,6 @@ static inline unsigned int is_pcie(const adapter_t *adap) } void t3_set_reg_field(adapter_t *adap, unsigned int addr, u32 mask, u32 val); -void t3_read_indirect(adapter_t *adap, unsigned int addr_reg, - unsigned int data_reg, u32 *vals, unsigned int nregs, - unsigned int start_idx); void t3_write_regs(adapter_t *adapter, const struct addr_val_pair *p, int n, unsigned int offset); int t3_wait_op_done_val(adapter_t *adapter, int reg, u32 mask, int polarity, @@ -627,13 +656,14 @@ 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_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_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); void mac_prep(struct cmac *mac, adapter_t *adapter, int index); void early_hw_init(adapter_t *adapter, const struct adapter_info *ai); -int t3_reset_adapter(adapter_t *adapter); 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); @@ -641,6 +671,7 @@ void t3_set_vlan_accel(adapter_t *adapter, unsigned int ports, int on); 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_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); @@ -657,7 +688,7 @@ int t3_mac_disable(struct cmac *mac, int which); int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu); int t3_mac_set_rx_mode(struct cmac *mac, struct t3_rx_mode *rm); int t3_mac_set_address(struct cmac *mac, unsigned int idx, u8 addr[6]); -int t3_mac_set_num_ucast(struct cmac *mac, int n); +int t3_mac_set_num_ucast(struct cmac *mac, unsigned char n); const struct mac_stats *t3_mac_update_stats(struct cmac *mac); int t3_mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex, int fc); @@ -718,6 +749,16 @@ int t3_sge_read_rspq(adapter_t *adapter, unsigned int id, u32 data[4]); int t3_sge_cqcntxt_op(adapter_t *adapter, unsigned int id, unsigned int op, unsigned int credits); +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_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); + void t3_mv88e1xxx_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr, const struct mdio_ops *mdio_ops); void t3_vsc8211_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr, diff --git a/sys/dev/cxgb/common/cxgb_mc5.c b/sys/dev/cxgb/common/cxgb_mc5.c index 9d3b94f..07a4d39 100644 --- a/sys/dev/cxgb/common/cxgb_mc5.c +++ b/sys/dev/cxgb/common/cxgb_mc5.c @@ -31,9 +31,11 @@ POSSIBILITY OF SUCH DAMAGE. __FBSDID("$FreeBSD$"); #ifdef CONFIG_DEFINED -#include <cxgb_include.h> +#include <common/cxgb_common.h> +#include <common/cxgb_regs.h> #else -#include <dev/cxgb/cxgb_include.h> +#include <dev/cxgb/common/cxgb_common.h> +#include <dev/cxgb/common/cxgb_regs.h> #endif enum { @@ -328,9 +330,9 @@ int t3_mc5_init(struct mc5 *mc5, unsigned int nservers, unsigned int nfilters, unsigned int tcam_size = mc5->tcam_size; adapter_t *adap = mc5->adapter; - if (tcam_size == 0) + if (!tcam_size) return 0; - + if (nroutes > MAX_ROUTES || nroutes + nservers + nfilters > tcam_size) return -EINVAL; diff --git a/sys/dev/cxgb/common/cxgb_t3_hw.c b/sys/dev/cxgb/common/cxgb_t3_hw.c index ac4a630..2e92187 100644 --- a/sys/dev/cxgb/common/cxgb_t3_hw.c +++ b/sys/dev/cxgb/common/cxgb_t3_hw.c @@ -30,12 +30,17 @@ POSSIBILITY OF SUCH DAMAGE. #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); + #ifdef CONFIG_DEFINED #include <cxgb_include.h> #else #include <dev/cxgb/cxgb_include.h> #endif +#define DENTER() printf("entered %s\n", __FUNCTION__); +#define DEXIT() printf("exiting %s\n", __FUNCTION__); + + /** * t3_wait_op_done_val - wait until an operation is completed * @adapter: the adapter performing the operation @@ -119,7 +124,7 @@ void t3_set_reg_field(adapter_t *adapter, unsigned int addr, u32 mask, u32 val) * Reads registers that are accessed indirectly through an address/data * register pair. */ -void t3_read_indirect(adapter_t *adap, unsigned int addr_reg, +static void t3_read_indirect(adapter_t *adap, unsigned int addr_reg, unsigned int data_reg, u32 *vals, unsigned int nregs, unsigned int start_idx) { @@ -202,7 +207,7 @@ static void mi1_init(adapter_t *adap, const struct adapter_info *ai) t3_write_reg(adap, A_MI1_CFG, val); } -#define MDIO_ATTEMPTS 10 +#define MDIO_ATTEMPTS 20 /* * MI1 read/write operations for direct-addressed PHYs. @@ -219,7 +224,7 @@ static int mi1_read(adapter_t *adapter, int phy_addr, int mmd_addr, MDIO_LOCK(adapter); t3_write_reg(adapter, A_MI1_ADDR, addr); t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(2)); - ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 20); + ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 10); if (!ret) *valp = t3_read_reg(adapter, A_MI1_DATA); MDIO_UNLOCK(adapter); @@ -239,7 +244,7 @@ static int mi1_write(adapter_t *adapter, int phy_addr, int mmd_addr, t3_write_reg(adapter, A_MI1_ADDR, addr); t3_write_reg(adapter, A_MI1_DATA, val); t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(1)); - ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 20); + ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 10); MDIO_UNLOCK(adapter); return ret; } @@ -262,11 +267,11 @@ static int mi1_ext_read(adapter_t *adapter, int phy_addr, int mmd_addr, t3_write_reg(adapter, A_MI1_ADDR, addr); t3_write_reg(adapter, A_MI1_DATA, reg_addr); t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(0)); - ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 20); + ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 10); if (!ret) { t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(3)); ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, - MDIO_ATTEMPTS, 20); + MDIO_ATTEMPTS, 10); if (!ret) *valp = t3_read_reg(adapter, A_MI1_DATA); } @@ -284,12 +289,12 @@ static int mi1_ext_write(adapter_t *adapter, int phy_addr, int mmd_addr, t3_write_reg(adapter, A_MI1_ADDR, addr); t3_write_reg(adapter, A_MI1_DATA, reg_addr); t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(0)); - ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 20); + ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 10); if (!ret) { t3_write_reg(adapter, A_MI1_DATA, val); t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(1)); ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, - MDIO_ATTEMPTS, 20); + MDIO_ATTEMPTS, 10); } MDIO_UNLOCK(adapter); return ret; @@ -435,27 +440,32 @@ int t3_set_phy_speed_duplex(struct cphy *phy, int speed, int duplex) } static struct adapter_info t3_adap_info[] = { - { 2, 0, 0, 0, + { 1, 1, 0, 0, 0, F_GPIO2_OEN | F_GPIO4_OEN | F_GPIO2_OUT_VAL | F_GPIO4_OUT_VAL, F_GPIO3 | F_GPIO5, 0, &mi1_mdio_ops, "Chelsio PE9000" }, - { 2, 0, 0, 0, + { 1, 1, 0, 0, 0, F_GPIO2_OEN | F_GPIO4_OEN | F_GPIO2_OUT_VAL | F_GPIO4_OUT_VAL, F_GPIO3 | F_GPIO5, 0, &mi1_mdio_ops, "Chelsio T302" }, - { 1, 0, 0, 0, + { 1, 0, 0, 0, 0, F_GPIO1_OEN | F_GPIO6_OEN | F_GPIO7_OEN | F_GPIO10_OEN | F_GPIO1_OUT_VAL | F_GPIO6_OUT_VAL | F_GPIO10_OUT_VAL, 0, SUPPORTED_10000baseT_Full | SUPPORTED_AUI, &mi1_mdio_ext_ops, "Chelsio T310" }, - { 2, 0, 0, 0, + { 1, 1, 0, 0, 0, F_GPIO1_OEN | F_GPIO2_OEN | F_GPIO4_OEN | F_GPIO5_OEN | F_GPIO6_OEN | F_GPIO7_OEN | F_GPIO10_OEN | F_GPIO11_OEN | F_GPIO1_OUT_VAL | F_GPIO5_OUT_VAL | F_GPIO6_OUT_VAL | F_GPIO10_OUT_VAL, 0, SUPPORTED_10000baseT_Full | SUPPORTED_AUI, &mi1_mdio_ext_ops, "Chelsio T320" }, + { 4, 0, 0, 0, 0, + F_GPIO5_OEN | F_GPIO6_OEN | F_GPIO7_OEN | F_GPIO5_OUT_VAL | + F_GPIO6_OUT_VAL | F_GPIO7_OUT_VAL, + F_GPIO1 | F_GPIO2 | F_GPIO3 | F_GPIO4, SUPPORTED_AUI, + &mi1_mdio_ops, "Chelsio T304" }, }; /* @@ -472,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 }, + { NULL, 0, NULL }, { t3_ael1002_phy_prep, CAPS_10G | SUPPORTED_FIBRE, "10GBASE-XR" }, { t3_vsc8211_phy_prep, CAPS_1G | SUPPORTED_TP | SUPPORTED_IRQ, @@ -656,6 +666,8 @@ static int get_vpd_params(adapter_t *adapter, struct vpd_params *p) } else { p->port_type[0] = (u8)hex2int(vpd.port0_data[0]); 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(vpd.xaui0cfg_data, NULL, 16); p->xauicfg[1] = simple_strtoul(vpd.xaui1cfg_data, NULL, 16); } @@ -847,6 +859,64 @@ static int t3_write_flash(adapter_t *adapter, unsigned int addr, 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) +{ + int ret; + u32 vers; + unsigned int major, minor; + + /* 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); + + major = G_TP_VERSION_MAJOR(vers); + minor = G_TP_VERSION_MINOR(vers); + + if (major == TP_VERSION_MAJOR && minor == TP_VERSION_MINOR) + return 0; + + return -EINVAL; +} + +/** + * t3_check_tpsram - check if provided protocol SRAM + * is compatible with this driver + * @adapter: the adapter + * @tp_sram: the firmware image to write + * @size: image size + * + * 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) +{ + u32 csum; + unsigned int i; + const u32 *p = (const u32 *)tp_sram; + + /* Verify checksum */ + for (csum = 0, i = 0; i < size / sizeof(csum); i++) + csum += ntohl(p[i]); + if (csum != 0xffffffff) { + CH_ERR(adapter, "corrupted protocol SRAM image, checksum %u\n", + csum); + return -EINVAL; + } + + return 0; +} + enum fw_version_type { FW_VERSION_N3, FW_VERSION_T3 @@ -889,9 +959,9 @@ int t3_check_fw_version(adapter_t *adapter) minor == FW_VERSION_MINOR) 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); + CH_ERR(adapter, "found wrong FW version (%u.%u), " + "driver needs version %d.%d\n", major, minor, + FW_VERSION_MAJOR, FW_VERSION_MINOR); return -EINVAL; } @@ -921,7 +991,7 @@ static int t3_flash_erase_sectors(adapter_t *adapter, int start, int end) /* * t3_load_fw - download firmware * @adapter: the adapter - * @fw_data: the firrware image to write + * @fw_data: the firmware image to write * @size: image size * * Write the supplied firmware image to the card's serial flash. @@ -936,7 +1006,7 @@ int t3_load_fw(adapter_t *adapter, const u8 *fw_data, unsigned int size) const u32 *p = (const u32 *)fw_data; int ret, addr, fw_sector = FW_FLASH_BOOT_ADDR >> 16; - if ((size & 3) || (size < FW_MIN_SIZE)) + if ((size & 3) || size < FW_MIN_SIZE) return -EINVAL; if (size > FW_VERS_ADDR + 8 - FW_FLASH_BOOT_ADDR) return -EFBIG; @@ -1015,9 +1085,10 @@ int t3_cim_ctl_blk_read(adapter_t *adap, unsigned int addr, unsigned int n, void t3_link_changed(adapter_t *adapter, int port_id) { int link_ok, speed, duplex, fc; - struct cphy *phy = &adapter->port[port_id].phy; - struct cmac *mac = &adapter->port[port_id].mac; - struct link_config *lc = &adapter->port[port_id].link_config; + struct port_info *pi = adap2pinfo(adapter, port_id); + struct cphy *phy = &pi->phy; + struct cmac *mac = &pi->mac; + struct link_config *lc = &pi->link_config; phy->ops->get_link_status(phy, &link_ok, &speed, &duplex, &fc); @@ -1487,8 +1558,12 @@ static void mc7_intr_handler(struct mc7 *mc7) */ static int mac_intr_handler(adapter_t *adap, unsigned int idx) { - struct cmac *mac = &adap->port[idx].mac; - u32 cause = t3_read_reg(adap, A_XGM_INT_CAUSE + mac->offset); + u32 cause; + struct cmac *mac; + + idx = idx == 0 ? 0 : adapter_info(adap)->nports0; /* MAC idx -> port */ + mac = &adap2pinfo(adap, idx)->mac; + cause = t3_read_reg(adap, A_XGM_INT_CAUSE + mac->offset); if (cause & V_TXFIFO_PRTY_ERR(M_TXFIFO_PRTY_ERR)) { mac->stats.tx_fifo_parity_err++; @@ -1524,7 +1599,7 @@ int t3_phy_intr_handler(adapter_t *adapter) u32 i, cause = t3_read_reg(adapter, A_T3DBG_INT_CAUSE); for_each_port(adapter, i) { - struct port_info *p = &adapter->port[i]; + struct port_info *p = adap2pinfo(adapter, i); mask = gpi - (gpi & (gpi - 1)); gpi -= mask; @@ -1556,7 +1631,6 @@ int t3_slow_intr_handler(adapter_t *adapter) cause &= adapter->slow_intr_mask; if (!cause) return 0; - if (cause & F_PCIM0) { if (is_pcie(adapter)) pcie_intr_handler(adapter); @@ -1647,11 +1721,10 @@ void t3_intr_enable(adapter_t *adapter) adapter_info(adapter)->gpio_intr); t3_write_reg(adapter, A_T3DBG_INT_ENABLE, adapter_info(adapter)->gpio_intr); - if (is_pcie(adapter)) { + if (is_pcie(adapter)) t3_write_reg(adapter, A_PCIE_INT_ENABLE, PCIE_INTR_MASK); - } else { + else t3_write_reg(adapter, A_PCIX_INT_ENABLE, PCIX_INTR_MASK); - } t3_write_reg(adapter, A_PL_INT_ENABLE0, adapter->slow_intr_mask); (void) t3_read_reg(adapter, A_PL_INT_ENABLE0); /* flush */ } @@ -1719,8 +1792,10 @@ void t3_intr_clear(adapter_t *adapter) */ void t3_port_intr_enable(adapter_t *adapter, int idx) { - t3_write_reg(adapter, XGM_REG(A_XGM_INT_ENABLE, idx), XGM_INTR_MASK); - adapter->port[idx].phy.ops->intr_enable(&adapter->port[idx].phy); + struct port_info *pi = adap2pinfo(adapter, idx); + + t3_write_reg(adapter, A_XGM_INT_ENABLE + pi->mac.offset, XGM_INTR_MASK); + pi->phy.ops->intr_enable(&pi->phy); } /** @@ -1733,8 +1808,10 @@ void t3_port_intr_enable(adapter_t *adapter, int idx) */ void t3_port_intr_disable(adapter_t *adapter, int idx) { - t3_write_reg(adapter, XGM_REG(A_XGM_INT_ENABLE, idx), 0); - adapter->port[idx].phy.ops->intr_disable(&adapter->port[idx].phy); + struct port_info *pi = adap2pinfo(adapter, idx); + + t3_write_reg(adapter, A_XGM_INT_ENABLE + pi->mac.offset, 0); + pi->phy.ops->intr_disable(&pi->phy); } /** @@ -1747,10 +1824,11 @@ void t3_port_intr_disable(adapter_t *adapter, int idx) */ void t3_port_intr_clear(adapter_t *adapter, int idx) { - t3_write_reg(adapter, XGM_REG(A_XGM_INT_CAUSE, idx), 0xffffffff); - adapter->port[idx].phy.ops->intr_clear(&adapter->port[idx].phy); -} + struct port_info *pi = adap2pinfo(adapter, idx); + t3_write_reg(adapter, A_XGM_INT_CAUSE + pi->mac.offset, 0xffffffff); + pi->phy.ops->intr_clear(&pi->phy); +} /** * t3_sge_write_context - write an SGE context @@ -2344,6 +2422,14 @@ 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 | @@ -2360,14 +2446,16 @@ static void tp_config(adapter_t *adap, const struct tp_params *p) F_IPV6ENABLE | F_NICMODE); t3_write_reg(adap, A_TP_TX_RESOURCE_LIMIT, 0x18141814); t3_write_reg(adap, A_TP_PARA_REG4, 0x5050105); - t3_set_reg_field(adap, A_TP_PARA_REG6, - adap->params.rev > 0 ? F_ENABLEESND : F_T3A_ENABLEESND, - 0); + t3_set_reg_field(adap, A_TP_PARA_REG6, 0, + adap->params.rev > 0 ? F_ENABLEESND : + F_T3A_ENABLEESND); t3_set_reg_field(adap, A_TP_PC_CONFIG, - F_ENABLEEPCMDAFULL | F_ENABLEOCSPIFULL, - F_TXDEFERENABLE | F_HEARBEATDACK | F_TXCONGESTIONMODE | - F_RXCONGESTIONMODE); + F_ENABLEEPCMDAFULL, + F_ENABLEOCSPIFULL |F_TXDEFERENABLE | F_HEARBEATDACK | + F_TXCONGESTIONMODE | F_RXCONGESTIONMODE); t3_set_reg_field(adap, A_TP_PC_CONFIG2, F_CHDRAFULL, 0); + t3_write_reg(adap, A_TP_PROXY_FLOW_CNTL, 1080); + t3_write_reg(adap, A_TP_PROXY_FLOW_CNTL, 1000); if (adap->params.rev > 0) { tp_wr_indirect(adap, A_TP_EGRESS_CONFIG, F_REWRITEFORCETOSIZE); @@ -2381,7 +2469,21 @@ static void tp_config(adapter_t *adap, const struct tp_params *p) t3_write_reg(adap, A_TP_TX_MOD_QUEUE_WEIGHT1, 0); t3_write_reg(adap, A_TP_TX_MOD_QUEUE_WEIGHT0, 0); t3_write_reg(adap, A_TP_MOD_CHANNEL_WEIGHT, 0); - t3_write_reg(adap, A_TP_MOD_RATE_LIMIT, 0); + t3_write_reg(adap, A_TP_MOD_RATE_LIMIT, 0xf2200000); + + if (adap->params.nports > 2) { + t3_set_reg_field(adap, A_TP_PC_CONFIG2, 0, + F_ENABLETXPORTFROMDA | F_ENABLERXPORTFROMADDR); + tp_wr_bits_indirect(adap, A_TP_QOS_RX_MAP_MODE, + V_RXMAPMODE(M_RXMAPMODE), 0); + tp_wr_indirect(adap, A_TP_INGRESS_CONFIG, V_BITPOS0(48) | + V_BITPOS1(49) | V_BITPOS2(50) | V_BITPOS3(51) | + F_ENABLEEXTRACT | F_ENABLEEXTRACTIONSFD | + F_ENABLEINSERTION | F_ENABLEINSERTIONSFD); + tp_wr_indirect(adap, A_TP_PREAMBLE_MSB, 0xfb000000); + tp_wr_indirect(adap, A_TP_PREAMBLE_LSB, 0xd5); + tp_wr_indirect(adap, A_TP_INTF_FROM_TX_PKT, F_INTFFROMTXPKT); + } } /* TCP timer values in ms */ @@ -2398,7 +2500,7 @@ static void tp_config(adapter_t *adap, const struct tp_params *p) */ static void tp_set_timers(adapter_t *adap, unsigned int core_clk) { - unsigned int tre = fls(core_clk / (1000000 / TP_TMR_RES)) - 1; + unsigned int tre = adap->params.tp.tre; unsigned int dack_re = adap->params.tp.dack_re; unsigned int tstamp_re = fls(core_clk / 1000); /* 1ms, at least */ unsigned int tps = core_clk >> tre; @@ -2456,6 +2558,7 @@ int t3_tp_set_coalescing_size(adapter_t *adap, unsigned int size, int psh) val |= F_RXCOALESCEENABLE; if (psh) val |= F_RXCOALESCEPSHEN; + size = min(MAX_RX_COALESCING_LEN, size); t3_write_reg(adap, A_TP_PARA_REG2, V_RXCOALESCESIZE(size) | V_MAXRXDATA(MAX_RX_COALESCING_LEN)); } @@ -2485,11 +2588,10 @@ static void __devinit init_mtus(unsigned short mtus[]) * are enabled and still have at least 8 bytes of payload. */ mtus[0] = 88; - mtus[1] = 88; /* workaround for silicon starting at 1 */ + mtus[1] = 88; mtus[2] = 256; mtus[3] = 512; mtus[4] = 576; - /* mtus[4] = 808; */ mtus[5] = 1024; mtus[6] = 1280; mtus[7] = 1492; @@ -2705,6 +2807,33 @@ static void ulp_config(adapter_t *adap, const struct tp_params *p) ulp_region(adap, PBL, m, p->chan_rx_size / 4); t3_write_reg(adap, A_ULPRX_TDDP_TAGMASK, 0xffffffff); } + + +/** + * t3_set_proto_sram - set the contents of the protocol sram + * @adapter: the adapter + * @data: the protocol image + * + * Write the contents of the protocol SRAM. + */ +int t3_set_proto_sram(adapter_t *adap, u8 *data) +{ + int i; + u32 *buf = (u32 *)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_FIELD0, i << 1 | 1 << 31); + if (t3_wait_op_done(adap, A_TP_EMBED_OP_FIELD0, 1, 1, 5, 1)) + return -EIO; + } + return 0; +} #endif void t3_config_trace_filter(adapter_t *adapter, const struct trace_params *tp, @@ -2883,20 +3012,22 @@ int t3_mps_set_active_ports(adapter_t *adap, unsigned int port_mask) } /* - * Perform the bits of HW initialization that are dependent on the number - * of available ports. + * Perform the bits of HW initialization that are dependent on the Tx + * channels being used. */ -static void init_hw_for_avail_ports(adapter_t *adap, int nports) +static void chan_init_hw(adapter_t *adap, unsigned int chan_map) { int i; - if (nports == 1) { + if (chan_map != 3) { /* one channel */ t3_set_reg_field(adap, A_ULPRX_CTL, F_ROUND_ROBIN, 0); t3_set_reg_field(adap, A_ULPTX_CONFIG, F_CFG_RR_ARB, 0); - t3_write_reg(adap, A_MPS_CFG, F_TPRXPORTEN | F_TPTXPORT0EN | - F_PORT0ACTIVE | F_ENFORCEPKT); - t3_write_reg(adap, A_PM1_TX_CFG, 0xc000c000); - } else { + t3_write_reg(adap, A_MPS_CFG, F_TPRXPORTEN | F_ENFORCEPKT | + (chan_map == 1 ? F_TPTXPORT0EN | F_PORT0ACTIVE : + F_TPTXPORT1EN | F_PORT1ACTIVE)); + t3_write_reg(adap, A_PM1_TX_CFG, + chan_map == 1 ? 0xffffffff : 0); + } else { /* two channels */ t3_set_reg_field(adap, A_ULPRX_CTL, 0, F_ROUND_ROBIN); t3_set_reg_field(adap, A_ULPTX_CONFIG, 0, F_CFG_RR_ARB); t3_write_reg(adap, A_ULPTX_DMA_WEIGHT, @@ -2999,9 +3130,9 @@ static int mc7_init(struct mc7 *mc7, unsigned int mc7_clock, int mem_type) adapter_t *adapter = mc7->adapter; const struct mc7_timing_params *p = &mc7_timings[mem_type]; - if (mc7->size == 0) + if (!mc7->size) return 0; - + val = t3_read_reg(adapter, mc7->offset + A_MC7_CFG); slow = val & F_SLOW; width = G_WIDTH(val); @@ -3166,6 +3297,12 @@ int t3_init_hw(adapter_t *adapter, u32 fw_params) else if (calibrate_xgm(adapter)) goto out_err; + 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); @@ -3194,8 +3331,8 @@ int t3_init_hw(adapter_t *adapter, u32 fw_params) else t3_set_reg_field(adapter, A_PCIX_CFG, 0, F_CLIDECEN); - t3_write_reg(adapter, A_PM1_RX_CFG, 0xf000f000); - init_hw_for_avail_ports(adapter, adapter->params.nports); + t3_write_reg(adapter, A_PM1_RX_CFG, 0xffffffff); + chan_init_hw(adapter, adapter->params.chan_map); t3_sge_init(adapter, &adapter->params.sge); t3_write_reg(adapter, A_CIM_HOST_ACC_DATA, vpd->uclk | fw_params); @@ -3210,6 +3347,7 @@ int t3_init_hw(adapter_t *adapter, u32 fw_params) CH_ERR(adapter, "uP initialization timed out\n"); goto out_err; } + err = 0; out_err: return err; @@ -3314,8 +3452,16 @@ static void __devinit mc7_prep(adapter_t *adapter, struct mc7 *mc7, 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; + index = 0; + } else + mac->nucast = 1; + mac->offset = (XGMAC0_1_BASE_ADDR - XGMAC0_0_BASE_ADDR) * index; - mac->nucast = 1; if (adapter->params.rev == 0 && uses_xaui(adapter)) { t3_write_reg(adapter, A_XGM_SERDES_CTRL + mac->offset, @@ -3327,7 +3473,8 @@ void mac_prep(struct cmac *mac, adapter_t *adapter, int index) void early_hw_init(adapter_t *adapter, const struct adapter_info *ai) { - u32 val = V_PORTSPEED(is_10G(adapter) ? 3 : 2); + u32 val = V_PORTSPEED(is_10G(adapter) || adapter->params.nports > 2 ? + 3 : 2); mi1_init(adapter, ai); t3_write_reg(adapter, A_I2C_CFG, /* set for 80KHz */ @@ -3335,7 +3482,7 @@ void early_hw_init(adapter_t *adapter, const struct adapter_info *ai) t3_write_reg(adapter, A_T3DBG_GPIO_EN, ai->gpio_out | F_GPIO0_OEN | F_GPIO0_OUT_VAL); t3_write_reg(adapter, A_MC5_DB_SERVER_INDEX, 0); - + if (adapter->params.rev == 0 || !uses_xaui(adapter)) val |= F_ENRGMII; @@ -3354,9 +3501,9 @@ void early_hw_init(adapter_t *adapter, const struct adapter_info *ai) * Reset the adapter. PCIe cards lose their config space during reset, PCI-X * ones don't. */ -int t3_reset_adapter(adapter_t *adapter) +static int t3_reset_adapter(adapter_t *adapter) { - int i, save_and_restore_pcie = + int i, save_and_restore_pcie = adapter->params.rev < T3_REV_B2 && is_pcie(adapter); uint16_t devid = 0; @@ -3397,7 +3544,8 @@ int __devinit t3_prep_adapter(adapter_t *adapter, get_pci_mode(adapter, &adapter->params.pci); adapter->params.info = ai; - adapter->params.nports = ai->nports; + adapter->params.nports = ai->nports0 + ai->nports1; + 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) ? @@ -3406,9 +3554,10 @@ int __devinit t3_prep_adapter(adapter_t *adapter, t3_os_find_pci_capability(adapter, PCI_CAP_ID_VPD); ret = get_vpd_params(adapter, &adapter->params.vpd); - if (ret < 0) + if (ret < 0) { + printf("failed to get VPD params\n"); return ret; - + } if (reset && t3_reset_adapter(adapter)) return -1; @@ -3421,7 +3570,7 @@ int __devinit t3_prep_adapter(adapter_t *adapter, mc7_prep(adapter, &adapter->pmtx, MC7_PMTX_BASE_ADDR, "PMTX"); mc7_prep(adapter, &adapter->cm, MC7_CM_BASE_ADDR, "CM"); - p->nchan = ai->nports; + p->nchan = adapter->params.chan_map == 3 ? 2 : 1; p->pmrx_size = t3_mc7_size(&adapter->pmrx); p->pmtx_size = t3_mc7_size(&adapter->pmtx); p->cm_size = t3_mc7_size(&adapter->cm); @@ -3433,11 +3582,14 @@ int __devinit t3_prep_adapter(adapter_t *adapter, p->tx_num_pgs = pm_num_pages(p->chan_tx_size, p->tx_pg_size); p->ntimer_qs = p->cm_size >= (128 << 20) || adapter->params.rev > 0 ? 12 : 6; + p->tre = fls(adapter->params.vpd.cclk / (1000 / TP_TMR_RES)) - + 1; p->dack_re = fls(adapter->params.vpd.cclk / 10) - 1; /* 100us */ } + adapter->params.offload = t3_mc7_size(&adapter->pmrx) && - t3_mc7_size(&adapter->pmtx) && - t3_mc7_size(&adapter->cm); + t3_mc7_size(&adapter->pmtx) && + t3_mc7_size(&adapter->cm); if (is_offload(adapter)) { adapter->params.mc5.nservers = DEFAULT_NSERVERS; @@ -3456,12 +3608,22 @@ int __devinit t3_prep_adapter(adapter_t *adapter, for_each_port(adapter, i) { u8 hw_addr[6]; - struct port_info *p = &adapter->port[i]; + struct port_info *p = adap2pinfo(adapter, i); - while (!adapter->params.vpd.port_type[j]) + while (adapter->params.vpd.port_type[j] == 0) { ++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 new file mode 100644 index 0000000..51e254e --- /dev/null +++ b/sys/dev/cxgb/common/cxgb_vsc7323.c @@ -0,0 +1,340 @@ + +/************************************************************************** + +Copyright (c) 2007, Chelsio Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Neither the name of the Chelsio Corporation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +***************************************************************************/ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#ifdef CONFIG_DEFINED +#include <common/cxgb_common.h> +#else +#include <dev/cxgb/common/cxgb_common.h> +#endif + +enum { + ELMR_ADDR = 0, + ELMR_STAT = 1, + ELMR_DATA_LO = 2, + ELMR_DATA_HI = 3, + + ELMR_MDIO_ADDR = 10 +}; + +#define VSC_REG(block, subblock, reg) \ + ((reg) | ((subblock) << 8) | ((block) << 12)) + +int t3_elmr_blk_write(adapter_t *adap, int start, const u32 *vals, int n) +{ + int ret; + const struct mdio_ops *mo = adapter_info(adap)->mdio_ops; + + ELMR_LOCK(adap); + ret = mo->write(adap, ELMR_MDIO_ADDR, 0, ELMR_ADDR, start); + for ( ; !ret && n; n--, vals++) { + ret = mo->write(adap, ELMR_MDIO_ADDR, 0, ELMR_DATA_LO, + *vals & 0xffff); + if (!ret) + ret = mo->write(adap, ELMR_MDIO_ADDR, 0, ELMR_DATA_HI, + *vals >> 16); + } + ELMR_UNLOCK(adap); + return ret; +} + +static int elmr_write(adapter_t *adap, int addr, u32 val) +{ + return t3_elmr_blk_write(adap, addr, &val, 1); +} + +int t3_elmr_blk_read(adapter_t *adap, int start, u32 *vals, int n) +{ + int ret; + unsigned int v; + const struct mdio_ops *mo = adapter_info(adap)->mdio_ops; + + ELMR_LOCK(adap); + + ret = mo->write(adap, ELMR_MDIO_ADDR, 0, ELMR_ADDR, start); + if (ret) + goto out; + ret = mo->read(adap, ELMR_MDIO_ADDR, 0, ELMR_STAT, &v); + if (ret) + goto out; + if (v != 1) { + ret = -ETIMEDOUT; + goto out; + } + + for ( ; !ret && n; n--, vals++) { + ret = mo->read(adap, ELMR_MDIO_ADDR, 0, ELMR_DATA_LO, vals); + if (!ret) { + ret = mo->read(adap, ELMR_MDIO_ADDR, 0, ELMR_DATA_HI, + &v); + *vals |= v << 16; + } + } +out: ELMR_UNLOCK(adap); + return ret; +} + +int t3_vsc7323_init(adapter_t *adap, int nports) +{ + static struct addr_val_pair sys_avp[] = { + { VSC_REG(7, 15, 0xf), 2 }, + { VSC_REG(7, 15, 0x19), 0xd6 }, + { VSC_REG(7, 15, 7), 0xc }, + { VSC_REG(7, 1, 0), 0x220 }, + }; + static struct addr_val_pair fifo_avp[] = { + { VSC_REG(2, 0, 0x2f), 0 }, + { VSC_REG(2, 0, 0xf), 0xa0010291 }, + { VSC_REG(2, 1, 0x2f), 1 }, + { VSC_REG(2, 1, 0xf), 0xa0026301 } + }; + static struct addr_val_pair xg_avp[] = { + { VSC_REG(1, 10, 0), 0x600b }, + { VSC_REG(1, 10, 2), 0x4000 }, + { VSC_REG(1, 10, 5), 0x65 }, + { VSC_REG(1, 10, 7), 3 }, + { VSC_REG(1, 10, 0x23), 0x800007bf }, + { VSC_REG(1, 10, 0x24), 4 } + }; + + int i, ret, ing_step, egr_step, ing_bot, egr_bot; + + 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))) + return ret; + + + ing_step = 0xc0 / nports; + egr_step = 0x40 / nports; + ing_bot = egr_bot = 0; +// ing_wm = ing_step * 64; +// 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), + ((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, 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; + + + 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; + + for (i = 0; i < ARRAY_SIZE(xg_avp); i++) + if ((ret = t3_elmr_blk_write(adap, xg_avp[i].reg_addr, + &xg_avp[i].val, 1))) + return ret; + + for (i = 0; i < nports; i++) + if ((ret = elmr_write(adap, VSC_REG(1, i, 0), 0xa59c)) || + (ret = elmr_write(adap, VSC_REG(1, i, 5), + (i << 12) | 0x63)) || + (ret = elmr_write(adap, VSC_REG(1, i, 0xb), 0x96)) || + (ret = elmr_write(adap, VSC_REG(1, i, 0x15), 0x21))) + return ret; + return ret; +} + +int t3_vsc7323_set_speed_fc(adapter_t *adap, int speed, int fc, int port) +{ + int mode, clk, r; + + if (speed >= 0) { + if (speed == SPEED_10) + mode = clk = 1; + else if (speed == SPEED_100) + mode = 1, clk = 2; + else if (speed == SPEED_1000) + mode = clk = 3; + else + return -EINVAL; + + if ((r = elmr_write(adap, VSC_REG(1, port, 0), + 0xa590 | (mode << 2))) || + (r = elmr_write(adap, VSC_REG(1, port, 0xb), + 0x91 | (clk << 1))) || + (r = elmr_write(adap, VSC_REG(1, port, 0xb), + 0x90 | (clk << 1))) || + (r = elmr_write(adap, VSC_REG(1, port, 0), + 0xa593 | (mode << 2)))) + return r; + } + + r = (fc & PAUSE_RX) ? 0x6ffff : 0x2ffff; + if (fc & PAUSE_TX) + r |= (1 << 19); + return elmr_write(adap, VSC_REG(1, port, 1), r); +} + +int t3_vsc7323_set_mtu(adapter_t *adap, unsigned int mtu, int port) +{ + return elmr_write(adap, VSC_REG(1, port, 2), mtu); +} + +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]); + if (!ret) + ret = elmr_write(adap, VSC_REG(1, port, 4), + (addr[3] << 16) | (addr[4] << 8) | addr[5]); + return ret; +} + +int t3_vsc7323_enable(adapter_t *adap, int port, int which) +{ + int ret; + unsigned int v, orig; + + ret = t3_elmr_blk_read(adap, VSC_REG(1, port, 0), &v, 1); + if (!ret) { + orig = v; + if (which & MAC_DIRECTION_TX) + v |= 1; + if (which & MAC_DIRECTION_RX) + v |= 2; + if (v != orig) + ret = elmr_write(adap, VSC_REG(1, port, 0), v); + } + return ret; +} + +int t3_vsc7323_disable(adapter_t *adap, int port, int which) +{ + int ret; + unsigned int v, orig; + + ret = t3_elmr_blk_read(adap, VSC_REG(1, port, 0), &v, 1); + if (!ret) { + orig = v; + if (which & MAC_DIRECTION_TX) + v &= ~1; + if (which & MAC_DIRECTION_RX) + v &= ~2; + if (v != orig) + ret = elmr_write(adap, VSC_REG(1, port, 0), v); + } + return ret; +} + +#define STATS0_START 1 +#define STATS1_START 0x24 +#define NSTATS0 (0x1d - STATS0_START + 1) +#define NSTATS1 (0x2a - STATS1_START + 1) + +const struct mac_stats *t3_vsc7323_update_stats(struct cmac *mac) +{ + int ret; + u64 rx_ucast, tx_ucast; + u32 stats0[NSTATS0], stats1[NSTATS1]; + + ret = t3_elmr_blk_read(mac->adapter, + VSC_REG(4, mac->ext_port, STATS0_START), + stats0, NSTATS0); + if (!ret) + ret = t3_elmr_blk_read(mac->adapter, + VSC_REG(4, mac->ext_port, STATS1_START), + stats1, NSTATS1); + if (ret) + goto out; + + /* + * HW counts Rx/Tx unicast frames but we want all the frames. + */ + rx_ucast = mac->stats.rx_frames - mac->stats.rx_mcast_frames - + mac->stats.rx_bcast_frames; + rx_ucast += (u64)(stats0[6 - STATS0_START] - (u32)rx_ucast); + tx_ucast = mac->stats.tx_frames - mac->stats.tx_mcast_frames - + mac->stats.tx_bcast_frames; + tx_ucast += (u64)(stats0[27 - STATS0_START] - (u32)tx_ucast); + +#define RMON_UPDATE(mac, name, hw_stat) \ + mac->stats.name += (u64)((hw_stat) - (u32)(mac->stats.name)) + + RMON_UPDATE(mac, rx_octets, stats0[4 - STATS0_START]); + RMON_UPDATE(mac, rx_frames, stats0[6 - STATS0_START]); + RMON_UPDATE(mac, rx_frames, stats0[7 - STATS0_START]); + RMON_UPDATE(mac, rx_frames, stats0[8 - STATS0_START]); + RMON_UPDATE(mac, rx_mcast_frames, stats0[7 - STATS0_START]); + RMON_UPDATE(mac, rx_bcast_frames, stats0[8 - STATS0_START]); + RMON_UPDATE(mac, rx_fcs_errs, stats0[9 - STATS0_START]); + RMON_UPDATE(mac, rx_pause, stats0[2 - STATS0_START]); + RMON_UPDATE(mac, rx_jabber, stats0[16 - STATS0_START]); + RMON_UPDATE(mac, rx_short, stats0[11 - STATS0_START]); + RMON_UPDATE(mac, rx_symbol_errs, stats0[1 - STATS0_START]); + RMON_UPDATE(mac, rx_too_long, stats0[15 - STATS0_START]); + + RMON_UPDATE(mac, rx_frames_64, stats0[17 - STATS0_START]); + RMON_UPDATE(mac, rx_frames_65_127, stats0[18 - STATS0_START]); + RMON_UPDATE(mac, rx_frames_128_255, stats0[19 - STATS0_START]); + RMON_UPDATE(mac, rx_frames_256_511, stats0[20 - STATS0_START]); + RMON_UPDATE(mac, rx_frames_512_1023, stats0[21 - STATS0_START]); + RMON_UPDATE(mac, rx_frames_1024_1518, stats0[22 - STATS0_START]); + RMON_UPDATE(mac, rx_frames_1519_max, stats0[23 - STATS0_START]); + + RMON_UPDATE(mac, tx_octets, stats0[26 - STATS0_START]); + RMON_UPDATE(mac, tx_frames, stats0[27 - STATS0_START]); + RMON_UPDATE(mac, tx_frames, stats0[28 - STATS0_START]); + RMON_UPDATE(mac, tx_frames, stats0[29 - STATS0_START]); + RMON_UPDATE(mac, tx_mcast_frames, stats0[28 - STATS0_START]); + RMON_UPDATE(mac, tx_bcast_frames, stats0[29 - STATS0_START]); + RMON_UPDATE(mac, tx_pause, stats0[25 - STATS0_START]); + + RMON_UPDATE(mac, tx_underrun, 0); + + RMON_UPDATE(mac, tx_frames_64, stats1[36 - STATS1_START]); + RMON_UPDATE(mac, tx_frames_65_127, stats1[37 - STATS1_START]); + RMON_UPDATE(mac, tx_frames_128_255, stats1[38 - STATS1_START]); + RMON_UPDATE(mac, tx_frames_256_511, stats1[39 - STATS1_START]); + RMON_UPDATE(mac, tx_frames_512_1023, stats1[40 - STATS1_START]); + RMON_UPDATE(mac, tx_frames_1024_1518, stats1[41 - STATS1_START]); + RMON_UPDATE(mac, tx_frames_1519_max, stats1[42 - STATS1_START]); + +#undef RMON_UPDATE + + mac->stats.rx_frames = rx_ucast + mac->stats.rx_mcast_frames + + mac->stats.rx_bcast_frames; + mac->stats.tx_frames = tx_ucast + mac->stats.tx_mcast_frames + + mac->stats.tx_bcast_frames; +out: return &mac->stats; +} diff --git a/sys/dev/cxgb/common/cxgb_xgmac.c b/sys/dev/cxgb/common/cxgb_xgmac.c index 22cd22e..34b05cd 100644 --- a/sys/dev/cxgb/common/cxgb_xgmac.c +++ b/sys/dev/cxgb/common/cxgb_xgmac.c @@ -1,3 +1,4 @@ + /************************************************************************** Copyright (c) 2007, Chelsio Inc. @@ -128,8 +129,23 @@ int t3_mac_reset(struct cmac *mac) xaui_serdes_reset(mac); } + + if (mac->multiport) { + t3_write_reg(adap, A_XGM_RX_MAX_PKT_SIZE + oft, + MAX_FRAME_SIZE - 4); + t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + oft, 0, + F_DISPREAMBLE); + t3_set_reg_field(adap, A_XGM_RX_CFG + oft, 0, F_COPYPREAMBLE | + F_ENNON802_3PREAMBLE); + t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + oft, + V_TXFIFOTHRESH(M_TXFIFOTHRESH), + V_TXFIFOTHRESH(64)); + t3_write_reg(adap, A_XGM_TX_CTRL + oft, F_TXEN); + t3_write_reg(adap, A_XGM_RX_CTRL + oft, F_RXEN); + } + val = F_MAC_RESET_; - if (is_10G(adap)) + if (is_10G(adap) || mac->multiport) val |= F_PCS_RESET_; else if (uses_xaui(adap)) val |= F_PCS_RESET_ | F_XG2G_RESET_; @@ -220,9 +236,14 @@ static void set_addr_filter(struct cmac *mac, int idx, const u8 *addr) /* Set one of the station's unicast MAC addresses. */ int t3_mac_set_address(struct cmac *mac, unsigned int idx, u8 addr[6]) { + if (mac->multiport) + idx = mac->ext_port + idx * mac->adapter->params.nports; if (idx >= mac->nucast) return -EINVAL; set_addr_filter(mac, idx, addr); + if (mac->multiport && idx < mac->adapter->params.nports) + t3_vsc7323_set_addr(mac->adapter, addr, idx); + return 0; } @@ -231,7 +252,7 @@ int t3_mac_set_address(struct cmac *mac, unsigned int idx, u8 addr[6]) * unicast addresses. Caller should reload the unicast and multicast addresses * after calling this. */ -int t3_mac_set_num_ucast(struct cmac *mac, int n) +int t3_mac_set_num_ucast(struct cmac *mac, unsigned char n) { if (n > EXACT_ADDR_FILTERS) return -EINVAL; @@ -239,6 +260,28 @@ int t3_mac_set_num_ucast(struct cmac *mac, int n) return 0; } +static void disable_exact_filters(struct cmac *mac) +{ + unsigned int i, reg = mac->offset + A_XGM_RX_EXACT_MATCH_LOW_1; + + for (i = 0; i < EXACT_ADDR_FILTERS; i++, reg += 8) { + u32 v = t3_read_reg(mac->adapter, reg); + t3_write_reg(mac->adapter, reg, v); + } + t3_read_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_LOW_1); /* flush */ +} + +static void enable_exact_filters(struct cmac *mac) +{ + unsigned int i, reg = mac->offset + A_XGM_RX_EXACT_MATCH_HIGH_1; + + for (i = 0; i < EXACT_ADDR_FILTERS; i++, reg += 8) { + u32 v = t3_read_reg(mac->adapter, reg); + t3_write_reg(mac->adapter, reg, v); + } + t3_read_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_LOW_1); /* flush */ +} + /* Calculate the RX hash filter index of an Ethernet address */ static int hash_hw_addr(const u8 *addr) { @@ -255,16 +298,18 @@ static int hash_hw_addr(const u8 *addr) int t3_mac_set_rx_mode(struct cmac *mac, struct t3_rx_mode *rm) { - u32 val, hash_lo, hash_hi; + u32 hash_lo, hash_hi; adapter_t *adap = mac->adapter; unsigned int oft = mac->offset; - val = t3_read_reg(adap, A_XGM_RX_CFG + oft) & ~F_COPYALLFRAMES; if (promisc_rx_mode(rm)) - val |= F_COPYALLFRAMES; - t3_write_reg(adap, A_XGM_RX_CFG + oft, val); + mac->promisc_map |= 1 << mac->ext_port; + else + mac->promisc_map &= ~(1 << mac->ext_port); + t3_set_reg_field(adap, A_XGM_RX_CFG + oft, F_COPYALLFRAMES, + mac->promisc_map ? F_COPYALLFRAMES : 0); - if (allmulti_rx_mode(rm)) + if (allmulti_rx_mode(rm) || mac->multiport) hash_lo = hash_hi = 0xffffffff; else { u8 *addr; @@ -289,7 +334,15 @@ int t3_mac_set_rx_mode(struct cmac *mac, struct t3_rx_mode *rm) return 0; } -int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu) +static int rx_fifo_hwm(int mtu) +{ + int hwm; + + hwm = max(MAC_RXFIFO_SIZE - 3 * mtu, (MAC_RXFIFO_SIZE * 38) / 100); + return min(hwm, MAC_RXFIFO_SIZE - 8192); +} + +int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu) { int hwm, lwm; unsigned int thres, v; @@ -300,17 +353,39 @@ int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu) * packet size register includes header, but not FCS. */ mtu += 14; + if (mac->multiport) + mtu += 8; /* for preamble */ if (mtu > MAX_FRAME_SIZE - 4) return -EINVAL; - t3_write_reg(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset, mtu); + if (mac->multiport) + return t3_vsc7323_set_mtu(adap, mtu - 4, mac->ext_port); + + if (adap->params.rev == T3_REV_B2 && + (t3_read_reg(adap, A_XGM_RX_CTRL + mac->offset) & F_RXEN)) { + disable_exact_filters(mac); + v = t3_read_reg(adap, A_XGM_RX_CFG + mac->offset); + t3_set_reg_field(adap, A_XGM_RX_CFG + mac->offset, + F_ENHASHMCAST | F_COPYALLFRAMES, F_DISBCAST); + + /* drain rx FIFO */ + if (t3_wait_op_done(adap, + A_XGM_RX_MAX_PKT_SIZE_ERR_CNT + mac->offset, + 1 << 31, 1, 20, 5)) { + t3_write_reg(adap, A_XGM_RX_CFG + mac->offset, v); + enable_exact_filters(mac); + return -EIO; + } + t3_write_reg(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset, mtu); + t3_write_reg(adap, A_XGM_RX_CFG + mac->offset, v); + enable_exact_filters(mac); + } else + t3_write_reg(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset, mtu); /* * Adjust the PAUSE frame watermarks. We always set the LWM, and the * HWM only if flow-control is enabled. */ - hwm = max_t(unsigned int, MAC_RXFIFO_SIZE - 3 * mtu, - MAC_RXFIFO_SIZE * 38 / 100); - hwm = min(hwm, MAC_RXFIFO_SIZE - 8192); + hwm = rx_fifo_hwm(mtu); lwm = min(3 * (int) mtu, MAC_RXFIFO_SIZE /4); v = t3_read_reg(adap, A_XGM_RXFIFO_CFG + mac->offset); v &= ~V_RXFIFOPAUSELWM(M_RXFIFOPAUSELWM); @@ -318,6 +393,7 @@ int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu) if (G_RXFIFOPAUSEHWM(v)) v = (v & ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM)) | V_RXFIFOPAUSEHWM(hwm / 8); + t3_write_reg(adap, A_XGM_RXFIFO_CFG + mac->offset, v); /* Adjust the TX FIFO threshold based on the MTU */ @@ -335,7 +411,7 @@ int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu) */ if (adap->params.rev > 0) t3_write_reg(adap, A_XGM_PAUSE_TIMER + mac->offset, - (hwm-lwm) * 4 / 8); + (hwm - lwm) * 4 / 8); t3_write_reg(adap, A_XGM_TX_PAUSE_QUANTA + mac->offset, MAC_RXFIFO_SIZE * 4 * 8 / 512); return 0; @@ -349,6 +425,8 @@ 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) + return t3_vsc7323_set_speed_fc(adap, speed, fc, mac->ext_port); if (speed >= 0) { if (speed == SPEED_10) val = V_PORTSPEED(0); @@ -364,13 +442,14 @@ int t3_mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex, int fc) t3_set_reg_field(adap, A_XGM_PORT_CFG + oft, V_PORTSPEED(M_PORTSPEED), val); } -#if 0 + val = t3_read_reg(adap, A_XGM_RXFIFO_CFG + oft); val &= ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM); if (fc & PAUSE_TX) - val |= V_RXFIFOPAUSEHWM(G_RXFIFOPAUSELWM(val) + 128); /* +1KB */ + 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); -#endif + t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN, (fc & PAUSE_RX) ? F_TXPAUSEEN : 0); return 0; @@ -383,6 +462,9 @@ int t3_mac_enable(struct cmac *mac, int which) unsigned int oft = mac->offset; struct mac_stats *s = &mac->stats; + if (mac->multiport) + 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); @@ -415,6 +497,9 @@ int t3_mac_disable(struct cmac *mac, int which) adapter_t *adap = mac->adapter; int val; + if (mac->multiport) + return t3_vsc7323_disable(adap, mac->ext_port, which); + if (which & MAC_DIRECTION_TX) { 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); |